File: conduits.texi

package info (click to toggle)
coldsync 3.0%2Bpre3-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 3,180 kB
  • ctags: 2,036
  • sloc: ansic: 20,386; perl: 2,302; cpp: 1,640; yacc: 1,102; lex: 802; makefile: 586; sh: 177
file content (2023 lines) | stat: -rw-r--r-- 68,259 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
\input texinfo	@c -*-texinfo-*-
@c
@c $Id: conduits.texi,v 1.17 2001/06/26 05:42:32 arensb Exp $
@c
@c %**start of header
@setfilename conduits.info
@settitle ColdSync Conduits
@dircategory ColdSync Documentation
@direntry
* Conduits: (conduits.info).    Specification and Hacker's Guide.
@end direntry
@setchapternewpage odd
@c %**end of header

@include version.texi

@ifinfo
This file documents ColdSync's conduits: what they do and how to write
them.

Copyright @copyright{} 2000-2001 Andrew Arensburger.

Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
@end ifinfo

@titlepage
@title ColdSync Conduits
@subtitle Specification and Hacker's Guide
@subtitle Version @value{VERSION}
@author Andrew Arensburger

@page
@vskip 0pt plus 1filll
Copyright @copyright 2000 Andrew Arensburger.

Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.

For external use only. Do not attempt to read this manual while
operating a motor vehicle.

@end titlepage

@node Top, Overview, (dir), (dir)
@comment  node-name,  next,  previous,  up
@unnumbered Introduction

	This manual is intended as a reference. Each chapter and, to the
extent possible, each section, is intended to stand on its own.
Consequently, if you read it from beginning to end, expect a certain
amount of repetition.

	The first chapter, ``Overview,'' is for the general user. It
explains what conduits are, why you would want to use one, and how to
set Coldsync up to use them.

	The second chapter, ``Tutorial,'' is a quick-start guide for
those who want to write their own conduits. It presents a short but
functional conduit in Perl, with annotations and comments, as well as a
set of recommendations for conduit authors.

	The third chapter, ``Specification,'' formally describes
interaction between ColdSync and conduits, what conduits are allowed to
do, and what they are forbidden from doing. This chapter is no
substitute for the source, but is probably easier to read.

@menu
* Overview::                    
* Tutorial::                    
* Specification::               
* Glossary::                    
* Index::                       

@detailmenu
 --- The Detailed Node Listing ---

Overview

* Kinds of Databases::          prc and .pdb explained.
* Creators and Types::          What is this database? Which application
				 does it go with?
* Overview-Flavors::            What the different flavors of conduit do.
* Preferences::                 Application customizations.

Tutorial

* Conduit Workings::            An overview of how conduits work.
* todo-dump::                   A simple conduit.
* pine-aliases::                A slightly more complex conduit.
* Style and Warnings::          Tips on writing good conduits.

@code{pine-aliases}

* &DoFetch::                    The Fetch part of the conduit
* &DoDump::                     The Dump part of the conduit
* Helper Functions::            Useful functions
* pine-aliases Limitations::    Real-world considerations

Specification

* Conduit Input::               What ColdSync sends to the conduit.
* Conduit Output::              What the conduit may send to ColdSync.
* SPC::                         Serialized Procedure Call protocol
* Conduit Flavors::             The different types of conduit.
* Status Codes::                Numerical error codes and thier meanings.

Standard Input

* Predefined Headers::          Headers with standard meanings

Conduit Flavors

* Sync conduits::               Conduits that run during the main sync
* Fetch Conduits::              Conduits that run before the main sync
* Dump Conduits::               Conduits that run after the main sync
* Install conduits::            Conduits that run before new databases are
                                  installed.

@end detailmenu
@end menu

@node Overview, Tutorial, Top, Top
@comment  node-name,  next,  previous,  up
@chapter Overview

@cindex Backups
	By default, ColdSync is simply a fancy way of keeping a backup
of what's on your Palm. This is all well and good, but what you'd really
like is for your Palm to share its information with the other tools you
have on your desktop.

	That's where conduits come in. A conduit is an external program
that ColdSync runs at certain times; you can use a conduit to extend
ColdSync's behavior.

	ColdSync is a generalist: it doesn't know a Calendar from a
MineSweeper, so it has to treat all applications and their data in a
fairly generic manner. Conduits, then, are specialists: they usually
know all about one particular type of application and nothing else. This
allows them to do the Right Thing for that particular application.

@menu
* Kinds of Databases::          prc and .pdb explained.
* Creators and Types::          What is this database? Which application
				 does it go with?
* Overview-Flavors::            What the different flavors of conduit do.
* Preferences::                 Application customizations.
@end menu

@node Kinds of Databases, Creators and Types, Overview, Overview
@comment  node-name,  next,  previous,  up
@section Kinds of Databases

@cindex Databases vs. files
	Since Palms don't have disks, everything has to be in memory.
Consequently, PalmOS doesn't distinguish between RAM and files, the way
other operating systems do. Instead, everything is a database.

	There are two types of database:
@emph{record databases} and
@emph{resource databases}.

@cindex Record database
@cindex Database, record
	Record databases consist, naturally, of records. These are the
databases that hold all of your information. The ``AddressDB'' database,
for instance, has one record for each address in the Address Book
application.

@cindex Resource database
@cindex Database, resource
@cindex Resource type
@cindex Resource identifier
	Resource databases are a bit more organized: each entry has a
four-letter type, and a numerical identifier. Most resource databases
are applications, containing one or more @samp{code} entries, perhaps a
few @samp{Tbmp} (bitmap image) entries, and so forth. The types are
documented strings that indicate what the resource is: @samp{code}
resources contain executable code, @samp{Tbmp} resources are always
bitmap images, and so forth. The numerical identifiers serve to tell
resources of the same type apart.

@cindex Macintosh
	Not coincidentally, resource databases are very similar to the
resource fork in MacOS files.

	Note that, for technical reasons, resource datatabases do not
lend themselves well to syncing, and ColdSync pretty much ignores them.

@node Creators and Types, Overview-Flavors, Kinds of Databases, Overview
@comment  node-name,  next,  previous,  up
@section Creators and Types

@cindex Database creator
@cindex Database type
	Each database also has a four-letter @emph{type} and a
four-letter @emph{creator}. Each PalmOS application has a unique creator
string. Every database that it creates has the the same creator string
as the application. For example, the built-in Datebook application has
the creator @samp{date}. The record database that contains the Datebook
entries also has the creator @samp{date}.

	An application can potentially create several databases to
represent different kinds of data. The built-in To Do application
creates three separate record databases: @file{ExpenseDB}, with creator
@code{exps} and type @code{DATA}; @file{CitiesDB}, with creator
@code{exps} and type @code{city}; @file{VendorsDB}, with creator
@code{exps} and type @code{vend}. All of these databases have the same
creator field as the application that created them, but have different
types, since they contain different kinds of information.

@cindex @file{.coldsyncrc}
@cindex @code{kab}
	Since each conduit typically handles only one specific kind of
database, you have to tell ColdSync what it is. For instance, to run the
@file{kab-fetch} conduit on databases with creator @samp{addr} and type
@samp{DATA}, you would add the following to your @file{.coldsyncrc}
file:

@example
@cartouche
conduit fetch @{
        path: "/usr/local/libexec/coldsync/kab-fetch";
        type: addr/DATA;
@}
@end cartouche
@end example

@cindex Wildcards
	An asterisk in a creator or type specification acts as a wildcard:
@example
        type: addr/*;
@end example

@noindent
the conduit will be run for every database with creator @samp{addr},
regardless of type. Likewise:

@example
        type: */DATA;
@end example

