Statistics
| Revision:

root / src / jpilot.c @ 1

History | View | Annotate | Download (41.3 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

    
57
#define JPILOT_DBHOME_DIR   ".jpilot"
58
#define JPILOT_DBHOME_FILE  "AddressDB.pdb"
59
#define PILOT_LINK_LIB_NAME "libpisock.so"
60

    
61
#define IND_LABEL_LASTNAME  0         /* Index of last name in address data */
62
#define IND_LABEL_FIRSTNAME 1         /* Index of first name in address data */
63
#define IND_PHONE_EMAIL     4         /* Index of E-Mail address in phone labels */
64
#define OFFSET_PHONE_LABEL  3         /* Offset to phone data in address data */
65
#define IND_CUSTOM_LABEL    14        /* Offset to custom label names */
66
#define NUM_CUSTOM_LABEL    4         /* Number of custom labels */
67

    
68
/* Shamelessly copied from JPilot (libplugin.h) */
69
typedef struct {
70
        unsigned char db_name[32];
71
        unsigned char flags[2];
72
        unsigned char version[2];
73
        unsigned char creation_time[4];
74
        unsigned char modification_time[4];
75
        unsigned char backup_time[4];
76
        unsigned char modification_number[4];
77
        unsigned char app_info_offset[4];
78
        unsigned char sort_info_offset[4];
79
        unsigned char type[4];/*Database ID */
80
        unsigned char creator_id[4];/*Application ID */
81
        unsigned char unique_id_seed[4];
82
        unsigned char next_record_list_id[4];
83
        unsigned char number_of_records[2];
84
} RawDBHeader;
85

    
86
/* Shamelessly copied from JPilot (libplugin.h) */
87
typedef struct {
88
        char db_name[32];
89
        unsigned int flags;
90
        unsigned int version;
91
        time_t creation_time;
92
        time_t modification_time;
93
        time_t backup_time;
94
        unsigned int modification_number;
95
        unsigned int app_info_offset;
96
        unsigned int sort_info_offset;
97
        char type[5];/*Database ID */
98
        char creator_id[5];/*Application ID */
99
        char unique_id_seed[5];
100
        unsigned int next_record_list_id;
101
        unsigned int number_of_records;
102
} DBHeader;
103

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

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

    
120
/* Shamelessly copied from JPilot (libplugin.h) */
121
#define SPENT_PC_RECORD_BIT        256
122

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

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

    
141
/* Shamelessly copied from JPilot (libplugin.h) */
142
typedef struct {
143
        unsigned long header_len;
144
        unsigned long header_version;
145
        unsigned long rec_len;
146
        unsigned long unique_id;
147
        unsigned long rt; /* Record Type */
148
        unsigned char attrib;
149
} PC3RecordHeader;
150

    
151
enum {
152
        FAMILY_LAST = 0,
153
        FAMILY_FIRST = 1
154
} name_order;
155

    
156
gboolean convert_charcode;
157

    
158
/*
159
* Create new pilot file object.
160
*/
161
JPilotFile *jpilot_create() {
162
        JPilotFile *pilotFile;
163
        pilotFile = g_new0( JPilotFile, 1 );
164
        pilotFile->name = NULL;
165
        pilotFile->file = NULL;
166
        pilotFile->path = NULL;
167
        pilotFile->addressCache = addrcache_create();
168
        pilotFile->readMetadata = FALSE;
169
        pilotFile->customLabels = NULL;
170
        pilotFile->labelInd = NULL;
171
        pilotFile->retVal = MGU_SUCCESS;
172
        pilotFile->accessFlag = FALSE;
173
        pilotFile->havePC3 = FALSE;
174
        pilotFile->pc3ModifyTime = 0;
175
        return pilotFile;
176
}
177

    
178
/*
179
* Create new pilot file object for specified file.
180
*/
181
JPilotFile *jpilot_create_path( const gchar *path ) {
182
        JPilotFile *pilotFile;
183
        pilotFile = jpilot_create();
184
        jpilot_set_file( pilotFile, path );
185
        return pilotFile;
186
}
187

    
188
/*
189
* Properties...
190
*/
191
void jpilot_set_name( JPilotFile* pilotFile, const gchar *value ) {
192
        g_return_if_fail( pilotFile != NULL );
193
        pilotFile->name = mgu_replace_string( pilotFile->name, value );
194
}
195
void jpilot_set_file( JPilotFile* pilotFile, const gchar *value ) {
196
        g_return_if_fail( pilotFile != NULL );
197
        addrcache_refresh( pilotFile->addressCache );
198
        pilotFile->readMetadata = FALSE;
199
        pilotFile->path = mgu_replace_string( pilotFile->path, value );
200
}
201
void jpilot_set_accessed( JPilotFile *pilotFile, const gboolean value ) {
202
        g_return_if_fail( pilotFile != NULL );
203
        pilotFile->accessFlag = value;
204
}
205

    
206
gint jpilot_get_status( JPilotFile *pilotFile ) {
207
        g_return_val_if_fail( pilotFile != NULL, -1 );
208
        return pilotFile->retVal;
209
}
210
ItemFolder *jpilot_get_root_folder( JPilotFile *pilotFile ) {
211
        g_return_val_if_fail( pilotFile != NULL, NULL );
212
        return addrcache_get_root_folder( pilotFile->addressCache );
213
}
214
gchar *jpilot_get_name( JPilotFile *pilotFile ) {
215
        g_return_val_if_fail( pilotFile != NULL, NULL );
216
        return pilotFile->name;
217
}
218

    
219
/*
220
* Test whether file was read.
221
* Return: TRUE if file was read.
222
*/
223
gboolean jpilot_get_read_flag( JPilotFile *pilotFile ) {
224
        g_return_val_if_fail( pilotFile != NULL, FALSE );
225
        return pilotFile->addressCache->dataRead;
226
}
227

    
228
/*
229
* Free up custom label list.
230
*/
231
void jpilot_clear_custom_labels( JPilotFile *pilotFile ) {
232
        GList *node;
233

    
234
        g_return_if_fail( pilotFile != NULL );
235

    
236
        /* Release custom labels */
237
        mgu_free_dlist( pilotFile->customLabels );
238
        pilotFile->customLabels = NULL;
239

    
240
        /* Release indexes */
241
        node = pilotFile->labelInd;
242
        while( node ) {
243
                node->data = NULL;
244
                node = g_list_next( node );
245
        }
246
        g_list_free( pilotFile->labelInd );
247
        pilotFile->labelInd = NULL;
248

    
249
        /* Force a fresh read */
250
        addrcache_refresh( pilotFile->addressCache );
251
}
252

    
253
/*
254
* Append a custom label, representing an E-Mail address field to the
255
* custom label list.
256
*/
257
void jpilot_add_custom_label( JPilotFile *pilotFile, const gchar *labelName ) {
258
        g_return_if_fail( pilotFile != NULL );
259

    
260
        if( labelName ) {
261
                gchar *labelCopy = g_strdup( labelName );
262
                g_strstrip( labelCopy );
263
                if( *labelCopy == '\0' ) {
264
                        g_free( labelCopy );
265
                }
266
                else {
267
                        pilotFile->customLabels = g_list_append( pilotFile->customLabels, labelCopy );
268
                        /* Force a fresh read */
269
                        addrcache_refresh( pilotFile->addressCache );
270
                }
271
        }
272
}
273

    
274
/*
275
* Get list of custom labels.
276
* Return: List of labels. Must use g_free() when done.
277
*/
278
GList *jpilot_get_custom_labels( JPilotFile *pilotFile ) {
279
        GList *retVal = NULL;
280
        GList *node;
281

    
282
        g_return_val_if_fail( pilotFile != NULL, NULL );
283

    
284
        node = pilotFile->customLabels;
285
        while( node ) {
286
                retVal = g_list_append( retVal, g_strdup( node->data ) );
287
                node = g_list_next( node );
288
        }
289
        return retVal;
290
}
291

    
292
/*
293
* Return filespec of PC3 file corresponding to JPilot PDB file.
294
* Note: Filespec should be g_free() when done.
295
*/
296
static gchar *jpilot_get_pc3_file( JPilotFile *pilotFile ) {
297
        gchar *fileSpec, *r;
298
        gint i, len, pos;
299

    
300
        if( pilotFile == NULL ) return NULL;
301
        if( pilotFile->path == NULL ) return NULL;
302

    
303
        fileSpec = g_strdup( pilotFile->path );
304
        len = strlen( fileSpec );
305
        pos = -1;
306
        r = NULL;
307
        for( i = len; i > 0; i-- ) {
308
                if( *(fileSpec + i) == '.' ) {
309
                        pos = i + 1;
310
                        r = fileSpec + pos;
311
                        break;
312
                }
313
        }
314
        if( r ) {
315
                if( len - pos == 3 ) {
316
                        *r++ = 'p'; *r++ = 'c'; *r = '3';
317
                        return fileSpec;
318
                }
319
        }
320
        g_free( fileSpec );
321
        return NULL;
322
}
323

    
324
/*
325
* Save PC3 file time to cache.
326
* return: TRUE if time marked.
327
*/
328
static gboolean jpilot_mark_files( JPilotFile *pilotFile ) {
329
        gboolean retVal = FALSE;
330
        struct stat filestat;
331
        gchar *pcFile;
332

    
333
        /* Mark PDB file cache */
334
        retVal = addrcache_mark_file( pilotFile->addressCache, pilotFile->path );
335

    
336
        /* Now mark PC3 file */
337
        pilotFile->havePC3 = FALSE;
338
        pilotFile->pc3ModifyTime = 0;
339
        pcFile = jpilot_get_pc3_file( pilotFile );
340
        if( pcFile == NULL ) return retVal;
341
        if( 0 == lstat( pcFile, &filestat ) ) {
342
                pilotFile->havePC3 = TRUE;
343
                pilotFile->pc3ModifyTime = filestat.st_mtime;
344
                retVal = TRUE;
345
        }
346
        g_free( pcFile );
347
        return retVal;
348
}
349

    
350
/*
351
* Check whether JPilot PDB or PC3 file has changed by comparing
352
* with cached data.
353
* return: TRUE if file has changed.
354
*/
355
static gboolean jpilot_check_files( JPilotFile *pilotFile ) {
356
        gboolean retVal = TRUE;
357
        struct stat filestat;
358
        gchar *pcFile;
359

    
360
        /* Check main file */
361
        if( addrcache_check_file( pilotFile->addressCache, pilotFile->path ) )
362
                return TRUE;
363

    
364
        /* Test PC3 file */
365
        if( ! pilotFile->havePC3 ) return FALSE;
366
        pcFile = jpilot_get_pc3_file( pilotFile );
367
        if( pcFile == NULL ) return FALSE;
368

    
369
        if( 0 == lstat( pcFile, &filestat ) ) {
370
                if( filestat.st_mtime == pilotFile->pc3ModifyTime ) retVal = FALSE;
371
        }
372
        g_free( pcFile );
373
        return retVal;
374
}
375

    
376
/*
377
* Test whether file was modified since last access.
378
* Return: TRUE if file was modified.
379
*/
380
gboolean jpilot_get_modified( JPilotFile *pilotFile ) {
381
        g_return_val_if_fail( pilotFile != NULL, FALSE );
382
        return jpilot_check_files( pilotFile );
383
}
384
gboolean jpilot_get_accessed( JPilotFile *pilotFile ) {
385
        g_return_val_if_fail( pilotFile != NULL, FALSE );
386
        return pilotFile->accessFlag;
387
}
388

    
389
/*
390
* Free up pilot file object by releasing internal memory.
391
*/
392
void jpilot_free( JPilotFile *pilotFile ) {
393
        g_return_if_fail( pilotFile != NULL );
394

    
395
        /* Free internal stuff */
396
        g_free( pilotFile->path );
397

    
398
        /* Release custom labels */
399
        jpilot_clear_custom_labels( pilotFile );
400

    
401
        /* Clear cache */
402
        addrcache_clear( pilotFile->addressCache );
403
        addrcache_free( pilotFile->addressCache );
404
        pilotFile->addressCache = NULL;
405
        pilotFile->readMetadata = FALSE;
406
        pilotFile->accessFlag = FALSE;
407
        pilotFile->havePC3 = FALSE;
408
        pilotFile->pc3ModifyTime = 0;
409

    
410
        /* Now release file object */
411
        g_free( pilotFile );
412
}
413

    
414
/*
415
* Refresh internal variables to force a file read.
416
*/
417
void jpilot_force_refresh( JPilotFile *pilotFile ) {
418
        addrcache_refresh( pilotFile->addressCache );
419
}
420

    
421
/*
422
* Print object to specified stream.
423
*/
424
void jpilot_print_file( JPilotFile *pilotFile, FILE *stream ) {
425
        GList *node;
426

    
427
        g_return_if_fail( pilotFile != NULL );
428

    
429
        fprintf( stream, "JPilotFile:\n" );
430
        fprintf( stream, "file spec: '%s'\n", pilotFile->path );
431
        fprintf( stream, " metadata: %s\n", pilotFile->readMetadata ? "yes" : "no" );
432
        fprintf( stream, "  ret val: %d\n", pilotFile->retVal );
433

    
434
        node = pilotFile->customLabels;
435
        while( node ) {
436
                fprintf( stream, "  c label: %s\n", (gchar *)node->data );
437
                node = g_list_next( node );
438
        }
439

    
440
        node = pilotFile->labelInd;
441
        while( node ) {
442
                fprintf( stream, " labelind: %d\n", GPOINTER_TO_INT(node->data) );
443
                node = g_list_next( node );
444
        }
445

    
446
        addrcache_print( pilotFile->addressCache, stream );
447
        fprintf( stream, "  ret val: %d\n", pilotFile->retVal );
448
        fprintf( stream, " have pc3: %s\n", pilotFile->havePC3 ? "yes" : "no" );
449
        fprintf( stream, " pc3 time: %lu\n", pilotFile->pc3ModifyTime );
450
        addritem_print_item_folder( pilotFile->addressCache->rootFolder, stream );
451
}
452

    
453
/*
454
* Print summary of object to specified stream.
455
*/
456
void jpilot_print_short( JPilotFile *pilotFile, FILE *stream ) {
457
        GList *node;
458
        g_return_if_fail( pilotFile != NULL );
459
        fprintf( stream, "JPilotFile:\n" );
460
        fprintf( stream, "file spec: '%s'\n", pilotFile->path );
461
        fprintf( stream, " metadata: %s\n", pilotFile->readMetadata ? "yes" : "no" );
462
        fprintf( stream, "  ret val: %d\n", pilotFile->retVal );
463

    
464
        node = pilotFile->customLabels;
465
        while( node ) {
466
                fprintf( stream, "  c label: %s\n", (gchar *)node->data );
467
                node = g_list_next( node );
468
        }
469

    
470
        node = pilotFile->labelInd;
471
        while( node ) {
472
                fprintf( stream, " labelind: %d\n", GPOINTER_TO_INT(node->data) );
473
                node = g_list_next( node );
474
        }
475
        addrcache_print( pilotFile->addressCache, stream );
476
        fprintf( stream, " have pc3: %s\n", pilotFile->havePC3 ? "yes" : "no" );
477
        fprintf( stream, " pc3 time: %lu\n", pilotFile->pc3ModifyTime );
478
}
479

    
480
/* Shamelessly copied from JPilot (libplugin.c) */
481
static unsigned int bytes_to_bin(unsigned char *bytes, unsigned int num_bytes) {
482
unsigned int i, n;
483
        n=0;
484
        for (i=0;i<num_bytes;i++) {
485
                n = n*256+bytes[i];
486
        }
487
        return n;
488
}
489

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

    
495
time_t pilot_time_to_unix_time ( unsigned long raw_time ) {
496
   return (time_t)(raw_time - PILOT_TIME_DELTA);
497
}
498

    
499
/* Shamelessly copied from JPilot (libplugin.c) */
500
static int raw_header_to_header(RawDBHeader *rdbh, DBHeader *dbh) {
501
        unsigned long temp;
502

    
503
        strncpy(dbh->db_name, rdbh->db_name, 31);
504
        dbh->db_name[31] = '\0';
505
        dbh->flags = bytes_to_bin(rdbh->flags, 2);
506
        dbh->version = bytes_to_bin(rdbh->version, 2);
507
        temp = bytes_to_bin(rdbh->creation_time, 4);
508
        dbh->creation_time = pilot_time_to_unix_time(temp);
509
        temp = bytes_to_bin(rdbh->modification_time, 4);
510
        dbh->modification_time = pilot_time_to_unix_time(temp);
511
        temp = bytes_to_bin(rdbh->backup_time, 4);
512
        dbh->backup_time = pilot_time_to_unix_time(temp);
513
        dbh->modification_number = bytes_to_bin(rdbh->modification_number, 4);
514
        dbh->app_info_offset = bytes_to_bin(rdbh->app_info_offset, 4);
515
        dbh->sort_info_offset = bytes_to_bin(rdbh->sort_info_offset, 4);
516
        strncpy(dbh->type, rdbh->type, 4);
517
        dbh->type[4] = '\0';
518
        strncpy(dbh->creator_id, rdbh->creator_id, 4);
519
        dbh->creator_id[4] = '\0';
520
        strncpy(dbh->unique_id_seed, rdbh->unique_id_seed, 4);
521
        dbh->unique_id_seed[4] = '\0';
522
        dbh->next_record_list_id = bytes_to_bin(rdbh->next_record_list_id, 4);
523
        dbh->number_of_records = bytes_to_bin(rdbh->number_of_records, 2);
524
        return 0;
525
}
526

    
527
/* Shamelessly copied from JPilot (libplugin.c) */
528
/* returns 1 if found */
529
/*         0 if eof */
530
static int find_next_offset( mem_rec_header *mem_rh, long fpos,
531
        unsigned int *next_offset, unsigned char *attrib, unsigned int *unique_id )
532
{
533
        mem_rec_header *temp_mem_rh;
534
        unsigned char found = 0;
535
        unsigned long found_at;
536

    
537
        found_at=0xFFFFFF;
538
        for (temp_mem_rh=mem_rh; temp_mem_rh; temp_mem_rh = temp_mem_rh->next) {
539
                if ((temp_mem_rh->offset > fpos) && (temp_mem_rh->offset < found_at)) {
540
                        found_at = temp_mem_rh->offset;
541
                        /* *attrib = temp_mem_rh->attrib; */
542
                        /* *unique_id = temp_mem_rh->unique_id; */
543
                }
544
                if ((temp_mem_rh->offset == fpos)) {
545
                        found = 1;
546
                        *attrib = temp_mem_rh->attrib;
547
                        *unique_id = temp_mem_rh->unique_id;
548
                }
549
        }
550
        *next_offset = found_at;
551
        return found;
552
}
553

    
554
/* Shamelessly copied from JPilot (libplugin.c) */
555
static void free_mem_rec_header(mem_rec_header **mem_rh) {
556
        mem_rec_header *h, *next_h;
557
        for (h=*mem_rh; h; h=next_h) {
558
                next_h=h->next;
559
                free(h);
560
        }
561
        *mem_rh = NULL;
562
}
563

    
564
#if 0
565
/* Shamelessly copied from JPilot (libplugin.c) */
566
static int jpilot_free_db_list( GList **br_list ) {
567
        GList *temp_list, *first;
568
        buf_rec *br;
569

570
        /* Go to first entry in the list */
571
        first=NULL;
572
        for( temp_list = *br_list; temp_list; temp_list = temp_list->prev ) {
573
                first = temp_list;
574
        }
575
        for (temp_list = first; temp_list; temp_list = temp_list->next) {
576
                if (temp_list->data) {
577
                        br=temp_list->data;
578
                        if (br->buf) {
579
                                free(br->buf);
580
                                temp_list->data=NULL;
581
                        }
582
                        free(br);
583
                }
584
        }
585
        g_list_free(*br_list);
586
        *br_list=NULL;
587
        return 0;
588
}
589
#endif
590

    
591
/* Shamelessly copied from JPilot (libplugin.c) */
592
/* Read file size */
593
static int jpilot_get_info_size( FILE *in, int *size ) {
594
        RawDBHeader rdbh;
595
        DBHeader dbh;
596
        unsigned int offset;
597
        record_header rh;
598

    
599
        fseek(in, 0, SEEK_SET);
600
        fread(&rdbh, sizeof(RawDBHeader), 1, in);
601
        if (feof(in)) {
602
                return MGU_EOF;
603
        }
604

    
605
        raw_header_to_header(&rdbh, &dbh);
606
        if (dbh.app_info_offset==0) {
607
                *size=0;
608
                return MGU_SUCCESS;
609
        }
610
        if (dbh.sort_info_offset!=0) {
611
                *size = dbh.sort_info_offset - dbh.app_info_offset;
612
                return MGU_SUCCESS;
613
        }
614
        if (dbh.number_of_records==0) {
615
                fseek(in, 0, SEEK_END);
616
                *size=ftell(in) - dbh.app_info_offset;
617
                return MGU_SUCCESS;
618
        }
619

    
620
        fread(&rh, sizeof(record_header), 1, in);
621
        offset = ((rh.Offset[0]*256+rh.Offset[1])*256+rh.Offset[2])*256+rh.Offset[3];
622
        *size=offset - dbh.app_info_offset;
623

    
624
        return MGU_SUCCESS;
625
}
626

    
627
/*
628
 * Read address file into address list. Based on JPilot's
629
 * libplugin.c (jp_get_app_info)
630
 */
631
static gint jpilot_get_file_info( JPilotFile *pilotFile, unsigned char **buf, int *buf_size ) {
632
        FILE *in;
633
         int num;
634
        unsigned int rec_size;
635
        RawDBHeader rdbh;
636
        DBHeader dbh;
637

    
638
        if( ( !buf_size ) || ( ! buf ) ) {
639
                return MGU_BAD_ARGS;
640
        }
641

    
642
        *buf = NULL;
643
        *buf_size=0;
644

    
645
        if( pilotFile->path ) {
646
                in = fopen( pilotFile->path, "rb" );
647
                if( !in ) {
648
                        return MGU_OPEN_FILE;
649
                }
650
        }
651
        else {
652
                return MGU_NO_FILE;
653
        }
654

    
655
        num = fread( &rdbh, sizeof( RawDBHeader ), 1, in );
656
        if( num != 1 ) {
657
                  if( ferror(in) ) {
658
                        fclose(in);
659
                        return MGU_ERROR_READ;
660
                }
661
        }
662
        if (feof(in)) {
663
                fclose(in);
664
                return MGU_EOF;
665
        }
666

    
667
        /* Convert header into something recognizable */
668
        raw_header_to_header(&rdbh, &dbh);
669

    
670
        num = jpilot_get_info_size(in, &rec_size);
671
        if (num) {
672
                fclose(in);
673
                return MGU_ERROR_READ;
674
        }
675

    
676
        fseek(in, dbh.app_info_offset, SEEK_SET);
677
        *buf = ( char * ) malloc(rec_size);
678
        if (!(*buf)) {
679
                fclose(in);
680
                return MGU_OO_MEMORY;
681
        }
682
        num = fread(*buf, rec_size, 1, in);
683
        if (num != 1) {
684
                if (ferror(in)) {
685
                        fclose(in);
686
                        free(*buf);
687
                        return MGU_ERROR_READ;
688
                }
689
        }
690
        fclose(in);
691

    
692
        *buf_size = rec_size;
693

    
694
        return MGU_SUCCESS;
695
}
696

    
697
/* Shamelessly copied from JPilot (libplugin.c) */
698
static int unpack_header(PC3RecordHeader *header, unsigned char *packed_header) {
699
        unsigned char *p;
700
        unsigned long l;
701

    
702
        p = packed_header;
703

    
704
        memcpy(&l, p, sizeof(l));
705
        header->header_len=ntohl(l);
706
        p+=sizeof(l);
707

    
708
        memcpy(&l, p, sizeof(l));
709
        header->header_version=ntohl(l);
710
        p+=sizeof(l);
711

    
712
        memcpy(&l, p, sizeof(l));
713
        header->rec_len=ntohl(l);
714
        p+=sizeof(l);
715

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

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

    
724
        memcpy(&(header->attrib), p, sizeof(unsigned char));
725
        p+=sizeof(unsigned char);
726

    
727
        return 0;
728
}
729

    
730
/* Shamelessly copied from JPilot (libplugin.c) */
731
static int read_header(FILE *pc_in, PC3RecordHeader *header) {
732
        unsigned long l, len;
733
        unsigned char packed_header[256];
734
        int num;
735

    
736
        num = fread(&l, sizeof(l), 1, pc_in);
737
        if (feof(pc_in)) {
738
                return -1;
739
        }
740
        if (num!=1) {
741
                return num;
742
        }
743
        memcpy(packed_header, &l, sizeof(l));
744
        len=ntohl(l);
745
        if (len > 255) {
746
                return -1;
747
        }
748
        num = fread(packed_header+sizeof(l), len-sizeof(l), 1, pc_in);
749
        if (feof(pc_in)) {
750
                return -1;
751
        }
752
        if (num!=1) {
753
                return num;
754
        }
755
        unpack_header(header, packed_header);
756
        return 1;
757
}
758

    
759
/* Read next record from PC3 file. Based on JPilot's
760
 * pc_read_next_rec (libplugin.c) */
761
static gint jpilot_read_next_pc( FILE *in, buf_rec *br ) {
762
        PC3RecordHeader header;
763
        int rec_len, num;
764
        char *record;
765

    
766
        if(feof(in)) {
767
                return MGU_EOF;
768
        }
769
        num = read_header(in, &header);
770
        if (num < 1) {
771
                if (ferror(in)) {
772
                        return MGU_ERROR_READ;
773
                }
774
                if (feof(in)) {
775
                        return MGU_EOF;
776
                }
777
        }
778
        rec_len = header.rec_len;
779
        record = malloc(rec_len);
780
        if (!record) {
781
                return MGU_OO_MEMORY;
782
        }
783
        num = fread(record, rec_len, 1, in);
784
        if (num != 1) {
785
                if (ferror(in)) {
786
                        free(record);
787
                        return MGU_ERROR_READ;
788
                }
789
        }
790
        br->rt = header.rt;
791
        br->unique_id = header.unique_id;
792
        br->attrib = header.attrib;
793
        br->buf = record;
794
        br->size = rec_len;
795

    
796
        return MGU_SUCCESS;
797
}
798

    
799
/*
800
 * Read address file into a linked list. Based on JPilot's
801
 * jp_read_DB_files (from libplugin.c)
802
 */
803
static gint jpilot_read_db_files( JPilotFile *pilotFile, GList **records ) {
804
        FILE *in, *pc_in;
805
        char *buf;
806
        GList *temp_list;
807
        int num_records, recs_returned, i, num, r;
808
        unsigned int offset, prev_offset, next_offset, rec_size;
809
        int out_of_order;
810
        long fpos;  /*file position indicator */
811
        unsigned char attrib;
812
        unsigned int unique_id;
813
        mem_rec_header *mem_rh, *temp_mem_rh, *last_mem_rh;
814
        record_header rh;
815
        RawDBHeader rdbh;
816
        DBHeader dbh;
817
        buf_rec *temp_br;
818
        gchar *pcFile;
819

    
820
        mem_rh = last_mem_rh = NULL;
821
        *records = NULL;
822
        recs_returned = 0;
823

    
824
        if( pilotFile->path == NULL ) {
825
                return MGU_BAD_ARGS;
826
        }
827

    
828
        in = fopen( pilotFile->path, "rb" );
829
        if (!in) {
830
                return MGU_OPEN_FILE;
831
        }
832

    
833
        /* Read the database header */
834
        num = fread(&rdbh, sizeof(RawDBHeader), 1, in);
835
        if (num != 1) {
836
                if (ferror(in)) {
837
                        fclose(in);
838
                        return MGU_ERROR_READ;
839
                }
840
                if (feof(in)) {
841
                        return MGU_EOF;
842
                }
843
        }
844
        raw_header_to_header(&rdbh, &dbh);
845

    
846
        /* Read each record entry header */
847
        num_records = dbh.number_of_records;
848
        out_of_order = 0;
849
        prev_offset = 0;
850

    
851
        for (i = 1; i < num_records + 1; i++) {
852
                num = fread(&rh, sizeof(record_header), 1, in);
853
                if (num != 1) {
854
                        if (ferror(in)) {
855
                                break;
856
                        }
857
                        if (feof(in)) {
858
                                return MGU_EOF;
859
                        }
860
                }
861

    
862
                offset = ((rh.Offset[0]*256+rh.Offset[1])*256+rh.Offset[2])*256+rh.Offset[3];
863
                if (offset < prev_offset) {
864
                        out_of_order = 1;
865
                }
866
                prev_offset = offset;
867
                temp_mem_rh = (mem_rec_header *)malloc(sizeof(mem_rec_header));
868
                if (!temp_mem_rh) {
869
                        break;
870
                }
871
                temp_mem_rh->next = NULL;
872
                temp_mem_rh->rec_num = i;
873
                temp_mem_rh->offset = offset;
874
                temp_mem_rh->attrib = rh.attrib;
875
                temp_mem_rh->unique_id = (rh.unique_ID[0]*256+rh.unique_ID[1])*256+rh.unique_ID[2];
876
                if (mem_rh == NULL) {
877
                        mem_rh = temp_mem_rh;
878
                        last_mem_rh = temp_mem_rh;
879
                } else {
880
                        last_mem_rh->next = temp_mem_rh;
881
                        last_mem_rh = temp_mem_rh;
882
                }
883
        }
884

    
885
        temp_mem_rh = mem_rh;
886

    
887
        if (num_records) {
888
                if (out_of_order) {
889
                        find_next_offset(mem_rh, 0, &next_offset, &attrib, &unique_id);
890
                } else {
891
                        if (mem_rh) {
892
                                next_offset = mem_rh->offset;
893
                                attrib = mem_rh->attrib;
894
                                unique_id = mem_rh->unique_id;
895
                        }
896
                }
897
                fseek(in, next_offset, SEEK_SET);
898
                while(!feof(in)) {
899
                        fpos = ftell(in);
900
                        if (out_of_order) {
901
                                find_next_offset(mem_rh, fpos, &next_offset, &attrib, &unique_id);
902
                        } else {
903
                                next_offset = 0xFFFFFF;
904
                                if (temp_mem_rh) {
905
                                        attrib = temp_mem_rh->attrib;
906
                                        unique_id = temp_mem_rh->unique_id;
907
                                        if (temp_mem_rh->next) {
908
                                                temp_mem_rh = temp_mem_rh->next;
909
                                                next_offset = temp_mem_rh->offset;
910
                                        }
911
                                }
912
                        }
913
                        rec_size = next_offset - fpos;
914
                        buf = malloc(rec_size);
915
                        if (!buf) break;
916
                        num = fread(buf, rec_size, 1, in);
917
                        if ((num != 1)) {
918
                                if (ferror(in)) {
919
                                        free(buf);
920
                                        break;
921
                                }
922
                        }
923

    
924
                        temp_br = malloc(sizeof(buf_rec));
925
                        if (!temp_br) {
926
                                break;
927
                        }
928
                        temp_br->rt = PALM_REC;
929
                        temp_br->unique_id = unique_id;
930
                        temp_br->attrib = attrib;
931
                        temp_br->buf = buf;
932
                        temp_br->size = rec_size;
933

    
934
                        *records = g_list_append(*records, temp_br);
935

    
936
                        recs_returned++;
937
                }
938
        }
939
        fclose(in);
940
        free_mem_rec_header(&mem_rh);
941

    
942
        /* Read the PC3 file, if present */
943
        pcFile = jpilot_get_pc3_file( pilotFile );
944
        if( pcFile == NULL ) return MGU_SUCCESS;
945
        pc_in = fopen( pcFile, "rb");
946
        g_free( pcFile );
947

    
948
        if( pc_in == NULL ) {
949
                return MGU_SUCCESS;
950
        }
951

    
952
        while( ! feof( pc_in ) ) {
953
                temp_br = malloc(sizeof(buf_rec));
954
                if (!temp_br) {
955
                        break;
956
                }
957
                r = jpilot_read_next_pc( pc_in, temp_br );
958
                if ( r != MGU_SUCCESS ) {
959
                        free(temp_br);
960
                        break;
961
                }
962
                if ((temp_br->rt!=DELETED_PC_REC)
963
                        &&(temp_br->rt!=DELETED_PALM_REC)
964
                        &&(temp_br->rt!=MODIFIED_PALM_REC)
965
                        &&(temp_br->rt!=DELETED_DELETED_PALM_REC)) {
966
                                *records = g_list_append(*records, temp_br);
967
                                recs_returned++;
968
                }
969
                if ((temp_br->rt==DELETED_PALM_REC) || (temp_br->rt==MODIFIED_PALM_REC)) {
970
                        temp_list=*records;
971
                        if (*records) {
972
                                while(temp_list->next) {
973
                                        temp_list=temp_list->next;
974
                                }
975
                        }
976
                        for (; temp_list; temp_list=temp_list->prev) {
977
                                if (((buf_rec *)temp_list->data)->unique_id == temp_br->unique_id) {
978
                                        ((buf_rec *)temp_list->data)->rt = temp_br->rt;
979
                                }
980
                        }
981
                }
982
        }
983
        fclose(pc_in);
984

    
985
        return MGU_SUCCESS;
986
}
987

    
988
#define FULLNAME_BUFSIZE        256
989
#define EMAIL_BUFSIZE                256
990
/*
991
 * Unpack address, building new data inside cache.
992
 */
993
static void jpilot_load_address( JPilotFile *pilotFile, buf_rec *buf, ItemFolder *folderInd[] ) {
994
        struct Address addr;
995
        gchar **addrEnt;
996
        gint num, k;
997
        gint cat_id = 0;
998
        guint unique_id;
999
        guchar attrib;
1000
        gchar fullName[ FULLNAME_BUFSIZE ];
1001
        gchar bufEMail[ EMAIL_BUFSIZE ];
1002
        ItemPerson *person;
1003
        ItemEMail *email;
1004
        gint *indPhoneLbl;
1005
        gchar *labelEntry;
1006
        GList *node;
1007
        gchar* extID;
1008
        struct AddressAppInfo *ai;
1009
        gchar **firstName = NULL;
1010
        gchar **lastName = NULL;
1011

    
1012
        /* Retrieve address */
1013
        num = unpack_Address( & addr, buf->buf, buf->size );
1014
        if( num > 0 ) {
1015
                addrEnt = addr.entry;
1016
                attrib = buf->attrib;
1017
                unique_id = buf->unique_id;
1018
                cat_id = attrib & 0x0F;
1019

    
1020
                *fullName = *bufEMail = '\0';
1021

    
1022
                if( addrEnt[ IND_LABEL_FIRSTNAME ] ) {
1023
                        firstName = g_strsplit( addrEnt[ IND_LABEL_FIRSTNAME ], "\01", 2 );
1024
                }
1025
                if( addrEnt[ IND_LABEL_LASTNAME ] ) {
1026
                        lastName = g_strsplit( addrEnt[ IND_LABEL_LASTNAME ], "\01", 2 );
1027
                }
1028

    
1029
                if( name_order == FAMILY_LAST ) {
1030
                        g_snprintf( fullName, FULLNAME_BUFSIZE, "%s %s",
1031
                                    firstName ? firstName[0] : "",
1032
                                    lastName ? lastName[0] : "" );
1033
                }
1034
                else {
1035
                        g_snprintf( fullName, FULLNAME_BUFSIZE, "%s %s",
1036
                                    lastName ? lastName[0] : "",
1037
                                    firstName ? firstName[0] : "" );
1038
                }
1039

    
1040
                if( firstName ) {
1041
                        g_strfreev( firstName );
1042
                }
1043
                if( lastName ) {
1044
                        g_strfreev( lastName );
1045
                }
1046

    
1047
                g_strstrip( fullName );
1048

    
1049
                if( convert_charcode ) {
1050
                        gchar *nameConv;
1051
                        nameConv = g_strdup( fullName );
1052
                        conv_sjistoeuc( fullName, FULLNAME_BUFSIZE, nameConv );
1053
                        g_free( nameConv );
1054
                }
1055

    
1056
                person = addritem_create_item_person();
1057
                addritem_person_set_common_name( person, fullName );
1058
                addritem_person_set_first_name( person, addrEnt[ IND_LABEL_FIRSTNAME ] );
1059
                addritem_person_set_last_name( person, addrEnt[ IND_LABEL_LASTNAME ] );
1060
                addrcache_id_person( pilotFile->addressCache, person );
1061

    
1062
                extID = g_strdup_printf( "%d", unique_id );
1063
                addritem_person_set_external_id( person, extID );
1064
                g_free( extID );
1065
                extID = NULL;
1066

    
1067
                /* Pointer to address metadata. */
1068
                ai = & pilotFile->addrInfo;
1069

    
1070
                /* Add entry for each email address listed under phone labels. */
1071
                indPhoneLbl = addr.phoneLabel;
1072
                for( k = 0; k < JPILOT_NUM_ADDR_PHONE; k++ ) {
1073
                        gint ind;
1074

    
1075
                        ind = indPhoneLbl[k];
1076
                        /*
1077
                        * fprintf( stdout, "%d : %d : %20s : %s\n", k, ind,
1078
                        * ai->phoneLabels[ind], addrEnt[3+k] );
1079
                        */
1080
                        if( indPhoneLbl[k] == IND_PHONE_EMAIL ) {
1081
                                labelEntry = addrEnt[ OFFSET_PHONE_LABEL + k ];
1082
                                if( labelEntry ) {
1083
                                        strcpy( bufEMail, labelEntry );
1084
                                        g_strchug( bufEMail );
1085
                                        g_strchomp( bufEMail );
1086

    
1087
                                        email = addritem_create_item_email();
1088
                                        addritem_email_set_address( email, bufEMail );
1089
                                        addrcache_id_email( pilotFile->addressCache, email );
1090
                                        addrcache_person_add_email
1091
                                                ( pilotFile->addressCache, person, email );
1092
                                }
1093
                        }
1094
                }
1095

    
1096
                /* Add entry for each custom label */
1097
                node = pilotFile->labelInd;
1098
                while( node ) {
1099
                        gchar convertBuff[ JPILOT_LEN_LABEL ];
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
                                                conv_sjistoeuc( convertBuff, JPILOT_LEN_LABEL, ai->labels[ind] );
1119
                                                addritem_email_set_remarks( email, convertBuff );
1120
                                        }
1121
                                        else {
1122
                                                addritem_email_set_remarks( email, ai->labels[ind] );
1123
                                        }
1124

    
1125
                                        addrcache_id_email( pilotFile->addressCache, email );
1126
                                        addrcache_person_add_email
1127
                                                ( pilotFile->addressCache, person, email );
1128
                                }
1129
                        }
1130

    
1131
                        node = g_list_next( node );
1132
                }
