"Fossies" - the Fresh Open Source Software Archive

Member "jpilot-2_0_1/libplugin.c" (3 Apr 2021, 25676 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 "libplugin.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  * libplugin.c
    3  * A module of J-Pilot http://jpilot.org
    4  *
    5  * Copyright (C) 1999-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 /********************************* Includes ***********************************/
   22 #include "config.h"
   23 #include <stdlib.h>
   24 #include <stdio.h>
   25 #include <string.h>
   26 #include <time.h>
   27 #include <ctype.h>
   28 #include <sys/types.h>
   29 #include <netinet/in.h>
   30 
   31 #include <glib.h>
   32 
   33 #include "libplugin.h"
   34 #include "i18n.h"
   35 #include "utils.h"
   36 
   37 /****************************** Prototypes ************************************/
   38 static int pack_header(PC3RecordHeader *header, unsigned char *packed_header);
   39 static int static_find_next_offset(mem_rec_header *mem_rh, long fpos,
   40                             long *next_offset,
   41                             unsigned char *attrib, unsigned int *unique_id);
   42 static void static_free_mem_rec_header(mem_rec_header **mem_rh);
   43 static int unpack_header(PC3RecordHeader *header, unsigned char *packed_header);
   44 
   45 /****************************** Main Code *************************************/
   46 /*
   47  * This deletes a record from the appropriate Datafile
   48  */
   49 int jp_delete_record(const char *DB_name, buf_rec *br, int flag)
   50 {
   51    FILE *pc_in;
   52    PC3RecordHeader header;
   53    char PC_name[FILENAME_MAX];
   54 
   55    if (br==NULL) {
   56       return EXIT_FAILURE;
   57    }
   58 
   59    g_snprintf(PC_name, sizeof(PC_name), "%s.pc3", DB_name);
   60 
   61    if ((br->rt==DELETED_PALM_REC) || (br->rt==MODIFIED_PALM_REC)) {
   62       jp_logf(JP_LOG_INFO, _("This record is already deleted.\n"
   63                   "It is scheduled to be deleted from the Palm on the next sync.\n"));
   64       return EXIT_SUCCESS;
   65    }
   66    switch (br->rt) {
   67     case NEW_PC_REC:
   68     case REPLACEMENT_PALM_REC:
   69       pc_in=jp_open_home_file(PC_name, "r+");
   70       if (pc_in==NULL) {
   71          jp_logf(JP_LOG_WARN, _("Unable to open PC records file\n"));
   72          return EXIT_FAILURE;
   73       }
   74       while(!feof(pc_in)) {
   75          read_header(pc_in, &header);
   76          if (feof(pc_in)) {
   77             jp_logf(JP_LOG_WARN, _("Couldn't find record to delete\n"));
   78             jp_close_home_file(pc_in);
   79             return EXIT_FAILURE;
   80          }
   81          if (header.header_version==2) {
   82             /* Keep unique ID intact */
   83             if ((header.unique_id==br->unique_id) &&
   84                ((header.rt==NEW_PC_REC) || (header.rt==REPLACEMENT_PALM_REC))) {
   85                if (fseek(pc_in, -header.header_len, SEEK_CUR)) {
   86                   jp_logf(JP_LOG_WARN, "fseek failed\n");
   87                }
   88                header.rt=DELETED_PC_REC;
   89                write_header(pc_in, &header);
   90                jp_logf(JP_LOG_DEBUG, "record deleted\n");
   91                jp_close_home_file(pc_in);
   92                return EXIT_SUCCESS;
   93             }
   94          } else {
   95             jp_logf(JP_LOG_WARN, _("Unknown header version %d\n"), header.header_version);
   96          }
   97          if (fseek(pc_in, header.rec_len, SEEK_CUR)) {
   98             jp_logf(JP_LOG_WARN, "fseek failed\n");
   99          }
  100       }
  101       jp_close_home_file(pc_in);
  102       return EXIT_FAILURE;
  103 
  104     case PALM_REC:
  105       jp_logf(JP_LOG_DEBUG, "Deleting Palm ID %d\n", br->unique_id);
  106       pc_in=jp_open_home_file(PC_name, "a");
  107       if (pc_in==NULL) {
  108          jp_logf(JP_LOG_WARN, _("Unable to open PC records file\n"));
  109          return EXIT_FAILURE;
  110       }
  111       header.unique_id=br->unique_id;
  112       if (flag==MODIFY_FLAG) {
  113          header.rt=MODIFIED_PALM_REC;
  114       } else {
  115          header.rt=DELETED_PALM_REC;
  116       }
  117       header.attrib=br->attrib;
  118       header.rec_len=br->size;
  119 
  120       jp_logf(JP_LOG_DEBUG, "writing header to pc file\n");
  121       write_header(pc_in, &header);
  122       /* This will be used during the sync process to make sure the palm
  123        * record hasn't changed before it is deleted. */
  124       jp_logf(JP_LOG_DEBUG, "writing record to pc file, %d bytes\n", header.rec_len);
  125       fwrite(br->buf, header.rec_len, 1, pc_in);
  126       jp_logf(JP_LOG_DEBUG, "record deleted\n");
  127       jp_close_home_file(pc_in);
  128       break;
  129     default:
  130       break;
  131    }
  132 
  133    return EXIT_SUCCESS;
  134 }
  135 
  136 int jp_edit_cats(GtkWidget *widget, char *db_name, struct CategoryAppInfo *cai)
  137 {
  138    return edit_cats(widget, db_name, cai);
  139 }
  140 
  141 int jp_free_DB_records(GList **br_list)
  142 {
  143    GList *temp_list;
  144    buf_rec *br;
  145 
  146    for (temp_list = *br_list; temp_list; temp_list = temp_list->next) {
  147       if (temp_list->data) {
  148          br=temp_list->data;
  149          if (br->buf) {
  150             free(br->buf);
  151             temp_list->data=NULL;
  152          }
  153          free(br);
  154       }
  155    }
  156    g_list_free(*br_list);
  157    *br_list=NULL;
  158 
  159    return EXIT_SUCCESS;
  160 }
  161 
  162 int jp_get_app_info(const char *DB_name, unsigned char **buf, int *buf_size)
  163 {
  164    FILE *in;
  165    int num;
  166    int rec_size;
  167    unsigned char raw_header[LEN_RAW_DB_HEADER];
  168    DBHeader dbh;
  169    char PDB_name[FILENAME_MAX];
  170 
  171    if ((!buf_size) || (!buf)) {
  172       return EXIT_FAILURE;
  173    }
  174    *buf = NULL;
  175    *buf_size=0;
  176 
  177    g_snprintf(PDB_name, sizeof(PDB_name), "%s.pdb", DB_name);
  178    in = jp_open_home_file(PDB_name, "r");
  179    if (!in) {
  180       jp_logf(JP_LOG_WARN, _("%s:%d Error opening file: %s\n"), __FILE__, __LINE__, PDB_name);
  181       return EXIT_FAILURE;
  182    }
  183    num = fread(raw_header, LEN_RAW_DB_HEADER, 1, in);
  184    if (num != 1) {
  185       if (ferror(in)) {
  186          jp_logf(JP_LOG_WARN, _("%s:%d Error reading file: %s\n"), __FILE__, __LINE__, PDB_name);
  187          jp_close_home_file(in);
  188          return EXIT_FAILURE;
  189       }
  190       if (feof(in)) {
  191          jp_close_home_file(in);
  192          return JPILOT_EOF;
  193       }
  194    }
  195    unpack_db_header(&dbh, raw_header);
  196 
  197    num = get_app_info_size(in, &rec_size);
  198    if (num) {
  199       jp_close_home_file(in);
  200       return EXIT_FAILURE;
  201    }
  202 
  203    fseek(in, dbh.app_info_offset, SEEK_SET);
  204    *buf=malloc(rec_size);
  205    if (!(*buf)) {
  206       jp_logf(JP_LOG_WARN, "jp_get_app_info(): %s\n", _("Out of memory"));
  207       jp_close_home_file(in);
  208       return EXIT_FAILURE;
  209    }
  210    num = fread(*buf, rec_size, 1, in);
  211    if (num != 1) {
  212       if (ferror(in)) {
  213          jp_close_home_file(in);
  214          free(*buf);
  215          jp_logf(JP_LOG_WARN, _("%s:%d Error reading file: %s\n"), __FILE__, __LINE__, PDB_name);
  216          return EXIT_FAILURE;
  217       }
  218    }
  219    jp_close_home_file(in);
  220 
  221    *buf_size=rec_size;
  222 
  223    return EXIT_SUCCESS;
  224 }
  225 
  226 int jp_get_home_file_name(const char *file, char *full_name, int max_size)
  227 {
  228    return get_home_file_name(file, full_name, max_size);
  229 }
  230 
  231 void jp_init(void)
  232 {
  233    jp_logf(0, "jp_init()\n");
  234 }
  235 
  236 int jp_install_append_line(char *line)
  237 {
  238    FILE *out;
  239    int r;
  240 
  241    out = jp_open_home_file(EPN".install", "a");
  242    if (!out) {
  243       return EXIT_FAILURE;
  244    }
  245 
  246    r = fprintf(out, "%s\n", line);
  247    if (r==EOF) {
  248       jp_close_home_file(out);
  249       return EXIT_FAILURE;
  250    }
  251    jp_close_home_file(out);
  252 
  253    return EXIT_SUCCESS;
  254 }
  255 
  256 /*
  257  * file must not be open elsewhere when this is called
  258  * the first line in file is 0
  259  */
  260 int jp_install_remove_line(int deleted_line)
  261 {
  262    FILE *in;
  263    FILE *out;
  264    char line[1002];
  265    char *Pc;
  266    int r, line_count;
  267 
  268    in = jp_open_home_file(EPN".install", "r");
  269    if (!in) {
  270       jp_logf(JP_LOG_DEBUG, "failed opening install_file\n");
  271       return EXIT_FAILURE;
  272    }
  273 
  274    out = jp_open_home_file(EPN".install.tmp", "w");
  275    if (!out) {
  276       jp_close_home_file(in);
  277       jp_logf(JP_LOG_DEBUG, "failed opening install_file.tmp\n");
  278       return EXIT_FAILURE;
  279    }
  280 
  281    for (line_count=0; (!feof(in)); line_count++) {
  282       line[0]='\0';
  283       Pc = fgets(line, sizeof(line), in);
  284       if (!Pc) {
  285          break;
  286       }
  287       if (line_count == deleted_line) {
  288          continue;
  289       }
  290       r = fprintf(out, "%s", line);
  291       if (r==EOF) {
  292          break;
  293       }
  294    }
  295    jp_close_home_file(in);
  296    jp_close_home_file(out);
  297 
  298    rename_file(EPN".install.tmp", EPN".install");
  299 
  300    return EXIT_SUCCESS;
  301 }
  302 
  303 static void jp_pack_htonl(unsigned char *dest, unsigned long l)
  304 {
  305    dest[3]=l & 0xFF;
  306    dest[2]=l>>8 & 0xFF;
  307    dest[1]=l>>16 & 0xFF;
  308    dest[0]=l>>24 & 0xFF;
  309 }
  310 
  311 /*
  312  * if buf_rec->unique_id==0 then the palm assigns an ID, else
  313  *  use buf_rec->unique_id.
  314  */
  315 int jp_pc_write(const char *DB_name, buf_rec *br)
  316 {
  317    PC3RecordHeader header;
  318    FILE *out;
  319    unsigned int next_unique_id;
  320    unsigned char packed_header[256];
  321    char PC_name[FILENAME_MAX];
  322 
  323    g_snprintf(PC_name, sizeof(PC_name), "%s.pc3", DB_name);
  324    if (br->unique_id==0) {
  325       get_next_unique_pc_id(&next_unique_id);
  326       header.unique_id=next_unique_id;
  327       br->unique_id=next_unique_id;
  328    } else {
  329       header.unique_id=br->unique_id;
  330    }
  331 #ifdef JPILOT_DEBUG
  332    jp_logf(JP_LOG_DEBUG, "br->unique id = %d\n",br->unique_id);
  333 #endif
  334 
  335    out = jp_open_home_file(PC_name, "a");
  336    if (!out) {
  337       jp_logf(JP_LOG_WARN, _("Error opening file: %s\n"), PC_name);
  338       return EXIT_FAILURE;
  339    }
  340 
  341    header.rec_len=br->size;
  342    header.rt=br->rt;
  343    header.attrib=br->attrib;
  344 
  345    pack_header(&header, packed_header);
  346    write_header(out, &header);
  347    fwrite(br->buf, header.rec_len, 1, out);
  348 
  349    jp_close_home_file(out);
  350 
  351    return EXIT_SUCCESS;
  352 }
  353 
  354 int jp_pdb_file_write_app_block(const char *DB_name, void *bufp, int size_in)
  355 {
  356    return pdb_file_write_app_block((char *)DB_name, bufp, size_in);
  357 }
  358 
  359 int jp_read_DB_files(const char *DB_name, GList **records)
  360 {
  361    FILE *in;
  362    FILE *pc_in;
  363    char *buf;
  364    GList *temp_list;
  365    GList *end_of_list;
  366    int num_records, recs_returned, i, num, r;
  367    long offset, prev_offset, next_offset, rec_size;
  368    int out_of_order;
  369    long fpos, fend;
  370    int ret;
  371    unsigned char attrib;
  372    unsigned int unique_id;
  373    mem_rec_header *mem_rh, *temp_mem_rh, *last_mem_rh;
  374    record_header rh;
  375    unsigned char raw_header[LEN_RAW_DB_HEADER];
  376    DBHeader dbh;
  377    buf_rec *temp_br;
  378    int temp_br_used;
  379    char PDB_name[FILENAME_MAX];
  380    char PC_name[FILENAME_MAX];
  381 
  382    jp_logf(JP_LOG_DEBUG, "Entering jp_read_DB_files: %s\n", DB_name);
  383 
  384    mem_rh = last_mem_rh = NULL;
  385    *records = end_of_list = NULL;
  386    recs_returned = 0;
  387    next_offset = 0;
  388    attrib = 0;
  389    unique_id = 0;
  390 
  391    g_snprintf(PDB_name, sizeof(PDB_name), "%s.pdb", DB_name);
  392    g_snprintf(PC_name, sizeof(PC_name), "%s.pc3", DB_name);
  393    in = jp_open_home_file(PDB_name, "r");
  394    if (!in) {
  395       jp_logf(JP_LOG_WARN, _("Error opening file: %s\n"), PDB_name);
  396       return -1;
  397    }
  398    /* Read the database header */
  399    num = fread(raw_header, LEN_RAW_DB_HEADER, 1, in);
  400    if (num != 1) {
  401       if (ferror(in)) {
  402          jp_logf(JP_LOG_WARN, _("Error reading file: %s\n"), PDB_name);
  403          jp_close_home_file(in);
  404          return -1;
  405       }
  406       if (feof(in)) {
  407          jp_close_home_file(in);
  408          return JPILOT_EOF;
  409       }
  410    }
  411    unpack_db_header(&dbh, raw_header);
  412 
  413 #ifdef JPILOT_DEBUG
  414    jp_logf(JP_LOG_DEBUG, "db_name = %s\n", dbh.db_name);
  415    jp_logf(JP_LOG_DEBUG, "num records = %d\n", dbh.number_of_records);
  416    jp_logf(JP_LOG_DEBUG, "app info offset = %d\n", dbh.app_info_offset);
  417 #endif
  418 
  419    /* Read each record entry header */
  420    num_records = dbh.number_of_records;
  421    out_of_order = 0;
  422    prev_offset = 0;
  423 
  424    for (i=1; i<num_records+1; i++) {
  425       num = fread(&rh, sizeof(record_header), 1, in);
  426       if (num != 1) {
  427          if (ferror(in)) {
  428             jp_logf(JP_LOG_WARN, _("Error reading file: %s\n"), PDB_name);
  429             break;
  430          }
  431          if (feof(in)) {
  432             jp_close_home_file(in);
  433             return JPILOT_EOF;
  434          }
  435       }
  436 
  437       offset = ((rh.Offset[0]*256+rh.Offset[1])*256+rh.Offset[2])*256+rh.Offset[3];
  438 
  439       if (offset < prev_offset) {
  440          out_of_order = 1;
  441       }
  442       prev_offset = offset;
  443 
  444 #ifdef JPILOT_DEBUG
  445       jp_logf(JP_LOG_DEBUG, "record header %u offset = %u\n",i, offset);
  446       jp_logf(JP_LOG_DEBUG, "       attrib 0x%x\n",rh.attrib);
  447       jp_logf(JP_LOG_DEBUG, "    unique_ID %d %d %d = ",rh.unique_ID[0],rh.unique_ID[1],rh.unique_ID[2]);
  448       jp_logf(JP_LOG_DEBUG, "%d\n",(rh.unique_ID[0]*256+rh.unique_ID[1])*256+rh.unique_ID[2]);
  449 #endif
  450       temp_mem_rh = malloc(sizeof(mem_rec_header));
  451       if (!temp_mem_rh) {
  452          jp_logf(JP_LOG_WARN, "jp_read_DB_files(): %s 1\n", _("Out of memory"));
  453          break;
  454       }
  455       temp_mem_rh->next = NULL;
  456       temp_mem_rh->rec_num = i;
  457       temp_mem_rh->offset = offset;
  458       temp_mem_rh->attrib = rh.attrib;
  459       temp_mem_rh->unique_id = (rh.unique_ID[0]*256+rh.unique_ID[1])*256+rh.unique_ID[2];
  460       if (mem_rh == NULL) {
  461          mem_rh = temp_mem_rh;
  462          last_mem_rh = temp_mem_rh;
  463       } else {
  464          last_mem_rh->next = temp_mem_rh;
  465          last_mem_rh = temp_mem_rh;
  466       }
  467    }
  468 
  469    temp_mem_rh = mem_rh;
  470    if (num_records) {
  471       if (out_of_order) {
  472          ret=static_find_next_offset(mem_rh, 0, &next_offset, &attrib, &unique_id);
  473       } else {
  474          if (mem_rh) {
  475             next_offset = mem_rh->offset;
  476             attrib = mem_rh->attrib;
  477             unique_id = mem_rh->unique_id;
  478          }
  479       }
  480       fseek(in, next_offset, SEEK_SET);
  481       while(!feof(in)) {
  482          fpos = ftell(in);
  483          if (out_of_order) {
  484             ret = static_find_next_offset(mem_rh, fpos, &next_offset, &attrib, &unique_id);
  485             if (!ret) {
  486                /* Next offset should be end of file */
  487                fseek(in, 0, SEEK_END);
  488                fend = ftell(in);
  489                fseek(in, fpos, SEEK_SET);
  490                next_offset = fend + 1;
  491             }
  492          } else {
  493             if (temp_mem_rh) {
  494                attrib = temp_mem_rh->attrib;
  495                unique_id = temp_mem_rh->unique_id;
  496                if (temp_mem_rh->next) {
  497                   temp_mem_rh = temp_mem_rh->next;
  498                   next_offset = temp_mem_rh->offset;
  499                } else {
  500                   /* Next offset should be end of file */
  501                   fseek(in, 0, SEEK_END);
  502                   fend = ftell(in);
  503                   fseek(in, fpos, SEEK_SET);
  504                   next_offset = fend + 1;
  505                }
  506             }
  507          }
  508          rec_size = next_offset - fpos;
  509 #ifdef JPILOT_DEBUG
  510          jp_logf(JP_LOG_DEBUG, "rec_size = %u\n",rec_size);
  511          jp_logf(JP_LOG_DEBUG, "fpos,next_offset = %u %u\n",fpos,next_offset);
  512          jp_logf(JP_LOG_DEBUG, "----------\n");
  513 #endif
  514          buf = malloc(rec_size);
  515          if (!buf) break;
  516          num = fread(buf, 1, rec_size, in);
  517          if (num<rec_size) {
  518             rec_size=num;
  519             buf = realloc(buf, rec_size);
  520          }
  521          if ((num < 1)) {
  522             if (ferror(in)) {
  523                jp_logf(JP_LOG_WARN, _("Error reading %s 5\n"), PDB_name);
  524                free(buf);
  525                break;
  526             }
  527          }
  528 
  529          temp_br = malloc(sizeof(buf_rec));
  530          if (!temp_br) {
  531             jp_logf(JP_LOG_WARN, "jp_read_DB_files(): %s 2\n", _("Out of memory"));
  532             break;
  533          }
  534          temp_br->rt = PALM_REC;
  535          temp_br->unique_id = unique_id;
  536          temp_br->attrib = attrib;
  537          temp_br->buf = buf;
  538          temp_br->size = rec_size;
  539 
  540          *records = g_list_prepend(*records, temp_br);
  541 
  542          recs_returned++;
  543       }
  544    }
  545    jp_close_home_file(in);
  546 
  547    static_free_mem_rec_header(&mem_rh);
  548 
  549    /* Get the appointments out of the PC database */
  550    pc_in = jp_open_home_file(PC_name, "r");
  551    if (pc_in==NULL) {
  552       jp_logf(JP_LOG_DEBUG, "jp_open_home_file failed: %s\n", PC_name);
  553       return -1;
  554    }
  555 
  556    while(!feof(pc_in)) {
  557       temp_br_used = 0;
  558       temp_br = malloc(sizeof(buf_rec));
  559       if (!temp_br) {
  560          jp_logf(JP_LOG_WARN, "jp_read_DB_files(): %s 3\n", _("Out of memory"));
  561          recs_returned = -1;
  562          break;
  563       }
  564       r = pc_read_next_rec(pc_in, temp_br);
  565       if ((r==JPILOT_EOF) || (r<0)) {
  566          free(temp_br);
  567          break;
  568       }
  569       if (temp_br->rt!=DELETED_PALM_REC  &&
  570           temp_br->rt!=MODIFIED_PALM_REC &&
  571           temp_br->rt!=DELETED_DELETED_PALM_REC) {
  572          *records = g_list_prepend(*records, temp_br);
  573          temp_br_used = 1;
  574          recs_returned++;
  575       }
  576       if ((temp_br->rt==DELETED_PALM_REC) || (temp_br->rt==MODIFIED_PALM_REC)) {
  577          for (temp_list=*records; temp_list; temp_list=temp_list->next) {
  578             if (((buf_rec *)temp_list->data)->unique_id == temp_br->unique_id) {
  579                if (((buf_rec *)temp_list->data)->rt == PALM_REC) {
  580                   ((buf_rec *)temp_list->data)->rt = temp_br->rt;
  581                }
  582             }
  583          }
  584       }
  585 
  586       if (!temp_br_used) {
  587          free(temp_br->buf);
  588          free(temp_br);
  589       }
  590    }
  591    jp_close_home_file(pc_in);
  592 
  593    jp_logf(JP_LOG_DEBUG, "Leaving jp_read_DB_files\n");
  594 
  595    return recs_returned;
  596 }
  597 
  598 const char *jp_strstr(const char *haystack, const char *needle, int case_sense)
  599 {
  600    char *needle2;
  601    char *haystack2;
  602    register char *Ps2;
  603    register const char *Ps1;
  604    char *r;
  605 
  606    if (!haystack) {
  607       return NULL;
  608    }
  609    if (!needle) {
  610       return haystack;
  611    }
  612    if (case_sense) {
  613       return strstr(haystack, needle);
  614    } else {
  615       needle2 = malloc(strlen(needle)+2);
  616       haystack2 = malloc(strlen(haystack)+2);
  617 
  618       Ps1 = needle;
  619       Ps2 = needle2;
  620       while (Ps1[0]) {
  621          Ps2[0] = tolower(Ps1[0]);
  622          Ps1++;
  623          Ps2++;
  624       }
  625       Ps2[0]='\0';
  626 
  627       Ps1 = haystack;
  628       Ps2 = haystack2;
  629       while (Ps1[0]) {
  630          Ps2[0] = tolower(Ps1[0]);
  631          Ps1++;
  632          Ps2++;
  633       }
  634       Ps2[0]='\0';
  635 
  636       r = strstr(haystack2, needle2);
  637       if (r) {
  638          r = (char *)((r-haystack2)+haystack);
  639       }
  640       free(needle2);
  641       free(haystack2);
  642       return r;
  643    }
  644 }
  645 
  646 /*
  647  * This undeletes a record from the appropriate Datafile
  648  */
  649 int jp_undelete_record(const char *DB_name, buf_rec *br, int flag)
  650 {
  651    char filename[FILENAME_MAX];
  652    char filename2[FILENAME_MAX];
  653    FILE *pc_file  = NULL;
  654    FILE *pc_file2 = NULL;
  655    PC3RecordHeader header;
  656    char *record;
  657    unsigned int unique_id;
  658    int found;
  659    int ret = -1;
  660    int num;
  661 
  662    if (br==NULL) {
  663       return EXIT_FAILURE;
  664    }
  665 
  666    unique_id = br->unique_id;
  667    found  = FALSE;
  668    record = NULL;
  669 
  670    g_snprintf(filename, sizeof(filename), "%s.pc3", DB_name);
  671    g_snprintf(filename2, sizeof(filename2), "%s.pct", filename);
  672 
  673    pc_file = jp_open_home_file(filename , "r");
  674    if (!pc_file) {
  675       return EXIT_FAILURE;
  676    }
  677 
  678    pc_file2=jp_open_home_file(filename2, "w");
  679    if (!pc_file2) {
  680       jp_close_home_file(pc_file);
  681       return EXIT_FAILURE;
  682    }
  683 
  684    while(!feof(pc_file)) {
  685       read_header(pc_file, &header);
  686       if (feof(pc_file)) {
  687          break;
  688       }
  689       /* Skip copying DELETED_PALM_REC entry which undeletes it */
  690       if ((header.unique_id == unique_id) &&
  691           (header.rt == DELETED_PALM_REC)) {
  692          found = TRUE;
  693          if (fseek(pc_file, header.rec_len, SEEK_CUR)) {
  694             jp_logf(JP_LOG_WARN, "fseek failed\n");
  695             ret = -1;
  696             break;
  697          }
  698          continue;
  699       }
  700       /* Change header on DELETED_PC_REC to undelete this type */
  701       if ((header.unique_id == unique_id) &&
  702           (header.rt == DELETED_PC_REC)) {
  703          found = TRUE;
  704          header.rt = NEW_PC_REC;
  705       }
  706 
  707       /* Otherwise, keep whatever is there by copying it to the new pc3 file */
  708       record = malloc(header.rec_len);
  709       if (!record) {
  710          jp_logf(JP_LOG_WARN, "cleanup_pc_file(): Out of memory\n");
  711          ret = -1;
  712          break;
  713       }
  714       num = fread(record, header.rec_len, 1, pc_file);
  715       if (num != 1) {
  716          if (ferror(pc_file)) {
  717             ret = -1;
  718             break;
  719          }
  720       }
  721       ret = write_header(pc_file2, &header);
  722       ret = fwrite(record, header.rec_len, 1, pc_file2);
  723       if (ret != 1) {
  724          ret = -1;
  725          break;
  726       }
  727       free(record);
  728       record = NULL;
  729    }
  730 
  731    if (record) {
  732       free(record);
  733    }
  734    if (pc_file) {
  735       jp_close_home_file(pc_file);
  736    }
  737    if (pc_file2) {
  738       jp_close_home_file(pc_file2);
  739    }
  740 
  741    if (found) {
  742       rename_file(filename2, filename);
  743    } else {
  744       unlink_file(filename2);
  745    }
  746 
  747    return ret;
  748 }
  749 
  750 static void jp_unpack_ntohl(unsigned long *l, unsigned char *src)
  751 {
  752     *l=src[0]<<24 | src[1]<<16 | src[2]<<8 | src[3];
  753 }
  754 
  755 static int pack_header(PC3RecordHeader *header, unsigned char *packed_header)
  756 {
  757    unsigned char *p;
  758 
  759    p=packed_header;
  760    /*
  761     * Header structure:
  762     * unsigned long header_len;
  763     * unsigned long header_version;
  764     * unsigned long rec_len;
  765     * unsigned long unique_id;
  766     * unsigned long rt;
  767     * unsigned char attrib;
  768     */
  769     /* 4 + 4 + 4 + 4 + 4 + 1 */
  770    header->header_len = 21;
  771 
  772    header->header_version = 2;
  773 
  774    jp_pack_htonl(p, header->header_len);
  775    jp_pack_htonl(p+4, header->header_version);
  776    jp_pack_htonl(p+8, header->rec_len);
  777    jp_pack_htonl(p+12, header->unique_id);
  778    jp_pack_htonl(p+16, header->rt);
  779    memcpy(p+20, &header->attrib, 1);
  780 
  781    return header->header_len;
  782 }
  783 
  784 int pc_read_next_rec(FILE *in, buf_rec *br)
  785 {
  786    PC3RecordHeader header;
  787    int rec_len, num;
  788    char *record;
  789 
  790    if (feof(in)) {
  791       return JPILOT_EOF;
  792    }
  793    num = read_header(in, &header);
  794    if (num < 1) {
  795       if (ferror(in)) {
  796          jp_logf(JP_LOG_WARN, _("Error reading PC file 1\n"));
  797          return JPILOT_EOF;
  798       }
  799       if (feof(in)) {
  800          return JPILOT_EOF;
  801       }
  802    }
  803    rec_len = header.rec_len;
  804    record = malloc(rec_len);
  805    if (!record) {
  806       jp_logf(JP_LOG_WARN, "pc_read_next_rec(): %s\n", _("Out of memory"));
  807       return JPILOT_EOF;
  808    }
  809    num = fread(record, rec_len, 1, in);
  810    if (num != 1) {
  811       if (ferror(in)) {
  812          jp_logf(JP_LOG_WARN, _("Error reading PC file 2\n"));
  813          free(record);
  814          return JPILOT_EOF;
  815       }
  816    }
  817    br->rt = header.rt;
  818    br->unique_id = header.unique_id;
  819    br->attrib = header.attrib;
  820    br->buf = record;
  821    br->size = rec_len;
  822 
  823    return EXIT_SUCCESS;
  824 }
  825 
  826 /* FIXME: Add jp_ and document. */
  827 int read_header(FILE *pc_in, PC3RecordHeader *header)
  828 {
  829    unsigned char packed_header[256];
  830    int num;
  831 
  832    num = fread(packed_header, 4, 1, pc_in);
  833    if (feof(pc_in)) {
  834       return JPILOT_EOF;
  835    }
  836    if (num!=1) {
  837       return num;
  838    }
  839    jp_unpack_ntohl(&(header->header_len), packed_header);
  840    if (header->header_len > sizeof(packed_header)-1) {
  841       jp_logf(JP_LOG_WARN, "read_header() %s\n", _("error"));
  842       return EXIT_FAILURE;
  843    }
  844    num = fread(packed_header+4, (header->header_len)-4, 1, pc_in);
  845    if (feof(pc_in)) {
  846       return JPILOT_EOF;
  847    }
  848    if (num!=1) {
  849       return num;
  850    }
  851    unpack_header(header, packed_header);
  852 #ifdef JPILOT_DEBUG
  853    printf("header_len    =%ld\n", header->header_len);
  854    printf("header_version=%ld\n", header->header_version);
  855    printf("rec_len       =%ld\n", header->rec_len);
  856    printf("unique_id     =%ld\n", header->unique_id);
  857    printf("rt            =%ld\n", header->rt);
  858    printf("attrib        =%d\n",  header->attrib);
  859 #endif
  860    return 1;
  861 }
  862 
  863 /* returns 1 if found */
  864 /*        0 if eof */
  865 static int static_find_next_offset(mem_rec_header *mem_rh, long fpos,
  866                                    long *next_offset, unsigned char *attrib, 
  867                                    unsigned int *unique_id)
  868 {
  869    mem_rec_header *temp_mem_rh;
  870    unsigned char found = 0;
  871    unsigned long found_at;
  872 
  873    found_at=0x1000000;
  874    for (temp_mem_rh=mem_rh; temp_mem_rh; temp_mem_rh = temp_mem_rh->next) {
  875       if ((temp_mem_rh->offset > fpos) && (temp_mem_rh->offset < found_at)) {
  876          found_at = temp_mem_rh->offset;
  877       }
  878       if ((temp_mem_rh->offset == fpos)) {
  879          found = 1;
  880          *attrib = temp_mem_rh->attrib;
  881          *unique_id = temp_mem_rh->unique_id;
  882       }
  883    }
  884    *next_offset = found_at;
  885    return found;
  886 }
  887 
  888 static void static_free_mem_rec_header(mem_rec_header **mem_rh)
  889 {
  890    mem_rec_header *h, *next_h;
  891 
  892    for (h=*mem_rh; h; h=next_h) {
  893       next_h=h->next;
  894       free(h);
  895    }
  896    *mem_rh=NULL;
  897 }
  898 
  899 static int unpack_header(PC3RecordHeader *header, unsigned char *packed_header)
  900 {
  901    unsigned char *p;
  902 
  903    /*
  904     * Header structure:
  905     * unsigned long header_len;
  906     * unsigned long header_version;
  907     * unsigned long rec_len;
  908     * unsigned long unique_id;
  909     * unsigned long rt;
  910     * unsigned char attrib;
  911     */
  912    p = packed_header;
  913 
  914    jp_unpack_ntohl(&(header->header_len), p);
  915    jp_unpack_ntohl(&(header->header_version), p+4);
  916 
  917    if (header->header_version > 2) {
  918       jp_logf(JP_LOG_WARN, _("Unknown PC header version = %d\n"), header->header_version);
  919    }
  920 
  921    jp_unpack_ntohl(&(header->rec_len), p+8);
  922    jp_unpack_ntohl(&(header->unique_id), p+12);
  923    jp_unpack_ntohl(&(header->rt), p+16);
  924    header->attrib = p[20];
  925 
  926    return EXIT_SUCCESS;
  927 }
  928 
  929 /* FIXME: Add jp_ and document */
  930 int write_header(FILE *pc_out, PC3RecordHeader *header)
  931 {
  932    unsigned long len;
  933    unsigned char packed_header[256];
  934 
  935    len = pack_header(header, packed_header);
  936    if (len>0) {
  937       fwrite(packed_header, len, 1, pc_out);
  938    } else {
  939       jp_logf(JP_LOG_WARN, "%s:%d pack_header returned error\n", __FILE__, __LINE__);
  940    }
  941 
  942    return len;
  943 }
  944