@noindent
the conduit will be run for every database with type @samp{DATA},
regardless of creator (though this isn't usually very useful). Finally,
you can specify wildcards for both the creator and type:

@example
        type: */*;
@end example

@noindent
In this case, the conduit will be run for every database.

@node Overview-Flavors, Preferences, Creators and Types, Overview
@comment  node-name,  next,  previous,  up
@section Conduit Flavors

@cindex Flavors
	ColdSync defines several @emph{flavors} of conduits. Each flavor
performs a different function and is designed for a different purpose.
Currently, four flavors are implemented.

@cindex Flavor, Sync
@cindex Sync conduits
	@emph{Sync} conduits implement the synchronization between a
database on the Palm and its backup copy on the desktop, what is
referred to here as the main sync.

	The generic default conduit is a Sync conduit. It reads records
from the Palm, compares them to what's on the desktop, and uploads or
downloads records as necessary to ensure that both the Palm and the
desktop have identical, up-to-date data.

	Since Sync conduits can talk directly to the Palm, they are the
most powerful, but also the most complex type of conduit. In the most
common case, where all you want to do is synchronize data between the
Palm and a file or database, it is simpler to write a Fetch conduit and
a Dump conduit. In some cases, however, this is not possible: if you
want to set the time on the Palm, your conduit needs to do so while the
Palm is connected. For this, you would need to use a Sync conduit.

@cindex Flavor, Fetch
@cindex Fetch conduits
	@emph{Fetch} conduits run before the main sync. The idea is that
a Fetch conduit will modify its database before ColdSync compares it to
the version on the Palm. For instance, a conduit might read a list of
scheduled meetings from @file{/usr/local/libdata/meetings} and make sure
that they're all in the Address Book database in your backup directory.
Then ColdSync wil make sure that any changes to the meeting list will be
reflected on your Palm.

	To specify a Fetch conduit in your @file{.coldsyncrc}, use
@code{fetch} or @code{pre-fetch} as the flavor argument to
@code{conduit}, e.g.:

@example
@cartouche
conduit fetch @{
        path: "/usr/local/libexec/coldsync/get-meetings";
        type: date/DATA;
@}
@end cartouche
@end example

@cindex Multiple conduits
@cindex Conduits, multiple
	If you specify several conduits of the same flavor for the same
database, they will be run one at a time, in the order in which they
appear in @file{.coldsyncrc}. This allows you to chain the effects of
several conduits. Bear in mind, however, that they may interfere with
each other

@cindex Flavor, Dump
@cindex Dump conduits
	@emph{Dump} conduits run after the main sync. The intended
purpose of a Dump conduit is to read its database after ColdSync is done
with it, and copy its contents to some other file, in some other format.
For instance, if you have made changes to your address list on the Palm,
ColdSync will make sure that the backup copy in your home directory
contains the same information as the Address Book database on the Palm.
After that's done, a conduit can export this list in your favorite
address book application's format.

	To specify a Dump conduit in your @file{.coldsyncrc}, use
@code{dump} or @code{post-dump} as the flavor argument to
@code{conduit}, e.g.:

@example
@cartouche
conduit dump @{
        path: "/usr/local/libexec/coldsync/save-meetings";
        type: date/DATA;
@}
@end cartouche
@end example

@cindex Syncing, one-way
@cindex Desktop overwrites handheld
	If you only have a Fetch conduit defined for a database, it can
implement ``Desktop overwrites handheld'' syncing, where the master copy
is kept on the desktop machine, and any changes made on the Palm are
lost.

@cindex Handheld overwrites desktop
	Conversely, if you only have a Dump conduit defined for a
database, it can implement ``Handheld overwrites desktop'' syncing,
where the master copy is kept on the Palm, and any changes made on the
desktop machine are lost.

@cindex Syncing, two-way
	If you have both a Fetch and a Dump conduit defined for a
database, they can implement two-way syncing, where changes made on the
desktop are propagated to the Palm and vice versa. Since the logic of
syncing can get rather hairy, especially in difficult cases, it's easier
to write two simple conduits, a Fetch and a Dump, than it is to write a
single conduit that does a two-way sync.

@cindex Flavor, Install
@cindex Install conduits
	@emph{Install} conduits provide a hook for manipulating
databases before they're installed. In the installation phase, ColdSync
looks for databases in the install directory (@file{~/.palm/install} by
default) and runs any applicable Install conduits on them. After that,
it installs any remaining files in the install directory.

	If you don't like the built-in Datebook application, but people
give you databases in this format, you could use an Install conduit to
convert them to your favorite format. Or, depending on how bleak the
future becomes, you may find it necessary to have an Install conduit
check new databases for viruses, and delete them if they're infected.

@node Preferences,  , Overview-Flavors, Overview
@comment  node-name,  next,  previous,  up
@section Preferences

@cindex Preferences
	The Palm has two special databases, ``Saved Preferences'' and
``Unsaved Preferences,'' that contain preferences. Preferences are the
PalmOS equivalent of dot files: they are neither applications nor data,
but rather user preferences that affect how an application runs. The
signature for outgoing mail in the Mail application is a preference. So
is the ``Owned by'' text you can set in the Prefs application.

	ColdSync conduits can request to be given the value of a
preference and act accordingly. For instance, a mail conduit might
request the signature preference and append it to outgoing messages.

@cindex Saved preferences
@cindex Unsaved preferences
@cindex God
	There are two types of preferences: saved and unsaved. I have no
idea what the difference is between these two types. Perhaps saved
preferences are those that have found God.

@node Tutorial, Specification, Overview, Top
@comment  node-name,  next,  previous,  up
@chapter Tutorial

@cindex Programming languages
@cindex Perl
	This chapter shows, by example, how to write ColdSync conduits.
The examples are written in Perl, simply because I happen to like it.
However, you can use any language you like to write conduits.

	The example conduits in this chapter use the @code{ColdSync.pm}
module that's part of the ColdSync distribution, and also the
@code{p5-Palm} module from@*
@uref{http://www.ooblick.com/software/coldsync/}.

@menu
* Conduit Workings::            An overview of how conduits work.
* todo-dump::                   A simple conduit.
* pine-aliases::                A slightly more complex conduit.
* Style and Warnings::          Tips on writing good conduits.
@end menu

@node Conduit Workings, todo-dump, Tutorial, Tutorial
@comment  node-name,  next,  previous,  up
@section Conduit Workings: A Quick Overview

	A conduit is simply a program, one that follows the ColdSync
conduit protocol (@pxref{Specification}).

	In a nutshell, ColdSync runs a conduit with two command-line
arguments: the string @code{conduit}, and another that indicates the
conduit flavor, either @code{fetch} or @code{dump}.

	ColdSync then writes a set of header lines to the conduit's
standard input, e.g.,

@example
@cartouche
Daemon: coldsync
Version: @value{VERSION}
InputDB: /homes/arensb/.palm/backup/ToDoDB.pdb
@cindex Moon, phase of
Phase-of-the-Moon: lunar eclipse
@end cartouche
@end example

@noindent
followed by a blank line.

	The conduit reports its status back to ColdSync by writing to
standard output, e.g.:

@example
@cartouche
202 Success.
@end cartouche
@end example

	The three-digit code indicates whether this is an error message,
a warning, or an informational message. @xref{Status Codes}. The rest of
the line is a text message to go with the status code. It is not parsed
by ColdSync; it is intended for human readers.

	A conduit should print such a message before exiting, to
indicate whether it was successful or not.

@node todo-dump, pine-aliases, Conduit Workings, Tutorial
@comment  node-name,  next,  previous,  up
@section @code{todo-dump}

	Let's write a Dump conduit that writes the current To Do list to
a file. This is a single-flavor conduit, so we'll use the following
template:

@cindex Template, single-flavor conduit
@example
#!/usr/bin/perl
use Palm::ToDo;
use ColdSync;

# Declarations and such go here.

StartConduit("dump");

# Actual conduit code goes here

EndConduit;
@end example

	The @code{Palm::ToDo} module is a parser for ToDo databases; it
adds hooks so that when the conduit reads the ToDo database, its records
will be parsed into structures that can easily be manipulated by a Perl
program (see Palm::ToDo(1)).

	The @code{ColdSync} module provides a framework for writing
conduits, and defines the @code{StartConduit} and @code{EndConduit}
functions.

	@code{StartConduit} takes one option indicating the conduit
flavor (Dump, in this case). It checks the command-line options and
makes sure the conduit was invoked with the proper flavor. It reads the
headers from standard input and puts them in @code{%HEADERS}. If the
conduit was given a @code{InputDB} header, @code{StartConduit} loads the
database into @code{$PDB}.

	@code{EndConduit} takes care of cleaning up when the conduit
finishes. For Fetch conduits, it writes @code{$PDB} to the file given by
@code{$HEADERS@{OutputDB@}}.

	Starting with this template, all we need to do now is to insert
the actual code:

@example
#!/usr/bin/perl
use Palm::ToDo;
use ColdSync;

$OUTFILE = "$ENV@{HOME@}/TODO";           # Where to write the output

format TODO =
@@ @@ @@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$marker, $priority, $description
      ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~
        $note
.

StartConduit("dump");

open OUTFILE, "> $OUTFILE" or die("401 Can't open $OUTFILE: $!\n");
select OUTFILE;
$~ = TODO;                      # Set the output format

foreach $record (@@@{$PDB->@{"records"@}@})
@{
        $marker         = ($record->@{"completed"@} ? "x" : "-");
        $priority       = $record->@{"priority"@};
        $description    = $record->@{"description"@};
        $note           = $record->@{"note"@};

        write;
@}

close OUTFILE;

EndConduit;
@end example

	The @code{ColdSync.pm} module provides wrappers for Perl's
@code{die} and @code{warn} functions, so that their messages will be
passed back to ColdSync. The rest of the code should be
self-explanatory.

@node pine-aliases, Style and Warnings, todo-dump, Tutorial
@comment  node-name,  next,  previous,  up
@section @code{pine-aliases}

@cindex Pine (mail reader)
@cindex Multi-flavor conduit
@cindex Conduit, multi-flavor
	Now that we've seen a trivial conduit, let's take a look at a
slightly more complicated one: a conduit to synchronize addresses in the
Palm Address Book database with those in Pine's address book.

	Note that this is still just a tutorial conduit: we'll be making
some simplifying assumptions that will make this conduit unsuitable for
use in the real world.

	Having said this, let's take a look at the conduit:

@cindex Template, multi-flavor conduit
@example
#!/usr/bin/perl
use Palm::Address;
use ColdSync;

$PINE_ALIASES = "$ENV@{HOME@}/.addressbook";

ConduitMain(
        "fetch" => \&DoFetch,
        "dump"  => \&DoDump,
        );
@end example

@cindex @code{ConduitMain}
	Unlike @code{todo-dump} (@pxref{todo-dump}), @code{pine-aliases}
is a multi-flavor conduit: it can be used either as a Fetch conduit or
as a Dump conduit. For this reason, we use @code{ConduitMain} rather
than @code{StartConduit}/@code{EndConduit}.

	There are several reasons why one might want to write a
multi-flavor conduit like this one. The first is that the Fetch and Dump
functions really just implement the two halves of a single conduit that
performs two-way synchronization between the Palm and Pine.

	Secondly, we'll be writing some convenience functions that will
be used by both @code{&DoFetch} and @code{&DoDump}, so it makes sense to
keep them together.

	Finally, in many cases, the two things that one is synchronizing
(in this case the Palm Address Book and Pine's addressbook file) don't
contain the same information, or represent it in such a way that it's
difficult to convert one to the other, and the conduit writer must
resort to a number of tricks to perform the sync correctly.

	For instance, the Fetch conduit for @code{kab} tries to save
each person's fax number in the Palm database. If there is no fax field,
it will append ``(212) 123-4567 (fax)'' to the ``Other'' field.
Therefore, the @code{kab} Dump conduit must look for the fax number in
the ``Other'' field as well as the ``Fax'' field. Keeping the two
conduits together in the same file makes it easier to keep track of
these sorts of tricks and make sure that the two conduits work properly.

@cindex @code{$PDB}
@cindex @code{%HEADERS}
	@code{ConduitMain} takes as its arguments a table that tells
which function to call for each flavor. When the conduit is run,
@code{ConduitMain} parses and checks the command-line arguments, reads
the headers from standard input and stores them in the hash
@code{%HEADERS}, and calls the appropriate function. If an
@code{InputDB} header was specified, that file will be read into the
variable @code{$PDB}. Then it calls the flavor-specific function (in
this case, either @code{&DoFetch} or @code{&DoDump}) to do the actual
work of the conduit, and finally cleans up: for Fetch conduits, it
writes the contents of @code{$PDB} to the file specified by the
@code{OutputDB} header.

@menu
* &DoFetch::                    The Fetch part of the conduit
* &DoDump::                     The Dump part of the conduit
* Helper Functions::            Useful functions
* pine-aliases Limitations::    Real-world considerations
@end menu

@node &DoFetch, &DoDump, pine-aliases, pine-aliases
@comment  node-name,  next,  previous,  up
@subsection @code{&DoFetch}

	The @code{&DoFetch} function reads Pine's alias file. For each
address that it finds there, it updates the email address in the
appropriate record in the Palm database.

@example
sub DoFetch
@{
        my %aliases = ();

        if (!defined($PDB))
        @{
                $PDB = new Palm::PDB;
                $PDB->Load($HEADERS@{"OutputDB"@}) or
                        die "502 No input database\n";
        @}

        open ALIASES, "< $PINE_ALIASES" or
                die "Can't open $PINE_ALIASES: $!\n";

        while (<ALIASES>)
        @{
                my $alias;
                my $addr;
                my $fullname;
                my @@rest;

                chomp;
                ($alias, $fullname, $addr, @@rest) = split /\t/;
                $aliases@{$fullname@} = $addr;
        @}

        my $fullname;
        my $address;

        while (($fullname, $address) = each %aliases)
        @{
                my $record = &find_person($PDB, $fullname);

                next if !defined($record);      # No entry in PDB

                my $pdb_addr = &get_address($record);

                next if $pdb_addr eq $address;
                                # It already matches. Ignore it.

                print STDOUT "101 Setting $fullname -> $address\n";
                &set_address($record, $address);
        @}
        close ALIASES;

        return 1;               # Success
@}
@end example

	The @code{InputDB} header is optional for Fetch conduits, so
@code{$PDB} may not have been initialized. But @code{pine-aliases} does
not create a new database from scratch; it only modifies an existing
one. If no @code{InputDB} database was specified, we load the database
specified by @code{OutputDB}.

	The body of @code{&DoFetch} is divided into two phases: in the
first phase, it reads the Pine alias file and builds a hash,
@code{%aliases}, that maps each full name to its email address. The
second phase goes through this map and updates each record in
@code{$PDB}. This two-phase approach may seem overly complex; the
reasons for it are discussd in @ref{pine-aliases Limitations}.

	Each line in the Pine address book contains a set of
tab-separated fields: the person's alias, full name, email address, and
a few others that we don't use.

	We'll need some way of figuring out which Pine alias goes with
which Palm Address Book record. Since the Pine alias file does not list
Palm record IDs and Palm records don't list mail aliases, we'll settle
on the full name as the next best way of uniquely identifying a person.

	The second phase of @code{&DoFetch} uses a number of helper
functions: @var{&find_person} takes a person's full name and returns a
reference to the corresponding record in @code{$PDB};
@code{&get_address} extracts the email address from that record; and
@code{&set_address} sets the email address in the record.

	One important thing to note is that @code{&set_address} marks
the record as dirty. During a normal sync, ColdSync only considers those
records that have changed in some way. When we update the address, we
need to make sure that the record is marked as dirty; otherwise it will
not be uploaded to the Palm.

	When @code{&DoFetch} returns, @code{ConduitMain} writes
@code{$PDB} to the file given by @code{$HEADERS@-@{"OutputDB"@}} and
exits. Then, during the main sync, ColdSync will upload to the Palm any
records @code{pine-aliases} has modified.

@node &DoDump, Helper Functions, &DoFetch, pine-aliases
@comment  node-name,  next,  previous,  up
@subsection @code{&DoDump}

	The @code{&DoDump} function implements the Dump conduit:

@example
sub DoDump
@{
        open ALIASES, "< $PINE_ALIASES" or
                die "502 Can't read $PINE_ALIASES: $!\n";
        open ALIASES_NEW, "> $PINE_ALIASES.new" or
                die "502 Can't write $PINE_ALIASES.new: $!\n";

        while (<ALIASES>)
        @{
                chomp;

                my $alias;
                my $addr;
                my $fullname;
                my @@rest;
                my $record;

                ($alias, $fullname, $addr, @@rest) = split /\t/;

                $record = &find_person($PDB, $fullname);
                if (!defined($record))
                @{
                        # This name doesn't appear in $PDB.
                        print ALIASES_NEW $_, "\n";
                        next;
                @}

                # This person appears in both the alias file and in
                # the PDB.
                my $pdb_addr = &get_address($record);

                if (defined($pdb_addr))
                @{
                        # Found an address
                        print STDOUT "101 $fullname -> $pdb_addr\n"
                                if $pdb_addr ne $addr;
                        print ALIASES_NEW
                                join("\t", $alias, $fullname,
                                        $pdb_addr, @@rest),
                                "\n";
                        next;
                @}

                # The PDB record doesn't have an email address. Mark it
                # as deleted.
                my $year;
                my $month;
                my $day;

                ($year, $month, $day) = (localtime)[5,4,3];
                $year %= 100;
                $month++;

                $alias = sprintf "#DELETED-%02d/%02d/%02d#%s",
                                $year, $month, $day, $alias;

                print ALIASES_NEW
                        join("\t", $alias, $fullname, $addr, @@rest),
                        "\n";
        @}

        close ALIASES_NEW;
        close ALIASES;
        rename "$PINE_ALIASES.new", $PINE_ALIASES or
                die "Can't rename $PINE_ALIASES.new: $!\n";

        return 1;               # Success
@}
@end example

	In @code{&DoDump}, we read each line of @file{~/.addressbook} in
turn and write a possibly-update version to @file{~/.addressbook.new}.
The reasons for using two files is twofold: first of all, the length of
a line might change, so we can't just update the file in place.
Secondly, if anything goes wrong during the sync, we can simply abort
before moving the new file into place, and leave the old alias file
untouched, rather than risk corrupting it.

	Again, we use @code{&find_person} to look up the Palm record
corresponding to a person's full name, and @code{&get_address} to
extract the email address from the record. There are three cases we
need to consider:

@itemize @bullet
@item There is no record corresponding to this alias.
@ifhtml
<P>
@end ifhtml

	There are two approaches we can take here: we can either delete
	the Pine alias (simply by not writing it to @code{ALIASES_NEW}),
	or we can ignore it. Since we're not trying to make sure that
	every Palm record has a corresponding Pine alias, we'll take the
	latter approach.

@item There is a record, and it has an email address.
@ifhtml
<P>
@end ifhtml

	We write the alias to @code{ALIASES_NEW}, with the email
	address listed in the Palm record. This may or may not be
	different from what was there before, but it doesn't matter:
	this is the most up-to-date address.

@item There is a record, but it doesn't have an email address.
@ifhtml
<P>
@end ifhtml

	In this case, we'll assume that the email address was deleted
	on the Palm, otherwise the Fetch conduit would have uploaded the
	email address. Hence, this email address is obsolete and
	should be commented out. In general, it is preferable to comment
	things out rather than delete them: that way, if there's a bug
	somewhere, the information isn't permanently lost.

@end itemize

@node Helper Functions, pine-aliases Limitations, &DoDump, pine-aliases
@comment  node-name,  next,  previous,  up
@subsection Helper functions

	These are the helper functions used in @code{pine-aliases}.

@cindex @code{find_person}
	@code{&find_person} takes a reference to a @code{Palm::Address}
and a full name, and returns a reference to the record corresponding to
that name:

@example
sub find_person
@{
        my $PDB = shift;
        my $fullname = shift;
        my $record;

        foreach $record (@@@{$PDB->@{"records"@}@})
        @{
                next unless ($record->@{"fields"@}@{"firstName"@} . " " .
                        $record->@{"fields"@}@{"name"@}) eq $fullname;
                return $record;
        @}
        return undef;           # Failure
@}
@end example

	Since Palm Address Book records don't contain a full name field,
we construct one from the first and last names, and see if it matches.

	Note that a better version of this function would also consider
other fields: an entry such as ``Ooblick Technical Support'' might be
listed on the Palm with no first or last name, but with the company
field set to ``Ooblick'' and the title field set to ``Technical
Support''.

@cindex @code{get_address}
	@code{&get_address} takes a reference to a Palm record, and
extracts the email address, if any:

@example
sub get_address
@{
        my $record = shift;
        my $field;

        # Look through all of the "phone*" fields
        foreach $field ( qw( phone1 phone2 phone3 phone4 phone5 ) )
        @{
                next unless $record->@{"phoneLabel"@}@{$field@} == 4;

                # Found the (or an) email field
                my $addr = $record->@{"fields"@}@{$field@};

                $addr =~ s/\n.*//;      # Keep only first line

                # Remove parenthesized expressions
                $addr =~ s/\([^\)]*\)//;
                $addr =~ s/^\s+//;      # Remove leading whitespace
                $addr =~ s/\s+$//;      # and trailing whitespace

                return $addr;
        @}

        return undef;           # Couldn't find anything