1133

    
1134
                if( person->listEMail ) {
1135
                        if( cat_id > -1 && cat_id < JPILOT_NUM_CATEG ) {
1136
                                /* Add to specified category */
1137
                                addrcache_folder_add_person
1138
                                        ( pilotFile->addressCache, folderInd[cat_id], person );
1139
                        }
1140
                        else {
1141
                                /* Add to root folder */
1142
                                addrcache_add_person( pilotFile->addressCache, person );
1143
                        }
1144
                }
1145
                else {
1146
                        addritem_free_item_person( person );
1147
                        person = NULL;
1148
                }
1149
        }
1150
}
1151

    
1152
/*
1153
 * Free up address list.
1154
 */
1155
static void jpilot_free_addrlist( GList *records ) {
1156
        GList *node;
1157
        buf_rec *br;
1158

    
1159
        node = records;
1160
        while( node ) {
1161
                br = node->data;
1162
                free( br );
1163
                node->data = NULL;
1164
                node = g_list_next( node );
1165
        }
1166

    
1167
        /* Free up list */
1168
        g_list_free( records );
1169
}
1170

    
1171
/*
1172
 * Read address file into address cache.
1173
 */
1174
static gint jpilot_read_file( JPilotFile *pilotFile ) {
1175
        gint retVal, i;
1176
        GList *records = NULL;
1177
        GList *node;
1178
        buf_rec *br;
1179
        ItemFolder *folderInd[ JPILOT_NUM_CATEG ];
1180

    
1181
        retVal = jpilot_read_db_files( pilotFile, &records );
1182
        if( retVal != MGU_SUCCESS ) {
1183
                jpilot_free_addrlist( records );
1184
                return retVal;
1185
        }
1186

    
1187
        /* Build array of pointers to categories */
1188
        i = 0;
1189
        node = addrcache_get_list_folder( pilotFile->addressCache );
1190
        while( node ) {
1191
                if( i < JPILOT_NUM_CATEG ) {
1192
                        folderInd[i] = node->data;
1193
                }
1194
                node = g_list_next( node );
1195
                i++;
1196
        }
1197

    
1198
        /* Load all addresses, free up old stuff as we go */
1199
        node = records;
1200
        while( node ) {
1201
                br = node->data;
1202
                if( ( br->rt != DELETED_PC_REC ) &&
1203
                    ( br->rt != DELETED_PALM_REC ) &&
1204
                    ( br->rt != MODIFIED_PALM_REC ) &&
1205
                    ( br->rt != DELETED_DELETED_PALM_REC ) ) {
1206
                        jpilot_load_address( pilotFile, br, folderInd );
1207
                }
1208
                free( br );
1209
                node->data = NULL;
1210
                node = g_list_next( node );
1211
        }
1212

    
1213
        /* Free up list */
1214
        g_list_free( records );
1215

    
1216
        return retVal;
1217
}
1218

    
1219

    
1220
/*
1221
* Read metadata from file.
1222
*/
1223
static gint jpilot_read_metadata( JPilotFile *pilotFile ) {
1224
        gint retVal;
1225
        unsigned int rec_size;
1226
        unsigned char *buf;
1227
        int num;
1228

    
1229
        g_return_val_if_fail( pilotFile != NULL, -1 );
1230

    
1231
        pilotFile->readMetadata = FALSE;
1232
        addrcache_clear( pilotFile->addressCache );
1233

    
1234
        /* Read file info */
1235
        retVal = jpilot_get_file_info( pilotFile, &buf, &rec_size);
1236
        if( retVal != MGU_SUCCESS ) {
1237
                pilotFile->retVal = retVal;
1238
                return pilotFile->retVal;
1239
        }
1240

    
1241
        num = unpack_AddressAppInfo( &pilotFile->addrInfo, buf, rec_size );
1242
        if( buf ) {
1243
                free(buf);
1244
        }
1245
        if( num <= 0 ) {
1246
                pilotFile->retVal = MGU_ERROR_READ;
1247
                return pilotFile->retVal;
1248
        }
1249

    
1250
        pilotFile->readMetadata = TRUE;
1251
        pilotFile->retVal = MGU_SUCCESS;
1252
        return pilotFile->retVal;
1253
}
1254

    
1255
/*
1256
* Setup labels and indexes from metadata.
1257
* Return: TRUE is setup successfully.
1258
*/
1259
static gboolean jpilot_setup_labels( JPilotFile *pilotFile ) {
1260
        gboolean retVal = FALSE;
1261
        struct AddressAppInfo *ai;
1262
        GList *node;
1263

    
1264
        g_return_val_if_fail( pilotFile != NULL, -1 );
1265

    
1266
        /* Release indexes */
1267
        node = pilotFile->labelInd;
1268
        while( node ) {
1269
                node->data = NULL;
1270
                node = g_list_next( node );
1271
        }
1272
        pilotFile->labelInd = NULL;
1273

    
1274
        if( pilotFile->readMetadata ) {
1275
                ai = & pilotFile->addrInfo;
1276
                node = pilotFile->customLabels;
1277
                while( node ) {
1278
                        gchar *lbl = node->data;
1279
                        gint ind = -1;
1280
                        gint i;
1281
                        for( i = 0; i < JPILOT_NUM_LABELS; i++ ) {
1282
                                gchar *labelName = ai->labels[i];
1283
                                gchar convertBuff[ JPILOT_LEN_LABEL ];
1284

    
1285
                                if( convert_charcode ) {
1286
                                        conv_sjistoeuc( convertBuff, JPILOT_LEN_LABEL, labelName );
1287
                                        labelName = convertBuff;
1288
                                }
1289

    
1290
                                if( g_strcasecmp( labelName, lbl ) == 0 ) {
1291
                                        ind = i;
1292
                                        break;
1293
                                }
1294
                        }
1295
                        pilotFile->labelInd = g_list_append( pilotFile->labelInd, GINT_TO_POINTER(ind) );
1296
                        node = g_list_next( node );
1297
                }
1298
                retVal = TRUE;
1299
        }
1300
        return retVal;
1301
}
1302

    
1303
/*
1304
* Load list with character strings of label names.
1305
*/
1306
GList *jpilot_load_label( JPilotFile *pilotFile, GList *labelList ) {
1307
        int i;
1308

    
1309
        g_return_val_if_fail( pilotFile != NULL, NULL );
1310

    
1311
        if( pilotFile->readMetadata ) {
1312
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1313
                for( i = 0; i < JPILOT_NUM_LABELS; i++ ) {
1314
                        gchar *labelName = ai->labels[i];
1315
                        gchar convertBuff[JPILOT_LEN_LABEL];
1316

    
1317
                        if( labelName ) {
1318
                                if( convert_charcode ) {
1319
                                        conv_sjistoeuc( convertBuff, JPILOT_LEN_LABEL, labelName );
1320
                                        labelName = convertBuff;
1321
                                }
1322
                                labelList = g_list_append( labelList, g_strdup( labelName ) );
1323
                        }
1324
                        else {
1325
                                labelList = g_list_append( labelList, g_strdup( "" ) );
1326
                        }
1327
                }
1328
        }
1329
        return labelList;
1330
}
1331

    
1332
/*
1333
* Return category name for specified category ID.
1334
* Enter:  Category ID.
1335
* Return: Name, or empty string if not invalid ID. Name should be g_free() when done.
1336
*/
1337
gchar *jpilot_get_category_name( JPilotFile *pilotFile, gint catID ) {
1338
        gchar *catName = NULL;
1339

    
1340
        g_return_val_if_fail( pilotFile != NULL, NULL );
1341

    
1342
        if( pilotFile->readMetadata ) {
1343
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1344
                struct CategoryAppInfo *cat = &        ai->category;
1345
                if( catID < 0 || catID > JPILOT_NUM_CATEG ) {
1346
                }
1347
                else {
1348
                        catName = g_strdup( cat->name[catID] );
1349
                }
1350
        }
1351
        if( ! catName ) catName = g_strdup( "" );
1352
        return catName;
1353
}
1354

    
1355
/*
1356
* Load list with character strings of phone label names.
1357
*/
1358
GList *jpilot_load_phone_label( JPilotFile *pilotFile, GList *labelList ) {
1359
        gint i;
1360

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

    
1363
        if( pilotFile->readMetadata ) {
1364
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1365
                for( i = 0; i < JPILOT_NUM_PHONELABELS; i++ ) {
1366
                        gchar        *labelName = ai->phoneLabels[i];
1367
                        if( labelName ) {
1368
                                labelList = g_list_append( labelList, g_strdup( labelName ) );
1369
                        }
1370
                        else {
1371
                                labelList = g_list_append( labelList, g_strdup( "" ) );
1372
                        }
1373
                }
1374
        }
1375
        return labelList;
1376
}
1377

    
1378
/*
1379
* Load list with character strings of label names. Only none blank names
1380
* are loaded.
1381
*/
1382
GList *jpilot_load_custom_label( JPilotFile *pilotFile, GList *labelList ) {
1383
        gint i;
1384
        char convertBuff[JPILOT_LEN_LABEL];
1385

    
1386
        g_return_val_if_fail( pilotFile != NULL, NULL );
1387

    
1388
        if( pilotFile->readMetadata ) {
1389
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1390
                for( i = 0; i < NUM_CUSTOM_LABEL; i++ ) {
1391
                        gchar *labelName = ai->labels[i+IND_CUSTOM_LABEL];
1392
                        if( labelName ) {
1393
                                g_strchomp( labelName );
1394
                                g_strchug( labelName );
1395
                                if( *labelName != '\0' ) {
1396
                                        if( convert_charcode ) {
1397
                                                conv_sjistoeuc( convertBuff, JPILOT_LEN_LABEL, labelName );
1398
                                                labelName = convertBuff;
1399
                                        }
1400
                                        labelList = g_list_append( labelList, g_strdup( labelName ) );
1401
                                }
1402
                        }
1403
                }
1404
        }
1405
        return labelList;
1406
}
1407

    
1408
/*
1409
* Load list with character strings of category names.
1410
*/
1411
GList *jpilot_get_category_list( JPilotFile *pilotFile ) {
1412
        GList *catList = NULL;
1413
        gint i;
1414

    
1415
        g_return_val_if_fail( pilotFile != NULL, NULL );
1416

    
1417
        if( pilotFile->readMetadata ) {
1418
                struct AddressAppInfo *ai = & pilotFile->addrInfo;
1419
                struct CategoryAppInfo *cat = &        ai->category;
1420
                for( i = 0; i < JPILOT_NUM_CATEG; i++ ) {
1421
                        gchar *catName = cat->name[i];
1422
                        if( catName ) {
1423
                                catList = g_list_append( catList, g_strdup( catName ) );
1424
                        }
1425
                        else {
1426
                                catList = g_list_append( catList, g_strdup( "" ) );
1427
                        }
1428
                }
1429
        }
1430
        return catList;
1431
}
1432

    
1433
/*
1434
* Build folder for each category.
1435
*/
1436
static void jpilot_build_category_list( JPilotFile *pilotFile ) {
1437
        struct AddressAppInfo *ai = & pilotFile->addrInfo;
1438
        struct CategoryAppInfo *cat = &        ai->category;
1439
        gint i;
1440

    
1441
        for( i = 0; i < JPILOT_NUM_CATEG; i++ ) {
1442
                ItemFolder *folder = addritem_create_item_folder();
1443

    
1444
                if( convert_charcode ) {
1445
                        gchar catName[ JPILOT_LEN_CATEG ];
1446
                        conv_sjistoeuc( catName, JPILOT_LEN_CATEG, cat->name[i] );
1447
                        addritem_folder_set_name( folder, catName );
1448
                }
1449
                else {
1450
                        addritem_folder_set_name( folder, cat->name[i] );
1451
                }
1452

    
1453
                addrcache_id_folder( pilotFile->addressCache, folder );
1454
                addrcache_add_folder( pilotFile->addressCache, folder );
1455
        }
1456
}
1457

    
1458
/*
1459
* Remove empty folders (categories).
1460
*/
1461
static void jpilot_remove_empty( JPilotFile *pilotFile ) {
1462
        GList *listFolder;
1463
        GList *remList;
1464
        GList *node;
1465
        gint i = 0;
1466

    
1467
        listFolder = addrcache_get_list_folder( pilotFile->addressCache );
1468
        node = listFolder;
1469
        remList = NULL;
1470
        while( node ) {
1471
                ItemFolder *folder = node->data;
1472
                if( ADDRITEM_NAME(folder) == NULL || *ADDRITEM_NAME(folder) == '\0' ) {
1473
                        if( folder->listPerson ) {
1474
                                /* Give name to folder */
1475
                                gchar name[20];
1476
                                sprintf( name, "? %d", i );
1477
                                addritem_folder_set_name( folder, name );
1478
                        }
1479
                        else {
1480
                                /* Mark for removal */
1481
                                remList = g_list_append( remList, folder );
1482
                        }
1483
                }
1484
                node = g_list_next( node );
1485
                i++;
1486
        }
1487
        node = remList;
1488
        while( node ) {
1489
                ItemFolder *folder = node->data;
1490
                addrcache_remove_folder( pilotFile->addressCache, folder );
1491
                node = g_list_next( node );
1492
        }
1493
        g_list_free( remList );
1494
}
1495

    
1496
/*
1497
* ============================================================================================
1498
* Read file into list. Main entry point
1499
* Return: TRUE if file read successfully.
1500
* ============================================================================================
1501
*/
1502
gint jpilot_read_data( JPilotFile *pilotFile ) {
1503
        const gchar *cur_locale;
1504

    
1505
        name_order = FAMILY_LAST;
1506
        convert_charcode = FALSE;
1507

    
1508
        cur_locale = conv_get_current_locale();
1509

    
1510
        if( g_strncasecmp( cur_locale, "ja", 2 ) == 0 ) {
1511
                name_order = FAMILY_FIRST;
1512
        }
1513

    
1514
        if( conv_get_locale_charset() == C_EUC_JP ) {
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_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
        gchar *homedir;
1624
        gchar str[ WORK_BUFLEN ];
1625
        gint len;
1626
        FILE *fp;
1627

    
1628
        homedir = g_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 = 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_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
*/