
# =======================================================
# Transfer addresses to and from pilot to XML.           
# Distributed under Artistic (Perl) license.             
#                                                        
# See http://www.velocigen.com/~tdarugar/pax/            
# for latest revisions and updates                       
#                                                        
# Copyright 2000, Parand Tony Darugar, VelociGen Inc.    
# $Id: adr.pl,v 1.11 2000/07/01 20:13:46 tdarugar Exp $
# =======================================================

use PDA::Pilot;
use Data::Dumper;
use strict;

my %ents=('&'=>'amp','<'=>'lt','>'=>'gt',"'"=>'apos','"'=>'quot');

# ---------------------------------------------------------
# Escapes characters to be suiteable for use as XML values 
#
sub xml_escape {
  my ($text) = @_;
  $text =~ s/([&<>'"])/&$ents{$1};/g;
	return $text;
}

# -------------------------------------------------------
# Read records from the pilot and output them in XML.    
# dlp is the pilot socket handle as returned from a      
# $dlp = PDA::Pilot::accept($socket);                    
# call, and $fh is the file handle for output.           
#
sub pilot_to_xml {
  my ($port, $fh) = @_;

  my $socket = PDA::Pilot::openPort($port);
  print STDERR "Now press the HotSync button\n";
  my $dlp = PDA::Pilot::accept($socket);
  
  my $db = $dlp->open("AddressDB");
  
  my $app = $db->getAppBlock;
  #print "Appblock: ", Dumper($app);
  my @label      = @{$app->{label}};
  my @phonelabel = @{$app->{phoneLabel}};
  my @categoryName = @{$app->{categoryName}};

  print $fh "<records>\n\n";
	my $now = localtime;
	print $fh " <comments>Generated on $now</comments>\n\n";

  my $i=0;
  my @phonelabels;
  my $tag;
  while(defined(my $r = $db->getRecord($i++))) {
    next if ( $r->{deleted} );

    print $fh " <record>\n";
    my @entries = @{$r->{entry}};
    @phonelabels = @{$r->{phoneLabel}};

    for (my $j=0; $j < $#entries; $j++) {
      next if (!$entries[$j]);
      if ($j >= 3 && $j < 8) {
        $tag = $phonelabel[$phonelabels[$j-3]];
      } else {
        $tag = $label[$j];
      }
      $tag =~ s/ /_/;
			my $escaped = xml_escape($entries[$j]);
      print $fh "  <", $tag, ">", $escaped, "</", $tag, ">\n";
    }
 
    if ($r->{secret}) {
      print $fh "  <Secret>", $r->{secret}, "</Secret>\n";
    }
    if ($r->{category}) {
		  my $category = @categoryName[$r->{category}];
      print $fh "  <Category>", $category, "</Category>\n";
    }
    if ($r->{showPhone}) {
      print $fh "  <Showphone>", $r->{showPhone}, "</Showphone>\n";
    }
    print $fh " </record>\n\n";
  }
  print $fh "</records>\n";
}

# -------------------------------------------------------
# 
#
sub add_category {
  my ($app, $category) = @_;
  
  my @categories = @{$app->{categoryName}};
  # Find unfilled category spot
  for (my $i=0; $i <= $#categories; $i++) {
    if (! $categories[$i] ) {
      ${$app->{categoryName}}[$i] = $category;
      ${$app->{categoryRenamed}}[$i] = 1;
      return $i;
    }
  }
  return -1;
}
  
# -------------------------------------------------------
# Read records from file and enters them into the pilot. 
# dlp is the pilot socket handle as returned from a      
# $dlp = PDA::Pilot::accept($socket);                    
# call, and $fh is the file handle for input.            
#
sub xml_to_pilot {
  my ($port, $fname) = @_;

  my $socket = PDA::Pilot::openPort($port);
  print STDERR "Now press the HotSync button\n";
  my $dlp = PDA::Pilot::accept($socket);

  my $db  = $dlp->open("AddressDB");
  my $app = $db->getAppBlock;

  my @label      = @{$app->{label}};
  my @phonelabel = @{$app->{phoneLabel}};
  my @categoryName = @{$app->{categoryName}};

  my %labelidx;
  
  for (my $i=0 ; $i <= $#label; $i++) {
    $labelidx{$label[$i]} = $i;
  }

  my %phoneidx;
  for (my $i=0 ; $i <= $#phonelabel; $i++) {
    $phoneidx{$phonelabel[$i]} = $i;
  }
  
  my %categoryidx;
  for (my $i=0 ; $i <= $#categoryName; $i++) {
    $categoryidx{$categoryName[$i]} = $i;
  }
  
  # Read the XML block into memory
  use XML::DOM;

  my $parser = new XML::DOM::Parser (NoExpand => 1);
  my $doc = $parser->parsefile ($fname);
  
  # Get the root of the DOM
  my $root = $doc->getDocumentElement();
  my $rootName = $root->getNodeName();

  if ($rootName ne "records") {
    printf STDERR "Wrong file type: outermost tag must be records\n";
  }

  foreach my $record ($root->getElementsByTagName("record", 0)) {
    my $a = $db->newRecord();

    foreach my $field ($record->getChildNodes()) {
      next if ($field->getNodeType() != XML::DOM::Node::ELEMENT_NODE());
      next if (! $field->hasChildNodes() );
      my $fieldname = $field->getNodeName();
      $fieldname   =~ s/_/ /;
      
      my $value     = $field->getFirstChild()->getNodeValue();
      
      if ($fieldname eq "Secret") {
        $a->{secret} = $value;
				next;
      }
      if ($fieldname eq "Showphone") {
        $a->{showPhone} = $value;
				next;
      }
      if ($fieldname eq "Category") {
        my $cidx = $categoryidx{$value};
				if (! defined($cidx) ) {
				  print "Category [$value] does not seem to exist; adding it.\n";
					$cidx = add_category($app, $value);
					$categoryidx{$value} = $cidx;
				}
				$a->{category} = $cidx;
				next;
			}
      my $idx = $labelidx{$fieldname};
      if (! defined $idx) {
        printf STDERR "Field [$fieldname] is not part of the addressbook.\n";
				next;
      }
      
      if (($idx <= 2) || ($idx >= 8 && $idx <= 18)) {
        # One of the easily fields; store it
				# print "idx for [$fieldname] is [$idx], with value [$value]\n";
        ${$a->{entry}}[$idx] = $value;
      } else {
        # Find next available phone slot
				my $idx;
				for ($idx = 3; $idx < 8; $idx++) {
				  last if (! defined ${$a->{entry}}[$idx]);
				}
        ${$a->{entry}}[$idx] = $value;
				my $pidx = $phoneidx{$fieldname};
				${$a->{phoneLabel}}[$idx-3] = $pidx;
      }
    }
#    if ( (! defined(${$a->{entry}}[0]) ) && 
#         (! defined(${$a->{entry}}[1]) )) {
#      print "Skipping record with no names defined.\n";
#      next;
#    }
    $db->setRecord($a);
  }
  $db->setAppBlock($app);
}

# -------------------------------------------------------
# Main                                                   
# -------------------------------------------------------

my $port = "/dev/pilot";

if ($ARGV[0] eq "r") {
  # Read from pilot
  my $fname = $ARGV[1];
  print STDERR "Reading from pilot, outputting to [$fname]\n";
  open(OUT, ">$fname");
  pilot_to_xml($port, *OUT);
  close OUT;
} elsif ($ARGV[0] eq "w") {
  my $fname = $ARGV[1];
  print STDERR "Reading from [$fname], outputting to pilot\n";
  xml_to_pilot($port, $fname);
} else {
  print "Usage:\nperl adr.pl [r] [w] filename\n";
  print "Use 'r' to read from the pilot and output to filename\n";
  print "Use 'w' to read from filename and write to pilot\n";
}