@}
@end example

	This was made into a separate function for clarity: the Palm
Address Book record format does not contain a separate field for the
email address. Rather, it has five fields named @code{phone1} through
@code{phone5}, each of which can be a home phone, work phone, fax
number, email address, etc. See Palm::Address(1) for details.

	@code{&get_address} looks at each phone field in turn until it
finds one whose @code{phoneLabel} is 4, meaning ``Email''. It extracts
the useful part of the address and returns it.

	Note that this function is very simplistic: all it does is
remove the parentheses from addresses of the form

@example
JDoe@@ooblick.com (John Doe)
@end example

@noindent
The general case is much more complex.

	@code{&set_address} is the converse of @code{&get_address}: it
stores an email address in a record:

@example
sub set_address
@{
        my $record = shift;
        my $addr = shift;
        my $field;

        # Find the Email phone field
        foreach $field ( qw( phone1 phone2 phone3 phone4 phone5 ) )
        @{
                next unless $record->@{"phoneLabel"@}@{$field@} == 4;

                # Found it.
                $record->@{"fields"@}@{$field@} = $addr;
                $record->@{"attributes"@}@{"dirty"@} = 1;
                return;
        @}

        # No Email field found.
        foreach $field ( qw( phone1 phone2 phone3 phone4 phone5 ) )
        @{
                next if $record->@{"phoneLabel"@}@{$field@} =~ /\S/;

                # Found an empty field
                $record->@{"phoneLabel"@}@{$field@} = 4;
                $record->@{"labels"@}@{$field@} = $addr;
                $record->@{"attributes"@}@{"dirty"@} = 1;
                return;
        @}

        # No Email fields, and no empty fields. Fail silently.
        return;
@}
@end example

	Again, due to the format of Palm Address Book records, this
