"Fossies" - the Fresh Open Source Software Archive

Member "jpilot-2_0_1/dat.c" (3 Apr 2021, 35669 Bytes) of package /linux/privat/jpilot-2_0_1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dat.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.8.2_vs_2_0_1.

    1 /*******************************************************************************
    2  * dat.c
    3  * A module of J-Pilot http://jpilot.org
    4  *
    5  * Copyright (C) 2001-2014 by Judd Montgomery
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; version 2 of the License.
   10  *
   11  * This program is distributed in the hope that it will be useful,
   12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  * GNU General Public License for more details.
   15  *
   16  * You should have received a copy of the GNU General Public License
   17  * along with this program; if not, write to the Free Software
   18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   19  ******************************************************************************/
   20 /*
   21  * Thanks to nseessle@mail.hh.provi.de
   22  * http://ourworld.compuserve.com/homepages/nseessle/frames/pilot/dat_e.htm
   23  * http://www.geocities.com/Heartland/Acres/3216/todo_dat.htm
   24  * Scott Leighton helphand@pacbell.net
   25  *
   26  * for their descriptions of the dat formats.
   27  */
   28 
   29 /********************************* Includes ***********************************/
   30 #include "config.h"
   31 #include <stdlib.h>
   32 #include <stdio.h>
   33 #include <string.h>
   34 #include <time.h>
   35 
   36 #include "i18n.h"
   37 #include "utils.h"
   38 #include "log.h"
   39 
   40 /********************************* Constants **********************************/
   41 #define DAT_STATUS_ADD     0x01
   42 #define DAT_STATUS_UPDATE  0x02
   43 #define DAT_STATUS_DELETE  0x04
   44 #define DAT_STATUS_PENDING 0x08
   45 #define DAT_STATUS_ARCHIVE 0x80
   46 /* I made this one up for a bit to store the private flag */
   47 #define DAT_STATUS_PRIVATE 0x10
   48 
   49 /* Repeat types */
   50 #define DAILY           1
   51 #define WEEKLY          2
   52 #define MONTHLY_BY_DAY  3
   53 #define MONTHLY_BY_DATE 4
   54 #define YEARLY_BY_DATE  5
   55 #define YEARLY_BY_DAY   6
   56 
   57 /* DAT field types */
   58 #define DAT_TYPE_INTEGER 1
   59 #define DAT_TYPE_CSTRING 5
   60 #define DAT_TYPE_DATE    3
   61 #define DAT_TYPE_BOOLEAN 6
   62 #define DAT_TYPE_BITFLAG 7
   63 #define DAT_TYPE_REPEAT  8
   64 
   65 /* #define JPILOT_DEBUG */
   66 
   67 /****************************** Prototypes ************************************/
   68 #ifdef JPILOT_DEBUG
   69 static int print_date(int palm_date);
   70 #endif
   71 
   72 struct field {
   73    int type;
   74    int i;
   75    long date;
   76    char *str;
   77 };
   78 
   79 /****************************** Main Code *************************************/
   80 static int x86_short(unsigned char *str)
   81 {
   82    return str[1] * 0x100 + str[0];
   83 }
   84 
   85 static long x86_long(unsigned char *str)
   86 {
   87    return str[3]*0x1000000 + str[2]*0x0010000 + str[1]*0x0000100 + str[0];
   88 }
   89 
   90 /* Returns the length of the CString read */
   91 static int get_CString(FILE *in, char **PStr)
   92 {
   93    unsigned char size1;
   94    unsigned char size2[2];
   95    int size;
   96 
   97    if (fread(&size1, 1, 1, in) < 1) {
   98       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
   99    }
  100    if (size1==0) {
  101       *PStr = NULL;
  102       return 0;
  103    }
  104    if (size1==0xFF) {
  105       if (fread(size2, 2, 1, in) < 1) {
  106          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  107       }
  108       size = x86_short(size2);
  109 #ifdef JPILOT_DEBUG
  110       printf("BIG STRING size=%d\n", size);
  111 #endif
  112    } else {
  113       size=size1;
  114    }
  115    /* malloc an extra byte just to be safe */
  116    *PStr=malloc(size+2);
  117    if (fread(*PStr, size, 1, in) < 1) {
  118       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  119    }
  120    (*PStr)[size]='\0';
  121 
  122    return size;
  123 }
  124 
  125 static int get_categories(FILE *in, struct CategoryAppInfo *ai)
  126 {
  127    unsigned char str_long[4];
  128    char *PStr;
  129    long count;
  130    int i;
  131 
  132    /* Get the category count */
  133    if (fread(str_long, 4, 1, in) < 1) {
  134       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  135    }
  136    count = x86_long(str_long);
  137 
  138    for (i=0; i<16; i++) {
  139       ai->renamed[i]=0;
  140       ai->name[i][0]=0;
  141       ai->ID[i]=0;
  142    }
  143    ai->lastUniqueID=0;
  144 
  145    for (i=0; i<count; i++) {
  146       /* category index */
  147       if (fread(str_long, 4, 1, in) < 1) {
  148          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  149       }
  150 
  151       /* category ID */
  152       if (fread(str_long, 4, 1, in) < 1) {
  153          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  154       }
  155       ai->ID[i] = x86_long(str_long);
  156 
  157       /* category dirty flag */
  158       if (fread(str_long, 4, 1, in) < 1) {
  159          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  160       }
  161 
  162       /* long category name */
  163       get_CString(in, &PStr);
  164       strncpy(ai->name[i], PStr, 16);
  165       ai->name[i][15]='\0';
  166       free(PStr);
  167 
  168       /* short category name */
  169       get_CString(in, &PStr);
  170       free(PStr);
  171    }
  172    return count;
  173 }
  174 
  175 static int get_repeat(FILE *in, struct Appointment *appt)
  176 {
  177    time_t t = 0;
  178    struct tm *now;
  179    unsigned char str_long[4];
  180    unsigned char str_short[2];
  181    int l, s, i, bit;
  182    char *PStr;
  183    int repeat_type;
  184 
  185    if (fread(str_short, 2, 1, in) < 1) {
  186       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  187    }
  188    s = x86_short(str_short);
  189 #ifdef JPILOT_DEBUG
  190    printf("  repeat entry follows:\n");
  191    printf("%d exceptions\n", s);
  192 #endif
  193    if (!appt)
  194       return EXIT_FAILURE;
  195 
  196    appt->exception=NULL;
  197    memset(&(appt->repeatEnd), 0, sizeof(appt->repeatEnd));
  198 
  199    appt->exceptions=s;
  200    if (s>0) {
  201       appt->exception=malloc(sizeof(struct tm) * s);
  202       if (!(appt->exceptions)) {
  203          jp_logf(JP_LOG_WARN, "get_repeat(): %s\n", _("Out of memory"));
  204       }
  205    }
  206 
  207    for (i=0; i<s; i++) {
  208       if (fread(str_long, 4, 1, in) < 1) {
  209          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  210       }
  211       l = x86_long(str_long);
  212       {
  213          t = l;
  214          now = localtime(&t);
  215          memcpy(&(appt->exception[i]), now, sizeof(struct tm));
  216       }
  217 #ifdef JPILOT_DEBUG
  218       printf("date_exception_entry: ");
  219       print_date(l);
  220 #endif
  221    }
  222 
  223    if (fread(str_short, 2, 1, in) < 1) {
  224       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  225    }
  226    s = x86_short(str_short);
  227 #ifdef JPILOT_DEBUG
  228    printf("0x%x repeat event flag\n", s);
  229 #endif
  230 
  231    if (s==0x0000) {
  232       appt->repeatType=calendarRepeatNone;
  233       return EXIT_SUCCESS;
  234    }
  235 
  236    if (s==0xFFFF) {
  237       /* Class entry here */
  238       if (fread(str_short, 2, 1, in) < 1) {
  239          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  240       }
  241       s = x86_short(str_short);
  242 #ifdef JPILOT_DEBUG
  243       printf("constant of 1 = %d\n", s);
  244 #endif
  245       if (fread(str_short, 2, 1, in) < 1) {
  246          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  247       }
  248       s = x86_short(str_short);
  249 #ifdef JPILOT_DEBUG
  250       printf("class name length = %d\n", s);
  251 #endif
  252 
  253       PStr = malloc(s+1);
  254       if (fread(PStr, s, 1, in) < 1) {
  255          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  256       }
  257       PStr[s]='\0';
  258 #ifdef JPILOT_DEBUG
  259       printf("class = [%s]\n", PStr);
  260 #endif
  261       free(PStr);
  262    }
  263 
  264    if (fread(str_long, 4, 1, in) < 1) {
  265       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  266    }
  267    repeat_type = x86_long(str_long);
  268    appt->repeatType=repeat_type;
  269 #ifdef JPILOT_DEBUG
  270    printf("repeatType=%d ", repeat_type);
  271    switch (repeat_type) {
  272     case DAILY:
  273       printf("Daily\n");
  274       break;
  275     case WEEKLY:
  276       printf("Weekly\n");
  277       break;
  278     case MONTHLY_BY_DAY:
  279       printf("MonthlyByDay\n");
  280       break;
  281     case MONTHLY_BY_DATE:
  282       printf("Monthly By Date\n");
  283       break;
  284     case YEARLY_BY_DATE:
  285       printf("Yearly By Date\n");
  286       break;
  287     case YEARLY_BY_DAY:
  288       printf("Yearly By Day\n");
  289       break;
  290     default:
  291       printf("unknown repeat type %d\n", l);
  292    }
  293 #endif
  294 
  295    if (fread(str_long, 4, 1, in) < 1) {
  296       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  297    }
  298    l = x86_long(str_long);
  299 #ifdef JPILOT_DEBUG
  300    printf("Interval = %d\n", l);
  301 #endif
  302    appt->repeatFrequency=l;
  303 
  304    if (fread(str_long, 4, 1, in) < 1) {
  305       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  306    }
  307    l = x86_long(str_long);
  308    {
  309       t = l;
  310       now = localtime(&t);
  311       memcpy(&(appt->repeatEnd), now, sizeof(struct tm));
  312    }
  313    if (t==0x749e77bf) {
  314       appt->repeatForever=TRUE;
  315    } else {
  316       appt->repeatForever=FALSE;
  317    }
  318 #ifdef JPILOT_DEBUG
  319    printf("repeatEnd: 0x%x -> ", l); print_date(l);
  320 #endif
  321    if (fread(str_long, 4, 1, in) < 1) {
  322       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  323    }
  324    l = x86_long(str_long);
  325    appt->repeatWeekstart=l;
  326 #ifdef JPILOT_DEBUG
  327    printf("First Day of Week = %d\n", l);
  328 #endif
  329 
  330    switch (repeat_type) {
  331     case DAILY:
  332       if (fread(str_long, 4, 1, in) < 1) {
  333          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  334       }
  335       l = x86_long(str_long);
  336 #ifdef JPILOT_DEBUG
  337       printf("Day Index = %d\n", l);
  338 #endif
  339       break;
  340     case WEEKLY:
  341       if (fread(str_long, 4, 1, in) < 1) {
  342          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  343       }
  344       l = x86_long(str_long);
  345 #ifdef JPILOT_DEBUG
  346       printf("Day Index = %d\n", l);
  347 #endif
  348 
  349       if (fread(str_long, 1, 1, in) < 1) {
  350          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  351       }
  352       for (i=0, bit=1; i<7; i++, bit=bit<<1) {
  353          appt->repeatDays[i]=( str_long[0] & bit );
  354       }
  355 #ifdef JPILOT_DEBUG
  356       printf("Days Mask = %x\n", str_long[0]);
  357 #endif
  358       break;
  359     case MONTHLY_BY_DAY:
  360       if (fread(str_long, 4, 1, in) < 1) {
  361          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  362       }
  363       s = x86_long(str_long);
  364 #ifdef JPILOT_DEBUG
  365       printf("Day Index = %d\n", l);
  366 #endif
  367 
  368       if (fread(str_long, 4, 1, in) < 1) {
  369          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  370       }
  371       l = x86_long(str_long);
  372 #ifdef JPILOT_DEBUG
  373       printf("Week Index = %d\n", l);
  374 #endif
  375 
  376       appt->repeatDay = 7*l + s;
  377       break;
  378     case MONTHLY_BY_DATE:
  379       if (fread(str_long, 4, 1, in) < 1) {
  380          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  381       }
  382       l = x86_long(str_long);
  383 #ifdef JPILOT_DEBUG
  384       printf("Day Number = %d\n", l);
  385 #endif
  386       break;
  387     case YEARLY_BY_DATE:
  388       if (fread(str_long, 4, 1, in) < 1) {
  389          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  390       }
  391       l = x86_long(str_long);
  392 #ifdef JPILOT_DEBUG
  393       printf("Day Number = %d\n", l);
  394 #endif
  395       if (fread(str_long, 4, 1, in) < 1) {
  396          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  397       }
  398       l = x86_long(str_long);
  399 #ifdef JPILOT_DEBUG
  400       printf("Month Index = %d\n", l);
  401 #endif
  402       break;
  403     case YEARLY_BY_DAY:
  404       break;
  405     default:
  406 #ifdef JPILOT_DEBUG
  407       printf("unknown repeat type2 %d\n", l);
  408 #endif
  409       break;
  410    }
  411 
  412    return EXIT_SUCCESS;
  413 }
  414 
  415 #ifdef JPILOT_DEBUG
  416 static int print_date(int palm_date)
  417 {
  418    time_t t;
  419    struct tm *now;
  420    char text[256];
  421 
  422    t = palm_date;   /* - 20828448800; */
  423    now = localtime(&t);
  424    strftime(text, sizeof(text), "%02m/%02d/%Y %02H:%02M:%02S", now);
  425    printf("%s\n", text);
  426 
  427    return EXIT_SUCCESS;
  428 }
  429 #endif
  430 
  431 #ifdef JPILOT_DEBUG
  432 static int print_field(struct field *f)
  433 {
  434 
  435    switch (f->type) {
  436     case DAT_TYPE_INTEGER:
  437       printf("%d\n", f->i);
  438       break;
  439     case DAT_TYPE_CSTRING:
  440       if (f->str)
  441          printf("%s\n", f->str);
  442       else
  443          printf("\n");
  444       break;
  445     case DAT_TYPE_BOOLEAN:
  446       if (f->i) {
  447          printf("True\n");
  448       } else {
  449          printf("False\n");
  450       }
  451       break;
  452     case DAT_TYPE_DATE:
  453       print_date(f->date);
  454       break;
  455     case DAT_TYPE_REPEAT:
  456       printf("Repeat Type\n");
  457       break;
  458     default:
  459       printf("print_field: unknown type = %d\n", f->type);
  460       break;
  461    }
  462 
  463    return EXIT_SUCCESS;
  464 }
  465 #endif
  466 
  467 static int get_field(FILE *in, struct field *f)
  468 {
  469    unsigned char str_long[4];
  470    long type;
  471    char *PStr;
  472 
  473    if (fread(str_long, 4, 1, in) < 1) {
  474       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  475    }
  476    type = x86_long(str_long);
  477    f->type=type;
  478    f->str=NULL;
  479 
  480    switch (type) {
  481     case DAT_TYPE_INTEGER:
  482       if (fread(str_long, 4, 1, in) < 1) {
  483          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  484       }
  485       f->i = x86_long(str_long);
  486       break;
  487     case DAT_TYPE_CSTRING:
  488       fseek(in, 4, SEEK_CUR); /* padding */
  489       get_CString(in, &PStr);
  490       f->str = PStr;
  491       break;
  492     case DAT_TYPE_BOOLEAN:
  493       if (fread(str_long, 4, 1, in) < 1) {
  494          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  495       }
  496       f->i = x86_long(str_long);
  497       break;
  498     case DAT_TYPE_DATE:
  499       if (fread(str_long, 4, 1, in) < 1) {
  500          jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  501       }
  502       f->date = x86_long(str_long);
  503       break;
  504     case DAT_TYPE_BITFLAG:
  505       /* I currently do not know how to read this datatype */
  506       break;
  507     case DAT_TYPE_REPEAT:
  508       /* The calling function needs to call this */
  509       /* get_repeat(in, NULL); */
  510       break;
  511     default:
  512       jp_logf(JP_LOG_WARN, "get_field(): %s %ld\n", _("unknown type ="), type);
  513       break;
  514    }
  515 
  516    return EXIT_SUCCESS;
  517 }
  518 
  519 int dat_check_if_dat_file(FILE *in)
  520 {
  521    char version[6];
  522 
  523    memset(version, 0, sizeof(version));
  524    fseek(in, 0, SEEK_SET);
  525    /* Version */
  526    if (fread(version, 4, 1, in) < 1) {
  527       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  528    }
  529    fseek(in, 0, SEEK_SET);
  530    jp_logf(JP_LOG_DEBUG, "dat_check_if_dat_file(): version = [%c%c%d%d]\n", version[3],version[2],version[1],version[0]);
  531    if ((version[3]=='D') && (version[2]=='B') &&
  532        (version[1]==1) && (version[0]==0)) {
  533       return DAT_DATEBOOK_FILE;
  534    }
  535    if ((version[3]=='A') && (version[2]=='B') &&
  536        (version[1]==1) && (version[0]==0)) {
  537       return DAT_ADDRESS_FILE;
  538    }
  539    if ((version[3]=='T') && (version[2]=='D') &&
  540        (version[1]==1) && (version[0]==0)) {
  541       return DAT_TODO_FILE;
  542    }
  543    if ((version[3]=='M') && (version[2]=='P') &&
  544        (version[1]==1) && (version[0]==0)) {
  545       return DAT_MEMO_FILE;
  546    }
  547    return EXIT_SUCCESS;
  548 }
  549 
  550 static int dat_read_header(FILE *in,
  551                            int expected_field_count,
  552                            char *schema,
  553                            struct CategoryAppInfo *ai,
  554                            int *schema_count, int *field_count, long *rec_count)
  555 {
  556    int i;
  557    unsigned char filler[100];
  558    char version[4];
  559    char *PStr;
  560    unsigned char str_long[4];
  561 
  562    fseek(in, 0, SEEK_SET);
  563 
  564    /* Version */
  565    if (fread(version, 4, 1, in) < 1) {
  566       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  567    }
  568    jp_logf(JP_LOG_DEBUG, "version = [%c%c%d%d]\n", version[3],version[2],version[1],version[0]);
  569 
  570    /* Full file path name */
  571    get_CString(in, &PStr);
  572    jp_logf(JP_LOG_DEBUG, "path:[%s]\n",PStr);
  573    free(PStr);
  574 
  575    /* Show Header */
  576    get_CString(in, &PStr);
  577    jp_logf(JP_LOG_DEBUG, "show header:[%s]\n",PStr);
  578    free(PStr);
  579 
  580    /* Next free category ID */
  581    if (fread(filler, 4, 1, in) < 1) {
  582       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  583    }
  584 
  585    /* Categories */
  586    get_categories(in, ai);
  587 #ifdef JPILOT_DEBUG
  588    for (i=0; i<16; i++) {
  589       printf("%d [%s]\n", ai->ID[i], ai->name[i]);
  590    }
  591 #endif
  592 
  593    /* Schema resource ID */
  594    if (fread(filler, 4, 1, in) < 1) {
  595       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  596    }
  597    /* Schema fields per row */
  598    if (fread(filler, 4, 1, in) < 1) {
  599       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  600    }
  601    *field_count=x86_long(filler);
  602    if (*field_count != expected_field_count) {
  603       jp_logf(JP_LOG_WARN, _("fields per row count != %d, unknown format\n"),
  604                   expected_field_count);
  605       return EXIT_FAILURE;
  606    }
  607    /* Schema record ID position */
  608    if (fread(filler, 4, 1, in) < 1) {
  609       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  610    }
  611    /* Schema record status position */
  612    if (fread(filler, 4, 1, in) < 1) {
  613       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  614    }
  615    /* Schema placement position */
  616    if (fread(filler, 4, 1, in) < 1) {
  617       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  618    }
  619    /* Schema fields count */
  620    if (fread(filler, 2, 1, in) < 1) {
  621       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  622    }
  623    *field_count = x86_short(filler);
  624    if (*field_count != expected_field_count) {
  625       jp_logf(JP_LOG_WARN, _("field count != %d, unknown format\n"),
  626                   expected_field_count);
  627       return EXIT_FAILURE;
  628    }
  629 
  630    /* Schema fields */
  631    if (fread(filler, (*field_count)*2, 1, in) < 1) {
  632       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  633    }
  634    if (memcmp(filler, schema, (*field_count)*2)) {
  635       jp_logf(JP_LOG_WARN, _("Unknown format, file has wrong schema\n"));
  636       jp_logf(JP_LOG_WARN, _("File schema is:"));
  637       for (i=0; i<(*field_count)*2; i++) {
  638          jp_logf(JP_LOG_WARN, " %02d\n", (char)filler[i]);
  639       }
  640       jp_logf(JP_LOG_WARN, _("It should be:"));
  641       for (i=0; i<(*field_count)*2; i++) {
  642          jp_logf(JP_LOG_WARN, " %02d\n", (char)schema[i]);
  643       }
  644       return EXIT_FAILURE;
  645    }
  646 
  647    /* Get record count */
  648    if (fread(str_long, 4, 1, in) < 1) {
  649       jp_logf(JP_LOG_WARN, "fread failed %s %d\n", __FILE__, __LINE__);
  650    }
  651    if ((*field_count)) {
  652       *rec_count = x86_long(str_long) / (*field_count);
  653    }
  654 #ifdef JPILOT_DEBUG
  655    printf("Record Count = %ld\n", *rec_count);
  656 #endif
  657    return EXIT_SUCCESS;
  658 }
  659 
  660 
  661 int dat_get_appointments(FILE *in, AppointmentList **alist, 
  662                          struct CategoryAppInfo *ai)
  663 {
  664 #ifdef JPILOT_DEBUG
  665    struct field hack_f;
  666 #endif
  667    int ret, i, j;
  668    struct field fa[28];
  669    int schema_count, field_count;
  670    long rec_count;
  671    AppointmentList *temp_alist;
  672    AppointmentList *last_alist;
  673    time_t t;
  674    struct tm *now;
  675    /* Should be 1, 1, 1, 3, 1, 5, 1, 5, 6, 6, 1, 6, 1, 1, 8 */
  676    char schema[30]={
  677       DAT_TYPE_INTEGER,0,
  678       DAT_TYPE_INTEGER,0,
  679       DAT_TYPE_INTEGER,0,
  680       DAT_TYPE_DATE,0,
  681       DAT_TYPE_INTEGER,0,
  682       DAT_TYPE_CSTRING,0,
  683       DAT_TYPE_INTEGER,0,
  684       DAT_TYPE_CSTRING,0,
  685       DAT_TYPE_BOOLEAN,0,
  686       DAT_TYPE_BOOLEAN,0,
  687       DAT_TYPE_INTEGER,0,
  688       DAT_TYPE_BOOLEAN,0,
  689       DAT_TYPE_INTEGER,0,
  690       DAT_TYPE_INTEGER,0,
  691       DAT_TYPE_REPEAT,0
  692    };
  693 #ifdef JPILOT_DEBUG
  694    char *rec_fields[]={
  695       "Record ID",
  696       "Status field",
  697       "Position"
  698    };
  699    char *field_names[]={
  700       "Start Time",
  701       "End Time",
  702       "Description",
  703       "Duration",
  704       "Note",
  705       "Untimed",
  706       "Private",
  707       "Category",
  708       "Alarm Set",
  709       "Alarm Advance Units",
  710       "Alarm Advance Type",
  711       "Repeat Event"
  712    };
  713 #endif
  714 
  715    jp_logf(JP_LOG_DEBUG, "dat_get_appointments\n");
  716 
  717    if (!alist) return EXIT_SUCCESS;
  718    *alist=NULL;
  719 
  720    ret = dat_read_header(in, 15, schema, ai,
  721                          &schema_count, &field_count, &rec_count);
  722 
  723    if (ret<0) return ret;
  724 
  725    /* Get records */
  726    last_alist=*alist;
  727 #ifdef JPILOT_DEBUG
  728    printf("---------- Records ----------\n");
  729 #endif
  730    for (i=0; i<rec_count; i++) {
  731       temp_alist = malloc(sizeof(AppointmentList));
  732       if (!temp_alist) {
  733          jp_logf(JP_LOG_WARN, "dat_get_appointments(): %s\n", _("Out of memory"));
  734          return i;
  735       }
  736 #ifdef JPILOT_DEBUG
  737       printf("----- record %d -----\n", i+1);
  738 #endif
  739       memset(&(temp_alist->mappt.appt), 0, sizeof(temp_alist->mappt.appt));
  740       temp_alist->next=NULL;
  741       temp_alist->app_type=DATEBOOK;
  742 
  743       /* Record ID */
  744       /* Status Field */
  745       /* Position */
  746       for (j=0; j<3; j++) {
  747          get_field(in, &(fa[j]));
  748 #ifdef JPILOT_DEBUG
  749          printf("rec field %d %s: ", j, rec_fields[j]); print_field(&(fa[j]));
  750 #endif
  751          if (fa[j].type!=schema[j*2]) {
  752             jp_logf(JP_LOG_WARN, _("%s:%d Record %d, field %d: Invalid type.  Expected %d, found %d\n"), __FILE__, __LINE__, i+1, j+3, schema[j*2], fa[j].type);
  753             jp_logf(JP_LOG_WARN, _("read of file terminated\n"));
  754             free(temp_alist);
  755             return EXIT_FAILURE;
  756          }
  757       }
  758       /* Get Fields */
  759       for (j=0; j<12; j++) {
  760          get_field(in, &(fa[j]));
  761 #ifdef JPILOT_DEBUG
  762          printf("field %d %s: ", j, field_names[j]); print_field(&(fa[j]));
  763          if (j==1) {
  764             hack_f.type=DAT_TYPE_DATE;
  765             hack_f.date=fa[j].i;
  766             printf("        "); print_field(&hack_f);
  767          }
  768 #endif
  769          if (fa[j].type!=schema[j*2+6]) {
  770             jp_logf(JP_LOG_WARN, _("%s:%d Record %d, field %d: Invalid type.  Expected %d, found %d\n"), __FILE__, __LINE__, i+1, j+3, schema[j*2+6], fa[j].type);
  771             jp_logf(JP_LOG_WARN, _("read of file terminated\n"));
  772             free(temp_alist);
  773             return EXIT_FAILURE;
  774          }
  775          if (fa[j].type==DAT_TYPE_REPEAT) {
  776             get_repeat(in, &(temp_alist->mappt.appt));
  777          }
  778       }
  779       /* Start Time */
  780       t = fa[0].date;
  781       now = localtime(&t);
  782       memcpy(&(temp_alist->mappt.appt.begin), now, sizeof(struct tm));
  783       /* End Time */
  784       t = fa[1].i;
  785       now = localtime(&t);
  786       memcpy(&(temp_alist->mappt.appt.end), now, sizeof(struct tm));
  787       /* Description */
  788       if (fa[2].str) {
  789          temp_alist->mappt.appt.description=fa[2].str;
  790       } else {
  791          temp_alist->mappt.appt.description=strdup("");
  792       }
  793       /* Duration */
  794       /* what is duration? (repeatForever?) */
  795 
  796       /* Note */
  797       if (fa[4].str) {
  798          temp_alist->mappt.appt.note=fa[4].str;
  799       } else {
  800          temp_alist->mappt.appt.note=strdup("");
  801       }
  802       /* Untimed */
  803       temp_alist->mappt.appt.event=fa[5].i;
  804       /* Private */
  805       temp_alist->mappt.attrib = 0;
  806       if (fa[6].i) {
  807          temp_alist->mappt.attrib |= DAT_STATUS_PRIVATE;
  808       }
  809       /* Category */
  810       temp_alist->mappt.unique_id = fa[7].i;
  811       if (temp_alist->mappt.unique_id > 15) {
  812          temp_alist->mappt.unique_id = 15;
  813       }
  814       if (temp_alist->mappt.unique_id < 0) {
  815          temp_alist->mappt.unique_id = 0;
  816       }
  817       /* Alarm Set */
  818       temp_alist->mappt.appt.alarm=fa[8].i;
  819       /* Alarm Advance Units */
  820       temp_alist->mappt.appt.advance=fa[9].i;
  821       /* Alarm Advance Type */
  822       temp_alist->mappt.appt.advanceUnits=fa[10].i;
  823 
  824       /* Append onto the end of the list */
  825       if (last_alist) {
  826          last_alist->next=temp_alist;
  827          last_alist=temp_alist;
  828       } else {
  829          last_alist=temp_alist;
  830          *alist=last_alist;
  831       }
  832    }
  833    return EXIT_SUCCESS;
  834 }
  835 
  836 int dat_get_addresses(FILE *in, AddressList **addrlist, 
  837                       struct CategoryAppInfo *ai)
  838 {
  839    int ret, i, j, k;
  840    struct field fa[28];
  841    int schema_count, field_count;
  842    long rec_count;
  843    AddressList *temp_addrlist;
  844    AddressList *last_addrlist;
  845    int dat_order[19]={
  846       0,1,3,5,7,9,11,13,14,15,16,17,18,2,22,23,24,25,19
  847    };
  848    /* Should be 1, 1, 1, 5, 5, 5, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5,
  849       5, 5, 5, 5, 5, 5, 6, 1, 5, 5, 5, 5, 1 */
  850    char schema[60]={
  851       DAT_TYPE_INTEGER,0,
  852       DAT_TYPE_INTEGER,0,
  853       DAT_TYPE_INTEGER,0,
  854       DAT_TYPE_CSTRING,0,
  855       DAT_TYPE_CSTRING,0,
  856       DAT_TYPE_CSTRING,0,
  857       DAT_TYPE_CSTRING,0,
  858       DAT_TYPE_INTEGER,0,
  859       DAT_TYPE_CSTRING,0,
  860       DAT_TYPE_INTEGER,0,
  861       DAT_TYPE_CSTRING,0,
  862       DAT_TYPE_INTEGER,0,
  863       DAT_TYPE_CSTRING,0,
  864       DAT_TYPE_INTEGER,0,
  865       DAT_TYPE_CSTRING,0,
  866       DAT_TYPE_INTEGER,0,
  867       DAT_TYPE_CSTRING,0,
  868       DAT_TYPE_CSTRING,0,
  869       DAT_TYPE_CSTRING,0,
  870       DAT_TYPE_CSTRING,0,
  871       DAT_TYPE_CSTRING,0,
  872       DAT_TYPE_CSTRING,0,
  873       DAT_TYPE_CSTRING,0,
  874       DAT_TYPE_BOOLEAN,0,
  875       DAT_TYPE_INTEGER,0,
  876       DAT_TYPE_CSTRING,0,
  877       DAT_TYPE_CSTRING,0,
  878       DAT_TYPE_CSTRING,0,
  879       DAT_TYPE_CSTRING,0,
  880       DAT_TYPE_INTEGER,0
  881    };
  882 #ifdef JPILOT_DEBUG
  883    char *rec_fields[]={
  884       "Record ID",
  885       "Status field",
  886       "Position"
  887    };
  888    char *field_names[]={
  889       "Last Name",
  890       "First Name",
  891       "Title",
  892       "Company",
  893       "Phone1 Label",
  894       "Phone1",
  895       "Phone2 Label",
  896       "Phone2",
  897       "Phone3 Label",
  898       "Phone3",
  899       "Phone4 Label",
  900       "Phone4",
  901       "Phone5 Label",
  902       "Phone5",
  903       "Address",
  904       "City",
  905       "State",
  906       "Zip",
  907       "Country",
  908       "Note",
  909       "Private",
  910       "Category",
  911       "Custom1",
  912       "Custom2",
  913       "Custom3",
  914       "Custom4",
  915       "Display Phone"
  916    };
  917 #endif
  918 
  919    jp_logf(JP_LOG_DEBUG, "dat_get_addresses\n");
  920 
  921    if (!addrlist) return EXIT_SUCCESS;
  922    *addrlist=NULL;
  923 
  924    ret = dat_read_header(in, 30, schema, ai,
  925                          &schema_count, &field_count, &rec_count);
  926 
  927    if (ret<0) return ret;
  928 
  929    /* Get records */
  930    last_addrlist=*addrlist;
  931 #ifdef JPILOT_DEBUG
  932    printf("---------- Records ----------\n");
  933 #endif
  934    for (i=0; i<rec_count; i++) {
  935       temp_addrlist = malloc(sizeof(AddressList));
  936       if (!temp_addrlist) {
  937          jp_logf(JP_LOG_WARN, "dat_get_addresses(): %s\n", _("Out of memory"));
  938          return i;
  939       }
  940       temp_addrlist->next=NULL;
  941       temp_addrlist->app_type=ADDRESS;
  942 #ifdef JPILOT_DEBUG
  943       printf("----- record %d -----\n", i+1);
  944 #endif
  945       /* Record ID */
  946       /* Status Field */
  947       /* Position */
  948       for (j=0; j<3; j++) {
  949          get_field(in, &(fa[j]));
  950 #ifdef JPILOT_DEBUG
  951          printf("rec field %d %s: ", j, rec_fields[j]); print_field(&(fa[j]));
  952 #endif
  953          if (fa[j].type!=schema[j*2]) {
  954             jp_logf(JP_LOG_WARN, _("%s:%d Record %d, field %d: Invalid type.  Expected %d, found %d\n"), __FILE__, __LINE__, i+1, j+3, schema[j*2], fa[j].type);
  955             jp_logf(JP_LOG_WARN, _("read of file terminated\n"));
  956             free(temp_addrlist);
  957             return EXIT_FAILURE;
  958          }
  959       }
  960       /* Get Fields */
  961       for (j=0; j<27; j++) {
  962          get_field(in, &(fa[j]));
  963 #ifdef JPILOT_DEBUG
  964          printf("field %d %s: ", j, field_names[j]); print_field(&(fa[j]));
  965 #endif
  966          if (fa[j].type!=schema[j*2+6]) {
  967             jp_logf(JP_LOG_WARN, _("%s:%d Record %d, field %d: Invalid type.  Expected %d, found %d\n"), __FILE__, __LINE__, i+1, j+3, schema[j*2+6], fa[j].type);
  968             jp_logf(JP_LOG_WARN, _("read of file terminated\n"));
  969             free(temp_addrlist);
  970             return EXIT_FAILURE;
  971          }
  972       }
  973       for (k=0; k<19; k++) {
  974          temp_addrlist->maddr.addr.entry[k]=fa[dat_order[k]].str;
  975       }
  976       temp_addrlist->maddr.addr.phoneLabel[0] = fa[4].i;
  977       temp_addrlist->maddr.addr.phoneLabel[1] = fa[6].i;
  978       temp_addrlist->maddr.addr.phoneLabel[2] = fa[8].i;
  979       temp_addrlist->maddr.addr.phoneLabel[3] = fa[10].i;
  980       temp_addrlist->maddr.addr.phoneLabel[4] = fa[12].i;
  981       /* Private */
  982       temp_addrlist->maddr.attrib = 0;
  983       if (fa[20].i) {
  984          temp_addrlist->maddr.attrib |= DAT_STATUS_PRIVATE;
  985       }
  986       /* Category */
  987       temp_addrlist->maddr.unique_id = fa[21].i;
  988       if (temp_addrlist->maddr.unique_id > 15) {
  989          temp_addrlist->maddr.unique_id = 15;
  990       }
  991       if (temp_addrlist->maddr.unique_id < 0) {
  992          temp_addrlist->maddr.unique_id = 0;
  993       }
  994       /* Show phone in list */
  995       temp_addrlist->maddr.addr.showPhone = fa[26].i - 1;
  996       for (k=0; k<19; k++) {
  997          if (temp_addrlist->maddr.addr.entry[k]==NULL) {
  998             temp_addrlist->maddr.addr.entry[k]=strdup("");
  999          }
 1000       }
 1001       /* Append onto the end of the list */
 1002       if (last_addrlist) {
 1003          last_addrlist->next=temp_addrlist;
 1004          last_addrlist=temp_addrlist;
 1005       } else {
 1006          last_addrlist=temp_addrlist;
 1007          *addrlist=last_addrlist;
 1008       }
 1009    }
 1010    return EXIT_SUCCESS;
 1011 }
 1012 
 1013 int dat_get_todos(FILE *in, ToDoList **todolist, struct CategoryAppInfo *ai)
 1014 {
 1015    int ret, i, j;
 1016    struct field fa[10];
 1017    int schema_count, field_count;
 1018    long rec_count;
 1019    time_t t;
 1020    struct tm *now;
 1021    ToDoList *temp_todolist;
 1022    ToDoList *last_todolist;
 1023    /* Should be 1, 1, 1, 5, 3, 6, 1, 6, 1, 5 */
 1024    char schema[20]={
 1025       DAT_TYPE_INTEGER,0,
 1026       DAT_TYPE_INTEGER,0,
 1027       DAT_TYPE_INTEGER,0,
 1028       DAT_TYPE_CSTRING,0,
 1029       DAT_TYPE_DATE,0,
 1030       DAT_TYPE_BOOLEAN,0,
 1031       DAT_TYPE_INTEGER,0,
 1032       DAT_TYPE_BOOLEAN,0,
 1033       DAT_TYPE_INTEGER,0,
 1034       DAT_TYPE_CSTRING,0
 1035    };
 1036 #ifdef JPILOT_DEBUG
 1037    char *rec_fields[]={
 1038       "Record ID",
 1039       "Status field",
 1040       "Position"
 1041    };
 1042    char *field_names[]={
 1043       "Description",
 1044       "Due Date",
 1045       "Completed",
 1046       "Priority",
 1047       "Private",
 1048       "Category",
 1049       "Note"
 1050    };
 1051 #endif
 1052 
 1053    jp_logf(JP_LOG_DEBUG, "dat_get_todos\n");
 1054 
 1055    if (!todolist) return EXIT_SUCCESS;
 1056    *todolist=NULL;
 1057 
 1058    ret = dat_read_header(in, 10, schema, ai,
 1059                          &schema_count, &field_count, &rec_count);
 1060 
 1061    if (ret<0) return ret;
 1062 
 1063    /* Get records */
 1064    last_todolist=*todolist;
 1065 #ifdef JPILOT_DEBUG
 1066    printf("---------- Records ----------\n");
 1067 #endif
 1068    for (i=0; i<rec_count; i++) {
 1069       temp_todolist = malloc(sizeof(ToDoList));
 1070       if (!temp_todolist) {
 1071          jp_logf(JP_LOG_WARN, "dat_get_todos(): %s\n", _("Out of memory"));
 1072          jp_logf(JP_LOG_WARN, _("read of file terminated\n"));
 1073          free(temp_todolist);
 1074          return i;
 1075       }
 1076       temp_todolist->next=NULL;
 1077       temp_todolist->app_type=TODO;
 1078 #ifdef JPILOT_DEBUG
 1079       printf("----- record %d -----\n", i+1);
 1080 #endif
 1081       /* Record ID */
 1082       /* Status Field */
 1083       /* Position */
 1084       for (j=0; j<3; j++) {
 1085          get_field(in, &(fa[j]));
 1086 #ifdef JPILOT_DEBUG
 1087          printf("rec field %d %s: ", j, rec_fields[j]); print_field(&(fa[j]));
 1088 #endif
 1089          if (fa[j].type!=schema[j*2]) {
 1090             jp_logf(JP_LOG_WARN, _("%s:%d Record %d, field %d: Invalid type.  Expected %d, found %d\n"), __FILE__, __LINE__, i+1, j+3, schema[j*2], fa[j].type);
 1091             jp_logf(JP_LOG_WARN, _("read of file terminated\n"));
 1092             free(temp_todolist);
 1093             return EXIT_FAILURE;
 1094          }
 1095       }
 1096       /* Get Fields */
 1097       for (j=0; j<7; j++) {
 1098          get_field(in, &(fa[j]));
 1099 #ifdef JPILOT_DEBUG
 1100          printf("field %d %s: ", j, field_names[j]); print_field(&(fa[j]));
 1101 #endif
 1102          if (fa[j].type!=schema[j*2+6]) {
 1103             jp_logf(JP_LOG_WARN, _("%s:%d Record %d, field %d: Invalid type.  Expected %d, found %d\n"), __FILE__, __LINE__, i+1, j+3, schema[j*2+6], fa[j].type);
 1104             jp_logf(JP_LOG_WARN, _("read of file terminated\n"));
 1105             free(temp_todolist);
 1106             return EXIT_FAILURE;
 1107          }
 1108       }
 1109       /* Description */
 1110       if (fa[0].str) {
 1111          temp_todolist->mtodo.todo.description=fa[0].str;
 1112       } else {
 1113          temp_todolist->mtodo.todo.description=strdup("");
 1114       }
 1115       /* Due Date */
 1116       if (fa[1].date==0x749E77BF) {
 1117          temp_todolist->mtodo.todo.indefinite=1;
 1118          memset(&(temp_todolist->mtodo.todo.due), 0, sizeof(temp_todolist->mtodo.todo.due));
 1119       } else {
 1120          t = fa[1].date;
 1121          now = localtime(&t);
 1122          memcpy(&(temp_todolist->mtodo.todo.due), now, sizeof(struct tm));
 1123          temp_todolist->mtodo.todo.indefinite=0;
 1124       }
 1125       /* Completed */
 1126       temp_todolist->mtodo.todo.complete = (fa[2].i==0) ? 0 : 1;
 1127       /* Priority */
 1128       if (fa[3].i < 0) fa[3].i=0;
 1129       if (fa[3].i > 5) fa[3].i=5;
 1130       temp_todolist->mtodo.todo.priority = fa[3].i;
 1131       /* Private */
 1132       temp_todolist->mtodo.attrib = 0;
 1133       if (fa[4].i) {
 1134          temp_todolist->mtodo.attrib |= DAT_STATUS_PRIVATE;
 1135       }
 1136       /* Category */
 1137       /* Normally the category would go into 4 bits of the attrib.
 1138        * They jumbled the attrib bits, so to make things easy I'll put it
 1139        * here.
 1140        */
 1141       if (fa[5].i < 0) fa[5].i=0;
 1142       if (fa[5].i > 15) fa[5].i=15;
 1143       temp_todolist->mtodo.unique_id = fa[5].i;
 1144       /* Note */
 1145       if (fa[6].str) {
 1146          temp_todolist->mtodo.todo.note=fa[6].str;
 1147       } else {
 1148          temp_todolist->mtodo.todo.note=strdup("");
 1149       }
 1150       /* Append onto the end of the list */
 1151       if (last_todolist) {
 1152          last_todolist->next=temp_todolist;
 1153          last_todolist=temp_todolist;
 1154       } else {
 1155          last_todolist=temp_todolist;
 1156          *todolist=last_todolist;
 1157       }
 1158    }
 1159 
 1160    return EXIT_SUCCESS;
 1161 }
 1162 
 1163 int dat_get_memos(FILE *in, MemoList **memolist, struct CategoryAppInfo *ai)
 1164 {
 1165    int ret, i, j;
 1166    struct field fa[10];
 1167    int schema_count, field_count;
 1168    long rec_count;
 1169    MemoList *temp_memolist;
 1170    MemoList *last_memolist;
 1171    char schema[12]={
 1172       DAT_TYPE_INTEGER,0,
 1173       DAT_TYPE_INTEGER,0,
 1174       DAT_TYPE_INTEGER,0,
 1175       DAT_TYPE_CSTRING,0,
 1176       DAT_TYPE_BOOLEAN,0,
 1177       DAT_TYPE_INTEGER,0
 1178    };
 1179 #ifdef JPILOT_DEBUG
 1180    char *rec_fields[]={
 1181       "Record ID",
 1182       "Status field",
 1183       "Position"
 1184    };
 1185    char *field_names[]={
 1186       "Memo",
 1187       "Private",
 1188       "Category"
 1189    };
 1190 #endif
 1191 
 1192    jp_logf(JP_LOG_DEBUG, "dat_get_memos\n");
 1193 
 1194    if (!memolist) return EXIT_SUCCESS;
 1195    *memolist=NULL;
 1196 
 1197    ret = dat_read_header(in, 6, schema, ai,
 1198                          &schema_count, &field_count, &rec_count);
 1199 
 1200    if (ret<0) return ret;
 1201 
 1202    /* Get records */
 1203    last_memolist=*memolist;
 1204 #ifdef JPILOT_DEBUG
 1205    printf("---------- Records ----------\n");
 1206 #endif
 1207    for (i=0; i<rec_count; i++) {
 1208       temp_memolist = malloc(sizeof(MemoList));
 1209       if (!temp_memolist) {
 1210          jp_logf(JP_LOG_WARN, "dat_get_memos(): %s\n", _("Out of memory"));
 1211          return i;
 1212       }
 1213       temp_memolist->next=NULL;
 1214       temp_memolist->app_type=MEMO;
 1215 #ifdef JPILOT_DEBUG
 1216       printf("----- record %d -----\n", i+1);
 1217 #endif
 1218       /* Record ID */
 1219       /* Status Field */
 1220       /* Position */
 1221       for (j=0; j<3; j++) {
 1222          get_field(in, &(fa[j]));
 1223 #ifdef JPILOT_DEBUG
 1224          printf("rec field %d %s: ", j, rec_fields[j]); print_field(&(fa[j]));
 1225 #endif
 1226          if (fa[j].type!=schema[j*2]) {
 1227             jp_logf(JP_LOG_WARN, _("%s:%d Record %d, field %d: Invalid type.  Expected %d, found %d\n"), __FILE__, __LINE__, i+1, j+3, schema[j*2], fa[j].type);
 1228             jp_logf(JP_LOG_WARN, _("read of file terminated\n"));
 1229             free(temp_memolist);
 1230             return EXIT_FAILURE;
 1231          }
 1232       }
 1233       /* Get Fields */
 1234       for (j=0; j<3; j++) {
 1235          get_field(in, &(fa[j]));
 1236 #ifdef JPILOT_DEBUG
 1237          printf("field %d %s: ", j, field_names[j]); print_field(&(fa[j]));
 1238 #endif
 1239          if (fa[j].type!=schema[j*2+6]) {
 1240             jp_logf(JP_LOG_WARN, _("%s:%d Record %d, field %d: Invalid type.  Expected %d, found %d\n"), __FILE__, __LINE__, i+1, j+3, schema[j*2+6], fa[j].type);
 1241             jp_logf(JP_LOG_WARN, _("read of file terminated\n"));
 1242             free(temp_memolist);
 1243             return EXIT_FAILURE;
 1244          }
 1245       }
 1246       /* Memo */
 1247       temp_memolist->mmemo.memo.text=fa[0].str;
 1248       /* Private */
 1249       temp_memolist->mmemo.attrib = 0;
 1250       if (fa[1].i) {
 1251          temp_memolist->mmemo.attrib |= DAT_STATUS_PRIVATE;
 1252       }
 1253       /* Category */
 1254       /* Normally the category would go into 4 bits of the attrib.
 1255        * They jumbled the attrib bits, so to make things easy I'll put it
 1256        * here.
 1257        */
 1258       if (fa[2].i < 0) fa[2].i=0;
 1259       if (fa[2].i > 15) fa[2].i=15;
 1260       temp_memolist->mmemo.unique_id = fa[2].i;
 1261       /* Append onto the end of the list */
 1262 
 1263       if (last_memolist) {
 1264          last_memolist->next=temp_memolist;
 1265          last_memolist=temp_memolist;
 1266       } else {
 1267          last_memolist=temp_memolist;
 1268          *memolist=last_memolist;
 1269       }
 1270    }
 1271 
 1272    return EXIT_SUCCESS;
 1273 }