Statistics
| Revision:

root / src / jpilot.c @ 601

History | View | Annotate | Download (41.4 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
#else
46
#  include <pi-args.h>
47
#  include <pi-appinfo.h>
48
#  include <pi-address.h>
49
#endif
50
51
#include "mgutils.h"
52
#include "addritem.h"
53
#include "addrcache.h"
54
#include "jpilot.h"
55
#include "codeconv.h"
56
#include "utils.h"
57
58
#define JPILOT_DBHOME_DIR   ".jpilot"
59
#define JPILOT_DBHOME_FILE  "AddressDB.pdb"
60
#define PILOT_LINK_LIB_NAME "libpisock.so"
61
62
#define IND_LABEL_LASTNAME  0         /* Index of last name in address data */
63
#define IND_LABEL_FIRSTNAME 1         /* Index of first name in address data */
64
#define IND_PHONE_EMAIL     4         /* Index of E-Mail address in phone labels */
65
#define OFFSET_PHONE_LABEL  3         /* Offset to phone data in address data */
66
#define IND_CUSTOM_LABEL    14        /* Offset to custom label names */
67
#define NUM_CUSTOM_LABEL    4         /* Number of custom labels */
68
69
/* Shamelessly copied from JPilot (libplugin.h) */
70
typedef struct {
71
        unsigned char db_name[32];
72
        unsigned char flags[2];
73
        unsigned char version[2];
74
        unsigned char creation_time[4];
75
        unsigned char modification_time[4];
76
        unsigned char backup_time[4];
77
        unsigned char modification_number[4];
78
        unsigned char app_info_offset[4];
79
        unsigned char sort_info_offset[4];
80
        unsigned char type[4];/*Database ID */
81
        unsigned char creator_id[4];/*Application ID */
82
        unsigned char unique_id_seed[4];
83
        unsigned char next_record_list_id[4];
84
        unsigned char number_of_records[2];
85
} RawDBHeader;
86
87
/* Shamelessly copied from JPilot (libplugin.h) */
88
typedef struct {
89
        char db_name[32];
90
        unsigned int flags;
91
        unsigned int version;
92
        time_t creation_time;
93
        time_t modification_time;
94
        time_t backup_time;
95
        unsigned int modification_number;
96
        unsigned int app_info_offset;
97
        unsigned int sort_info_offset;
98
        char type[5];/*Database ID */
99
        char creator_id[5];/*Application ID */
100
        char unique_id_seed[5];
101
        unsigned int next_record_list_id;
102
        unsigned int number_of_records;
103
} DBHeader;
104
105
/* Shamelessly copied from JPilot (libplugin.h) */
106
typedef struct {
107
        unsigned char Offset[4];  /*4 bytes offset from BOF to record */
108
        unsigned char attrib;
109
        unsigned char unique_ID[3];
110
} record_header;
111
112
/* Shamelessly copied from JPilot (libplugin.h) */
113
typedef struct mem_rec_header_s {
114
        unsigned int rec_num;
115
        unsigned int offset;
116
        unsigned int unique_id;
117
        unsigned char attrib;
118
        struct mem_rec_header_s *next;
119
} mem_rec_header;
120
121
/* Shamelessly copied from JPilot (libplugin.h) */
122
#define SPENT_PC_RECORD_BIT        256
123
124
typedef enum {
125
        PALM_REC = 100L,
126
        MODIFIED_PALM_REC = 101L,
127
        DELETED_PALM_REC = 102L,
128
        NEW_PC_REC = 103L,
129
        DELETED_PC_REC = SPENT_PC_RECORD_BIT + 104L,
130
        DELETED_DELETED_PALM_REC = SPENT_PC_RECORD_BIT + 105L
131
} PCRecType;
132
133
/* Shamelessly copied from JPilot (libplugin.h) */
134
typedef struct {
135
        PCRecType rt;
136
        unsigned int unique_id;
137
        unsigned char attrib;
138
        void *buf;
139
        int size;
140
} buf_rec;
141
142
/* Shamelessly copied from JPilot (libplugin.h) */
143
typedef struct {
144
        unsigned long header_len;
145
        unsigned long header_version;
146
        unsigned long rec_len;
147
        unsigned long unique_id;
148
        unsigned long rt; /* Record Type */
149
        unsigned char attrib;
150
} PC3RecordHeader;
151
152
enum {
153
        FAMILY_LAST = 0,
154
        FAMILY_FIRST = 1
155
} name_order;
156
157
gboolean convert_charcode;
158
159
/*
160
* Create new pilot file object.
161
*/
162
JPilotFile *jpilot_create() {
163
        JPilotFile *pilotFile;
164
        pilotFile = g_new0( JPilotFile, 1 );
165
        pilotFile->name = NULL;
166
        pilotFile->file = NULL;
167
        pilotFile->path = NULL;
168
        pilotFile->addressCache = addrcache_create();
169
        pilotFile->readMetadata = FALSE;
170
        pilotFile->customLabels = NULL;
171
        pilotFile->labelInd = NULL;
172
        pilotFile->retVal = MGU_SUCCESS;
173
        pilotFile->accessFlag = FALSE;
174
        pilotFile->havePC3 = FALSE;
175
        pilotFile->pc3ModifyTime = 0;
176
        return pilotFile;
177
}
178
179
/*
180
* Create new pilot file object for specified file.
181
*/
182
JPilotFile *jpilot_create_path( const gchar *path ) {
183
        JPilotFile *pilotFile;
184
        pilotFile = jpilot_create();
185
        jpilot_set_file( pilotFile, path );
186
        return pilotFile;
187
}
188
189
/*
190
* Properties...
191
*/
192
void jpilot_set_name( JPilotFile* pilotFile, const gchar *value ) {
193
        g_return_if_fail( pilotFile != NULL );
194
        pilotFile->name = mgu_replace_string( pilotFile->name, value );
195
}
196
void jpilot_set_file( JPilotFile* pilotFile, const gchar *value ) {
197
        g_return_if_fail( pilotFile != NULL );
198
        addrcache_refresh( pilotFile->addressCache );
199
        pilotFile->readMetadata = FALSE;
200
        pilotFile->path = mgu_replace_string( pilotFile->path, value );
201
}
202
void jpilot_set_accessed( JPilotFile *pilotFile, const gboolean value ) {
203
        g_return_if_fail( pilotFile != NULL );
204
        pilotFile->accessFlag = value;
205
}
206
207
gint jpilot_get_status( JPilotFile *pilotFile ) {
208
        g_return_val_if_fail( pilotFile != NULL, -1 );
209
        return pilotFile->retVal;
210
}
211
ItemFolder *jpilot_get_root_folder( JPilotFile *pilotFile ) {
212
        g_return_val_if_fail( pilotFile != NULL, NULL );
213
        return addrcache_get_root_folder( pilotFile->addressCache );
214
}
215
gchar *jpilot_get_name( JPilotFile *pilotFile ) {
216
        g_return_val_if_fail( pilotFile != NULL, NULL );
217
        return pilotFile->name;
218
}
219
220
/*
221
* Test whether file was read.
222
* Return: TRUE if file was read.
223
*/
224
gboolean jpilot_get_read_flag( JPilotFile *pilotFile ) {
225
        g_return_val_if_fail( pilotFile != NULL, FALSE );
226
        return pilotFile->addressCache->dataRead;
227
}
228
229
/*
230
* Free up custom label list.
231
*/
232
void jpilot_clear_custom_labels( JPilotFile *pilotFile ) {
233
        GList *node;
234
235
        g_return_if_fail( pilotFile != NULL );
236
237
        /* Release custom labels */
238
        mgu_free_dlist( pilotFile->customLabels );
239
        pilotFile->customLabels = NULL;
240
241
        /* Release indexes */
242
        node = pilotFile->labelInd;
243
        while( node ) {
244
                node->data = NULL;
245
                node = g_list_next( node );
246
        }
247
        g_list_free( pilotFile->labelInd );
248
        pilotFile->labelInd = NULL;
249
250
        /* Force a fresh read */
251
        addrcache_refresh( pilotFile->addressCache );
252
}
253
254
/*
255
* Append a custom label, representing an E-Mail address field to the
256
* custom label list.
257
*/
258
void jpilot_add_custom_label( JPilotFile *pilotFile, const gchar *labelName ) {
259
        g_return_if_fail( pilotFile != NULL );
260
261
        if( labelName ) {
262
                gchar *labelCopy = g_strdup( labelName );
263
                g_strstrip( labelCopy );
264
                if( *labelCopy == '\0' ) {
265
                        g_free( labelCopy );
266
                }
267
                else {
268
                        pilotFile->customLabels = g_list_append( pilotFile->customLabels, labelCopy );
269
                        /* Force a fresh read */
270
                        addrcache_refresh( pilotFile->addressCache );
271
                }
272
        }
273
}
274
275
/*
276
* Get list of custom labels.
277
* Return: List of labels. Must use g_free() when done.
278
*/
279
GList *jpilot_get_custom_labels( JPilotFile *pilotFile ) {
280
        GList *retVal = NULL;
281
        GList *node;
282
283
        g_return_val_if_fail( pilotFile != NULL, NULL );
284
285
        node = pilotFile->customLabels;
286
        while( node ) {
287
                retVal = g_list_append( retVal, g_strdup( node->data ) );
288
                node = g_list_next( node );
289
        }
290
        return retVal;
291
}
292
293
/*
294
* Return filespec of PC3 file corresponding to JPilot PDB file.
295
* Note: Filespec should be g_free() when done.
296
*/
297
static gchar *jpilot_get_pc3_file( JPilotFile *pilotFile ) {
298
        gchar *fileSpec, *r;
299
        gint i, len, pos;
300
301
        if( pilotFile == NULL ) return NULL;
302
        if( pilotFile->path == NULL ) return NULL;
303
304
        fileSpec = g_strdup( pilotFile->path );
305
        len = strlen( fileSpec );
306
        pos = -1;
307
        r = NULL;
308
        for( i = len; i > 0; i-- ) {
309
                if( *(fileSpec + i) == '.' ) {
310
                        pos = i + 1;
311
                        r = fileSpec + pos;
312
                        break;
313
                }
314
        }
315
        if( r ) {
316
                if( len - pos == 3 ) {
317
                        *r++ = 'p'; *r++ = 'c'; *r = '3';
318
                        return fileSpec;
319
                }
320
        }
321
        g_free( fileSpec );
322
        return NULL;
323
}
324
325
/*
326
* Save PC3 file time to cache.
327
* return: TRUE if time marked.
328
*/
329
static gboolean jpilot_mark_files( JPilotFile *pilotFile ) {
330
        gboolean retVal = FALSE;
331
        struct stat filestat;
332
        gchar *pcFile;
333
334
        /* Mark PDB file cache */
335
        retVal = addrcache_mark_file( pilotFile->addressCache, pilotFile->path );
336
337
        /* Now mark PC3 file */
338
        pilotFile->havePC3 = FALSE;
339
        pilotFile->pc3ModifyTime = 0;
340
        pcFile = jpilot_get_pc3_file( pilotFile );
341
        if( pcFile == NULL ) return retVal;
342
        if( 0 == g_lstat( pcFile, &filestat ) ) {
343
                pilotFile->havePC3 = TRUE;
344
                pilotFile->pc3ModifyTime = filestat.st_mtime;
345
                retVal = TRUE;
346
        }
347
        g_free( pcFile );
348
        return retVal;
349
}
350
351
/*
352
* Check whether JPilot PDB or PC3 file has changed by comparing
353
* with cached data.
354
* return: TRUE if file has changed.
355
*/
356
static gboolean jpilot_check_files( JPilotFile *pilotFile ) {
357
        gboolean retVal = TRUE;
358
        struct stat filestat;
359
        gchar *pcFile;
360
361
        /* Check main file */
362
        if( addrcache_check_file( pilotFile->addressCache, pilotFile->path ) )
363
                return TRUE;
364
365
        /* Test PC3 file */
366
        if( ! pilotFile->havePC3 ) return FALSE;
367
        pcFile = jpilot_get_pc3_file( pilotFile );
368
        if( pcFile == NULL ) return FALSE;
369
370
        if( 0 == g_lstat( pcFile, &filestat ) ) {
371
                if( filestat.st_mtime == pilotFile->pc3ModifyTime ) retVal = FALSE;
372
        }
373
        g_free( pcFile );
374
        return retVal;
375
}
376
377
/*
378
* Test whether file was modified since last access.
379
* Return: TRUE if file was modified.
380
*/
381
gboolean jpilot_get_modified( JPilotFile *pilotFile ) {
382
        g_return_val_if_fail( pilotFile != NULL, FALSE );
383
        return jpilot_check_files( pilotFile );
384
}
385
gboolean jpilot_get_accessed( JPilotFile *pilotFile ) {
386
        g_return_val_if_fail( pilotFile != NULL, FALSE );
387
        return pilotFile->accessFlag;
388
}
389
390
/*
391
* Free up pilot file object by releasing internal memory.
392
*/
393
void jpilot_free( JPilotFile *pilotFile ) {
394
        g_return_if_fail( pilotFile != NULL );
395
396
        /* Free internal stuff */
397
        g_free( pilotFile->path );
398
399
        /* Release custom labels */
400
        jpilot_clear_custom_labels( pilotFile );
401
402
        /* Clear cache */
403
        addrcache_clear( pilotFile->addressCache );
404
        addrcache_free( pilotFile->addressCache );
405
        pilotFile->addressCache = NULL;
406
        pilotFile->readMetadata = FALSE;
407
        pilotFile->accessFlag = FALSE;
408
        pilotFile->havePC3 = FALSE;
409
        pilotFile->pc3ModifyTime = 0;
410
411
        /* Now release file object */
412
        g_free( pilotFile );
413
}
414
415
/*
416
* Refresh internal variables to force a file read.
417
*/
418
void jpilot_force_refresh( JPilotFile *pilotFile ) {
419
        addrcache_refresh( pilotFile->addressCache );
420
}
421
422
/*
423
* Print object to specified stream.
424
*/
425
void jpilot_print_file( JPilotFile *pilotFile, FILE *stream ) {
426
        GList *node;
427
428
        g_return_if_fail( pilotFile != NULL );
429
430
        fprintf( stream, "JPilotFile:\n" );
431
        fprintf( stream, "file spec: '%s'\n", pilotFile->path );
432
        fprintf( stream, " metadata: %s\n", pilotFile->readMetadata ? "yes" : "no" );
433
        fprintf( stream, "  ret val: %d\n", pilotFile->retVal );
434
435
        node = pilotFile->customLabels;
436
        while( node ) {
437
                fprintf( stream, "  c label: %s\n", (gchar *)node->data );
438
                node = g_list_next( node );
439
        }
440
441
        node = pilotFile->labelInd;
442
        while( node ) {
443
                fprintf( stream, " labelind: %d\n", GPOINTER_TO_INT(node->data) );
444
                node = g_list_next( node );
445
        }
446
447
        addrcache_print( pilotFile->addressCache, stream );
448
        fprintf( stream, "  ret val: %d\n", pilotFile->retVal );
449
        fprintf( stream, " have pc3: %s\n", pilotFile->havePC3 ? "yes" : "no" );
450
        fprintf( stream, " pc3 time: %lu\n", pilotFile->pc3ModifyTime );
451
        addritem_print_item_folder( pilotFile->addressCache->rootFolder, stream );
452
}
453
454
/*
455
* Print summary of object to specified stream.
456
*/
457
void jpilot_print_short( JPilotFile *pilotFile, FILE *stream ) {
458
        GList *node;
459
        g_return_if_fail( pilotFile != NULL );
460
        fprintf( stream, "JPilotFile:\n" );
461
        fprintf( stream, "file spec: '%s'\n", pilotFile->path );
462
        fprintf( stream, " metadata: %s\n", pilotFile->readMetadata ? "yes" : "no" );
463
        fprintf( stream, "  ret val: %d\n", pilotFile->retVal );
464
465
        node = pilotFile->customLabels;
466
        while( node ) {
467
                fprintf( stream, "  c label: %s\n", (gchar *)node->data );
468
                node = g_list_next( node );
469
        }
470
471
        node = pilotFile->labelInd;
472
        while( node ) {
473
                fprintf( stream, " labelind: %d\n", GPOINTER_TO_INT(node->data) );
474
                node = g_list_next( node );
475
        }
476
        addrcache_print( pilotFile->addressCache, stream );
477
        fprintf( stream, " have pc3: %s\n", pilotFile->havePC3 ? "yes" : "no" );
478
        fprintf( stream, " pc3 time: %lu\n", pilotFile->pc3ModifyTime );
479
}
480
481
/* Shamelessly copied from JPilot (libplugin.c) */
482
static unsigned int bytes_to_bin(unsigned char *bytes, unsigned int num_bytes) {
483
unsigned int i, n;
484
        n=0;
485
        for (i=0;i<num_bytes;i++) {
486
                n = n*256+bytes[i];
487
        }
488
        return n;
489
}
490
491
/* Shamelessly copied from JPilot (utils.c) */
492
/* These next 2 functions were copied from pi-file.c in the pilot-link app */
493
/* Exact value of "Jan 1, 1970 0:00:00 GMT" - "Jan 1, 1904 0:00:00 GMT" */
494
#define PILOT_TIME_DELTA (unsigned)(2082844800)
495
496
time_t pilot_time_to_unix_time ( unsigned long raw_time ) {
497
   return (time_t)(raw_time - PILOT_TIME_DELTA);
498
}
499
500
/* Shamelessly copied from JPilot (libplugin.c) */
501
static int raw_header_to_header(RawDBHeader *rdbh, DBHeader *dbh) {
502
        unsigned long temp;
503
504
        strncpy(dbh->db_name, rdbh->db_name, 31);
505
        dbh->db_name[31] = '\0';
506
        dbh->flags = bytes_to_bin(rdbh->flags, 2);
507
        dbh->version = bytes_to_bin(rdbh->version, 2);
508
        temp = bytes_to_bin(rdbh->creation_time, 4);
509
        dbh->creation_time = pilot_time_to_unix_time(temp);
510
        temp = bytes_to_bin(rdbh->modification_time, 4);
511
        dbh->modification_time = pilot_time_to_unix_time(temp);
512
        temp = bytes_to_bin(rdbh->backup_time, 4);
513
        dbh->backup_time = pilot_time_to_unix_time(temp);
514
        dbh->modification_number = bytes_to_bin(rdbh->modification_number, 4);
515
        dbh->app_info_offset = bytes_to_bin(rdbh->app_info_offset, 4);
516
        dbh->sort_info_offset = bytes_to_bin(rdbh->sort_info_offset, 4);
517
        strncpy(dbh->type, rdbh->type, 4);
518
        dbh->type[4] = '\0';
519
        strncpy(dbh->creator_id, rdbh->creator_id, 4);
520
        dbh->creator_id[4] = '\0';
521
        strncpy(dbh->unique_id_seed, rdbh->unique_id_seed, 4);
522
        dbh->unique_id_seed[4] = '\0';
523
        dbh->next_record_list_id = bytes_to_bin(rdbh->next_record_list_id, 4);
524
        dbh->number_of_records = bytes_to_bin(rdbh->number_of_records, 2);
525
        return 0;
526
}
527
528
/* Shamelessly copied from JPilot (libplugin.c) */
529
/* returns 1 if found */
530
/*         0 if eof */
531
static int find_next_offset( mem_rec_header *mem_rh, long fpos,
532
        unsigned int *next_offset, unsigned char *attrib, unsigned int *unique_id )
533
{
534
        mem_rec_header *temp_mem_rh;
535
        unsigned char found = 0;
536
        unsigned long found_at;
537
538
        found_at=0xFFFFFF;
539
        for (temp_mem_rh=mem_rh; temp_mem_rh; temp_mem_rh = temp_mem_rh->next) {
540
                if ((temp_mem_rh->offset > fpos) && (temp_mem_rh->offset < found_at)) {
541
                        found_at = temp_mem_rh->offset;
542
                        /* *attrib = temp_mem_rh->attrib; */
543
                        /* *unique_id = temp_mem_rh->unique_id; */
544
                }
545
                if ((temp_mem_rh->offset == fpos)) {
546
                        found = 1;
547
                        *attrib = temp_mem_rh->attrib;
548
                        *unique_id = temp_mem_rh->unique_id;
549
                }
550
        }
551
        *next_offset = found_at;
552
        return found;
553
}
554
555
/* Shamelessly copied from JPilot (libplugin.c) */
556
static void free_mem_rec_header(mem_rec_header **mem_rh) {
557
        mem_rec_header *h, *next_h;
558
        for (h=*mem_rh; h; h=next_h) {
559
                next_h=h->next;
560
                free(h);
561
        }
562
        *mem_rh = NULL;
563
}
564
565
#if 0
566
/* Shamelessly copied from JPilot (libplugin.c) */
567
static int jpilot_free_db_list( GList **br_list ) {
568
        GList *temp_list, *first;
569
        buf_rec *br;
570
571
        /* Go to first entry in the list */
572
        first=NULL;
573
        for( temp_list = *br_list; temp_list; temp_list = temp_list->prev ) {
574
                first = temp_list;
575
        }
576
        for (temp_list = first; temp_list; temp_list = temp_list->next) {
577
                if (temp_list->data) {
578
                        br=temp_list->data;
579
                        if (br->buf) {
580
                                free(br->buf);
581
                                temp_list->data=NULL;
582
                        }
583
                        free(br);
584
                }
585
        }
586
        g_list_free(*br_list);
587
        *br_list=NULL;
588
        return 0;
589
}
590
#endif
591
592
/* Shamelessly copied from JPilot (libplugin.c) */
593
/* Read file size */
594
static int jpilot_get_info_size( FILE *in, int *size ) {
595
        RawDBHeader rdbh;
596
        DBHeader dbh;
597
        unsigned int offset;
598
        record_header rh;
599
600
        fseek(in, 0, SEEK_SET);
601
        fread(&rdbh, sizeof(RawDBHeader), 1, in);
602
        if (feof(in)) {
603
                return MGU_EOF;
604
        }
605
606
        raw_header_to_header(&rdbh, &dbh);
607
        if (dbh.app_info_offset==0) {
608
                *size=0;
609
                return MGU_SUCCESS;
610
        }
611
        if (dbh.sort_info_offset!=0) {
612
                *size = dbh.sort_info_offset - dbh.app_info_offset;
613
                return MGU_SUCCESS;
614
        }
615
        if (dbh.number_of_records==0) {
616
                fseek(in, 0, SEEK_END);
617
                *size=ftell(in) - dbh.app_info_offset;
618
                return MGU_SUCCESS;
619
        }
620
621
        fread(&rh, sizeof(record_header), 1, in);
622
        offset = ((rh.Offset[0]*256+rh.Offset[1])*256+rh.Offset[2])*256+rh.Offset[3];
623
        *size=offset - dbh.app_info_offset;
624
625
        return MGU_SUCCESS;
626
}
627
628
/*
629
 * Read address file into address list. Based on JPilot's
630
 * libplugin.c (jp_get_app_info)
631
 */
632
static gint jpilot_get_file_info( JPilotFile *pilotFile, unsigned char **buf, int *buf_size ) {
633
        FILE *in;
634
         int num;
635
        unsigned int rec_size;
636
        RawDBHeader rdbh;
637
        DBHeader dbh;
638
639
        if( ( !buf_size ) || ( ! buf ) ) {
640
                return MGU_BAD_ARGS;
641
        }
642
643
        *buf = NULL;
644
        *buf_size=0;
645
646
        if( pilotFile->path ) {
647
                in = g_fopen( pilotFile->path, "rb" );
648
                if( !in ) {
649
                        return MGU_OPEN_FILE;
650
                }
651
        }
652
        else {
653
                return MGU_NO_FILE;
654
        }
655
656
        num = fread( &rdbh, sizeof( RawDBHeader ), 1, in );
657
        if( num != 1 ) {
658
                  if( ferror(in) ) {
659
                        fclose(in);
660
                        return MGU_ERROR_READ;
661
                }
662
        }
663
        if (feof(in)) {
664
                fclose(in);
665
                return MGU_EOF;
666
        }
667
668
        /* Convert header into something recognizable */
669
        raw_header_to_header(&rdbh, &dbh);
670
671
        num = jpilot_get_info_size(in, &rec_size);
672
        if (num) {
673
                fclose(in);
674
                return MGU_ERROR_READ;
675
        }
676
677
        fseek(in, dbh.app_info_offset, SEEK_SET);
678
        *buf = ( char * ) malloc(rec_size);
679
        if (!(*buf)) {
680
                fclose(in);
681
                return MGU_OO_MEMORY;
682
        }
683
        num = fread(*buf, rec_size, 1, in);
684
        if (num != 1) {
685
                if (ferror(in)) {
686
                        fclose(in);
687
                        free(*buf);
688
                        return MGU_ERROR_READ;
689
                }
690
        }
691
        fclose(in);
692
693
        *buf_size = rec_size;
694
695
        return MGU_SUCCESS;
696
}
697
698
/* Shamelessly copied from JPilot (libplugin.c) */
699
static int unpack_header(PC3RecordHeader *header, unsigned char *packed_header) {
700
        unsigned char *p;
701
        unsigned long l;
702
703
        p = packed_header;
704
705
        memcpy(&l, p, sizeof(l));
706
        header->header_len=ntohl(l);
707
        p+=sizeof(l);
708
709
        memcpy(&l, p, sizeof(l));
710
        header->header_version=ntohl(l);
711
        p+=sizeof(l);
712
713
        memcpy(&l, p, sizeof(l));
714
        header->rec_len=ntohl(l);
715
        p+=sizeof(l);
716
717
        memcpy(&l, p, sizeof(l));
718
        header->unique_id=ntohl(l);
719
        p+=sizeof(l);
720
721
        memcpy(&l, p, sizeof(l));
722
        header->rt=ntohl(l);
723
        p+=sizeof(l);
724
725
        memcpy(&(header->attrib), p, sizeof(unsigned char));
726
        p+=sizeof(unsigned char);
727
728
        return 0;
729
}
730
731
/* Shamelessly copied from JPilot (libplugin.c) */
732
static int read_header(FILE *pc_in, PC3RecordHeader *header) {
733
        unsigned long l, len;
734
        unsigned char packed_header[256];
735
        int num;
736
737
        num = fread(&l, sizeof(l), 1, pc_in);
738
        if (feof(pc_in)) {
739
                return -1;
740
        }
741
        if (num!=1) {
742
                return num;
743
        }
744
        memcpy(packed_header, &l, sizeof(l));
745
        len=ntohl(l);
746
        if (len > 255) {
747
                return -1;
748
        }
749
        num = fread(packed_header+sizeof(l), len-sizeof(l), 1, pc_in);
750
        if (feof(pc_in)) {
751
                return -1;
752
        }
753
        if (num!=1) {
754
                return num;
755
        }
756
        unpack_header(header, packed_header);
757
        return 1;
758
}
759
760
/* Read next record from PC3 file. Based on JPilot's
761
 * pc_read_next_rec (libplugin.c) */
762
static gint jpilot_read_next_pc( FILE *in, buf_rec *br ) {
763
        PC3RecordHeader header;
764
        int rec_len, num;
765
        char *record;
766
767
        if(feof(in)) {
768
                return MGU_EOF;
769
        }
770
        num = read_header(in, &header);
771
        if (num < 1) {
772
                if (ferror(in)) {
773
                        return MGU_ERROR_READ;
774
                }
775
                if (feof(in)) {
776
                        return MGU_EOF;
777
                }
778
        }
779
        rec_len = header.rec_len;
780
        record = malloc(rec_len);
781
        if (!record) {
782
                return MGU_OO_MEMORY;
783
        }
784
        num = fread(record, rec_len, 1, in);
785
        if (num != 1) {
786
                if (ferror(in)) {
787
                        free(record);
788
                        return MGU_ERROR_READ;
789
                }
790
        }
791
        br->rt = header.rt;
792
        br->unique_id = header.unique_id;
793
        br->attrib = header.attrib;
794
        br->buf = record;
795
        br->size = rec_len;
796
797
        return MGU_SUCCESS;
798
}
799
800
/*
801
 * Read address file into a linked list. Based on JPilot's
802
 * jp_read_DB_files (from libplugin.c)
803
 */
804
static gint jpilot_read_db_files( JPilotFile *pilotFile, GList **records ) {
805
        FILE *in, *pc_in;
806
        char *buf;
807
        GList *temp_list;
808
        int num_records, recs_returned, i, num, r;
809
        unsigned int offset, prev_offset, next_offset, rec_size;
810
        int out_of_order;
811
        long fpos;  /*file position indicator */
812
        unsigned char attrib;
813
        unsigned int unique_id;
814
        mem_rec_header *mem_rh, *temp_mem_rh, *last_mem_rh;
815
        record_header rh;
816
        RawDBHeader rdbh;
817
        DBHeader dbh;
818
        buf_rec *temp_br;
819
        gchar *pcFile;
820
821
        mem_rh = last_mem_rh = NULL;
822
        *records = NULL;
823
        recs_returned = 0;
824
825
        if( pilotFile->path == NULL ) {
826
                return MGU_BAD_ARGS;
827
        }
828
829
        in = g_fopen( pilotFile->path, "rb" );
830
        if (!in) {
831
                return MGU_OPEN_FILE;
832
        }
833
834
        /* Read the database header */
835
        num = fread(&rdbh, sizeof(RawDBHeader), 1, in);
836
        if (num != 1) {
837
                if (ferror(in)) {
838
                        fclose(in);
839
                        return MGU_ERROR_READ;
840
                }
841
                if (feof(in)) {
842
                        return MGU_EOF;
843
                }
844
        }
845
        raw_header_to_header(&rdbh, &dbh);
846
847
        /* Read each record entry header */
848
        num_records = dbh.number_of_records;
849
        out_of_order = 0;
850
        prev_offset = 0;
851
852
        for (i = 1; i < num_records + 1; i++) {
853
                num = fread(&rh, sizeof(record_header), 1, in);
854
                if (num != 1) {
855
                        if (ferror(in)) {
856
                                break;
857
                        }
858
                        if (feof(in)) {
859
                                return MGU_EOF;
860
                        }
861
                }
862
863
                offset = ((rh.Offset[0]*256+rh.Offset[1])*256+rh.Offset[2])*256+rh.Offset[3];
864
                if (offset < prev_offset) {
865
                        out_of_order = 1;
866
                }
867
                prev_offset = offset;
868
                temp_mem_rh = (mem_rec_header *)malloc(sizeof(mem_rec_header));
869
                if (!temp_mem_rh) {
870
                        break;
871
                }
872
                temp_mem_rh->next = NULL;
873
                temp_mem_rh->rec_num = i;
874
                temp_mem_rh->offset = offset;
875
                temp_mem_rh->attrib = rh.attrib;
876
                temp_mem_rh->unique_id = (rh.unique_ID[0]*256+rh.unique_ID[1])*256+rh.unique_ID[2];
877
                if (mem_rh == NULL) {
878
                        mem_rh = temp_mem_rh;
879
                        last_mem_rh = temp_mem_rh;
880
                } else {
881
                        last_mem_rh->next = temp_mem_rh;
882
                        last_mem_rh = temp_mem_rh;
883
                }
884
        }
885
886
        temp_mem_rh = mem_rh;
887
888
        if (num_records) {
889
                if (out_of_order) {
890
                        find_next_offset(mem_rh, 0, &next_offset, &attrib, &unique_id);
891
                } else {
892
                        if (mem_rh) {
893
                                next_offset = mem_rh->offset;
894
                                attrib = mem_rh->attrib;
895
                                unique_id = mem_rh->unique_id;
896
                        }
897
                }
898
                fseek(in, next_offset, SEEK_SET);
899
                while(!feof(in)) {
900
                        fpos = ftell(in);
901
                        if (out_of_order) {
902
                                find_next_offset(mem_rh, fpos, &next_offset, &attrib, &unique_id);
903
                        } else {
904
                                next_offset = 0xFFFFFF;
905
                                if (temp_mem_rh) {
906
                                        attrib = temp_mem_rh->attrib;
907
                                        unique_id = temp_mem_rh->unique_id;
908
                                        if (temp_mem_rh->next) {
909
                                                temp_mem_rh = temp_mem_rh->next;
910
                                                next_offset = temp_mem_rh->offset;
911
                                        }
912
                                }
913
                        }
914
                        rec_size = next_offset - fpos;
915
                        buf = malloc(rec_size);
916
                        if (!buf) break;
917
                        num = fread(buf, rec_size, 1, in);
918
                        if ((num != 1)) {
919
                                if (ferror(in)) {
920
                                        free(buf);
921
                                        break;
922
                                }
923
                        }
924
925
                        temp_br = malloc(sizeof(buf_rec));
926
                        if (!temp_br) {
927
                                break;
928
                        }
929
                        temp_br->rt = PALM_REC;
930
                        temp_br->unique_id = unique_id;
931
                        temp_br->attrib = attrib;
932
                        temp_br->buf = buf;
933
                        temp_br->size = rec_size;
934
935
                        *records = g_list_append(*records, temp_br);
936
937
                        recs_returned++;
938
                }
939
        }
940
        fclose(in);
941
        free_mem_rec_header(&mem_rh);
942
943
        /* Read the PC3 file, if present */
944
        pcFile = jpilot_get_pc3_file( pilotFile );
945
        if( pcFile == NULL ) return MGU_SUCCESS;
946
        pc_in = g_fopen( pcFile, "rb");
947
        g_free( pcFile );
948
949
        if( pc_in == NULL ) {
950
                return MGU_SUCCESS;
951
        }
952
953
        while( ! feof( pc_in ) ) {
954
                temp_br = malloc(sizeof(buf_rec));
955
                if (!temp_br) {
956
                        break;
957
                }
958
                r = jpilot_read_next_pc( pc_in, temp_br );
959
                if ( r != MGU_SUCCESS ) {
960
                        free(temp_br);
961
                        break;
962
                }
963
                if ((temp_br->rt!=DELETED_PC_REC)
964
                        &&(temp_br->rt!=DELETED_PALM_REC)
965
                        &&(temp_br->rt!=MODIFIED_PALM_REC)
966
                        &&(temp_br->rt!=DELETED_DELETED_PALM_REC)) {
967
                                *records = g_list_append(*records, temp_br);
968
                                recs_returned++;
969
                }
970
                if ((temp_br->rt==DELETED_PALM_REC) || (temp_br->rt==MODIFIED_PALM_REC)) {
971
                        temp_list=*records;
972
                        if (*records) {
973
                                while(temp_list->next) {
974
                                        temp_list=temp_list->next;
975
                                }
976
                        }
977
                        for (; temp_list; temp_list=temp_list->prev) {
978
                                if (((buf_rec *)temp_list->data)->unique_id == temp_br->unique_id) {
979
                                        ((buf_rec *)temp_list->data)->rt = temp_br->rt;
980
                                }
981
                        }
982
                }
983
        }
984
        fclose(pc_in);
985
986
        return MGU_SUCCESS;
987
}
988
989
#define FULLNAME_BUFSIZE        256
990
#define EMAIL_BUFSIZE                256
991
/*
992
 * Unpack address, building new data inside cache.
993
 */
994
static void jpilot_load_address( JPilotFile *pilotFile, buf_rec *buf, ItemFolder *folderInd[] ) {
995
        struct Address addr;
996
        gchar **addrEnt;
997
        gint num, k;
998
        gint cat_id = 0;
999
        guint unique_id;
1000
        guchar attrib;
1001
        gchar fullName[ FULLNAME_BUFSIZE ];
1002
        gchar bufEMail[ EMAIL_BUFSIZE ];
1003
        ItemPerson *person;
1004
        ItemEMail *email;
1005
        gint *indPhoneLbl;
1006
        gchar *labelEntry;
1007
        GList *node;
1008
        gchar* extID;
1009
        struct AddressAppInfo *ai;
1010
        gchar **firstName = NULL;
1011
        gchar **lastName = NULL;
1012
1013
        /* Retrieve address */
1014
        num = unpack_Address( & addr, buf->buf, buf->size );
1015
        if( num > 0 ) {
1016
                addrEnt = addr.entry;
1017
                attrib = buf->attrib;
1018
                unique_id = buf->unique_id;
1019
                cat_id = attrib & 0x0F;
1020
1021
                *fullName = *bufEMail = '\0';
1022
1023
                if( addrEnt[ IND_LABEL_FIRSTNAME ] ) {
1024
                        firstName = g_strsplit( addrEnt[ IND_LABEL_FIRSTNAME ], "\01", 2 );
1025
                }
1026
                if( addrEnt[ IND_LABEL_LASTNAME ] ) {
1027
                        lastName = g_strsplit( addrEnt[ IND_LABEL_LASTNAME ], "\01", 2 );
1028
                }
1029
1030
                if( name_order == FAMILY_LAST ) {
1031
                        g_snprintf( fullName, FULLNAME_BUFSIZE, "%s %s",
1032
                                    firstName ? firstName[0] : "",
1033
                                    lastName ? lastName[0] : "" );
1034
                }
1035
                else {
1036
                        g_snprintf( fullName, FULLNAME_BUFSIZE, "%s %s",
1037
                                    lastName ? lastName[0] : "",
1038
                                    firstName ? firstName[0] : "" );
1039
                }
1040
1041
                if( firstName ) {
1042
                        g_strfreev( firstName );
1043
                }
1044
                if( lastName ) {
1045
                        g_strfreev( lastName );
1046
                }
1047
1048
                g_strstrip( fullName );
1049
1050
                if( convert_charcode ) {
1051
                        gchar *nameConv;
1052
                        nameConv = conv_codeset_strdup( fullName, CS_SHIFT_JIS, CS_INTERNAL );
1053
                        strncpy2( fullName, nameConv, FULLNAME_BUFSIZE );
1054
                        g_free( nameConv );
1055
                }
1056
1057
                person = addritem_create_item_person();
1058
                addritem_person_set_common_name( person, fullName );
1059
                addritem_person_set_first_name( person, addrEnt[ IND_LABEL_FIRSTNAME ] );
1060
                addritem_person_set_last_name( person, addrEnt[ IND_LABEL_LASTNAME ] );
1061
                addrcache_id_person( pilotFile->addressCache, person );
1062
1063
                extID = g_strdup_printf( "%d", unique_id );
1064
                addritem_person_set_external_id( person, extID );
1065
                g_free( extID );
1066
                extID = NULL;
1067
1068
                /* Pointer to address metadata. */
1069
                ai = & pilotFile->addrInfo;
1070
1071
                /* Add entry for each email address listed under phone labels. */
1072
                indPhoneLbl = addr.phoneLabel;
1073
                for( k = 0; k < JPILOT_NUM_ADDR_PHONE; k++ ) {
1074
                        gint ind;
1075
1076
                        ind = indPhoneLbl[k];
1077
                        /*
1078
                        * fprintf( stdout, "%d : %d : %20s : %s\n", k, ind,
1079
                        * ai->phoneLabels[ind], addrEnt[3+k] );
1080
                        */
1081
                        if( indPhoneLbl[k] == IND_PHONE_EMAIL ) {
1082
                                labelEntry = addrEnt[ OFFSET_PHONE_LABEL + k ];
1083
                                if( labelEntry ) {
1084
                                        strcpy( bufEMail, labelEntry );
1085
                                        g_strchug( bufEMail );
1086
                                        g_strchomp( bufEMail );
1087
1088
                                        email = addritem_create_item_email();
1089
                                        addritem_email_set_address( email, bufEMail );
1090
                                        addrcache_id_email( pilotFile->addressCache, email );
1091
                                        addrcache_person_add_email
1092
                                                ( pilotFile->addressCache, person, email );
1093
                                }
1094
                        }
1095
                }
1096
1097
                /* Add entry for each custom label */
1098
                node = pilotFile->labelInd;
1099
                while( node ) {
1100
                        gint ind;
1101
1102
                        ind = GPOINTER_TO_INT( node->data );
1103
                        if( ind > -1 ) {
1104
                                /*
1105
                                * fprintf( stdout, "%d : %20s : %s\n", ind, ai->labels[ind],
1106
                                * addrEnt[ind] );
1107
                                */
1108
                                labelEntry = addrEnt[ind];
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
1117
                                        if( convert_charcode ) {
1118
                                                gchar *convertBuff;
1119
                                                convertBuff = conv_codeset_strdup( ai->labels[ind], CS_SHIFT_JIS, CS_INTERNAL );
1120
                                                addritem_email_set_remarks( email, convertBuff );
1121
                                                g_free( convertBuff );
1122
                                        }
1123
                                        else {
1124
                                                addritem_email_set_remarks( email, ai->labels[ind] );
1125
                                        }
1126
1127
                                        addrcache_id_email( pilotFile->addressCache, email );
1128
                                        addrcache_person_add_email
1129
                                                ( pilotFile->addressCache, person, email );
1130
                                }
1131
                        }
1132
1133
                        node = g_list_next( node );
1134
                }
1135
1136
                if( person->listEMail ) {
1137
                        if( cat_id > -1 && cat_id < JPILOT_NUM_CATEG ) {
1138
                                /* Add to specified category */
1139
                                addrcache_folder_add_person
1140
                                        ( pilotFile->addressCache, folderInd[cat_id], person );
1141
                        }
1142
                        else {
1143
                                /* Add to root folder */
1144
                                addrcache_add_person( pilotFile->addressCache, person );
1145
                        }
1146
                }
1147
                else {
1148
                        addritem_free_item_person( person );
1149
                        person = NULL;
1150
                }
1151
        }
1152
}
1153
1154
/*
1155
 * Free up address list.
1156
 */