function is more complicated than it seems that it ought to be.

	In the simplest case, we look at all of the phone fields, find
one marked ``Email'', and update it.

	If there is no email field, @code{&set_address} tries to find
an empty field and turn it into an email field, then writes the address
to that field.

	If there are no empty fields, we'll give up, since this is just
a tutorial. A real conduit ought to keep trying: it might consider
adding the email address to the ``Other'' phone field, if there is one.
As a last resort, it might add the email address to the note. Of
course, @code{&get_address} also needs to know about all of the places
where an email address might lurk.

	In any case, @code{&set_address} marks the record as being
dirty, so that it will be uploaded to the Palm at the next sync.

@node pine-aliases Limitations,  , Helper Functions, pine-aliases
@comment  node-name,  next,  previous,  up
@subsection Limitations of @code{pine-aliases}

	The conduit we've just seen is just a tutorial. For the sake of
simplicity, we've ignored several real-world considerations that would
have made the code even harder to read.

	The first simplifying assumption we've made is that there is
only one email address per person. In the real world, people often have
a home address and a work address. To deal with this, @code{&DoFetch}
should collect an array of addresses for each person, then make sure
that each address in the array exists in the Palm record (this is why
@code{&DoFetch} is split up into two phases).

	One issue that complicates matters is that a Palm Address Book
