14
my ($controldir, $dlp, $info, $db, $port);
15
my (%control, %pilothash, %pilotID, %planID, %exceptID, %planRecord,
17
my ($slowsync, $file, $pilotname, $maxseed, $netplanversion);
24
my @plversion; # pilot-link version (version, major, minor, patch)
26
# any or alll of these may be undefined, depending on the
29
$plversion[0] = PDA::Pilot::PILOT_LINK_VERSION();
30
$plversion[1] = PDA::Pilot::PILOT_LINK_MAJOR();
31
$plversion[2] = PDA::Pilot::PILOT_LINK_MINOR();
32
$plversion[3] = PDA::Pilot::PILOT_LINK_PATCH();
35
# msg and status are here to localize the differences between the
36
# standalone sync-plan.PL and the SyncPlan.pm module for PilotManager.
38
############################################################
40
############################################################
48
############################################################
49
# CheckErrNotFound: Argument is a PDA::Pilot::DLP or a
50
# PDA::Pilot::DLP::DB. It's in its own package so that croak will
51
# give more useful information. I'm not using the equivalent function
52
# from the PilotMgr package because there is a stand-alone version of
53
# this conduit in the pilot-link distribution.
54
############################################################
61
my $errno = $obj->errno();
62
if (defined $plversion[0]) { # pilot-link version is >= 0.12.0-pre2
63
if ($errno != PDA::Pilot::PI_ERR_DLP_PALMOS()) {
66
if (($errno = $obj->palmos_errno()) != PDA::Pilot::dlpErrNotFound()) {
67
croak "Error $errno: " . PDA::Pilot::errorText($errno);
70
croak "Error $errno" if ($errno != -5); # dlpErrNotFound
74
*checkErrNotFound = \&ErrorCheck::checkErrNotFound;
77
############################################################
79
############################################################
12
80
sub DatePlanToPerl {
14
my($m,$d,$y) = split(m!/!,$PlanDate);
82
my ($m,$d,$y) = split(m!/!,$PlanDate);
23
timelocal(0,0,0,$d,$m,$y);
91
timegm(0,0,0,$d,$m,$y);
94
############################################################
96
############################################################
26
97
sub TimePlanToPerl {
28
my($h,$m,$s) = split(m!:!,$PlanTime);
99
my ($h,$m,$s) = split(m!:!,$PlanTime);
30
101
return undef if $h == 99 and $m == 99 and $s == 99;
32
$s + ($m*60) + ($h*60*60);
103
$s + ($m * 60) + ($h * 60 * 60);
106
############################################################
108
############################################################
35
109
sub TimePerlToPlan {
37
111
return "99:99:99" if not defined $PerlDT;
39
my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
113
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
42
116
"$hour:$min:$sec";
119
############################################################
121
############################################################
45
122
sub TimeRelPerlToPlan {
47
124
return "99:99:99" if not defined $PerlDT;
126
my ($sec,$min,$hour);
51
128
$hour = int($PerlDT/ (60*60));
52
129
$PerlDT -= $hour*60*60;
71
175
"$mon/$mday/$year";
178
############################################################
180
############################################################
74
181
sub RecordPlanToPilot {
75
my($plan,$pilot) = @_;
182
my ($plan,$pilot) = @_;
76
183
if (not defined $pilot) {
77
184
$pilot = PDA::Pilot::AppointmentDatabase->record;
80
$pilot->{id} = $plan->{pilotid};
81
$pilot->{description} = join("\xA", @{$plan->{note}}) if defined $plan->{note};
82
$pilot->{note} = join("\xA", @{$plan->{message}}) if defined $plan->{message};
83
$pilot->{description} ||= "";
187
$pilot->{'id'} = $plan->{'pilotid'};
188
$pilot->{'description'} = join("\xA", @{$plan->{'note'}}) if defined $plan->{'note'};
189
$pilot->{'note'} = join("\xA", @{$plan->{'message'}}) if defined $plan->{'message'};
190
$pilot->{'description'} ||= "";
85
if (defined $plan->{time}) {
86
$pilot->{begin} = [localtime($plan->{date}+$plan->{time})];
87
$pilot->{end} = [localtime($plan->{date}+$plan->{time}+$plan->{length})];
192
if (defined $plan->{'time'}) {
193
$pilot->{'begin'} = [gmtime($plan->{'date'}+$plan->{'time'})];
194
$pilot->{'end'} = [gmtime($plan->{'date'}+$plan->{'time'}+$plan->{'length'})];
90
$pilot->{begin} = [localtime($plan->{date})];
197
$pilot->{'begin'} = [gmtime($plan->{'date'})];
198
$pilot->{'event'} = 1;
199
$plan->{'early'} = 0;
96
if ($plan->{early} and $plan->{late} and ($plan->{early} != $plan->{late})) {
203
if ($plan->{'early'} and $plan->{'late'} and ($plan->{'early'} != $plan->{'late'})) {
204
msg( "Two alarms - using earlier one." );
205
$plan->{'late'} = $plan->{'early'};
99
if ($plan->{early} or $plan->{late}) {
100
my($alarm) = $plan->{early} || $plan->{late};
207
if ($plan->{'early'} or $plan->{'late'}) {
208
my ($alarm) = $plan->{'early'} || $plan->{'late'};
101
209
if ($alarm > (60*60*24)) {
102
$pilot->{alarm}->{units} = "days";
103
$pilot->{alarm}->{advance} = int($alarm / (60*60*24));
210
$pilot->{'alarm'}->{'units'} = "days";
211
$pilot->{'alarm'}->{'advance'} = int($alarm / (60*60*24));
104
212
} elsif ($alarm > (60*60)) {
105
$pilot->{alarm}->{units} = "hours";
106
$pilot->{alarm}->{advance} = int($alarm / (60*60));
213
$pilot->{'alarm'}->{'units'} = "hours";
214
$pilot->{'alarm'}->{'advance'} = int($alarm / (60*60));
108
$pilot->{alarm}->{units} = "minutes";
109
$pilot->{alarm}->{advance} = int($alarm / 60);
216
$pilot->{'alarm'}->{'units'} = "minutes";
217
$pilot->{'alarm'}->{'advance'} = int($alarm / 60);
113
if (defined $plan->{exceptions}) {
114
foreach (@{$plan->{exceptions}}) {
115
push @{$pilot->{exceptions}}, [localtime($_)];
221
if (defined $plan->{'exceptions'}) {
222
foreach (@{$plan->{'exceptions'}}) {
223
push @{$pilot->{'exceptions'}}, [gmtime($_)];
118
delete $pilot->{exceptions};
226
delete $pilot->{'exceptions'};
121
if (defined $plan->{repeat}) {
122
print "Converting repetition...\n";
123
delete $pilot->{repeat};
124
if ($plan->{repeat}->[1]) {
125
$pilot->{repeat}->{end} = [gmtime($plan->{repeat}->[1])];
229
if (defined $plan->{'repeat'}) {
230
msg( "Converting repetition...\n" ) if ($PREFS->{'Debug'} > 2);
231
delete $pilot->{'repeat'};
232
if ($plan->{'repeat'}->[1]) {
233
$pilot->{'repeat'}->{'end'} = [gmtime($plan->{'repeat'}->[1])];
127
my($days,$end,$weekday,$mday,$yearly) = @{$plan->{repeat}};
128
print "Days: $days, End: $end, Weekday: $weekday, Mday: $mday, Yearly: $yearly\n";
129
$pilot->{repeat}->{weekstart} = 0;
130
$pilot->{repeat}->{frequency} = 1;
235
my ($days,$end,$weekday,$mday,$yearly) = @{$plan->{'repeat'}};
236
msg( "Days: $days, End: $end, Weekday: $weekday, Mday: $mday, Yearly: $yearly\n" ) if ($PREFS->{'Debug'} > 2);
237
$pilot->{'repeat'}->{'weekstart'} = 0;
238
$pilot->{'repeat'}->{'frequency'} = 1;
131
239
if ($days and !$weekday and !$mday and !$yearly) {
132
$pilot->{repeat}->{type} = "Daily";
133
$pilot->{repeat}->{frequency} = $days / (60*60*24);
240
$pilot->{'repeat'}->{'type'} = "Daily";
241
$pilot->{'repeat'}->{'frequency'} = $days / (60*60*24);
134
242
} elsif(!$days and !$weekday and !$mday and $yearly) {
135
$pilot->{repeat}->{type} = "Yearly";
136
} elsif(!$days and !$weekday and ($mday == (1 << $pilot->{begin}[3])) and !$yearly) {
137
$pilot->{repeat}->{type} = "MonthlyByDate";
243
$pilot->{'repeat'}->{'type'} = "Yearly";
244
} elsif(!$days and !$weekday and ($mday == (1 << $pilot->{'begin'}[3])) and !$yearly) {
245
$pilot->{'repeat'}->{'type'} = "MonthlyByDate";
139
247
} elsif(!$days and $weekday and (($weekday & 0xff80) == 0) and !$mday and !$yearly) {
140
$pilot->{repeat}->{type} = "Weekly";
142
$pilot->{repeat}->{days}[$i] = !! ($weekday & (1<<$i));
248
$pilot->{'repeat'}->{'type'} = "Weekly";
249
foreach my $i (0..6) {
250
$pilot->{'repeat'}->{'days'}[$i] = !! ($weekday & (1<<$i));
144
252
# If the weekday list does include the day the event is one, abort
145
if (!$pilot->{repeat}{days}[$pilot->{begin}[6]]) {
253
if (!$pilot->{'repeat'}{'days'}[$pilot->{'begin'}[6]]) {
148
256
} elsif(not $days and $weekday and not $mday and not $yearly) {
149
my($wday) = $pilot->{begin}[6];
150
my($week) = int(($pilot->{begin}[3]-1)/7);
151
print "weekday = $weekday, wday = $wday, week = $week\n";
257
my ($wday) = $pilot->{'begin'}[6];
258
my ($week) = int(($pilot->{'begin'}[3]-1)/7);
259
msg( "weekday = $weekday, wday = $wday, week = $week\n" ) if ($PREFS->{'Debug'} > 2);
152
260
if (($weekday & 0x7f) != (1<<$wday)) {
168
$pilot->{repeat}->{type} = "MonthlyByDay";
169
$pilot->{repeat}->{day} = $week*7+$wday;
276
$pilot->{'repeat'}->{'type'} = "MonthlyByDay";
277
$pilot->{'repeat'}->{'day'} = $week*7+$wday;
174
delete $pilot->{repeat};
282
delete $pilot->{'repeat'};
288
############################################################
290
############################################################
180
291
sub RecordPilotToPlan {
181
my($pilot,$plan) = @_;
292
my ($pilot,$plan) = @_;
182
293
$plan = {color => 0} if not defined $plan;
184
$plan->{pilotid} = $pilot->{id};
186
$plan->{message} = [split("\xA", $pilot->{note})] if defined $pilot->{note};
187
$plan->{note} = [split("\xA", $pilot->{description})] if defined $pilot->{description};
189
my($date) = timelocal(@{$pilot->{begin}});
190
my($time) = $pilot->{begin}[0]+$pilot->{begin}[1]*60+$pilot->{begin}[2]*60*60;
191
$plan->{date} = $date;
192
if ($pilot->{event}) {
193
$plan->{time} = undef;
295
$plan->{'pilotid'} = $pilot->{'id'};
297
$plan->{'message'} = [split("\xA", $pilot->{'note'})] if defined $pilot->{'note'};
298
$plan->{'note'} = [split("\xA", $pilot->{'description'})] if defined $pilot->{'description'};
300
my ($date, $time) = DatePilotToPerl($pilot->{'begin'});
302
msg("Begin time in Palm record untranslatable.");
306
$plan->{'date'} = $date;
307
if ($pilot->{'event'}) {
308
$plan->{'time'} = undef;
309
$plan->{'length'} = 0;
196
$plan->{time} = $time;
197
$plan->{length} = timelocal(@{$pilot->{end}}) - $date;
311
$plan->{'time'} = $time;
312
my $end = DatePilotToPerl($pilot->{'end'});
314
msg("End time in Palm record untranslatable.");
317
$plan->{'length'} = $end - $date;
200
if (exists $pilot->{alarm}) {
202
$plan->{noalarm} = 0;
203
if ($pilot->{alarm}{units} eq "days") {
204
$alarm = $pilot->{alarm}->{advance} * (60*60*24);
205
} elsif ($pilot->{alarm}{units} eq "hours") {
206
$alarm = $pilot->{alarm}->{advance} * (60*60);
207
} elsif ($pilot->{alarm}{units} eq "minutes") {
208
$alarm = $pilot->{alarm}->{advance} * (60);
320
if (exists $pilot->{'alarm'}) {
322
if ($pilot->{'alarm'}{'units'} eq "days") {
323
$alarm = $pilot->{'alarm'}->{'advance'} * (60*60*24);
324
} elsif ($pilot->{'alarm'}{'units'} eq "hours") {
325
$alarm = $pilot->{'alarm'}->{'advance'} * (60*60);
326
} elsif ($pilot->{'alarm'}{'units'} eq "minutes") {
327
$alarm = $pilot->{'alarm'}->{'advance'} * (60);
211
$plan->{late} = $alarm;
329
if ($plan->{'late'}) {
330
$plan->{'late'} = $alarm;
331
$plan->{'early'} = 0;
215
$plan->{early} = $alarm;
334
$plan->{'early'} = $alarm;
218
$plan->{noalarm} = 1;
223
if (exists $pilot->{exceptions}) {
341
if (exists $pilot->{'exceptions'}) {
224
342
# Plan records can only deal with four exceptions,
225
if (@{$pilot->{exceptions}} > 4) {
343
if (@{$pilot->{'exceptions'}} > 4) {
344
msg("Too many exceptions.");
228
foreach (@{$pilot->{exceptions}}) {
229
push @{$plan->{exceptions}}, timelocal(@{$_});
347
foreach (@{$pilot->{'exceptions'}}) {
348
push @{$plan->{'exceptions'}}, timegm(@{$_});
233
delete $plan->{repeat};
352
delete $plan->{'repeat'};
235
if (exists $pilot->{repeat}) {
236
$plan->{repeat} = [0,0,0,0,0];
237
if ($pilot->{repeat}->{type} eq "Daily") {
238
$plan->{repeat}->[0] = (60*60*24) * $pilot->{repeat}->{frequency};
239
$plan->{repeat}->[4] = 0;
240
} elsif ($pilot->{repeat}->{type} eq "Yearly" and ($pilot->{repeat}->{frequency}==1)) {
241
$plan->{repeat}->[4] = 1;
354
if (exists $pilot->{'repeat'}) {
355
$plan->{'repeat'} = [0,0,0,0,0];
356
if ($pilot->{'repeat'}->{'type'} eq "Daily") {
357
$plan->{'repeat'}->[0] = (60*60*24) * $pilot->{'repeat'}->{'frequency'};
358
$plan->{'repeat'}->[4] = 0;
359
} elsif ($pilot->{'repeat'}->{'type'} eq "Yearly" and ($pilot->{'repeat'}->{'frequency'}==1)) {
360
$plan->{'repeat'}->[4] = 1;
243
} elsif ($pilot->{repeat}->{type} eq "Weekly" and ($pilot->{repeat}->{frequency}==1)) {
246
if ($pilot->{repeat}->{days}[$i]) {
362
} elsif ($pilot->{'repeat'}->{'type'} eq "Weekly" and ($pilot->{'repeat'}->{'frequency'}==1)) {
364
foreach my $i (0..6) {
365
if ($pilot->{'repeat'}->{'days'}[$i]) {
250
$plan->{repeat}->[2] = $r;
251
} elsif ($pilot->{repeat}->{type} eq "Weekly" and ($pilot->{repeat}->{frequency}>1)) {
252
$plan->{repeat}->[0] = (60*60*24) * $pilot->{repeat}->{frequency} * 7;
253
$plan->{repeat}->[4] = 0;
254
} elsif ($pilot->{repeat}->{type} eq "MonthlyByDate" and ($pilot->{repeat}->{frequency}==1)) {
255
$plan->{repeat}->[3] = 1 << $pilot->{begin}[3];
256
} elsif ($pilot->{repeat}->{type} eq "MonthlyByDay" and ($pilot->{repeat}->{frequency}==1)) {
257
my($day) = $pilot->{repeat}{day} % 7;
258
my($week) = int($pilot->{repeat}{day} / 7);
259
$week=5 if $week == 4;
260
$plan->{repeat}->[2] = (1 << $day) | (256 << $week);
369
$plan->{'repeat'}->[2] = $r;
370
} elsif ($pilot->{'repeat'}->{'type'} eq "Weekly" and ($pilot->{'repeat'}->{'frequency'}>1)) {
371
# Weekly repeat, not every week. If it repeats only once per week, convert it to a daily
372
# repeat with frequency a multiple of 7. If it repeats more than once a week, bail.
374
foreach my $i (0..6) {
375
$count ++ if ($pilot->{repeat}->{days}[$i]);
378
$plan->{'repeat'}->[0] = (60*60*24) * $pilot->{'repeat'}->{'frequency'} * 7;
379
$plan->{'repeat'}->[4] = 0;
381
msg("Repeat pattern too complex.");
384
} elsif ($pilot->{'repeat'}->{'type'} eq "MonthlyByDate" and ($pilot->{'repeat'}->{'frequency'}==1)) {
385
$plan->{'repeat'}->[3] = 1 << $pilot->{'begin'}[3];
386
} elsif ($pilot->{'repeat'}->{'type'} eq "MonthlyByDay" and ($pilot->{'repeat'}->{'frequency'}==1)) {
387
my ($day) = $pilot->{'repeat'}{'day'} % 7;
388
my ($week) = int($pilot->{'repeat'}{'day'} / 7);
389
$week = 5 if $week == 4;
390
$plan->{'repeat'}->[2] = (1 << $day) | (256 << $week);
392
msg("Repeat pattern too complex.");
264
if (defined $pilot->{repeat}->{end}) {
265
$plan->{repeat}->[1] = timelocal(@{$pilot->{repeat}->{end}});
395
if (defined $pilot->{'repeat'}->{'end'}) {
396
$plan->{'repeat'}->[1] = timegm(@{$pilot->{'repeat'}->{'end'}});
403
############################################################
405
############################################################
272
406
sub generaterecord {
276
410
#print "Generating Plan record: ", Dumper($rec),"\n";
278
push(@output, DatePerlToPlan($rec->{date})." ".
279
TimeRelPerlToPlan($rec->{time})." ".
280
TimeRelPerlToPlan($rec->{length})." ".
281
TimeRelPerlToPlan($rec->{early})." ".
282
TimeRelPerlToPlan($rec->{late})." ".
283
($rec->{suspended} ? "S" : "-").
284
($rec->{private} ? "P" : "-").
285
($rec->{noalarm} ? "N" : "-").
286
($rec->{hide_month} ? "M" : "-").
287
($rec->{hide_year} ? "Y" : "-").
288
($rec->{hide_week} ? "W" : "-").
289
($rec->{hide_yearover} ? "O" : "-").
290
($rec->{d_flag} ? "D" : "-").
412
push(@output, DatePerlToPlan($rec->{'date'})." ".
413
TimeRelPerlToPlan($rec->{'time'})." ".
414
TimeRelPerlToPlan($rec->{'length'})." ".
415
TimeRelPerlToPlan($rec->{'early'})." ".
416
TimeRelPerlToPlan($rec->{'late'})." ".
417
($rec->{'suspended'} ? "S" : "-").
418
($rec->{'private'} ? "P" : "-").
419
($rec->{'noalarm'} ? "N" : "-").
420
($rec->{'hide_month'} ? "M" : "-").
421
($rec->{'hide_year'} ? "Y" : "-").
422
($rec->{'hide_week'} ? "W" : "-").
423
($rec->{'hide_yearover'} ? "O" : "-").
424
($rec->{'d_flag'} ? "D" : "-").
427
" ".$rec->{'color'});
295
if (defined $rec->{repeat}) {
296
push @output, "R\t".join(" ",@{$rec->{repeat}});
429
if (defined $rec->{'repeat'}) {
430
push @output, "R\t".join(" ",@{$rec->{'repeat'}});
298
if (defined $rec->{exceptions}) {
299
foreach (@{$rec->{exceptions}}) {
432
if (defined $rec->{'exceptions'}) {
433
foreach (@{$rec->{'exceptions'}}) {
300
434
push @output, "E\t".DatePerlToPlan($_);
303
if (defined $rec->{note}) {
304
push @output, map("N\t$_", @{$rec->{note}});
306
if (defined $rec->{message}) {
307
push @output, map("M\t$_", @{$rec->{message}});
309
if (defined $rec->{script}) {
310
push @output, map("S\t$_", @{$rec->{script}});
312
if (defined $rec->{other}) {
313
foreach (@{$rec->{other}}) {
437
if (defined $rec->{'note'}) {
438
push @output, map("N\t$_", @{$rec->{'note'}});
440
if (defined $rec->{'message'}) {
441
push @output, map("M\t$_", @{$rec->{'message'}});
443
if (defined $rec->{'script'}) {
444
push @output, map("S\t$_", @{$rec->{'script'}});
446
if (defined $rec->{'other'}) {
447
foreach (@{$rec->{'other'}}) {
314
448
push @output, $_;
452
my ($hash) = new Digest::MD5;
319
453
foreach (@output) {
320
454
#print "Adding |$_| to hash\n";
323
$rec->{pilothash} = $hash->hexdigest;
457
$rec->{'pilothash'} = $hash->hexdigest;
326
for($i=0;$i<@output;$i++) {
460
for ($i=0;$i<@output;$i++) {
327
461
last if $output[$i] =~ /^S/;
329
$rec->{pilotexcept} += 0;
330
my(@US) = @{$rec->{unhashedscript}};
331
unshift @US, "S\t#Pilot: 1 $pilotname $rec->{pilothash} $rec->{pilotexcept} $rec->{pilotid}";
463
$rec->{'pilotexcept'} += 0;
465
@US = @{$rec->{'unhashedscript'}} if defined $rec->{'unhashedscript'};
466
unshift @US, "S\t#Pilot: 1 $pilotname $rec->{'pilothash'} $rec->{'pilotexcept'} $rec->{'pilotid'}";
332
467
splice @output, $i, 0, @US;
335
print "Generated record |",join("\n", @output),"|\n";
470
msg( "Generated record |" . join("\n", @output). "|\n" ) if ($PREFS->{'Debug'} > 2);
337
472
join("\n",@output);
475
############################################################
477
############################################################
340
478
sub PrintPlanRecord {
344
$output = DatePerlToPlan($rec->{date});
346
$output .= " ".TimePerlToPlan($rec->{time})."-".
347
TimePerlToPlan($rec->{time}+$rec->{length});
482
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
483
gmtime($rec->{'date'});
486
$output = "$year/$mon/$mday";
488
if ($rec->{'time'}) {
489
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
490
gmtime($rec->{'time'});
491
$output .= sprintf(" %02d:%02d-", $hour, $min);
493
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
494
gmtime($rec->{'time'}+$rec->{'length'});
495
$output .= sprintf("%02d:%02d", $hour, $min);
349
$output .= " '".join("\\n",@{$rec->{note}})."'";
350
$output .= " (".join("\\n",@{$rec->{message}}).")" if defined $rec->{message};
497
$output .= " '".join("\\n",@{$rec->{'note'}})."'" if defined $rec->{'note'};
498
$output .= " (".join("\\n",@{$rec->{'message'}}).")" if defined $rec->{'message'};
352
if ($rec->{repeat}) {
354
if ($rec->{repeat}[0]) {
355
push @r, "every " . ($rec->{repeat}[0] / (60*60*24)) . " days";
500
if ($rec->{'repeat'}) {
502
if ($rec->{'repeat'}[0]) {
503
push @r, "every " . ($rec->{'repeat'}[0] / (60*60*24)) . " days";
358
if ($rec->{repeat}[4]) {
506
if ($rec->{'repeat'}[4]) {
359
507
push @r, "every year";
361
if ($rec->{repeat}[3]) {
362
my($i) = $rec->{repeat}[3];
509
if ($rec->{'repeat'}[3]) {
510
my ($i) = $rec->{'repeat'}[3];
364
512
push @r, "the last day of each month";
407
# takes a Plan record in hash format
572
############################################################
574
# Takes a Plan record in hash format
576
############################################################
408
577
sub WritePlanRecord {
409
my($socket, $record) = @_;
410
my($raw) = generaterecord($record);
413
#print "ID is $record->{id}\n";
578
my ($socket, $record) = @_;
579
my ($raw) = generaterecord($record);
581
$record->{'id'} ||= 0;
582
#print "ID is $record->{'id'}\n";
414
583
$raw =~ s/\n/\\\n/g;
415
$raw = "w$file $record->{id} $raw\n";
416
$record->{raw} = $raw;
584
$raw = "w$file $record->{'id'} $raw\n";
585
$record->{'raw'} = $raw;
417
586
SendPlanCommand($socket, $raw);
418
587
$reply = ReadPlanReply($socket);
419
#print "Installing record $record->{id} (PilotID: $record->{pilotid}) in Plan: ", Dumper($record);
588
#print "Installing record $record->{'id'} (PilotID: $record->{'pilotid'}) in Plan: ", Dumper($record);
420
589
# syswrite $socket, $raw, length($raw);
421
590
# sysread $socket, $reply, 1024;
422
591
# print "Reply to installation: |$reply|\n";
423
592
if ($reply =~ /^w[tf](\d+)/) {
593
$record->{'id'} = $1;
425
594
$planRecord{$1} = $record;
426
595
# print "New record id: $1\n";
428
print "Failed write: $reply\n";
597
msg( "Failed write: $reply\n" );
602
############################################################
604
############################################################
433
605
sub LoadPilotRecord {
435
my($record) = $db->getRecord($i);
607
my ($record) = $db->getRecord($i);
437
$pilotID{$record->{id}} = $record;
609
$pilotID{$record->{'id'}} = $record;
611
checkErrNotFound($db);
616
############################################################
442
618
# takes a Plan record in hash format
620
############################################################
443
621
sub DeletePlanRecord {
444
my($socket, $record) = @_;
446
$raw = "d$file $record->{id}\n";
447
# print "Deleting record $record->{id} (PilotID: $record->{pilotid}) in Plan\n";
622
my ($socket, $record) = @_;
624
$raw = "d$file $record->{'id'}\n";
625
# print "Deleting record $record->{'id'} (PilotID: $record->{'pilotid'}) in Plan\n";
448
626
# syswrite $socket, $raw, length($raw);
449
627
SendPlanCommand($socket, $raw);
630
############################################################
452
632
# takes a Palm record in hash format
634
############################################################
453
635
sub WritePilotRecord {
454
my($db, $control, $record) = @_;
636
my ($db, $control, $record) = @_;
638
$record->{'id'} ||= 0;
639
$record->{'category'} ||= 0;
458
641
#print "Installing record in Palm: ",Dumper($record);
460
my($id) = $db->setRecord($record);
643
my ($id) = $db->setRecord($record);
463
$pilotID{$id} = $record;
464
my ($hash) = HashPilotRecord($record);
646
$pilotID{$id} = $record;
647
my ($hash) = HashPilotRecord($record);
465
648
$pilothash{$id} = $hash;
466
$dbname{$id} = $control->{name};
649
$dbname{$id} = $control->{'name'};
650
$record->{'id'} = $id;
657
############################################################
659
############################################################
474
660
sub DeletePilotRecord {
476
my($result) = $db->deleteRecord($id);
662
my ($result) = $db->deleteRecord($id);
477
663
if ($result>=0) {
478
664
delete $pilothash{$id};
479
665
delete $pilotID{$id};
526
715
} elsif (/^R\t/) {
529
$rec->{repeat} = [split(/\s+/, $r)];
718
$rec->{'repeat'} = [split(/\s+/, $r)];
531
push @{$rec->{other}}, $_;
720
push @{$rec->{'other'}}, $_;
533
722
#print "Adding |$_| to hash\n";
536
725
$hash = $hash->hexdigest;
537
#print "Old hash: $hash, New hash: $rec->{pilothash}\n";
538
$rec->{modified} = ($rec->{pilothash} ne $hash);
539
$rec->{note} = \@N if @N;
540
$rec->{script} = \@S if @S;
541
$rec->{unhashedscript} = \@US if @US;
542
$rec->{message} = \@M if @M;
543
$rec->{date} = DatePlanToPerl($date);
544
$rec->{time} = TimePlanToPerl($time);
545
$rec->{length} = TimePlanToPerl($length);
546
$rec->{early} = TimePlanToPerl($early);
547
$rec->{late} = TimePlanToPerl($late);
548
$rec->{color} = $color;
726
#print "Old hash: $hash, New hash: $rec->{'pilothash'}\n";
727
$rec->{'modified'} = (!defined($rec->{'pilothash'}) ||
728
($rec->{'pilothash'} ne $hash));
729
$rec->{'note'} = \@N if @N;
730
$rec->{'script'} = \@S if @S;
731
$rec->{'unhashedscript'} = \@US if @US;
732
$rec->{'message'} = \@M if @M;
733
$rec->{'date'} = DatePlanToPerl($date);
734
$rec->{'time'} = TimePlanToPerl($time);
735
$rec->{'length'} = TimePlanToPerl($length);
736
$rec->{'early'} = TimePlanToPerl($early);
737
$rec->{'late'} = TimePlanToPerl($late);
738
$rec->{'color'} = $color;
550
$rec->{suspended} = substr($flags,0,1) ne "-";
551
$rec->{private} = substr($flags,1,1) ne "-";
552
$rec->{noalarm} = substr($flags,2,1) ne "-";
553
$rec->{hide_month} = substr($flags,3,1) ne "-";
554
$rec->{hide_year} = substr($flags,4,1) ne "-";
555
$rec->{hide_week} = substr($flags,5,1) ne "-";
556
$rec->{hide_yearover} = substr($flags,6,1) ne "-";
557
$rec->{d_flag} = substr($flags,7,1) ne "-";
740
$rec->{'suspended'} = substr($flags,0,1) ne "-";
741
$rec->{'private'} = substr($flags,1,1) ne "-";
742
$rec->{'noalarm'} = substr($flags,2,1) ne "-";
743
$rec->{'hide_month'} = substr($flags,3,1) ne "-";
744
$rec->{'hide_year'} = substr($flags,4,1) ne "-";
745
$rec->{'hide_week'} = substr($flags,5,1) ne "-";
746
$rec->{'hide_yearover'} = substr($flags,6,1) ne "-";
747
$rec->{'d_flag'} = substr($flags,7,1) ne "-";
748
$rec->{'locked'} = 1;
561
$rec->{exceptions} = [map(DatePlanToPerl($_), @E)] if @E;
751
$rec->{'exceptions'} = [map(DatePlanToPerl($_), @E)] if @E;
563
753
$planRecord{$i} = $rec;
566
756
#print Dumper($rec);
759
############################################################
761
############################################################
569
762
sub HashPilotRecord {
572
$hash->add($record->{raw});
764
my ($hash) = new Digest::MD5;
765
$hash->add($record->{'raw'});
573
766
$hash->hexdigest;
770
############################################################
772
############################################################
577
773
sub doafterplan {
579
$ticklecount = 0; # Reset ticklecount
580
$doticklecount = 100; # Tickle every 100 loop
582
my($db,$socket,$control) = @_;
583
print "After stuff:\n";
585
# This batch of code scans for Plan records with identical Pilot IDs,
586
# presumambly caused by duplicating a plan record. We remove the ids
587
# from the duplicates. The weird sort is magic to prefer keeping the id
588
# (and thus leaving unmodified) of an otherwise unmodified record.
774
my ($db,$socket,$control) = @_;
775
msg( "After stuff:\n" ) if ($PREFS->{'Debug'} > 2);
777
##################################################################
778
# This batch of code scans for Plan records with identical Pilot
779
# IDs, presumambly caused by duplicating a plan record. We remove
780
# the ids from the duplicates. The weird sort is magic to prefer
781
# keeping the id (and thus leaving unmodified) of an otherwise
783
##################################################################
590
my (@uniq) = sort {$a->{pilotid} <=> $b->{pilotid} or $a->{modified} <=> $b->{modified}} grep {exists $_->{pilotid}} values %planRecord;
785
my (@uniq) = sort {$a->{'pilotid'} <=> $b->{'pilotid'} or $a->{'modified'} <=> $b->{'modified'}} grep {exists $_->{'pilotid'}} values %planRecord;
592
787
for($i=@uniq-1;$i>=1;$i--) {
593
788
#print "Checking plan record: ", Dumper($uniq[$i]),"\n";
594
if ($uniq[$i]->{pilotid} == $uniq[$i-1]->{pilotid}) {
595
delete $uniq[$i]->{pilotid};
596
$planID{$uniq[$i-1]->{pilotid}} = $uniq[$i-1];
789
if ($uniq[$i]->{'pilotid'} == $uniq[$i-1]->{'pilotid'}) {
790
delete $uniq[$i]->{'pilotid'};
791
$planID{$uniq[$i-1]->{'pilotid'}} = $uniq[$i-1];
597
792
#print "... A dup, blessed be ye without id, and be ye modified.\n";
598
$uniq[$i]->{modified} = 1;
793
$uniq[$i]->{'modified'} = 1;
602
# Use our saved Pilot ID cache to detect deleted Plan records.
603
# This will not catch deleted Plan records that were never assigned
604
# a Pilot ID, but that is OK because such records do not have to be removed
797
######################################################################
798
# Use our saved Pilot ID cache to detect deleted Plan records. This
799
# will not catch deleted Plan records that were never assigned a
800
# Pilot ID, but that is OK because such records do not have to be
801
# removed from the Palm.
802
######################################################################
803
my ($loop_count) = (0);
608
806
foreach (keys %pilothash) {
610
808
# Palm records originally downloaded from a different Plan database
611
809
# are off-limits during this pass.
613
next if $dbname{$_} ne $control->{name};
811
next if $dbname{$_} ne $control->{'name'};
616
814
# print "Palm cached ID: $_\n";
617
815
if (not defined $planID{$_} and not $exceptID{$_}) {
618
816
#print "Deleted plan record, with Pilot ID $_\n";
619
$planID{$_}->{deleted} = 1;
620
$planID{$_}->{pilotid} = $_;
621
$planID{$_}->{id} = $del;
817
$planID{$_}->{'deleted'} = 1;
818
$planID{$_}->{'pilotid'} = $_;
819
$planID{$_}->{'id'} = $del;
622
820
$planRecord{$del} = $planID{$_};
825
msg( "Palm loop\n" ) if ($PREFS->{'Debug'} > 2);
629
827
foreach (keys %pilotID) {
828
$dlp->tickle unless (++$loop_count % 50);
631
# Tickle the pilot so it will not time out during this
633
if ($ticklecount >= $doticklecount) {
638
830
# Palm records originally downloaded from a different Plan database
639
831
# are off-limits during this pass.
641
next if $dbname{$_} ne $control->{name};
644
print "Palm record: ",PrintPilotRecord($pilotID{$_}),"\n";
833
next if $dbname{$_} ne $control->{'name'};
836
msg( "Palm record: " . PrintPilotRecord($pilotID{$_}) . "\n" ) if ($PREFS->{'Debug'} > 1);
645
837
#print "Palm record: ",Dumper($pilotID{$_}),"\n";
646
if ($pilotID{$_}->{deleted} || $pilotID{$_}->{archived}) {
838
if ($pilotID{$_}->{'deleted'} || $pilotID{$_}->{'archived'}) {
648
840
# # At this point are seeing Palm records marked as deleted or
649
841
# # archived. In the case of a slow sync, deleted records may not
737
938
$exceptID{$_} = 1;
739
print "Log: Palm record modified while Plan record deleted, but new Palm record unsyncable\n";
940
msg( "Palm record modified while Plan record deleted, but new Palm record unsyncable\n" );
742
943
WritePlanRecord($socket, $record);
744
print "Log: Palm record modified while Plan record deleted\n";
945
msg( "Palm record modified while Plan record deleted\n" ) if ($PREFS->{'Debug'} > 1);
747
} elsif ($pilotID{$_}->{modified} and $planID{$_}->{modified}) {
749
# The Palm record has a matching _modified_ Plan record.
751
# TODO: Use a comparator function to verify that the records
752
# are actually substantially different. If not, simply skip
755
# This is collision with an ugly, but lossless, solution.
756
# Neither the Palm or Plan record is inherantly preferable,
757
# so we duplicate each record on the other side, severing
758
# the link between the original new records, forging two new
759
# links and two new records, one on each side.
761
# Action: Install the Palm record in Plan as a new,
762
# distinct, record, and install the Plan record on the Palm
763
# as a new, distinct, record.
765
print "Log: Conflicting modified Plan and Palm records\n";
948
} elsif ($pilotID{$_}->{'modified'} and $planID{$_}->{'modified'}) {
951
############################################
952
# The Palm record has a matching _modified_
955
# TODO: Use a comparator function to verify
956
# that the records are actually
957
# substantially different. If not, simply
960
# This is collision with an ugly, but
961
# lossless, solution. Neither the Palm or
962
# Plan record is inherantly preferable, so
963
# we duplicate each record on the other
964
# side, severing the link between the
965
# original new records, forging two new
966
# links and two new records, one on each
969
# Action: Install the Palm record in Plan as
970
# a new, distinct, record, and install the
971
# Plan record on the Palm as a new,
973
############################################
976
msg( "Conflicting modified Plan and Palm records\n" );
768
my($record) = RecordPlanToPilot($planID{$_});
979
my ($record) = RecordPlanToPilot($planID{$_});
769
980
if (not defined $record) {
770
981
# The Plan record is not translatable to a Palm record.
772
983
# Action: Abort the install.
774
print "Log: Conflicting Plan record unsyncable.\n";
985
msg( "Conflicting Plan record unsyncable.\n" );
777
my($id) = WritePilotRecord($db, $control, $record);
988
my ($id) = WritePilotRecord($db, $control, $record);
779
990
#$db->setRecord($record);
781
992
#my ($hash) = HashPilotRecord($record);
782
993
#$pilothash{$id} = $hash;
784
#$record->{id} = $id;
995
#$record->{'id'} = $id;
785
996
#$pilotID{$id} = $record;
786
997
#$dbname{$id} = $dbname;
788
$planID{$_}->{pilotid} = $id;
999
$planID{$_}->{'pilotid'} = $id;
790
$planID{$_}->{modified} = 0;
1001
$planID{$_}->{'modified'} = 0;
792
1003
WritePlanRecord($socket, $planID{$_});
794
print "ID of new Palm record is $id\n";
1005
msg( "ID of new Palm record is $id\n" ) if ($PREFS->{'Debug'} > 2);
799
my($record) = RecordPilotToPlan($pilotID{$_});
1010
my ($record) = RecordPilotToPlan($pilotID{$_});
800
1011
if (not defined $record) {
801
1012
# The Palm record is not translatable to a Plan record.
892
1100
# Remove the record from the exception cache if it has been
893
1101
# modified: perhaps it is not exceptional any more
895
delete $record->{pilotexcept} if $record->{modified};
1103
delete $record->{'pilotexcept'} if $record->{'modified'};
897
1105
# If this is a fast sync, it's possible the record hasn't been
1108
# This is dead code. Fast sync was never
1109
# implemented, so $slowsync is always 1. I'm
1110
# leaving it here as a hint in case someone
1111
# ever gets around to implementing fast sync.
1112
# But it looks incorrect to me:
1113
# LoadPilotRecord takes an index, not an
900
1116
if (!$slowsync and defined $pid and not exists $pilotID{$pid}) {
901
my($precord) = LoadPilotRecord($db, $pid);
1117
my ($precord) = LoadPilotRecord($db, $pid);
902
1118
#$db->getRecord($pid);
903
1119
if (defined $precord) {
904
1120
if (not defined $dbname{$pid}) {
905
$dbname{$pid} = $control->{defaultname};
1121
$dbname{$pid} = $control->{'defaultname'};
907
1123
$pilotID{$pid} = $precord;
911
if (defined $pid and defined $pilotID{$pid} and ($dbname{$pid} ne $control->{name})) {
912
print "Weird: Plan database $control->{name} claims to own Palm record $pid,\n";
913
print "but my ID database says it is owned by $dbname{$pid}. I'll skip it.\n";
1127
if (defined $pid and defined $pilotID{$pid} and ($dbname{$pid} ne $control->{'name'})) {
1128
msg( "Weird: Plan database $control->{'name'} claims to own Palm record $pid,\n" );
1129
msg( "but my ID database says it is owned by $dbname{$pid}. I'll skip it.\n" );
917
1133
#print "Matching pilot record: ", Dumper($pilotID{$pid}),"\n";
919
1135
if (not defined $pid or not defined $pilotID{$pid}) {
920
if (!$record->{pilotexcept}) {
1136
if (!$record->{'pilotexcept'}) {
921
1137
# The Plan record has no matching Palm record
923
1139
# Action: Install the Plan record in Palm, regardless of
924
1140
# changed status
926
print "Action: Install Plan record in Palm.\n";
1142
msg( "Installing Plan record in Palm: ".
1143
PrintPlanRecord($record). "\n" ) if ($PREFS->{'Debug'});
928
1145
#print "Installing plan record in pilot: ",Dumper($record);
929
1146
#print "Trying to install Plan record: ",Dumper($record),"\n";
931
my($newrecord) = RecordPlanToPilot($record);
1148
my ($newrecord) = RecordPlanToPilot($record);
932
1149
if (not defined $newrecord) {
933
1150
# The record is not translatable to a Palm record.
1093
print "Plan delete loop\n";
1305
msg( "Plan delete loop\n" ) if ($PREFS->{'Debug'} > 2);
1095
1307
foreach (keys %planRecord) {
1097
# Tickle the pilot so it will not time out during this
1099
if ($ticklecount >= $doticklecount) {
1308
$dlp->tickle unless (++$loop_count % 100);
1104
my($record) = $planRecord{$_};
1105
my($pid) = $planRecord{$_}->{pilotid};
1310
my ($record) = $planRecord{$_};
1311
my ($pid) = $planRecord{$_}->{'pilotid'};
1106
1312
#print "Plan record: ",Dumper($record),"\n";
1107
print "Plan record: ",PrintPlanRecord($planRecord{$_}),"\n";
1313
msg( "Plan record: " . PrintPlanRecord($planRecord{$_}) . "\n" ) if ($PREFS->{'Debug'} > 1);
1109
1315
# In a fast sync, we might not have loaded the record yet.
1317
# This is dead code. Fast sync was never implemented,
1318
# so $slowsync is always 1. I'm leaving it here as a
1319
# hint in case someone ever gets around to
1320
# implementing fast sync. But it looks incorrect to
1321
# me: LoadPilotRecord takes an index, not an id. -ANK
1111
1323
if (!$slowsync and defined $pid and not exists $pilotID{$pid}) {
1112
my($precord) = LoadPilotRecord($db, $pid);
1324
my ($precord) = LoadPilotRecord($db, $pid);
1113
1325
#$db->getRecord($pid);
1114
1326
if (defined $precord) {
1115
1327
if (not defined $dbname{$pid}) {
1116
$dbname{$pid} = $control->{defaultname};
1328
$dbname{$pid} = $control->{'defaultname'};
1118
1330
$pilotID{$pid} = $precord;
1122
if (defined $pid and defined $pilotID{$pid} and ($dbname{$pid} ne $control->{name})) {
1123
print "Weird: Plan database $control->{name} claims to own Palm record $pid,\n";
1124
print "but my ID database says it is owned by $dbname{$pid}. I'll skip it.\n";
1334
if (defined $pid and defined $pilotID{$pid} and ($dbname{$pid} ne $control->{'name'})) {
1335
msg( "Weird: Plan database $control->{'name'} claims to own Palm record $pid,\n" );
1336
msg( "but my ID database says it is owned by $dbname{$pid}. I'll skip it.\n" );
1128
if ($record->{deleted}) {
1340
if ($record->{'deleted'}) {
1130
1342
# At this point are seeing Palm records marked as deleted or
1131
1343
# archived. In the case of a slow sync, deleted records may not
1367
1585
print C "# default) or read only access. If a database is read-only, any record changes\n";
1368
1586
print C "# on the Palm will be discarded. However, for technical reasons, you must have\n";
1369
1587
print C "# read/write access to the plan database itself.\n";
1372
open(C,"<$controldir/control");
1591
open(C,"<$controldir/control");
1376
my($i,@i) = split(/\s+/, $_);
1595
my ($i,@i) = split(/\s+/, $_);
1381
my($mode, $name, $host) = m/^(?:(wr|ro|rw):)?([^\@]+)(?:\@(.+))?$/;
1382
if (not defined $mode) {
1385
if (not defined $host) {
1386
$host = "localhost";
1388
if ($mode !~ /^rw$/) {
1389
die "Access mode $mode (for Palm '$i') at line $. of $controldir/control unknown or unsupported.\n";
1392
$defaultname = $name.'@'.$host;
1394
push @I, {mode => $mode, name => $name.'@'.$host, dbname => $name, host => $host, port => 5444, read => ($mode =~ /r/), write => ($mode =~ /w/), default => $first, defaultname => $defaultname};
1600
my ($mode, $name, $host) = m/^(?:(wr|ro|rw):)?([^\@]+)(?:\@(.+))?$/;
1601
if (not defined $mode) {
1604
if (not defined $host) {
1605
$host = "localhost";
1607
if ($mode !~ /^rw$/) {
1608
croak "Access mode $mode (for Palm '$i') at line $. of $controldir/control unknown or unsupported.\n";
1611
$defaultname = $name.'@'.$host;
1613
push @I, {mode => $mode, name => $name.'@'.$host, dbname => $name, host => $host, port => $PREFS->{'NetplanPort'}, 'read' => ($mode =~ /r/), 'write' => ($mode =~ /w/), default => $first, defaultname => $defaultname};
1397
1616
$control{$i} = [@I];
1400
if (loadpilotrecords) {
1402
foreach (@{$control{$pilotname}}) {
1403
$sawName{$_->{name}} = 1;
1406
if (!@{$control{$pilotname}}) {
1407
print "No plan databases are registered for the '$pilotname' Palm. Please\n";
1408
print "edit $controldir/control and add one or more databases.\n";
1411
open (I, "<$controldir/ids.$pilotname");
1621
############################################################
1623
############################################################
1629
# initialize variables that may still be set from last sync (which
1630
# can happen when conduitSync is called from PilotManager).
1639
$pilotname = $db = $slowsync = $file = $maxseed = $netplanversion = undef;
1643
$pilotname = $info->{'name'} . "_ " . $info->{'userID'};
1644
$pilotname =~ s/[^A-Za-z0-9]+/_/g;
1646
foreach (@{$control{$pilotname}}) {
1647
$sawName{$_->{'name'}} = 1;
1650
if (open (I, "<$controldir/ids.$pilotname")) {
1412
1651
foreach (<I>) {
1414
my($id, $hash, $except, $dbname) = split(/\s+/, $_);
1415
$pilothash{$id} = $hash;
1416
$exceptID{$id} = $except;
1417
if (not defined $dbname or not length $dbname) {
1418
$dbname = $control{$pilotname}->[0]->{name};
1420
$dbname{$id} = $dbname if defined $dbname and length $dbname;
1421
#print Dumper({dbname=>$dbname{$id}});
1422
if (not defined $sawName{$dbname}) {
1423
print "Warning! The ID file, $controldir/ids.$pilotname, lists a record as belonging\n";
1424
print "to database $dbname, but the control file $controldir/control does not list this\n";
1425
print "this database. If you have renamed a database, please edit $controldir/ids.$pilotname\n";
1426
print "so all references to this database match the new name.\n";
1427
print "\nIf you wish to delete all on the Palm that were originally from $dbname, then\n";
1428
print "delete the database name from the end of each record's line.\n";
1429
print "To merge the records into the default database, delete each affected line entriely.\n";
1653
my ($id, $hash, $except, $dbname) = split(/\s+/, $_);
1654
$pilothash{$id} = $hash;
1655
$exceptID{$id} = $except;
1656
if (not defined $dbname or not length $dbname) {
1657
$dbname = $control{$pilotname}->[0]->{'name'};
1659
$dbname{$id} = $dbname if defined $dbname and length $dbname;
1660
#print Dumper({dbname=>$dbname{$id}});
1661
if (not defined $sawName{$dbname}) {
1662
msg( "Warning! The ID file, $controldir/ids.$pilotname, lists a record as belonging\n" );
1663
msg( "to database $dbname, but the control file $controldir/control does not list this\n" );
1664
msg( "this database. If you have renamed a database, please edit $controldir/ids.$pilotname\n" );
1665
msg( "so all references to this database match the new name.\n" );
1666
msg( "\nIf you wish to delete all on the Palm that were originally from $dbname, then\n" );
1667
msg( "delete the database name from the end of each record's line.\n" );
1668
msg( "To merge the records into the default database, delete each affected line entirely.\n" );
1431
$sawName{$dbname} = 1;
1436
foreach (keys %pilotID) {
1437
if (not defined $dbname{$_}) {
1438
$dbname{$_} = $control{$pilotname}->[0]->{name};
1670
$sawName{$dbname} = 1;
1678
if (loadpilotrecords) {
1680
if (!@{$control{$pilotname}}) {
1681
msg( "No plan databases are registered for the '$pilotname' Palm. Please\n" );
1682
msg( "edit $controldir/control and add one or more databases.\n" );
1685
foreach (keys %pilotID) {
1686
if (not defined $dbname{$_}) {
1687
$dbname{$_} = $control{$pilotname}->[0]->{'name'};
1445
1691
foreach (@{$control{$pilotname}}) {
1446
next if not defined $_->{host}; # Sigh. Autoviv problem.
1692
next if not defined $_->{'host'}; # Sigh. Autoviv problem.
1450
1696
# Delete deleted & archived records