1157
static void jpilot_free_addrlist( GList *records ) {
1158
        GList *node;
1159
        buf_rec *br;
1160
1161
        node = records;
1162
        while( node ) {
1163
                br = node->data;
1164
                free( br );
1165
                node->data = NULL;
1166
                node = g_list_next( node );
1167
        }
1168
1169
        /* Free up list */
1170
        g_list_free( records );
1171
}
1172
1173
/*
1174
 * Read address file into address cache.
1175
 */
1176
static gint jpilot_read_file( JPilotFile *pilotFile ) {
1177
        gint retVal, i;
1178
        GList *records = NULL;
1179
        GList *node;
1180
        buf_rec *br;
1181
        ItemFolder *folderInd[ JPILOT_NUM_CATEG ];
1182
1183
        retVal = jpilot_read_db_files( pilotFile, &records );
1184
        if( retVal != MGU_SUCCESS ) {
1185
                jpilot_free_addrlist( records );
1186
                return retVal;
1187
        }
1188
1189
        /* Build array of pointers to categories */
1190
        i = 0;
1191
        node = addrcache_get_list_folder( pilotFile->addressCache );
1192
        while( node ) {
1193
                if( i < JPILOT_NUM_CATEG ) {
1194
                        folderInd[i] = node->data;
1195
                }
1196
                node = g_list_next( node );
1197
                i++;
1198
        }
1199
1200
        /* Load all addresses, free up old stuff as we go */
1201
        node = records;
1202
        while( node ) {
1203
                br = node->data;
1204
                if( ( br->rt != DELETED_PC_REC ) &&
1205
                    ( br->rt != DELETED_PALM_REC ) &&
1206
                    ( br->rt != MODIFIED_PALM_REC ) &&
1207
                    ( br->rt != DELETED_DELETED_PALM_REC ) ) {
1208
                        jpilot_load_address( pilotFile, br, folderInd );
1209
                }
1210
                free( br );
1211
                node->data = NULL;
1212
                node = g_list_next( node );
1213
        }
1214
1215
        /* Free up list */
1216
        g_list_free( records );
1217
1218
        return retVal;
1219
}
1220
1221
1222
/*
1223
* Read metadata from file.
1224
*/
1225
static gint jpilot_read_metadata( JPilotFile *pilotFile ) {
1226
        gint retVal;
1227
        unsigned int rec_size;
1228
        unsigned char *buf;
1229
        int num;
1230
1231
        g_return_val_if_fail( pilotFile != NULL, -1 );
1232
1233
        pilotFile->readMetadata = FALSE;
1234
        addrcache_clear( pilotFile->addressCache );
1235
1236
        /* Read file info */
1237
        retVal = jpilot_get_file_info( pilotFile, &buf, &rec_size);
1238
        if( retVal != MGU_SUCCESS ) {
1239
                pilotFile->retVal = retVal;
1240
                return pilotFile->retVal;
1241
        }
1242
1243
        num = unpack_AddressAppInfo( &pilotFile->addrInfo, buf, rec_size );
1244
        if( buf ) {
1245
                free(buf);
1246
        }
1247
        if( num <= 0 ) {
1248
                pilotFile->retVal = MGU_ERROR_READ;
1249
                return pilotFile->retVal;
1250
        }
1251
1252
        pilotFile->readMetadata = TRUE;
1253
        pilotFile->retVal = MGU_SUCCESS;
1254
        return pilotFile->retVal;
1255
}
1256
1257
/*
1258
* Setup labels and indexes from metadata.
1259
* Return: TRUE is setup successfully.
1260
*/
1261
static gboolean jpilot_setup_labels( JPilotFile *pilotFile ) {
1262
        gboolean retVal = FALSE;
1263
        struct AddressAppInfo *ai;
1264
        GList *node;
1265
1266
        g_return_val_if_fail( pilotFile != NULL, -1 );
1267
1268
        /* Release indexes */
1269
        node = pilotFile->labelInd;
1270
        while( node ) {
1271
                node->data = NULL;
1272
                node = g_list_next( node );
1273
        }
1274
        pilotFile->labelInd = NULL;
1275
1276
        if( pilotFile->readMetadata ) {
1277
                ai = & pilotFile->addrInfo;
1278
                node = pilotFile->customLabels;
1279
                while( node ) {
1280
                        gchar *lbl = node->data;
1281
                        gint ind = -1;
1282
                        gint i;
1283
                        for( i = 0; i < JPILOT_NUM_LABELS; i++ ) {
1284
                                gchar *labelName = ai->labels[i];
1285
                                gchar convertBuff[ JPILOT_LEN_LABEL ];
1286
1287
                                if( convert_charcode ) {
1288
                                        labelName = conv_codeset_strdup( labelName, CS_SHIFT_JIS, CS_INTERNAL );
1289
                                        strncpy2( convertBuff, labelName, JPILOT_LEN_LABEL );
1290
                                        g_free( labelName );
1291
                                        labelName = convertBuff;
1292
                                }
1293
1294
                                if( g_ascii_strcasecmp( labelName, lbl ) == 0 ) {
1295
                                        ind = i;
1296
                                        break;
1297
                                }
1298
                        }
1299
                        pilotFile->labelInd = g_list_append( pilotFile->labelInd, GINT_TO_POINTER(ind) );
1300
                        node = g_list_next( node );
1301
                }
1302
                retVal = TRUE;
1303
        }
1304
        return retVal;
1305
}
1306
1307
/*
1308
* Load list with character strings of label names.
1309
*/
1310
GList *jpilot_load_label( JPilotFile *pilotFile, GList *labelList ) {
1311
        int i;
1312
1313
        g_return_val_if_fail( pilotFile != NULL, NULL );
1314
1315
        if( pilotFile->readMetadata ) {
1316
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1317
                for( i = 0; i < JPILOT_NUM_LABELS; i++ ) {
1318
                        gchar *labelName = ai->labels[i];
1319
1320
                        if( labelName ) {
1321
                                if( convert_charcode ) {
1322
                                        labelName = conv_codeset_strdup( labelName, CS_SHIFT_JIS, CS_INTERNAL );
1323
                                }
1324
                                else {
1325
                                        labelName = g_strdup( labelName );
1326
                                }
1327
                                labelList = g_list_append( labelList, labelName );
1328
                        }
1329
                        else {
1330
                                labelList = g_list_append( labelList, g_strdup( "" ) );
1331
                        }
1332
                }
1333
        }
1334
        return labelList;
1335
}
1336
1337
/*
1338
* Return category name for specified category ID.
1339
* Enter:  Category ID.
1340
* Return: Name, or empty string if not invalid ID. Name should be g_free() when done.
1341
*/
1342
gchar *jpilot_get_category_name( JPilotFile *pilotFile, gint catID ) {
1343
        gchar *catName = NULL;
1344
1345
        g_return_val_if_fail( pilotFile != NULL, NULL );
1346
1347
        if( pilotFile->readMetadata ) {
1348
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1349
                struct CategoryAppInfo *cat = &        ai->category;
1350
                if( catID < 0 || catID > JPILOT_NUM_CATEG ) {
1351
                }
1352
                else {
1353
                        catName = g_strdup( cat->name[catID] );
1354
                }
1355
        }
1356
        if( ! catName ) catName = g_strdup( "" );
1357
        return catName;
1358
}
1359
1360
/*
1361
* Load list with character strings of phone label names.
1362
*/
1363
GList *jpilot_load_phone_label( JPilotFile *pilotFile, GList *labelList ) {
1364
        gint i;
1365
1366
        g_return_val_if_fail( pilotFile != NULL, NULL );
1367
1368
        if( pilotFile->readMetadata ) {
1369
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1370
                for( i = 0; i < JPILOT_NUM_PHONELABELS; i++ ) {
1371
                        gchar        *labelName = ai->phoneLabels[i];
1372
                        if( labelName ) {
1373
                                labelList = g_list_append( labelList, g_strdup( labelName ) );
1374
                        }
1375
                        else {
1376
                                labelList = g_list_append( labelList, g_strdup( "" ) );
1377
                        }
1378
                }
1379
        }
1380
        return labelList;
1381
}
1382
1383
/*
1384
* Load list with character strings of label names. Only none blank names
1385
* are loaded.
1386
*/
1387
GList *jpilot_load_custom_label( JPilotFile *pilotFile, GList *labelList ) {
1388
        gint i;
1389
1390
        g_return_val_if_fail( pilotFile != NULL, NULL );
1391
1392
        if( pilotFile->readMetadata ) {
1393
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1394
                for( i = 0; i < NUM_CUSTOM_LABEL; i++ ) {
1395
                        gchar *labelName = ai->labels[i+IND_CUSTOM_LABEL];
1396
                        if( labelName ) {
1397
                                g_strchomp( labelName );
1398
                                g_strchug( labelName );
1399
                                if( *labelName != '\0' ) {
1400
                                        if( convert_charcode ) {
1401
                                                labelName = conv_codeset_strdup( labelName, CS_SHIFT_JIS, CS_INTERNAL );
1402
                                        }
1403
                                        else {
1404
                                                labelName = g_strdup( labelName );
1405
                                        }
1406
                                        labelList = g_list_append( labelList, labelName );
1407
                                }
1408
                        }
1409
                }
1410
        }
1411
        return labelList;
1412
}
1413
1414
/*
1415
* Load list with character strings of category names.
1416
*/
1417
GList *jpilot_get_category_list( JPilotFile *pilotFile ) {
1418
        GList *catList = NULL;
1419
        gint i;
1420
1421
        g_return_val_if_fail( pilotFile != NULL, NULL );
1422
1423
        if( pilotFile->readMetadata ) {
1424
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1425
                struct CategoryAppInfo *cat = &        ai->category;
1426
                for( i = 0; i < JPILOT_NUM_CATEG; i++ ) {
1427
                        gchar *catName = cat->name[i];
1428
                        if( catName ) {
1429
                                catList = g_list_append( catList, g_strdup( catName ) );
1430
                        }
1431
                        else {
1432
                                catList = g_list_append( catList, g_strdup( "" ) );
1433
                        }
1434
                }
1435
        }
1436
        return catList;
1437
}
1438
1439
/*
1440
* Build folder for each category.
1441
*/
1442
static void jpilot_build_category_list( JPilotFile *pilotFile ) {
1443
        struct AddressAppInfo *ai = & pilotFile->addrInfo;
1444
        struct CategoryAppInfo *cat = &        ai->category;
1445
        gint i;
1446
1447
        for( i = 0; i < JPILOT_NUM_CATEG; i++ ) {
1448
                ItemFolder *folder = addritem_create_item_folder();
1449
1450
                if( convert_charcode ) {
1451
                        gchar *catName;
1452
                        catName = conv_codeset_strdup( cat->name[i], CS_SHIFT_JIS, CS_INTERNAL );
1453
                        addritem_folder_set_name( folder, catName );
1454
                        g_free( catName );
1455
                }
1456
                else {
1457
                        addritem_folder_set_name( folder, cat->name[i] );
1458
                }
1459
1460
                addrcache_id_folder( pilotFile->addressCache, folder );
1461
                addrcache_add_folder( pilotFile->addressCache, folder );
1462
        }
1463
}
1464
1465
/*
1466
* Remove empty folders (categories).
1467
*/
1468
static void jpilot_remove_empty( JPilotFile *pilotFile ) {
1469
        GList *listFolder;
1470
        GList *remList;
1471
        GList *node;
1472
        gint i = 0;
1473
1474
        listFolder = addrcache_get_list_folder( pilotFile->addressCache );
1475
        node = listFolder;
1476
        remList = NULL;
1477
        while( node ) {
1478
                ItemFolder *folder = node->data;
1479
                if( ADDRITEM_NAME(folder) == NULL || *ADDRITEM_NAME(folder) == '\0' ) {
1480
                        if( folder->listPerson ) {
1481
                                /* Give name to folder */
1482
                                gchar name[20];
1483
                                sprintf( name, "? %d", i );
1484
                                addritem_folder_set_name( folder, name );
1485
                        }
1486
                        else {
1487
                                /* Mark for removal */
1488
                                remList = g_list_append( remList, folder );
1489
                        }
1490
                }
1491
                node = g_list_next( node );
1492
                i++;
1493
        }
1494
        node = remList;
1495
        while( node ) {
1496
                ItemFolder *folder = node->data;
1497
                addrcache_remove_folder( pilotFile->addressCache, folder );
1498
                node = g_list_next( node );
1499
        }
1500
        g_list_free( remList );
1501
}
1502
1503
/*
1504
* ============================================================================================
1505
* Read file into list. Main entry point
1506
* Return: TRUE if file read successfully.
1507
* ============================================================================================
1508
*/
1509
gint jpilot_read_data( JPilotFile *pilotFile ) {
1510
        name_order = FAMILY_LAST;
1511
        convert_charcode = FALSE;
1512
1513
        if( conv_is_ja_locale() ) {
1514
                name_order = FAMILY_FIRST;
1515
                convert_charcode = TRUE;
1516
        }
1517
1518
        g_return_val_if_fail( pilotFile != NULL, -1 );
1519
1520
        pilotFile->retVal = MGU_SUCCESS;
1521
        pilotFile->accessFlag = FALSE;
1522
1523
        if( jpilot_check_files( pilotFile ) ) {
1524
                addrcache_clear( pilotFile->addressCache );
1525
                jpilot_read_metadata( pilotFile );
1526
                if( pilotFile->retVal == MGU_SUCCESS ) {
1527
                        jpilot_setup_labels( pilotFile );
1528
                        jpilot_build_category_list( pilotFile );
1529
                        pilotFile->retVal = jpilot_read_file( pilotFile );
1530
                        if( pilotFile->retVal == MGU_SUCCESS ) {
1531
                                jpilot_remove_empty( pilotFile );
1532
                                jpilot_mark_files( pilotFile );
1533
                                pilotFile->addressCache->modified = FALSE;
1534
                                pilotFile->addressCache->dataRead = TRUE;
1535
                        }
1536
                }
1537
        }
1538
        return pilotFile->retVal;
1539
}
1540
1541
/*
1542
* Return link list of persons.
1543
*/
1544
GList *jpilot_get_list_person( JPilotFile *pilotFile ) {
1545
        g_return_val_if_fail( pilotFile != NULL, NULL );
1546
        return addrcache_get_list_person( pilotFile->addressCache );
1547
}
1548
1549
/*
1550
* Return link list of folders. This is always NULL since there are
1551
* no folders in GnomeCard.
1552
* Return: NULL.
1553
*/
1554
GList *jpilot_get_list_folder( JPilotFile *pilotFile ) {
1555
        g_return_val_if_fail( pilotFile != NULL, NULL );
1556
        return addrcache_get_list_folder( pilotFile->addressCache );
1557
}
1558
1559
/*
1560
* Return link list of all persons. Note that the list contains references
1561
* to items. Do *NOT* attempt to use the addrbook_free_xxx() functions...
1562
* this will destroy the addressbook data!
1563
* Return: List of items, or NULL if none.
1564
*/
1565
GList *jpilot_get_all_persons( JPilotFile *pilotFile ) {
1566
        g_return_val_if_fail( pilotFile != NULL, NULL );
1567
        return addrcache_get_all_persons( pilotFile->addressCache );
1568
}
1569
1570
/*
1571
* Check label list for specified label.
1572
*/
1573
gint jpilot_check_label( struct AddressAppInfo *ai, gchar *lblCheck ) {
1574
        gint i;
1575
        gchar *lblName;
1576
1577
        if( lblCheck == NULL ) return -1;
1578
        if( strlen( lblCheck ) < 1 ) return -1;
1579
        for( i = 0; i < JPILOT_NUM_LABELS; i++ ) {
1580
                lblName = ai->labels[i];
1581
                if( lblName ) {
1582
                        if( strlen( lblName ) ) {
1583
                                if( g_ascii_strcasecmp( lblName, lblCheck ) == 0 ) return i;
1584
                        }
1585
                }
1586
        }
1587
        return -2;
1588
}
1589
1590
/*
1591
* Validate that all parameters specified.
1592
* Return: TRUE if data is good.
1593
*/
1594
gboolean jpilot_validate( const JPilotFile *pilotFile ) {
1595
        gboolean retVal;
1596
1597
        g_return_val_if_fail( pilotFile != NULL, FALSE );
1598
1599
        retVal = TRUE;
1600
        if( pilotFile->path ) {
1601
                if( strlen( pilotFile->path ) < 1 ) retVal = FALSE;
1602
        }
1603
        else {
1604
                retVal = FALSE;
1605
        }
1606
        if( pilotFile->name ) {
1607
                if( strlen( pilotFile->name ) < 1 ) retVal = FALSE;
1608
        }
1609
        else {
1610
                retVal = FALSE;
1611
        }
1612
        return retVal;
1613
}
1614
1615
#define WORK_BUFLEN 1024
1616
1617
/*
1618
* Attempt to find a valid JPilot file.
1619
* Return: Filename, or home directory if not found, or empty string if
1620
* no home. Filename should be g_free() when done.
1621
*/
1622
gchar *jpilot_find_pilotdb( void ) {
1623
        const gchar *homedir;
1624
        gchar str[ WORK_BUFLEN ];
1625
        gint len;
1626
        FILE *fp;
1627
1628
        homedir = get_home_dir();
1629
        if( ! homedir ) return g_strdup( "" );
1630
1631
        strcpy( str, homedir );
1632
        len = strlen( str );
1633
        if( len > 0 ) {
1634
                if( str[ len-1 ] != G_DIR_SEPARATOR ) {
1635
                        str[ len ] = G_DIR_SEPARATOR;
1636
                        str[ ++len ] = '\0';
1637
                }
1638
        }
1639
        strcat( str, JPILOT_DBHOME_DIR );
1640
        strcat( str, G_DIR_SEPARATOR_S );
1641
        strcat( str, JPILOT_DBHOME_FILE );
1642
1643
        /* Attempt to open */
1644
        if( ( fp = g_fopen( str, "rb" ) ) != NULL ) {
1645
                fclose( fp );
1646
        }
1647
        else {
1648
                /* Truncate filename */
1649
                str[ len ] = '\0';
1650
        }
1651
        return g_strdup( str );
1652
}
1653
1654
/*
1655
* Attempt to read file, testing for valid JPilot format.
1656
* Return: TRUE if file appears to be valid format.
1657
*/
1658
gint jpilot_test_read_file( const gchar *fileSpec ) {
1659
        JPilotFile *pilotFile;
1660
        gint retVal;
1661
1662
        if( fileSpec ) {
1663
                pilotFile = jpilot_create_path( fileSpec );
1664
                retVal = jpilot_read_metadata( pilotFile );
1665
                jpilot_free( pilotFile );
1666
                pilotFile = NULL;
1667
        }
1668
        else {
1669
                retVal = MGU_NO_FILE;
1670
        }
1671
        return retVal;
1672
}
1673
1674
/*
1675
* Check whether label is in custom labels.
1676
* Return: TRUE if found.
1677
*/
1678
gboolean jpilot_test_custom_label( JPilotFile *pilotFile, const gchar *labelName ) {
1679
        gboolean retVal;
1680
        GList *node;
1681
1682
        g_return_val_if_fail( pilotFile != NULL, FALSE );
1683
1684
        retVal = FALSE;
1685
        if( labelName ) {
1686
                node = pilotFile->customLabels;
1687
                while( node ) {
1688
                        if( g_ascii_strcasecmp( labelName, node->data ) == 0 ) {
1689
                                retVal = TRUE;
1690
                                break;
1691
                        }
1692
                        node = g_list_next( node );
1693
                }
1694
        }
1695
        return retVal;
1696
}
1697
1698
/*
1699
* Test whether pilot link library installed.
1700
* Return: TRUE if library available.
1701
*/
1702
#if 0
1703
gboolean jpilot_test_pilot_lib( void ) {
1704
        void *handle, *fun;
1705
1706
        handle = dlopen( PILOT_LINK_LIB_NAME, RTLD_LAZY );
1707
        if( ! handle ) {
1708
                return FALSE;
1709
        }
1710
1711
        /* Test for symbols we need */
1712
        fun = dlsym( handle, "unpack_Address" );
1713
        if( ! fun ) {
1714
                dlclose( handle );
1715
                return FALSE;
1716
        }
1717
1718
        fun = dlsym( handle, "unpack_AddressAppInfo" );
1719
        if( ! fun ) {
1720
                dlclose( handle );
1721
                return FALSE;
1722
        }
1723
        dlclose( handle );
1724
        return TRUE;
1725
}
1726
#endif /* 0 */
1727
1728
#endif        /* USE_JPILOT */
1729
1730
/*
1731
* End of Source.
1732
*/