record might contain multiple phone fields marked ``Email''.
@code{&get_address} ought to handle this case. The other side of the
issue is that @code{&set_address} shouldn't just dump all of the email
addresses into the first ``Email'' phone record that it finds,
otherwise the second and subsequent addresses will be duplicated.

	Secondly, we've assumed that each full name uniquely identifies
a single person. This obviously fails if the user knows two people named
John Smith. In the case of @code{pine-aliases}, we can get away with
documenting this limitation and requiring the user to list one of them
as ``John Allan Smith'' and the other as ``John Paul Smith''. We might
also consider setting up a separate file that maps Pine mail aliases to
Palm record IDs, since those are unique identifiers in their respective
domains.

	Finally, @code{&set_address} shouldn't fail so easily: if it
fails to add an email address to the record, then at the next sync, the
corresponding Pine alias will be commented out. If a record is so full
that there are no empty phone records, then obviously it's very
important, and the user would be rather upset at losing this email
address.

@node Style and Warnings,  , pine-aliases, Tutorial
@comment  node-name,  next,  previous,  up
@section Style and Warnings: things to watch out for

	The conduit presented above is very simple, and does not address
many problems you will run into when writing ``real'' conduits.

@itemize @bullet

@item
When writing a Fetch conduit, think about what it should do if
there is no input: if the input file is empty, this might mean that
there are no records, and the conduit should write a database with no
records.
@ifhtml
<P>
@end ifhtml

	However, if the input file doesn't exist, then it's probably a
bad idea to delete all of the records in the backup database. In this
case, it's probably best just to abort: most likely, the file was
accidentally deleted, or else it's on an NFS partition and the remote
host is down, or the file is supposed to be generated by a Dump conduit
that hasn't been run yet.
@ifhtml
<P>
@end ifhtml

@item
@cindex Fast sync
@cindex Deleting records
@cindex Bad idea
Deleting records: the obvious way to delete a record is to simply fail
to write it to the output database. This is a bad idea, because of the
way that fast syncs work. Use @code{$pdb->delete_Record($record)} or
@code{$pdb->delete_Record($record, 1)}instead
@ifhtml
<P>
@end ifhtml

	When you modify a record on the Palm, the record is marked as
being dirty (modified). Likewise, when you delete a record on the Palm,
it is not actually deleted; rather, it is simply marked as being
deleted.
@footnote{If you uncheck the ``Save archive copy on PC'' box, the data
in the record will be deleted to save space, but the Palm will still
save the record header until the next sync.}
This way, ColdSync needn't bother downloading the entire database from
the Palm to see which records have changed: it simply asks the Palm for
a list of records that have been modified and/or deleted.
@ifhtml
<P>
@end ifhtml

	ColdSync does the same thing in reverse, as well: it reads its
backup copy of the database, looking for records that are marked as
having been modified or deleted. It uploads modified records, and tells
the Palm to purge the deleted records.
@ifhtml
<P>
@end ifhtml

	If you're writing to the backup file and simply fail to write a
deleted record, ColdSync will never notice this record and won't tell
the Palm to delete it. It will remain on the Palm, and you will have to
delete it manually.
@ifhtml
<P>
@end ifhtml

@item
@cindex @code{kab}
If you're converting a Palm database to another format, you'll often
find that the Palm database and the other format hold different
information. For instance, the KDE address book, @code{kab}, does not
distinguish between home and work telephone numbers. On the other hand,
it allows you to specify a person's URL, which the Palm Address Book
does not directly support.
@ifhtml
<P>
@end ifhtml

	Keep these sorts of differences in mind, or you'll risk losing
information. One approach is to start by reading both the source and
destination files, modify the records as necessary, and then write the
resulting file. That way, if the output file has a field that doesn't
correspond to anything on the Palm (like URLs in @code{kab} files,
above), you won't delete those fields.
@ifhtml
<P>
@end ifhtml

	An additional benefit of this approach is that if you encounter
a fatal error in the middle of processing, you can simply abort without
writing the output file. The information in the output file will be out
of date, but at least it won't be lost.
@ifhtml
<P>
@end ifhtml

@item
If you want to implement two-way syncing by having both Fetch and Dump
conduits for a database, consider writing a single program that
implements both flavors. Parts of the code will likely be the same, and
you'll be more likely to keep the two mutually compatible.
@ifhtml
<P>
@end ifhtml

@cindex @code{kab}
	For instance, the @code{kab} format only has a single
``telephone'' field, and does not distinguish between home and work
phone numbers. When converting a Palm database to a @code{kab} file, you
can simply concatenate all of the various phone fields. When doing the
reverse, however, you should look at each phone number in turn and see
if it appears in @emph{any} phone field in the Palm database.
@ifhtml
<P>
@end ifhtml

	You're less likely to forget this if you only have one program.
@ifhtml
<P>
@end ifhtml

