pilot-addresses.c

Go to the documentation of this file.
00001 /*
00002  * $Id: pilot-addresses.c,v 1.89 2007-07-30 04:56:46 desrod Exp $ 
00003  *
00004  * pilot-addresses.c:  Palm address transfer utility
00005  *
00006  * This program is free software; you can redistribute it and/or modify it
00007  * under the terms of the GNU General Public License as published by the
00008  * Free Software Foundation; either version 2 of the License, or (at your
00009  * option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful, but
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
00014  * Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License along
00017  * with this program; if not, write to the Free Software Foundation, Inc.,
00018  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00019  *
00020  */
00021 
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <strings.h>
00026 #include <errno.h>
00027 
00028 #include "pi-socket.h"
00029 #include "pi-dlp.h"
00030 #include "pi-address.h"
00031 #include "pi-header.h"
00032 #include "pi-userland.h"
00033 
00034 /* These are indexes in the tabledelims array */
00035 enum terminators { term_newline=0,
00036         term_comma=1,
00037         term_semi=2,
00038         term_tab=3 } ;
00039 char    tabledelims[4] = { '\n', ',', ';', '\t' };
00040 
00041 
00042 
00043 /* Define prototypes */
00044 int inchar(FILE * in);
00045 int read_field(char *dest, FILE * in, size_t length);
00046 void outchar(char c, FILE * out);
00047 int write_field(FILE * out, const char *source, enum terminators more);
00048 int match_phone(char *buf, struct AddressAppInfo *aai);
00049 int read_file(FILE * in, int sd, int db, struct AddressAppInfo *aai);
00050 int write_file(FILE * out, int sd, int db, struct AddressAppInfo *aai, int human /* human-readable or CSV */);
00051 
00052 int realentry[21] =
00053     { 0, 1, 13, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20 };
00054 
00055 char *tableheads[21] = {
00056         "Last name",    /* 0    */
00057         "First name",   /* 1    */
00058         "Title",        /* 2    (real entry 13)*/
00059         "Company",      /* 3    */
00060         "Phone1",       /* 4    */
00061         "Phone2",       /* 5    */
00062         "Phone3",       /* 6    */
00063         "Phone4",       /* 7    */
00064         "Phone5",       /* 8    */
00065         "Address",      /* 9    */
00066         "City",         /* 10   */
00067         "State",        /* 11   */
00068         "Zip Code",     /* 12   */
00069         "Country",      /* 13   */
00070         "Custom 1",     /* 14   */
00071         "Custom 2",     /* 15   */
00072         "Custom 3",     /* 16   */
00073         "Custom 4",     /* 17   */
00074         "Note",         /* 18   */
00075         "Private",      /* 19   */
00076         "Category"      /* 20   */
00077 };
00078 
00079 int
00080         tabledelim      = term_comma,
00081         augment         = 0,
00082         defaultcategory = 0;
00083 
00084 
00085 
00086 /***********************************************************************
00087  *
00088  * Function:    inchar
00089  *
00090  * Summary:     Turn the protected name back into the "original"
00091  *              characters
00092  *
00093  * Parameters:
00094  *
00095  * Returns:     Modified character, 'c'
00096  *
00097  ***********************************************************************/
00098 int inchar(FILE * in)
00099 {
00100         int     c;      /* switch */
00101 
00102         c = getc(in);
00103         if (c == '\\') {
00104                 c = getc(in);
00105                 switch (c) {
00106                 case 'b':
00107                         c = '\b';
00108                         break;
00109                 case 'f':
00110                         c = '\f';
00111                         break;
00112                 case 'n':
00113                         c = '\n';
00114                         break;
00115                 case 't':
00116                         c = '\t';
00117                         break;
00118                 case 'r':
00119                         c = '\r';
00120                         break;
00121                 case 'v':
00122                         c = '\v';
00123                         break;
00124                 case '\\':
00125                         c = '\\';
00126                         break;
00127                 default:
00128                         ungetc(c, in);
00129                         c = '\\';
00130                         break;
00131                 }
00132         }
00133         return c;
00134 }
00135 
00136 
00137 /***********************************************************************
00138  *
00139  * Function:    read_field
00140  *
00141  * Summary:     Reach each field of the CSV during read_file
00142  *
00143  * Parameters:  dest    <-> Buffer for storing field contents
00144  *              in      --> Inbound filehandle
00145  *              length  --> Size of buffer
00146  *
00147  * Returns:     0 for end of line
00148  *              1 for , termination
00149  *              2 for ; termination
00150  *              3 for \t termination
00151  *             -1 on end of file
00152  *
00153  *              Note that these correspond to indexes in the tabledelims
00154  *              array, and should be preserved.
00155  *
00156  ***********************************************************************/
00157 int read_field(char *dest, FILE *in, size_t length)
00158 {
00159         int     c;
00160 
00161         if (length<=1) return -1;
00162         /* reserve space for trailing NUL */
00163         length--;
00164 
00165         do {    /* Absorb whitespace */
00166                 c = getc(in);
00167                 if(c == '\n') {
00168                         *dest = 0;
00169                         return term_newline;
00170                 }
00171 
00172         } while ((c != EOF) && ((c == ' ') || (c == '\t') || (c == '\r')));
00173 
00174         if (c == '"') {
00175                 c = inchar(in);
00176 
00177                 while (c != EOF) {
00178                         if (c == '"') {
00179                                 c = inchar(in);
00180                                 if (c != '"')
00181                                         break;
00182                         }
00183                         *dest++ = c;
00184                         if (!(--length))
00185                                 break;
00186                         c = inchar(in);
00187                 }
00188         } else {
00189                 while (c != EOF) {
00190                         if ((c == '\n') || (c == tabledelims[tabledelim])) {
00191                                 break;
00192                         }
00193                         *dest++ = c;
00194                         if (!(--length))
00195                                 break;
00196                         c = inchar(in);
00197                 }
00198         }
00199         *dest++ = '\0';
00200 
00201         /* Absorb whitespace */
00202         while ((c != EOF) && ((c == ' ') || (c == '\t')))
00203                 c = getc(in);
00204 
00205         if (c == ',')
00206                 return term_comma;
00207 
00208         else if (c == ';')
00209                 return term_semi;
00210 
00211         else if (c == '\t')
00212                 return term_tab;
00213 
00214         else if (c == EOF)
00215                 return -1;      /* No more */
00216         else
00217                 return term_newline;
00218 }
00219 
00220 
00221 /***********************************************************************
00222  *
00223  * Function:    outchar
00224  *
00225  * Summary:     Protect each of the 'illegal' characters in the output
00226  *
00227  * Parameters:  filehandle
00228  *
00229  * Returns:     Nothing
00230  *
00231  ***********************************************************************/
00232 void outchar(char c, FILE * out)
00233 {
00234                 switch (c) {
00235                 case '"':
00236                         putc('"', out);
00237                         putc('"', out);
00238                         break;
00239                 case '\b':
00240                         putc('\\', out);
00241                         putc('b', out);
00242                         break;
00243                 case '\f':
00244                         putc('\\', out);
00245                         putc('f', out);
00246                         break;
00247                 case '\n':
00248                         putc('\\', out);
00249                         putc('n', out);
00250                         break;
00251                 case '\t':
00252                         putc('\\', out);
00253                         putc('t', out);
00254                         break;
00255                 case '\r':
00256                         putc('\\', out);
00257                         putc('r', out);
00258                         break;
00259                 case '\v':
00260                         putc('\\', out);
00261                         putc('v', out);
00262                         break;
00263                 case '\\':
00264                         putc('\\', out);
00265                         putc('\\', out);
00266                         break;
00267                 default:
00268                         putc(c, out);
00269                         break;
00270                 }
00271 }
00272 
00273 
00274 /***********************************************************************
00275  *
00276  * Function:    write_field
00277  *
00278  * Summary:     Write out each field in the CSV
00279  *
00280  * Parameters:  out    --> output file handle
00281  *              source --> NUL-terminated data to output
00282  *              more   --> delimiter number
00283  *
00284  * Returns:
00285  *
00286  ***********************************************************************/
00287 int write_field(FILE * out, const char *source, enum terminators more)
00288 {
00289         putc('"', out);
00290 
00291         while (*source) {
00292                 outchar(*source, out);
00293                 source++;
00294         }
00295         putc('"', out);
00296 
00297         putc(tabledelims[more], out);
00298         return 0;
00299 }
00300 
00301 
00302 
00303 
00304 /***********************************************************************
00305  *
00306  * Function:    match_phone
00307  *
00308  * Summary:     Find and match the 'phone' entries in 'buf'
00309  *
00310  * Parameters:
00311  *
00312  * Returns:
00313  *
00314  ***********************************************************************/
00315 int match_phone(char *buf, struct AddressAppInfo *aai)
00316 {
00317         int     i;
00318 
00319         for (i = 0; i < 8; i++)
00320                 if (strncasecmp(buf, aai->phoneLabels[i], sizeof(aai->phoneLabels[0])) == 0)
00321                         return i;
00322         return atoi(buf);       /* 0 is default */
00323 }
00324 
00325 
00326 /***********************************************************************
00327  *
00328  * Function:    read_file
00329  *
00330  * Summary:     Open specified file and read into address records
00331  *
00332  * Parameters:  filehandle
00333  *
00334  * Returns:
00335  *
00336  ***********************************************************************/
00337 int read_file(FILE *f, int sd, int db, struct AddressAppInfo *aai)
00338 {
00339         int     i       = -1,
00340                 l,
00341                 attribute,
00342                 category;
00343         char    buf[0xffff];
00344         int showPhone = -1;
00345 
00346         pi_buffer_t *record;
00347 
00348         struct  Address addr;
00349 
00350         int fields = 0; /* Number of fields in this entry */
00351         int count = 0; /* Number of entries read */
00352         const char *progress = "   Reading CSV entries, writing to Palm Address Book... ";
00353 
00354         if (!plu_quiet) {
00355                 printf("%s",progress);
00356                 fflush(stdout);
00357         }
00358 
00359         while (!feof(f)) {
00360                 fields = 0;
00361                 l = getc(f);
00362                 if (feof(f) || (l<0)) {
00363                         break;
00364                 }
00365                 if ('#' == l) {
00366                         /* skip remainder of line */
00367                         while (!feof(f) && (l!='\n') && (l>=0)) {
00368                                 l = getc(f);
00369                         }
00370                         continue;
00371                 } else {
00372                         ungetc(l,f);
00373                 }
00374                 i = read_field(buf, f, sizeof(buf));
00375                 /* fprintf(stderr,"* Field=%s\n",buf); */
00376 
00377                 memset(&addr, 0, sizeof(addr));
00378                 addr.showPhone = 0;
00379                 showPhone = -1; /* None specified this record */
00380 
00381                 if ((i == term_semi) && (tabledelim != term_semi)) {
00382                         /* This is an augmented entry */
00383                         category = plu_findcategory(&aai->category,buf,
00384                                 PLU_CAT_CASE_INSENSITIVE | PLU_CAT_DEFAULT_UNFILED);
00385                         i = read_field(buf, f, sizeof(buf));
00386                         if (i == term_semi) {
00387                                 showPhone = match_phone(buf, aai);
00388                                 i = read_field(buf, f, sizeof(buf));
00389                         }
00390                 } else {
00391                         category = defaultcategory;
00392                 }
00393 
00394                 if (i < 0)
00395                         break;
00396 
00397                 attribute = 0;
00398 
00399                 for (l = 0; (i >= 0) && (l < 21); l++) {
00400                         int l2 = realentry[l];
00401 
00402                         if ((l2 >= 3) && (l2 <= 7)) {
00403                                 if ((i != term_semi) || (tabledelim == term_semi)) {
00404                                         addr.phoneLabel[l2 - 3] = l2 - 3;
00405                                 }
00406                                 else {
00407                                         addr.phoneLabel[l2 - 3] = match_phone(buf, aai);
00408                                         i = read_field(buf, f, sizeof(buf));
00409                                 }
00410                                 if (buf[0]) {
00411                                         addr.entry[l2] = strdup(buf);
00412                                         ++fields;
00413                                 } else {
00414                                         addr.entry[l2] = NULL;
00415                                 }
00416                         } else if (19 <= l2) {
00417                                 if (19 == l2) {
00418                                         attribute = (atoi(buf) ? dlpRecAttrSecret : 0);
00419                                 }
00420                                 if (20 == l2) {
00421                                         category = plu_findcategory(&aai->category,buf,
00422                                                 PLU_CAT_CASE_INSENSITIVE | PLU_CAT_DEFAULT_UNFILED);
00423                                 }
00424                         } else {
00425                                 if (buf[0]) {
00426                                         addr.entry[l2] = strdup(buf);
00427                                         ++fields;
00428                                 } else {
00429                                         addr.entry[l2] = NULL;
00430                                 }
00431 
00432                         }
00433 
00434                         if (i == 0)
00435                                 break;
00436 
00437                         i = read_field(buf, f, sizeof(buf));
00438                 }
00439 
00440 
00441                 while (i > 0) { /* Too many fields in record */
00442                         i = read_field(buf, f, sizeof(buf));
00443                 }
00444 
00445                 if (showPhone >= 0) {
00446                         /* Find which label matches the category to display */
00447                         addr.showPhone = 0;
00448                         for (i=0; i<5; ++i) {
00449                                 if (showPhone == addr.phoneLabel[i]) {
00450                                         addr.showPhone = i;
00451                                         break;
00452                                 }
00453                         }
00454                 }
00455 
00456                 if (fields>0) {
00457                         record = pi_buffer_new(0);
00458                         pack_Address(&addr, record, address_v1);
00459                         dlp_WriteRecord(sd, db, attribute, 0, category,
00460                                         (unsigned char *) record->data, record->used, 0);
00461                         pi_buffer_free(record);
00462                         ++count;
00463                 }
00464                 free_Address(&addr);
00465 
00466                 if (!plu_quiet) {
00467                         printf("\r%s%d",progress,count);
00468                         fflush(stdout);
00469                 }
00470 
00471         }
00472 
00473         if (!plu_quiet) {
00474                 printf("\r%s%d\n   Done.\n",progress,count);
00475                 fflush(stdout);
00476         }
00477         return 0;
00478 }
00479 
00480 
00481 /***********************************************************************
00482  *
00483  * Function:    write_file
00484  *
00485  * Summary:     Writes Address records in CSV format to <file>
00486  *
00487  * Parameters:  filehandle
00488  *
00489  * Returns:     0
00490  *
00491  ***********************************************************************/
00492 
00493 void write_record_CSV(FILE *out, const struct AddressAppInfo *aai, const struct Address *addr, const int attribute, const int category)
00494 {
00495         int j;
00496         char buffer[16];
00497 
00498         if (augment && (category || addr->showPhone)) {
00499                 write_field(out,
00500                                 aai->category.name[category],
00501                                 term_semi);
00502                 write_field(out,
00503                                 aai->phoneLabels[addr->phoneLabel[addr->showPhone]],
00504                                 term_semi);
00505         }
00506 
00507         for (j = 0; j < 19; j++) {
00508                 if (addr->entry[realentry[j]]) {
00509                         if (augment && (j >= 4) && (j <= 8)) {
00510                                 write_field(out,
00511                                                 aai->phoneLabels[addr->phoneLabel
00512                                                                 [j - 4]], term_semi);
00513                         }
00514                         write_field(out, addr->entry[realentry[j]],
00515                                         tabledelim);
00516                 } else {
00517                         write_field(out, "", tabledelim);
00518                 }
00519         }
00520 
00521         snprintf(buffer, sizeof(buffer), "%d", (attribute & dlpRecAttrSecret) ? 1 : 0);
00522         write_field(out, buffer, tabledelim);
00523 
00524         write_field(out,
00525                 aai->category.name[category],
00526                 term_newline);
00527 }
00528 
00529 void write_record_human(struct AddressAppInfo *aai, struct Address *addr, const int category)
00530 {
00531         int i;
00532 
00533         printf("Category: %s\n", aai->category.name[category]);
00534 
00535         for (i = 0; i < 19; i++) {
00536                 if (addr->entry[i]) {
00537                         int l = i;
00538 
00539                         if ((l >= entryPhone1) && (l <= entryPhone5)) {
00540                                 printf("%s: %s\n",
00541                                         aai->phoneLabels[addr->phoneLabel[l - entryPhone1]],
00542                                         addr->entry[i]);
00543                         } else {
00544                                 printf("%s: %s\n", aai->labels[l],
00545                                         addr->entry[i]);
00546                         }
00547                 }
00548         }
00549         printf("\n");
00550 }
00551 
00552 int write_file(FILE *out, int sd, int db, struct AddressAppInfo *aai, int human)
00553 {
00554         int     i,
00555                 j,
00556                 attribute,
00557                 category;
00558         struct  Address addr;
00559         pi_buffer_t *buf;
00560 
00561         int count = 0;
00562         const char *progress = "   Writing Palm Address Book entries to file... ";
00563 
00564         if (!human) {
00565                 /* Print out the header and fields with fields intact. Note we
00566                 'ignore' the last field (Private flag) and print our own here, so
00567                 we don't have to chop off the trailing comma at the end. Hacky. */
00568                 fprintf(out, "# ");
00569                 for (j = 0; j < 21; j++) {
00570                         write_field(out, tableheads[j],
00571                                 j<20 ? tabledelim : term_newline);
00572                 }
00573                 if (augment) {
00574                         fprintf(out,"### This in an augmented (non-standard) CSV file.\n");
00575                 }
00576         }
00577 
00578         if (!plu_quiet) {
00579                 printf("%s",progress);
00580                 fflush(stdout);
00581         }
00582 
00583         buf = pi_buffer_new (0xffff);
00584         for (i = 0;
00585              (j =
00586               dlp_ReadRecordByIndex(sd, db, i, buf, 0,
00587                                     &attribute, &category)) >= 0;
00588              i++) {
00589 
00590 
00591                 if (attribute & dlpRecAttrDeleted)
00592                         continue;
00593                 unpack_Address(&addr, buf, address_v1);
00594 
00595                 if (!human) {
00596                         write_record_CSV(out,aai,&addr,attribute,category);
00597                 } else {
00598                         write_record_human(aai,&addr,category);
00599                 }
00600 
00601 
00602                 ++count;
00603                 if (!plu_quiet) {
00604                         printf("\r%s%d",progress,count);
00605                         fflush(stdout);
00606                 }
00607         }
00608         pi_buffer_free (buf);
00609 
00610         if (!plu_quiet) {
00611                 printf("\r%s%d\n   Done.\n",progress,count);
00612                 fflush(stdout);
00613         }
00614         return 0;
00615 }
00616 
00617 
00618 int main(int argc, const char *argv[])
00619 {
00620 
00621         int     c,                      /* switch */
00622                 db,
00623                 l,
00624                 sd                      = -1;
00625 
00626         enum { mode_none, mode_read, mode_write, mode_delete_all, mode_delete }
00627                 run_mode = mode_none;
00628 
00629         const char
00630                 *progname               = argv[0];
00631 
00632         char    *defaultcategoryname    = 0,
00633                 *deletecategory         = 0,
00634                 *wrFilename             = NULL,
00635                 *rdFilename             = NULL,
00636                 buf[0xffff];
00637 
00638         int writehuman = 0;
00639 
00640         pi_buffer_t *appblock;
00641 
00642         struct  AddressAppInfo  aai;
00643         struct  PilotUser       User;
00644         struct  SysInfo         info;
00645 
00646         poptContext po;
00647 
00648         struct poptOption options[] = {
00649                 USERLAND_RESERVED_OPTIONS
00650                 {"delete-all",   0 , POPT_ARG_NONE, NULL,  mode_delete_all, "Delete all Palm records in all categories", NULL},
00651                 {"delimiter",   't', POPT_ARG_INT,  &tabledelim,          0, "Include category, use delimiter (3=tab, 2=;, 1=,)", "<delimeter>"},
00652                 {"delete-category",     'd', POPT_ARG_STRING, &deletecategory,'d', "Delete old Palm records in <category>", "category"},
00653                 {"category",    'c', POPT_ARG_STRING, &defaultcategoryname, 0, "Category to install to", "category"},
00654                 {"augment",     'a', POPT_ARG_NONE, &augment,             0, "Augment records with additional information", NULL},
00655                 {"read",        'r', POPT_ARG_STRING, &rdFilename, 'r', "Read records from <file> and install them to Palm", "file"},
00656                 {"write",       'w', POPT_ARG_STRING, &wrFilename, 'w', "Get records from Palm and write them to <file>", "file"},
00657                 {"human-readable",'C', POPT_ARG_NONE, &writehuman, 0, "Write generic human-readable output instead of CSV", NULL},
00658                 POPT_TABLEEND
00659         };
00660 
00661         const char *mode_error = "   ERROR: Specify exactly one of read, write, delete or delete all.\n";
00662 
00663         po = poptGetContext("pilot-addresses", argc, argv, options, 0);
00664         poptSetOtherOptionHelp(po,"\n\n"
00665                 "   Reads addresses from a file and installs on the Palm, or\n"
00666                 "   writes addresses from the Palm to a file.\n\n"
00667                 "   Provide exactly one of --read or --write.\n\n");
00668         plu_popt_alias(po,"delall",0,"--bad-option --delete-all");
00669         plu_popt_alias(po,"delcat",0,"--bad-option --delete-category");
00670         plu_popt_alias(po,"install",0,"--bad-option --category");
00671         /* Useful alias */
00672         plu_popt_alias(po,"no-csv",0,"--human-readable");
00673 
00674         if (argc < 2) {
00675                 poptPrintUsage(po,stderr,0);
00676                 return 1;
00677         }
00678 
00679         while ((c = poptGetNextOpt(po)) >= 0) {
00680                 switch (c) {
00681                 /* these are the mode-setters. delete-all does it through
00682                  * popt hooks, since it doesn't take an argument.
00683                  *
00684                  * Special case is that you can mix -w and -d to write the
00685                  * file and then delete a category.
00686                  */
00687                 case mode_delete_all :
00688                         if (run_mode != mode_none) {
00689                                 fprintf(stderr,"%s",mode_error);
00690                                 return 1;
00691                         }
00692                         run_mode = mode_delete_all;
00693                         break;
00694                 case 'r':
00695                         if (run_mode != mode_none) {
00696                                 fprintf(stderr,"%s",mode_error);
00697                                 return 1;
00698                         }
00699                         run_mode = mode_read;
00700                         break;
00701                 case 'w':
00702                         if ((run_mode != mode_none) && (run_mode != mode_delete)) {
00703                                 fprintf(stderr,"%s",mode_error);
00704                                 return 1;
00705                         }
00706                         run_mode = mode_write;
00707                         break;
00708                 case 'd':
00709                         if ((run_mode != mode_none) && (run_mode != mode_write)) {
00710                                 fprintf(stderr,"%s",mode_error);
00711                                 return 1;
00712                         }
00713                         run_mode = mode_delete;
00714                         break;
00715                 default:
00716                         fprintf(stderr,"   ERROR: Unhandled option %d.\n",c);
00717                         return 1;
00718                 }
00719         }
00720 
00721         if (c < -1)
00722                 plu_badoption(po,c);
00723 
00724         if (mode_none == run_mode) {
00725                 fprintf(stderr,"%s",mode_error);
00726                 return 1;
00727         }
00728 
00729         /* The first implies that -t was given; the second that it wasn't,
00730            so use default, and the third if handles weird values. */
00731         if ((tabledelim < 0) || (tabledelim > sizeof(tabledelim))) {
00732                 fprintf(stderr,"   ERROR: Invalid delimiter number %d (use 0-%d).\n",
00733                         tabledelim,(int)(sizeof(tabledelim)));
00734                 return 1;
00735         }
00736 
00737         sd = plu_connect();
00738 
00739         if (sd < 0)
00740                 goto error;
00741 
00742         if (dlp_ReadUserInfo(sd, &User) < 0)
00743                 goto error_close;
00744 
00745         if (dlp_ReadSysInfo(sd,&info) < 0) {
00746                 fprintf(stderr,"   ERROR: Could not read Palm System Information.\n");
00747                 return -1;
00748         }
00749 
00750         if (info.romVersion > 0x05003000) {
00751                 printf("PalmOS 5.x (Garnet) and later devices are not currently supported by this\n"
00752                        "tool. The data format of the AddressBook has changed. The legacy format is\n"
00753                        "called \"Classic\" and PalmOS 5.x and later uses \"Extended\" databases with a\n"
00754                        "different structure. Your Palm has \"Contacts\", and this tool reads the\n"
00755                        "\"AddressBook\" database. (Found: %x)\n\n"
00756 
00757                        "Due to this change, pilot-addresses and other tools must be rewritten to\n"
00758                        "compensate. Sorry about the inconvenience.\n\n", info.romVersion);
00759                 return -1;
00760         }
00761 
00762         /* Open the AddressDB.pdb database, store access handle in db */
00763         if (dlp_OpenDB(sd, 0, 0x80 | 0x40, "AddressDB", &db) < 0) {
00764                 puts("Unable to open AddressDB");
00765                 dlp_AddSyncLogEntry(sd, "Unable to open AddressDB.\n");
00766                 goto error_close;
00767         }
00768 
00769         appblock = pi_buffer_new(0xffff);
00770         l = dlp_ReadAppBlock(sd, db, 0, 0xffff, appblock);
00771         unpack_AddressAppInfo(&aai, appblock->data, l);
00772         pi_buffer_free(appblock);
00773 
00774         if (defaultcategoryname) {
00775                 defaultcategory =
00776                     plu_findcategory(&aai.category,defaultcategoryname,
00777                         PLU_CAT_CASE_INSENSITIVE | PLU_CAT_DEFAULT_UNFILED);
00778         } else {
00779                 defaultcategory = 0;    /* Unfiled */
00780         }
00781 
00782         switch(run_mode) {
00783                 FILE *f;
00784                 int i;
00785                 int old_quiet;
00786         case mode_none:
00787                 /* impossible */
00788                 fprintf(stderr,"%s",mode_error);
00789                 break;
00790         case mode_write:
00791                 /* FIXME - Must test for existing file first! DD 2002/03/18 */
00792                 if (strcmp(wrFilename,"-") == 0) {
00793                         f = stdout;
00794                         old_quiet = plu_quiet;
00795                         plu_quiet = 1;
00796                 } else {
00797                         f = fopen(wrFilename, "w");
00798                 }
00799                 if (f == NULL) {
00800                         sprintf(buf, "%s: %s", progname, wrFilename);
00801                         perror(buf);
00802                         goto error_close;
00803                 }
00804                 write_file(f, sd, db, &aai, writehuman);
00805                 if (f == stdout) {
00806                         plu_quiet = old_quiet;
00807                 }
00808                 if (deletecategory) {
00809                         dlp_DeleteCategory(sd, db,
00810                                 plu_findcategory(&aai.category,deletecategory,PLU_CAT_CASE_INSENSITIVE | PLU_CAT_WARN_UNKNOWN));
00811                 }
00812                 if (f != stdout) {
00813                         fclose(f);
00814                 }
00815                 break;
00816         case mode_read:
00817                 f = fopen(rdFilename, "r");
00818 
00819                 if (f == NULL) {
00820                         fprintf(stderr, "Unable to open input file");
00821                         fprintf(stderr, " '%s' (%s)\n\n",
00822                                 rdFilename, strerror(errno));
00823                         fprintf(stderr, "Please make sure the file");
00824                         fprintf(stderr, "'%s' exists, and that\n",
00825                                 rdFilename);
00826                         fprintf(stderr, "it is readable by this user");
00827                         fprintf(stderr, " before launching.\n\n");
00828 
00829                         goto error_close;
00830                 }
00831                 read_file(f, sd, db, &aai);
00832                 fclose(f);
00833                 break;
00834         case mode_delete:
00835                 i = plu_findcategory (&aai.category,deletecategory,PLU_CAT_CASE_INSENSITIVE | PLU_CAT_WARN_UNKNOWN);
00836                 if (i>=0) {
00837                         dlp_DeleteCategory(sd, db, i);
00838                 }
00839                 break;
00840         case mode_delete_all:
00841                 for (i = 0; i < 16; i++)
00842                         if (aai.category.name[i][0])
00843                                 dlp_DeleteCategory(sd, db, i);
00844                 break;
00845         }
00846 
00847         /* Close the database */
00848         dlp_CloseDB(sd, db);
00849 
00850         /* Tell the user who it is, with a different PC id. */
00851         User.lastSyncPC = 0x00010000;
00852         User.successfulSyncDate = time(NULL);
00853         User.lastSyncDate = User.successfulSyncDate;
00854         dlp_WriteUserInfo(sd, &User);
00855 
00856         if (run_mode == mode_read) {
00857                 dlp_AddSyncLogEntry(sd, "Wrote entries to Palm Address Book.\n");
00858         } else if (run_mode == mode_write) {
00859                 dlp_AddSyncLogEntry(sd, "Successfully read Address Book from Palm.\n");
00860         }
00861 
00862         dlp_EndOfSync(sd, 0);
00863         pi_close(sd);
00864 
00865         return 0;
00866 
00867 error_close:
00868         pi_close(sd);
00869 
00870 error:
00871         return -1;
00872 }
00873 
00874 /* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */
00875 /* ex: set tabstop=4 expandtab: */
00876 /* Local Variables: */
00877 /* indent-tabs-mode: t */
00878 /* c-basic-offset: 8 */
00879 /* End: */

© 1996-2007 by pilot-link.org. All rights reserved.