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
|