@item
@cindex Newspaper
@cindex Washingon Post
@cindex World-Wide Web
Fetch conduits should run quickly: when they run, the Palm is in the
cradle and the user is waiting. It would be nifty to have a Fetch
conduit that downloads the latest headlines from the web, but do you
really want to wait for the conduit to surf to
@url{http://www.washingtonpost.com} every time you sync?
@ifhtml
<P>
@end ifhtml

	If you want to do this sort of thing, consider setting up a
@code{cron} job that'll fetch the latest headlines every hour and save
the results to a file. Then your Fetch conduit can quickly read this
file and not keep the user waiting.
@ifhtml
<P>
@end ifhtml

	Dump conduits, on the other hand, run after the main sync, after
the Palm has displayed the ``HotSync complete'' message. The user can
pick up the Palm and walk away, even if the Dump conduits are still
running.
@ifhtml
<P>
@end ifhtml

@item
@cindex Deleting records
The database that your conduit reads or writes may have other conduits
associated with it. Try not to mess things up for them. The fundamental
rule of syncing is, ``Don't delete unless you're sure.''
@ifhtml
<P>
@end ifhtml

	For instance, if you have a conduit that updates the Address
Book from a company-wide database, don't just delete every address
that's not on the list: you'll delete private addresses as well. In this
case, it would probably be best to consider only addresses in the
``Business'' category, and leave the other ones alone.

@end itemize

@node Specification, Glossary, Tutorial, Top
@comment  node-name,  next,  previous,  up
@chapter Specification

@cindex Conduits
	ColdSync allows the user to extend its functionality by means of
@emph{conduits}. A conduit is a program that is run from ColdSync, and
which interacts with ColdSync according to a well-defined protocol.

@cindex Flavors
	Conduits come in multiple @emph{flavors}. ColdSync runs conduits
at several points during its execution. The flavor of a conduit
indicates the intended purpose of the conduit.
See @ref{Conduit Flavors}.

	ColdSync communicates with conduits by sending information to
the conduit's standard input (@pxref{Conduit Input}), and by reading
results from the conduit's standard output (@pxref{Conduit Output}).
This information is mostly in human-readable text form.

@c XXX - Define "backup directory".

@cindex Sync overview
@cindex Timeline
	A sync consists of the following phases (somewhat simplified):

@enumerate
@item Initialization
@ifhtml
<BR>
@end ifhtml

	ColdSync starts up, reads its configuration file(s), and
performs basic initialization.

@item User presses HotSync button
@ifhtml
<BR>
@end ifhtml

	This indicates the beginning of the sync.

@item Gather information
@ifhtml
<BR>
@end ifhtml

	ColdSync gathers information from the Palm, such as the list of
databases.

@item Fetch preferences
@ifhtml
<BR>
@end ifhtml

	ColdSync fetches from the Palm any preferences specified in the
conduit configuration. Note that in the current implementation, ColdSync
fetches all preferences listed in all conduits' configuration, even if
those conduits will not be run.

@item Run Install conduits and install new databases (before sync)
@ifhtml
<BR>
@end ifhtml

	If ColdSync was told to install new databases before the main
sync (the @code{-z} option was not specified), it now examines each
database in the install directory and runs its Install conduits.
@ifhtml
<P>
@end ifhtml

	Afterwards, if any databases remain in the install directory,
ColdSync uploads them to the Palm. If the upload was successful,
ColdSync deletes the file from the install directory, and adds an entry
for the new database to its list of databases installed on the Palm.

@item Run Fetch conduits
@ifhtml
<BR>
@end ifhtml

	For each database on the Palm (including ones that have just
been installed), ColdSync runs its Fetch conduits. Fetch conduits are
expected to create or modify the databases in the backup directory.
See @ref{Fetch Conduits}.

@item Run Sync conduits (main sync)
@ifhtml
<BR>
@end ifhtml

	ColdSync runs Sync conduits for each database on the Palm. If no
other conduit was specified for a given database, ColdSync defaults to
running the generic conduit. As each database is synchronized, the
message ``Synchronizing @var{Database}'' appears on the Palm. If no
backup file exists, ColdSync creates one by downloading the database.
@ifhtml
<P>
@end ifhtml

	ColdSync then checks all of the files in the backup directory:
if a file does not correspond to any database on the Palm, that file is
moved to the Attic directory.
@ifhtml
<P>
@end ifhtml

@item Run Install conduits and install new databases (after sync)
@ifhtml
<BR>
@end ifhtml

	If ColdSync was invoked with the @code{-z} option, it will run
Install conduits and install new databases after the main sync. See
above.

@item Close the connection
@ifhtml
<BR>
@end ifhtml

	The message ``HotSync complete'' appears on the Palm. The user
may remove it from the cradle.

@item Run Dump conduits
@ifhtml
<BR>
@end ifhtml

	For each database on the Palm (including the ones that were just
installed), ColdSync runs its Dump conduits. Dump conduits are expected
to read the databases in the backup directory.
See @ref{Dump Conduits}.

@item Clean up
@ifhtml
<BR>
@end ifhtml

	ColdSync cleans up and terminates.

@end enumerate

	If the configuration file calls for more than one conduit of the
same flavor to be run for the same database, the conduits will be run in
the order in which they are listed in the configuration file.

	ColdSync makes no guarantees as to the order in which different
databases' conduits will be run, nor is there any guarantee that all of
the conduits for one database will be run before the first conduit of
another database.

@menu
* Conduit Input::               What ColdSync sends to the conduit.
* Conduit Output::              What the conduit may send to ColdSync.
* SPC::                         Serialized Procedure Call protocol
* Conduit Flavors::             The different types of conduit.
* Status Codes::                Numerical error codes and thier meanings.
@end menu

@node Conduit Input, Conduit Output, Specification, Specification
@comment  node-name,  next,  previous,  up
@section Conduit Input

@cindex Headers
@cindex Preferences
@cindex Standard input
@cindex Stdin
@cindex SPC
	ColdSync passes information to conduits in three ways: as
command-line arguments, in a series of @emph{headers} and
@emph{preferences} on standard input, and through a designated special
file descriptor (@pxref{SPC}).

@subsection Command-line Arguments
@cindex Command-line arguments
	A conduit is invoked with two command-line arguments. The first
is the string @code{conduit}. This argument will always be present when
the conduit is run from ColdSync.

	The second argument designates the conduit flavor: the string
@file{fetch}, for Fetch conduits, the string @code{dump}, for Dump
conduits, the string @file{sync}, for Sync conduits, or the string
@code{install} for Install conduits. (@pxref{Conduit Flavors}).

@subsection Standard Input
@cindex Standard input
@cindex Stdin
@cindex Headers
@cindex Preferences
	ColdSync writes a series of @emph{headers} and @emph{preference
values} to the conduit's standard input. Each header is a line of the
form
@example
@var{Field}: @var{Value}
@end example

	@var{Field} is a string indicating a particular type of header.
It may consist of upper- and lower-case letters, digits, hyphens, and
underscores. The first character may only be a letter or an underscore.
The length of @var{Field} may not exceed 32 characters. Fields are
case-sensitive: @code{Foo} is not the same as @code{FOO}.

	The field is followed by a colon, a space, the @var{Value}
string, and a newline character. The entire line may not be more than
255 characters in length, including the field, but not including the
terminating newline character.

	Note that a single space follows the colon. Any other whitespace
is part of the value. This allows a conduit to accept an all-whitespace
header value (e.g., a paragraph indentation string).

	@var{Value} is a string. It may not contain any newline
characters. No other restrictions are placed upon its contents, although
conduit writers are encouraged to use human-readable strings.

@cindex Multi-line header
	There is currently no provision for multi-line header lines, nor
for encoding methods such as ``Quoted-printable.''

@cindex End of header
@cindex Blank line
	The end of the header is indicated by a blank line, i.e., two
newlines in a row.

@cindex Preferences
	Since preference data is binary, preferences are passed to the
conduit in two parts: first, a set of @code{Preference} headers specify
the preference's creator, ID, and length.

	Then, after the two newlines indicating the end of the headers,
comes the preference data. This is simply the concatenation of the
binary data for all of the preferences referred to by the
@code{Preference} headers, in the order in which those headers appeared.

@menu
* Predefined Headers::          Headers with standard meanings
@end menu

@node Predefined Headers,  , Conduit Input, Conduit Input
@comment  node-name,  next,  previous,  up
@subsection Predefined Headers

	Certain header fields have predefined meanings and formats:

@table @code

@item Daemon

	The @code{Daemon} header identifies the program that ran the
conduit. ColdSync uses the string @code{coldsync} as the value.
@ifhtml
<P>
@end ifhtml

	According to the terms of the Artistic License, a person may
modify ColdSync. If the modified version is incompatible with the
Standard Distribution of ColdSync, it should use some string other than
@code{coldsync} to identify itself.

@item Version

	The @code{Version} header specifies the version of the program
identified by @code{Daemon}.

@item InputDB

	The @code{InputDB} header specifies the full pathname to the
database file that the conduit should use as its input. This header is
mandatory for Sync and Dump conduits, and is optional for Fetch and
Install conduits.
@ifhtml
<P>
@end ifhtml

	The file specified by @code{InputDB} might not exist, or might
not be readable by the conduit. In such cases, the conduit should fail
gracefully.
@c XXX - Exit status

@item OutputDB

	The @code{OutputDB} header specifies the full pathname to the
database file that the conduit should use as its output. This header is
mandatory for Sync, Fetch, and Install conduits, and is optional for
Dump conduits.
@ifhtml
<P>
@end ifhtml

	The file specified by @code{OutputDB} might not exist, in which
case the conduit may create it. If it exists but is not writable by the
conduit, the conduit should fail gracefully.
@c XXX - Exit status

@item Preference

@cindex Preferences
	A @code{Preference} header identifies a preference being passed
to the conduit. Each @code{Peference} header is of the form

@example
Preference: @var{creator}/@var{ID}/@var{length}
@end example

where @var{creator} is the preference's four-character creator, @var{ID}
is its numerical identifier (decimal), and @var{length} is the length of
the preference data following the header (decimal).

@item SPCPipe

@cindex SPCPipe
@cindex SPC
@cindex Serialized Procedure Call
	The @code{SPCPipe} header specifies the number (decimal) of an
open file descriptor. This file descriptor may be used for SPC
communications (@pxref{SPC}).

@end table

	Other headers may be passed to the conduit, so the conduit
should be prepared to handle them.

@cindex Headers, repeated
@cindex Repeated headers 
	If multiple @code{InputDB} or @code{OutputDB} headers are sent
to a conduit, the last value sent is the authoritative one. It is an
error to send more than one @code{Daemon} or @code{Version} header.

@node Conduit Output, SPC, Conduit Input, Specification
@comment  node-name,  next,  previous,  up
@section Conduit Output

@cindex Status code
@cindex Status message
	A conduit may write lines to standard output. Each line should
be of the form
@example
@var{NNN} @var{Message}
@end example

@noindent
where @var{NNN} is a three-digit status code (@pxref{Status Codes}), and
@var{Message} is a human-readable string. A single space separates the
status code from the message.

	Each line may be up to 255 characters in length, counting the
status code, but not counting the terminating newline. There is
currently no provision for multi-line messages.

	The three-digit status code indicates some condition that the
conduit wishes to report to ColdSync, such as successful or unsuccessful
termination, a warning, or an informational progress report. The
meanings of various status codes are defined in @ref{Status Codes}.

	ColdSync does not attempt to parse the message string. It is
intended solely for human readers.

@cindex Exit status
	A conduit may print any number of lines. The status code of the
last line printed by the conduit before it exits indicates the final
exit status of the conduit, i.e., success or failure.

	Only 2@i{yz}, 4@i{yz}, and 5@i{yz} status codes may be used for
the exit status.

@node SPC, Conduit Flavors, Conduit Output, Specification
@comment  node-name,  next,  previous,  up
@section SPC

@cindex SPC
@cindex Serialized Procedure Call
	The Serialized Procedure Call (SPC) is a protocol that allows a
Sync conduit to communicate with the Palm. A Sync conduit is passed an
@code{SPCPipe} header that gives the number of a file descriptor over
which it can communicate via SPC (@pxref{Predefined Headers}).

	SPC is similar in spirit to RPC (Remote Procedure Call): the
conduit sends an SPC request over the SPC file descriptor, and receives
a response.

	SPC requests and responses have the same form:
@example
	unsigned short op;
	unsigned short status;
	unsigned long len;
	@i{// @code{len} bytes of data}
@end example

where @code{op} is an opcode indicating which operation to perform;
@code{status} indicates whether the operation was successful or not;
@code{len} gives the length of the data following the header.

	Supported values for @code{op} are given by the @var{SPCOP_*}
constants in @file{spc.h} in the ColdSync distribution. For known values
for @code{status}, see the @var{SPCERR_*} constants in that file.

	All numeric values are given in network byte order. A
@code{short} is 16 bits long; a @code{long} is 32 bits long.

	@code{status} is ignored in a request packet.

	In a response packet, @code{op} is the opcode of the request.

	The following SPC operations are currently defined:

@itemize @bullet
@item @code{NOP}
	No-op. This does nothing, neither sends nor receives any data
from the Palm, and is mainly useful as a connectivity test between the
conduit and ColdSync. The response to a @code{NOP} has 0 bytes of data.

@item @code{DBINFO}
	Get database information. Returns a @code{struct dlp_dbinfo},
similar to those returned by the @code{dlpReadDBList} request, except
that the SPC request returns the copy that ColdSync has already fetched,
so it does not involve extra communication with the Palm over a slow
serial connection.

@item @code{DLPC}
	This is the most powerful SPC request. The data for a
@code{DLPC} request is a raw DLP request that will be sent to the Palm.
The response is the raw response, as received from the Palm.

@end itemize

@node Conduit Flavors, Status Codes, SPC, Specification
@comment  node-name,  next,  previous,  up
@section Conduit Flavors

	There are currently four conduit flavors: Sync, Fetch, Dump, and
Install.

@menu
* Sync conduits::               Conduits that run during the main sync
* Fetch Conduits::              Conduits that run before the main sync
* Dump Conduits::               Conduits that run after the main sync
* Install conduits::            Conduits that run before new databases are
                                  installed.
@end menu

@node Sync conduits, Fetch Conduits, Conduit Flavors, Conduit Flavors
@comment  node-name,  next,  previous,  up
@subsection Sync conduits

@cindex Sync conduits
	Sync conduits run during the main sync. The intended purpose of
a Sync conduit is to ensure that a database on the Palm and its backup
on the desktop both contain identical, up-to-date information. The
generic conduit is a special instance of a Sync conduit.

	Sync conduits have the unique property that they run while
ColdSync is connected to the Palm, and so may communicate with it by
using the SPC protocol (@pxref{SPC}).

@node Fetch Conduits, Dump Conduits, Sync conduits, Conduit Flavors
@comment  node-name,  next,  previous,  up
@subsection Fetch Conduits

@cindex Fetch conduits
	@emph{Fetch conduits} run before the main sync. The purpose of a
Fetch conduit is to create or modify the backup copy of a database
before ColdSync compares it to the copy on the Palm. The conduit may,
for instance, add new records to be uploaded to the Palm.

@node Dump Conduits, Install conduits, Fetch Conduits, Conduit Flavors
@comment  node-name,  next,  previous,  up
@subsection Dump Conduits

@cindex Dump conduits
	@emph{Dump conduits} run after the main sync. The purpose of a
Dump conduit is to examine a database in the backup directory after it
has been synchronized with the copy on the Palm. Usually, a Dump conduit
will write the contents of the database in some other format, e.g., that
of some other application.

	In most cases, a Dump conduit will only need to read its
database. If necessary, however, it may modify the database. For
instance, a Dump conduit for the Palm Mail application may send out
every message in the Outbox, then delete it from the database.

@node Install conduits,  , Dump Conduits, Conduit Flavors
@comment  node-name,  next,  previous,  up
@subsection Install conduits

@cindex Install conduits
	@emph{Install conduits} run just before new databases are
uploaded to the Palm, which may happen either before or after the main
sync. The purpose of an Install conduit is to examine a database that is
about to be installed, and possibly delete or modify it, or create a new
one.

@node Status Codes,  , Conduit Flavors, Specification
@comment  node-name,  next,  previous,  up
@section Status Codes

@cindex Status code
@cindex Code, status
	The status codes that a conduit sends to ColdSync should be of
the form of a three-digit decimal integer @i{xyz}.

@cindex Message class
	The first digit, @i{x}, indicates a general message class
(success, failure, informational message, etc).

@cindex Message category
	The second digit, @i{y}, represents a category within the
message class (file error, system error, etc.)

	The third digit, @i{z}, indicates a specific condition (out of
memory, no such file, etc.)

	The precise meaning of most status codes is still undefined.
Only the following classes have been defined:

@table @asis
@item 0@i{yz}
@cindex Debugging messages
@cindex Messages, debugging
Debugging messages. These will normally not be shown to the user. The
precise circumstances under which they will be shown to the user have
yet to be defined.

@c XXX - What if this is the last status code printed to stdout?

@item 1@i{yz}
@cindex Informational messages
@cindex Messages, informational
Informational messages. These will normally be shown to the user, but do
not indicate that anything is wrong.
@ifhtml
<P>
@end ifhtml

	In future versions of ColdSync, certain 1@i{yz} codes may
acquire standard meanings, and their associated text strings will have a
recommended format. This should allow real-time updates of the form
``NN% complete'' that can be displayed on the user's desktop.

@c XXX - What if this is the last status code printed to stdout?

@item 2@i{yz}
@cindex Success messages
@cindex Messages, success
Successful completion.
@ifhtml
<P>
@end ifhtml

	There might conceivably be multiple forms of success. In the
meantime, the recommended code for a plain, ordinary success is 202.

@item 3@i{yz}
@cindex Warning messages
@cindex Messages, warning
Warning. The 3@i{yz} status codes indicate that something is wrong, but
that the conduit has managed to recover.

	@table @asis

	@item 301
	Unspecified warning.

	Indicates that something odd has occurred, but does not specify
	what. This is the default warning printed by the
	@code{ColdSync.pm} module if no status code was provided.

	@end table

@c XXX - What if this is the last status code printed to stdout?

@item 4@i{yz}
@cindex Error messages
@cindex Messages, error
@cindex Caller error
@cindex ColdSync error
ColdSync (caller) error. A 4@i{yz} code indicates that the conduit has
failed because it was given improper input, e.g., invalid or missing
command-line arguments, nonexistent @code{InputDB} file, unsupported
version of ColdSync, and so forth.

	@table @asis

	@item 401
	Unspecified Error.

	@item 402
	Lost connection to Palm.

	@end table

@item 5@i{yz}
@cindex Error messages
@cindex Messages, error
@cindex Conduit error
Conduit error. A 5@i{yz} code indicates that the conduit should have
been able to perform its function, but couldn't. Reasons include running
out of memory, segmentation violation, inability to parse an
apparently-correct @code{InputDB} file, etc.

	@table @asis
	@item 501
	Unspecified error.

	Indicates that the conduit was not able to terminate for some
	reason other than improper input, but does not specify the
	cause. This is the default error code used by the
	@code{ColdSync.pm} Perl module.

	@end table

@item 6@i{yz}-9@i{yz}
These error codes are currently undefined, but may be used in future
versions. Until then, they should not be used.

@end table

@cindex Exit status
	The last status code sent by the conduit before exiting gives
the exit status of the conduit as a whole. That is, if a conduit exits
successfully, the last thing it prints should be a 2@i{yz} status code.

	Only 2@i{yz}, 4@i{yz}, and 5@i{yz} status codes may be used for
the final exit status.

@node Glossary, Index, Specification, Top
@comment  node-name,  next,  previous,  up
@unnumbered Glossary

@table @asis

@item @file{.coldsyncrc}

	The per-user configuration file for ColdSync. Specifies the
serial device to which the cradle is attached, and the list of conduits
to run for each database.

@item Archive file

	A file containing records that have been deleted, but which were
marked for archival, usually by checking the ``Save archive copy on PC''
box.

@item Archive directory

	The directory in which ColdSync stores archive files.
@code{~/.palm/archive} by default.

@item Archived record

	A record that has been deleted on the Palm, but saved in an
archive file on the workstation.

@item Attic directory

	When ColdSync finds a file in the backup directory that has no
corresponding database on the Palm, it moves the file to the attic
directory, in case the database was deleted by mistake. The attic
directory is @code{~/.palm/backup/Attic} by default.

@item Backup

	A file in the user's home directory, containing a copy of a Palm
database.

@item Backup directory

	The directory in which ColdSync keeps backups of the databases
on the Palm. @code{~/.palm/backup} by default.

@item Conduit

	An external program, run at specific times by ColdSync, which
provides a ``hook'' by which the user may extend ColdSync's
functionality.

@item Database
PalmOS's equivalent of files. Often used interchangeably with `files',
if the database in question has been downloaded to a file on a
workstation.

@item Database creator

	A four-letter string that identifies the application that
created a database. Each application has a unique creator string.

@item Database type

	Either `record database' or `resource database'.

@item Deleted record

	A record that has been marked for deletion. Deleted records are
not removed from a database until a sync.

@item Dump conduit

	A conduit that runs after the main sync, usually to convert a
PDB to some other format.

@item Export

	To convert a Palm database into another format, often one
readable by another application.

@item Expunged record

	A deleted record that need not be archived, usually because the
``Save archive copy on PC'' box was left unchecked when the record was
deleted.
@ifhtml
<P>
@end ifhtml

	The data portion of an expunged record is immediately reclaimed.
The header, however, is not deleted until a sync.

@item Fetch conduit

	A conduit that runs before the main sync, usually to convert a
file to a PDB.

@item Flavor

	One of several types of conduit. Each flavor serves a different
purpose.

@item Header

	A set of input values that ColdSync passes a conduit on standard
input.

@item Header field

	The identifier on a header line, as opposed to the header value.

@item Import

	To convert a file, typically one generated by another
application, to Palm database format.

@item Install directory

	A directory in which ColdSync looks for new databases to upload
to the Palm. @code{~/.palm/install} by default.

@item Main sync

	The phase of a sync during which ColdSync compares the databases
on the Palm with their backups in the backup directory.

@item Record database

	A database that contains data records, as opposed to a resource
database. Almost all of the ``useful information'' on a Palm is stored
in record databases. Record database files have a @code{.pdb} extension.

@item Record identifier

	An integer that uniquely identifies a record in a record
database.

@item Resource database

	A database that contains resources, as opposed to a record
database. Resource databases tend to have a static structure. Palm
applications are resource databases. Resource databases have a
@code{.prc} extension.

@item Resource identifier

	An integer that uniquely identifies a resource among all of the
other resource of the same type in a resource database. The resource
identifier is chosen by the application programmer, and remains
constant.

@item Resource type

	A four-letter string that identifies the type of data contained
in a resource, e.g. executable code, bitmap images, menu entries, etc.

@item Serialized Procedure Call (SPC)

	A protocol that allows a Sync conduit to send DLP requests to
the Palm.

@item Status code

	A three-digit integer by which a conduit can keep ColdSync
informed of its situation, e.g., whether a conduit has succeeded or
failed.

@item Sync

	@i{vi}. To compare the databases on a Palm with those in a
backup directory, and make whatever changes are necessary so that the
two copies have identical contents.

	@i{n}. The process of syncing.

@end table

@node Index,  , Glossary, Top
@comment  node-name,  next,  previous,  up
@unnumbered Index

@printindex cp

@cindex Self-reference

@contents
@bye