summaryrefslogtreecommitdiffstats
path: root/kpilot
diff options
context:
space:
mode:
Diffstat (limited to 'kpilot')
-rw-r--r--kpilot/.emacs-dirvars7
-rw-r--r--kpilot/AUTHORS29
-rw-r--r--kpilot/CMakeLists.txt96
-rw-r--r--kpilot/COPYING355
-rw-r--r--kpilot/ChangeLog4220
-rw-r--r--kpilot/Documentation/ConduitProgrammingTutorial/ConduitStructure.eps500
-rw-r--r--kpilot/Documentation/ConduitProgrammingTutorial/Makefile25
-rw-r--r--kpilot/Documentation/ConduitProgrammingTutorial/index.tex1708
-rw-r--r--kpilot/Documentation/ConduitProgrammingTutorial/mal-factory.cc123
-rw-r--r--kpilot/Documentation/ConduitProgrammingTutorial/mal-factory.h54
-rw-r--r--kpilot/Documentation/ConduitProgrammingTutorial/pictures/ConnectionsDialog.pngbin0 -> 9676 bytes
-rw-r--r--kpilot/Documentation/ConduitProgrammingTutorial/pictures/NoLayoutDialog.pngbin0 -> 81069 bytes
-rw-r--r--kpilot/Documentation/ConduitProgrammingTutorial/pictures/ProxyTab.pngbin0 -> 85254 bytes
-rw-r--r--kpilot/Documentation/HOWTO-CODE.txt112
-rw-r--r--kpilot/Documentation/HOWTO-CONDUIT.txt67
-rw-r--r--kpilot/Documentation/README17
-rw-r--r--kpilot/Documentation/README-3.2.1+156
-rw-r--r--kpilot/Documentation/README-4.0.0103
-rw-r--r--kpilot/Documentation/README-4.2.1106
-rw-r--r--kpilot/Documentation/README-4.2.2108
-rw-r--r--kpilot/Documentation/UML/vcal-classdiagram.xmi.tgzbin0 -> 134659 bytes
-rw-r--r--kpilot/Documentation/checkPlugin.sh77
-rwxr-xr-xkpilot/Documentation/merge-into-svn.sh165
-rw-r--r--kpilot/INSTALL56
-rw-r--r--kpilot/Mainpage.dox31
-rw-r--r--kpilot/Makefile.am20
-rw-r--r--kpilot/Makefile.cmake65
-rw-r--r--kpilot/NEWS24
-rw-r--r--kpilot/README43
-rw-r--r--kpilot/TODO201
-rw-r--r--kpilot/cmake/modules/FindMal.cmake62
-rw-r--r--kpilot/cmake/modules/FindPilotlink.cmake55
-rw-r--r--kpilot/cmake/modules/KPilotCustom.cmake53
-rw-r--r--kpilot/cmake_uninstall.cmake.in23
-rw-r--r--kpilot/conduits/CMakeLists.txt35
-rw-r--r--kpilot/conduits/Makefile.am30
-rw-r--r--kpilot/conduits/abbrowserconduit/CMakeLists.txt46
-rw-r--r--kpilot/conduits/abbrowserconduit/KPilotCustomFieldEditor.ui276
-rw-r--r--kpilot/conduits/abbrowserconduit/Makefile.am24
-rw-r--r--kpilot/conduits/abbrowserconduit/abbrowser-conduit.cc1897
-rw-r--r--kpilot/conduits/abbrowserconduit/abbrowser-conduit.h222
-rw-r--r--kpilot/conduits/abbrowserconduit/abbrowser-factory.cc45
-rw-r--r--kpilot/conduits/abbrowserconduit/abbrowser-factory.h40
-rw-r--r--kpilot/conduits/abbrowserconduit/abbrowser-setup.cc195
-rw-r--r--kpilot/conduits/abbrowserconduit/abbrowser-setup.h52
-rw-r--r--kpilot/conduits/abbrowserconduit/abbrowserSettings.kcfgc7
-rw-r--r--kpilot/conduits/abbrowserconduit/abbrowser_conduit.desktop116
-rw-r--r--kpilot/conduits/abbrowserconduit/abbrowserconduit.kcfg80
-rw-r--r--kpilot/conduits/abbrowserconduit/kabcRecord.cc710
-rw-r--r--kpilot/conduits/abbrowserconduit/kabcRecord.h263
-rw-r--r--kpilot/conduits/abbrowserconduit/kaddressbookConduit.ui746
-rw-r--r--kpilot/conduits/abbrowserconduit/resolutionDialog.cc323
-rw-r--r--kpilot/conduits/abbrowserconduit/resolutionDialog.h70
-rw-r--r--kpilot/conduits/abbrowserconduit/resolutionDialog_base.ui129
-rw-r--r--kpilot/conduits/abbrowserconduit/resolutionTable.h70
-rw-r--r--kpilot/conduits/configure.in.bot14
-rw-r--r--kpilot/conduits/configure.in.in241
-rw-r--r--kpilot/conduits/docconduit/CMakeLists.txt87
-rw-r--r--kpilot/conduits/docconduit/DOC-converter.cc631
-rw-r--r--kpilot/conduits/docconduit/DOC-converter.h183
-rw-r--r--kpilot/conduits/docconduit/Icons/CMakeLists.txt3
-rw-r--r--kpilot/conduits/docconduit/Icons/Makefile.am7
-rw-r--r--kpilot/conduits/docconduit/Icons/cr16-app-kpalmdoc.pngbin0 -> 747 bytes
-rw-r--r--kpilot/conduits/docconduit/Icons/cr22-app-kpalmdoc.pngbin0 -> 1088 bytes
-rw-r--r--kpilot/conduits/docconduit/Icons/cr32-app-kpalmdoc.pngbin0 -> 2007 bytes
-rw-r--r--kpilot/conduits/docconduit/Icons/cr48-app-kpalmdoc.pngbin0 -> 3254 bytes
-rw-r--r--kpilot/conduits/docconduit/Makefile.am38
-rw-r--r--kpilot/conduits/docconduit/bmkSpecification.txt199
-rw-r--r--kpilot/conduits/docconduit/doc-conduit.cc1018
-rw-r--r--kpilot/conduits/docconduit/doc-conduit.h152
-rw-r--r--kpilot/conduits/docconduit/doc-conflictdialog.cc182
-rw-r--r--kpilot/conduits/docconduit/doc-conflictdialog.h83
-rw-r--r--kpilot/conduits/docconduit/doc-factory.cc116
-rw-r--r--kpilot/conduits/docconduit/doc-factory.h74
-rw-r--r--kpilot/conduits/docconduit/doc-setup.cc136
-rw-r--r--kpilot/conduits/docconduit/doc-setup.h47
-rw-r--r--kpilot/conduits/docconduit/doc-setupdialog.ui557
-rw-r--r--kpilot/conduits/docconduit/doc_conduit.desktop59
-rw-r--r--kpilot/conduits/docconduit/docconduit.kcfg54
-rw-r--r--kpilot/conduits/docconduit/docconduitSettings.kcfgc7
-rw-r--r--kpilot/conduits/docconduit/kpalmdoc.cpp58
-rw-r--r--kpilot/conduits/docconduit/kpalmdoc.desktop65
-rw-r--r--kpilot/conduits/docconduit/kpalmdoc.kcfg41
-rw-r--r--kpilot/conduits/docconduit/kpalmdoc.upd6
-rw-r--r--kpilot/conduits/docconduit/kpalmdocSettings.kcfgc7
-rw-r--r--kpilot/conduits/docconduit/kpalmdoc_dlg.cc529
-rw-r--r--kpilot/conduits/docconduit/kpalmdoc_dlg.h67
-rw-r--r--kpilot/conduits/docconduit/kpalmdoc_dlgbase.ui435
-rw-r--r--kpilot/conduits/docconduit/makedoc9.cc405
-rw-r--r--kpilot/conduits/docconduit/makedoc9.h111
-rw-r--r--kpilot/conduits/docconduit/pilotDOCBookmark.cc87
-rw-r--r--kpilot/conduits/docconduit/pilotDOCBookmark.h51
-rw-r--r--kpilot/conduits/docconduit/pilotDOCEntry.cc92
-rw-r--r--kpilot/conduits/docconduit/pilotDOCEntry.h73
-rw-r--r--kpilot/conduits/docconduit/pilotDOCHead.cc101
-rw-r--r--kpilot/conduits/docconduit/pilotDOCHead.h62
-rw-r--r--kpilot/conduits/docconduit/tests/testcompress.cpp59
-rw-r--r--kpilot/conduits/knotes/CMakeLists.txt52
-rw-r--r--kpilot/conduits/knotes/Makefile.am21
-rw-r--r--kpilot/conduits/knotes/cr32-app-knotesconduit.pngbin0 -> 369 bytes
-rw-r--r--kpilot/conduits/knotes/knotes-action.cc872
-rw-r--r--kpilot/conduits/knotes/knotes-action.h113
-rw-r--r--kpilot/conduits/knotes/knotes-conduit.desktop94
-rw-r--r--kpilot/conduits/knotes/knotes-factory.cc133
-rw-r--r--kpilot/conduits/knotes/knotes-factory.h70
-rw-r--r--kpilot/conduits/knotes/knotes-setup.cc83
-rw-r--r--kpilot/conduits/knotes/knotes-setup.h49
-rw-r--r--kpilot/conduits/knotes/knotesconduit.kcfg25
-rw-r--r--kpilot/conduits/knotes/knotesconduitSettings.kcfgc7
-rw-r--r--kpilot/conduits/knotes/setup_base.ui88
-rw-r--r--kpilot/conduits/malconduit/CMakeLists.txt48
-rw-r--r--kpilot/conduits/malconduit/Makefile.am18
-rw-r--r--kpilot/conduits/malconduit/README12
-rw-r--r--kpilot/conduits/malconduit/mal-conduit.cc319
-rw-r--r--kpilot/conduits/malconduit/mal-conduit.h66
-rw-r--r--kpilot/conduits/malconduit/mal-factory.cc143
-rw-r--r--kpilot/conduits/malconduit/mal-factory.h67
-rw-r--r--kpilot/conduits/malconduit/mal-setup.cc185
-rw-r--r--kpilot/conduits/malconduit/mal-setup.h54
-rw-r--r--kpilot/conduits/malconduit/mal-setup_dialog.ui634
-rw-r--r--kpilot/conduits/malconduit/mal_conduit.desktop96
-rw-r--r--kpilot/conduits/malconduit/malconduit.kcfg56
-rw-r--r--kpilot/conduits/malconduit/malconduitSettings.kcfgc7
-rw-r--r--kpilot/conduits/memofileconduit/CMakeLists.txt44
-rw-r--r--kpilot/conduits/memofileconduit/Makefile.am16
-rw-r--r--kpilot/conduits/memofileconduit/design/SQD - copyHHToPC.jpgbin0 -> 111060 bytes
-rw-r--r--kpilot/conduits/memofileconduit/design/SQD - copyPCToHH.jpgbin0 -> 69573 bytes
-rw-r--r--kpilot/conduits/memofileconduit/design/SQD - detailed load.jpgbin0 -> 119635 bytes
-rw-r--r--kpilot/conduits/memofileconduit/design/SQD - sync.jpgbin0 -> 112438 bytes
-rw-r--r--kpilot/conduits/memofileconduit/memofile-conduit.cc567
-rw-r--r--kpilot/conduits/memofileconduit/memofile-conduit.desktop93
-rw-r--r--kpilot/conduits/memofileconduit/memofile-conduit.h92
-rw-r--r--kpilot/conduits/memofileconduit/memofile-factory.cc128
-rw-r--r--kpilot/conduits/memofileconduit/memofile-factory.h40
-rw-r--r--kpilot/conduits/memofileconduit/memofile.cc239
-rw-r--r--kpilot/conduits/memofileconduit/memofile.h113
-rw-r--r--kpilot/conduits/memofileconduit/memofileSettings.kcfgc7
-rw-r--r--kpilot/conduits/memofileconduit/memofileconduit.kcfg16
-rw-r--r--kpilot/conduits/memofileconduit/memofileconduit.xmi241
-rw-r--r--kpilot/conduits/memofileconduit/memofiles.cc700
-rw-r--r--kpilot/conduits/memofileconduit/memofiles.h96
-rw-r--r--kpilot/conduits/memofileconduit/setup_base.ui143
-rw-r--r--kpilot/conduits/notepadconduit/CMakeLists.txt38
-rw-r--r--kpilot/conduits/notepadconduit/Makefile.am14
-rw-r--r--kpilot/conduits/notepadconduit/notepad-conduit.cc265
-rw-r--r--kpilot/conduits/notepadconduit/notepad-conduit.desktop65
-rw-r--r--kpilot/conduits/notepadconduit/notepad-conduit.h94
-rw-r--r--kpilot/conduits/notepadconduit/notepad-factory.cc124
-rw-r--r--kpilot/conduits/notepadconduit/notepad-factory.h38
-rw-r--r--kpilot/conduits/notepadconduit/notepad-setup.ui79
-rw-r--r--kpilot/conduits/notepadconduit/notepadconduit.kcfg14
-rw-r--r--kpilot/conduits/notepadconduit/notepadconduit.kcfgc7
-rw-r--r--kpilot/conduits/null/CMakeLists.txt38
-rw-r--r--kpilot/conduits/null/Makefile.am15
-rw-r--r--kpilot/conduits/null/null-conduit.cc98
-rw-r--r--kpilot/conduits/null/null-conduit.desktop64
-rw-r--r--kpilot/conduits/null/null-conduit.h65
-rw-r--r--kpilot/conduits/null/null-factory.cc125
-rw-r--r--kpilot/conduits/null/null-factory.h40
-rw-r--r--kpilot/conduits/null/nullSettings.kcfgc7
-rw-r--r--kpilot/conduits/null/nullconduit.kcfg13
-rw-r--r--kpilot/conduits/null/setup_base.ui128
-rw-r--r--kpilot/conduits/popmail/CMakeLists.txt43
-rw-r--r--kpilot/conduits/popmail/Makefile.am24
-rw-r--r--kpilot/conduits/popmail/popmail-conduit.cc416
-rw-r--r--kpilot/conduits/popmail/popmail-conduit.desktop109
-rw-r--r--kpilot/conduits/popmail/popmail-conduit.h74
-rw-r--r--kpilot/conduits/popmail/popmail-factory.cc47
-rw-r--r--kpilot/conduits/popmail/popmail-factory.h37
-rw-r--r--kpilot/conduits/popmail/popmail.kcfg25
-rw-r--r--kpilot/conduits/popmail/popmailSettings.kcfgc7
-rw-r--r--kpilot/conduits/popmail/setup-dialog.ui141
-rw-r--r--kpilot/conduits/popmail/setupDialog.cc158
-rw-r--r--kpilot/conduits/popmail/setupDialog.h62
-rw-r--r--kpilot/conduits/recordconduit/Makefile.am15
-rw-r--r--kpilot/conduits/recordconduit/factory.cc144
-rw-r--r--kpilot/conduits/recordconduit/factory.h40
-rw-r--r--kpilot/conduits/recordconduit/record-conduit.desktop93
-rw-r--r--kpilot/conduits/recordconduit/settings.kcfg22
-rw-r--r--kpilot/conduits/recordconduit/settings.kcfgc7
-rw-r--r--kpilot/conduits/recordconduit/setup_base.ui158
-rw-r--r--kpilot/conduits/sysinfoconduit/CMakeLists.txt50
-rw-r--r--kpilot/conduits/sysinfoconduit/Makefile.am24
-rw-r--r--kpilot/conduits/sysinfoconduit/Template.html184
-rw-r--r--kpilot/conduits/sysinfoconduit/Template.txt76
-rw-r--r--kpilot/conduits/sysinfoconduit/sysinfo-conduit.cc611
-rw-r--r--kpilot/conduits/sysinfoconduit/sysinfo-conduit.h79
-rw-r--r--kpilot/conduits/sysinfoconduit/sysinfo-factory.cc43
-rw-r--r--kpilot/conduits/sysinfoconduit/sysinfo-factory.h36
-rw-r--r--kpilot/conduits/sysinfoconduit/sysinfo-setup.cc198
-rw-r--r--kpilot/conduits/sysinfoconduit/sysinfo-setup.h47
-rw-r--r--kpilot/conduits/sysinfoconduit/sysinfo-setup_dialog.ui214
-rw-r--r--kpilot/conduits/sysinfoconduit/sysinfoSettings.kcfgc7
-rw-r--r--kpilot/conduits/sysinfoconduit/sysinfo_conduit.desktop111
-rw-r--r--kpilot/conduits/sysinfoconduit/sysinfoconduit.kcfg64
-rw-r--r--kpilot/conduits/timeconduit/CMakeLists.txt44
-rw-r--r--kpilot/conduits/timeconduit/Makefile.am22
-rw-r--r--kpilot/conduits/timeconduit/time-conduit.cc121
-rw-r--r--kpilot/conduits/timeconduit/time-conduit.h49
-rw-r--r--kpilot/conduits/timeconduit/time-factory.cc46
-rw-r--r--kpilot/conduits/timeconduit/time-factory.h41
-rw-r--r--kpilot/conduits/timeconduit/time-setup.cc86
-rw-r--r--kpilot/conduits/timeconduit/time-setup.h50
-rw-r--r--kpilot/conduits/timeconduit/time-setup_dialog.ui122
-rw-r--r--kpilot/conduits/timeconduit/timeConduitSettings.kcfgc7
-rw-r--r--kpilot/conduits/timeconduit/time_conduit.desktop107
-rw-r--r--kpilot/conduits/timeconduit/timeconduit.kcfg17
-rw-r--r--kpilot/conduits/vcalconduit/CMakeLists.txt75
-rw-r--r--kpilot/conduits/vcalconduit/Makefile.am43
-rw-r--r--kpilot/conduits/vcalconduit/README11
-rw-r--r--kpilot/conduits/vcalconduit/cleanupstate.cc132
-rw-r--r--kpilot/conduits/vcalconduit/cleanupstate.h49
-rw-r--r--kpilot/conduits/vcalconduit/conduitstate.h86
-rw-r--r--kpilot/conduits/vcalconduit/deleteunsyncedhhstate.cc115
-rw-r--r--kpilot/conduits/vcalconduit/deleteunsyncedhhstate.h53
-rw-r--r--kpilot/conduits/vcalconduit/deleteunsyncedpcstate.cc135
-rw-r--r--kpilot/conduits/vcalconduit/deleteunsyncedpcstate.h53
-rw-r--r--kpilot/conduits/vcalconduit/hhtopcstate.cc249
-rw-r--r--kpilot/conduits/vcalconduit/hhtopcstate.h55
-rw-r--r--kpilot/conduits/vcalconduit/initstate.cc109
-rw-r--r--kpilot/conduits/vcalconduit/initstate.h52
-rw-r--r--kpilot/conduits/vcalconduit/kcalRecord.cc143
-rw-r--r--kpilot/conduits/vcalconduit/kcalRecord.h49
-rw-r--r--kpilot/conduits/vcalconduit/korganizerConduit.ui275
-rw-r--r--kpilot/conduits/vcalconduit/pctohhstate.cc159
-rw-r--r--kpilot/conduits/vcalconduit/pctohhstate.h54
-rw-r--r--kpilot/conduits/vcalconduit/teststate.cc127
-rw-r--r--kpilot/conduits/vcalconduit/teststate.h55
-rw-r--r--kpilot/conduits/vcalconduit/todo-conduit.cc373
-rw-r--r--kpilot/conduits/vcalconduit/todo-conduit.desktop107
-rw-r--r--kpilot/conduits/vcalconduit/todo-conduit.h108
-rw-r--r--kpilot/conduits/vcalconduit/todo-factory.cc46
-rw-r--r--kpilot/conduits/vcalconduit/todo-factory.h40
-rw-r--r--kpilot/conduits/vcalconduit/todo-setup.cc86
-rw-r--r--kpilot/conduits/vcalconduit/todo-setup.h44
-rw-r--r--kpilot/conduits/vcalconduit/todoRecord.cc141
-rw-r--r--kpilot/conduits/vcalconduit/todoRecord.h49
-rw-r--r--kpilot/conduits/vcalconduit/vcal-conduit.cc309
-rw-r--r--kpilot/conduits/vcalconduit/vcal-conduit.desktop105
-rw-r--r--kpilot/conduits/vcalconduit/vcal-conduit.h101
-rw-r--r--kpilot/conduits/vcalconduit/vcal-conduitbase.cc622
-rw-r--r--kpilot/conduits/vcalconduit/vcal-conduitbase.h202
-rw-r--r--kpilot/conduits/vcalconduit/vcal-factory.cc50
-rw-r--r--kpilot/conduits/vcalconduit/vcal-factory.h41
-rw-r--r--kpilot/conduits/vcalconduit/vcal-factorybase.h44
-rw-r--r--kpilot/conduits/vcalconduit/vcal-setup.cc78
-rw-r--r--kpilot/conduits/vcalconduit/vcal-setup.h46
-rw-r--r--kpilot/conduits/vcalconduit/vcal-setupbase.cc110
-rw-r--r--kpilot/conduits/vcalconduit/vcal-setupbase.h51
-rw-r--r--kpilot/conduits/vcalconduit/vcalRecord.cc548
-rw-r--r--kpilot/conduits/vcalconduit/vcalRecord.h51
-rw-r--r--kpilot/conduits/vcalconduit/vcalconduitSettings.kcfgc7
-rw-r--r--kpilot/conduits/vcalconduit/vcalconduitbase.kcfg31
-rw-r--r--kpilot/config.h.cmake43
-rwxr-xr-xkpilot/configure213
-rw-r--r--kpilot/configure.in.bot18
-rw-r--r--kpilot/configure.in.in256
-rw-r--r--kpilot/kpilot/CMakeLists.txt180
-rw-r--r--kpilot/kpilot/Icons/CMakeLists.txt4
-rw-r--r--kpilot/kpilot/Icons/Makefile.am19
-rw-r--r--kpilot/kpilot/Icons/busysync.pngbin0 -> 2872 bytes
-rw-r--r--kpilot/kpilot/Icons/cr16-action-backup.pngbin0 -> 747 bytes
-rw-r--r--kpilot/kpilot/Icons/cr16-action-busysync.pngbin0 -> 705 bytes
-rw-r--r--kpilot/kpilot/Icons/cr16-action-fastsync.pngbin0 -> 705 bytes
-rw-r--r--kpilot/kpilot/Icons/cr16-action-fullsync.pngbin0 -> 674 bytes
-rw-r--r--kpilot/kpilot/Icons/cr16-action-hotsync.pngbin0 -> 701 bytes
-rw-r--r--kpilot/kpilot/Icons/cr16-action-listsync.pngbin0 -> 427 bytes
-rw-r--r--kpilot/kpilot/Icons/cr16-action-nosync.pngbin0 -> 844 bytes
-rw-r--r--kpilot/kpilot/Icons/cr16-action-restore.pngbin0 -> 787 bytes
-rw-r--r--kpilot/kpilot/Icons/cr16-app-kpilotDaemon.pngbin0 -> 712 bytes
-rw-r--r--kpilot/kpilot/Icons/cr22-action-backup.pngbin0 -> 1036 bytes
-rw-r--r--kpilot/kpilot/Icons/cr22-action-busysync.pngbin0 -> 1119 bytes
-rw-r--r--kpilot/kpilot/Icons/cr22-action-fastsync.pngbin0 -> 1052 bytes
-rw-r--r--kpilot/kpilot/Icons/cr22-action-fullsync.pngbin0 -> 994 bytes
-rw-r--r--kpilot/kpilot/Icons/cr22-action-hotsync.pngbin0 -> 984 bytes
-rw-r--r--kpilot/kpilot/Icons/cr22-action-listsync.pngbin0 -> 628 bytes
-rw-r--r--kpilot/kpilot/Icons/cr22-action-nosync.pngbin0 -> 1462 bytes
-rw-r--r--kpilot/kpilot/Icons/cr22-action-restore.pngbin0 -> 1060 bytes
-rw-r--r--kpilot/kpilot/Icons/cr22-app-kpilotDaemon.pngbin0 -> 1151 bytes
-rw-r--r--kpilot/kpilot/Icons/cr32-action-fastsync.pngbin0 -> 1638 bytes
-rw-r--r--kpilot/kpilot/Icons/cr32-action-fullsync.pngbin0 -> 1577 bytes
-rw-r--r--kpilot/kpilot/Icons/cr32-action-hotsync.pngbin0 -> 1647 bytes
-rw-r--r--kpilot/kpilot/Icons/cr32-action-listsync.pngbin0 -> 972 bytes
-rw-r--r--kpilot/kpilot/Icons/cr32-app-kpilotDaemon.pngbin0 -> 1836 bytes
-rw-r--r--kpilot/kpilot/Icons/cr48-action-fastsync.pngbin0 -> 2768 bytes
-rw-r--r--kpilot/kpilot/Icons/cr48-action-fullsync.pngbin0 -> 2675 bytes
-rw-r--r--kpilot/kpilot/Icons/cr48-action-hotsync.pngbin0 -> 2769 bytes
-rw-r--r--kpilot/kpilot/Icons/cr48-action-listsync.pngbin0 -> 1608 bytes
-rw-r--r--kpilot/kpilot/Icons/cr48-app-kpilotDaemon.pngbin0 -> 3228 bytes
-rw-r--r--kpilot/kpilot/Icons/cr64-action-kpilotaddress.pngbin0 -> 5176 bytes
-rw-r--r--kpilot/kpilot/Icons/cr64-action-kpilotbhotsync.pngbin0 -> 5163 bytes
-rw-r--r--kpilot/kpilot/Icons/cr64-action-kpilotcalendar.pngbin0 -> 5187 bytes
-rw-r--r--kpilot/kpilot/Icons/cr64-action-kpilotdb.pngbin0 -> 4988 bytes
-rw-r--r--kpilot/kpilot/Icons/cr64-action-kpilotfileinstaller.pngbin0 -> 4489 bytes
-rw-r--r--kpilot/kpilot/Icons/cr64-action-kpilotknotes.pngbin0 -> 4808 bytes
-rw-r--r--kpilot/kpilot/Icons/cr64-action-kpilottodo.pngbin0 -> 4526 bytes
-rw-r--r--kpilot/kpilot/Icons/fastsync.pngbin0 -> 1052 bytes
-rw-r--r--kpilot/kpilot/Icons/hi16-app-kpilot.pngbin0 -> 712 bytes
-rw-r--r--kpilot/kpilot/Icons/hi22-app-kpilot.pngbin0 -> 1151 bytes
-rw-r--r--kpilot/kpilot/Icons/hi32-app-kpilot.pngbin0 -> 1836 bytes
-rw-r--r--kpilot/kpilot/Icons/hi48-app-kpilot.pngbin0 -> 3228 bytes
-rw-r--r--kpilot/kpilot/Icons/hotsync.pngbin0 -> 3832 bytes
-rw-r--r--kpilot/kpilot/Icons/kpilot-splash.pngbin0 -> 68819 bytes
-rw-r--r--kpilot/kpilot/Icons/mini-kpilot.pngbin0 -> 1126 bytes
-rw-r--r--kpilot/kpilot/Icons/nosync.pngbin0 -> 844 bytes
-rw-r--r--kpilot/kpilot/Makefile-standalone167
-rw-r--r--kpilot/kpilot/Makefile.am104
-rw-r--r--kpilot/kpilot/addressEditor.cc271
-rw-r--r--kpilot/kpilot/addressEditor.h87
-rw-r--r--kpilot/kpilot/addressWidget.cc733
-rw-r--r--kpilot/kpilot/addressWidget.h144
-rw-r--r--kpilot/kpilot/conduitConfigDialog.cc849
-rw-r--r--kpilot/kpilot/conduitConfigDialog.h112
-rw-r--r--kpilot/kpilot/datebookWidget.cc133
-rw-r--r--kpilot/kpilot/datebookWidget.h66
-rw-r--r--kpilot/kpilot/dbAppInfoEditor.cc105
-rw-r--r--kpilot/kpilot/dbAppInfoEditor.h51
-rw-r--r--kpilot/kpilot/dbFlagsEditor.cc157
-rw-r--r--kpilot/kpilot/dbFlagsEditor.h56
-rw-r--r--kpilot/kpilot/dbFlagsEditor_base.ui376
-rw-r--r--kpilot/kpilot/dbFlagsEditor_base.ui.h24
-rw-r--r--kpilot/kpilot/dbRecordEditor.cc235
-rw-r--r--kpilot/kpilot/dbRecordEditor.h94
-rw-r--r--kpilot/kpilot/dbRecordEditor_base.ui151
-rw-r--r--kpilot/kpilot/dbSelectionDialog.cc144
-rw-r--r--kpilot/kpilot/dbSelectionDialog.h60
-rw-r--r--kpilot/kpilot/dbSelection_base.ui80
-rw-r--r--kpilot/kpilot/dbviewerWidget.cc440
-rw-r--r--kpilot/kpilot/dbviewerWidget.h91
-rw-r--r--kpilot/kpilot/fileInstallWidget.cc304
-rw-r--r--kpilot/kpilot/fileInstallWidget.h92
-rw-r--r--kpilot/kpilot/fileInstaller.cc184
-rw-r--r--kpilot/kpilot/fileInstaller.h82
-rw-r--r--kpilot/kpilot/hotSync.cc1156
-rw-r--r--kpilot/kpilot/hotSync.h175
-rw-r--r--kpilot/kpilot/internalEditorAction.cc394
-rw-r--r--kpilot/kpilot/internalEditorAction.h68
-rw-r--r--kpilot/kpilot/kpilot.cc1136
-rw-r--r--kpilot/kpilot/kpilot.desktop87
-rw-r--r--kpilot/kpilot/kpilot.gifbin0 -> 295 bytes
-rw-r--r--kpilot/kpilot/kpilot.h214
-rw-r--r--kpilot/kpilot/kpilot.kcfg186
-rw-r--r--kpilot/kpilot/kpilot.magic12
-rw-r--r--kpilot/kpilot/kpilot.upd34
-rw-r--r--kpilot/kpilot/kpilotConfig.cc346
-rw-r--r--kpilot/kpilot/kpilotConfig.h126
-rw-r--r--kpilot/kpilot/kpilotConfigDialog.cc528
-rw-r--r--kpilot/kpilot/kpilotConfigDialog.h134
-rw-r--r--kpilot/kpilot/kpilotConfigDialog_backup.ui207
-rw-r--r--kpilot/kpilot/kpilotConfigDialog_device.ui189
-rw-r--r--kpilot/kpilot/kpilotConfigDialog_startup.ui118
-rw-r--r--kpilot/kpilot/kpilotConfigDialog_sync.ui171
-rw-r--r--kpilot/kpilot/kpilotConfigDialog_viewers.ui149
-rw-r--r--kpilot/kpilot/kpilotConfigWizard.cc233
-rw-r--r--kpilot/kpilot/kpilotConfigWizard.h58
-rw-r--r--kpilot/kpilot/kpilotConfigWizard_address.kcfgc7
-rw-r--r--kpilot/kpilot/kpilotConfigWizard_app.ui112
-rw-r--r--kpilot/kpilot/kpilotConfigWizard_notes.kcfgc7
-rw-r--r--kpilot/kpilot/kpilotConfigWizard_user.ui168
-rw-r--r--kpilot/kpilot/kpilotConfigWizard_vcal.kcfgc7
-rw-r--r--kpilot/kpilot/kpilotDCOP.h75
-rw-r--r--kpilot/kpilot/kpilotProbeDialog.cc363
-rw-r--r--kpilot/kpilot/kpilotProbeDialog.h102
-rw-r--r--kpilot/kpilot/kpilotSettings.kcfgc7
-rw-r--r--kpilot/kpilot/kpilot_config.desktop159
-rw-r--r--kpilot/kpilot/kpilotconduit.desktop60
-rw-r--r--kpilot/kpilot/kpilotdaemon.desktop43
-rw-r--r--kpilot/kpilot/kpilotui.rc53
-rw-r--r--kpilot/kpilot/kroupware.cc311
-rw-r--r--kpilot/kpilot/kroupware.h87
-rw-r--r--kpilot/kpilot/listCat.cc272
-rw-r--r--kpilot/kpilot/listCat.h229
-rw-r--r--kpilot/kpilot/listItems.cc242
-rw-r--r--kpilot/kpilot/listItems.h114
-rw-r--r--kpilot/kpilot/logFile.cc128
-rw-r--r--kpilot/kpilot/logFile.h64
-rw-r--r--kpilot/kpilot/logWidget.cc396
-rw-r--r--kpilot/kpilot/logWidget.h90
-rw-r--r--kpilot/kpilot/loggerDCOP.h58
-rw-r--r--kpilot/kpilot/main-config.cc0
-rw-r--r--kpilot/kpilot/main-test.cc437
-rw-r--r--kpilot/kpilot/memoWidget.cc803
-rw-r--r--kpilot/kpilot/memoWidget.h112
-rw-r--r--kpilot/kpilot/pilot-addresses.c362
-rw-r--r--kpilot/kpilot/pilotComponent.cc190
-rw-r--r--kpilot/kpilot/pilotComponent.h141
-rw-r--r--kpilot/kpilot/pilotDaemon.cc1404
-rw-r--r--kpilot/kpilot/pilotDaemon.h279
-rw-r--r--kpilot/kpilot/pilotDaemonDCOP.h103
-rw-r--r--kpilot/kpilot/stamp-h.in0
-rw-r--r--kpilot/kpilot/syncCalendar.cc87
-rw-r--r--kpilot/kpilot/todoEditor.cc173
-rw-r--r--kpilot/kpilot/todoEditor.h74
-rw-r--r--kpilot/kpilot/todoEditor_base.ui180
-rw-r--r--kpilot/kpilot/todoWidget.cc608
-rw-r--r--kpilot/kpilot/todoWidget.h167
-rw-r--r--kpilot/lib/CMakeLists.txt90
-rw-r--r--kpilot/lib/COPYING509
-rw-r--r--kpilot/lib/Makefile.am60
-rw-r--r--kpilot/lib/actionQueue.cc172
-rw-r--r--kpilot/lib/actionQueue.h162
-rw-r--r--kpilot/lib/actions.cc137
-rw-r--r--kpilot/lib/actions.h115
-rw-r--r--kpilot/lib/idmapper.cc247
-rw-r--r--kpilot/lib/idmapper.h159
-rw-r--r--kpilot/lib/idmapperxml.cc213
-rw-r--r--kpilot/lib/idmapperxml.h84
-rw-r--r--kpilot/lib/idmapping.cc89
-rw-r--r--kpilot/lib/idmapping.h66
-rw-r--r--kpilot/lib/kpilotdevicelink.cc966
-rw-r--r--kpilot/lib/kpilotdevicelink.h220
-rw-r--r--kpilot/lib/kpilotdevicelinkPrivate.h330
-rw-r--r--kpilot/lib/kpilotlib.kcfg9
-rw-r--r--kpilot/lib/kpilotlibSettings.kcfgc7
-rw-r--r--kpilot/lib/kpilotlink.cc272
-rw-r--r--kpilot/lib/kpilotlink.h501
-rw-r--r--kpilot/lib/kpilotlocallink.cc368
-rw-r--r--kpilot/lib/kpilotlocallink.h95
-rw-r--r--kpilot/lib/options.cc157
-rw-r--r--kpilot/lib/options.h199
-rw-r--r--kpilot/lib/pilot.cc264
-rw-r--r--kpilot/lib/pilot.h410
-rw-r--r--kpilot/lib/pilotAddress.cc636
-rw-r--r--kpilot/lib/pilotAddress.h339
-rw-r--r--kpilot/lib/pilotAppInfo.cc77
-rw-r--r--kpilot/lib/pilotAppInfo.h216
-rw-r--r--kpilot/lib/pilotCard.h65
-rw-r--r--kpilot/lib/pilotDatabase.cc112
-rw-r--r--kpilot/lib/pilotDatabase.h272
-rw-r--r--kpilot/lib/pilotDateEntry.cc478
-rw-r--r--kpilot/lib/pilotDateEntry.h388
-rw-r--r--kpilot/lib/pilotLinkVersion.h60
-rw-r--r--kpilot/lib/pilotLocalDatabase.cc762
-rw-r--r--kpilot/lib/pilotLocalDatabase.h201
-rw-r--r--kpilot/lib/pilotMemo.cc135
-rw-r--r--kpilot/lib/pilotMemo.h105
-rw-r--r--kpilot/lib/pilotRecord.cc132
-rw-r--r--kpilot/lib/pilotRecord.h355
-rw-r--r--kpilot/lib/pilotSerialDatabase.cc432
-rw-r--r--kpilot/lib/pilotSerialDatabase.h144
-rw-r--r--kpilot/lib/pilotSysInfo.h144
-rw-r--r--kpilot/lib/pilotTodoEntry.cc270
-rw-r--r--kpilot/lib/pilotTodoEntry.h166
-rw-r--r--kpilot/lib/pilotUser.h128
-rw-r--r--kpilot/lib/plugin.cc760
-rw-r--r--kpilot/lib/plugin.h476
-rw-r--r--kpilot/lib/pluginfactory.h98
-rw-r--r--kpilot/lib/recordConduit.cc1145
-rw-r--r--kpilot/lib/recordConduit.h181
-rw-r--r--kpilot/lib/syncAction.cc512
-rw-r--r--kpilot/lib/syncAction.h410
-rw-r--r--kpilot/tests/CMakeLists.txt55
-rw-r--r--kpilot/tests/conduits/vcalconduit/exampletest.cc26
-rw-r--r--kpilot/tests/conduits/vcalconduit/exampletest.h28
-rw-r--r--kpilot/tests/data/AddressDB.pdbbin0 -> 1545 bytes
-rw-r--r--kpilot/tests/data/MailDB.pdbbin0 -> 1342 bytes
-rw-r--r--kpilot/tests/data/MemoDB.pdbbin0 -> 5262 bytes
-rw-r--r--kpilot/tests/data/ToDoDB.pdbbin0 -> 881 bytes
-rw-r--r--kpilot/tests/data/bogus.pdb367
-rw-r--r--kpilot/tests/exportdatebook.cc136
-rw-r--r--kpilot/tests/importaddresses.cc128
-rw-r--r--kpilot/tests/importdatebook.cc131
-rw-r--r--kpilot/tests/main.cc17
-rw-r--r--kpilot/tests/mergecalendars.cc228
-rw-r--r--kpilot/tests/testactions.cc92
-rw-r--r--kpilot/tests/testaddress.cc106
-rw-r--r--kpilot/tests/testcategories.cc215
-rw-r--r--kpilot/tests/testconstants.cc68
-rw-r--r--kpilot/tests/testdatabase.cc316
-rw-r--r--kpilot/tests/testdatebook.cc95
-rw-r--r--kpilot/tests/testidmapper.cc314
471 files changed, 74441 insertions, 0 deletions
diff --git a/kpilot/.emacs-dirvars b/kpilot/.emacs-dirvars
new file mode 100644
index 000000000..beac4cb1f
--- /dev/null
+++ b/kpilot/.emacs-dirvars
@@ -0,0 +1,7 @@
+;; -*- emacs-lisp -*-
+;;
+;; This file is processed by the dirvars emacs package. Each variable
+;; setting below is performed when this dirvars file is loaded.
+;;
+indent-tabs-mode: t
+tab-width: 4
diff --git a/kpilot/AUTHORS b/kpilot/AUTHORS
new file mode 100644
index 000000000..6d1d418d2
--- /dev/null
+++ b/kpilot/AUTHORS
@@ -0,0 +1,29 @@
+KPilot was written by Dan Pilone. It is currently under
+active development by a worldwide group of contributors.
+Adriaan de Groot and Reinhold Kainhofe are currently the maintainers.
+
+
+o Jason 'vanRijn' Kasper is prime motivator in 2006.
+o The vcal and todo conduit were originally written by Preston Brown.
+o The popclient conduit was written by Michael Kropfberger.
+o The null conduit and KNotes conduit were written by Adriaan de Groot.
+o The XML GUI stuff was written by Martin Junius.
+o Philipp Hullmann fixed many bugs in the todo conduit.
+o David Bishop converted most of the UI to Qt Designer .ui.
+o Reinhold Kainhofer fixed and extended the VCal conduits when it was
+ really needed.
+o The addressbook conduit was rewritten by R. Kainhofer to use libkabc
+o The time conduit, the MAL conduit (AvantGo) and the PalmDOC conduit
+ were also written by R. Kainhofer
+o Aaron J. Seigo, Jorg Habenicht, and others contributed too.
+o David Mott contributed useful extra features.
+
+For more information, see the About box or:
+http://www.kpilot.org/
+
+-- Dan Pilone 5/30/99
+-- Adriaan de Groot April 14th 2001
+-- Adriaan de Groot January 20th 2002
+-- Reinhold Kainhofer, April 5th 2003
+-- Adriaan de Groot, March 4th 2004
+-- Adriaan de Groot, November 18th 2006
diff --git a/kpilot/CMakeLists.txt b/kpilot/CMakeLists.txt
new file mode 100644
index 000000000..aae086ce5
--- /dev/null
+++ b/kpilot/CMakeLists.txt
@@ -0,0 +1,96 @@
+project(kpilot)
+
+if(EXISTS ${CMAKE_SOURCE_DIR}/CMakeOptions.txt)
+ include(${CMAKE_SOURCE_DIR}/CMakeOptions.txt)
+else(EXISTS ${CMAKE_SOURCE_DIR}/CMakeOptions.txt)
+ message(FATAL_ERROR "CMakeOptions.txt not found! Run configure first.")
+endif(EXISTS ${CMAKE_SOURCE_DIR}/CMakeOptions.txt)
+
+# Search our own cmake modules path first
+set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
+
+# Need 2.4.3 for its KDE3 support
+# Need 2.4.4 for its fixed KDE3 support
+cmake_minimum_required(VERSION 2.4.4)
+
+CONFIGURE_FILE(
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
+ IMMEDIATE @ONLY)
+
+ADD_CUSTOM_TARGET(uninstall
+ "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
+
+# Disallow in-source build
+STRING(COMPARE EQUAL "${kpilot_SOURCE_DIR}" "${kpilot_BINARY_DIR}" insource)
+if(insource)
+ MESSAGE(FATAL_ERROR
+ "KPilot requires an out of source build. Please create a separate build
+directory and run 'cmake path_to_kpilot [options]' there."
+ )
+endif(insource)
+
+find_package(Qt3 REQUIRED) # find and setup Qt3 for this project
+find_package(KDE3 REQUIRED) # find and setup KDE3 for this project
+find_package(Pilotlink REQUIRED)
+find_package(Mal) # see if mal is available, but it's not required
+
+add_definitions(
+ ${QT_DEFINITIONS}
+ ${KDE3_DEFINITIONS}
+ -DQT_THREAD_SUPPORT
+)
+
+STRING(COMPARE EQUAL "${CMAKE_BUILD_TYPE}" "debug" builddebug)
+if (NOT builddebug)
+ add_definitions(-DNDEBUG)
+endif(NOT builddebug)
+
+
+# Get the kde3 dir. This is a bit tricky, i'm not sure how well
+# this works on other systems.
+STRING(REPLACE "/lib" "" KDE3_DIR ${KDE3_LIB_DIR})
+
+# TODO: INSTALL PREFIX. RIGHT NOW EVERYTHING IS INSTALLED IN $KDEDIR
+if(NOT CMAKE_INSTALL_PREFIX)
+ set(CMAKE_INSTALL_PREFIX ${KDE3_DIR})
+endif(NOT CMAKE_INSTALL_PREFIX)
+set(KDE3_KCFG_DIR ${CMAKE_INSTALL_PREFIX}/share/config.kcfg)
+set(KDE3_SERVICETYPES_DIR ${CMAKE_INSTALL_PREFIX}/share/servicetypes)
+set(KDE3_SERVICES_DIR ${CMAKE_INSTALL_PREFIX}/share/services)
+set(KDE3_XDG_APPS_DIR ${CMAKE_INSTALL_PREFIX}/share/applications/kde)
+set(KDE3_LIB_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib)
+set(KDE3_PLUGIN_INSTALL_DIR ${KDE3_LIB_INSTALL_DIR}/kde3)
+
+# tell cmake where to search for libraries:
+link_directories(${KDE3_LIB_DIR})
+
+# tell cmake where to search for Qt/KDE headers:
+include_directories(${PILOTLINK_INCLUDE_DIR} ${KDE3_INCLUDE_DIR} ${QT_INCLUDE_DIR})
+
+# include custom macros
+INCLUDE(${CMAKE_SOURCE_DIR}/cmake/modules/KPilotCustom.cmake)
+
+# tell cmake to process CMakeLists.txt in that subdirectory
+add_subdirectory(lib)
+add_subdirectory(kpilot)
+add_subdirectory(conduits)
+
+
+STRING(COMPARE EQUAL "${ENABLE_TESTS}" "YES" buildtests)
+if (buildtests)
+ MESSAGE(STATUS "BUILD: Test suite enabled.")
+ enable_testing()
+ add_subdirectory(tests)
+else (buildtests)
+ MESSAGE(STATUS "BUILD: Test suite disabled.")
+endif(buildtests)
+
+if (builddebug)
+ MESSAGE(STATUS "BUILD: Debug build selected.")
+else(builddebug)
+ MESSAGE(STATUS "BUILD: Normal build selected.")
+endif(builddebug)
+
+MESSAGE(STATUS "BUILD: Install prefix set to ${CMAKE_INSTALL_PREFIX} .")
+
diff --git a/kpilot/COPYING b/kpilot/COPYING
new file mode 100644
index 000000000..7c3158817
--- /dev/null
+++ b/kpilot/COPYING
@@ -0,0 +1,355 @@
+[KPilot is licensed under the terms of this GNU GENERAL PUBLIC LICENSE,
+except for the following parts which are licenced under the GNU LESSER
+GENERAL PUBLIC LICENSE:
+
+* The contents of the lib/ directory under this directory (ie. kpilot/lib/),
+to allow plugins with non-GPL yet LGPL-compatible licenses to be written.
+
+* The NULL conduit in conduits/null/, so that it can serve as a development
+example even for non-GPL conduits.
+
+* The malconduit in conduits/malconduit/ is licensed under the GPL with the
+ additional specific permission for the code to be linked to libmal,
+ which is released under the Mozilla Public License (MPL).
+ This is necessary because the libmal license is not GPL-compatible.
+]
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/kpilot/ChangeLog b/kpilot/ChangeLog
new file mode 100644
index 000000000..01da1b8d9
--- /dev/null
+++ b/kpilot/ChangeLog
@@ -0,0 +1,4220 @@
+** KPILOT CHANGELOG **
+======================
+
+TODO: Figure out why archived records are bad.
+ [23:07] <till> Now i'm hunting why new entries on the palm are dropped and
+ deletes from the palm as well.
+ [23:44] <till> [ade]: Hm, I delete a task on the palm, sync, and the
+ record->isDeleted() is false, on sync, but it is modified and
+ updated on the pc, although that does not change anything.
+
+TODO: store map of pilot-id <-> uid elsewhere (not in the .vcf file)
+TODO: don't make ActionQueue auto-delete the actions in it.
+TODO: provide template-based, interpreted databases much like the
+ AppInfo classes now have.
+TODO: give the knotes conduit a decent test mode.
+TODO: only re-write a local database if it is changed.
+
+2007-12-30 Jason 'vanRijn' Kasper
+* Fixing bug reported by Pablo Yepes on kdepim-users mailing list. We did
+ severe goofiness with middle names... The Palm can't handle them, so we
+ blindly tacked firstname + " " + lastname and stuck it into the Palm's
+ firstname field. The problem is that whenever a copy from palm->pc is
+ done, the kludged first name is transferred to kabc ("firstname middle").
+ And, it's compounded by every change in either direction. It's an ugly
+ hack and I've removed it. The only way to work around it would be to add
+ an additional check for !firstname.endsWith(abEntry.additionalName()),
+ but that's even sillier. Stop the insanity!
+
+2007-12-17 Jason 'vanRijn' Kasper
+* Woot! Fixing major breakage for funky usb devices. pulled back some
+ removed code from KDE 3.5.6's kpilot for usb workaround code and fit it
+ into the new threaded model. This fixes syncing for me on my Palm Treo
+ 700p.
+* Reformatting and cleaning up kpilotdevicelink.cc.
+* New Private.h to hold the bits of kpilotdevicelink.cc that should not be
+ exposed via kpilotdevicelink.h. Also, DeviceCommThread extends QObject
+ and QThread, so we need to have automoc run on it.
+* Switching from using QCustomEvent to using QEvent for device tickle
+ thread to match what is done in kpilotdevicelink.
+
+2007-04-15 Jason 'vanRijn' Kasper
+* merging all development and bug fixes from kdepim-3.5.5+ branch into
+ stable branches/KDE/3.5 in preparation for KDE 3.5.7
+* cmake cleanups
+* namespacing and cleanups in sysinfoconduit
+* lots of debugging cleanups. remove #ifdef DEBUG from much of the code.
+* cleanups in memofile conduit. now try to use new (OS5) database
+ (MemosDB-PMem) if it's found, otherwise fall back to the legacy one
+ (MemoDB)
+* as a first step to combatting the "kpilot ate my future" e-mails (read:
+ data loss), we now use a CUDCounter (Create/Update/Delete). step 1 is to
+ track these and report on them to the user in their sync log. step 2 is
+ to catch ill behavior and prompt the user as to whether or not to allow
+ kpilot to make the large amount of changes. step 3 is to allow the user
+ to configure the count or percentage of changes that kpilot can make
+ without his/her confirmation. step 1 is done. we'll approach steps 2 and
+ 3 post kde 3.5.7.
+* new strings related to the above
+* bug fixing in popconduit... making sure we always have a sent date
+* Bertjan has the start of knotes cleanup going on
+* bug fixing in vcalconduit... long-time bug that existed in libkcal that
+ caused every calendar resource save to mark every calendar event as
+ modified. now kpilot won't have to sync every record every time.
+* bug fixing kabc resource problems in abbrowser conduit. although it's
+ not documented in kabc, it looks like we should be removing a local
+ resource from the address book before we delete it.
+* bringing mal conduit back alive again. none of our small band of merry
+ men use it, though, so it may or may not actually do what it's supposed
+ to.
+* fixing bug where we were saving conduit databases to DBBackup instead of
+ conduits/ directory.
+* changing KPilotDeviceLink to use a separate thread, dedicated to doing
+ device communication. this is much better design as a start, but fixes
+ the problems kpilot was having (and widely talked about) where kpilot
+ would hang and crash if our user was using "usb:" or "net:any" devices
+ because of how these new "device"s operated (allowed immediate opening,
+ even though there is no physical device connected, and then hung
+ indefinitely until the real device connected).
+* bringing in design documents (jpegs) for memofile conduit from 2004-12-12
+ (they're not installed, but are valuable for documentation and insight)
+* icon naming error bug fix 122582
+
+
+2006-10-24 Jason 'vanRijn' Kasper
+* Getting rid of FastSync. The only difference between it and HotSync was
+ that HotSync did a Backup and FastSync did not. Having a third
+ permutation because of not having a way to set it in the Backup settings
+ seems wrong. Also, if one of them is to go, I think that HotSync is much
+ more recognizable and widely used than FastSync.
+* Allowing finer-grained control around when database backups are done.
+ This is so that users can choose when they want a backup to be done.
+ The problem I need to solve for myself is that since I'm now syncing
+ between 2 PCs, I need a full sync to be done whenever I switch. But I
+ do not EVER want an automatic backup to be done. Currently, this is not
+ possible. Fixing it. =:) This will also allow for schedule backups to
+ be done, which is also of interest to me.
+
+2006-01-30 Adriaan de Groot
+* Updated pilot-link to today's CVS, with one change - use of pl_socklen_t
+ in inet.c changed back to socklen_t.
+* Added --loop to kpilotTest to repeatedly run the same action. Only
+ works for --list right now.
+
+2006-01-23 Adriaan de Groot
+* Gosh, where to begin. KPilot moved SVN repositories, changed build
+ systems, had the guts of the device link class refactored, bumped the
+ plugin API version again, and tons more. The commit logs are probably
+ the most useful source of information about what's changed.
+
+2005-08-18 Adriaan de Groot
+* Found out that the PilotAppCategory constructor that takes
+ a PilotRecord * was passing subsequent parameters in the wrong
+ order, which caused Jason's problem below.
+* Renamed soem icons and fixed up the icon loading code so that
+ the "sidebar" icons in KPilot can now be themed as well.
+
+2005-08-18 Jason 'vanRijn' Kasper
+* Started fixing bug #103581. Got side-tracked by my discovery that when
+ we change ToDos on the palm, we sync them to the PC and then promptly
+ delete them from the Palm--not very nice of us. I'll try to get the rest
+ working tomorrow, but the end result will be that if our user changes a
+ ToDo category and there is only one category in korganizer for that ToDo,
+ we will change the category for the KCal event. If there is already more
+ than one category that korganizer knows about, then we'll continue to
+ append the Palm's category to the one in korganizer.
+
+2005-08-17 Adriaan de Groot
+* Promote the new Pilot*Info (template) classes which simplify loading
+ AppInfo structures from a database. Deprecate some AddressEntry
+ constructors to do so, and add one that takes a PilotAddressInfo
+ instead. In kpilot/, replace a bunch of error-prone buffer-handling
+ calls by the use of these template classes.
+* Use PilotAddressInfo also in the abbrowser conduit. This removes a
+ bunch of tricky encoding handling from the conduit and puts it in
+ the base Info class, where it belongs.
+
+2005-08-16 Jason 'vanRijn' Kasper
+* Fixed annoyance in vcalconduit (korganizer calendar/todo conduit) that
+ caused it to not clean up duplicates/things that should be deleted from
+ the Palm on a copy PC to Handheld sync.
+* Fixed some majorly ugly bugs in the addressbook conduit that caused
+ duplicate addressbook records to be generated and not deleted once
+ created.
+
+2005-08-15 Adriaan de Groot
+* Added lots of null-pointer checks so that it may become possible to
+ run conduits without a device link soon. This would be good for testing.
+* Noticed that the factory code needs refactoring into templates.
+ Did so, and ported the abbrowser factory to it. Basically, this
+ removes a lot of cut-and-paste from the whole thing. Same for the
+ timeconduit.
+
+2005-06-05 Adriaan de Groot
+* I learned to make Chinese dumplings yesterday. That's a much better use
+ of a saturday afternoon than bug hunting, don't you think?
+* Put lots of effort into the dox for PilotDateEntry, normalized a lot
+ of things, gave things slightly more sensible names. This is work towards
+ implementing the DatabaseInterpreter for appointments, so you can treat
+ the data on the Pilot as a sequence of (libkcal) Events instead of as
+ binary blobs.
+* Patch from Dylan G applied that replaces 15s and 16s in the code with a
+ defined constant (there already was one, just not used consistently).
+ Did some more rationalizing, finally removed the CATEGORY_COUNT define
+ which was just a duplicate.
+
+2005-05-27 Adriaan de Groot
+* Start of the PIM meeting! Way!
+* Committed some critical data-loss fixes yesterday. Too late for the KDE 3.4.1 release.
+ Argh. I think it would have been better not to touch BRANCH at all and leave it
+ at the same buggy state as in KDE 3.4.0
+* Fairly large-scale deprecation of functions in lib/, finally factored out the
+ shared attributes/category/id stuff from records and AppCategory objects.
+
+2005-05-26 Jason 'vanRijn' Kasper
+* Fixing nasty little bug (#106324) causing data loss in memofile conduit
+* isFirstSync() is true for both copyHHtoPC and copyPCtoHH. memofile
+ conduit only wants to do copyHHtoPC if we're either told to, or we don't
+ have any local memos in the filesystem
+
+2005-05-22 Adriaan de Groot
+* Gratuitously update the version number, call this one "kind" (Dutch for
+ "child", or otherwise short for "kind of liable to eat your data").
+ This sort-of makes me wish we'd just left BRANCH totally unchanged
+ since the last release. KDE 3.4.1 tomorrow.
+
+2005-05-20 Adriaan de Groot
+* Split PISOCK_LIB into PISOCK_LIB and PISOCK_LDFLAGS. This makes it possible
+ to slip the include and library dir for pilot-link right in front, which in
+ turn makes it possible to build against development pilot-link versions even
+ if there are installed copies in standard locations as well.
+* Extended the AppInfo template class with a pack function as well, so that
+ reading and writing AppInfo blocks can be delegated there.
+* Ported the ToDo conduit to use the PilotToDoInfo template instantiation.
+
+2005-05-16 Adriaan de Groot
+* Added yet another constructor to the local databases, this time hopefully
+ one that doesn't have a horribly convoluted semantics -- it just opens
+ a file (or not).
+* Added more tests for lib. These will always fail unless you have a copy
+ of Aesop's fables in /tmp .
+
+2005-05-13 Adriaan de Groot
+* Friday the 13th! I merged HEAD to BRANCH and am now working in
+ BRANCH (branches/KDE/3.4/kdepim/kpilot) to do bugfixes. New features
+ and strings go in HEAD, and we'll forward-port bugfixes at some
+ point. The cutover is revision 413061.
+
+2005-05-11 Adriaan de Groot
+* Wasted much time trying to get generic FreeBSD USB support for non-
+ Visors working in pilot-link-0.12 before I found out that ColdSync
+ doesn't support that either.
+* Removed non-working calendar conduits (calendarbaseconduit/ and
+ calendarconduits/) from the conduits dir; restore them w/ SVN
+ commits near 412528. These were recordconduit-based conduits
+ by Reinhold, but I broke the RecordConduit in the meantime.
+
+2005-05-07 Adriaan de Groot
+* After tweaking pilot-link 0.12-pre3 so that KPilot will with it (has to do
+ with API consistency) the AppInfo template class works again, and i've
+ extended it a little to make setting and getting category names nicer.
+* Applied the new template to the memofile conduit.
+
+2005-04-22 Adriaan de Groot
+* Fixed (I hope) bug in notepad conduit related to having zero records in the
+ database.
+* Added some more dox.
+
+2005-04-20 Adriaan de Groot
+* Finally added a general test() function to sync actions to mirror the
+ exec() call. By default, this calls exec() and logs a warning. Removed it
+ again because it won't work -- SyncAction doesn't _have_ a SyncMode set.
+* Started doing a little bit of test code in the KNotes conduit.
+
+2005-04-18 Adriaan de Groot
+* Being on vacation doesn't mean I'm not on the job. Doxied a lot, did some cleanup.
+* Renamed PilotLocalDatabase::writeID() and changed its signature, since it
+ was kind of stupid. Doxied it, too.
+
+2005-04-12 Adriaan de Groot
+* For a lark, and for David, re-added some KDE 3.2 compatibility code.
+* Template madness! An easy way to create the right appinfo's from any database.
+
+2005-04-11 Adriaan de Groot
+* Bumped KPilot version.
+* Added a test program for some parts of the library. Woo! A first!
+ Finally something resembling actual software engineering in KPilot.
+* Cleaned up headers that weren't including all required (system) headers.
+* Moved all the conduits to the new SyncMode.
+
+2005-04-10 Adriaan de Groot
+* Some useful patches from Philip T. to the vcal conduit committed.
+* Made the sync mode a full-fledged class and ported lib/ and kpilot/
+ to use it. Disabled all the conduits for the time being. Bumped the
+ conduit API because of this. This might cause some serious breakage
+ for the time being.
+
+2005-04-09 Adriaan de Groot
+* Geez, can we switch to Subversion yet?
+* Committed the weird-ass record conduit template changes. This makes the
+ RecordConduit a fully templated "container". You plug in 5 other classes
+ to get a working implementation. This is similar to what the record
+ conduit already. The main difference is that it is easier to re-use
+ the things you plug into the recordconduit template. I have a KNotes
+ partial implementation that wraps KCal::Calendar, so that is immediately
+ reuseable for the other 4-button ones.
+* Ripped out test mode from KPilotTest and elsewhere, since it wasn't working
+ at all. I think the "mode" setting for conduits needs a lot more structure.
+ Just having an enum doesn't cut it (what about doing a test-mode local
+ PC to HH sync? Such a sync could be used to produce .pdb files from Kontact
+ data, which is just what the doctor ordered sometimes).
+
+2005-03-22 Adriaan de Groot
+* Long drought in doing any KPilot work or updating the ChangeLog.
+* Meddled in lib/ some to add modifiedIDList() and sanitize some types.
+* Prepared to make fFirstSync private, though it has getters and setters
+ so that doesn't really do much for OO'ness.
+* Wrote a template class for doing syncs generically, to replace the
+ RecordConduit. This one I understand, at least. It's not done yet though,
+ by a long shot, though I have classes to plug in to it for KNotes.
+
+
+
+2005-01-30 Adriaan de Groot
+* Fixed one nasty random crash thanks to vanRijn, probably fixed
+ the KNotes HHtoPC problem, tagged 4.4.7, released it. This
+ is the last version to support KDE 3.2 at all, since KDE PIM
+ moved to KDE 3.3 ages ago and KDE 3.4 is at the door.
+
+2005-01-12 Adriaan de Groot
+* Made KNotes conduit work when KNotes is embedded in kontact, too.
+* One branch of the check-username code wasn't setting the username properly.
+* More debugging niftiness, major NO_CAST cleanup.
+* Fixed sysinfo conduit, which didn't read its config file.
+
+
+2005-01-11 Adriaan de Groot
+* Added a workaround for buggy Zire USB behavior. It works most of the time.
+* Fixed memory leak when reading AppInfo.
+* Updated website with some more OS-specific information. As always, I am
+ in dire need of workable explanations for OS (usually Linux-distro)
+ specific quirks.
+* Worked on debugging output a little, normalized more output.
+* Verified that copy PC to HH works on Addressbook, ToDo, Calendar.
+
+
+2005-01-05 Adriaan de Groot
+* Pilot-link 0.12, when it comes out, is source incompatible with 0.11,
+ but KPilot is already ported to it.
+* Fixed up silly conflict resolution question in the datebook, but
+ really it needs the field-by-field resolution that the addressbook has.
+* In KPilotDeviceLink, move around check for unconfigured device to
+ notice earlier, before doing any work. Minor coding style fixes.
+* Revamped debugging (again) so it's now much more 7 * 191; the call trace
+ is pretty readable now.
+
+2004-12-27 Adriaan de Groot
+* Quitting and having the daemon go with you works now.
+
+2004-12-07 Adriaan de Groot
+* Tried to make conduit descriptions more consistent. Remember: "handheld",
+ not "Pilot". Removed ugly const_cast. Added depth indication to the
+ call trace -- this is a pretty big change, it makes the output from
+ kpilot with --debug 1 more tree-ish, so it's easier to see what is being
+ called from where.
+
+2004-12-06 Adriaan de Groot
+* Imported memofile from vanRijn.
+
+2004-11-30 Adriaan de Groot
+* Having a second child .. puts a dent in development time.
+* Make the daemon's next-sync match the one in KPilot, added tooltips
+ and whatsthis. Make the daemon tell KPilot what the next sync is,
+ so that changes from the tray menu are visible. This removes some strings.
+
+2004-11-29 Adriaan de Groot
+* Waiting for second child .. puts a dent in development time too.
+* Ported KPilot to pilot-link 0.12 (unreleased) which adds support
+ for newer devices and saves memory in the process.
+* Data-loss on restore bug fixed by Will Stephenson.
+
+2004-11-23 Adriaan de Groot
+* Squashed several silly bugs in wizard and startup code.
+
+2004-11-17 Adriaan de Groot
+* Hiatus in KPilot due to working upstream on pilot-link.
+* Patches from Olivier, merci.
+
+2004-10-11 Adriaan de Groot
+* Made an actual CVS tag for KPilot, kpilot_4_4_6. Uploaded new 4.4.6
+ tarballs. Updated the site. Posted more developer's notes.
+* Added initial encoding-selection boxes to the doc conduit, to indicate
+ that the input text files are not UTF-8 but something else.
+* Started revamping PilotLocalDatabase so we can get rid of the must-
+ sync-to-delete-new-(memo|address|whatever) in the internal viewers.
+* All the bugs in the database really need a "can you check this again"?
+ added. Till Adam has been messing with recent code and is reporting
+ new crashes and bugs.
+
+
+2004-10-07 Adriaan de Groot
+* Started adding encoding support to PalmDOC conduit dialogs. Not
+ sure how to proceed there.
+* Closed some more bugs, generally confused about some of the bugs
+ remaining in the database -- I need cooperation from the folks
+ reporting the bugs.
+* Went on a str*cpy() hunt to avoid bad copies; converted most to
+ strlcpy(). Not the ones in the docconduit, though, since there,
+ the strncpy()s go to a data structure that doesn't necessarily
+ expect NUL termination (note to self: need to check that _extracting_
+ data from the structure doesn't rely on NUL).
+
+2004-10-05 Adriaan de Groot
+* I wonder if the codec() stuff shouldn't move from the PilotAppCategory
+ to the device link -- after all, it's the _device_ that knows what
+ the encoding is (who knows, maybe future versions of Pilots will be
+ able to tell th desktop this).
+* Added a localBackup action, so we can make ~ backup files of all the
+ database files before doing a sync, just in case.
+* Merged lots of bugs.
+* Found out that KPilot uses title instead of prefix for the honorific
+ titles in the addressbook - this means KPilot and KAddressbook got
+ out of sync. Fixed.
+* New questionYesNoCancel() didn't return correct button codes.
+* Checked all the codec stuff, added some in relevant places but can't
+ spot any addressbook fields that are not synced.
+
+2004-10-04 Adriaan de Groot
+* Bail if the Pilot disconnects, but only between conduits. Conduits
+ themselves should still check for disconnect.
+* Bug maintainence turned up a useful patch for category support
+ in the calendar.
+
+2004-10-01 Adriaan de Groot
+* Merged nice patch from Adrian S for HotPlug.
+* Moved tickle stuff into a separate thread, so that it doesn't
+ require a Qt event loop to keep the Pilot awake.
+* Added tickles in the right (?) places in the abbrowser - around
+ the loading part.
+* Discovered that UserCheck used KMessageBox::question*() instead of
+ a version with timeouts. Fixed that by adding a qYNCancel() to
+ InteractiveSync, and updated both qYN*() methods there to use
+ KDE 3.3 KMessageBox support.
+* Merged InteractiveAction with SyncAction, cleaning up the inheritance
+ tree and making it possible to conduits to use the question* methods.
+
+2004-09-26 Adriaan de Groot
+* Put up new tarballs on kpilot.org.
+* Patched up the KNotes conduit a little - notes listed as modified
+ but unknown to the Pilot are now added as new.
+* Bumped version to 4.4.5. Polished the splash a little.
+* Fixed 71122, finally. There wasn't any code at all in the conduit
+ for deleting memos.
+
+
+2004-09-22 Adriaan de Groot
+* Added some cheap RTTI to PilotDatabase, so you can call
+ dbType() to find out if it's really a local or a serial DB.
+* Stared at the doc conduit for a long time. Did whitespace first.
+
+2004-09-18 Adriaan de Groot & Reinhold Kainhofer
+* Deprecated a bunch of poorly-named functions in lib/, and
+ moved everything to the new names. Finally, no more getCat(),
+ but just category().
+* Detect special case of bad resource headers in file installer.
+* Rearranged sync enum just a little. Moved eTest out of the way,
+ since it's not really a valid value to pass to the demon and made
+ 0 the value to indicate "default, whatever is stored in the
+ config file".
+* Fixed up sync-type not honored, clarified next-sync menu (I
+ think so, didn't ask -usability about it though).
+
+
+2004-08-16 Adriaan de Groot
+* Was away at a summer school for two weeks. Got no KPilot stuff
+ done except an off-by-one bug in the memo stuff.
+* Split the CopyHHtoPC code out in the knotes conduit,
+ ready for QThreading (maybe).
+
+2004-07-27 Adriaan de Groot
+* MAL conduit proxy password not loaded properly. Reported by
+ Olivier D.
+* Clean out ancient cruft in fileInstaller.{h,cc}. Run file installer
+ twice, to allow conduits to create files to install. Determine
+ list of files at ::exec() time, not at object creation time.
+* Added some docs to the conduit configure.in.in.
+* Give PERL conduit more information to work with.
+
+2004-07-19 Adriaan de Groot
+* In kontact, if the daemon gets started it shouldn't complain loudly
+ about messed-up configurations.
+
+2004-07-14 Adriaan de Groot
+* Joyeux quatorze juillet! Spent most of the past week totally ignoring
+ KPilot, working on personal websites, KDE-FreeBSD, and porting
+ k3b to FreeBSD (breaking it on Linux only briefly).
+
+2004-06-29 Reinhold Kainhofer
+* Fix the bug that todos that were marked finished on the handheld
+ lost that state when synced to the PC.
+* A few layout adjustments for the perl/python conduits (QTextEdit
+ instead of QLineEdit)
+
+
+2004-06-29 Joern Ahrens
+* Corrected the behavior of the configuration dialog, when the
+ screensaver option is changed.
+* Moved the tickle code from InteractiveAction to SyncAction.
+ Now it can be used in ConduitAction subclasses as well.
+* Ahh, got Adriaans m100, now I'm able to test without destroying
+ my data on the palm. Thanks Adriaan !
+
+2004-06-27 Joern Ahrens
+* Filled the notepad conduit with life. The notepads are saved as png
+ files in a configurable directory.
+
+2004-06-21 Adriaan de Groot
+* Disable editor buttons when 'internal editors' is disabled (Carlos)
+ and fix up the tooltips when they are disabled. Also update some
+ copyright lines. Work on the docs.
+
+2004-06-16 Adriaan de Groot
+* Disposed of foolish file installer bug. Updated tarballs on website
+ before fixing it, so now we're stuck :) Looked at 71122 again,
+ testing with my m500.
+* Corrected finaly layout problems in some conduit config pages.
+
+2004-06-10 Adriaan de Groot
+* Much delay in getting back to work on KPilot, even after a new mobo
+ arrived for my primary devel system. Useful patches were received
+ in the meantime, and commited by Joern. Olivier D. has started
+ improving the MAL conduit, wrt. proxy and password support.
+
+2004-06-02 Joern Ahrens
+* Improved the wizards whatsthis text, thanks to David Bishop
+
+2004-05-30 Adriaan de Groot
+* Handle first-time startups more gracefully by just running configure or
+ the config wizard. Better reporting of non-running daemon. Fix some
+ copyright headers. Add icons to next-sync menu in daemon.
+
+2004-05-28 Adriaan de Groot
+* Make the tarballs available on the site; still no resolution for
+ memo bug, or timezone bug. Change strings in the applications to
+ point ot the new kpilot.org.
+
+2004-05-20 Adriaan de Groot
+* Tested new tarballs for 4.4.3, and they seem ok. Put their md5s up on the
+ website. Note that the memos-not-deleted-on-palm bug still exists, as
+ do 60 others by last count.
+
+2004-05-16 Adriaan de Groot
+* Put up the new KPilot.org website.
+* Updated docs about net: syncing, thanks to Miles Sabin.
+* Patch from Joern probably closes 4 bugs at once.
+
+2004-05-11 Reinhold Kainhofer
+* Deprecated the JPilotProxy and expenses conduits, moved to nonbeta.
+
+2004-05-07 Adriaan de Groot
+* PilotDatabase was a QObject. I wonder why, it didn't have signals or slots.
+* PilotDatabase creation and destruction is now tracked (counted, at least,
+ so you can see if there's a leak there).
+
+2004-04-30 Adriaan de Groot
+* Vrolijke koninginnedag!
+* Finally updated the site some.
+* Removed deprecated files, started using KDevelop, fixed random stuff.
+
+2004-04-28 Adriaan de Groot
+* [kpilotConfigDialog] Added UI for screenlockSecure option. Docs, too.
+* [kpilot] Changed hotSync button to one with a little dropdown
+ menu, thanks to Joern. [kpilotConfig] String fix for outdated config.
+ [probeDialog] Fixed up comments. [hotSync] Normalized debugging output.
+ [pilotDaemon] Fixed backwards logic.
+
+2004-04-26 Adriaan de Groot
+* [kpilot.kcfg] Added [a68k] as default skip in the database list.
+* [pilotDaemon] Use standard names for sync actions. Queue sorry
+ when sync type is bad.
+* [hotSync] Change signature of backup action, lose the confusing
+ int mode parameter.
+* [syncStack] Took out the mode stuff, replaced with SyncAction::SyncMode.
+ This simplified a lot of things, actually. Removed extra changed-PC check
+ in ConduitProxy, on the assumption this is already checked elsewhere.
+
+2004-04-21 Adriaan de Groot
+* [hotSync] Made skip-database work properly, with wildcard support
+ and proper checking again, so you can now backup your Pilot and
+ specify that FATFS and *a68k can be skipped. Even did docs for it.
+* [syncAction] Added function to return standard names for the
+ (enum) sync actions.
+
+2004-04-19 Adriaan de Groot
+* Cleaned up header comments, copyrights, body comments, indentation,
+ brace style, and unused code in all kinds of files. Normalized use of
+ magic constant 0xffff in PilotRecord::APP_BUFFER_SIZE. Removed
+ some * in char *buffer[] where char buffer[] was meant, reducing KPilot's
+ stack memory usage there by a factor of 4 or more.
+* Patch from Joern Ahrens to close another Bugzilla bug.
+
+2004-04-18 Reinhold Kainhofer
+* Finish the autodetection of the handheld for the wizard. You *CAN* pi_bind
+ to multiple devices, so I just create a bunch of device links and wait for
+ connected signals... This also means we can get rid of page one of the wizard.
+ There is one problem left: If /dev/pilot or so is a symlink to a real device,
+ a connection on /dev/pilot and the actual device will be detected, and kpilot
+ will lock up. I guess I'll have to keep a (static) QStringList of real devices
+ we are bound to in KPilotDeviceLink and disallow binding to the same real
+ device again.
+
+2004-04-18 Adriaan de Groot
+* Default debug_level to 0, so it doesn't print the call trace, but just the
+ (sometimes) useful debug output; use --debug 1 to print the call trace.
+* [pilotDaemon] Add more useful warning output when conversation with screen-
+ saver fails. Add human-friendly way to request a specific sync type.
+ Factor out a whole lot in the startHotSync() to clear up the actual logic.
+* Massive damage inflicted to factor out the one set of sync-enums and
+ use them everywhere, while cleaning up the setup-sync logic too.
+ Remove leading 'e' from enum type names (not the elements).
+
+2004-04-16 Adriaan de Groot
+* Fixed double dialog when cancelling a change in the selection in the config
+ dialog. Took patch from Joern to fix resize problem in abbrowser resolution
+ dialog. Minor constructor mod in pilotMemo.h, and a much more nasty problem
+ in pilotMemo.cc, which seems to use a wrong memo length. Added some
+ docs. Removed a warning in addressWidget.cc.
+* [conduitConfigWizard] Can't assign copyright except in writing, and even then
+ in the EU you can't renounce your copyright. Added a "None" sync setting,
+ for the use-case described on 4-11.
+
+2004-04-11 Adriaan de Groot
+* Testing, testing, 1, 2, 3. Let's look at a use case: someone who doesn't want
+ to sync his or her palm with KDE apps, but does want a convenient application
+ to install files and keep a backup of their palm. How can they use KPilot?
+ Well, uncheck all the conduits except install files, set the daemon to auto-start,
+ and do nothing more than drop the pilot inthe cradle occasionally and hit the
+ HotSync button. Use kpilot's viewers to check the state of the backup.
+* [conduitConfigDialog] Use the CE macro for general config pages. Tighten typing
+ on handleGeneralPages. Add names to the viewers tabs. Make unsaved-changes
+ message make sense.
+
+2004-04-11 Reinhold Kainhofer
+* Fix the codec handling to use KGlobal::charsets.
+* Implemented the startListening and stopListening methods of the daemon.
+* Fixed the config dialog so that just showing a conduit's config widget
+ doesn't trigger the modified signal.
+* Some cleanup in the daemon
+
+2004-04-10 Reinhold Kainhofer
+* Split kpilot's configuration into several files, one for each conduit.
+ Also wrote a kconf_update script so the old settings are preserved.
+ We still need to sort out the remaining settings written to kpilotrc.
+* Corrected all path variables in the .kcfg files from type String to Path
+* The configuration wizard now also sets the conduits' settings to sensitive
+ defaults for the chosen application (kde pim, kontact, evolution)
+
+2004-04-10 Adriaan de Groot
+* Move about in config dialog to sensible spot. Follow suggestions by Carlos
+ to simplify the config dialog a bit. Default general setup to open, even
+ if the message says it it for esoteric stuff.
+
+2004-04-09 Adriaan de Groot
+* Work on docs. Accept patch from Joern for broken config in abbrowser
+ conduit. Receive docs patches from Carlos.
+
+2004-04-05 Adriaan de Groot
+* Work on the Kontact plugin for KPilot, make daemon's installedConduits
+ DCOP call return human-readable names instead of internal stuff.
+
+2004-04-04 Adriaan de Groot
+* Split out the general settings pages so that no tab widgets are
+ needed. Joern's title patch for those pages made the tabs weird
+ anyway, and now things are consistent, at least. We could move
+ the backup page to "Actions", if we want.
+
+2004-04-01 Adriaan de Groot
+* Happy birthday to Mira, who has now managed to watch a whole
+ year of KPilot development, and has learned to sit up and say
+ "aya!" appreciatively when Daddy fixes a bug. Or something.
+
+2004-03-28 Adriaan de Groot
+* Added a "reset daemon" button. Added whatsthis help to toolbar.
+* Added a "suppress confirm" option to the notes conduit, partly
+ for 71122.
+* Suppressed some more warnings. Fixed little buglets. Put off
+ testing 71122 as long as possible.
+
+2004-03-26 Adriaan de Groot
+* Another day, another fix from Joern.
+* Backported the fix for backup settings being ignored from Sebastian V.
+ (Actually, just used his original patch, which didn't use kcfgXT.
+* Prevent sync when screen locked, as a security measure.
+* Still haven't tested 69595 or 71122. Ugh.
+
+2004-03-24 Adriaan de Groot
+* 71122 has been top of the list for over a week - not getting around to
+ it at all. Fixes elsewhere; working on getting a Linux machine up and
+ running to be able to run POSE with a null-modem pseudo-device.
+* Another patch from Joern; arr, it's a learning experience!
+* Removed logging weirdness in the fileinstall action.
+
+2004-03-19 Adriaan de Groot
+* Discovered that the daemon's DCOP interface disappears after one
+ HotSync. Man, that's weird. Removed QString(CSL1()) constructs -
+ CSL1() returns a QString already. Using DCOPClient::attach() in
+ the pop conduit is a really bad idea!
+* Picked bug 72251 to work on tonight. Closed another one related to
+ settings not propagating properly as well.
+* Minor cleanup in the log on the pilot, get conduits to start on new lines.
+ Use correct name for icon. Handle FastSync correctly, don't queue all
+ the extra checks for it based on the sync settings (or do we want to
+ deprecate fastsync as a fNextSyncMode entirely?). At end of sync
+ reset next sync to normal.
+
+2004-03-17 Reinhold Kainhofer
+* Implemented a first version of the config wizard. The code to autodetect
+ the device is not yet finished, though.
+* Extended the daemon DCOP interface to stop listening and start listening
+ on the configured device (needed e.g. if some other application wants to
+ bind to that device for some time, like the autodetect dialog needs to).
+ Here, also the code for really (de-)attaching to the device is not there
+ yet, just the interface to the functions.
+
+2004-03-17 Adriaan de Groot
+* Ripped out all the dead and broken and useless code in the mail
+ conduit, fixed up the code that was left, reduced the size of the
+ setup dialog, and ended up with something that actually works again.
+ Fixed bugs 60579 and 77948.
+* Yet another patch from Joern, added him to credits, too.
+
+2004-03-15 Adriaan de Groot
+* Patches from David Mott and Joern Ahrens today. Excellent!
+* Worked on the docs and website some.
+
+2004-03-14 Reinhold Kainhofer
+* Make sure the config is really read in in the vcal conduit's setup dlg.
+* also the conduit version number of the vcal conduit needs to be really
+ written to the cfg file to make sure categories are really synced. So far,
+ the version number was not written to the config, which resulted in a full
+ sync every time!
+
+2004-03-13 Adriaan de Groot
+* Stared at the screen for a while trying to think of how to test syncing
+ with my spare m100 without breaking my existing stuff from my m500.
+ And I realize that it means I need a second monitor and to run X dual-head.
+* Some minor rearrangements in the config dialog again.
+* Added configuration widget to perl conduit.
+
+2004-03-12 Adriaan de Groot
+* Received patches from Joern Ahrens and Sebastian Voitzsch for
+ various issues. Thanks guys! It's contributions like this that
+ really inspire me to keep working on KPilot. Reinhold and I can't
+ do everything by ourselves.
+* There will be tarballs of KPilot 4.4.2 soon; this will make it
+ possible to get the bugfixes from Joern and Sebastian - and others -
+ on your system now without waiting for another KDE release.
+
+2004-03-08 Reinhold Kainhofer
+* Ported all conduits' setup dialog to the new style and remove all old code
+* First steps for the config wizard.
+* Updated the malconduit to work with libmal 0.4, too (using configure
+ checks, as the code is source-incompatible)
+* Moved the kpilot config page to the correct place in the kontact
+ setup dlg hierarchy
+* Fixed a crash in the old-style conduits' setup code (widget was removed
+ in favor of some other, but code still tried to access it)
+
+2004-03-08 Adriaan de Groot
+* Wow, lots of activity by Reinhold. I hope he updates the ChangeLog
+ sometime as well.
+* Revert the variable timeout, just do a straight 5 second wait, that
+ should just fix it, and save us a lot of trouble too. Anyway, who
+ wants to sync again within 5 seconds of the previous one finishing?
+ It's just as well that the value wasn't saved anywhere anyway.
+
+2004-03-05 Adriaan de Groot
+* Spent most of the day putting together new tarballs, so I can push
+ KPilot improvements out the door again when needed.
+
+2004-03-02 Adriaan de Groot
+* Add a variable timeout after the sync, specially for some T3 users.
+ Thanks to Alec Mitchell for pointing that out and providing an initial patch.
+
+2004-02-25 Adriaan de Groot
+* In the KNotes conduit: Coding style fixes. Cleanup doubled strings.
+ Improved status reporting. Probably dealt with the memo viewer issue.
+* Imported another patch from David Mott, for drag-n-drop file install.
+* Added a config option and UI for running conduits during a backup.
+ Default to not, in order to fix bug 7xxxx.
+
+
+2004-02-21 Adriaan de Groot
+* At FOSDEM, not much hacking was done, but it was fun and boozy.
+
+2004-02-03 Adriaan de Groot
+* I see lots of spelling fixes have been introduced in HEAD. Thanks, TLs.
+* Plans for a photo conduit (Zire71) and a NotePad conduit are forming.
+ pilot-link has the relevant code already, it just needs to be fit
+ into KPilot's form.
+* Worked on the KNotes conduit some more. Remember to update the
+ local database copy, and non-CopyHHtoPC code needs work.
+
+2004-01-31 Adriaan de Groot
+* Finished up the KNotes conduit, I think. The copy to PC part was
+ a little over-enthusiastic.
+
+2004-01-25 Adriaan de Groot
+* Fixed up copyright notices here and there. Dan is listed as copyright
+ holder in lots of files he's never worked on; since copyright cannot
+ be assigned except in writing, I'm going to have to take responsibility
+ for my parts.
+* Fixed up conduit modes in kpilotTest.
+* Removed compile warnings in the vcal conduit.
+* Moved 72342 to top of list, since now I got HHtoPC copy
+ working in kpilotTest I can actually _see_ the bug. It seems to be in
+ PilotMemo.
+
+2004-01-20 Adriaan de Groot
+* Added experimental A-A-P build system.
+* Cleanups in conduit config, added stub buttons for wizards.
+
+2004-01-16 Adriaan de Groot
+* De-tabified ChangeLog again.
+* Updated version. Hope that \374 makes sense (it's a ü).
+* Added explanation for "Actions" page in config. Ditto for "Conduits".
+ Prevent user from collapsing the tree.
+* Fixup layout for popmail conduit when including it in the config dialog.
+* Experimental stab at separating the config into separate bits in the
+ new KCM config dialog.
+
+2004-01-02 - 2004-01-11 Reinhold Kainhofer
+* This was work done in osnabrueck_branch, at the 2004 kdepim meeting
+ and the week afterwards. This issue is one of the feature targets
+ for the kdepim 3.3 release in Q1 2004.
+* Moved the general setup dialog from a separate dialog to a page of
+ the conduit config dlg. Combined the kpilot setup and conduit config
+ dialog to one dialog.
+* Implemented the kontact plugin for KPilot (showing status information)
+* Added three DCOP functions to the daemon for querying status information
+* Hotsync log is written out to a file (~/.kde/share/apps/kpilot/lastsync.log)
+* Converted all conduits to KConfig XT (mail und kroupware still missing)
+* Converted the config dialog to a KCM module
+* KPilot plugin for contact: shows status in summary and makes config available
+* kpilotDaemon sends a DCOP signal when its settings/state are changed
+* New DCOP functions in the daemon to query its state and settings
+* the kontact plugin also detects if the daemon is quit
+* Use a QSplitter in the config dialog instead of the QHBox layout
+* implemented the kconf_update scripts to move groupless entries to the
+ [General] group
+* Still missing:
+ o) KConfig sync between the three processes working on the
+ kpilot config: kpilot, kpilotDaemon and possibly kontact
+ with the kpilot plugin
+ o) Wizard to setup kpilot correctly for kontact (the defaults
+ should suffice, just in case someone played around and
+ messed them up)
+
+
+2004-01-02 - 2004-01-04 Adriaan de Groot
+* This was work done in osnabrueck_branch, at the 2004 kdepim meeting.
+* Fixed the TODO_I18N -> they're all i18n() now.
+* Discovered ttypatch, which is da bong. Thanks to Dan Clemmensen
+ for writing it, and Bernhard Reiter for showing it to me. All of
+ a sudden, POSE actually looks usable.
+
+2004-01-02 Adriaan de Groot
+* Non-functional commits all over; split off osnabrueck_branch.
+* Naming changes in todo conduit.
+* Fix sync race in knotes conduit.
+
+2003-12-29 Adriaan de Groot
+* Reenabled the popmail conduit, but in severely limited form.
+
+2003-12-28 Adriaan de Groot
+* Committed the knotes stuff, since it does do HH->PC properly. OTOH,
+ I don't think the mode code is right in that conduit either.
+* Stared at various bugs that I can't reproduce.
+* Looked into #69987, changed some names in the todo conduit.
+* Changed the parts of the changelog to real changelog format
+ (dates must be yyyy-mm-dd, with leading zeroes if needed).
+
+2003-12-23 Adriaan de Groot
+* Added recent hardware reports. If you reported something and I've
+ forgotten it, please send me a gentle reminder.
+* Added IrDA howto from Stuart, who failed to provide an email
+ address that I can respond to.
+* I think I got the KNotes conduit working again, but it needs some
+ testing so that change hasn't been committed yet.
+
+2003-12-12 Adriaan de Groot
+* Reduce warnings in vcalconduit.
+
+2003-12-10 Adriaan de Groot
+* Fix for #66321 - fill in a default value for the vcal file.
+
+2003-12-05 Adriaan de Groot
+* Het heerlijk avondje is gekomen. Damn right it is.
+
+2003-12-02 Adriaan de Groot
+* Removed #if 0'ed code; moved some deprecated code to #if 0; removed
+ use of deprecated stuff. Fixed up includes.
+
+2003-11-23 Adriaan de Groot
+* Minor string fixups that don't affect TL.
+
+2003-11-22 Reinhold Kainhofer
+* Fixed the broken conduit config dialog (wasn't able to show config
+ widgets of more than one conduit. If you configured one conduit, and
+ switched to another, its config widget couldn't be added to the stack).
+* Configure conduits dialog now has an apply button.
+
+2003-10-21 Adriaan de Groot
+* Updated the website some with lots of new hardware. Thanks to
+ everyone who reported new stuff.
+
+2003-10-10 Adriaan de Groot
+* Sure, we let the ChangeLog slide, but didn't do much, I don't
+ think, over the summer. Main point is that AAP can pretty much
+ build KPilot now, suck to be auto* and make.
+
+2003-07-30 Reinhold Kainhofer
+* The addressbook conduit now uses a different algorithm to find
+ the type of address on the PC to sync with.
+ First, if there is a preferred address (no matter if home, work
+ or whatever), this one is synced to the handheld. If no preferred
+ address exists, either home or work (depending on the setting in
+ the conduit config dialog) is used for the sync. If that doesn't
+ exist, either, the other one (work/home) is tried. If that also
+ doesn't exist, and the address is copied to the PC, its type is
+ set to preferred+the setting from the config dialog.
+ This fixes both bugs #50560 (conduit should sync with preferred
+ address) as well as bug #60659 (conduit should use the existing
+ address from the PC, even if the type is not the one chosen in
+ the config dialog). (also backported to BRANCH)
+* Allow two addressbook entries with the same name and organization,
+ but different phones, addresses etc. Actually, it allows entries
+ which are equal up to at least one entry. This fixes bug #59569.
+* Fixed bug #60691 where events recurring monthly on a given weekday
+ were shifted by one day. (also backported to BRANCH)
+* Also, when initializing a LocalCalendar, you are not supposed
+ to give a time zone...
+* Also, fixed infinite loop glitch by Cornelius.
+* If the user chose to sync to an iCalendar file instead of the
+ standard (resource) calendar, and he gave an empty or invalid
+ file name, an error message is now written out to inform him/her
+ about the problem.
+ I don't want to ask him for a file name, because one of the
+ guidelines of conduit development is that a sync should be able
+ to run without user intervention.
+ this should probably also be backported, but it introduces two
+ new i18n strings, so it is not possible. Thus the bug will remain
+ in 3.1 branch.
+* Fixed the toolbar configuration.
+
+2003-07-27 Reinhold Kainhofer
+* The internal editor action now displays the contents of the conflicting
+ records and lets the user decide which one overrides (Fixes bug #61103).
+* For this I added a function getTextRepresentation(bool richText) to
+ PilotAppCategory, PilotAddress, PilotMemo, PilotDateEnty and PilotTodoEnty,
+ which returns the contents of the record as a string that can be displayed
+ to the user. Moved that code from the internal viewers to the classes.
+* If there is no nice-text representation, I now use KHE::KHexEdit to
+ show the raw contents, so the user gets an idea of the conflicting records.
+
+
+2003-07-26 Adriaan de Groot
+* Time flies when you're having fun and mucking with other
+ bits of KDE. Worked on meinproc, build fixes, dependencies, etc.
+
+2003-07-26 Reinhold Kainhofer
+* Changed a few accelerators (duplicates reported by Dr.Klash)
+* Also show items marked as deleted in the GenericDB viewer.
+* All conduits now have their own copy of the handheld's database
+ in $KDEHOME/share/apps/kpilot/conduits/UserName/*.pdb. This was
+ needed so that backup runs don't break the conduit's algorithm to
+ detect changed records on the PC. So far, we compared each entry
+ to the corresponding entry in the backup database. It that changed,
+ basically we are screwed.
+ For this new feature I extended the constructur of PilotLocalDatabase
+ to take an additional boolean parameter useConduitDBs. If that is set,
+ the db will be opened in ..../conduits/Username/
+* Do not return "Unfiled" or "Nicht abgelegt" as category label
+ if no category is set. Instead return an empty string.
+* Added isArchived() and makeArchived() methods to PilotAppCategory
+ to set the dlpRecArchived flag.
+* Changed the way how the DBBackup/username/ and conduits/username/
+ directories are created (now I'm using KStandardDirs::makeDir and
+ KStandardDirs::exists).
+* FirstSync now also means PC->HH or HH->PC directions (which is clear
+ intuitively, as with these direction, nothing that's on the other
+ side should matter at all).
+* Added eDelete to the sync actions in the SyncAction class
+
+
+2003-07-15 to 2003-7-26 Reinhold Kainhofer
+Complete rewrite of the addressbook conduit (for the, umhh, third(?) time).
+* NEW FEATURE: custom fields can now also be synced with
+ birth date, URL, ICQ, etc. (bug #50871)
+* Conflict resolution shows the whole conflicting item
+ and all conflicting fields (so far, every conflicting
+ field was shown on its own, bug #59222). The conflict
+ resolution is done completely independent from the addressee
+ object and might so be reused later in other conduits as well.
+* Separated the mechanism to detect changes from the mechanism
+ to sync/merge addressees. This makes the whole thing a lot
+ easier to understand and maintain, and there are far less
+ cases you have to consider.
+* the conduit now obeys the global conflict resolution (ask,
+ PC overrides, HH overrides, last sync overrides, duplicate)
+ and sync direction (fast, full, only PC->HH, only HH->PC)
+ settings. Bug #59220.
+* The "only HH->PC" and "only PC->HH" sync directions first
+ copy all existing entries to the receiving end, and only then
+ remove all other entries from there. This avoids data loss if
+ the connection breaks while such a special sync is running.
+* Added a crash handler to clean up the addressbook if the
+ conduit crashes.
+
+2003-07-11 Reinhold Kainhofer
+* Records in the PilotLocalDatabase with ID 0 (i.e. new records
+ added by KPilot's internal editors) will always be treated as
+ modified records and found by readNextModifiedRecord, even if
+ they don't have the dirty flag set. This ensures that all new
+ records from KPilot will be added to the handheld
+* Finished the internal todo editor:
+ Entries can be maked completed and edited directly in the check
+ list view.
+ Moved the editor dialog to a designer ui file instead of a
+ manually created layout
+* Finished the sync action that copies the changes done in the
+ internal editors of KPilot to the handheld. So, finally, the
+ internal viewers/editors of KPilot are working again, unlike
+ the last few years, where they were in a terribly broken state.
+
+2003-06-01 to 2003-7-10 Reinhold Kainhofer
+* I was busy with a lot of stuff from KPilot, none of which is actually
+ in a state where I can commit it. In particular, I'm working on
+ -) Custom field sync of the addressbook conduit
+ -) Make the conflict resolution of the abook conduit more
+ intuitive (ask just once for each conflicting address)
+ -) Finish up the todo editor
+ -) Make the generic DB viewer an editor (more or less finished,
+ but the KHexEdit widget is not yet publically available, so
+ I can't commit that part either)
+ -) Implement the InternalEditorAction which syncs the changes
+ done in the internal editors/viewers to the handheld
+
+
+KPilot Developer's notes for July 9th
+=====================================
+
+2003-7-9 Adriaan de Groot
+* Ditched spurious code in KNotes conduit config. Updated copyrights,
+ still assigned to Dan. Updated the notes interface stubs.
+
+2003-7-7 Adriaan de Groot
+* Added a conduit description to PalmDOC. Well, fixed the "Conduit"
+ vs. "Comment" typo in the .desktop file.
+
+2003-7-6 Adriaan de Groot
+* Made the bugreport and question and help links in the about pages
+ clickable through KActiveLabel. Made the credits text scrollable
+ with a QTextEdit.
+* Weird redraw bugs reappear in the conduit config dialog, fixed again.
+* Added sorryVersionOutdated() to KPilotConfig to notify user that
+ the configs are old, and telling what's changed. Used in kpilot and
+ the daemon. Includes cleanup. Use getDebugLevel() properly.
+
+2003-7-5 Adriaan de Groot
+* Upped the config version number to 440.
+* Worked on the docs (really!), so the HEAD docs now reflect _some_ of
+ the reality of KPilot 4.4.0. Noted lots of inconsistencies.
+ Put in lots of TODO's, and the whole thing needs going over.
+* Using the trademark HotSync in the GUI might not be a good idea.
+ Removed where I could, added a trademark reference in the about pages.
+
+2003-7-5 Adriaan de Groot
+* Renamed all conduit plugins from lib<bla>conduit (and variants) to
+ conduit_<bla>, so that they're easier to identify in $KDEDIR/lib/kde3.
+ Of course, this doesn't work right. Feh.
+* Removed listCat again.
+* Implemented a notion of "internal conduit", so that we can move
+ the "install files" and "kroupware" stuff to the conduit config
+ dialog and out of the general stuff, where it looks weird.
+
+2003-7-4 Adriaan de Groot
+* Removed the words "KPilot", "KDE" and "Conduit" from all the conduit names.
+* Removed double logging in NULL conduit, added message for explicit fail.
+ Use the generic config dialog implementation. I see now that the NULL
+ conduit isn't built or installed anymore. Fixed its .desktop comment.
+* Disabled the expenses and popmail conduit from compiling.
+* Made new-style config for the vcal conduit. Made new-style config for the
+ todo conduit. Stripped out lots of extra #includes. Stripped out extra
+ Q_OBJECT macros. Reduced space in widget some. Fixed void return 0;
+ Fixed improper AboutData in todo conduit.
+* New-style for abbrowser. Minor == vs = mixup.
+* Shrunk margin for kpilot config dialog. Use the available charsets from
+ KDE instead of our own list. Added a quit-after-sync option.
+
+
+
+2003-6-29 Adriaan de Groot
+* Added some code validation support to plugin.h
+* Messed about with popmail's config. What was the firewall stuff for?
+ Created new-style configs, didn't complete the load/save code, and
+ then sortof gave up because is there really any point to doing this
+ conduit without switching to the SMTP ioslave? And using identities
+ then?
+
+2003-6-26 Adriaan de Groot
+* Removed stupid comment in popmail/Makefile.am
+
+2003-6-25 Adriaan de Groot
+* Be consistent about naming the sysinfo conduit "System Information"
+ in user-visible strings.
+* Remove "conduit" from the name of the Palm DOC conduit, and add a
+ new-style config panel to it. Made it resize properly.
+* Note that ConduitConfigBase::load() and its overrides should set
+ fModified to false.
+
+2003-6-22 Adriaan de Groot
+* Turn off NO_CAST_ASCII when doing DEBUG_CERR, because ostream is
+ lacking an operator << for QString. (Nicer is probably to add
+ such an operator, but hey.)
+* Removed uselessly virtual conduitName() function from conduit classes.
+ No-one was overriding it anyway.
+* The vcal and abbrowser conduits shouldn't be compiled if you're building
+ KPilot HEAD on older systems.
+
+2003-6-21 Adriaan de Groot
+* Fixed up the layout of the sysinfo conduit.
+* Documented ConduitConfigBase::isModified() and made it virtual.
+* Fixed up the sysinfo conduit and saving modified entries.
+* Moved the --debug argument to all apps individually.
+
+2003-6-20 Adriaan de Groot
+* Updated the hardware lists on the website.
+* Updated some "What's This?" texts.
+* Removed evil static QStrings in kpilotConfigDialog.cc.
+* Discovered that the "start at login" functionality has been broken forever.
+* Added a workaround for KTimeWidget not present in KDE 3.1.x.
+
+2003-6-20 Reinhold Kainhofer
+* Implemented the dialog to change the database flags and the dates (DBInfo
+ struct) in the internal generic DB viewer. PilotLocalDatabase got a new
+ method setDBInfo for this.
+* Implemented creating, editing and deleting records in the generic DB editor.
+* Added the CHexViewWidget from khexedit to the kpilot/kpilot/ directory.
+ There are still several open issues with it (i.e. how do I set the data
+ at all???)
+
+2003-6-19 Reinhold Kainhofer
+* Implemented the list of records in the generic DB viewer. To be
+ able to sort the records by their index, I had to write my own
+ compare method of the QListViewItem, which compares the numerical
+ representation of the column entries. For large DBs (>300 records)
+ this is way too slow (QString::toULong for each comparison, increasing
+ with n*n), so I had to implement some caching. Now even large databases
+ are sorted very fast.
+
+2003-6-16 Reinhold Kainhofer
+* First layout of the internal calendar viewer/editor. The KDatePicker
+ poses a big problem to me as it swallows all toolbar buttons.
+* Implemented a InternalEditorAction to sync changes done to the databases
+ in the internal viewers. Every PilotComponent that changes a database
+ needs to mark it as dirty (e.g. markDBDirt("AddressDB")) so the
+ Action knows which databases need to be considered.
+
+2003-6-15 Reinhold Kainhofer
+* Implemented a first layout of the generic database viewer. To view
+ the records, I'd need a hex editor, which is not available in KDE, yet.
+ I tried using the widget that khexedit uses, but somehow I can't get
+ it to work :-((
+
+KPilot Developer's notes for June 15th, 2003
+============================================
+
+2003-6-15 Adriaan de Groot
+* Yay, father's day. Which includes me. Mira drew me a wonderful card.
+* Fixed some TL problems in debug output, and added documentation.
+
+2003-6-14 Adriaan de Groot
+* Fixed the conduit config dialog's repaint and behavior problems by
+ ditching the .ui file and implementing it by hand again. I'll look
+ into a switch back to .ui later.
+
+2003-6-12 Reinhold Kainhofer
+* Tracked down why the handheld crashes with Invalid UniqueID error
+ message (bugs #59313 and #51216). RecordIDs are supposed to be 3
+ bytes, and the handheld will crash if they are longer. For some
+ reason, several entries in the calendar or the addressbook were
+ assigned longer Record IDs, so I added a check for invalid values
+ before sending them to the handheld. This fixes the symptoms (i.e.
+ these crashes won't appear in the future again, and new valid ids
+ will be assigned), but there is still another bug that assigned
+ the wrong values in the first place...
+
+2003-6-9 Reinhold Kainhofer
+* Fixed crash from bug #59315. I used the value of a char as a char*,
+ in the code for extension cards in the sysinfo conduit. pilot-link
+ doesn't detect my Clie's memory stick as extension card so this code
+ was never executed on my machine, and I didn't detect the bug myself.
+
+2003-6-1 Reinhold Kainhofer
+* Fixed several (possible and really occurring) null pointer crashes
+* Submited most of the items in our TODO list as bugs or wishes on
+ bugs.kde.org
+
+2003-5-31 Reinhold Kainhofer
+* Restructured the setup dialog of KPilot. Several per-conduit
+ settings were moved to global settings. The conduits now have
+ isFullSync(), isFirstSync(), getSyncDirection(), and
+ getConflictResolution() members for these settings. I think I fixed
+ all conduits to use these new settings and didn't miss anything.
+* The Backup works again (fast sync doesn't do a backup, hot sync
+ does conduits and a fast backup, full sync does a full backup where
+ the modified flags are ignored). Also added a fast backup where
+ only modified records are retrieved.
+
+
+2003-6-1 Adriaan de Groot
+* pilotComponent.cc Another fix for 52138 - I'd missed the category
+ drop-down box.
+* Woo. After months of wrestling, I actually managed to run KPilotTest
+ and list the contents of my m500. Sometimes, there is something
+ to be said for Linux and a working USB stack. This means I have
+ limited testing hardware available again.
+* Minor fixups to make HEAD compile with 3.1.x again.
+
+2003-5-31 Adriaan de Groot
+* Updated my build environment to HEAD. This will leave some people
+ in the dust, for sure, since 4.4.0 will thus have an address conduit
+ that requires HEAD, not 3.1.x. Perhaps we can ship two tarballs,
+ but that's going to start to be messy again.
+* Talked to lioux about conduits and categories on IRC. It seems
+ that PC->Palm syncs usually respect categories and such, but Palm->PC
+ doesn't, among other little tidbits. He'll file bug reports.
+
+
+KPilot Developer's notes for May 30th, 2003
+===========================================
+
+2003-5-30 Adriaan de Groot
+* Spent this week at conferences (Mira at 8 weeks was the
+ youngest attendee of the EEF School on Formal Methods,
+ though I doubt she'll remember how to do protocol
+ verification in PVS).
+
+2003-5-19 Reinhold Kainhofer
+* This weekend I wrote this new conduit for KPilot, called
+ sysinfoconduit. It writes all important Palm system information
+ to a text or html file. For an example, see
+ http://reinhold.kainhofer.com/Linux/KPilot/KPilotSysInfo.html.
+ The output is completely customizable via templates. Currently,
+ txt and html templates are available, but the user can provide
+ his/her own template in the conduit configuration dialog. The
+ current html template uses css for the markup, and passes the
+ w3c html validator without warnings.
+ Hopefully, the debug output section will help us kpilot developers
+ track down problems easier (the users can send us the output of
+ this conduit, and we can let it write out all important stuff we
+ need/want to see).
+
+2003-5-11 Adriaan de Groot
+* kpilotDCOP.h Changed enum values so that you can distinguish
+ between call failed and normal operation.
+* conduitConfigDialog.cc When closing config dialog, release last
+ selected conduit.
+
+2003-5-9 Adriaan de Groot
+* Fixed up some config issues in the NULL conduit.
+* Added conduitName() to conduit config things and their actions,
+ to provide a user-readable name for the conduit.
+
+2003-5-5 Adriaan de Groot
+* plugin.{h,cc} Added a maybeSave() function for the new conduit config
+ style. Removed some unused variables.
+* conduitConfigDialog.{h,cc} Using maybeSave() to save or cancel selection
+ changes.
+
+2003-5-3 Adriaan de Groot
+* Spent lots of time panicing my system and causing fatal exceptions
+ on my Pilot by playing with pilot-link 0.11.7 and FreeBSD's USB
+ stack.
+* kpilotlink.cc Suppress printing the "accidentally in acceptDevice"
+ more than once. Try to escape from the infinite socketnotifier loop.
+
+
+2003-5-2 Adriaan de Groot
+* Aiming for bi-weekly notes this month again.
+* Looks like I reverted the PRETTY_FUNCTION printing.
+* I'm working from an everything-HEAD-except vcal and abbrowser
+ checkout, because the new resources framework breaks everything.
+* Next KPilot tarballs will be 4.4.0 (HEAD) release.
+
+KPilot Developer's notes for April 30th, 2003
+=============================================
+
+2003-4-25 Adriaan de Groot
+* Updated resizing action in the conduit config dialog.
+* Added a ConduitConfigBase to the knotes conduit.
+* Changed a bunch of Name[] entries for the time conduit. We
+ need shorter names; most of them are horribly redundant.
+* Noticed that the conduit checklist items don't always get
+ painted right. Added a workaround.
+
+2003-4-24 Adriaan de Groot
+* More work on the conduit configuration stuff.
+* Make FUNCTIONSETUP print PRETTY_FUNCTION instead of just FUNCTION.
+* Added a ConduitConfigBase object to the time conduit.
+
+2003-4-22 Reinhold Kainhofer
+* Cleanup of several cout and other debug messages
+* In the addressbook and todo conduits, after the sync the AppInfoBlock
+ is written back to the databases so that adding categories to the
+ database finally works.
+
+2003-4-21 Adriaan de Groot
+* Changed the description for the KPilot NULL conduit to just "NULL",
+ since both "KPilot" and "conduit" are redundant in this context.
+* Messed around a little with the types of plugin code, created a
+ class ConduitConfigBase which is supposed to supplant the current
+ config widget stuff.
+
+2003-4-21 Reinhold Kainhofer
+* Implemented different ways to convert the bookmarks in the doc
+ conduit when doing Handheld->PC sync.
+* Some tab order fixes in several conduit setup dialogs.
+* Improved the question when the handheld and the KPilot user
+ names don't match.
+
+2003-4-20 Adriaan de Groot
+* Added the sources for a generic DB viewer and a datebook viewer.
+ These don't show up anywhere yet though. The datebook viewer has
+ no functionality yet.
+* kpilot.cc Minor change to detect non-functioning daemon better.
+* Restored the tooltip code to the conduit config dialog. Removed
+ the "description" column again.
+* uiDialog.{h,cc} Moved the addAboutPage() code to a static function so
+ that it can be reused elsewhere.
+* plugin.{h,cc} Added a new base class ConduitConfigBase for deriving
+ the configuration widgets for conduits from. This will make them
+ more generically pluggable.
+
+2003-4-19 Reinhold Kainhofer
+* Fixed the categories sync in both the addressbook and the todo conduits.
+
+2003-4-18 Adriaan de Groot
+* Laurent Montel did some compile fixes for restrictive (NO_ASCII_ ...)
+ compile environments. And I fixed them to match the coding guide.
+* Make file installer emit a [] message like the conduits do, to
+ give the "No files to install" message context. Tell the user how
+ many files will be installed.
+* Tell the user if the daemon can't be started. Tell the user what
+ charset is selected.
+
+
+2003-4-17 Adriaan de Groot
+* Finished moving the conduit config to checklist items. Worked out
+ a sensible compromise with the command buttons. The conduit
+ descriptions (comment lines in the .desktop files) need work.
+
+2003-4-16 Reinhold Kainhofer
+* Tried to add a logMessagePart slot which would append some words
+ to the last line of the sync log (but would not start a new paragraph,
+ and more text could be added to the last paragraph). Realized that this
+ is not possible in a QTextEdit with LogText, and using RichText is too
+ buggy to be useful. However, I found a way to get rid of the pseudo-
+ progressbar in the libmal output, so this is not an issue any longer.
+
+2003-4-16 Adriaan de Groot
+* Moved conduit config to a list of QCheckListItems, finally.
+ This was easier than I thought. Took a bit of time to polish,
+ though. This change introduces a new class ConduitConfigWidget
+ which could be placed in a tab elsewhere if needed.
+
+2003-4-15 Reinhold Kainhofer
+* Finally fixed the configure.in.in check for libmal in the malconduit
+* calendar conduit had wrong RadioButton IDs, so the Resource and LocalCalendar
+ settings were messed upt
+
+2003-4-14 Adriaan de Groot
+* Made some reasonable mock-ups, see my kpilot page, mulled over the
+ non-editing by the viewers. I'm now working in HEAD only.
+* kpilot.{h,cc} Fixed up backwards compatibility.
+
+2003-4-12 Adriaan de Groot
+* Mucking about with KPilot's UI again. Trying to remove dialogs
+ and to make the viewers just viewers.
+
+2003-4-1 Adriaan de Groot
+* My daughter, Mira Annelie Engel, was born this evening and is a
+ bouncing healthy girl. But she's going to put a crimp in KPilot
+ development, that's for sure.
+
+KPilot Developer's notes for March 26th, 2003
+=============================================
+
+2003-3-26 Adriaan de Groot
+* pilotLocalDatabase.cc [BOTH] Qt 3.0 compatibility.
+* More merging: lib/ just spacing fixes.
+* kpilot/ In HEAD, muck about with the toggle actions that were removed
+ from kpilot.cc. This stuff is supposed to build in all KDE 3.x.
+* I've been thinking about _where_ to hack next. HEAD is evolving
+ further under Reinhold's influence, and I feel pretty much stymied
+ in BRANCH because I can't touch strings and the like. However, I'm
+ still running KDE 3.1 and dedicated to KDE 3.0 compatibility as well.
+ Since the things I want to change are in lib/ and kpilot/ and affect
+ strings, I'm going to pick up those from HEAD, but stick to BRANCH
+ conduits for the next while. Then I can catch up with HEAD in the
+ conduits one by one. So initial KPilot 4.4.x tarballs will be from
+ a mix of CVS branches. We might consider doing the conduit releases
+ separately from KPilot itself - more 3rd party-ish - since the conduits
+ change far more drastically than KPilot itself.
+
+ Initial plans for 4.4.0: disable editing in the viewers ; move the
+ configuration things into the JanusWidget, and out of separate dialogs.
+
+2003-3-24 Reinhold Kainhofer
+* Adapted the layout of the addressbook conduit's setup dialog to
+ resemble the one from the calendar/todo conduit
+* Addressbook conduit: Implemented the option to sync with an
+ arbitrary vcard file instead of only the standard addressbook.
+ This actually involved quite a lot of dealing with resources,
+ factories etc., so I'm still looking for an easier way to
+ obtain the addressbook from a single local vcard file.
+
+2003-3-23 Reinhold Kainhofer
+* Lot of work on the docconduit. Finished the KPalmDOC application.
+ It converts text files to .pdb files that can be viewed as ebooks
+ on the handheld. The user can either convert single text files
+ to or from PalmDOC .pdb files, or choose a directory, where all
+ *.txt or *.pdb files will be converted to another directory.
+ I created some icons by just putting the text mime-type icon
+ behind the kpilot icon, so the icons don't look too well. All artists
+ are welcome to improve them.
+* Tried to implement a configure option for libmal, and use autoconf's
+ built-in functionality to detect libmal. Doesn't work yet, so I
+ haven't committed it yet.
+
+2003-3-23 Adriaan de Groot
+* More merging .. conduits today:
+* null/ There's a single string change, "Failure" -> "failure".
+* expense/ knotes/ Nothing changed - except the Makefile.am,
+ which breaks things in HEAD.
+* malconduit/ "" -> QString() for QString cleanness. Some authors
+ should have been credits. There's still a spelling fix string
+ change in HEAD. Lots of spacing updates.
+
+2003-3-21 Adriaan de Groot
+* Heh, noone ever noticed the "Edit Toolbars" menu item called the
+ "Edit Keyboard Shortcuts" dialog.
+
+2003-3-20 Adriaan de Groot
+* Merging between BRANCH and HEAD.
+* options.h [BRANCH] Upped the version number again.
+* lib/ [BOTH] Merged documentation, fixed minor bug in plugin.cc in HEAD.
+* kpilot/ [BOTH] Merged stuff.
+* pilotDaemon.{h,cc} [HEAD] The daemon has extra DCOP features and kroupware.
+* kpilot.h [HEAD] Extra in-use code and Ben's removal of toolbars
+ (supported by standards in KDE 3.2 - this needs backporting and
+ #ifdeffing).
+* conduitConfigDialog.cc [HEAD] Has all the setup stuff for the checkbox
+ list conversion (a GJJ) but #if 0'ed out.
+* kpilotConfig{Dialog,}.{h,cc} [HEAD] Adds a GUI for the pilot encoding.
+* kpilotDCOP.h [HEAD] Extra configure methods from David.
+* listCat.h [BOTH] One-up the spelling mafia.
+
+2003-3-17 Adriaan de Groot
+* [fileInstallWidget.cc] Applied file-installer multiselect patch
+ from Ulrik Mikaelsson.
+* [pilotDaemon.cc] Applied DCOP interface additions from David Mott.
+
+2003-3-15 Adriaan de Groot
+* The popmail conduit runs in backup mode during syncs. So do all the
+ other conduits. What's going on? Thanks to Tobia Baier for spotting this.
+ Worse still, the bug comes from the difference between & and &&. Fixed.
+* syncStack.cc [BOTH] Fixed --backup bug.
+* David Mott is back with more patches, but he's got competition from
+ Ulrik Mikaelsson, who's also doing GJJs.
+
+KPilot Developer's notes for March 12th, 2003
+=============================================
+
+2003-3-12 Adriaan de Groot
+* Lots of administrivia changes, like the FSF address.
+* Really ought to merge the copyright changes into BRANCH, since they're
+ still being released with weird copyright assignments.
+* vcal conduit in local-test mode will write out an .ics.
+
+2003-3-4 Adriaan de Groot
+* Welcome back to David Mott, author of several patches already and
+ ready to dive into the code again for GJJs. Happy distraction, dude.
+* [vcal-conduitbase.cc] Checked against wrong KDE_VERSION. [BRANCH]
+* Various merging from BRANCH to HEAD. Layout fixups here and there.
+* Test mode in the vcal conduit by default uses local databases from
+ /tmp.
+
+2003-3-3 Adriaan de Groot
+* pilotDatabase.h [BRANCH] Merged additional parameters to findDatabase
+ from HEAD. Merged every other change in lib/ from BRANCH to HEAD.
+* pilotRecord.{h,cc} [BRANCH] Added instrumentation for alloc/delete count.
+
+2003-3-2 Adriaan de Groot
+* Continued instrumentation of the vcal conduit.
+
+2003-3-2 Reinhold Kainhofer
+* the DOC conduit now also finds the correct sync direction
+ if the user only wants PC->PDA or only PDA->PC sync.
+ Also, if a text was deleted on one side, it is also deleted
+ on the other end
+* The resolution dialog of the DOC conduit now uses a QScrollView
+ instead of a QTable for the list of conflicting texts
+* In the DOC conduit, regular expressions as bookmark names work
+ now. E.g. a bookmark search string of "return (\S+);" and a
+ bookmark name of "RetVal: $1" or "RetVal: \1" replaces all $i or
+ \i by the i-th subexpression of the match.
+* DOC databases are now also kept locally if the user set this option
+ (installDatabases has the addidtional argument not to delete
+ the files)
+* The calendar and todo conduits now use the standard calendar by
+ default. The user can also specify a single file to sync with
+ instead of the whole calendar.
+* The calendar and todo conduits use identical setup dialogs, so
+ there is no reason for code duplication. Removed the setup dialog
+ of the todo conduit and derived it from the calendar conduit setup
+ dialog.
+* Updated the copyright lines in the source files as well as
+ in the about tabs of kpilot and the conduits.
+* Since we have the calendar resource framework, the calendarr conduit
+ can run even while korganizer has the calendar open without causing
+ calendar corruption. So I removed the check for running korganizer
+ and alarm daemon
+
+
+2003-2-28 Adriaan de Groot
+* Discovered that the changes from 2003-1-31 to syncAction.{h,cc}
+ had disappeared in some of my periodic CVS screwups. Re-did them.
+* vcal-conduitbase.{h,cc} [BRANCH] Added more instruments for
+ running test mode.
+
+2003-2-27 Adriaan de Groot
+* Merged Reinhold's print-conduit-id patch from HEAD.
+* Continued updating the documentation. Ripped out the revision
+ history, Lauri says I'm the only developer in the history of
+ KDE to actually maintain it in the docs.
+* Updated version to 4.3.9 now that 4.3.8 is out.
+* Started work on a real test mode for the vcal conduit.
+* syncStack.cc [BRANCH] Set conduit action name to the conduit's name.
+
+KPilot Developer's notes for February 26th, 2003
+================================================
+
+2003-2-26 Adriaan de Groot
+* Finally solved KDE 3.0 build issues, incorporated minor fixes, updated
+ build scripts and RELEASED KPILOT 4.3.8. Get it from the website,
+ possibly in a few hours after it updates or from my personal
+ backup copy (replace pilone by adridg in the URL).
+
+KPilot Developer's notes for February 14th, 2003
+================================================
+
+2003-2-14 Adriaan de Groot
+* Happy Valentine's Day, eh. Remember guys, today your girlfriend
+ _is_ more important than hacking. Which reminds me ..
+
+2003-2-13 Adriaan de Groot
+* kpilotLink.{h,cc} [BRANCH] Added a messagesType flag to distinguish
+ error messages from normal once-only messages in shouldPrint().
+ Print out device name before opening in open().
+
+2003-2-12 Adriaan de Groot
+* Applied David Mott's DCOP patches to HEAD. Also applied his RMB
+ patches to HEAD. This takes care of some GJJs.
+* memoWidget.cc [BOTH] Replaced the label "Memos:" beside the
+ category combobox by "Category:" which is also used by the
+ address widget. Kept the old string around for safekeeping.
+* Dealing with non-latin1 Pilots again, now in Russian. And it
+ _seems_ to work. I think last week's changes were sufficiently
+ general. Added in the rest of the Pilot languages as well,
+ from the JPilot source.
+
+2003-2-10 Adriaan de Groot
+* popmail-conduit.cc [HEAD] Did some actual TODO_I18N work,
+ removed printfs from the message construction in the conduit.
+ Added a GJJ for it.
+* pilotDaemon.cc has lots of Kroupware additions in HEAD and
+ also changes "unix" -> "KDE" in the about box.
+* conduitConfigDialog.cc has lots of new code for changing the
+ conduit list to a list of checkboxes.
+* kpilotConfigDialog_base has been edited in HEAD for new Kroupware
+ options. Same with kpilotConfigDialog.cc, kpilotConfig.{h,cc}.
+* conduitSetup.cc may be deprecated, but there was a minor difference
+ between files. HEAD <- BRANCH (ie. HEAD gets BRANCH version).
+* hotSync.cc variable names changed, BRANCH <- HEAD.
+* interactiveSync.cc typos and latin1() fixes. BRANCH <-> HEAD.
+* logWidgetDCOP.h still had Log: tag in it,. removed [HEAD,BRANCH]
+* abbrowser conduit has new custom field code. Did BRANCH <- HEAD
+ for the includes, though, just to normalize 'em. But, to quote
+ TMBG, "Who keeps moving my #includes?" The only unmerged stuff
+ that _could_ be merged is minor code beautification in
+ @@ -1496,22 +1563,26 @@
+* Should re-add a Pilot*Database constructor that takes a const char *
+ for those places that already have a dbName.
+* vcalconduit has startOffset() support for alarms.
+
+
+2003-2-9 Adriaan de Groot (merge status)
+* Merging. I hate merging. We _definitely_ need a better process for
+ this, like merging every fix into HEAD as soon as it's done. That
+ would save a lot of effort, I think. And I'm going to check out
+ KPilot with -kk for merging efforts from now on. Here's the list
+ of features I found in HEAD that are not in BRANCH:
+ - KPilotDeviceLink::installFiles() extra arguments.
+ - KPilotDeviceLink::findDatabase() extra arguments.
+ - PilotDatabase::createDatabase() and deleteDatabase() added.
+ - Pilot*Database::readNextModifiedRec() extra arguments.
+ - Pilot*Database::deleteRecord() added.
+ - PilotLocalDatabase::PilotLocalDatabase extra arguments.
+ - FileInstallWidget lots of changes. FileInstaller as well. [MERGED]
+* Managed to revert, prevert, and advert syncStack.{h,cc} all in
+ one go. I think I have it back to normal now.
+
+KPilot Developer's notes for February 7th, 2003
+===============================================
+
+* KPilot 4.3.7 is released. Tarballs on the website tonight.
+* Need to backport the changes from 2002-11-10 to BRANCH.
+* Grep for and destroy latin1() calls in code. These are now in
+ the code to keep KPilot working under QT_NO_ASCII_CAST conditions,
+ but should all be replaced by the proper functions instead - either
+ QFile::encodeName() or by updating other functions to take QStrings
+ instead of const char *, and using the Pilot codec where appropriate.
+* Reinhold's on vacation for a little while.
+
+2003-2-7 Adriaan de Groot
+* Updated the website some.
+* options.h [BRANCH] Version number now 4.3.7.
+
+2003-2-6 Adriaan de Groot
+* Did a big chunk of merging from BRANCH to HEAD. Discovered two
+ things that didn't work well:
+ - Changes in the abbrowser conduit wrt. getCustomField()
+ - Memo widget optimizations
+ I hope I got them right. I'm going back to work in BRANCH.
+* Constant strings in the source are now (almost all) marked
+ with CSL1() for Constant String Latin 1. This reduces the
+ number of hits for [lL]atin1. The macro uses a syntactic trick
+ to make sure it's only applied to constant strings.
+
+
+2003-2-5 Adriaan de Groot
+* Almost everywhere [BRANCH] Search and destroyed latin1().
+* options.h [BRANCH] Handle <kdebugclasses.h> properly. Um, sort of.
+ The dag-blabbed file is obsolete in KDE 3.2, required in 3.1, and
+ incomplete in 3.0. Ignore it instead. Ignore all the fancy Q*
+ operator <<s and do it all by hand.
+
+2003-2-2 Adriaan de Groot
+* conduitConfigDialog.cc [HEAD] Started inserting code for improved
+ conduit selection and activation.
+* kpilot.cc [BRANCH] Improve perceived startup time by delaying
+ the loading of databases till the GUI is up.
+* options.h [BRANCH] To enforce discipline, use NO_ASCII_CAST.
+ NOT COMMITTED - it'll break a lot of debug stuff as well.
+ However, as an occasional test, it's a good idea.
+* {many files} [BRANCH] Clean up random char * conversions.
+* kpilotConfig.{h,cc} [BRANCH] Introduce config entry for encoding.
+* kpilot.cc pilotDaemon.cc pilotAppCategory.h pilotRecord.cc [BRANCH]
+ Use the config entry for encoding. Applications that use any
+ PilotAppCategory derived class - ie. that interpret data from the
+ Pilot in any way - should call setupPilotCodec() beforehand with
+ the name of the encoding (QString::null == "ISO8859-1", the default,
+ or use something like "Shift-JIS").
+* pilotMemo.{h,cc} memoWidget.cc [BRANCH] Use the codec for the returned
+ title of the memo. This is the first step on making PilotMemo return
+ everything in QString format suitable for any encoding. In order to
+ change the encoding, add
+ Encoding=<name>
+ to the kpilotrc file in the top part (ie. after DeviceName).
+
+2003-2-1 Adriaan de Groot
+* Some time spent tracking down double activations of slowShowMemo().
+* memoWidget.{h,cc} [BRANCH] Removed double initialization. Removed
+ heavy-handed initialize() call after memo deletion. Found potential
+ data-loss bug with deleting memos after unselecting one. Decided that
+ extended select in this case is just _evil_. I can't decide which
+ memo to show after deselections, and there's several other problems
+ as well related to slotUpdateButtons(). Reverted the multiple-select.
+* options.h [BRANCH] Added the TODO_I18N macro to BRANCH as well,
+ where it's more important.
+* kpilotlink.cc [BRANCH] Reordered ReadSysInfo and ReadUserInfo to
+ copy JPilot's setup, maybe that will help with password issues.
+* kpilot.cc [BRANCH] Cleaned up deprecated headers.
+* conduitConfigDialog.cc [BRANCH] Preparing to repair the clumsy
+ conduit selection and activation
+
+
+KPilot Developer's notes for January 30th, 2003
+===============================================
+
+* Ugh. Looked at jpilot source. Now I remember why doing C often
+ seemed a little unproductive. But it does give some very useful
+ information: We need a combo box to choose the Pilot's encoding.
+ We can use the list from JPilot. Next, we need to make _all_ the
+ QString::fromLatin1() and QString::latin1() -- also all the
+ implicit ones -- that refer to pilot records use the right codec.
+ This will require some possibly major work on the database classes.
+* The logging is still lousy for many conduits. I ran the
+ notes and address conduits, and the log was less than enlightening.
+* We need to sync _all_ databases, not just the conduited ones.
+* Encoding and decoding non-latin1 Pilots is a priority.
+
+2003-2-1 Adriaan de Groot
+* memoWidget.{h,cc} [BRANCH] Applied patch from David Mott for the GJJ
+ "Lose QMLE". Good job! ... Ugh, and it breaks on KDE 3.0. Hacked.
+* pilotDatabase.h [BRANCH] Missing #include fixed. How this ever compiled
+ is a mystery to me.
+* pilotRecord.{h,cc} [BRANCH] Inlined trivial functions.
+* pilotRecord.{h,cc} pilotAppCategory.h [BRANCH] Start of codec support.
+* Put together some scripts to do more automated building and testing
+ in KDE 3.1 and 3.0 environments. This makes tarball delivery a _lot_
+ easier.
+
+
+2003-1-31 Adriaan de Groot
+* Let's do the time-warp again!
+* syncAction.{h,cc} [HEAD] Added a delayDone() function for use from
+ exec() to avoid possible stack growth as follows:
+ conduitExec()
+ exec()
+ syncDone()
+ SyncStack::conduitDone()
+ delete syncAction // The one whose exec() we're still in!
+ conduitExec() // Another conduit!
+ ...
+ return true;
+ I'm not sure I trust all the pointers to still be OK when this happens.
+ Using delayDone() makes sure that exec() and conduitExec() return
+ first and we get back to the main event loop.
+* syncStack.{h,cc} [HEAD] Using a stack instead of a queue has some
+ comp-sci chique, but little practical value. Break up the API
+ to make it more easy to use elsewhere and practical to insert
+ extra items (like Kroupware) into the sync order.
+
+2003-1-30 Adriaan de Groot
+* Removing local8bit() calls in the code. They're not wanted.
+* Marked conduitSetup.{h,cc} as deprecated and removed from build.
+* Looked into bug #52138 again, and I just can't see it. My Pilot
+ syncs fine with KAddressbook and KNotes, both ways, with names
+ and memos with any latin1 character. [Update: aha! The bug is
+ about Japanese language Sony Clie's. So it turns out there are
+ Pilots that don't use latin1 at all. I'll take a look at how
+ jpilot deals with them.]
+* I'd like to change the About box tag-line for KPilot to:
+ KPilot - HotSync software for KDE
+ for a variety of consistency reasons. This can only happen
+ in HEAD, though.
+* Reversed some confusing accidental commits by me in the
+ debugging department for the daemon.
+
+
+2003-1-26 Adriaan de Groot
+* Ugh. Still sick with the flu. Hacking just a little, though.
+ The Kroupware stuff in HEAD needs to be moved. Ugh, it's ugly.
+ It needs to become a conduit of its own, but it's hard to tell
+ just what it's doing.
+
+2003-1-24 Adriaan de Groot
+* Received a patch from David Mott that removes lots of the Log:
+ tags from the KPilot source (mostly in kpilot/). Finished the
+ job too, committed.
+
+2003-1-20 Adriaan de Groot
+* For the next little while, I'll be working in _BRANCH fixing
+ bugs as best I can. These will end up in KDE 3.1.x releases.
+ Reinhold will be working in HEAD, adding neat features.
+ BRANCH will be merged to HEAD regularly so that no bug-fixes
+ are lost in HEAD.
+* Reduced debugging output clutter in PilotAddress by changing
+ to FUNCTIONSETUPL(). Assigned Levels are: 4=PilotAddress.
+
+
+2003-1-18 Reinhold Kainhofer
+* Removed several Log: ... tags from the conduits I maintain
+* started implementing the custom fields sync of the addressbook conduit.
+ I still have problems converting a string to a QDate using a custom format
+* Cleanup of includes in my conduits.
+* Some more work on the DOCConduit. There are still several open issues, but
+ the basic functionality works just fine!
+
+
+KPilot Developer's notes for January 17th, 2003
+===============================================
+
+2003-1-15 Adriaan de Groot
+* Back to BSD. Committed lots of header file changes. Did some fixing
+ for strlcpy() in 3_0_BRANCH for folks with KDE < 3.0.5a.
+
+2003-1-11 Adriaan de Groot
+* Weirdly, I can list the databases on the pilot just fine with kpilotTest,
+ but at the end of the sync the pilot complains about the password.
+* Similarly, using the daemon I can back up the pilot just fine (pilot-link
+ 0.11.3, all this) and at the end the pilot complains. The data is backed
+ up just fine, though.
+* Wow, USB connections are _fast_.
+* Weirdness comes in threes: after a while the debug output stops printing.
+ Even when it's sent to cerr directly. Hmm .. has something to do with
+ printing NULL QStrings.
+* [hotSync.cc] Every "Backing up:" message was logged twice.
+* [logWidget.cc] Added more version information. Discovered that
+ QTextView is obsolete. Fixed log tailing problem. #ifdeffed it to
+ Qt 3.1 and later.
+
+2003-1-10 Adriaan de Groot
+* [kpilot/interactivesync.cc] Some strlcpy problems when compiling HEAD
+ (or BRANCH) KPilot on a KDE 3.0 system. Since we don't maintain branches,
+ backwards compatibility in HEAD is essential. Added #if KDE_VERSION < 310.
+* [lib/kpilotlink.cc] Might have found the source of the KPilot-hangs-with-USB
+ problems. There's a note in the QSocketNotifier docs saying not to disable
+ read-notifiers. I did anyway, and it never caused problems before.
+ Added some workaround crud.
+* I'm currently building kdelibs and base and pim on a Linux box, something
+ I haven't done in over a year. This will allow me access to a USB stack
+ that can actually handle the m500, so I can do some more testing.
+ Primary platform remains FreeBSD, though, for all-the-other-KDE-problems-
+ on-nonlinux.
+* Made a round of removing <iostream.h>, since it's already in options.h.
+ Needed a "using namespace std;" in options to get stuff to work.
+
+2003-1-9 Adriaan de Groot
+* Made new tarballs of the build system (for 3.0 and 3.1) and
+ the sources.
+* Decision: I'm going to do bugfixes in _BRANCH. Reinhold can do
+ bugfixes and new conduits in HEAD, and I'll merge from BRANCH to
+ HEAD fairly regularly. I think that's the best balance between
+ getting stuff out the door and sticking to the KDE release schedule.
+* Decision: Remove all the Log: tags from the source files.
+ The Id: tags stay in, for debugging output.
+
+2003-1-1 Adriaan de Groot
+* Ho ho ho. Happy new year.
+
+KPilot Developer's notes for December 30th, 2002
+================================================
+
+2002-12-30 Reinhold Kainhofer
+* Some more work on the docconduit. I'm currently restructuring again,
+ so right now it doesn't work at all, but should be finished really
+ soon now.
+* Add a method PilotDatabase::deleteDatabase() to delete the database.
+* Add a warning to the vcal conduit's setup dialog to clear any
+ misconception about conflict resolution. Also changed "Pilot" to
+ "handheld" at several places.
+
+2002-12-15 Reinhold Kainhofer
+* Added a parameter "bool useDefaultPath=false" to
+ PilotLocalDatabase::PilotLocalDatabase to prevent resetting
+ the dbPathName to the default path (kpilot/DBBackup/UserName)
+
+2002-12-13 Reinhold Kainhofer
+* Initial import of the docconduit, which syncs text files on
+ the desktop with PalmDOC databases (kind of e-book format for
+ the palm) on the handheld for use with AportisDoc, TealReader,
+ QED, etc.
+* VCalConduit: yearly recurrence now works correctly (had wrong
+ yearly recurrence type rYearlyDay instead of rYearlyMonth)
+* Addressbook conduit: _equal also compares the categories to
+ check if an item was changed
+* Added the new methods createDatabase(..) and deleteRecord(..)
+ to the PilotDatabase classes. createDatabase creates a new
+ database with given type and creator, and deleteRecord deletes
+ either a single record or all records in the whole database
+* PilotDatabse::readNextModifiedRec has a new optional argument
+ of type int* which receives the index of the returned record.
+* PilotDatabase::findDatabase has optional arguments
+ int index=0, long type=0, long creator=0
+
+
+
+KPilot Developer's notes for november 10th, 2002
+================================================
+
+2002-11-10 Adriaan de Groot
+* Is kate acting up? I would have sworn I did some ChangeLog
+ editing last night. Anyway:
+* Expanded the DCOP interface so the daemon can signal KPilot
+ when the HotSync is done. This causes postHotSync things to
+ be called and unfreezes the FileInstaller.
+* Adjusted the progress bar during installing files.
+* Daemon->Quit now still waits til lthe end of the sync.
+* Display some form of progress during a restore. Reduce verbosity a little.
+
+2002-11-08 Adriaan de Groot
+* Clear the file installer list after a HotSync. Disable dropping files
+ on the installer during a Sync.
+* When installing files, the "done" message was printed at the
+ beginning of the last file to be installed. Fixed.
+
+2002-11-07 Adriaan de Groot
+* only call slotTextChanged() in the MemoWidget
+ when switching memos, and only if the memo is changed.
+ This saves rewriting the database every time you hit a
+ key in the memo edit box.
+
+2002-11-06 Adriaan de Groot
+* Fix the KNotes conduit's name.
+
+2002-11-05 Adriaan de Groot
+* Patched up the website again a bit.
+* Mucking about in libkcal to make it useful for KPilot.
+* Lots of includes changed in the vcalconduit to reflect that.
+
+2002-11-02 Adriaan de Groot
+* Regarding the "Hidden config feature", it's in the group for the
+ popmail conduit, called "outboxFolder". Set it to the i18n'ed name
+ of KMail's outbox. Damn KMail's DCOP interface / config. This
+ should make it possible to send mail with KMail again.
+* Finally got a separate build tree of KPilot working. Can distribute
+ sources again, now, assuming SLAC can suffer the bandwidth penalty.
+* Most of libkcal's header files aren't installed. Why? Is it really intended
+ to be totally internal to the kdepim module in KDE's CVS?
+
+2002-10-31 Adriaan de Groot
+* Happy Hallowe'en, eh.
+
+2002-10-27 Adriaan de Groot
+* Don't you hate code / feature freezes? It always stops KPilot development
+ in it's tracks, if only because fixing the bug related to KMail's outbox
+ requires a new string. Bitch bitch, moan moan.
+* Added new TODO_I18N macro to flag I18N todos. The popmail
+ conduit is a big candidate for fixups.
+* Thought of a new starter project: moving the popmail conduit config
+ dialog to Qt Designer. Another one would be to fixup the capitalization
+ of popmail in that conduit.
+* Added extra undocumented configuration option to the popmail
+ conduit in an effort to save KMail sending capability.
+
+
+KPilot Developer's notes for september 19th, 2002
+=================================================
+
+
+2002-09-13 Reinhold Kainhofer
+* Finally, the addressbook conduit is in a shape where I can release
+ it with beta 2. There are still some issues (e.g. duplication as
+ conflict resolution is messed up on the next sync. Also, entries
+ with newlines in an address field are always determined as changed,
+ so the fast sync is not so fast with them.), but they can be targeted
+ later on.
+
+2002-09-10 Adriaan de Groot
+* Problems related to immediate "Exiting on Cancel" traced back to
+ having two pilot-link versions installed; compile against one
+ and link against the other.
+
+2002-09-02 Adriaan de Groot
+* Added finer-grained pilot-link version checking in configure.in.in.
+ Removed all support for ancient pilot-link versions.
+
+2002-08-30 Adriaan de Groot
+* Much mucking about with dlp_ functions in an attempt to discover why
+ syncing wasn't discovering _any_ of my databases. Also handling
+ dlp_ReadUserInfo failures, indicating possible password use. Weird.
+
+2002-08-28 Adriaan de Groot
+* Mess around a bit with Chris' crashes and the exiting-on-cancel one.
+* PilotDaemon not passing on correct signals and slots to KPilot.
+ This should finally enable some progress-meter changing.
+* Ditched the check of dlp_OpenConduit when the device is opened
+ initially, it's returning -18 after the user name is read correctly.
+ The USB support under FBSD is still very patchy, though, since
+ it thinks I have just one database.
+
+2002-08-24 Adriaan de Groot
+* Add a "Fail Now" mode to the NULL conduit to help debugging.
+
+2002-08-24 Adriaan de Groot
+* (syncAction.cc) Whoops, forgot to implement the timeout feature
+ in interactive questionYesNo.
+* One more go through all the sources removing warnings.
+
+2002-08-23 Adriaan de Groot
+* (addressWidget.cc) Added more debugging output in response to bug #45977.
+ Gosh, it's even a FreeBSD user. This basically means that the database
+ can't be opened, and I have no idea why.
+* (kpilotlink.cc) Added more debugging output in KPilotLink::acceptDevice()
+ to deal with problems from Chris Cowell and Beat Straehl.
+* (kpilotlink.cc) (Perhaps) check pilot-link version more gracefully.
+* (pilotUser.h) bzero() new KPilotUser data structures, just in case.
+* (interactiveSync.cc) Fix compile warnings.
+* (knotes-action.cc) Fix bug that causes the KNotes conduit to hang
+ when KNotes isn't running.
+* (everything dependent on SyncAction) Changed the type of exec() to virtual
+ bool, and removed it from the slots. Added a new slot execConduit() which
+ calls exec(). This makes you return a value from exec(), and false is intended
+ to indicate "processing never started due to errors" and will cause execConduit()
+ to generate a generic error message and emit the syncDone(this) signal, which
+ is otherwise easily forgotten when just doing return;
+
+
+KPilot Developer's notes for august 15th, 2002
+==============================================
+
+2002-08-15 Reinhold Kainhofer
+* Implemented categories in the todo conduit
+* Fixed the bug which prevented error messages from
+ being included in the hotsync log (the signals from
+ fDeviceLink were not connected!)
+* Included the malconduit in the CVS tree (but disabled
+ its compilation for now), wrote several
+ emails asking for permission to either relicense libmal
+ to use MPL 1.1, or to include special permission into
+ KPilot's COPYING to permit linking to libmal.
+
+
+KPilot Developer's notes for july 31th, 2002
+===========================================
+
+2002-07-31 Reinhold Kainhofer
+* Added a time conduit which syncs the time from the pc to the palm
+* Also wrote an AvantGo conduit, but didn't add it to the cvs tree yet
+ because it uses libmal, which is MPL (and thus GPL-incompatible).
+ We have yet to figure out a way to make them compatible...
+
+KPilot Developer's notes for july 17th, 2002
+===========================================
+
+2002-07-17 Reinhold Kainhofer
+* A first almost-working version of the address conduit. Chances are,
+ some data will be lost, but most parts work. "Duplicate entries"
+ conflict resolution setting does not yet work.
+
+
+KPilot Developer's notes for july 4th, 2002
+===========================================
+
+2002-07-04 Reinhold Kainhofer
+* Added a function KPilotDeviceLink::tickle() which prevents a timeout
+ on the palm side if it is called with a timer (e.g. when a dialog is open)
+* Some more work on the addressbook conduit, which seems to be trickier
+ than I had thought initially.
+
+
+KPilot Developer's notes for june 24th, 2002
+============================================
+
+Moving on past 3.0.2 and trying to sort things out.
+
+2002-06-24 Adriaan de Groot
+* The config file the daemon allocates is read-only. This is inconvenient
+ when conduits want to save data in the config file. Backed that out,
+ am now worried about what happens when you leave the KPilot UI running
+ during a sync, since both applications have a RW copy of the config file.
+
+2002-06-24 Reinhold Kainhofer
+ Still fighting with the addressbook conduit. The Palm -> PC way already
+ seems to work. Haven't committed anything yet to prevent breaking
+ compilation of the kdepim module with a conduit which won't work yet anyway.
+
+
+KPilot Developer's notes for june 16th, 2002
+============================================
+
+2002-06-16 Reinhold Kainhofer
+* backported many fixes in the vcal conduits to the BRANCH for the 3.0.2
+ release.
+* For the addressbook conduit I implemented a method
+ QValueList<recordid_t> PilotDatabase::idList()
+ which returns a list of all record ids in the database
+* KPilotDeviceLink::openDatabases now fetches the database from the palm
+ if no backup copy exists on the PC.
+
+KPilot Developer's notes for june 9th, 2002
+===========================================
+
+Not sure just what Reinhold has been up to recently, but
+I know I've been sitting in the sun and relaxing. Mostly.
+
+H==HEAD, B==Branch in the bracketed notes after the patch description.
+
+2002-06-10 Adriaan de Groot
+* Using version 4.3.3 in BRANCH for the 3.0.2 release, and
+ 4.3.4 in HEAD for later.
+
+2002-06-08 Adriaan de Groot
+* Conduits, conduits, conduits and documentation, documentation, documentation.
+ That's what we need. Sigh.
+
+2002-06-07 Adriaan de Groot
+* Patched VCalConduitBase::cleanup() to be careful about
+ calling functions on objects that may not be allocated. [H,B]
+* Patched VCalConduitBase to use variables from ConduitBase. [H]
+* Added tooltip for daemon. Gosh, that's ugly. Should put a
+ nicer message in there. [H]
+
+KPilot Developer's notes for may 25th 2002
+==========================================
+
+2002-05-23 Adriaan de Groot
+* KNotes syncing now really seems to work both ways.
+* Time to deal with a lot of little administrative files.
+* Fixed tooltips in config dialog.
+* KPilotTest now resets after a sync as well.
+* Added hooks in LogWidget to allow extra buttons.
+
+2002-05-21 Adriaan de Groot
+* Renamed PilotDatabase::cleanUpDatabase() to cleanup(), this
+ affected the Serial and Local reimplementations and also the
+ abbrowser conduit, which is the only conduit to do the right
+ thing and cleanup the database after a sync.
+* Added missing close and delete on the databases for plugins.
+
+2002-05-19 Adriaan de Groot
+* Time to take a good hard look at the conduits individually.
+ We'll start with the notes conduit, since it only does one-
+ way syncing. I suspect this will chime in some more testing
+ instrumentation in the base classes for conduits, too.
+* Changed lots of bitconstants to hex, for clarity.
+* Added a FlagLocal to plugin.h with the intent that you can
+ then try to sync two _local_ databases -- so you don't even
+ need a Pilot for testing.
+* The KNotes conduit now tries to do something sensible with
+ getting notes back to the Pilot, but fails.
+
+KPilot Developer's notes for may 18th 2002
+==========================================
+
+2002-05-18 Adriaan de Groot
+* Bunch of compile fixes. What happened?
+
+2002-05-15 Adriaan de Groot
+* Updated the version number.
+* Removed the device type combobox, since it's not needed.
+* Updated the what's this text for the speed combobox.
+* Removed the "alpha" warning from the log widget.
+
+
+KPilot Developer's notes for april 28st 2002
+============================================
+
+Hopefully we'll have merged the HEAD version of the vcal conduit --
+by Reinhold K. -- with branch so that it actually works.
+
+
+
+KPilot Developer's notes for april 21st 2002
+============================================
+
+A week when I should have been working on KPilot, and I've been
+working on the build system instead. Reinhold K. has hinted that
+he's making tremendous progress on the vcal conduit, which is a good thing.
+
+2002-04-20 Adriaan de Groot
+* Closed a few bugs that I could verify are resolved. Other conduit-
+ related bugs remain open even if I suspect they're done, since I
+ haven't actually physically tested them.
+
+2002-04-16 Adriaan de Groot
+* Finally committed all of David B's patches and things. [HEAD]
+* More modification of configure.in.in and the Makefile.am's to
+ make pilot-link more easily found (I hope). [BRANCH]
+
+2002-04-15 Adriaan de Groot
+* Cosmetic fix: center splash image under KDE3 as well.
+* Fixed misleading debug statement when KPilot starts the daemon.
+
+KPilot Developer's notes for mid-april 2002
+===========================================
+
+2002-04-13 Adriaan de Groot
+* Received a patch from Carlo Perassi for handling cases where there
+ is no user name set in the Pilot.
+* Worked on configure changes to detect pilot-link automatically and
+ properly. [BRANCH]
+
+2002-04-09 Adriaan de Groot
+* Did some minor debugging in setting flags for the conduits.
+
+2002-04-07 Adriaan de Groot
+* There are now two real branches of development for KPilot. KDE_3_0_BRANCH
+ gets bugfixes to the existing code, while HEAD gets new features. I imagine
+ I'll merge BRANCH back to HEAD sometime when I feel that the main bugs
+ are out (like next week, I hope). I'll be showing where patches go until
+ we merge again.
+* Added a message (no i18n) showing KPilot and pilot-link versions.
+* Still need a workaround for dlp_addSyncLogEntry() for pilot-link 0.10.1
+ [BRANCH - should go in HEAD as well]
+* Fixed Makefile.am bug in popmailconduit. [BRANCH]
+- --test mode wasn't working with kpilotTest (when running conduits) [BRANCH]
+
+2002-04-06 Adriaan de Groot
+* Applied patch to avoid crash with undefined symbol. I forget who sent
+ it in, though. Thanks to you, anonymous! Wrote a script to catch this
+ kind of situation in the future.
+
+
+
+KPilot Developer's notes for sometime in march 2002
+===================================================
+
+2002-03-09 Adriaan de Groot
+* Sanitized syncStack so that nextAction isn't so ambiguous.
+* Fixed missing default (--list) in kpilotTest.
+* Some neatness fixes in pilotDaemon.cc and pilotDaemonDCOP.h.
+* Test syncs shouldn't run conduits or install files. Fixed in pilotDaemon.
+* The daemon leaked 2 FD's on every sync, which is bad. Added some extra
+ ::close() calls, which fixes this (under p-l 0.9.5 and 0.10.1).
+* Mucked about with USB devices some more, but it looks like the m500
+ is going to be unusable under FBSD for some time. This isn't bad, since
+ I can then concentrate on getting things working with the serial PalmV.
+* It might be a good idea to start using the daemon to do just device tests
+ instead of kpilotTest -- though it doens't make a big difference.
+
+2002-03-08 Adriaan de Groot
+* Fiddled around w/ getting a broadband connection, for whatever
+ reason. I guess effortless connectivity is the goal. Fiddled with
+ my new m500 USB and discovered that pilot-link 0.10.1pre works
+ perfectly with it under Linux (well, pilot-xfer -l works). Under
+ FreeBSD, though, it seems that there's nothing available for this
+ kind of device. Hmph. So now I need to spend some time to figure
+ out how to get KDE up and running on my somewhat deprecated Linux
+ install. Serve the source by NFS?
+
+2002-03-07 Adriaan de Groot
+* Finally picked up where I left off, adding yet another message to
+ the startup log window (again, I think this is temporary). The versions
+ of relevant items now appear there.
+* Messed around with crashes while deleting CleanupActions.
+
+2002-03-06 David Bishop
+* Lots of work on exporting memos in XML format. It looks like the
+ whole memo viewer widget is going to be reworked, slightly.
+* Finished off the kdDebug() repairs someone else started.
+
+KPilot Developer's notes for february 11th 2002
+===============================================
+
+2002-02-06 Adriaan de Groot
+* kpilot/listItems.cc lib/pilotRecord.cc
+ - Removed some FUNCTIONSETUPs, since they were really clogging debugging
+ output and not adding anything interesting. Changes some other
+ debug output as well.
+* kpilot/addressWidget.cc
+ - I *think* I squashed a memory leak, caused by createTitle which
+ was still returning char * instead of QString. Moved to QString anyway.
+
+2002-02-03 Adriaan de Groot
+* kpilot/Icons/kpilot-hotsync.png
+ - Whipped up a new icon for HotSyncing. This makes all the icons in
+ the Janus view the same size.
+
+KPilot Developer's notes for february 2nd 2002
+==============================================
+
+2002-01-26 Adriaan de Groot
+* Wherever
+ - Invented an icon for the address viewer.
+ - Doubleclick on conduit in active column configures it.
+ - Fixed some compile problems under KDE3.
+ - Messed around with the vcal conduit.
+ - Configuring conduits resets the daemon.
+ - You can't reset the daemon during a sync; replaced fQuitAfterSync.
+
+I'm starting to think the logWidget belongs with the *daemon*
+(and should be showable from the daemon's context menu), not
+from KPilot (which should be just a viewer). Opinions?
+
+2002-01-27 Adriaan de Groot
+* Wherever
+ - Got rid of the remaining dlp_ functions in code outside
+ of kpilotlink.cc and pilotSerialDatabase.cc. This leaves the pi_ stuff.
+
+Development of KPilot is now done on a 80x25 serial terminal running at
+38400 baud. I have no idea what kind of effect this will have, but it means
+I can sit on the couch and do devel work :)
+
+2002-02-02 Adriaan de Groot
+* lib/kpilotlink.{h,cc}
+ - Continue moving pilot-link related things (pi_*) into the KPilotLink
+ class, so that Dag might have an easier time of it.
+* lib/options.cc
+ - Removed some messy #ifdef DEBUG stuff, with debugging enabled
+ call tracing is now default on.
+* kpilot/logWidget.cc
+ - Added some text stating that KPilot is really alpha. No-one will read
+ this, of course, and it will only piss off the translators.
+
+KPilot Developer's notes for january 25th 2002
+==============================================
+
+Found my Pilot again, made tea, thought about Dag's and Neil's comments
+on ColdSync (I still believe that ColdSync has the drawback that it's not
+meant to be a library you can build on, it resembles the pilot-xfer tools
+much more than anything else). Grepped for dlp_ in the sources. They seem
+fairly isolated, which is good -- maybe we *can* move to some other Pilot
+access method.
+
+Looked at some old sources. *uuuuugly*. PilotRecord, PilotAppCategory,
+PilotTodoEntry, etc. could use a good dose of sanity.
+
+2002-01-21 Adriaan de Groot
+* conduits/vcalconduit/*
+ - Some serious rewriting going on.
+* kpilot/hotSync.cc
+ - Removed old KPilotLink code
+ - Moved calls from dlp_OpenConduit to KPilotDeviceLink::openConduit()
+* lib/syncAction.h lib/kpilotlink.{h,cc}
+ - Added openConduit to abstract the underlying lib interface more.
+* kpilot/logWidget.cc
+ - suppress empty log lines.
+* lib/pilotLocalDatabase.{h,cc}
+ - Added a hook for UserCheck to set the default search path for
+ databases opened by name only.
+
+It's time to say hi, welcome, and thanks to a couple of new people on
+the KPilot / kde-pim team. There's Chris Abiad, who has already made his
+presence felt on the mailing list. Thanks for fielding questions for
+me, Chris, and stalling on the question of when the next release is.
+Chris will also be maintaining the website. Next up is Stephanie Bryant,
+a writer of technical documentation. She'll be helping me document the
+various files in kpilot/lib so that they actually form an understandable
+and usable API for third-party conduit-writers. Philipp Hullmann, you
+should be overjoyed to hear this :) Once she's practiced on KPilot, Steph
+will be leaving us for kdelibs, where weird and wonderful things await ...
+
+2002-01-25 Adriaan de Groot
+* *.ui
+ - Danimo was wondering why we use ToolTips everywhere instead of WhatsThis.
+ My answer was "because we knew about QToolTip before QWhatsThis." Anyway,
+ switching over to the correct form of on-line help is a simple search-
+ and-replace thing. So that has happened. David, can you keep that in
+ mind as well?
+* kpilot/pilotDaemon.{h,cc} kpilot/Icons/
+ - Minor changes to get the daemon's icons to display properly.
+ - Woo.. the busysync icon is *ugly*. Partly fixed, and I hope Kristof
+ can do something about it sometime. Really we need the icon in 4 rotated
+ states (well, maybe 2) to indicate activity during the sync.
+ - Of course the daemon was exiting after each sync .. I forgot to initialize
+ fQuitAfterSync (which isn't used, BTW, except if you use DCOP to call
+ quitNow()) to false.
+* kpilot/kpilot.cc
+ - Forgot to inform daemon of changing settings.
+* kpilot/syncStack.cc
+ - All conduits now put *something* in the Sync log.
+
+
+KPilot Developer's notes for january 20th 2002
+==============================================
+
+It's been a slightly sleepy time. Some rocky backporting has occurred,
+though, as KDE3-isms sneak into the codebase and break my compiles at
+home. At work, though, I've switched to KDE3 and it's really nice.
+Now if only I could release a version of KPilot that works before KDE3
+comes out and makes all this compatibility effort moot ...
+
+2002-01-15 Adriaan de Groot
+* conduits/vcalconduit/*
+ - Class Recurrence is the KDE3 name of class KORecurrence. Where the
+ libkcal API has changed, added #ifdefs to use the right one, and
+ #define Recurrence KORecurrence when compiling under KDE2.
+2002-01-16 David Bishop
+* *.ui
+ - Added <qt>'s to all tooltips, neatness fixes.
+2002-01-16 Adriaan de Groot
+* lib/options.{h,cc}
+ - Added support for both ostream and kdbgstream << QSize to avoid
+ plugin crashes when the plugin is compiled with different DEBUG_CERR
+ settings from libkpilot.
+2002-01-19 Adriaan de Groot
+* Documentation
+ - Added a warning "Docs out of date" to the docs, adapted all the top-level
+ README &c. files to reflect the current situation.
+2002-01-20 Adriaan de Groot
+* lib/pilotLocalDatabase.{h,cc}
+ - Added new constructor that doesn't take a path, but just uses the
+ application-instance database directory.
+* lib/plugin.{h,cc}
+ - Added isRunning() to PluginUtility, since several conduits need to
+ know if the application they are syncing is already running or not.
+* conduits/knotes/knotes-action.{h,cc}
+ - Replaced knotesRunning by call to isRunning();
+* conduits/vcalconduit/*
+ - Started a real re-write of the vcal conduit (what??!)
+* TODO
+ - Updated the TODO list with some concrete stuff.
+
+KPilot Developer's notes for december 31st 2001
+===============================================
+
+Time to go out with a bang, eh.
+
+Fixing the VCal conduits so they actually do a sync was a fair bit of
+work, partly because it was so weirdly crufty, partly because of the
+peculiar separation of the todo from the vcal conduit.
+
+
+2001-12-28 Adriaan de Groot
+* conduits/vcalconduit/vcalBase.{h,cc}
+* conduits/vcalconduit/vcal-conduit.{h,cc}
+* conduits/vcalconduit/todo-conduit.{h,cc}
+ - Well, it compiles now.
+* lib/plugin.{h,cc}
+ - Added isBackup() so that conduits can now also do their own
+ backups. Note that conduits aren't called (yet) during a backup
+ action.
+* conduits/popmail/*
+ - Why the heck does this (still) use FILE *?
+ - It compiles and there is a sync action.
+
+Next up is checking out kpilotTest and making sure that it does sensible
+things, like closing the device handle, allowing multiple syncs, and
+running file install correctly. After that, testing testing testing.
+
+2001-12-28 Adriaan de Groot
+* kpilot/main-test.cc
+ - Added one-letter cmd-line-options, sanity checking.
+ - Switched to SyncStack integrated syncing (see below).
+* kpilot/main-config.cc
+ - Removed unused new-style option.
+* kpilot/syncStack.{h,cc}
+ - New files encapsulating sync sequence knowledge.
+
+2001-12-29 Adriaan de Groot
+* kpilot/pilotDaemon.{h,cc}
+ - Switched to SyncStack.
+* lib/kpilotlink.cc
+ - Work around an off-by-one bug in pilot-link versions < 0.9.6.
+* kpilot/interactiveSync.cc
+ - Added support for don't ask again in the check-user questions.
+ This changes the API of questionYesNo, but only inserts a
+ (defaulted) parameter, so "regular" calls of this should be
+ unaffected.
+
+The GUI isn't updated at all (?) during a backup action. Hmph. Well, only
+between databases, but that's not much. The backup appears to work, which
+is a good thing. Gonna hafta try the restore action soon ;)
+
+2001-12-29 Adriaan de Groot
+* conduits/null/null-*.{h,cc}
+ - Fixed some configuration load / restore / use bugs.
+ Moved configuration keys to the factory.
+* kpilot/syncStack.{h,cc}
+ - The conduit proxy action also needs to proxy the messages from the conduit.
+ I never knew connect(p,SIGNAL(),q,SIGNAL()) worked! Wow.
+* kpilot/logWidget.{h,cc}
+ - Added missing slot for logProgress.
+
+Aieee! I'm becoming a kate user, vi is suffering from abandonment on my
+devel box. This is troubling -- using the software you write. Heck, next
+thing you know, I'll be using KPilot to sync my Pilot. Ewwwww.
+
+
+2001-12-29 Adriaan de Groot
+* kpilot/conduitConfigDialog.{h,cc}
+ - Removed old Exec= style conduits entirely. They're warned for now.
+* conduits/abbrowserconduit/*
+ - See conduit run. See DrKonqui. Whee! Oh, and this *one* conduit has
+ a name of the form bla_conduit, while all others are bla-conduit. Yay.
+ See pointer get used before initialization. Cool! It crashes elsewhere.
+ Isn't delayed loading great? __rs__FR11QDataStreamRt5QDict1Z12ContactEntry
+ And ... that was fucking amazing. Greg, you da man.
+
+ OK, so that one also runs to completion, at least the first time. It looks
+ like FirstTime isn't being turned off like it should, so I'll do that by
+ hand. OK, changes get copied from the Pilot to KAddressbook ok, but the
+ conduit seems to read *all* records from the Pilot, not just the modified
+ ones. That's bad for the batteries. Oh well, I'm just so happy it works
+ that I'll move on to the next conduit and deal with bugs tomorrow.
+* conduits/expense/*
+ - Seems to work fine.
+* conduits/knotes/*
+ - Undefined symbols ... man, I (semi) hate libtool libraries.
+ See, I just left some essential code *out* here, and thus libtool
+ thinks it'll be resolved later. Ha!
+
+ OK, it at least copies new KNotes to the Pilot. That's enough for now.
+* conduits/popmail/*
+ - Um, does this actually *do* anything? OK, config fixes, dcop fixes ...
+ and voila, a message shows up in the outbox of KMail. So let's call
+ sending via KMail a success and have a cup of tea.
+* conduits/vcalconduit/*
+ - Now things get hairy / exciting. Let's start with the ToDo conduit:
+
+ kpilotTest: WARNING: [void ConduitProxy::exec()] : Can't create SyncAction.
+
+ Very wise. Of course, the code to create a conduit is not in the
+ factory. Brilliant! Nothing a little cut-n-paste can't cure, and
+ configure, and .. DrKonqui. Did some indenting, my brain hurts from
+ trying to (a) understand this (b) fix all the memory leaks. Rewrite?
+ - VCalConduit: it doesn't crash, but it's probably going to read all
+ the things from my Pilot and install them in KOrganizer with a date
+ of 0000/00/00 (from looking at the debug messages as they fly by).
+ And .. whump, KOrganizer now can't read the .ics file anymore.
+
+*Every* sync, KPilot tells me that the name in the pilot is different
+from the name in KPilot. Gotta fix that.
+
+2001-12-30 Aaron J Seigo
+* kpilot/logWidget.cc
+* kpilot/kpilot.cc
+ - Paint the KPilot version number in the splash screen.
+
+2001-12-30 Adriaan de Groot
+* conduits/vcalconduit/vcal-conduit.cc
+* conduits/vcalconduit/vcalBase.cc
+ - Removed some __FUNCTION__ things, added #ifdef DEBUG to debug code.
+ In some other files, too.
+ - The code in vcalBase.cc is in heavy need of an invocation of indent.
+ It's horrible and ugly in other ways, too, but this is a start.
+
+2001-12-31 Adriaan de Groot
+
+Some general polishing of ToolTips &c.
+
+* kpilot/*
+ - Added Kristof's icon for the file installer. It's still a preliminary
+ version, though.
+ - TODO: after reconfiguring the username, re-initialize all components
+ in kpilot, to get the new databases.
+ - Switched the ToolTips in the address viewer to use <qt>
+ - TODO: ditch the toolbar; perhaps add the select-kind-of-sync
+ functionality to the logWidget.
+
+KPilot Developer's notes for december 27th 2001
+===============================================
+
+So I never posted the previous notes. And besides Maarten's little comment
+on the odd jobs, no response either --- but then again, it was Xmas and
+maybe people had more important things to do. I know I had enough dinners
+that I can fast & hack for the rest of the week.
+
+Things fixed now:
+
+* conduits/vcalconduit/
+ - All the configuration dialogs now look ok, after a little fiddling
+ about with the .ui files, and the configuration is saved as well.
+ A sync is out of the question right now.
+
+Yet another odd job: someone (David?) needs to check all the ToolTips
+in the .ui files for the conduits with Qt *2*'s designer. And we need
+to check that all the configurations are in fact saved properly. Testers?
+
+KPilot Developer's notes for december 23rd 2001
+===============================================
+
+HoHoHo. Let's look back in the ChangeLog to see where we were one year ago.
+Struggling with the vcal conduit (it's *still* wonky); missing the 2.1
+release deadine (was it that long ago?); cleaning up code.
+
+In these complex modern final days, (to quote Pogo), what's up?
+
+2001-12-18 Adriaan de Groot
+* conduits/expense/*
+* conduits/null/*
+ - These two conduits now have a full configure dialog that's sized
+ correctly (afaict without messing around with font settings), that
+ saves the settings, and have a working sync action. Whee!
+
+2001-12-20 Adriaan de Groot
+* conduits/abbrowser/*
+ - This conduit now has a working config dialog and does a sync, although
+ I haven't really looked at the sync code itself to check for bugs.
+* conduits/knotes/*
+ - Ditto; it configures and syncs, although the sync is rather sparse.
+ I discovered that const char * const is a useful type, though. It saves
+ an accessor function for KConfig entry keys.
+
+The bad conduits:
+
+* conduits/popmail/*
+ - Still no .ui file and not many tooltips, but you *can* configure
+ this conduit. No sync though.
+* conduits/todoconduit/
+ - This one is seriously deprecated and I'll try to remove it soon.
+* conduits/vcalconduit/*
+ - It's got a .ui file which is used badly and which is missing layouts.
+ Not a hint of saving configurations though.
+
+OPEN JOBS:
+
+Are you bored? Is your love life lackluster? Do you want to MAKE MONEY FAST?
+Do you want to FIND OUT WHAT MICROSOFT DOESNT WANT YOU to KNOW? ... um ...
+back to reality: If you'd like to help out with KPilot but don't really know
+where to start, and would like to get a little acquainted with the code,
+the coding style, and some of the conventions used in KPilot, read on!
+If you have grep and a text editor, read on!
+
+The code, and particularly the debugging code, has gone though a number
+of phases. For a while, there was that --debug 1023 stuff. I've decided
+that that's actually kinda cumbersome for a GUI program, and debugging
+has switched back to an all-or-nothing kinda thing. So some things need
+to be changed all over the source code, and that's just the kind of
+exploratory job for someone with grep and vi. In particular:
+
+* kdDebug() everywhere needs to change into DEBUGCONDUIT, DEBUGKPILOT,
+ or one of the other DEBUG* macros defined in kpilot/lib/options.h.
+ This will send the debugging output to the sensible debug area.
+ Which one you choose depends on where the file lives -- choose wisely.
+
+* DEBUG* calls everywhere need to be surrounded by #ifdef DEBUG #endif.
+ This is because some compilers don't optimize away unused strings,
+ leading to big bulky (well, sorta) executables. Adding the #ifdefs
+ makes sure that there's nothing at all left over from the debugging code
+ when debugging is turned off.
+
+* __FUNCTION__ needs to be replaced by k_funcinfo. The popmail conduit is
+ bad for that one, at the very least.
+
+* if (debug_level) and its cousin if (debug_level & SOMETHING) need to be
+ removed, along with the set of brackets they introduce. The debugging
+ statement (usually just a kdDebug() << whatever << endl;) needs to be
+ out-dented one tabstop, to line it up properly.
+
+These are, in one sense, rotten little jobs. But they'll take you to all
+the corners of the KPilot code, show you some ugly (and some not-so-ugly)
+code, and give you a feel for "the lay of the land." After that, fixing
+all the remaining off-by-one bugs in the vcal conduit should be a breeze.
+
+KPilot Developer's notes for december 16th 2001
+===============================================
+
+Worked on some conduits for danimo, who has UI updates. So more conduits
+compile now, but I haven't tested them. However, they do get installed
+if you do make install, and they may eat your Pilot, you Buick, or New York
+when run. USE EXTREME CAUTION.
+
+I think the NULL conduit is safe, though :)
+
+Abbrowser Conduit: it compiles, and it has but a setup dialog and a
+sync part which has not been tested at all.
+
+* Makefile.am
+ - Fixed up includes, removed old PISOCK_INCLUDE.
+* abbrowser-conduit.cc
+ - Changed kdDebug() to DEBUGCONDUIT, applied indent style, #ifdef DEBUGs
+ - Replaced static QString objects by const char * (KConfig keys)
+ - Removed old files
+ - Assume FirstTime is always *true*, this is at least partly broken,
+ but it makes the conduit compile at least.
+
+The other conduits all compile and have config dialogs but don't do anything.
+
+And in other news, little bugfixes and other neat stuff sometimes shows up
+in my mailbox. Martin Junius is a long-time contributor, and he's volunteered
+(again) to make new KPilot rpms for RH 7.2 once the system is stable again.
+
+* kpilot/addressWidget.cc
+ setupWidget() - Martin Junius found a display bug and sent a patch.
+* conduits/vcalconduit/vcal-conduit.cc
+ setRepetition() - Philipp Hullmann noticed that the Pilot's week starts
+ on day 0 = sunday, and in KDE day 0 = monday.
+
+KPilot Developer's notes for december 2nd 2001
+===============================================
+
+More work on the expense conduit. In conduits/expense:
+
+* setupDialog.h
+ - Added an #include <qwidget.h> to make header self-contained.
+* setupDialog.cc
+ - Disabled MySQL button, since there's no code to make it work.
+ - Disabled "logRotate" stuff, since I can't remember what was
+ wanted there and there's no code for it.
+* expense.cc
+ - Reordered #includes, removed extra #ifdeffing. Removed extra #includes.
+ - Split up actions into CSV, MySQL and Postgres specific parts.
+ - Made the other-db methods also write CSV files if needed.
+ - Support both overwrite and append modes for CSV.
+ - TODO: create the mysql code.
+ - TODO: patch possible security hole in echo passwd |
+ - TODO: spawn fewer processes for psql.
+ - TODO? use klocale's date formatting, not US-specific code.
+* expense.h
+ - Changes reflecting the above, and
+ - Documenting what's going on.
+
+In other news:
+
+* conduits/knotes/knotes-action.cc
+ listNotes() - Removed spurious #ifdef DEBUG. Test mode should always work.
+
+And oh, wow, thanks to messing around with the logWidget for KPilot,
+KPilotTest now also has a funky splash screen :)
+
+* kpilot/main-test.cc
+ main() - connect signals from the test action to the log widget.
+
+KPilot Developer's notes for november 25th 2001
+===============================================
+
+More work on the Expense conduit.
+
+In other news:
+
+* kpilot/logWidget.{h,cc}
+ Nifty feature for the sync log: clear the log. Save the log. ToolTips.
+
+
+KPilot Developer's notes for november 18th 2001
+===============================================
+
+Kudos to Marko Hollomon for spotting a pointer error in the KPilot daemon
+and fixing it. The patch changes pilotDaemon.{h,cc}.
+
+Thanks too to Palle Girgensohn, who made an icon for the internal memo-
+viewer and the KNotes conduit. This looks really neat in the new IconView
+mode of the main KJanusWidget.
+
+Shuffling the DCOP interfaces and cleaning up the UI, by [ade]:
+
+* logWidget.{h,cc}
+ Made the splash more like a splash, removed some ugliness, moved the
+ progress bar into the SyncLog widget.
+* kpilotDCOP.h
+ Removed the spurious filesChanged() call -- use KDirWatcher instead.
+* kpilot.{h,cc}
+ Removed the inheritance from kpilotDCOP.h, moved the DCOP interface to
+ LogWidget. Removed the status bar, since it's all in the LogWidget anyway.
+* pilotDaemon.cc
+ Renamed KPilotDCOP interface, removed filesChanged DCOP signal.
+* Makefile.am
+ Now logWidget requires kpilotDCOP, so moved that.
+
+Now that conduits are .so's, the conduitConfigDialog needs to have some
+strings changed to reflect that they're not executed anymore [ade].
+
+* conduitConfigDialog.{h,cc}
+ Added a warnNoLibrary function, moved warnings to Qt richtext.
+
+The FileInstallerWidget has some lousy strings with \n, and it needs
+a KDirWatcher [ade].
+
+* fileInstallWidget.{h,cc}
+ Changed the i18n strings to remove \n's. The Watcher remains a TODO.
+
+Attacked the expense conduit, finally. Maybe *this* one won't run aground on
+things like fundamental API changes in the stuff it syncs against.
+
+* Makefile.am
+ Removed spurious LIBPISOCK_PATH, moved files around a little.
+* setupDialog.{h,cc}
+ Ported to UIDialog classes, layout fixups. This is the one conduit that
+ still uses hard-coded layouts. It's possible, see? This isn't really the
+ way to go, I'd much rather have David B. make dialogs with Qt designer.
+ Added a break; in ExpenseDBPage::slotPolicyChanged() to avoid warnings.
+
+KPilot Developer's notes for november 11th 2001
+===============================================
+
+Much messing-about with hardware, OSsen and the like has delayed many
+things. I've discovered that the configure.in.in and Makefile.am for
+KPilot were really badly broken under anything non-Linux.
+
+* configure.in.in
+ Possibly fixed all kinds of shell-script breakage (under Solaris)
+ and not-finding pilot-link under FreeBSD. You will have to pass in
+ the --with-extra-libs and --with-extra-includes flags; configure now
+ looks there correctly.
+* All the Makefile.am's
+ Removed the extra spurious $(LIBPISOCK_PATH) which was breaking
+ things under FreeBSD.
+* lib/uiDialog.{h,cc}
+ Added a virtual bool function validate() so that when Okaying a
+ dialog, you can check first for valid settings. The default implementation
+ is return true;
+* kpilot/kpilotConfigDialog.{h,cc}
+ Added validate(), check that string for Pilot device doesn't overflow
+ the buffer for it. Also enforce the length restriction for the device
+ name. This is all conditioned on pilot-link < 1.0.0.
+* kpilot/kpilot.{h,cc}
+ Use a KJanusWidget instead of a QWidgetStack and deprecate the View
+ menu to make it clearer which views / actions / things KPilot actually
+ *has*. Moved the Spash Screen to the log widget, and made it a real splash.
+
+
+KPilot Developer's notes for october 28th 2001
+==============================================
+
+So fun to have distributions release broken versions of an application.
+It sometimes makes me wish I didn't have to commit stuff to CVS at all
+until the application is totally right according to me (which is then
+sure to run into trouble with the KDE release schedule).
+
+Another fun thing is wrestling with broken hardware. But it's finally fixed
+now. So I hope the pace picks up again now. I've been working on the
+abbrowser conduti sporadically, so we now have at least three conduits
+partially ported to the new setup.
+
+KPilot Developer's notes for october 21st 2001
+==============================================
+
+2001-10-21 Adriaan de Groot
+
+Since to do the popmail conduit I first need to learn about IOSlaves
+and the KNotes conduit is hard, I spent some time playing with the
+abbrowser / KAddressbook conduit.
+
+* conduits/abbrowser/*
+ () Removed all the old files for the setup dialog, now using David Bishop's
+ .ui files with some polish from me (like putting his name in the "Author"
+ field in the .ui file).
+ () Fixed up the Makefile.am to make the library and the test apps.
+ () Added a factory function.
+ () Removed all the palettes from the deconflict dialog. This takes 150k out
+ of the .ui file. Next challenge is to make it respect the KDE system
+ settings.
+
+2001-10-20 Adriaan de Groot
+
+Worse is when your AGP bus turns out to be broken instead.
+
+* conduits/knotes/knotes-action.{h,cc}
+ () Added method resetIndexes which should be called at the end of every phase
+ of the sync, basically to reset the counter and list iterator to the
+ beginning of the list of KNotes.
+ () Added method modifyNoteOnPilot which does the modified-notes-to Pilot
+ work. It isn't very robust yet, since it doesn't handle weird cases
+ (modified yet unknown on Pilot, for example) at all.
+
+2001-10-19 Adriaan de Groot
+
+Dern. Having your video card break and being thrown back to a 4MB SiS card
+fit only for a firewall with no monitor is *no* fun. Where's a 24-hour
+computer store when you need one? Not only that, but I realise I'm
+going to have to put some serious thought into the KNotes conduit and
+how it is supposed to sync. So since that's hard, I'm going to look at
+the Mail conduit instead, since the functionality there is pretty much
+complete.
+
+2001-10-18 Adriaan de Groot
+
+* kpilot/Icons/
+ () Incorporated most of Kristof Borrey's fantastic new icons for KPilot.
+* conduits/knotes/
+ () Removed old files setupDialog.{h,cc}
+* conduits/knotes/knotes-action.{h,cc}
+ () Added new function getConfigInfo that reads the config file for
+ the lists of Ids (matching KNote ids to memo ids).
+
+2001-10-16 Adriaan de Groot
+
+* lib/options.h
+ Upped the version number to 4.2.9b just because.
+* kpilot/kpilot.cc
+ Changed some credits around, copyright notice, etc.
+* kpilot/Makefile.am kpilot/Makefile-standalone
+ Fixed some breakage caused by all the moving around of files. You may
+ need to make clean ; make in KPilot some time to get things back to normal.
+
+KPilot Developer's notes for october 16th 2001
+==============================================
+
+2001-10-16 Adriaan de Groot
+
+Well, the b-day party got in the way of actually releasing something,
+and there's quite a lot of polish still to apply -- ie. the KNotes conduit
+still does nothing more than install new notes to the Pilot. So I'm going
+to start keeping the TODO list more up to date, including assignments for
+various people, and keeping the ChangeLog more up-to-date according to
+the ChangeLog standard, instead of these long rambling stories.
+
+2001-10-14 Adriaan de Groot
+
+Whee! It's KDE's birthday today. What a fitting day to finally release
+a version of KPilot that actually works, has useful features, and
+doesn't gum up your Pilot hopelessly.
+
+2001-10-10 Adriaan de Groot
+
+* Actually add new KNotes to the memo pad. This means conduit syncing is
+ actually coming closer. Works from kpilotTest.
+* Renamed --test --list in kpilotTest, added option --notest to force a
+ conduit to *really* run (may be hazardous!) from the tester.
+* Moved many things into lib/ -- whatever is shared between KPilot and
+ conduits, basically.
+* Wow! There's stuff in PilotAddress I'd never noticed before that deserves
+ to be moved to a superclass -- like setCategory. Kudos to Greg.
+* Updated the TODO list.
+* Added a nicer credits section in the about page of dialogs.
+
+2001-10-09 Adriaan de Groot
+
+* nothing! Fixed old compile issues on KDE 2.2 iob Solaris.
+
+2001-10-08 Adriaan de Groot
+
+* Added lots of things in lib/ to enforce some kind of uniformity on
+ conduits and factories. Utility functions, too.
+* Added an app-icon for the KNotes conduit. It's ugly as all get-out.
+* Added a test-conduits and a list-conduits mode to kpilotTest.
+* Went back and tested all the stuff we already had, since this
+ re-architecting carries risks. This showed that not everything had
+ gone right: I'd lost track of the pilot socket somewhere. Hmph.
+ Two rounds of re-writing headers, all the parameters finally end
+ up in the right place.
+* The knotes conduit now lists new knotes but doesn't install them.
+
+KPilot Developer's notes for october 7th 2001
+=============================================
+
+Ah, post-KDE3-alpha1. And that when KPilot remains completely 2.1 and 2.2
+compatible. A new release of KPilot for 2.2 is imminent, say oct. 14th or so.
+KDE 2.2.2 was just released, but contains no changes to KPilot at all --
+all the bugfixes were not of the kind that would fit in the 2.2.2 plan.
+
+2001-10-07 Adriaan de Groot
+
+Hmm. Missed a few days. What I remember:
+
+* Implemented the Null- and KNotes-conduits setup dialogs in plugin
+ libraries using David's UI files. That was fun and easy to do.
+* Make the new-style conduit configurator handle plugin libraries.
+ This was less fun, but it works. I haven't had any feedback on
+ which of the two config dialogs is easier to use, but right now
+ I'm leaning towards the new-style one (two columns + some buttons,
+ just like it was *long* ago.) D'nD would be nice though.
+* The new-style thingy doesn't handle saving which conduits are enabled.
+* Made a new subdir lib/, since the plugins need to share some code
+ with KPilot and you need a .so to make it link properly.
+* Wrestled with sensible layout of the about page.
+
+2001-10-01 Adriaan de Groot
+
+* Picked up David's new UI file for the conduit configuration dialog
+ and gave that a whirl. The results can be found in kpilotConfig,
+ use --help to find out which options to use.
+
+KPilot Developer's notes for september 30th 2001
+================================================
+
+2001-09-30 Adriaan de Groot
+
+Last minute sneak-it-in-for-the-alpha things. More code and layout cleanup,
+although the big commit changing to tabs & the KPilot style was yesterday.
+Fixed some minor display bugs, made preHotSync more useful, normalized
+some strings. The kpilot/Icons/ directory now contains only those icons
+actually needed and used, and they're all in PNG format. Saves lots of space,
+in the sense that the KPilot binary is 300k smaller now than it was, due to
+dumping XPMs.
+
+I added a private-d-ptr to kpilot.h, but haven't moved all the data
+members there. For an app it doesn't matter so much, but this will reduce
+the amount of recompiling and who knows what the plugin API will look like
+eventually.
+
+The conduit configuration is different -- again -- and easier to understand.
+
+2001-09-27 Adriaan de Groot
+* Added FUNCTIONSETUP everywhere.
+* Replaced email addresses with [email protected] or [email protected].
+* Removed qDebug everywhere.
+
+2001-09-26 Adriaan de Groot
+
+* Surrounded much debugging output with #ifdef DEBUG.
+* Replaced remaining calls to kdDebug() by macros with debug areas.
+* Applied indent everywhere.
+* Added some () where needed to resolve ambiguity.
+
+2001-09-25 Adriaan de Groot
+
+Wrestled with crashes (cerr << i ; debugstatement ; cerr << i ; gave
+two different values for i) caused by mixing debug conde and non-debug
+code. Discovered that qglobal.h defines DEBUG unless NO_DEBUG is
+set. Hmph. Also found that gcc does a poor job in optimizing away
+debugging statements with NDEBUG defined. Therefore, debugging statements
+will be once again surrounded by #ifdefs. The plan is that I'll get all
+the code formatting and this kind of silly issues out of the way in the
+next few days and then start to deal with the next problem, namely the
+existing conduits.
+
+2001-09-24 Adriaan de Groot
+* kpilot/uiDialog.{h,cc}
+* kpilot/kpilotConfigDialog.cc
+* kpilot/kpilotConfigDialog_base.ui
+ Minor changes to get the dialog to size correctly when other fonts / other
+ settings are used. This solves David's complaint about ugly dialogs.
+* kpilot/hotSync.{h,cc}
+ () Removed lots of commented out code from previous incarnations.
+ () Added a cleanup action.
+ () Removed a heap-corruption bug caused by using QStringList & and
+ then deleting what it points to in FileInstallAction.
+ () Removed deadlock when last file to install couldn't be read.
+ () Moved RestoreAction to interactiveSync.{h,cc}, since I feel it
+ needs to ask "Are you sure?" at the very least.
+* kpilot/interactiveSync.{h,cc}
+ New files with support for, and some types of, interactive syncing.
+ Used for asking the user questions during a sync, for example confirm
+ dialogs. This means we can now update user settings &c, since we needed
+ some interaction for that. Moved RestoreAction to here.
+* kpilot/kpilotlink.{h,cc}
+ Made exec() pure virtual for SyncActions, since that makes more sense
+ than having an empty default action.
+* kpilot/Makefile.am
+ Added interactiveSync.cc to the list of sources.
+* kpilot/pilotUser.h
+ Squashed a buffer overflow. Squashed several buffer overflows. Yowk!
+ This code has been around since 1996?
+* kpilot/main-test.h
+ Added some extra code to make the sync cleaner; handled the move of
+ RestoreAction.
+
+KPilot Developer's notes for september 23rd 2001
+================================================
+
+My current development platform is RH 7.1 with KDE 2.1.1 -- even so I'm
+committing things into HEAD. I'm sure this will explode sometime and
+I'll be forced to upgrade to KDE 2.2 or worse, but for now, that's the
+platform I'm aiming for.
+
+I'd like to take a moment to thank David Bishop, for sending me .ui files,
+for causing noise on the mailing lists, and for being a pleasure to work
+with. Together we've wrestled with Qt designer, uic, and replacing the
+KPilot dialogs with something sensible made with designer.
+
+* kpilot/options.h
+* kpilot/kpilotConfig.{h,cc}
+* kpilot/kpilot.cc kpilot/kpilotDaemon.cc kpilot/main-*.cc
+ Factored out the --debug flags from each individual app, now in
+ options.cc. This means each file with a main() was modified too.
+ I must say it was a real bitch figuring out exactly which sequence of
+ calls were needed for KCmdLineArgs::addCmdLineOptions(), and then
+ finding out that ParsedArgs() also needed help.
+* kpilot/kpilotDaemon.cc
+ Sneaking in the QStack<> stuff just under the wire was a bad idea.
+ Fixed an uninitialized pointer bug.
+* kpilot/hotSync.cc
+ Fixed missing syncDone() signal in FileInstallAction; added some
+ logProgress() calls, extra debugging.
+* kpilot/kpilot.cc
+ Added KillDaemonOnExit logic to KPilotInstaller.
+
+2001-09-23 Adriaan de Groot
+* kpilot/uiDialog.{h,cc}
+* kpilot/kpilotConfigDialog.{h,cc}
+* kpilot/kpilotConfigDialog_base.ui
+ New files -- the .ui file is from David Bishop -- re-implementing the
+ configuration dialog using modern technology. uiDialog.{h,cc} are
+ abstract base classes, suitable for reuse. kpilotConfigDialog.{h,cc}
+ contains the behavior of the dialog, and the .ui file the UI.
+* kpilot/kpilotConfig.{h,cc}
+ Switched around #ifdef and #ifndef. This disabled setting debug levels
+ in code with debugging on. Duh. Getting it right then showed all kinds
+ of bugs in the other code. Added some documentation explaining possible
+ crashes due to missing KApplication instance.
+ FINALLY did something sensible about code duplication -- added get and
+ set methods to a subclass of KConfig for all KPilot settings.
+* kpilot/kpilotOptions.{h,cc}
+ Is deprecated and removed. Say hello to the new world of .ui files.
+* kpilot/kpilot.{h,cc}
+* kpilot/memoWidget.cc
+* kpilot/addressWidget.cc
+* kpilot/conduitSetup.cc
+ Lots of little changes to reflect the KPilotConfig changes. Mostly
+ removing calls to setGroup() and readEntry(), which are now safely
+ encapsulated.
+* kpilot/pilotDaemon.{h,cc}
+* kpilot/pilotDaemonDCOP.h
+ Removed cruft, adapted to KPilotConfigSettings, and adapted to SyncActions.
+ Changed silly startHotSync(int) DCOP method to requestSync(int).
+
+
+2001-09-21 Adriaan de Groot
+* kpilot/hotSync.{h,cc}
+ Added an InstallFilesAction class, to run during a HotSync.
+
+2001-09-20 Adriaan de Groot
+* kpilot/kpilotlink.{h,cc}
+* kpilot/main-test.{h,cc}
+ All these files changed because of yet another re-architecting. Now we
+ have HotSyncActions, which have direct access to the PilotDeviceLink,
+ and which do "something". The test action just lists the databases
+ present on the device. This has been tested with USB and with serial
+ devices.
+* kpilot/hotSync.{h,cc}
+ Changed again to split the actions away from the device link (really,
+ how I ever decided on that is a mystery to me now).
+* kpilot/Makefile-standalone
+ A Makefile that can be tweaked, that does not use autoconf, and is
+ useful for making standalone tarballs.
+
+2001-09-17 Adriaan de Groot
+* kpilot/Makefile-kpilotConfig
+ () New file for building a standalone config program.
+* kpilot/main-config.{h,cc}
+ () New .h file, new classes for implementing some behavior. The behavior
+ is very minimal right now, but as an illustration for David (hey, now
+ he needs to learn C++ coding) it's fine.
+* TODO
+ () Thought of lots of new things to do.
+
+KPilot Developer's notes for september 16th 2001
+================================================
+
+KPilot now compiles completely again, at least on a KDE 2.1.1 platform.
+I'll check w/ KDE 2.2 as soon as I get that working here, and then we'll
+take another look at Qt3 -- I saw Cornelius has already put some changes in.
+
+2001-09-15 Adriaan de Groot
+* TODO
+ () Added a TODO file. I didn't copy all the TODO's from the ChangeLog
+ into it, though, since many make no sense right now.
+
+2001-09-13 Adriaan de Groot
+* kpilot/kpilotlink.{h,cc}
+ () Changed fTransientDevice into fDeviceType since we have lots of
+ variants to deal with.
+ () Added functions installFiles() and installFile() to handle
+ the installation (!) of files to the Pilot.
+* kpilot/pilotDaemon.cc
+ () Finally dealt with all the changed classes and methods of the
+ device link.
+ (slotEndHotSync) No need to tell the link to end the Sync, since
+ it's the one that's telling *us*.
+
+2001-09-08 Adriaan de Groot
+* kpilot/options.h
+ () I've installed RH 7.1 and gone back to KDE 2.1.1. Whee. They've
+ somehow utterly broken kdDebug() and kdWarning(). Added compile flag
+ DEBUG_CERR to make all the debugging info go to cerr instead.
+* kpilot/kpilot.cc
+ () Startup notification was added to startService...() in 2.2, so now
+ there's an #ifdef handling that case.
+
+2001-09-07 Adriaan de Groot
+* kpilot/pilotComponent.h
+ () Fixed up #ifdefs for new style
+* kpilot/kpilotlink.h
+ () Make many data members private with protected access functions.
+ (statusString) Made into a virtual function.
+
+2001-09-06 Adriaan de Groot
+
+* kpilot/Makefile.am
+ () Forgot to add logWidget.cc to kpilot_SOURCES
+* kpilot/kpilotOptions.cc
+ () Added more tooltips, switched most to <qt></qt> rich text.
+ () Changed default value for SyncFiles to true.
+* kpilot/kpilotlink.{h,cc}
+ () Added new state CreatedSocket and member fRetries
+ (open) Allow for retries on pi_bind(), since it may fail on
+ USB style devices.
+ () Added ASSERT() and member fDeviceLink to enforce singleton=ness.
+* kpilot/main-test.{h,cc}
+ () Added ASSERT() to enforce singleton-ness.
+* kpilot/hotSync.{h,cc}
+ () New files, containing most of the old HotSync code from
+ kpilotlink.{h,cc}, now using the new KPilotDeviceLink base class.
+
+KPilot Developer's notes for september 5th 2001
+===============================================
+
+It's tough keeping this ChangeLog up-to-date, since I'm doing
+lots of work but not committing much to CVS. But I'll try to
+keep things documented nonetheless.
+
+
+2001-09-05 Adriaan de Groot
+
+A new application, kpilotTest, has been added. It does a very basic
+test of the pilot-link library and some device handling for KPilot.
+It is *not* installed by default, since it's pretty much useless for
+normal use, but useful to get some feedback about whether the
+new architecture works as expected.
+
+A new widget, LogWidget (logWidget.{h,cc}) is now included for, yup,
+logging stuff. It's used to long things during a sync.
+
+pilotListener is no longer built or needed.
+
+A new application, kpilotConfig, has been added. It is not installed
+by default. It just calls up a config dialog for KPilot, much like
+kpilot --config does. It's useful mostly because it exercises a clear
+subset of the code.
+
+I've tooltipified (?) the whole hardware setup dialog. I think it really
+needs more work, since the distribution of options is really unclear.
+And why are exactly *these* things grouped together? The "Address" tab
+really should go.
+
+The compilation of everything besides kpilotTest and kpilotConfig
+is now seriously broken (tm).
+
+KPilot Developer's notes for september 3rd 2001
+===============================================
+
+Hoo doggies. This is a *big* set of changes. I finally sat down
+to do some of the serious rework that KPilot has been needing for
+a long time. In essence:
+
+* Use DCOP for as much communication as possible, and
+* Support USB devices and other transient device nodes.
+
+Basically PilotDaemon and KPilotLink have been completely rewritten.
+
+What more is there to say? Almost every file has changed, even the
+coding guidelines have been relaxed (I'm not going to put #ifdefs
+around #include anymore, not since it turns out that the gnu cpp
+handles this situation efficiently anyway).
+
+Comments and documentation in most files have been vastly improved.
+
+
+KPilot Developer's notes for august 27th 2001
+=============================================
+
+Hm. Long time no notes. Which is not to say that nothing happened,
+since while I was away at a conference in Finland I dropped in at
+Marko G's place (see patches listed way down below) and we had a great
+time talking about KPilot, hacking, etc. I forget what I patched
+there, though.
+
+2001-08-27 Adriaan de Groot
+* kpilot/addressWidget.*
+ Fixed up Martin's patch to make it comply with the KPilot coding
+ style, added some more docs, did a bunch of re-layouting. I read
+ somewhere that there is a direct correlation between shoddy indenting
+ style and bug density.
+* kpilot/pilotDaemon.h
+ Added a missing class declaration for KServerSocket.
+* kpilot/kpilot.{h,cc}
+ Removed all remaining KPilotLink cruft. KPilot now communicates with
+ the daemon through DCOP only.
+
+Still very much on the TODO list:
+- actually make the daemon quit when that's relevant
+- ditch pilotListener (backport from kitchensync)
+
+KPilot Developer's notes for august 2nd 2001
+============================================
+
+Vacation good. Bugs bad. Received a wonderful patch in the mail from
+Martin Junius, which proves once again that he's really dedicated to
+making KPilot look good and work well. Martin's patch "pushes the envelope"
+udirng the freeze, so it may not get in into KDE 2.2.
+
+2001-08-01 Adriaan de Groot
+
+* kpilot/pilotDaemon.cc
+ (PilotSystemTray) Fix for bug #29764 -- I'd forgotten to initialize some
+ pointers in the constuctor again.
+* conduits/abbrowser/abbrowser-conduit.cc
+ (main) Workaround for bug #28104 allowing abbrowser to start from the conduit.
+* conduits/abbrowser/Makefile.am
+ Minuscule change enabling --enable-final builds here.
+
+2001-07-23 Martin Junius <[email protected]>
+
+* kpilot/addressEditor.cc (MakeField, MakeFieldL): removed i18n(),
+ now done in initLayout().
+ (initLayout): use i18n() for label strings passed to
+ MakeField. This is IMHO a cleaner approach than using I18N_NOOP()
+ as before.
+ (phoneLabelText): new function, get text for phone label,
+ basically fAppInfo->phoneLabels[] featuring some sanity checking.
+ (fillFields): use phoneLabelText().
+ (initLayout): dito.
+ (initLayout): argument addressInfo removed, no longer needed.
+
+2001-07-21 Martin Junius <[email protected]>
+
+* kpilot/addressEditor.cc (initLayout): use m_phoneLabel[] for
+ display phone labels because this change from entry to entry and
+ cannot be set to fixed texts.
+ (fillFields): update phone labels for editor dialog.
+ (initLayout): reworked and hopefully ;-) improved spacing.
+
+* kpilot/addressWidget.cc (setupWidget): replaced QMultiLineEdit
+ with QTextView for address info widget.
+ (slotShowAddress): function totally rewritten to use QTextView
+ and the Qt pseudo-XHTML code for formatted display of the
+ address entry. The sequence and formatting is more or less what
+ my Palm IIIxe does.
+
+KPilot Developer's notes for june 15th 2001
+===========================================
+
+The 2.2b1 tarballs are packaged real soon now. Whee!
+This marks the release of KPilot 4.2.3 (KDE 2.2, third
+subpackage release (alpha1, alpha2, beta1)). This version
+scheme makes it much easier to keep track of what was
+released when.
+
+Many bugs were fixed after Cornelius sent a message
+asking about the KPilot code; the abbrowser conduit
+has been renamed the KAddressBook conduit (it's still in
+conduits/abbrowser), some little stuff in the vcal conduit
+was fixed, much dead code was removed from KPilot and
+some code was simplified.
+
+Cornelius' mail also somehow pushed me into reading the
+KDE-PIM server suggestions. I'm sure you've noticed how
+much mail *that* has caused.
+
+KPilot Developer's notes for june 5th 2001
+==========================================
+
+[ade]: Well, I'm back from my conference -- which was pretty neat -- and lo!
+In my mailbox are many patches to be applied. Thanks guys. This keeps
+KPilot moving forward even when all of the "regular" developers are
+doing silly things (like moving).
+
+2001-06-05 Palle Girgensohn
+
+* */Makefile.am
+ I had to tweak some Makefiles to get kpilot working on FreeBSD.
+ KPilot must include LIBPISOCK_PATH in its INCLUDES setup.
+ [Newer CVS versions already did, but I would like to note my
+ appreciation for sent-in patches that aid in portability -- ade]
+
+2001-06-02 Philipp Hullmann
+
+* conduits/vcalconduit/*.{h,cc}
+ This is a new version of my large todoconduit/vcalconduit patch,
+ hopefully more suitable for human consumption than the previous one. It
+ mostly splits the large sync functions into smaller pieces, simplifies the
+ code for recurring events a lot, and moves some more code to vcalBase.
+
+* kpilot/pilot*Entry.cc
+ ... and one more patch to PilotDateEntry and PilotTodoEntry: replace
+ notes of length 0 with empty ones.
+
+2001-05-23 Philipp Hullmann
+
+* kpilot/pilot{Date,Todo}Entry.{h,cc}
+ Many fixes realted to accidental freeing of unallocated memory
+ and some pointer ugliness. Fixes rare crashes on machines where
+ malloc() doesn't zero the memory.
+
+2001-05-25 Adriaan de Groot
+
+* *.cc, options.h
+ Simplified the debugging code, no more #ifdef DEBUG if (debug_level &)
+ stuff, just straightforward DEBUGXXX statements which get optimized
+ aay for free when debugging is turned off.
+
+
+KPilot Developer's notes for may 14th 2001
+==========================================
+
+Not a lot of movement on the coding front for me [ade]; I
+did remember mothers' day though. Changes relevant to KPilot:
+
+* abbrowser has moved into kdebase, so the abbrowser conduit will
+ now be available to everyone, not just those that also compile
+ all of kdepim.
+
+2001-05-08 Marko Gronroos
+
+* conduits/popmail/*
+ Totally revamped the mail conduits with a new, well designed
+ setup. This solves most of the smtp and sendmail problems
+ we've been having.
+
+
+KPilot Developer's notes for may 7th 2001
+=========================================
+
+It's been great to receive patches from all over the place in the
+past two weeks. What has been fixed is listed below; I have the nasty
+feeling that one set of patches has slipped through the cracks. If
+you've sent me a patch in the past two weeks and don't find yourself
+listed here, please let me know.
+
+2001-04-27 Adriaan de Groot <[email protected]>
+
+* I actually worked on the docs. Stephan Kulow's meinproc
+ HTMLizer was wonderfully useful here. The docs aren't
+ completely up-to-date yet, but they're moving.
+
+2001-04-28 Martin Junius <[email protected]>
+
+* kpilot/kpilot.cc
+ (initMenu): use KToggleAction and setExclusiveGroup for view menu.
+ (addComponentPage): same here for the other components.
+ (initMenu): setChecked for view_kpilot action.
+
+2001-05-07 Philipp Hullmann
+
+* conduits/vcalconduit/todo-conduit.cc
+ (): fixed missing due-date bugs
+
+
+
+
+
+KPilot Developer's notes for april 26th 2001
+============================================
+
+Ahh, spring is in the air; the time when a young man's mind turns
+to nights of C++ hacking. This has been a great few weeks for open-
+source collaboration. I've had useful and helpful mail from Philipp
+Hullmann, Martin Junius, and Marko Gronoos (maybe more -- if i've
+forgotten you please complain privately) with patches, hints, and
+offers of help. Thanks guys!
+
+* Fixed the non-initialization of the conduitCombo pointer by
+ removing it completely. (Thanks Martin!) At compile-time you can
+ choose between XML and traditional UI style. [19-4]
+* Greg's abbrowser conduit is (almost) ready for the prime-time! [23-4]
+* Fixed bug where absent executables could hang the conduit
+ setup dialog. [23-4]
+* Fixed small UI bug where toggling toolbar didn't resize the contents
+ of the main KPilot window. [23-4]
+* Removed unnecessary connection to (serial) pilot database when
+ conduits are started in --info or --setup mode. [23-4]
+* Discovered many i18n bugs in the sendmail conduit. Ouch. Some fixed. [23-4]
+* In a flash, implemented sending-via-KMail in the sendmail conduit.
+ This is utterly untested and possibly hazardous. I'd appreciate it
+ if some people used a test account for KMail and tried it out.
+ I will too, soon. [23-4]
+* Looked for the right place to force KPilot conduits to use the KPilot
+ .po file. The TLs are now OK. Thanks to Marko for prodding me to sort
+ this bug out (conduit in Finnish is "siirtokanava"). [24-4]
+* Added QToolTips and buddies to the NULL conduit setup. [24-4]
+* Fixed a bug in the KMail sending if you use a different outbox
+ from "outbox". [26-4]
+* Made KPilotLink::addSyncLogEntry marginally more useful -- this
+ is to work towards a read log window. As a side effect (which
+ obscures what I've done a little) I've reformatted kpilotlink.h
+ according to the coding style guide, and added docs. [26-4]
+
+Todo:
+
+* Found out why the vcal and todo conduits are so slow -- they
+ really do read in the whole Pilot database through the serial
+ line *twice* each sync. This needs fixing. [19-4]
+* Add QToolTips to the remaining conduits. [24-4]
+* Add "buddies" to relevant entry fields (usually QLineEdits). [24-4]
+* Remove all the UI stuff from KPilotLink and put it somewhere sensible. [26-4]
+* Split KPilotLink into the client and server ends. [26-4]
+
+The following list is stuff from the ChangeLog that was once on
+the Todo list; I'm repeating it here because it was time we went
+through it again to see how things stand. I've added comments in
+[ ] after each.
+
+* Split KPilotLink into its separate functionalities: config management,
+ local database management, and link from daemon to conduits. [partly
+ done, but kpilotlink still serves both ends of a client-server link]
+* Make KPilot and KPilotDaemon communicate only through DCOP. [bad idea -
+ causes extra overhead, and the kpilotlink protocol is pretty good]
+* Add an extra message concerning NULL user on hotsync.
+* Make the progress bar show something during a conduit sync.
+* Should just use the KPilotLink::config object to store all kinds
+ of user settings instead of copying them from the config file to
+ local variables, since this is just asking for inconsistency.
+ [dunno -- as long as KPilot is the app for configuring what the
+ daemon does, we just have to get KPilot to tell the daemon to re-
+ read the config file when something changes.]
+* Clean up more of the butt-ugly parts of the code base [less of this now!]
+* KPilot is an i18n nightmare [less of this now!]
+* The password dialog in the popmail conduit is probably a very bad idea
+ I think kdesud should come into play here. [not looked into]
+* The messages need validation - Pilot vs pilot, HotSync vs whatever
+* Actually *doing* a fast sync for Heiko
+* More and better information in the progress bar
+* KPilot should display the sync log as well, just like the Pilot
+ does. This is useful for reporting the result of a sync to the
+ user (who then doesn't need to look at the Pilot)
+* I noticed Thomas Zander has submitted an official wishlist item:
+ DateBk3 (the new date book format in PalmOS3.5) support. I think
+ I'll get back to him on that when Mirko pans out with the free
+ hardware goodies from Palm :)
+
+KPilot Developer's notes for april 19th 2001
+============================================
+
+* Martin Junius has contributed an XML GUI framework for KPilot, so
+ it now finally uses the "modern" way of doing GUIs. This *does*
+ mean it's time for yet-another set of screenshots for the docs
+ and yet-another set of menus for users to get used to. [14-4]
+* Disposed of reported bug: bad category selection. [15-4]
+* Moved the todo-conduit into the vcalconduit directory. This makes
+ building much simpler. [15-4]
+* Fixed up more #include shenanigans for --enable-final. (Don't
+ forget the #ifndef conventions from HOWTO-CODE.txt!) KPilot now
+ builds without warnings with --enable-final --disable-debug. [15-4]
+
+Things to do:
+
+* Fixup the documentation.
+* Add QToolTips to the conduits setups, KPilot's setup, and the conduit setup.
+ This is already partially done, but someone else needs to finish this off.
+* Make KPilot installation and run easier -- JPilot seems to work out-of-the
+ box on systems where KPilot doesn't.
+* Look into bugs #23385 (crash in VCalConduit), #20318 (munged 8-bit chars)
+ and #24291 (doubled appointments).
+
+KPilot Developer's notes for april 8th 2001
+===========================================
+
+It seems like only yesterday that KDE 2.1.1 was out, and we're already
+in KDE 2.2b1. Thoreau said "Simplify, Simplify". Anyway, this week's
+feature creep:
+
+* Bugfix for infinite loop when changing categories. [1-4]
+* Some xpms could profitably be removed, since we use pngs now. [1-4]
+* I normalized some more header-file #ifdef / #defines. [1-4]
+* Incorporated patches from Aaron Seigo. [1-4]
+* The todo conduit didn't compile due to changes in vcalBase. [1-4]
+* The vcal conduit's test mode has been expanded. [1-4]
+* KPilot's version number has been upped (again) to 4.2.1 for the
+ KDE 2.2a1 release; I hope we can up the revision number with every
+ release of KDE 2.2 move on to KPilot 4.3 with KDE 2.3. [9-4]
+* Messed around with some of the icons and images. [9-4]
+
+
+KPilot Developer's notes for march 24th 2001
+============================================
+
+KDE 2.1.1! With bugfixes and translation fixes! So only some of the
+bugfixes listed under march 10th have made it into there. On the
+western front though, we have:
+
+* Chris Molnar has started work on DB integration for the expense conduit,
+ so that you can actually do something useful with it. The CSV export seems
+ to be done, too. Thanks Chris!
+* Greg Stern has pretty much finished the abbrowser conduit (which a *lot*
+ of people have wanted for a long time). It hasn't been committed yet, but
+ will be soon.
+* The memo viewer has been very slightly beautified.
+* Some work for bugs #22112 and #21908, fixing deficiencies in the todo-
+ conduit and in selecting categories under other locales. This isn't
+ done yet, though -- some attempts have been checking into CVS for testing.
+
+
+KPilot Developer's notes for march 10th 2001
+============================================
+
+This weeks "cleanup" action is to normalize the #ifdef thingies in
+the header files so that they follow some kind of plan. And then reduce
+the number of #includes actually included by adding #ifdefs areound most
+of them, to prevent redundant #includes. This is a pain, but some say
+it's worth it in compile time. (See Documentation/HOWTO-CODE.txt for info).
+
+* Removed yet another silly struct tm issue. [4-3]
+* Added FileInstaller to KPilotDaemon. [4-3]
+* Added DCOP to KPilot. Files dropped on daemon show up in KPilot. [4-3]
+* Added a #define KPILOT_VERSION to unify all the version strings. [5-3]
+* Added Documentation/HOWTO-CODE.txt for the source code conventions. [5-3]
+* Fixed a bunch of Solaris compile issues. [5-3]
+* Factored out a bunch of generic vcal code from the vcal conduit into
+ a new base class VCalBaseConduit; the todo conduit also inherits from
+ there. [10-3]
+* Yet another stab at the "latin1 chars munged in KOrganizer" bug. [10-3]
+
+The double-sync problem still exists though, which is bad. I suspect that
+some extra bytes are left waiting in the serial port queue after slotEndSync
+but I haven't got that sorted out yet.
+
+The web-site has been updated, finally, which means you can finally check
+for new releases and info there again:
+
+ http://www.slac.com/~pilone/kpilot_home/
+
+And, I've started to use KDevelop 1.4 for maintaining KPilot. I'm still
+making the transition from vi / make / 4 konsole windows, but so far I've
+been mostly pleased by the effect it has.
+
+Bugs that are still open in the bug database: (Dan? you bored?)
+
+* Todo conduit doesn't take due dates into account
+* Double sync
+* Address edit window doesn't follow addressDB custom fields & layout
+
+Things to think about:
+
+* Usability. I've swept all the menu items into one "File" menu that
+ contains two configure wrenches, 4 actions, and a quit button. I'm
+ wondering whether this is the right way to go or whether separate
+ "file", "sync" and "conduit" menu items would be better.
+
+
+
+KPilot Developer's notes for march 4th 2001
+===========================================
+
+So after "the big cleanup" I've continued doing cleanup code in smaller
+chunks with more commits, mostly for reasons of bug-tracking. Dates in []
+indicate when the fix or change was committed.
+
+* Removed a really stupid crash from KPilotConfig::fixed(). [23-2]
+* The internal conduits' names weren't reported properly anymore. This
+ is a binary and source incompatible change. [23-2]
+* Extra debugging while starting the listener process. [26-2]
+* Changed exit(-1) to exit(3) in the daemon. [26-2]
+* Use Qt layout classes in fileInstallWidget. [26-2]
+* Removed some null-conduit comments from the KNotes conduit. [26-2]
+* Removed some #include <getopt.h> for Solaris. Cleaned up other
+ includes as well, just a little. [26-2]
+* Started a change to KActions. [ 1-3]
+* Added a new FileInstaller for use in the daemon and the widget. [ 1-3]
+ It's currently only used by the widget.
+* Added listItems.{h,cc} in response to bug #21392; changed address
+ and memo widgets to use them. [ 4-3]
+
+KPilot Developer's notes for february 19th 2001
+===============================================
+
+Yay! KDE 2.1 is out. Which means we can commit all kinds of changes
+to KPilot again, not just well-thought-out bugfixes. That means that
+we can get to work on cleaning up the code base again.
+
+* Split all the config-file stuff out of KPilotLink into a new class
+ KPilotConfig. Fixed all the resulting include dependencies.
+* The function fixed() in KPilotInstaller obviously belongs to KPilotConfig.
+* The {address,memo,fileInstall} widgets all had unnecessary dependencies
+ on KPilotInstaller. Removed. KPilotInstaller now adds the widgets it
+ creates itself.
+* Removed as many dependencies on kpilot.h and kpilotlink.h as possible.
+* Removed a bunch of char[] buffer stupidities from pilotLocalDatabase &c.
+* Removed the database open and close functions from kpilotlink.
+
+All the sensible fixes, like those listed under feb. 4th, will come later.
+
+KPilot Developer's notes for february 4th 2001
+==============================================
+
+Nick Papadonis spent hours tracking down the vcal conduit crash and
+we found at least one bug in kpilotlink. It's been removed and I
+hope this quashes all the vcal crashes. Other than that there's simply
+not much we *can* do with the message and feature freeze and all.
+This is why the todo-immediately-after-freeze list exists:
+
+* Split KPilotLink into its separate functionalities: config management,
+ local database management, and link from daemon to conduits.
+* Make KPilot and KPilotDaemon communicate only through DCOP.
+* Add an extra message concerning NULL user on hotsync.
+* Sort out all the icon issues.
+* Make the progress bar show something during a conduit sync.
+
+
+
+KPilot Developer's notes for january 6th 2001
+=============================================
+
+Happy Millennium. I ([ade]) am off on a two-week vacation to
+Calgary, so no KPilot news from me till (almost) february.
+
+There have been several troublesome bugreports this week,
+ranging from "all the conduits crash" to "daemon dies on
+hotsync." That don't make me happy at all.
+
+
+Done this week:
+
+* Built POSE, the Palm Emulator, so this may help in testing
+ stuff for the OS versions that I don't actually have.
+ POSE is a real $#*%^ to build, but I can now actually use my
+ PalmV on-screen (with a PalmIII skin, which is kinda weird).
+* Replaced the addressEditor widget with something less stone-age.
+* Added a nifty feature so that you can edit one address in two
+ windows and they keep semi-in-sync. abbrowser doesn't have this
+ (which means abbrowser has a bug :( ).
+* #&$%#$ conduitApp doesn't turn the GUI on by default, so recent
+ vcal crashes can be blamed on trying to create a KMessageBox without
+ a GUI :( Changed the default values.
+* Tried fixing some ugly icons. I'm no artist though.
+* Teeny-tiny layout change in Address page of setup dialog.
+* If you try to add records to the address book before you've done
+ a HotSync / Backup KPilot has an empty AddressDB and doesn't deal
+ with the address very well. Added a sorry() there.
+* Added a doTest() to vcal-conduit.
+* More cleanups in the debugging code. There's still a weird mix of
+ code controlled by --debug and kdebugdialog style stuff. Functions
+ kdWarning() and kdError() should be given __FUNCTION__ as their
+ << argument, while kdDebug() should get fname as first argument.
+ This will make all the debugs optimize away painlessly while keeping
+ the warnings and error messages. Since messages may change status some
+ time there's now a #define TEST_DEBUG that makes fname a weird object
+ that can only be passed to kndbgstreams. So sensible combinations are:
+ production: NDEBUG defined, DEBUG undefined, TEST_DEBUG undefined
+ test nodebug: NDEBUG defined, DEBUG undefined, TEST_DEBUG defined
+ testing: NDEBUG undefined, DEBUG defined, TEST_DEBUG defined
+* Actually KPilotLink::doFullBackup wasn't all that bad. Still, all the
+ code needs going-over for i18n yuckiness. doFullRestore() was worse;
+ also fixed up directory yuckiness.
+ Note to self: text for user is i18n()ed, kdDebug() &c. is in
+ english ('cause Dan or I have to read it :) )
+* Finished integrating Heiko's patches. I believe that both HotSync and
+ FastSync now do what the ought to do.
+* Started adding a DCOP interface to the daemon.
+
+
+Other stuff:
+
+* It's a HotSync and a Pilot. I'll change strings in the source as
+ I come across them. As for conjugations: I HotSynced, it HotSyncs.
+
+Todo:
+
+* Should just use the KPilotLink::config object to store all kinds
+ of user settings instead of copying them from the config file to
+ local variables, since this is just asking for inconsistency.
+* Close bug 16457.html in some way.
+* More vcal work
+* Clean up more of the butt-ugly parts of the code base (less of this now!)
+* Tell the KOrganizer docs people about KPilot
+* KPilot is an i18n nightmare
+ - The const char *s in the pilot databases can be addressed most
+ easily, I think.
+ - get rid of most of the strcpy, strcat, etc. But not all!
+ We're stuck with pilot-link, after all.
+* The password dialog in the popmail conduit is probably a very bad idea
+ I think kdesud should come into play here. Anyway, a KMail conduit would
+ be much cooler and safer. Sigh.
+
+
+Things-to-be-considered:
+
+* Splitting kpilotlink up into its various functionalities
+
+
+KPilot Developer's notes for december 30th 2000
+===============================================
+
+Ho ho ho. Merry Christmas. Happy new year. Last week started out
+with Thomas Zander reporting that he *still* has the totally bizzarre
+and inexplicable crash in KPilot that he's had ever since KPilot was
+ported to KDE2 (+). That pretty much colors this week's work. The rest
+of the week was used for the KNotes conduit. After a pleasant exchange
+of ideas with Wynn Wilkes (of KNotes) we got a DCOP interface working and
+this make the KNotes conduit more useful. Talked to Greg about the
+kab conduit and he's enthusiastic about the possibilities there,
+we hope to have a framework in CVS soon.
+
+Done:
+
+* Claimed some debug areas (5510,5511,5512).
+* KNotes rereads the notes dir after a sync, so new notes (which
+ have come from Pilot memos) appear there.
+* KNotes conduit --test now displays all the notes (on screen) that
+ knotes shares with the pilot. This is a test (!) of the DCOP stuff,
+ mostly.
+* KNotes conduit now has a checksum function (md5) to reduce the
+ number of notes that has to be copied between KNotes and the
+ Pilot.
+* Applied Dag Nygren's vcal patches so that repeating events now
+ show up in KOrganizer properly.
+* Fixed the button-enabling in the address app
+* Added more debugging output for Thomas.
+* Added more debugging output for Nick.
+
+Todo:
+
+* More vcal work
+* Clean up more of the butt-ugly parts of the code base
+* Tell the KOrganizer docs people about KPilot
+* KPilot is an i18n nightmare
+ - The const char *s in the pilot databases can be addressed most
+ easily, I think.
+ - KPilotLink::doFullBackup should cause i18n people to run away
+ - get rid of most of the strcpy, strcat, etc. But not all!
+ We're stuck with pilot-link, after all.
+* The messages need validation - Pilot vs pilot, HotSync vs whatever
+* The password dialog in the popmail conduit is probably a very bad idea
+
++ Thomas' crash produces the following (partial) backtrace:
+
+#4 0x408960b7 in read_png_image () from /usr/kde2/source/qt-copy/lib/libqt.so.2
+#5 0x40838dd9 in QImageIO::read () from /usr/kde2/source/qt-copy/lib/libqt.so.2
+#6 0x40836cf1 in QImage::load () from /usr/kde2/source/qt-copy/lib/libqt.so.2
+#7 0x408305b2 in QImage::QImage () from /usr/kde2/source/qt-copy/lib/libqt.so.2
+#8 0x40483fcf in KIconLoader::loadIcon () from /usr/kde2/lib/libkdecore.so.3
+#9 0x805a166 in KPilotInstaller::initIcons ()
+
+ which is weird since the only possible png image being read is the
+ quit icon, which is standard in KDE2. Maybe some weird combo of options?
+
+KPilot Developer's notes for december 18th 2000
+===============================================
+
+It looks like kdepim and KPilot aren't going to make the 2.1 release.
+Darn. This does give us more time to deal with docs and bugfixes.
+Every time I get something done though I find I've discovered two
+new things to do :(. I hope Lukas will help out with a lot of the
+i18n stuff though.
+
+Done:
+
+* Moved all the (english) docs to the correct place.
+* More doc fixes: use &kpilot; and &pilot; properly, added screen shots for
+ various conduit setups. The docs still aren't complete but they're a
+ darn sight better than they were.
+* Modal dialogs need exec() instead of show()
+* Changes in kdelibs caused some dialogs to hang in slotCancel()
+* Changes in includes means we have to include kdebug.h ourselves
+* Get rid of cerr and use kdDebug or kdWarning or kdError as appropriate.
+ There are still a very few cerrs left in places where we can't rely on
+ kdDebug().
+* Added #ifdef DEBUG to the debug sections of code. So KPilot now compiles
+ without debugging stuff. I realise now that I should have stuck to the
+ KDE kdDebug() guidelines, but, um, I didn't know they existed when the
+ port from KDE1 to KDE2 started. Darn.
+
+ToDo:
+
+* More vcal work
+* Clean up more of the butt-ugly parts of the code base
+* Detect memo-too-large in knotes conduit
+* Try to reduce number of updates in knotes conduit
+* Figure out a nice DCOP interface with Wynn (KNotes)
+* Finally take a look at kab or whatever for the address book conduit.
+ Should probably talk to Greg about this one too.
+* Tell the KOrganizer docs people about KPilot
+* Fix the button-enabling in the address app
+* KPilot is an i18n nightmare
+ - The const char *s in the pilot databases can be addressed most
+ easily, I think.
+ - KPilotLink::doFullBackup should cause i18n people to run away
+ - get rid of most of the strcpy, strcat, etc. But not all!
+ We're stuck with pilot-link, after all.
+* The messages need validation - Pilot vs pilot, HotSync vs whatever
+* The password dialog in the popmail conduit is probably a very bad idea
+
+
+KPilot Developer's notes for december 10th 2000
+===============================================
+
+Lots of internal stuff going on:
+
+* The sense of the debugging flags was the wrong way around,
+ so using --debug 4 gave you all the UI debugging messages
+ as opposed to just the major and minor ones. This is what
+ you get from suggesting debug 1023 all the time.
+* BaseConduit had some weird debugging output -- not controlled
+ by --debug -- so patched that up. And there was ugliness in the
+ icon loading function. This changes the interface to BaseConduit
+ slightly, 3rd party conduit authors beware.
+* Finally fixed up the Makefile.ams for the standard conduits so
+ that they run properly (without setting LD_LIBRARY_PATH).
+
+Visible changes:
+
+* Fixed up the documentation, the screenshots, the descriptions of the
+ conduits, etc. etc. It's still not complete but at least it matches
+ what happens when you run KPilot.
+
+Still on the todo-list:
+
+* Really fix the vcal conduit. I've patched some things up and once
+ again I hope it works, but since I can't reproduce the error I'm
+ a little stuck here.
+
+Still on the wish-list:
+
+* Actually *doing* a fast sync for Heiko
+* More and better information in the progress bar
+* The PilotMemo class is butt-ugly and filled with weird C-string
+ manipulations.
+* KPilot should display the sync log as well, just like the Pilot
+ does. This is useful for reporting the result of a sync to the
+ user (who then doesn't need to look at the Pilot)
+* I noticed Thomas Zander has submitted an official wishlist item:
+ DateBk3 (the new date book format in PalmOS3.5) support. I think
+ I'll get back to him on that when Mirko pans out with the free
+ hardware goodies from Palm :)
+
+
+KPilot Developer's notes for december 2nd 2000
+===============================================
+
+Almost Sinterklaas, so I'd like to wish all the KPilot users in
+.nl a Happy Sinterklaas en Weg met de Kerstman.
+
+UI Changes:
+
+* Added Heiko's Fast-Sync icon .. but it's ugly and hard to
+ distinguish from the regular icon. This needs fixing by an artist.
+* Added an ugly restore icon as well.
+* Added an undocumented config-file option. You can now add the
+ following line to kpilotrc in the null group if you really want to:
+
+ ToolbarIcons=list
+
+ where list is a comma-separated list of icons to appear on the
+ KPilot toolbar. You can choose from HotSync,FastSync,Backup and
+ Restore. The standard setting is:
+
+ ToolbarIcons=HotSync,Backup
+
+ That's not a lot but it should keep Heiko happy for a while and
+ it reminds us that we should move towards a more modern method
+ of setting up the UI -- or not?
+* Tried to fix some UI weirdneses like:
+ - Delete Memo button enabled when no memo selected
+ but QListBox has the nasty habit of always having *something*
+ selected, even if you can't see what it is.
+
+ Now I know that the internal conduits -- memoWidget and addressWidget
+ will probably die out soon when we have a real working kab2 conduit
+ as well as a KNotes conduit, but till then it's nice to have something
+ that at least obeys basic UI design rules.
+* The following bugs in QListBox and QListView made me ditch the old
+ two column layout with movement buttons for something else. Let me
+ know which one you prefer.
+ - There is some *bizzarre* behavior in the handling of
+ conduits being selected: select the top item in
+ the left column, the top item in the right column
+ (um, so install a conduit first) and then the top
+ item in the left column again.
+ The new layout allows you to drag conduits from one state (available)
+ to another (active). Click on a conduit to set it up -- you may have
+ to doubleclick depending on you KDE settings.
+
+
+Internal Changes:
+
+* Conduits that crash no longer hang KPilot and the entire sync.
+* Made a lot of static const int members of various classes
+ enum values instead, and added a function write() to CStatusMessages
+ for a clean way to write status messages to the link.
+* Replaced several if else if ... constructions with switch()
+* Added a sensibleTitle() and shortTitle() to PilotMemo for use
+ by the KNotes conduit (and maybe others)
+
+Documentation:
+
+* Spent a little time on the (english) documentation and brought a few
+ parts of it back up-to-date. It needs up-to-date URL's, probably we
+ should move the mailing list to [email protected], and we need new
+ screenshots.
+
+Wishlist:
+
+* More and better information in the progress bar
+* The PilotMemo class is butt-ugly and filled with weird C-string
+ manipulations.
+* KPilot should display the sync log as well, just like the Pilot
+ does. This is useful for reporting the result of a sync to the
+ user (who then doesn't need to look at the Pilot)
+
+KPilot Developer's notes for november 25th 2000
+===============================================
+
+Spent most of the week at a conference, but managed to get
+the KNotes conduit almost fully functional. New memos (KNotes)
+are copied to the desktop (Pilot). Memos changed on the pilot
+are changed on the desktop. However, not all deleted memos are
+deleted on the other side, nor are modified memos copied
+from the desktop to the Pilot.
+
+I don't know what the desired action for KPilot is in the
+cases of deleted memos. Any suggestions? There's now a config
+option in the KNotes conduit setup, but maybe that should be
+subsumed by the global Local Overrides Pilot setting. Anyway,
+if a memo is deleted on the Pilot the corresponding KNote is
+deleted as well.
+
+If KNotes is running and the KNotes conduit makes changes,
+these aren't picked up by KNotes. There are also some
+obvious race conditions caused by the conduit writing KNotes
+config files. This basically means that we need to talk to
+the KNotes maintainer to resolve these coordination problems.
+
+As for the code, I wrote this:
+ class KNotesOptions : public setupDialog { Q_OBJECT
+ protected: static const QString KNotesGroup; };
+[with better layout, of course] But there's a static QString
+there, and I read somewhere that Static Objects Are Evil (tm).
+I could use a const char * there, since it's just the name of
+a group in the config file, but what's the consensus on things
+like this?
+
+I did handle some more of Heiko's patches. From last week's list:
+ - Some phone number magic I don't understand yet
+ - Some changes in the address import function
+ - getShowPhone() -- don't understand that yet either
+ - Fix bad repeat-n-times handling in vcal-conduit
+This leaves just the Fast Sync capability still unimplemented.
+
+Given the release schedule that has been discussed recently
+(and we really do want to have KPilot in KDE 2.1, so as to add
+a nifty feature to the desktop as a whole) I think feature creep
+should be abandoned for the time being and we should try to
+fix as many bugs in what we have before the release (around the
+middle of december, IIRC). This means testing, lots of it. So
+people, take the plunge, give it a try, compile the latest kdepim
+CVS stuff with KPilot in it and then complain when your Pilot
+catches fire, OK? O yeah .. when you *do* give it a try, make
+sure you do something like:
+
+ $ export LD_LIBRARY_PATH=$QTDIR/lib:
+ $ kpilot --debug 1023
+
+To make sure none of the conduits crashes with library loading
+problems and with all the debugging messages turned on.
+
+
+KPilot Developer's notes for november 19th 2000
+===============================================
+
+Fixes:
+
+* Added most of Heiko's patches to the vcal-conduit
+* Added convention to conduits --info handling: return "<none>" for
+ no databases. Handled in conduitSetup as well.
+* Made some minor changes to the info page presented in dialogs
+ (generally the setup dialog of a conduit) so that it gracefully
+ handles weird settings and handles its own resizing properly.
+* Added some const-qualifiers to various char *s
+* Add a "kill daemon on exit" feature -- there was already some code
+ for this, but not complete.
+* Changed all the boolean config entries to booleans as opposed to
+ 0-or-1 ints.
+* Removed all the "const char * id defined but not used" warnings
+* Added some extra robustness in PilotDaemon::setupConnections
+* Made the daemon obey the "show in system tray" setting -- this was
+ broken during the first port to KDE2
+* Handle reconfiguration through the settings dialog properly --
+ at least KPilot picks up the changes to "Kill Daemon on Exit"
+* (re)Added --test option to conduits, though not all of them
+ will support actual tests.
+* KNotes conduit is now functional in the sense that notes you write
+ on your desktop are in fact copied to the Pilot.
+
+Some general comments:
+
+* Suggestion: call the desktop files for conduits
+ conduit-pilot-appname.desktop
+ and the conduit executables themselves
+ conduit-pilot-Appname
+ This at least gives conduits some consistent naming scheme and
+ the addition of -pilot leaves some namespace for conduits for
+ other PDA's.
+
+ Well, actually this naming scheme isn't much good. But we *do*
+ need to think about how to handle sync-programs for various
+ PDA's in a nice fashion -- I can imagine having a Nokia phone,
+ a Psion and a Pilot and wanting to sync them all.
+
+Still on the todo-list:
+
+* Fix bad repeat-n-times handling in vcal-conduit
+* Dealing with the rest of Heiko's patches
+ - Some phone number magic I don't understand yet
+ - Some changes in the address import function
+ - Fast-sync capability (this is different from SyncLast)
+ - getShowPhone() -- don't understand that yet either
+* More and better information in the progress bar
+* The PilotMemo class is butt-ugly and filled with weird C-string
+ manipulations.
+
+
+KPilot Developer's notes for november 14th 2000
+===============================================
+
+Lots of things have changed in the class hierarchy.
+
+* Jorg's bug in the memo-import function was handled OK in addressWidget,
+ but it seemed clumsy to deal with the same problem in two different
+ places. Moved findSelectedCategory() to PilotComponent. Added some
+ other convenience functions there for the category combo box.
+
+* The getConfig() change was very poorly done, sorry about that.
+ Added some (semi-) bizarre debugging functions into options.{h,cc}
+ that are #ifdeffed out.
+
+* Ditched all the #ifdef KDE2 stuff and dropped the KDE1 backport.
+
+* Added a .desktop file for the NULL conduit (with some translations
+ of my own)
+
+* Added Qt2 layout code to the address and memo widgets so that they
+ become easier to i18n() (ie. they display properly when the string
+ lengths change).
+
+* Adopted some of Heiko's patches:
+ - New feature ForceFirst causes every conduit to behave
+ as if FirstTime=true every time (this is off by default,
+ which matches previous behavior)
+ - New feature SyncLastPC causes a slow sync if the Pilot
+ is synced with a different PC than the last time it
+ was synced (this is on by default, matching old behavior)
+ - "fixed" font in address and memo editor replaced by the
+ user's system preference
+ - In some cases the title (first name+last name or something
+ similar) in an address was empty. This now gives the title
+ [unknown]
+ - Similar for memos
+
+Let's sum up the current wishlist:
+
+* KNotes conduit
+* Dealing with the rest of Heiko's patches
+ - Proper multi-day appointments in the vcal conduit
+ - Some phone number magic I don't understand yet
+ - Some changes in the address import function
+ - Fast-sync capability (this is different from SyncLast)
+ - getShowPhone() -- don't understand that yet either
+ These patches are quite useful but it takes a lot of work to
+ unsnarl them, which is why they're taking so long.
+
+
+
+Developer's notes for november 9th 2000
+=======================================
+
+What's new? Lots of little bugs found by code review, some new (trivial?)
+features. KPilot 4 is in Mandrake cooker so it receives a little more
+attention now than before.
+
+* Jorg Habenicht found a bug in the memo-import function. It causes
+ array-bounds overruns. The same bug was present in many other parts
+ of the memo widget. I think I got them all.
+
+* Added some robustness checking in the daemon to cover weird cases
+ like running conduits by hand.
+
+* Added better handling of the "first time" dialog in the vcal conduit.
+
+* The NULL-conduit now has an extra configuration field "Databases" which
+ you can attach it to. This allows you to do a bogus conduit sync with
+ a database (almost equivalent to putting it in the "backup only" entry
+ of the global KPilot settings, except you run the external conduit.
+
+* Made KPilotLink::getConfig return a reference instead of a pointer, to
+ avoid new()ing and delete()ing the config data structure all the time.
+ I hope this increases consistency as well. This has caused lots of
+ little type changes throughout the conduit system, so third-party
+ conduit authors beware :) -- all the changes cause compile failures though.
+
+* Jorg brought in a patch so that KPilot uses the pilot-link environment
+ variables to set initial values.
+
+
+Some wishlist-style items:
+
+* The memo and address internal conduits are (a) ugly and (b) impossible
+ to i18n properly, because they have hard-coded sizes. Need to spend some
+ time cleaning that up.
+
+* Really, it's time to write a conduit that syncs with KNotes. It's
+ not that hard, but KNotes has some silly bugs that need fixing first :(
+
+* A patch to introduce a notion of "fast sync" has been produced for
+ KPilot 3.2.1 -- we're now looking into how to integrate that into
+ the KPilot 4.x series. The idea is you only run a sync on the databases
+ you have a conduit for.
+
+Developer's notes for october 29th 2000
+=======================================
+
+* Thomas Zander pointed out that KPilot doesn't write a config file
+ the first time it is run, leading it to *still* believe it's the
+ first time it's run the next time. Fixed.
+
+* In PilotDaemon::setupConnections() things have been reorganized so that
+ a failure on opening the Pilot device will not allow KPilot to start.
+
+* Added an undocumented Debug= entry to conduit's configuration, to
+ ease debugging. Conduits will have to read this themselves.
+
+* Added a "Run KPilot" menu item to the daemon.
+
+And there's some really strange behavior that I've noticed: when I run
+the setup for an external conduit -- which is a separate process --
+KPilot always "jumps in front" of that conduits setup dialog when I
+give KPilot the focus. This is very irritating.
+
+Bugs noted still remaining:
+
+* Much weirdness in conduit startup (mode must be set before running
+ the conduit's constructor, but mode wasn't set till after) has been
+ looked at but not repaired.
+
+* The vcal-conduit had trouble running a sync the first time (you really
+ should do a backup instead). We're working on this one.
+
+
+
+Developer's notes for october 26th 2000
+=======================================
+
+OK, I admit it:
+
+ code,commit,announce,test
+
+is the *wrong* way to do things. I made some mistakes in the code that
+looks up conduits in the .desktop files, so conduits *still* won't run
+with this morning's commits. This has been fixed now, and the conduits
+run. Of course, vcalconduit just SIGSEGV'ed on me, so ...
+
+This brings me to a couple of wishlist items for KPilot:
+
+* A "Cancel" button. I just clicked on Backup when I was aiming for
+ HotSync, and there's nothing I can do about it.
+
+* A timeout when running conduits so that badly behaved conduits don't
+ hang up the KPilot system.
+
+Some other minor issues have been fixed as well:
+
+* Boatloads of compiler warnings in the included .xpm files
+* Some i18n stuff
+
+And new questions raised for people who know the code (I'm thinking
+Preston or Cornelius may be able to explain):
+
+* vcal-conduit.cc line 522, what's the purpose of voStatus there?
+
+
+
+Developer's notes for october 23rd 2000
+=======================================
+
+It's been a week where I couldn't bring myself to tackle
+really big problems, like an address-book conduit for
+kab or pine. So I sat back and polished things, wandered
+through the code finding little bugs (if I was an OpenBSD
+kinda guy I'd call it a proactive code audit). This has
+led to:
+
+A whole slew of minor fixes:
+
+* Updated Help menu in main menu bar
+* Removed superfluous about tab in kpilot setup dialog
+* Fixed config-doesn't-change bug
+* Disable autostart-daemon option if .desktop file unavailable
+* Added quit icon into file menu
+* Added hotsync and backup icons into file menu
+* Cleaned up include files in conduitSetup.h
+* Cleaned up dialog code in conduitSetup.cc for KDE2 compliance
+* Fixed conduits-not-running-during-sync bug in kpilotlink.cc
+* Fixed a minor Qt2 incompatibility in messageDialog.cc
+* Fixed some i18n issues in kpilotlink.cc
+* Replaced sprintf stuff with QString operations in kpilotlink.cc
+* Added hot-sync to file menu for consistency (it's in the toolbar)
+* Added logic in showTitlePage in kpilot.cc to reduce flicker
+
+Some remaining issues:
+
+* The icon for "About KPilot" in the help menu is the wrong one
+* We still need pretty icons for various things (like external conduits)
+
+Some questions:
+
+* Is there a memory leak with the config file in kpilotOptions.cc?
+* Do we really want to be new() and delete()ing the config file so
+ often? Perhaps getConfig() should do some caching.
+* Should we add icons for the other menu items?
+* Is there an entry iterator in KConfig so that you can iterate over
+ entries in a certain group (and possibly delete them?)
+
+Some philosophical stuff:
+
+* Maybe it's time to ditch the internal conduits altogether and work
+ on external conduits for kab and knotes? Although that would still
+ leave the file installer. Maybe a splash of the kpilot logo and then
+ an icon view of what has been dropped into the file installer?
+
+
+
+As far as I can tell KPilot 4 now has the same functionality and bugs
+as KPilot 3.2.1 did (with some polishing). So you still have to be
+careful with KOrganizer. But I think the framework is sufficiently
+OK to make it worthwhile to really write some conduits for various
+KDE 2 apps. Like a kab conduit and a knotes conduit.
diff --git a/kpilot/Documentation/ConduitProgrammingTutorial/ConduitStructure.eps b/kpilot/Documentation/ConduitProgrammingTutorial/ConduitStructure.eps
new file mode 100644
index 000000000..1559b365e
--- /dev/null
+++ b/kpilot/Documentation/ConduitProgrammingTutorial/ConduitStructure.eps
@@ -0,0 +1,500 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 88 4 608 264
+%%HiResBoundingBox: 88 4 608 264
+%.........................................
+%%Creator: GNU Ghostscript 705 (epswrite)
+%%CreationDate: 2003/01/12 00:28:24
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%EndComments
+%%BeginProlog
+% This copyright applies to everything between here and the %%EndProlog:
+% Copyright (C) 2002 artofcode LLC, Benicia, CA. All rights reserved.
+%%BeginResource: procset GS_epswrite_2_0_1001
+/GS_epswrite_2_0_1001 80 dict dup begin
+/PageSize 2 array def/setpagesize{ PageSize aload pop 3 index eq exch
+4 index eq and{ pop pop pop}{ PageSize dup 1
+5 -1 roll put 0 4 -1 roll put dup null eq {false} {dup where} ifelse{ exch get exec}
+{ pop/setpagedevice where
+{ pop 1 dict dup /PageSize PageSize put setpagedevice}
+{ /setpage where{ pop PageSize aload pop pageparams 3 {exch pop} repeat
+setpage}if}ifelse}ifelse}ifelse} bind def
+/!{bind def}bind def/#{load def}!/N/counttomark #
+/rG{3{3 -1 roll 255 div}repeat setrgbcolor}!/G{255 div setgray}!/K{0 G}!
+/r6{dup 3 -1 roll rG}!/r5{dup 3 1 roll rG}!/r3{dup rG}!
+/w/setlinewidth #/J/setlinecap #
+/j/setlinejoin #/M/setmiterlimit #/d/setdash #/i/setflat #
+/m/moveto #/l/lineto #/c/rcurveto #
+/p{N 2 idiv{N -2 roll rlineto}repeat}!
+/P{N 0 gt{N -2 roll moveto p}if}!
+/h{p closepath}!/H{P closepath}!
+/lx{0 rlineto}!/ly{0 exch rlineto}!/v{0 0 6 2 roll c}!/y{2 copy c}!
+/re{4 -2 roll m exch dup lx exch ly neg lx h}!
+/^{3 index neg 3 index neg}!
+/f{P fill}!/f*{P eofill}!/s{H stroke}!/S{P stroke}!
+/q/gsave #/Q/grestore #/rf{re fill}!
+/Y{P clip newpath}!/Y*{P eoclip newpath}!/rY{re Y}!
+/|={pop exch 4 1 roll 3 array astore cvx exch 1 index def exec}!
+/|{exch string readstring |=}!
+/+{dup type/nametype eq{2 index 7 add -3 bitshift 2 index mul}if}!
+/@/currentfile #/${+ @ |}!
+/B{{2 copy string{readstring pop}aload pop 4 array astore cvx
+3 1 roll}repeat pop pop true}!
+/Ix{[1 0 0 1 11 -2 roll exch neg exch neg]exch}!
+/,{true exch Ix imagemask}!/If{false exch Ix imagemask}!/I{exch Ix image}!
+/Ic{exch Ix false 3 colorimage}!
+/F{/Columns counttomark 3 add -2 roll/Rows exch/K -1/BlackIs1 true>>
+/CCITTFaxDecode filter}!/FX{<</EndOfBlock false F}!
+/X{/ASCII85Decode filter}!/@X{@ X}!/&2{2 index 2 index}!
+/@F{@ &2<<F}!/@C{@X &2 FX}!
+/$X{+ @X |}!/&4{4 index 4 index}!/$F{+ @ &4<<F |}!/$C{+ @X &4 FX |}!
+/IC{3 1 roll 10 dict begin 1{/ImageType/Interpolate/Decode/DataSource
+/ImageMatrix/BitsPerComponent/Height/Width}{exch def}forall
+currentdict end image}!
+/~{@ read {pop} if}!
+end readonly def
+%%EndResource
+/pagesave null def
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+GS_epswrite_2_0_1001 begin
+/pagesave save store 100 dict begin
+0.1 0.1 scale
+%%EndPageSetup
+gsave mark
+K
+0 0 0 0 rf
+Q q
+880 40 5200 2600 re
+Y
+5 w
+1 J
+1 j
+K
+2418.78 2362.79 2122.43 215.332 re
+S
+2864 2440 63 63 /6D
+$C
+-3EVIp"uqN5ELN^?[CSCot>e>HM_jXp?V&3fCu2HmZ[P:9D@;0n%C7OH<:+%0E&IhlJB9uI=8N=~>
+,
+2932 2437 58 68 /1O
+$C
+,fPr)6kD=D_K6eZFQe8qk_91a60SU<2lEJ.TCeWPT""Y_s')E$s8W-!s8,Fgs0_gkC\qgqBj4l>
+D/Fs1_V"uN=K>K)=A[L$TYX7*+9~>
+,
+2999 2440 15 87 /6H
+$X
+#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-
+#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-
+#Q=u-#Q=]'zzzzz#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=~>
+,
+3026 2437 56 90 /1S
+$C
++U+!Y`"6m?4sG5I:JXbS1\9Z](skRsH?>aL-`p^glX+u<ea*88s8W,romcG^g\&82p=@d%[;B?+
+A2En8"<Q.Fef*1CCBb.i"ipZCs8W,7~>
+,
+3122 2444 48 46 /6L
+$C
+.LMgJhd;Ndc+8!;-[M\kHGaj,dSSd3.F;?%K6ek00^s[H&IK@TKH)2kmLBP>*"pp2^m;gQ/VcsQ
+Xm&4(osJPPfN;QN7t9.Jg40~>
+,
+3180 2440 6H ,
+3207 2440 55 65 /1W
+$C
+3"UXos8W-!s8W-!s8W-!s8W-!s8W,rs8N&qm=*X`9-OiapgJLR$$JMaCUMmTY/5uKUhE:~>
+,
+3274 2440 6H ,
+3292 2437 35 83 /6P
+$C
+.Ktq8KaY&rJp]/"s8W-!s8W-!s8W-!s8W-!oAQ,;q:$els8W-!qu~>
+,
+3326 2419 74 6 /2A
+$C
+/dI=7J,~>
+,
+3401 2440 15 87 /6T
+$X
+#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-
+#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-
+#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=u-#Q=~>
+,
+3427 2440 6H ,
+3454 2437 60 90 /2E
+$C
+-3]Y7`"6tk+S\7pqL(Q"6o!"!6nlUlD[H'mS(%*'qYPU9qpYTFpJ:hhs8W,m^Xr>Ns%@iIf%7(Q
+g?gFJYeoHDi6MUV`Hpop\8/=Y@;s*GTm6V;s8W-!s8RT~>
+,
+3521 2440 88 65 /6X
+$C
+3"Vkk8VI-Ds8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VNes1@Z"^=-<#dn=DX(dY;m*#Kf+
+]nlq5=)%Q>g2"(I%0jENKb.Yp$:)QW"b6~>
+,
+3621 2437 61 68 /2I
+$C
+,6]P%3WfA5KFL6W64HlBiMq2H`5IGP,H*PoK3Ae`U`[=CrVQWls*oLp&&[`UA2[Mp)/%V,SCn>p
+nAc%M,6L\4L1H,FaX@Qb_u'Hn'E@h,XhSYYXf`LF#&"-L[;+2K$n,OMJsBbP~>
+,
+3687 2440 6T ,
+3714 2437 54 68 /7B
+$C
+.`IMM6kF<iT]%qRl-TPmd0p6KK@4[68\I86s%Dg]?D%6D@Cke)s8W,nJ,[M+9E3mlhpT"$D5FYK
+Q%g'jJlo'STrV#,L(l=>TL]~>
+,
+3774 2437 1O ,
+3841 2440 1W ,
+3907 2437 1S ,
+3974 2437 55 66 /2M
+$C
+-,l=(Ld9o'Ag2PI%o6LsNd;k!ha*86FJ!l/Vr.N(rVuots8W-!s8W-!s8W-!s8W-!s82~>
+,
+4041 2440 6H ,
+4059 2437 6P ,
+3480 2362.79 0 -215.33 S
+2418.78 1716.79 2122.43 430.664 re
+S
+2864 1970 12 87 /7F
+$X
+J+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sW
+J+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sW
+J+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+.sWJ+*~>
+,
+2889 1970 1W ,
+2956 1967 52 68 /2Q
+$C
+-,NABU'M_]E1I5/SN7pcD]t"F&8t?82m6$E-ia2]eL4NNJVK".$7$I"b&D$G$5/"++K-"VU';""
+%FrN2"G'sg93V7W$31$@IquEnXr(@ca/i;.>)'+,@6oL,@3>~>
+,
+3008 1967 6P ,
+3050 1967 2I ,
+3116 1970 1W ,
+3183 1967 7B ,
+3243 1967 59 68 /7J
+$C
+,fGl)Se,j,cu=W8:7VsBcA4(p#WG$RkrtT4qJZ"u=5LZHqYbp7$O4AtrujfqrVuQJlKc4Ydb<Qd
+[aNf4%4_i5@)6YZX&]t6@7(A1'U'.~>
+,
+3340 1967 1O ,
+3399 1970 36 87 /2U
+$C
+2$EsZs8W-!s8W-!s8W-!s8W-!s8V9"2uiJG:]LIprr*q"c>2k9iPE;~>
+,
+3473 1970 76 87 /7N
+$C
+4qs<8p!W0lV:,B:V>cfSYHF4!>qVK?>qbi]?g2[D?eS^WIaZqSp6O.a['l:dCQP<Km<@r@]CrjB
+^>Ek<g[4_3ID4TW\(g<DqgH39Dn"KgpA99Phf$!YmIpF*^>Ef~>
+,
+3553 1970 61 87 /2Y
+$C
+4pN20r.Q^%s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,g~>
+,
+3620 1970 6H ,
+3646 1967 2E ,
+3721 1970 58 87 /0C
+$C
+-D>qhs8W-!s8W-!s8W-!s,]1cs8W*B6GNR#s8W-!s8W+\=Z-6Z^]~>
+,
+3786 1967 2I ,
+3853 1967 7B ,
+3905 1967 6P ,
+3947 1967 1O ,
+4013 1970 36 65 /3C
+$C
+3"u>ls8W-!s8W-!s8W-!huA1UHf"LZ#7nZE6U@mT^AIB5*(,>c~>
+,
+4053 1944 54 89 /0G
+$C
+4=h%+4lQA.mRRJ8mr.*4qnE%'HLK>^TCi/]pI$G.Id6e.eb/Y%lMK2`pTLXd>M%`@Vu:O0qVIk#
+I6Y=Aol^.XlMgJ,rTgN]X8~>
+,
+2856 1829 2Q ,
+2916 1829 2M ,
+2983 1829 2E ,
+3050 1829 7B ,
+3110 1832 6T ,
+3136 1829 2I ,
+3203 1829 2Q ,
+3263 1829 2Q ,
+2065.03 1393.82 1414.97 322.97 1414.97 -322.97 S
+1003.81 855.516 2122.43 538.304 re
+S
+1349 1235 7F ,
+1374 1235 1W ,
+1441 1232 2Q ,
+1493 1232 6P ,
+1534 1232 2I ,
+1601 1235 1W ,
+1667 1232 7B ,
+1727 1232 7J ,
+1825 1232 1O ,
+1884 1235 2U ,
+1957 1232 78 91 /3G
+$C
+,/If')o3*1/dOF&cu>N\:(s?/-Lr&?F9iq>DLr>GI5aaih']%FIrq=TTAI0UIt#(XjNojOYQ+Y&
+s8UjRrSRR8YdaB"^Ugkg[[-f+]!f4CfLj%c$kfdPQ8iX0WsTc"'JQ2r8<@M8~>
+,
+2044 1232 1O ,
+2111 1235 1W ,
+2177 1232 1S ,
+2244 1232 2M ,
+2311 1235 6H ,
+2330 1232 6P ,
+2371 1232 71 91 /0K
+$C
+,@P,M.$.ic#TOuG#78b!l-TY>d/j?[#TKFhiAX@#h(MLNJ*ZKurI=kDNg4BPYcp_+6"HWDjA6a?
+BH#f\Pl[p0"'uO85c>A@)JTigUBhSGb7m>PPX/+s'a:^;f@M<W5QCELDsR@uIqrmP0XfEI$!8lc
+'l)5PX[<F4:gg+BBRg~>
+,
+2451 1232 7J ,
+2510 1232 6P ,
+2551 1232 2M ,
+2618 1209 60 91 /3K
+$C
+2A?,js8W-!s8V7ZGsF%!"6_o^kWYV7VhkQ>Jg#k&K6hH3VY'_'^9>8bht6sK\psb[s8W,tDSQ1_
+rH7#LFk:>EG*^`oA3n*>GVd1.Z!FNaCTt<aL(luY+@<j~>
+,
+1341 1091 2Q ,
+1401 1091 2M ,
+1467 1091 2E ,
+1534 1091 7B ,
+1594 1094 6T ,
+1621 1091 2I ,
+1687 1091 2Q ,
+1747 1091 2Q ,
+0.2 i
+1870.92 1075.76 m
+-16.8 11.16 -18.92 31.44 -18.92 50.04 c
+0 17.64 4.23 35.4 18.68 46.56 c
+-1.32 2.04 p
+-3.12 -2.28 -6.36 -4.44 -9.36 -6.96 c
+-12.48 -10.2 -18 -25.68 -18 -41.52 c
+0 -24.12 6.84 -39.24 27.48 -52.32 c
+h
+f*
+1877 1087 86 95 @C
+,
+44QZ?V^2?WOW\P3&29Uc1nb,<+OYomJqU+#"Vap'6?&k74Tl^sPG"7.3_@aq8:uu!Jo=W]C@t@o
+K\pR@dsQR,DdS"Fo`+sWFT;C@s8W-!CA%W,C\u^hpT:XdV>FtDDO106D/H+c-&/kF<Z"HFKWH":
+@]`!)eV+H"$5b0F;C3:>~>
+1978 1094 69 87 /0Q
+$C
+-D9%R<*'<[LPNS%mib9u!s1G@_gT8t^AYeE^\7]bhu!H2J,fQ9s8W-!s8W-!l$ra5?XNh??%:<&
+9<VZg9<V!A\1],D^+3C(eeYJl/;%=A~>
+,
+2057 1094 6H ,
+2083 1091 2I ,
+2150 1094 6T ,
+2177 1091 1O ,
+2243 1068 56 91 /3Q
+$C
+-,Cq4DZh%&FQ!I"SIf2t":md&kr5NhFJ$:N^Z0P;64]30NY$R\lmJ^/K_s.$3Tq%`2B[Y$V"En7
+H_p17]mmf#?iU0+s8W,.rkEgVhWoWmp8tHtC;U=2*sN+X>?b<9=CGWlL(Q$WOFk7~>
+,
+2341 1091 7B ,
+2401 1094 55 87 /0U
+$C
+3"UXos8W-!s8W-!s8W-!s8W-!s8W,rs8N&qm=+q:9+>jWj<3C,!?I6/g?j'q>VNZA\Yr7fs8W-!
+s8W,W~>
+,
+2467 1094 6H ,
+2494 1094 6T ,
+2521 1091 1S ,
+2616 1125.92 m
+0 15.96 -5.54 31.2 -18.48 41.52 c
+-3 2.52 -6.24 4.68 -9.36 6.96 c
+-1.32 -2.04 p
+14.64 -11.16 19.16 -28.92 19.16 -46.56 c
+0 -18.72 -2.41 -38.76 -19.4 -50.04 c
+1.44 -2.16 p
+20.64 13.08 27.96 28.2 27.96 52.32 c
+h
+f*
+2649 1094 2U ,
+2690 1091 1O ,
+2757 1094 3C ,
+1341 950 7B ,
+1401 950 1O ,
+1467 953 1W ,
+1534 950 1S ,
+1601 950 2M ,
+1667 953 6H ,
+1686 950 6P ,
+1758 950 7B ,
+1818 950 1O ,
+1885 953 1W ,
+1943 953 2U ,
+1985 953 6H ,
+2011 927 3Q ,
+2078 950 2M ,
+2145 953 3C ,
+2185 950 2I ,
+2244 950 6P ,
+2285 953 6H ,
+2312 950 1O ,
+2378 953 1W ,
+1 i
+2065.03 855.52 0 -215.33 S
+1357.57 101.88 1414.97 538.304 re
+S
+1718 478 7J ,
+1776 481 61 63 /3U
+$C
+4rfOcF_r_\f%jP'Xh(s->BOd8[d)RPD:Q"r];oXOG?-3i[=)5mWVU`83dCumX4"SgVknNS:J0p/
+Ss@j>2bU2tDO4Drh(GhoYQ~>
+,
+1844 478 7J ,
+1911 478 7B ,
+0.2 i
+2001.92 462.76 m
+-16.8 11.16 -18.92 31.44 -18.92 50.04 c
+0 17.64 4.23 35.4 18.68 46.56 c
+-1.32 2.04 p
+-3.12 -2.28 -6.36 -4.44 -9.36 -6.96 c
+-12.48 -10.2 -18 -25.68 -18 -41.52 c
+0 -24.12 6.84 -39.24 27.48 -52.32 c
+h
+f*
+2038 512.92 m
+0 15.96 -5.54 31.2 -18.48 41.52 c
+-3 2.52 -6.24 4.68 -9.36 6.96 c
+-1.32 -2.04 p
+14.64 -11.16 19.16 -28.92 19.16 -46.56 c
+0 -18.72 -2.41 -38.76 -19.4 -50.04 c
+1.44 -2.16 p
+20.64 13.08 27.96 28.2 27.96 52.32 c
+h
+f*
+2080 478 2Q ,
+2140 481 0U ,
+2206 478 1O ,
+2265 481 90 63 /0Y
+$C
+.KYlDpXO]kT@_nIrBJokOU%dj64a+nX4+7ZJ,d*k:;?Q'Id<fqs)7pC02;K?s7E\4hgaLtlV$X>
+rTjHiYIF3!rEcnshuA2Vl9;BN^KiM\s1MK@qgJ<@rr'V~>
+,
+2360 478 2Q ,
+1710 339 6P ,
+1751 342 0U ,
+1818 339 7J ,
+1916 339 7B ,
+1976 339 1O ,
+2043 342 1W ,
+2102 342 2U ,
+2143 342 6H ,
+2170 316 3Q ,
+1718 199 1S ,
+1784 202 6H ,
+1811 199 2I ,
+1878 202 6T ,
+1904 199 1O ,
+1971 176 3Q ,
+1 i
+3833.76 855.516 2122.43 538.304 re
+S
+4226 1231 7F ,
+4252 1231 1W ,
+4318 1228 2Q ,
+4370 1228 6P ,
+4412 1228 2I ,
+4478 1231 1W ,
+4545 1228 7B ,
+4605 1228 7J ,
+4703 1228 1O ,
+4761 1231 2U ,
+4835 1228 3G ,
+4922 1228 1O ,
+4989 1231 1W ,
+5055 1228 1S ,
+5122 1228 2M ,
+5189 1231 6H ,
+5207 1228 6P ,
+5241 1231 83 87 /3Y
+$C
+4rgSXFh7OZp%rOjp=IjnYH.P-='aGFYHQ\f<^3Y`?g>^2*gZ^#9)nUMs6V?:g/n;k0CH!Xh-GNA
+])QnqrOV=lFk:bcY3Q!L?eYM2p:L~>
+,
+5329 1228 7B ,
+5381 1228 6P ,
+5422 1231 6H ,
+5449 1228 1O ,
+5515 1231 1W ,
+4218 1090 2Q ,
+4278 1090 2M ,
+4345 1090 2E ,
+4412 1090 7B ,
+4472 1093 6T ,
+4498 1090 2I ,
+4565 1090 2Q ,
+4625 1090 2Q ,
+4708 1090 6P ,
+4750 1090 1O ,
+4849 1090 1S ,
+4916 1090 1O ,
+5007 1090 6P ,
+5048 1093 0U ,
+5115 1090 7J ,
+5213 1090 2I ,
+5280 1090 7B ,
+5332 1090 6P ,
+5373 1090 2M ,
+5440 1090 2I ,
+5507 1093 6T ,
+4218 953 2Q ,
+4278 930 0G ,
+4338 956 1W ,
+4405 953 7B ,
+4465 956 3C ,
+4505 953 1O ,
+4572 956 1W ,
+4638 956 6H ,
+4665 956 52 63 /1C
+$C
+,D)Qfr.c\<h7_\$]6<pqG4"&?mG#*ggUD(V]C+LeG43%dmG#ABgUAjDs8W,g~>
+,
+4725 953 2I ,
+4784 953 6P ,
+4825 956 6H ,
+4852 953 1O ,
+4918 956 1W ,
+4894.97 855.52 0 -215.33 S
+4187.46 101.88 1414.97 538.304 re
+S
+4488 407 7J ,
+4547 410 3U ,
+4615 407 7J ,
+4682 407 7B ,
+0.2 i
+4772.92 391.76 m
+-16.8 11.16 -18.92 31.44 -18.92 50.04 c
+0 17.64 4.23 35.4 18.68 46.56 c
+-1.32 2.04 p
+-3.12 -2.28 -6.36 -4.44 -9.36 -6.96 c
+-12.48 -10.2 -18 -25.68 -18 -41.52 c
+0 -24.12 6.84 -39.24 27.48 -52.32 c
+h
+f*
+4809 441.92 m
+0 15.96 -5.54 31.2 -18.48 41.52 c
+-3 2.52 -6.24 4.68 -9.36 6.96 c
+-1.32 -2.04 p
+14.64 -11.16 19.16 -28.92 19.16 -46.56 c
+0 -18.72 -2.41 -38.76 -19.4 -50.04 c
+1.44 -2.16 p
+20.64 13.08 27.96 28.2 27.96 52.32 c
+h
+f*
+4850 407 1S ,
+4917 407 1O ,
+4984 407 7J ,
+5050 407 2Q ,
+5134 407 6P ,
+5175 410 0U ,
+5242 407 7J ,
+4488 269 2Q ,
+4548 246 0G ,
+4608 272 1W ,
+4675 269 7B ,
+cleartomark end end pagesave restore showpage
+%%PageTrailer
+%%Trailer
+%%Pages: 1
diff --git a/kpilot/Documentation/ConduitProgrammingTutorial/Makefile b/kpilot/Documentation/ConduitProgrammingTutorial/Makefile
new file mode 100644
index 000000000..1dd8b068b
--- /dev/null
+++ b/kpilot/Documentation/ConduitProgrammingTutorial/Makefile
@@ -0,0 +1,25 @@
+# Makefile for the conduit programming tutorial
+
+# This will probably go horribly wrong because all of the
+# files have been reduced to just the sources, and so
+# pdflatex can't read the required embedded pdf / eps
+# pictures that should be created from the png's.
+
+
+all : index.dvi index.pdf
+
+
+
+# latex index && pdflatex index && latex2html -local_icons index && latex2rtf index && dvips index
+#
+# We'll need to create the required pdf files in pictures/ as well.
+
+
+ConduitStructures.pdf : ConduitStructure.eps
+ epstopdf ConduitStructure.eps
+
+index.dvi : index.tex
+ latex index
+
+index.pdf : ConduitStructures.pdf index.tex index.dvi
+ pdflatex index
diff --git a/kpilot/Documentation/ConduitProgrammingTutorial/index.tex b/kpilot/Documentation/ConduitProgrammingTutorial/index.tex
new file mode 100644
index 000000000..aed082efc
--- /dev/null
+++ b/kpilot/Documentation/ConduitProgrammingTutorial/index.tex
@@ -0,0 +1,1708 @@
+\documentclass[10pt,a4paper]{article}
+%\usepackage{hyperlatex}
+\usepackage{graphicx}
+\usepackage{listings}
+\usepackage{geometry}
+\usepackage{html}
+\usepackage{verbatim}
+
+\geometry{left=2.5cm, right=2.5cm, bottom=2cm, top=2cm}
+%\htmltitle{KPilot Conduits programming tutorial}
+%\htmladdress{\xlink{Reinhold Kainhofer}{mailto:[email protected]},
+%\htmladdnormallink{http://reinhold.kainhofer.com}{http://reinhold.kainhofer.com/} \today}
+%\htmlattributes{BODY}{BGCOLOR=#ffffee text=#000000 link=#0000FF vlink=#000099 alink=#000099}
+
+
+%\setcounter{htmldepth}{2}
+%\setcounter{secnumdepth}{4}
+
+\title{KPilot conduit programming tutorial}
+\author{\htmladdnormallink{Reinhold Kainhofer}{mailto:[email protected]}, with help of
+\htmladdnormallink{A. de Groot}{mailto:[email protected]} and \htmladdnormallink{Dan Pilone}{mailto:[email protected]}}
+\date{\today}
+
+%\W \newcommand{\texttrademark}{}
+\newcommand{\code}[1]{{\small\texttt{#1}}}
+\newcommand{\file}[1]{{\small\texttt{#1}}}
+\newcommand{\class}[1]{{\small\em\texttt{#1}}}
+
+\newcommand{\codesize}[0]{\scriptsize}
+
+\begin{document}
+
+\maketitle
+
+
+%\htmlmenu{3}
+
+\tableofcontents
+
+
+
+\section{Introduction and General}
+
+\subsection{Introduction}
+ One of the greatest assets of the handheld computers is their ability to
+interconnect with other applications. KPilot supports this capability
+through conduits. A conduit is a small separate program that talks to
+KPilot during the hot sync. The conduit translates between the Palm
+Pilot and the application you're syncing with.
+
+For KPilot to be a really usable synchronization application, it depends
+on third-party developers to enlarge the conduit gallery to other applications. In particular, I want to encourage developers of Palm applications to provide not only a Windows\texttrademark conduit, but at the same time put some effort in providing also a conduit for Linux and other platforms.
+This is also the reason why I'm writing this tutorial:
+To encourage third-party developers to write conduits for KPilot.
+
+I will show the process at several examples: \\
+First, the general framework (library, factory etc.) for a conduit is presented
+in section \ref{FactorySection}, then in section \ref{SetupSection}.
+I will describe how you can write a configuration dialog for your conduit. These
+two sections will use the malconduit (AvantGo conduit) as an example.
+The synchronization part (the conduit class) will be described in the next few
+sections. Section \ref{SectionSimpleConduit} will show a very simple
+synchronization at the example of the AvantGo conduit, where we will use the
+functions of an external library which will do the synchronization for us.
+In section \ref{SectionDatabasesConduit} I will show a synchronization process
+where one file on disk corresponds to one database on the palm, and where no conflict
+resolution and no record comparison needs to be done, because we have to copy the
+whole database either from or to the handheld. The particular example there will be the docconduit which
+synchronizes text files on the harddisk with PalmDOC documents for AportisDoc, TealDoc, MobiPocket Reader, Gutenpalm etc.
+on the Palm.
+Finally, I wanted to show an example of a record-based conduit, but then decided it
+would be too extensive to replicate all the complex sync and conflict resolution code.
+Instead I refer to the addressbook conduit, which you should be able to understand
+quite well after studying the other conduits explained in the previous chapters of this How-To.
+Using KDE's KitchenSync general synchronization framework for syncing will be the topic of section
+\ref{SectionKitchenSync}, where I give some argument why we do not yet switch to kitchensync yet.
+
+\subsection{Further information and links}
+
+There are loads of information about the PalmOS\texttrademark Database format
+out there:
+\begin{itemize}
+\item Palm's official Developer Knowledge Base document: \htmladdnormallink{http://oasis.palm.com/dev/kb/faq/FileFormat/PDB+PRCFormat.cfm}{http://oasis.palm.com/dev/kb/faq/FileFormat/PDB+PRCFormat.cfm}
+\item PilotRecord Databse format: \htmladdnormallink{http://www.pda-parade.com/prog/palm/doc/pdb.html}{http://www.pda-parade.com/prog/palm/doc/pdb.html}
+\item EBNF representation of the database format: \htmladdnormallink{http://obermuhlner.com/public/Projects/Palm/PDBC/Documentation/pdbc\_file.html}{http://obermuhlner.com/public/Projects/Palm/PDBC/Documentation/pdbc\_file.html}
+\item A list of several Palm databse formats: \htmladdnormallink{http://myfileformats.com/search.php?name=Palm}{http://myfileformats.com/search.php?name=Palm}
+\end{itemize}
+
+\subsection{Legal}
+You can skip this chapter if you are familiar with HOWTOs,
+or just hate to read all this assembly-unrelated crap.
+
+\subsubsection{Legal Blurb}
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU \htmladdnormallink{Free Documentation
+License}{http://www.gnu.org/copyleft/fdl.html} Version 1.1;
+with no Invariant Sections, with no Front-Cover Texts, and no Back-Cover texts.
+A copy of the license is included in the \htmladdnormallink{Free Documentation
+License}{http://www.gnu.org/copyleft/fdl.html} appendix.
+
+
+The most recent official version of this document is available from
+\htmladdnormallink{my homepage}{http://reinhold.kainhofer.com/Linux/KPilot/ConduitTutorial}.
+If you are reading a few-months-old copy,
+consider checking the above URLs for a new version.
+
+
+
+\section{The general conduit framework}\label{FactorySection}
+
+\subsection{How conduits work in general}
+ KPilot is divided into three major components: the GUI, the
+syncing daemon, and the conduits. When the GUI is started it attempts
+to make a connection to the syncing daemon. If it can't it starts the
+daemon then makes the socket connection. When the user hits the
+hot-sync button on the cradle the daemon checks to see if the GUI is
+connected. If it is, the daemon notifies the GUI that a hot-sync has
+started. The daemon then steps through all activated conduits and lets them
+do their sync. When the conduit is started it
+makes a connection back to the daemon and asks the daemon to read and
+write entries into the database. When the conduit finishes it exits
+and the daemon continues on to the next conduit. Once all the
+conduits have run the daemon alerts the GUI that it has
+finished and goes back to waiting for a sync to start. Note that the backup
+of the Handheld is also done by a conduit, which is not visible to the user, though.
+
+
+ The basic conduit implements three important features:
+info/setup, backup, and normal hot-sync. If the user clicks the setup
+button in KPilot's conduit menu the conduit is started and requested
+to show a settings dialog. If the conduit doesn't have any settings
+to adjust then it should simply display an about dialog. When the
+dialog is closed the conduit will exit. Next, if the user requested
+KPilot back up the pilot the conduit will be given the opportunity to
+grab everything off the pilot. This is useful if this is the first
+time the conduit is being used. For example if the user had never
+synced before this would be a good time to copy the data into the
+calendar, money database, etc. Lastly, the conduit is requested to
+hot-sync whenever KPilot is hot-syncing with the pilot.
+
+
+
+\subsection{A conduit is a KDE shared library}
+
+From your system's point of view, a conduit is a shared library which is loaded
+on demand by KPilot. This means that as long as you don't do a sync, the conduit will not
+be in memory. Once a hotsync is initiated, kpilotDaemon (the process running in
+the background that does the actual sync) loads the conduit, let's say its name
+is "malconduit" and it is installed as /opt/kde3/lib/kde3/libmalconduit.so. It
+then calls the function \code{init\_libmalconduit} (the name after init\_ is the
+filename of the library), which needs to return a pointer to an instance
+of a \class{KLibFactory} subclass.
+
+{\small\begin{verbatim}
+extern "C" {
+
+void *init_libmalconduit() {
+ return new MALConduitFactory;
+}
+
+};
+\end{verbatim}
+}
+
+Whenever the conduit needs to do some action
+(show the configure dialog or do a sync), the \code{createObject(...)} method
+of this instance is called with the appropriate values to specify the action. It either returns an instance
+of a \class{ConduitConfig} subclass to show the configuration dialog, or an
+instance of an \class{ConduitAction} subclass which will later do the actual sync
+with the handheld. Figure \ref{ConduitStructure} shows this as a diagram:
+
+\begin{figure}
+\begin{center}
+\includegraphics[width=13cm]{ConduitStructure}
+\caption{The general structure of a conduit}\label{ConduitStructure}
+\end{center}
+\end{figure}
+
+
+\subsection{Makefile.am and KDE build process}
+
+Before we delve into programming details, let us look a bit at the compilation framework.
+
+If you develop your conduit inside the \file{kdepim/kpilot/conduits} directory of KDE's
+CVS tree, all you need to do is to provide a Makefile.am in your conduit directory
+(e.g. \file{kdepim/kpilot/conduits/malconduit}), and add the name of your
+directory (\file{malconduit} in this example) to the variable \code{SUBDIRS}
+in \file{kdepim/kpilot/conduits/Makefile.am}:
+{\small
+\begin{verbatim}
+SUBDIRS = knotes expense null vcalconduit \
+ popmail timeconduit malconduit
+\end{verbatim}
+}
+\vspace{1em}
+
+The \file{Makefile.am} in your conduit's directory will look similar to the following one
+(taken from the malconduit). Since this is a tutorial on KPilot conduits, and not
+on automake/conf, make and Makefiles, I will not explain it in detail. However,
+it should be easy to adapt it to your conduit's needs:
+
+{\footnotesize
+\begin{verbatim}
+### Makefile for the AvantGo conduit
+###
+### The mal conduit is Copyright (C) 2002 by Reinhold Kainhofer
+
+
+INCLUDES= $(PISOCK_INCLUDE) $(MAL_INCLUDE) \
+ -I$(top_srcdir)/kpilot/lib $(all_includes)
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = mal_conduit.desktop
+
+kde_module_LTLIBRARIES = libmalconduit.la
+
+libmalconduit_la_SOURCES = \
+ mal-factory.cc \
+ mal-setup.cc \
+ mal-conduit.cc \
+ mal-setup_dialog.ui
+libmalconduit_la_LDFLAGS = $(KDE_RPATH) -L../../lib
+libmalconduit_la_LIBADD = -lkpilot $(MAL_LIB)
+\end{verbatim}
+}
+
+Here is a short table of the variables used in \file{Makefile.am}:
+
+\begin{tabular}{ll}
+\code{service\_DATA} & name of the desktop file of your conduit \\
+ &(tells KDE which library it needs to load)\\
+\code{kde\_module\_LTLIBRARIES} & tell make which libraries to compile\\
+\code{libraryname\_SOURCES} & a list of all source files to be compiled into \\
+ &libraryname (where a . is replaced by a \_)\\
+\code{libraryname\_LDFLAGS} & linker flags when linking your conduit \\
+\code{libraryname\_LIBADD} & additional libraries the conduit links to \\
+ &(-lkpilot is the KPilot base library and\\
+ & needs to be linked to every conduit)
+\end{tabular}
+
+\vspace{0.5em}
+
+Both \code{MAL\_INCLUDE} and \code{MAL\_LIB} are special variables
+pointing to the headers and the library of libmal, and are set by
+\file{configure.in.in} (see below).
+
+\vspace{1em}
+
+If you have special library requirements (e.g. the malconduit needs libmal to work),
+you need to add special configure checks to the autoconf file \file{kdepim/kpilot/conduits/configure.in.in} (for an
+example, you should look at the checks the malconduit added to the file in CVS)
+and include the directory only if the appropriate libraries and header files are installed.
+One way to achieve this is to add the following line after your configure checks, which set
+the variable \code{HAVE\_MAL} to \code{1}. This automake command in
+\file{configure.in.in} defines "\code{include\_malconduit}" for use
+in Makefile.am, if \code{HAVE\_MAL==1}:
+{\small\begin{verbatim}
+AM_CONDITIONAL(include_malconduit, test "$HAVE_MAL" = "1")
+\end{verbatim}
+}
+
+You can then use "\code{include\_malconduit}" in the KPilot conduit
+directory's makefile \file{kdepim/kpilot/conduits/Makefile.am}:
+{\footnotesize
+\begin{verbatim}
+MALSUBDIR=
+if include_malconduit
+ MALSUBDIR = malconduit
+endif
+
+SUBDIRS = knotes expense null vcalconduit popmail timeconduit $(MALSUBDIR)
+\end{verbatim}
+}
+
+\subsection{The conduit factory}
+
+In KDE's dynamic library system, the library factory plays a crucial rule. The \code{init\_libraryname()} function
+always returns a pointer to a \class{KLibFactory} instance. Whenever a program needs a special action by
+the conduit, it calls the \code{createObject} of the \class{KLibFactory} to get an appropriate object.
+Furthermore, the conduit factory initializes the about dialog of the conduit.
+
+The factories of all conduits are very similar, so you best just copy the .h and .cc file of an existing conduit
+for your conduit. All you need to do is to change the copyright notices for the about dialog, and
+change the class names of the \class{ConduitAction} and \class{ConduitSetup} to your own class names. Also,
+the factory is a good place to define the strings for the config settings' entries to the config file.
+If you define them like:
+{\footnotesize\begin{verbatim}
+class MALConduitFactory : public KLibFactory
+{
+...
+public:
+ static const char *configSetting1() {return fConfigSetting1;};
+private:
+ static const char *fConfigSetting1;
+} ;
+\end{verbatim}
+}
+and in the .cc file
+{\small\begin{verbatim}
+const char*MALConduitFactory::fConfigSetting1="NameOfSetting";
+\end{verbatim}
+}
+you can use them as \code{MALConduitFactory::configSetting1()} in
+both the configuration dialog and the sync routine without running the risk of misspelling
+them.
+
+Everything else in the factory can stay as it is.
+
+Here is an example of the malsync's factory:
+\begin{htmlonly}
+ \htmladdnormallink{Source code of mal-factory.h}{mal-factory.h}
+ \htmladdnormallink{Source code of mal-factory.cc}{mal-factory.cc}
+\end{htmlonly}
+
+
+\begin{latexonly}
+\subsubsection{mal-factory.h}
+{\scriptsize
+ \verbatiminput{mal-factory.h}
+}
+\subsubsection{mal-factory.cc}
+{\scriptsize
+ \verbatiminput{mal-factory.cc}
+}
+\end{latexonly}
+
+\subsection{Debugging conduits}
+
+Debugging KPilot conduits is not an easy task, as one cannot use a debugger
+(because conduits are shared libraries and kpilotDaemon forks itself
+in the background when it is started).
+
+So printing debug output is the only way to get any information about what
+the conduit is doing. If you don't configure kdepim it with \code{--no-debug}, or don't add
+\code{--NDEBUG} in Makefile.am, then you can easily print out debug messages
+using the \code{DEBUGCONDUIT} stream. However, at the beginning of each
+function where you want to use it, you need to add the macro \code{FUNCTIONSETUP;},
+which prints out a debug message with the current function name. Additionally,
+it sets several variables like \code{fname} which holds the name of the current function.
+
+ As an example, the following code
+{\footnotesize\begin{verbatim}
+void YourConduit::somefunction() {
+ FUNCTIONSETUP;
+ int i=5;
+#ifdef DEBUG
+ DEBUGCONDUIT<<fname<<": Value of i="<<i<<endl;
+#endif
+}
+\end{verbatim}
+}
+prints out the following debug message to stdout:
+{\small\begin{verbatim}
+kpilotdaemon: somefunction: Value of i=5
+\end{verbatim}
+}
+
+
+
+\section{The Conduit Setup Dialog}\label{SetupSection}
+
+In this section I will shortly describe how you can implement a configuration dialog for your conduit.
+There is nothing Palm- or KPilot-specific about this. All the configuration dialog does is to read the
+configuration settings from the config file (using the \class{KConfig} class from kdelibs), and let
+the user change them in the dialog. If the user exists the dialog by pressing OK, the new values are
+read from the dialog controls and written back to the configuration file.
+
+To provide a consistent experience to KPilot users, there already
+exists a class \class{ConduitConfig} which is a subclass of \class{KDialog}.
+This dialog does most of the basic work for you.
+
+\subsection{The dialog template, using QT Designer}
+Of course, first we need to have a dialog template in the form of a QT
+Designer file (which has an extension .ui). Start up \file{designer} and
+create a new widget (no dialogbox, i.e. no OK or cancel buttons, these will be added automatically). The dialogbox should contain a QTabWidget, even if you only need one tab. A second tab "About" will be added more or less automatically by the conduit listing the copyright and the authors of your conduit. A typical example of the coknduit setup widget dialog is shown in the following screenshot:
+\includegraphics[width=14cm]{pictures/ProxyTab}
+
+
+\subsection{Using the dialog template for your conduit}
+
+Now that we have the dialog template, we can include it in the configuration dialog box.
+First, create a subclass of \class{ConduitConfig}, where we only have to implement the con- and
+destructor as well as the methods
+\begin{itemize}
+\item \code{virtual void readSettings()}
+\item \code{virtual void commitChanges()}
+\end{itemize}
+This class \class{ConduitConfig} will do most of the work for us, all
+that is left to us is to read the config settings from the config file
+and set the values of the controls in the dialog (in the
+\code{readSettings()} method). Also, when \code{commitChanges()} is
+called, this means that the dialog was existed with the OK button, so
+we need to read the new values from the controls and store them to the
+configuration file.
+
+The whole class declaration is:
+{\footnotesize\begin{verbatim}
+class MALWidget;
+
+class MALWidgetSetup : public ConduitConfig
+{
+Q_OBJECT
+public:
+ MALWidgetSetup(QWidget *,const char *,const QStringList &);
+ virtual ~MALWidgetSetup() {};
+ virtual void readSettings();
+protected:
+ virtual void commitChanges();
+private:
+ MALWidget *fConfigWidget;
+} ;
+\end{verbatim}
+}
+
+This class implements the dialog box itself, and our dialog template
+will be inserted into this dialog by the constructor:
+{\footnotesize\begin{verbatim}
+MALWidgetSetup::MALWidgetSetup(QWidget *w, const char *n,
+ const QStringList & a) :
+ ConduitConfig(w,n,a)
+{
+ FUNCTIONSETUP;
+
+ fConfigWidget = new MALWidget(widget());
+ setTabWidget(fConfigWidget->tabWidget);
+ addAboutPage(false,MALConduitFactory::about());
+
+ fConfigWidget->tabWidget->adjustSize();
+ fConfigWidget->resize(fConfigWidget->tabWidget->size());
+}
+\end{verbatim}
+}
+
+The first two lines create an instance of our dialog template and add it
+as the tab widget to the dialog. Since we will have to set and read the
+values of the controls in that tab widget, we need to store a pointer to
+the instance in the variable \code{fConfigWidget} which is of the same type
+(\code{MALWidget}) we assigned to our dialog template in QT Designer. The
+third line of code adds the about page (which is created by the factory,
+see last section) to the tab widget, while the last two line just adjust
+the size of the dialog box and are not always needed.
+
+As mentioned above, we only need to implement \code{MALWidgetSetup::readSettings()}
+and \code{MALWidgetSetup::commitChanges()}. The \class{ConduitConfig} class
+already stores an instance named fConfig to KPilot's configuration facility.
+We only have to set the correct configuration group name (I suggest, you
+store the name of the configuration group for you conduit in a \code{static
+char*} variable of the conduit factory class), and then we can use the methods
+\begin{itemize}
+\item \code{fConfig->readNumEntry("entryname", \em{defaultNumericValue})}
+\item \code{fConfig->readEntry("entryname", \em{defaultstring})}
+\item \code{fConfig->readBoolEntry("entryname", \em{defaultBoolValue})}
+\end{itemize}
+to retrieve the settings from the configuration file. We then use the methods of the QT and KDE widgets to assign the text or value to the controls:
+
+{\footnotesize\begin{verbatim}
+/* virtual */ void MALWidgetSetup::readSettings()
+{
+ FUNCTIONSETUP;
+
+ if (!fConfig) return;
+ KConfigGroupSaver s(fConfig,MALConduitFactory::group());
+
+ fConfigWidget->syncTime->setButton(fConfig->readNumEntry(MALConduitFactory::syncTime(), 0));
+
+ // Proxy settings
+ fConfigWidget->proxyType->setButton(
+ fConfig->readNumEntry(MALConduitFactory::proxyType(), 0));
+ fConfigWidget->proxyServerName->setEditText(
+ fConfig->readEntry(MALConduitFactory::proxyServer(), ""));
+ int proxyPortNr=fConfig->readNumEntry(MALConduitFactory::proxyPort(), 0);
+ if (proxyPortNr>0 && proxyPortNr<65536)
+ {
+ fConfigWidget->proxyCustomPortCheck->setChecked(true);
+ fConfigWidget->proxyCustomPort->setEnabled(true);
+ fConfigWidget->proxyCustomPort->setValue(proxyPortNr);
+ }
+ fConfigWidget->proxyUserName->setText(fConfig->readEntry(
+ MALConduitFactory::proxyUser(), ""));
+ fConfigWidget->proxyPassword->setText(fConfig->readEntry(
+ MALConduitFactory::proxyPassword(), ""));
+}
+\end{verbatim}
+}
+
+In this example, we don't store to the configuration file if a custom proxy port should be used. Instead, we just store a port number, and if the port number is 0 this means to use the default port. In this case, the custom port CheckBox needs to stay unchecked, and the port NumEntry control will stay disabled as it is in the dialog template. In all other cases, however, the custom port CheckBox should be checked, and the port NumEntry control will be enabled and filled with the correct custom port.
+
+
+The KPilot user can then change all the settings in the dialogbox without any intervention from KPilot, so we don't need to write any code for that. Only the \code{commitChanges()} method remains to be done, which does the opposite of the readSettings() method. It reads the values of the controls and stores them to the configuration file. The \class{KConfig} class (the \code{fConfig} variable, resp.) has only one method \code{KConfig::writeEntry("entryname", valueOfWhateverType)} to write a value to the configuration file. However, this method has several overloaded implementations so that you can write numeric, string, boolean, date and many more variable types with the same syntax. First, we need to set the correct configuration group again, and then we just read each of the settings and write it out immediately using the \code{writeEntry} method:
+
+{\footnotesize\begin{verbatim}
+/* virtual */ void MALWidgetSetup::commitChanges()
+{
+ FUNCTIONSETUP;
+
+ if (!fConfig) return;
+ KConfigGroupSaver s(fConfig,MALConduitFactory::group());
+
+ fConfig->writeEntry(MALConduitFactory::syncTime(),
+ fConfigWidget->syncTime->id(fConfigWidget->syncTime->selected()));
+
+ // Proxy settings
+ fConfig->writeEntry(MALConduitFactory::proxyType(),
+ fConfigWidget->proxyType->id(fConfigWidget->proxyType->selected()));
+ fConfig->writeEntry(MALConduitFactory::proxyServer(),
+ fConfigWidget->proxyServerName->currentText() );
+
+ if (fConfigWidget->proxyCustomPortCheck->isChecked() )
+ {
+ fConfig->writeEntry(MALConduitFactory::proxyPort(),
+ fConfigWidget->proxyCustomPort->value());
+ }
+ else
+ {
+ fConfig->writeEntry(MALConduitFactory::proxyPort(), 0);
+ }
+ fConfig->writeEntry(MALConduitFactory::proxyUser(),
+ fConfigWidget->proxyUserName->text() );
+ fConfig->writeEntry(MALConduitFactory::proxyPassword(),
+ fConfigWidget->proxyPassword->text() );
+}
+\end{verbatim}
+}
+
+This was all that is needed to implement the configuration for your conduit. Simple, isn't it?
+
+
+
+\section{How the conduits work}
+
+ First a little background on pilot databases would be useful.
+Each database on the pilot is divided into multiple records. Each
+record is a specific entry into the database. For example, one
+address in the Address Book corresponds to one record in AddressDB.
+Each record has a unique id assigned by the pilot when the record is
+created, and an index number in the database. The index numbers get
+reused, for example if you delete the second record from the database
+then create a new one it will fill in the empty slot and become index
+number two. However, it will have a unique ID number. (The moral of
+this story is only use index numbers when you need to iterate through
+the whole Database, otherwise use the unique record id.)
+
+ When a new record is created by the user on the local side, it
+is inserted into the backed up copy of the databases but given a
+unique ID of 0. When the syncing occurs this record is installed on
+the pilot and the pilot will return with the new unique id for it.
+This same process happens with a conduit. If two records have the
+same unique id they will overwrite each other.
+
+ Lastly, the conduit is requested to
+hot-sync whenever KPilot is hot-syncing with the pilot. During this
+time the conduit asks KPilot if there are any modified records on the
+pilot and should back them up into the program the conduit syncs
+with. Then, the conduit checks to see if there are any locally
+modified records and asks KPilot to put those on the pilot. Once
+finished, it exits gracefully by a
+{\small\begin{verbatim}
+emit syncDone();
+\end{verbatim}
+}
+and KPilot will continue with the next conduit.
+
+In the next few sections I will present the most important classes KPilot provides to the conduit programmers, and after that I will show several examples of different conduits.
+
+
+\subsection{The \class{SyncAction} base class for conduits}
+
+All conduits are subclasses of \class{SyncAction}, which provides the following methods. The \code{exec} method is a pure virtual function and needs to be implemented by each conduit:
+
+\begin{itemize}
+\item
+ \code{virtual bool exec()=0} ... This function starts the actual processing done
+ by the conduit. It should return false if the
+ processing cannot be initiated, f.ex. because
+ some parameters were not set or a needed library
+ is missing. This will be reported to the user.
+ It should return true if processing is started
+ normally. If processing starts normally, it is
+ the {\bf conduit's} responsibility to eventually
+ \code{emit syncDone();} if processing does not start
+ normally (ie. \code{exec()} returns false) then the
+ environment will deal with \code{syncDone()}.
+
+\item
+ \code{void addSyncLogEntry(const QString \&e,bool suppress=false)} ... Write a log entry to the pilot. Causes signal \code{logEntry(const char *)} to be emitted.
+\item
+ \code{int pilotSocket()}\qquad ... returns the pilot socket (needed if you use your own functions to talk to the handheld. This is not recommended, but necessary in some cases)
+\item
+ \code{int openConduit()}\qquad ... Notify the handheld which conduit is running now.
+\end{itemize}
+
+In addition to these functions the class also has some signals you can emit to display log messages and to indicate that the conduit has finished and KPilot should go on with the next conduit:\
+
+\begin{itemize}
+\item \code{void syncDone(SyncAction *)} ... tell KPilot that the conduit has finished. Every conduit that returns true in its \code{exec()} method needs to emit this signal, otherwise KPilot will wait forever for the conduit to return.
+
+\item \code{void logMessage(const QString \&)} ... Adds a message to KPilot's log, but not to the handheld's log.
+\item \code{void logError(const QString \&)} ... Adds an error message to KPilot's log
+\item \code{void logProgress(const QString \&,int)} ... Adds a log message and sets the progress bar to the given percentage.
+\end{itemize}
+
+
+If your conduit will have to ask the user some question, the handheld needs to be tickled to prevent a timeout while the message box or dialog window is shown. The \class{InteractiveAction} class (which is a subclass of \class{SyncAction}) can be used as a base class for your conduit in this case. Call \code{startTickle()} some time before showing a dialog to the user (we're assuming a local event loop here) so that while the dialog is up and the user is thinking, the pilot stays awake. Afterwards, call \code{stopTickle()}. The parameter to \code{startTickle} indicates the timeout, in seconds, before signal timeout is emitted. You can connect to that signal, to take down the user interface part if the user isn't reacting.
+In addition to \class{SyncAction}'s methods it adds the following methods:
+
+\begin{itemize}
+\item\code{void tickle()} ... Tickles the handheld to reset the timeout counter.
+\item \code{void startTickle(unsigned count=0)} ... start a timer to tickle
+the handheld in regular intervals
+\item \code{void stopTickle()} ... stop the timer
+
+\item\code{int questionYesNo(const QString \&question ,
+ const QString \&caption = QString::null,
+ const QString \&key = QString::null,
+ unsigned timeout = 20000)} ... Ask a yes-no question of the user.
+ This has a timeout so that you don't wait forever for inattentive users.
+ It's much like \code{KMessageBox::questionYesNo()}, but with this extra
+ timeout-on-no-answer feature. Returns a \code{KDialogBase::ButtonCode}
+ value - Yes,No or Cancel on timeout. If there is a key set and the user
+ indicates not to ask again, the selected answer (Yes or No) is
+ remembered for future reference.
+\end{itemize}
+
+
+For conduits that sync one specific database (e.g. "AddressDB" or "TodoDB"),
+there is the class \class{ConduitAction}, which is a child class of
+\class{SyncAction}, and adds the following methods and members:
+
+\begin{itemize}
+\item\code{PilotDatabase *fDatabase,*fLocalDatabase;} ... Pointers to the
+database on the handheld and the backup database on the harddisk. These are
+set by openDatabases.
+\item\code{bool openDatabases(const char *dbName, bool*retrieved=0L)} ...
+opens the database named \code{dbName} on the handheld and the backup database
+on the harddisk (in the directory \file{\$KDEHOME/share/apps/kpilot/DBBackup/PalmUserName/}).
+If the backup database does not exist, the current database from the palm is
+fetched, and \code{*retrieved} is set to \code{true}.
+\end{itemize}
+
+
+\subsection{The \class{KPilotDeviceLink} class for communicating with the handheld}
+For the communication with the handheld KPilot has a class
+\class{KPilotDeviceLink}, and the ConduitAction class always stores an
+instance of \class{KPilotDeviceLink} pointing to the current connection
+in a variable called \code{fHandle}. The following list shows all members
+of this class that you might need in your conduit:
+
+\begin{itemize}
+\item
+ \code{int getNextDatabase(int index,struct DBInfo *)}\qquad ... Returns
+ the database at position index and stores its information to the DBInfo
+ variable, which can then be used in other functions.
+\item
+ \code{int findDatabase(char*name, struct DBInfo*)}\qquad ... Finds a
+ database with a given name like "AddressDB" and stores its information
+ to the \code{DBInfo} variable, which can then be used in other functions.
+
+\item
+ \code{bool retrieveDatabase(const QString \&path, struct DBInfo *db)}
+ \qquad ... Retrieve the database indicated by \code{DBInfo *db} into
+ the local file path.
+
+
+\item
+ \code{bool installFile(const QString \&, bool deleteFile=true)}\qquad ... Installs the .prc
+ or .pdb database from the PC to the handheld. Returns true on success.
+ If deleteFile is set true or left out, the local file is deleted after successful installation.
+\item
+ \code{int installFiles(const QStringList \&, bool deleteFiles=true)}\qquad ... Installs
+ several .prc or .pdb databases from the PC to the handheld. Returns
+ the number of successfully installed databases. If deleteFiles is set true
+ or left out, the local files are deleted after successful installation.
+
+
+
+\item
+ \code{static KPilotDeviceLink *link()}\qquad ... returns the current
+ connection (only one can be open at the same time)
+
+\item
+ \code{void tickle()}\qquad ... Tickle the palm to reset the timeout.
+ This is needed if you need to do a lengthy calculation or display a
+ dialogbox where the user might not respond immediately.
+
+\item
+ \code{KPilotUser *getPilotUser()}\qquad ... Returns the user
+ information as set on the handheld.
+
+
+\item
+ \code{QDateTime getTime()}\qquad ... Get the time from the handheld
+ device into a \class{QDateTime}
+\item
+ \code{bool setTime(const time\_t \&pctime)}\qquad ... Set the time
+ on the handheld to the give \code{time\_t} (\class{QDateTime} didn't
+ work for me, so I implemented it with \code{time\_t})
+
+
+\item
+ \code{unsigned long ROMversion()}\qquad ... Get the version number
+ from the handheld
+\item
+ \code{unsigned long majorVersion()}\qquad ... Get the major PalmOS
+ version number (e.g. 3 for PalmOS 3.0 and 3.5, 4 for PalmOS 4.x etc.)
+
+\end{itemize}
+
+If you want to modify a database on the handheld, you can work with a
+PilotDatabase instance (see next subsection), which does all the
+communication for you.
+
+
+
+\subsection{The \class{PilotDatabase} classes for working with databases}
+KPilot's class library knows two types of databases: local databases from
+a .pdb file on your PC's harddisk, and serial databases on a PalmOS device
+connected through a serial or USB cable. To work with a database, you just
+create an instance of either a \class{PilotLocalDatabase} or a
+\class{PilotSerialDatabase}, both of which are derived from
+\class{PilotDatabase}. This base class has the following important members:
+
+\begin{itemize}
+\item\code{virtual int recordCount()} ... returns the number of records
+in the database
+\item\code{virtual QValueList<recordid\_t> idList()} ... Returns a list
+of all record ids in the database.
+\item\code{virtual PilotRecord* readRecordById(recordid\_t id)} ... Reads
+a record from database by id.
+\item\code{virtual PilotRecord* readRecordByIndex(int index)} ... Reads a
+record from database.
+\item\code{virtual PilotRecord* readNextRecInCategory(int category)} ...
+Reads the next record from database in category 'category'
+\item\code{virtual PilotRecord* readNextModifiedRec()} ... Reads the next
+record from database that has the dirty flag set.
+\item\code{virtual recordid\_t writeRecord(PilotRecord* newRecord)} ... Writes
+a new record to database (if 'id' == 0 for a serial database, one will be
+assigned to newRecord)
+\item\code{virtual int resetSyncFlags()} ... Resets all records in the
+database to not dirty.
+\item\code{virtual int resetDBIndex()} ... Resets next record index to beginning
+\item\code{virtual int cleanup()} ... Purges all Archived/Deleted records
+from Palm Pilot database
+\item\code{bool isOpen()} ... Returns false if the database could not be
+opened, e.g. no connection to the handheld or file could not be created.
+\item\code{virtual QString dbPathName()} ... Returns some sensible human-readable
+identifier for the database. Serial databases get Pilot:, local databases
+return the full path.
+\item\code{virtual int readAppBlock(unsigned char* buffer, int maxLen)} ...
+Reads the application block info, returns size.
+\item\code{virtual int writeAppBlock(unsigned char* buffer, int len)} ...
+Writes the application block info.
+\end{itemize}
+
+
+The constructors of \class{PilotLocalDatabase} and \class{PilotSerialDatabase} are:
+\begin{itemize}
+\item\code{PilotSerialDatabase(int linksocket, const char* dbName)} ... linksocket
+\item\code{PilotLocalDatabase( const QString\& path, const QString\& name)}
+\item\code{PilotLocalDatabase(const QString \&name)} ... open database by name only
+(no explicit path). The path \file{\$KDEHOME/share/apps/kpilot/DBBackup/PalmUserName/}
+is set by KPilot automatically.
+\end{itemize}
+
+
+
+\subsection{The \class{PilotRecord} classes for working with records}
+
+Each database consists of several database records, so we also need a
+class \class{PilotRecord} to work with records. A PilotRecord is just
+a long string of binary data, without any meaning so far. You will
+have to implement your own classes that take the data from the record
+and turn it into usable values (use the database format specification
+for the database you are working with). The class \class{PilotAppCategory}
+can be used as base class for this, and the \code{pack()} method packs
+the human-readable variable values into one whole binary string that
+is then sent to the handheld as the data of the record. Usually you
+don't create an instance of \class{PilotRecord} yourself, but either
+get a \code{PilotRecord*} from one of the methods of the \class{PilotDatabase}
+class, or you pack your own subclass of \class{PilotAppCategory} (e.g.
+PilotTodoEntry, PilotAddress, PilotDateEntry) with a call to \code{pack()}.
+
+The \class{PilotRecord} class has the following important methods:
+
+\begin{itemize}
+\item\code{char* getData()} ... gets the binary data directly from the
+database. You need to "unpack" the data yourself.
+\item\code{void setData(const char* data, int len)} ... sets the packed
+binary data of the record.
+\item\code{int getLen()} ... Returns the length of the record data.
+\item\code{int getAttrib(} ... Returns the attributes of the record
+(e.g. modified, archived, deleted, secret etc.). For possible values
+see the pilot-link header files.
+\item\code{void setAttrib(int attrib)} ... Sets the record attributes.
+
+\item\code{int getCat()} ... Returns the category of the record (0-15).
+The names of the categories are stored in the database's header.
+\item\code{void setCat(int cat)} ... Sets the category of the record.
+\code{cat} needs to be in the range 0-15.
+
+\item\code{unsigned long getID()} ... Returns the unique record ID.
+\item\code{void setID(unsigned long id)} ... Sets the record ID. If you
+already have a record with that ID, it will be overwritten!
+
+\item\code{bool isDeleted()} ... Self-explaining
+\item\code{bool isSecret()} ... Self-explaining
+\item\code{bool isArchived()} ... Self-explaining
+\item\code{void makeDeleted()} ... Self-explaining
+\item\code{void makeSecret()} ... Self-explaining
+\end{itemize}
+
+
+
+
+\section{A very simple conduit: malconduit}\label{SectionSimpleConduit}
+
+To have a working conduit, we still have to implement the synchronization
+itself. For the AvantGo conduit there already exists a library named
+"libmal" which does all the synchronization for us. In the section on
+autoconf and automake I already described the configure commands to check
+for the library and to link to the library on runtime (the \code{-lmal}
+flag stored in the variable \code{\$(MAL\_LIB)} ).
+
+When using the libmal library, all we have to do is to make some proxy settings, and then call the function \texttt{malsync( pilotSocket(), pInfo);}, which will do the actual sync for us:
+{\footnotesize
+\begin{verbatim}
+void MALConduit::readConfig() {
+ FUNCTIONSETUP;
+ QDateTime dt;
+ KConfigGroupSaver g(fConfig, MALConduitFactory::group());
+ fLastSync = fConfig->readDateTimeEntry(MALConduitFactory::lastSync(), &dt);
+ DEBUGCONDUIT<<"Last sync was "<<fLastSync.toString()<<endl;
+
+ eSyncTime=fConfig->readNumEntry(MALConduitFactory::syncTime(), 0);
+
+ // Proxy settings
+ eProxyType=fConfig->readNumEntry(MALConduitFactory::proxyType(), 0);
+ fProxyServer=fConfig->readEntry(MALConduitFactory::proxyServer(), "");
+
+ fProxyPort=fConfig->readNumEntry(MALConduitFactory::proxyPort(), 0);
+ fProxyUser=fConfig->readEntry(MALConduitFactory::proxyUser(), "");
+ fProxyPassword=fConfig->readEntry(MALConduitFactory::proxyPassword(), "");
+}
+
+
+
+void MALConduit::saveConfig() {
+ FUNCTIONSETUP;
+ KConfigGroupSaver g(fConfig, MALConduitFactory::group());
+ fConfig->writeEntry(MALConduitFactory::lastSync(), QDateTime::currentDateTime());
+}
+
+
+
+bool MALConduit::skip() {
+ QDateTime now=QDateTime::currentDateTime();
+ if (!fLastSync.isValid() || !now.isValid()) return false;
+
+ switch (eSyncTime) {
+ case eEveryHour:
+ if ( (fLastSync.secsTo(now)<=3600) && (fLastSync.time().hour()==now.time().hour()) ) return true;
+ else return false;
+ case eEveryDay:
+ if ( fLastSync.date() == now.date() ) return true;
+ else return false;
+ case eEveryWeek:
+ if ( (fLastSync.daysTo(now)<=7) && ( fLastSync.date().dayOfWeek()<=now.date().dayOfWeek()) ) return true;
+ else return false;
+ case eEveryMonth:
+ if ( (fLastSync.daysTo(now)<=31) && (fLastSync.date().month()==now.date().month()) ) return true;
+ else return false;
+ case eEverySync:
+ default:
+ return false;
+ }
+ return false;
+}
+
+
+
+/* virtual */ bool MALConduit::exec() {
+ FUNCTIONSETUP;
+
+ if (!fConfig) {
+ kdWarning() << k_funcinfo << ": No config file was set!" << endl;
+ return false;
+ }
+
+ readConfig();
+
+ if (skip()) {
+ emit logMessage(i18n("Skipping MAL sync, because last synchronization was not long enough ago."));
+ emit syncDone(this);
+ return true;
+ }
+
+ // Set all proxy settings
+ switch (eProxyType) {
+ case eProxyHTTP:
+ if (fProxyServer.isEmpty()) break;
+ setHttpProxy(fProxyServer.latin1());
+ if (fProxyPort>0 && fProxyPort<65536) setHttpProxyPort( fProxyPort );
+ else setHttpProxyPort(80);
+
+ if (!fProxyUser.isEmpty()) {
+ setProxyUsername( fProxyUser.latin1() );
+ if (!fProxyPassword.isEmpty()) setProxyPassword( fProxyPassword.latin1() );
+ }
+ break;
+ case eProxySOCKS:
+ setSocksProxy( fProxyServer.latin1() );
+ if (fProxyPort>0 && fProxyPort<65536) setSocksProxyPort( fProxyPort );
+ else setSocksProxyPort(1080);
+ break;
+ default:
+ break;
+ }
+
+
+ // Now initiate the sync.
+ PalmSyncInfo* pInfo=syncInfoNew();
+ if (!pInfo) {
+ kdWarning() << k_funcinfo << ": Could not allocate SyncInfo!" << endl;
+ emit logError(i18n("MAL synchronization failed (no SyncInfo)."));
+ return false;
+ }
+ malsync( pilotSocket(), pInfo);
+ syncInfoFree(pInfo);
+
+ saveConfig();
+ emit syncDone(this);
+ return true;
+}
+
+\end{verbatim}
+}
+
+When you use an external library to do the sync, the external functions need a reference to the current connection to the handheld. In the pilot-link library, which is the base for all of KPilot's communication with the handheld, this is implemented via an integer identifier, which can be obtained by the function \texttt{pilotSocket()} of the SyncAction class.
+
+The libmal also needs some internal data structed "PalmSyncInfo", which is obtained by its own syncInfoNew() function, but this part is libmal-specific.
+
+Another issue is how to propagate log messages from the external library to KPilot's log window. SyncAction provides slots logError, logMessage and logProgress to put messages into KPilot's sync log. All you have to do is to call
+\begin{verbatim}
+emit logMessage(i18n("My own log message"));
+\end{verbatim}
+
+The problem with these slots is that they are Qt-specific, while most libraries are written in C, and expect a hook function that will be called whenever a message needs to be written out. Unfortunately you cannot pass a member of your SyncAction-derived class, either, so the way out is to store a pointer to the current conduit instance (only one will be active at any time, anyway) in a static variable, and call the member method from this pointer:
+
+{\footnotesize
+\begin{verbatim}
+// static pointer to the current conduit instance
+static MALConduit *conduitInstance=0L;
+
+// The hook function which will be called by the library
+int malconduit_logf(const char *format, ...) {
+ FUNCTIONSETUP;
+ va_list val;
+ int rval;
+ va_start(val, format);
+#define WRITE_MAX_BUF 4096
+ char msg[WRITE_MAX_BUF];
+ msg[0]='\0';
+ rval=vsnprintf(&msg[0], sizeof(msg), format, val);
+ va_end(val);
+ if (rval == -1) {
+ msg[WRITE_MAX_BUF-1] = '\0';
+ rval=WRITE_MAX_BUF-1;
+ }
+ if (conduitInstance) {
+ conduitInstance->printLogMessage(msg);
+ } else {
+ // write out to stderr
+ kdWarning()<<msg<<endl;
+ }
+ return rval;
+}
+
+void MALConduit::printLogMessage(QString msg) {
+ FUNCTIONSETUP;
+ emit logMessage(msg);
+}
+
+// Here we have to set the hooks for libmal to call.
+MALConduit::MALConduit(KPilotDeviceLink * o,
+ const char *n,
+ const QStringList & a) :
+ ConduitAction(o, n, a)
+{
+ FUNCTIONSETUP;
+ register_printStatusHook(malconduit_logf);
+ register_printErrorHook(malconduit_logf);
+ conduitInstance=this;
+ (void) MAL_conduit_id;
+}
+\end{verbatim}
+}
+
+
+
+\section{A per-file conduit: docconduit}\label{SectionDatabasesConduit}
+
+The PalmDoc conduit of KPilot takes a directory of text files and synchronized them with PalmDOC databases on the handheld. These PalmDOC documents can be read with AportisDoc, TealReader, and modified with applications like QED. Optionally, the conduit can also keep local copies of the pdb handheld databases in a local directory.
+
+The conduit just needs to find out if a document has changed either on the handheld or on the pc (or on both sides), and then copy the text either to or from the handheld. The docconduit has a class \class{DOCConverter} which does the actual conversion. You only have to set the local path to the text file, and give a pointer to an opened \class{PilotDatabase} (either \class{PilotLocalDatabase} or \class{PilotSerialDatabase}), and then call
+\code{docconverter.convertPDBtoDOC();} or \code{docconverter.convertDOCtoPDB();}. I will not explain this class here, but rather the algorithm to determine the sync direction and the actual calls of the DOCConverter.
+
+The conduit has to find out
+\begin{itemize}
+\item which PalmDoc databases on the handheld have been changed or edited (using the modified flag of the records inside the database)
+\item which text files on disk have changed (using an md5 checksum on the text)
+\item if a local copy is kept, if the local copy of a database has been changed or added (again using the modified flat of the records inside the database).
+\end{itemize}
+
+To assure a responsive user interface, we will once again use \texttt{QTimer::singleShot(this, 0, SLOT(whatever()));} for each of these steps.
+
+The \code{DOCConduit::exec()} function is just the entry point and calls syncNextDB, which will go through all PalmDOC databases on the handheld and determine if any of them has been changed:
+
+{\footnotesize
+\begin{verbatim}
+/* virtual */ bool DOCConduit::exec() {
+ FUNCTIONSETUP;
+ readConfig();
+ dbnr=0;
+ QTimer::singleShot(0, this, SLOT(syncNextDB()));
+ return true;
+}
+\end{verbatim}
+}
+
+
+
+syncNextDB then walks through all PalmDoc databases on the handheld and decides if they are supposed to be synced to the PC. The function needsSync (which we will describe later), checks which files have actually changed or were added or deleted and so determines the sync direction. The docSyncInfo is just an internal structure to store all information about the text:
+
+{\footnotesize
+\begin{verbatim}
+void DOCConduit::syncNextDB() {
+ FUNCTIONSETUP;
+ DBInfo dbinfo;
+
+ if (eSyncDirection==eSyncPCToPDA || fHandle->findDatabase(NULL, &dbinfo, dbnr, dbtype(), dbcreator() /*, cardno */ ) < 0) {
+ // no more databases available, so check for PC->Palm sync
+ QTimer::singleShot(0, this, SLOT(syncNextDOC()));
+ return;
+ }
+ dbnr=dbinfo.index+1;
+ DEBUGCONDUIT<<"Next Palm database to sync: "<<dbinfo.name<<", Index="<<dbinfo.index<<endl;
+
+ // if creator and/or type don't match, go to next db
+ if (!isCorrectDBTypeCreator(dbinfo) || fDBNames.contains(dbinfo.name)) {
+ QTimer::singleShot(0, this, SLOT(syncNextDB()));
+ return;
+ }
+
+ QString docfilename=constructDOCFileName(dbinfo.name);
+ QString pdbfilename=constructPDBFileName(dbinfo.name);
+
+ docSyncInfo syncInfo(dbinfo.name, docfilename, pdbfilename, eSyncNone);
+ syncInfo.dbinfo=dbinfo;
+ needsSync(syncInfo);
+ fSyncInfoList.append(syncInfo);
+ fDBNames.append(dbinfo.name);
+
+ QTimer::singleShot(0, this, SLOT(syncNextDB()));
+ return;
+}
+\end{verbatim}
+}
+
+To go through all .txt files on disk, we use a QStringList::Iterator, again set the fields of the docSyncInfo for each text, and call \code{needsSync} to do the actual comparison of the local and handheld text to the versions of the previous sync. If a local copy of the pdb files should be kept, we proceed similar using the slot \code{checkPDBFiles}:
+
+{\footnotesize
+\begin{verbatim}
+void DOCConduit::syncNextDOC() {
+ FUNCTIONSETUP;
+
+ if (eSyncDirection==eSyncPDAToPC ) {
+ // We don't sync from PC to PDB, so start the conflict resolution and then the actual sync process
+ docnames.clear();
+ QTimer::singleShot(0, this, SLOT(checkPDBFiles()));
+ return;
+ }
+
+ // if docnames isn't initialized, get a list of all *.txt files in fDOCDir
+ if (docnames.isEmpty()/* || dociterator==docnames.end() */) {
+ docnames=QDir(fDOCDir, "*.txt").entryList() ;
+ dociterator=docnames.begin();
+ }
+ if (dociterator==docnames.end()) {
+ // no more databases available, so start the conflict resolution and then the actual sync proces
+ docnames.clear();
+ QTimer::singleShot(0, this, SLOT(checkPDBFiles()));
+ return;
+ }
+
+ QString fn=(*dociterator);
+
+ QDir dr(fDOCDir);
+ QFileInfo fl(dr, fn );
+ QString docfilename=fl.absFilePath();
+ QString pdbfilename;
+ dociterator++;
+
+ DBInfo dbinfo;
+ // Include all "extensions" except the last. This allows full stops inside the database name (e.g. abbreviations)
+ // first fill everything with 0, so we won't have a buffer overflow.
+ memset(&dbinfo.name[0], 0, 33);
+ strncpy(&dbinfo.name[0], fl.baseName(TRUE), 30);
+
+ bool alreadySynced=fDBNames.contains(dbinfo.name);
+ if (!alreadySynced) {
+ docSyncInfo syncInfo(dbinfo.name, docfilename, pdbfilename, eSyncNone);
+ syncInfo.dbinfo=dbinfo;
+ needsSync(syncInfo);
+ fSyncInfoList.append(syncInfo);
+ fDBNames.append(dbinfo.name);
+ }
+
+ QTimer::singleShot(0, this, SLOT(syncNextDOC()));
+ return;
+}
+
+
+/** This slot will only be used if fKeepPDBLocally to check if new doc databases have been copied to the pdb directory.
+ * If so, install it to the handheld and sync it to the PC */
+void DOCConduit::checkPDBFiles() {
+ FUNCTIONSETUP;
+
+ if (fLocalSync || !fKeepPDBLocally || eSyncDirection==eSyncPCToPDA )
+ {
+ // no more databases available, so check for PC->Palm sync
+ QTimer::singleShot(0, this, SLOT(resolve()));
+ return;
+ }
+
+ // Walk through all files in the pdb directory and check if it has already been synced.
+ // if docnames isn't initialized, get a list of all *.pdb files in fPDBDir
+ if (docnames.isEmpty()/* || dociterator==docnames.end() */) {
+ docnames=QDir(fPDBDir, "*.pdb").entryList() ;
+ dociterator=docnames.begin();
+ }
+ if (dociterator==docnames.end()) {
+ // no more databases available, so start the conflict resolution and then the actual sync proces
+ docnames.clear();
+ QTimer::singleShot(0, this, SLOT(resolve()));
+ return;
+ }
+
+ QString fn=(*dociterator);
+
+ QDir dr(fPDBDir);
+ QFileInfo fl(dr, fn );
+ QString pdbfilename=fl.absFilePath();
+ dociterator++;
+
+ // Get the doc title and check if it has already been synced (in the synced docs list of in fDBNames to be synced)
+ // If the doc title doesn't appear in either list, install it to the Handheld, and add it to the list of dbs to be synced.
+ QString dbname=fl.baseName(TRUE).left(30);
+ if (!fDBNames.contains(dbname) && !fDBListSynced.contains(dbname)) {
+ if (fHandle->installFiles(pdbfilename )) {
+ DBInfo dbinfo;
+ // Include all "extensions" except the last. This allows full stops inside the database name (e.g. abbreviations)
+ // first fill everything with 0, so we won't have a buffer overflow.
+ memset(&dbinfo.name[0], 0, 33);
+ strncpy(&dbinfo.name[0], dbname, 30);
+
+ docSyncInfo syncInfo(dbinfo.name, constructDOCFileName(dbname), pdbfilename, eSyncNone);
+ syncInfo.dbinfo=dbinfo;
+ needsSync(syncInfo);
+ fSyncInfoList.append(syncInfo);
+ fDBNames.append(dbinfo.name);
+ } else {
+ DEBUGCONDUIT<<"Could not install database "<<dbname<<" ("<<pdbfilename<<") to the handheld"<<endl;
+ }
+ }
+
+ QTimer::singleShot(0, this, SLOT(checkPDBFiles()));
+}
+\end{verbatim}
+}
+
+After all databases have been identified, we possibly need to do some conflict resolution in the slot \code{resolve()}. The conflict resolution dialog just displays the list of databases and lets the user choose the sync direction for each database. When the user presses Ok, the direction field of each docSyncInfo object is set to the chosen value.
+
+{\footnotesize
+\begin{verbatim}
+void DOCConduit::resolve() {
+ FUNCTIONSETUP;
+
+ for (fSyncInfoListIterator=fSyncInfoList.begin(); fSyncInfoListIterator!=fSyncInfoList.end(); fSyncInfoListIterator++) {
+ // Walk through each database and apply the conflictResolution option.
+ // the remaining conflicts will be resolved in the resolution dialog
+ if ((*fSyncInfoListIterator).direction==eSyncConflict){
+ DEBUGCONDUIT<<"We have a conflict for "<<(*fSyncInfoListIterator).handheldDB<<", default="<<eConflictResolution<<endl;
+ switch (eConflictResolution)
+ {
+ case eSyncPDAToPC:
+ DEBUGCONDUIT<<"PDA overrides for database "<<(*fSyncInfoListIterator).handheldDB<<endl;
+ (*fSyncInfoListIterator).direction = eSyncPDAToPC;
+ break;
+ case eSyncPCToPDA:
+ DEBUGCONDUIT<<"PC overrides for database "<<(*fSyncInfoListIterator).handheldDB<<endl;
+ (*fSyncInfoListIterator).direction = eSyncPCToPDA;
+ break;
+ case eSyncNone:
+ DEBUGCONDUIT<<"No sync for database "<<(*fSyncInfoListIterator).handheldDB<<endl;
+ (*fSyncInfoListIterator).direction = eSyncNone;
+ break;
+ case eSyncDelete:
+ case eSyncConflict:
+ default:
+ DEBUGCONDUIT<<"Conflict remains due to default resolution setting for database "<<(*fSyncInfoListIterator).handheldDB<<endl;
+ break;
+ }
+ }
+ }
+
+ // Show the conflict resolution dialog and ask for the action for each database
+ ResolutionDialog*dlg=new ResolutionDialog( 0, i18n("Conflict Resolution"), &fSyncInfoList , fHandle);
+ bool show=fAlwaysUseResolution || (dlg && dlg->hasConflicts);
+ if (show) {
+ if (!dlg || !dlg->exec() ) {
+ KPILOT_DELETE(dlg)
+ emit logMessage(i18n("Sync aborted by user."));
+ QTimer::singleShot(0, this, SLOT(cleanup()));
+ return;
+ }
+ }
+ KPILOT_DELETE(dlg)
+
+
+ // fDBNames will be filled with the names of the databases that are actually synced (not deleted), so I can write the list to the config file
+ fDBNames.clear();
+ fSyncInfoListIterator=fSyncInfoList.begin();
+ QTimer::singleShot(0,this, SLOT(syncDatabases()));
+ return;
+}
+\end{verbatim}
+}
+
+
+Finally, the actual sync of the databases is done again with \code{QTimer::singleShot}s in the slot \code{syncDatabases()}. Each entry in the list is processed in one pass of \code{syncDatabases}, and then \code{syncDatabases} is again called using a \code{QTimer::singleShot}, until all databases have been synced.
+
+{\footnotesize
+\begin{verbatim}
+void DOCConduit::syncDatabases() {
+ FUNCTIONSETUP;
+ if (fSyncInfoListIterator==fSyncInfoList.end()) {
+ QTimer::singleShot(0, this, SLOT(cleanup()));
+ return;
+ }
+
+ docSyncInfo sinfo=(*fSyncInfoListIterator);
+ fSyncInfoListIterator++;
+
+ switch (sinfo.direction) {
+ case eSyncConflict:
+ DEBUGCONDUIT<<"Entry "<<sinfo.handheldDB<<"( docfilename: "<<sinfo.docfilename<<
+ ", pdbfilename: "<<sinfo.pdbfilename<<") had sync direction eSyncConflict!!!"<<endl;
+ break;
+ case eSyncDelete:
+ case eSyncPDAToPC:
+ case eSyncPCToPDA:
+ emit logMessage(i18n("Synchronizing text \"%1\"").arg(sinfo.handheldDB));
+ if (!doSync(sinfo)) {
+ // The sync could not be done, so inform the user (the error message should probably issued inside doSync)
+ DEBUGCONDUIT<<"There was some error syncing the text \""<<sinfo.handheldDB<<"\" with the file "<<sinfo.docfilename<<endl;
+ }
+ break;
+ case eSyncNone:
+// case eSyncAll:
+ break;
+ }
+ if (sinfo.direction != eSyncDelete) fDBNames.append(sinfo.handheldDB);
+
+ QTimer::singleShot(0,this, SLOT(syncDatabases()));
+ return;
+}
+\end{verbatim}
+}
+
+The actual sync is done by the function \code{doSync(docSyncInfo\&)}, which first checks for deletion of the database as a special case. Otherwise, it uses the \class{DOCConverter} class to copy the text file to or from the handheld, and then recalculates the md5 checksum of the text file on disk and stores it in KPilot's config.
+
+{\footnotesize
+\begin{verbatim}
+bool DOCConduit::doSync(docSyncInfo &sinfo) {
+ bool res=false;
+
+ if (sinfo.direction==eSyncDelete) {
+ if (!sinfo.docfilename.isEmpty()) {
+ if (!QFile::remove(sinfo.docfilename)) {
+ kdWarning()<<i18n("Unable to delete the text file \"%1\" on the PC").arg(sinfo.docfilename)<<endl;
+ }
+ QString bmkfilename = sinfo.docfilename;
+ if (bmkfilename.endsWith(".txt")){
+ bmkfilename.remove(bmkfilename.length()-4, 4);
+ }
+ bmkfilename+=PDBBMK_SUFFIX;
+ if (!QFile::remove(bmkfilename)) {
+ DEBUGCONDUIT<<"Could not remove bookmarks file "<<bmkfilename<<" for database "<<sinfo.handheldDB<<endl;
+ }
+ }
+ if (!sinfo.pdbfilename.isEmpty() && fKeepPDBLocally) {
+ PilotLocalDatabase*database=new PilotLocalDatabase(fPDBDir, sinfo.dbinfo.name, false);
+ if (database) {
+ if ( database->deleteDatabase() !=0 ) {
+ kdWarning()<<i18n("Unable to delete database \"%1\" on the PC").arg(sinfo.dbinfo.name)<<endl;
+ }
+ KPILOT_DELETE(database);
+ }
+ }
+ if (!fLocalSync) {
+ PilotDatabase *database=new PilotSerialDatabase(pilotSocket(), sinfo.dbinfo.name);
+ if ( database->deleteDatabase() !=0 ) {
+ kdWarning()<<i18n("Unable to delete database \"%1\" from the handheld").arg(sinfo.dbinfo.name)<<endl;
+ }
+ KPILOT_DELETE(database);
+ }
+ return true;
+ }
+ // preSyncAction should initialize the custom databases/files for the
+ // specific action chosen for this db and return a pointer to a docDBInfo
+ // instance which points either to a local database or a database on the handheld.
+ PilotDatabase *database = preSyncAction(sinfo);
+
+ if (database && ( !database->isOpen() ) ) {
+ DEBUGCONDUIT<<"Database "<<sinfo.dbinfo.name<<" does not yet exist. Creating it:"<<endl;
+ if (!database->createDatabase(dbcreator(), dbtype()) ) {
+ DEBUGCONDUIT<<"Failed"<<endl;
+ }
+ }
+
+ if (database && database->isOpen()) {
+ DOCConverter docconverter;
+ connect(&docconverter, SIGNAL(logError(const QString &)), SIGNAL(logError(const QString &)));
+ connect(&docconverter, SIGNAL(logMessage(const QString &)), SIGNAL(logMessage(const QString &)));
+
+ docconverter.setDOCpath(fDOCDir, sinfo.docfilename);
+ docconverter.setPDB(database);
+ docconverter.setBookmarkTypes(fBookmarks);
+ docconverter.setCompress(fCompress);
+
+ switch (sinfo.direction) {
+ case eSyncPDAToPC:
+ res = docconverter.convertPDBtoDOC();
+ break;
+ case eSyncPCToPDA:
+ res = docconverter.convertDOCtoPDB();
+ break;
+ default:
+ break;
+ }
+
+ // Now calculate the md5 checksum of the PC text and write it to the config file
+ {
+ KConfigGroupSaver g(fConfig, DOCConduitFactory::fGroup);
+ KMD5 docmd5;
+ QFile docfile(docconverter.docFilename());
+ if (docfile.open(IO_ReadOnly)) {
+ docmd5.update(docfile);
+ QString thisDigest(docmd5.hexDigest().data());
+ fConfig->writeEntry(docconverter.docFilename(), thisDigest);
+ fConfig->sync();
+ DEBUGCONDUIT<<"MD5 Checksum of the text "<<sinfo.docfilename<<" is "<<thisDigest<<endl;
+ } else {
+ DEBUGCONDUIT<<"couldn't open file "<<docconverter.docFilename()<<" for reading!!!"<<endl;
+ }
+ }
+
+ if (!postSyncAction(database, sinfo, res))
+ emit logError(i18n("Unable to install the locally created PalmDOC %1 to the handheld.").arg(sinfo.dbinfo.name));
+ if (!res)
+ emit logError(i18n("Conversion of PalmDOC \"%1\" failed.").arg(sinfo.dbinfo.name));
+// disconnect(&docconverter, SIGNAL(logError(const QString &)), SIGNAL(logError(const QString &)));
+// disconnect(&docconverter, SIGNAL(logMessage(const QString &)), SIGNAL(logMessage(const QString &)));
+// KPILOT_DELETE(database);
+ }
+ else
+ {
+ emit logError(i18n("Unable to open or create the database %1").arg(sinfo.dbinfo.name));
+ }
+ return res;
+}
+
+\end{verbatim}
+}
+
+
+After the sync is done, just call cleanup and emit the \code{syncDone} signal:
+
+{\footnotesize
+\begin{verbatim}
+void DOCConduit::cleanup() {
+ FUNCTIONSETUP;
+
+ KConfigGroupSaver g(fConfig, DOCConduitFactory::fGroup);
+ fConfig->writeEntry(DOCConduitFactory::fDOCList, fDBNames);
+ fConfig->sync();
+
+ emit syncDone(this);
+}
+\end{verbatim}
+}
+
+
+
+The worst part about the conduit is to find out which side has been changed (and how), and what needs to be done about this. The function \code{needsSync} does exactly this. If the database was not included in the last sync, it is new, so it will be synced from the side where it was added.
+
+First, we find out, how each of the two sides have changed.
+If the database was already included, check if it was changed using the function \code{textChanged} to compare the md5 checksum of the current text on disk with the checksum of the last sync (stored in kpilot's config). The handheld side is a bit trickier: A PalmDOC on the handheld contains of a header record, several text records, and finally several bookmark records. Each of these records can have the dirty flag set, so we first get the number of text records from the header record. Then we search for the index of the first changed record (i.e. dirty flag set) after the header record. If no text record (but a bookmark record) was changed, a config setting determines if the PalmDOC should still be considered as changed.
+
+Finally, from the status of the two sides, determine the sync direction:
+
+{\footnotesize
+\begin{verbatim}
+bool DOCConduit::needsSync(docSyncInfo &sinfo)
+{
+ FUNCTIONSETUP;
+ sinfo.direction = eSyncNone;
+
+ PilotDatabase*docdb=openDOCDatabase(sinfo.dbinfo.name);
+ if (!fDBListSynced.contains(sinfo.handheldDB)) {
+ // the database wasn't included on last sync, so it has to be new.
+ DEBUGCONDUIT<<"Database "<<sinfo.dbinfo.name<<" wasn't included in the previous sync!"<<endl;
+
+ if (QFile::exists(sinfo.docfilename)) sinfo.fPCStatus=eStatNew;
+ else sinfo.fPCStatus=eStatDoesntExist;
+ if (docdb && docdb->isOpen()) sinfo.fPalmStatus=eStatNew;
+ else sinfo.fPalmStatus=eStatDoesntExist;
+ KPILOT_DELETE(docdb);
+
+ if (sinfo.fPCStatus==eStatNew && sinfo.fPalmStatus==eStatNew) {
+ sinfo.direction=eSyncConflict;
+ return true;
+ };
+ if (sinfo.fPCStatus==eStatNew) {
+ sinfo.direction=eSyncPCToPDA;
+ return true;
+ }
+ if (sinfo.fPalmStatus==eStatNew) {
+ sinfo.direction=eSyncPCToPDA;
+ return true;
+ }
+ return true;
+ }
+
+ // Text was included in the last sync, so if one side doesn't exist, it was deleted and needs to be deleted from the other side, too
+ if (!QFile::exists(sinfo.docfilename)) sinfo.fPCStatus=eStatDeleted;
+ else if(textChanged(sinfo.docfilename)) {
+ sinfo.fPCStatus=eStatChanged;
+ DEBUGCONDUIT<<"PC side has changed!"<<endl;
+ // TODO: Check for changed bookmarks on the PC side
+ } else {
+ DEBUGCONDUIT<<"PC side has NOT changed!"<<endl;
+ }
+ if (!docdb || !docdb->isOpen()) sinfo.fPalmStatus=eStatDeleted;
+ else {
+ PilotRecord *firstRec = docdb->readRecordByIndex(0);
+ PilotDOCHead docHeader(firstRec);
+ KPILOT_DELETE(firstRec);
+
+ int storyRecs = docHeader.numRecords;
+
+ // determine the index of the next modified record (does it lie beyond the actual text records?)
+ int modRecInd=-1;
+ PilotRecord*modRec=docdb->readNextModifiedRec(&modRecInd);
+ DEBUGCONDUIT<<"Index of first changed record: "<<modRecInd<<endl;
+
+ KPILOT_DELETE(modRec);
+ // if the header record was changed, find out which is the first changed real document record:
+ if (modRecInd==0) {
+ modRec=docdb->readNextModifiedRec(&modRecInd);
+ DEBUGCONDUIT<<"Reread Index of first changed records: "<<modRecInd<<endl;
+ KPILOT_DELETE(modRec);
+ }
+
+ // The record index starts with 0, so only a negative number means no modified record was found
+ if (modRecInd >= 0) {
+// sinfo.fPalmStatus=eStatBookmarksChanged;
+ DEBUGCONDUIT<<"Handheld side has changed!"<<endl;
+ if ((!fIgnoreBmkChangesOnly) || (modRecInd <= storyRecs))
+ sinfo.fPalmStatus=eStatChanged;
+ DEBUGCONDUIT<<"PalmStatus="<<sinfo.fPalmStatus<<", condition="<<((!fIgnoreBmkChangesOnly) || (modRecInd <= storyRecs))<<endl;
+ } else {
+ DEBUGCONDUIT<<"Handheld side has NOT changed!"<<endl;
+ }
+ }
+ KPILOT_DELETE(docdb);
+
+ if (sinfo.fPCStatus == eStatNone && sinfo.fPalmStatus==eStatNone) {
+ DEBUGCONDUIT<<"Nothing has changed, not need for a sync."<<endl;
+ return false;
+ }
+ // if either is deleted, and the other is not changed, delete
+ if ( ((sinfo.fPCStatus == eStatDeleted) && (sinfo.fPalmStatus!=eStatChanged)) ||
+ ((sinfo.fPalmStatus == eStatDeleted) && (sinfo.fPCStatus!=eStatChanged)) ) {
+ DEBUGCONDUIT<<"Database was deleted on one side and not changed on the other -> Delete it."<<endl;
+ sinfo.direction=eSyncDelete;
+ return true;
+ }
+
+ // eStatDeleted (and both not changed) have already been treated, for all
+ // other values in combination with eStatNone, just copy the texts.
+ if (sinfo.fPCStatus==eStatNone) {
+ DEBUGCONDUIT<<"PC side has changed!"<<endl;
+ sinfo.direction=eSyncPDAToPC;
+ return true;
+ }
+
+ if (sinfo.fPalmStatus==eStatNone) {
+ sinfo.direction=eSyncPCToPDA;
+ return true;
+ }
+
+ // All other cases (deleted,changed), (changed, deleted), (changed,changed) create a conflict:
+ sinfo.direction=eSyncConflict;
+ return true;
+}
+
+\end{verbatim}
+}
+
+
+These code pieces from the docconduit are supposed to give you an insight into how to structure a conduit.
+
+
+
+
+
+
+\section{A record-based conduit}\label{SectionRecordBasedConduit}
+If you work with record-based conduits (e.g. addressbook, calendar conduits etc.), you might proceed similar to a document-based conduit (where records correspond to documents, of course), although you probably want to do the synchronization step immediately instead of storing all information about the states in a big list and only later sync the data. To dig deeper into the structure of such conduits (which I admit are the most common ones, but also the most complex), take a look at the addressbook conduit of KDE 3.1 (e.g. using KDE's webcvs at \htmladdnormallink{http://webcvs.kde.org/cgi-bin/cvsweb.cgi/kdepim/kpilot/conduits/abbrowserconduit/}{http://webcvs.kde.org/cgi-bin/cvsweb.cgi/kdepim/kpilot/conduits/abbrowserconduit/}).
+%TODO
+
+
+
+\section{Using KitchenSync in your conduit} \label{SectionKitchenSync}
+
+Currently none of the KPilot conduits use the KitchenSync framework, which
+is intended to be KDE's synchronization application of the future. Thus I cannot and will not
+describe how to use it for your conduits. In the future, however,
+KPilot will probably 's conduits will be ported to KitchenSync. For a quick overview over
+KitchenSync see Cornelius Schumacher's original proposal at \htmladdnormallink{http://pim.kde.org/development/ksync.php}{http://pim.kde.org/development/ksync.php}.
+
+Currently, the KitchenSync framework doesn't seem to be mature enough to replace KPilot's already very sophisticated conduits and their conflict resolution.
+Some time ago I mailed Holger Freyther (one of the KitchenSync authors) about the current state of KitschenSync, and asked several important questions. His answer is printed below. In my eyes, KitchenSync is just lacking too many important features to be able to replace KPilot soon (or rather port KPilot to KitchenSync):
+
+{\footnotesize
+\begin{verbatim}
+Re: [Kitchensync] [Kde-pim] Some Kitchensync questions
+From: Holger Freyther <[email protected]> (Opie)
+To: Reinhold Kainhofer <[email protected]>
+Date: 05.10.2002 00:01
+
+
+On Wednesday 18 September 2002 19:57, Reinhold Kainhofer wrote:
+> Hello,
+> Yesterday night I took a quick look at the kitchensync sources to find out
+> how kpilot might use it or how kpilot might need to be changed. Please
+> forgive me if some questions might be obvious or stupid, but I this is my
+> first look at kitchensync/ksync, and I didn't have too much time. Just give
+> me a hint on where to look. Additionally, it was very late at night, so my
+> brain wasn't working properly any more ;-))
+>
+> My questions will of course be from a Palm/handheld syncing view, so they
+> are quite specific concerning the current functionality of the conduits. I
+> wouldn't like switching to something that - in theory - has a better and
+> cleaner architecture, but for the next few years will provide less features
+> than we currently have.
+
+Thats good! so then we find problems because you look at it from a different
+point of view
+
+> 1) Do I understand it right from the ksync proposal on pim.kde.org that
+> kitchensync is the application that does all the communication with the
+> "devices" (korganizer, palm, opie, kabc, local files etc.), while ksync is
+> just the abstract library with the sync algorithm framework?
+
+It's a bit more.
+KitchenSync is the name of the whole framework (hmm deutsch oder englisch? ;)
+Konnector sind die Plugins, die Sachen vom Geraet holen, MetaDaten sammeln und
+schreiben
+KSync ist 1. ein Kontainer und 2. Syncing Interface
+und KitchenSyncApp ist ne part
+
+
+> 2) Do we have to ditch KPilot completely? So once again, once something in
+> kpilot seems to get stable, the underlying infrastructure changes, and
+> everything has to be completely rewritten from scratch.... That thought is
+> not very comforting to me, no matter how big the advantages of a unified
+> sync machinery seems.
+
+It would be a lost to just ditch KPilot. I would like to see a port of KPilot
+to KitchenSync where we improve the framework.
+
+
+> 3a) How can one sync the palm where you also have the backup record
+> available, so you possibly know how the record looked like (on the pc and
+> the palm side) after the previous sync
+
+The Palm Konnector would only have to care for the Palm side. There is
+something called MetaSyncing. If it is enabled the PalmKonnector is demanded
+to save the backend. Otherwise you do first syncs (just fetch it )
+
+> 3b) How can one achieve a "smart merge", i.e. from the backup record the
+> fields which have changed on the handheld and the pc are determined, and
+> the fields are merged, instead of copying the whole record over.
+
+This is part of KSync. Currently we don't have it but it's planned including
+intelligent conflict resolution.
+So what happens if the PC have a XYZ field but the Palm not. Now you change
+anything on the palm and on the next sync you want the Palm to take advance
+but not to lose the stuff in the other fields.
+So there needs to be this kind of merge. Fill the entry with all fields from
+the other record with the same uid but do not overwrite
+And then there needs to be the smart merge. Which will also be part of the
+KSync.
+But this is needed and will be added as soon as I find the time to do it.
+
+
+> 4) How can one use plugins that just copy something to the device and don't
+> need any record-based sync and conflict resolution (e.g. using libmal to
+> copy the AvantGo content to the palm).
+
+The KonnectorManager does allow you to either push QByteArrays or files behind
+filenames to the device.
+There is one short coming with it. It's asynchronus and currently no success
+or failure is emmitted.
+But when taking in consideration that you want to fetch anything from the
+device. You will need a special layer in Konnector which loads plugins for
+Konnectors which allow some sort of getting stuff from the device.
+This is also varpoware
+
+
+> 5) How about responsiveness of the front end? I realized there are no
+> QTimer::singleShot to let qt process the queue between syncing two records.
+> Or did I miss something?
+
+currenlty this is true. While we aim for ASYNC the syncing is currently
+synchron. I first want to get it right.
+
+
+> 6) How can one do the sync when you only know the changed records on one
+> side, but not those that stayed the same? Especially when working with
+> serial devices, minimizing the traffic is of very high priority, so I don't
+> think we should always transfer the whole calendar/todo/addressbook
+> database from and to the handheld (On windows to my surprise the sync of
+> these needs only about 3 seconds. We have to compete with that ...).
+
+This is implementation detail of the Konnector again. I would store all the
+records on my mighty PC
+
+
+> 7) What if the device (i.e. Palm) does not support timestamps in any form
+> for the records?
+
+This is a problem with Qtopia. QtopiaDesktop is using md5sums ( quite fast )
+for figuring changes.
+I've a copy of the files around and templates to do the diffing
+
+
+> 8) How can one achieve archived records (i.e. marked as quasi-deleted from
+> the palm and deleted after the sync, but they exist locally on the pc side.
+> They are NO LONGER synced to the device. As an example take past events.
+> You don't need them on the handheld any longer, but of course you don't
+> want to loose the history on the PC.).
+
+Not thought of ;)
+A field inside the SyncEntry and the KonnectorPlugin needs to honor that
+
+
+> 9) What if one side (handheld) does not support all features the pc side
+> supports? I.e. the palm only has 5 phone/email fields, while you can have
+> many more on the pc. The two addressbook items should still correspond and
+> even be equal, although one side has less information available.
+
+see above about merging
+
+
+> 10) Is there a daemon or does the whole app have to be in memory? (Sorry if
+> this should be obvious, it was very late when I looked through the code and
+> wrote down these questions)
+
+All in one for now
+
+
+> 11) Is it possible to sync a list of todos where the order of the entries
+> is important? (Needed for the Project Manager conduits). I realize that
+> korganizer disregards the order of the todos currently, but other
+> applications might use the ics file corretly (i.e. preserving the order)
+
+we're using Syncee's they should not sort
+
+
+I hope this helps
+
+regards Holger
+\end{verbatim}
+}
+
+
+%\section{Further ideas and thoughts}\label{SectionFurtherThoughts}
+%TODO
+
+
+
+
+\end{document}
+
diff --git a/kpilot/Documentation/ConduitProgrammingTutorial/mal-factory.cc b/kpilot/Documentation/ConduitProgrammingTutorial/mal-factory.cc
new file mode 100644
index 000000000..caa2ab20d
--- /dev/null
+++ b/kpilot/Documentation/ConduitProgrammingTutorial/mal-factory.cc
@@ -0,0 +1,123 @@
+/* Time-factory.cc KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This file defines the factory for the MAL-conduit plugin.
+*/
+
+#include "options.h"
+
+#include <kapplication.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+
+#include <time.h> // Needed by pilot-link include
+#include "mal-conduit.h"
+#include "mal-setup.h"
+
+#include "mal-factory.moc"
+
+
+extern "C"
+{
+
+void *init_libmalconduit()
+{
+ return new MALConduitFactory;
+}
+
+} ;
+
+
+// A number of static variables
+KAboutData *MALConduitFactory::fAbout = 0L;
+const char *MALConduitFactory::fGroup = "MAL-conduit";
+const char *MALConduitFactory::fLastSync = "Last MAL Sync";
+const char *MALConduitFactory::fSyncTime = "Sync Frequency";
+const char *MALConduitFactory::fProxyType = "Proxy Type";
+const char *MALConduitFactory::fProxyServer = "Proxy Server";
+const char *MALConduitFactory::fProxyPort = "Proxy Port";
+const char *MALConduitFactory::fProxyUser = "Proxy User";
+const char *MALConduitFactory::fProxyPassword = "Proxy Password";
+
+MALConduitFactory::MALConduitFactory(QObject *p, const char *n) :
+ KLibFactory(p,n)
+{
+ FUNCTIONSETUP;
+
+ fInstance = new KInstance("MALconduit");
+ fAbout = new KAboutData("MALconduit",
+ I18N_NOOP("MAL Synchronization Conduit for KPilot"),
+ KPILOT_VERSION,
+ I18N_NOOP("Synchronizes the content from MAL Servers like AvantGo to the Handheld"),
+ KAboutData::License_GPL,
+ "(C) 2002, Reinhold Kainhofer");
+ fAbout->addAuthor("Reinhold Kainhofer",
+ I18N_NOOP("Primary Author"), "[email protected]", "http://reinhold.kainhofer.com/");
+ fAbout->addAuthor("Jason Day",
+ I18N_NOOP("Author of libmal and the JPilot AvantGo conduit"), "[email protected]");
+ fAbout->addAuthor("Tom Whittaker",
+ I18N_NOOP("Author of syncmal"), "[email protected]", "http://www.tomw.org/");
+ fAbout->addAuthor("AvantGo, Inc.",
+ I18N_NOOP("Authors of the malsync library (c) 1997-1999"), "www.avantgo.com", "http://www.avantgo.com/");
+}
+
+MALConduitFactory::~MALConduitFactory()
+{
+ FUNCTIONSETUP;
+
+ KPILOT_DELETE(fInstance);
+ KPILOT_DELETE(fAbout);
+}
+
+/* virtual */ QObject *MALConduitFactory::createObject( QObject *p,
+ const char *n,
+ const char *c,
+ const QStringList &a)
+{
+ FUNCTIONSETUP;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Creating object of class "
+ << c
+ << endl;
+#endif
+
+ if (qstrcmp(c,"ConduitConfig")==0)
+ {
+ QWidget *w = dynamic_cast<QWidget *>(p);
+
+ if (w)
+ {
+ return new MALWidgetSetup(w,n,a);
+ }
+ else
+ {
+ kdError() << k_funcinfo
+ << ": Couldn't cast parent to widget."
+ << endl;
+ return 0L;
+ }
+ }
+
+ if (qstrcmp(c,"SyncAction")==0)
+ {
+ KPilotDeviceLink *d = dynamic_cast<KPilotDeviceLink *>(p);
+
+ if (d)
+ {
+ return new MALConduit(d,n,a);
+ }
+ else
+ {
+ kdError() << k_funcinfo
+ << ": Couldn't cast parent to KPilotDeviceLink"
+ << endl;
+ return 0L;
+ }
+ }
+
+ return 0L;
+}
+
diff --git a/kpilot/Documentation/ConduitProgrammingTutorial/mal-factory.h b/kpilot/Documentation/ConduitProgrammingTutorial/mal-factory.h
new file mode 100644
index 000000000..b92b9cb9e
--- /dev/null
+++ b/kpilot/Documentation/ConduitProgrammingTutorial/mal-factory.h
@@ -0,0 +1,54 @@
+#ifndef _TIME_FACTORY_H
+#define _TIME_FACTORY_H
+/* MAL-factory.h KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This file defines the factory for the mal-conduit plugin.
+*/
+
+#include <klibloader.h>
+
+class KInstance;
+class KAboutData;
+
+class MALConduitFactory : public KLibFactory
+{
+Q_OBJECT
+
+public:
+ MALConduitFactory(QObject * = 0L,const char * = 0L);
+ virtual ~MALConduitFactory();
+
+ static KAboutData *about() { return fAbout; } ;
+ static const char *lastSync() { return fLastSync; };
+ static const char *syncTime() {return fSyncTime;};
+ static const char *proxyType() {return fProxyType;};
+ static const char *proxyServer() {return fProxyServer;};
+ static const char *proxyPort() {return fProxyPort;};
+ static const char *proxyUser() {return fProxyUser;};
+ static const char *proxyPassword() {return fProxyPassword;};
+ static const char *malServer() {return fMALServer;};
+ static const char *malPort() {return fMALPort;};
+ static const char *malUser() {return fMALUser;};
+ static const char *malPassword() {return fMALPassword;};
+
+protected:
+ virtual QObject* createObject( QObject* parent = 0,
+ const char* name = 0,
+ const char* classname = "QObject",
+ const QStringList &args = QStringList() );
+private:
+ KInstance *fInstance;
+ static KAboutData *fAbout;
+ // KConfig entry keys.
+ static const char *fGroup;
+ static const char *fLastSync, *fSyncTime,
+ *fProxyType, *fProxyServer, *fProxyPort, *fProxyUser, *fProxyPassword;
+} ;
+
+extern "C" {
+ void *init_libmalconduit();
+} ;
+
+#endif
diff --git a/kpilot/Documentation/ConduitProgrammingTutorial/pictures/ConnectionsDialog.png b/kpilot/Documentation/ConduitProgrammingTutorial/pictures/ConnectionsDialog.png
new file mode 100644
index 000000000..0ed0997f8
--- /dev/null
+++ b/kpilot/Documentation/ConduitProgrammingTutorial/pictures/ConnectionsDialog.png
Binary files differ
diff --git a/kpilot/Documentation/ConduitProgrammingTutorial/pictures/NoLayoutDialog.png b/kpilot/Documentation/ConduitProgrammingTutorial/pictures/NoLayoutDialog.png
new file mode 100644
index 000000000..64e088a2c
--- /dev/null
+++ b/kpilot/Documentation/ConduitProgrammingTutorial/pictures/NoLayoutDialog.png
Binary files differ
diff --git a/kpilot/Documentation/ConduitProgrammingTutorial/pictures/ProxyTab.png b/kpilot/Documentation/ConduitProgrammingTutorial/pictures/ProxyTab.png
new file mode 100644
index 000000000..2cc9cd540
--- /dev/null
+++ b/kpilot/Documentation/ConduitProgrammingTutorial/pictures/ProxyTab.png
Binary files differ
diff --git a/kpilot/Documentation/HOWTO-CODE.txt b/kpilot/Documentation/HOWTO-CODE.txt
new file mode 100644
index 000000000..99c093c67
--- /dev/null
+++ b/kpilot/Documentation/HOWTO-CODE.txt
@@ -0,0 +1,112 @@
+Coding Guidelines for KPilot
+============================
+
+Of course we can wage war about what constitutes "good programming
+practice". And agreeing on indentation style is difficult as well.
+Below you can find the guidelines I try to stick to when writing
+KPilot, split into "C++ Source Code" and "Header Files".
+
+(For actual coding information and some information about how
+KPilot works, see HOWTO-CONDUIT.txt)
+
+
+C++ Source Code
+===============
+
+There are coding guidelines for KDE somewhere. I think they say
+indent with 4 spaces, { on same line, } on separate line. I disagree,
+so code I write -- and code I maintain -- slowly mutates to
+
+ * Indent with tabs
+ * { and } on separate lines
+ * C comments only for the GPL header and KDoc stuff
+ * C++ before the stuff they document, same indent level,
+ with possibly two extra lines with just // to set the
+ comment off from the code.
+
+Whether or not anyone else follows is irrelevant, and I do try to
+avoid gratuitous reformatting. Honest.
+
+What I might do every now and then to get stuff "into shape" (and
+I'd really appreciate it if you did so too before sending me patches)
+is the following horrible invocation of indent:
+
+indent -kr \
+ --blank-lines-after-declarations \
+ --braces-after-if-line \
+ --dont-cuddle-else \
+ --dont-line-up-parentheses \
+ --honour-newlines \
+ --space-after-cast \
+ --brace-indent 0 \
+ --case-brace-indentation 0 \
+ --case-indentation 0 \
+ --continuation-indentation 8 \
+ --indent-level 8 \
+ --tab-size 8 \
+ --line-length 78
+
+This doesn't yield "perfect" code but it's close to my personal ideal.
+If this coding style gives you gas, just use your own favorite indent
+invocation to change it all back.
+
+NOTE: indent wreaks havoc with C++ class definitions in header files,
+so it's best not to touch those with it.
+
+
+Header Files
+============
+
+One thing we *do* need to agree on is how to protect
+.h files from double-inclusion. In Qt and KDE there's:
+
+ #ifndef QTCLASS_H
+ #ifndef _KDECLASS_H
+
+so for KPilot the convention will be
+
+ #ifndef _KPILOT_FILENAME_H
+
+where KPILOT is literal, ie. options.h is _KPILOT_OPTIONS_H and,
+unfortunately, kpilotOptions.h is _KPILOT_KPILOTOPTIONS_H. This is
+because the filename and the class don't always match up and not
+every file contains a class of interest.
+
+
+DEBUG Output
+============
+
+There are macros defined in options.h (which every source file
+should include) that provide some uniform debugging output.
+These are:
+
+ * FUNCTIONSETUP - Use this at the beginning of every function
+ (or those that are vaguely interesting). This will print out
+ a call trace indicator when debugging is on. It also defines
+ a local symbol fname for use with DEBUG* below.
+ * FUNCTIONSETUPL(level) - Use this at the beginning of a function.
+ It is like FUNCTIONSETUP but only prints if the debug level
+ is at least @p level. This avoids excessive debug output from
+ common functions.
+
+For regular debugging output, use one of the three DEBUG* macros:
+
+ * DEBUGLIBRARY in code in lib/
+ * DEBUGKPILOT in code in kpilot/
+ * DEBUGCONDUIT in code in conduits/
+
+This sends the debug output to the appropriate debug area. A typical
+debug output stream looks like this:
+
+ DEBUGKPILOT << fname << ": "
+ << actual debug info
+ << endl;
+
+Here, DEBUGKPILOT depends on what bit of code is being debugged; fname
+is defined by FUNCTIONSETUP and takes care of proper indentation for
+the call trace, the colon is for consistency and the actual debug
+info can be whatever you want.
+
+ Adriaan de Groot
+ March 5th 2001
+ September 5th 2001 (revised)
diff --git a/kpilot/Documentation/HOWTO-CONDUIT.txt b/kpilot/Documentation/HOWTO-CONDUIT.txt
new file mode 100644
index 000000000..7b6dccd0b
--- /dev/null
+++ b/kpilot/Documentation/HOWTO-CONDUIT.txt
@@ -0,0 +1,67 @@
+One of the greatest assets of the Palm Pilot is its ability to
+interconnect with other applications. KPilot supports this capabilty
+through conduits. A conduit is a small shared library that is loaded by
+the daemon during the hot sync. The conduit translates between the Palm
+Pilot and the application you're syncing with.
+
+*** How it works
+
+KPilot is divided into three major components: the GUI, the
+syncing daemon, and the conduits. The GUI part is actually irrelevant
+for the operation of the daemon, although it _is_ required for the
+configuration dialog (and possibly viewing databases). In theory
+you could run the daemon on a box without even starting X, although
+that is difficult (in particular, how would you do conflict resolution?).
+
+The daemon sits around and polls the configured device every second or
+so (there are devices where this should be more often, I think). Once
+data arrives (and the device exists, consider hotplug with USB), the
+daemon enters sync mode, and constructs a queue of SyncActions to perform.
+These vary from checking the Pilot's username to performing full backups
+to -- whatever sync actions the conduits provide. This means that during
+a sync the shared library containing a conduit is loaded, a factory
+function is called to produce an Action, this action is run, and the
+library unloaded.
+
+*** How the conduits work
+
+The conduits can actually be divided into two parts: the configuration
+widget, and the Action. Both are produced by a factory function in
+the shared library. The conduits have only one really interesting method
+that they must override, and that is exec(). When this is called the
+conduit is already set up with a socket descriptor and the conduit should
+quickly do its thing. In particular, conduits can't just sleep(45) and
+continue, since the connection with the Pilot will time out.
+
+*** Write your very own conduit
+
+Writing a conduit is actually rather easy. The conduit class
+should inherit from ConduitAction and override the exec() method
+(which actually comes from SyncAction).
+
+
+*** Debugging things
+
+lib/options.h contains two defines that are really important for
+debugging. These are
+
+ // #define DEBUG (1)
+ // #define DEBUG_CERR (1)
+
+Uncommenting DEBUG will enable most of the debug information in
+KPilot. Uncommenting DEBUG_CERR will make debug output go direct
+to stderr (cerr) instead of through kdDebug. If in addition, you
+pass --debug N (say, N=1 or N=4) to KPilot or the daemon when you
+start them, they will print call traces (that's what FUNCTIONSETUP
+does, which you will see at the beginning of every function).
+
+Another useful tool is kpilotTest, which is in kpilot/kpilot. It
+is an uninstalled binary, which behaves like the daemon with a
+log window and which will run a single conduit. Something like:
+
+ kpilotTest -p /dev/ucom0 \ # port
+ -E conduit_knotes \ # .desktop file
+ -T # _really_ run
+
+use kpilotTest -L to list the installed conduits and their
+desktop files (look at the "In ..." lines).
diff --git a/kpilot/Documentation/README b/kpilot/Documentation/README
new file mode 100644
index 000000000..9810abc0b
--- /dev/null
+++ b/kpilot/Documentation/README
@@ -0,0 +1,17 @@
+kpilot/Documentation
+====================
+
+This directory contains information pertinent to the design of
+KPilot -- which is therefore only really interesting for
+developers of KPilot conduits, maintainers, etc.
+
+Files in this directory are:
+
+README - This file
+README-3.2.1+ - The README for KPilot 3.2.1 with some changes
+ that refer to KPilot 4 and KDE2, so it's quite
+ confusing.
+README-4.0.0 - The real README for KPilot 4.0.0
+HOWTO-CONDUIT.txt - An introduction to writing conduits, last
+ updated for KPilot 3.1b9 (which is a LONG
+ time ago)
diff --git a/kpilot/Documentation/README-3.2.1+ b/kpilot/Documentation/README-3.2.1+
new file mode 100644
index 000000000..f32267b82
--- /dev/null
+++ b/kpilot/Documentation/README-3.2.1+
@@ -0,0 +1,156 @@
+KPILOT 4.0.0 by Dan Pilone
+===========================
+ Additional work by Robert Ambrose,
+ Preston Brown, Adriaan de Groot,
+ and probably many more.
+
+ KPilot is software for syncing the 3Com Palm Pilot and IBM Workpad
+(UNTESTED!) with a machine running some flavor of unix. The actual PC->PP
+communcations was originally based on pilot-link.0.8.7. By default it
+attempts to connnect using /dev/pilot which should be a link to the actual
+serial port, however this is configurable in the settings dialog.
+
+ Additional release notes can be found in the user documentation.
+The user documentation (translations in: en and de) can be found
+under kpilot/doc in this directory or in the KDE documentation directory
+under kpilot. Or run kpilot --htmlhelp to start the KDE help browser.
+
+
+Current features include:
+ * Now a KDE2 application.
+ o Plug in conduit support, currently including
+ KOrganizer, todolist, null and PopMail
+ o Hot-Sync daemon. - Now hot-sync with just the push of the
+ Hot-Sync button on your cradle. No need to launch KPilot.
+ o Add/Delete/Edit memos.
+ o Add/Delete/Edit addresses.
+ o Full Category support for both memos and addresses.
+ o KPilot now respects secret data.
+ o More configuration options including port speed and
+ docking control.
+ o Now supports signature files for email.
+ o Drag and drop to docked icon for file install.
+ o International Support
+ o Full Backup/Restore capabilities of Palm Pilot
+ o File (prc,pdb) installation
+ o Email syncing capabilities (via POP3 & sendmail)
+ o SmartSync backing up modified data even
+ for databases KPilot doesn't recognize
+ o Import/Export to/from virtually any text format for
+ Addresses.
+ o Import/Export to/from text files for memos
+ o Sort and display addresses in different ways
+ o A null conduit (programming example)
+ o Syncing with UNIX mailboxes
+ o Database dispositions (sync, backup only, or ignore)
+
+ (* = new in this release)
+
+INSTALLATION
+============
+ KPilot 4.0.0 _REQUIRES_ KDE 2 (http://www.kde.org/) and
+v2.2.0 or better of the QT widget set (http://www.troll.no/).
+KPilot also _REQUIRES_ pilot-link, which is not distributed with
+all the linux distro's out there. You may have to go looking.
+
+ If you have these packages, a simple (see *NOTE*):
+
+ ./configure
+ make
+ make install
+
+ from the kpilot-4.0.0 directory should configure and install KPilot.
+If you are using KPanel (the panel that comes with KDE) restarting it
+should insert an icon into the Utilities submenu. If you are not using
+KPanel, the executable is named kpilot and will be installed in either
+/opt/kde/bin/ or /usr/local/kde/bin (whichever is appropriate for your
+system).
+
+ In some cases KPilot will not compile due to configuration
+differences; in this case a less simple
+
+ autoconf
+ automake
+ ./configure
+ make
+ make install
+
+should do the trick. If this fails as well, you can subscribe to the
+KPilot mailing list and state the nature of the failure there.
+
+ *NOTE* that KPilot makes assumptions about where pilot-link and
+the Qt libraries are; in particular it is important to set QTDIR correctly
+(to the Qt 1.44 directories) when compiling KPilot. On many systems the
+command to do this will be
+
+ export QTDIR=/usr/lib/qt-2*
+
+but your mileage may vary. RedHat 6.2 systems ship with Qt 1.45 and Qt 2.1,
+in which case it is doubly important to set QTDIR properly.
+
+USING THE SOFTWARE
+==================
+ The user's documentation in the kpilot/doc directory is the
+best source for information on using KPilot.
+ When KPilot is run for the first time it will display the settings
+dialog. The default device is /dev/pilot (which should be a link to the
+proper device for the pilot) though this is configurable. Please verify
+this is correct.
+ IMPORTANT NOTE: the KPilot installation DOES NOT setup the serial
+link; your OS installation may also require special handling. See the
+section "Troubleshooting," below.
+ Other settings can be configured at this time but are
+not mandatory (though HIGHLY recommended). The one setting that you might
+want to take notice of is "Local overrides pilot". Setting this to true
+means that if both the local record and the pilot record are modified,
+during the next hot sync the local record will be considered the valid one
+and both will be set to that. By default the Pilot is considered to be the
+valid record and if both the local record and the pilot record have been
+modified the local is overwritten by the pilot copy.
+ Hitting "OK" will continue to the main KPilot screen.
+ It is recommended you preform a full backup of your Pilot at this
+point so that all of the data visible in KPilot is accurate and any
+importing or exporting is properly merged the next time you hot-sync.
+You can do a full backup of your Pilot by selecting Backup from the File
+Menu.
+
+TROUBLESHOOTING
+===============
+ The default serial device (/dev/pilot) does not exist on
+most systems. Be SURE to either (a) use the actual serial port the Pilot
+is attached to (i.e. /dev/ttyS0 for the device DOS calls COM1:) OR (b) set
+up the link to the actual serial port by running (as root) "ln -s
+/dev/ttySx /dev/pilot", where x is the number of the serial port. Note
+that some older Linux setups use /dev/cuax instead of /dev/ttySx.
+ If you're running Mandrake 7 and having trouble getting the
+daemon to start or KPilot can't connect to the daemon, check the system
+security setting. Sometimes local processes can't connect to *any*
+local ports.
+ More information is available in the user documentation.
+
+
+
+
+STANDARD DISCLAIMER, WARNINGS, ETC..
+====================================
+ THIS SOFTWARE HAS BUGS. Use at your own risk. It has not even
+been tested anywhere but on my machine and only with my Palm Pilot. I
+have been using it against XCopilot for development then verifying it
+works with a real pilot with my Palm Pilot Professional running OS v2.0.4.
+I make no claims that it will work, or even try to work. I take no
+responsibility for any data loss, damage, etc. done by this software.
+ie: Should your pilot burst into flames while trying to sync a new game..
+sorry.
+ That being said, I _really_ want comments regarding the software
+as well as suggestions. Bug fixes are even snazzier and code
+contributions are welcome. :)
+
+ Dan Pilone
+ http://www.slac.com/pilone/kpilot_home/
+ July 20, 2000
+
+ Adriaan de Groot
+ http://www.cs.kun.nl/~adridg/kpilot-bugs.html
+ July 20, 2000
diff --git a/kpilot/Documentation/README-4.0.0 b/kpilot/Documentation/README-4.0.0
new file mode 100644
index 000000000..f9fdccb13
--- /dev/null
+++ b/kpilot/Documentation/README-4.0.0
@@ -0,0 +1,103 @@
+KPILOT 4.0.0 by Dan Pilone
+===========================
+ Additional work by Robert Ambrose,
+ Preston Brown, Adriaan de Groot,
+ Heiko Purnhagen, Jorg Habenicht,
+ and probably many more.
+
+ KPilot is software for syncing the 3Com Palm Pilot, Palm III, IIIe,
+IIIc, IIIx, V, Vx, M100, Handspring Visor and IBM Workpad with a machine
+running some flavor of unix. The actual PC->PP communcations was originally
+based on pilot-link.0.8.7, though you should use pilot-link.0.9.3 now.
+By default KPilot attempts to connnect using /dev/pilot which should be
+a link to the actual serial port, however this is configurable in the
+settings dialog.
+
+ This is the first release of KPilot 4.x, the first version of
+KPilot that works with and under KDE2. It is released as part of KDE 2.1.
+
+INSTALLATION INSTRUCTIONS
+=========================
+
+ The file ../README contains minimal information on how to compile
+and install KPilot. Since KPilot is part of the kdepim package, you
+should also have the INSTALL file for kdepim, probably in ../../INSTALL.
+
+ This README file only contains the release notes for KPilot 4.0.0.
+
+UPGRADING FROM OLDER KPILOTS
+============================
+
+The first time you run KPilot 4.0.0, it will automatically display
+the setup screen and you can check all the configuration settings.
+If you used KPilot 3.x, you should also immediately configure all your
+conduits (again) because many things have changed there.
+
+CURRENT FEATURES
+================
+ * Conduit for KNotes.
+ * Now a KDE2 application.
+ o Plug in conduit support, currently including
+ KOrganizer, todolist, null and PopMail
+ o Hot-Sync daemon. - Now hot-sync with just the push of the
+ Hot-Sync button on your cradle. No need to launch KPilot.
+ o Add/Delete/Edit memos.
+ o Add/Delete/Edit addresses.
+ o Full Category support for both memos and addresses.
+ o KPilot now respects secret data.
+ o More configuration options including port speed and
+ docking control.
+ o Now supports signature files for email.
+ o Drag and drop to docked icon for file install.
+ o International Support
+ o Full Backup/Restore capabilities of Palm Pilot
+ o File (prc,pdb) installation
+ o Email syncing capabilities (via POP3 & sendmail)
+ o SmartSync backing up modified data even
+ for databases KPilot doesn't recognize
+ o Import/Export to/from virtually any text format for
+ Addresses.
+ o Import/Export to/from text files for memos
+ o Sort and display addresses in different ways
+ o A null conduit (programming example)
+ o Syncing with UNIX mailboxes
+ o Database dispositions (sync, backup only, or ignore)
+
+(* = new in this release)
+
+
+KNOWN BUGS
+==========
+ All the known bugs in KPilot can be found in the KDE bugs database
+
+ http://bugs.kde.org/db/pa/lkpilot.html
+
+Please check with that database before reporting bugs.
+
+
+
+
+STANDARD DISCLAIMER, WARNINGS, ETC..
+====================================
+ THIS SOFTWARE HAS BUGS. Use at your own risk. It has not even
+been tested anywhere but on my machine and only with my Palm Pilot. I
+have been using it against XCopilot for development then verifying it
+works with a real pilot with my Palm Pilot Professional running OS v2.0.4.
+It works with Adriaan's Palm V running PalmOS 3.5 as well.
+I make no claims that it will work, or even try to work. I take no
+responsibility for any data loss, damage, etc. done by this software.
+ie: Should your pilot burst into flames while trying to sync a new game..
+sorry.
+ That being said, I _really_ want comments regarding the software
+as well as suggestions. Bug fixes are even snazzier and code
+contributions are welcome. :)
+
+ Dan Pilone
+ http://www.slac.com/pilone/kpilot_home/
+ July 20, 2000
+
+ Adriaan de Groot
+ http://www.cs.kun.nl/~adridg/kpilot-bugs.html
+ February 24, 2001
diff --git a/kpilot/Documentation/README-4.2.1 b/kpilot/Documentation/README-4.2.1
new file mode 100644
index 000000000..71db72853
--- /dev/null
+++ b/kpilot/Documentation/README-4.2.1
@@ -0,0 +1,106 @@
+KPILOT 4.2.1 by Dan Pilone
+===========================
+ Additional work by Robert Ambrose,
+ Preston Brown, Adriaan de Groot,
+ Heiko Purnhagen, Jorg Habenicht,
+ and probably many more.
+
+ KPilot is software for syncing the 3Com Palm Pilot, Palm III, IIIe,
+IIIc, IIIx, V, Vx, M100, Handspring Visor and IBM Workpad with a machine
+running some flavor of unix. The actual PC->PP communcations was originally
+based on pilot-link.0.8.7, though you should use pilot-link.0.9.3 now.
+By default KPilot attempts to connnect using /dev/pilot which should be
+a link to the actual serial port, however this is configurable in the
+settings dialog.
+
+ This is the second release of KPilot 4.x, the first version of
+KPilot that works with and under KDE2. It is released as part of KDE 2.2.
+
+INSTALLATION INSTRUCTIONS
+=========================
+
+ The file ../README contains minimal information on how to compile
+and install KPilot. Since KPilot is part of the kdepim package, you
+should also have the INSTALL file for kdepim, probably in ../../INSTALL.
+
+ This README file only contains the release notes for KPilot 4.2.1.
+
+UPGRADING FROM OLDER KPILOTS
+============================
+
+The first time you run KPilot 4.2.1, it will automatically display
+the setup screen and you can check all the configuration settings.
+If you used KPilot 3.x, you should also immediately configure all your
+conduits (again) because many things have changed there.
+
+CURRENT FEATURES
+================
+ * Conduit for abbrowser (experimental).
+ * Conduit for expenses (experimental).
+ * Improved international-character support.
+ o Conduit for KNotes (still experimental).
+ o Now a KDE2 application.
+ o Plug in conduit support, currently including
+ KOrganizer, todolist, null and PopMail
+ o Hot-Sync daemon. - Now hot-sync with just the push of the
+ Hot-Sync button on your cradle. No need to launch KPilot.
+ o Add/Delete/Edit memos.
+ o Add/Delete/Edit addresses.
+ o Full Category support for both memos and addresses.
+ o KPilot now respects secret data.
+ o More configuration options including port speed and
+ docking control.
+ o Now supports signature files for email.
+ o Drag and drop to docked icon for file install.
+ o International Support
+ o Full Backup/Restore capabilities of Palm Pilot
+ o File (prc,pdb) installation
+ o Email syncing capabilities (via POP3 & sendmail)
+ o SmartSync backing up modified data even
+ for databases KPilot doesn't recognize
+ o Import/Export to/from virtually any text format for
+ Addresses.
+ o Import/Export to/from text files for memos
+ o Sort and display addresses in different ways
+ o A null conduit (programming example)
+ o Syncing with UNIX mailboxes
+ o Database dispositions (sync, backup only, or ignore)
+
+(* = new in this release)
+
+
+KNOWN BUGS
+==========
+ All the known bugs in KPilot can be found in the KDE bugs database
+
+ http://bugs.kde.org/db/pa/lkpilot.html
+
+Please check with that database before reporting bugs.
+
+
+
+
+STANDARD DISCLAIMER, WARNINGS, ETC..
+====================================
+ THIS SOFTWARE HAS BUGS. Use at your own risk. It has not even
+been tested anywhere but on my machine and only with my Palm Pilot. I
+have been using it against XCopilot for development then verifying it
+works with a real pilot with my Palm Pilot Professional running OS v2.0.4.
+It works with Adriaan's Palm V running PalmOS 3.5 as well.
+I make no claims that it will work, or even try to work. I take no
+responsibility for any data loss, damage, etc. done by this software.
+ie: Should your pilot burst into flames while trying to sync a new game..
+sorry.
+ That being said, I _really_ want comments regarding the software
+as well as suggestions. Bug fixes are even snazzier and code
+contributions are welcome. :)
+
+ Dan Pilone
+ http://www.slac.com/pilone/kpilot_home/
+ July 20, 2000
+
+ Adriaan de Groot
+ http://www.cs.kun.nl/~adridg/kpilot-bugs.html
+ April 11, 2001
diff --git a/kpilot/Documentation/README-4.2.2 b/kpilot/Documentation/README-4.2.2
new file mode 100644
index 000000000..604460fc7
--- /dev/null
+++ b/kpilot/Documentation/README-4.2.2
@@ -0,0 +1,108 @@
+KPILOT 4.2.2 by Dan Pilone
+===========================
+ Additional work by Robert Ambrose,
+ Preston Brown, Adriaan de Groot,
+ Heiko Purnhagen, Jorg Habenicht,
+ and probably many more.
+
+ KPilot is software for syncing the 3Com Palm Pilot, Palm III, IIIe,
+IIIc, IIIx, V, Vx, M100, Handspring Visor and IBM Workpad with a machine
+running some flavor of unix. The actual PC->PP communcations was originally
+based on pilot-link.0.8.7, though you should use pilot-link.0.9.3 now.
+By default KPilot attempts to connnect using /dev/pilot which should be
+a link to the actual serial port, however this is configurable in the
+settings dialog.
+
+ This is the second release of KPilot 4.x, the first version of
+KPilot that works with and under KDE2. It is released as part of KDE 2.2.
+KPilot 4.2.2 is the revision released AFTER KDE 2.2 alpha 1.
+
+INSTALLATION INSTRUCTIONS
+=========================
+
+ The file ../README contains minimal information on how to compile
+and install KPilot. Since KPilot is part of the kdepim package, you
+should also have the INSTALL file for kdepim, probably in ../../INSTALL.
+
+ This README file only contains the release notes for KPilot 4.2.2.
+
+UPGRADING FROM OLDER KPILOTS
+============================
+
+The first time you run KPilot 4.2.2, it may automatically display
+the setup screen and you can check all the configuration settings.
+If you used KPilot 3.x, you should also immediately configure all your
+conduits (again) because many things have changed there.
+
+CURRENT FEATURES
+================
+ * XML GUI support (courtesy of Martin Junius).
+ * Conduit for abbrowser (experimental).
+ * Conduit for expenses (experimental).
+ * Improved international-character support.
+ o Conduit for KNotes (still experimental).
+ o Now a KDE2 application.
+ o Plug in conduit support, currently including
+ KOrganizer, todolist, null and PopMail
+ o Hot-Sync daemon. - Now hot-sync with just the push of the
+ Hot-Sync button on your cradle. No need to launch KPilot.
+ o Add/Delete/Edit memos.
+ o Add/Delete/Edit addresses.
+ o Full Category support for both memos and addresses.
+ o KPilot now respects secret data.
+ o More configuration options including port speed and
+ docking control.
+ o Now supports signature files for email.
+ o Drag and drop to docked icon for file install.
+ o International Support
+ o Full Backup/Restore capabilities of Palm Pilot
+ o File (prc,pdb) installation
+ o Email syncing capabilities (via POP3 & sendmail)
+ o SmartSync backing up modified data even
+ for databases KPilot doesn't recognize
+ o Import/Export to/from virtually any text format for
+ Addresses.
+ o Import/Export to/from text files for memos
+ o Sort and display addresses in different ways
+ o A null conduit (programming example)
+ o Syncing with UNIX mailboxes
+ o Database dispositions (sync, backup only, or ignore)
+
+(* = new in this release)
+
+
+KNOWN BUGS
+==========
+ All the known bugs in KPilot can be found in the KDE bugs database
+
+ http://bugs.kde.org/db/pa/lkpilot.html
+
+Please check with that database before reporting bugs.
+
+
+
+
+STANDARD DISCLAIMER, WARNINGS, ETC..
+====================================
+ THIS SOFTWARE HAS BUGS. Use at your own risk. It has not even
+been tested anywhere but on my machine and only with my Palm Pilot. I
+have been using it against XCopilot for development then verifying it
+works with a real pilot with my Palm Pilot Professional running OS v2.0.4.
+It works with Adriaan's Palm V running PalmOS 3.5 as well.
+I make no claims that it will work, or even try to work. I take no
+responsibility for any data loss, damage, etc. done by this software.
+ie: Should your pilot burst into flames while trying to sync a new game..
+sorry.
+ That being said, I _really_ want comments regarding the software
+as well as suggestions. Bug fixes are even snazzier and code
+contributions are welcome. :)
+
+ Dan Pilone
+ http://www.slac.com/pilone/kpilot_home/
+ July 20, 2000
+
+ Adriaan de Groot
+ http://www.cs.kun.nl/~adridg/kpilot-bugs.html
+ April 14, 2001
diff --git a/kpilot/Documentation/UML/vcal-classdiagram.xmi.tgz b/kpilot/Documentation/UML/vcal-classdiagram.xmi.tgz
new file mode 100644
index 000000000..1e222f370
--- /dev/null
+++ b/kpilot/Documentation/UML/vcal-classdiagram.xmi.tgz
Binary files differ
diff --git a/kpilot/Documentation/checkPlugin.sh b/kpilot/Documentation/checkPlugin.sh
new file mode 100644
index 000000000..bc0b840c7
--- /dev/null
+++ b/kpilot/Documentation/checkPlugin.sh
@@ -0,0 +1,77 @@
+#! /bin/sh
+##
+## checkPlugin.sh
+##
+## Copyright (C) 2002 by Adriaan de Groot
+##
+## Distributed under the GNU General Public License (GPL) Version 2.
+##
+
+##
+## Usage: checkPlugin.sh <app-path> <plugin-path> [<extra-lib> ...]
+##
+## <app-path> : path to the application that will be loading the
+## plugin. This is used to get the list of library
+## dependencies.
+## <plugin-path> : path to the plugin (.so) that will be loaded.
+## <extra-lib> : paths to additional libraries to get defined symbols from.
+##
+
+USAGE="Usage: checkPlugin.sh <app-path> <plugin-path> [<extra-lib> ...]"
+
+UNDEF_RE="^ *U "
+DEF_RE="^[0-9a-fA-F]* [TdWBVDR] "
+TMP="/tmp/$$"
+
+APP_PATH="$1"
+PLUGIN_PATH="$2"
+
+test -z "$APP_PATH" && echo "$USAGE"
+test -z "$APP_PATH" && exit 1
+test -f "$APP_PATH" || echo "$USAGE"
+test -f "$APP_PATH" || exit 1
+
+test -z "$PLUGIN_PATH" && echo "$USAGE"
+test -z "$PLUGIN_PATH" && exit 1
+test -f "$PLUGIN_PATH" || echo "$USAGE"
+test -f "$PLUGIN_PATH" || exit 1
+
+shift 2
+
+if nm --demangle "$PLUGIN_PATH" > "$TMP-1" ; then
+ echo `wc -l < "$TMP-1"` "symbols in $PLUGIN_PATH"
+else
+ echo "nm failed on $PLUGIN_PATH"
+ exit 1
+fi
+
+cat "$TMP-1" | grep "$UNDEF_RE" | sed "s/$UNDEF_RE//" | sort > "$TMP-undef"
+
+T=`ldd "$APP_PATH" | grep -v "$APP_PATH" | grep -v "not found" | sed -e 's/.*=> //' -e 's/ (.*) *$//' | sort | uniq`
+
+for LIBF in $T $* ; do
+ test -f "$LIBF" || echo "$LIBF: Not found"
+ test -f "$LIBF" || exit 1
+
+ if nm --demangle "$LIBF" > "$TMP-2" 2> /dev/null ; then
+ nm --demangle --dynamic "$LIBF" >> "$TMP-2" 2> /dev/null
+ # echo `wc -l < "$TMP-2"` "symbols defined in $LIBF"
+ else
+ echo "nm failed on $LIBF"
+ exit 1
+ fi
+
+ cat "$TMP-2" | grep "$DEF_RE" | sed "s/$DEF_RE//" | sort | uniq > "$TMP-def"
+ cat "$TMP-undef" "$TMP-def" | sort | uniq -d > "$TMP-now-defined"
+ cat "$TMP-undef" "$TMP-now-defined" | sort | uniq -u > "$TMP-still"
+
+ echo `wc -l < "$TMP-now-defined"` "symbols resolved by $LIBF"
+
+ cat "$TMP-still" > "$TMP-undef"
+done
+
+echo `wc -l < "$TMP-undef"` "undefined symbols remain"
+
+cat "$TMP-undef"
+
+rm -f "$TMP" "$TMP-1" "$TMP-2" "$TMP-undef" "$TMP-def" "$TMP-now-defined" "$TMP-still"
diff --git a/kpilot/Documentation/merge-into-svn.sh b/kpilot/Documentation/merge-into-svn.sh
new file mode 100755
index 000000000..c012deed5
--- /dev/null
+++ b/kpilot/Documentation/merge-into-svn.sh
@@ -0,0 +1,165 @@
+#!/bin/bash
+COPYTO=$1
+
+if [ "x$COPYTO" = "x" ] || [ ! -d "$COPYTO" ]
+then
+ echo "$(basename $0) <directory to merge to>"
+ exit 1
+fi
+
+STARTDIR=$(pwd)
+
+COPYFILES=""
+DELFILES=""
+NEWFILES=""
+
+function isversioned {
+ F=$1
+ svn info $F 2>&1 | grep Checksum > /dev/null
+ rc=$?
+ if [ $rc -eq 0 ]
+ then
+ echo 1
+ else
+ echo 0
+ fi
+}
+
+function checkCopy {
+
+echo "[-] Checking for files that need to be copied to: [$COPYTO]..."
+echo "-----------------------------------------------------"
+
+# first pass is to copy all files we care about from current to destination
+for f in $(find . | egrep -vi \
+"aap|build-|\.svn|\.libs|Makefile$|Makefile.in|~$|\.la$")
+do
+if [ -f $f ]; then
+ F=$(printf "%-60s\n" $f)
+ C=$(sum -r $f)
+ O=$(sum -r $COPYTO/$f 2>/dev/null)
+ if [ "$C" = "$O" ] ; then
+ S="SAME"
+ elif [ ! -f $COPYTO/$f ]; then
+ S="NEW"
+ else
+ S="DIFF"
+ fi
+
+ if [ "$S" != "SAME" ]; then
+ echo "file: [$F], status: [$S]"
+ if [ "$S" = "DIFF" ]; then
+ COPY="y"
+ elif [ "$S" = "NEW" ] ; then
+ V=$(isversioned $f)
+ if [ "$V" -eq 0 ]; then
+ echo " - new file, but not versioned, so ignoring."
+ COPY="n"
+ elif [ "$V" -eq 1 ]; then
+ echo -n " - new file. versioned. copy this one? (Y/N) -> "
+ read ANS
+ ANS=$(echo $ANS | tr '[A-Z]' '[a-z]')
+ if [ "$ANS" = "y" ]; then
+ COPY="y"
+ NEWFILES="$NEWFILES $f"
+ else
+ COPY="n"
+ fi
+ fi
+ fi
+ if [ "$COPY" = "y" ]; then
+ echo " - copying this file..."
+ COPYFILES="$COPYFILES $f"
+ else
+ echo " - not copying it..."
+ fi
+ fi
+fi
+done
+}
+
+function checkDelete {
+
+echo "[-] Checking for files that should be deleted from: [$COPYTO] ..."
+echo "-----------------------------------------------------"
+
+# now see if there's anything that was in dest, but is not in new and
+# remove it
+cd $COPYTO
+for f in $(find . | egrep -vi \
+"aap|build|.svn|.libs|Makefile|~$|lib/pilot-link|.la$|.deps|.moc$|.lo$|\.o$")
+do
+if [ -f $f ]; then
+ F=$(printf "%-60s\n" $f)
+ if [ ! -f $STARTDIR/$f ] ; then
+ V=$(isversioned $f)
+ if [ "$V" -eq 1 ]; then
+ echo -n " - file: [$F] looks like it's been deleted. should I remove it? (Y/N) -> "
+ read ANS
+ ANS=$(echo $ANS | tr '[A-Z]' '[a-z]')
+ if [ "$ANS" = "y" ]; then
+ echo " - okay, I'll remove this one..."
+ DELFILES="$DELFILES $f"
+ fi
+ fi
+ fi
+fi
+done
+}
+
+checkCopy
+checkDelete
+
+cd "$STARTDIR"
+
+echo "okay, here are the files that I'll copy:"
+for f in $(echo $COPYFILES)
+do
+ echo " - $f"
+done
+
+echo "and here are the files that I'll do an svn remove on:"
+for f in $(echo $DELFILES)
+do
+ echo " - $f"
+done
+
+echo "and here are the files that I'll do an svn add on:"
+for f in $(echo $NEWFILES)
+do
+ echo " - $f"
+done
+
+echo -n "Okay to proceed? (y/n) -> "
+read ANS
+ANS=$(echo $ANS | tr '[A-Z]' '[a-z]')
+if [ "$ANS" != "y" ]; then
+ echo " - okay, stopping."
+ exit
+fi
+
+cd "$STARTDIR"
+
+echo "okay, copying..."
+for f in $(echo $COPYFILES)
+do
+ cp --parents -v "$f" "$COPYTO"
+done
+
+cd "$COPYTO"
+
+echo "doing svn remove..."
+for f in $(echo $DELFILES)
+do
+ echo " - $f"
+ svn remove "$f"
+done
+
+cd "$COPYTO"
+
+echo "doing svn add..."
+for f in $(echo $NEWFILES)
+do
+ echo " - $f"
+ svn add "$f"
+done
diff --git a/kpilot/INSTALL b/kpilot/INSTALL
new file mode 100644
index 000000000..3fa5f0ff5
--- /dev/null
+++ b/kpilot/INSTALL
@@ -0,0 +1,56 @@
+Basic Installation
+==================
+
+
+KPilot uses the CMake build system which is the native build system
+for KDE4; for KDE3 applications like KPilot, CMake is also useable.
+You need CMake installed on your system to compile KPilot, but CMake
+is becoming more widespread now. You can get it from www.cmake.org .
+
+First configure KPilot by running
+
+ ./configure [options]
+
+If you run configure with no options it will tell you which ones
+are available; you *must* provide at least one for configure to
+work. A most-vanilla configure looks like this:
+
+ ./configure --enable-tests=no
+
+Suggested options are at least:
+
+ ./configure --enable-debug=yes --enable-tests=yes
+
+You may need to specify a prefix or a location where pilot-link
+is installed; run ./configure --show for a summary of options.
+
+Once configure is done, compile KPilot, by running
+
+ make -f Makefile.cmake
+
+in the KPilot source directory (that is the one containing this
+INSTALL file). This will run CMake to generate the real Makefiles,
+then run make again to build the project in a build-* subdirectory.
+Once it is done, you can run
+
+ make -f Makefile.cmake install
+
+to install KPilot in the KDE directory.
+
+
+
+
+Advanced Installation
+=====================
+
+In order to build KPilot somewhere else, or if the sources are on
+read-only media, use CMake directly instead of using the basic
+Makefile included with KPilot. To do this,
+ 1) Create a build directory somewhere
+ 2) cd into that build directory
+ 3) Run cmake /path/to/kpilot/sources
+ 4) Run make
+
+In order to install KPilot somewhere else, use -DCMAKE_INSTALL_PREFIX .
+
+
diff --git a/kpilot/Mainpage.dox b/kpilot/Mainpage.dox
new file mode 100644
index 000000000..7e0b086c3
--- /dev/null
+++ b/kpilot/Mainpage.dox
@@ -0,0 +1,31 @@
+/** \mainpage %KPilot API Overview
+
+\section Architecture
+
+%KPilot consists of a core library of utility and communications
+classes which are used by two applications: KPilot itself
+(which is little more than a clumsy data viewer and
+configuration shell) and the KPilot daemon which does
+the actual communications with the hadheld.
+The daemon loads plugins (called conduits) on demand
+which are used for syncing specific data on the PC
+with the handheld.
+
+The lib/ directory holds the base library for KPilot.
+This boils down to a bunch of wrappers for pilot-link
+classes (not using p-l's C++ code because that isn't
+Qt-ish) and a few classes that do interesting things:
+KPilotDeviceLink for managing the device connection,
+and SyncAction for doing stuff during a sync.
+
+The kpilot/ directory houses several applications:
+kpilot and kpilotDaemon are installed, and kpilotTest
+which is not installed but which can function as a demon
+under closely-controlled circumstances from the command-line.
+
+Under conduits/ a bunch of directories hold the individual
+conduits; the "four button" apps are in vcalconduit/ (ToDo and
+Datebook), abbrowserconduit/ (Addresses, not the newer Contacts)
+and knotes/ or memofileconduit/ (Memos).
+
+*/
diff --git a/kpilot/Makefile.am b/kpilot/Makefile.am
new file mode 100644
index 000000000..e787d42e6
--- /dev/null
+++ b/kpilot/Makefile.am
@@ -0,0 +1,20 @@
+## kdepim/kpilot/Makefile.am
+## (C) 1997 Stephan Kulow
+## Modified by Adriaan de Groot
+
+SUBDIRS = lib kpilot conduits
+
+messages:
+ $(EXTRACTRC) `find . -name "*.rc" -o -name "*.ui"` > rc.cpp
+ $(XGETTEXT) `find . -name "*.cc" -o -name "*.cpp"` -o $(podir)/kpilot.pot
+ -rm -f rc.cpp
+
+DOXYGEN_REFERENCES = kpilot/lib kpilot/kpilot
+include $(top_srcdir)/admin/Doxyfile.am
+
+# Just for the KPilot developers: grab all the strings, for checking.
+devel-pot :
+ extractrc `find . -name "*.rc" -o -name "*.ui"` > /tmp/rc.cpp
+ xgettext -C --keyword=i18n --keyword=I18N_NOOP -o /tmp/kpilot.po \
+ `find . -name "*.cc"` /tmp/rc.cpp
+
diff --git a/kpilot/Makefile.cmake b/kpilot/Makefile.cmake
new file mode 100644
index 000000000..55dba5af5
--- /dev/null
+++ b/kpilot/Makefile.cmake
@@ -0,0 +1,65 @@
+# This is a GNU makefile. You need GNU make to process it.
+# FreeBSD users should use gmake.
+#
+#
+
+# Unusual configuration things:
+# CMAKE = path to cmake
+# BUILD_DIR = directory to build things in
+# CMAKE_FLAGS = extra flags to CMake. These will get set by
+# ./configure, saved to CMakeOptions.txt, and read in below...
+#
+
+-include Makefile.cmake.in
+
+BUILD_DIR ?= build-$(shell uname -sr | tr -d [:space:] | tr -Cs a-zA-Z0-9 _ )
+# these come from CMakeOptions.txt (from ./configure)
+CMAKE_FLAGS ?=
+CMAKE ?= cmake
+
+all: build-check
+ @cd "$(BUILD_DIR)" && $(MAKE)
+
+check: lib tests
+ $(BUILD_DIR)/tests/testconstants
+ $(BUILD_DIR)/tests/testcategories --data-dir=tests/data
+ $(BUILD_DIR)/tests/testaddresses --data-dir=tests/data
+ $(BUILD_DIR)/tests/testdatebook --data-dir=tests/data
+
+install: build-check
+ @cd "$(BUILD_DIR)" && $(MAKE) install
+
+uninstall:
+ @cd "$(BUILD_DIR)" && $(MAKE) uninstall
+
+lib: $(BUILD_DIR)/lib/libkpilot.so
+
+$(BUILD_DIR)/lib/libkpilot.so: build-check
+ @cd "$(BUILD_DIR)/lib" && $(MAKE)
+
+tests: build-check
+ @cd "$(BUILD_DIR)/tests" && $(MAKE)
+
+
+build-check:
+ test -d "$(BUILD_DIR)" || mkdir -p "$(BUILD_DIR)"
+ test -d "$(BUILD_DIR)"
+ test -f "$(BUILD_DIR)/Makefile" || (cd "$(BUILD_DIR)" && $(CMAKE) .. )
+
+messages:
+ extractrc `find . -name *.rc` > rc.cc
+ extractrc `find . -name *.ui` >> rc.cc
+ xgettext -o kpilot.po --keyword=i18n rc.cc `find . -name *.h` `find . -name *.cc`
+
+clean:
+ @rm -rf $(BUILD_DIR)
+
+svnclean:
+ @rm -rf `svn status --no-ignore | awk '/^[?I]/{print $2}'`
+
+help:
+ @echo "Usage: make ( all | install | uninstall | clean )"
+ @echo ""
+
+.PHONY : all check install uninstall lib build-check clean help
+
diff --git a/kpilot/NEWS b/kpilot/NEWS
new file mode 100644
index 000000000..4e9a6983a
--- /dev/null
+++ b/kpilot/NEWS
@@ -0,0 +1,24 @@
+KPilot news. This file lists only major releases &c.
+For more detailed information and musings, see the
+ChangeLog or the README files. There is also the
+history page on www.kpilot.org.
+
+* November 18, 2006: KDE 3.5.5 is getting KPilot backported
+ to it, and KPilot itself now uses CMake as its buildsystem.
+* November 4, 2004: KDE 3.3.1 contains KPilot 4.4.5; there is
+ a 4.4.6 available from the website, but it is of dubious
+ quality.
+* January 18, 2004: KDE 3.2 released, with KPilot 4.4.0. I'd
+ say 4.4.0 is dead in the water, there's too much new useful
+ stuff in 4.4.1 (for the PIM release).
+* August 19, 2002: License change for the lib part of KPilot to
+ LGPL and an exception made in the COPYING file for libmal to
+ allow the AvantGo (tm) conduit to use that library.
+* May 23, 2002: KPilot 4.3.2 seems ok now. It's too late for
+ KDE 3.0.1. It should still work for KDE 2.2.2.
+* January 20, 2002: KPilot 4.3.0b still isn't ready for release.
+* April 8, 2001: KPilot 4.2.2 released with KDE 2.2a1.
+* February 12, 2001: KPilot 4.0.0 released with KDE 2.1.
+* 2000: KPilot 3.2.1 released. This is the last KDE 1.x release.
+
+
diff --git a/kpilot/README b/kpilot/README
new file mode 100644
index 000000000..bffacdbdc
--- /dev/null
+++ b/kpilot/README
@@ -0,0 +1,43 @@
+KPILOT 4.9.1 by Adriaan de Groot
+=============================================
+ Additional work by Robert Ambrose,
+ Preston Brown, Adriaan de Groot,
+ Heiko Purnhagen, Joerg Habenicht,
+ David Bishop, Aaron Seigo,
+ Reinhold Kainhofer, Joern Ahrens,
+ Jason Kasper,
+ and probably many more.
+
+ KPilot is software for syncing PalmOS based handhelds
+such as the 3Com Palm Pilot with a machine running some flavor of UNIX.
+
+ Developer's notes are listed in the file ChangeLog. This is
+probably only of interest if you want to see how certain features developed
+or if certain bugs have been reported before.
+
+ http://www.kpilot.org/
+
+
+
+STANDARD DISCLAIMER, WARNINGS, ETC..
+====================================
+ THIS SOFTWARE HAS BUGS. Use at your own risk. It has not even
+been tested anywhere but on my machine and only with my Palm Pilot. I
+have been using it against XCopilot for development then verifying it
+works with a real Pilot with my Palm Pilot Professional running OS v2.0.4.
+I make no claims that it will work, or even try to work. I take no
+responsibility for any data loss, damage, etc. done by this software.
+ie: Should your Pilot burst into flames while trying to sync a new game..
+sorry.
+ That being said, I _really_ want comments regarding the software
+as well as suggestions. Bug fixes are even snazzier and code
+contributions are welcome. :) Send mail to [email protected] .
+
+ Dan Pilone
+ July 20, 2000
+
+ Adriaan de Groot
+ November 18, 2006
+
diff --git a/kpilot/TODO b/kpilot/TODO
new file mode 100644
index 000000000..1729fafbc
--- /dev/null
+++ b/kpilot/TODO
@@ -0,0 +1,201 @@
+This is a TODO file. Open issues are unmarked, partly resolved issues
+are marked with a *, ignored issues get an -, and resolved issues a +
+(or they are completely removed from the list). Check the ChangeLog
+for details on how an issue is resolved, since resolved issues are
+ periodically purged from this list.
+
+
+* Import pilot-link 0.12 CVS again
+* Implement correct full syncing in memofile conduit. honestly, we should
+ really have a generic sync engine that knows how to do all of the
+ different sync types and only calls conduits for comparisons, list
+ fetching, pilotid->whateverId persistence and retrieval, etc. *sigh* is
+ that what opensync gives us?
+
+Essential
+=========
+3b) Implement reset to last sync and ignore conflict resolution options in
+ vcal conduits (bug #59221)
+4a) Config troubles: Start kpilotDaemon and then kpilot. Configure a conduit
+ in kpilot, then do a sync (which writes something to the config, e.g.
+ run the docconduit). Now configure another conduit in kpilot. The config
+ file will be changed again, but the changes from the sync are lost (i.e.
+ after a sync, kpilot needs to reload the config). (seems connected to bug #56115)
+*4b) Conduits should not use the backup databases, otherwise a backup run will
+ screw up the conduit's mechanism to detect changes. (bug #59219)
+4c) Need to find a better way to detect runs without a conduit, and switch to
+ full sync in that case to prevent data loss.
+4d) Need to find a good way to avoid a mess when implementing new features
+ (e.g. after implementing the correct category sync, how do I ensure that
+ no category settings are lost?)
+5) After the special sync is done, ask if the next sync should again be the
+ same special sync, a fast or a hot sync. (wish #59218)
+
+
+Important (hight priority)
+============================
+6a) The abook conduit currently only syncs one email address and one
+ phone number of each type. I need to find a way to sync two email
+ addresses to and from the handheld. (Bug #56364)
+7) Check the first-time syncing behavior of all the conduits.
+15) Add force-first-time to the KNotes conduit.
+17) Include a calendar viewer, or get rid of the internal viewers
+ altogether.
+19) GJJ: Replace newlines in TODO summaries (not allowed in libkcal),
+ also do the same for phone numbers etc. (bug #56379)
+19b)Make the doc conduit use the new global settings instead of its own
+
+
+Medium (nice to have, but not essential)
+========================================
+18) VCal conduit: events going over midnight need to be split up
+ on the handheld (bug #59223)
+20) GJJ: Check all debug output, what should be put in the log (i.e.
+ be visible to the user) and what is just debug output to track
+ down problems.
+21) GJJ: Hunt down and kill printfs. Hunt down bad i18n.
+26) ABook conduit: sync with preferred address (not home or work address)
+27) Update the conduit programming howto (some changes in the database
+ and record classes)
+31) GJJ: Extend all conduits to allow arbitrary URLs instead of local
+ files.
+32) JPilot conduit: fix the configure.in.in checks for gtk/glibc
+ (although the conduit isn't even remotely finished)
+32a)Find a replacement for the NULL conduit (skip databases when
+ doing a backup)
+
+
+Unimportant (lowest priority)
+=============================
+33) JPilot conduit: Implement the conduit as an external GTK application,
+ that is embedded into kpilot using qxembed
+34) JJ: Add tooltips to all controls in all conduit configure dialogs
+35) Do not store the RecordID with the vcalendar entry, but in the kpilot
+ config
+37) JJ: Show the sync log as a KPassivePopup
+39) Make an application that just has a LogWidget and KPilot's dcop
+ interface (and registration!) so that you can follow the daemon's
+ log output without starting KPilot at all.
+40) Allow the todo conduit to use the manana database (see jpilot)
+41) Allow the memo conduit to use the pedit32 database (see jpilot)
+42) Use pdf2text application to also install pdb files with the palmdoc
+ conduit.
+
+
+
+
+
+
+FINISHED TODO jobs
+==================
+
++(1) VCal conduit: Currently using the ResourceCalendar (standard
+ calendar) doesn't work for some (unknown) reason. Every sync
+ happens with the filename given in the setup dialog. Probably
+ very easy to fix.
++(2) 4d) Need to find a good way to avoid a mess when implementing new features
+ (e.g. after implementing the correct category sync, how do I ensure that
+ no category settings are lost?)
++(3a) Implement the CopyToPC and CopyToHH directions in the addressbook conduit (bug #59220)
+5) After the special sync is done, ask if the next sync should again be the
+ same special sync, a fast or a hot sync. (wish #59218)
+
+ Redesign the config dialog of kpilot (get rid of deprecated
+ options, include conflict resolution, etc.)
++(3) Fix all conduits to use the new global options: conflict resolution,
+ emergency sync, sync mode etc.
++(4) VCal conduit: Fields not supported on the handheld are erased
+ in the calendar (e.g. categories). I need to get the Event
+ before I copy all fields over, and only overwrite the fields
+ from the handheld, so the others remain unchanged.
+ RESOLUTION: Found out that this is not true any longer, and everything
+ works just fine!
++(5) AvantGo conduit: fix the configure.in.in checks for libmal
++(6) ABook conduit: fix the first sync setting
++(8) Find out what's the reason of the "Invalid unique ID" crashes in
+ the calendar conduits (and the addresssbook conduit) (bug #51216)
+-(9) GJJ: PalmDOC conduit: kpalmdoc is run as a modal dialog, not as
+ a standalone dialog (e.g. create a link on the desktop to
+ kpalmdoc and start kpalmdoc from there. You can't access the
+ desktop until you quit kpalmdoc)
+ RESOLUTION: This is a general KDE Bug!!!!
+-(10) GJJ: Add a flag to the log{Error,Message} functions to prevent
+ the addition of the trailing <br> and the date to each output
+ (e.g. to put all output from the AvantGo conduit in one line,
+ instead of one separate line for each .)
+ RESOLUTION: This is not possible in a QTextEdit in LogText mode.
+ However, I got rid of the pseudoo-progressbar, so this i no longer
+ needed.
++(11) Merge between HEAD and BRANCH (again).
++(12) ABook conduit: Check all fields for differences before asking
+ for conflict resolution. (i.e. don't ask for conflict resolution
+ of single fields, just for the whole record) (bug #59222)
++(13) ABook conduit: custom field sync doesn't work with birthdate
+ (how do I convert a date to a string and back in an arbitrary
+ format???) (Bug #50871)
++(14) ABook conduit: Fix categories sync
+ RESOLUTION: Fixed for the abook and the todo conduit
++(16) Remove the edit capabilities from the built-in viewers. (fixes bug #54765)
+ Or write a SyncAction childclass that merges the changes from the internal
+ editors to the databases on the handheld before the sync takes place
+ RESOLUTION: Implemented the InternalEditorAction that syncs these modifications
++(19a)Implement the internal editor sync
++(19a)When syncing, also backup the databases (if option is set)
++(19b)Add all codecs that are supported by Qt, automatically fill the
+ combobox in the config dialog. Change the combobox to an editable
+ Combobox so that the user can also give other encodings (if he
+ installed the corresponding plugins).
++(22) Update README, TODO, NEWS, AUTHORS in HEAD.
++(23) GJJ: Move the conduit configuration dialog (for the umpteenth time)
+ to a list of QCheckBoxes, like noatun's plain playlist or
+ kdebugdialog
++(24) PalmDOC conduit: choosing the bookmark type of the pdb->txt
+ conversion is not yet implemented. Only create .bm file, if there
+ are bookmarks in the text.
+-(25) ABook conduit: sync with multiple email addresses (space-separated
+ list received from handheld)
+ RESOLUTION: Duplicate of 6a)
++(28) GJJ: The question asked when kpilot and the pilot's usernames don't
+ match isn't very intuitive. It should be changed to a yes/no/cancel
+ with "Use KPilot name" "Use Pilot name" "Cancel". This is in
+ interactiveSync.cc.
+-(29) Fix the NULL conduit's tooltip - OR - make it actually do what the
+ current tooltip says.
+ RESOLUTION: The NULL conduit is no longer needed at all, so I disabled
+ it completely
+-(30) GJJ: Create good icons for the kpalmdoc converter application.
++(38) Should interactiveSync and syncStack be moved to lib/ ?
+
+
+
+
+
+Specific JOBS
+=============
+
+***
+*** PilotLocalDatabase fixups
+***
+
+The PilotLocalDatabase class is really ugly and clunky -- and far worse,
+it has a hard-coded limit of 10000 records per database. This may have hurt
+us once or twice already (consider that a Visor w/ 16Mb could *easily*
+hold 10000 addresses). It needs careful reworking.
+
+I think using a Q(Ptr)List is the way to go here -- well, maybe a QVector
+would work as well; that depends on whether QVectors resize well. The tricky
+part is implementing the "current record pointer" with the same behavior
+as the current fCurrentRecord member, since conduits may depend on it.
+
+
+***
+*** Popmail Conduit & IOSlaves
+***
+
+The popmail conduit duplicates a lot of code found elsewhere -- it does
+SMTP sending and POP3 retrieval of mail messages. That should really be
+left to IOSlaves, which are better debugged. Using tickle() will be
+necessary while waiting for responses from the slaves, since you must keep
+the pilot awake. (This opens the door to multi-threading conduits, with
+possibly an asynchronous "pre-sync" action).
+
diff --git a/kpilot/cmake/modules/FindMal.cmake b/kpilot/cmake/modules/FindMal.cmake
new file mode 100644
index 000000000..9439d277e
--- /dev/null
+++ b/kpilot/cmake/modules/FindMal.cmake
@@ -0,0 +1,62 @@
+INCLUDE(CheckCXXSourceCompiles)
+
+set(CMAKE_INCLUDE_PATH "${MAL_BASE}/include")
+FIND_PATH(MAL_INCLUDE_DIR libmal.h
+ ${MAL_BASE}/include
+ ${MAL_BASE}/include/libmal
+ /usr/include
+ /usr/include/libmal
+ /usr/local/include
+ /usr/local/include/libmal
+)
+set(CMAKE_LIBRARY_PATH "${MAL_BASE}/lib")
+FIND_LIBRARY(MAL_LIBRARY mal
+ ${MAL_BASE}/lib
+ /usr/lib
+ /usr/lib/libmal
+ /usr/local/lib
+ /usr/local/lib/libmal
+)
+
+IF (NOT MAL_INCLUDE_DIR)
+ MESSAGE(STATUS "Could not find libmal.h")
+ELSE (NOT MAL_INCLUDE_DIR)
+ MESSAGE(STATUS "Found libmal.h in ${MAL_INCLUDE_DIR}")
+ENDIF (NOT MAL_INCLUDE_DIR)
+
+IF (NOT MAL_LIBRARY)
+ MESSAGE(STATUS "Could not find libmal")
+ELSE (NOT MAL_LIBRARY)
+ MESSAGE(STATUS "Found libmal in ${MAL_LIBRARY}")
+ENDIF (NOT MAL_LIBRARY)
+
+IF (MAL_INCLUDE_DIR AND MAL_LIBRARY)
+ SET(MAL_FOUND TRUE)
+ENDIF (MAL_INCLUDE_DIR AND MAL_LIBRARY)
+
+IF (MAL_FOUND)
+ SET(CMAKE_REQUIRED_INCLUDES ${MAL_INCLUDE_DIR} ${PILOTLINK_INCLUDE_DIR})
+ CHECK_CXX_SOURCE_COMPILES("
+#include <libmal.h>
+#define LIBMAL_IS(a,b) ((LIBMAL_VERSION > a) || ((LIBMAL_VERSION == a) && ((LIBMAL_MAJOR > b) || (LIBMAL_MAJOR == b))))
+#if !LIBMAL_IS(0,40)
+#error \"Libmal version is < 0.40\"
+#else
+int main() { return 0; }
+#endif
+"
+ MAL_VERSION_OK)
+ENDIF (MAL_FOUND)
+
+IF (NOT MAL_VERSION_OK)
+ SET(MAL_FOUND FALSE)
+ MESSAGE(STATUS "Found mal, but it's not at least version 0.40.")
+ENDIF (NOT MAL_VERSION_OK)
+
+
+IF (MAL_FOUND)
+ MESSAGE(STATUS "Found mal: ${MAL_LIBRARY}")
+ELSE (MAL_FOUND)
+ MESSAGE(STATUS "Couldn't find acceptable mal version. Won't be able to build malconduit")
+ENDIF (MAL_FOUND)
+
diff --git a/kpilot/cmake/modules/FindPilotlink.cmake b/kpilot/cmake/modules/FindPilotlink.cmake
new file mode 100644
index 000000000..649419e6f
--- /dev/null
+++ b/kpilot/cmake/modules/FindPilotlink.cmake
@@ -0,0 +1,55 @@
+INCLUDE(CheckCXXSourceCompiles)
+
+set(CMAKE_INCLUDE_PATH "${PILOTLINK_BASE}/include")
+FIND_PATH(PILOTLINK_INCLUDE_DIR pi-dlp.h
+ /usr/include
+ /usr/include/libpisock
+ /usr/local/include
+ )
+set(CMAKE_LIBRARY_PATH "${PILOTLINK_BASE}/lib")
+FIND_LIBRARY(PILOTLINK_LIBRARY pisock
+ /usr/lib
+ /usr/local/lib
+ )
+
+IF (NOT PILOTLINK_INCLUDE_DIR)
+ MESSAGE(STATUS "Could not find pilot-link (pi-dlp.h)")
+ELSE (NOT PILOTLINK_INCLUDE_DIR)
+ MESSAGE(STATUS "Found pilot-link includes in ${PILOTLINK_INCLUDE_DIR}")
+ENDIF (NOT PILOTLINK_INCLUDE_DIR)
+
+IF (NOT PILOTLINK_LIBRARY)
+ MESSAGE(STATUS "Could not find pilot-link (libpisock.so)")
+ELSE (NOT PILOTLINK_LIBRARY)
+ MESSAGE(STATUS "Found pilot-link libraries in ${PILOTLINK_LIBRARY}")
+ENDIF (NOT PILOTLINK_LIBRARY)
+
+IF (PILOTLINK_INCLUDE_DIR AND PILOTLINK_LIBRARY)
+ SET(PILOTLINK_FOUND TRUE)
+ENDIF (PILOTLINK_INCLUDE_DIR AND PILOTLINK_LIBRARY)
+
+IF (PILOTLINK_FOUND)
+ SET(CMAKE_REQUIRED_INCLUDES ${PILOTLINK_INCLUDE_DIR})
+ CHECK_CXX_SOURCE_COMPILES("
+#include <pi-version.h>
+#if !PILOT_LINK_IS(0,12,0)
+#error \"Pilot-link version is < 0.12.0\"
+#else
+int main() { return 0; }
+#endif
+"
+ PILOTLINK_VERSION_OK)
+ENDIF (PILOTLINK_FOUND)
+
+IF (NOT PILOTLINK_VERSION_OK)
+ SET(PILOTLINK_FOUND FALSE)
+ENDIF (NOT PILOTLINK_VERSION_OK)
+
+
+IF (NOT PILOTLINK_FOUND)
+ IF (Pilotlink_FIND_REQUIRED)
+ MESSAGE(STATUS "KPilot requires pilot-link 0.12.0 or later. Pilot-link is available from pilot-link.org and is packaged by most distributions. Remember to install the development package with the compilation headers as well.")
+ MESSAGE(FATAL_ERROR "Could not find pilot-link.")
+ ENDIF (Pilotlink_FIND_REQUIRED)
+ENDIF (NOT PILOTLINK_FOUND)
+
diff --git a/kpilot/cmake/modules/KPilotCustom.cmake b/kpilot/cmake/modules/KPilotCustom.cmake
new file mode 100644
index 000000000..08b255dc0
--- /dev/null
+++ b/kpilot/cmake/modules/KPilotCustom.cmake
@@ -0,0 +1,53 @@
+MACRO(KDE3_INSTALL_ICONS_CUSTOM _theme)
+ ADD_CUSTOM_TARGET(install_icons )
+ SET_TARGET_PROPERTIES(install_icons PROPERTIES POST_INSTALL_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake )
+ FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake "# icon installations rules\n")
+ FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake "SET(CMAKE_BACKWARDS_COMPATIBILITY \"2.2\") \n")
+
+ FILE(GLOB _icons *.png)
+ FOREACH(_current_ICON ${_icons} )
+ STRING(REGEX REPLACE "^.*/[a-zA-Z]+([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\1" _size "${_current_ICON}")
+ STRING(REGEX REPLACE "^.*/[a-zA-Z]+([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\2" _group "${_current_ICON}")
+ STRING(REGEX REPLACE "^.*/[a-zA-Z]+([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\3" _name "${_current_ICON}")
+
+ SET(_icon_GROUP "unknown")
+
+ IF(${_group} STREQUAL "mime")
+ SET(_icon_GROUP "mimetypes")
+ ENDIF(${_group} STREQUAL "mime")
+
+ IF(${_group} STREQUAL "filesys")
+ SET(_icon_GROUP "filesystems")
+ ENDIF(${_group} STREQUAL "filesys")
+
+ IF(${_group} STREQUAL "device")
+ SET(_icon_GROUP "devices")
+ ENDIF(${_group} STREQUAL "device")
+
+ IF(${_group} STREQUAL "app")
+ SET(_icon_GROUP "apps")
+ ENDIF(${_group} STREQUAL "app")
+
+ IF(${_group} STREQUAL "action")
+ SET(_icon_GROUP "actions")
+ ENDIF(${_group} STREQUAL "action")
+
+ IF( NOT ${_icon_GROUP} STREQUAL "unknown")
+# message(STATUS "icon: ${_current_ICON} size: ${_size} group: ${_group} name: ${_name}" )
+ SET(_ICON_INSTALL_NAME ${CMAKE_INSTALL_PREFIX}/share/icons/${_theme}/${_size}x${_size}/${_icon_GROUP}/${_name})
+ FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake "message(STATUS \"Installing ${_ICON_INSTALL_NAME}\") \n")
+ FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake "CONFIGURE_FILE( ${_current_ICON} ${_ICON_INSTALL_NAME} COPYONLY) \n")
+ ELSE( NOT ${_icon_GROUP} STREQUAL "unknown")
+ message(STATUS "icon: ${_current_ICON} doesn't fit naming conventions. ignoring." )
+ ENDIF( NOT ${_icon_GROUP} STREQUAL "unknown")
+
+ ENDFOREACH (_current_ICON)
+ENDMACRO(KDE3_INSTALL_ICONS_CUSTOM)
+
+
+MACRO(KPILOT_RPATH _thing)
+ set_target_properties(${_thing} PROPERTIES
+ INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib;${KDE3_DIR}/lib;${PILOTLINK_LIBRARY}
+ INSTALL_RPATH_USE_LINK_PATH true
+ )
+ENDMACRO(KPILOT_RPATH _thing)
diff --git a/kpilot/cmake_uninstall.cmake.in b/kpilot/cmake_uninstall.cmake.in
new file mode 100644
index 000000000..397e3aa75
--- /dev/null
+++ b/kpilot/cmake_uninstall.cmake.in
@@ -0,0 +1,23 @@
+IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+ MESSAGE(FATAL_ERROR "Cannot find install manifest:
+\"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
+ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+STRING(REGEX REPLACE "\n" ";" files "${files}")
+FOREACH(file ${files})
+ MESSAGE(STATUS "Uninstalling \"${file}\"")
+ IF(EXISTS "${file}")
+ EXEC_PROGRAM(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ IF("${rm_retval}" STREQUAL 0)
+ ELSE("${rm_retval}" STREQUAL 0)
+ MESSAGE(FATAL_ERROR "Problem when removing \"${file}\"")
+ ENDIF("${rm_retval}" STREQUAL 0)
+ ELSE(EXISTS "${file}")
+ MESSAGE(STATUS "File \"${file}\" does not exist.")
+ ENDIF(EXISTS "${file}")
+ENDFOREACH(file)
diff --git a/kpilot/conduits/CMakeLists.txt b/kpilot/conduits/CMakeLists.txt
new file mode 100644
index 000000000..e8f49e53f
--- /dev/null
+++ b/kpilot/conduits/CMakeLists.txt
@@ -0,0 +1,35 @@
+include_directories(
+ ${CMAKE_BINARY_DIR}/lib
+ ${CMAKE_SOURCE_DIR}/lib
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+add_subdirectory(abbrowserconduit)
+add_subdirectory(docconduit)
+add_subdirectory(knotes)
+add_subdirectory(memofileconduit)
+add_subdirectory(notepadconduit)
+add_subdirectory(null)
+add_subdirectory(popmail)
+add_subdirectory(sysinfoconduit)
+add_subdirectory(timeconduit)
+
+FIND_PATH( HAVE_CALENDARLOCAL_H "libkcal/calendarlocal.h" ${KDE3_INCLUDE_DIR} )
+
+IF (HAVE_CALENDARLOCAL_H)
+ add_subdirectory(vcalconduit)
+ELSE (HAVE_CALENDARLOCAL_H)
+ MESSAGE(STATUS "No KDE PIM development headers were found.")
+ENDIF (HAVE_CALENDARLOCAL_H)
+
+###
+#
+# MAL seems to be broken, or the MAL API has changed somewhat
+# since the last time that the conduit was compiled by the development
+# team. Since we don't use the conduit it is disabled.
+IF (MAL_FOUND)
+ add_subdirectory(malconduit)
+ELSE (MAL_FOUND)
+ MESSAGE(STATUS "Couldn't find mal. Won't be able to build malconduit")
+ENDIF (MAL_FOUND)
+
diff --git a/kpilot/conduits/Makefile.am b/kpilot/conduits/Makefile.am
new file mode 100644
index 000000000..fed44984b
--- /dev/null
+++ b/kpilot/conduits/Makefile.am
@@ -0,0 +1,30 @@
+###
+### The NULL conduit is a neat programming example, but shouldn't be
+### installed on user systems.
+###
+
+if include_malconduit
+MAL_SUBDIR = malconduit
+else
+MAL_SUBDIR =
+endif
+
+SUBDIRS = \
+ abbrowserconduit \
+ docconduit \
+ knotes \
+ $(MAL_SUBDIR) \
+ memofileconduit \
+ notepadconduit \
+ popmail \
+ sysinfoconduit \
+ timeconduit \
+ vcalconduit
+
+###
+### Subdirs you might have for experimental purposes:
+###
+### null - a conduit that just logs a single message.
+### $(PERL_SUBDIR) - fires off a perl interpreter in a thread.
+### $(PYTHON_SUBDIR) - starts a python interpreter in a thread.
+###
diff --git a/kpilot/conduits/abbrowserconduit/CMakeLists.txt b/kpilot/conduits/abbrowserconduit/CMakeLists.txt
new file mode 100644
index 000000000..2459d1db9
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/CMakeLists.txt
@@ -0,0 +1,46 @@
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+set(conduit_abbrowser_SRCS
+ resolutionDialog.cc
+ abbrowser-factory.cc
+ abbrowser-setup.cc
+ kabcRecord.cc
+ abbrowser-conduit.cc
+)
+
+set(conduit_abbrowser_UIS
+ resolutionDialog_base.ui
+ kaddressbookConduit.ui
+)
+
+set(conduit_abbrowser_KCFGS
+ abbrowserSettings.kcfgc
+)
+
+kde3_add_kcfg_files(conduit_abbrowser_SRCS ${conduit_abbrowser_KCFGS})
+kde3_add_ui_files(conduit_abbrowser_SRCS ${conduit_abbrowser_UIS})
+kde3_automoc(${conduit_abbrowser_SRCS})
+add_library(conduit_address SHARED ${conduit_abbrowser_SRCS})
+target_link_libraries(conduit_address kabc_file kabc)
+set_target_properties(conduit_address PROPERTIES LOCATION ${KDE3_PLUGIN_INSTALL_DIR}
+ INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib
+ PREFIX ""
+)
+
+kde3_install_libtool_file(conduit_address)
+
+install(
+ TARGETS conduit_address
+ LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR}
+)
+
+install(
+ FILES abbrowser_conduit.desktop DESTINATION ${KDE3_SERVICES_DIR}
+)
+
+install(
+ FILES abbrowserconduit.kcfg DESTINATION ${KDE3_KCFG_DIR}
+)
+
diff --git a/kpilot/conduits/abbrowserconduit/KPilotCustomFieldEditor.ui b/kpilot/conduits/abbrowserconduit/KPilotCustomFieldEditor.ui
new file mode 100644
index 000000000..d4bb9078f
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/KPilotCustomFieldEditor.ui
@@ -0,0 +1,276 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KPilotCustomFields</class>
+<comment>This form lets you edit the custom fields synced from PalmOS handhelds by the addressbook conduit of KPilot.</comment>
+<author>Reinhold Kainhofer &lt;[email protected]&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KPILOT</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>461</width>
+ <height>409</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>KPilot Custom Fields</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>mCustomFieldsGroups</cstring>
+ </property>
+ <property name="title">
+ <string>KPilot Custom Fields</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>On your handheld, each address also provides four custom fields for your personal use. KPilot can sync these either to birthdate, URL, IM address, or just store them as a custom field on your PC with no special meaning. In the last case, you can change the values here. Note, however, that for all other settings the values entered here will have no effect.</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>mCustom3Label</cstring>
+ </property>
+ <property name="text">
+ <string>Custom &amp;3:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>X_CUSTOM3</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Edit or enter the value of the third custom field here. Using KPilot, you can synchronize these values with the handheld's Address application custom fields.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>mCustom4Label</cstring>
+ </property>
+ <property name="text">
+ <string>Custom &amp;4:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>X_CUSTOM3</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Edit or enter the value of the fourth custom field here. Using KPilot, you can synchronize these values with the handheld's Address application custom fields.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>X_CUSTOM2</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Edit or enter the value of the third custom field here. Using KPilot, you can synchronize these values with the handheld's Address application custom fields.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>X_CUSTOM1</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Edit or enter the value of the second custom field here. Using KPilot, you can synchronize these values with the handheld's Address application custom fields.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="4" column="1">
+ <property name="name">
+ <cstring>X_CUSTOM3</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Edit or enter the value of the fourth custom field here. Using KPilot, you can synchronize these values with the handheld's Address application custom fields.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>mCustom2Label</cstring>
+ </property>
+ <property name="text">
+ <string>Custom &amp;2:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>X_CUSTOM2</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Edit or enter the value of the second custom field here. Using KPilot, you can synchronize these values with the handheld's Address application custom fields.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>mCustom1Label</cstring>
+ </property>
+ <property name="text">
+ <string>Custom &amp;1:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>X_CUSTOM1</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Edit or enter the value of the first custom field here. Using KPilot, you can synchronize these values with the handheld's Address application custom fields.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>X_CUSTOM0</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Edit or enter the value of the first custom field here. Using KPilot, you can synchronize these values with the handheld's Address application custom fields.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>mCustomFieldsExplanation</cstring>
+ </property>
+ <property name="text">
+ <string>If you let KPilot sync the handheld's custom fields as custom fields on the PC, you can change the values here. Note, however, that for all other settings the values entered here will have no effect.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>mMetaSyncGroup</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>KPilot's Private (meta-sync) Settings</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>mRecordIDLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Record&amp;ID:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>X_RecordID</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="3">
+ <property name="name">
+ <cstring>mSyncFlagLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Sync &amp;flag:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>X_Flag</cstring>
+ </property>
+ </widget>
+ <spacer row="1" column="5">
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>41</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="1" column="2">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="6">
+ <property name="name">
+ <cstring>mMetaSyncSettingsWarning</cstring>
+ </property>
+ <property name="text">
+ <string>These values indicate the state of the record for KPilot, and connect an entry on the handheld with an entry on the PC.
+Do NOT change these values: doing so will almost certainly result in data loss when you next do a sync.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>X_RecordID</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxValue">
+ <number>2147483647</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="4">
+ <property name="name">
+ <cstring>X_Flag</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxValue">
+ <number>3</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>210</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpilot/conduits/abbrowserconduit/Makefile.am b/kpilot/conduits/abbrowserconduit/Makefile.am
new file mode 100644
index 000000000..6bb86c687
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/Makefile.am
@@ -0,0 +1,24 @@
+INCLUDES= $(PISOCK_INCLUDE) -I$(top_srcdir)/kpilot/lib $(all_includes)
+
+kde_module_LTLIBRARIES = conduit_address.la
+
+conduit_address_la_SOURCES = \
+ resolutionDialog_base.ui \
+ kaddressbookConduit.ui \
+ abbrowserSettings.kcfgc \
+ resolutionDialog.cc \
+ abbrowser-factory.cc \
+ abbrowser-setup.cc \
+ kabcRecord.cc \
+ abbrowser-conduit.cc
+conduit_address_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+conduit_address_la_LIBADD = ../../lib/libkpilot.la -lkabc -lkabc_file
+
+servicedir = $(kde_servicesdir)
+service_DATA = abbrowser_conduit.desktop
+kde_kcfg_DATA = abbrowserconduit.kcfg
+
+kabcustompagedir = $(kde_datadir)/kaddressbook/contacteditorpages
+kabcustompage_DATA = KPilotCustomFieldEditor.ui
+
+METASOURCES = AUTO
diff --git a/kpilot/conduits/abbrowserconduit/abbrowser-conduit.cc b/kpilot/conduits/abbrowserconduit/abbrowser-conduit.cc
new file mode 100644
index 000000000..bf038bb21
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/abbrowser-conduit.cc
@@ -0,0 +1,1897 @@
+/* KPilot
+**
+** Copyright (C) 2000,2001 by Dan Pilone
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+** Copyright (C) 2007 by Adriaan de Groot <[email protected]>
+**
+** The abbrowser conduit copies addresses from the Pilot's address book to
+** the KDE addressbook maintained via the kabc library.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected].
+*/
+
+
+
+#include "options.h"
+
+#include <qtimer.h>
+#include <qtextcodec.h>
+#include <qfile.h>
+#include <qregexp.h>
+
+#include <kabc/stdaddressbook.h>
+#include <kabc/resourcefile.h>
+#include <kio/netaccess.h>
+#include <ksavefile.h>
+
+#include <pilotSerialDatabase.h>
+#include <pilotLocalDatabase.h>
+
+#include "resolutionDialog.h"
+#include "resolutionTable.h"
+#include "abbrowserSettings.h"
+#include "kabcRecord.h"
+
+#include "abbrowser-conduit.moc"
+
+// Something to allow us to check what revision
+// the modules are that make up a binary distribution.
+//
+//
+extern "C"
+{
+unsigned long version_conduit_address = Pilot::PLUGIN_API;
+}
+
+
+/* This is partly stolen from the boost libraries, partly from
+* "Modern C++ design" for doing compile time checks; we need
+* to make sure that the enum values in KABCSync:: and in the
+* AbbrowserSettings class are the same so that both interpret
+* configuration values the same way.
+*/
+template<bool> struct EnumerationMismatch;
+template<> struct EnumerationMismatch<true>{};
+
+#define CHECK_ENUM(a) (void)sizeof(EnumerationMismatch<((int)KABCSync::a)==((int)AbbrowserSettings::a)>)
+
+static inline void compile_time_check()
+{
+ // Mappings for other phone
+ CHECK_ENUM(eOtherPhone);
+ CHECK_ENUM(eOtherPhone);
+ CHECK_ENUM(eAssistant);
+ CHECK_ENUM(eBusinessFax);
+ CHECK_ENUM(eCarPhone);
+ CHECK_ENUM(eEmail2);
+ CHECK_ENUM(eHomeFax);
+ CHECK_ENUM(eTelex);
+ CHECK_ENUM(eTTYTTDPhone);
+
+ // Mappings for custom fields
+ CHECK_ENUM(eCustomField);
+ CHECK_ENUM(eCustomBirthdate);
+ CHECK_ENUM(eCustomURL);
+ CHECK_ENUM(eCustomIM);
+}
+
+inline int faxTypeOnPC()
+{
+ return KABC::PhoneNumber::Fax |
+ ( (AbbrowserSettings::pilotFax()==0) ?
+ KABC::PhoneNumber::Home :
+ KABC::PhoneNumber::Work );
+}
+
+
+using namespace KABC;
+
+/*********************************************************************
+ C O N S T R U C T O R
+ *********************************************************************/
+
+
+AbbrowserConduit::AbbrowserConduit(KPilotLink * o, const char *n, const QStringList & a):
+ ConduitAction(o, n, a),
+ aBook(0L),
+ fAddressAppInfo(0L),
+ addresseeMap(),
+ syncedIds(),
+ abiter(),
+ fTicket(0L),
+ fCreatedBook(false),
+ fBookResource(0L)
+{
+ FUNCTIONSETUP;
+ fConduitName=i18n("Addressbook");
+}
+
+
+
+AbbrowserConduit::~AbbrowserConduit()
+{
+ FUNCTIONSETUP;
+
+ if (fTicket)
+ {
+ DEBUGKPILOT << fname << ": Releasing ticket" << endl;
+ aBook->releaseSaveTicket(fTicket);
+ fTicket=0L;
+ }
+
+ _cleanupAddressBookPointer();
+ // unused function warnings.
+ compile_time_check();
+}
+
+
+
+/*********************************************************************
+ L O A D I N G T H E D A T A
+ *********************************************************************/
+
+
+
+/* Builds the map which links record ids to uid's of Addressee
+*/
+void AbbrowserConduit::_mapContactsToPilot(QMap < recordid_t, QString > &idContactMap)
+{
+ FUNCTIONSETUP;
+
+ idContactMap.clear();
+
+ for(AddressBook::Iterator contactIter = aBook->begin();
+ contactIter != aBook->end(); ++contactIter)
+ {
+ Addressee aContact = *contactIter;
+ QString recid = aContact.custom(KABCSync::appString, KABCSync::idString);
+ if(!recid.isEmpty())
+ {
+ recordid_t id = recid.toULong();
+ // safety check: make sure that we don't already have a map for this pilot id.
+ // if we do (this can come from a copy/paste in kaddressbook, etc.), then we need
+ // to reset our Addressee so that we can assign him a new pilot Id later and sync
+ // him properly. if we don't do this, we'll lose one of these on the pilot.
+ if (!idContactMap.contains(id))
+ {
+ idContactMap.insert(id, aContact.uid());
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": found duplicate pilot key: ["
+ << id << "], removing pilot id from addressee: ["
+ << aContact.realName() << "]" << endl;
+ aContact.removeCustom(KABCSync::appString, KABCSync::idString);
+ aBook->insertAddressee(aContact);
+ abChanged = true;
+ }
+ }
+ }
+ DEBUGKPILOT << fname << ": Loaded " << idContactMap.size() <<
+ " addresses from the addressbook. " << endl;
+}
+
+
+
+bool AbbrowserConduit::_prepare()
+{
+ FUNCTIONSETUP;
+
+ readConfig();
+ syncedIds.clear();
+ pilotindex = 0;
+
+ return true;
+}
+
+
+
+void AbbrowserConduit::readConfig()
+{
+ FUNCTIONSETUP;
+ AbbrowserSettings::self()->readConfig();
+
+ // Conflict page
+ SyncAction::ConflictResolution res = (SyncAction::ConflictResolution)AbbrowserSettings::conflictResolution();
+ setConflictResolution(res);
+
+ DEBUGKPILOT << fname
+ << ": Reading addressbook "
+ << ( AbbrowserSettings::addressbookType() == AbbrowserSettings::eAbookFile ?
+ AbbrowserSettings::fileName() : CSL1("Standard") )
+ << endl;
+ DEBUGKPILOT << fname
+ << ": "
+ << " fConflictResolution=" << getConflictResolution()
+ << " fArchive=" << AbbrowserSettings::archiveDeleted()
+ << " fFirstTime=" << isFirstSync()
+ << endl;
+ DEBUGKPILOT << fname
+ << ": "
+ << " fPilotStreetHome=" << AbbrowserSettings::pilotStreet()
+ << " fPilotFaxHome=" << AbbrowserSettings::pilotFax()
+ << " eCustom[0]=" << AbbrowserSettings::custom0()
+ << " eCustom[1]=" << AbbrowserSettings::custom1()
+ << " eCustom[2]=" << AbbrowserSettings::custom2()
+ << " eCustom[3]=" << AbbrowserSettings::custom3()
+ << endl;
+}
+
+
+
+bool isDeleted(const PilotAddress *addr)
+{
+ if (!addr)
+ {
+ return true;
+ }
+ if (addr->isDeleted() && !addr->isArchived())
+ {
+ return true;
+ }
+ if (addr->isArchived())
+ {
+ return !AbbrowserSettings::archiveDeleted();
+ }
+ return false;
+}
+
+bool isArchived(const PilotAddress *addr)
+{
+ if (addr && addr->isArchived())
+ {
+ return AbbrowserSettings::archiveDeleted();
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+
+bool AbbrowserConduit::_loadAddressBook()
+{
+ FUNCTIONSETUP;
+
+ startTickle();
+ switch ( AbbrowserSettings::addressbookType() )
+ {
+ case AbbrowserSettings::eAbookResource:
+ DEBUGKPILOT<<"Loading standard addressbook"<<endl;
+ aBook = StdAddressBook::self( true );
+ fCreatedBook=false;
+ break;
+ case AbbrowserSettings::eAbookFile:
+ { // initialize the abook with the given file
+ DEBUGKPILOT<<"Loading custom addressbook"<<endl;
+ KURL kurl(AbbrowserSettings::fileName());
+ if(!KIO::NetAccess::download(AbbrowserSettings::fileName(), fABookFile, 0L) &&
+ !kurl.isLocalFile())
+ {
+ emit logError(i18n("You chose to sync with the file \"%1\", which "
+ "cannot be opened. Please make sure to supply a "
+ "valid file name in the conduit's configuration dialog. "
+ "Aborting the conduit.").arg(AbbrowserSettings::fileName()));
+ KIO::NetAccess::removeTempFile(fABookFile);
+ stopTickle();
+ return false;
+ }
+
+ aBook = new AddressBook();
+ if (!aBook)
+ {
+ stopTickle();
+ return false;
+ }
+ fBookResource = new ResourceFile(fABookFile, CSL1("vcard") );
+
+ bool r = aBook->addResource( fBookResource );
+ if ( !r )
+ {
+ DEBUGKPILOT << "Unable to open resource for file " << fABookFile << endl;
+ KPILOT_DELETE( aBook );
+ stopTickle();
+ return false;
+ }
+ fCreatedBook=true;
+ break;
+ }
+ default: break;
+ }
+ // find out if this can fail for reasons other than a non-existent
+ // vcf file. If so, how can I determine if the missing file was the problem
+ // or something more serious:
+ if ( !aBook || !aBook->load() )
+ {
+ // Something went wrong, so tell the user and return false to exit the conduit
+ emit logError(i18n("Unable to initialize and load the addressbook for the sync.") );
+ addSyncLogEntry(i18n("Unable to initialize and load the addressbook for the sync.") );
+ WARNINGKPILOT << "Unable to initialize the addressbook for the sync." << endl;
+ _cleanupAddressBookPointer();
+ stopTickle();
+ return false;
+ }
+ abChanged = false;
+
+ fTicket=aBook->requestSaveTicket();
+ if (!fTicket)
+ {
+ WARNINGKPILOT << "Unable to lock addressbook for writing " << endl;
+ emit logError(i18n("Unable to lock addressbook for writing. Can't sync!"));
+ addSyncLogEntry(i18n("Unable to lock addressbook for writing. Can't sync!"));
+ _cleanupAddressBookPointer();
+ stopTickle();
+ return false;
+ }
+
+ fCtrPC->setStartCount(aBook->allAddressees().count());
+
+ // get the addresseMap which maps Pilot unique record(address) id's to
+ // a Abbrowser Addressee; allows for easy lookup and comparisons
+ if(aBook->begin() == aBook->end())
+ {
+ setFirstSync( true );
+ }
+ else
+ {
+ _mapContactsToPilot(addresseeMap);
+ }
+ stopTickle();
+ return(aBook != 0L);
+}
+
+bool AbbrowserConduit::_saveAddressBook()
+{
+ FUNCTIONSETUP;
+
+ bool saveSuccessful = false;
+
+ fCtrPC->setEndCount(aBook->allAddressees().count());
+
+ Q_ASSERT(fTicket);
+
+ if (abChanged)
+ {
+ saveSuccessful = aBook->save(fTicket);
+ }
+ else
+ {
+ DEBUGKPILOT << fname
+ << "Addressbook not changed, no need to save it" << endl;
+ }
+ // XXX: KDE4: release ticket in all cases (save no longer releases it)
+ if ( !saveSuccessful ) // didn't save, delete ticket manually
+ {
+ aBook->releaseSaveTicket(fTicket);
+ }
+ fTicket=0L;
+
+ if ( AbbrowserSettings::addressbookType()!= AbbrowserSettings::eAbookResource )
+ {
+ KURL kurl(AbbrowserSettings::fileName());
+ if(!kurl.isLocalFile())
+ {
+ DEBUGKPILOT << fname << "Deleting local addressbook tempfile" << endl;
+ if(!KIO::NetAccess::upload(fABookFile, AbbrowserSettings::fileName(), 0L)) {
+ emit logError(i18n("An error occurred while uploading \"%1\". You can try to upload "
+ "the temporary local file \"%2\" manually")
+ .arg(AbbrowserSettings::fileName()).arg(fABookFile));
+ }
+ else {
+ KIO::NetAccess::removeTempFile(fABookFile);
+ }
+ QFile backup(fABookFile + CSL1("~"));
+ backup.remove();
+ }
+
+ }
+
+ // now try to remove the resource from the addressbook...
+ if (fBookResource)
+ {
+ bool r = aBook->removeResource( fBookResource );
+ if ( !r )
+ {
+ DEBUGKPILOT << fname <<": Unable to close resource." << endl;
+ }
+ }
+
+ return saveSuccessful;
+}
+
+
+
+void AbbrowserConduit::_getAppInfo()
+{
+ FUNCTIONSETUP;
+
+ delete fAddressAppInfo;
+ fAddressAppInfo = new PilotAddressInfo(fDatabase);
+ fAddressAppInfo->dump();
+}
+
+void AbbrowserConduit::_setAppInfo()
+{
+ FUNCTIONSETUP;
+ if (fDatabase) fAddressAppInfo->writeTo(fDatabase);
+ if (fLocalDatabase) fAddressAppInfo->writeTo(fLocalDatabase);
+}
+
+
+void AbbrowserConduit::_cleanupAddressBookPointer()
+{
+ if (fCreatedBook)
+ {
+ KPILOT_DELETE(aBook);
+ fCreatedBook=false;
+ }
+ else
+ {
+ aBook=0L;
+ }
+}
+
+
+
+
+/*********************************************************************
+ D E B U G O U T P U T
+ *********************************************************************/
+
+
+
+
+
+void AbbrowserConduit::showPilotAddress(const PilotAddress *pilotAddress)
+{
+ FUNCTIONSETUPL(3);
+ if (debug_level < 3)
+ {
+ return;
+ }
+ if (!pilotAddress)
+ {
+ DEBUGKPILOT<< fname << "| EMPTY"<<endl;
+ return;
+ }
+ DEBUGKPILOT << fname << "\n"
+ << pilotAddress->getTextRepresentation(
+ fAddressAppInfo,Qt::PlainText) << endl;
+}
+
+
+void AbbrowserConduit::showAddresses(
+ const Addressee &pcAddr,
+ const PilotAddress *backupAddr,
+ const PilotAddress *palmAddr)
+{
+ FUNCTIONSETUPL(3);
+ if (debug_level >= 3)
+ {
+ DEBUGKPILOT << fname << "abEntry:" << endl;
+ KABCSync::showAddressee(pcAddr);
+ DEBUGKPILOT << fname << "pilotAddress:" << endl;
+ showPilotAddress(palmAddr);
+ DEBUGKPILOT << fname << "backupAddress:" << endl;
+ showPilotAddress(backupAddr);
+ DEBUGKPILOT << fname << "------------------------------------------------" << endl;
+ }
+}
+
+
+
+/*********************************************************************
+ S Y N C S T R U C T U R E
+ *********************************************************************/
+
+
+
+/* virtual */ bool AbbrowserConduit::exec()
+{
+ FUNCTIONSETUP;
+
+ _prepare();
+
+ bool retrieved = false;
+ if(!openDatabases(CSL1("AddressDB"), &retrieved))
+ {
+ emit logError(i18n("Unable to open the addressbook databases on the handheld."));
+ return false;
+ }
+ setFirstSync( retrieved );
+
+ _getAppInfo();
+
+ // Local block
+ {
+ QString dbpath = fLocalDatabase->dbPathName();
+ DEBUGKPILOT << fname << ": Local database path " << dbpath << endl;
+ }
+
+ if ( syncMode().isTest() )
+ {
+ QTimer::singleShot(0, this, SLOT(slotTestRecord()));
+ return true;
+ }
+
+ if(!_loadAddressBook())
+ {
+ emit logError(i18n("Unable to open the addressbook."));
+ return false;
+ }
+ setFirstSync( isFirstSync() || (aBook->begin() == aBook->end()) );
+
+ DEBUGKPILOT << fname << ": First sync now " << isFirstSync()
+ << " and addressbook is "
+ << ((aBook->begin() == aBook->end()) ? "" : "non-")
+ << "empty." << endl;
+
+ // perform syncing from palm to abbrowser
+ // iterate through all records in palm pilot
+
+ DEBUGKPILOT << fname << ": fullsync=" << isFullSync() << ", firstSync=" << isFirstSync() << endl;
+ DEBUGKPILOT << fname << ": "
+ << "syncDirection=" << syncMode().name() << ", "
+ << "archive = " << AbbrowserSettings::archiveDeleted() << endl;
+ DEBUGKPILOT << fname << ": conflictRes="<< getConflictResolution() << endl;
+ DEBUGKPILOT << fname << ": PilotStreetHome=" << AbbrowserSettings::pilotStreet() << ", PilotFaxHOme" << AbbrowserSettings::pilotFax() << endl;
+
+ if (!isFirstSync())
+ {
+ allIds=fDatabase->idList();
+ }
+
+ QValueVector<int> v(4);
+ v[0] = AbbrowserSettings::custom0();
+ v[1] = AbbrowserSettings::custom1();
+ v[2] = AbbrowserSettings::custom2();
+ v[3] = AbbrowserSettings::custom3();
+
+ fSyncSettings.setCustomMapping(v);
+ fSyncSettings.setFieldForOtherPhone(AbbrowserSettings::pilotOther());
+ fSyncSettings.setDateFormat(AbbrowserSettings::customDateFormat());
+ fSyncSettings.setPreferHome(AbbrowserSettings::pilotStreet()==0);
+ fSyncSettings.setFaxTypeOnPC(faxTypeOnPC());
+
+ /* Note:
+ if eCopyPCToHH or eCopyHHToPC, first sync everything, then lookup
+ those entries on the receiving side that are not yet syncced and delete
+ them. Use slotDeleteUnsyncedPCRecords and slotDeleteUnsyncedHHRecords
+ for this, and no longer purge the whole addressbook before the sync to
+ prevent data loss in case of connection loss. */
+
+ QTimer::singleShot(0, this, SLOT(slotPalmRecToPC()));
+
+ return true;
+}
+
+
+
+void AbbrowserConduit::slotPalmRecToPC()
+{
+ FUNCTIONSETUP;
+ PilotRecord *palmRec = 0L, *backupRec = 0L;
+
+ if ( syncMode() == SyncMode::eCopyPCToHH )
+ {
+ DEBUGKPILOT << fname << ": Done; change to PCtoHH phase." << endl;
+ abiter = aBook->begin();
+ QTimer::singleShot(0, this, SLOT(slotPCRecToPalm()));
+ return;
+ }
+
+ if(isFullSync())
+ {
+ palmRec = fDatabase->readRecordByIndex(pilotindex++);
+ }
+ else
+ {
+ palmRec = fDatabase->readNextModifiedRec();
+ }
+
+ // no record means we're done going in this direction, so switch to
+ // PC->Palm
+ if(!palmRec)
+ {
+ abiter = aBook->begin();
+ QTimer::singleShot(0, this, SLOT(slotPCRecToPalm()));
+ return;
+ }
+
+ // already synced, so skip:
+ if(syncedIds.contains(palmRec->id()))
+ {
+ KPILOT_DELETE(palmRec);
+ QTimer::singleShot(0, this, SLOT(slotPalmRecToPC()));
+ return;
+ }
+
+ backupRec = fLocalDatabase->readRecordById(palmRec->id());
+ PilotRecord*compareRec=(backupRec)?(backupRec):(palmRec);
+ Addressee e = _findMatch(PilotAddress(compareRec));
+
+ PilotAddress*backupAddr=0L;
+ if (backupRec)
+ {
+ backupAddr=new PilotAddress(backupRec);
+ }
+
+ PilotAddress*palmAddr=0L;
+ if (palmRec)
+ {
+ palmAddr=new PilotAddress(palmRec);
+ }
+
+ syncAddressee(e, backupAddr, palmAddr);
+
+ syncedIds.append(palmRec->id());
+ KPILOT_DELETE(palmAddr);
+ KPILOT_DELETE(backupAddr);
+ KPILOT_DELETE(palmRec);
+ KPILOT_DELETE(backupRec);
+
+ QTimer::singleShot(0, this, SLOT(slotPalmRecToPC()));
+}
+
+
+
+void AbbrowserConduit::slotPCRecToPalm()
+{
+ FUNCTIONSETUP;
+
+ if ( (syncMode()==SyncMode::eCopyHHToPC) ||
+ abiter == aBook->end() || (*abiter).isEmpty() )
+ {
+ DEBUGKPILOT << fname << ": Done; change to delete records." << endl;
+ pilotindex = 0;
+ QTimer::singleShot(0, this, SLOT(slotDeletedRecord()));
+ return;
+ }
+
+ PilotRecord *palmRec=0L, *backupRec=0L;
+ Addressee ad = *abiter;
+
+ abiter++;
+
+ // If marked as archived, don't sync!
+ if (KABCSync::isArchived(ad))
+ {
+ DEBUGKPILOT << fname << ": address with id " << ad.uid() <<
+ " marked archived, so don't sync." << endl;
+ QTimer::singleShot(0, this, SLOT(slotPCRecToPalm()));
+ return;
+ }
+
+
+ QString recID(ad.custom(KABCSync::appString, KABCSync::idString));
+ bool ok;
+ recordid_t rid = recID.toLong(&ok);
+ if (recID.isEmpty() || !ok || !rid)
+ {
+ DEBUGKPILOT << fname << ": This is a new record." << endl;
+ // it's a new item(no record ID and not inserted by the Palm -> PC sync), so add it
+ syncAddressee(ad, 0L, 0L);
+ QTimer::singleShot(0, this, SLOT(slotPCRecToPalm()));
+ return;
+ }
+
+ // look into the list of already synced record ids to see if the addressee hasn't already been synced
+ if (syncedIds.contains(rid))
+ {
+ DEBUGKPILOT << ": address with id " << rid << " already synced." << endl;
+ QTimer::singleShot(0, this, SLOT(slotPCRecToPalm()));
+ return;
+ }
+
+
+ backupRec = fLocalDatabase->readRecordById(rid);
+ // only update if no backup record or the backup record is not equal to the addressee
+
+ PilotAddress*backupAddr=0L;
+ if (backupRec)
+ {
+ backupAddr=new PilotAddress(backupRec);
+ }
+ if(!backupRec || isFirstSync() || !_equal(backupAddr, ad) )
+ {
+ DEBUGKPILOT << fname << ": Updating entry." << endl;
+ palmRec = fDatabase->readRecordById(rid);
+ PilotAddress *palmAddr = 0L;
+ if (palmRec)
+ {
+ palmAddr = new PilotAddress(palmRec);
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": No HH record with id " << rid << endl;
+ }
+ syncAddressee(ad, backupAddr, palmAddr);
+ // update the id just in case it changed
+ if (palmRec) rid=palmRec->id();
+ KPILOT_DELETE(palmRec);
+ KPILOT_DELETE(palmAddr);
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": Entry not updated." << endl;
+ }
+ KPILOT_DELETE(backupAddr);
+ KPILOT_DELETE(backupRec);
+
+ DEBUGKPILOT << fname << ": adding id:["<< rid << "] to syncedIds." << endl;
+
+ syncedIds.append(rid);
+ // done with the sync process, go on with the next one:
+ QTimer::singleShot(0, this, SLOT(slotPCRecToPalm()));
+}
+
+
+
+void AbbrowserConduit::slotDeletedRecord()
+{
+ FUNCTIONSETUP;
+
+ PilotRecord *backupRec = fLocalDatabase->readRecordByIndex(pilotindex++);
+ if(!backupRec || isFirstSync() )
+ {
+ KPILOT_DELETE(backupRec);
+ QTimer::singleShot(0, this, SLOT(slotDeleteUnsyncedPCRecords()));
+ return;
+ }
+
+ recordid_t id = backupRec->id();
+
+ QString uid = addresseeMap[id];
+ Addressee e = aBook->findByUid(uid);
+
+ DEBUGKPILOT << fname << ": now looking at palm id: ["
+ << id << "], kabc uid: [" << uid << "]." << endl;
+
+ PilotAddress*backupAddr=0L;
+ if (backupRec)
+ {
+ backupAddr=new PilotAddress(backupRec);
+ }
+ PilotRecord*palmRec=fDatabase->readRecordById(id);
+
+ if ( e.isEmpty() )
+ {
+ DEBUGKPILOT << fname << ": no Addressee found for this id." << endl;
+ DEBUGKPILOT << fname << "\n"
+ << backupAddr->getTextRepresentation(
+ fAddressAppInfo,Qt::PlainText) << endl;
+
+ if (palmRec) {
+ DEBUGKPILOT << fname << ": deleting from database on palm." << endl;
+ fDatabase->deleteRecord(id);
+ fCtrHH->deleted();
+ }
+ DEBUGKPILOT << fname << ": deleting from backup database." << endl;
+ fLocalDatabase->deleteRecord(id);
+
+ // because we just deleted a record, we need to go back one
+ pilotindex--;
+ }
+
+ KPILOT_DELETE(palmRec);
+ KPILOT_DELETE(backupAddr);
+ KPILOT_DELETE(backupRec);
+ QTimer::singleShot(0, this, SLOT(slotDeletedRecord()));
+}
+
+
+
+void AbbrowserConduit::slotDeleteUnsyncedPCRecords()
+{
+ FUNCTIONSETUP;
+ if ( syncMode()==SyncMode::eCopyHHToPC )
+ {
+ QStringList uids;
+ RecordIDList::iterator it;
+ QString uid;
+ for ( it = syncedIds.begin(); it != syncedIds.end(); ++it)
+ {
+ uid=addresseeMap[*it];
+ if (!uid.isEmpty()) uids.append(uid);
+ }
+ // TODO: Does this speed up anything?
+ // qHeapSort( uids );
+ AddressBook::Iterator abit;
+ for (abit = aBook->begin(); abit != aBook->end(); ++abit)
+ {
+ if (!uids.contains((*abit).uid()))
+ {
+ DEBUGKPILOT<<"Deleting addressee "<<(*abit).realName()<<" from PC (is not on HH, and syncing with HH->PC direction)"<<endl;
+ abChanged = true;
+ // TODO: Can I really remove the current iterator???
+ aBook->removeAddressee(*abit);
+ fCtrPC->deleted();
+ }
+ }
+ }
+ QTimer::singleShot(0, this, SLOT(slotDeleteUnsyncedHHRecords()));
+}
+
+
+
+void AbbrowserConduit::slotDeleteUnsyncedHHRecords()
+{
+ FUNCTIONSETUP;
+ if ( syncMode()==SyncMode::eCopyPCToHH )
+ {
+ RecordIDList ids=fDatabase->idList();
+ RecordIDList::iterator it;
+ for ( it = ids.begin(); it != ids.end(); ++it )
+ {
+ if (!syncedIds.contains(*it))
+ {
+ DEBUGKPILOT<<"Deleting record with ID "<<*it<<" from handheld (is not on PC, and syncing with PC->HH direction)"<<endl;
+ fDatabase->deleteRecord(*it);
+ fCtrHH->deleted();
+ fLocalDatabase->deleteRecord(*it);
+ }
+ }
+ }
+ QTimer::singleShot(0, this, SLOT(slotCleanup()));
+}
+
+
+void AbbrowserConduit::slotCleanup()
+{
+ FUNCTIONSETUP;
+
+ // Set the appInfoBlock, just in case the category labels changed
+ _setAppInfo();
+ if(fDatabase)
+ {
+ fDatabase->resetSyncFlags();
+ fDatabase->cleanup();
+ }
+ if(fLocalDatabase)
+ {
+ fLocalDatabase->resetSyncFlags();
+ fLocalDatabase->cleanup();
+ }
+
+ // Write out the sync maps
+ QString syncFile = fLocalDatabase->dbPathName() + CSL1(".sync");
+ DEBUGKPILOT << fname << ": Writing sync map to " << syncFile << endl;
+ KSaveFile map( syncFile );
+ if ( map.status() == 0 )
+ {
+ DEBUGKPILOT << fname << ": Writing sync map ..." << endl;
+ (*map.dataStream()) << addresseeMap ;
+ map.close();
+ }
+ // This also picks up errors from map.close()
+ if ( map.status() != 0 )
+ {
+ WARNINGKPILOT << "Could not make backup of sync map." << endl;
+ }
+
+ _saveAddressBook();
+ delayDone();
+}
+
+
+
+/*********************************************************************
+ G E N E R A L S Y N C F U N C T I O N
+ These functions modify the Handheld and the addressbook
+ *********************************************************************/
+
+
+
+bool AbbrowserConduit::syncAddressee(Addressee &pcAddr, PilotAddress*backupAddr,
+ PilotAddress*palmAddr)
+{
+ FUNCTIONSETUP;
+ showAddresses(pcAddr, backupAddr, palmAddr);
+
+ if ( syncMode() == SyncMode::eCopyPCToHH )
+ {
+ if (pcAddr.isEmpty())
+ {
+ return _deleteAddressee(pcAddr, backupAddr, palmAddr);
+ }
+ else
+ {
+ return _copyToHH(pcAddr, backupAddr, palmAddr);
+ }
+ }
+
+ if ( syncMode() == SyncMode::eCopyHHToPC )
+ {
+ if (!palmAddr)
+ {
+ return _deleteAddressee(pcAddr, backupAddr, palmAddr);
+ }
+ else
+ {
+ return _copyToPC(pcAddr, backupAddr, palmAddr);
+ }
+ }
+
+ if ( !backupAddr || isFirstSync() )
+ {
+ DEBUGKPILOT<< fname << ": Special case: no backup." << endl;
+ /*
+ Resolution matrix (0..does not exist, E..exists, D..deleted flag set, A..archived):
+ HH PC | Resolution
+ ------------------------------------------------------------
+ 0 A | -
+ 0 E | PC -> HH, reset ID if not set correctly
+ D 0 | delete (error, should never occur!!!)
+ D E | CR (ERROR)
+ E/A 0 | HH -> PC
+ E/A E/A| merge/CR
+ */
+ if (!palmAddr && KABCSync::isArchived(pcAddr) )
+ {
+ return true;
+ }
+ else if (!palmAddr && !pcAddr.isEmpty())
+ {
+ DEBUGKPILOT << fname << ": case: 1a"<<endl;
+ // PC->HH
+ bool res=_copyToHH(pcAddr, 0L, 0L);
+ return res;
+ }
+ else if (!palmAddr && pcAddr.isEmpty())
+ {
+ DEBUGKPILOT << fname << ": case: 1b"<<endl;
+ // everything's empty -> ERROR
+ return false;
+ }
+ else if ( (isDeleted(palmAddr) || isArchived(palmAddr)) && pcAddr.isEmpty())
+ {
+ DEBUGKPILOT << fname << ": case: 1c"<<endl;
+ if (isArchived(palmAddr))
+ return _copyToPC(pcAddr, 0L, palmAddr);
+ else
+ // this happens if you add a record on the handheld and delete it again before you do the next sync
+ return _deleteAddressee(pcAddr, 0L, palmAddr);
+ }
+ else if ((isDeleted(palmAddr)||isArchived(palmAddr)) && !pcAddr.isEmpty())
+ {
+ DEBUGKPILOT << fname << ": case: 1d"<<endl;
+ // CR (ERROR)
+ return _smartMergeAddressee(pcAddr, 0L, palmAddr);
+ }
+ else if (pcAddr.isEmpty())
+ {
+ DEBUGKPILOT << fname << ": case: 1e"<<endl;
+ // HH->PC
+ return _copyToPC(pcAddr, 0L, palmAddr);
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": case: 1f"<<endl;
+ // Conflict Resolution
+ return _smartMergeAddressee(pcAddr, 0L, palmAddr);
+ }
+ } // !backupAddr
+ else
+ {
+ DEBUGKPILOT << fname << ": case: 2"<<endl;
+ /*
+ Resolution matrix:
+ 1) if HH.(empty| (deleted &! archived) ) -> { if (PC==B) -> delete, else -> CR }
+ if HH.archied -> {if (PC==B) -> copyToPC, else -> CR }
+ if PC.empty -> { if (HH==B) -> delete, else -> CR }
+ if PC.archived -> {if (HH==B) -> delete on HH, else CR }
+ 2) if PC==HH -> { update B, update ID of PC if needed }
+ 3) if PC==B -> { HH!=PC, thus HH modified, so copy HH->PC }
+ if HH==B -> { PC!=HH, thus PC modified, so copy PC->HH }
+ 4) else: all three addressees are different -> CR
+ */
+
+ if (!palmAddr || isDeleted(palmAddr) )
+ {
+ DEBUGKPILOT << fname << ": case: 2a"<<endl;
+ if (_equal(backupAddr, pcAddr) || pcAddr.isEmpty())
+ {
+ return _deleteAddressee(pcAddr, backupAddr, 0L);
+ }
+ else
+ {
+ return _smartMergeAddressee(pcAddr, backupAddr, 0L);
+ }
+ }
+ else if (pcAddr.isEmpty())
+ {
+ DEBUGKPILOT << fname << ": case: 2b"<<endl;
+ if (*palmAddr == *backupAddr)
+ {
+ return _deleteAddressee(pcAddr, backupAddr, palmAddr);
+ }
+ else
+ {
+ return _smartMergeAddressee(pcAddr, backupAddr, palmAddr);
+ }
+ }
+ else if (_equal(palmAddr, pcAddr))
+ {
+ DEBUGKPILOT << fname << ": case: 2c"<<endl;
+ // update Backup, update ID of PC if neededd
+ return _writeBackup(palmAddr);
+ }
+ else if (_equal(backupAddr, pcAddr))
+ {
+ DEBUGKPILOT << fname << ": case: 2d"<<endl;
+ DEBUGKPILOT << fname << ": Flags: "<<palmAddr->attributes()<<", isDeleted="<<
+ isDeleted(palmAddr)<<", isArchived="<<isArchived(palmAddr)<<endl;
+ if (isDeleted(palmAddr))
+ return _deleteAddressee(pcAddr, backupAddr, palmAddr);
+ else
+ return _copyToPC(pcAddr, backupAddr, palmAddr);
+ }
+ else if (*palmAddr == *backupAddr)
+ {
+ DEBUGKPILOT << fname << ": case: 2e"<<endl;
+ return _copyToHH(pcAddr, backupAddr, palmAddr);
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": case: 2f"<<endl;
+ // CR, since all are different
+ return _smartMergeAddressee(pcAddr, backupAddr, palmAddr);
+ }
+ } // backupAddr
+ return false;
+}
+
+
+
+bool AbbrowserConduit::_copyToHH(Addressee &pcAddr, PilotAddress*backupAddr,
+ PilotAddress*palmAddr)
+{
+ FUNCTIONSETUP;
+
+ if (pcAddr.isEmpty()) return false;
+ PilotAddress*paddr=palmAddr;
+ bool paddrcreated=false;
+ if (!paddr)
+ {
+ paddr=new PilotAddress();
+ paddrcreated=true;
+ fCtrHH->created();
+ }
+ else
+ {
+ fCtrHH->updated();
+ }
+ KABCSync::copy(*paddr, pcAddr, *fAddressAppInfo, fSyncSettings);
+
+ DEBUGKPILOT << fname << "palmAddr->id=" << paddr->id()
+ << ", pcAddr.ID=" << pcAddr.custom(KABCSync::appString, KABCSync::idString) << endl;
+
+ if(_savePalmAddr(paddr, pcAddr))
+ {
+ _savePCAddr(pcAddr, backupAddr, paddr);
+ }
+ if (paddrcreated) KPILOT_DELETE(paddr);
+ return true;
+}
+
+
+
+bool AbbrowserConduit::_copyToPC(Addressee &pcAddr, PilotAddress*backupAddr,
+ PilotAddress*palmAddr)
+{
+ FUNCTIONSETUP;
+ if (!palmAddr)
+ {
+ return false;
+ }
+ // keep track of CUD's...
+ if (pcAddr.isEmpty())
+ {
+ fCtrPC->created();
+ }
+ else
+ {
+ fCtrPC->updated();
+ }
+ showPilotAddress(palmAddr);
+
+ KABCSync::copy(pcAddr, *palmAddr, *fAddressAppInfo, fSyncSettings);
+ if (isArchived(palmAddr))
+ {
+ KABCSync::makeArchived(pcAddr);
+ }
+
+ _savePCAddr(pcAddr, backupAddr, palmAddr);
+ _writeBackup(palmAddr);
+ return true;
+}
+
+
+
+bool AbbrowserConduit::_writeBackup(PilotAddress *backup)
+{
+ FUNCTIONSETUP;
+ if (!backup) return false;
+
+ showPilotAddress(backup);
+
+ PilotRecord *pilotRec = backup->pack();
+ fLocalDatabase->writeRecord(pilotRec);
+ KPILOT_DELETE(pilotRec);
+ return true;
+}
+
+
+
+bool AbbrowserConduit::_deleteAddressee(Addressee &pcAddr, PilotAddress*backupAddr,
+ PilotAddress*palmAddr)
+{
+ FUNCTIONSETUP;
+
+ if (palmAddr)
+ {
+ if (!syncedIds.contains(palmAddr->id())) {
+ DEBUGKPILOT << fname << ": adding id:["<< palmAddr->id() << "] to syncedIds." << endl;
+ syncedIds.append(palmAddr->id());
+ }
+ fDatabase->deleteRecord(palmAddr->id());
+ fCtrHH->deleted();
+ fLocalDatabase->deleteRecord(palmAddr->id());
+ }
+ else if (backupAddr)
+ {
+ if (!syncedIds.contains(backupAddr->id())) {
+ DEBUGKPILOT << fname << ": adding id:["<< backupAddr->id() << "] to syncedIds." << endl;
+ syncedIds.append(backupAddr->id());
+ }
+ fLocalDatabase->deleteRecord(backupAddr->id());
+ }
+ if (!pcAddr.isEmpty())
+ {
+ DEBUGKPILOT << fname << " removing " << pcAddr.formattedName() << endl;
+ abChanged = true;
+ aBook->removeAddressee(pcAddr);
+ fCtrPC->deleted();
+ }
+ return true;
+}
+
+
+
+/*********************************************************************
+ l o w - l e v e l f u n c t i o n s f o r
+ adding / removing palm/pc records
+ *********************************************************************/
+
+
+
+bool AbbrowserConduit::_savePalmAddr(PilotAddress *palmAddr, Addressee &pcAddr)
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname << ": Saving to pilot " << palmAddr->id()
+ << " " << palmAddr->getField(entryFirstname)
+ << " " << palmAddr->getField(entryLastname)<< endl;
+
+ PilotRecord *pilotRec = palmAddr->pack();
+ DEBUGKPILOT << fname << ": record with id=" << pilotRec->id()
+ << " len=" << pilotRec->size() << endl;
+ recordid_t pilotId = fDatabase->writeRecord(pilotRec);
+ DEBUGKPILOT << fname << ": Wrote "<<pilotId<<": ID="<<pilotRec->id()<<endl;
+ fLocalDatabase->writeRecord(pilotRec);
+ KPILOT_DELETE(pilotRec);
+
+ // pilotId == 0 if using local db, so don't overwrite the valid id
+ if(pilotId != 0)
+ {
+ palmAddr->setID(pilotId);
+ if (!syncedIds.contains(pilotId)) {
+ DEBUGKPILOT << fname << ": adding id:["<< pilotId << "] to syncedIds." << endl;
+ syncedIds.append(pilotId);
+ }
+ }
+
+ recordid_t abId = 0;
+ abId = pcAddr.custom(KABCSync::appString, KABCSync::idString).toUInt();
+ if(abId != pilotId)
+ {
+ pcAddr.insertCustom(KABCSync::appString, KABCSync::idString, QString::number(pilotId));
+ return true;
+ }
+
+ return false;
+}
+
+
+
+bool AbbrowserConduit::_savePCAddr(Addressee &pcAddr, PilotAddress*,
+ PilotAddress*)
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT<<"Before _savePCAddr, pcAddr.custom="<<pcAddr.custom(KABCSync::appString, KABCSync::idString)<<endl;
+ QString pilotId = pcAddr.custom(KABCSync::appString, KABCSync::idString);
+ long pilotIdL = pilotId.toLong();
+ if(!pilotId.isEmpty())
+ {
+ // because we maintain a mapping between pilotId -> kabc uid, whenever we add
+ // a new relationship, we have to remove any old mapping that would tie a different
+ // pilot id -> this kabc uid
+ QMap < recordid_t, QString>::iterator it;
+ for ( it = addresseeMap.begin(); it != addresseeMap.end(); ++it ) {
+ QString kabcUid = it.data();
+ if (kabcUid == pcAddr.uid()) {
+ addresseeMap.remove(it);
+ break;
+ }
+ }
+
+ // now put the new mapping in
+ addresseeMap.insert(pilotIdL, pcAddr.uid());
+ }
+
+ aBook->insertAddressee(pcAddr);
+
+ abChanged = true;
+ return true;
+}
+
+
+
+
+/*********************************************************************
+ C O P Y R E C O R D S
+ *********************************************************************/
+
+
+
+bool AbbrowserConduit::_equal(const PilotAddress *piAddress, const Addressee &abEntry,
+ enum eqFlagsType flags) const
+{
+ FUNCTIONSETUP;
+
+ // empty records are never equal!
+ if (!piAddress) {
+ DEBUGKPILOT << fname << ": no pilot address passed" << endl;
+ return false;
+ }
+ if (abEntry.isEmpty()) {
+ DEBUGKPILOT << fname << ":abEntry.isEmpty()" << endl;
+ return false;
+ }
+ // Archived records match anything so they won't be copied to the HH again
+ if (flags & eqFlagsFlags)
+ if (isArchived(piAddress) && KABCSync::isArchived(abEntry) ) return true;
+
+ if (flags & eqFlagsName)
+ {
+ if(!_equal(abEntry.familyName(), piAddress->getField(entryLastname)))
+ {
+ DEBUGKPILOT << fname << ": last name not equal" << endl;
+ return false;
+ }
+ if(!_equal(abEntry.givenName(), piAddress->getField(entryFirstname)))
+ {
+ DEBUGKPILOT << fname << ": first name not equal" << endl;
+ return false;
+ }
+ if(!_equal(abEntry.prefix(), piAddress->getField(entryTitle)))
+ {
+ DEBUGKPILOT << fname << ": title/prefix not equal" << endl;
+ return false;
+ }
+ if(!_equal(abEntry.organization(), piAddress->getField(entryCompany)))
+ {
+ DEBUGKPILOT << fname << ": company/organization not equal" << endl;
+ return false;
+ }
+ }
+ if (flags & eqFlagsNote)
+ if(!_equal(abEntry.note(), piAddress->getField(entryNote)))
+ {
+ DEBUGKPILOT << fname << ": note not equal" << endl;
+ return false;
+ }
+
+ if (flags & eqFlagsCategory)
+ {
+ // Check that the name of the category of the HH record
+ // is one matching the PC record.
+ QString addressCategoryLabel = fAddressAppInfo->categoryName(piAddress->category());
+ QString cat = KABCSync::bestMatchedCategoryName(abEntry.categories(),
+ *fAddressAppInfo, piAddress->category());
+ if(!_equal(cat, addressCategoryLabel))
+ {
+ DEBUGKPILOT << fname << ": category not equal" << endl;
+ return false;
+ }
+ }
+
+ if (flags & eqFlagsPhones)
+ {
+ // first, look for missing e-mail addresses on either side
+ QStringList abEmails(abEntry.emails());
+ QStringList piEmails(piAddress->getEmails());
+
+ if (abEmails.count() != piEmails.count())
+ {
+ DEBUGKPILOT << fname << ": email count not equal" << endl;
+ return false;
+ }
+ for (QStringList::Iterator it = abEmails.begin(); it != abEmails.end(); it++) {
+ if (!piEmails.contains(*it))
+ {
+ DEBUGKPILOT << fname << ": pilot e-mail missing" << endl;
+ return false;
+ }
+ }
+ for (QStringList::Iterator it = piEmails.begin(); it != piEmails.end(); it++) {
+ if (!abEmails.contains(*it))
+ {
+ DEBUGKPILOT << fname << ": kabc e-mail missing" << endl;
+ return false;
+ }
+ }
+
+ // now look for differences in phone numbers. Note: we can't just compare one
+ // of each kind of phone number, because there's no guarantee that if the user
+ // has more than one of a given type, we're comparing the correct two.
+
+ PhoneNumber::List abPhones(abEntry.phoneNumbers());
+ PhoneNumber::List piPhones = KABCSync::getPhoneNumbers(*piAddress);
+ // first make sure that all of the pilot phone numbers are in kabc
+ for (PhoneNumber::List::Iterator it = piPhones.begin(); it != piPhones.end(); it++) {
+ PhoneNumber piPhone = *it;
+ bool found=false;
+ for (PhoneNumber::List::Iterator it = abPhones.begin(); it != abPhones.end(); it++) {
+ PhoneNumber abPhone = *it;
+ // see if we have the same number here...
+ // * Note * We used to check for preferred number matching, but
+ // this seems to have broke in kdepim 3.5 and I don't have time to
+ // figure out why, so we won't check to see if preferred number match
+ if ( _equal(piPhone.number(), abPhone.number()) ) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ DEBUGKPILOT << fname << ": not equal because kabc phone not found." << endl;
+ return false;
+ }
+ }
+ // now the other way. *cringe* kabc has the capacity to store way more addresses
+ // than the Pilot, so this might give false positives more than we'd want....
+ for (PhoneNumber::List::Iterator it = abPhones.begin(); it != abPhones.end(); it++) {
+ PhoneNumber abPhone = *it;
+ bool found=false;
+ for (PhoneNumber::List::Iterator it = piPhones.begin(); it != piPhones.end(); it++) {
+ PhoneNumber piPhone = *it;
+ if ( _equal(piPhone.number(), abPhone.number()) ) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ DEBUGKPILOT << fname << ": not equal because pilot phone not found." << endl;
+ return false;
+ }
+ }
+
+ if(!_equal(KABCSync::getFieldForHHOtherPhone(abEntry,fSyncSettings),
+ piAddress->getPhoneField(PilotAddressInfo::eOther)))
+ {
+ DEBUGKPILOT << fname << ": not equal because of other phone field." << endl;
+ return false;
+ }
+ }
+
+ if (flags & eqFlagsAdress)
+ {
+ KABC::Address address = KABCSync::getAddress(abEntry,fSyncSettings);
+ if(!_equal(address.street(), piAddress->getField(entryAddress)))
+ {
+ DEBUGKPILOT << fname << ": address not equal" << endl;
+ return false;
+ }
+ if(!_equal(address.locality(), piAddress->getField(entryCity)))
+ {
+ DEBUGKPILOT << fname << ": city not equal" << endl;
+ return false;
+ }
+ if(!_equal(address.region(), piAddress->getField(entryState)))
+ {
+ DEBUGKPILOT << fname << ": state not equal" << endl;
+ return false;
+ }
+ if(!_equal(address.postalCode(), piAddress->getField(entryZip)))
+ {
+ DEBUGKPILOT << fname << ": zip not equal" << endl;
+ return false;
+ }
+ if(!_equal(address.country(), piAddress->getField(entryCountry)))
+ {
+ DEBUGKPILOT << fname << ": country not equal" << endl;
+ return false;
+ }
+ }
+
+ if (flags & eqFlagsCustom)
+ {
+ unsigned int customIndex = 0;
+ unsigned int hhField = entryCustom1;
+
+ for ( ; customIndex<4; ++customIndex,++hhField )
+ {
+ if (!_equal(KABCSync::getFieldForHHCustom(customIndex, abEntry, fSyncSettings),
+ piAddress->getField(hhField)))
+ {
+ DEBUGKPILOT << fname << ": Custom field " << customIndex
+ << " (HH field " << hhField << ") differs." << endl;
+ return false;
+ }
+ }
+ }
+
+ // if any side is marked archived, but the other is not, the two
+ // are not equal.
+ if ( (flags & eqFlagsFlags) && (isArchived(piAddress) || KABCSync::isArchived(abEntry) ) )
+ {
+ DEBUGKPILOT << fname << ": archived flags don't match" << endl;
+ return false;
+ }
+
+ return true;
+}
+
+
+
+
+
+
+
+
+
+
+/*********************************************************************
+ C O N F L I C T R E S O L U T I O N a n d M E R G I N G
+ *********************************************************************/
+
+
+
+/** smartly merge the given field for the given entry. use the backup record to determine which record has been modified
+ @pc, @backup, @palm ... entries of the according databases
+ @returns string of the merged entries.
+*/
+QString AbbrowserConduit::_smartMergeString(const QString &pc, const QString & backup,
+ const QString & palm, ConflictResolution confRes)
+{
+ FUNCTIONSETUP;
+
+ // if both entries are already the same, no need to do anything
+ if(pc == palm) return pc;
+
+ // If this is a first sync, we don't have a backup record, so
+ if(isFirstSync() || backup.isEmpty()) {
+ if (pc.isEmpty() && palm.isEmpty() ) return QString::null;
+ if(pc.isEmpty()) return palm;
+ if(palm.isEmpty()) return pc;
+ } else {
+ // only one side modified, so return that string, no conflict
+ if(palm == backup) return pc;
+ if(pc == backup) return palm;
+ }
+
+ DEBUGKPILOT<<"pc="<<pc<<", backup="<<backup<<", palm="<<
+ palm<<", ConfRes="<<confRes<<endl;
+ DEBUGKPILOT<<"Use conflict resolution :"<<confRes<<
+ ", PC="<<SyncAction::ePCOverrides<<endl;
+ switch(confRes) {
+ case SyncAction::ePCOverrides: return pc; break;
+ case SyncAction::eHHOverrides: return palm; break;
+ case SyncAction::ePreviousSyncOverrides: return backup; break;
+ default: break;
+ }
+ return QString::null;
+}
+
+
+
+bool AbbrowserConduit::_buildResolutionTable(ResolutionTable*tab, const Addressee &pcAddr,
+ PilotAddress *backupAddr, PilotAddress *palmAddr)
+{
+ FUNCTIONSETUP;
+ if (!tab) return false;
+ tab->setAutoDelete( TRUE );
+ tab->labels[0]=i18n("Item on PC");
+ tab->labels[1]=i18n("Handheld");
+ tab->labels[2]=i18n("Last sync");
+ if (!pcAddr.isEmpty())
+ tab->fExistItems=(eExistItems)(tab->fExistItems|eExistsPC);
+ if (backupAddr)
+ tab->fExistItems=(eExistItems)(tab->fExistItems|eExistsBackup);
+ if (palmAddr)
+ tab->fExistItems=(eExistItems)(tab->fExistItems|eExistsPalm);
+
+#define appendGen(desc, abfield, palmfield) \
+ tab->append(new ResolutionItem(desc, tab->fExistItems, \
+ (!pcAddr.isEmpty())?(abfield):(QString::null), \
+ (palmAddr)?(palmAddr->palmfield):(QString::null), \
+ (backupAddr)?(backupAddr->palmfield):(QString::null) ))
+#define appendAddr(desc, abfield, palmfield) \
+ appendGen(desc, abfield, getField(palmfield))
+#define appendGenPhone(desc, abfield, palmfield) \
+ appendGen(desc, abfield, getPhoneField(PilotAddressInfo::palmfield))
+#define appendPhone(desc, abfield, palmfield) \
+ appendGenPhone(desc, pcAddr.phoneNumber(PhoneNumber::abfield).number(), palmfield)
+
+
+ appendAddr(i18n("Last name"), pcAddr.familyName(), entryLastname);
+ appendAddr(i18n("First name"), pcAddr.givenName(), entryFirstname);
+ appendAddr(i18n("Organization"), pcAddr.organization(), entryCompany);
+ appendAddr(i18n("Title"), pcAddr.prefix(), entryTitle);
+ appendAddr(i18n("Note"), pcAddr.note(), entryNote);
+
+ appendAddr(i18n("Custom 1"), KABCSync::getFieldForHHCustom(0, pcAddr, fSyncSettings), entryCustom1);
+ appendAddr(i18n("Custom 2"), KABCSync::getFieldForHHCustom(1, pcAddr, fSyncSettings), entryCustom2);
+ appendAddr(i18n("Custom 3"), KABCSync::getFieldForHHCustom(2, pcAddr, fSyncSettings), entryCustom3);
+ appendAddr(i18n("Custom 4"), KABCSync::getFieldForHHCustom(3, pcAddr, fSyncSettings), entryCustom4);
+
+ appendPhone(i18n("Work Phone"), Work, eWork);
+ appendPhone(i18n("Home Phone"), Home, eHome);
+ appendPhone(i18n("Mobile Phone"), Cell, eMobile);
+ appendGenPhone(i18n("Fax"), pcAddr.phoneNumber(faxTypeOnPC()).number(), eFax);
+ appendPhone(i18n("Pager"), Pager, ePager);
+ appendGenPhone(i18n("Other"), KABCSync::getFieldForHHOtherPhone(pcAddr,fSyncSettings), eOther);
+ appendGenPhone(i18n("Email"), pcAddr.preferredEmail(), eEmail);
+
+ KABC::Address abAddress = KABCSync::getAddress(pcAddr,fSyncSettings);
+ appendAddr(i18n("Address"), abAddress.street(), entryAddress);
+ appendAddr(i18n("City"), abAddress.locality(), entryCity);
+ appendAddr(i18n("Region"), abAddress.region(), entryState);
+ appendAddr(i18n("Postal code"), abAddress.postalCode(), entryZip);
+ appendAddr(i18n("Country"), abAddress.country(), entryCountry);
+
+ QString palmAddrCategoryLabel;
+ if (palmAddr)
+ {
+ palmAddrCategoryLabel = fAddressAppInfo->categoryName(palmAddr->category());
+ }
+ QString backupAddrCategoryLabel;
+ if (backupAddr)
+ {
+ backupAddrCategoryLabel = fAddressAppInfo->categoryName(backupAddr->category());
+ }
+ int category = palmAddr ? palmAddr->category() : 0;
+ tab->append(new ResolutionItem(
+ i18n("Category"),
+ tab->fExistItems,
+ !pcAddr.isEmpty() ?
+ KABCSync::bestMatchedCategoryName(pcAddr.categories(), *fAddressAppInfo, category) :
+ QString::null,
+ palmAddrCategoryLabel,
+ backupAddrCategoryLabel));
+#undef appendGen
+#undef appendAddr
+#undef appendGenPhone
+#undef appendPhone
+
+ return true;
+}
+
+
+/// This function just sets the phone number of type "type" to "phone"
+static inline void setPhoneNumber(Addressee &abEntry, int type, const QString &nr)
+{
+ PhoneNumber phone = abEntry.phoneNumber(type);
+ phone.setNumber(nr);
+ abEntry.insertPhoneNumber(phone);
+}
+
+
+bool AbbrowserConduit::_applyResolutionTable(ResolutionTable*tab, Addressee &pcAddr,
+ PilotAddress *backupAddr, PilotAddress *palmAddr)
+{
+ FUNCTIONSETUP;
+ if (!tab) return false;
+ if (!palmAddr) {
+ WARNINGKPILOT << "Empty palmAddr after conflict resolution." << endl;
+ return false;
+ }
+
+ ResolutionItem*item=tab->first();
+#define SETGENFIELD(abfield, palmfield) \
+ if (item) {\
+ abfield; \
+ palmAddr->setField(palmfield, item->fResolved); \
+ }\
+ item=tab->next();
+#define SETFIELD(abfield, palmfield) \
+ SETGENFIELD(pcAddr.set##abfield(item->fResolved), palmfield)
+#define SETCUSTOMFIELD(abfield, palmfield) \
+ SETGENFIELD(KABCSync::setFieldFromHHCustom(abfield, pcAddr, item->fResolved, fSyncSettings), palmfield)
+#define SETGENPHONE(abfield, palmfield) \
+ if (item) { \
+ abfield; \
+ palmAddr->setPhoneField(PilotAddressInfo::palmfield, item->fResolved, PilotAddress::Replace); \
+ }\
+ item=tab->next();
+#define SETPHONEFIELD(abfield, palmfield) \
+ SETGENPHONE(setPhoneNumber(pcAddr, PhoneNumber::abfield, item->fResolved), palmfield)
+#define SETADDRESSFIELD(abfield, palmfield) \
+ SETGENFIELD(abAddress.abfield(item->fResolved), palmfield)
+
+ SETFIELD(FamilyName, entryLastname);
+ SETFIELD(GivenName, entryFirstname);
+ SETFIELD(Organization, entryCompany);
+ SETFIELD(Prefix, entryTitle);
+ SETFIELD(Note, entryNote);
+
+ SETCUSTOMFIELD(0, entryCustom1);
+ SETCUSTOMFIELD(1, entryCustom2);
+ SETCUSTOMFIELD(2, entryCustom3);
+ SETCUSTOMFIELD(3, entryCustom4);
+
+ SETPHONEFIELD(Work, eWork);
+ SETPHONEFIELD(Home, eHome);
+ SETPHONEFIELD(Cell, eMobile);
+ SETGENPHONE(setPhoneNumber(pcAddr, faxTypeOnPC(), item->fResolved), eFax);
+ SETPHONEFIELD(Pager, ePager);
+ SETGENPHONE(KABCSync::setFieldFromHHOtherPhone(pcAddr, item->fResolved, fSyncSettings), eOther);
+
+ // TODO: fix email
+ if (item)
+ {
+ palmAddr->setPhoneField(PilotAddressInfo::eEmail, item->fResolved, PilotAddress::Replace);
+ if (backupAddr)
+ {
+ pcAddr.removeEmail(backupAddr->getPhoneField(PilotAddressInfo::eEmail));
+ }
+ pcAddr.removeEmail(palmAddr->getPhoneField(PilotAddressInfo::eEmail));
+ pcAddr.insertEmail(item->fResolved, true);
+ }
+ item=tab->next();
+
+ KABC::Address abAddress = KABCSync::getAddress(pcAddr, fSyncSettings);
+ SETADDRESSFIELD(setStreet, entryAddress);
+ SETADDRESSFIELD(setLocality, entryCity);
+ SETADDRESSFIELD(setRegion, entryState);
+ SETADDRESSFIELD(setPostalCode, entryZip);
+ SETADDRESSFIELD(setCountry, entryCountry);
+ pcAddr.insertAddress(abAddress);
+
+ // TODO: Is this correct?
+ if (item)
+ {
+ palmAddr->setCategory( fAddressAppInfo->findCategory(item->fResolved) );
+ KABCSync::setCategory(pcAddr, item->fResolved);
+ }
+
+
+#undef SETGENFIELD
+#undef SETFIELD
+#undef SETCUSTOMFIELD
+#undef SETGENPHONE
+#undef SETPHONEFIELD
+#undef SETADDRESSFIELD
+
+ return true;
+}
+
+
+
+bool AbbrowserConduit::_smartMergeTable(ResolutionTable*tab)
+{
+ FUNCTIONSETUP;
+ if (!tab) return false;
+ bool noconflict=true;
+ ResolutionItem*item;
+ for ( item = tab->first(); item; item = tab->next() )
+ {
+ // try to merge the three strings
+ item->fResolved=_smartMergeString(item->fEntries[0],
+ item->fEntries[2], item->fEntries[1], getConflictResolution());
+ // if a conflict occurred, set the default to something sensitive:
+ if (item->fResolved.isNull() && !(item->fEntries[0].isEmpty() &&
+ item->fEntries[1].isEmpty() && item->fEntries[2].isEmpty() ) )
+ {
+ item->fResolved=item->fEntries[0];
+ noconflict=false;
+ }
+ if (item->fResolved.isNull()) item->fResolved=item->fEntries[1];
+ if (item->fResolved.isNull()) item->fResolved=item->fEntries[2];
+ }
+ return noconflict;
+}
+
+
+
+/** Merge the palm and the pc entries with the additional information of
+ * the backup.
+ * return value: no meaning yet
+ */
+bool AbbrowserConduit::_smartMergeAddressee(Addressee &pcAddr,
+ PilotAddress *backupAddr, PilotAddress *palmAddr)
+{
+ FUNCTIONSETUP;
+
+ // Merge them, then look which records have to be written to device or abook
+ int res = SyncAction::eAskUser;
+ bool result=true;
+ ResolutionTable tab;
+
+ result &= _buildResolutionTable(&tab, pcAddr, backupAddr, palmAddr);
+ // Now attempt a smart merge. If that fails, let conflict resolution do the job
+ bool mergeOk=_smartMergeTable(&tab);
+
+ if (!mergeOk)
+ {
+ QString dlgText;
+ if (!palmAddr)
+ {
+ dlgText=i18n("The following address entry was changed, but does no longer exist on the handheld. Please resolve this conflict:");
+ }
+ else if (pcAddr.isEmpty())
+ {
+ dlgText=i18n("The following address entry was changed, but does no longer exist on the PC. Please resolve this conflict:");
+ }
+ else
+ {
+ dlgText=i18n("The following address entry was changed on the handheld as well as on the PC side. The changes could not be merged automatically, so please resolve the conflict yourself:");
+ }
+ ResolutionDlg*resdlg=new ResolutionDlg(0L, fHandle, i18n("Address conflict"), dlgText, &tab);
+ resdlg->exec();
+ KPILOT_DELETE(resdlg);
+ }
+ res=tab.fResolution;
+
+ // Disallow some resolution under certain conditions, fix wrong values:
+ switch (res) {
+ case SyncAction::eHHOverrides:
+ if (!palmAddr) res=SyncAction::eDelete;
+ break;
+ case SyncAction::ePCOverrides:
+ if (pcAddr.isEmpty()) res=SyncAction::eDelete;
+ break;
+ case SyncAction::ePreviousSyncOverrides:
+ if (!backupAddr) res=SyncAction::eDoNothing;
+ break;
+ }
+
+ PilotAddress*pAddr=palmAddr;
+ bool pAddrCreated=false;
+ // Now that we have done a possible conflict resolution, apply the changes
+ switch (res) {
+ case SyncAction::eDuplicate:
+ // Set the Palm ID to 0 so we don't overwrite the existing record.
+ pcAddr.removeCustom(KABCSync::appString, KABCSync::idString);
+ result &= _copyToHH(pcAddr, 0L, 0L);
+ {
+ Addressee pcadr;
+ result &= _copyToPC(pcadr, backupAddr, palmAddr);
+ }
+ break;
+ case SyncAction::eDoNothing:
+ break;
+ case SyncAction::eHHOverrides:
+ result &= _copyToPC(pcAddr, backupAddr, palmAddr);
+ break;
+ case SyncAction::ePCOverrides:
+ result &= _copyToHH(pcAddr, backupAddr, pAddr);
+ break;
+ case SyncAction::ePreviousSyncOverrides:
+ KABCSync::copy(pcAddr, *backupAddr, *fAddressAppInfo, fSyncSettings);
+ if (palmAddr && backupAddr) *palmAddr=*backupAddr;
+ result &= _savePalmAddr(backupAddr, pcAddr);
+ result &= _savePCAddr(pcAddr, backupAddr, backupAddr);
+ break;
+ case SyncAction::eDelete:
+ result &= _deleteAddressee(pcAddr, backupAddr, palmAddr);
+ break;
+ case SyncAction::eAskUser:
+ default:
+ if (!pAddr)
+ {
+ pAddr=new PilotAddress();
+ pAddrCreated=true;
+ }
+ result &= _applyResolutionTable(&tab, pcAddr, backupAddr, pAddr);
+showAddresses(pcAddr, backupAddr, pAddr);
+ // savePalmAddr sets the RecordID custom field already
+ result &= _savePalmAddr(pAddr, pcAddr);
+ result &= _savePCAddr(pcAddr, backupAddr, pAddr);
+ if (pAddrCreated) KPILOT_DELETE(pAddr);
+ break;
+ }
+
+ return result;
+}
+
+
+
+// TODO: right now entries are equal if both first/last name and organization are
+// equal. This rules out two entries for the same person(e.g. real home and weekend home)
+// or two persons with the same name where you don't know the organization.!!!
+Addressee AbbrowserConduit::_findMatch(const PilotAddress & pilotAddress) const
+{
+ FUNCTIONSETUP;
+ // TODO: also search with the pilotID
+ // first, use the pilotID to UID map to find the appropriate record
+ if( !isFirstSync() && (pilotAddress.id() > 0) )
+ {
+ QString id(addresseeMap[pilotAddress.id()]);
+ DEBUGKPILOT << fname << ": PilotRecord has id " << pilotAddress.id() << ", mapped to " << id << endl;
+ if(!id.isEmpty())
+ {
+ Addressee res(aBook->findByUid(id));
+ if(!res.isEmpty()) return res;
+ DEBUGKPILOT << fname << ": PilotRecord has id " << pilotAddress.id() << ", but could not be found in the addressbook" << endl;
+ }
+ }
+
+ for(AddressBook::Iterator iter = aBook->begin(); iter != aBook->end(); ++iter)
+ {
+ Addressee abEntry = *iter;
+ QString recID(abEntry.custom(KABCSync::appString, KABCSync::idString));
+ bool ok;
+ if (!recID.isEmpty() )
+ {
+ recordid_t rid = recID.toLong(&ok);
+ if (ok && rid)
+ {
+ if (rid==pilotAddress.id()) return abEntry;// yes, we found it
+ // skip this addressee, as it can an other corresponding address on the handheld
+ if (allIds.contains(rid)) continue;
+ }
+ }
+
+ if (_equal(&pilotAddress, abEntry, eqFlagsAlmostAll))
+ {
+ return abEntry;
+ }
+ }
+ DEBUGKPILOT << fname << ": Could not find any addressbook enty matching " << pilotAddress.getField(entryLastname) << endl;
+ return Addressee();
+}
+
+void AbbrowserConduit::slotTestRecord()
+{
+ FUNCTIONSETUP;
+
+ // Get a record and interpret it as an address.
+ PilotRecord *r = fDatabase->readRecordByIndex( pilotindex );
+ if (!r)
+ {
+ delayDone();
+ return;
+ }
+ PilotAddress a(r);
+ KPILOT_DELETE(r);
+
+ // Process this record.
+ showPilotAddress(&a);
+
+ // Schedule more work.
+ ++pilotindex;
+ QTimer::singleShot(0, this, SLOT(slotTestRecord()));
+}
diff --git a/kpilot/conduits/abbrowserconduit/abbrowser-conduit.h b/kpilot/conduits/abbrowserconduit/abbrowser-conduit.h
new file mode 100644
index 000000000..484f61292
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/abbrowser-conduit.h
@@ -0,0 +1,222 @@
+#ifndef _ABBROWSER_CONDUIT_H
+#define _ABBROWSER_CONDUIT_H
+/* abbrowser-conduit.h KPilot
+**
+** Copyright (C) 2000,2001 by Dan Pilone
+** Copyright (C) 2000 Gregory Stern
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include <kabc/addressbook.h>
+
+#include <pilotAddress.h>
+#include <plugin.h>
+
+#include "kabcRecord.h"
+
+
+class ResolutionTable;
+namespace KABC
+{
+class Addressee;
+class Address;
+class PhoneNumber;
+class Ticket;
+}
+
+using namespace KABC;
+
+typedef QValueList<recordid_t> RecordIDList;
+
+class AbbrowserConduit : public ConduitAction
+{
+Q_OBJECT
+public:
+ AbbrowserConduit(KPilotLink *o,const char *n = 0L,
+ const QStringList &a = QStringList() );
+ virtual ~AbbrowserConduit();
+
+/*********************************************************************
+ S Y N C S T R U C T U R E
+ *********************************************************************/
+ virtual bool exec();
+protected slots:
+ void slotPalmRecToPC();
+ void slotPCRecToPalm();
+ void slotDeletedRecord();
+ void slotDeleteUnsyncedPCRecords();
+ void slotDeleteUnsyncedHHRecords();
+ void slotCleanup();
+
+ void slotTestRecord();
+
+private:
+
+ /********************************************************/
+ /* Handle the configuration */
+ /********************************************************/
+
+ /* Read the global KPilot config file for settings
+ * particular to the AbbrowserConduit conduit. */
+ void readConfig();
+
+ void showPilotAddress(const PilotAddress *pilotAddress);
+ void showAddresses(
+ const Addressee &pcAddr,
+ const PilotAddress *backupAddr,
+ const PilotAddress *palmAddr);
+
+
+ /********************************************************/
+ /* Loading and saving the addressbook and database */
+ /********************************************************/
+
+
+ /* Given a list of contacts, creates the pilot id to contact key map
+ * and a list of new contacts in O(n) time (single pass) */
+ void _mapContactsToPilot( QMap < recordid_t, QString> &idContactMap);
+ /* Do the preperations before doSync or doBackup.
+ * Load contacts, set the pilot */
+ bool _prepare();
+ /* Load the contacts from the addressbook.
+ * @return true if successful, false if not */
+ bool _loadAddressBook();
+ /* Save the contacts back to the addressbook.
+ * @return true if successful, false if not */
+ bool _saveAddressBook();
+ void _getAppInfo();
+ void _setAppInfo();
+
+ void _cleanupAddressBookPointer();
+
+
+
+/*********************************************************************
+ G E N E R A L S Y N C F U N C T I O N
+ These functions modify the Handheld and the addressbook
+ *********************************************************************/
+ bool syncAddressee(Addressee &pcAddr, PilotAddress*backupAddr,
+ PilotAddress*palmAddr);
+ bool _copyToHH(Addressee &pcAddr, PilotAddress*backupAddr,
+ PilotAddress*palmAddr);
+ bool _copyToPC(Addressee &pcAddr, PilotAddress*backupAddr,
+ PilotAddress*palmAddr);
+ bool _writeBackup(PilotAddress *backup);
+ bool _deleteAddressee(Addressee &pcAddr, PilotAddress*backupAddr,
+ PilotAddress*palmAddr);
+
+
+/*********************************************************************
+ l o w - l e v e l f u n c t i o n s f o r
+ adding / removing palm/pc records
+ *********************************************************************/
+ bool _savePalmAddr(PilotAddress *palmAddr, Addressee &pcAddr);
+ bool _savePCAddr(Addressee &pcAddr, PilotAddress*backupAddr,
+ PilotAddress*palmAddr);
+
+
+/*********************************************************************
+ C O P Y R E C O R D S
+ *********************************************************************/
+ inline bool _equal(const QString & str1, const QString & str2) const
+ {
+ return (str1.isEmpty() && str2.isEmpty()) || (str1 == str2);
+ } ;
+ typedef enum eqFlagsType
+ {
+ eqFlagsName=0x1,
+ eqFlagsAdress=0x2,
+ eqFlagsPhones=0x4,
+ eqFlagsNote=0x8,
+ eqFlagsCategory=0x10,
+ eqFlagsFlags=0x20,
+ eqFlagsCustom=0x40,
+ eqFlagsAll=0xFFFF,
+ eqFlagsAlmostAll=eqFlagsName|eqFlagsAdress|eqFlagsPhones|eqFlagsNote|eqFlagsCustom
+ };
+ bool _equal(const PilotAddress *piAddress, const Addressee &abEntry,
+ enum eqFlagsType flags=eqFlagsAll) const;
+
+/*********************************************************************
+ C O N F L I C T R E S O L U T I O N a n d M E R G I N G
+ *********************************************************************/
+ /** smartly merge the given field for the given entry. use the
+ * backup record to determine which record has been modified
+ * @pc, @backup, @palm ... entries of the according databases
+ * @returns string of the merged entries.
+ */
+ QString _smartMergeString(const QString &pc, const QString & backup,
+ const QString & palm, ConflictResolution confRes);
+ bool _buildResolutionTable(ResolutionTable*tab, const Addressee &pcAddr,
+ PilotAddress *backupAddr, PilotAddress *palmAddr);
+ bool _applyResolutionTable(ResolutionTable*tab, Addressee &pcAddr,
+ PilotAddress *backupAddr, PilotAddress *palmAddr);
+ bool _smartMergeTable(ResolutionTable*tab);
+ /** Merge the palm and the pc entries with the additional
+ * information of the backup record. Calls _smartMerge
+ * which does the actual syncing of the data structures.
+ * According to the return value of _smartMerge, this function
+ * writes the data back to the palm/pc.
+ * return value: no meaning yet
+ */
+ bool _smartMergeAddressee(Addressee &pcAddr, PilotAddress *backupAddr,
+ PilotAddress *palmAddr);
+ Addressee _findMatch(const PilotAddress & pilotAddress) const;
+
+
+/********************************************************/
+/* D A T A M E M B E R S , S E T T I N G S */
+/********************************************************/
+
+ AddressBook* aBook;
+
+ PilotAddressInfo *fAddressAppInfo;
+
+ KABCSync::Settings fSyncSettings;
+
+ int pilotindex;
+ bool abChanged;
+ /** addresseeMap maps record ids to IDs of Addressees. This is used to speed up searching the local addressbook */
+ QMap < recordid_t, QString> addresseeMap;
+ RecordIDList syncedIds, allIds;
+ QString fABookFile;
+ AddressBook::Iterator abiter;
+ /** For a local file resource, we need to obtain a saveTicket
+ * when opening the abook, just in case we want to modify it
+ * at all.
+ */
+ Ticket *fTicket;
+ bool fCreatedBook;
+
+ /** if we add a resource from the addressbook, track it to remove it
+ * later...
+ */
+ KABC::Resource *fBookResource;
+
+
+} ;
+
+#endif
diff --git a/kpilot/conduits/abbrowserconduit/abbrowser-factory.cc b/kpilot/conduits/abbrowserconduit/abbrowser-factory.cc
new file mode 100644
index 000000000..9a8450840
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/abbrowser-factory.cc
@@ -0,0 +1,45 @@
+/* KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+**
+** This file defines the factory for the abbrowser-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include "pluginfactory.h"
+
+#include "abbrowser-conduit.h"
+#include "abbrowser-setup.h"
+
+extern "C"
+{
+
+void *init_conduit_address()
+{
+ return new ConduitFactory<AbbrowserWidgetSetup,AbbrowserConduit>(0,"abbrowserconduit");
+}
+
+}
diff --git a/kpilot/conduits/abbrowserconduit/abbrowser-factory.h b/kpilot/conduits/abbrowserconduit/abbrowser-factory.h
new file mode 100644
index 000000000..bbf573c7f
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/abbrowser-factory.h
@@ -0,0 +1,40 @@
+#ifndef _ABBROWSER_FACTORY_H
+#define _ABBROWSER_FACTORY_H
+/* abbrowser-factory.h KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+**
+** This file defines the factory for the abbrowser-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+extern "C"
+{
+
+void *init_conduit_address();
+
+}
+
+#endif
+
diff --git a/kpilot/conduits/abbrowserconduit/abbrowser-setup.cc b/kpilot/conduits/abbrowserconduit/abbrowser-setup.cc
new file mode 100644
index 000000000..4a2aa4215
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/abbrowser-setup.cc
@@ -0,0 +1,195 @@
+/* KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+**
+** This file defines the setup dialog for the abbrowser-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qbuttongroup.h>
+
+#include <kurlrequester.h>
+#include <kaboutdata.h>
+
+#include "kaddressbookConduit.h"
+#include "abbrowser-setup.h"
+#include "abbrowserSettings.h"
+
+
+
+static KAboutData *createAbout()
+{
+ KAboutData *fAbout = new KAboutData("abbrowserconduit",
+ I18N_NOOP("Abbrowser Conduit for KPilot"),
+ KPILOT_VERSION,
+ I18N_NOOP("Configures the Abbrowser Conduit for KPilot"),
+ KAboutData::License_GPL,
+ "(C) 2001, Dan Pilone\n(C) 2002-2003, Reinhold Kainhofer");
+ fAbout->addAuthor("Greg Stern",
+ I18N_NOOP("Primary Author"));
+ fAbout->addAuthor("Adriaan de Groot",
+ I18N_NOOP("Maintainer"),
+ "http://www.cs.kun.nl/~adridg/kpilot");
+ fAbout->addAuthor("Reinhold Kainhofer", I18N_NOOP("Maintainer"),
+ "[email protected]", "http://reinhold.kainhofer.com");
+ fAbout->addCredit("David Bishop", I18N_NOOP("UI"));
+ return fAbout;
+}
+
+AbbrowserWidgetSetup::AbbrowserWidgetSetup(QWidget *w, const char *n) :
+ ConduitConfigBase(w,n),
+ fConfigWidget(new AbbrowserWidget(w))
+{
+ FUNCTIONSETUP;
+
+ fConduitName=i18n("Addressbook");
+ fAbout = createAbout();
+ ConduitConfigBase::addAboutPage(fConfigWidget->tabWidget,fAbout);
+ fWidget=fConfigWidget;
+ fConfigWidget->fAbookFile->setMode(KFile::File);
+#define CM(a,b) connect(fConfigWidget->a,b,this,SLOT(modified()));
+ CM(fSyncDestination,SIGNAL(clicked(int)));
+ CM(fAbookFile,SIGNAL(textChanged(const QString &)));
+ CM(fArchive,SIGNAL(toggled(bool)));
+ CM(fConflictResolution,SIGNAL(activated(int)));
+ CM(fOtherPhone,SIGNAL(activated(int)));
+ CM(fAddress,SIGNAL(activated(int)));
+ CM(fFax,SIGNAL(activated(int)));
+ CM(fCustom0,SIGNAL(activated(int)));
+ CM(fCustom1,SIGNAL(activated(int)));
+ CM(fCustom2,SIGNAL(activated(int)));
+ CM(fCustom3,SIGNAL(activated(int)));
+ CM(fCustomDate, SIGNAL(activated(int)));
+ CM(fCustomDate, SIGNAL(textChanged(const QString&)));
+#undef CM
+}
+
+AbbrowserWidgetSetup::~AbbrowserWidgetSetup()
+{
+ FUNCTIONSETUP;
+}
+
+/* virtual */ void AbbrowserWidgetSetup::commit()
+{
+ FUNCTIONSETUP;
+
+ QButtonGroup*grp=fConfigWidget->fSyncDestination;
+ AbbrowserSettings::setAddressbookType(grp->id(grp->selected()));
+ AbbrowserSettings::setFileName(fConfigWidget->fAbookFile->url());
+ AbbrowserSettings::setArchiveDeleted(fConfigWidget->fArchive->isChecked());
+
+ // Conflicts page
+ AbbrowserSettings::setConflictResolution(
+ fConfigWidget->fConflictResolution->currentItem()+SyncAction::eCROffset);
+
+ // Fields page
+ AbbrowserSettings::setPilotOther(fConfigWidget->fOtherPhone->currentItem());
+ AbbrowserSettings::setPilotStreet(fConfigWidget->fAddress->currentItem());
+ AbbrowserSettings::setPilotFax(fConfigWidget->fFax->currentItem());
+
+ // Custom fields page
+ AbbrowserSettings::setCustom0(fConfigWidget->fCustom0->currentItem());
+ AbbrowserSettings::setCustom1(fConfigWidget->fCustom1->currentItem());
+ AbbrowserSettings::setCustom2(fConfigWidget->fCustom2->currentItem());
+ AbbrowserSettings::setCustom3(fConfigWidget->fCustom3->currentItem());
+#ifdef DEBUG
+ DEBUGKPILOT <<fname<<
+ "Custom0: "<<fConfigWidget->fCustom0->currentItem()<<" "<<
+ "Custom1: "<<fConfigWidget->fCustom1->currentItem()<<" "<<
+ "Custom2: "<<fConfigWidget->fCustom2->currentItem()<<" "<<
+ "Custom3: "<<fConfigWidget->fCustom3->currentItem()<<" "
+ << " eCustom[0]=" << AbbrowserSettings::custom0()<<" "
+ << " eCustom[1]=" << AbbrowserSettings::custom1()<<" "
+ << " eCustom[2]=" << AbbrowserSettings::custom2()<<" "
+ << " eCustom[3]=" << AbbrowserSettings::custom3()<<" "<<
+ endl;
+#endif
+ int fmtindex=fConfigWidget->fCustomDate->currentItem();
+ AbbrowserSettings::setCustomDateFormat(
+ (fmtindex==0)?(QString::null):fConfigWidget->fCustomDate->currentText() );
+
+ AbbrowserSettings::self()->writeConfig();
+ unmodified();
+}
+
+/* virtual */ void AbbrowserWidgetSetup::load()
+{
+ FUNCTIONSETUP;
+ AbbrowserSettings::self()->readConfig();
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Settings "
+ << " fPilotStreetHome=" << AbbrowserSettings::pilotStreet()
+ << " fPilotFaxHome=" << AbbrowserSettings::pilotFax()
+ << " fArchive=" << AbbrowserSettings::archiveDeleted()
+ << " eCustom[0]=" << AbbrowserSettings::custom0()
+ << " eCustom[1]=" << AbbrowserSettings::custom1()
+ << " eCustom[2]=" << AbbrowserSettings::custom2()
+ << " eCustom[3]=" << AbbrowserSettings::custom3()
+ << endl;
+#endif
+
+ // General page
+ fConfigWidget->fSyncDestination->setButton(AbbrowserSettings::addressbookType());
+ fConfigWidget->fAbookFile->setURL(AbbrowserSettings::fileName());
+ fConfigWidget->fArchive->setChecked(AbbrowserSettings::archiveDeleted());
+
+ // Conflicts page
+ fConfigWidget->fConflictResolution->setCurrentItem(
+ AbbrowserSettings::conflictResolution() - SyncAction::eCROffset );
+
+ // Fields page
+ fConfigWidget->fOtherPhone->setCurrentItem(AbbrowserSettings::pilotOther());
+ fConfigWidget->fAddress->setCurrentItem(AbbrowserSettings::pilotStreet());
+ fConfigWidget->fFax->setCurrentItem(AbbrowserSettings::pilotFax());
+
+ // Custom fields page
+ fConfigWidget->fCustom0->setCurrentItem(AbbrowserSettings::custom0());
+ fConfigWidget->fCustom1->setCurrentItem(AbbrowserSettings::custom1());
+ fConfigWidget->fCustom2->setCurrentItem(AbbrowserSettings::custom2());
+ fConfigWidget->fCustom3->setCurrentItem(AbbrowserSettings::custom3());
+ QString datefmt=AbbrowserSettings::customDateFormat();
+ if (datefmt.isEmpty())
+ {
+ fConfigWidget->fCustomDate->setCurrentItem(0);
+ }
+ else
+ {
+ fConfigWidget->fCustomDate->setCurrentText(datefmt);
+ }
+
+ unmodified();
+}
+
+/* static */ ConduitConfigBase *AbbrowserWidgetSetup::create(QWidget *w, const char *n)
+{
+ return new AbbrowserWidgetSetup(w,n);
+}
+
diff --git a/kpilot/conduits/abbrowserconduit/abbrowser-setup.h b/kpilot/conduits/abbrowserconduit/abbrowser-setup.h
new file mode 100644
index 000000000..71981dc09
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/abbrowser-setup.h
@@ -0,0 +1,52 @@
+#ifndef _ABBROWSER_ABBROWSER_SETUP_H
+#define _ABBROWSER_ABBROWSER_SETUP_H
+/* knotes-setup.h KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+**
+** This file defines the widget and behavior for the config dialog
+** of the KNotes conduit.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "plugin.h"
+
+class AbbrowserWidget;
+class KAboutData;
+
+class AbbrowserWidgetSetup : public ConduitConfigBase
+{
+public:
+ AbbrowserWidgetSetup(QWidget *,const char *);
+ virtual ~AbbrowserWidgetSetup();
+ virtual void load();
+ virtual void commit();
+ static ConduitConfigBase *create(QWidget *,const char *);
+private:
+ AbbrowserWidget *fConfigWidget;
+ KAboutData *fAbout;
+} ;
+
+#endif
+
diff --git a/kpilot/conduits/abbrowserconduit/abbrowserSettings.kcfgc b/kpilot/conduits/abbrowserconduit/abbrowserSettings.kcfgc
new file mode 100644
index 000000000..f6ea2097f
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/abbrowserSettings.kcfgc
@@ -0,0 +1,7 @@
+File=abbrowserconduit.kcfg
+ClassName=AbbrowserSettings
+Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/conduits/abbrowserconduit/abbrowser_conduit.desktop b/kpilot/conduits/abbrowserconduit/abbrowser_conduit.desktop
new file mode 100644
index 000000000..f25f458f2
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/abbrowser_conduit.desktop
@@ -0,0 +1,116 @@
+[Desktop Entry]
+Type=Service
+Comment=This conduit syncs the handheld addressbook with KDE's addressbook.
+Comment[af]=Hierdie pad sinkroniseer die draagbare toestel adresboek met KDE se adresboek.
+Comment[bg]=Синхронизация на адресника на KDE с мобилни устройства
+Comment[bs]=Ovaj conduit sinhronizuje adresar ručnog računara sa KDEovim adresarom.
+Comment[ca]=Aquest conducte sincronitza la llibreta d'adreces de la vostra agenda electrònica amb la llibreta d'adreces de KDE.
+Comment[cs]=Toto propojení synchronizuje vašeho Pilota Knihou adres
+Comment[cy]=Mae'r cwndid yma yn cydamseru llyfr cyfeiriadau'r llawiadur efo llyfr cyfeiriadau KDE.
+Comment[da]=Denne kanal synkroniserer din håndholdte med KDE's adressebog.
+Comment[de]=Abgleich der Adressbücher von Taschencomputer und KDE.
+Comment[el]=Αυτός ο σύνδεσμος συγχρονίζει το βιβλίο διευθύνσεων του υπολογιστή παλάμης με το βιβλίο διευθύνσεων του KDE.
+Comment[eo]=Tiu kanalo sinkronigas vian poŝkomputil-adreslibron kun la KDE-aadreslibro.
+Comment[es]=Este conducto sincroniza la libreta de direcciones de su agenda electrónica con la de KDE
+Comment[et]=See kanal sünkroniseerib pihuarvuti ja KDE aadressiraamatu.
+Comment[eu]=Kanal honek agenda-elektronikoaren helbide-liburua KDE-ren helbide-liburuarekin sinkronizatzen du.
+Comment[fa]=این لوله، کتاب نشانی دستی را با کتاب نشانی KDE همگام می‌سازد.
+Comment[fi]=Tämä yhdyskäytävä synkronoi taskutietokoneen KDE:n osoitekirjan kanssa
+Comment[fr]=Ce canal synchronise le carnet d'adresses du périphérique avec celui de KDE.
+Comment[fy]=Dit conduit syngronisearret jo handheld mei KDE's adresboek.
+Comment[gl]=Este conducto sincroniza o caderno de enderezos do seu aparello portátil co caderno de enderezos de KDE.
+Comment[hi]=यह कन्ड्यूइट हैंडहेल्ड पता-पुस्तिका को केडीई के पता-पुस्तिका से सिंक करती है.
+Comment[hu]=Ezzel a csatolóval egy kéziszámítógép és a KDE címjegyzéke között lehet szinkronizálást végezni.
+Comment[is]=Þessi rás samstillir póstfangaskrár KDE og lófatölvunnar
+Comment[it]=Questo condotto sincronizza il tuo palmare con la rubrica indirizzi di KDE
+Comment[ja]=このコンジットはハンドヘルドのアドレス帳をKDEのアドレス帳と同期させます。
+Comment[ka]=ეს არხი KDE-ს წიგნაკის სინქრონიზაციას ახდენს პორტატიულ წიგნაკთან.
+Comment[kk]=Қалта құрылғыдағы адрестік кітапшамен KDE-нің адрестік кітапшаларды қадамдастыру арнасы.
+Comment[km]=បំពង់​នេះ​អាច​ឲ្យ​សៀវភៅ​អាសយដ្ឋាន​របស់​ឧបករណ៍​យួរដៃ ធ្វើ​សមកាលកម្ម​ជាមួយ​នឹង​សៀវភៅ​អាសយដ្ឋាន​របស់ KDE
+Comment[lt]=Šis kanalas sinchronizuoja nešiojamą adresų knygelę su KDE adresų knygele.
+Comment[mk]=Овој канал ги синхронизира адресарите од рачниот уред и од KDE.
+Comment[ms]=Saluran ini mensegerakkan buku alamat komputer telapak dengan buku alamat KDE.
+Comment[nb]=Denne kanalen synkroniserer Pilotens adressebok med KDEs adressebok.
+Comment[nds]=Synkroniseert de Adressböker vun Handreekners un KDE.
+Comment[ne]=यो कन्ड्युटले केडीई को ठेगाना पुस्तकमा ह्यान्डल गरिएका ठेगाना पुस्तिका सिन्क गर्दछ ।
+Comment[nl]=Dit conduit synchroniseert uw handheld met KDE's adresboek.
+Comment[nn]=Denne koplinga synkroniserer den handheldte adresseboka med med KDE-adresseboka.
+Comment[pl]=Ten łącznik synchronizuje książkę adresową palmtopa z książką adresową KDE.
+Comment[pt]=Esta conduta sincroniza o livro de endereços ou agenda do seu dispositivo com a agenda do KDE.
+Comment[pt_BR]=Este conduíte sincroniza o livro de endereços do handheld com o livro de endereços do KDE.
+Comment[ru]=Канал синхронизации адресных книг КПК и KDE.
+Comment[sk]=Táto spojka synchronizuje adresár vášho prenosného zariadenia s adresárom KDE.
+Comment[sl]=Ta veznik usklajuje adresar v ročnem računalniku z adresarjem v KDE.
+Comment[sr]=Овај провод синхронизује адресар ручног рачунара са KDE-овим адресаром
+Comment[sr@Latn]=Ovaj provod sinhronizuje adresar ručnog računara sa KDE-ovim adresarom
+Comment[sv]=Den här kanalen synkroniserar handdatorns adressbok med KDE:s adressbok.
+Comment[ta]=இந்த குழாய் கையில் உள்ள முகவரிப்புத்தகத்தை கேடிஇயின் முகவரிப்புத்தகத்தோடு ஒத்திசைக்கிறது
+Comment[tg]=Канали синхронизатсияи китоби адресии Pilot ва KDE.
+Comment[tr]=Bu bileşen el bilgisayarı adres defteri ile KDE'ninkini birleştirir.
+Comment[uk]=Цей акведук синхронізує адресну книгу кишенькового пристрою з адресною книгою KDE.
+Comment[zh_CN]=此管道会将您的手持设备与 KDE 的地址簿同步。
+Comment[zh_TW]=此軟體讓您把 KDE 通訊錄與手邊通訊錄同步。
+Name=Addressbook
+Name[af]=Adresboek
+Name[ar]=دفتر العناوين
+Name[az]=Ünvan Dəftəri
+Name[be]=Адрасная кніга
+Name[bg]=Адресник
+Name[br]=Karned chomlec'hioù
+Name[bs]=Adresar
+Name[ca]=Llibreta d'adreces
+Name[cs]=Kniha adres
+Name[cy]=Llyfr Cyfeiriadau
+Name[da]=Adressebog
+Name[de]=Adressbuch
+Name[el]=Βιβλίο διευθύνσεων
+Name[eo]=Adresaro
+Name[es]=Libreta de direcciones
+Name[et]=Aadressiraamat
+Name[eu]=Helbide-liburua
+Name[fa]=کتاب نشانی
+Name[fi]=Osoitekirja
+Name[fr]=Carnet d'adresses
+Name[fy]=Adresboek
+Name[ga]=Leabhar Seoltaí
+Name[gl]=Libro de enderezos
+Name[hi]=पता-पुस्तिका
+Name[hr]=Adresar
+Name[hu]=Címjegyzék
+Name[id]=Buku alamat
+Name[is]=Póstfangaskrá
+Name[it]=Rubrica degli indirizzi
+Name[ja]=アドレス帳
+Name[ka]=წიგნაკი
+Name[kk]=Адрестік кітапшасы
+Name[km]=សៀវភៅ​អាសយដ្ឋាន
+Name[lt]=Adresų knygelė
+Name[mk]=Адресар
+Name[ms]=Buku Alamat
+Name[nb]=Addressebok
+Name[nds]=Adressbook
+Name[ne]=ठेगाना पुस्तिका
+Name[nl]=Adresboek
+Name[nn]=Adressebok
+Name[pl]=Książka adresowa
+Name[pt]=Livro de Endereços
+Name[pt_BR]=Livro de Endereços
+Name[ro]=Carte de adrese
+Name[ru]=Адресная книга
+Name[se]=Čujuhusgirji
+Name[sk]=Adresár
+Name[sl]=Adresar
+Name[sr]=Адресар
+Name[sr@Latn]=Adresar
+Name[sv]=Adressbok
+Name[ta]=முகவரிப்புத்தகம்
+Name[tg]=Китоби адресӣ
+Name[tr]=Adresdefteri
+Name[uk]=Адресна книга
+Name[uz]=Manzillar daftari
+Name[uz@cyrillic]=Манзиллар дафтари
+Name[zh_CN]=地址簿
+Name[zh_TW]=通訊錄
+Implemented=file
+ServiceTypes=KPilotConduit
+X-KDE-Library=conduit_address
diff --git a/kpilot/conduits/abbrowserconduit/abbrowserconduit.kcfg b/kpilot/conduits/abbrowserconduit/abbrowserconduit.kcfg
new file mode 100644
index 000000000..aed770641
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/abbrowserconduit.kcfg
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kpilot_addressconduitrc"/>
+ <group name="General">
+ <entry name="AddressbookType" key="Addressbook type" type="Enum">
+ <choices>
+ <choice name="eAbookResource"/>
+ <choice name="eAbookFile"/>
+ </choices>
+ <default>eAbookFile</default>
+ </entry>
+ <entry name="FileName" type="Path">
+ <default>$HOME/.kde/share/apps/kabc/std.vcf</default>
+ </entry>
+ <entry name="ArchiveDeleted" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry name="ConflictResolution" key="ConflictResolve" type="Int">
+ <default>-1</default>
+ </entry>
+ <entry name="PilotOther" type="Enum">
+ <choices>
+ <choice name="eOtherPhone"/>
+ <choice name="eAssistant"/>
+ <choice name="eBusinessFax"/>
+ <choice name="eCarPhone"/>
+ <choice name="eEmail2"/>
+ <choice name="eHomeFax"/>
+ <choice name="eTelex"/>
+ <choice name="eTTYTTDPhone"/>
+ </choices>
+ <default>eOtherPhone</default>
+ </entry>
+ <entry name="PilotStreet" type="Enum">
+ <choices>
+ <choice name="ePilotStreetHome"/>
+ <choice name="ePilotStreetWork"/>
+ </choices>
+ <default>ePilotStreetHome</default>
+ </entry>
+ <entry name="PilotFax" type="Enum">
+ <choices>
+ <choice name="ePilotFaxHome"/>
+ <choice name="ePilotFaxWork"/>
+ </choices>
+ <default>ePilotFaxHome</default>
+ </entry>
+ <entry name="Custom0" key="Custom 0" type="Enum">
+ <choices label="eCustomEnum">
+ <choice name="eCustomField"/>
+ <choice name="eCustomBirthdate"/>
+ <choice name="eCustomURL"/>
+ <choice name="eCustomIM"/>
+ </choices>
+ <default>eCustomField</default>
+ </entry>
+ <entry name="Custom1" key="Custom 1" type="Enum">
+ <choices label="eCustomEnum">
+ </choices>
+ <default>eCustomField</default>
+ </entry>
+ <entry name="Custom2" key="Custom 2" type="Enum">
+ <choices label="eCustomEnum">
+ </choices>
+ <default>eCustomField</default>
+ </entry>
+ <entry name="Custom3" key="Custom 3" type="Enum">
+ <choices label="eCustomEnum">
+ </choices>
+ <default>eCustomField</default>
+ </entry>
+ <entry name="CustomDateFormat" type="String">
+ <default></default>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kpilot/conduits/abbrowserconduit/kabcRecord.cc b/kpilot/conduits/abbrowserconduit/kabcRecord.cc
new file mode 100644
index 000000000..b5d68121a
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/kabcRecord.cc
@@ -0,0 +1,710 @@
+/* KPilot
+**
+** Copyright (C) 2000,2001 by Dan Pilone
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+** Copyright (C) 2007 by Adriaan de Groot <[email protected]>
+**
+** The abbrowser conduit copies addresses from the Pilot's address book to
+** the KDE addressbook maintained via the kabc library. This file
+** deals with the actual copying of HH addresses to KABC addresses
+** and back again.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected].
+*/
+
+#include "options.h"
+
+#include <qregexp.h>
+
+#include <kglobal.h>
+#include <kabc/addressee.h>
+
+#include "kabcRecord.h"
+
+/**
+ * Okay, this is so that we can map the Pilot phone types to Phone Number
+ * types. Email addresses are NOT included in this map, and are handled
+ * separately (not in PhoneNumber at all). The Pilot has 8 different kinds
+ * of phone numbers (which may be *labeled* however you like). These
+ * need to be mapped to the things that KABC::PhoneNumber handles.
+ *
+ * From KABC::PhoneNumber
+ * enum Types { Home = 1, Work = 2, Msg = 4, Pref = 8, Voice = 16, Fax = 32,
+ * Cell = 64, Video = 128, Bbs = 256, Modem = 512, Car = 1024,
+ * Isdn = 2048, Pcs = 4096, Pager = 8192 };
+ *
+ *
+ * From PilotAddress:
+ * enum EPhoneType {
+ * eWork=0, eHome, eFax, eOther, eEmail, eMain,
+ * ePager, eMobile
+ * };
+ *
+ * This array must have as many elements as PilotAddress::PhoneType
+ * and its elements must be KABC::PhoneNumber::Types.
+ */
+
+static KABC::PhoneNumber::Types pilotToPhoneMap[8] = {
+ KABC::PhoneNumber::Work, // eWork
+ KABC::PhoneNumber::Home, // eHome,
+ KABC::PhoneNumber::Fax, // eFax,
+ (KABC::PhoneNumber::Types)0, // eOther -> wasn't mapped properly,
+ (KABC::PhoneNumber::Types)0, // eEmail -> shouldn't occur,
+ KABC::PhoneNumber::Home, // eMain
+ KABC::PhoneNumber::Pager, // ePager,
+ KABC::PhoneNumber::Cell // eMobile
+} ;
+
+KABC::PhoneNumber::List KABCSync::getPhoneNumbers(const PilotAddress &a)
+{
+ FUNCTIONSETUP;
+
+ KABC::PhoneNumber::List list;
+ QString test;
+
+ PhoneSlot shownPhone = a.getShownPhone();
+
+ DEBUGKPILOT << fname << ": preferred pilot index is: ["
+ << shownPhone << "], preferred phone number is: ["
+ << a.getField(shownPhone) << "]" << endl;
+
+ for (PhoneSlot i = PhoneSlot::begin(); i.isValid(); ++i)
+ {
+ // skip email entries
+ if ( a.getPhoneType(i) == PilotAddressInfo::eEmail )
+ {
+ continue;
+ }
+
+ test = a.getField(i);
+ // only look at this if the field is populated
+ if (test.isEmpty())
+ {
+ continue;
+ }
+
+ int phoneType = pilotToPhoneMap[a.getPhoneType(i)];
+
+ // only populate a PhoneNumber if we have a corresponding type
+ if (phoneType >=0)
+ {
+ // if this is the preferred phone number, set it as such
+ if (shownPhone == i)
+ {
+ phoneType |= KABC::PhoneNumber::Pref;
+ DEBUGKPILOT << fname << ": found preferred pilot index: ["
+ << i << "], text: [" << test << "]" << endl;
+ }
+ KABC::PhoneNumber ph(test, phoneType);
+ list.append(ph);
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": whoopsie. pilot phone number: ["
+ << test << "], index: [" << i << "], type: ["
+ << phoneType << "], has no corresponding PhoneNumber type." << endl;
+ }
+ }
+
+ DEBUGKPILOT << fname << ": returning: ["
+ << list.count() << "] phone numbers." << endl;
+
+ return list;
+}
+
+void KABCSync::setPhoneNumbers(const PilotAddressInfo &info,
+ PilotAddress &a,
+ const KABC::PhoneNumber::List &list)
+{
+ FUNCTIONSETUP;
+ QString test;
+
+ // clear all phone numbers (not e-mails) first
+ for ( PhoneSlot i = PhoneSlot::begin(); i.isValid() ; ++i )
+ {
+ PilotAddressInfo::EPhoneType ind = a.getPhoneType( i );
+ if (ind != PilotAddressInfo::eEmail)
+ {
+ a.setField(i, QString());
+ }
+ }
+
+ // now iterate through the list and for each PhoneNumber in the list,
+ // iterate through our phone types using our map and set the first one
+ // we find as the type of address for the Pilot
+ for(KABC::PhoneNumber::List::ConstIterator listIter = list.begin();
+ listIter != list.end(); ++listIter)
+ {
+ KABC::PhoneNumber phone = *listIter;
+
+ PilotAddressInfo::EPhoneType phoneType = PilotAddressInfo::eHome;
+
+ for ( int pilotPhoneType = PilotAddressInfo::eWork;
+ pilotPhoneType <= PilotAddressInfo::eMobile;
+ ++pilotPhoneType)
+ {
+ int phoneKey = pilotToPhoneMap[pilotPhoneType];
+ if ( phone.type() & phoneKey)
+ {
+ DEBUGKPILOT << fname << ": found pilot type: ["
+ << pilotPhoneType << "] ("
+ << info.phoneLabel( (PilotAddressInfo::EPhoneType)pilotPhoneType)
+ << ") for PhoneNumber: ["
+ << phone.number() << "]" << endl;
+
+ phoneType = (PilotAddressInfo::EPhoneType) pilotPhoneType;
+ break;
+ }
+ }
+ PhoneSlot fieldSlot =
+ a.setPhoneField(phoneType, phone.number(), PilotAddress::NoFlags);
+
+ // if this is the preferred phone number, then set it as such
+ if (fieldSlot.isValid() && (phone.type() & KABC::PhoneNumber::Pref))
+ {
+ DEBUGKPILOT << fname << ": found preferred PhoneNumber. "
+ << "setting showPhone to index: ["
+ << fieldSlot << "], PhoneNumber: ["
+ << phone.number() << "]" << endl;
+ a.setShownPhone( fieldSlot );
+ }
+
+ if (!fieldSlot.isValid())
+ {
+ DEBUGKPILOT << fname << ": Phone listing overflowed." << endl;
+ }
+ }
+
+ DEBUGKPILOT << fname << ": Pilot's showPhone now: ["
+ << a.getShownPhone() << "]." << endl;
+
+ // after setting the numbers, make sure that something sensible is set as the
+ // shownPhone on the Pilot if nothing is yet...
+ QString pref = a.getField(a.getShownPhone());
+ if (!a.getShownPhone().isValid() || pref.isEmpty())
+ {
+ DEBUGKPILOT << fname << ": Pilot's showPhone: ["
+ << a.getShownPhone()
+ << "] not properly set to a default."
+ << endl;
+
+ for (PhoneSlot i = PhoneSlot::begin(); i.isValid(); ++i)
+ {
+ pref = a.getField(i);
+ if (!pref.isEmpty())
+ {
+ a.setShownPhone( i );
+ DEBUGKPILOT << fname << ": Pilot's showPhone now: ["
+ << a.getShownPhone()
+ << "], and that's final." << endl;
+ break;
+ }
+ }
+ }
+}
+
+unsigned int KABCSync::bestMatchedCategory(const QStringList &pccategories,
+ const PilotAddressInfo &info,
+ unsigned int hhcategory)
+{
+ FUNCTIONSETUP;
+ // No categories in list, must be unfiled
+ if (pccategories.size()<1)
+ {
+ return Pilot::Unfiled;
+ }
+
+ // See if the suggested hhcategory is in the list, and if
+ // so that is the best match.
+ if (Pilot::validCategory(hhcategory) &&
+ pccategories.contains(info.categoryName(hhcategory)))
+ {
+ return hhcategory;
+ }
+
+ // Look for the first category from the list which is available on
+ // the handheld as well.
+ for(QStringList::ConstIterator it = pccategories.begin(); it != pccategories.end(); ++it)
+ {
+ // Do not map unknown to unfiled when looking for category
+ int c = info.findCategory( *it, false );
+ if ( c >= 0)
+ {
+ Q_ASSERT(Pilot::validCategory(c));
+ return c;
+ }
+ }
+
+ // didn't find anything. return null
+ return Pilot::Unfiled;
+}
+
+void KABCSync::setCategory(KABC::Addressee & abEntry, const QString &cat)
+{
+ if ( (!cat.isEmpty()))
+ {
+ abEntry.insertCategory(cat);
+ }
+}
+
+
+QString KABCSync::getFieldForHHCustom(
+ const unsigned int index,
+ const KABC::Addressee &abEntry,
+ const KABCSync::Settings &settings)
+{
+ FUNCTIONSETUPL(4);
+
+ QString retval;
+
+ if (index>3)
+ {
+ WARNINGKPILOT << "Bad index number " << index << endl;
+ retval = QString();
+ }
+ if (settings.customMapping().count() != 4)
+ {
+ WARNINGKPILOT << "Mapping does not have 4 elements." << index << endl;
+ retval = QString();
+ }
+
+ switch (settings.custom(index))
+ {
+ case eCustomBirthdate:
+ if (settings.dateFormat().isEmpty())
+ {
+ retval = KGlobal::locale()->formatDate(abEntry.birthday().date());
+ }
+ else
+ {
+ QString tmpfmt(KGlobal::locale()->dateFormat());
+ KGlobal::locale()->setDateFormat(settings.dateFormat());
+ QString ret(KGlobal::locale()->formatDate(abEntry.birthday().date()));
+ KGlobal::locale()->setDateFormat(tmpfmt);
+ retval = ret;
+ }
+ break;
+ case eCustomURL:
+ retval = abEntry.url().url();
+ break;
+ case eCustomIM:
+ retval = abEntry.custom(CSL1("KADDRESSBOOK"), CSL1("X-IMAddress"));
+ break;
+ case eCustomField:
+ default:
+ retval = abEntry.custom(appString, CSL1("CUSTOM")+QString::number(index));
+ break;
+ }
+
+ return retval;
+}
+
+void KABCSync::setFieldFromHHCustom(
+ const unsigned int index,
+ KABC::Addressee &abEntry,
+ const QString &value,
+ const KABCSync::Settings &settings)
+{
+ FUNCTIONSETUPL(4);
+
+ if (index>3)
+ {
+ WARNINGKPILOT << "Bad index number " << index << endl;
+ return;
+ }
+ if (settings.customMapping().count() != 4)
+ {
+ WARNINGKPILOT << "Mapping does not have 4 elements." << index << endl;
+ return;
+ }
+
+ switch (settings.custom(index))
+ {
+ case eCustomBirthdate:
+ {
+ QDate bdate;
+ bool ok=false;
+ if (settings.dateFormat().isEmpty())
+ {
+ // empty format means use locale setting
+ bdate=KGlobal::locale()->readDate(value, &ok);
+ }
+ else
+ {
+ // use given format
+ bdate=KGlobal::locale()->readDate(value, settings.dateFormat(), &ok);
+ }
+
+ if (!ok)
+ {
+ QString format = KGlobal::locale()->dateFormatShort();
+ QRegExp re(CSL1("%[yY][^%]*"));
+ format.remove(re); // Remove references to year and following punctuation
+ bdate = KGlobal::locale()->readDate(value, format, &ok);
+ }
+ DEBUGKPILOT << "Birthdate from " << index << "-th custom field: "
+ << bdate.toString() << endl;
+ DEBUGKPILOT << "Is Valid: " << bdate.isValid() << endl;
+ if (bdate.isValid())
+ {
+ abEntry.setBirthday(bdate);
+ }
+ else
+ {
+ abEntry.insertCustom(CSL1("KADDRESSBOOK"), CSL1("X-Birthday"), value);
+ }
+ break;
+ }
+ case eCustomURL:
+ abEntry.setUrl(value);
+ break;
+ case eCustomIM:
+ abEntry.insertCustom(CSL1("KADDRESSBOOK"), CSL1("X-IMAddress"), value);
+ break;
+ case eCustomField:
+ default:
+ abEntry.insertCustom(appString, CSL1("CUSTOM")+QString::number(index), value);
+ break;
+ }
+}
+
+
+/** First search for a preferred address. If we don't have one, search
+ * for home or work as specified in the config dialog. If we don't have
+ * such one, either, search for the other type. If we still have no luck,
+ * return an address with preferred + home/work flag (from config dlg). */
+KABC::Address KABCSync::getAddress(const KABC::Addressee &abEntry, const KABCSync::Settings &s)
+{
+ // preferhome == (AbbrowserSettings::pilotStreet==0)
+
+ // Check for preferred address first
+ KABC::Address ad(abEntry.address(KABC::Address::Pref));
+ if (!ad.isEmpty()) return ad;
+
+ // Look for home or work, whichever is preferred
+ int type = s.preferHome() ? KABC::Address::Home : KABC::Address::Work;
+ ad=abEntry.address(type);
+ if (!ad.isEmpty()) return ad;
+
+ // Switch preference if still none found
+ type = !s.preferHome() ? KABC::Address::Home : KABC::Address::Work;
+ ad=abEntry.address(type);
+ if (!ad.isEmpty()) return ad;
+
+ // Last-ditch attempt; see if there is a preferred home or work address
+ type = s.preferHome() ? KABC::Address::Home : KABC::Address::Work;
+ return abEntry.address(type | KABC::Address::Pref);
+}
+
+
+QString KABCSync::getFieldForHHOtherPhone(const KABC::Addressee & abEntry, const KABCSync::Settings &s)
+{
+ switch(s.fieldForOtherPhone())
+ {
+ case eOtherPhone:
+ return abEntry.phoneNumber(0).number();
+ case eAssistant:
+ return abEntry.custom(CSL1("KADDRESSBOOK"), CSL1("AssistantsName"));
+ case eBusinessFax:
+ return abEntry.phoneNumber(KABC::PhoneNumber::Fax | KABC::PhoneNumber::Work).number();
+ case eCarPhone:
+ return abEntry.phoneNumber(KABC::PhoneNumber::Car).number();
+ case eEmail2:
+ return abEntry.emails().first();
+ case eHomeFax:
+ return abEntry.phoneNumber(KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home).number();
+ case eTelex:
+ return abEntry.phoneNumber(KABC::PhoneNumber::Bbs).number();
+ case eTTYTTDPhone:
+ return abEntry.phoneNumber(KABC::PhoneNumber::Pcs).number();
+ default:
+ return QString::null;
+ }
+}
+
+void KABCSync::setFieldFromHHOtherPhone(KABC::Addressee & abEntry, const QString &nr, const KABCSync::Settings &s)
+{
+ int phoneType = 0;
+ switch (s.fieldForOtherPhone())
+ {
+ // One very special case which doesn't even map to a real phone type in KABC
+ case eAssistant:
+ abEntry.insertCustom(CSL1("KADDRESSBOOK"), CSL1("AssistantsName"), nr);
+ return;
+ // Special case: map phone to email, needs different handling.
+ case eEmail2:
+ abEntry.insertEmail(nr);
+ return;
+ // Remaining cases all map to various phone types
+ case eOtherPhone:
+ phoneType = 0;
+ break;
+ case eBusinessFax:
+ phoneType = KABC::PhoneNumber::Fax | KABC::PhoneNumber::Work;
+ break;
+ case eHomeFax:
+ phoneType = KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home;
+ break;
+ case eCarPhone:
+ phoneType = KABC::PhoneNumber::Car;
+ break;
+ case eTelex:
+ phoneType = KABC::PhoneNumber::Bbs;
+ break;
+ case eTTYTTDPhone:
+ phoneType = KABC::PhoneNumber::Pcs;
+ break;
+ default:
+ WARNINGKPILOT << "Unknown phone mapping " << s.fieldForOtherPhone() << endl;
+ phoneType = 0;
+ }
+ KABC::PhoneNumber phone = abEntry.phoneNumber(phoneType);
+ phone.setNumber(nr);
+ phone.setType(phoneType); // Double-check in case there was no phonenumber of given type
+ abEntry.insertPhoneNumber(phone);
+}
+
+void KABCSync::setAddress(PilotAddress &toPilotAddr,
+ const KABC::Address & abAddress)
+{
+ toPilotAddr.setField(entryAddress, abAddress.street());
+ toPilotAddr.setField(entryCity, abAddress.locality());
+ toPilotAddr.setField(entryState, abAddress.region());
+ toPilotAddr.setField(entryZip, abAddress.postalCode());
+ toPilotAddr.setField(entryCountry, abAddress.country());
+}
+
+
+bool KABCSync::isArchived(const KABC::Addressee &addr)
+{
+ return addr.custom(KABCSync::appString, KABCSync::flagString) == QString::number(SYNCDEL);
+}
+
+void KABCSync::makeArchived(KABC::Addressee &addr)
+{
+ FUNCTIONSETUP;
+ addr.insertCustom(KABCSync::appString, KABCSync::flagString, QString::number(SYNCDEL));
+ addr.removeCustom(KABCSync::appString, KABCSync::idString);
+}
+
+
+
+
+void KABCSync::copy(PilotAddress &toPilotAddr,
+ const KABC::Addressee &fromAbEntry,
+ const PilotAddressInfo &appInfo,
+ const KABCSync::Settings &syncSettings)
+{
+ FUNCTIONSETUP;
+
+ toPilotAddr.setDeleted(false);
+
+ // don't do a reset since this could wipe out non copied info
+ //toPilotAddr.reset();
+ toPilotAddr.setField(entryLastname, fromAbEntry.familyName());
+ toPilotAddr.setField(entryFirstname, fromAbEntry.givenName());
+ toPilotAddr.setField(entryCompany, fromAbEntry.organization());
+ toPilotAddr.setField(entryTitle, fromAbEntry.prefix());
+ toPilotAddr.setField(entryNote, fromAbEntry.note());
+
+ // do email first, to ensure they get stored
+ toPilotAddr.setEmails(fromAbEntry.emails());
+
+ // now in one fell swoop, set all phone numbers from the Addressee. Note,
+ // we don't need to differentiate between Fax numbers here--all Fax numbers
+ // (Home Fax or Work Fax or just plain old Fax) will get synced to the Pilot
+ KABCSync::setPhoneNumbers(appInfo,toPilotAddr,fromAbEntry.phoneNumbers());
+
+ // Other field is an oddball and if the user has more than one field set
+ // as "Other" then only one will be carried over.
+ QString oth = KABCSync::getFieldForHHOtherPhone(fromAbEntry,syncSettings);
+ DEBUGKPILOT << fname << ": putting: ["<<oth<<"] into Palm's other"<<endl;
+ toPilotAddr.setPhoneField(PilotAddressInfo::eOther,
+ oth, PilotAddress::Replace);
+
+ KABC::Address homeAddress = KABCSync::getAddress(fromAbEntry, syncSettings);
+ KABCSync::setAddress(toPilotAddr, homeAddress);
+
+ // Process the additional entries from the Palm(the palm database app block tells us the name of the fields)
+ unsigned int customIndex = 0;
+ unsigned int hhField = entryCustom1;
+
+ for ( ; customIndex<4; ++customIndex,++hhField )
+ {
+ toPilotAddr.setField(hhField,getFieldForHHCustom(customIndex,fromAbEntry,syncSettings));
+ }
+
+ int categoryForHH = KABCSync::bestMatchedCategory(fromAbEntry.categories(),
+ appInfo,toPilotAddr.category());
+ toPilotAddr.setCategory(categoryForHH);
+
+ if (isArchived(fromAbEntry))
+ {
+ toPilotAddr.setArchived( true );
+ }
+ else
+ {
+ toPilotAddr.setArchived( false );
+ }
+}
+
+void KABCSync::copy(KABC::Addressee &toAbEntry,
+ const PilotAddress &fromPiAddr,
+ const PilotAddressInfo &appInfo,
+ const KABCSync::Settings &syncSettings)
+{
+ FUNCTIONSETUP;
+
+ // copy straight forward values
+ toAbEntry.setFamilyName(fromPiAddr.getField(entryLastname));
+ toAbEntry.setGivenName(fromPiAddr.getField(entryFirstname));
+ toAbEntry.setOrganization(fromPiAddr.getField(entryCompany));
+ toAbEntry.setPrefix(fromPiAddr.getField(entryTitle));
+ toAbEntry.setNote(fromPiAddr.getField(entryNote));
+
+ // set the formatted name
+ // TODO this is silly and should be removed soon.
+ toAbEntry.setFormattedName(toAbEntry.realName());
+
+ // copy the phone stuff
+ // first off, handle the e-mail addresses as a group and separate from
+ // the other phone number fields
+ toAbEntry.setEmails(fromPiAddr.getEmails());
+
+ // going from Pilot to kabc, we need to clear out all phone records in kabc
+ // so that they can be set from the Pilot. If we do not do this, then records
+ // will be left in kabc when they are removed from the Pilot and we'll look
+ // broken.
+ KABC::PhoneNumber::List old = toAbEntry.phoneNumbers();
+ for (KABC::PhoneNumber::List::Iterator it = old.begin(); it != old.end(); ++it) {
+ KABC::PhoneNumber phone = *it;
+ toAbEntry.removePhoneNumber(phone);
+ }
+
+ // now, get the phone numbers from the Pilot and set them one at a time in kabc
+ KABC::PhoneNumber::List phones = KABCSync::getPhoneNumbers(fromPiAddr);
+ for (KABC::PhoneNumber::List::Iterator it = phones.begin(); it != phones.end(); ++it) {
+ KABC::PhoneNumber phone = *it;
+ // check for fax number if it is one, set the type per the user's direction
+ if (phone.type() & KABC::PhoneNumber::Fax)
+ {
+ phone.setType(syncSettings.faxTypeOnPC());
+ }
+ toAbEntry.insertPhoneNumber(phone);
+ }
+
+ // Note: this is weird, and it may cause data to not be synced if there is
+ // more than one "Other" field being used on the Pilot, since only one will
+ // be synced in either direction.
+ KABCSync::setFieldFromHHOtherPhone(toAbEntry,
+ fromPiAddr.getPhoneField(PilotAddressInfo::eOther),syncSettings);
+
+ // going from Pilot to kabc, we need to clear out all addresses in kabc
+ // so that they can be set from the Pilot. If we do not do this, then records
+ // will be left in kabc when they are removed from the Pilot and we'll look
+ // broken.
+ KABC::Address::List oAddr = toAbEntry.addresses();
+ for (KABC::Address::List::Iterator it = oAddr.begin(); it != oAddr.end(); ++it) {
+ const KABC::Address addr = *it;
+ toAbEntry.removeAddress(addr);
+ }
+ KABC::Address homeAddress = KABCSync::getAddress(toAbEntry,syncSettings);
+ homeAddress.setStreet(fromPiAddr.getField(entryAddress));
+ homeAddress.setLocality(fromPiAddr.getField(entryCity));
+ homeAddress.setRegion(fromPiAddr.getField(entryState));
+ homeAddress.setPostalCode(fromPiAddr.getField(entryZip));
+ homeAddress.setCountry(fromPiAddr.getField(entryCountry));
+ toAbEntry.insertAddress(homeAddress);
+
+ unsigned int customIndex = 0;
+ unsigned int hhField = entryCustom1;
+
+ for ( ; customIndex<4; ++customIndex,++hhField )
+ {
+ KABCSync::setFieldFromHHCustom(customIndex,
+ toAbEntry,
+ fromPiAddr.getField(hhField),
+ syncSettings);
+ }
+
+ // copy the fromPiAddr pilot id to the custom field KPilot_Id;
+ // pilot id may be zero(since it could be new) but couldn't hurt
+ // to even assign it to zero; let's us know what state the
+ // toAbEntry is in
+ toAbEntry.insertCustom(KABCSync::appString, KABCSync::idString, QString::number(fromPiAddr.id()));
+
+ KABCSync::setCategory(toAbEntry, appInfo.categoryName(fromPiAddr.category()));
+
+ showAddressee(toAbEntry);
+}
+
+void KABCSync::showAddressee(const KABC::Addressee & abAddress)
+{
+ FUNCTIONSETUP;
+#ifdef DEBUG
+ DEBUGKPILOT << "\tAbbrowser Contact Entry" << endl;
+ if (abAddress.isEmpty())
+ {
+ DEBUGKPILOT<< "\t\tEMPTY"<<endl;
+ return;
+ }
+ DEBUGKPILOT << "\t\tLast name = " << abAddress.familyName() << endl;
+ DEBUGKPILOT << "\t\tFirst name = " << abAddress.givenName() << endl;
+ DEBUGKPILOT << "\t\tCompany = " << abAddress.organization() << endl;
+ DEBUGKPILOT << "\t\tJob Title = " << abAddress.prefix() << endl;
+ DEBUGKPILOT << "\t\tNote = " << abAddress.note() << endl;
+ DEBUGKPILOT << "\t\tCategory = " << abAddress.categories().first() << endl;
+ DEBUGKPILOT << "\t\tEmail = " << abAddress.emails().join(",") << endl;
+
+ KABC::PhoneNumber::List phs = abAddress.phoneNumbers();
+ for (KABC::PhoneNumber::List::Iterator it = phs.begin(); it != phs.end(); ++it) {
+ KABC::PhoneNumber phone = *it;
+ DEBUGKPILOT << "\t\t" << phone.label()
+ << "= " << phone.number() << endl;
+ }
+
+ KABC::Address::List ads = abAddress.addresses();
+ for (KABC::Address::List::Iterator it = ads.begin(); it != ads.end(); ++it) {
+ const KABC::Address addr = *it;
+ DEBUGKPILOT << "\t\tAddress = " << addr.street() <<endl;
+ DEBUGKPILOT << "\t\tLocality = " << addr.locality() <<endl;
+ DEBUGKPILOT << "\t\tRegion = " << addr.region() <<endl;
+ DEBUGKPILOT << "\t\tPostal code = " << addr.postalCode() <<endl;
+ DEBUGKPILOT << "\t\tCountry = " << addr.country() <<endl << endl;
+ }
+#else
+ Q_UNUSED( abAddress );
+#endif
+}
+
+
+
+
+KABCSync::Settings::Settings() :
+ fDateFormat(),
+ fCustomMapping(4), // Reserve space for 4 elements, value 0 == CustomField
+ fOtherPhone(eOtherPhone),
+ fPreferHome(true),
+ fFaxTypeOnPC(KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home)
+{
+}
+
diff --git a/kpilot/conduits/abbrowserconduit/kabcRecord.h b/kpilot/conduits/abbrowserconduit/kabcRecord.h
new file mode 100644
index 000000000..13a3e2694
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/kabcRecord.h
@@ -0,0 +1,263 @@
+#ifndef _KPILOT_KABCRECORD_H
+#define _KPILOT_KABCRECORD_H
+/* KPilot
+**
+** Copyright (C) 2000,2001 by Dan Pilone
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+** Copyright (C) 2007 by Adriaan de Groot <[email protected]>
+**
+** The abbrowser conduit copies addresses from the Pilot's address book to
+** the KDE addressbook maintained via the kabc library. This file
+** deals with the actual copying of HH addresses to KABC addresses
+** and back again.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected].
+*/
+
+#include <qvaluevector.h>
+
+#include <kabc/phonenumber.h>
+
+#include "pilotAddress.h"
+
+#define SYNCNONE 0
+#define SYNCMOD 1
+#define SYNCDEL 3
+
+namespace KABCSync
+{
+ // This duplicates values from the config settings,
+ // and must be kept in sync if new settings are added
+ // -- there are compile time checks for this in the
+ // abbrowser conduit code.
+ enum MappingForOtherPhone {
+ eOtherPhone=0,
+ eAssistant,
+ eBusinessFax,
+ eCarPhone,
+ eEmail2,
+ eHomeFax,
+ eTelex,
+ eTTYTTDPhone
+ } ;
+
+ enum MappingForCustomField {
+ eCustomField=0,
+ eCustomBirthdate,
+ eCustomURL,
+ eCustomIM
+ } ;
+
+ class Settings
+ {
+ public:
+ Settings();
+ QString dateFormat() const
+ {
+ return fDateFormat;
+ }
+ void setDateFormat(const QString& s)
+ {
+ fDateFormat = s;
+ }
+
+ const QValueVector<int> &customMapping() const
+ {
+ return fCustomMapping;
+ }
+ void setCustomMapping(const QValueVector<int> &v)
+ {
+ if (v.count()==4)
+ {
+ fCustomMapping = v;
+ }
+ }
+ int custom(int index) const
+ {
+ if ( (index<0) || (index>3) )
+ {
+ return 0;
+ }
+ else
+ {
+ return fCustomMapping[index];
+ }
+ }
+
+ int fieldForOtherPhone() const
+ {
+ return fOtherPhone;
+ }
+ void setFieldForOtherPhone(int v)
+ {
+ fOtherPhone = v;
+ }
+
+ bool preferHome() const
+ {
+ return fPreferHome;
+ }
+ void setPreferHome(bool v)
+ {
+ fPreferHome = v;
+ }
+
+ int faxTypeOnPC() const
+ {
+ return fFaxTypeOnPC;
+ }
+ void setFaxTypeOnPC(int v)
+ {
+ fFaxTypeOnPC = v;
+ }
+ private:
+ QString fDateFormat;
+ QValueVector<int> fCustomMapping;
+ int fOtherPhone;
+ bool fPreferHome;
+ int fFaxTypeOnPC;
+ } ;
+
+
+ /** Return a list of all the phone numbers (max. 8) set in this
+ * handheld entry @p a . Email entries are ignored.
+ */
+ KABC::PhoneNumber::List getPhoneNumbers(const PilotAddress &a);
+
+ /** Set the phone numbers from @p list in the handheld entry
+ * @p a (with info block @p info providing the mapping of category
+ * names and some other fiddly stuff) as far as possible.
+ * @em No overflow handling is done at all. If the desktop has
+ * more than 5 phone entries, the remainder are dropped.
+ */
+ void setPhoneNumbers(const PilotAddressInfo &info,
+ PilotAddress &a,
+ const KABC::PhoneNumber::List &list);
+
+ /** Given a list of category names from the KDE side (e.g. attached
+ * to a PC-based Addressee) @p categorynames , look for the
+ * category @em best matching the category @p category
+ * in the appinfo block @p info . Here, best is defined as follows:
+ * - if the name of category @p category is in the list, use it
+ * - otherwise use the first category from the list that is a valid
+ * category on the handheld.
+ * - use Pilot::Unfiled if none match.
+ *
+ * @return Category index that best matches.
+ * @return Pilot::Unfiled if no best match.
+ */
+ unsigned int bestMatchedCategory(const QStringList &categorynames,
+ const PilotAddressInfo &info,
+ unsigned int category);
+
+ /** As above, but return the name of the category. */
+ inline QString bestMatchedCategoryName(const QStringList &categorynames,
+ const PilotAddressInfo &info,
+ unsigned int category)
+ {
+ return info.categoryName(
+ bestMatchedCategory(categorynames, info, category));
+ }
+
+ /** Give the addressee @p abEntry the category @p cat (leaving
+ * existing category assignments intact).
+ */
+ void setCategory(KABC::Addressee &abEntry, const QString &cat);
+
+ /* These are string identifiers used for custom properties in the addressees,
+ * used to store KPilot-specific settings.
+ */
+ const QString appString=CSL1("KPILOT"); ///< Identifier for the application
+ const QString flagString=CSL1("Flag"); ///< Flags: synced or not
+ const QString idString=CSL1("RecordID"); ///< Record ID on HH for this addressee
+
+
+ /** Get the string value for HH custom field @p index (0..3) from the addressee
+ * @p abEntry . Which @em actual field this is depends on the mapping
+ * of custom HH fields to PC fields. This mapping is given by the @p customMapping
+ * which may be created from the conduit settings or by hand. Since one of the
+ * possible actual fields is "birthday," which needs formatting, use the date format
+ * string @p dateFormat. If this is empty, use the locale setting.
+ *
+ * @return String value for HH custom field @p index
+ * @return Null QString on error (is also a valid return value)
+ */
+ QString getFieldForHHCustom(
+ unsigned int index,
+ const KABC::Addressee &abEntry,
+ const Settings &settings);
+
+ /** Set a field of the PC @p abEntry address from the custom HH field.
+ * Use value @p value . The value comes from custom field @p index
+ * using the interpretation of custom fields @p customMapping . Because
+ * one of the interpretations includes the birthday, use the date format
+ * @p dateFormat ; if empty, use the local format when setting dates from the HH.
+ */
+ void setFieldFromHHCustom(
+ const unsigned int index,
+ KABC::Addressee &abEntry,
+ const QString &value,
+ const Settings &settings);
+
+ /** The HH has a phone type "other" which may be mapped to any one of
+ * several PC side phone numbers. Return the right one depending in the mapping.
+ *
+ * @note @p mappingForOther should come from AbbrowserSettings::pilotOther()
+ */
+ QString getFieldForHHOtherPhone(const KABC::Addressee &abEntry, const Settings &s);
+
+ /** The HH has a phone type "other" which may be mapped to any one
+ * of several PC side phone numbers. Store the number @p nr in the
+ * PC side phone field indicated by @p mappingForOther .
+ *
+ * @note @p mappingForOther should come from AbbrowserSettings::pilotOther()
+ */
+ void setFieldFromHHOtherPhone(KABC::Addressee &abEntry, const QString &nr, const Settings &s);
+
+ /** Returns the address portion of an addressee. Since the HH can only store
+ * one address, we return the preferred address (if the Addressee @p abEntry
+ * has one) and then either home or business depending on @p preferHome
+ * and if that doesn't exist, the other one and if @em that doesn't exist,
+ * return the preferred home or work address if it exists.
+ */
+ KABC::Address getAddress(const KABC::Addressee &abEntry, const Settings &);
+
+ /** Set the address fields of the HH record from the @p abAddress . */
+ void setAddress(PilotAddress &toPilotAddr, const KABC::Address &abAddress);
+
+ bool isArchived(const KABC::Addressee &);
+ void makeArchived(KABC::Addressee &);
+
+ void copy(PilotAddress &toPilotAddr,
+ const KABC::Addressee &fromAbEntry,
+ const PilotAddressInfo &appInfo,
+ const Settings &syncSettings);
+ void copy(KABC::Addressee &toAbEntry,
+ const PilotAddress &fromPiAddr,
+ const PilotAddressInfo &appInfo,
+ const Settings &syncSettings);
+
+ void showAddressee(const KABC::Addressee &);
+}
+
+#endif
+
diff --git a/kpilot/conduits/abbrowserconduit/kaddressbookConduit.ui b/kpilot/conduits/abbrowserconduit/kaddressbookConduit.ui
new file mode 100644
index 000000000..6447caa07
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/kaddressbookConduit.ui
@@ -0,0 +1,746 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>AbbrowserWidget</class>
+<author>Adriaan de Groot and David Bishop</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Form2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>645</width>
+ <height>287</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>50</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QButtonGroup" row="0" column="0">
+ <property name="name">
+ <cstring>fSyncDestination</cstring>
+ </property>
+ <property name="title">
+ <string>Sync Destination</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fSyncStdAbook</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Standard addressbook</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to synchronize with KDE's standard addressbook (i.e. the addressbook that you edit in KAddressBook, and which you use in KMail)&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>fSyncFile</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>vCard &amp;file:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to use a specific address book file, instead of the standard KDE address book. This file must be in the vCard format (.vcf). Type the location of this file in the edit box or select it clicking the file picker button.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="1">
+ <property name="name">
+ <cstring>fAbookFile</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter the vCard file name here or select it by clicking the file picker button. vCard is a standard format for exchanging contact information. &lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>fArchive</cstring>
+ </property>
+ <property name="text">
+ <string>Store &amp;archived records in the KDE addressbook</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;If you delete an address on your handheld, you can determine if it should be archived on the PC. If you check that and this checkbox, the address will be added to your addressbook, but no longer synchronized with the handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Conflicts</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox4</cstring>
+ </property>
+ <property name="title">
+ <string>Conflict Resolution</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_2_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Conflict &amp;resolution:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fConflictResolution</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select in this list how conflicting entries (entries which were edited both on your handheld and on the PC) are resolved. Possibly values are "Use KPilot's Global Setting" to use the settings defined in KPilot HotSync configuration, "Ask User" to let you decide case by case, "Do Nothing" to allow the entries to be different, "PC overrides", "Handheld overrides", "Use values from last sync" and "Use both entries" to create a new entry on both the PC and handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>Use KPilot's Global Setting</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Ask User</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Do Nothing</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Handheld Overrides</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>PC Overrides</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Values From Last Sync (if possible)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Use Both Entries</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fConflictResolution</cstring>
+ </property>
+ <property name="currentItem">
+ <number>6</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select in this list how conflicting entries (entries which were edited both on your handheld and on the PC) are resolved. Possibly values are "Use KPilot's Global Setting" to use the settings defined in KPilot HotSync configuration, "Ask User" to let you decide case by case, "Do Nothing" to allow the entries to be different, "PC overrides", "Handheld overrides", "Use values from last sync" and "Use both entries" to create a new entry on both the PC and handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel1_7</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;p&gt;Select the default action if an event was modified on both sides here. &lt;/p&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignJustify|AlignVCenter</set>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>41</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Fields</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Handheld other phone:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select which KAddressBook field should be used to store the Pilot's &amp;quot;Other&amp;quot; phone here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>Other Phone</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Assistant</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Business Fax</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Car Phone</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Email 2</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Home Fax</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Telex</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>TTY/TTD Phone</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fOtherPhone</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select which KAddressBook field should be used to store the Pilot's &amp;quot;Other&amp;quot; phone here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Handheld street address:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select which KAddressBook field should be used to store the Pilot's Street Address here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>Preferred, then Home Address</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Preferred, then Business Address</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fAddress</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select which KAddressBook field should be used to store the Pilot's Street Address here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Handheld fax:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select which KAddressBook field should be used to store the Fax number from the Pilot here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>Home Fax</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Business Fax</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fFax</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select which KAddressBook field should be used to store the Fax number from the Pilot here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Custom Fields</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Handheld custom field 1:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select the field from this list that represents best the meaning given by your use of the first custom field on your handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Handheld custom field 2:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select the field from this list that represents best the meaning given by your use of the second custom field on your handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Handheld custom field 3:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select the field from this list that represents best the meaning given by your use of the third custom field on your handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Handheld custom field 4:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select the field from this list that represents best the meaning given by your use of the fourth custom field on your handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>Store as Custom Field</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Birthdate</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>URL</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>IM Address (ICQ, MS, ...)</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fCustom0</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select the field from this list that represents best the meaning given by your use of the first custom field on your handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>Store as Custom Field</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Birthdate</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>URL</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>IM Address (ICQ, MSN, ...)</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fCustom1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select the field from this list that represents best the meaning given by your use of the second custom field on your handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>Store as Custom Field</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Birthdate</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>URL</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>IM Address (ICQ, MSN, ...)</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fCustom2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select the field from this list that represents best the meaning given by your use of the third custom field on your handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="3" column="1">
+ <item>
+ <property name="text">
+ <string>Store as Custom Field</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Birthdate</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>URL</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>IM Address (ICQ, MSN, ...)</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fCustom3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select the field from this list that represents best the meaning given by your use of the fourth custom field on your handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="Line" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>textLabel1_5</cstring>
+ </property>
+ <property name="text">
+ <string>Date &amp;format:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fCustomDate</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select the birthdate format here, if you selected "birthdate" for any of the custom fields above. Possible placeholders are:&lt;br&gt; %d for the day, %m for the month, %y for the two-digit year, %Y for the four-digit year. For example, %d.%m.%Y would generate a date like 27.3.1952, while %m/%d/%y would write the same date as 03/27/52. &lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="6" column="1">
+ <item>
+ <property name="text">
+ <string>Locale Settings</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>%d.%m.%Y</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>%d.%m.%y</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>%d/%m/%Y</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>%d/%m/%y</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>%m/%d/%Y</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>%m/%d/%y</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fCustomDate</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select the birthdate format here, if you selected "birthdate" for any of the custom fields above. Possible placeholders are:&lt;br&gt; %d for the day, %m for the month, %y for the two-digit year, %Y for the four-digit year. For example, %d.%m.%Y would generate a date like 27.3.1952, while %m/%d/%y would write the same date as 03/27/52. &lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <spacer row="8" column="1">
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>fSyncFile</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>fAbookFile</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>fArchive</tabstop>
+ <tabstop>tabWidget</tabstop>
+ <tabstop>fOtherPhone</tabstop>
+ <tabstop>fAddress</tabstop>
+ <tabstop>fFax</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includes>
+ <include location="global" impldecl="in implementation">kurlrequester.h</include>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+ <include location="global" impldecl="in implementation">kpushbutton.h</include>
+</includes>
+</UI>
diff --git a/kpilot/conduits/abbrowserconduit/resolutionDialog.cc b/kpilot/conduits/abbrowserconduit/resolutionDialog.cc
new file mode 100644
index 000000000..2749074f8
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/resolutionDialog.cc
@@ -0,0 +1,323 @@
+/* resolutionDialog.h KPilot
+**
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+**
+** See the .cc file for an explanation of what this file is for.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qtimer.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qlistview.h>
+#include <qregexp.h>
+
+#include "resolutionTable.h"
+#include "resolutionDialog_base.h"
+
+#include "resolutionDialog.moc"
+
+/** This class describes the controllers of the conflict resolution ListView,
+ * as well as its child radio buttons. There are two different constructors
+ * for them.
+ * Each controller has three child radio buttons, and if any of them is
+ * activated (stateChange), it sets the text of its parent (which is the
+ * controller, which is an instance of ResolutionCheckListItem, too).
+ **/
+class ResolutionCheckListItem : QCheckListItem {
+public:
+ ResolutionCheckListItem(ResolutionItem*it, ResolutionTable*tb,
+ QListView*parent);
+ ResolutionCheckListItem(QString header, QString text,
+ ResolutionCheckListItem*parent);
+ ~ResolutionCheckListItem() {};
+ virtual void stateChange(bool newstate);
+ virtual void setValue(QString text);
+ virtual void setCaption(QString caption);
+
+protected:
+ void updateText();
+ /* fResItem is only set for the controller */
+ ResolutionItem*fResItem;
+ bool isController;
+ /* The description of the entry, e.g. Backup, PC, Palm for the radio buttons,
+ * of the field name for the controllers
+ */
+ QString fCaption;
+ /* The currrent value of the entry (for controllers this changes with the
+ * selected button */
+ QString fText;
+};
+
+
+ResolutionCheckListItem::ResolutionCheckListItem(ResolutionItem*it,
+ ResolutionTable*tb, QListView*parent) :
+ QCheckListItem(parent, QString::null, QCheckListItem::Controller),
+ fResItem(it),
+ isController(true),
+ fCaption(it?(it->fName):(QString::null)),
+ fText(it?(it->fResolved):(QString::null))
+{
+ FUNCTIONSETUP;
+ if (it && tb)
+ {
+ // If all three texts are identical, there is no need for
+ // resolution so don't show the radio items below
+ bool itemsEqual=true;
+ QString testtext(QString::null);
+ const enum eExistItems its[3]={eExistsPC, eExistsPalm, eExistsBackup};
+ // get a valid text from a valid field, which will serve as the
+ // test text for the comparison
+ for (int i=0; i<3; i++)
+ {
+ if ((testtext.isNull()) && (it->fExistItems & its[i]) )
+ testtext=it->fEntries[i];
+ }
+ for (int i=0; i<3; i++)
+ {
+ if (it->fExistItems & its[i])
+ itemsEqual&=(it->fEntries[i]==testtext);
+ }
+ if (!itemsEqual)
+ {
+ ResolutionCheckListItem*item;
+ for (int i=2; i>=0; i--)
+ {
+ // Add only existing items
+ if (it->fExistItems & its[i])
+ {
+ item=new ResolutionCheckListItem(it->fEntries[i], tb->labels[i], this);
+ item->setOn(it->fEntries[i]==fText);
+ }
+ }
+ }
+ updateText();
+ }
+ setOpen(true);
+}
+
+ResolutionCheckListItem::ResolutionCheckListItem(QString text, QString header,
+ ResolutionCheckListItem*parent) :
+ QCheckListItem(parent, QString(), QCheckListItem::RadioButton),
+ fResItem(0L),
+ isController(false),
+ fCaption(header),
+ fText(text)
+{
+ updateText();
+}
+
+void ResolutionCheckListItem::stateChange(bool newstate)
+{
+ if (newstate && !isController)
+ {
+ ResolutionCheckListItem*par=static_cast<ResolutionCheckListItem*>(parent());
+ {
+ par->setValue(fText);
+ }
+ }
+}
+
+void ResolutionCheckListItem::setValue(QString text)
+{
+ FUNCTIONSETUP;
+ fText=text;
+ if (isController && fResItem)
+ {
+ fResItem->fResolved=text;
+ }
+ updateText();
+}
+
+void ResolutionCheckListItem::setCaption(QString caption)
+{
+ fCaption=caption;
+ updateText();
+}
+
+void ResolutionCheckListItem::updateText()
+{
+ QString newText(i18n("Entries in the resolution dialog. First the name of the field, then the entry from the Handheld or PC after the colon", "%1: %2").arg(fCaption).arg(fText));
+ newText.replace(QRegExp(CSL1("\n")),
+ i18n("Denoting newlines in Address entries. No need to translate", " | "));
+ setText(0, newText);
+}
+
+
+
+/*****************************************************************
+ *
+ *****************************************************************/
+
+ResolutionDlg::ResolutionDlg( QWidget* parent, KPilotLink*fH,
+ const QString &caption, const QString &helpText, ResolutionTable*tab) :
+ KDialogBase( parent, "ResolutionDlg", false, caption, Apply|Cancel, Apply),
+ tickleTimer(0L),
+ fHandle(fH),
+ fTable(tab)
+{
+ fWidget = new ResolutionDialogBase( this );
+ setMainWidget(fWidget);
+ fTable->fResolution=SyncAction::eDoNothing;
+ fWidget->fIntroText->setText(helpText);
+
+ fillListView();
+ adjustButtons(tab);
+
+ adjustSize();
+ resize(size());
+
+ if (fHandle) tickleTimer=new QTimer(this, "TickleTimer");
+
+ if (tickleTimer)
+ {
+ connect( tickleTimer, SIGNAL(timeout()), this, SLOT(_tickle()));
+ // tickle the palm every 10 seconds to prevent a timeout until the
+ // sync is really finished.
+ tickleTimer->start( 10000 );
+ }
+
+ connect(fWidget->fKeepBoth, SIGNAL(clicked()), SLOT(slotKeepBoth()));
+ connect(fWidget->fBackupValues, SIGNAL(clicked()), SLOT(slotUseBackup()));
+ connect(fWidget->fPalmValues, SIGNAL(clicked()), SLOT(slotUsePalm()));
+ connect(fWidget->fPCValues, SIGNAL(clicked()), SLOT(slotUsePC()));
+}
+
+void ResolutionDlg::adjustButtons(ResolutionTable*tab)
+{
+ FUNCTIONSETUP;
+ if (!tab) return;
+ if (!(tab->fExistItems & eExistsPC) )
+ {
+ fWidget->fPCValues->setText(i18n("Delete entry"));
+ fWidget->fKeepBoth->setDisabled(TRUE);
+ fWidget->fKeepBoth->hide();
+ }
+ if (!(tab->fExistItems & eExistsPalm) )
+ {
+ fWidget->fPalmValues->setText(i18n("Delete entry"));
+ fWidget->fKeepBoth->setDisabled(TRUE);
+ fWidget->fKeepBoth->hide();
+ }
+ if (!(tab->fExistItems & eExistsBackup) )
+ {
+ fWidget->fBackupValues->setDisabled(TRUE);
+ }
+}
+
+void ResolutionDlg::fillListView()
+{
+ FUNCTIONSETUP;
+ fWidget->fResolutionView->setSorting(-1, FALSE);
+ fWidget->fResolutionView->clear();
+ for ( ResolutionItem* it = fTable->last(); it; it = fTable->prev() )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT<<"Building table, items="<<it->fExistItems<<", PC="<<
+ it->fEntries[0]<<", Palm="<<it->fEntries[1]<<", Backup="<<
+ it->fEntries[2]<<endl;
+#endif
+ bool hasValidValues=false;
+ if (it->fExistItems & eExistsPC)
+ hasValidValues = hasValidValues || !(it->fEntries[0].isEmpty());
+ if (it->fExistItems & eExistsPalm)
+ hasValidValues = hasValidValues || !(it->fEntries[1].isEmpty());
+ if (it->fExistItems & eExistsBackup)
+ hasValidValues = hasValidValues || !(it->fEntries[2].isEmpty());
+ if (hasValidValues)
+ new ResolutionCheckListItem(it, fTable, fWidget->fResolutionView);
+ }
+}
+
+void ResolutionDlg::slotKeepBoth()
+{
+ if ( (fTable->fExistItems & eExistsPC) && (fTable->fExistItems & eExistsPalm) )
+ {
+ fTable->fResolution=SyncAction::eDuplicate;
+ }
+ else
+ {
+ fTable->fResolution=SyncAction::eDoNothing;
+ }
+ done(fTable->fResolution);
+}
+
+void ResolutionDlg::slotUseBackup()
+{
+ if (fTable->fExistItems & eExistsBackup)
+ {
+ fTable->fResolution=SyncAction::ePreviousSyncOverrides;
+ }
+ else
+ {
+ fTable->fResolution=SyncAction::eDoNothing;
+ }
+ done(fTable->fResolution);
+}
+
+void ResolutionDlg::slotUsePalm()
+{
+ if (fTable->fExistItems & eExistsPalm)
+ {
+ fTable->fResolution=SyncAction::eHHOverrides;
+ }
+ else
+ {
+ fTable->fResolution=SyncAction::eDelete;
+ }
+ done(fTable->fResolution);
+}
+
+void ResolutionDlg::slotUsePC()
+{
+ if (fTable->fExistItems & eExistsPC)
+ {
+ fTable->fResolution=SyncAction::ePCOverrides;
+ }
+ else
+ {
+ fTable->fResolution=SyncAction::eDelete;
+ }
+ done(fTable->fResolution);
+}
+
+void ResolutionDlg::slotApply()
+{
+ fTable->fResolution=SyncAction::eAskUser;
+ done(fTable->fResolution);
+}
+
+void ResolutionDlg::_tickle()
+{
+ if (fHandle) fHandle->tickle();
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+ResolutionDlg::~ResolutionDlg()
+{
+ // no need to delete child widgets, Qt does it all for us
+}
diff --git a/kpilot/conduits/abbrowserconduit/resolutionDialog.h b/kpilot/conduits/abbrowserconduit/resolutionDialog.h
new file mode 100644
index 000000000..5f41ba0f2
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/resolutionDialog.h
@@ -0,0 +1,70 @@
+#ifndef RESOLUTIONDIALOG_H
+#define RESOLUTIONDIALOG_H
+/* resolutionDialog.h KPilot
+**
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+**
+** See the .cc file for an explanation of what this file is for.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <kdialogbase.h>
+class KPilotLink;
+class QTimer;
+class QListView;
+class ResolutionDialogBase;
+
+
+class ResolutionTable;
+
+class ResolutionDlg : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ ResolutionDlg( QWidget* parent=0,
+ KPilotLink*fH=0L,
+ const QString &caption=QString(),
+ const QString &helpText=QString(),
+ ResolutionTable *tab=0L );
+ ~ResolutionDlg();
+
+public slots:
+ void slotKeepBoth();
+ void slotUseBackup();
+ void slotUsePalm();
+ void slotUsePC();
+ void slotApply();
+ void _tickle();
+protected:
+ void fillListView();
+ void adjustButtons(ResolutionTable*tab);
+
+ QTimer* tickleTimer;
+ KPilotLink* fHandle;
+ ResolutionTable*fTable;
+
+ ResolutionDialogBase*fWidget;
+};
+
+#endif // RESOLUTIONDIALOG_H
diff --git a/kpilot/conduits/abbrowserconduit/resolutionDialog_base.ui b/kpilot/conduits/abbrowserconduit/resolutionDialog_base.ui
new file mode 100644
index 000000000..38fa73e89
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/resolutionDialog_base.ui
@@ -0,0 +1,129 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>ResolutionDialogBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>widget2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>459</width>
+ <height>350</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>widget2</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>fIntroText</cstring>
+ </property>
+ <property name="text">
+ <string>The following record was edited both on the handheld and on the PC. Please choose which values shall be synced:</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QListView" row="1" column="0">
+ <column>
+ <property name="text">
+ <string>Field</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>false</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>fResolutionView</cstring>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>true</bool>
+ </property>
+ <property name="resizeMode">
+ <enum>AllColumns</enum>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Use this list to resolve, field by field, the conflicts created when a record was edited both on the handheld and on the PC. For each record, the different values from the last sync, the handheld and PC are displayed for each field, allowing you to choose the desired value.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Line breaks in any of the entries are denoted by a " | " (without the quotes).</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QFrame" row="3" column="0">
+ <property name="name">
+ <cstring>frame3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>GroupBoxPanel</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton" row="0" column="1">
+ <property name="name">
+ <cstring>fKeepBoth</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Keep Both</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Click this button to use both values, resulting in the duplication of the record.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="0" column="0">
+ <property name="name">
+ <cstring>fPCValues</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;PC Values</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Click this button to use the PC values for synchronizing all conflicting fields in this record.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="1" column="0">
+ <property name="name">
+ <cstring>fBackupValues</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Last Sync Values</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Click this button to use the last sync values (old values) for synchronizing all conflicting fields in this record.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>fPalmValues</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Handheld Values</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Click this button to use the handheld values for synchronizing all conflicting fields in this record.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpilot/conduits/abbrowserconduit/resolutionTable.h b/kpilot/conduits/abbrowserconduit/resolutionTable.h
new file mode 100644
index 000000000..760f962e2
--- /dev/null
+++ b/kpilot/conduits/abbrowserconduit/resolutionTable.h
@@ -0,0 +1,70 @@
+#ifndef RESOLUTIONTABLE_H
+#define RESOLUTIONTABLE_H
+/* resolutionTable.h KPilot
+**
+** Copyright (C) 2003 by Reinhold Kainhofer
+**
+** See the .cc file for an explanation of what this file is for.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include <qvaluelist.h>
+#include "syncAction.h"
+
+typedef enum eExistItems {
+ eExistsPC=0x1, eExistsPalm=0x2, eExistsBackup=0x4,
+ eExistsAll=eExistsPC|eExistsPalm|eExistsBackup
+};
+
+class ResolutionItem
+{
+public:
+ enum eExistItems fExistItems;
+ QString fEntries[3];
+ QString fResolved;
+ QString fName;
+public:
+ ResolutionItem() {}
+ ResolutionItem(QString name, int ex, QString pc, QString palm, QString backup):fExistItems((eExistItems)ex),fName(name)
+ {fEntries[0]=pc;fEntries[1]=palm; fEntries[2]=backup; /*fExistItems=(eExistItems)ex;*/ }
+ ~ResolutionItem() {}
+};
+
+/**
+@author Reinhold Kainhofer
+*/
+class ResolutionTable : public QPtrList<ResolutionItem>
+{
+public:
+ ResolutionTable():QPtrList<ResolutionItem>() {fResolution=SyncAction::eAskUser;};
+
+ ~ResolutionTable() {};
+
+ SyncAction::ConflictResolution fResolution;
+ QString labels[3];
+ enum eExistItems fExistItems;
+};
+
+#endif
+
diff --git a/kpilot/conduits/configure.in.bot b/kpilot/conduits/configure.in.bot
new file mode 100644
index 000000000..688f775f9
--- /dev/null
+++ b/kpilot/conduits/configure.in.bot
@@ -0,0 +1,14 @@
+dnl Configure.in.bot for KPilot conduits.
+dnl
+dnl Copyright (C) 2000,2001 Adriaan de Groot
+dnl Copyright (C) 2002 Reinhold Kainhofer
+dnl
+dnl This file is released under the terms of the Gnu General Public
+dnl Licence (GPL) Version 2.
+
+if test "$with_mal" = NOTFOUND -o "$with_mal" = no ; then
+ echo ""
+ echo "KPILOT: MAL headers or library not found. AvantGo conduit will not be compiled."
+ echo "KPILOT: Download libmal>=0.20 from http://jasonday.home.att.net/code/libmal/"
+ echo ""
+fi
diff --git a/kpilot/conduits/configure.in.in b/kpilot/conduits/configure.in.in
new file mode 100644
index 000000000..c6a0d1437
--- /dev/null
+++ b/kpilot/conduits/configure.in.in
@@ -0,0 +1,241 @@
+dnl Configure.in.in for KPilot conduits.
+dnl
+dnl Copyright (C) 2000,2001 Adriaan de Groot
+dnl Copyright (C) 2002 Reinhold Kainhofer
+dnl
+dnl This file is released under the terms of the Gnu General Public
+dnl Licence (GPL) Version 2.
+
+
+
+
+dnl ----------------------------------------------------------------------------
+dnl
+dnl checks for the MAL conduit
+dnl
+dnl ----------------------------------------------------------------------------
+
+dnl
+dnl
+dnl Check to see if MAL header and library are available
+dnl
+
+dnl
+dnl Questions and comments can be sent to [email protected]
+dnl
+dnl This was copied and adapted from kabc's ldap configure.in.in
+
+
+AC_DEFUN([KPILOT_CHECK_MAL],
+[
+AC_REQUIRE([KDE_CHECK_LIB64])
+AC_REQUIRE([KPILOT_CHECK_PISOCK])
+
+AC_MSG_CHECKING(for libmal (for KPilots MAL conduit))
+AC_ARG_WITH(mal,
+[ --with-mal=PATH set path for libmal files @<:@default=check@:>@],
+[ case "$withval" in
+ yes)
+ with_mal=CHECK
+ ;;
+ esac ],
+[ with_mal=CHECK ]
+)dnl
+
+if test "x$with_mal" = "xCHECK" ; then
+ with_mal=NOTFOUND
+ search_incs_tmp="$kde_includes /usr/include /usr/local/include"
+ dnl build the list of include dirs, both with and without libmal appended
+ search_incs="";
+ for idir in $search_incs_tmp; do
+ search_incs="$search_incs $idir $idir/libmal"
+ done
+ AC_FIND_FILE(libmal.h, $search_incs, mal_incdir)
+ if test -r $mal_incdir/libmal.h ; then
+ test "x$mal_incdir" != "x/usr/include" && MAL_INCLUDE="-I$mal_incdir"
+ with_mal=FOUND
+ fi
+ if test $with_mal = FOUND ; then
+ with_mal=NOTFOUND
+ for ext in la so sl a ; do
+ AC_FIND_FILE(libmal.$ext, $kde_libraries $libdir /usr/lib$kdelibsuff /usr/local/lib$kdelibsuff $libdir/libmal /usr/lib/libmal /usr/local/lib/libmal,
+ mal_libdir)
+ if test -r $mal_libdir/libmal.$ext ; then
+ if test "x$mal_libdir" != "x/usr/lib$kdelibsuff" ; then
+ MAL_LIB="-L$mal_libdir "
+ test "$USE_RPATH" = yes && MAL_RPATH="-R $mal_libdir"
+ fi
+ MAL_LIB="${MAL_LIB}-lmal"
+ with_mal=FOUND
+ break
+ fi
+ done
+ fi
+fi
+
+case "$with_mal" in
+no) AC_MSG_RESULT(no) ;;
+NOTFOUND) AC_MSG_RESULT(searched but not found) ;;
+*)
+ if test "x$with_mal" = "xFOUND" ; then
+ msg="incs=$mal_incdir libs=$mal_libdir"
+ else
+ msg="$with_mal"
+ MAL_ROOT="$with_mal"
+ if test "x$MAL_ROOT" != "x/usr" ; then
+ MAL_INCLUDE="-I${MAL_ROOT}/include"
+ MAL_LIB="-L${MAL_ROOT}/lib$kdelibsuff "
+ if test "$USE_RPATH" = "yes" ; then
+ MAL_RPATH="-R ${MAL_ROOT}/lib$kdelibsuff"
+ fi
+ fi
+ MAL_LIB="${MAL_LIBS}-lmal"
+ fi
+
+ kde_save_LIBS="$LIBS"
+ kde_save_CFLAGS="$CFLAGS"
+ kde_save_CPPFLAGS="$CPPFLAGS"
+ kde_save_LDFLAGS="$LDFLAGS"
+ LIBS="$LIBS $PISOCK_LIB $MAL_LIB"
+ CFLAGS="$CFLAGS $MAL_INCLUDE"
+ CPPFLAGS="$CPPFLAGS $all_includes $PISOCK_INCLUDE $MAL_INCLUDE"
+ LDFLAGS="$LDFLAGS $PISOCK_LDFLAGS $all_libraries"
+ AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+ AC_TRY_LINK(dnl
+ [
+ #include <libmal.h>
+ ],
+ [
+ PalmSyncInfo *psi;
+ ],
+ , with_mal=no
+ )
+ if test "$with_mal" = "no" ; then
+ MAL_LIB="$MAL_LIB -ldl"
+ LIBS="$LIBS $PISOCK_LIB $MAL_LIB"
+ with_mal=yes
+ AC_TRY_LINK(dnl
+ [
+ #include <libmal.h>
+ ],
+ [
+ PalmSyncInfo *psi;
+ ],
+ , with_mal=no
+ )
+ fi
+ if test "$with_mal" = "no" ; then
+ MAL_INCLUDE=
+ MAL_LIB=
+ MAL_RPATH=
+ AC_MSG_RESULT(no (but first try gave $msg))
+ else
+ AC_DEFINE(HAVE_LIBMAL, 1, [Define if you have MAL libraries])
+ dnl check which version we have (pre 0.40 or >=0.40):
+ AC_TRY_LINK(dnl
+ [#include <libmal.h>],
+ [
+ PalmSyncInfo *psi;
+ psi->httpProxy;
+ ],
+ , mal_version20=yes
+ )
+ if test "$mal_version20" = "yes" ; then
+ AC_DEFINE(LIBMAL20, 1, [Define if we have the old libmal version (<0.40)])
+ fi
+ HAVE_LIBMAL=1
+ AC_MSG_RESULT($msg)
+ fi
+ AC_LANG_RESTORE
+ CFLAGS=$kde_save_CFLAGS
+ CPPFLAGS=$kde_save_CPPFLAGS
+ LIBS=$kde_save_LIBS
+ LDFLAGS=$kde_save_LDFLAGS
+ ;;
+esac
+
+AC_SUBST(MAL_INCLUDE)
+AC_SUBST(MAL_LIB)
+AC_SUBST(MAL_RPATH)
+
+AM_CONDITIONAL(include_malconduit, test "$HAVE_LIBMAL" = 1)
+
+])
+
+dnl ----------------------------------------------------------------------------
+dnl
+dnl checks for the addressbook conduit
+dnl
+dnl ----------------------------------------------------------------------------
+
+AC_DEFUN([KPILOT_CHECK_KABC],[HAVE_KABC=0
+KDE_CHECK_HEADER(kresources/factory.h,HAVE_KABC=1,
+ AC_MSG_WARN([KPILOT: Older kaddressbook version detected. No address book
+ conduit will be compiled.]))
+AM_CONDITIONAL(include_abc, test "$HAVE_KABC" = 1)
+])
+
+dnl ----------------------------------------------------------------------------
+dnl
+dnl checks for the notepad conduit
+dnl
+dnl ----------------------------------------------------------------------------
+
+AC_DEFUN([KPILOT_CHECK_NOTEPAD],[HAVE_NOTEPAD=0
+kpilot_save_cflags="$CPPFLAGS"
+kpilot_save_ldflags="$LDFLAGS"
+
+test -z "$PISOCK_INCLUDE" || CPPFLAGS="$CPPFLAGS $PISOCK_INCLUDE"
+KDE_CHECK_HEADER(pi-notepad.h,HAVE_NOTEPAD=1,
+ AC_MSG_WARN([KPILOT: No notepad.h for pilot-link. Your pilot-link is too old.]))
+
+CPPFLAGS="$kpilot_save_cflags"
+LDFLAGS="$kpilot_save_ldflags"
+unset kpilot_save_cflags
+unset kpilot_save_ldflags
+
+AM_CONDITIONAL(include_notepad, test "$HAVE_NOTEPAD" = 1)
+])
+
+dnl ----------------------------------------------------------------------------
+dnl
+dnl checks for embedded language conduits
+dnl
+dnl ----------------------------------------------------------------------------
+
+AC_DEFUN([KPILOT_CHECK_PERL],[HAVE_PERL=0
+AC_MSG_CHECKING([for Perl embedding])
+if perl -MExtUtils::Embed -e ccopts > /dev/null 2> /dev/null ; then
+ PERL_CFLAGS=`perl -MExtUtils::Embed -e ccopts 2> /dev/null`
+ PERL_LDFLAGS=`perl -MExtUtils::Embed -e ldopts 2> /dev/null`
+ HAVE_PERL=1
+ AC_MSG_RESULT(yes)
+else
+ PERL_CFLAGS=""
+ PERL_LDFLAGS=""
+ AC_MSG_RESULT(no)
+fi
+AC_SUBST(PERL_CFLAGS)
+AC_SUBST(PERL_LDFLAGS)
+AM_CONDITIONAL(include_perl, test "$HAVE_PERL" = 1)
+])
+
+AC_DEFUN([KPILOT_CHECK_PYTHON],[HAVE_PYTHON=0
+AC_MSG_CHECKING([for Python embedding])
+AM_CONDITIONAL(include_python, test "$HAVE_PYTHON" = 1)
+AC_MSG_RESULT(N/A)
+])
+
+dnl ----------------------------------------------------------------------------
+dnl
+dnl actually call the checks
+dnl
+dnl ----------------------------------------------------------------------------
+
+KPILOT_CHECK_MAL
+KPILOT_CHECK_KABC
+KPILOT_CHECK_PERL
+KPILOT_CHECK_PYTHON
+KPILOT_CHECK_NOTEPAD
+
diff --git a/kpilot/conduits/docconduit/CMakeLists.txt b/kpilot/conduits/docconduit/CMakeLists.txt
new file mode 100644
index 000000000..fa87eb0fb
--- /dev/null
+++ b/kpilot/conduits/docconduit/CMakeLists.txt
@@ -0,0 +1,87 @@
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+set(doc_shared_SRCS
+ makedoc9.cc
+ pilotDOCHead.cc
+ pilotDOCEntry.cc
+ pilotDOCBookmark.cc
+ DOC-converter.cc
+)
+
+set(conduit_doc_SRCS
+ ${doc_shared_SRCS}
+ kpalmdoc_dlg.cc
+ kpalmdoc.cpp
+ doc-factory.cc
+ doc-setup.cc
+ doc-conduit.cc
+ doc-conflictdialog.cc
+)
+
+set(conduit_doc_UIS
+ kpalmdoc_dlgbase.ui
+ doc-setupdialog.ui
+)
+
+set(conduit_doc_KCFGS
+ docconduitSettings.kcfgc
+ kpalmdocSettings.kcfgc
+)
+
+kde3_add_kcfg_files(conduit_doc_SRCS ${conduit_doc_KCFGS})
+kde3_add_ui_files(conduit_doc_SRCS ${conduit_doc_UIS})
+kde3_automoc(${conduit_doc_SRCS})
+add_library(conduit_doc SHARED ${conduit_doc_SRCS})
+
+kpilot_rpath(conduit_doc)
+
+set_target_properties(
+ conduit_doc PROPERTIES LOCATION ${KDE3_PLUGIN_INSTALL_DIR}
+ PREFIX ""
+)
+
+kde3_install_libtool_file(conduit_doc)
+
+install(
+ TARGETS conduit_doc
+ LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR}
+)
+
+set(kpalmdoc_SRCS
+ ${doc_shared_SRCS}
+ kpalmdoc_dlg.cc
+ kpalmdoc.cpp
+)
+kde3_add_kcfg_files(kpalmdoc_SRCS kpalmdocSettings.kcfgc)
+kde3_add_ui_files(kpalmdoc_SRCS kpalmdoc_dlgbase.ui)
+kde3_automoc(${kpalmdoc_SRCS})
+add_executable(kpalmdoc ${kpalmdoc_SRCS})
+target_link_libraries(kpalmdoc ${QT_LIBRARIES} kpilot kdeui kio)
+kpilot_rpath(kpalmdoc)
+
+install(
+ TARGETS kpalmdoc conduit_doc
+ LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
+)
+
+install(
+ FILES doc_conduit.desktop DESTINATION ${KDE3_SERVICES_DIR}
+)
+
+install(
+ FILES docconduit.kcfg kpalmdoc.kcfg DESTINATION ${KDE3_KCFG_DIR}
+)
+
+install(
+ FILES kpalmdoc.desktop DESTINATION ${KDE3_XDG_APPS_DIR}
+)
+
+install(
+ FILES kpalmdoc.upd
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/apps/kconf_update
+)
+
+add_subdirectory(Icons)
diff --git a/kpilot/conduits/docconduit/DOC-converter.cc b/kpilot/conduits/docconduit/DOC-converter.cc
new file mode 100644
index 000000000..c8d7ac02d
--- /dev/null
+++ b/kpilot/conduits/docconduit/DOC-converter.cc
@@ -0,0 +1,631 @@
+/* KPilot
+**
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+**
+** The doc converter synchronizes text files on the PC with DOC databases on the Palm
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "options.h"
+#include "DOC-converter.moc"
+
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qsortedlist.h>
+
+#include <pilotDatabase.h>
+#include <pilotLocalDatabase.h>
+#include <pilotSerialDatabase.h>
+
+#include "pilotDOCHead.h"
+#include "pilotDOCEntry.h"
+#include "pilotDOCBookmark.h"
+
+
+
+#define min(a,b) (a<b)?(a):(b)
+
+
+
+/****************************************************************************************************
+ * various bookmark classes. Most important is the bmkList findMatches(QString) function,
+ * which needs to return a list of all bookmarks found for the given bookmark expression.
+ * A bookmark usually consists of a bookmark text and an offset into the text document.
+ ****************************************************************************************************/
+
+
+bool docBookmark::compare_pos=true;
+
+bool operator< ( const docBookmark &s1, const docBookmark &s2)
+{
+ if (docBookmark::compare_pos) { return s1.position<s2.position;}
+ else {return s2.bmkName<s2.bmkName;}
+}
+
+bool operator== ( const docBookmark &s1, const docBookmark &s2)
+{
+ return (s1.position==s2.position) && (s1.bmkName==s2.bmkName);
+}
+
+
+int docMatchBookmark::findMatches(QString doctext, bmkList &fBookmarks) {
+ FUNCTIONSETUP;
+// bmkList res;
+ int pos = 0, nr=0, found=0;
+#ifdef DEBUG
+ DEBUGKPILOT<<"Finding matches of "<<pattern<<endl;
+#endif
+
+ while (pos >= 0 && found<to) {
+ pos = doctext.find(pattern, pos);
+#ifdef DEBUG
+ DEBUGKPILOT<<"Result of search: pos="<<pos<<endl;
+#endif
+ if (pos >= 0)
+ {
+ ++found;
+ if (found>=from && found<=to) {
+ fBookmarks.append(new docBookmark(pattern, pos));
+ ++nr;
+
+ }
+ ++pos;
+ }
+ }
+ return nr;
+}
+
+
+
+int docRegExpBookmark::findMatches(QString doctext, bmkList &fBookmarks)
+{
+ FUNCTIONSETUP;
+// bmkList res;
+ QRegExp rx(pattern);
+ int pos = 0, nr=0, found=0;
+
+ while (pos>=0 && found<=to) {
+#ifdef DEBUG
+ DEBUGKPILOT<<"Searching for bookmark "<<pattern<<endl;
+#endif
+ pos=rx.search(doctext, pos);
+ if (pos > -1) {
+ ++found;
+ if (found>=from && found<to) {
+ if (capSubexpression>=0) {
+ fBookmarks.append(new docBookmark(/*bmkName.left(16)*/rx.cap(capSubexpression), pos));
+ } else {
+ // TODO: use the subexpressions from the regexp for the bmk name ($1..$9) (given as separate regexp)
+ QString bmkText(bmkName);
+ for (int i=0; i<=rx.numCaptures(); ++i) {
+ bmkText.replace(CSL1("$%1").arg(i), rx.cap(i));
+ bmkText.replace(CSL1("\\%1").arg(i), rx.cap(i));
+ }
+ fBookmarks.append(new docBookmark(bmkText.left(16), pos));
+ }
+ ++nr;
+ }
+ ++pos;
+ }
+ }
+ return nr;
+}
+
+
+
+
+
+
+
+
+/*********************************************************************
+ C O N S T R U C T O R
+ *********************************************************************/
+
+
+DOCConverter::DOCConverter(QObject *parent, const char *name):QObject(parent,name) {
+ FUNCTIONSETUP;
+ docdb=0L;
+ eSortBookmarks=eSortNone;
+ fBookmarks.setAutoDelete( TRUE );
+}
+
+
+
+DOCConverter::~DOCConverter() {
+ FUNCTIONSETUP;
+}
+
+
+
+
+
+/*********************************************************************
+ S Y N C S T R U C T U R E
+ *********************************************************************/
+
+
+
+void DOCConverter::setTXTpath(QString path, QString file) {
+ QDir dr(path);
+ QFileInfo pth(dr, file);
+ if (!file.isEmpty())
+ txtfilename = pth.absFilePath();
+}
+
+
+
+void DOCConverter::setTXTpath(QString filename) {
+ if (!filename.isEmpty()) txtfilename = filename;
+}
+
+
+
+void DOCConverter::setPDB(PilotDatabase * dbi) {
+ if (dbi) docdb = dbi;
+}
+
+
+
+QString DOCConverter::readText() {
+ FUNCTIONSETUP;
+ if (txtfilename.isEmpty()) return QString();
+ QFile docfile(txtfilename);
+ if (!docfile.open(IO_ReadOnly))
+ {
+ emit logError(i18n("Unable to open text file %1 for reading.").arg(txtfilename));
+ return QString();
+ }
+
+ QTextStream docstream(&docfile);
+
+ QString doc = docstream.read();
+ docfile.close();
+ return doc;
+}
+
+
+
+int DOCConverter::findBmkEndtags(QString &text, bmkList&fBmks) {
+ FUNCTIONSETUP;
+ // Start from the end of the text
+ int pos = text.length() - 1, nr=0;
+ bool doSearch=true;
+ while (pos >= 0/* && doSearch*/) {
+ DEBUGKPILOT<<"Current character is \'"<<text[pos].latin1()<<"\'"<<endl;
+ // skip whitespace until we reach a >
+ while (text[pos].isSpace() && pos >= 0) {
+ DEBUGKPILOT<<"Skipping whitespaces at the end of the file"<<endl;
+ pos--;
+ }
+ // every other character than a > is assumed to belong to the text, so there are no more bookmarks.
+ if (pos < 0 || text[pos] != '>') {
+ DEBUGKPILOT<<"Current character \'"<<text[pos].latin1()<<"\' at position "<<pos<<" is not and ending >. Finish searching for bookmarks."<<endl;
+
+ pos=-1;
+ break;
+ } else {
+ int endpos = pos;
+ doSearch=true;
+ DEBUGKPILOT<<"Found the ending >, now looking for the opening <"<<endl;
+
+ // Search for the opening <. There must not be a newline in the bookmark text.
+ while (doSearch && pos > 0) {
+// DEBUGKPILOT<<"pos="<<pos<<", char="<<text[pos].latin1()<<endl;
+ pos--;
+ if (text[pos] == '\n') {
+ DEBUGKPILOT<<"Found carriage return at position "<<pos<<" inside the bookmark text, assuming this is not a bookmark, and the text ends in a >"<<endl;
+ doSearch = false;
+ pos = -1;
+ break;
+ }
+ if (text[pos] == '<') {
+ fBmks.append(new docMatchBookmark(text.mid(pos + 1, endpos - pos - 1)));
+ ++nr;
+ DEBUGKPILOT<<"Found opening < at position "<<pos<<", bookmarktext ="<<text.mid(pos+1, endpos-pos-1)<<endl;
+ text.remove(pos, text.length());
+ pos--;
+ doSearch = false;
+ }
+ }
+ }
+ DEBUGKPILOT<<"Finished processing the next bookmark, current position: "<<pos<<endl;
+ }
+ return nr;
+}
+
+int DOCConverter::findBmkInline(QString &text, bmkList &fBmks) {
+ FUNCTIONSETUP;
+// bmkList res;
+ int nr=0;
+ QRegExp rx(CSL1("<\\*(.*)\\*>"));
+
+ rx.setMinimal(TRUE);
+ int pos = 0;
+ while (pos >= 0) {
+ pos = rx.search(text, pos);
+ if (pos >= 0) {
+ fBmks.append(new docBookmark(rx.cap(1), pos+1));
+ ++nr;
+ text = text.remove(pos, rx.matchedLength());
+ }
+ }
+ return nr;
+}
+
+int DOCConverter::findBmkFile(QString &, bmkList &fBmks) {
+ FUNCTIONSETUP;
+ int nr=0;
+
+ QString bmkfilename = txtfilename;
+ if (bmkfilename.endsWith(CSL1(".txt"))){
+ bmkfilename.remove(bmkfilename.length()-4, 4);
+ }
+ QString oldbmkfilename=bmkfilename;
+ bmkfilename+=CSL1(BMK_SUFFIX);
+ QFile bmkfile(bmkfilename);
+ if (!bmkfile.open(IO_ReadOnly)) {
+ bmkfilename=oldbmkfilename+CSL1(PDBBMK_SUFFIX);
+ bmkfile.setName(bmkfilename);
+ if (!bmkfile.open(IO_ReadOnly)) {
+ DEBUGKPILOT<<"Unable to open bookmarks file "<<bmkfilename<<" for reading the bookmarks of "<<docdb ->dbPathName()<<endl;
+ return 0;
+ }
+ }
+
+ DEBUGKPILOT<<"Bookmark file: "<<bmkfilename<<endl;
+
+ QTextStream bmkstream(&bmkfile);
+ QString line;
+ while ( !(line=bmkstream.readLine()).isEmpty() ) {
+ if (!line.isEmpty() && !line.startsWith(CSL1("#")) ) {
+ QStringList bmkinfo=QStringList::split(CSL1(","), line);
+ int fieldnr=bmkinfo.count();
+ // We use the same syntax for the entries as MakeDocJ bookmark files:
+ // <bookmark>,<string-to-search>,<bookmark-name-string>,<starting-bookmark>,<ending-bookmark>
+ // For an explanation see: http://home.kc.rr.com/krzysztow/PalmPilot/MakeDocJ/index.html
+ if (fieldnr>0){
+ DEBUGKPILOT<<"Working on bookmark \""<<line<<"\""<<endl;
+ docMatchBookmark*bmk=0L;
+ QString bookmark=bmkinfo[0];
+ bool ok;
+ int pos=bookmark.toInt(&ok);
+ if (ok) {
+ if (fieldnr>1) {
+ QString name(bmkinfo[1]);
+ DEBUGKPILOT<<"Bookmark \""<<name<<"\" set at position "<<pos<<endl;
+ fBmks.append(new docBookmark(name, pos));
+ }
+ } else if (bookmark==CSL1("-") || bookmark==CSL1("+")) {
+ if (fieldnr>1) {
+ QString patt(bmkinfo[1]);
+ QString name(patt);
+ if (fieldnr>2) {
+ int cap=bmkinfo[2].toInt(&ok);
+ if (ok) {
+ bmk=new docRegExpBookmark(patt, cap);
+ } else {
+ name=bmkinfo[2];
+ bmk=new docRegExpBookmark(patt, name);
+ }
+ } else{
+ bmk=new docRegExpBookmark(patt, name);
+ }
+ // The third entry in the line (optional) denotes the index of a capture subexpression (if an integer) or the bookmark text as regexp (if a string)
+ DEBUGKPILOT<<"RegExp Bookmark, pattern="<<patt<<", name="<<name<<endl;
+ if (bmk) {
+ if (bookmark==CSL1("-")) {
+ bmk->from=1;
+ bmk->to=1;
+ } else {
+ if (fieldnr>3) {
+ bool ok;
+ int tmp=bmkinfo[3].toInt(&ok);
+ if (ok) bmk->from=tmp;
+ if (fieldnr>4) {
+ tmp=bmkinfo[4].toInt(&ok);
+ if (ok) bmk->to=tmp;
+ }
+ }
+ }
+ fBmks.append(bmk);
+ bmk=0L;
+ } else {
+ DEBUGKPILOT<<"Could not allocate bookmark "<<name<<endl;
+ }
+ } else {
+ DEBUGKPILOT<<"RegExp bookmark found with no other information (no bookmark pattern nor name)"<<endl;
+ }
+ } else {
+ QString pattern(bookmark);
+ if (fieldnr>1) pattern=bmkinfo[1];
+ if (fieldnr>2) bookmark=bmkinfo[2];
+ DEBUGKPILOT<<"RegExp Bookmark, pattern="<<pattern<<", name="<<bookmark<<endl;
+ bmk=new docRegExpBookmark(pattern, bookmark);
+ if (bmk) {
+ bmk->from=1;
+ bmk->to=1;
+ fBmks.append(bmk);
+ }
+ }
+ } // fieldnr>0
+ } // !line.isEmpty()
+ } // while
+ return nr;
+}
+
+bool DOCConverter::convertTXTtoPDB() {
+ FUNCTIONSETUP;
+
+ if (!docdb) {
+ emit logError(i18n("Unable to open Database for writing"));
+ return false;
+ }
+
+ QString text = readText();
+
+ if (fBmkTypes & eBmkEndtags) {
+ findBmkEndtags(text, fBookmarks);
+ } // end: EndTag Bookmarks
+
+
+ // Search for all tags <* Bookmark text *> in the text. We have to delete them immediately, otherwise the later bookmarks will be off.
+ if (fBmkTypes & eBmkInline) {
+ findBmkInline(text, fBookmarks);
+ } // end: Inline Bookmarks
+
+
+ // Read in regular expressions and positions from an external file (doc-filename with extension .bmk)
+ if (fBmkTypes & eBmkFile)
+ {
+ findBmkFile(text, fBookmarks);
+ }
+
+ // Process the bookmarks: find the occurrences of the regexps, and sort them if requested:
+ bmkSortedList pdbBookmarks;
+ pdbBookmarks.setAutoDelete(TRUE);
+ docBookmark*bmk;
+ for (bmk = fBookmarks.first(); bmk; bmk = fBookmarks.next())
+ {
+ bmk->findMatches(text, pdbBookmarks);
+ }
+
+ switch (eSortBookmarks)
+ {
+ case eSortName:
+ docBookmark::compare_pos=false;
+// qHeapSort(pdbBookmarks);
+ pdbBookmarks.sort();
+ break;
+ case eSortPos:
+ docBookmark::compare_pos=true;
+ pdbBookmarks.sort();
+ break;
+ case eSortNone:
+ default:
+ break;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << "Bookmarks: "<<endl;
+ for (bmk = pdbBookmarks.first(); bmk; bmk = pdbBookmarks.next())
+ {
+ DEBUGKPILOT<<bmk->bmkName.left(20)<<" at position "<<bmk->position<<endl;
+ }
+#endif
+
+ if (!docdb->isOpen()) {
+ emit logError(i18n("Unable to open palm doc database %1").arg(docdb->dbPathName()) );
+ return false;
+ }
+
+ // Clean the whole database, otherwise the records would be just appended!
+ docdb->deleteRecord(0, true);
+
+ // Header record for the doc file format
+ PilotDOCHead docHead;
+ docHead.position=0;
+ docHead.recordSize=4096;
+ docHead.spare=0;
+ docHead.storyLen=text.length();
+ docHead.version=compress?DOC_COMPRESSED:DOC_UNCOMPRESSED;
+ docHead.numRecords=(int)( (text.length()-1)/docHead.recordSize)+1;
+ PilotRecord*rec=docHead.pack();
+ docdb->writeRecord(rec);
+ KPILOT_DELETE(rec);
+
+ DEBUGKPILOT << "Write header record: length="<<text.length()<<", compress="<<compress<<endl;
+
+ // First compress the text, then write out the bookmarks and - if existing - also the annotations
+ int len=text.length();
+ int start=0,reclen=0;
+ int recnum=0;
+ while (start<len)
+ {
+ reclen=min(len-start, PilotDOCEntry::TEXT_SIZE);
+ DEBUGKPILOT << "Record #"<<recnum<<", reclen="<<reclen<<", compress="<<compress<<endl;
+
+ PilotDOCEntry recText;
+// recText.setText(text.mid(start, reclen), reclen);
+ recText.setText(text.mid(start, reclen));
+// if (compress)
+ recText.setCompress(compress);
+ PilotRecord*textRec=recText.pack();
+ docdb->writeRecord(textRec);
+ ++recnum;
+ start+=reclen;
+ KPILOT_DELETE(textRec);
+ }
+
+ recnum=0;
+ // Finally, write out the bookmarks
+ for (bmk = pdbBookmarks.first(); bmk; bmk = pdbBookmarks.next())
+// for (bmkList::const_iterator it=pdbBookmarks.begin(); it!=pdbBookmarks.end(); ++it)
+ {
+ ++recnum;
+ DEBUGKPILOT << "Bookmark #"<<recnum<<", Name="<<bmk->bmkName.left(20)<<", Position="<<bmk->position<<endl;
+
+ PilotDOCBookmark bmkEntry;
+ bmkEntry.pos=bmk->position;
+ strncpy(&bmkEntry.bookmarkName[0], bmk->bmkName.latin1(), 16);
+ PilotRecord*bmkRecord=bmkEntry.pack();
+ docdb->writeRecord(bmkRecord);
+ KPILOT_DELETE(bmkRecord);
+ }
+
+ pdbBookmarks.clear();
+ fBookmarks.clear();
+
+ return true;
+}
+
+
+
+bool DOCConverter::convertPDBtoTXT()
+{
+ FUNCTIONSETUP;
+ if (txtfilename.isEmpty()) {
+ emit logError(i18n("No filename set for the conversion"));
+ return false;
+ }
+
+ if (!docdb) {
+ emit logError(i18n("Unable to open Database for reading"));
+ return false;
+ }
+
+ // The first record of the db is the document header containing information about the doc db
+ PilotRecord*headerRec = docdb->readRecordByIndex(0);
+ if (!headerRec)
+ {
+ emit logError(i18n("Unable to read database header for database %1.").arg(docdb->dbPathName()));
+ KPILOT_DELETE(docdb);
+ return false;
+ }
+ PilotDOCHead header(headerRec);
+ KPILOT_DELETE(headerRec);
+
+ DEBUGKPILOT<<"Database "<<docdb->dbPathName()<<" has "<<header.numRecords<<" text records, "<<endl
+ <<" total number of records: "<<docdb->recordCount()<<endl
+ <<" position="<<header.position<<endl
+ <<" recordSize="<<header.recordSize<<endl
+ <<" spare="<<header.spare<<endl
+ <<" storyLen="<<header.storyLen<<endl
+// <<" textRecordSize="<<header.textRecordSize<<endl
+ <<" version="<<header.version<<endl;
+
+ // next come the header.numRecords real document records (might be compressed, see the version flag in the header)
+ QFile docfile(txtfilename);
+ if (!docfile.open(IO_WriteOnly))
+ {
+ emit logError(i18n("Unable to open output file %1.").arg(txtfilename));
+ KPILOT_DELETE(docdb);
+ return false;
+ }
+ QString doctext;
+ for (int i=1; i<header.numRecords+1; ++i)
+ {
+ PilotRecord*rec=docdb->readRecordByIndex(i);
+ if (rec)
+ {
+ PilotDOCEntry recText(rec, header.version==DOC_COMPRESSED);
+ doctext.append(recText.getText());
+ DEBUGKPILOT<<"Record "<<i<<endl;
+ KPILOT_DELETE(rec);
+ } else {
+ emit logMessage(i18n("Could not read text record #%1 from Database %2").arg(i).arg(docdb->dbPathName()));
+ }
+ }
+
+ // After the document records possibly come a few bookmark records, so read them in and put them in a separate bookmark file.
+ // for the ztxt conduit there might be annotations after the bookmarks, so the upper bound needs to be adapted.
+ int upperBmkRec=docdb->recordCount();
+ bmkSortedList bmks;
+ bmks.setAutoDelete(TRUE);
+ for (int i=header.numRecords+1; i<upperBmkRec; ++i)
+ {
+ PilotRecord*rec=docdb->readRecordByIndex(i);
+ if (rec)
+ {
+ PilotDOCBookmark bookie(rec);
+ docBookmark*bmk=new docBookmark(QString::fromLatin1(bookie.bookmarkName), bookie.pos);
+ bmks.append(bmk);
+ KPILOT_DELETE(rec);
+ } else {
+ emit logMessage(i18n("Could not read bookmark record #%1 from Database %2").arg(i).arg(docdb->dbPathName()));
+ }
+ }
+ // TODO: Sort the list of bookmarks according to their position
+ docBookmark::compare_pos=true;
+ bmks.sort();
+
+ if ((fBmkTypes & eBmkFile) && (bmks.count()>0))
+ {
+ QString bmkfilename = docfile.name();
+ if (bmkfilename.endsWith(CSL1(".txt"))){
+ bmkfilename.remove(bmkfilename.length()-4, 4);
+ }
+ bmkfilename+=CSL1(PDBBMK_SUFFIX);
+ QFile bmkfile(bmkfilename);
+ if (!bmkfile.open(IO_WriteOnly))
+ {
+ emit logError(i18n("Unable to open file %1 for the bookmarks of %2.")
+ .arg(bmkfilename).arg(docdb ->dbPathName()));
+ }
+ else
+ {
+ DEBUGKPILOT<<"Writing "<<upperBmkRec-header.numRecords<<
+ "("<<upperBmkRec<<") bookmarks to file "<<bmkfilename<<endl;
+ QTextStream bmkstream(&bmkfile);
+ for (docBookmark*bmk=bmks.first(); bmk; bmk=bmks.next())
+ {
+ bmkstream<<bmk->position<<", "<<bmk->bmkName<<endl;
+ }
+ //bmkstream.close();
+ bmkfile.close();
+ }
+ }
+ if (fBmkTypes & eBmkInline)
+ {
+ for (docBookmark*bmk=bmks.last(); bmk; bmk=bmks.prev())
+ {
+ doctext.insert(bmk->position, QString(CSL1("<*") +
+ bmk->bmkName +
+ CSL1("*>")));
+ }
+ }
+
+ // Finally, write the actual text out to the file.
+ QTextStream docstream(&docfile);
+ docstream<<doctext;
+ //docstream.close();
+ docfile.close();
+ docdb->cleanup();
+ // reset all records to unchanged. I don't know if this is really such a wise idea?
+ docdb->resetSyncFlags();
+ return true;
+}
+
+
diff --git a/kpilot/conduits/docconduit/DOC-converter.h b/kpilot/conduits/docconduit/DOC-converter.h
new file mode 100644
index 000000000..f3747ea1d
--- /dev/null
+++ b/kpilot/conduits/docconduit/DOC-converter.h
@@ -0,0 +1,183 @@
+#ifndef _DOC_CONVERTER_H
+#define _DOC_CONVERTER_H
+/* DOC-converter.h KPilot
+**
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+
+#define DOC_UNCOMPRESSED 1
+#define DOC_COMPRESSED 2
+
+
+#define BMK_SUFFIX ".bmk"
+#define PDBBMK_SUFFIX ".bm"
+
+#include <qptrlist.h>
+#include <qobject.h>
+
+class PilotDatabase;
+
+
+/****************************************************************************************************
+ * various bookmark classes. Most important is the bmkList findMatches(QString, bmkList &) function,
+ * which needs to return a list of all bookmarks found for the given bookmark expression.
+ * A bookmark usually consists of a bookmark text and an offset into the text document.
+ ****************************************************************************************************/
+
+class docBookmark;
+#define bmkList QPtrList<docBookmark>
+#define bmkSortedList QSortedList<docBookmark>
+
+class docBookmark {
+public:
+ static bool compare_pos;
+ docBookmark():bmkName(), position(0) { };
+ docBookmark(QString name, long int pos):bmkName(name), position(pos) { };
+ docBookmark(const docBookmark &bmk):bmkName(bmk.bmkName),position(bmk.position){};
+ virtual ~ docBookmark() { };
+ virtual int findMatches(QString, bmkList &fBookmarks) {
+ FUNCTIONSETUP;
+ fBookmarks.append(new docBookmark(*this));
+ return 1;
+ };
+
+ QString bmkName;
+ long int position;
+};
+
+class docMatchBookmark:public docBookmark {
+ public:
+ docMatchBookmark():docBookmark() { from=0; to=100;};
+ docMatchBookmark(QString pattrn, int options=0):docBookmark(),
+ pattern(pattrn), opts(options) { from=0; to=100; };
+ docMatchBookmark(QString pattrn, QString bmkname,
+ int options=0):docBookmark(bmkname, 0), pattern(pattrn),
+ opts(options) { from=0; to=100; };
+ virtual ~ docMatchBookmark() { };
+
+ virtual int findMatches(QString, bmkList &fBookmarks);
+ QString pattern;
+ int opts;
+ int from, to;
+};
+
+class docRegExpBookmark:public docMatchBookmark {
+ public:
+ docRegExpBookmark():docMatchBookmark() { capSubexpression=-1;};
+ docRegExpBookmark(QString regexp, int cap=0,
+ int options=0):docMatchBookmark(regexp, options) {capSubexpression=cap; };
+ docRegExpBookmark(QString pattrn, QString bmkname,
+ int options=0):docMatchBookmark(pattrn, bmkname, options) { capSubexpression=-1; };
+ virtual ~ docRegExpBookmark() { };
+
+ virtual int findMatches(QString, bmkList &fBookmarks);
+ int capSubexpression;
+};
+
+
+/*************************************************************************************************************
+ * The converter class that does the real work for us.
+ *************************************************************************************************************/
+
+class DOCConverter:public QObject {
+Q_OBJECT
+private:
+ PilotDatabase * docdb;
+ QString txtfilename;
+ QString bmkfilename;
+ bool compress;
+
+ bmkList fBookmarks;
+public:
+ enum eSortBookmarksEnum
+ {
+ eSortNone,
+ eSortPos,
+ eSortName
+ } eSortBookmarks;
+
+public:
+ DOCConverter(QObject *parent=0L, const char *name=0L);
+ virtual ~ DOCConverter();
+
+ QString readText();
+ void setTXTpath(QString path, QString file);
+ void setTXTpath(QString filename);
+ void setPDB(PilotDatabase * dbi);
+ QString txtFilename() const {return txtfilename;}
+ QString bmkFilename() const {return bmkfilename;}
+ void setBmkFilename(QString bmkf) { bmkfilename=bmkf;}
+
+ bool getCompress() const { return compress; };
+ void setCompress(bool newcomp) {compress=newcomp;};
+
+ bool convertTXTtoPDB();
+ bool convertPDBtoTXT();
+
+ int setBookmarks(bmkList bookmarks) {
+ fBookmarks = bookmarks;
+ return fBookmarks.count();
+ };
+ int clearBookmarks() {
+ fBookmarks.clear();
+ return fBookmarks.count();
+ };
+ int addBookmark(docBookmark*bookmark) {
+ fBookmarks.append(bookmark);
+ return fBookmarks.count();
+ };
+
+ int findBmkEndtags(QString &, bmkList&);
+ int findBmkInline(QString &, bmkList&);
+ int findBmkFile(QString &, bmkList&);
+
+
+ void setSort(enum eSortBookmarksEnum sort) {eSortBookmarks=sort;}
+ enum eSortBookmarksEnum getSort() {return eSortBookmarks;}
+
+ enum eBmkTypesEnum {
+ eBmkNone = 0,
+ eBmkFile = 1,
+ eBmkInline = 2,
+ eBmkEndtags = 4,
+ eBmkDefaultBmkFile = 8
+ } fBmkTypes;
+ void setBookmarkTypes(int types) {
+ fBmkTypes = (eBmkTypesEnum) types;
+ };
+
+protected:
+ int findBookmarks();
+
+private:
+ void readConfig();
+signals:
+ void logMessage(const QString &);
+ void logError(const QString &);
+};
+
+#endif
diff --git a/kpilot/conduits/docconduit/Icons/CMakeLists.txt b/kpilot/conduits/docconduit/Icons/CMakeLists.txt
new file mode 100644
index 000000000..3d1034d44
--- /dev/null
+++ b/kpilot/conduits/docconduit/Icons/CMakeLists.txt
@@ -0,0 +1,3 @@
+
+kde3_install_icons_custom( hicolor )
+
diff --git a/kpilot/conduits/docconduit/Icons/Makefile.am b/kpilot/conduits/docconduit/Icons/Makefile.am
new file mode 100644
index 000000000..f371f4aed
--- /dev/null
+++ b/kpilot/conduits/docconduit/Icons/Makefile.am
@@ -0,0 +1,7 @@
+METASOURCES = AUTO
+
+kpalmdocicondir = $(kde_datadir)/kpilot/icons
+kpalmdocicon_ICON = kpalmdoc
+
+KDE_ICON = kpalmdoc
+
diff --git a/kpilot/conduits/docconduit/Icons/cr16-app-kpalmdoc.png b/kpilot/conduits/docconduit/Icons/cr16-app-kpalmdoc.png
new file mode 100644
index 000000000..0f5fb75d5
--- /dev/null
+++ b/kpilot/conduits/docconduit/Icons/cr16-app-kpalmdoc.png
Binary files differ
diff --git a/kpilot/conduits/docconduit/Icons/cr22-app-kpalmdoc.png b/kpilot/conduits/docconduit/Icons/cr22-app-kpalmdoc.png
new file mode 100644
index 000000000..d93aa4bae
--- /dev/null
+++ b/kpilot/conduits/docconduit/Icons/cr22-app-kpalmdoc.png
Binary files differ
diff --git a/kpilot/conduits/docconduit/Icons/cr32-app-kpalmdoc.png b/kpilot/conduits/docconduit/Icons/cr32-app-kpalmdoc.png
new file mode 100644
index 000000000..09a7020b5
--- /dev/null
+++ b/kpilot/conduits/docconduit/Icons/cr32-app-kpalmdoc.png
Binary files differ
diff --git a/kpilot/conduits/docconduit/Icons/cr48-app-kpalmdoc.png b/kpilot/conduits/docconduit/Icons/cr48-app-kpalmdoc.png
new file mode 100644
index 000000000..41cb3b9b1
--- /dev/null
+++ b/kpilot/conduits/docconduit/Icons/cr48-app-kpalmdoc.png
Binary files differ
diff --git a/kpilot/conduits/docconduit/Makefile.am b/kpilot/conduits/docconduit/Makefile.am
new file mode 100644
index 000000000..77df2b61b
--- /dev/null
+++ b/kpilot/conduits/docconduit/Makefile.am
@@ -0,0 +1,38 @@
+### Makefile for KPilot's doc conduit
+###
+### The doc conduit is Copyright (C) 2002 by Reinhold Kainhofer
+### the files makedoc9.{h,cpp} are also Copyright (C) 2000 by Pat Beirne
+
+SUBDIRS = Icons
+
+INCLUDES= $(PISOCK_INCLUDE) -I$(top_srcdir)/kpilot/lib $(all_includes)
+METASOURCES = AUTO
+
+
+servicedir = $(kde_servicesdir)
+service_DATA = doc_conduit.desktop
+
+noinst_LTLIBRARIES = libpalmdoc_shared.la
+kde_module_LTLIBRARIES = conduit_doc.la
+bin_PROGRAMS = kpalmdoc
+
+libpalmdoc_shared_la_SOURCES = makedoc9.cc pilotDOCHead.cc pilotDOCEntry.cc pilotDOCBookmark.cc DOC-converter.cc
+
+conduit_doc_la_SOURCES = docconduitSettings.kcfgc doc-factory.cc doc-setup.cc doc-conduit.cc doc-setupdialog.ui doc-conflictdialog.cc
+conduit_doc_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+conduit_doc_la_LIBADD = ../../lib/libkpilot.la libpalmdoc_shared.la \
+ $(LIB_KDEUI) $(LIB_KFILE)
+
+##libpalmdoc_shared.la
+
+kpalmdoc_SOURCES = kpalmdocSettings.kcfgc kpalmdoc_dlgbase.ui kpalmdoc_dlg.cc kpalmdoc.cpp
+kpalmdoc_LDFLAGS = $(PISOCK_LDFLAGS) $(all_libraries) $(KDE_RPATH)
+kpalmdoc_LDADD = $(LIB_KFILE) $(PISOCK_LIB) ../../lib/libkpilot.la libpalmdoc_shared.la
+
+xdg_apps_DATA = kpalmdoc.desktop
+servicetypedir = $(kde_servicetypesdir)
+kde_kcfg_DATA = docconduit.kcfg kpalmdoc.kcfg
+
+update_DATA = kpalmdoc.upd
+updatedir = $(kde_datadir)/kconf_update
+
diff --git a/kpilot/conduits/docconduit/bmkSpecification.txt b/kpilot/conduits/docconduit/bmkSpecification.txt
new file mode 100644
index 000000000..f8a68d961
--- /dev/null
+++ b/kpilot/conduits/docconduit/bmkSpecification.txt
@@ -0,0 +1,199 @@
+KPilot PalmDoc Conduit bookmark Specification
+=============================================
+
+(c) 2003 Reinhold Kainhofer, [email protected]
+
+This document is licensed under the FDL (Free Documentation License)
+as published by the FSF. Any version of the FDL can be applied
+at your convenience.
+
+
+
+
+The PalmDoc conduit has three ways to indicate bookmarks for a text:
+ -) Inline tags of the form <* bookmarkname *>
+ -) Endtags of the form <bookmarkname> at the end of the document
+ -) Regular expressions in a separate textname.bmk file
+ (textname.bmk ist the filename of the text with the .txt replaced by .bmk)
+
+
+In the design of the .bmk file, I tried to stay close to the
+syntac of MakeDocJ bookmark files, but it turned out that I
+needed to extend the syntax a little. Also, MakeDocJ uses Java
+RegExps, while the PalmDoc conduit uses the QRegExp, which have
+some slight differences (especially concerning the ^ and $
+patterns as well as backreferences). So if you used MakeDocJ,
+the .bmk file syntax will be quite familiar, but you will still
+have to adapt your bookmark files for Qt regular expressions
+instead of Java regular expressions
+
+
+
+1) INLINE TAGS
+
+Whenever a tag of the form <* someText *> appears in the text,
+this sequence is removed from the text, and a bookmark is set
+there with the bookmark name "someText" (the part between the
+<* and the *>).
+
+
+2) ENDTAGS
+
+If the text ends with tags of the form <someText>, the string
+in braces is used as bookmark name, and wherever it appears in
+the text, a bookmark is set.
+After the > any number of whitespace is allowed, but no other
+characters like letters, numbers, or punctuation. Also, inside
+the braces no line break must occur. The conduit searches the
+text from the end and if it finds a line break inside a <...>
+sequence, the tag and everything before it is assumed to belong
+to the text and doesn't form a bookmark tag.
+Between endtags any number of whitespace (spaces, tabs, line
+feeds etc.) is allowed.
+
+As an example, assume you have a text ending in:
+... the bad guy was punished, and they lived happily
+ever after!
+<Tag with
+line feed>
+ <bad guy> <princess>
+<married>
+
+The conduit starts at the end, ignores all whitespace between
+the tags, so it finds the tags "married", "princess", and "bad guy".
+The "Tag with line feed" has a line feed, so it is assumed to belong
+to the text.
+Assume now you have a text ending in:
+... the bad guy was punished, and they lived happily
+ever after!
+<bad guy> The End <princess>
+<married>
+
+Here, only "married" and "princess" are found as bookmarks. Because
+of the letters before the "princess" tags, the search for the
+bookmarks ends at the letter "d" of "The End" (the conduit starts
+from the end and moves backward until it finds some text which
+cannot be seen as a endtag.
+
+
+
+
+3) REGULAR EXPRESSIONS IN A SEPARATE FILE
+
+This is by far the most complex way to specify bookmarks, but
+it is also the mose powerful.
+If you have a text with filename "My fairy tale.txt", the
+bookmarks will be specified in a file called "My fairy tale.bmk"
+(just the text filename with the .txt replaced by .bmk). This
+file contains the bookmark definitions, one in each line. Lines
+starting with a # are seen as comments, and empty lines are also
+ignored.
+
+
+In the .bmk file, each bookmark line has one of the following syntaces
+(I will explain all fields later on). Fields in [..] are optional:
+
+bmkName
+bmkPosition, bmkName
++, bmkPatternRegExp[, bmkNameAsString[, firstIncludedBmk[, lastIncludedBmk]]]
++, bmkPatternRegExp[, bmkNameIndexOfSubexpression[, firstIncludedBmk[, lastIncludedBmk]]]
+-, bmkPatternRegExp[, bmkNameAsString]
+-, bmkPatternRegExp[, bmkNameIndexOfSubexpression]
+
+ If the first field is a string, it is used as the bookmark name
+and pattern to search for.
+ If the first field is a number, it means the position of the
+bookmark, and the second field is the name of the bookmark.
+ If the first field is either + or -, the second field gives
+a regular expression that is used to find the position of the
+bookmark. If the first field is a -, the search is done only
+once and only the first match will be added as bookmark. If
+the first field is a +, the search is done until the regular
+expression can no longer be found (the fourth and fifth fields
+can be used to include only a certain range of hits). If there
+is a third field, and it is a string, it gives the name of the
+bookmark as a regular expression (i.e. \1 are replaced by the
+first subexpression of the search, where subexpressions are
+specified by round brackets in the regexp of the second field).
+If there is a third field, and it is a number, it gives the index
+of the subexpression of bmkPatternRegExp that is used as the
+bookmark name.
+If there is no third field, the whole matched text will be used
+as bookmark name.
+The optional fourth and fifth fields can be used to set bookmarks
+only after the first few ocurrences of the regexp in the text, and
+to stop the search after the expression has been found a certain
+number of times.
+
+
+
+If the PDB->PC sync is set up to store the bookmarks in a bookmark file,
+it will create a file "My fairy tale.bm" (no "k") with entries of the form
+position,bmkName
+The .bmk file will be used if it exists, but if no .bmk file exists, the .bm file
+will be used. This way you can override the bookmark settings, while
+at the same time the PDB->TXT sync does not destroy your possibly
+existing .bmk file.
+
+
+
+Examples:
+
+1) Imagine you have a line like:
+frog princess
+In this case, the text is searched for "frog princess", and a
+bookmark is set whenever "frog princess" occurs in the text.
+The name of each of these bookmarks will be "frog princess".
+
+2) A bookmark line:
+55, Bookmark at offset 55
+Here, a bookmark will be set at offset 55 (55th character of
+the text), and it will have the name "Bookmark at offs" (truncated
+to 16 characters)
+
+3) A bookmark line
+-,Chapter \d+
+causes a bookmark to be set at the first ocurrence of "Chapter XXX",
+where XXX denotes one or more digits. The bookmark name will be
+"Chapter XXX" (XXX replaced by the actual digits).
+
+4) A bookmark line
++,Chapter \d+
+causes bookmarks to be set wherever "Chapter XXX" (XXX being one
+or more digits) appears in the text. The bookmark name will again
+be "Chapter XXX", but the search does not stop after the first hit.
+
+5) A bookmark line
++,\n\s*(Chapter \d+)\D+, 1
+causes a bookmark to be set whenever a new line starts with
+"Chapter XXX" (whitespace is allowed before the "Chapter"), and
+uses the first subexpression in (..) as the bookmark name. If you
+have a passage
+ Chapter 15: here it starts
+The regular expression will match, so a bookmark will be set there
+and the subexpression "Chapter 15" (which matches the (Chapter \d+) )
+will be used as bookmark text.
+
+6) A bookmark line
++,\n\s*Part (\d+),\1\. part
+sets a bookmark whenever a line starts with "Part XXX". The XXX
+will be stored as the first matched subexpression. The third field
+"\1\. part" is the regular expression for the bookmark name, where
+\1 is replaced by the first matched subexpression of the search (XXX
+in this case). So if a line starts with " Part 17: ", the bookmark
+name will be "17. part".
+
+7) A bookmark line
++,Table (\d+): ,\1\. Tabelle,5,25
+will match whenever "Table XXX: " appears in the text, and the bookmark
+name will be "XXX. Tabelle". However, the fourth field means that the
+first four hits are ignored (the 5th hit is the first hit to be included
+as a bookmark), and the fifth field means that all further hits after the
+25th will be ignored, too.
+
+8) In law texts, I use a regular expression
++,\n *(�\.? *\d+[a-z]?\.?) +, 1
+to search for all paragraphs starting like "�. 15. " or " �23 ", and set
+a bookmark there using only the part from the � to the last digit or the
+full stop after the last digit (the pattern between the (), in our two
+cases the bookmark names will be "�. 15." and "�23" ).
diff --git a/kpilot/conduits/docconduit/doc-conduit.cc b/kpilot/conduits/docconduit/doc-conduit.cc
new file mode 100644
index 000000000..eee36080c
--- /dev/null
+++ b/kpilot/conduits/docconduit/doc-conduit.cc
@@ -0,0 +1,1018 @@
+/* KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** The doc conduit synchronizes text files on the PC with DOC databases on the Palm
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected].
+*/
+
+
+// naming of the bookmark file:
+// PDB->TXT: convert bookmarks to a .bm file
+// TXT->PDB: If a .bmk file exists, use it, otherwise use the .bm file (from the PDB->TXT conversion)
+// This way, the bookmark file is not overwritten, a manual bookmark file overrides, but the bookmarks from the handheld are still available
+
+
+#include "options.h"
+#include "doc-conduit.moc"
+
+#include <qtimer.h>
+#include <qdir.h>
+
+#include <kconfig.h>
+#include <kmdcodec.h>
+
+#include <pilotLocalDatabase.h>
+#include <pilotSerialDatabase.h>
+
+#include "doc-factory.h"
+#include "doc-conflictdialog.h"
+#include "DOC-converter.h"
+#include "pilotDOCHead.h"
+#include "docconduitSettings.h"
+
+
+// Something to allow us to check what revision
+// the modules are that make up a binary distribution.
+extern "C"
+{
+unsigned long version_conduit_doc = Pilot::PLUGIN_API;
+}
+
+QString dirToString(eSyncDirectionEnum dir) {
+ switch(dir) {
+// case eSyncAll: return "eSyncAll";
+ case eSyncPDAToPC: return CSL1("eSyncPDAToPC");
+ case eSyncPCToPDA: return CSL1("eSyncPCToPDA");
+ case eSyncNone: return CSL1("eSyncNone");
+ case eSyncConflict: return CSL1("eSyncConflict");
+ case eSyncDelete: return CSL1("eSyncDelete");
+ default: return CSL1("ERROR");
+ }
+}
+
+
+/*********************************************************************
+ C O N S T R U C T O R
+ *********************************************************************/
+
+
+DOCConduit::DOCConduit(KPilotLink * o,
+ const char *n, const QStringList & a):ConduitAction(o, n, a)
+{
+ FUNCTIONSETUP;
+ fConduitName=i18n("DOC");
+}
+
+
+
+DOCConduit::~DOCConduit()
+{
+ FUNCTIONSETUP;
+}
+
+
+bool DOCConduit::isCorrectDBTypeCreator(DBInfo dbinfo) {
+ return dbinfo.type == dbtype() && dbinfo.creator == dbcreator();
+}
+const unsigned long DOCConduit::dbtype() {
+ return get_long(DOCConduitFactory::dbDOCtype);
+}
+const unsigned long DOCConduit::dbcreator() {
+ return get_long(DOCConduitFactory::dbDOCcreator);
+}
+
+
+
+/*********************************************************************
+ L O A D I N G T H E D A T A
+ *********************************************************************/
+
+
+
+void DOCConduit::readConfig()
+{
+ FUNCTIONSETUP;
+ DOCConduitSettings::self()->readConfig();
+
+ eConflictResolution = (enum eSyncDirectionEnum) (DOCConduitSettings::conflictResolution() );
+ fTXTBookmarks = DOCConverter::eBmkNone;
+ if ( DOCConduitSettings::convertBookmarks() )
+ {
+ if ( DOCConduitSettings::bmkFileBookmarks() )
+ fTXTBookmarks |= DOCConverter::eBmkFile;
+ if ( DOCConduitSettings::inlineBookmarks() )
+ fTXTBookmarks |= DOCConverter::eBmkInline;
+ if ( DOCConduitSettings::endtagBookmarks() )
+ fTXTBookmarks |= DOCConverter::eBmkEndtags;
+ }
+
+ eSyncDirection = (enum eSyncDirectionEnum)(DOCConduitSettings::syncDirection() );
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Settings "
+ << " tXTDirectory=" << DOCConduitSettings::tXTDirectory()
+ << " pDBDirectory=" << DOCConduitSettings::pDBDirectory()
+ << " keepPDBLocally=" << DOCConduitSettings::keepPDBsLocally()
+ << " eConflictResolution=" << eConflictResolution
+ << " tXTBookmarks=" << fTXTBookmarks
+ << " pDBBookmarks=" << DOCConduitSettings::bookmarksToPC()
+ << " compress=" << DOCConduitSettings::compress()
+ << " eSyncDirection=" << eSyncDirection << endl;
+#endif
+}
+
+
+
+bool DOCConduit::pcTextChanged(QString txtfn)
+{
+ FUNCTIONSETUP;
+ // How do I find out if a text file has changed shince we last synced it??
+ // Use KMD5 for now. If I realize it is too slow, then I have to go back to comparing modification times
+ // if there is no config setting yet, assume the file has been changed. the md5 sum will be written to the config file after the sync.
+ QString oldDigest=DOCConduitSettings::self()->config()->readEntry(txtfn);
+ if (oldDigest.length()<=0)
+ {
+ return true;
+ }
+#ifdef DEBUG
+ DEBUGKPILOT<<"Old digest is "<<oldDigest<<endl;
+#endif
+
+ KMD5 docmd5;
+ QFile txtfile(txtfn);
+ if (txtfile.open(IO_ReadOnly)){
+ docmd5.update(txtfile);
+ QString thisDigest(docmd5.hexDigest() /* .data() */);
+#ifdef DEBUG
+ DEBUGKPILOT<<"New digest is "<<thisDigest<<endl;
+#endif
+ return (thisDigest.length()<=0) || (thisDigest!=oldDigest);
+ } else {
+ // File does not exist. This should actually never happen. Anyways, just return true to indicate it has changed.
+ // doSync should detect this and delete the doc from the handheld.
+ return true;
+ }
+ return false;
+}
+
+
+
+bool DOCConduit::hhTextChanged(PilotDatabase*docdb)
+{
+ FUNCTIONSETUP;
+ if (!docdb) return false;
+
+ PilotRecord *firstRec = docdb->readRecordByIndex(0);
+ PilotDOCHead docHeader(firstRec);
+ KPILOT_DELETE(firstRec);
+
+ int storyRecs = docHeader.numRecords;
+
+ // determine the index of the next modified record (does it lie
+ // beyond the actual text records?)
+ int modRecInd=-1;
+ PilotRecord*modRec=docdb->readNextModifiedRec(&modRecInd);
+#ifdef DEBUG
+ DEBUGKPILOT<<"Index of first changed record: "<<modRecInd<<endl;
+#endif
+
+ KPILOT_DELETE(modRec);
+ // if the header record was changed, find out which is the first changed
+ // real document record:
+ if (modRecInd==0) {
+ modRec=docdb->readNextModifiedRec(&modRecInd);
+#ifdef DEBUG
+ DEBUGKPILOT<<"Reread Index of first changed records: "<<modRecInd<<endl;
+#endif
+ KPILOT_DELETE(modRec);
+ }
+
+ // The record index starts with 0, so only a negative number means
+ // no modified record was found
+ if (modRecInd >= 0) {
+#ifdef DEBUG
+ DEBUGKPILOT<<"Handheld side has changed, condition="<<
+ ((!DOCConduitSettings::ignoreBmkChanges()) || (modRecInd <= storyRecs))<<endl;
+#endif
+ if ((!DOCConduitSettings::ignoreBmkChanges()) || (modRecInd <= storyRecs))
+ return true;
+ } else {
+#ifdef DEBUG
+ DEBUGKPILOT<<"Handheld side has NOT changed!"<<endl;
+#endif
+ return false;
+ }
+ return false;
+}
+
+
+
+/*********************************************************************
+ * Helper functions
+ ********************************************************************/
+
+QString DOCConduit::constructPDBFileName(QString name) {
+ FUNCTIONSETUP;
+ QString fn;
+ QDir dr(DOCConduitSettings::pDBDirectory());
+ QFileInfo pth(dr, name);
+ if (!name.isEmpty()) fn=pth.absFilePath()+CSL1(".pdb");
+ return fn;
+}
+QString DOCConduit::constructTXTFileName(QString name) {
+ FUNCTIONSETUP;
+ QString fn;
+ QDir dr( DOCConduitSettings::tXTDirectory() );
+ QFileInfo pth(dr, name);
+ if (!name.isEmpty()) fn=pth.absFilePath()+CSL1(".txt");
+ return fn;
+}
+
+
+
+
+
+/*********************************************************************
+ S Y N C S T R U C T U R E
+ *********************************************************************/
+
+
+
+
+
+/* virtual */ bool DOCConduit::exec()
+{
+ FUNCTIONSETUP;
+
+ readConfig();
+ dbnr=0;
+
+ emit logMessage(i18n("Searching for texts and databases to synchronize"));
+
+ QTimer::singleShot(0, this, SLOT(syncNextDB()));
+ return true;
+}
+
+
+
+bool DOCConduit::doSync(docSyncInfo &sinfo)
+{
+ FUNCTIONSETUP;
+ bool res=false;
+
+ if (sinfo.direction==eSyncDelete) {
+ if (!sinfo.txtfilename.isEmpty()) {
+ if (!QFile::remove(sinfo.txtfilename)) {
+ WARNINGKPILOT << "Unable to delete the text file " << sinfo.txtfilename << " on the PC" << endl;
+ }
+ QString bmkfilename = sinfo.txtfilename;
+ if (bmkfilename.endsWith(CSL1(".txt"))){
+ bmkfilename.remove(bmkfilename.length()-4, 4);
+ }
+ bmkfilename+=CSL1(PDBBMK_SUFFIX);
+ if (!QFile::remove(bmkfilename)) {
+#ifdef DEBUG
+ DEBUGKPILOT<<"Could not remove bookmarks file "<<bmkfilename<<" for database "<<sinfo.handheldDB<<endl;
+#endif
+ }
+ }
+ if (!sinfo.pdbfilename.isEmpty() && DOCConduitSettings::keepPDBsLocally() ) {
+ PilotLocalDatabase*database=new PilotLocalDatabase(DOCConduitSettings::pDBDirectory(),
+ QString::fromLatin1(sinfo.dbinfo.name), false);
+ if (database) {
+ if ( database->deleteDatabase() !=0 ) {
+ WARNINGKPILOT << "Unable to delete database " << sinfo.dbinfo.name << " on the PC" << endl;
+ }
+ KPILOT_DELETE(database);
+ }
+ }
+ if (!DOCConduitSettings::localSync()) {
+ PilotDatabase *database=deviceLink()->database( sinfo.dbinfo.name );
+ if ( database->deleteDatabase() !=0 ) {
+ WARNINGKPILOT << "Unable to delete database " << sinfo.dbinfo.name << " from the handheld" << endl;
+ }
+ KPILOT_DELETE(database);
+ }
+ return true;
+ }
+ // preSyncAction should initialize the custom databases/files for the
+ // specific action chosen for this db and return a pointer to a docDBInfo
+ // instance which points either to a local database or a database on the handheld.
+ PilotDatabase *database = preSyncAction(sinfo);
+
+ if (database && ( !database->isOpen() ) ) {
+#ifdef DEBUG
+ DEBUGKPILOT<<"Database "<<sinfo.dbinfo.name<<" does not yet exist. Creating it:"<<endl;
+#endif
+ if (!database->createDatabase(dbcreator(), dbtype()) ) {
+#ifdef DEBUG
+ DEBUGKPILOT<<"Failed"<<endl;
+ emit logMessage(i18n("Database created."));
+#endif
+ }
+ }
+
+ if (database && database->isOpen()) {
+ DOCConverter docconverter;
+ connect(&docconverter, SIGNAL(logError(const QString &)), SIGNAL(logError(const QString &)));
+ connect(&docconverter, SIGNAL(logMessage(const QString &)), SIGNAL(logMessage(const QString &)));
+
+ docconverter.setTXTpath( DOCConduitSettings::tXTDirectory(), sinfo.txtfilename );
+ docconverter.setPDB(database);
+ docconverter.setCompress(DOCConduitSettings::compress());
+
+ switch (sinfo.direction) {
+ case eSyncPDAToPC:
+ docconverter.setBookmarkTypes(DOCConduitSettings::bookmarksToPC());
+ res = docconverter.convertPDBtoTXT();
+ break;
+ case eSyncPCToPDA:
+ docconverter.setBookmarkTypes(fTXTBookmarks);
+ res = docconverter.convertTXTtoPDB();
+ break;
+ default:
+ break;
+ }
+
+ // Now calculate the md5 checksum of the PC text and write it to the config file
+ if (res)
+ {
+ KMD5 docmd5;
+ QFile txtfile(docconverter.txtFilename());
+ if (txtfile.open(IO_ReadOnly)) {
+ docmd5.update(txtfile);
+ QString thisDigest(docmd5.hexDigest() /* .data() */);
+ DOCConduitSettings::self()->config()->writeEntry(docconverter.txtFilename(), thisDigest);
+ DOCConduitSettings::self()->config()->sync();
+#ifdef DEBUG
+ DEBUGKPILOT<<"MD5 Checksum of the text "<<sinfo.txtfilename<<" is "<<thisDigest<<endl;
+#endif
+ } else {
+#ifdef DEBUG
+ DEBUGKPILOT<<"couldn't open file "<<docconverter.txtFilename()<<" for reading!!!"<<endl;
+#endif
+ }
+ }
+
+ if (!postSyncAction(database, sinfo, res))
+ emit logError(i18n("Unable to install the locally created PalmDOC %1 to the handheld.")
+ .arg(QString::fromLatin1(sinfo.dbinfo.name)));
+ if (!res)
+ emit logError(i18n("Conversion of PalmDOC \"%1\" failed.")
+ .arg(QString::fromLatin1(sinfo.dbinfo.name)));
+// disconnect(&docconverter, SIGNAL(logError(const QString &)), SIGNAL(logError(const QString &)));
+// disconnect(&docconverter, SIGNAL(logMessage(const QString &)), SIGNAL(logMessage(const QString &)));
+// KPILOT_DELETE(database);
+ }
+ else
+ {
+ emit logError(i18n("Unable to open or create the database %1.")
+ .arg(QString::fromLatin1(sinfo.dbinfo.name)));
+ }
+ return res;
+}
+
+
+/** syncNextDB walks through all PalmDoc databases on the handheld and decides if they are supposed to be synced to the PC.
+ * syncNextDB and syncNextTXT fist build the list of all PalmDoc texts, and then the method syncDatabases does the actual sync. */
+void DOCConduit::syncNextDB() {
+ FUNCTIONSETUP;
+ DBInfo dbinfo;
+
+ if (eSyncDirection==eSyncPCToPDA || fHandle->findDatabase(NULL, &dbinfo, dbnr, dbtype(), dbcreator() /*, cardno */ ) < 0)
+ {
+ // no more databases available, so check for PC->Palm sync
+ QTimer::singleShot(0, this, SLOT(syncNextTXT()));
+ return;
+ }
+ dbnr=dbinfo.index+1;
+#ifdef DEBUG
+ DEBUGKPILOT<<"Next Palm database to sync: "<<dbinfo.name<<", Index="<<dbinfo.index<<endl;
+#endif
+
+ // if creator and/or type don't match, go to next db
+ if (!isCorrectDBTypeCreator(dbinfo) ||
+ fDBNames.contains(QString::fromLatin1(dbinfo.name)))
+ {
+ QTimer::singleShot(0, this, SLOT(syncNextDB()));
+ return;
+ }
+
+ QString txtfilename=constructTXTFileName(QString::fromLatin1(dbinfo.name));
+ QString pdbfilename=constructPDBFileName(QString::fromLatin1(dbinfo.name));
+
+ docSyncInfo syncInfo(QString::fromLatin1(dbinfo.name),
+ txtfilename, pdbfilename, eSyncNone);
+ syncInfo.dbinfo=dbinfo;
+ needsSync(syncInfo);
+ fSyncInfoList.append(syncInfo);
+ fDBNames.append(QString::fromLatin1(dbinfo.name));
+
+ QTimer::singleShot(0, this, SLOT(syncNextDB()));
+ return;
+}
+
+
+
+void DOCConduit::syncNextTXT()
+{
+ FUNCTIONSETUP;
+
+ if (eSyncDirection==eSyncPDAToPC )
+ {
+ // We don't sync from PC to PDB, so start the conflict resolution and then the actual sync process
+ docnames.clear();
+ QTimer::singleShot(0, this, SLOT(checkPDBFiles()));
+ return;
+ }
+
+ // if docnames isn't initialized, get a list of all *.txt files in DOCConduitSettings::tXTDirectory()
+ if (docnames.isEmpty()/* || dociterator==docnames.end() */) {
+ docnames=QDir( DOCConduitSettings::tXTDirectory(), CSL1("*.txt")).entryList() ;
+ dociterator=docnames.begin();
+ }
+ if (dociterator==docnames.end()) {
+ // no more databases available, so start the conflict resolution and then the actual sync proces
+ docnames.clear();
+ QTimer::singleShot(0, this, SLOT(checkPDBFiles()));
+ return;
+ }
+
+ QString fn=(*dociterator);
+
+ QDir dr( DOCConduitSettings::tXTDirectory() );
+ QFileInfo fl(dr, fn );
+ QString txtfilename=fl.absFilePath();
+ QString pdbfilename;
+ ++dociterator;
+
+ DBInfo dbinfo;
+ // Include all "extensions" except the last. This allows full stops inside the database name (e.g. abbreviations)
+ // first fill everything with 0, so we won't have a buffer overflow.
+ memset(&dbinfo.name[0], 0, 33);
+ strncpy(&dbinfo.name[0], fl.baseName(TRUE).latin1(), 30);
+
+ bool alreadySynced=fDBNames.contains(fl.baseName(TRUE));
+ if (!alreadySynced) {
+ docSyncInfo syncInfo(QString::fromLatin1(dbinfo.name),
+ txtfilename, pdbfilename, eSyncNone);
+ syncInfo.dbinfo=dbinfo;
+ needsSync(syncInfo);
+ fSyncInfoList.append(syncInfo);
+ fDBNames.append(QString::fromLatin1(dbinfo.name));
+ } else {
+#ifdef DEBUG
+ DEBUGKPILOT<<txtfilename<<" has already been synced, skipping it."<<endl;
+#endif
+ }
+
+ QTimer::singleShot(0, this, SLOT(syncNextTXT()));
+ return;
+}
+
+
+
+/** This slot will only be used if DOCConduitSettings::keepPDBsLocally() to check if new doc databases have been copied to the pdb directory.
+ * If so, install it to the handheld and sync it to the PC */
+void DOCConduit::checkPDBFiles() {
+ FUNCTIONSETUP;
+
+ if ( DOCConduitSettings::localSync() || !DOCConduitSettings::keepPDBsLocally() || eSyncDirection==eSyncPCToPDA )
+ {
+ // no more databases available, so check for PC->Palm sync
+ QTimer::singleShot(0, this, SLOT(checkDeletedDocs()));
+ return;
+ }
+
+ // Walk through all files in the pdb directory and check if it has already been synced.
+ // if docnames isn't initialized, get a list of all *.pdb files in DOCConduitSettings::pDBDirectory()
+ if (docnames.isEmpty()/* || dociterator==docnames.end() */) {
+ docnames=QDir(DOCConduitSettings::pDBDirectory(), CSL1("*.pdb")).entryList() ;
+ dociterator=docnames.begin();
+ }
+ if (dociterator==docnames.end()) {
+ // no more databases available, so start the conflict resolution and then the actual sync proces
+ docnames.clear();
+ QTimer::singleShot(0, this, SLOT(checkDeletedDocs()));
+ return;
+ }
+
+ QString fn=(*dociterator);
+
+ QDir dr(DOCConduitSettings::pDBDirectory());
+ QFileInfo fl(dr, fn );
+ QString pdbfilename=fl.absFilePath();
+ ++dociterator;
+
+ // Get the doc title and check if it has already been synced (in the synced docs list of in fDBNames to be synced)
+ // If the doc title doesn't appear in either list, install it to the Handheld, and add it to the list of dbs to be synced.
+ QString dbname=fl.baseName(TRUE).left(30);
+ if (!fDBNames.contains(dbname) && !fDBListSynced.contains(dbname)) {
+ if (fHandle->installFiles(pdbfilename, false)) {
+ DBInfo dbinfo;
+ // Include all "extensions" except the last. This allows full stops inside the database name (e.g. abbreviations)
+ // first fill everything with 0, so we won't have a buffer overflow.
+ memset(&dbinfo.name[0], 0, 33);
+ strncpy(&dbinfo.name[0], dbname.latin1(), 30);
+
+ docSyncInfo syncInfo(dbname, constructTXTFileName(dbname), pdbfilename, eSyncNone);
+ syncInfo.dbinfo=dbinfo;
+ needsSync(syncInfo);
+ fSyncInfoList.append(syncInfo);
+ fDBNames.append(dbname);
+ } else {
+#ifdef DEBUG
+ DEBUGKPILOT<<"Could not install database "<<dbname<<" ("<<pdbfilename<<") to the handheld"<<endl;
+#endif
+ }
+ }
+
+ QTimer::singleShot(0, this, SLOT(checkPDBFiles()));
+}
+
+
+
+void DOCConduit::checkDeletedDocs()
+{
+ FUNCTIONSETUP;
+
+ for (QStringList::Iterator it=fDBListSynced.begin(); it!=fDBListSynced.end(); ++it ) {
+ if (!fDBNames.contains(*it)) {
+ // We need to delete this doc:
+ QString dbname(*it);
+ QString txtfilename=constructTXTFileName(dbname);
+ QString pdbfilename=constructPDBFileName(dbname);
+ docSyncInfo syncInfo(dbname, txtfilename, pdbfilename, eSyncDelete);
+
+ DBInfo dbinfo;
+ memset(&dbinfo.name[0], 0, 33);
+ strncpy(&dbinfo.name[0], dbname.latin1(), 30);
+ syncInfo.dbinfo=dbinfo;
+
+ fSyncInfoList.append(syncInfo);
+ }
+ }
+ QTimer::singleShot(0, this, SLOT(resolve()));
+ return;
+}
+
+
+
+void DOCConduit::resolve() {
+ FUNCTIONSETUP;
+
+ for (fSyncInfoListIterator=fSyncInfoList.begin(); fSyncInfoListIterator!=fSyncInfoList.end(); ++fSyncInfoListIterator) {
+ // Walk through each database and apply the conflictResolution option.
+ // the remaining conflicts will be resolved in the resolution dialog
+ if ((*fSyncInfoListIterator).direction==eSyncConflict){
+#ifdef DEBUG
+ DEBUGKPILOT<<"We have a conflict for "<<(*fSyncInfoListIterator).handheldDB<<", default="<<eConflictResolution<<endl;
+#endif
+ switch (eConflictResolution)
+ {
+ case eSyncPDAToPC:
+#ifdef DEBUG
+ DEBUGKPILOT<<"PDA overrides for database "<<(*fSyncInfoListIterator).handheldDB<<endl;
+#endif
+ (*fSyncInfoListIterator).direction = eSyncPDAToPC;
+ break;
+ case eSyncPCToPDA:
+#ifdef DEBUG
+ DEBUGKPILOT<<"PC overrides for database "<<(*fSyncInfoListIterator).handheldDB<<endl;
+#endif
+ (*fSyncInfoListIterator).direction = eSyncPCToPDA;
+ break;
+ case eSyncNone:
+#ifdef DEBUG
+ DEBUGKPILOT<<"No sync for database "<<(*fSyncInfoListIterator).handheldDB<<endl;
+#endif
+ (*fSyncInfoListIterator).direction = eSyncNone;
+ break;
+ case eSyncDelete:
+ case eSyncConflict:
+ default:
+#ifdef DEBUG
+ DEBUGKPILOT<<"Conflict remains due to default resolution setting for database "<<(*fSyncInfoListIterator).handheldDB<<endl;
+#endif
+ break;
+ }
+ }
+ }
+
+ // Show the conflict resolution dialog and ask for the action for each database
+ ResolutionDialog*dlg=new ResolutionDialog( 0, i18n("Conflict Resolution"), &fSyncInfoList , fHandle);
+ bool show=DOCConduitSettings::alwaysShowResolutionDialog() || (dlg && dlg->hasConflicts);
+ if (show) {
+ if (!dlg || !dlg->exec() ) {
+ KPILOT_DELETE(dlg)
+ emit logMessage(i18n("Sync aborted by user."));
+ QTimer::singleShot(0, this, SLOT(cleanup()));
+ return;
+ }
+ }
+ KPILOT_DELETE(dlg)
+
+
+ // fDBNames will be filled with the names of the databases that are actually synced (not deleted), so I can write the list to the config file
+ fDBNames.clear();
+ fSyncInfoListIterator=fSyncInfoList.begin();
+ QTimer::singleShot(0,this, SLOT(syncDatabases()));
+ return;
+}
+
+
+
+void DOCConduit::syncDatabases() {
+ FUNCTIONSETUP;
+ if (fSyncInfoListIterator==fSyncInfoList.end()) {
+ // We're done, so clean up
+ QTimer::singleShot(0, this, SLOT(cleanup()));
+ return;
+ }
+
+ docSyncInfo sinfo=(*fSyncInfoListIterator);
+ ++fSyncInfoListIterator;
+
+ switch (sinfo.direction) {
+ case eSyncConflict:
+#ifdef DEBUG
+ DEBUGKPILOT<<"Entry "<<sinfo.handheldDB<<"( txtfilename: "<<sinfo.txtfilename<<
+ ", pdbfilename: "<<sinfo.pdbfilename<<") had sync direction eSyncConflict!!!"<<endl;
+#endif
+ break;
+ case eSyncDelete:
+ case eSyncPDAToPC:
+ case eSyncPCToPDA:
+ emit logMessage(i18n("Synchronizing text \"%1\"").arg(sinfo.handheldDB));
+ if (!doSync(sinfo)) {
+ // The sync could not be done, so inform the user (the error message should probably issued inside doSync)
+#ifdef DEBUG
+ DEBUGKPILOT<<"There was some error syncing the text \""<<sinfo.handheldDB<<"\" with the file "<<sinfo.txtfilename<<endl;
+#endif
+ }
+ break;
+ case eSyncNone:
+// case eSyncAll:
+ break;
+ }
+ if (sinfo.direction != eSyncDelete) fDBNames.append(sinfo.handheldDB);
+
+ QTimer::singleShot(0,this, SLOT(syncDatabases()));
+ return;
+}
+
+
+PilotDatabase*DOCConduit::openDOCDatabase(const QString &dbname) {
+ if (DOCConduitSettings::localSync())
+ {
+ return new PilotLocalDatabase(DOCConduitSettings::pDBDirectory(), dbname, false);
+ }
+ else
+ {
+ return deviceLink()->database( dbname );
+ }
+}
+
+
+bool DOCConduit::needsSync(docSyncInfo &sinfo)
+{
+ FUNCTIONSETUP;
+ sinfo.direction = eSyncNone;
+
+ PilotDatabase*docdb=openDOCDatabase(QString::fromLatin1(sinfo.dbinfo.name));
+ if (!fDBListSynced.contains(sinfo.handheldDB)) {
+ // the database wasn't included on last sync, so it has to be new.
+#ifdef DEBUG
+ DEBUGKPILOT<<"Database "<<sinfo.dbinfo.name<<" wasn't included in the previous sync!"<<endl;
+#endif
+
+ /* Resolution Table:
+ PC HH | normal PC->HH HH->PC
+ -----------------------------------------
+ N - | P P D
+ - N | H D H
+ N N | C P H
+ */
+
+ if (QFile::exists(sinfo.txtfilename)) sinfo.fPCStatus=eStatNew;
+ else sinfo.fPCStatus=eStatDoesntExist;
+ if (docdb && docdb->isOpen()) sinfo.fPalmStatus=eStatNew;
+ else sinfo.fPalmStatus=eStatDoesntExist;
+ KPILOT_DELETE(docdb);
+
+ switch (eSyncDirection) {
+ case eSyncPDAToPC:
+ if (sinfo.fPalmStatus==eStatDoesntExist)
+ sinfo.direction=eSyncDelete;
+ else sinfo.direction=eSyncPDAToPC;
+ break;
+ case eSyncPCToPDA:
+ if (sinfo.fPCStatus==eStatDoesntExist)
+ sinfo.direction=eSyncDelete;
+ else sinfo.direction=eSyncPCToPDA;
+ break;
+ case eSyncNone: // means actually both directions!
+ if (sinfo.fPCStatus==eStatNew) {
+ if (sinfo.fPalmStatus==eStatNew) sinfo.direction=eSyncConflict;
+ else sinfo.direction=eSyncPCToPDA;
+ } else {
+ if (sinfo.fPalmStatus==eStatNew) sinfo.direction=eSyncPDAToPC;
+ else {
+ sinfo.direction=eSyncNone;
+#ifdef DEBUG
+ DEBUGKPILOT<<"I'm supposed to find a sync direction, but the "<<
+ " text "<<sinfo.dbinfo.name<<" doesn't exist on either "<<
+ " the handheld or the PC"<<endl;
+#endif
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ // Text was included in the last sync
+ if (!QFile::exists(sinfo.txtfilename)) sinfo.fPCStatus=eStatDeleted;
+ else if(pcTextChanged(sinfo.txtfilename)) {
+ sinfo.fPCStatus=eStatChanged;
+#ifdef DEBUG
+ DEBUGKPILOT<<"PC side has changed!"<<endl;
+#endif
+ // TODO: Check for changed bookmarks on the PC side
+#ifdef DEBUG
+ } else {
+ DEBUGKPILOT<<"PC side has NOT changed!"<<endl;
+#endif
+ }
+
+ if (!docdb || !docdb->isOpen()) sinfo.fPalmStatus=eStatDeleted;
+ else if (hhTextChanged(docdb)) {
+#ifdef DEBUG
+ DEBUGKPILOT<<"Handheld side has changed!"<<endl;
+#endif
+ sinfo.fPalmStatus=eStatChanged;
+#ifdef DEBUG
+ } else {
+ DEBUGKPILOT<<"Handheld side has NOT changed!"<<endl;
+#endif
+ }
+ KPILOT_DELETE(docdb);
+
+
+ // Now that we know the status of both sides, determine what to do.
+ /* Resolution Table:
+ PC HH | normal PC->HH HH->PC
+ -----------------------------------------
+ - - | - - -
+ C - | P P H
+ - C | H P H
+ C C | C P H
+ D - | D D H
+ - D | D P D
+ D D | D D D
+ -----------------------------------------
+ C D | C P D
+ D C | C D H
+ */
+
+
+ if (sinfo.fPCStatus == eStatNone && sinfo.fPalmStatus==eStatNone) {
+#ifdef DEBUG
+ DEBUGKPILOT<<"Nothing has changed, not need for a sync."<<endl;
+#endif
+ sinfo.direction=eSyncNone;
+ return false;
+ }
+
+ // In all other cases, if only one direction (PC->HH or HH->PC)
+ // should be done, check if the DB was deleted or if we are supposed
+ // to sync that direction
+
+ if (eSyncDirection==eSyncPCToPDA) {
+ if (sinfo.fPCStatus==eStatDeleted) sinfo.direction=eSyncDelete;
+ else sinfo.direction=eSyncPCToPDA;
+ return true;
+ }
+ if (eSyncDirection==eSyncPDAToPC) {
+ if (sinfo.fPalmStatus==eStatDeleted) sinfo.direction=eSyncDelete;
+ else sinfo.direction=eSyncPDAToPC;
+ return true;
+ }
+
+
+ // ---------------------------------------------------------------
+ // Finally, do the normal case, where both directions are possible
+ // ---------------------------------------------------------------
+
+
+ // if either is deleted, and the other is not changed, delete
+ if ( ((sinfo.fPCStatus==eStatDeleted) && (sinfo.fPalmStatus!=eStatChanged)) ||
+ ((sinfo.fPalmStatus==eStatDeleted) && (sinfo.fPCStatus!=eStatChanged)) )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT<<"DB was deleted on one side and not changed on "
+ "the other -> Delete it."<<endl;
+#endif
+ sinfo.direction=eSyncDelete;
+ return true;
+ }
+
+ // eStatDeleted (and both not changed) have already been treated, for all
+ // other values in combination with eStatNone, just copy the texts.
+ if (sinfo.fPCStatus==eStatNone) {
+#ifdef DEBUG
+ DEBUGKPILOT<<"PC side has changed!"<<endl;
+#endif
+ sinfo.direction=eSyncPDAToPC;
+ return true;
+ }
+
+ if (sinfo.fPalmStatus==eStatNone) {
+ sinfo.direction=eSyncPCToPDA;
+ return true;
+ }
+
+ // All other cases
+ // (deleted,changed), (changed, deleted), (changed,changed)
+ // create a conflict:
+ sinfo.direction=eSyncConflict;
+ return true;
+}
+
+
+
+PilotDatabase *DOCConduit::preSyncAction(docSyncInfo &sinfo) const
+{
+ FUNCTIONSETUP;
+
+ {
+ // make sure the dir for the local texts really exists!
+ QDir dir( DOCConduitSettings::tXTDirectory() );
+ if (!dir.exists())
+ {
+ dir.mkdir(dir.absPath());
+ }
+ }
+
+ DBInfo dbinfo=sinfo.dbinfo;
+ switch (sinfo.direction)
+ {
+ case eSyncPDAToPC:
+ if (DOCConduitSettings::keepPDBsLocally())
+ {
+ // make sure the dir for the local db really exists!
+ QDir dir(DOCConduitSettings::pDBDirectory());
+
+ if (!dir.exists())
+ {
+ dir.mkdir(dir.absPath());
+ }
+#ifdef DEBUG
+ DEBUGKPILOT<<"Need to fetch database "<<dbinfo.name<<
+ " to the directory "<<dir.absPath()<<endl;
+#endif
+ dbinfo.flags &= ~dlpDBFlagOpen;
+
+ if (!fHandle->retrieveDatabase(sinfo.pdbfilename, &dbinfo) )
+ {
+ WARNINGKPILOT << "Unable to retrieve database " << dbinfo.name <<
+ " from the handheld into " << sinfo.pdbfilename << "." << endl;
+ return 0L;
+ }
+ }
+ break;
+ case eSyncPCToPDA:
+ if (DOCConduitSettings::keepPDBsLocally())
+ {
+ // make sure the dir for the local db really exists!
+ QDir dir(DOCConduitSettings::pDBDirectory());
+ if (!dir.exists())
+ {
+ dir.mkdir(dir.absPath());
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ if (DOCConduitSettings::keepPDBsLocally())
+ {
+ return new PilotLocalDatabase(DOCConduitSettings::pDBDirectory(),
+ QString::fromLatin1(dbinfo.name), false);
+ }
+ else
+ {
+ return deviceLink()->database(QString::fromLatin1(dbinfo.name));
+ }
+}
+
+
+// res gives us information whether the sync worked and the db might need to be
+// transferred to the handheld or not (and we just need to clean up the mess)
+bool DOCConduit::postSyncAction(PilotDatabase * database,
+ docSyncInfo &sinfo, bool res)
+{
+ FUNCTIONSETUP;
+ bool rs = true;
+
+ switch (sinfo.direction)
+ {
+ case eSyncPDAToPC:
+ // also reset the sync flags on the handheld
+#ifdef DEBUG
+ DEBUGKPILOT<<"Resetting sync flags for database "
+ <<sinfo.dbinfo.name<<endl;
+#endif
+ if (DOCConduitSettings::keepPDBsLocally() && !DOCConduitSettings::localSync())
+ {
+ PilotDatabase*db=deviceLink()->database(
+ QString::fromLatin1(sinfo.dbinfo.name));
+#ifdef DEBUG
+ DEBUGKPILOT<<"Middle 1 Resetting sync flags for database "
+ <<sinfo.dbinfo.name<<endl;
+#endif
+ if (db)
+ {
+ db->resetSyncFlags();
+ KPILOT_DELETE(db);
+ }
+ }
+#ifdef DEBUG
+ DEBUGKPILOT<<"End Resetting sync flags for database "
+ <<sinfo.dbinfo.name<<endl;
+#endif
+ break;
+ case eSyncPCToPDA:
+ if (DOCConduitSettings::keepPDBsLocally() && !DOCConduitSettings::localSync() && res)
+ {
+ // Copy the database to the palm
+ PilotLocalDatabase*localdb=dynamic_cast<PilotLocalDatabase*>(database);
+ if (localdb)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT<<"Installing file "<<localdb->dbPathName()<<" ("
+ <<sinfo.handheldDB<<") to the handheld"<<endl;
+#endif
+ QString dbpathname=localdb->dbPathName();
+ // This deletes localdb as well, which is just a cast from database
+ KPILOT_DELETE(database);
+ if (!fHandle->installFiles(dbpathname, false))
+ {
+ rs = false;
+#ifdef DEBUG
+ DEBUGKPILOT<<"Could not install the database "<<dbpathname<<" ("
+ <<sinfo.handheldDB<<")"<<endl;
+#endif
+ }
+ }
+ }
+ default:
+ break;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT<<"Vor KPILOT_DELETE(database)"<<endl;
+#endif
+
+ KPILOT_DELETE(database);
+#ifdef DEBUG
+ DEBUGKPILOT<<"End postSyncAction"<<endl;
+#endif
+ return rs;
+}
+
+
+
+void DOCConduit::cleanup()
+{
+ FUNCTIONSETUP;
+ DOCConduitSettings::setConvertedDOCfiles( fDBNames );
+ DOCConduitSettings::self()->writeConfig();
+
+ emit syncDone(this);
+}
+
diff --git a/kpilot/conduits/docconduit/doc-conduit.h b/kpilot/conduits/docconduit/doc-conduit.h
new file mode 100644
index 000000000..834002bea
--- /dev/null
+++ b/kpilot/conduits/docconduit/doc-conduit.h
@@ -0,0 +1,152 @@
+#ifndef _doc_CONDUIT_H
+#define _doc_CONDUIT_H
+/* doc-conduit.h KPilot
+**
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include <plugin.h>
+
+class docSyncInfo;
+typedef QValueList<docSyncInfo> syncInfoList;
+
+typedef enum eSyncDirectionEnum {
+ eSyncNone,
+// eSyncAll,
+ eSyncPDAToPC,
+ eSyncPCToPDA,
+ eSyncDelete,
+ eSyncConflict
+ };
+typedef enum eTextStatus {
+ eStatNone=0,
+ eStatNew=1,
+ eStatChanged=2,
+ eStatBookmarksChanged=4,
+ eStatDeleted=8,
+ eStatDoesntExist=16
+ };
+
+
+QString dirToString(eSyncDirectionEnum dir);
+
+class DOCConduit:public ConduitAction {
+Q_OBJECT
+public:
+ eSyncDirectionEnum eSyncDirection;
+
+public:
+ DOCConduit(KPilotLink * o,
+ const char *n = 0L, const QStringList & a = QStringList());
+ virtual ~ DOCConduit();
+
+ bool encode(QStringList fileName, PilotDatabase * db);
+ bool decode(PilotDatabase * db, QString fileName);
+ virtual bool exec();
+protected:
+ virtual bool isCorrectDBTypeCreator(DBInfo dbinfo);
+ virtual const unsigned long dbtype();
+ virtual const unsigned long dbcreator();
+
+public slots:
+/** syncNextDB walks through all PalmDoc databases on the handheld and decides if they are supposed to be synced to the PC.
+ * syncNextDB and syncNextDOC fist build the list of all PalmDoc texts, and then the method syncDatabases does the actual sync. */
+ void syncNextDB();
+ void syncNextTXT();
+ void checkPDBFiles();
+ void checkDeletedDocs();
+ void resolve();
+ void syncDatabases();
+ void cleanup();
+
+ private:
+ /**
+ * Read the global KPilot config file for settings
+ * particular to the docConduit conduit.
+ */
+ void readConfig();
+
+ /**
+ * Check if the database needs to be synced at all.
+ */
+ bool needsSync(docSyncInfo &sinfo);
+ /**
+ * If necessary, copy the database from the palm to a local dir.
+ * Also initialize the docDBInfo that will be passed to the docconverter
+ */
+ PilotDatabase *preSyncAction(docSyncInfo &sinfo) const;
+
+ bool doSync(docSyncInfo &sinfo);
+ /**
+ * Clean up after the sync. The bool parameter res tells
+ * the function if the conversion was successful or not
+ */
+ bool postSyncAction(PilotDatabase * dbinfo, docSyncInfo &sinfo, bool res = true);
+
+ bool pcTextChanged(QString txtfn);
+ bool hhTextChanged(PilotDatabase*docdb);
+
+ /** Opens the database with name dbname. For a local sync, this will be a
+ * PilotLocalDatabase, otherwise it will be a database on the serial device
+ * (i.e. an object of class PilotSerialDatabase) */
+ PilotDatabase *openDOCDatabase(const QString &dbname);
+
+ QString constructPDBFileName(QString name);
+ QString constructTXTFileName(QString name);
+
+ eSyncDirectionEnum eConflictResolution;
+ int fTXTBookmarks, fPDBBookmarks;
+ QStringList fDBListSynced;
+ QStringList fDBNames;
+ syncInfoList fSyncInfoList;
+ syncInfoList::Iterator fSyncInfoListIterator;
+ long int dbnr;
+
+ QStringList docnames;
+ QStringList::Iterator dociterator;
+};
+
+class docSyncInfo
+{
+public:
+ docSyncInfo(QString hhDB=QString(), QString txtfn=QString(), QString pdbfn=QString(), eSyncDirectionEnum dir=eSyncNone)
+ {
+ handheldDB=hhDB;
+ txtfilename=txtfn;
+ pdbfilename=pdbfn;
+ direction=dir;
+ fPCStatus=eStatNone;
+ fPalmStatus=eStatNone;
+ };
+ ~docSyncInfo(){};
+ QString handheldDB, txtfilename, pdbfilename;
+ DBInfo dbinfo;
+ eSyncDirectionEnum direction;
+ eTextStatus fPCStatus, fPalmStatus;
+};
+
+
+#endif
diff --git a/kpilot/conduits/docconduit/doc-conflictdialog.cc b/kpilot/conduits/docconduit/doc-conflictdialog.cc
new file mode 100644
index 000000000..7dafd9b66
--- /dev/null
+++ b/kpilot/conduits/docconduit/doc-conflictdialog.cc
@@ -0,0 +1,182 @@
+/* KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+#include "doc-conflictdialog.moc"
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qbuttongroup.h>
+#include <kmessagebox.h>
+#include <qtimer.h>
+#include <qtable.h>
+#include <qcombobox.h>
+#include <qscrollview.h>
+
+
+ResolutionDialog::ResolutionDialog( QWidget* parent, const QString& caption, syncInfoList*sinfo, KPilotLink*lnk )
+ : KDialogBase( parent, "resolutionDialog", true, caption, KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true), tickleTimer(0L), fHandle(lnk) {
+ FUNCTIONSETUP;
+ syncInfo=sinfo;
+ hasConflicts=false;
+
+ QWidget *page = new QWidget( this );
+ setMainWidget(page);
+ QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
+
+ // First, insert the texts on top:
+ textLabel1 = new QLabel(i18n("Here is a list of all text files and DOC databases the conduit found. The conduit tried to determine the correct sync direction, but for databases in bold red letters a conflict occurred (i.e. the text was changed both on the desktop and on the handheld). For these databases please specify which version is the current one."), page);
+ textLabel1->setAlignment( int( QLabel::WordBreak | QLabel::AlignVCenter ) );
+ topLayout->addWidget(textLabel1);
+
+ textLabel2 = new QLabel(i18n("You can also change the sync direction for databases without a conflict." ), page );
+ textLabel2->setAlignment( int( QLabel::WordBreak | QLabel::AlignVCenter ) );
+ topLayout->addWidget(textLabel2);
+
+ resolutionGroupBox = new QGroupBox(i18n("DOC Databases"), page );
+ QVBoxLayout*playout = new QVBoxLayout(resolutionGroupBox);
+ QScrollView* sv = new QScrollView(resolutionGroupBox);
+ playout->addWidget(sv);
+ sv->setResizePolicy(QScrollView::AutoOneFit);
+ sv->setHScrollBarMode(QScrollView::AlwaysOff);
+ sv->setMargin(5);
+ QFrame* big_box = new QFrame(sv->viewport());
+ sv->addChild(big_box);
+
+
+ resolutionGroupBoxLayout = new QGridLayout( big_box, syncInfo->size(), 3 );
+ resolutionGroupBoxLayout->setAlignment( Qt::AlignTop );
+
+ // Invisible button group for the information buttons to use the same slot for all of them (see Dallheimer's book, page 309f)
+ QButtonGroup *bgroup = new QButtonGroup( this );
+ bgroup->hide();
+ QObject::connect(bgroup, SIGNAL(clicked(int)), this, SLOT(slotInfo(int)));
+
+ if (syncInfo) {
+ DEBUGKPILOT<<"Adding resolution options for the databases "<<endl;
+ syncInfoList::Iterator it;
+ int nr=0;
+ DEBUGKPILOT<<"We're having "<<(*syncInfo).size()<<" entries in the database list"<<endl;
+ for (it=syncInfo->begin(); it!=syncInfo->end(); ++it ) {
+ docSyncInfo si=(*it);
+ conflictEntry cE;
+ cE.index=nr;
+ cE.conflict=(si.direction==eSyncConflict);
+ DEBUGKPILOT<<"Adding "<<si.handheldDB<<" to the conflict resolution dialog"<<endl;
+
+ QString text=si.handheldDB;
+ if (cE.conflict) {
+ text=CSL1("<qt><b><font color=red>")+text+CSL1("</font></b></qt>");
+ DEBUGKPILOT<<"We have a conflict for database "<<si.handheldDB<<endl;
+ hasConflicts=true;
+ }
+ cE.dbname=new QLabel(text, big_box);
+ resolutionGroupBoxLayout->addWidget( cE.dbname, cE.index, 0 );
+
+ cE.resolution=new QComboBox( FALSE, big_box);
+ cE.resolution->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)7,
+ (QSizePolicy::SizeType)0, 0, 0,
+ cE.resolution->sizePolicy().hasHeightForWidth() ) );
+ cE.resolution->clear();
+ cE.resolution->insertItem( i18n( "No Sync" ) );
+ cE.resolution->insertItem( i18n( "Sync Handheld to PC" ) );
+ cE.resolution->insertItem( i18n( "Sync PC to Handheld" ) );
+ cE.resolution->insertItem( i18n( "Delete Both Databases" ) );
+ cE.resolution->setCurrentItem((int)si.direction);
+ resolutionGroupBoxLayout->addWidget( cE.resolution, cE.index, 1);
+
+ cE.info = new QPushButton( i18n("More Info..."), big_box );
+ resolutionGroupBoxLayout->addWidget(cE.info, cE.index, 2);
+ bgroup->insert(cE.info);
+
+ conflictEntries.append(cE);
+ ++nr;
+ }
+ } else {
+ WARNINGKPILOT << "The list of text files is not available to the resolution dialog." << endl;
+ }
+
+
+ topLayout->addWidget( resolutionGroupBox );
+ resize( QSize(600, 480).expandedTo(minimumSizeHint()) );
+
+ if (fHandle) tickleTimer=new QTimer(this, "TickleTimer");
+ if (tickleTimer) {
+ connect( tickleTimer, SIGNAL(timeout()), this, SLOT(_tickle()) );
+ tickleTimer->start( 10000 ); // tickle the palm every 10 seconds to prevent a timeout until the sync is really finished.
+ }
+
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+ResolutionDialog::~ResolutionDialog()
+{
+ // no need to delete child widgets, Qt does it all for us
+}
+
+/* virtual slot */ void ResolutionDialog::slotOk() {
+ FUNCTIONSETUP;
+ QValueList<conflictEntry>::Iterator ceIt;
+ for (ceIt=conflictEntries.begin(); ceIt!=conflictEntries.end(); ++ceIt) {
+ (*syncInfo)[(*ceIt).index].direction=(eSyncDirectionEnum)((*ceIt).resolution->currentItem());
+ }
+ KDialogBase::slotOk();
+}
+
+QString eTextStatusToString(eTextStatus stat) {
+ switch(stat) {
+ case eStatNone: return i18n("unchanged");
+ case eStatNew: return i18n("new");
+ case eStatChanged: return i18n("changed");
+ case eStatBookmarksChanged: return i18n("only bookmarks changed");
+ case eStatDeleted: return i18n("deleted");
+ case eStatDoesntExist: return i18n("does not exist");
+ default: return i18n("unknown");
+ }
+}
+
+void ResolutionDialog::slotInfo(int index) {
+ FUNCTIONSETUP;
+ conflictEntry cE=conflictEntries[index];
+ int ix=cE.index;
+ if (!syncInfo) return;
+ docSyncInfo si=(*syncInfo)[ix];
+ QString text=i18n("Status of the database %1:\n\n").arg(si.handheldDB);
+ text+=i18n("Handheld: %1\n").arg(eTextStatusToString(si.fPalmStatus));
+ text+=i18n("Desktop: %1\n").arg(eTextStatusToString(si.fPCStatus));
+
+ KMessageBox::information(this, text, i18n("Database information"));
+}
+
+
+void ResolutionDialog::_tickle() {
+ FUNCTIONSETUP;
+ if (fHandle) fHandle->tickle();
+}
diff --git a/kpilot/conduits/docconduit/doc-conflictdialog.h b/kpilot/conduits/docconduit/doc-conflictdialog.h
new file mode 100644
index 000000000..f8ad8caf7
--- /dev/null
+++ b/kpilot/conduits/docconduit/doc-conflictdialog.h
@@ -0,0 +1,83 @@
+#ifndef CONFLICTDIALOG_H
+#define CONFLICTDIALOG_H
+/* doc-conflictdialog.h KPilot
+**
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include <kdialogbase.h>
+#include "doc-conduit.h"
+
+
+class QComboBox;
+class QGridLayout;
+class QGroupBox;
+
+class QLabel;
+class QPushButton;
+class QTimer;
+class KPilotLink;
+
+
+typedef struct conflictEntry {
+ QLabel*dbname;
+ QComboBox* resolution;
+ QPushButton*info;
+ int index;
+ bool conflict;
+};
+
+
+class ResolutionDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ ResolutionDialog( QWidget* parent=0, const QString& caption=i18n("Resolution Dialog"), syncInfoList*sinfo=0L, KPilotLink*lnk=0L);
+ ~ResolutionDialog();
+
+ bool hasConflicts;
+public slots:
+ void _tickle();
+protected:
+ QTimer* tickleTimer;
+ KPilotLink* fHandle;
+
+protected:
+ QGroupBox* resolutionGroupBox;
+ QGridLayout*resolutionGroupBoxLayout;
+
+ syncInfoList*syncInfo;
+ QValueList<conflictEntry> conflictEntries;
+ QLabel *textLabel1,*textLabel2;
+
+protected slots:
+ virtual void slotOk();
+ void slotInfo(int index);
+
+};
+
+#endif // CONFLICTDIALOG_H
diff --git a/kpilot/conduits/docconduit/doc-factory.cc b/kpilot/conduits/docconduit/doc-factory.cc
new file mode 100644
index 000000000..3d2a16b11
--- /dev/null
+++ b/kpilot/conduits/docconduit/doc-factory.cc
@@ -0,0 +1,116 @@
+/* KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This file defines the factory for the doc-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+#include "doc-factory.moc"
+#include "doc-factory.h"
+
+#include <kinstance.h>
+#include <kaboutdata.h>
+#include <kpilotlink.h>
+
+#include "doc-conduit.h"
+#include "doc-setup.h"
+
+
+extern "C" {
+ void *init_conduit_doc() {
+ return new DOCConduitFactory;
+ }
+}
+
+
+
+// A number of static variables
+KAboutData * DOCConduitFactory::fAbout = 0L;
+
+const char *DOCConduitFactory::dbDOCtype = "TEXt";
+const char *DOCConduitFactory::dbDOCcreator = "REAd";
+
+
+
+DOCConduitFactory::DOCConduitFactory(QObject * p, const char *n):
+KLibFactory(p, n)
+{
+ FUNCTIONSETUP;
+ fInstance = new KInstance("docconduit");
+ fAbout =new KAboutData("docconduit",
+ I18N_NOOP("Palm DOC Conduit for KPilot"), KPILOT_VERSION,
+ I18N_NOOP("Configures the DOC Conduit for KPilot"),
+ KAboutData::License_GPL, "(C) 2002, Reinhold Kainhofer");
+
+ fAbout->addAuthor("Reinhold Kainhofer",
+ I18N_NOOP("Maintainer"), "[email protected]",
+ "http://reinhold.kainhofer.com");
+}
+
+DOCConduitFactory::~DOCConduitFactory()
+{
+ FUNCTIONSETUP;
+ KPILOT_DELETE(fInstance);
+ KPILOT_DELETE(fAbout);
+}
+
+
+/* virtual */ QObject * DOCConduitFactory::createObject(QObject * p,
+ const char *n, const char *c, const QStringList & a)
+{
+ FUNCTIONSETUP;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname <<": Creating object of class " <<c <<endl;
+#endif
+ if (qstrcmp(c, "ConduitConfigBase") == 0)
+ {
+ QWidget *w = dynamic_cast<QWidget *>(p);
+ if (w)
+ {
+ return new DOCWidgetConfig(w,n);
+ }
+ else
+ {
+ WARNINGKPILOT << "Couldn't cast parent to widget." << endl;
+ return 0L;
+ }
+ }
+ if (qstrcmp(c, "SyncAction") == 0)
+ {
+ KPilotLink * d = dynamic_cast < KPilotLink * >(p);
+ if (d)
+ {
+ return new DOCConduit(d, n, a);
+ }
+ else
+ {
+ WARNINGKPILOT << "Couldn't cast parent to KPilotLink" <<endl;
+ return 0L;
+ }
+ }
+ return 0L;
+}
+
diff --git a/kpilot/conduits/docconduit/doc-factory.h b/kpilot/conduits/docconduit/doc-factory.h
new file mode 100644
index 000000000..c848777a0
--- /dev/null
+++ b/kpilot/conduits/docconduit/doc-factory.h
@@ -0,0 +1,74 @@
+#ifndef _DOC_FACTORY_H
+#define _DOC_FACTORY_H
+
+/* doc-factory.h KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This file defines the factory for the doc-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <klibloader.h>
+
+class KInstance;
+class KAboutData;
+
+
+class DOCConduitFactory:public KLibFactory
+{
+
+Q_OBJECT
+
+public:
+ DOCConduitFactory(QObject * = 0L, const char * = 0L);
+ virtual ~ DOCConduitFactory();
+
+ static KAboutData *about() {
+ return fAbout;
+ };
+
+ static const char
+ *fDBListSynced;
+ static const char *dbDOCtype;
+ static const char *dbDOCcreator;
+
+
+protected:
+ virtual QObject * createObject(QObject * parent = 0,
+ const char *name = 0,
+ const char *classname = "QObject",
+ const QStringList & args = QStringList());
+
+private:
+ KInstance * fInstance;
+ static KAboutData *fAbout;
+};
+
+
+extern "C" {
+ void *init_libdocconduit();
+}
+
+
+#endif
diff --git a/kpilot/conduits/docconduit/doc-setup.cc b/kpilot/conduits/docconduit/doc-setup.cc
new file mode 100644
index 000000000..a6de2d2ad
--- /dev/null
+++ b/kpilot/conduits/docconduit/doc-setup.cc
@@ -0,0 +1,136 @@
+/* KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This file defines the setup dialog for the doc-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qtabwidget.h>
+#include <qcheckbox.h>
+#include <qbuttongroup.h>
+#include <qcombobox.h>
+
+#include <kconfig.h>
+#include <kurlrequester.h>
+#include <kcharsets.h>
+
+#include "doc-setupdialog.h"
+#include "doc-factory.h"
+#include "doc-setup.h"
+#include "docconduitSettings.h"
+
+
+DOCWidgetConfig::DOCWidgetConfig(QWidget * w, const char *n):
+ ConduitConfigBase(w, n),
+ fConfigWidget(new DOCWidget(w))
+{
+ FUNCTIONSETUP;
+
+ fWidget=fConfigWidget;
+
+ QStringList l = KGlobal::charsets()->descriptiveEncodingNames();
+ for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it)
+ {
+ fConfigWidget->fEncoding->insertItem(*it);
+ }
+
+ fConfigWidget->fTXTDir->setMode(KFile::Directory);
+ fConfigWidget->fPDBDir->setMode(KFile::Directory);
+ ConduitConfigBase::addAboutPage(fConfigWidget->tabWidget,DOCConduitFactory::about());
+
+ fConduitName=i18n("Palm DOC");
+
+#define CMOD(a,b) connect(fConfigWidget->a,SIGNAL(b),this,SLOT(modified()))
+ CMOD(fTXTDir,textChanged(const QString &));
+ CMOD(fPDBDir,textChanged(const QString &));
+ CMOD(fkeepPDBLocally,clicked());
+ CMOD(fConflictResolution,clicked(int));
+ CMOD(fConvertBookmarks,stateChanged(int));
+ CMOD(fBookmarksBmk,stateChanged(int));
+ CMOD(fBookmarksInline,stateChanged(int));
+ CMOD(fBookmarksEndtags,stateChanged(int));
+ CMOD(fCompress,stateChanged(int));
+ CMOD(fSyncDirection,clicked(int));
+ CMOD(fNoConversionOfBmksOnly,stateChanged(int));
+ CMOD(fAlwaysUseResolution,stateChanged(int));
+ CMOD(fPCBookmarks,clicked(int));
+ CMOD(fEncoding,textChanged(const QString &));
+#undef CMOD
+
+ fConfigWidget->adjustSize();
+}
+
+/* virtual */ void DOCWidgetConfig::commit()
+{
+ FUNCTIONSETUP;
+
+ DOCConduitSettings::setTXTDirectory( fConfigWidget->fTXTDir->url() );
+ DOCConduitSettings::setPDBDirectory( fConfigWidget->fPDBDir->url() );
+
+ DOCConduitSettings::setKeepPDBsLocally( fConfigWidget->fkeepPDBLocally->isChecked());
+ DOCConduitSettings::setConflictResolution( fConfigWidget->fConflictResolution->id(
+ fConfigWidget->fConflictResolution->selected()) );
+ DOCConduitSettings::setConvertBookmarks(fConfigWidget->fConvertBookmarks->isChecked());
+ DOCConduitSettings::setBmkFileBookmarks(fConfigWidget->fBookmarksBmk->isChecked());
+ DOCConduitSettings::setInlineBookmarks(fConfigWidget->fBookmarksInline->isChecked());
+ DOCConduitSettings::setEndtagBookmarks(fConfigWidget->fBookmarksEndtags->isChecked());
+ DOCConduitSettings::setCompress(fConfigWidget->fCompress->isChecked());
+ DOCConduitSettings::setSyncDirection(fConfigWidget->fSyncDirection->id(
+ fConfigWidget->fSyncDirection->selected()));
+ DOCConduitSettings::setIgnoreBmkChanges(fConfigWidget->fNoConversionOfBmksOnly->isChecked());
+ DOCConduitSettings::setAlwaysShowResolutionDialog(fConfigWidget->fAlwaysUseResolution->isChecked());
+ DOCConduitSettings::setBookmarksToPC( fConfigWidget->fPCBookmarks->id(
+ fConfigWidget->fPCBookmarks->selected()) );
+ DOCConduitSettings::setEncoding( fConfigWidget->fEncoding->currentText() );
+
+ DOCConduitSettings::self()->writeConfig();
+ unmodified();
+}
+
+/* virtual */ void DOCWidgetConfig::load()
+{
+ FUNCTIONSETUP;
+ DOCConduitSettings::self()->readConfig();
+
+ fConfigWidget->fTXTDir->setURL( DOCConduitSettings::tXTDirectory() );
+ fConfigWidget->fPDBDir->setURL( DOCConduitSettings::pDBDirectory() );
+ fConfigWidget->fkeepPDBLocally->setChecked( DOCConduitSettings::keepPDBsLocally() );
+ fConfigWidget->fConflictResolution->setButton(DOCConduitSettings::conflictResolution() );
+ fConfigWidget->fConvertBookmarks->setChecked(DOCConduitSettings::convertBookmarks() );
+ fConfigWidget->fBookmarksBmk->setChecked(DOCConduitSettings::bmkFileBookmarks() );
+ fConfigWidget->fBookmarksInline->setChecked(DOCConduitSettings::inlineBookmarks() );
+ fConfigWidget->fBookmarksEndtags->setChecked(DOCConduitSettings::endtagBookmarks() );
+ fConfigWidget->fCompress->setChecked(DOCConduitSettings::compress() );
+ fConfigWidget->fSyncDirection->setButton(DOCConduitSettings::syncDirection() );
+
+ fConfigWidget->fNoConversionOfBmksOnly->setChecked( DOCConduitSettings::ignoreBmkChanges() );
+ fConfigWidget->fAlwaysUseResolution->setChecked( DOCConduitSettings::alwaysShowResolutionDialog() );
+
+ fConfigWidget->fPCBookmarks->setButton(DOCConduitSettings::bookmarksToPC() );
+ fConfigWidget->fEncoding->setCurrentText(DOCConduitSettings::encoding() );
+ unmodified();
+}
+
diff --git a/kpilot/conduits/docconduit/doc-setup.h b/kpilot/conduits/docconduit/doc-setup.h
new file mode 100644
index 000000000..470585e01
--- /dev/null
+++ b/kpilot/conduits/docconduit/doc-setup.h
@@ -0,0 +1,47 @@
+#ifndef _DOC_DOC_SETUP_H
+#define _DOC_DOC_SETUP_H
+/* doc-setup.h KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This file defines the widget and behavior for the config dialog
+** of the doc conduit.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "plugin.h"
+
+class DOCWidget;
+
+class DOCWidgetConfig : public ConduitConfigBase
+{
+public:
+ DOCWidgetConfig(QWidget *, const char *);
+ virtual void commit();
+ virtual void load();
+protected:
+ DOCWidget *fConfigWidget;
+} ;
+
+
+#endif
diff --git a/kpilot/conduits/docconduit/doc-setupdialog.ui b/kpilot/conduits/docconduit/doc-setupdialog.ui
new file mode 100644
index 000000000..cbb45e344
--- /dev/null
+++ b/kpilot/conduits/docconduit/doc-setupdialog.ui
@@ -0,0 +1,557 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>DOCWidget</class>
+<author>Reinhold Kainhofer</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Form2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>564</width>
+ <height>266</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Text files:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fTXTDir</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter here, or select clicking the file picker button, the name and location of the folder used to find and synchronize text files. All files with extension .txt located in this folder will be synced to Palm DOC databases in your handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>fkeepPDBLocally</cstring>
+ </property>
+ <property name="text">
+ <string>Local co&amp;py:</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box if you want to save a copy of the Palm DOC databases (.pdb files) on your PC.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="0" column="1">
+ <property name="name">
+ <cstring>fTXTDir</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter here, or select clicking the file picker button, the name and location of the folder used to find and synchronize text files. All files with extension .txt located in this folder will be synced to Palm DOC databases in your handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fSyncDirection</cstring>
+ </property>
+ <property name="title">
+ <string>Synchronization Mode</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton" row="2" column="0">
+ <property name="name">
+ <cstring>RadioButton3</cstring>
+ </property>
+ <property name="text">
+ <string>Sync only P&amp;C to PDA</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>2</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to synchronize texts changed in your PC to Palm DOC databases in your handheld. Palm DOC databases modified in the handheld will not be converted to text files, but texts changed in the PC will be converted to the Palm DOC databases.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>RadioButton2</cstring>
+ </property>
+ <property name="text">
+ <string>Sync only P&amp;DA to PC</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to synchronize the changes made to Palm DOC databases in your handheld to the PC text files. Palm DOC databases modified in the handheld will be converted to text files, but texts changed in the PC will not be converted to the Palm DOC databases.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>RadioButton1</cstring>
+ </property>
+ <property name="text">
+ <string>Sync &amp;all</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="buttonGroupId">
+ <number>0</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to synchronize the file texts in your PC to Palm DOC databases in your handheld. Palm DOC databases modified in the handheld will be converted to text files, and texts changed in the PC will be converted to the Palm DOC databases, keeping both versions in sync.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="3" column="1">
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KURLRequester" row="1" column="1">
+ <property name="name">
+ <cstring>fPDBDir</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter here, or select clicking the file picker button, the name and location of the folder where copies of the handheld databases are kept (.pdb files). Local copies are only made if the box is checked as well.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>PC -&gt; Handheld</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>fCompress</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Compress</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Check this box, if the text should be compressed on the handheld to save memory. Most doc reader on the handheld support compressed texts.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;The Palm DOC format supports compressing the text to save memory. Check this box to enable text compression, so the resulting Palm DOC database will consume about 50% less memory than in uncompressed state. Almost all DOC readers on the Palm support compressed texts.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>fConvertBookmarks</cstring>
+ </property>
+ <property name="text">
+ <string>Convert &amp;bookmarks</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to enable bookmark creation when converting text files to Palm DOC databases. Most doc readers support bookmarks. In order to create a bookmark, it is necessary to to provide the location in the text where the bookmark should be set and the bookmark title, in at least one of the formats listed below.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <spacer row="6" column="2">
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="2" column="1">
+ <property name="name">
+ <cstring>fBookmarksInline</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Inline tags in text</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this box to create bookmarks from inline tags in the text. The inline tag consist of tags in the form &lt;* bookmarktext *&gt;. The bookmark location is set using the location of the inline tag in the text, and the name is the text between the &lt;* and the *&gt;. The inline tag (&lt;*...*&gt;) will be removed from the text.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Encoding:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fEncoding</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="1">
+ <property name="name">
+ <cstring>fBookmarksEndtags</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Tags at end of text</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this box to convert tags of the form &lt;bookmarkname&gt; at the end of the text to bookmarks. The text inside the tag ("bookmarkname") will be searched in the text, and whenever found, a bookmark will be set there. The endtags &lt;...&gt; will then be removed from the end of the text.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="1">
+ <property name="name">
+ <cstring>fBookmarksBmk</cstring>
+ </property>
+ <property name="text">
+ <string>Regular &amp;expressions in .bmk file</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to use regular expressions in a file to search the text for bookmarks. The file should have the same name as the text file, but should end in .bmk instead of .txt (for instance, the regular expression file for textname.txt should be textname.bmk). See the documentation for a description of the format of the bmk file.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="5" column="1">
+ <property name="name">
+ <cstring>fEncoding</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Handheld -&gt; PC</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>spacer16</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>fNoConversionOfBmksOnly</cstring>
+ </property>
+ <property name="text">
+ <string>Do not convert, if text unchanged (only bookmarks)</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to avoid syncing the text on the handheld to the PC if you only changed the bookmarks on the handheld (but not the text).&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="0" column="0">
+ <property name="name">
+ <cstring>fPCBookmarks</cstring>
+ </property>
+ <property name="title">
+ <string>Convert Bookmarks</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>radioButton8</cstring>
+ </property>
+ <property name="text">
+ <string>Do &amp;not convert bookmarks</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>0</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to avoid converting Palm DOC bookmarks to inline tags or to a bookmark file.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>radioButton11</cstring>
+ </property>
+ <property name="text">
+ <string>Convert into .bm &amp;file</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="buttonGroupId">
+ <number>1</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to convert the Palm DOC database bookmarks to a separate file, in the bmk format (see more about this format in the documentation). The resulting bookmark file shares the same filename as the resulting .txt file, but ends in .bmk instead. This approach creates a clean text file and a bookmark file.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="2" column="0">
+ <property name="name">
+ <cstring>radioButton9</cstring>
+ </property>
+ <property name="text">
+ <string>Convert as &amp;inline tags</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>2</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to convert the Palm DOC database bookmarks to inline tags, in the form &amp;lt;* BookmarkName *&amp;gt;. These tags are inserted in the text in the position marked by the bookmark, and the text inside the tag corresponds to the bookmark name. Inline tags are easy to create, delete, move and edit.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Conflicts</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>fConflictResolution</cstring>
+ </property>
+ <property name="title">
+ <string>Conflict Resolution</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>If the same text was changed on the PC and the handheld, which of the two versions should be used as the new version?</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;The Palm DOC conduit does not feature merging the modifications when a text is changed both in the handheld and in the computer. Therefore, the choice is between working with the files out of sync, or discarding the changes in one of them.&lt;/qt&gt;</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>radioButton12</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;No resolution</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>0</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;The Palm DOC conduit does not feature merging the modifications when a text is changed both in the handheld and in the computer. Therefore, when conflicts appear, the choice is between working with the files out of sync, or discarding the changes in one of them. Select this option to prevent KPilot from overwriting your modifications.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>RadioButton5</cstring>
+ </property>
+ <property name="text">
+ <string>P&amp;DA overrides</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>1</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;The Palm DOC conduit does not feature merging the modifications when a text is changed both in the handheld and in the computer. Therefore, when conflicts appear, the choice is between working with the files out of sync, or discarding the changes in one of them. Select this option to make the PDA version overwrite the PC version in case of conflict.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="2" column="0">
+ <property name="name">
+ <cstring>RadioButton4</cstring>
+ </property>
+ <property name="text">
+ <string>P&amp;C overrides</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>2</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;The Palm DOC conduit does not feature merging the modifications when a text is changed both in the handheld and in the computer. Therefore, when conflicts appear, the choice is between working with the files out of sync, or discarding the changes in one of them. Select this option to make the PC version overwrite the PDA version in case of conflict.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="3" column="0">
+ <property name="name">
+ <cstring>RadioButton7</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Ask the user</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="buttonGroupId">
+ <number>4</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;The Palm DOC conduit does not feature merging the modifications when a text is changed both in the handheld and in the computer. Therefore, when conflicts appear, the choice is between working with the files out of sync, or discarding the changes in one of them. Select this option to show the resolution dialog to let the user decide on a case by case basis.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>fAlwaysUseResolution</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Always show the resolution dialog</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to force the resolution dialog to appear even when there are no conflicts.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>fConvertBookmarks</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>fBookmarksInline</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>fConvertBookmarks</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>fBookmarksEndtags</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>fConvertBookmarks</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>fBookmarksBmk</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>fkeepPDBLocally</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>fPDBDir</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>fTXTDir</tabstop>
+ <tabstop>fkeepPDBLocally</tabstop>
+ <tabstop>fPDBDir</tabstop>
+ <tabstop>fCompress</tabstop>
+ <tabstop>fConvertBookmarks</tabstop>
+ <tabstop>fBookmarksInline</tabstop>
+ <tabstop>fBookmarksEndtags</tabstop>
+ <tabstop>fBookmarksBmk</tabstop>
+ <tabstop>radioButton11</tabstop>
+ <tabstop>fNoConversionOfBmksOnly</tabstop>
+ <tabstop>RadioButton7</tabstop>
+ <tabstop>fAlwaysUseResolution</tabstop>
+ <tabstop>tabWidget</tabstop>
+ <tabstop>RadioButton1</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includes>
+ <include location="global" impldecl="in implementation">kurlrequester.h</include>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+ <include location="global" impldecl="in implementation">kpushbutton.h</include>
+</includes>
+</UI>
diff --git a/kpilot/conduits/docconduit/doc_conduit.desktop b/kpilot/conduits/docconduit/doc_conduit.desktop
new file mode 100644
index 000000000..65f1ce425
--- /dev/null
+++ b/kpilot/conduits/docconduit/doc_conduit.desktop
@@ -0,0 +1,59 @@
+[Desktop Entry]
+Type=Service
+Comment=Adds text files to your handheld, suitable for DOC readers.
+Comment[af]=Voeg teks lêers by jou draagbare toestel in DOC leser formaat.
+Comment[bg]=Добавяне на текстови файлове към мобилно устройство.
+Comment[ca]=Afegeix fitxers de text a la vostra agenda, apropiat per a lectors de DOC.
+Comment[cs]=Přidává textové soubory do vašeho Pilotu, výhodné pro čtenáře dokumentů.
+Comment[da]=Tilføjer tekstfiler til din håndholdte, passende for DOC-læsere.
+Comment[de]=Gibt Textdateien in Taschencomputer ein, passend für DOC-Leser.
+Comment[el]=Προσθέτει αρχεία κειμένου στον υπολογιστή παλάμης σας, κατάλληλο για αναγνώστες DOC.
+Comment[es]=Añade archivos de texto a su agenda electrónica. Compatible con los lectores DOC.
+Comment[et]=Lisab DOC-riiderile sobilikud tekstifailid sinu pihuseadmele.
+Comment[eu]=Zure agenda elektronikora DOC irakurleentzako aproposak diren testu fitxategiak gehitzen ditu.
+Comment[fa]=پرونده‌های متن را به دستی شما اضافه می‌کند، که برای خوانندگان DOC مفید است.
+Comment[fi]=Lisää tekstitiedostoja taskutietokoneeseen. Tämä on käyttökelpoinen DOC-lukijoille.
+Comment[fr]=Ajoute des fichiers texte à votre Palm, approprié pour les lecteurs de DOC.
+Comment[fy]=Heakket tekstfjilden ta oan jo handheld, geskikt faor DOC-lêzers.
+Comment[gl]=Engade ficheiros de texto ao seu aparello de man, axeitado para os lectores DOC.
+Comment[hu]=Szöveges fájlok hozzáadása a kézi számítógéphez, DOC-olvasók számára.
+Comment[is]=Bætir textaskrám, sem hægt er að lesa í DOC lesara, við lófatölvuna þína.
+Comment[it]=Aggiunge file di testo al tuo Pilot, adatti per lettori DOC.
+Comment[ja]=テキストファイルを DOC リーダーに適した形式でハンドヘルドに追加します。
+Comment[ka]=უმატებს ტექსტურ ფაილებს თქვენს პროტატიულ მოწყობილობას, რომელიც შესაფერისია DOC წამკითხავებისთვის
+Comment[kk]=DOC файлды оқи алатын қалта құрылғыға мәтінді көшіру.
+Comment[km]=បន្ថែម​ឯកសារ​អត្ថបទ​ទៅ​ឧបករណ៍​យួរ​ដៃ​របស់​អ្នក (សមស្រប​សម្រាប់​កម្មវិធី​អាន DOC) ។
+Comment[lt]=Prideda teksto bylas prie Jūsų nešiojamos knygelės, tinka DOC skaityklėms.
+Comment[ms]=Menambah fail teks ke komputer telapak, sesuai dengan pembaca DOC.
+Comment[nb]=Legger til tekstfiler på PDA-en, som passer for DOC-lesere.
+Comment[nds]=Föögt Textdateien op den Handreekner to, de för DOC-Kiekers passt.
+Comment[ne]=DOC रिडरका लागि उपयुक्त हुने पाठ फाइल तपाईँको ह्यान्डहेल्डमा थप्दछ ।
+Comment[nl]=Voegt tekstvelden toe aan uw handheld, geschikt voor DOC-lezers.
+Comment[nn]=Legg til tekstfiler på den handhaldne, passar til DOC-lesarar.
+Comment[pl]=Dodaje pliki tekstowe do Twojego palmtopa, w postaci odpowiedniej dla przeglądarek DOC.
+Comment[pt]=Adiciona ficheiros de texto ao seu PDA, indicado para os leitores de DOC.
+Comment[pt_BR]=Adiciona arquivos de texto ao seu handheld, adequado para leitors de DOC.
+Comment[ru]=Перенос текстовых файлов на КПК.
+Comment[sk]=Pridá textové súbory do ručného zariadenia, vhodné pre čítanie DOC.
+Comment[sl]=V vaš ročni računalnik doda besedilne datoteke, primerne za bralnike DOC.
+Comment[sr]=Додаје текстуалне фајлове вашем ручном рачунару, погодне за DOC читаче.
+Comment[sr@Latn]=Dodaje tekstualne fajlove vašem ručnom računaru, pogodne za DOC čitače.
+Comment[sv]=Lägger till textfiler i en handdator, lämpliga för DOC-läsare.
+Comment[ta]=DOC படிப்பவர்களுக்கு பொருத்தமான உங்கள் பைலட்டுக்குரிய உரை கோப்புகளை சேர்க்கும்
+Comment[tr]=Metin dosyalarını el bilgisayarınıza ekler, DOC biçimi okuyucuları için uygundur.
+Comment[uk]=Додає текстові файли до вашого кишенькового пристрою так, що вони читатимуться у переглядачах DOC.
+Comment[zh_CN]=将文本文件添加到您的手持设备中,以便适合 DOC 阅读程序。
+Comment[zh_TW]=新增文字到您的 handheld。
+Name=Palm DOC
+Name[ca]=DOC de Palm
+Name[cy]=DOC Palm
+Name[de]=Palm-DOC
+Name[fa]=رایانۀ جیبی DOC
+Name[hi]=पॉम डॉक
+Name[nds]=Palm-DOC
+Name[ne]=पाल्म DOC
+Name[pt]=DOC do Palm
+Name[ta]=பாம் ஆவணம்
+Implemented=file
+ServiceTypes=KPilotConduit
+X-KDE-Library=conduit_doc
diff --git a/kpilot/conduits/docconduit/docconduit.kcfg b/kpilot/conduits/docconduit/docconduit.kcfg
new file mode 100644
index 000000000..6301f4595
--- /dev/null
+++ b/kpilot/conduits/docconduit/docconduit.kcfg
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kpilot_docconduitrc"/>
+ <group name="General">
+ <entry name="TXTDirectory" key="TXT Directory" type="Path"/>
+ <entry name="PDBDirectory" key="PDB Directory" type="Path"/>
+ <entry name="KeepPDBsLocally" key="Keep PDBs locally" type="Bool">
+ <default>false</default>
+ </entry>
+ <entry name="LocalSync" key="Sync only locally" type="Bool">
+ <default>false</default>
+ </entry>
+ <entry name="ConflictResolution" key="Conflict Resolution" type="UInt">
+ <default>0</default>
+ </entry>
+ <entry name="ConvertBookmarks" key="Convert Bookmarks" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry name="BmkFileBookmarks" key="Bmk file bookmarks" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry name="InlineBookmarks" key="Inline bookmarks" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry name="EndtagBookmarks" key="Endtag bookmarks" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry name="Compress" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry name="SyncDirection" key="Sync Direction" type="UInt">
+ <default>1</default>
+ </entry>
+ <entry name="IgnoreBmkChanges" key="Ignore only bookmark changes" type="Bool">
+ <default>false</default>
+ </entry>
+ <entry name="AlwaysShowResolutionDialog" key="Always show resolution dialog" type="Bool">
+ <default>false</default>
+ </entry>
+ <entry name="BookmarksToPC" key="Bookmarks to PC" type="UInt">
+ <default>0</default>
+ </entry>
+ <entry name="ConvertedDOCfiles" key="Converted PalmDOCs" type="StringList">
+ <default></default>
+ </entry>
+ <entry name="Encoding" type="String">
+ <default>ISO8859-15</default>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kpilot/conduits/docconduit/docconduitSettings.kcfgc b/kpilot/conduits/docconduit/docconduitSettings.kcfgc
new file mode 100644
index 000000000..2a9a3a0f7
--- /dev/null
+++ b/kpilot/conduits/docconduit/docconduitSettings.kcfgc
@@ -0,0 +1,7 @@
+File=docconduit.kcfg
+ClassName=DOCConduitSettings
+Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/conduits/docconduit/kpalmdoc.cpp b/kpilot/conduits/docconduit/kpalmdoc.cpp
new file mode 100644
index 000000000..55956cf48
--- /dev/null
+++ b/kpilot/conduits/docconduit/kpalmdoc.cpp
@@ -0,0 +1,58 @@
+/* converter.cpp
+**
+** Copyright (C) 2003 by Reinhold Kainhofer
+**
+** This is the main program of the KDE PalmDOC converter.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <kapplication.h>
+
+#include "kpalmdoc_dlg.h"
+
+
+
+int main(int argc, char *argv[])
+{
+
+ KAboutData about("converter", I18N_NOOP("KPalmDOC"), "-0.0.1",
+ "KPalmDOC - KDE Converter for PalmDOC texts.\n\n",
+ KAboutData::License_GPL, "(c) 2003, Reinhold Kainhofer");
+ about.addAuthor("Reinhold Kainhofer", I18N_NOOP("Main Developer"),
+ "[email protected]", "http://reinhold.kainhofer.com/Linux/");
+ about.addCredit("Adriaan de Groot", I18N_NOOP("Maintainer of KPilot"),
+ "[email protected]", "http://www.kpilot.org/");
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KApplication::addCmdLineOptions();
+
+ KApplication app;
+ ConverterDlg *dlg=new ConverterDlg(0L, i18n("PalmDOC Converter"));
+ dlg->show();
+ return app.exec();
+}
+
diff --git a/kpilot/conduits/docconduit/kpalmdoc.desktop b/kpilot/conduits/docconduit/kpalmdoc.desktop
new file mode 100644
index 000000000..df897fb7d
--- /dev/null
+++ b/kpilot/conduits/docconduit/kpalmdoc.desktop
@@ -0,0 +1,65 @@
+# KDE Config File
+[Desktop Entry]
+Name=KPalmDOC
+Name[hi]=के-पॉम-डॉक
+Name[sv]=Kpalm DOC
+Name[ta]=கேகைdoc
+GenericName=PalmDOC Converter
+GenericName[af]=PalmDOC omskakelaar
+GenericName[bg]=Конвертиране на PalmDOC
+GenericName[bs]=PalmDOC konverter
+GenericName[ca]=Convertidor a PalmDOC
+GenericName[cs]=Konvertor PalmDoc
+GenericName[cy]=Trosiadydd PalmDOC
+GenericName[da]=PalmDOC konverterer
+GenericName[de]=PalmDOC-Konvertierung
+GenericName[el]=Μετατροπέας PalmDOC
+GenericName[eo]=PalmDOC-konvertilo
+GenericName[es]=Conversor de PalmDOC
+GenericName[et]=PalmDOC konverter
+GenericName[eu]=PalmDOC bihurtzailea
+GenericName[fa]=مبدل PalmDOC
+GenericName[fi]=PalmDOC-muunnin
+GenericName[fr]=Convertisseur PalmDOC
+GenericName[fy]=PalmDOC-oersetter
+GenericName[ga]=Tiontaire PalmDOC
+GenericName[gl]=Convertidor de PalmDOC
+GenericName[hi]=पॉम-डॉक परिवर्तक
+GenericName[hu]=PalmDOC-konverter
+GenericName[is]=PalmDOC umbreytir
+GenericName[it]=Convertitore PalmDOC
+GenericName[ja]= PalmDOC コンバータ
+GenericName[ka]=კონვერტორი PalmDOC
+GenericName[kk]=PalmDOC аударғышы
+GenericName[km]=កម្មវិធី​បម្លែង PalmDOC
+GenericName[lt]=PalmDOC konverteris
+GenericName[ms]=Penukar PalmDOC
+GenericName[nb]=PalmDOC-konvertering
+GenericName[nds]=PalmDOC-Ümwanneln
+GenericName[ne]=PalmDOC रुपान्तरणकर्ता
+GenericName[nl]=PalmDOC-conversie
+GenericName[nn]=PalmDOC-omformar
+GenericName[pl]=Konwerter formatu PalmDOC
+GenericName[pt]=Conversor de PalmDOC
+GenericName[pt_BR]=Conversor para PalmDOC
+GenericName[ro]=Convertor PalmDOC
+GenericName[ru]=Конвертер PalmDOC
+GenericName[sk]=PalmDOC prevod
+GenericName[sl]=Pretvornik v PalmDOC
+GenericName[sr]=PalmDOC конвертор
+GenericName[sr@Latn]=PalmDOC konvertor
+GenericName[sv]=Konvertering av Palm DOC
+GenericName[ta]=பாம்DOC மாற்றி
+GenericName[tg]=Конвертёри PalmDOC
+GenericName[tr]=PalmDOC Çevirici
+GenericName[uk]=Перетворювач PalmDOC
+GenericName[zh_CN]=PalmDOC 转换器
+GenericName[zh_TW]=PalmDOC 轉換器
+Exec=kpalmdoc
+Icon=kpalmdoc
+Type=Application
+DocPath=kpalmdoc/index.html
+Terminal=false
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Unique
+Categories=Qt;KDE;Utility;X-KDE-Utilities-File;Office;PDA;
diff --git a/kpilot/conduits/docconduit/kpalmdoc.kcfg b/kpilot/conduits/docconduit/kpalmdoc.kcfg
new file mode 100644
index 000000000..4d3d22119
--- /dev/null
+++ b/kpilot/conduits/docconduit/kpalmdoc.kcfg
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="converterrc"/>
+ <group name="General">
+ <entry name="TXTFolder" key="TXT folder" type="Path"/>
+ <entry name="PDBFolder" key="PDB folder" type="Path"/>
+ <entry name="SyncFolders" key="Sync folders" type="Bool">
+ <default>false</default>
+ </entry>
+ <entry name="AskOverwrite" key="Ask before overwriting files" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry name="VerboseMessages" key="Verbose messages" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry name="Compress" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry name="ConvertBookmarks" key="Convert bookmarks" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry name="BookmarksInline" key="Bookmarks inline" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry name="BookmarksEndtags" key="Bookmarks endtags" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry name="BookmarksBmk" key="Bookmarks bmk" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry name="BookmarksToPC" key="Bookmarks to PC" type="UInt">
+ <default>0</default>
+ </entry>
+ <entry name="Encoding" type="String">
+ <default>ISO8859-15</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kpilot/conduits/docconduit/kpalmdoc.upd b/kpilot/conduits/docconduit/kpalmdoc.upd
new file mode 100644
index 000000000..77d3d1eeb
--- /dev/null
+++ b/kpilot/conduits/docconduit/kpalmdoc.upd
@@ -0,0 +1,6 @@
+Id=kdepim_3.3
+File=converterrc
+Group=<default>,General
+AllKeys
+
+
diff --git a/kpilot/conduits/docconduit/kpalmdocSettings.kcfgc b/kpilot/conduits/docconduit/kpalmdocSettings.kcfgc
new file mode 100644
index 000000000..6da45c5e2
--- /dev/null
+++ b/kpilot/conduits/docconduit/kpalmdocSettings.kcfgc
@@ -0,0 +1,7 @@
+File=kpalmdoc.kcfg
+ClassName=KPalmDocSettings
+Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/conduits/docconduit/kpalmdoc_dlg.cc b/kpilot/conduits/docconduit/kpalmdoc_dlg.cc
new file mode 100644
index 000000000..5bdacba8c
--- /dev/null
+++ b/kpilot/conduits/docconduit/kpalmdoc_dlg.cc
@@ -0,0 +1,529 @@
+/* kpalmdoc_dlg.cpp
+**
+** Copyright (C) 2003 by Reinhold Kainhofer
+**
+** This is the main dialog of the KDE PalmDOC converter.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+#include "options.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <iostream>
+
+#include <qtabwidget.h>
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+#include <qbuttongroup.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kaboutapplication.h>
+#include <kapplication.h>
+#include <kurlrequester.h>
+#include <kmessagebox.h>
+#include <kcharsets.h>
+
+#include <pilotLocalDatabase.h>
+
+#include "kpalmdoc_dlg.h"
+#include "kpalmdoc_dlgbase.h"
+#include "DOC-converter.h"
+#include "kpalmdocSettings.h"
+
+
+ConverterDlg::ConverterDlg( QWidget *parent, const QString& caption)
+ : KDialogBase( parent, "converterdialog", false, caption, KDialogBase::Close|KDialogBase::Help|KDialogBase::User1,
+ KDialogBase::Close, true, i18n("&About"))
+{
+ QWidget *page = makeHBoxMainWidget();
+ dlg=new ConverterDlgBase(page);
+ QStringList l = KGlobal::charsets()->descriptiveEncodingNames();
+ for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it)
+ {
+ dlg->fEncoding->insertItem(*it);
+ }
+
+ readSettings();
+
+ connect(dlg->fDirectories, SIGNAL(toggled(bool)),
+ this, SLOT(slotDirectories(bool)));
+ connect(dlg->fTextToPDB, SIGNAL(clicked()), this, SLOT(slotToPDB()));
+ connect(dlg->fPDBToText, SIGNAL(clicked()), this, SLOT(slotToText()));
+
+ resize(minimumSize());
+}
+
+ConverterDlg::~ConverterDlg()
+{
+ // no need to delete child widgets, Qt does it all for us
+}
+void ConverterDlg::writeSettings()
+{
+ // General page
+ KPalmDocSettings::setTXTFolder( dlg->fTXTDir->url() );
+ KPalmDocSettings::setPDBFolder( dlg->fPDBDir->url() );
+ KPalmDocSettings::setSyncFolders( dlg->fDirectories->isChecked() );
+ KPalmDocSettings::setAskOverwrite( dlg->fAskOverwrite->isChecked() );
+ KPalmDocSettings::setVerboseMessages( dlg->fVerbose->isChecked() );
+ KPalmDocSettings::setEncoding( dlg->fEncoding->currentText() );
+
+ // PC->Handheld page
+ KPalmDocSettings::setCompress( dlg->fCompress->isChecked() );
+ KPalmDocSettings::setConvertBookmarks( dlg->fConvertBookmarks->isChecked() );
+ KPalmDocSettings::setBookmarksInline( dlg->fBookmarksInline->isChecked() );
+ KPalmDocSettings::setBookmarksEndtags( dlg->fBookmarksEndtags->isChecked() );
+ KPalmDocSettings::setBookmarksBmk( dlg->fBookmarksBmk->isChecked() );
+
+ // Handheld->PC page
+ KPalmDocSettings::setBookmarksToPC( dlg->fPCBookmarks->id(dlg->fPCBookmarks->selected()) );
+
+ KPalmDocSettings::self()->writeConfig();
+}
+
+void ConverterDlg::readSettings()
+{
+ FUNCTIONSETUP;
+
+ KPalmDocSettings::self()->readConfig();
+
+ // General Page:
+ dlg->fTXTDir->setURL(KPalmDocSettings::tXTFolder());
+ dlg->fPDBDir->setURL(KPalmDocSettings::pDBFolder());
+ bool dir=KPalmDocSettings::syncFolders();
+ dlg->fDirectories->setChecked(dir);
+ slotDirectories(dir);
+ dlg->fAskOverwrite->setChecked( KPalmDocSettings::askOverwrite() );
+ dlg->fVerbose->setChecked( KPalmDocSettings::verboseMessages() );
+ QString encoding = KPalmDocSettings::encoding();
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Encoding=" << encoding << endl;
+#endif
+ dlg->fEncoding->setCurrentText( KPalmDocSettings::encoding() );
+
+ // PC->Handheld page
+ dlg->fCompress->setChecked(KPalmDocSettings::compress() );
+ dlg->fConvertBookmarks->setChecked(KPalmDocSettings::convertBookmarks());
+ dlg->fBookmarksInline->setChecked(KPalmDocSettings::bookmarksInline());
+ dlg->fBookmarksEndtags->setChecked(KPalmDocSettings::bookmarksEndtags());
+ dlg->fBookmarksBmk->setChecked(KPalmDocSettings::bookmarksBmk());
+
+ // Handheld->PC page
+ dlg->fPCBookmarks->setButton(KPalmDocSettings::bookmarksToPC() );
+}
+
+void ConverterDlg::slotClose()
+{
+ writeSettings();
+ kapp->quit();
+ delete this;
+}
+
+void ConverterDlg::slotToText()
+{
+ FUNCTIONSETUP;
+ // First, get the settings from the controls and initialize
+ // the converter object
+ int bmks=dlg->fPCBookmarks->id(dlg->fPCBookmarks->selected());
+ DOCConverter conv;
+ switch(bmks) {
+ case 0: conv.setBookmarkTypes(DOCConverter::eBmkNone); break;
+ case 1: conv.setBookmarkTypes(DOCConverter::eBmkInline); break;
+ case 2: conv.setBookmarkTypes(DOCConverter::eBmkEndtags); break;
+ case 3: conv.setBookmarkTypes(DOCConverter::eBmkDefaultBmkFile); break;
+ default:
+ break;
+ }
+
+ askOverwrite=dlg->fAskOverwrite->isChecked();
+ verbose=dlg->fVerbose->isChecked();
+
+
+ bool dir=dlg->fDirectories->isChecked();
+ QString txturl=dlg->fTXTDir->url();
+ QString pdburl=dlg->fPDBDir->url();
+
+ QFileInfo txtinfo(txturl);
+ QFileInfo pdbinfo(pdburl);
+
+ if (dir)
+ {
+ if (pdbinfo.isFile())
+ {
+ int res=KMessageBox::questionYesNo(this,
+ i18n("<qt>You selected to sync folders, "
+ "but gave a filename instead (<em>%1</em>)."
+ "<br>Use folder <em>%2</em> instead?</qt>").arg(pdburl)
+ .arg(pdbinfo.dirPath(true)), QString::null, i18n("Use Folder"), KStdGuiItem::cancel());
+ if (res==KMessageBox::Yes)
+ {
+ pdburl=pdbinfo.dirPath(true);
+ pdbinfo.setFile(pdburl);
+ }
+ else return;
+ }
+
+ if (!pdbinfo.isDir())
+ {
+ // no directory, so error message and return
+ KMessageBox::sorry(this,
+ i18n("<qt>The folder <em>%1</em> for "
+ "the handheld database files is not a valid "
+ "folder.</qt>").arg(pdburl));
+ return;
+ }
+
+ if (!pdbinfo.exists())
+ {
+ KMessageBox::sorry(this,
+ i18n("<qt>The folder <em>%1</em> for "
+ "the handheld database files is not a "
+ "valid directory.</qt>").arg(pdburl));
+ return;
+ }
+
+
+ // Now check the to directory:
+ if (txtinfo.isFile())
+ {
+ int res=KMessageBox::questionYesNo(this,
+ i18n("<qt>You selected to sync folders, "
+ "but gave a filename instead (<em>%1</em>)."
+ "<br>Use folder <em>%2</em> instead?</qt>").arg(txturl)
+ .arg(txtinfo.dirPath(true)), QString::null, i18n("Use Folder"), KStdGuiItem::cancel());
+ if (res==KMessageBox::Yes) {
+ txturl=txtinfo.dirPath(true);
+ txtinfo.setFile(txturl);
+ }
+ else return;
+ }
+
+ // Now that we have a directory path, try to create it:
+ if (!txtinfo.isDir()) {
+ txtinfo.dir().mkdir(txturl, true);
+ }
+ if (!txtinfo.isDir()) {
+ KMessageBox::sorry(this,
+ i18n("<qt>The folder <em>%1</em> for "
+ "the text files could not be created.</qt>").arg(txturl));
+ return;
+ }
+
+
+ // Now that we have both directories, create the converter object
+ DEBUGKPILOT<<"Pdbinfo.dir="<<pdbinfo.dir().absPath()<<endl;
+ DEBUGKPILOT<<"txtinfo.dir="<<txtinfo.dir().absPath()<<endl;
+ QStringList pdbfiles(pdbinfo.dir().entryList(CSL1("*.pdb")));
+ QStringList converted_Files;
+
+ DEBUGKPILOT<<"Length of filename list: "<<pdbfiles.size()<<endl;
+ for ( QStringList::Iterator it = pdbfiles.begin(); it != pdbfiles.end(); ++it )
+ {
+ QString txtfile=QFileInfo(*it).baseName(true)+CSL1(".txt");
+ DEBUGKPILOT<<"pdbfile="<<*it<<", pdbdir="<<pdburl<<", txtfile="<<txtfile<<", txtdir="<<txturl<<endl;
+ if (convertPDBtoTXT(pdburl, *it, txturl, txtfile, &conv))
+ {
+ converted_Files.append(*it);
+ }
+ }
+ if (converted_Files.size()>0) {
+ KMessageBox::informationList(this, i18n("The following texts were "
+ "successfully converted:"), converted_Files, i18n("Conversion Successful"));
+ }
+ else
+ {
+ KMessageBox::sorry(this, i18n("No text files were converted correctly"));
+ }
+
+
+ } else { // no dir
+
+
+ // Check the from file
+ if (!pdbinfo.isFile() || !pdbinfo.exists())
+ {
+ KMessageBox::sorry(this, i18n("<qt>The file <em>%1</em> does not "
+ "exist.</qt>").arg(pdburl));
+ return;
+ }
+
+ // Now check the to file
+/* // I can't check if a given filename is a valid filename
+ if (!txtinfo.isFile())
+ {
+ KMessageBox::sorry(this, i18n("<qt>The filename <em>%1</em> for the "
+ "text is not a valid filename.</qt>").arg(txturl));
+ return;
+ }*/
+ if (convertPDBtoTXT(pdbinfo.dirPath(true), pdbinfo.fileName(),
+ txtinfo.dirPath(true), txtinfo.fileName(), &conv) )
+ {
+ KMessageBox::information(this, i18n("Conversion of file %1 successful.").arg(pdburl));
+ }
+
+ }
+
+}
+
+void ConverterDlg::slotToPDB()
+{
+ FUNCTIONSETUP;
+ // First, get the settings from the controls and initialize
+ // the converter object
+ bool compress=dlg->fCompress->isChecked();
+ int bmks=0;
+ if (dlg->fConvertBookmarks->isChecked())
+ {
+ if (dlg->fBookmarksInline->isChecked()) bmks|=DOCConverter::eBmkInline;
+ if (dlg->fBookmarksEndtags->isChecked()) bmks|=DOCConverter::eBmkEndtags;
+ if(dlg->fBookmarksBmk->isChecked()) bmks|=DOCConverter::eBmkDefaultBmkFile;
+ }
+ DOCConverter conv;
+ conv.setBookmarkTypes(bmks);
+ conv.setCompress(compress);
+ conv.setSort(DOCConverter::eSortName);
+
+
+ askOverwrite=dlg->fAskOverwrite->isChecked();
+ verbose=dlg->fVerbose->isChecked();
+
+
+ bool dir=dlg->fDirectories->isChecked();
+ QString txturl=dlg->fTXTDir->url();
+ QString pdburl=dlg->fPDBDir->url();
+
+ QFileInfo txtinfo(txturl);
+ QFileInfo pdbinfo(pdburl);
+
+ if (dir)
+ {
+ if (txtinfo.isFile())
+ {
+ int res=KMessageBox::questionYesNo(this,
+ i18n("<qt>You selected to sync folders, "
+ "but gave a filename instead (<em>%1</em>)."
+ "<br>Use folder <em>%2</em> instead?</qt>").arg(txturl)
+ .arg(txtinfo.dirPath(true)), QString::null, i18n("Use Folder"), KStdGuiItem::cancel());
+ if (res==KMessageBox::Yes)
+ {
+ txturl=txtinfo.dirPath(true);
+ txtinfo.setFile(txturl);
+ }
+ else return;
+ }
+
+ if (!txtinfo.isDir() || !txtinfo.exists())
+ {
+ KMessageBox::sorry(this,
+ i18n("<qt>The folder <em>%1</em> for "
+ "the text files is not a valid folder.</qt>").arg(txturl));
+ return;
+ }
+
+
+ // Now check the to directory:
+ if (pdbinfo.isFile())
+ {
+ int res=KMessageBox::questionYesNo(this,
+ i18n("<qt>You selected to sync folders, "
+ "but gave a filename instead (<em>%1</em>)."
+ "<br>Use folder <em>%2</em> instead?</qt>")
+ .arg(pdburl)
+ .arg(pdbinfo.dirPath(true)), QString::null, i18n("Use Folder"), KStdGuiItem::cancel());
+ if (res==KMessageBox::Yes) {
+ pdburl=pdbinfo.dirPath(true);
+ pdbinfo.setFile(pdburl);
+ }
+ else return;
+ }
+
+ // Now that we have a directory path, try to create it:
+ if (!pdbinfo.isDir()) {
+ pdbinfo.dir().mkdir(pdburl, true);
+ }
+ if (!pdbinfo.isDir()) {
+ KMessageBox::sorry(this, i18n("<qt>The folder <em>%1</em> for "
+ "the PalmDOC files could not be created.</qt>").arg(pdburl));
+ return;
+ }
+
+
+ // Now that we have both directories, create the converter object
+ DEBUGKPILOT<<"Pdbinfo.dir="<<pdbinfo.dir().absPath()<<endl;
+ DEBUGKPILOT<<"txtinfo.dir="<<txtinfo.dir().absPath()<<endl;
+ QStringList txtfiles(txtinfo.dir().entryList(CSL1("*.txt")));
+ QStringList converted_Files;
+
+ DEBUGKPILOT<<"Length of filename list: "<<txtfiles.size()<<endl;
+ for ( QStringList::Iterator it = txtfiles.begin(); it != txtfiles.end(); ++it )
+ {
+ QString pdbfile=QFileInfo(*it).baseName(true)+CSL1(".pdb");
+ DEBUGKPILOT<<"pdbfile="<<pdbfile<<", pdbdir="<<pdburl<<", txtfile="<<*it<<", txtdir="<<txturl<<endl;
+ if (convertTXTtoPDB(txturl, *it, pdburl, pdbfile, &conv))
+ {
+ converted_Files.append(*it);
+ }
+ }
+ if (converted_Files.size()>0) {
+ KMessageBox::informationList(this, i18n("The following texts were "
+ "successfully converted:"), converted_Files, i18n("Conversion Successful"));
+ }
+ else
+ {
+ KMessageBox::sorry(this, i18n("No text files were converted correctly"));
+ }
+
+
+ } else { // no dir
+
+
+ // Check the from file
+ if (!txtinfo.isFile() || !txtinfo.exists())
+ {
+ KMessageBox::sorry(this, i18n("<qt>The file <em>%1</em> does not "
+ "exist.</qt>").arg(txturl));
+ return;
+ }
+
+ if (convertTXTtoPDB(txtinfo.dirPath(true), txtinfo.fileName(),
+ pdbinfo.dirPath(true), pdbinfo.fileName(), &conv) )
+ {
+ KMessageBox::information(this, i18n("Conversion of file %1 successful.").arg(txturl));
+ }
+
+ }
+
+}
+
+
+void ConverterDlg::slotUser1()
+{
+ KAboutApplication ab(KGlobal::instance()->aboutData(), this);
+ ab.show();
+ ab.exec();
+ return;
+}
+
+void ConverterDlg::slotDirectories(bool dir)
+{
+ FUNCTIONSETUP;
+ DEBUGKPILOT<<"Slot Directories: "<<dir<<endl;
+ if (dir)
+ {
+ dlg->fTextLabel->setText(i18n("&Text folder:"));
+ dlg->fPdbLabel->setText(i18n("&PalmDOC folder:"));
+ dlg->fTXTDir->setMode(KFile::LocalOnly | KFile::Directory);
+ dlg->fPDBDir->setMode(KFile::LocalOnly | KFile::Directory);
+ } else {
+ dlg->fTextLabel->setText(i18n("&Text file:"));
+ dlg->fPdbLabel->setText(i18n("&DOC file:"));
+ dlg->fTXTDir->setMode(KFile::LocalOnly | KFile::File);
+ dlg->fPDBDir->setMode(KFile::LocalOnly | KFile::File);
+ }
+}
+
+bool ConverterDlg::convertTXTtoPDB(QString txtdir, QString txtfile,
+ QString pdbdir, QString pdbfile, DOCConverter*conv)
+{
+ FUNCTIONSETUP;
+ bool res=false;
+ QFileInfo dbfileinfo(pdbdir, pdbfile);
+ DEBUGKPILOT<<"Working on file "<<pdbfile<<endl;
+ if (!dbfileinfo.exists() || !askOverwrite ||
+ (KMessageBox::Yes==KMessageBox::questionYesNo(this,
+ i18n("<qt>The database file <em>%1</em> already exists. Overwrite it?</qt>")
+ .arg(dbfileinfo.filePath()), QString::null, i18n("Overwrite"), KStdGuiItem::cancel() ) ))
+ {
+ PilotLocalDatabase*pdbdb=new PilotLocalDatabase(pdbdir, QFileInfo(pdbfile).baseName(), false);
+ if (pdbdb)
+ {
+ if (!pdbdb->isOpen())
+ {
+#ifdef DEBUG
+ DEBUGKPILOT<<pdbfile<<" does not yet exist. Creating it"<<endl;
+#endif
+ if (!pdbdb->createDatabase(get_long("REAd"), get_long("TEXt")) ) {
+ }
+ }
+
+ if (pdbdb->isOpen())
+ {
+ conv->setPDB(pdbdb);
+ conv->setTXTpath(txtdir, txtfile);
+ DEBUGKPILOT<<"Converting "<<txtfile<<" (dir "<<txtdir<<") to "<<dbfileinfo.filePath()<<endl;
+ if (conv->convertTXTtoPDB()) res=true;
+ }
+ delete pdbdb;
+ }
+ if ( !res && verbose )
+ {
+ KMessageBox::sorry(this, i18n("<qt>Error while converting the text %1.</qt>").arg(txtfile));
+ }
+ }
+ else
+ {
+ DEBUGKPILOT<<"Ignoring the file "<<txtfile<<endl;
+ }
+ return res;
+}
+
+bool ConverterDlg::convertPDBtoTXT(QString pdbdir, QString pdbfile,
+ QString txtdir, QString txtfile, DOCConverter*conv)
+{
+ FUNCTIONSETUP;
+ bool res=false;
+ QFileInfo txtfileinfo(txtdir, txtfile);
+ DEBUGKPILOT<<"Working on file "<<txtfile<<endl;
+ if (!txtfileinfo.exists() || !askOverwrite ||
+ (KMessageBox::Yes==KMessageBox::questionYesNo(this,
+ i18n("<qt>The text file <em>%1</em> already exists. Overwrite it?</qt>")
+ .arg(txtfileinfo.filePath()), QString::null, i18n("Overwrite"), KStdGuiItem::cancel() ) ))
+ {
+ PilotLocalDatabase*pdbdb=new PilotLocalDatabase(pdbdir, QFileInfo(pdbfile).baseName(), false);
+ if (pdbdb)
+ {
+ if (pdbdb->isOpen())
+ {
+ conv->setPDB(pdbdb);
+ conv->setTXTpath(txtdir, txtfile);
+ DEBUGKPILOT<<"Converting "<<txtfile<<" (dir "<<txtdir<<") from "<<pdbfile<<" (dir "<<pdbdir<<")"<<endl;
+ if (conv->convertPDBtoTXT()) res=true;
+ }
+ delete pdbdb;
+ }
+ if ( !res && verbose )
+ {
+ KMessageBox::sorry(this, i18n("<qt>Error while converting the text %1.</qt>").arg(pdbfile));
+ }
+ }
+ else
+ {
+ DEBUGKPILOT<<"Ignoring the file "<<pdbfile<<endl;
+ }
+ return res;
+
+}
+
+#include "kpalmdoc_dlg.moc"
diff --git a/kpilot/conduits/docconduit/kpalmdoc_dlg.h b/kpilot/conduits/docconduit/kpalmdoc_dlg.h
new file mode 100644
index 000000000..410b24568
--- /dev/null
+++ b/kpilot/conduits/docconduit/kpalmdoc_dlg.h
@@ -0,0 +1,67 @@
+/* kpalmdoc_dlg.cpp
+**
+** Copyright (C) 2003 by Reinhold Kainhofer
+**
+** This is the main dialog of the KDE PalmDOC converter.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+#ifndef CONVERTERDLG_H
+#define CONVERTERDLG_H
+
+#include <kdialogbase.h>
+class ConverterDlgBase;
+class DOCConverter;
+
+class ConverterDlg : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ ConverterDlg( QWidget *parent=0, const QString& caption=0);
+ ~ConverterDlg();
+
+protected slots:
+ virtual void slotClose();
+ void slotToText();
+ void slotToPDB();
+ void slotDirectories(bool dir);
+ void slotUser1();
+protected:
+ void writeSettings();
+ void readSettings();
+
+ // These two functions convert one single file to or from a pdb database
+ bool convertTXTtoPDB(QString txtdir, QString txtfile,
+ QString pdbdir, QString pdbfile, DOCConverter*conv);
+ bool convertPDBtoTXT(QString pdbdir, QString pdbfile,
+ QString txtdir, QString txtfile, DOCConverter*conv);
+
+
+ // The actual dialog widget (designer created) holding all controls
+ ConverterDlgBase*dlg;
+ // Settings
+ bool askOverwrite;
+ bool verbose;
+};
+
+#endif // CONVERTERDLG_H
diff --git a/kpilot/conduits/docconduit/kpalmdoc_dlgbase.ui b/kpilot/conduits/docconduit/kpalmdoc_dlgbase.ui
new file mode 100644
index 000000000..8b3e89668
--- /dev/null
+++ b/kpilot/conduits/docconduit/kpalmdoc_dlgbase.ui
@@ -0,0 +1,435 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>ConverterDlgBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ConverterDlgBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>492</width>
+ <height>339</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>fPdbLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;PalmDOC file:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fPDBDir</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>fTextLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Text file:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fTXTDir</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fDirectories</cstring>
+ </property>
+ <property name="text">
+ <string>Convert whole &amp;folders</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fPDBDir</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Folder where copies of the handheld databases are kept. You can install them to any PalmOS handheld, and distribute these copies to other people (but beware of copyright infringement).</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fAskOverwrite</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Ask before overwriting files</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fVerbose</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Verbose messages</string>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="7" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fTextToPDB</cstring>
+ </property>
+ <property name="text">
+ <string>Convert Text to PalmDOC</string>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="7" column="2">
+ <property name="name">
+ <cstring>fPDBToText</cstring>
+ </property>
+ <property name="text">
+ <string>Convert PalmDOC to Text</string>
+ </property>
+ </widget>
+ <spacer row="6" column="1">
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KURLRequester" row="0" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fTXTDir</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the name of the folder where the text files reside on the PC. All files with extension .txt will be synced to the handheld.</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="5" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fEncoding</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Encoding:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fEncoding</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>PC -&gt; Handheld</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="4" column="0">
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="2" column="1">
+ <property name="name">
+ <cstring>fBookmarksInline</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Inline tags in text</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>When a &lt;* bookmarktext *&gt; appears somewhere in the text, a bookmark will be set at this position, and the text between the &lt;* and the *&gt; will be used as bookmark name. The &lt;*...*&gt; will be removed from the text.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="1">
+ <property name="name">
+ <cstring>fBookmarksEndtags</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Tags at end of text</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Tags of the form &lt;bookmarkname&gt; at the end of the text will be used to search the text for the pattern between the &lt; and &gt;. Whenever "bookmarkname" appears in the text, a bookmark will be set there. The endtags &lt;...&gt; will then be removed from the end of the text.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fCompress</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Compress</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Check this box, if the text should be compressed on the handheld to save memory. Most doc reader on the handheld support compressed texts.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The Palm doc format supports compressing the text to save memory. If you check this box, the text will consume about 50% less memory than in uncompressed state. Almost all DOC readers on the Palm support compressed texts.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fConvertBookmarks</cstring>
+ </property>
+ <property name="text">
+ <string>Convert &amp;bookmarks</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Do you want to convert bookmarks? Most doc readers support bookmarks. You have to provide some information about where the bookmarks should be set and their titles. Check at least one of the bookmark types below.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="1">
+ <property name="name">
+ <cstring>fBookmarksBmk</cstring>
+ </property>
+ <property name="text">
+ <string>Regular &amp;expressions in .bmk file</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Use regular expressions in a file textname.bmk (textname.txt is the filename of the text) to search the text for bookmarks.See the documentation for a description of the format of the bmk file.</string>
+ </property>
+ </widget>
+ <spacer row="5" column="1">
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>200</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Handheld -&gt; PC</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>190</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QButtonGroup" row="0" column="0">
+ <property name="name">
+ <cstring>fPCBookmarks</cstring>
+ </property>
+ <property name="title">
+ <string>Convert Bookmarks</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>radioButton9</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Convert as &amp;inline tags</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>radioButton8</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Do &amp;not convert bookmarks</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="2" column="0">
+ <property name="name">
+ <cstring>radioButton10</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Convert as &amp;end tags</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="3" column="0">
+ <property name="name">
+ <cstring>radioButton11</cstring>
+ </property>
+ <property name="text">
+ <string>Convert into .bmk &amp;file</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>fConvertBookmarks</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>fBookmarksInline</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>fConvertBookmarks</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>fBookmarksEndtags</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>fConvertBookmarks</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>fBookmarksBmk</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includes>
+ <include location="global" impldecl="in implementation">kurlrequester.h</include>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+ <include location="global" impldecl="in implementation">kpushbutton.h</include>
+</includes>
+</UI>
diff --git a/kpilot/conduits/docconduit/makedoc9.cc b/kpilot/conduits/docconduit/makedoc9.cc
new file mode 100644
index 000000000..1f1c56ff1
--- /dev/null
+++ b/kpilot/conduits/docconduit/makedoc9.cc
@@ -0,0 +1,405 @@
+// based on: MakeDoc, version 2
+// I only took the tBuf class from there and adapted it.
+//
+// Compresses text files into a format that is ready to export to a Pilot
+// and work with Rick Bram's PilotDOC reader.
+// Copyright (C) Reinhold Kainhofer, 2002
+// Copyrigth (C) Pat Beirne, 2000
+//
+// Original file (makedoc9.cpp) copyright by:
+// Copyright (C) Pat Beirne, 2000.
+// Distributable under the GNU General Public License Version 2 or later.
+//
+// ver 0.6 enforce 31 char limit on database names
+// ver 0.7 change header and record0 to structs
+// ver 2.0 added category control on the command line
+// changed extensions from .prc to .pdb
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <iostream>
+
+
+#include "makedoc9.h"
+
+
+
+//
+// Issue()
+//
+// action: handle the details of writing a single
+// character to the compressed stream
+//
+unsigned
+ tBuf::Issue(byte src, int &bSpace)
+{
+ unsigned int iDest = len;
+ byte *dest = buf;
+
+ // TODO: which of the if parts should really be included???
+#if 0
+ // modified version of issue
+ // just issue the char
+ if (src >= 0x80 || src <= 8)
+ dest[iDest++] = 1;
+ dest[iDest++] = src;
+
+#else
+ // if there is an outstanding space char, see if
+ // we can squeeze it in with an ASCII char
+ if (bSpace)
+ {
+ if (src >= 0x40 && src <= 0x7F)
+ dest[iDest++] = src ^ 0x80;
+ else
+ {
+ // couldn't squeeze it in, so issue the space char by itself
+ // most chars go out simple, except the range 1...8,0x80...0xFF
+ dest[iDest++] = ' ';
+ if (src < 0x80 && (src == 0 || src > 8))
+ dest[iDest++] = src;
+ else
+ dest[iDest++] = 1, dest[iDest++] = src;
+ }
+ // knock down the space flag
+ bSpace = 0;
+ }
+ else
+ {
+ // check for a space char
+ if (src == ' ')
+ bSpace = 1;
+ else
+ {
+ if (src < 0x80 && (src == 0 || src > 8))
+ dest[iDest++] = src;
+ else
+ dest[iDest++] = 1, dest[iDest++] = src;
+
+ }
+ }
+#endif
+ len = iDest;
+ return iDest;
+}
+
+//
+// Compress
+//
+// params: none
+//
+// action: takes the given buffer,
+// and compresses
+// the original data down into a second buffer
+//
+// comment: This version make heavy use of walking pointers.
+//
+unsigned tBuf::Compress()
+{
+ if (!buf)
+ return 0;
+ if (isCompressed) {
+// cout<<"Buffer is already compressed!"<<endl;
+ return len;
+// } else {
+// cout<<" Compressing buffer!!!"<<endl;
+ }
+
+ unsigned int i;
+
+ // run through the input buffer
+ byte *pBuffer; // points to the input buffer
+ byte *pHit; // points to a walking test hit; works upwards on successive matches
+ byte *pPrevHit; // previous value of pHit; also, start of next test
+ byte *pTestHead; // current test string
+ byte *pTestTail; // current walking pointer; one past the current test buffer
+ byte *pEnd; // 1 past the end of the input buffer
+
+ pHit = pPrevHit = pTestHead = pBuffer = buf;
+ pTestTail = pTestHead + 1;
+ pEnd = buf + len; // should point to a 0!
+
+ // make a dest buffer and reassign the local buffer
+ buf = new byte[6000];
+ len = 0; // used to walk through the output buffer
+
+ // loop, absorbing one more char from the input buffer on each pass
+ for (; pTestHead != pEnd; pTestTail++)
+ {
+ // if we already have 10 char match, don't bother scanning again for the 11th (wasted time)
+ if (pTestTail - pTestHead != (1 << COUNT_BITS) + 3)
+ {
+ // scan in the previous data for a match
+ // terminate the test string (and the matcher string, as well!) in a 0
+ byte tmp = *pTestTail;
+
+ *pTestTail = 0;
+ pHit = (byte *) strstr((const char *) pPrevHit,
+ (const char *) pTestHead);
+ *pTestTail = tmp; // restore the char
+ }
+
+ // on a mismatch or end of buffer, issued codes
+ if (pHit == pTestHead
+ || pTestTail - pTestHead > (1 << COUNT_BITS) + 2
+ || pTestTail == pEnd)
+ {
+ // issue the codes
+ // first, check for short runs
+ if (pTestTail - pTestHead < 4)
+ {
+ if (pTestHead[0] > 0x7F || pTestHead[0] <= 8)
+ buf[len++] = 1;
+ buf[len++] = pTestHead[0];
+ pTestHead++;
+ }
+ // for longer runs, issue a run-code
+ else
+ {
+ unsigned int dist = pTestHead - pPrevHit;
+ unsigned int compound =
+ (dist << COUNT_BITS) + pTestTail - pTestHead - 4;
+
+//if (dist>=(1<<DISP_BITS)) printf("\n!! error dist overflow");
+//if (pTestTail-pTestHead-4>7) printf("\n!! error len overflow");
+
+ buf[len++] = 0x80 + (compound >> 8);
+ buf[len++] = compound & 0xFF;
+//printf("\nissuing code for sequence len %d <%c%c%c>",pTestTail-pTestHead-1,pTestHead[0],pTestHead[1],pTestHead[2]);
+//printf("\n <%x%x>",pOut[-2],pOut[-1]);
+ // and start again
+ pTestHead = pTestTail - 1;
+ }
+ // start the search again
+ pPrevHit = pBuffer;
+ // within range
+ if (pTestHead - pPrevHit > ((1 << DISP_BITS) - 1))
+ pPrevHit = pTestHead - ((1 << DISP_BITS) - 1);
+ }
+ // got a match
+ else
+ {
+ pPrevHit = pHit;
+ }
+ // when we get to the end of the buffer, don't inc past the end
+ // this forces the residue chars out one at a time
+ if (pTestTail == pEnd)
+ pTestTail--;
+ }
+
+
+ // final scan to merge consecutive high chars together
+ // and merge space chars
+ unsigned int k;
+
+ for (i = k = 0; i < len; i++, k++)
+ {
+ buf[k] = buf[i];
+ // skip the run-length codes
+ if (buf[k] >= 0x80 && buf[k] < 0xC0)
+ buf[++k] = buf[++i];
+ // if we hit a high char marker, look ahead for another
+ // and merge multiples together
+ else if (buf[k] == 1)
+ {
+ buf[k + 1] = buf[i + 1];
+ while (i + 2 < len && buf[i + 2] == 1 && buf[k] < 8)
+ {
+ buf[k]++;
+ buf[k + buf[k]] = buf[i + 3];
+ i += 2;
+ }
+ k += buf[k];
+ i++;
+ }
+ else if (buf[k] == ' ' && i < len - 1 && buf[i + 1] <= 0x7F
+ && buf[i + 1] >= 0x40)
+ buf[k] = 0x80 | buf[++i];
+ }
+
+ // delete original buffer
+ delete[]pBuffer;
+ len = k;
+
+ isCompressed = true;
+ return k;
+}
+
+/*
+ Decompress
+
+ params: none
+
+ action: make a new buffer
+ run through the source data
+ check the 4 cases:
+ 0,9...7F represent self
+ 1...8 escape n chars
+ 80...bf reference earlier run
+ c0...ff space+ASCII
+
+*/
+unsigned tBuf::Decompress()
+{
+ if (!buf)
+ return 0;
+ if (!isCompressed) {
+// cout<<"Buffer already uncompressed. Doing nothing"<<endl;
+ return len;
+// } else {
+// cout<<"Decompressing buffer"<<endl;
+ }
+
+ // we "know" that all decompresses fit within 4096, right?
+ byte *pOut = new byte[6000];
+ byte *in_buf = buf;
+ byte *out_buf = pOut;
+
+ unsigned int i, j;
+
+ for (j = i = 0; j < len;)
+ {
+ unsigned int c;
+
+ // take a char from the input buffer
+ c = in_buf[j++];
+
+ // separate the char into zones: 0, 1...8, 9...0x7F, 0x80...0xBF, 0xC0...0xFF
+
+ // codes 1...8 mean copy that many bytes; for accented chars & binary
+ if (c > 0 && c < 9)
+ while (c--)
+ out_buf[i++] = in_buf[j++];
+
+ // codes 0, 9...0x7F represent themselves
+ else if (c < 0x80)
+ out_buf[i++] = c;
+
+ // codes 0xC0...0xFF represent "space + ascii char"
+ else if (c >= 0xC0)
+ out_buf[i++] = ' ', out_buf[i++] = c ^ 0x80;
+
+ // codes 0x80...0xBf represent sequences
+ else
+ {
+ int m, n;
+
+ c <<= 8;
+ c += in_buf[j++];
+ m = (c & 0x3FFF) >> COUNT_BITS;
+ n = c & ((1 << COUNT_BITS) - 1);
+ n += 3;
+ while (n--)
+ {
+ out_buf[i] = out_buf[i - m];
+ i++;
+ }
+ }
+ }
+ out_buf[i++]='\0';
+ out_buf[i++]='\0';
+ delete[]buf;
+ buf = pOut;
+ len = i;
+
+ isCompressed = false;
+ return i;
+}
+
+unsigned tBuf::DuplicateCR()
+{
+ if (!buf)
+ return 0;
+ byte *pBuf = new byte[2 * len];
+
+ unsigned int k, j;
+
+ for (j = k = 0; j < len; j++, k++)
+ {
+ pBuf[k] = buf[j];
+ if (pBuf[k] == 0x0A)
+ pBuf[k++] = 0x0D, pBuf[k] = 0x0A;
+ }
+ delete[]buf;
+ buf = pBuf;
+ len = k;
+ return k;
+}
+
+
+
+// this nasty little beast removes really low ASCII and 0's
+// and handles the CR problem
+//
+// if a cr appears before a lf, then remove the cr
+// if a cr appears in isolation, change to a lf
+unsigned tBuf::RemoveBinary()
+{
+ if (!buf)
+ return 0;
+ byte *in_buf = buf;
+ byte *out_buf = new byte[len];
+
+ unsigned int k, j;
+
+ for (j = k = 0; j < len; j++, k++)
+ {
+ // copy each byte
+ out_buf[k] = in_buf[j];
+
+ // throw away really low ASCII
+ if (( /*out_buf[k]>=0 && */ out_buf[k] < 9))
+ k--;
+
+ // for CR
+ if (out_buf[k] == 0x0D)
+ {
+ // if next is LF, then drop it
+ if (j < len - 1 && in_buf[j + 1] == 0x0A)
+ k--;
+ else // turn it into a LF
+ out_buf[k] = 0x0A;
+ }
+ }
+ delete[]buf;
+ buf = out_buf;
+ len = k;
+ return k;
+}
+
+void tBuf::setText(const byte * text, unsigned txtlen, bool txtcomp)
+{
+ if (buf)
+ delete[]buf;
+ buf = 0L;
+
+ if (txtlen <= 0)
+ txtlen = strlen((const char *) text);
+ len = txtlen;
+ buf = new byte[len];
+
+ memcpy(buf, text, len*sizeof(char));
+// strncpy((char *) buf, (const char *) text, len);
+ isCompressed = txtcomp;
+// cout<<"Setting text, compressed="<<txtcomp<<endl;
+}
diff --git a/kpilot/conduits/docconduit/makedoc9.h b/kpilot/conduits/docconduit/makedoc9.h
new file mode 100644
index 000000000..27e3695d4
--- /dev/null
+++ b/kpilot/conduits/docconduit/makedoc9.h
@@ -0,0 +1,111 @@
+#ifndef MAKEDOC_H
+#define MAKEDOC_H
+// based on: MakeDoc, version 2
+// I only took the tBuf class from there and adapted it.
+//
+// Compresses text files into a format that is ready to export to a Pilot
+// and work with Rick Bram's PilotDOC reader.
+// Copyright (C) Reinhold Kainhofer, 2002
+// Copyrigth (C) Pat Beirne, 2000
+//
+// Original file (makedoc9.cpp) copyright by:
+// Copyright (C) Pat Beirne, 2000.
+// Distributable under the GNU General Public License Version 2 or later.
+//
+// ver 0.6 enforce 31 char limit on database names
+// ver 0.7 change header and record0 to structs
+// ver 2.0 added category control on the command line
+// changed extensions from .prc to .pdb
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+#include <stdio.h>
+
+typedef unsigned char byte;
+typedef unsigned long DWORD;
+typedef unsigned short WORD;
+
+#define DISP_BITS 11
+#define COUNT_BITS 3
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+///////////////////// //////////////////////
+///////////////////// tBuf class //////////////////////
+///////////////////// //////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+
+class tBuf {
+ private:
+// byte hichar[10];
+// int hicharnum;
+// bool space;
+
+ byte * buf;
+ unsigned len;
+ bool isCompressed;
+ public:
+ tBuf() {
+ buf = 0L;
+ len=0;
+ isCompressed=false;
+ };
+
+ ~tBuf()
+ {
+ if (buf)
+ delete[]buf;
+ }
+
+ void Clear() {
+ delete[]buf;
+ buf = 0L;
+ }
+ void setText(const byte * text, unsigned int txtlen =
+ 0, bool txtcomp = false);
+ byte *text() const {
+ return buf;
+ }
+ unsigned Len() const {
+ return len;
+ }
+ void setCompressed(bool compressed = true) {
+ isCompressed = compressed;
+ }
+ bool compressed() const {
+ return isCompressed;
+ }
+ unsigned RemoveBinary();
+ unsigned DuplicateCR();
+
+ unsigned Decompress();
+ unsigned Compress();
+
+ private:
+ unsigned Issue(byte src, int &bSpace);
+ void Dump() const {
+ printf("\nbuffer len=%d", len);
+}};
+
+
+#endif
diff --git a/kpilot/conduits/docconduit/pilotDOCBookmark.cc b/kpilot/conduits/docconduit/pilotDOCBookmark.cc
new file mode 100644
index 000000000..9b93f2af1
--- /dev/null
+++ b/kpilot/conduits/docconduit/pilotDOCBookmark.cc
@@ -0,0 +1,87 @@
+/* KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This is a C++ class for the DOC bookmark record structure
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+#include "pilotDOCBookmark.h"
+
+
+
+PilotDOCBookmark::PilotDOCBookmark():PilotRecordBase(), pos(0)
+{
+ FUNCTIONSETUP;
+ memset(&bookmarkName[0], 0, 16);
+}
+
+
+
+/* initialize the entry from another one. If rec==NULL, this constructor does the same as PilotDOCBookmark()
+*/
+PilotDOCBookmark::PilotDOCBookmark(PilotRecord * rec):PilotRecordBase(rec)
+{
+ if (rec)
+ {
+ const pi_buffer_t *b = rec->buffer();
+ unsigned int offset = 0;
+ Pilot::dlp<char *>::read(b,offset,bookmarkName,16);
+ bookmarkName[16]='\0';
+ pos = Pilot::dlp<long>::read(b,offset);
+ }
+}
+
+
+
+PilotDOCBookmark::PilotDOCBookmark(const PilotDOCBookmark & e):PilotRecordBase(e)
+{
+ FUNCTIONSETUP;
+ *this = e;
+}
+
+
+
+PilotDOCBookmark & PilotDOCBookmark::operator =(const PilotDOCBookmark & e)
+{
+ if (this != &e)
+ {
+ strncpy(&bookmarkName[0], &e.bookmarkName[0], 16);
+ bookmarkName[16]='\0';
+ pos = e.pos;
+ }
+ return *this;
+}
+
+
+
+PilotRecord *PilotDOCBookmark::pack() const
+{
+ pi_buffer_t *b = pi_buffer_new( 16 + Pilot::dlp<long>::size );
+ pi_buffer_append(b, bookmarkName, 16);
+ b->data[16] = 0;
+ Pilot::dlp<long>::append(b,pos);
+ PilotRecord* rec = new PilotRecord(b, this);
+ return rec;
+}
diff --git a/kpilot/conduits/docconduit/pilotDOCBookmark.h b/kpilot/conduits/docconduit/pilotDOCBookmark.h
new file mode 100644
index 000000000..fe511fc17
--- /dev/null
+++ b/kpilot/conduits/docconduit/pilotDOCBookmark.h
@@ -0,0 +1,51 @@
+/* pilotDOCBookmark.h -*- C++ -*- KPilot
+**
+** Copyright (C) 2003 by Reinhold Kainhofer
+**
+** See the .cc file for an explanation of what this file is for.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+#ifndef _KPILOT_PILOTDOCBOOKMARK_H
+#define _KPILOT_PILOTDOCBOOKMARK_H
+
+#include <pilotRecord.h>
+class PilotRecord;
+
+
+class PilotDOCBookmark:public PilotRecordBase {
+public:
+ PilotDOCBookmark();
+ PilotDOCBookmark(PilotRecord * rec);
+ PilotDOCBookmark(const PilotDOCBookmark & e);
+ ~PilotDOCBookmark() {};
+ PilotDOCBookmark & operator=(const PilotDOCBookmark & e);
+
+ PilotRecord *pack() const;
+
+public:
+ char bookmarkName[17];
+ long int pos;
+};
+
+
+#endif
diff --git a/kpilot/conduits/docconduit/pilotDOCEntry.cc b/kpilot/conduits/docconduit/pilotDOCEntry.cc
new file mode 100644
index 000000000..75a51cefa
--- /dev/null
+++ b/kpilot/conduits/docconduit/pilotDOCEntry.cc
@@ -0,0 +1,92 @@
+/* KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This is a C++ class dealing with PalmDOC text records
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+#include "pilotDOCEntry.h"
+
+
+
+const int PilotDOCEntry::TEXT_SIZE = 4096;
+
+
+PilotDOCEntry::PilotDOCEntry():PilotRecordBase()
+{
+ FUNCTIONSETUP;
+ compress = false;
+}
+
+
+
+/* initialize the entry from another one. If rec==NULL, this constructor does the same as PilotDOCEntry()
+*/
+PilotDOCEntry::PilotDOCEntry(PilotRecord * rec, bool compressed):PilotRecordBase(rec)
+{
+ if (rec) fText.setText((unsigned char *) rec->data(), rec->size(), compressed);
+ compress = compressed;
+}
+
+
+
+PilotDOCEntry::PilotDOCEntry(const PilotDOCEntry & e):PilotRecordBase(e)
+{
+ FUNCTIONSETUP;
+ // See PilotDateEntry::operator = for details
+ fText.setText(e.fText.text(), e.fText.Len(), e.fText.compressed());
+ compress = e.compress;
+}
+
+
+
+PilotDOCEntry & PilotDOCEntry::operator =(const PilotDOCEntry & e)
+{
+ if (this != &e)
+ {
+ fText.setText(e.fText.text(), e.fText.Len(), e.fText.compressed());
+ compress = e.compress;
+ }
+ return *this;
+}
+
+
+
+
+PilotRecord *PilotDOCEntry::pack()
+{
+ int len = compress ? fText.Compress() : fText.Decompress();
+
+ if (len<0)
+ {
+ return 0L;
+ }
+
+ pi_buffer_t *b = pi_buffer_new( len + 4 ); // +4 for safety
+ memcpy( b->data, (const char *) fText.text(), len );
+ b->used = len;
+ PilotRecord* rec = new PilotRecord(b, this);
+ return rec;
+}
diff --git a/kpilot/conduits/docconduit/pilotDOCEntry.h b/kpilot/conduits/docconduit/pilotDOCEntry.h
new file mode 100644
index 000000000..b1b9ba45b
--- /dev/null
+++ b/kpilot/conduits/docconduit/pilotDOCEntry.h
@@ -0,0 +1,73 @@
+/* pilotDOCEntry.h -*- C++ -*- KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** See the .cc file for an explanation of what this file is for.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to the mailinlist [email protected]
+*/
+#ifndef _KPILOT_PILOTDOCENTRY_H
+#define _KPILOT_PILOTDOCENTRY_H
+
+#include <pilotRecord.h>
+#include "makedoc9.h"
+
+
+class PilotRecord;
+
+
+class PilotDOCEntry:public PilotRecordBase {
+private:
+ bool compress;
+ tBuf fText;
+public:
+ static const int TEXT_SIZE;
+ PilotDOCEntry();
+ PilotDOCEntry(PilotRecord * rec, bool compressed = false);
+ PilotDOCEntry(const PilotDOCEntry & e);
+ ~PilotDOCEntry() {};
+ PilotDOCEntry & operator=(const PilotDOCEntry & e);
+
+
+ QString getText() {
+ fText.Decompress();
+ return QString::fromLatin1((const char *) fText.text());
+ };
+ void setText(QString newtext, bool compressed = false) {
+ fText.setText((const unsigned char *) newtext.latin1(),
+ newtext.length(), compressed);
+ };
+
+ bool getCompress() const {
+ return compress;
+ }
+ void setCompress(bool compressed) {
+ compress = compressed;
+ };
+
+ PilotRecord *pack(); // Not const because it can change the compression
+};
+
+
+
+#endif
+
diff --git a/kpilot/conduits/docconduit/pilotDOCHead.cc b/kpilot/conduits/docconduit/pilotDOCHead.cc
new file mode 100644
index 000000000..1f07e2867
--- /dev/null
+++ b/kpilot/conduits/docconduit/pilotDOCHead.cc
@@ -0,0 +1,101 @@
+/* KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This is a C++ class dealing with PalmDOC text records
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+#include "options.h"
+#include "pilotDOCHead.h"
+
+#include "makedoc9.h"
+
+
+
+const int PilotDOCHead::textRecordSize = 4096;
+
+PilotDOCHead::PilotDOCHead():PilotRecordBase(),
+version(0),
+spare(0), storyLen(0), numRecords(0), recordSize(textRecordSize), position(0)
+{
+ FUNCTIONSETUP;
+}
+
+
+
+/* initialize the entry from another one. If rec==NULL, this constructor does the same as PilotDOCHead()
+*/
+PilotDOCHead::PilotDOCHead(PilotRecord * rec):PilotRecordBase(rec)
+{
+ const unsigned char *b = (const unsigned char *) rec->data();
+ unsigned int offset = 0;
+
+ version = Pilot::dlp<short>::read(b,offset);
+ spare = Pilot::dlp<short>::read(b,offset);
+ storyLen = Pilot::dlp<long>::read(b,offset);
+ numRecords = Pilot::dlp<short>::read(b,offset);
+ recordSize = Pilot::dlp<short>::read(b,offset);
+ position = Pilot::dlp<long>::read(b,offset);
+}
+
+
+PilotDOCHead::PilotDOCHead(const PilotDOCHead & e):PilotRecordBase(e)
+{
+ FUNCTIONSETUP;
+ *this = e;
+}
+
+
+
+PilotDOCHead & PilotDOCHead::operator =(const PilotDOCHead & e)
+{
+ if (this != &e)
+ {
+ version = e.version;
+ spare = e.spare;
+ storyLen = e.storyLen;
+ numRecords = e.numRecords;
+ recordSize = e.recordSize;
+ position = e.position;
+ }
+ return *this;
+}
+
+
+
+
+PilotRecord *PilotDOCHead::pack() const
+{
+ pi_buffer_t *b = pi_buffer_new(16);
+
+ Pilot::dlp<short>::append(b,version);
+ Pilot::dlp<short>::append(b,spare);
+ Pilot::dlp<long>::append(b,storyLen);
+ Pilot::dlp<short>::append(b,numRecords);
+ Pilot::dlp<short>::append(b,recordSize);
+ Pilot::dlp<long>::append(b,position);
+
+ PilotRecord *rec = new PilotRecord(b, this);
+ return rec;
+}
+
diff --git a/kpilot/conduits/docconduit/pilotDOCHead.h b/kpilot/conduits/docconduit/pilotDOCHead.h
new file mode 100644
index 000000000..aeb7fb526
--- /dev/null
+++ b/kpilot/conduits/docconduit/pilotDOCHead.h
@@ -0,0 +1,62 @@
+/* pilotDOCHead.h -*- C++ -*- KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** See the .cc file for an explanation of what this file is for.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to the mailinlist [email protected]
+*/
+#ifndef _KPILOT_PILOTDOCHEAD_H
+#define _KPILOT_PILOTDOCHEAD_H
+
+#include <pilotRecord.h>
+
+class PilotRecord;
+
+
+class PilotDOCHead:public PilotRecordBase {
+ private:
+ static const int textRecordSize;
+
+ public:
+ int version;
+ int spare;
+ long int storyLen;
+ int numRecords;
+ int recordSize;
+ long int position;
+
+ PilotRecord *pack() const;
+
+ public:
+ PilotDOCHead();
+ PilotDOCHead(PilotRecord * rec);
+ PilotDOCHead(const PilotDOCHead & e);
+ ~PilotDOCHead() { }
+
+ PilotDOCHead & operator=(const PilotDOCHead & e);
+};
+
+
+
+#endif
+
diff --git a/kpilot/conduits/docconduit/tests/testcompress.cpp b/kpilot/conduits/docconduit/tests/testcompress.cpp
new file mode 100644
index 000000000..b8367b2b9
--- /dev/null
+++ b/kpilot/conduits/docconduit/tests/testcompress.cpp
@@ -0,0 +1,59 @@
+/*
+** Copyright (C) 2003 by Reinhold Kainhofer
+**
+** This is just a very simple programm to check the compress/uncompress
+** routines by taking one string, compress and then decompress it and
+** see if it is the original string.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+#include <stdio.h>
+#include <iostream.h>
+
+
+#include "../makedoc9.h"
+
+void main ()
+{
+ tBuf fText;
+ char*text="asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf";
+
+ fText.setText((const byte*)text);
+ cout<<"Decompressed text: "<<fText.text()<<" ("<<fText.Len()<<") -- Compressed: "<<fText.compressed()<<endl;
+
+ fText.Compress();
+ cout<<" Compressed text: "<<fText.text()<<" ("<<fText.Len()<<") -- Compressed: "<<fText.compressed()<<endl;
+ fText.Decompress();
+ cout<<"Decompressed text: "<<fText.text()<<" ("<<fText.Len()<<") -- Compressed: "<<fText.compressed()<<endl;
+
+ fText.Compress();
+ cout<<" Compressed text: "<<fText.text()<<" ("<<fText.Len()<<") -- Compressed: "<<fText.compressed()<<endl;
+ fText.Decompress();
+ cout<<"Decompressed text: "<<fText.text()<<" ("<<fText.Len()<<") -- Compressed: "<<fText.compressed()<<endl;
+
+ fText.Compress();
+ cout<<" Compressed text: "<<fText.text()<<" ("<<fText.Len()<<") -- Compressed: "<<fText.compressed()<<endl;
+ fText.Decompress();
+ cout<<"Decompressed text: "<<fText.text()<<" ("<<fText.Len()<<") -- Compressed: "<<fText.compressed()<<endl;
+
+
+}
diff --git a/kpilot/conduits/knotes/CMakeLists.txt b/kpilot/conduits/knotes/CMakeLists.txt
new file mode 100644
index 000000000..568adb427
--- /dev/null
+++ b/kpilot/conduits/knotes/CMakeLists.txt
@@ -0,0 +1,52 @@
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+set(conduit_knotes_SRCS
+ knotes-factory.cc
+ knotes-setup.cc
+ knotes-action.cc
+)
+
+set(conduit_knotes_UIS
+ setup_base.ui
+)
+
+set(conduit_knotes_KCFGS
+ knotesconduitSettings.kcfgc
+)
+
+#set(conduit_knotes_STUBS
+# KNotesIface.h
+#)
+
+#kde3_add_dcop_skels(conduit_knotes_SRCS ${conduit_knotes_STUBS})
+#kde3_add_dcop_stubs(conduit_knotes_SRCS ${conduit_knotes_STUBS})
+
+kde3_add_kcfg_files(conduit_knotes_SRCS ${conduit_knotes_KCFGS})
+kde3_add_ui_files(conduit_knotes_SRCS ${conduit_knotes_UIS})
+kde3_automoc(${conduit_knotes_SRCS})
+
+add_library(conduit_knotes SHARED ${conduit_knotes_SRCS})
+target_link_libraries(conduit_knotes kcal)
+
+set_target_properties(conduit_knotes PROPERTIES
+ LOCATION ${KDE3_PLUGIN_INSTALL_DIR}
+ INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib
+ PREFIX ""
+)
+
+kde3_install_libtool_file(conduit_knotes)
+
+install(
+ TARGETS conduit_knotes
+ LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR}
+)
+
+install(
+ FILES knotes-conduit.desktop DESTINATION ${KDE3_SERVICES_DIR}
+)
+
+install(
+ FILES knotesconduit.kcfg DESTINATION ${KDE3_KCFG_DIR}
+)
diff --git a/kpilot/conduits/knotes/Makefile.am b/kpilot/conduits/knotes/Makefile.am
new file mode 100644
index 000000000..db4cff3ec
--- /dev/null
+++ b/kpilot/conduits/knotes/Makefile.am
@@ -0,0 +1,21 @@
+INCLUDES= $(PISOCK_INCLUDE) -I$(top_srcdir) -I$(top_srcdir)/kpilot/lib $(all_includes)
+
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = knotes-conduit.desktop
+
+kde_module_LTLIBRARIES = conduit_knotes.la
+
+
+conduit_knotes_la_SOURCES = \
+ knotesconduitSettings.kcfgc \
+ knotes-factory.cc \
+ knotes-setup.cc \
+ knotes-action.cc \
+ setup_base.ui
+
+conduit_knotes_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+conduit_knotes_la_LIBADD = ../../lib/libkpilot.la $(LIB_KDEUI)
+
+kde_kcfg_DATA = knotesconduit.kcfg
diff --git a/kpilot/conduits/knotes/cr32-app-knotesconduit.png b/kpilot/conduits/knotes/cr32-app-knotesconduit.png
new file mode 100644
index 000000000..6bca79009
--- /dev/null
+++ b/kpilot/conduits/knotes/cr32-app-knotesconduit.png
Binary files differ
diff --git a/kpilot/conduits/knotes/knotes-action.cc b/kpilot/conduits/knotes/knotes-action.cc
new file mode 100644
index 000000000..905e5ef39
--- /dev/null
+++ b/kpilot/conduits/knotes/knotes-action.cc
@@ -0,0 +1,872 @@
+/* KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2002,2003,2004 by Adriaan de Groot
+**
+** This file defines the SyncAction for the knotes-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qmap.h>
+#include <qtimer.h>
+
+#include <kapplication.h>
+
+#include <kurl.h>
+#include <libkcal/calendarlocal.h>
+#include <kstandarddirs.h>
+
+
+#include <kconfig.h>
+//#include <dcopclient.h>
+
+#include <time.h> // required by pilot-link includes
+
+#include <pi-memo.h>
+
+#include "pilotMemo.h"
+#include "pilotSerialDatabase.h"
+
+//#include "KNotesIface_stub.h"
+
+#include "knotes-factory.h"
+
+#include "knotes-action.moc"
+#include "knotesconduitSettings.h"
+
+extern "C"
+{
+
+unsigned long version_conduit_knotes = Pilot::PLUGIN_API;
+
+}
+
+typedef QString KNoteID_t;
+typedef const QString &KNoteID_pt;
+
+class NoteAndMemo
+{
+public:
+ NoteAndMemo() : noteId(),memoId(-1) { } ;
+ NoteAndMemo(KNoteID_pt noteid,int memoid) : noteId(noteid),memoId(memoid) { } ;
+ bool operator ==(const NoteAndMemo &p) const
+ {
+ return (p.memo()==memoId) && (p.note()==noteId);
+ }
+
+ int memo() const { return memoId; } ;
+ KNoteID_t note() const { return noteId; } ;
+ inline bool valid() const { return (memoId>0) && (!noteId.isEmpty()) ; } ;
+ QString toString() const { return CSL1("<%1,%2>").arg(noteId).arg(memoId); } ;
+
+ static NoteAndMemo findNote(const QValueList<NoteAndMemo> &,KNoteID_pt note);
+ static NoteAndMemo findMemo(const QValueList<NoteAndMemo> &,int memo);
+
+protected:
+ KNoteID_t noteId;
+ int memoId;
+} ;
+
+NoteAndMemo NoteAndMemo::findNote(const QValueList<NoteAndMemo> &l ,KNoteID_pt note)
+{
+ FUNCTIONSETUP;
+
+ for (QValueList<NoteAndMemo>::ConstIterator it = l.begin();
+ it != l.end();
+ ++it)
+ {
+ if ((*it).note()==note) return *it;
+ }
+
+ return NoteAndMemo();
+}
+
+NoteAndMemo NoteAndMemo::findMemo(const QValueList<NoteAndMemo> &l , int memo)
+{
+ FUNCTIONSETUP;
+
+ for (QValueList<NoteAndMemo>::ConstIterator it =l.begin();
+ it != l.end();
+ ++it)
+ {
+ if ((*it).memo()==memo) return *it;
+ }
+
+ return NoteAndMemo();
+}
+
+class KNotesAction::KNotesActionPrivate
+{
+public:
+ KNotesActionPrivate() :
+ fNotesResource(0L),
+ fTimer(0L),
+ fDeleteCounter(0),
+ fModifiedNotesCounter(0),
+ fModifiedMemosCounter(0),
+ fAddedNotesCounter(0),
+ fAddedMemosCounter(0),
+ fDeletedNotesCounter(0),
+ fDeletedMemosCounter(0),
+ fDeleteNoteForMemo(false)
+ { } ;
+ ~KNotesActionPrivate()
+ {
+ fNotesResource->save();
+
+ KPILOT_DELETE(fNotesResource);
+ KPILOT_DELETE(fTimer);
+ }
+
+ // The record index we're dealing with. Used by
+ // CopyHHToPC sync only.
+ int fRecordIndex;
+
+ KCal::CalendarLocal *fNotesResource;
+ // This is the collection of notes held by KNotes and
+ KCal::Journal::List fNotes;
+
+ // This iterates through that list; it's in here because
+ // we use slots to process one item at a time and need
+ // to keep track of where we are between slot calls.
+ KCal::Journal::List::ConstIterator fIndex;
+
+ // The DCOP client for this application, and the KNotes stub.
+ // DCOPClient *fDCOP;
+ //KNotesIface_stub *fKNotes;
+
+ // The timer for invoking process() to do some more work.
+ QTimer *fTimer;
+
+ // The database we're working with (MemoDB)
+ // PilotSerialDatabase *fDatabase;
+ // Some counter that needs to be preserved between calls to
+ // process(). Typically used to note how much work is done.
+ int fDeleteCounter; // Count deleted memos as well.
+ unsigned int fModifiedNotesCounter; // Count modified KNotes.
+ unsigned int fModifiedMemosCounter;
+ unsigned int fAddedNotesCounter;
+ unsigned int fAddedMemosCounter;
+ unsigned int fDeletedNotesCounter;
+ unsigned int fDeletedMemosCounter;
+
+ // We need to translate between the ids that KNotes uses and
+ // Pilot id's, so we make a list of pairs.
+ //
+ QValueList<NoteAndMemo> fIdList;
+
+ // Setting to delete a KNote when the corresponding memo
+ // has been deleted.
+ bool fDeleteNoteForMemo;
+};
+
+
+
+KNotesAction::KNotesAction(KPilotLink *o,
+ const char *n, const QStringList &a) :
+ ConduitAction(o,n ? n : "knotes-conduit",a),
+ fP(new KNotesActionPrivate)
+{
+ FUNCTIONSETUP;
+
+/*
+ if (fP) fP->fDCOP = KApplication::kApplication()->dcopClient();
+
+ if (fP && !fP->fDCOP)
+ {
+ WARNINGKPILOT << "Can't get DCOP client." << endl;
+ }
+*/
+}
+
+/* virtual */ KNotesAction::~KNotesAction()
+{
+ FUNCTIONSETUP;
+
+ KPILOT_DELETE(fP);
+}
+
+/* virtual */ bool KNotesAction::exec()
+{
+ FUNCTIONSETUP;
+ DEBUGKPILOT << fname << ": Starting knotes conduit." << endl;
+
+ if (syncMode().isTest())
+ {
+ test();
+ delayDone();
+ return true;
+ }
+
+ QString e;
+ if (!openKNotesResource()) return false;
+
+ // Database names seem to be latin1
+ if (!openDatabases(CSL1("MemoDB")))
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << "Can not open databases." << endl;
+#endif
+ emit logError(i18n("Could not open MemoDB on the handheld."));
+ return false;
+ }
+
+ fP->fTimer = new QTimer(this);
+ fActionStatus = Init;
+
+ // this is not needed. As it is done in the initstate in process();
+ // resetIndexes();
+
+ connect(fP->fTimer,SIGNAL(timeout()),SLOT(process()));
+ fP->fTimer->start(0,false);
+
+ return true;
+}
+
+void KNotesAction::test()
+{
+ if (!openKNotesResource()) return;
+ listNotes();
+}
+
+bool KNotesAction::openKNotesResource()
+{
+ FUNCTIONSETUP;
+
+ KConfig korgcfg( locate( "config", CSL1("korganizerrc") ) );
+ korgcfg.setGroup( "Time & Date" );
+ QString tz(korgcfg.readEntry( "TimeZoneId" ) );
+
+ fP->fNotesResource = new KCal::CalendarLocal(tz);
+ KURL mURL = KGlobal::dirs()->saveLocation( "data", "knotes/" ) + "notes.ics";
+
+ if( fP->fNotesResource->load( mURL.path() ) )
+ {
+ fP->fNotes = fP->fNotesResource->journals();
+ return true;
+ }
+ else
+ {
+ emit logError( i18n("Could not load the resource at: %1").arg(mURL.path()) );
+ return false;
+ }
+}
+
+
+void KNotesAction::resetIndexes()
+{
+ FUNCTIONSETUP;
+
+ fP->fRecordIndex = 0;
+ fP->fIndex = fP->fNotes.begin();
+}
+
+void KNotesAction::listNotes()
+{
+ FUNCTIONSETUP;
+
+ KCal::Journal::List notes = fP->fNotesResource->journals();
+ DEBUGKPILOT << fname << ": the resource contains " << notes.size()
+ << " note(s)." << endl;
+
+ KCal::Journal::List::ConstIterator it;
+ int i = 1;
+ for ( it = notes.begin(); it != notes.end(); ++it )
+ {
+ DEBUGKPILOT << fname << ": note " << i << " has id " << (*it)->uid()
+ << endl;
+ i++;
+ }
+
+ DEBUGKPILOT << fname << ": "
+ << "Sync direction: " << syncMode().name() << endl;
+}
+
+/* slot */ void KNotesAction::process()
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname << ": Now in state " << fActionStatus << endl;
+
+ switch(fActionStatus)
+ {
+ case Init:
+ resetIndexes();
+ getAppInfo();
+ getConfigInfo();
+ switch(syncMode().mode())
+ {
+ case SyncAction::SyncMode::eBackup:
+ case SyncAction::SyncMode::eRestore:
+ // Impossible!
+ fActionStatus = Done;
+ break;
+ case SyncAction::SyncMode::eCopyHHToPC :
+ listNotes(); // Debugging
+ fActionStatus = MemosToKNotes;
+ break;
+ case SyncAction::SyncMode::eHotSync:
+ case SyncAction::SyncMode::eFullSync:
+ case SyncAction::SyncMode::eCopyPCToHH:
+ fActionStatus = ModifiedNotesToPilot;
+ break;
+ }
+ break;
+ case ModifiedNotesToPilot:
+ if (modifyNoteOnPilot())
+ {
+ resetIndexes();
+ fActionStatus = DeleteNotesOnPilot;
+ }
+ break;
+ case DeleteNotesOnPilot:
+ if (deleteNoteOnPilot())
+ {
+ resetIndexes();
+ fActionStatus = NewNotesToPilot;
+ }
+ break;
+ case NewNotesToPilot :
+ if (addNewNoteToPilot())
+ {
+ resetIndexes();
+ fDatabase->resetDBIndex();
+ switch(syncMode().mode())
+ {
+ case SyncAction::SyncMode::eBackup:
+ case SyncAction::SyncMode::eRestore:
+ case SyncAction::SyncMode::eCopyHHToPC :
+ // Impossible!
+ fActionStatus = Done;
+ break;
+ case SyncAction::SyncMode::eHotSync:
+ case SyncAction::SyncMode::eFullSync:
+ fActionStatus = MemosToKNotes;
+ break;
+ case SyncAction::SyncMode::eCopyPCToHH:
+ fActionStatus = Cleanup;
+ break;
+ }
+ }
+ break;
+ case MemosToKNotes :
+ if (syncMemoToKNotes())
+ {
+ fActionStatus=Cleanup;
+ }
+ break;
+ case Cleanup :
+ cleanupMemos();
+ break;
+ default :
+ if (fP->fTimer) fP->fTimer->stop();
+ delayDone();
+ }
+}
+
+
+void KNotesAction::getConfigInfo()
+{
+ FUNCTIONSETUP;
+
+ KNotesConduitSettings::self()->readConfig();
+
+ fP->fDeleteNoteForMemo = KNotesConduitSettings::deleteNoteForMemo();
+
+ QValueList<KNoteID_t> notes;
+ QValueList<int> memos;
+
+ // Make this match the type of KNoteID_t !
+ notes=KNotesConduitSettings::noteIds();
+ memos=KNotesConduitSettings::memoIds();
+
+ if (notes.count() != memos.count())
+ {
+ WARNINGKPILOT
+ << ": Notes and memo id lists don't match ("
+ << notes.count()
+ << ","
+ << memos.count()
+ << ")"
+ << endl;
+ notes.clear();
+ memos.clear();
+ setFirstSync( true );
+ }
+
+ QValueList<KNoteID_t>::ConstIterator iNotes = notes.begin();
+ QValueList<int>::ConstIterator iMemos = memos.begin();
+
+ while((iNotes != notes.end()) && (iMemos != memos.end()))
+ {
+ fP->fIdList.append(NoteAndMemo(*iNotes,*iMemos));
+ ++iNotes;
+ ++iMemos;
+ }
+}
+
+void KNotesAction::getAppInfo()
+{
+ FUNCTIONSETUP;
+
+ resetIndexes();
+}
+
+
+bool KNotesAction::modifyNoteOnPilot()
+{
+ FUNCTIONSETUP;
+ return true;
+ /*
+ if (fP->fIndex == fP->fNotes.end())
+ {
+ return true;
+ }
+ */
+
+ //TODO DCOP_REMOVAL
+ /*
+ if (fP->fKNotes->isModified(CSL1("kpilot"),fP->fIndex.key()))
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": The note #"
+ << fP->fIndex.key()
+ << " with name "
+ << fP->fIndex.data()
+ << " is modified in KNotes."
+ << endl;
+#endif
+
+ NoteAndMemo nm = NoteAndMemo::findNote(fP->fIdList,
+ fP->fIndex.key());
+
+ if (nm.valid())
+ {
+ QString text,title,body;
+ title = fP->fIndex.data();
+ body = fP->fKNotes->text(fP->fIndex.key());
+ if (body.startsWith(title))
+ {
+ text = body;
+ }
+ else
+ {
+ text = title + CSL1("\n") + body;
+ }
+
+ PilotMemo *a = new PilotMemo(text);
+ PilotRecord *r = a->pack();
+ r->setID(nm.memo());
+
+ int newid = fDatabase->writeRecord(r);
+ fLocalDatabase->writeRecord(r);
+
+ if (newid != nm.memo())
+ {
+ WARNINGKPILOT
+ << ": Memo id changed during write? "
+ << "From "
+ << nm.memo()
+ << " to "
+ << newid
+ << endl;
+ }
+ }
+ else
+ {
+ WARNINGKPILOT << "Modified note unknown to Pilot" << endl;
+ // Add it anyway, with new PilotID.
+ int newid = addNoteToPilot();
+ fP->fIdList.remove(nm);
+ fP->fIdList.append(NoteAndMemo(fP->fIndex.key(),newid));
+ }
+
+ ++(fP->fModifiedMemosCounter);
+ }
+ */
+
+ //++(fP->fIndex);
+ //return false;
+}
+
+bool KNotesAction::deleteNoteOnPilot()
+{
+ FUNCTIONSETUP;
+
+ /*
+ QValueList<NoteAndMemo>::Iterator i = fP->fIdList.begin();
+ while ( i != fP->fIdList.end() )
+ {
+ // TODO DCOP_REMOVE
+ if (fP->fNotes.contains((*i).note()))
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Note " << (*i).note() << " still exists." << endl;
+#endif
+ }
+ else
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Note " << (*i).note() << " is deleted." << endl;
+#endif
+ fDatabase->deleteRecord((*i).memo());
+ fLocalDatabase->deleteRecord((*i).memo());
+ i = fP->fIdList.remove(i);
+ fP->fDeletedMemosCounter++;
+ continue;
+ }
+ ++i;
+ }
+ */
+ return true;
+}
+
+bool KNotesAction::addNewNoteToPilot()
+{
+ FUNCTIONSETUP;
+
+ if (fP->fIndex == fP->fNotes.end())
+ {
+ return true;
+ }
+
+ KCal::Journal *j = (*fP->fIndex);
+
+ if( j->pilotId() == 0 )
+ {
+ DEBUGKPILOT << fname << ": Adding note with id " << j->uid()
+ << " to pilot." << endl;
+
+ int newid = addNoteToPilot();
+
+ ++(fP->fAddedMemosCounter);
+ }
+ //TODO DCOP_REMOVAL
+ /*
+ if (fP->fKNotes->isNew(CSL1("kpilot"),fP->fIndex.key()))
+ {
+ int newid = addNoteToPilot();
+ fP->fIdList.append(NoteAndMemo(fP->fIndex.key(),newid));
+ ++(fP->fAddedMemosCounter);
+ }
+ */
+
+ ++(fP->fIndex);
+ return false;
+}
+
+bool KNotesAction::syncMemoToKNotes()
+{
+ FUNCTIONSETUP;
+
+ PilotRecord *rec = 0L;
+
+ if ( syncMode() == SyncAction::SyncMode::eCopyHHToPC )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Read record " << fP->fRecordIndex << endl;
+#endif
+ rec = fDatabase->readRecordByIndex(fP->fRecordIndex);
+ fP->fRecordIndex++;
+ }
+ else
+ {
+ rec = fDatabase->readNextModifiedRec();
+ }
+
+ if (!rec)
+ {
+ return true;
+ }
+
+ PilotMemo *memo = new PilotMemo(rec);
+ NoteAndMemo m = NoteAndMemo::findMemo(fP->fIdList,memo->id());
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Looking at memo "
+ << memo->id()
+ << " which was found "
+ << m.toString()
+ << endl;
+#endif
+
+ if (memo->isDeleted())
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": It's been deleted." << endl;
+#endif
+ if (m.valid())
+ {
+ // We knew about the note already, but it
+ // has changed on the Pilot.
+ //
+ //
+ if (fP->fDeleteNoteForMemo)
+ {
+ //TODO DCOP_REMOVAL
+ //fP->fKNotes->killNote(m.note(),KNotesConduitSettings::suppressKNotesConfirm()
+ //) ;
+ fP->fDeletedNotesCounter++;
+ }
+ }
+ else
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": It's new and deleted." << endl;
+#endif
+ }
+
+ fLocalDatabase->deleteRecord(rec->id());
+ }
+ else
+ {
+ if (m.valid())
+ {
+ #ifdef DEBUG
+ DEBUGKPILOT << fname << ": It's just modified." << endl;
+ DEBUGKPILOT << fname << ": <"
+// << fP->fNotes[m.note()]
+ << "> <"
+ << memo->shortTitle()
+ << ">"
+ << endl;
+ #endif
+ // Check if KNotes still knows about this note
+ //TODO DCOP_REMOVAL
+ /*
+ if (!(fP->fKNotes->name(m.note()).isEmpty()))
+ {
+ updateNote(m,memo);
+ }
+ else
+ {
+ uint c = fP->fIdList.remove(m);
+ if (!c)
+ {
+ WARNINGKPILOT
+ << "Tried to remove valid note and failed."
+ << endl;
+ }
+ addMemoToKNotes(memo);
+ }
+ */
+ }
+ else
+ {
+ addMemoToKNotes(memo);
+ }
+ fLocalDatabase->writeRecord(rec);
+ }
+
+ KPILOT_DELETE(memo);
+ KPILOT_DELETE(rec);
+
+ return false;
+}
+
+void KNotesAction::updateNote(const NoteAndMemo &m, const PilotMemo *memo)
+{
+ FUNCTIONSETUP;
+ //TODO DCOP_REMOVAL
+ if (true/*fP->fNotes[m.note()] != memo->shortTitle()*/)
+ {
+ // Name changed. KNotes might complain though.
+ //TODO DCOP_REMOVAL
+ //fP->fKNotes->setName(m.note(), memo->shortTitle());
+ }
+ //TODO DCOP_REMOVAL
+ //fP->fKNotes->setText(m.note(),memo->text());
+ fP->fModifiedNotesCounter++;
+}
+
+void KNotesAction::addMemoToKNotes(const PilotMemo *memo)
+{
+ FUNCTIONSETUP;
+ // This note is new to KNotes
+ //TODO DCOP_REMOVAL
+ //KNoteID_t i = fP->fKNotes->newNote(memo->shortTitle(), memo->text());
+ //fP->fIdList.append(NoteAndMemo(i,memo->id()));
+ //fP->fAddedNotesCounter++;
+
+#ifdef DEBUG
+ //TODO DCOP_REMOVAL
+ //DEBUGKPILOT << fname << ": It's new with knote id " << i << endl;
+#endif
+}
+int KNotesAction::addNoteToPilot()
+{
+ FUNCTIONSETUP;
+
+ KCal::Journal *j = (*fP->fIndex);
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": The note #"
+ << j->uid()
+ << " with name "
+ << j->summary()
+ << " is new to the Pilot."
+ << endl;
+#endif
+
+ QString text = j->summary() + CSL1("\n");
+ text.append( j->description() );
+ //TODO DCOP_REMOVAL
+ //text.append(fP->fKNotes->text(fP->fIndex.key()));
+
+ PilotMemo *a = new PilotMemo(text);
+ PilotRecord *r = a->pack();
+
+ int newid = fDatabase->writeRecord(r);
+ fLocalDatabase->writeRecord(r);
+
+ j->setPilotId( newid );
+
+ delete r;
+ delete a;
+ delete j;
+
+ fP->fAddedMemosCounter++;
+
+ return newid;
+}
+
+
+void KNotesAction::cleanupMemos()
+{
+ FUNCTIONSETUP;
+
+ // Tell KNotes we're up-to-date
+ //TODO DCOP_REMOVAL
+ //fP->fKNotes->sync(CSL1("kpilot"));
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Writing "
+ << fP->fIdList.count()
+ << " pairs to the config file."
+ << endl;
+ DEBUGKPILOT << fname
+ << ": The config file is read-only: "
+ << KNotesConduitSettings::self()->config()->isReadOnly()
+ << endl;
+#endif
+
+ QValueList<KNoteID_t> notes;
+ QValueList<int> memos;
+
+ for (QValueList<NoteAndMemo>::ConstIterator i =
+ fP->fIdList.begin();
+ i!=fP->fIdList.end();
+ ++i)
+ {
+ notes.append((*i).note());
+ memos.append((*i).memo());
+ }
+
+ KNotesConduitSettings::setNoteIds(notes);
+ KNotesConduitSettings::setMemoIds(memos);
+ KNotesConduitSettings::self()->writeConfig();
+
+ fActionStatus=Done;
+ fDatabase->cleanup();
+ fDatabase->resetSyncFlags();
+ fLocalDatabase->cleanup();
+ fLocalDatabase->resetSyncFlags();
+
+ // Tell the user what happened. If no changes were
+ // made, spoke remains false and we'll tack a
+ // message on to the end saying so, so that
+ // the user always gets at least one message.
+ bool spoke = false;
+ if (fP->fAddedMemosCounter)
+ {
+ addSyncLogEntry(i18n("Added one new memo.",
+ "Added %n new memos.",
+ fP->fAddedMemosCounter));
+ }
+ if (fP->fModifiedMemosCounter)
+ {
+ addSyncLogEntry(i18n("Modified one memo.",
+ "Modified %n memos.",
+ fP->fModifiedMemosCounter));
+ spoke = true;
+ }
+ if (fP->fDeletedMemosCounter)
+ {
+ addSyncLogEntry(i18n("Deleted one memo.",
+ "Deleted %n memos.",fP->fDeletedMemosCounter));
+ spoke = true;
+ }
+ if (fP->fAddedNotesCounter)
+ {
+ addSyncLogEntry(i18n("Added one note to KNotes.",
+ "Added %n notes to KNotes.",fP->fAddedNotesCounter));
+ spoke = true;
+ }
+ if (fP->fModifiedNotesCounter)
+ {
+ addSyncLogEntry(i18n("Modified one note in KNotes.",
+ "Modified %n notes in KNotes.",fP->fModifiedNotesCounter));
+ spoke = true;
+ }
+ if (fP->fDeletedNotesCounter)
+ {
+ addSyncLogEntry(i18n("Deleted one note from KNotes.",
+ "Deleted %n notes from KNotes.",fP->fDeletedNotesCounter));
+ spoke = true;
+ }
+ if (!spoke)
+ {
+ addSyncLogEntry(i18n("No change to KNotes."));
+ }
+}
+
+
+/* virtual */ QString KNotesAction::statusString() const
+{
+ switch(fActionStatus)
+ {
+ case Init : return CSL1("Init");
+ case NewNotesToPilot :
+ return CSL1("NewNotesToPilot key=%1");
+ // TODO DCOP_REMOVAL .arg(fP->fIndex.key());
+ case ModifiedNotesToPilot :
+ return CSL1("ModifiedNotesToPilot key=%1");
+ //TODO DCOP_REMOVAL .arg(fP->fIndex.key());
+ case MemosToKNotes :
+ return CSL1("MemosToKNotes rec=%1")
+ .arg(fP->fRecordIndex);
+ case Cleanup : return CSL1("Cleanup");
+ case Done :
+ return CSL1("Done");
+ default :
+ return CSL1("Unknown (%1)").arg(fActionStatus);
+ }
+}
+
+
+
diff --git a/kpilot/conduits/knotes/knotes-action.h b/kpilot/conduits/knotes/knotes-action.h
new file mode 100644
index 000000000..695e90747
--- /dev/null
+++ b/kpilot/conduits/knotes/knotes-action.h
@@ -0,0 +1,113 @@
+#ifndef _KPILOT_KNOTES_ACTION_H
+#define _KPILOT_KNOTES_ACTION_H
+/* knotes-action.h KPilot
+**
+** Copyright (C) 2001,2003 by Dan Pilone
+**
+** This file defines the SyncAction that the KNotes conduit performs.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <plugin.h>
+
+
+class NoteAndMemo;
+class PilotMemo;
+
+class KNotesAction : public ConduitAction
+{
+Q_OBJECT
+public:
+ KNotesAction(
+ KPilotLink *o,
+ const char *n = 0L,
+ const QStringList &a = QStringList() );
+ virtual ~KNotesAction();
+
+ enum Status { Init,
+ ModifiedNotesToPilot,
+ DeleteNotesOnPilot,
+ NewNotesToPilot,
+ MemosToKNotes,
+ Cleanup,
+ Done } ;
+ virtual QString statusString() const;
+
+protected:
+ virtual bool exec();
+
+protected:
+ /**
+ * For test mode -- just list the notes KNotes has.
+ */
+ void listNotes();
+
+ /** Run a test on the conduit. */
+ void test();
+
+ /**
+ * Loads the KNotes resource and retrieve the list of notes it
+ * has. @return false if the the resource could not be opened and a new
+ * resource could not be created. Modifies fP to store the notes in.
+ */
+ bool openKNotesResource();
+
+ /**
+ * For actual processing. These are called by process
+ * and it is critical that fP->fIndex is set properly.
+ *
+ * Each returns true when it is completely finished processing,
+ * if it returns a bool. Void functions need only be called once.
+ */
+ void getAppInfo();
+ void getConfigInfo();
+ bool modifyNoteOnPilot();
+ bool deleteNoteOnPilot();
+ bool addNewNoteToPilot();
+ bool syncMemoToKNotes();
+ void cleanupMemos();
+
+ void updateNote(const NoteAndMemo &,const PilotMemo *);
+
+ /**
+ * Add the Memo to KNotes.
+ */
+ void addMemoToKNotes(const PilotMemo *);
+ /**
+ * Add the Note currently being processed to the
+ * pilot as a new memo. Returns the id of the record.
+ */
+ int addNoteToPilot();
+
+
+ void resetIndexes();
+
+protected slots:
+ void process();
+
+private:
+ class KNotesActionPrivate;
+ KNotesActionPrivate *fP;
+} ;
+
+#endif
diff --git a/kpilot/conduits/knotes/knotes-conduit.desktop b/kpilot/conduits/knotes/knotes-conduit.desktop
new file mode 100644
index 000000000..7f405cdb1
--- /dev/null
+++ b/kpilot/conduits/knotes/knotes-conduit.desktop
@@ -0,0 +1,94 @@
+[Desktop Entry]
+Type=Service
+Comment=This conduit syncs the Memo Pad application with KNotes.
+Comment[af]=Hierdie pad synkroniseer die Memo Pad program met KNotes.
+Comment[bg]=Синхронизация на бележки на KDE с мобилни устройства
+Comment[bs]=Ovaj conduit sinhronizuje Memo Pad aplikaciju sa KNotes.
+Comment[ca]=Aquest conducte sincronitza l'aplicació Memo Pad amb Knotes.
+Comment[cs]=Toto propojení synchronizuje vašeho Pilota s poznámkami v KNotes.
+Comment[cy]=Mae'r cwndid yma yn cydamseru y cymhwysiad Memo Pad efo KNodiadau.
+Comment[da]=Denne kanal synkroniserer dit memopad-program med KNotes.
+Comment[de]=Abgleich des Memo Pad mit KNotes
+Comment[el]=Αυτός ο σύνδεσμος συγχρονίζει την εφαρμογή Memo Pad με το KNotes.
+Comment[eo]=Tiu kanalo sinkronigas la MemoPad-aplikaĵon kun KNotoj.
+Comment[es]=Este conducto sincroniza la aplicación de Notas con KNotes.
+Comment[et]=See kanal sünkroniseerib Memo Pad rakenduse ja KNotesi.
+Comment[eu]=Kanal honek Memo Pad aplikazioa KNotes-ekin sinkronizatzen du.
+Comment[fa]=این لوله، کاربرد Memo Pad را با KNotes همگام می‌سازد.
+Comment[fi]=Tämä yhdyskäytävä synkronoi Memo Pad -ohelman KNotesin kanssa.
+Comment[fr]=Ce canal synchronise l'application « Memo Pad » avec KNotes.
+Comment[fy]=Dit conduit syngronisearret de Memo Pad mei KNotes.
+Comment[gl]=Este conducto sincroniza a aplicación Memo Pad con KNotes.
+Comment[hi]=यह कन्ड्यूइट मेमो पेड अनुप्रयोगों को के-नोट्स के साथ सिंक करता है
+Comment[hu]=Ezzel a csatolóval a Memo Pad program és a KNotes között lehet szinkronizálást végezni.
+Comment[is]=Þessi rás samstillir lófatölvuna þína við KNotes.
+Comment[it]=Questo condotto sincronizza l'applicazione Memo Pad con KNotes.
+Comment[ja]=このコンジットはメモ帳アプリケーションを KNotes と同期させます。
+Comment[ka]=ეს არხი ახდენს Memo Pad პროგრამის სინქრონიზაციას KNotes-თან.
+Comment[kk]=Memo Pad қолданбаны KNotes жазбаларымен қадамдастыру арнасы.
+Comment[km]=បំពង់​នេះ​អាច​ឲ្យ​កម្មវិធី Memo Pad ធ្វើ​សមកាលកម្ម​ជាមួយ​នឹង KNotes ។
+Comment[lt]=Šis kanalas sinchronizuoja Memo Pad programą su KNotes.
+Comment[mk]=Овој канал ја синхронизира апликацијата Memo Pad со КБелешки.
+Comment[ms]=Saluran ini mensegerakkan aplikasi Memo Pad dengan KNotes.
+Comment[nb]=Denne kanalen synkroniserer notatblokk-programmet med KNotes.
+Comment[nds]=Synkroniseert dat Palm-Programm "Memo Pad" mit KNotes.
+Comment[ne]=यो कन्ड्युटले मेमो प्याड अनुप्रयोग केडीई टिप्पणीमा सिन्क गर्दछ ।
+Comment[nl]=Dit conduit synchroniseert de Memo Pad met KNotes.
+Comment[nn]=Denne koplinga synkroniserer «Memo Pad»-applikasjonen med KNotes.
+Comment[pl]=Ten łącznik synchronizuje program Memo Pad palmtopa z KNotes (notatkami).
+Comment[pt]=Esta conduta sincroniza os memorandos com o KNotes.
+Comment[pt_BR]=Este conduíte sincroniza a aplicação Memo Pad com o KNotes.
+Comment[ro]=Această conductă sincronizează aplicaţia Memo Pad cu KNotes.
+Comment[ru]=Канал синхронизации заметок КПК и KDE.
+Comment[sk]=Táto spojka synchronizuje aplikáciu Memo Pad s KNotes
+Comment[sl]=Ta veznik usklajuje program Memo Pad s KNotice.
+Comment[sr]=Овај провод синхронизује Memo Pad програме са KNotes-ом.
+Comment[sr@Latn]=Ovaj provod sinhronizuje Memo Pad programe sa KNotes-om.
+Comment[sv]=Den här kanalen synkroniserar programmet Memo Pad med Knotes.
+Comment[ta]=இந்த காப்புக் குழாய் குறிப்பாணை அட்டை பயன்பாடு கேகுறிப்புகளுடன் ஒத்திசைக்கிறது
+Comment[tg]=Канали синхронизатсияи қайдоти Pilot ва KDE.
+Comment[tr]=Bu kanal KNotes ile el bilgisayarınızı senkronize etmenize olanak sağlar
+Comment[uk]=Цей акведук синхронізує Memo Pad з тижневиком KNotes.
+Comment[zh_CN]=此管道将会将您的备忘程序与 KNotes 同步。
+Comment[zh_TW]=此軟體將 KNote 與 Memo Pad 應用程式同步。
+Name=KNotes / Memos
+Name[be]=K Нататкі
+Name[bg]=KNotes/Memos
+Name[cs]=KNotes / Poznámky
+Name[cy]=KNodiadau/Memos
+Name[da]=KNotes / Memoer
+Name[el]=KNotes / Υπομνήματα
+Name[eo]=KNotoj
+Name[et]=KNotes / memod
+Name[eu]=KNotes / Oharrak
+Name[fr]=KNotes / Mémos
+Name[fy]=KNotes / memo's
+Name[ga]=KNotes / Meamraim
+Name[hi]=के-नोट्स / मेमो
+Name[hu]=KNotes / memók
+Name[is]=KNotes / minnisblöð
+Name[it]=KNotes / Memo
+Name[ka]=KNotes / ჩანიშვნები
+Name[kk]=KNotes / Жазбалар
+Name[km]=KNotes / អនុស្សរណៈ
+Name[lt]=KNotes / Memo
+Name[mk]=КБелешки / Меморандуми
+Name[ms]=KNotes / Memo
+Name[nds]=KNotes / Notizen
+Name[ne]=केडीई टिप्पणी / मेमो
+Name[nl]=KNotes / memo's
+Name[nn]=KNotes / Memoar
+Name[pl]=KNotes / Notatki
+Name[pt]=Notas / Memorandos
+Name[pt_BR]=KNotes / Memorandos
+Name[ru]=KNotes / Заметки
+Name[sk]=Poznámky / Memo
+Name[sl]=KNotice / Opomniki
+Name[sv]=Knotes/Memo Pad
+Name[ta]=கேகுறிப்புகள்/குறிப்பாணைகள்
+Name[tg]=KNotes / Қайдот
+Name[tr]=KNotlar / Hatırlatmalar
+Name[zh_CN]=KNotes / 备忘
+Implemented=file
+ServiceTypes=KPilotConduit
+X-KDE-Library=conduit_knotes
diff --git a/kpilot/conduits/knotes/knotes-factory.cc b/kpilot/conduits/knotes/knotes-factory.cc
new file mode 100644
index 000000000..a919e1ed1
--- /dev/null
+++ b/kpilot/conduits/knotes/knotes-factory.cc
@@ -0,0 +1,133 @@
+/* KPilot
+**
+** Copyright (C) 2001,2003 by Dan Pilone
+**
+** This file defines the factory for the knotes-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <kapplication.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+
+#include <dcopclient.h>
+
+#include <time.h> // Needed by pilot-link include
+
+#include <pi-memo.h>
+
+#include "knotes-action.h"
+#include "knotes-setup.h"
+
+#include "knotes-factory.moc"
+
+
+extern "C"
+{
+
+void *init_conduit_knotes()
+{
+ return new KNotesConduitFactory;
+}
+
+}
+
+
+/* static */ KAboutData *KNotesConduitFactory::fAbout = 0L;
+
+KNotesConduitFactory::KNotesConduitFactory(QObject *p, const char *n) :
+ KLibFactory(p,n)
+{
+ FUNCTIONSETUP;
+
+ fInstance = new KInstance("knotesconduit");
+ fAbout = new KAboutData("knotesconduit",
+ I18N_NOOP("KNotes Conduit for KPilot"),
+ KPILOT_VERSION,
+ I18N_NOOP("Configures the KNotes Conduit for KPilot"),
+ KAboutData::License_GPL,
+ "(C) 2001, Adriaan de Groot");
+ fAbout->addAuthor("Adriaan de Groot",
+ I18N_NOOP("Primary Author"),
+ "http://www.cs.kun.nl/~adridg/kpilot");
+ fAbout->addCredit("David Bishop",
+ I18N_NOOP("UI"));
+}
+
+KNotesConduitFactory::~KNotesConduitFactory()
+{
+ FUNCTIONSETUP;
+
+ KPILOT_DELETE(fInstance);
+ KPILOT_DELETE(fAbout);
+}
+
+/* virtual */ QObject *KNotesConduitFactory::createObject( QObject *p,
+ const char *n,
+ const char *c,
+ const QStringList &a)
+{
+ FUNCTIONSETUP;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Creating object of class "
+ << c
+ << endl;
+#endif
+
+ if (qstrcmp(c,"ConduitConfigBase")==0)
+ {
+ QWidget *w = dynamic_cast<QWidget *>(p);
+ if (w)
+ {
+ return new KNotesConfigBase(w,0L);
+ }
+ else
+ {
+ return 0L;
+ }
+ }
+ else
+ if (qstrcmp(c,"SyncAction")==0)
+ {
+ KPilotLink *d = dynamic_cast<KPilotLink *>(p);
+
+ if (d)
+ {
+ return new KNotesAction(d,n,a);
+ }
+ else
+ {
+ WARNINGKPILOT
+ << "Couldn't cast parent to KPilotDeviceLink"
+ << endl;
+ return 0L;
+ }
+ }
+
+ return 0L;
+}
diff --git a/kpilot/conduits/knotes/knotes-factory.h b/kpilot/conduits/knotes/knotes-factory.h
new file mode 100644
index 000000000..94ad44429
--- /dev/null
+++ b/kpilot/conduits/knotes/knotes-factory.h
@@ -0,0 +1,70 @@
+#ifndef _KPILOT_NULL_FACTORY_H
+#define _KPILOT_NULL_FACTORY_H
+/* null-factory.h KPilot
+**
+** Copyright (C) 2001,2003 by Dan Pilone
+**
+** This file defines the factory for the null-conduit plugin.
+** It also defines the class for the behavior of the setup dialog.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <klibloader.h>
+
+class KInstance;
+class KAboutData;
+
+class KNotesConduitFactory : public KLibFactory
+{
+Q_OBJECT
+
+public:
+ KNotesConduitFactory(QObject * = 0L,const char * = 0L);
+ virtual ~KNotesConduitFactory();
+
+ static KAboutData *about() { return fAbout; } ;
+
+ // The KNotes instance, unlike previous conduits (alphabetically)
+ // has const char * const members. The extra const prevents people
+ // from assigning to this variable, so you have to work hard to
+ // break its value. We store group and entry keys in here.
+
+protected:
+ virtual QObject* createObject( QObject* parent = 0,
+ const char* name = 0,
+ const char* classname = "QObject",
+ const QStringList &args = QStringList() );
+private:
+ KInstance *fInstance;
+ static KAboutData *fAbout;
+} ;
+
+extern "C"
+{
+
+void *init_libknotesconduit();
+
+}
+
+
+#endif
diff --git a/kpilot/conduits/knotes/knotes-setup.cc b/kpilot/conduits/knotes/knotes-setup.cc
new file mode 100644
index 000000000..da8b31c48
--- /dev/null
+++ b/kpilot/conduits/knotes/knotes-setup.cc
@@ -0,0 +1,83 @@
+/* KPilot
+**
+** Copyright (C) 2001,2003 by Dan Pilone
+**
+** This file defines the setup dialog for the knotes-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qtabwidget.h>
+#include <qcheckbox.h>
+#include <qmap.h>
+#include <qtimer.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+
+#include "setup_base.h"
+
+#include "knotes-factory.h"
+#include "knotes-setup.h"
+#include "knotesconduitSettings.h"
+
+
+KNotesConfigBase::KNotesConfigBase(QWidget *w, const char *n) :
+ ConduitConfigBase(w,n),
+ fConfigWidget(0L)
+{
+ fConfigWidget = new KNotesWidget(w);
+ ConduitConfigBase::addAboutPage(fConfigWidget->tabWidget,KNotesConduitFactory::about());
+ fWidget = fConfigWidget;
+ QObject::connect(fConfigWidget->fDeleteNoteForMemo,SIGNAL(clicked()),
+ this,SLOT(modified()));
+ QObject::connect(fConfigWidget->fSuppressConfirm,SIGNAL(clicked()),
+ this,SLOT(modified()));
+ QObject::connect(fConfigWidget->fDeleteNoteForMemo,SIGNAL(toggled(bool)),
+ fConfigWidget->fSuppressConfirm,SLOT(setEnabled(bool)));
+ fConduitName=i18n("KNotes");
+}
+
+void KNotesConfigBase::commit()
+{
+ KNotesConduitSettings::setDeleteNoteForMemo( fConfigWidget->fDeleteNoteForMemo->isChecked() );
+ KNotesConduitSettings::setSuppressKNotesConfirm(fConfigWidget->fSuppressConfirm->isChecked());
+ KNotesConduitSettings::self()->writeConfig();
+ unmodified();
+}
+
+void KNotesConfigBase::load()
+{
+ KNotesConduitSettings::self()->readConfig();
+ fConfigWidget->fDeleteNoteForMemo->setChecked(KNotesConduitSettings::deleteNoteForMemo() );
+ fConfigWidget->fSuppressConfirm->setChecked(KNotesConduitSettings::suppressKNotesConfirm() );
+ fConfigWidget->fSuppressConfirm->setEnabled(KNotesConduitSettings::deleteNoteForMemo());
+ unmodified();
+}
+
+/* static */ ConduitConfigBase *KNotesConfigBase::create(QWidget *w, const char *n)
+{
+ return new KNotesConfigBase(w,n);
+}
+
diff --git a/kpilot/conduits/knotes/knotes-setup.h b/kpilot/conduits/knotes/knotes-setup.h
new file mode 100644
index 000000000..9e7603df7
--- /dev/null
+++ b/kpilot/conduits/knotes/knotes-setup.h
@@ -0,0 +1,49 @@
+#ifndef _KPILOT_KNOTES_SETUP_H
+#define _KPILOT_KNOTES_SETUP_H
+/* knotes-setup.h KPilot
+**
+** Copyright (C) 2001,2003 by Dan Pilone
+**
+** This file defines the widget and behavior for the config dialog
+** of the KNotes conduit.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "plugin.h"
+
+class KNotesWidget;
+
+class KNotesConfigBase : public ConduitConfigBase
+{
+public:
+ KNotesConfigBase(QWidget *parent, const char *name);
+
+ virtual void commit();
+ virtual void load();
+
+ static ConduitConfigBase *create(QWidget *p, const char *n);
+private:
+ KNotesWidget *fConfigWidget;
+} ;
+
+#endif
diff --git a/kpilot/conduits/knotes/knotesconduit.kcfg b/kpilot/conduits/knotes/knotesconduit.kcfg
new file mode 100644
index 000000000..41d86d2b4
--- /dev/null
+++ b/kpilot/conduits/knotes/knotesconduit.kcfg
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kpilot_notesconduitrc"/>
+ <group name="General">
+ <entry name="DeleteNoteForMemo" type="Bool">
+ <default>false</default>
+ </entry>
+ <entry name="SuppressKNotesConfirm" type="Bool">
+ <label>Suppress the confirmation KNotes normally shows when deleting a note.</label>
+ <default>false</default>
+ </entry>
+
+ <entry name="MemoIds" type="IntList">
+ <label>list of the synced MemoDB records</label>
+ <default></default>
+ </entry>
+ <entry name="NoteIds" type="StringList">
+ <label>list of the corresponding KNotes note IDs</label>
+ <default></default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kpilot/conduits/knotes/knotesconduitSettings.kcfgc b/kpilot/conduits/knotes/knotesconduitSettings.kcfgc
new file mode 100644
index 000000000..33152ac69
--- /dev/null
+++ b/kpilot/conduits/knotes/knotesconduitSettings.kcfgc
@@ -0,0 +1,7 @@
+File=knotesconduit.kcfg
+ClassName=KNotesConduitSettings
+Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/conduits/knotes/setup_base.ui b/kpilot/conduits/knotes/setup_base.ui
new file mode 100644
index 000000000..e6aef8042
--- /dev/null
+++ b/kpilot/conduits/knotes/setup_base.ui
@@ -0,0 +1,88 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>KNotesWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KNotesWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>436</width>
+ <height>394</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>fDeleteNoteForMemo</cstring>
+ </property>
+ <property name="text">
+ <string>Delete KNote when Pilot memo is deleted</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box if you wish to delete notes from KNotes automatically when the corresponding Pilot memo is deleted. Use this option with care, as the notes you want to keep in the handheld and in the desktop are not necessarily the same.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>fSuppressConfirm</cstring>
+ </property>
+ <property name="text">
+ <string>Suppress delete-confirmation in KNotes</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box if you wish to delete notes from KNotes, without confirmation, when the corresponding Pilot memo is deleted. Use this option only if you want to keep the same notes in the handheld and in the PC.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>101</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpilot/conduits/malconduit/CMakeLists.txt b/kpilot/conduits/malconduit/CMakeLists.txt
new file mode 100644
index 000000000..092f340fd
--- /dev/null
+++ b/kpilot/conduits/malconduit/CMakeLists.txt
@@ -0,0 +1,48 @@
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${MAL_INCLUDE_DIR}
+)
+
+set(conduit_mal_SRCS
+ mal-factory.cc
+ mal-setup.cc
+ mal-conduit.cc
+)
+
+set(conduit_mal_UIS
+ mal-setup_dialog.ui
+)
+
+set(conduit_mal_KCFGS
+ malconduitSettings.kcfgc
+)
+
+kde3_add_kcfg_files(conduit_mal_SRCS ${conduit_mal_KCFGS})
+kde3_add_ui_files(conduit_mal_SRCS ${conduit_mal_UIS})
+kde3_automoc(${conduit_mal_SRCS})
+add_library(conduit_mal SHARED ${conduit_mal_SRCS})
+target_link_libraries(conduit_mal ${MAL_LIBRARY})
+
+set_target_properties(
+ conduit_mal PROPERTIES
+ LOCATION ${KDE3_PLUGIN_INSTALL_DIR}
+ PREFIX ""
+ INSTALL_RPATH "${MAL_LIBRARY}"
+ INSTALL_RPATH_USE_LINK_PATH true
+)
+
+kde3_install_libtool_file(conduit_mal)
+
+install(
+ TARGETS conduit_mal
+ LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR}
+)
+
+install(
+ FILES mal_conduit.desktop DESTINATION ${KDE3_SERVICES_DIR}
+)
+
+install(
+ FILES malconduit.kcfg DESTINATION ${KDE3_KCFG_DIR}
+)
+
diff --git a/kpilot/conduits/malconduit/Makefile.am b/kpilot/conduits/malconduit/Makefile.am
new file mode 100644
index 000000000..d8a222431
--- /dev/null
+++ b/kpilot/conduits/malconduit/Makefile.am
@@ -0,0 +1,18 @@
+### Makefile for the avantgo conduit
+###
+### The mal conduit is Copyright (C) 2002 by Reinhold Kainhofer
+
+
+INCLUDES= $(PISOCK_INCLUDE) $(MAL_INCLUDE) -I$(top_srcdir)/kpilot/lib $(all_includes)
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = mal_conduit.desktop
+kde_kcfg_DATA = malconduit.kcfg
+
+kde_module_LTLIBRARIES = conduit_mal.la
+
+conduit_mal_la_SOURCES = malconduitSettings.kcfgc mal-setup_dialog.ui mal-factory.cc mal-setup.cc mal-conduit.cc
+conduit_mal_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+conduit_mal_la_LIBADD = ../../lib/libkpilot.la $(MAL_LIB) $(LIB_KDEUI)
+
diff --git a/kpilot/conduits/malconduit/README b/kpilot/conduits/malconduit/README
new file mode 100644
index 000000000..deeeb12ef
--- /dev/null
+++ b/kpilot/conduits/malconduit/README
@@ -0,0 +1,12 @@
+KPilot's malconduit
++++++++++++++++++++
+
+Summary: This conduit syncs the handheld with
+ MAL servers such as AvantGo.
+Author: Reinhold Kainhofer, [email protected]
+Date: August 15, 2002
+License: GPL, linking to libmal (MPL) is explicitly allowed
+Depends: The conduits needs libmal >=0.20 installed
+ (otherwise it will not be compiled). libmal
+ can be downloaded from
+ http://jasonday.home.att.net/code/libmal/
diff --git a/kpilot/conduits/malconduit/mal-conduit.cc b/kpilot/conduits/malconduit/mal-conduit.cc
new file mode 100644
index 000000000..73a77a141
--- /dev/null
+++ b/kpilot/conduits/malconduit/mal-conduit.cc
@@ -0,0 +1,319 @@
+/*
+** MAL conduit for KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+**
+**
+** Specific permission is granted for this code to be linked to libmal
+** (this is necessary because the libmal license is not GPL-compatible).
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+
+
+#include "options.h"
+
+#include <qregexp.h>
+#include <kconfig.h>
+#include <kdebug.h>
+
+#include "mal-factory.h"
+#include "mal-conduit.moc"
+#include <libmal.h>
+#include "malconduitSettings.h"
+
+
+static MALConduit *conduitInstance=0L;
+
+int malconduit_logf(const char *, ...) __attribute__ ((format (printf, 1, 2)));
+
+int malconduit_logf(const char *format, ...)
+{
+ FUNCTIONSETUP;
+ va_list val;
+ int rval;
+ va_start(val, format);
+#define WRITE_MAX_BUF 4096
+ char msg[WRITE_MAX_BUF];
+ msg[0]='\0';
+ rval=vsnprintf(&msg[0], sizeof(msg), format, val);
+ va_end(val);
+ if (rval == -1) {
+ msg[WRITE_MAX_BUF-1] = '\0';
+ rval=WRITE_MAX_BUF-1;
+ }
+ if (conduitInstance)
+ {
+ conduitInstance->printLogMessage(msg);
+ }
+ else
+ {
+ // write out to stderr
+ WARNINGKPILOT<< msg << endl;
+ }
+ return rval;
+}
+
+#ifndef LIBMAL20
+int32 cbTask (void * /*out*/,
+ int32 * /*returnErrorCode*/,
+ char *currentTask,
+ AGBool /*bufferable*/)
+{
+ if (currentTask) {
+ malconduit_logf ("%s\n", currentTask);
+ }
+
+ return AGCLIENT_CONTINUE;
+}
+
+static int32 cbItem (void */*out*/,
+ int32 * /*returnErrorCode*/,
+ int32 /*currentItemNumber*/,
+ int32 /*totalItemCount*/,
+ char * /*currentItem*/)
+{
+// The log widget only supports writing out whole lines. You just can't add a single character
+// to the last line. Thus I completely remove the pseudo-percentbar.
+/* malconduit_logf (".");
+
+ if (currentItemNumber == totalItemCount) {
+ malconduit_logf ("\n");
+ }
+*/
+ return AGCLIENT_CONTINUE;
+}
+#endif
+
+
+MALConduit::MALConduit(KPilotLink * o,
+ const char *n,
+ const QStringList & a) :
+ ConduitAction(o, n, a)
+{
+ FUNCTIONSETUP;
+#ifdef LIBMAL20
+ register_printStatusHook(malconduit_logf);
+ register_printErrorHook(malconduit_logf);
+#endif
+ conduitInstance=this;
+ fConduitName=i18n("MAL");
+}
+
+
+
+MALConduit::~MALConduit()
+{
+ FUNCTIONSETUP;
+}
+
+
+
+void MALConduit::readConfig()
+{
+ FUNCTIONSETUP;
+ MALConduitSettings::self()->readConfig();
+#ifdef DEBUG
+ DEBUGKPILOT<<"Last sync was "<<MALConduitSettings::lastMALSync().toString()<<endl;
+#endif
+}
+
+
+
+void MALConduit::saveConfig()
+{
+ FUNCTIONSETUP;
+ MALConduitSettings::setLastMALSync( QDateTime::currentDateTime() );
+ MALConduitSettings::self()->writeConfig();
+}
+
+
+
+bool MALConduit::skip()
+{
+ QDateTime now=QDateTime::currentDateTime();
+ QDateTime lastSync=MALConduitSettings::lastMALSync();
+
+ if (!lastSync.isValid() || !now.isValid()) return false;
+
+ switch ( MALConduitSettings::syncFrequency() )
+ {
+ case MALConduitSettings::eEveryHour:
+ if ( (lastSync.secsTo(now)<=3600) && (lastSync.time().hour()==now.time().hour()) ) return true;
+ else return false;
+ case MALConduitSettings::eEveryDay:
+ if ( lastSync.date() == now.date() ) return true;
+ else return false;
+ case MALConduitSettings::eEveryWeek:
+ if ( (lastSync.daysTo(now)<=7) && ( lastSync.date().dayOfWeek()<=now.date().dayOfWeek()) ) return true;
+ else return false;
+ case MALConduitSettings::eEveryMonth:
+ if ( (lastSync.daysTo(now)<=31) && (lastSync.date().month()==now.date().month()) ) return true;
+ else return false;
+ case MALConduitSettings::eEverySync:
+ default:
+ return false;
+ }
+ return false;
+}
+
+
+
+/* virtual */ bool MALConduit::exec()
+{
+ FUNCTIONSETUP;
+
+ readConfig();
+
+ // TODO: set the log/error message hooks of libmal here!!!
+
+ if (skip())
+ {
+ emit logMessage(i18n("Skipping MAL sync, because last synchronization was not long enough ago."));
+ emit syncDone(this);
+ return true;
+ }
+
+ // Now initiate the sync.
+ PalmSyncInfo* pInfo=syncInfoNew();
+ if (!pInfo) {
+ WARNINGKPILOT << "Could not allocate SyncInfo!" << endl;
+ emit logError(i18n("MAL synchronization failed (no SyncInfo)."));
+ return false;
+ }
+
+ QString proxyServer( MALConduitSettings::proxyServer() );
+ int proxyPort( MALConduitSettings::proxyPort() );
+ QString syncMessage;
+ bool canContinue = true;
+ // Set all proxy settings
+ switch (MALConduitSettings::proxyType())
+ {
+ case MALConduitSettings::eProxyHTTP:
+ if (proxyServer.isEmpty())
+ {
+ canContinue = false;
+ syncMessage = i18n("No proxy server is set.");
+ break;
+ }
+ syncMessage = i18n("Using proxy server: %1").arg(proxyServer);
+
+#ifdef DEBUG
+ DEBUGKPILOT<<" Using HTTP proxy server \""<<proxyServer<<
+ "\", Port "<<proxyPort<<", User "<<MALConduitSettings::proxyUser()<<
+ ", Password "<<( (MALConduitSettings::proxyPassword().isEmpty())?QString("not "):QString())<<"set"
+ <<endl;
+#endif
+#ifdef LIBMAL20
+ setHttpProxy(const_cast<char *>(proxyServer.latin1()));
+ if (proxyPort>0 && proxyPort<65536) setHttpProxyPort( proxyPort );
+ else setHttpProxyPort(80);
+#else
+ pInfo->httpProxy = new char[ proxyServer.length() + 1 ];
+ strlcpy( pInfo->httpProxy, proxyServer.latin1(), proxyServer.length() + 1);
+ if (proxyPort>0 && proxyPort<65536) pInfo->httpProxyPort = proxyPort;
+ else pInfo->httpProxyPort = 80;
+#endif
+
+ if (!MALConduitSettings::proxyUser().isEmpty())
+ {
+#ifdef LIBMAL20
+ setProxyUsername( const_cast<char *>(MALConduitSettings::proxyUser().latin1()) );
+ if (!MALConduitSettings::proxyPassword().isEmpty()) setProxyPassword( const_cast<char *>(MALConduitSettings::proxyPassword().latin1()) );
+#else
+ pInfo->proxyUsername = new char[ MALConduitSettings::proxyUser().length() + 1 ];
+ strlcpy( pInfo->proxyUsername, MALConduitSettings::proxyUser().latin1(), MALConduitSettings::proxyUser().length() + 1);
+ if (!MALConduitSettings::proxyPassword().isEmpty()) {
+// pInfo->proxyPassword = MALConduitSettings::proxyPassword().latin1();
+ pInfo->proxyPassword = new char[ MALConduitSettings::proxyPassword().length() + 1 ];
+ strlcpy( pInfo->proxyPassword, MALConduitSettings::proxyPassword().latin1(), MALConduitSettings::proxyPassword().length() + 1);
+ }
+#endif
+ }
+ break;
+ case MALConduitSettings::eProxySOCKS:
+ if (proxyServer.isEmpty())
+ {
+ canContinue = false;
+ syncMessage = i18n("No SOCKS proxy is set.");
+ break;
+ }
+ syncMessage = i18n("Using SOCKS proxy: %1").arg(proxyServer);
+#ifdef DEBUG
+ DEBUGKPILOT<<" Using SOCKS proxy server \""<<proxyServer<<"\", Port "<<proxyPort<<", User "<<MALConduitSettings::proxyUser()<<", Password "<<( (MALConduitSettings::proxyPassword().isEmpty())?QString("not "):QString() )<<"set"<<endl;
+#endif
+#ifdef LIBMAL20
+ setSocksProxy( const_cast<char *>(proxyServer.latin1()) );
+ if (proxyPort>0 && proxyPort<65536) setSocksProxyPort( proxyPort );
+ else setSocksProxyPort(1080);
+#else
+// pInfo->socksProxy = proxyServer.latin1();
+ pInfo->socksProxy = new char[ proxyServer.length() + 1 ];
+ strlcpy( pInfo->socksProxy, proxyServer.latin1(), proxyServer.length() + 1);
+ if (proxyPort>0 && proxyPort<65536) pInfo->socksProxyPort = proxyPort;
+ else pInfo->socksProxyPort = 1080;
+#endif
+ break;
+ default:
+ break;
+ }
+
+ logMessage(syncMessage);
+
+ if (!canContinue)
+ {
+ return false;
+ }
+
+#ifdef LIBMAL20
+ malsync( pilotSocket(), pInfo);
+#else
+ pInfo->sd = pilotSocket();
+ pInfo->taskFunc = cbTask;
+ pInfo->itemFunc = cbItem;
+ malsync( pInfo );
+ delete[] pInfo->httpProxy;
+ delete[] pInfo->proxyUsername;
+ delete[] pInfo->proxyPassword;
+ delete[] pInfo->socksProxy;
+ syncInfoFree(pInfo);
+#endif
+
+ saveConfig();
+ return delayDone();
+}
+
+void MALConduit::printLogMessage(QString msg)
+{
+ FUNCTIONSETUP;
+ // Remove the pseudo-progressbar:
+ QString newmsg(msg);
+ newmsg.replace( QRegExp("^\\s*\\.*\\s*"), "");
+ newmsg.replace( QRegExp("\\s*\\.*\\s*$"), "");
+ if (newmsg.length()>0)
+ {
+ emit logMessage(newmsg);
+ }
+}
+
diff --git a/kpilot/conduits/malconduit/mal-conduit.h b/kpilot/conduits/malconduit/mal-conduit.h
new file mode 100644
index 000000000..83f72ace1
--- /dev/null
+++ b/kpilot/conduits/malconduit/mal-conduit.h
@@ -0,0 +1,66 @@
+#ifndef _MAL_CONDUIT_H
+#define _MAL_CONDUIT_H
+/* mal-conduit.h KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+**
+**
+** Specific permission is granted for this code to be linked to libmal
+** (this is necessary because the libmal license is not GPL-compatible).
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+
+#include <plugin.h>
+
+class MALConduit : public ConduitAction
+{
+Q_OBJECT
+public:
+ MALConduit(
+ KPilotLink *o,
+ const char *n = 0L,
+ const QStringList &a = QStringList() );
+ virtual ~MALConduit();
+ void printLogMessage(QString msg);
+ virtual bool exec();
+
+protected:
+ /**
+ * Read in the config from the KPilot config files and fill the member variables accordingly
+ */
+ void readConfig();
+ /**
+ * Store the sync time in the KPilot configuration
+ */
+ void saveConfig();
+ /**
+ * Check if the last sync was not so long ago that according to MALConduitSettings::syncFrequency() we can skip the sync this time
+ */
+ bool skip();
+} ;
+
+
+#endif
diff --git a/kpilot/conduits/malconduit/mal-factory.cc b/kpilot/conduits/malconduit/mal-factory.cc
new file mode 100644
index 000000000..f9a8bcafb
--- /dev/null
+++ b/kpilot/conduits/malconduit/mal-factory.cc
@@ -0,0 +1,143 @@
+/* Time-factory.cc KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This file defines the factory for the MAL-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+**
+**
+** Specific permission is granted for this code to be linked to libmal
+** (this is necessary because the libmal license is not GPL-compatible).
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <kapplication.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+
+#include <time.h> // Needed by pilot-link include
+#include "mal-conduit.h"
+#include "mal-setup.h"
+
+#include "mal-factory.moc"
+
+
+extern "C"
+{
+
+void *init_conduit_mal()
+{
+ return new MALConduitFactory;
+}
+
+unsigned long version_conduit_mal = Pilot::PLUGIN_API;
+
+}
+
+
+// A number of static variables
+//
+KAboutData *MALConduitFactory::fAbout = 0L;
+
+MALConduitFactory::MALConduitFactory(QObject *p, const char *n) :
+ KLibFactory(p,n)
+{
+ FUNCTIONSETUP;
+
+ fInstance = new KInstance("MALconduit");
+ fAbout = new KAboutData("MALconduit",
+ I18N_NOOP("MAL Synchronization Conduit for KPilot"),
+ KPILOT_VERSION,
+ I18N_NOOP("Synchronizes the content from MAL Servers like AvantGo to the Handheld"),
+ KAboutData::License_GPL,
+ "(C) 2002, Reinhold Kainhofer");
+ fAbout->addAuthor("Reinhold Kainhofer",
+ I18N_NOOP("Primary Author"), "[email protected]", "http://reinhold.kainhofer.com/");
+ fAbout->addCredit("Jason Day",
+ I18N_NOOP("Author of libmal and the JPilot AvantGo conduit"), "[email protected]");
+ fAbout->addCredit("Tom Whittaker",
+ I18N_NOOP("Author of syncmal"), "[email protected]", "http://www.tomw.org/");
+ fAbout->addCredit("AvantGo, Inc.",
+ I18N_NOOP("Authors of the malsync library (c) 1997-1999"), "", "http://www.avantgo.com/");
+}
+
+MALConduitFactory::~MALConduitFactory()
+{
+ FUNCTIONSETUP;
+
+ KPILOT_DELETE(fInstance);
+ KPILOT_DELETE(fAbout);
+}
+
+/* virtual */ QObject *MALConduitFactory::createObject( QObject *p,
+ const char *n,
+ const char *c,
+ const QStringList &a)
+{
+ FUNCTIONSETUP;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Creating object of class "
+ << c
+ << endl;
+#endif
+
+ if (qstrcmp(c,"ConduitConfigBase")==0)
+ {
+ QWidget *w = dynamic_cast<QWidget *>(p);
+
+ if (w)
+ {
+ return new MALWidgetSetup(w,n);
+ }
+ else
+ {
+ WARNINGKPILOT
+ << "Couldn't cast parent to widget."
+ << endl;
+ return 0L;
+ }
+ }
+
+ if (qstrcmp(c,"SyncAction")==0)
+ {
+ KPilotLink *d = dynamic_cast<KPilotLink *>(p);
+
+ if (d)
+ {
+ return new MALConduit(d,n,a);
+ }
+ else
+ {
+ WARNINGKPILOT
+ << "Couldn't cast parent to KPilotLink"
+ << endl;
+ return 0L;
+ }
+ }
+
+ return 0L;
+}
+
diff --git a/kpilot/conduits/malconduit/mal-factory.h b/kpilot/conduits/malconduit/mal-factory.h
new file mode 100644
index 000000000..82631e1ac
--- /dev/null
+++ b/kpilot/conduits/malconduit/mal-factory.h
@@ -0,0 +1,67 @@
+#ifndef _TIME_FACTORY_H
+#define _TIME_FACTORY_H
+/* MAL-factory.h KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This file defines the factory for the mal-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+**
+**
+** Specific permission is granted for this code to be linked to libmal
+** (this is necessary because the libmal license is not GPL-compatible).
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <klibloader.h>
+
+class KInstance;
+class KAboutData;
+
+class MALConduitFactory : public KLibFactory
+{
+Q_OBJECT
+
+public:
+ MALConduitFactory(QObject * = 0L,const char * = 0L);
+ virtual ~MALConduitFactory();
+
+ static KAboutData *about() { return fAbout; } ;
+
+protected:
+ virtual QObject* createObject( QObject* parent = 0,
+ const char* name = 0,
+ const char* classname = "QObject",
+ const QStringList &args = QStringList() );
+private:
+ KInstance *fInstance;
+ static KAboutData *fAbout;
+} ;
+
+extern "C"
+{
+
+void *init_libtimeconduit();
+
+}
+
+#endif
diff --git a/kpilot/conduits/malconduit/mal-setup.cc b/kpilot/conduits/malconduit/mal-setup.cc
new file mode 100644
index 000000000..d2652b035
--- /dev/null
+++ b/kpilot/conduits/malconduit/mal-setup.cc
@@ -0,0 +1,185 @@
+/* MAL-setup.cc KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This file defines the setup dialog for the MAL-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+**
+**
+** Specific permission is granted for this code to be linked to libmal
+** (this is necessary because the libmal license is not GPL-compatible).
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qtabwidget.h>
+#include <qradiobutton.h>
+#include <qbuttongroup.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+
+#include <kcombobox.h>
+#include <knuminput.h>
+#include <kpassdlg.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+
+
+#include "mal-setup_dialog.h"
+
+#include "mal-factory.h"
+#include "mal-setup.moc"
+#include "malconduitSettings.h"
+
+
+MALWidgetSetup::MALWidgetSetup(QWidget *w, const char *n) :
+ ConduitConfigBase(w,n),
+ fConfigWidget(new MALWidget(w))
+{
+ FUNCTIONSETUP;
+
+ fConduitName=i18n("MAL");
+ ConduitConfigBase::addAboutPage(fConfigWidget->tabWidget,MALConduitFactory::about());
+ fWidget = fConfigWidget;
+
+ fConfigWidget->tabWidget->adjustSize();
+ fConfigWidget->resize(fConfigWidget->tabWidget->size());
+#define CM(a,b) connect(fConfigWidget->a,b,this,SLOT(modified()));
+ CM( syncTime, SIGNAL(clicked(int)) );
+ CM( proxyType, SIGNAL(clicked(int)) );
+
+ CM( proxyServerName, SIGNAL(textChanged(const QString &)) );
+ CM( proxyCustomPortCheck, SIGNAL(clicked()) );
+ CM( proxyCustomPort, SIGNAL(valueChanged(int)) );
+ CM( proxyUserName, SIGNAL(textChanged(const QString &)) );
+ CM( proxyPassword, SIGNAL(textChanged(const QString &)) );
+
+ CM( malServerName, SIGNAL(textChanged(const QString &)) );
+ CM( malCustomPortCheck, SIGNAL(clicked()) );
+ CM( malCustomPort, SIGNAL(valueChanged(int)) );
+ CM( malUserName, SIGNAL(textChanged(const QString &)) );
+ CM( malPassword, SIGNAL(textChanged(const QString &)) );
+#undef CM
+}
+
+MALWidgetSetup::~MALWidgetSetup()
+{
+ FUNCTIONSETUP;
+}
+
+/* virtual */ void MALWidgetSetup::commit()
+{
+ FUNCTIONSETUP;
+
+ MALConduitSettings::setSyncFrequency(
+ fConfigWidget->syncTime->id(fConfigWidget->syncTime->selected()));
+
+ // Proxy settings
+ MALConduitSettings::setProxyType(
+ fConfigWidget->proxyType->id(fConfigWidget->proxyType->selected()));
+ MALConduitSettings::setProxyServer( fConfigWidget->proxyServerName->currentText() );
+
+ if (fConfigWidget->proxyCustomPortCheck->isChecked() )
+ {
+ MALConduitSettings::setProxyPort( fConfigWidget->proxyCustomPort->value());
+ }
+ else
+ {
+ MALConduitSettings::setProxyPort(0);
+ }
+ MALConduitSettings::setProxyUser( fConfigWidget->proxyUserName->text() );
+ MALConduitSettings::setProxyPassword( fConfigWidget->proxyPassword->password() );
+
+ // MAL Server settings (not yet possible!!!)
+ MALConduitSettings::setMALServer( fConfigWidget->malServerName->currentText() );
+
+ if (fConfigWidget->malCustomPortCheck->isChecked() )
+ {
+ MALConduitSettings::setMALPort( fConfigWidget->malCustomPort->value());
+ }
+ else
+ {
+ MALConduitSettings::setMALPort(0);
+ }
+ MALConduitSettings::setMALUser( fConfigWidget->malUserName->text() );
+ MALConduitSettings::setMALPassword( fConfigWidget->malPassword->text() );
+
+ MALConduitSettings::self()->writeConfig();
+ unmodified();
+}
+
+
+
+/* virtual */ void MALWidgetSetup::load()
+{
+ FUNCTIONSETUP;
+ MALConduitSettings::self()->readConfig();
+
+ fConfigWidget->syncTime->setButton( MALConduitSettings::syncFrequency() );
+
+ // Proxy settings
+ fConfigWidget->proxyType->setButton(MALConduitSettings::proxyType());
+ fConfigWidget->proxyServerName->setEditText(MALConduitSettings::proxyServer());
+
+ int proxyPortNr=MALConduitSettings::proxyPort();
+ if (proxyPortNr>0 && proxyPortNr<65536)
+ {
+ fConfigWidget->proxyCustomPortCheck->setChecked(true);
+ fConfigWidget->proxyCustomPort->setEnabled(true);
+ fConfigWidget->proxyCustomPort->setValue(proxyPortNr);
+ }
+ fConfigWidget->proxyUserName->setText(MALConduitSettings::proxyUser());
+ fConfigWidget->proxyPassword->setText(QString::null);
+ fConfigWidget->proxyPassword->insert(MALConduitSettings::proxyPassword());
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Got proxy password <"
+ << MALConduitSettings::proxyPassword()
+ << "> set Text <"
+ << fConfigWidget->proxyPassword->text()
+ << "> and Pwd <"
+ << fConfigWidget->proxyPassword->password()
+ << ">" << endl;
+#endif
+
+ // MAL Server settings (not yet possible!!!)
+ fConfigWidget->malServerName->setEditText(MALConduitSettings::mALServer());
+
+ int malPortNr=MALConduitSettings::mALPort();
+ if (malPortNr>0 && malPortNr<65536)
+ {
+ fConfigWidget->malCustomPortCheck->setChecked(true);
+ fConfigWidget->malCustomPort->setEnabled(true);
+ fConfigWidget->malCustomPort->setValue(proxyPortNr);
+ }
+ fConfigWidget->malUserName->setText(MALConduitSettings::mALUser());
+ fConfigWidget->malPassword->setText(MALConduitSettings::mALPassword());
+ unmodified();
+}
+
+/* static */ ConduitConfigBase *MALWidgetSetup::create(QWidget *w, const char *n)
+{
+ return new MALWidgetSetup(w,n);
+}
+
diff --git a/kpilot/conduits/malconduit/mal-setup.h b/kpilot/conduits/malconduit/mal-setup.h
new file mode 100644
index 000000000..78b6a0ee2
--- /dev/null
+++ b/kpilot/conduits/malconduit/mal-setup.h
@@ -0,0 +1,54 @@
+#ifndef _MAL_SETUP_H
+#define _MAL_SETUP_H
+/* mal-setup.h KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This file defines the widget and behavior for the config dialog
+** of the mal conduit.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+**
+**
+** Specific permission is granted for this code to be linked to libmal
+** (this is necessary because the libmal license is not GPL-compatible).
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "plugin.h"
+
+class MALWidget;
+
+class MALWidgetSetup : public ConduitConfigBase
+{
+Q_OBJECT
+public:
+ MALWidgetSetup(QWidget *,const char *);
+ virtual ~MALWidgetSetup();
+ virtual void load();
+ virtual void commit();
+ static ConduitConfigBase *create(QWidget *, const char *);
+private:
+ MALWidget *fConfigWidget;
+} ;
+
+
+#endif
diff --git a/kpilot/conduits/malconduit/mal-setup_dialog.ui b/kpilot/conduits/malconduit/mal-setup_dialog.ui
new file mode 100644
index 000000000..8814d190c
--- /dev/null
+++ b/kpilot/conduits/malconduit/mal-setup_dialog.ui
@@ -0,0 +1,634 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>MALWidget</class>
+<author>Reinhold Kainhofer</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>MalWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>534</width>
+ <height>505</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup" row="0" column="0">
+ <property name="name">
+ <cstring>syncTime</cstring>
+ </property>
+ <property name="title">
+ <string>Sync</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Select how often AvantGo should be synchronised</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>RadioButton1</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Every sync</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to synchronize with the MAL server on every HotSync. To perform a successful synchronization, you need to have access to the MAL server during the HotSync.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>RadioButton1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Once per &amp;hour</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to synchronize with the MAL server on every HotSync that is at least one hour after the previous MAL sync. To perform a successful synchronization, you need to have access to the MAL server during the HotSync.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="2" column="0">
+ <property name="name">
+ <cstring>RadioButton1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Once a &amp;day</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to synchronize with the MAL server on every HotSync that is at least one day after the previous MAL sync. To perform a successful synchronization, you need to have access to the MAL server during the HotSync.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="3" column="0">
+ <property name="name">
+ <cstring>RadioButton1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Once a &amp;week</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to synchronize with the MAL server on every HotSync that is at least one week after the previous MAL sync. To perform a successful synchronization, you need to have access to the MAL server during the HotSync.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="4" column="0">
+ <property name="name">
+ <cstring>RadioButton1_5</cstring>
+ </property>
+ <property name="text">
+ <string>Once a &amp;month</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to synchronize with the MAL server on every HotSync that is at least one month after the previous MAL sync. To perform a successful synchronization, you need to have access to the MAL server during the HotSync.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Proxy</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>proxyType</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>GroupBoxPanel</enum>
+ </property>
+ <property name="title">
+ <string>Proxy Type</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>RadioButton8</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;No proxy</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option if you do not want KPilot to use a proxy server. Use this option if you connect to the internet directly.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>RadioButton8_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;HTTP proxy</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option if you want KPilot to use a HTTP proxy.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>RadioButton8_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;SOCKS proxy</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option if you want KPilot to use a SOCKS proxy.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>proxyServerInformation</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="title">
+ <string>Server Information</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer row="1" column="2">
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>proxyCustomPortCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Custom &amp;port:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this box to use a non-standard proxy port.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Ser&amp;ver name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>proxyServerName</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;If you selected HTTP or SOCKS proxy, type the address of the proxy server to use here, in the form &lt;i&gt;foo.bar.com&lt;/i&gt; (not &lt;i&gt;http://foo.bar.com&lt;/i&gt; or &lt;i&gt;http://foo.bar.com:8080&lt;/i&gt;).&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="KHistoryCombo" row="0" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>proxyServerName</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;If you selected HTTP or SOCKS proxy, type the address of the proxy server to use here, in the form &lt;i&gt;foo.bar.com&lt;/i&gt; (not &lt;i&gt;http://foo.bar.com&lt;/i&gt; or &lt;i&gt;http://foo.bar.com:8080&lt;/i&gt;).&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="1" column="1">
+ <property name="name">
+ <cstring>proxyCustomPort</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="value">
+ <number>80</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>65535</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter the port you want KPilot to use when connecting to your proxy server here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="KPasswordEdit" row="5" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>proxyPassword</cstring>
+ </property>
+ <property name="echoMode">
+ <enum>Password</enum>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;If your proxy requires authentication, enter your password here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="4" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>proxyUserName</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;If your proxy requires authentication, enter your username here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>TextLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Password:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>proxyPassword</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;User name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>proxyUserName</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;If your proxy requires authentication, enter your username here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="Line" row="3" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>Line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>proxyExclude</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter a list of MAL servers that do not need the use of a proxy here, separated with commas, e.g: &lt;br&gt;&lt;i&gt;localhost,127.0.0.1,.lan&lt;/i&gt;&lt;qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>N&amp;o proxy for:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>proxyExclude</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter a list of MAL servers that do not need the use of a proxy here, separated with commas, e.g: &lt;br&gt;&lt;i&gt;localhost,127.0.0.1,.lan&lt;/i&gt;&lt;qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer3_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>70</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>MAL Server</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QGroupBox" row="1" column="0">
+ <property name="name">
+ <cstring>GroupBox1_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="title">
+ <string>MAL Server Information</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;MAL server name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>malServerName</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>malCustomPortCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Custom &amp;port:</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="1" column="2">
+ <property name="name">
+ <cstring>malCustomPort</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="value">
+ <number>80</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>65535</number>
+ </property>
+ </widget>
+ <spacer row="1" column="3">
+ <property name="name">
+ <cstring>Spacer2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KHistoryCombo" row="0" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>malServerName</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>malUserName</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Password:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>malPassword</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;User name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>malUserName</cstring>
+ </property>
+ </widget>
+ <widget class="Line" row="2" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>Line1_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="KPasswordEdit" row="4" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>malPassword</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>Spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;qt&gt;There is currently &lt;b&gt;no way to set server parameters on the desktop&lt;/b&gt;; you need to use the &lt;i&gt;MobileLink&lt;/i&gt; or &lt;i&gt;AGConnect&lt;/i&gt; application on the handheld device. &lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>RadioButton8</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>proxyServerInformation</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>RadioButton8_2</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>proxyServerInformation</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>RadioButton8_2_2</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>proxyServerInformation</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>proxyCustomPortCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>proxyCustomPort</receiver>
+ <slot>setEditFocus(bool)</slot>
+ </connection>
+ <connection>
+ <sender>proxyCustomPortCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>proxyCustomPort</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>malCustomPortCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>malCustomPort</receiver>
+ <slot>setEditFocus()</slot>
+ </connection>
+ <connection>
+ <sender>malCustomPortCheck</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>malCustomPort</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>tabWidget</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includes>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+ <include location="global" impldecl="in implementation">knuminput.h</include>
+</includes>
+</UI>
diff --git a/kpilot/conduits/malconduit/mal_conduit.desktop b/kpilot/conduits/malconduit/mal_conduit.desktop
new file mode 100644
index 000000000..47bfe45b0
--- /dev/null
+++ b/kpilot/conduits/malconduit/mal_conduit.desktop
@@ -0,0 +1,96 @@
+[Desktop Entry]
+Type=Service
+Name=MAL (AvantGo) Conduit
+Name[af]=MAL (AvantGo) pad
+Name[ca]=Conducte MAL (AvantGo)
+Name[cs]=Propojení s AvantGo
+Name[cy]=Cwndid MAL (AvantGo)
+Name[de]=MAL- (AvantGo) Abgleich (Conduit)
+Name[el]=Σύνδεσμος MAL (AvantGo)
+Name[eo]=MAL (AvantGo) Kanalo
+Name[es]=Conducto MAL (AvantGo)
+Name[et]=MAL (AvantGo) kanal
+Name[eu]=MAL (AvantGo) kanala
+Name[fa]=لولۀ MAL (AvantGo)
+Name[fi]=MAL (AvantGo)- yhdyskäytävä
+Name[fr]=MAL (AvantGo) Canal
+Name[ga]=Seoladán MAL (AvantGo)
+Name[gl]=Conducto MAL (AvantGo)
+Name[he]=ממשק AvantGo) MAL)
+Name[hi]=एमएएल (AvantGo) कन्ड्यूइट
+Name[hu]=MAL- (AvantGo) csatoló
+Name[is]=MAL (AvantGo)-rás
+Name[it]=Conduit MAL (AvantGo)
+Name[ja]=MAL (AvantGo) コンジット
+Name[ka]=არხი MAL (AvantGo)
+Name[kk]=MAL (AvantGo) арнасы
+Name[km]=បំពង់ MAL (AvantGo)
+Name[lt]=MAL (AvantGo) kanalas
+Name[ms]=Saluran MAL (AvantGo)
+Name[nb]=MAL (AvantGo) kanal
+Name[nds]=MAL(AvantGo)-Synkroniseren
+Name[ne]=MAL (AvantGo) कन्ड्युट
+Name[nn]=MAL-kopling (AvantGo)
+Name[nso]=Conduit ya MAL (AvantGo)
+Name[pl]=Łącznik do MAL (AvantGo)
+Name[pt]=Conduta MAL (AvantGo)
+Name[pt_BR]=Conduto MAL (AvantGo)
+Name[ro]=Conductă MAL (AvantGo)
+Name[ru]=Канал MAL (AvantGo)
+Name[sk]=Spojka MAL (AvantGo)
+Name[sl]=Veznik MAL (AvantGo)
+Name[sr]=MAL (AvantGo) провод
+Name[sr@Latn]=MAL (AvantGo) provod
+Name[sv]=MAL (AvantGo)-kanal
+Name[ta]=MAL (AvantGo) காப்புக் குழாய்
+Name[tg]=Канали MAL (AvantGo)
+Name[tr]=MAL (AvantGo) Kanalı
+Name[uk]=Акведук MAL (AvantGo)
+Name[zh_CN]=MAL (AvantGo) 管道
+Comment=Syncronize AvantGo (or generally a MAL server's content) to the handheld. This allows you to view web-pages offline on the handheld, like your cinema or TV schedule, or any other web page.
+Comment[af]=Sinkroniseer AvantGo (MAL bediener inhoud) informasie na die draagbare toestel. Dit maak dit moontlik om aflyn na web blaaie, soos TV en fliek skedules, te kyk.
+Comment[bg]=Синхронизиране на AvantGo към мобилно устройство. Тази приставка ви позволява да разглеждате уеб страници без връзка с Мрежата.
+Comment[ca]=Sincronitza AvantGo (o el contingut d'un servidor MAL en general) a l'agenda electrònica. Això us permet veure pàgines web a l'agenda electrònica en mode desconnectat, com ara la programació de TV o cinema o qualsevol altra pàgina web.
+Comment[cs]=Synchronizace AvantGo (nebo obecně obsahu MAL serverů) s PDA. To umožňuje offline prohlížení stránek v PDA např. TV programů, programů kin a mnoha dalších stránek.
+Comment[da]=Synkronisér AvantGo (eller mere alment indholdet på en MAL-server) med den håndholdte. Det lader dig kigge på nedsider offline på den håndholdte, såsom biografer eller tv-programmer, eller en hvilken som helst anden netside.
+Comment[de]=Gleicht AvantGo (oder allgemein den Inhalt eines MAL-Servers) mit dem Taschencomputer ab. So können Sie z. B. Internetseiten ohne Internetverbindung auf dem Taschencomputer lesen, zum Beispiel einen Kinoplan oder die aktuelle Programmzeitschrift.
+Comment[el]=Συγχρονισμός ενός AvantGo (ή γενικότερα τα περιεχόμενα ενός εξυπηρετητή MAL) με τον υπολογιστή παλάμης. Αυτό σας επιτρέπει να βλέπετε ιστοσελίδες στον υπολογιστή παλάμης χωρίς να είστε συνδεδεμένοι, όπως το πρόγραμμα των κινηματογράφων ή της τηλεόρασης, ή οποιαδήποτε άλλη ιστοσελίδα.
+Comment[en_GB]=Syncronise AvantGo (or generally a MAL server's content) to the handheld. This allows you to view web-pages offline on the handheld, like your cinema or TV schedule, or any other web page.
+Comment[es]=Sincroniza AvantGo (o más genéricamente, el contenido de un servidor MAL) con la agenda electrónica. Le permite ver páginas web en la agenda electrónica sin estar conectado, como la programación de televisión o la cartelera de cine, o cualquier otra página web.
+Comment[et]=See kanal sünkroniseerib AvantGo (või üldisemalt MAL serveri sisu) pihuarvutiga. See võimaldab vaadata veebilehekülgi pihuseadmelt ilma võrguühendusega, näiteks uurida kino- või telekava või mis tahes muud huvipakkuvat veebilehekülge.
+Comment[eu]=Sinkronizatu AvantGo (edo orokorrean MAL zerbitzariaren edukina) agenda elektronikora. Honek web-orriak agendan konexio gabe ikusteko aukera ematen dizu, zure zine edo TB antolatzailean bezala, edo beste web orri bat bezala.
+Comment[fa]=همگام‌سازی AvantGo (یا عموماً محتوای کارساز MAL) با دستی. به شما اجازه می‌دهد که صفحات وب برون‌خطی روی دستی، مانند برنامۀ سینما یا تلویزیون شما، یا هر صفحه وب دیگری را مشاهده کنید.
+Comment[fi]=Synkronoi AvantGo (tai yleisesti MAL-palvelimen sisältö) taskutietokoneeseen. Tämä mahdollistaa web-sivujen lukemisen offline-tilassa (esim. elokuva- tai tv-ohjelmasivujen).
+Comment[fr]=Synchronise AvantGo (ou plus généralement tout serveur MAL) avec votre Palm. Ceci vous permet de consulter des pages Web hors ligne sur votre Palm, comme des programmes TV, Cinéma ou n'importe quelle page Web.
+Comment[fy]=Avantgo mei de handheld syngronosearje (of eins mei de ynhâld fan in g MAL-tsjinner). Dit makket it mooglik om in webside sûnder ferbining te besjen op jo handheld. Dit is hanjnich foar in soad saken lykas de TV-gids.
+Comment[gl]=Sincronizar AvantGo (ou xeralmente o contido dun servidor MAL) co aparello portátil. Isto permite ver as páxinas web fóra de liña no aparello portátil, como a programación do cine ou da TV, ou calquera outra páxina web.
+Comment[hu]=AvantGo (vagy MAL-kiszolgáló) adatainak szinkronizálása a kézi számítógéppel. Lehetővé teszi weboldalak offline módban való megtekintését, például a mozi- vagy tévéműsort, vagy bármi mást.
+Comment[is]=Samstillir AvantGo (eða venjulega innihald MAL þjóns) við lófatölvuna. Þetta gerir þér kleyft að skoða vefsíður þegar þú ert ótengd(ur) vefnum, t.d. kvikmynda eða sjónvarpsdagskrá.
+Comment[it]=Sincronizza AvantGo (o il contenuto di un generico server MAL) con il palmare. In questo modo potrai visualizzare le pagine web offline sul palmare come per esempio la programmazione di un cinema o una TV o qualsiasi altra pagina web.
+Comment[ja]=AvantGo (または一般に MAL サーバのコンテンツ) とハンドヘルドを同期させます。これにより、ハンドヘルドで映画や TV 番組表、その他のウェブページをオフラインで閲覧できるようになります。
+Comment[ka]= AvantGo-ს სინქრონიზაცია (ძირითადად MAL სერვერების შემადგენლობით) პორტატიულ მოწყობილობასთან. ეს ვებ-გვერდების ავტონომიურ რეჟიმში დათვალიერების საშუალებას იძლევა,მაგ.: თქვენი კინო ან ტელე პროგრამა, ან სხვა ვებ-გვერდები.
+Comment[kk]=AvantGo (немесе жалпы MAL сервердің мазмұнын) қалта құрылғымен қадамдастыру арнасы. Бұл сол құрылғыда кино, ТВ кестеңізді немесе басқа веб парақтарды желіге қосылмай көруге мүмкіндік береді.
+Comment[km]=ធ្វើ​សមកាលកម្ម AvantGo (ជាទូទៅ​គឺ មាតិកា​របស់​ម៉ាស៊ីន​បម្រើ MAL) ទៅ​នឹង​ឧបករណ៍​យួរ​ដៃ ។ វា​អនុញ្ញាត​ឲ្យ​អ្នក​មើល​ទំព័រ​បណ្ដាញ (កាលវិភាគ​រោង​ភាពយន្ត ឬ ទូរទស្សន៍...) នៅ​ក្រៅ​បណ្ដាញ នៅ​លើ​ឧបករណ៍​យួរ​ដៃ​របស់​អ្នក ។
+Comment[lt]=Sinchronizuoti AvantGo (ar MAL serverio turinį apskritai) su nešiojamu įrenginiu. Tai leis jums peržiūrėti žiniatinklio puslapius nešiojamame įrenginyje, tokius kaip kino teatro ar TV programas, bei bet kokį kitą puslapį, neprisijungus prie Interneto.
+Comment[ms]=Mensegerakkan AvantGo (atau kandungan pelayan MAL secara umum) ke komputer telapak. Ini membolehkan anda memaparkan laman web di luar talian pada komputer telapak, seperti pawagam atau jadual TV, atau laman web lain.
+Comment[nb]=Synkroniser AvantGo (eller generelt innholdet i en MAL-tjener) til PDA-en. På denne måten kan du se nettsider frakoblet på PDA-en. slik som TV-programlister, kinoprogrammer eller andre nettsider.
+Comment[nds]=Synkroniseert den Inholt vun AvantGo oder jichtenseen anner MAL-Server ("Mobile Application Link") mit den Handreekner. So kannst Du Nettsieden ahn Verbinnen op den Handreekner ankieken, t.B. dat Kino- oder Feernsehprogramm.
+Comment[ne]=AvantGo (वा साधारणतया एउटा MAL सर्भरको सामाग्री) ह्यान्डहेल्डमा समक्रमण गर्नुहोस् । यसले तपाईँलाई वेब पृष्ठ, जस्तै: सिनेमा वा टी भी कार्यतालिका, वा अन्य कुनै वेब पृष्ठ ह्यान्डहेल्डको अफलाईनमा हेर्न अनुमति दिन्छ ।
+Comment[nl]=Avantgo met de handheld synchroniseren (of eigenlijk met de inhoud van een MAL-server). Dit maakt het mogelijk om een webpagina offline op uw handheld te bekijken. Dit is handig voor allerlei zaken als bijvoorbeeld de TV-gids.
+Comment[pl]=Synchronizuje AvantGo (lub ogólnie zawartość serwera MAL) z palmtopem. Pozwala to przeglądać bez połączenia z siecią strony WWW na palmtopie, np. repertuar kin lub program telewizyjny.
+Comment[pt]=Sincroniza o AvantGo (ou, genericamente, o conteúdo de um servidor de MAL) para o dispositivo móvel. Isto permite-lhe ver as páginas Web no dispositivo móvel sem estar ligado, como o seu horário de cinema ou TV ou ainda qualquer outra página Web.
+Comment[pt_BR]=Sincroniza AvantGo (ou geralmente o conteúodo de um servidor MAL) com o handheld. Isto permite que você visualize páginas web offline no handheld, por exemplo a grade do cinema ou TV, ou qualquer outra página.
+Comment[ru]=Синхронизация AvantGo (содержимого серверов MAL) с КПК. Это позволит вам просматривать веб-страницы без подключения к Интернет.
+Comment[sk]=Synchronizuje AvantGo (alebo všeobecne obsah MAL servera) s ručným zariadením. Toto umožní vidieť webovské stránky bez pripojenia na ručnom zariadení, ako sú programy kina alebo TV, alebo hociakej webovskej stránky.
+Comment[sl]=Uskladi AvantGo (oziroma v splošnem vsebino strežnika MAL) na ročnem računalniku. S tem si lahko na njem ogledujete spletne strani brez povezave, kot so razpored kino predstav ali pa TV spored ali pa katerokoli drugo spletno stran.
+Comment[sr]=Синхронизује AvantGo (или уопштено садржај MAL сервера) са ручним рачунаром. Ово вам омогућава да на ручном рачунару прегледате веб стране ван везе, као биоскопски или ТВ програм, или било коју другу веб страну.
+Comment[sr@Latn]=Sinhronizuje AvantGo (ili uopšteno sadržaj MAL servera) sa ručnim računarom. Ovo vam omogućava da na ručnom računaru pregledate veb strane van veze, kao bioskopski ili TV program, ili bilo koju drugu veb stranu.
+Comment[sv]=Synkronisera AvantGo (eller mer allmänt innehållet på en MAL-server) med handdatorn. Det låter dig titta på webbsidor i nerkopplat läge på handdatorn, som bio eller tv-program, eller vilken annan webbsida som helst.
+Comment[ta]=AvantGoஐ கையில் வைத்திருப்பதில் கூட்டிணைக்கவும் (அல்லது ஒரு MAL சேவகனின் உள்ளடக்கத்திற்கு). இதன்மூலம் கையில் இருப்பதிலேயே வலைப்பக்கங்களை பார்க்கலாம், அதாவது சினிமா, தொலைக்காட்டி அட்டவ்ணை, அல்லது ஏதாவது ஒரு வலைப்பக்கம்.
+Comment[tr]=AvantGo içeriğini (ya da genel olarak MAL sunucuları içeriğini) el bilgisayarı ile birleştirir. Bu, web sayfalarını el bilgisayarınızda çevirim dışı olarak görüntülemenizi sağlar.
+Comment[uk]=Синхронізація AvantGo (або вміст серверів MAL) на кишеньковий пристрій . Це дозволяє переглядати веб-сторінки на кишеньковому пристрої без з'єднання з Інтернетом.
+Comment[zh_CN]=将 AvantGo(或 MAL 服务器的内容)同步到手持设备中。这允许您在手持设备中脱机查看 Web 页,比如影讯、电视节目时间表或任何其它网页。
+Comment[zh_TW]=同步 AvantGo (或通常為一 MAL 伺服器內容) 與 handheld。
+Implemented=file
+ServiceTypes=KPilotConduit
+X-KDE-Library=conduit_mal
diff --git a/kpilot/conduits/malconduit/malconduit.kcfg b/kpilot/conduits/malconduit/malconduit.kcfg
new file mode 100644
index 000000000..146f7869c
--- /dev/null
+++ b/kpilot/conduits/malconduit/malconduit.kcfg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kpilot_malconduitrc"/>
+ <group name="General">
+ <entry name="LastMALSync" key="Last MAL Sync" type="DateTime">
+ <default>QDateTime( QDate(1970,1,1), QTime(0,0,0) )</default>
+ </entry>
+
+ <entry name="SyncFrequency" key="Sync Frequency" type="Enum">
+ <choices>
+ <choice name="eEverySync"/>
+ <choice name="eEveryHour"/>
+ <choice name="eEveryDay"/>
+ <choice name="eEveryWeek"/>
+ <choice name="eEveryMonth"/>
+ </choices>
+ <default>eEverySync</default>
+ </entry>
+
+ <entry name="ProxyType" key="Proxy Type" type="Enum">
+ <choices>
+ <choice name="eProxyNone"/>
+ <choice name="eProxyHTTP"/>
+ <choice name="eProxySOCKS"/>
+ </choices>
+ <default>eProxyNone</default>
+ </entry>
+ <entry name="ProxyServer" key="Proxy Server" type="String">
+ <default></default>
+ </entry>
+ <entry name="ProxyPort" key="Proxy Port" type="UInt">
+ <default>0</default>
+ </entry>
+ <entry name="ProxyUser" key="Proxy User" type="String">
+ <default></default>
+ </entry>
+ <entry name="ProxyPassword" key="Proxy Password" type="Password">
+ <default></default>
+ </entry>
+ <entry name="MALServer" key="MAL Server" type="String">
+ <default>sync.avantgo.com</default>
+ </entry>
+ <entry name="MALPort" key="MAL Port" type="UInt">
+ <default>0</default>
+ </entry>
+ <entry name="MALUser" key="MAL User" type="String">
+ <default></default>
+ </entry>
+ <entry name="MALPassword" key="MAL Password" type="String">
+ <default></default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kpilot/conduits/malconduit/malconduitSettings.kcfgc b/kpilot/conduits/malconduit/malconduitSettings.kcfgc
new file mode 100644
index 000000000..d4254c41b
--- /dev/null
+++ b/kpilot/conduits/malconduit/malconduitSettings.kcfgc
@@ -0,0 +1,7 @@
+File=malconduit.kcfg
+ClassName=MALConduitSettings
+Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/conduits/memofileconduit/CMakeLists.txt b/kpilot/conduits/memofileconduit/CMakeLists.txt
new file mode 100644
index 000000000..56994570f
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/CMakeLists.txt
@@ -0,0 +1,44 @@
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+set(conduit_memofile_SRCS
+ memofile-factory.cc
+ memofile.cc
+ memofiles.cc
+ memofile-conduit.cc
+)
+
+set(conduit_memofile_UIS
+ setup_base.ui
+)
+
+set(conduit_memofile_KCFGS
+ memofileSettings.kcfgc
+)
+
+kde3_add_kcfg_files(conduit_memofile_SRCS ${conduit_memofile_KCFGS})
+kde3_add_ui_files(conduit_memofile_SRCS ${conduit_memofile_UIS})
+kde3_automoc(${conduit_memofile_SRCS})
+add_library(conduit_memofile SHARED ${conduit_memofile_SRCS})
+
+set_target_properties(
+ conduit_memofile PROPERTIES LOCATION ${KDE3_PLUGIN_INSTALL_DIR}
+ INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib
+ PREFIX ""
+)
+
+kde3_install_libtool_file(conduit_memofile)
+
+install(
+ TARGETS conduit_memofile
+ LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR}
+)
+
+install(
+ FILES memofile-conduit.desktop DESTINATION ${KDE3_SERVICES_DIR}
+)
+
+install(
+ FILES memofileconduit.kcfg DESTINATION ${KDE3_KCFG_DIR}
+)
diff --git a/kpilot/conduits/memofileconduit/Makefile.am b/kpilot/conduits/memofileconduit/Makefile.am
new file mode 100644
index 000000000..e4a244b51
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/Makefile.am
@@ -0,0 +1,16 @@
+INCLUDES= $(PISOCK_INCLUDE) -I$(top_srcdir)/kpilot/lib $(all_includes)
+
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = memofile-conduit.desktop
+
+kde_module_LTLIBRARIES = conduit_memofile.la
+
+
+conduit_memofile_la_SOURCES = memofileSettings.kcfgc setup_base.ui \
+ memofile-factory.cc memofile.cc memofiles.cc memofile-conduit.cc
+conduit_memofile_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+conduit_memofile_la_LIBADD = ../../lib/libkpilot.la $(LIB_KDEUI) $(LIB_KFILE)
+
+kde_kcfg_DATA = memofileconduit.kcfg
diff --git a/kpilot/conduits/memofileconduit/design/SQD - copyHHToPC.jpg b/kpilot/conduits/memofileconduit/design/SQD - copyHHToPC.jpg
new file mode 100644
index 000000000..82cc11880
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/design/SQD - copyHHToPC.jpg
Binary files differ
diff --git a/kpilot/conduits/memofileconduit/design/SQD - copyPCToHH.jpg b/kpilot/conduits/memofileconduit/design/SQD - copyPCToHH.jpg
new file mode 100644
index 000000000..ef4254d43
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/design/SQD - copyPCToHH.jpg
Binary files differ
diff --git a/kpilot/conduits/memofileconduit/design/SQD - detailed load.jpg b/kpilot/conduits/memofileconduit/design/SQD - detailed load.jpg
new file mode 100644
index 000000000..4e0601f6a
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/design/SQD - detailed load.jpg
Binary files differ
diff --git a/kpilot/conduits/memofileconduit/design/SQD - sync.jpg b/kpilot/conduits/memofileconduit/design/SQD - sync.jpg
new file mode 100644
index 000000000..91299ce07
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/design/SQD - sync.jpg
Binary files differ
diff --git a/kpilot/conduits/memofileconduit/memofile-conduit.cc b/kpilot/conduits/memofileconduit/memofile-conduit.cc
new file mode 100644
index 000000000..1dc5fe386
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/memofile-conduit.cc
@@ -0,0 +1,567 @@
+/* memofile-conduit.cc KPilot
+**
+** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper
+**
+** This file does the actual conduit work.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "options.h"
+
+// Only include what we really need:
+// First UNIX system stuff, then std C++,
+// then Qt, then KDE, then local includes.
+//
+//
+
+#include <time.h> // required by pilot-link includes
+
+#include <pi-memo.h>
+
+#include "pilotMemo.h"
+
+#include <qfile.h>
+#include <qdir.h>
+#include <qtextcodec.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+
+#include "pilotRecord.h"
+#include "pilotSerialDatabase.h"
+#include "memofile-factory.h"
+#include "memofile-conduit.h"
+#include "memofileSettings.h"
+
+
+/**
+ * Our workhorse. This is the main driver for the conduit.
+ */
+MemofileConduit::MemofileConduit(KPilotLink *d,
+ const char *n,
+ const QStringList &l) :
+ ConduitAction(d,n,l),
+ _DEFAULT_MEMODIR(QDir::homeDirPath() + CSL1("/MyMemos")),
+ fMemoAppInfo(0L),
+ _memofiles(0L)
+{
+ FUNCTIONSETUP;
+ fConduitName=i18n("Memofile");
+ fMemoList.setAutoDelete(true);
+}
+
+MemofileConduit::~MemofileConduit()
+{
+ FUNCTIONSETUP;
+ KPILOT_DELETE(_memofiles);
+}
+
+/* virtual */ bool MemofileConduit::exec()
+{
+ FUNCTIONSETUP;
+
+ setFirstSync( false );
+ // try new format first...
+ // DEBUGKPILOT << fname << ": trying new format database first." << endl;
+ bool _open = false;
+ /*
+ _open = openDatabases(CSL1("MemosDB-PMem"));
+ if(!_open) {
+ DEBUGKPILOT << fname << ": unable to open new format database. trying old one." << endl;
+ */
+ _open = openDatabases(CSL1("MemoDB"));
+ /*
+ } else {
+ DEBUGKPILOT << fname << ": able to open new format database." << endl;
+ }
+ */
+
+ if(!_open) {
+ emit logError(i18n("Unable to open the memo databases on the handheld."));
+ DEBUGKPILOT << fname << ": unable to open new or old format database." << endl;
+ return false;
+ }
+
+ readConfig();
+
+ if (! initializeFromPilot()) {
+ emit logError(i18n("Cannot initialize from pilot."));
+ return false;
+ }
+
+ _memofiles = new Memofiles(fCategories, *fMemoAppInfo,
+ _memo_directory, *fCtrHH);
+ if (! _memofiles || ! _memofiles->isReady()) {
+ emit logError(i18n("Cannot initialize the memo files from disk."));
+ return false;
+ }
+
+ fCtrPC->setStartCount(_memofiles->count());
+
+ setFirstSync( _memofiles->isFirstSync() );
+ addSyncLogEntry(i18n(" Syncing with %1.").arg(_memo_directory));
+
+ if ( (syncMode() == SyncAction::SyncMode::eCopyHHToPC) || _memofiles->isFirstSync() ) {
+ addSyncLogEntry(i18n(" Copying Pilot to PC..."));
+ DEBUGKPILOT << fname << ": copying Pilot to PC." << endl;
+ copyHHToPC();
+ } else if ( syncMode() == SyncAction::SyncMode::eCopyPCToHH ) {
+ DEBUGKPILOT << fname << ": copying PC to Pilot." << endl;
+ addSyncLogEntry(i18n(" Copying PC to Pilot..."));
+ copyPCToHH();
+ } else {
+ DEBUGKPILOT << fname << ": doing regular sync." << endl;
+ addSyncLogEntry(i18n(" Doing regular sync..."));
+ sync();
+ }
+
+ cleanup();
+
+ return delayDone();
+}
+
+bool MemofileConduit::readConfig()
+{
+ FUNCTIONSETUP;
+
+ QString dir(MemofileConduitSettings::directory());
+ if (dir.isEmpty()) {
+ dir = _DEFAULT_MEMODIR;
+
+ DEBUGKPILOT << fname
+ << ": no directory given to us. defaulting to: ["
+ << _DEFAULT_MEMODIR
+ << "]" << endl;
+ }
+
+ _memo_directory = dir;
+ _sync_private = MemofileConduitSettings::syncPrivate();
+
+
+ DEBUGKPILOT << fname
+ << ": Settings... "
+ << " directory: [" << _memo_directory
+ << "], first sync: [" << isFirstSync()
+ << "], sync private: [" << _sync_private
+ << "]" << endl;
+
+ return true;
+
+}
+
+bool MemofileConduit::setAppInfo()
+{
+ FUNCTIONSETUP;
+
+ // reset our category mapping from the filesystem
+ MemoCategoryMap map = _memofiles->readCategoryMetadata();
+
+ if (map.count() <=0) {
+ DEBUGKPILOT << fname
+ << ": category metadata map is empty, nothing to do." << endl;
+ return true;
+ }
+
+ fCategories = map;
+
+ for (unsigned int i = 0; i < Pilot::CATEGORY_COUNT; i++)
+ {
+ if (fCategories.contains(i)) {
+ fMemoAppInfo->setCategoryName(i,fCategories[i]);
+ }
+ }
+
+ if (fDatabase)
+ {
+ fMemoAppInfo->writeTo(fDatabase);
+ }
+ if (fLocalDatabase)
+ {
+ fMemoAppInfo->writeTo(fLocalDatabase);
+ }
+
+ return true;
+}
+
+bool MemofileConduit::getAppInfo()
+{
+ FUNCTIONSETUP;
+
+ KPILOT_DELETE(fMemoAppInfo);
+ fMemoAppInfo = new PilotMemoInfo(fDatabase);
+ fMemoAppInfo->dump();
+ return true;
+}
+
+
+/**
+ * Methods related to getting set up from the Pilot.
+ */
+
+bool MemofileConduit::initializeFromPilot()
+{
+
+ if (!getAppInfo()) return false;
+
+ if (!loadPilotCategories()) return false;
+
+ return true;
+}
+
+bool MemofileConduit::loadPilotCategories()
+{
+ FUNCTIONSETUP;
+
+ fCategories.clear();
+
+ QString _category_name;
+ int _category_id=0;
+ int _category_num=0;
+
+ for (unsigned int i = 0; i < Pilot::CATEGORY_COUNT; i++)
+ {
+ _category_name = fMemoAppInfo->categoryName(i);
+ if (!_category_name.isEmpty())
+ {
+ _category_name = Memofiles::sanitizeName( _category_name );
+ _category_id = fMemoAppInfo->categoryInfo()->ID[i];
+ _category_num = i;
+ fCategories[_category_num] = _category_name;
+
+ DEBUGKPILOT << fname
+ << ": Category #"
+ << _category_num
+ << " has ID "
+ << _category_id
+ << " and name "
+ <<_category_name << endl;
+ }
+ }
+ return true;
+}
+
+/**
+ * Read all memos in from Pilot.
+ */
+void MemofileConduit::getAllFromPilot()
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname
+ << ": Database has " << fDatabase->recordCount()
+ << " records." << endl;
+
+ fMemoList.clear();
+
+ int currentRecord = 0;
+ PilotRecord *pilotRec;
+ PilotMemo *memo = 0;
+
+ while ((pilotRec = fDatabase->readRecordByIndex(currentRecord)) != NULL) {
+ if ((!pilotRec->isSecret()) || _sync_private) {
+ memo = new PilotMemo(pilotRec);
+ fMemoList.append(memo);
+
+ DEBUGKPILOT << fname
+ << ": Added memo: ["
+ << currentRecord
+ << "], id: ["
+ << memo->id()
+ << "], category: ["
+ << fCategories[memo->category()]
+ << "], title: ["
+ << memo->getTitle()
+ << "]" << endl;
+ } else {
+ DEBUGKPILOT << fname
+ << ": Skipped secret record: ["
+ << currentRecord
+ << "], title: ["
+ << memo->getTitle()
+ << "]" << endl;
+ }
+
+ KPILOT_DELETE(pilotRec);
+
+ currentRecord++;
+ }
+
+ DEBUGKPILOT << fname
+ << ": read: [" << fMemoList.count()
+ << "] records from palm." << endl;
+}
+
+/**
+ * Read all modified memos in from Pilot.
+ */
+void MemofileConduit::getModifiedFromPilot()
+{
+ FUNCTIONSETUP;
+
+ fMemoList.clear();
+
+ int currentRecord = 0;
+ PilotRecord *pilotRec;
+ PilotMemo *memo = 0;
+
+ while ((pilotRec = fDatabase->readNextModifiedRec()) != NULL) {
+ memo = new PilotMemo(pilotRec);
+ // we are syncing to both our filesystem and to the local
+ // database, so take care of the local database here
+ if (memo->isDeleted()) {
+ fLocalDatabase->deleteRecord(memo->id());
+ } else {
+ fLocalDatabase->writeRecord(pilotRec);
+ }
+
+ if ((!pilotRec->isSecret()) || _sync_private) {
+ fMemoList.append(memo);
+
+ DEBUGKPILOT << fname
+ << ": modified memo id: ["
+ << memo->id()
+ << "], title: ["
+ << memo->getTitle()
+ << "]" << endl;
+ } else {
+ DEBUGKPILOT << fname
+ << ": skipped secret modified record id: ["
+ << memo->id()
+ << "], title: ["
+ << memo->getTitle()
+ << "]" << endl;
+ }
+
+ KPILOT_DELETE(pilotRec);
+
+ currentRecord++;
+ }
+
+ DEBUGKPILOT << fname
+ << ": read: [" << fMemoList.count()
+ << "] modified records from palm." << endl;
+}
+
+
+/* slot */ void MemofileConduit::process()
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname << ": Now in state " << fActionStatus << endl;
+}
+
+
+void MemofileConduit::listPilotMemos()
+{
+ FUNCTIONSETUP;
+
+ PilotMemo *memo;
+ for ( memo = fMemoList.first(); memo; memo = fMemoList.next() ) {
+ QString _category_name = fCategories[memo->category()];
+
+ DEBUGKPILOT << fConduitName
+ << ": listing record id: [" << memo->id()
+ << "] category id: [" << memo->category()
+ << "] category name: [" << _category_name
+ << "] title: [" << memo->getTitle()
+ << "]" << endl;
+ }
+}
+
+bool MemofileConduit::copyHHToPC()
+{
+ FUNCTIONSETUP;
+
+ getAllFromPilot();
+
+ _memofiles->eraseLocalMemos();
+
+ _memofiles->setPilotMemos(fMemoList);
+
+ _memofiles->save();
+
+ return true;
+
+}
+
+bool MemofileConduit::copyPCToHH()
+{
+ FUNCTIONSETUP;
+
+ // set category info from the filesystem, if we can.
+ // Note: This will reset both fCategories and fMemoAppInfo, so
+ // after this, we need to reinitialize our memofiles object...
+ setAppInfo();
+
+ // re-create our memofiles helper...
+ KPILOT_DELETE(_memofiles);
+ _memofiles = new Memofiles(fCategories, *fMemoAppInfo,
+ _memo_directory, *fCtrHH);
+
+ _memofiles->load(true);
+
+ QPtrList<Memofile> memofiles = _memofiles->getAll();
+
+ Memofile * memofile;
+
+ for ( memofile = memofiles.first(); memofile; memofile = memofiles.next() ) {
+ writeToPilot(memofile);
+ }
+
+ _memofiles->save();
+
+ // now that we've copied from the PC to our handheld, remove anything extra from the
+ // handheld...
+ deleteUnsyncedHHRecords();
+
+ return true;
+
+}
+
+void MemofileConduit::deleteUnsyncedHHRecords()
+{
+ FUNCTIONSETUP;
+ if ( syncMode()==SyncMode::eCopyPCToHH )
+ {
+ Pilot::RecordIDList ids=fDatabase->idList();
+ Pilot::RecordIDList::iterator it;
+ for ( it = ids.begin(); it != ids.end(); ++it )
+ {
+ if (!_memofiles->find(*it))
+ {
+ DEBUGKPILOT << fname
+ << "Deleting record with ID "<< *it <<" from handheld "
+ << "(is not on PC, and syncing with PC->HH direction)"
+ << endl;
+ fDatabase->deleteRecord(*it);
+ fLocalDatabase->deleteRecord(*it);
+ }
+ }
+ }
+}
+
+int MemofileConduit::writeToPilot(Memofile * memofile)
+{
+ FUNCTIONSETUP;
+
+ int oldid = memofile->id();
+
+ PilotRecord *r = memofile->pack();
+
+ if (!r) {
+ DEBUGKPILOT << fname
+ << ": ERROR: [" << memofile->toString()
+ << "] could not be written to the pilot."
+ << endl;
+ return -1;
+ }
+
+ int newid = fDatabase->writeRecord(r);
+ fLocalDatabase->writeRecord(r);
+
+ KPILOT_DELETE(r);
+
+ memofile->setID(newid);
+
+ QString status;
+ if (oldid <=0) {
+ fCtrHH->created();
+ status = "new to pilot";
+ } else {
+ fCtrHH->updated();
+ status = "updated";
+ }
+
+ DEBUGKPILOT << fname
+ << ": memofile: [" << memofile->toString()
+ << "] written to the pilot, [" << status << "]."
+ << endl;
+
+ return newid;
+}
+
+void MemofileConduit::deleteFromPilot(PilotMemo * memo)
+{
+ FUNCTIONSETUP;
+
+ PilotRecord *r = memo->pack();
+ if (r) {
+ r->setDeleted(true);
+ fDatabase->writeRecord(r);
+ fLocalDatabase->writeRecord(r);
+ }
+ KPILOT_DELETE(r);
+
+ fCtrHH->deleted();
+
+ DEBUGKPILOT << fname
+ << ": memo: [" << memo->getTitle()
+ << "] deleted from the pilot."
+ << endl;
+}
+
+bool MemofileConduit::sync()
+{
+ FUNCTIONSETUP;
+
+ _memofiles->load(false);
+
+ getModifiedFromPilot();
+
+ PilotMemo *memo;
+ for ( memo = fMemoList.first(); memo; memo = fMemoList.next() ) {
+ _memofiles->addModifiedMemo(memo);
+ }
+
+ QPtrList<Memofile> memofiles = _memofiles->getModified();
+
+ Memofile *memofile;
+ for ( memofile = memofiles.first(); memofile; memofile = memofiles.next() ) {
+ if (memofile->isDeleted()) {
+ deleteFromPilot(memofile);
+ } else {
+ writeToPilot(memofile);
+ }
+ }
+
+ _memofiles->save();
+
+ return true;
+}
+
+void MemofileConduit::cleanup()
+{
+ FUNCTIONSETUP;
+
+ fDatabase->resetSyncFlags();
+ fDatabase->cleanup();
+ fLocalDatabase->resetSyncFlags();
+ fLocalDatabase->cleanup();
+
+ fCtrPC->setEndCount(_memofiles->count());
+}
+
+
+#include "memofile-conduit.moc"
+
diff --git a/kpilot/conduits/memofileconduit/memofile-conduit.desktop b/kpilot/conduits/memofileconduit/memofile-conduit.desktop
new file mode 100644
index 000000000..c453821f5
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/memofile-conduit.desktop
@@ -0,0 +1,93 @@
+[Desktop Entry]
+Type=Service
+Name=Memo File
+Name[af]=Memo Lêer
+Name[bg]=Бележка
+Name[ca]=Fitxer de notes
+Name[cs]=Soubor s poznámkou
+Name[da]=Memo-fil
+Name[de]=Memo Datei
+Name[el]=Αρχείο υπομνήματος
+Name[eo]=Memo-dosiero
+Name[es]=Archivo de nota
+Name[et]=Memofail
+Name[eu]=Ohar fitxategia
+Name[fa]=پروندۀ Memo
+Name[fi]=Muistiotiedosto
+Name[fr]=Fichier mémo
+Name[fy]=Memotriem
+Name[ga]=Comhad Meamraim
+Name[gl]=Ficheiro Memo
+Name[hu]=Memófájl
+Name[is]=Minnismiðaskrá
+Name[it]=File appunti
+Name[ja]=メモファイル
+Name[ka]=ჩანიშვნა
+Name[kk]=Жазба файлы
+Name[km]=ឯកសារ​អនុស្សរណៈ
+Name[lt]=Memo byla
+Name[ms]=Fail Memo
+Name[nb]=Notatfil
+Name[nds]=Notiz-Datei
+Name[ne]=स्मृति फाइल
+Name[nl]=Memobestand
+Name[nn]=Memofil
+Name[pl]=Plik notatki
+Name[pt]=Ficheiro Memorando
+Name[pt_BR]=Arquivo Memo
+Name[ru]=Заметка
+Name[sk]=Memo súbor
+Name[sl]=Datoteka z opombami
+Name[sv]=Anteckningsfil
+Name[ta]=மெமோ கோப்பு
+Name[tr]=Hatırlatma Dosyası
+Name[uk]=Файл примітки
+Name[zh_CN]=备忘文件
+Name[zh_TW]=Memo 檔
+Comment=This conduit syncs your handheld memos with a local directory.
+Comment[af]=Hierdie pad sinkroniseer jou draagbare toestel se memos met 'n plaaslike gids.
+Comment[bg]=Синхронизация на бележките на KDE с мобилни устройства.
+Comment[ca]=Aquest conducte sincronitza les notes de l'agenda electrònica amb un directori local.
+Comment[cs]=Toto propojení synchronizuje vaše poznámky v PDA s lokálním adresářem.
+Comment[da]=Denne kanal synkroniserer dine håndholdte memoer med en lokal mappe.
+Comment[de]=Abgleich der Memos von Taschencomputer und einem lokalen Ordner
+Comment[el]=Αυτός ο σύνδεσμος συγχρονίζει τα υπομνήματα του υπολογιστή παλάμης σας με έναν τοπικό κατάλογο.
+Comment[eo]=Tiu kanalo sinkronigas viajn poŝkomputil-memoojn kun loka dosierujo.
+Comment[es]=Este conducto sincroniza las notas de su agenda electrónica con el directorio local.
+Comment[et]=See kanal sünkroniseerib pihuarvutis ja arvutis olevad memod.
+Comment[eu]=Kanal honek zure agendako oharrak direktorio lokal batekin sinkronizatzen ditu.
+Comment[fa]=این لوله، memo‌های دستی خود را با فهرست راهنمای محلی همگام‌سازی می‌کند.
+Comment[fi]=Tämä yhdyskäytävä synkronoi taskutietokoneen muistiot paikalliseen kansioon.
+Comment[fr]=Ce canal synchronise les mémos du Palm avec ceux de KDE.
+Comment[fy]=Dit conduit syngronisearret de memo's fan jo handheld mei in lokale triemtafel.
+Comment[gl]=Este conducto sincroniza os memos do seu aparello portátil cun cartafol local.
+Comment[hu]=Ezzel a csatolóval egy kézi számítógép memóit lehet szinkronizálni a helyi címjegyzékkel.
+Comment[is]=Þessi rás samstillir minnismiða lófatölvunnar þinnar við staðbundna möppu.
+Comment[it]=Questo condotto sincronizza gli appunti del tuo palmare con una cartella locale.
+Comment[ja]=このコンジットはハンドヘルドのメモをローカルのディレクトリと同期させます。
+Comment[ka]=ეს არხი თქვენი პორტატიული მოწყობილობის ლოკალურ დირექტორიასთან სინქრონიზაციას ახდენს .
+Comment[kk]=Қалта құрылғыдағы жазбаларды қапшықтағы файлымен қадамдастыру арнасы.
+Comment[km]=បំពង់​នេះ​អាច​ឲ្យ​អនុស្សរណៈ​ឧបករណ៍​យួរ​ដៃ​របស់​អ្នក ធ្វើ​សមកាលកម្ម​ជាមួយ​នឹង​ថត​មូលដ្ឋាន ។​
+Comment[lt]=Šis kanalas sinchronizuoja Jūsų užrašus su vietiniu aplanku.
+Comment[ms]=Saluran ini mensegerakkan memo komputer telapak anda dengan direktori setempat.
+Comment[nb]=Denne kanalen synkroniserer PDA-ens notater med en lokal mappe.
+Comment[nds]=Synkroniseert de Notizen op den Handreekner mit en lokaal Orner.
+Comment[ne]=यो कन्ड्युटले स्थानीय डाइरेक्टरीमा तपाईँका ह्यान्डहेल्ड मेमो सिन्क गर्दछ ।
+Comment[nl]=Dit conduit synchroniseert de memo's van uw handheld met een lokale map.
+Comment[pl]=Ten łącznik synchronizuje notatki z palmtopa z lokalnym katalogiem.
+Comment[pt]=Esta conduta sincroniza os memorandos do seu PDA com uma pasta local.
+Comment[pt_BR]=Este conduíte sincroniza as anotações no seu handheld com um diretório local.
+Comment[ru]=Канал синхронизации заметок КПК и KDE.
+Comment[sk]=Táto spojka synchronizuje adresár vášho prenosného zariadenia s lokálnym priečinkom.
+Comment[sl]=Ta veznik usklajuje opombe v ročnem računalniku s krajevnim imenikom.
+Comment[sr]=Овај провод синхронизује белешке на вашем ручном рачунару са локалним директоријумом.
+Comment[sr@Latn]=Ovaj provod sinhronizuje beleške na vašem ručnom računaru sa lokalnim direktorijumom.
+Comment[sv]=Den här kanalen synkroniserar handdatorns anteckningar med en lokal katalog.
+Comment[ta]=இந்த குழாய் கையில் உள்ள முகவரிப்புத்தகத்தை கேடிஇயின் முகவரிப்புத்தகத்தோடு ஒத்திசைக்கிறது
+Comment[tr]=Bu bileşen el bilgisayarı hatırlatmalarını yerel bir dosyaya aktarır veya alır.
+Comment[uk]=Цей акведук синхронізує примітки кишенькового пристрою з локальним каталогом.
+Comment[zh_CN]=此管道会将您手持设备中的备忘与本地目录同步。
+Comment[zh_TW]=此軟體同步您的 handheld memo 及本地端目錄。
+Implemented=file
+ServiceTypes=KPilotConduit
+X-KDE-Library=conduit_memofile
diff --git a/kpilot/conduits/memofileconduit/memofile-conduit.h b/kpilot/conduits/memofileconduit/memofile-conduit.h
new file mode 100644
index 000000000..08fdbd0f7
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/memofile-conduit.h
@@ -0,0 +1,92 @@
+#ifndef _MEMOFILE_MEMOFILE_CONDUIT_H
+#define _MEMOFILE_MEMOFILE_CONDUIT_H
+/* memofile-conduit.h KPilot
+**
+** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <pi-memo.h>
+
+#include "plugin.h"
+
+#include "memofiles.h"
+
+class PilotMemo;
+
+class MemofileConduit : public ConduitAction
+{
+Q_OBJECT
+public:
+ MemofileConduit(KPilotLink *,
+ const char *name=0L,
+ const QStringList &args = QStringList());
+ virtual ~MemofileConduit();
+
+protected:
+ virtual bool exec();
+
+
+protected slots:
+ void process();
+
+private:
+ // configuration settings...
+ QString _DEFAULT_MEMODIR;
+ QString _memo_directory;
+ bool _sync_private;
+
+ PilotMemoInfo *fMemoAppInfo;
+ QPtrList<PilotMemo> fMemoList;
+
+ // our categories
+ MemoCategoryMap fCategories;
+
+ Memofiles * _memofiles;
+
+
+ bool readConfig();
+ bool getAppInfo();
+ bool setAppInfo();
+
+ bool initializeFromPilot();
+ bool loadPilotCategories();
+
+ void listPilotMemos();
+
+ void getAllFromPilot();
+ void getModifiedFromPilot();
+
+ bool copyHHToPC();
+ bool copyPCToHH();
+ void deleteUnsyncedHHRecords();
+ bool sync();
+
+ int writeToPilot(Memofile * memofile);
+ void deleteFromPilot(PilotMemo* memo);
+
+ void cleanup();
+
+};
+
+#endif
diff --git a/kpilot/conduits/memofileconduit/memofile-factory.cc b/kpilot/conduits/memofileconduit/memofile-factory.cc
new file mode 100644
index 000000000..e373a0185
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/memofile-factory.cc
@@ -0,0 +1,128 @@
+/* memofile-factory.cc KPilot
+**
+** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper
+**
+** This file defines the factory for the memofile-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qtabwidget.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+
+#include <kconfig.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+#include <kurlrequester.h>
+
+#include "setup_base.h"
+#include "memofile-conduit.h"
+#include "memofileSettings.h"
+
+#include "pluginfactory.h"
+
+class MemofileConduitConfig : public ConduitConfigBase
+{
+public:
+ MemofileConduitConfig(QWidget *parent=0L, const char *n=0L);
+ virtual void commit();
+ virtual void load();
+protected:
+ MemofileWidget *fConfigWidget;
+} ;
+
+MemofileConduitConfig::MemofileConduitConfig(QWidget *p, const char *n) :
+ ConduitConfigBase(p,n),
+ fConfigWidget(new MemofileWidget(p))
+{
+ FUNCTIONSETUP;
+ fConduitName = i18n("Memofile");
+ KAboutData *about = new KAboutData("MemofileConduit",
+ I18N_NOOP("Memofile Conduit for KPilot"),
+ KPILOT_VERSION,
+ I18N_NOOP("Configures the Memofile Conduit for KPilot"),
+ KAboutData::License_GPL,
+ "(C) 2004, Jason 'vanRijn' Kasper");
+ about->addAuthor("Jason 'vanRijn' Kasper",
+ I18N_NOOP("Primary Author"),
+ "http://www.cs.kun.nl/~adridg/kpilot");
+
+ ConduitConfigBase::addAboutPage(fConfigWidget->tabWidget,about);
+ fWidget=fConfigWidget;
+ QObject::connect(fConfigWidget->fDirectory,SIGNAL(textChanged(const QString&)),
+ this,SLOT(modified()));
+ QObject::connect(fConfigWidget->fSyncPrivate,SIGNAL(toggled(bool)),
+ this,SLOT(modified()));
+
+}
+
+/* virtual */ void MemofileConduitConfig::commit()
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname
+ << ": Directory="
+ << fConfigWidget->fDirectory->url()
+ << endl;
+
+ MemofileConduitSettings::setDirectory( fConfigWidget->fDirectory->url() );
+ MemofileConduitSettings::setSyncPrivate( fConfigWidget->fSyncPrivate->isChecked() );
+ MemofileConduitSettings::self()->writeConfig();
+ unmodified();
+}
+
+/* virtual */ void MemofileConduitConfig::load()
+{
+ FUNCTIONSETUP;
+ MemofileConduitSettings::self()->readConfig();
+
+ fConfigWidget->fDirectory->setURL( MemofileConduitSettings::directory() );
+ fConfigWidget->fSyncPrivate->setChecked( MemofileConduitSettings::syncPrivate() );
+
+ DEBUGKPILOT << fname
+ << ": Read Directory: ["
+ << fConfigWidget->fDirectory->url()
+ << "], sync private records: ["
+ << fConfigWidget->fSyncPrivate
+ << "]" << endl;
+
+ unmodified();
+}
+
+
+
+extern "C"
+{
+
+void *init_conduit_memofile()
+{
+ return new ConduitFactory<MemofileConduitConfig,MemofileConduit>(0,"memofileconduit");
+}
+
+unsigned long version_conduit_memofile = Pilot::PLUGIN_API;
+
+}
+
diff --git a/kpilot/conduits/memofileconduit/memofile-factory.h b/kpilot/conduits/memofileconduit/memofile-factory.h
new file mode 100644
index 000000000..b42fb6577
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/memofile-factory.h
@@ -0,0 +1,40 @@
+#ifndef _KPILOT_MEMOFILE_FACTORY_H
+#define _KPILOT_MEMOFILE_FACTORY_H
+/* memofile-factory.h KPilot
+**
+** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper
+**
+** This file defines the factory for the Memofile-conduit plugin.
+** It also defines the class for the behavior of the setup dialog.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+extern "C"
+{
+
+void *init_libmemofileconduit();
+
+}
+
+#endif
diff --git a/kpilot/conduits/memofileconduit/memofile.cc b/kpilot/conduits/memofileconduit/memofile.cc
new file mode 100644
index 000000000..1428c487d
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/memofile.cc
@@ -0,0 +1,239 @@
+/* memofile.cc KPilot
+**
+** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "memofile.h"
+
+Memofile::Memofile(PilotMemo * memo, QString categoryName, QString fileName, QString baseDirectory) :
+ PilotMemo(memo,memo->text()), _categoryName(categoryName), _filename(fileName), _baseDirectory(baseDirectory)
+{
+ _lastModified = 0;
+ _size = 0;
+ _modified = _modifiedByPalm = false;
+}
+
+Memofile::Memofile(recordid_t id, int category, uint lastModifiedTime, uint size,
+ QString categoryName, QString fileName, QString baseDirectory) :
+ PilotMemo(), _categoryName(categoryName),
+ _filename(fileName),_baseDirectory(baseDirectory)
+{
+ setID(id);
+ PilotRecordBase::setCategory(category);
+ _lastModified = lastModifiedTime;
+ _size = size;
+ _modified = _modifiedByPalm = false;
+}
+
+Memofile::Memofile(int category, QString categoryName, QString fileName, QString baseDirectory) :
+ PilotMemo(),
+ _categoryName(categoryName), _filename(fileName), _baseDirectory(baseDirectory)
+{
+ setID(0);
+ _new = true;
+ PilotRecordBase::setCategory(category);
+ _modified = true;
+ _modifiedByPalm = false;
+ _lastModified = 0;
+ _size = 0;
+}
+
+bool Memofile::load()
+{
+ FUNCTIONSETUP;
+ if (filename().isEmpty()) {
+ DEBUGKPILOT << fname
+ << ": I was asked to load, but have no filename to load. "
+ << endl;
+ return false;
+ }
+
+ QFile f( filenameAbs() );
+ if ( !f.open( IO_ReadOnly ) ) {
+ DEBUGKPILOT << fname
+ << ": Couldn't open file: [" << filenameAbs() << "] to read. "
+ << endl;
+ return false;
+ }
+
+ QTextStream ts( &f );
+
+ QString text,title,body;
+ title = filename();
+ body = ts.read();
+
+ // funky magic. we want the text of the memofile to have the filename
+ // as the first line....
+ if (body.startsWith(title)) {
+ text = body;
+ } else {
+ DEBUGKPILOT << fname
+ << ": text of your memofile: [" << filename()
+ << "] didn't include the filename as the first line. fixing it..." << endl;
+ text = title + CSL1("\n") + body;
+ }
+
+ // check length of text. if it's over the allowable length, warn user.
+ // NOTE: We don't need to truncate this here, since PilotMemo::setText()
+ // does it for us.
+ int _len = text.length();
+ int _maxlen = PilotMemo::MAX_MEMO_LEN;
+ if (_len > _maxlen) {
+ DEBUGKPILOT << fname << ": memofile: [" << filename()
+ << "] length: [" << _len << "] is over maximum: ["
+ << _maxlen << "] and will be truncated to fit." << endl;
+ }
+
+ setText(text);
+ f.close();
+
+ return true;
+}
+
+void Memofile::setID(recordid_t i)
+{
+ if (i != id())
+ _modifiedByPalm = true;
+
+ PilotMemo::setID(i);
+}
+
+bool Memofile::save()
+{
+ bool result = true;
+
+ if ((isModified() && isLoaded()) || _modifiedByPalm) {
+ result = saveFile();
+ }
+
+ return result;
+}
+
+bool Memofile::deleteFile()
+{
+ FUNCTIONSETUP;
+ DEBUGKPILOT << fname
+ << ": deleting file: [" << filenameAbs() << "]." << endl;
+ return QFile::remove(filenameAbs());
+
+}
+
+bool Memofile::saveFile()
+{
+ FUNCTIONSETUP;
+
+ if (filename().isEmpty()) {
+ DEBUGKPILOT << fname
+ << ": I was asked to save, but have no filename to save to. "
+ << endl;
+ return false;
+ }
+
+ DEBUGKPILOT << fname
+ << ": saving memo to file: ["
+ << filenameAbs() << "]" << endl;
+
+
+ QFile f( filenameAbs() );
+ if ( !f.open( IO_WriteOnly ) ) {
+ DEBUGKPILOT << fname
+ << ": Couldn't open file: [" << filenameAbs() << "] to write your memo to. "
+ << "This won't end well." << endl;
+ return false;
+ }
+
+ QTextStream stream(&f);
+ stream << text() << endl;
+ f.close();
+
+ _lastModified = getFileLastModified();
+ _size = getFileSize();
+
+ return true;
+
+}
+
+bool Memofile::isModified(void)
+{
+ // first, check to see if this file is deleted....
+ if (!fileExists()) {
+ return true;
+ }
+
+ bool modByTimestamp = false;
+ bool modBySize = false;
+
+ if (_lastModified > 0)
+ modByTimestamp = isModifiedByTimestamp();
+
+ if (_size > 0)
+ modBySize = isModifiedBySize();
+
+ bool ret = _modified || modByTimestamp || modBySize;
+
+ return ret;
+}
+
+bool Memofile::isModifiedByTimestamp()
+{
+ if (_lastModified <=0) {
+ return true;
+ }
+
+ uint lastModifiedTime = getFileLastModified();
+ if ( lastModifiedTime != _lastModified) {
+ return true;
+ }
+
+ return false;
+}
+
+bool Memofile::isModifiedBySize()
+{
+ if (_size <=0) {
+ return true;
+ }
+
+ uint size = getFileSize();
+ if ( size != _size) {
+ return true;
+ }
+
+ return false;
+}
+
+uint Memofile::getFileLastModified()
+{
+ QFileInfo f = QFileInfo(filenameAbs());
+ uint lastModifiedTime = f.lastModified().toTime_t();
+ return lastModifiedTime;
+}
+
+uint Memofile::getFileSize()
+{
+ QFileInfo f = QFileInfo(filenameAbs());
+ uint size = f.size();
+ return size;
+}
diff --git a/kpilot/conduits/memofileconduit/memofile.h b/kpilot/conduits/memofileconduit/memofile.h
new file mode 100644
index 000000000..27931cdfe
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/memofile.h
@@ -0,0 +1,113 @@
+#ifndef _MEMOFILE_MEMOFILE_H
+#define _MEMOFILE_MEMOFILE_H
+/* memofile.h KPilot
+**
+** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "options.h"
+
+// Only include what we really need:
+// First UNIX system stuff, then std C++,
+// then Qt, then KDE, then local includes.
+//
+//
+
+#include <time.h> // required by pilot-link includes
+
+#include <pi-memo.h>
+
+#include <qfile.h>
+#include <qdir.h>
+#include <qtextstream.h>
+#include <qtextcodec.h>
+
+#include "pilotMemo.h"
+
+#include "memofiles.h"
+
+/**
+ * Class that represents our filesystem memo.
+ */
+class Memofile : public PilotMemo
+{
+ public:
+ Memofile(PilotMemo * memo, QString categoryName, QString fileName, QString baseDirectory);
+ Memofile(recordid_t id, int category, uint lastModifiedTime, uint size, QString categoryName, QString filename, QString baseDirectory);
+ Memofile(int category, QString categoryName, QString fileName, QString baseDirectory);
+
+ uint lastModified() const { return _lastModified; } ;
+ uint size() const { return _size; } ;
+
+ void setModifiedByPalm(bool mod) { _modifiedByPalm = mod; } ;
+ void setModified(bool modified) { _modified = modified; } ;
+
+ bool isModified(void);
+ bool isModifiedByPalm() { return _modifiedByPalm; } ;
+ bool isLoaded(void) { return (! text().isEmpty()); } ;
+ bool isNew(void) { return _new; } ;
+
+ bool load();
+
+ bool fileExists() { return QFile::exists(filenameAbs()); } ;
+
+ void setID(recordid_t id);
+
+ bool save();
+ bool deleteFile();
+
+ QString toString() {
+ return CSL1("id: [") + QString::number(id())
+ + CSL1("], category:[") + _categoryName
+ + CSL1("], filename: [") + _filename + CSL1("]");
+ } ;
+ const QString & getCategoryName() { return _categoryName; } ;
+ const QString & getFilename() { return _filename; } ;
+ const QString & filename() { return _filename; } ;
+
+ private:
+ bool saveFile();
+ bool isModifiedByTimestamp();
+ bool isModifiedBySize();
+
+ QString filenameAbs() { return dirName() + filename(); } ;
+ QString dirName() { return _baseDirectory + QDir::separator() + _categoryName + QDir::separator(); } ;
+ bool setCategory(const QString &label);
+ uint getFileLastModified();
+ uint getFileSize();
+
+ bool _modifiedByPalm;
+ bool _modified;
+ bool _new;
+ uint _lastModified;
+ uint _size;
+
+ QString _categoryName;
+ QString _filename;
+ QString _baseDirectory;
+} ;
+
+#endif
diff --git a/kpilot/conduits/memofileconduit/memofileSettings.kcfgc b/kpilot/conduits/memofileconduit/memofileSettings.kcfgc
new file mode 100644
index 000000000..3d1373b88
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/memofileSettings.kcfgc
@@ -0,0 +1,7 @@
+File=memofileconduit.kcfg
+ClassName= MemofileConduitSettings
+Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/conduits/memofileconduit/memofileconduit.kcfg b/kpilot/conduits/memofileconduit/memofileconduit.kcfg
new file mode 100644
index 000000000..506e040ed
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/memofileconduit.kcfg
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE kcfg SYSTEM "http://www.kde.org/standards/kcfg/1.0/kcfg.dtd">
+<kcfg><kcfgfile name="kpilotrc"/>
+ <group name="memofile-conduit">
+ <entry name="Directory" type="Path">
+ <label>What directory do you want to sync your PDA's memos with?</label>
+ <default>$HOME/MyMemos</default>
+ </entry>
+ <entry name="SyncPrivate" type="Bool">
+ <label>Do you want to sync your private records to the filesystem?</label>
+ <default>true</default>
+ </entry>
+
+ </group>
+
+</kcfg>
diff --git a/kpilot/conduits/memofileconduit/memofileconduit.xmi b/kpilot/conduits/memofileconduit/memofileconduit.xmi
new file mode 100644
index 000000000..33ff89f85
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/memofileconduit.xmi
@@ -0,0 +1,241 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<XMI xmlns:UML="org.omg/standards/UML" verified="false" timestamp="" xmi.version="1.2" >
+ <XMI.header>
+ <XMI.documentation>
+ <XMI.exporter>umbrello uml modeller http://uml.sf.net</XMI.exporter>
+ <XMI.exporterVersion>1.2.90</XMI.exporterVersion>
+ <XMI.exporterEncoding>UnicodeUTF8</XMI.exporterEncoding>
+ </XMI.documentation>
+ <XMI.model xmi.name="umbrelloJSFhpc" href="/tmp/kde-gideon/umbrelloJSFhpc.tmp" />
+ <XMI.metamodel xmi.name="UML" href="UML.xml" xmi.version="1.3" />
+ </XMI.header>
+ <XMI.content>
+ <UML:Model>
+ <UML:Stereotype visibility="public" xmi.id="3" name="datatype" />
+ <UML:Stereotype visibility="public" xmi.id="18" name="enum" />
+ <UML:Stereotype visibility="public" xmi.id="35" name="typedef" />
+ <UML:DataType stereotype="3" visibility="public" xmi.id="2" name="int" />
+ <UML:DataType stereotype="3" visibility="public" xmi.id="4" name="char" />
+ <UML:DataType stereotype="3" visibility="public" xmi.id="5" name="bool" />
+ <UML:DataType stereotype="3" visibility="public" xmi.id="6" name="float" />
+ <UML:DataType stereotype="3" visibility="public" xmi.id="7" name="double" />
+ <UML:DataType stereotype="3" visibility="public" xmi.id="8" name="long" />
+ <UML:DataType stereotype="3" visibility="public" xmi.id="9" name="short" />
+ <UML:DataType stereotype="3" visibility="public" xmi.id="10" name="string" />
+ <UML:Class visibility="public" xmi.id="11" name="MemofileConduit" >
+ <UML:Operation visibility="public" xmi.id="12" type="" name="MemofileConduit" >
+ <UML:Parameter visibility="public" xmi.id="13" value="" type="KPilotDeviceLink*" />
+ <UML:Parameter visibility="public" xmi.id="14" value="" type="const char*" name="name" />
+ <UML:Parameter visibility="public" xmi.id="15" value="" type="const QStringList&amp;" name="args" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="16" type="" name="~ MemofileConduit" />
+ <UML:Operation visibility="protected" xmi.id="26" type="bool" name="exec" />
+ <UML:Operation visibility="protected" xmi.id="27" type="void" name="listPilotMemos" />
+ <UML:Operation visibility="protected" xmi.id="28" type="void" name="process" />
+ <UML:Operation visibility="private" xmi.id="43" type="bool" name="readConfig" />
+ <UML:Operation visibility="private" xmi.id="44" type="void" name="getAppInfo" />
+ <UML:Operation visibility="private" xmi.id="45" type="QString" name="getCategoryName" >
+ <UML:Parameter visibility="public" xmi.id="46" value="" type="int" name="category" />
+ </UML:Operation>
+ <UML:Operation visibility="private" xmi.id="47" type="bool" name="initializeFromPilot" />
+ <UML:Operation visibility="private" xmi.id="48" type="bool" name="loadPilotMemos" />
+ <UML:Operation visibility="private" xmi.id="49" type="bool" name="loadPilotCategories" />
+ <UML:Operation visibility="private" xmi.id="50" type="bool" name="initializeFromFilesystem" />
+ <UML:Operation visibility="private" xmi.id="51" type="bool" name="initializeMemofileList" />
+ <UML:Operation visibility="private" xmi.id="52" type="bool" name="checkDirectory" >
+ <UML:Parameter visibility="public" xmi.id="53" value="" type="QString" name="dir" />
+ </UML:Operation>
+ <UML:Operation visibility="private" xmi.id="54" type="bool" name="ensureFilesystemReady" />
+ <UML:Operation visibility="private" xmi.id="55" type="bool" name="copyHHToPC" />
+ <UML:Operation visibility="private" xmi.id="56" type="bool" name="saveCategoriesToFilesystem" />
+ <UML:Operation visibility="private" xmi.id="57" type="bool" name="saveMemoInfoToFilesystem" />
+ <UML:Operation visibility="private" xmi.id="58" type="bool" name="saveMemosToFilesystem" />
+ <UML:Operation visibility="private" xmi.id="59" type="bool" name="saveAsText" >
+ <UML:Parameter visibility="public" xmi.id="60" value="" type="const QString&amp;" name="fileName" />
+ <UML:Parameter visibility="public" xmi.id="61" value="" type="Memofile*" name="theMemo" />
+ </UML:Operation>
+ <UML:Attribute visibility="private" xmi.id="29" value="" type="QString" name="_DEFAULT_MEMODIR" />
+ <UML:Attribute visibility="private" xmi.id="30" value="" type="QString" name="_memo_directory" />
+ <UML:Attribute visibility="private" xmi.id="31" value="" type="bool" name="_sync_private" />
+ <UML:Attribute visibility="private" xmi.id="32" value="" type="QPtrList&lt; PilotMemo >" name="fMemoList" />
+ <UML:Attribute visibility="private" xmi.id="33" value="" type="struct MemoAppInfo" name="fMemoAppInfo" />
+ <UML:Attribute visibility="private" xmi.id="37" value="" type="QPtrList&lt; Memofile >" name="fMemofileList" />
+ <UML:Attribute visibility="private" xmi.id="38" value="" type="int" name="fRecordIndex" />
+ <UML:Attribute visibility="private" xmi.id="39" value="" type="QTimer*" name="fTimer" />
+ <UML:Attribute visibility="private" xmi.id="40" value="" type="int" name="fCounter" />
+ <UML:Attribute visibility="private" xmi.id="41" value="" type="int" name="fDeleteCounter" />
+ <UML:Attribute visibility="private" xmi.id="42" value="" type="int" name="fModifyCounter" />
+ <UML:Enumeration stereotype="18" visibility="public" xmi.id="17" name="Status" >
+ <UML:EnumerationLiteral visibility="public" xmi.id="19" name="Init" />
+ <UML:EnumerationLiteral visibility="public" xmi.id="20" name="ModifiedFilesToPilot" />
+ <UML:EnumerationLiteral visibility="public" xmi.id="21" name="DeleteFilesOnPilot" />
+ <UML:EnumerationLiteral visibility="public" xmi.id="22" name="NewFilesToPilot" />
+ <UML:EnumerationLiteral visibility="public" xmi.id="23" name="MemosToFiles" />
+ <UML:EnumerationLiteral visibility="public" xmi.id="24" name="Cleanup" />
+ <UML:EnumerationLiteral visibility="public" xmi.id="25" name="Done" />
+ </UML:Enumeration>
+ <UML:Class stereotype="35" visibility="public" xmi.id="34" name="MemoCategoryMap" />
+ </UML:Class>
+ <UML:Class visibility="public" xmi.id="63" name="Memofiles" >
+ <UML:Operation visibility="public" xmi.id="80" type="Memofiles" name="Memofiles" >
+ <UML:Parameter visibility="public" xmi.id="81" value="" type="QMap" name="categories" />
+ <UML:Parameter visibility="public" xmi.id="82" value="" type="QString" name="baseDirectory" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="87" type="void" name="load" >
+ <UML:Parameter visibility="public" xmi.id="88" value="" type="bool" name="loadAll" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="89" type="QPtrList&lt;Memofile>" name="getAll" />
+ <UML:Operation visibility="public" xmi.id="90" type="void" name="save" />
+ <UML:Operation visibility="public" xmi.id="91" type="void" name="eraseLocalMemos" />
+ <UML:Operation visibility="public" xmi.id="95" type="void" name="setModified" >
+ <UML:Parameter visibility="public" xmi.id="96" value="" type="QPtrList&lt;PilotMemo>" name="memos" />
+ </UML:Operation>
+ <UML:Operation visibility="private" xmi.id="97" type="void" name="ensureDirectoryReady" />
+ <UML:Operation visibility="public" xmi.id="98" type="void" name="loadIds" />
+ <UML:Operation visibility="public" xmi.id="99" type="Memofile" name="find" >
+ <UML:Parameter visibility="public" xmi.id="100" value="" type="QString" name="category" />
+ <UML:Parameter visibility="public" xmi.id="101" value="" type="QString" name="filename" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="102" type="void" name="addModified" >
+ <UML:Parameter visibility="public" xmi.id="103" value="" type="PilotMemo *" name="memo" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="104" type="QPtrList&lt;Memofile>" name="getModified" />
+ <UML:Attribute visibility="private" xmi.id="83" value="" type="QMap" name="_categories" />
+ <UML:Attribute visibility="private" xmi.id="85" value="" type="QString" name="_baseDirectory" />
+ <UML:Attribute visibility="private" xmi.id="93" value="" type="QPtrList&lt;Memofile>" name="_memofiles" />
+ </UML:Class>
+ <UML:Class visibility="public" xmi.id="64" name="Memofile" >
+ <UML:Operation visibility="public" xmi.id="65" type="" name="Memofile" >
+ <UML:Parameter visibility="public" xmi.id="66" value="" type="PilotMemo*" name="memo" />
+ <UML:Parameter visibility="public" xmi.id="67" value="" type="QString" name="categoryName" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="68" type="" name="Memofile" >
+ <UML:Parameter visibility="public" xmi.id="69" value="" type="recordid_t" name="id" />
+ <UML:Parameter visibility="public" xmi.id="70" value="" type="int" name="category" />
+ <UML:Parameter visibility="public" xmi.id="71" value="" type="QString" name="categoryName" />
+ <UML:Parameter visibility="public" xmi.id="72" value="" type="uint" name="lastModifiedTime" />
+ <UML:Parameter visibility="public" xmi.id="73" value="" type="QString" name="filename" />
+ <UML:Parameter visibility="public" xmi.id="74" value="" type="QString" name="text" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="75" type="uint" name="lastModified" />
+ <UML:Operation visibility="public" xmi.id="76" type="QString" name="filename" />
+ <UML:Attribute visibility="private" xmi.id="77" value="" type="uint" name="_lastModified" />
+ <UML:Attribute visibility="private" xmi.id="78" value="" type="QString" name="_categoryName" />
+ <UML:Attribute visibility="private" xmi.id="79" value="" type="QString" name="_filename" />
+ </UML:Class>
+ <UML:DataType stereotype="3" visibility="public" xmi.id="84" name="QMap" />
+ <UML:DataType stereotype="3" visibility="public" xmi.id="86" name="QString" />
+ <UML:DataType stereotype="3" visibility="public" xmi.id="94" name="QPtrList&lt;Memofile>" />
+ <UML:Association visibility="public" xmi.id="36" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="composite" type="11" />
+ <UML:AssociationEndRole visibility="private" type="34" />
+ </UML:Association.connection>
+ </UML:Association>
+ </UML:Model>
+ </XMI.content>
+ <XMI.extensions xmi.extender="umbrello" >
+ <docsettings viewid="62" documentation="" uniqueid="107" />
+ <diagrams>
+ <diagram snapgrid="0" showattsig="1" fillcolor="#ffffc0" linewidth="0" zoom="100" showgrid="0" showopsig="1" usefillcolor="1" snapx="10" canvaswidth="807" snapy="10" showatts="1" xmi.id="1" documentation="" type="402" showops="1" showpackage="0" name="class diagram" localid="30000" showstereotype="0" showscope="1" snapcsgrid="0" font="Sans,10,-1,5,50,0,0,0,0,0" linecolor="#ff0000" canvasheight="591" >
+ <widgets/>
+ <messages/>
+ <associations/>
+ </diagram>
+ <diagram snapgrid="0" showattsig="1" fillcolor="#ffffc0" linewidth="0" zoom="100" showgrid="0" showopsig="1" usefillcolor="1" snapx="10" canvaswidth="999" snapy="10" showatts="1" xmi.id="62" documentation="" type="402" showops="1" showpackage="0" name="memofile classes" localid="30000" showstereotype="0" showscope="1" snapcsgrid="0" font="Sans,10,-1,5,50,0,0,0,0,0" linecolor="#ff0000" canvasheight="630" >
+ <widgets>
+ <classwidget usesdiagramfillcolour="1" width="543" showattsigs="601" usesdiagramusefillcolour="1" x="428" linecolour="none" y="62" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="1" fillcolour="none" height="544" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="11" showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Sans,10,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="1" width="432" showattsigs="601" usesdiagramusefillcolour="1" x="17" linecolour="none" y="33" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="1" fillcolour="none" height="255" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="63" showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Sans,10,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="1" width="767" showattsigs="601" usesdiagramusefillcolour="1" x="3" linecolour="none" y="467" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="1" fillcolour="none" height="136" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="64" showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Sans,10,-1,5,75,0,0,0,0,0" />
+ </widgets>
+ <messages/>
+ <associations/>
+ </diagram>
+ </diagrams>
+ <listview>
+ <listitem open="1" type="800" id="-1" label="Views" >
+ <listitem open="1" type="801" id="-1" label="Logical View" >
+ <listitem open="0" type="807" id="1" label="class diagram" />
+ <listitem open="0" type="807" id="62" label="memofile classes" />
+ <listitem open="0" type="813" id="64" >
+ <listitem open="0" type="814" id="78" />
+ <listitem open="0" type="814" id="79" />
+ <listitem open="0" type="814" id="77" />
+ <listitem open="0" type="815" id="65" />
+ <listitem open="0" type="815" id="68" />
+ <listitem open="0" type="815" id="76" />
+ <listitem open="0" type="815" id="75" />
+ </listitem>
+ <listitem open="0" type="813" id="11" >
+ <listitem open="1" type="813" id="34" />
+ <listitem open="0" type="814" id="29" />
+ <listitem open="0" type="814" id="30" />
+ <listitem open="0" type="814" id="31" />
+ <listitem open="0" type="814" id="40" />
+ <listitem open="0" type="814" id="41" />
+ <listitem open="0" type="814" id="33" />
+ <listitem open="0" type="814" id="32" />
+ <listitem open="0" type="814" id="37" />
+ <listitem open="0" type="814" id="42" />
+ <listitem open="0" type="814" id="38" />
+ <listitem open="0" type="814" id="39" />
+ <listitem open="0" type="815" id="12" />
+ <listitem open="0" type="815" id="52" />
+ <listitem open="0" type="815" id="55" />
+ <listitem open="0" type="815" id="54" />
+ <listitem open="0" type="815" id="26" />
+ <listitem open="0" type="815" id="44" />
+ <listitem open="0" type="815" id="45" />
+ <listitem open="0" type="815" id="50" />
+ <listitem open="0" type="815" id="47" />
+ <listitem open="0" type="815" id="51" />
+ <listitem open="0" type="815" id="27" />
+ <listitem open="0" type="815" id="49" />
+ <listitem open="0" type="815" id="48" />
+ <listitem open="0" type="815" id="28" />
+ <listitem open="0" type="815" id="43" />
+ <listitem open="0" type="815" id="59" />
+ <listitem open="0" type="815" id="56" />
+ <listitem open="0" type="815" id="57" />
+ <listitem open="0" type="815" id="58" />
+ <listitem open="0" type="815" id="16" />
+ <listitem open="1" type="831" id="17" />
+ </listitem>
+ <listitem open="1" type="813" id="63" >
+ <listitem open="0" type="814" id="85" />
+ <listitem open="0" type="814" id="83" />
+ <listitem open="0" type="814" id="93" />
+ <listitem open="0" type="815" id="80" />
+ <listitem open="0" type="815" id="102" />
+ <listitem open="0" type="815" id="97" />
+ <listitem open="0" type="815" id="91" />
+ <listitem open="0" type="815" id="99" />
+ <listitem open="0" type="815" id="89" />
+ <listitem open="0" type="815" id="104" />
+ <listitem open="0" type="815" id="87" />
+ <listitem open="0" type="815" id="98" />
+ <listitem open="0" type="815" id="90" />
+ <listitem open="0" type="815" id="95" />
+ </listitem>
+ <listitem open="0" type="830" id="-1" label="Datatypes" >
+ <listitem open="1" type="829" id="84" />
+ <listitem open="1" type="829" id="94" />
+ <listitem open="1" type="829" id="86" />
+ <listitem open="1" type="829" id="5" />
+ <listitem open="1" type="829" id="4" />
+ <listitem open="1" type="829" id="7" />
+ <listitem open="1" type="829" id="6" />
+ <listitem open="1" type="829" id="2" />
+ <listitem open="1" type="829" id="8" />
+ <listitem open="1" type="829" id="9" />
+ <listitem open="1" type="829" id="10" />
+ </listitem>
+ </listitem>
+ <listitem open="1" type="802" id="-1" label="Use Case View" />
+ <listitem open="1" type="821" id="-1" label="Component View" />
+ <listitem open="1" type="827" id="-1" label="Deployment View" />
+ </listitem>
+ </listview>
+ <codegeneration/>
+ </XMI.extensions>
+</XMI>
diff --git a/kpilot/conduits/memofileconduit/memofiles.cc b/kpilot/conduits/memofileconduit/memofiles.cc
new file mode 100644
index 000000000..2846d448b
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/memofiles.cc
@@ -0,0 +1,700 @@
+/* memofile-conduit.cc KPilot
+**
+** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include "memofiles.h"
+#include "memofile.h"
+
+QString Memofiles::FIELD_SEP = CSL1("\t");
+
+Memofiles::Memofiles (MemoCategoryMap & categories, PilotMemoInfo &appInfo,
+ QString & baseDirectory, CUDCounter &fCtrPC) :
+ _categories(categories), _memoAppInfo(appInfo),
+ _baseDirectory(baseDirectory), _cudCounter(fCtrPC)
+{
+ FUNCTIONSETUP;
+ _memofiles.clear();
+ _memoMetadataFile = _baseDirectory + QDir::separator() + CSL1(".ids");
+ _categoryMetadataFile = _baseDirectory + QDir::separator() + CSL1(".categories");
+ _memofiles.setAutoDelete(true);
+
+ _ready = ensureDirectoryReady();
+
+ _metadataLoaded = loadFromMetadata();
+}
+
+Memofiles::~Memofiles()
+{
+ FUNCTIONSETUP;
+}
+
+void Memofiles::load (bool loadAll)
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname
+ << ": now looking at all memofiles in your directory." << endl;
+
+ // now go through each of our known categories and look in each directory
+ // for that category for memo files
+ MemoCategoryMap::ConstIterator it;
+ int counter = -1;
+
+ for ( it = _categories.begin(); it != _categories.end(); ++it ) {
+ int category = it.key();
+ QString categoryName = it.data();
+ QString categoryDirname = _baseDirectory + QDir::separator() + categoryName;
+
+ QDir dir = QDir(categoryDirname);
+ if (! dir.exists() ) {
+ DEBUGKPILOT << fname
+ << ": category directory: [" << categoryDirname
+ << "] doesn't exist. skipping." << endl;
+ continue;
+ }
+
+
+ QStringList entries = dir.entryList(QDir::Files);
+ QString file;
+ for(QStringList::Iterator it = entries.begin(); it != entries.end(); ++it) {
+ file = *it;
+ QFileInfo info(dir, file);
+
+ if(info.isFile() && info.isReadable()) {
+// DEBUGKPILOT << fname
+// << ": checking category: [" << categoryName
+// << "], file: [" << file << "]." << endl;
+ Memofile * memofile = find(categoryName, file);
+ if (NULL == memofile) {
+ memofile = new Memofile(category, categoryName, file, _baseDirectory);
+ memofile->setModified(true);
+ _memofiles.append(memofile);
+ DEBUGKPILOT << fname
+ << ": looks like we didn't know about this one until now. "
+ << "created new memofile for category: ["
+ << categoryName << "], file: [" << file << "]." << endl;
+
+ }
+
+ counter++;
+
+ // okay, we should have a memofile for this file now. see if we need
+ // to load its text...
+ if (memofile->isModified() || loadAll) {
+ DEBUGKPILOT << fname
+ << ": now loading text for: [" << info.filePath() << "]." << endl;
+ memofile->load();
+ }
+ } else {
+ DEBUGKPILOT << fname
+ << ": couldn't read file: [" << info.filePath() << "]. skipping it." << endl;
+
+ }
+ } // end of iterating through files in this directory
+
+ } // end of iterating through our categories/directories
+
+ DEBUGKPILOT << fname
+ << ": looked at: [" << counter << "] files from your directories." << endl;
+
+
+ // okay, now we've loaded everything from our directories. make one last
+ // pass through our loaded memofiles and see if we need to mark any of them
+ // as deleted (i.e. we created a memofile object from our metadata, but
+ // the file is now gone, so it's deleted.
+ Memofile * memofile;
+
+ for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) {
+ if (! memofile->fileExists()) {
+ memofile->setDeleted( true );
+ }
+ }
+}
+
+/**
+* Make sure that our directory is ready to synchronize with our
+* Palm's database. This means we need to make sure that the directory
+* that our user has specified for storing his/her memos exists, as well
+* as a directory inside that directory for each of his/her memo categories.
+*/
+bool Memofiles::ensureDirectoryReady()
+{
+ FUNCTIONSETUP;
+
+ if (!checkDirectory(_baseDirectory))
+ return false;
+
+ int failures = 0;
+ // now make sure that a directory for each category exists.
+ QString _category_name;
+ QString dir;
+
+ MemoCategoryMap::Iterator it;
+ for ( it = _categories.begin(); it != _categories.end(); ++it ) {
+ _category_name = it.data();
+ dir = _baseDirectory + QDir::separator() + _category_name;
+
+ DEBUGKPILOT << fname
+ << ": checking directory: [" << dir << "]" << endl;
+
+ if (!checkDirectory(dir))
+ failures++;
+ }
+
+ return failures == 0;
+}
+
+bool Memofiles::checkDirectory(QString & dir)
+{
+ FUNCTIONSETUP;
+ // make sure that the directory we're asked to write to exists
+ QDir d(dir);
+ QFileInfo fid( dir );
+
+ if ( ! fid.isDir() ) {
+
+ DEBUGKPILOT << fname
+ << ": directory: [" << dir
+ << "] doesn't exist. creating...."
+ << endl;
+
+ if (!d.mkdir(dir)) {
+
+ DEBUGKPILOT << fname
+ << ": could not create directory: [" << dir
+ << "]. this won't end well." << endl;
+ return false;
+ } else {
+ DEBUGKPILOT << fname
+ << ": directory created: ["
+ << dir << "]." << endl;
+
+ }
+ } else {
+ DEBUGKPILOT << fname
+ << ": directory already existed: ["
+ << dir << "]." << endl;
+
+ }
+
+ return true;
+
+}
+
+void Memofiles::eraseLocalMemos ()
+{
+ FUNCTIONSETUP;
+
+ MemoCategoryMap::Iterator it;
+ for ( it = _categories.begin(); it != _categories.end(); ++it ) {
+ QString dir = _baseDirectory + QDir::separator() + it.data();
+
+ if (!folderRemove(QDir(dir))) {
+ DEBUGKPILOT << fname
+ << ": couldn't erase all local memos from: ["
+ << dir << "]." << endl;
+ }
+ }
+ QDir d(_baseDirectory);
+ d.remove(_memoMetadataFile);
+
+ ensureDirectoryReady();
+
+ _memofiles.clear();
+}
+
+void Memofiles::setPilotMemos (QPtrList<PilotMemo> & memos)
+{
+ FUNCTIONSETUP;
+
+ PilotMemo * memo;
+
+ _memofiles.clear();
+
+ for ( memo = memos.first(); memo; memo = memos.next() ) {
+ addModifiedMemo(memo);
+ }
+
+ DEBUGKPILOT << fname
+ << ": set: ["
+ << _memofiles.count() << "] from Palm to local." << endl;
+
+}
+
+bool Memofiles::loadFromMetadata ()
+{
+ FUNCTIONSETUP;
+
+ _memofiles.clear();
+
+ QFile f( _memoMetadataFile );
+ if ( !f.open( IO_ReadOnly ) ) {
+ DEBUGKPILOT << fname
+ << ": ooh, bad. couldn't open your memo-id file for reading."
+ << endl;
+ return false;
+ }
+
+ QTextStream t( &f );
+ Memofile * memofile;
+
+ while ( !t.atEnd() ) {
+ QString data = t.readLine();
+ int errors = 0;
+ bool ok;
+
+ QStringList fields = QStringList::split( FIELD_SEP, data );
+ if ( fields.count() >= 4 ) {
+ int id = fields[0].toInt( &ok );
+ if ( !ok )
+ errors++;
+ int category = fields[1].toInt( &ok );
+ if ( !ok )
+ errors++;
+ uint lastModified = fields[2].toInt( &ok );
+ if ( !ok )
+ errors++;
+ uint size = fields[3].toInt( &ok );
+ if ( !ok )
+ errors++;
+ QString filename = fields[4];
+ if ( filename.isEmpty() )
+ errors++;
+
+ if (errors <= 0) {
+ memofile = new Memofile(id, category, lastModified, size,
+ _categories[category], filename, _baseDirectory);
+ _memofiles.append(memofile);
+ // DEBUGKPILOT << fname
+ // << ": created memofile from metadata. id: [" << id
+ // << "], category: ["
+ // << _categories[category] << "], filename: [" << filename << "]."
+ // << endl;
+ }
+ } else {
+ errors++;
+ }
+
+ if (errors > 0) {
+ DEBUGKPILOT << fname
+ << ": error: couldn't understand this line: [" << data << "]."
+ << endl;
+ }
+ }
+
+ DEBUGKPILOT << fname
+ << ": loaded: [" << _memofiles.count() << "] memofiles."
+ << endl;
+
+ f.close();
+
+ return true;
+}
+
+Memofile * Memofiles::find (recordid_t id)
+{
+
+ Memofile * memofile;
+
+ for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) {
+ if ( memofile->id() == id) {
+ return memofile;
+ }
+ }
+
+ return NULL;
+
+}
+
+Memofile * Memofiles::find (const QString & category, const QString & filename)
+{
+
+ Memofile * memofile;
+
+ for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) {
+ if ( memofile->getCategoryName() == category &&
+ memofile->getFilename() == filename ) {
+ return memofile;
+ }
+ }
+
+ return NULL;
+
+}
+
+void Memofiles::deleteMemo(PilotMemo * memo)
+{
+ FUNCTIONSETUP;
+ if (! memo->isDeleted())
+ return;
+
+ Memofile * memofile = find(memo->id());
+ if (memofile) {
+ memofile->deleteFile();
+ _memofiles.remove(memofile);
+ _cudCounter.deleted();
+ }
+}
+
+
+void Memofiles::addModifiedMemo (PilotMemo * memo)
+{
+ FUNCTIONSETUP;
+
+ if (memo->isDeleted()) {
+ deleteMemo(memo);
+ return;
+ }
+
+ QString debug = CSL1(": adding a PilotMemo. id: [")
+ + QString::number(memo->id()) + CSL1("], title: [")
+ + memo->getTitle() + CSL1("]. ");
+
+ Memofile * memofile = find(memo->id());
+
+ if (NULL == memofile) {
+ _cudCounter.created();
+ debug += CSL1(" new from pilot.");
+ } else {
+ // we have found a local memofile that was modified on the palm. for the time
+ // being (until someone complains, etc.), we will always overwrite changes to
+ // the local filesystem with changes to the palm (palm overrides local). at
+ // some point in the future, we should probably honor a user preference for
+ // this...
+ _cudCounter.updated();
+ _memofiles.remove(memofile);
+ debug += CSL1(" modified from pilot.");
+ }
+
+ DEBUGKPILOT << fname
+ << debug << endl;
+
+ memofile = new Memofile(memo, _categories[memo->category()], filename(memo), _baseDirectory);
+ memofile->setModifiedByPalm(true);
+ _memofiles.append(memofile);
+
+}
+
+QPtrList<Memofile> Memofiles::getModified ()
+{
+ FUNCTIONSETUP;
+
+ QPtrList<Memofile> modList;
+ modList.clear();
+
+ Memofile * memofile;
+
+ for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) {
+ if ( memofile->isModified() && ! memofile->isModifiedByPalm() ) {
+ modList.append(memofile);
+ }
+ }
+
+ DEBUGKPILOT << fname
+ << ": found: [" << modList.count() << "] memofiles modified on filesystem." << endl;
+
+ return modList;
+}
+
+void Memofiles::save()
+{
+ FUNCTIONSETUP;
+
+ saveCategoryMetadata();
+ saveMemos();
+ // this needs to be done last, because saveMemos() might change
+ // attributes of the Memofiles
+ saveMemoMetadata();
+
+}
+
+bool Memofiles::saveMemoMetadata()
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname
+ << ": saving memo metadata to file: ["
+ << _memoMetadataFile << "]" << endl;
+
+ QFile f( _memoMetadataFile );
+ QTextStream stream(&f);
+
+ if( !f.open(IO_WriteOnly) ) {
+ DEBUGKPILOT << fname
+ << ": ooh, bad. couldn't open your memo-id file for writing."
+ << endl;
+ return false;
+ }
+
+ Memofile * memofile;
+
+ // each line looks like this, but FIELD_SEP is the separator instead of ","
+ // id,category,lastModifiedTime,filesize,filename
+ for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) {
+ // don't save deleted memos to our id file
+ if (! memofile->isDeleted()) {
+ stream << memofile->id() << FIELD_SEP
+ << memofile->category() << FIELD_SEP
+ << memofile->lastModified() << FIELD_SEP
+ << memofile->size() << FIELD_SEP
+ << memofile->filename()
+ << endl;
+ }
+ }
+
+ f.close();
+
+ return true;
+
+}
+
+MemoCategoryMap Memofiles::readCategoryMetadata()
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname
+ << ": reading categories from file: ["
+ << _categoryMetadataFile << "]" << endl;
+
+ MemoCategoryMap map;
+ map.clear();
+
+ QFile f( _categoryMetadataFile );
+ QTextStream stream(&f);
+
+ if( !f.open(IO_ReadOnly) ) {
+ DEBUGKPILOT << fname
+ << ": ooh, bad. couldn't open your categories file for reading."
+ << endl;
+ return map;
+ }
+
+
+ while ( !stream.atEnd() ) {
+ QString data = stream.readLine();
+ int errors = 0;
+ bool ok;
+
+ QStringList fields = QStringList::split( FIELD_SEP, data );
+ if ( fields.count() >= 2 ) {
+ int id = fields[0].toInt( &ok );
+ if ( !ok )
+ errors++;
+ QString categoryName = fields[1];
+ if ( categoryName.isEmpty() )
+ errors++;
+
+ if (errors <= 0) {
+ map[id] = categoryName;
+ }
+ } else {
+ errors++;
+ }
+
+ if (errors > 0) {
+ DEBUGKPILOT << fname
+ << ": error: couldn't understand this line: [" << data << "]."
+ << endl;
+ }
+ }
+
+ DEBUGKPILOT << fname
+ << ": loaded: [" << map.count() << "] categories."
+ << endl;
+
+ f.close();
+
+ return map;
+}
+
+bool Memofiles::saveCategoryMetadata()
+{
+ FUNCTIONSETUP;
+
+
+ DEBUGKPILOT << fname
+ << ": saving categories to file: ["
+ << _categoryMetadataFile << "]" << endl;
+
+ QFile f( _categoryMetadataFile );
+ QTextStream stream(&f);
+
+ if( !f.open(IO_WriteOnly) ) {
+ DEBUGKPILOT << fname
+ << ": ooh, bad. couldn't open your categories file for writing."
+ << endl;
+ return false;
+ }
+
+ MemoCategoryMap::Iterator it;
+ for ( it = _categories.begin(); it != _categories.end(); ++it ) {
+ stream << it.key()
+ << FIELD_SEP
+ << it.data()
+ << endl;
+ }
+
+ f.close();
+
+ return true;
+}
+
+bool Memofiles::saveMemos()
+{
+ FUNCTIONSETUP;
+
+ Memofile * memofile;
+ bool result = true;
+
+ for ( memofile = _memofiles.first(); memofile; memofile = _memofiles.next() ) {
+ if (memofile->isDeleted()) {
+ _memofiles.remove(memofile);
+ } else {
+ result = memofile->save();
+ // Fix prompted by Bug #103922
+ // if we weren't able to save the file, then remove it from the list.
+ // if we don't do this, the next sync will think that the user deliberately
+ // deleted the memofile and will then delete it from the Pilot.
+ // TODO -- at some point, we should probably tell the user that this
+ // did not work, but that will require a String change.
+ // Also, this is a partial fix since at this point
+ // this memo will never make its way onto the PC, but at least
+ // we won't delete it from the Pilot erroneously either. *sigh*
+ if (!result) {
+ DEBUGKPILOT << fname
+ << ": unable to save memofile: ["
+ << memofile->filename()
+ << "], now removing it from the metadata list."
+ << endl;
+ _memofiles.remove(memofile);
+ }
+ }
+ }
+ return true;
+}
+
+bool Memofiles::isFirstSync()
+{
+ FUNCTIONSETUP;
+ bool metadataExists = QFile::exists(_memoMetadataFile) &&
+ QFile::exists(_categoryMetadataFile);
+
+ bool valid = metadataExists && _metadataLoaded;
+
+ DEBUGKPILOT << fname
+ << ": local metadata exists: [" << metadataExists
+ << "], metadata loaded: [" << _metadataLoaded
+ << "], returning: [" << ! valid << "]" << endl;
+ return ! valid;
+}
+
+
+
+bool Memofiles::folderRemove(const QDir &_d)
+{
+ FUNCTIONSETUP;
+
+ QDir d = _d;
+
+ QStringList entries = d.entryList();
+ for(QStringList::Iterator it = entries.begin(); it != entries.end(); ++it) {
+ if(*it == CSL1(".") || *it == CSL1(".."))
+ continue;
+ QFileInfo info(d, *it);
+ if(info.isDir()) {
+ if(!folderRemove(QDir(info.filePath())))
+ return FALSE;
+ } else {
+ DEBUGKPILOT << fname
+ << ": deleting file: [" << info.filePath() << "]" << endl;
+ d.remove(info.filePath());
+ }
+ }
+ QString name = d.dirName();
+ if(!d.cdUp())
+ return FALSE;
+ DEBUGKPILOT << fname
+ << ": removing folder: [" << name << "]" << endl;
+ d.rmdir(name);
+
+ return TRUE;
+}
+
+QString Memofiles::filename(PilotMemo * memo)
+{
+ FUNCTIONSETUP;
+
+ QString filename = memo->getTitle();
+
+ if (filename.isEmpty()) {
+ QString text = memo->text();
+ int i = text.find(CSL1("\n"));
+ if (i > 1) {
+ filename = text.left(i);
+ }
+ if (filename.isEmpty()) {
+ filename = CSL1("empty");
+ }
+ }
+
+ filename = sanitizeName(filename);
+
+ QString category = _categories[memo->category()];
+
+ Memofile * memofile = find(category, filename);
+
+ // if we couldn't find a memofile with this filename, or if the
+ // memofile that is found is the same as the memo that we're looking
+ // at, then use the filename
+ if (NULL == memofile || memofile == memo) {
+ return filename;
+ }
+
+ int uniq = 2;
+ QString newfilename;
+
+ // try to find a good filename, but only do this 20 times at the most.
+ // if our user has 20 memos with the same filename, he/she is asking
+ // for trouble.
+ while (NULL != memofile && uniq <=20) {
+ newfilename = QString(filename + CSL1(".") + QString::number(uniq++) );
+ memofile = find(category, newfilename);
+ }
+
+ return newfilename;
+}
+
+QString Memofiles::sanitizeName(QString name)
+{
+ QString clean = name;
+ // safety net. we can't save a
+ // filesystem separator as part of a filename, now can we?
+ clean.replace('/', CSL1("-"));
+ return clean;
+}
+
diff --git a/kpilot/conduits/memofileconduit/memofiles.h b/kpilot/conduits/memofileconduit/memofiles.h
new file mode 100644
index 000000000..ec0497d5b
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/memofiles.h
@@ -0,0 +1,96 @@
+#ifndef _MEMOFILE_MEMOFILES_H
+#define _MEMOFILE_MEMOFILES_H
+/* memofiles.h KPilot
+**
+** Copyright (C) 2004-2007 by Jason 'vanRijn' Kasper
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "plugin.h"
+#include <qmap.h>
+
+#include "memofile.h"
+
+typedef QMap<int, QString> MemoCategoryMap;
+
+class Memofile;
+
+class Memofiles {
+
+public:
+
+ Memofiles (MemoCategoryMap & categories, PilotMemoInfo &appInfo,
+ QString & baseDirectory, CUDCounter &fCtrHH);
+ ~Memofiles();
+
+ void load(bool loadAll);
+ void save();
+ void eraseLocalMemos();
+ void setPilotMemos (QPtrList<PilotMemo> & memos);
+ void addModifiedMemo (PilotMemo * memo);
+ void deleteMemo (PilotMemo * memo);
+
+ bool isFirstSync();
+ bool isReady() { return _ready; };
+
+ QPtrList<Memofile> getModified();
+ QPtrList<Memofile> getAll() { return _memofiles; } ;
+ Memofile * find (const QString & category, const QString & filename);
+ Memofile * find (recordid_t id);
+
+ MemoCategoryMap readCategoryMetadata();
+ void setCategories(MemoCategoryMap map) { _categories = map; } ;
+
+ static QString FIELD_SEP;
+ static QString sanitizeName(QString name);
+
+ int count() { return _memofiles.count(); }
+
+private:
+
+ MemoCategoryMap _categories;
+ PilotMemoInfo &_memoAppInfo;
+ QString & _baseDirectory;
+ CUDCounter &_cudCounter;
+ QPtrList<Memofile> _memofiles;
+
+ bool loadFromMetadata();
+ bool ensureDirectoryReady();
+ bool checkDirectory(QString & dir);
+ bool saveMemoMetadata();
+ bool saveCategoryMetadata();
+ bool saveMemos();
+ bool folderRemove(const QDir & dir);
+
+ QString filename(PilotMemo * memo);
+
+
+ QString _categoryMetadataFile;
+ QString _memoMetadataFile;
+
+ bool _metadataLoaded;
+ bool _ready;
+
+};
+#endif //MEMOFILES_H
+
diff --git a/kpilot/conduits/memofileconduit/setup_base.ui b/kpilot/conduits/memofileconduit/setup_base.ui
new file mode 100644
index 000000000..215c18057
--- /dev/null
+++ b/kpilot/conduits/memofileconduit/setup_base.ui
@@ -0,0 +1,143 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>MemofileWidget</class>
+<comment>A tabWidget for configuring
+the Memofile-conduit settings.</comment>
+<author>Jason 'vanRijn' Kasper</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Form1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>342</width>
+ <height>412</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>570</width>
+ <height>270</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>Memofile Conduit Options</string>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>Widget2</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="2" column="2">
+ <property name="name">
+ <cstring>Spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>180</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Sync private records:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Memos directory:</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="0" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fDirectory</cstring>
+ </property>
+ <property name="mode">
+ <number>18</number>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Select the directory you want to store your PDA's memos in</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="1">
+ <property name="name">
+ <cstring>fSyncPrivate</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>tabWidget</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includes>
+ <include location="global" impldecl="in implementation">kurlrequester.h</include>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+ <include location="global" impldecl="in implementation">kpushbutton.h</include>
+</includes>
+</UI>
diff --git a/kpilot/conduits/notepadconduit/CMakeLists.txt b/kpilot/conduits/notepadconduit/CMakeLists.txt
new file mode 100644
index 000000000..90e202d60
--- /dev/null
+++ b/kpilot/conduits/notepadconduit/CMakeLists.txt
@@ -0,0 +1,38 @@
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+set(conduit_notepad_SRCS
+ notepad-factory.cc
+ notepad-conduit.cc
+)
+
+set(conduit_notepad_UIS
+ notepad-setup.ui
+)
+
+set(conduit_notepad_KCFGS
+ notepadconduit.kcfgc
+)
+
+kde3_add_kcfg_files(conduit_notepad_SRCS ${conduit_notepad_KCFGS})
+kde3_add_ui_files(conduit_notepad_SRCS ${conduit_notepad_UIS})
+kde3_automoc(${conduit_notepad_SRCS})
+add_library(conduit_notepad SHARED ${conduit_notepad_SRCS})
+
+set_target_properties(
+ conduit_notepad PROPERTIES LOCATION ${KDE3_PLUGIN_INSTALL_DIR}
+ INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib
+ PREFIX ""
+)
+
+kde3_install_libtool_file(conduit_notepad)
+
+install(
+ TARGETS conduit_notepad
+ LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR}
+)
+
+install(
+ FILES notepad-conduit.desktop DESTINATION ${KDE3_SERVICES_DIR}
+)
diff --git a/kpilot/conduits/notepadconduit/Makefile.am b/kpilot/conduits/notepadconduit/Makefile.am
new file mode 100644
index 000000000..d50e4fd48
--- /dev/null
+++ b/kpilot/conduits/notepadconduit/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES= $(PISOCK_INCLUDE) -I$(top_srcdir)/kpilot/lib $(all_includes)
+
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = notepad-conduit.desktop
+
+kde_module_LTLIBRARIES = conduit_notepad.la
+
+conduit_notepad_la_SOURCES = notepadconduit.kcfgc notepad-setup.ui \
+ notepad-conduit.cc notepad-factory.cc
+conduit_notepad_la_LDFLAGS= -module $(KDE_PLUGIN) $(all_libraries)
+conduit_notepad_la_LIBADD= ../../lib/libkpilot.la $(LIB_KDEUI) $(LIB_KIO)
+
diff --git a/kpilot/conduits/notepadconduit/notepad-conduit.cc b/kpilot/conduits/notepadconduit/notepad-conduit.cc
new file mode 100644
index 000000000..763f3acd0
--- /dev/null
+++ b/kpilot/conduits/notepadconduit/notepad-conduit.cc
@@ -0,0 +1,265 @@
+/* KPilot
+**
+** Copyright (C) 2004 by Adriaan de Groot, Joern Ahrens
+**
+** The code for NotepadActionThread::unpackNotePad was taken from
+** Angus Ainslies read-notepad.c, which is part of pilot-link.
+** NotepadActionThread::saveImage is also based on read-notepad.c.
+**
+** This file is part of the Notepad conduit, a conduit for KPilot that
+** stores the notepad drawings to files.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+#include "pilotUser.h"
+#include "pilotSerialDatabase.h"
+
+#include "notepad-conduit.h" // The Conduit action
+#include "notepadconduit.h" // The settings class
+
+#include <pi-notepad.h>
+
+#include <qthread.h>
+#include <qapplication.h>
+#include <qvaluelist.h>
+#include <qimage.h>
+#include <qdir.h>
+#include <qcstring.h>
+
+extern "C"
+{
+unsigned long version_conduit_notepad = Pilot::PLUGIN_API;
+}
+
+NotepadConduit::NotepadConduit(KPilotLink *d, const char *n,
+ const QStringList &args) : ConduitAction(d, n, args)
+{
+ FUNCTIONSETUP;
+ fConduitName=i18n("Notepad");
+ thread = 0L;
+
+}
+
+NotepadConduit::~NotepadConduit()
+{
+ FUNCTIONSETUP;
+}
+
+/* virtual */ bool NotepadConduit::exec()
+{
+ FUNCTIONSETUP;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": In exec() @" << (unsigned long) this << endl;
+#endif
+
+ QDir dir(NotepadConduitSettings::outputDirectory());
+ if(!dir.exists() && !dir.mkdir(dir.path())) {
+ emit logError(i18n("Unable to open %1").arg(dir.path()));
+ delayDone();
+ return false;
+ }
+ else {
+ thread = new NotepadActionThread(this, deviceLink());
+ thread->start();
+ // tickle is disabled due to crashs during sync
+ // -> PADP TX "unexpected package"
+// startTickle();
+ }
+
+ return true;
+}
+
+bool NotepadConduit::event(QEvent *e)
+{
+ FUNCTIONSETUP;
+
+ if(e->type() == QEvent::User) {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Notepad thread done." << endl;
+#endif
+// stopTickle();
+ delayDone();
+ if(thread->getFailed())
+ logError(i18n("1 notepad could not be saved", "%n notepads could not be saved", thread->getFailed()));
+ logMessage(i18n("1 notepad saved", "%n notepads saved", thread->getSaved()));
+ delete thread;
+ return true;
+ }
+ else
+ return ConduitAction::event(e);
+}
+
+//-----------------------------------------------------------------------------
+// NotepadActionThread
+//-----------------------------------------------------------------------------
+
+NotepadActionThread::NotepadActionThread(QObject *parent, KPilotLink *link) :
+ fParent(parent), fLink(link), notSaved(0), saved(0)
+{
+ FUNCTIONSETUP;
+}
+
+void NotepadActionThread::run()
+{
+ FUNCTIONSETUP;
+
+ PilotDatabase *db = fLink->database( CSL1("npadDB") );
+
+ int n = db->recordCount();
+
+ if ( n > 0 )
+ {
+ QValueList<recordid_t> vl = db->idList();
+ QValueList<recordid_t>::iterator it;
+ struct NotePad a;
+ for ( it = vl.begin(); it != vl.end(); ++it )
+ {
+ PilotRecord *pr = db->readRecordById(*it);
+ if(pr)
+ {
+ unpack_NotePad(&a, (unsigned char*)pr->data(), pr->size());
+ saveImage(&a);
+ free_NotePad(&a);
+ }
+ }
+ }
+ KPILOT_DELETE(db);
+ QApplication::postEvent(fParent, new QEvent(QEvent::User));
+}
+
+static void saveImageFromBITS(QImage &image, struct NotePad *n, unsigned int width)
+{
+ FUNCTIONSETUP;
+ image.setColor(0, qRgb(0xaa, 0xc1 ,0x91));
+ image.setColor(1, qRgb(0x30, 0x36, 0x29));
+
+ int x = 0;
+ int y = 0;
+ int pos = 0;
+ for(unsigned int i=0; i<n->body.dataLen/2; ++i)
+ {
+ for(int j=0; j<n->data[i].repeat; ++j)
+ {
+ for(int k=0; k<8; ++k)
+ {
+ y = pos / width;
+ x = pos % width ;
+
+ image.setPixel( x, y,
+ (n->data[i].data & 1<<(7-k)) ? 1 : 0 );
+ ++pos;
+ }
+ }
+ }
+}
+
+static void saveImageFromUNCOMPRESSED(QImage &image, struct NotePad *n, unsigned int width)
+{
+ FUNCTIONSETUP;
+
+ image.setColor(0, qRgb(0xaa, 0xc1 ,0x91));
+ image.setColor(1, qRgb(0x30, 0x36, 0x29));
+
+ unsigned int pos = 0;
+ unsigned int x,y;
+
+ for (unsigned int i=0; i<n->body.dataLen / 2; ++i)
+ {
+ for (unsigned int k=0; k<8; ++k)
+ {
+ y = pos / width;
+ x = pos % width ;
+
+ image.setPixel( x, y,
+ (n->data[i].repeat & 1<<(7-k)) ? 1 : 0 );
+ ++pos;
+ }
+
+ for (unsigned int k=0; k<8; ++k)
+ {
+ y = pos / width;
+ x = pos % width ;
+
+ image.setPixel( x, y,
+ (n->data[i].data & 1<<(7-k)) ? 1 : 0 );
+ ++pos;
+ }
+ }
+}
+
+void NotepadActionThread::saveImage(struct NotePad *n)
+{
+ FUNCTIONSETUP;
+
+ // Width needs adjusting, based on whether it's low res (+8)
+ // or a hi-res notepad image.
+ int width = n->body.width + ( n->body.width > 160 ? 16 : 8 );
+ int height = n->body.height;
+
+
+ QImage image(width, height, 8, 2);
+
+ switch (n->body.dataType)
+ {
+ case NOTEPAD_DATA_BITS :
+ saveImageFromBITS( image,n,width );
+ break;
+ case NOTEPAD_DATA_UNCOMPRESSED :
+ saveImageFromUNCOMPRESSED( image,n,width );
+ break;
+ case NOTEPAD_DATA_PNG :
+ image.loadFromData((uchar*)(n->data), n->body.dataLen);
+ break;
+ default :
+ // Unknown data type
+ WARNINGKPILOT << "Unknown data type: " << n->body.dataType << endl;
+ return;
+
+ // TODO: Post a warning to the UI
+ }
+
+ QString filename(n->name);
+ if(filename.isEmpty())
+ {
+ filename.sprintf("%4d-%02d-%02d_%02d-%02d-%02d",
+ n->changeDate.year,
+ n->changeDate.month,
+ n->changeDate.day,
+ n->changeDate.hour,
+ n->changeDate.min,
+ n->changeDate.sec);
+ }
+ QString imgname = QString("%1/%2.png").arg(NotepadConduitSettings::outputDirectory()).arg(filename);
+
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Notepad " << imgname << endl;
+#endif
+ if(!image.save(imgname, "PNG", -1))
+ ++notSaved;
+ else
+ ++saved;
+}
+
diff --git a/kpilot/conduits/notepadconduit/notepad-conduit.desktop b/kpilot/conduits/notepadconduit/notepad-conduit.desktop
new file mode 100644
index 000000000..4aa10dbee
--- /dev/null
+++ b/kpilot/conduits/notepadconduit/notepad-conduit.desktop
@@ -0,0 +1,65 @@
+[Desktop Entry]
+Type=Service
+Name=NotePad
+Name[cs]=Poznámkový blok
+Name[da]=Notesblok
+Name[de]=Notizen
+Name[es]=Bloc de notas
+Name[fi]=Muistio
+Name[fr]=Notes
+Name[gl]=Caderno de Notas
+Name[hu]=Notepad
+Name[nb]=NotisBlokk
+Name[ne]=नोटप्याड
+Name[nn]=NotisBlokk
+Name[pl]=Notatnik
+Name[sv]=Anteckningar
+Name[ta]=நோட்பேட்
+Name[tg]=Эзоҳот
+Name[zh_CN]=记事本
+Comment=This conduit backs up NotePad drawings to a local folder.
+Comment[af]=Hierdie pad sinkroniseer NotePad tekeninge na 'n plaaslike gids.
+Comment[bg]=Създаване на архивни копия на изображенията създадени с NotePad в локална директория.
+Comment[ca]=Aquest conducte copia els dibuixos NotePad a una carpeta local.
+Comment[cs]=Toto propojení synchronizuje záznamy v PDA s lokálním adresářem.
+Comment[da]=Denne kanal sikkerhedskopierer NotePad's tegninger til en lokal mappe.
+Comment[de]=Diese Erweiterung (Conduit) sichert NotePad-Zeichnungen in einen lokalen Ordner.
+Comment[el]=Αυτός ο σύνδεσμος δημιουργεί αντίγραφα ασφαλείας σχεδίων του NotePad σε έναν τοπικό φάκελο.
+Comment[es]=Este conducto copia los dibujos del bloc de notas en una carpeta local.
+Comment[et]=See kanal teeb NotePadi joonistustest varukoopia kohalikku kataloogi.
+Comment[eu]=Kanal honek Ohar-blokaren marrazkiak karpeta lokal batera gordetzen ditu.
+Comment[fa]=این لوله، ترسیمهای NotePad را در پوشه‌ای محلی پشتیبانی می‌کند.
+Comment[fi]=Tämä yhdyskäytävä tekee varmuuskopion NotePad -piirroksista paikalliseen kansioon.
+Comment[fr]=Ce conduit enregistre les dessins (Notes) dans un dossier local.
+Comment[fy]=Dit conduit makket in reservekopy fan de notysje fan de notysje-oantekenings nei in lokale map.
+Comment[gl]=Este conducto pon de volta os debuxos do NotePad a un cartafol local.
+Comment[hu]=Bővítőmodul NotePad-rajzok helyi könyvtárba való lementéséhez.
+Comment[is]=Þessi rás afritar NotePad teikningar í staðbundna möppu.
+Comment[it]=Questo conduit archivia i disegni NotePad in una cartella locale.
+Comment[ja]=このコンジットは NotePad の絵をローカルのフォルダにバックアップします。
+Comment[ka]=ეს არხი ლოკალურ საქაღალდეში ინახავს NotePad-ის სარეზერვო მონახაზებს
+Comment[kk]=NotePad файлдарының сақтық көшірмелерін жергілікті қапшықта жасау арнасы.
+Comment[km]=បំពង់​នេះ​អាច​បម្រុង​ទុក​គំនូរ NotePad ទៅ​ថត​មូលដ្ឋាន ។
+Comment[lt]=Šis kanalas padaro NotePad piešinių atsargines kopijas į vietinį aplanką.
+Comment[ms]=Saluran ini menyandarkan lukisan NotePad ke folder setempat.
+Comment[nb]=Denne kanalen tar sikkerhetskopi av NotePad tegninger til en lokal mappe.
+Comment[nds]=Sekert NotePad-Teken binnen en lokaal Orner.
+Comment[ne]=यो कन्ड्युटले स्थानीय फाइलमा नोटप्याड रेखाचित्र ब्याकअप गर्छ ।
+Comment[nl]=Dit conduit maakt een backup van de notitie-aantekeningen naar een lokale map.
+Comment[pl]=Ten łącznik robi kopię zapasową rysunków z Notatnika do lokalnego katalogu.
+Comment[pt]=Esta conduta salvaguarda desenhos NotePad para uma pasta local.
+Comment[pt_BR]=Este conduíte faz backup de desenhos do NotePad em uma pasta local.
+Comment[ru]=Канал создания резервных копий примечаний в локальной папке.
+Comment[sk]=Táto spojka zálohuje poznámky NotePad do lokálneho priečinku.
+Comment[sl]=Ta veznik arhivira risanja z NotePadom v krajevno mapo.
+Comment[sr]=Овај провод прави резервне копије NotePad цртежа у локалну фасциклу.
+Comment[sr@Latn]=Ovaj provod pravi rezervne kopije NotePad crteža u lokalnu fasciklu.
+Comment[sv]=Den här kanalen säkerhetskopierar ritade anteckningar i en lokal katalog.
+Comment[ta]=இது நோட்பேடின் வரைபடங்களை உள்ளடைவுக்கு சேமிக்கிறது
+Comment[tr]=Bu bileşen, NotePad çizimlerini yerel bir dosyaya aktarır veya alır.
+Comment[uk]=Цей акведук створює резервну копію нотаток у локальній теці.
+Comment[zh_CN]=此管道将记事本的绘图保存到本地文件夹。
+Comment[zh_TW]=此軟體備份 NotePad 畫的圖到本地端資料夾。
+Implemented=file
+ServiceTypes=KPilotConduit
+X-KDE-Library=conduit_notepad
diff --git a/kpilot/conduits/notepadconduit/notepad-conduit.h b/kpilot/conduits/notepadconduit/notepad-conduit.h
new file mode 100644
index 000000000..5ba915e31
--- /dev/null
+++ b/kpilot/conduits/notepadconduit/notepad-conduit.h
@@ -0,0 +1,94 @@
+#ifndef _KPILOT_NOTEPAD_CONDUIT_H
+#define _KPILOT_NOTEPAD_CONDUIT_H
+/* notepad-conduit.h KPilot
+**
+** Copyright (C) 2004 by Adriaan de Groot, Joern Ahrens, Angus Ainslie
+**
+** The code for NotepadActionThread::unpackNotePad was taken from
+** Angus Ainslies read-notepad.c, which is part of pilot-link.
+** NotepadActionThread::saveImage is also based on read-notepad.c.
+**
+** This file is part of the Notepad conduit, a conduit for KPilot that
+** store the notepad drawings to files.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "plugin.h"
+
+#include <qthread.h>
+struct NotePad;
+class NotepadActionThread;
+
+class NotepadConduit : public ConduitAction
+{
+public:
+ NotepadConduit(KPilotLink *,
+ const char *name=0L,
+ const QStringList &args = QStringList());
+ virtual ~NotepadConduit();
+ virtual bool event(QEvent *e);
+
+protected:
+ virtual bool exec(); // From ConduitAction
+
+private:
+ NotepadActionThread *thread;
+};
+
+
+/**
+ * This class saves the notepads to disk
+ */
+class NotepadActionThread : public QThread
+{
+public:
+ NotepadActionThread(QObject *parent, KPilotLink *link);
+
+ virtual void run();
+ int getFailed() { return notSaved; }
+ int getSaved() { return saved; }
+
+private:
+ QObject *fParent;
+ KPilotLink *fLink;
+
+ /**
+ * counts how many notepads couldn't be saved during the sync
+ */
+ int notSaved;
+ /**
+ * counts how many files a saved during the sync
+ */
+ int saved;
+
+ int unpackNotePad(struct NotePad *a, unsigned char *buffer, int len);
+
+ /**
+ * Saves a single NotePad structure to disk, using the name in
+ * the Note @p n, or if no name is specified, using the
+ * timestamp in the note.
+ */
+ void saveImage(struct NotePad *n);
+};
+
+#endif
diff --git a/kpilot/conduits/notepadconduit/notepad-factory.cc b/kpilot/conduits/notepadconduit/notepad-factory.cc
new file mode 100644
index 000000000..f934a2cb1
--- /dev/null
+++ b/kpilot/conduits/notepadconduit/notepad-factory.cc
@@ -0,0 +1,124 @@
+/* KPilot
+**
+** Copyright (C) 2004 by Adriaan de Groot, Joern Ahrens
+**
+** This file defines the factory for the notepad-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <kconfig.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+#include <kurlrequester.h>
+#include <kmessagebox.h>
+#include <qlineedit.h>
+
+#include "pluginfactory.h"
+
+#include "notepad-conduit.h" // Conduit action
+#include "notepad-setup.h"
+#include "notepadconduit.h" // Settings class
+
+//----------------------------------------------------------------------------
+// Conduit Configuration
+//----------------------------------------------------------------------------
+class NotepadConduitConfig : public ConduitConfigBase
+{
+public:
+ NotepadConduitConfig(QWidget *parent=0L, const char *n=0L);
+ virtual void commit();
+ virtual void load();
+ static ConduitConfigBase *create(QWidget *p, const char *n)
+ {
+ return new NotepadConduitConfig(p, n);
+ };
+
+protected:
+ NotepadWidget *fConfigWidget;
+} ;
+
+static KAboutData *createAbout()
+{
+ FUNCTIONSETUP;
+
+ KAboutData *fAbout = new KAboutData("NotepadConduit",
+ I18N_NOOP("Saves notepads to png files"),
+ KPILOT_VERSION,
+ I18N_NOOP("Configures the Notepad Conduit for KPilot"),
+ KAboutData::License_LGPL,
+ "(C) 2004, Joern Ahrens");
+ fAbout->addAuthor("Joern Ahrens",
+ I18N_NOOP("Primary Author"),
+ "http://www.jokele.de/");
+ fAbout->addCredit("Adriaan de Groot");
+ fAbout->addCredit("Angus Ainslies",
+ I18N_NOOP("Notepad conduit is based on Angus' read-notepad, part of pilot-link" ));
+ return fAbout;
+}
+
+
+NotepadConduitConfig::NotepadConduitConfig(QWidget *p, const char *n) :
+ ConduitConfigBase(p, n),
+ fConfigWidget(new NotepadWidget(p))
+{
+ FUNCTIONSETUP;
+
+ fConduitName = i18n("Notepad");
+ ConduitConfigBase::addAboutPage(fConfigWidget->tabWidget, createAbout());
+ fWidget=fConfigWidget;
+ QObject::connect(fConfigWidget->fOutputDirectory, SIGNAL(textChanged(const QString&)),
+ this, SLOT(modified()));
+ fConfigWidget->fOutputDirectory->setMode(KFile::Directory |
+ KFile::LocalOnly);
+}
+
+/* virtual */ void NotepadConduitConfig::commit()
+{
+ FUNCTIONSETUP;
+
+ NotepadConduitSettings::setOutputDirectory(fConfigWidget->fOutputDirectory->url());
+ NotepadConduitSettings::self()->writeConfig();
+}
+
+/* virtual */ void NotepadConduitConfig::load()
+{
+ FUNCTIONSETUP;
+
+ NotepadConduitSettings::self()->readConfig();
+ fConfigWidget->fOutputDirectory->setURL(NotepadConduitSettings::outputDirectory());
+ fModified=false;
+}
+
+extern "C"
+{
+
+void *init_conduit_notepad()
+{
+ return new ConduitFactory<NotepadConduitConfig,NotepadConduit>(0,"abbrowserconduit");
+}
+
+}
+
diff --git a/kpilot/conduits/notepadconduit/notepad-factory.h b/kpilot/conduits/notepadconduit/notepad-factory.h
new file mode 100644
index 000000000..f208cd1fe
--- /dev/null
+++ b/kpilot/conduits/notepadconduit/notepad-factory.h
@@ -0,0 +1,38 @@
+#ifndef _KPILOT_NOTEPAD_FACTORY_H
+#define _KPILOT_NOTEPAD_FACTORY_H
+/* notepad-factory.h KPilot
+**
+** Copyright (C) 2004 by Adriaan de Groot, Joern Ahrens
+**
+** This file defines the factory for the notepad-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+extern "C"
+{
+
+void *init_conduit_notepad();
+
+}
+
+#endif
diff --git a/kpilot/conduits/notepadconduit/notepad-setup.ui b/kpilot/conduits/notepadconduit/notepad-setup.ui
new file mode 100644
index 000000000..ccc3feb28
--- /dev/null
+++ b/kpilot/conduits/notepadconduit/notepad-setup.ui
@@ -0,0 +1,79 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>NotepadWidget</class>
+<author>Jörn Ahrens</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Form2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>435</width>
+ <height>391</height>
+ </rect>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Path to the directory to which the pictures should be exported.</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="2" column="1">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>250</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KURLRequester" row="1" column="1">
+ <property name="name">
+ <cstring>fOutputDirectory</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Output:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includes>
+ <include location="global" impldecl="in implementation">kurlrequester.h</include>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+ <include location="global" impldecl="in implementation">kpushbutton.h</include>
+</includes>
+</UI>
diff --git a/kpilot/conduits/notepadconduit/notepadconduit.kcfg b/kpilot/conduits/notepadconduit/notepadconduit.kcfg
new file mode 100644
index 000000000..1a2c9bf6f
--- /dev/null
+++ b/kpilot/conduits/notepadconduit/notepadconduit.kcfg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kpilotrc"/>
+ <group name="Notepad-conduit">
+ <entry name="outputDirectory" type="Path">
+ <label>The export directory for the notepad drawings</label>
+ <default>$HOME</default>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kpilot/conduits/notepadconduit/notepadconduit.kcfgc b/kpilot/conduits/notepadconduit/notepadconduit.kcfgc
new file mode 100644
index 000000000..e18fa7c0c
--- /dev/null
+++ b/kpilot/conduits/notepadconduit/notepadconduit.kcfgc
@@ -0,0 +1,7 @@
+File=notepadconduit.kcfg
+ClassName=NotepadConduitSettings
+Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/conduits/null/CMakeLists.txt b/kpilot/conduits/null/CMakeLists.txt
new file mode 100644
index 000000000..b2fdbb8ad
--- /dev/null
+++ b/kpilot/conduits/null/CMakeLists.txt
@@ -0,0 +1,38 @@
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+set(conduit_null_SRCS
+ null-conduit.cc
+ null-factory.cc
+)
+
+set(conduit_null_UIS
+ setup_base.ui
+)
+
+set(conduit_null_KCFGS
+ nullSettings.kcfgc
+)
+
+kde3_add_kcfg_files(conduit_null_SRCS ${conduit_null_KCFGS})
+kde3_add_ui_files(conduit_null_SRCS ${conduit_null_UIS})
+kde3_automoc(${conduit_null_SRCS})
+add_library(conduit_null SHARED ${conduit_null_SRCS})
+
+set_target_properties(
+ conduit_null PROPERTIES LOCATION ${KDE3_PLUGIN_INSTALL_DIR}
+ INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib
+ PREFIX ""
+)
+
+kde3_install_libtool_file(conduit_null)
+
+install(
+ TARGETS conduit_null
+ LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR}
+)
+
+install(
+ FILES null-conduit.desktop DESTINATION ${KDE3_SERVICES_DIR}
+)
diff --git a/kpilot/conduits/null/Makefile.am b/kpilot/conduits/null/Makefile.am
new file mode 100644
index 000000000..c1057b4df
--- /dev/null
+++ b/kpilot/conduits/null/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES= $(PISOCK_INCLUDE) -I$(top_srcdir)/kpilot/lib $(all_includes)
+
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = null-conduit.desktop
+
+kde_module_LTLIBRARIES = conduit_null.la
+
+
+conduit_null_la_SOURCES = nullSettings.kcfgc setup_base.ui null-conduit.cc null-factory.cc
+conduit_null_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+conduit_null_la_LIBADD = ../../lib/libkpilot.la $(LIB_KDEUI)
+
+kde_kcfg_DATA = nullconduit.kcfg
diff --git a/kpilot/conduits/null/null-conduit.cc b/kpilot/conduits/null/null-conduit.cc
new file mode 100644
index 000000000..56599fec9
--- /dev/null
+++ b/kpilot/conduits/null/null-conduit.cc
@@ -0,0 +1,98 @@
+/* KPilot
+**
+** Copyright (C) 2000-2001 by Adriaan de Groot
+**
+** This file is part of the NULL conduit, a conduit for KPilot that
+** does nothing except add a log message to the Pilot's HotSync log.
+** It is also intended as a programming example.
+**
+** This file does the actual conduit work.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "options.h"
+
+// Only include what we really need:
+// First UNIX system stuff, then std C++,
+// then Qt, then KDE, then local includes.
+//
+//
+#include <time.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+
+#include "pilotSerialDatabase.h"
+#include "null-factory.h"
+#include "null-conduit.h"
+#include "nullSettings.h"
+
+// A conduit that does nothing has a very
+// simple constructor and destructor.
+//
+//
+NullConduit::NullConduit(KPilotLink *d,
+ const char *n,
+ const QStringList &l) :
+ ConduitAction(d,n,l),
+ fDatabase(0L),
+ fFailImmediately( l.contains( CSL1("--fail") ))
+{
+ FUNCTIONSETUP;
+ fConduitName=i18n("Null");
+}
+
+NullConduit::~NullConduit()
+{
+ FUNCTIONSETUP;
+ KPILOT_DELETE(fDatabase);
+}
+
+/* virtual */ bool NullConduit::exec()
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname << ": Mode " << syncMode().name() << endl;
+
+ if ( fFailImmediately )
+ {
+ DEBUGKPILOT << fname << ": Config says to fail now." << endl;
+ emit logError(i18n("NULL conduit is programmed to fail."));
+ return false;
+ }
+
+ QString m(NullConduitSettings::logMessage());
+ if (!m.isEmpty())
+ {
+ addSyncLogEntry(m);
+ }
+
+ DEBUGKPILOT << fname
+ << ": Message from null-conduit: "
+ << m
+ << endl;
+
+ emit syncDone(this);
+ return true;
+}
diff --git a/kpilot/conduits/null/null-conduit.desktop b/kpilot/conduits/null/null-conduit.desktop
new file mode 100644
index 000000000..1a0c225dc
--- /dev/null
+++ b/kpilot/conduits/null/null-conduit.desktop
@@ -0,0 +1,64 @@
+[Desktop Entry]
+Type=Service
+Name=NULL
+Name[ca]=NUL
+Name[fa]=پوچ
+Name[mk]=Нулов
+Name[ro]=NUL
+Name[sk]=NIČ
+Name[ta]=வெற்று மதிப்பு
+Name[tr]=BOŞ
+Comment=This conduit does nothing.
+Comment[af]=Hierdie pad doen niks
+Comment[bg]=Това нещо прави нищо
+Comment[bs]=Ovaj conduit ne radi ništa.
+Comment[ca]=Aquest conducte no fa res.
+Comment[cs]=Toto propojení nedělá nic.
+Comment[cy]=Nid yw'r cwndid yma yn gwneud unrhyw beth.
+Comment[da]=Denne kanal gør ingenting.
+Comment[de]=Diese Erweiterung (Conduit) ist ohne Funktion
+Comment[el]=Αυτός ο σύνδεσμος δεν κάνει τίποτα.
+Comment[eo]=Tiu kanalo faras nenion.
+Comment[et]=See kanal ei tee mitte kui midagi.
+Comment[eu]=Kanal honek ez du ezer egiten.
+Comment[fa]=این لوله هیچ چیز ندارد.
+Comment[fi]=Tämä yhdyskäytävä ei tee mitään.
+Comment[fr]=Ce canal ne fait rien.
+Comment[fy]=Dit conduit docht neat.
+Comment[ga]=Ní dhéanann an seoladán seo faic.
+Comment[gl]=Este conducto non fai nada.
+Comment[hi]=यह कन्ड्यूइट कुछ नहीं करता है.
+Comment[hu]=Ez a csatoló üres, csak tesztelési célokat szolgál
+Comment[is]=Þessi rás gerir ekki neitt.
+Comment[it]=Questo conduit non fa nulla.
+Comment[ja]=このコンジットは未知です。
+Comment[ka]=ეს არხი არაფერს არ აკეთებს.
+Comment[kk]=Ештеңе істемейтін арна.
+Comment[km]=បំពង់​នេះ​មិន​ធ្វើ​អ្វី​ទាំងអស់ ។
+Comment[lt]=Šis kanalas nieko neatlieka.
+Comment[mk]=Овој канал не прави ништо.
+Comment[ms]=Saluran ini tidak berbuat apa-apa.
+Comment[nb]=Denne kanalen gjør ingenting.
+Comment[nds]=Disse Kanaal deit gor nix.
+Comment[ne]=यो कन्ड्युटले केही पनि गर्दैन ।
+Comment[nl]=Dit conduit doet niets.
+Comment[nn]=Denne koplinga gjer ingenting.
+Comment[pl]=Ten łącznik nic nie robi.
+Comment[pt]=Esta conduta não faz nada.
+Comment[pt_BR]=Este conduíte não faz coisa alguma.
+Comment[ro]=Această conductă nu face nimic.
+Comment[ru]=Канал, который ничего не делает.
+Comment[sk]=Táto spojka nič nerobí.
+Comment[sl]=Ta veznik ne počne ničesar.
+Comment[sr]=Овај провод не ради ништа.
+Comment[sr@Latn]=Ovaj provod ne radi ništa.
+Comment[sv]=Den här kanalen gör ingenting.
+Comment[ta]=இந்த காப்புக் குழாய் ஒன்றும் செய்யாது
+Comment[tg]=Канале, ки дар ҳолати шурӯъ нест.
+Comment[tr]=Bu kanal herhangi bir işlem yapmaz.
+Comment[uk]=Цей акведук нічого не робить.
+Comment[zh_CN]=此管道不做任何事。
+Comment[zh_TW]=不做任何事。
+Implemented=file
+ServiceTypes=KPilotConduit
+X-KDE-Library=conduit_null
diff --git a/kpilot/conduits/null/null-conduit.h b/kpilot/conduits/null/null-conduit.h
new file mode 100644
index 000000000..7bf1b67de
--- /dev/null
+++ b/kpilot/conduits/null/null-conduit.h
@@ -0,0 +1,65 @@
+#ifndef _NULL_NULL_CONDUIT_H
+#define _NULL_NULL_CONDUIT_H
+/* null-conduit.h KPilot
+**
+** Copyright (C) 2000-2001 by Adriaan de Groot
+**
+** This file is part of the NULL conduit, a conduit for KPilot that
+** does nothing except add a log message to the Pilot's HotSync log.
+** It is also intended as a programming example.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "plugin.h"
+
+class PilotRecord;
+class PilotDatabase;
+
+/**
+ * The conduit Null does nothing. Almost nothing, anyway.
+ * It writes a single log message to the sync log and then
+ * completes successfully. For debugging purposes it can
+ * also simulate failure, but that is a very specialized
+ * case available only programmatically.
+ */
+class NullConduit : public ConduitAction
+{
+public:
+ /** Constructor. Special case is if @p contains
+ * @c --fail as an argument to the conduit, then
+ * the conduit will fail instead of trivially succeeding.
+ */
+ NullConduit(KPilotLink *,
+ const char *name=0L,
+ const QStringList &args = QStringList());
+ virtual ~NullConduit();
+
+protected:
+ virtual bool exec();
+
+protected:
+ PilotDatabase *fDatabase;
+ bool fFailImmediately;
+};
+
+#endif
diff --git a/kpilot/conduits/null/null-factory.cc b/kpilot/conduits/null/null-factory.cc
new file mode 100644
index 000000000..2a829c6e3
--- /dev/null
+++ b/kpilot/conduits/null/null-factory.cc
@@ -0,0 +1,125 @@
+/* KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the factory for the null-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qtabwidget.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+
+#include <kconfig.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+
+#include "pluginfactory.h"
+
+#include "setup_base.h"
+#include "null-conduit.h"
+#include "null-factory.h"
+#include "nullSettings.h"
+
+
+class NullConduitConfig : public ConduitConfigBase
+{
+public:
+ NullConduitConfig(QWidget *parent=0L, const char *n=0L);
+ virtual void commit();
+ virtual void load();
+protected:
+ NullWidget *fConfigWidget;
+ KAboutData *fAbout;
+} ;
+
+NullConduitConfig::NullConduitConfig(QWidget *p, const char *n) :
+ ConduitConfigBase(p,n),
+ fConfigWidget(new NullWidget(p))
+{
+ FUNCTIONSETUP;
+ fConduitName = i18n("Null");
+ fAbout = new KAboutData("nullConduit",
+ I18N_NOOP("Null Conduit for KPilot"),
+ KPILOT_VERSION,
+ I18N_NOOP("Configures the Null Conduit for KPilot"),
+ KAboutData::License_GPL,
+ "(C) 2001, Adriaan de Groot");
+ fAbout->addAuthor("Adriaan de Groot",
+ I18N_NOOP("Primary Author"),
+ "http://www.cs.kun.nl/~adridg/kpilot");
+
+ ConduitConfigBase::addAboutPage(fConfigWidget->tabWidget,fAbout);
+ fWidget=fConfigWidget;
+ QObject::connect(fConfigWidget->fLogMessage,SIGNAL(textChanged(const QString&)),
+ this,SLOT(modified()));
+}
+
+/* virtual */ void NullConduitConfig::commit()
+{
+ FUNCTIONSETUP;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Message="
+ << fConfigWidget->fLogMessage->text()
+ << endl;
+#endif
+
+ NullConduitSettings::setLogMessage( fConfigWidget->fLogMessage->text() );
+ NullConduitSettings::self()->writeConfig();
+ unmodified();
+}
+
+/* virtual */ void NullConduitConfig::load()
+{
+ FUNCTIONSETUP;
+ NullConduitSettings::self()->readConfig();
+
+ fConfigWidget->fLogMessage->setText( NullConduitSettings::logMessage() );
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Read Message="
+ << fConfigWidget->fLogMessage->text()
+ << endl;
+#endif
+
+ unmodified();
+}
+
+
+
+extern "C"
+{
+
+unsigned long version_conduit_null = Pilot::PLUGIN_API;
+void *init_conduit_null()
+{
+ return new ConduitFactory<NullConduitConfig,NullConduit>(0,"nullconduit");
+}
+
+}
+
diff --git a/kpilot/conduits/null/null-factory.h b/kpilot/conduits/null/null-factory.h
new file mode 100644
index 000000000..2897ad4f8
--- /dev/null
+++ b/kpilot/conduits/null/null-factory.h
@@ -0,0 +1,40 @@
+#ifndef _KPILOT_NULL_FACTORY_H
+#define _KPILOT_NULL_FACTORY_H
+/* null-factory.h KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the factory for the null-conduit plugin.
+** It also defines the class for the behavior of the setup dialog.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+extern "C"
+{
+
+void *init_conduit_null();
+
+}
+
+#endif
diff --git a/kpilot/conduits/null/nullSettings.kcfgc b/kpilot/conduits/null/nullSettings.kcfgc
new file mode 100644
index 000000000..17a65cade
--- /dev/null
+++ b/kpilot/conduits/null/nullSettings.kcfgc
@@ -0,0 +1,7 @@
+File=nullconduit.kcfg
+ClassName= NullConduitSettings
+Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/conduits/null/nullconduit.kcfg b/kpilot/conduits/null/nullconduit.kcfg
new file mode 100644
index 000000000..3e899f1ad
--- /dev/null
+++ b/kpilot/conduits/null/nullconduit.kcfg
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kpilotrc"/>
+ <group name="Null-conduit">
+ <entry name="LogMessage" type="String">
+ <label>The error message if the null conduit is supposed to fail</label>
+ <default>KPilot was here.</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kpilot/conduits/null/setup_base.ui b/kpilot/conduits/null/setup_base.ui
new file mode 100644
index 000000000..7e0d02ee9
--- /dev/null
+++ b/kpilot/conduits/null/setup_base.ui
@@ -0,0 +1,128 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>NullWidget</class>
+<comment>A tabWidget for configuring
+the Null-conduit settings.</comment>
+<author>Adriaan de Groot</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Form1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>342</width>
+ <height>163</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>570</width>
+ <height>270</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>Null-Conduit Options</string>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>Widget2</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>fLogMessage</cstring>
+ </property>
+ <property name="text">
+ <string>KPilot was here.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter the message to add to the Sync Log on your Pilot here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Log message:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fLogMessage</cstring>
+ </property>
+ </widget>
+ <spacer row="3" column="1">
+ <property name="name">
+ <cstring>Spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>tabWidget</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpilot/conduits/popmail/CMakeLists.txt b/kpilot/conduits/popmail/CMakeLists.txt
new file mode 100644
index 000000000..daec3c3a8
--- /dev/null
+++ b/kpilot/conduits/popmail/CMakeLists.txt
@@ -0,0 +1,43 @@
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+set(conduit_popmail_SRCS
+ popmail-factory.cc
+ popmail-conduit.cc
+ setupDialog.cc
+)
+
+set(conduit_popmail_UIS
+ setup-dialog.ui
+)
+
+set(conduit_popmail_KCFGS
+ popmailSettings.kcfgc
+)
+
+kde3_add_kcfg_files(conduit_popmail_SRCS ${conduit_popmail_KCFGS})
+kde3_add_ui_files(conduit_popmail_SRCS ${conduit_popmail_UIS})
+kde3_automoc(${conduit_popmail_SRCS})
+add_library(conduit_popmail SHARED ${conduit_popmail_SRCS})
+
+set_target_properties(
+ conduit_popmail PROPERTIES LOCATION ${KDE3_PLUGIN_INSTALL_DIR}
+ INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib
+ PREFIX ""
+)
+
+kde3_install_libtool_file(conduit_popmail)
+
+install(
+ TARGETS conduit_popmail
+ LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR}
+)
+
+install(
+ FILES popmail-conduit.desktop DESTINATION ${KDE3_SERVICES_DIR}
+)
+
+install(
+ FILES popmail.kcfg DESTINATION ${KDE3_KCFG_DIR}
+)
diff --git a/kpilot/conduits/popmail/Makefile.am b/kpilot/conduits/popmail/Makefile.am
new file mode 100644
index 000000000..0e565805d
--- /dev/null
+++ b/kpilot/conduits/popmail/Makefile.am
@@ -0,0 +1,24 @@
+### Makefile for the popmail conduit
+###
+
+INCLUDES= $(PISOCK_INCLUDE) -I$(top_srcdir)/kpilot/lib $(all_includes)
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = popmail-conduit.desktop
+kde_kcfg_DATA = popmail.kcfg
+
+####### This part is very kpilot specific
+# you can add here more. This one gets installed
+kde_module_LTLIBRARIES = conduit_popmail.la
+
+# Which sources should be compiled for popmail_conduit
+conduit_popmail_la_SOURCES = popmailSettings.kcfgc setup-dialog.ui \
+ popmail-factory.cc setupDialog.cc \
+ popmail-conduit.cc
+conduit_popmail_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+conduit_popmail_la_LIBADD = ../../lib/libkpilot.la $(LIB_KIO)
+
+# this option you can leave out. Just, if you use "make dist", you need it
+noinst_HEADERS = popmail-conduit.h setupDialog.h
+
diff --git a/kpilot/conduits/popmail/popmail-conduit.cc b/kpilot/conduits/popmail/popmail-conduit.cc
new file mode 100644
index 000000000..47315edaa
--- /dev/null
+++ b/kpilot/conduits/popmail/popmail-conduit.cc
@@ -0,0 +1,416 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 Dan Pilone
+** Copyright (C) 1999,2000 Michael Kropfberger
+**
+** This file is part of the popmail conduit, a conduit for KPilot that
+** synchronises the Pilot's email application with the outside world,
+** which currently means:
+** -- sendmail or SMTP for outgoing mail
+** -- POP or mbox for incoming mail
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+#include "popmail-conduit.h"
+
+extern "C"
+{
+
+unsigned long version_conduit_popmail = Pilot::PLUGIN_API;
+
+}
+
+#include <qsocket.h>
+#include <qregexp.h>
+
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include <ctype.h>
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <time.h> // Needed by pilot-link include
+#include <pi-version.h>
+#if PILOT_LINK_MAJOR < 10
+#include <pi-config.h>
+#endif
+#include <pi-mail.h>
+
+#include <qdir.h>
+#include <qtextstream.h>
+#include <qtextcodec.h>
+
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <ksock.h>
+#include <kconfig.h>
+#include <ksimpleconfig.h>
+#include <dcopclient.h>
+#include <ktempfile.h>
+
+#include "pilotRecord.h"
+#include "pilotSerialDatabase.h"
+
+#include "popmailSettings.h"
+#include "setupDialog.h"
+
+static QString DATE_FORMAT("ddd, d MMM yyyy hh:mm:ss");
+
+PopMailConduit::PopMailConduit(KPilotLink *d,
+ const char *n,
+ const QStringList &l) :
+ ConduitAction(d,n,l)
+{
+ FUNCTIONSETUP;
+ fConduitName=i18n("KMail");
+}
+
+PopMailConduit::~PopMailConduit()
+{
+ FUNCTIONSETUP;
+}
+
+void PopMailConduit::doSync()
+{
+ FUNCTIONSETUP;
+
+ int sent_count=0;
+ int mode=MailConduitSettings::syncOutgoing();
+
+ DEBUGKPILOT << fname
+ << ": Outgoing mail disposition "
+ << mode << endl;
+
+ if(mode)
+ {
+ sent_count=sendPendingMail(mode);
+ }
+
+ if (sent_count>0)
+ {
+ if (sent_count>0)
+ {
+ addSyncLogEntry(i18n("Sent one message",
+ "Sent %n messages",sent_count));
+ }
+ }
+}
+
+
+// additional changes by Michael Kropfberger
+int PopMailConduit::sendPendingMail(int mode)
+{
+ FUNCTIONSETUP;
+ int count=0;
+
+ if (mode==PopMailWidgetConfig::SendKMail)
+ {
+ count=sendViaKMail();
+ }
+
+ if (count == 0)
+ {
+ WARNINGKPILOT << "Mail was not sent at all!" << endl;
+ emit logError(i18n("No mail was sent."));
+ }
+ else if (count < 0)
+ {
+ WARNINGKPILOT
+ << "Mail sending returned error " << count
+ << endl;
+ emit logError(i18n("No mail could be sent."));
+ }
+ else
+ {
+ DEBUGKPILOT << fname
+ << ": Sent "
+ << count
+ << " messages"
+ << endl;
+ }
+
+ return count;
+}
+
+
+QString PopMailConduit::getKMailOutbox() const
+{
+ FUNCTIONSETUP;
+
+ // Default to "outbox" with newer KMails.
+ KSimpleConfig c(CSL1("kmailrc"),true);
+ c.setGroup("General");
+
+ QString outbox = c.readEntry("outboxFolder");
+ if (outbox.isEmpty())
+ {
+ outbox = MailConduitSettings::outboxFolder();
+ }
+
+ if (outbox.isEmpty()) outbox=CSL1("outbox");
+
+ return outbox;
+}
+
+/*
+ * This function uses KMail's DCOP interface to put all the
+ * outgoing mail into the outbox.
+ */
+int PopMailConduit::sendViaKMail()
+{
+ FUNCTIONSETUP;
+ int count=0;
+ QString kmailOutboxName = getKMailOutbox();
+
+ DCOPClient *dcopptr = KApplication::kApplication()->dcopClient();
+ if (!dcopptr)
+ {
+ WARNINGKPILOT << "Cannot get DCOP client."
+ << endl;
+ KMessageBox::error(0L,
+ i18n("Could not connect to DCOP server for "
+ "the KMail connection."),
+ i18n("Error Sending Mail"));
+ return -1;
+ }
+
+ if (!dcopptr->isAttached())
+ {
+ dcopptr->attach();
+ }
+
+ while (PilotRecord *pilotRec = fDatabase->readNextRecInCategory(1))
+ {
+ DEBUGKPILOT << fname
+ << ": Reading "
+ << count + 1
+ << "th message"
+ << endl;
+
+ if (pilotRec->isDeleted() || pilotRec->isArchived())
+ {
+ DEBUGKPILOT << fname
+ << ": Skipping record."
+ << endl;
+ continue;
+ }
+
+ struct Mail theMail;
+ KTempFile t;
+ t.setAutoDelete(true);
+
+ if (t.status())
+ {
+ WARNINGKPILOT << "Cannot open temp file." << endl;
+ KMessageBox::error(0L,
+ i18n("Cannot open temporary file to store "
+ "mail from Pilot in."),
+ i18n("Error Sending Mail"));
+ continue;
+ }
+
+ FILE *sendf = t.fstream();
+
+ if (!sendf)
+ {
+ WARNINGKPILOT
+ << "Cannot open temporary file for writing!" << endl;
+ KMessageBox::error(0L,
+ i18n("Cannot open temporary file to store "
+ "mail from Pilot in."),
+ i18n("Error Sending Mail"));
+ continue;
+ }
+
+ unpack_Mail(&theMail,
+ (unsigned char*)pilotRec->data(),
+ pilotRec->size());
+ writeMessageToFile(sendf, theMail);
+
+
+ QByteArray data,returnValue;
+ QCString returnType;
+ QDataStream arg(data,IO_WriteOnly);
+
+ arg << kmailOutboxName << t.name() << CSL1("N") ;
+
+ if (!dcopptr->call("kmail",
+ "KMailIface",
+ "dcopAddMessage(QString,QString,QString)",
+ data,
+ returnType,
+ returnValue,
+ true))
+ {
+ WARNINGKPILOT << "DCOP call failed." << endl;
+
+ KMessageBox::error(0L,
+ i18n("DCOP connection with KMail failed."),
+ i18n("Error Sending Mail"));
+ continue;
+ }
+
+ DEBUGKPILOT << fname
+ << ": DCOP call returned "
+ << returnType
+ << " of "
+ << (const char *)returnValue
+ << endl;
+
+ // Mark it as filed...
+ pilotRec->setCategory(3);
+ pilotRec->setModified( false );
+ fDatabase->writeRecord(pilotRec);
+ delete pilotRec;
+ // This is ok since we got the mail with unpack mail..
+ free_Mail(&theMail);
+
+ count++;
+ }
+
+ return count;
+}
+
+// From pilot-link-0.8.7 by Kenneth Albanowski
+// additional changes by Michael Kropfberger
+
+void PopMailConduit::writeMessageToFile(FILE* sendf, struct Mail& theMail)
+{
+ FUNCTIONSETUP;
+
+ QTextStream mailPipe(sendf, IO_WriteOnly);
+
+ QString fromAddress = MailConduitSettings::emailAddress();
+ mailPipe << "From: " << fromAddress << "\r\n";
+ mailPipe << "To: " << theMail.to << "\r\n";
+ if(theMail.cc)
+ mailPipe << "Cc: " << theMail.cc << "\r\n";
+ if(theMail.bcc)
+ mailPipe << "Bcc: " << theMail.bcc << "\r\n";
+ if(theMail.replyTo)
+ mailPipe << "Reply-To: " << theMail.replyTo << "\r\n";
+ if(theMail.subject)
+ mailPipe << "Subject: " << theMail.subject << "\r\n";
+
+ // if our struct indicates that it's dated, then use the date it
+ // holds. otherwise, provide current date. either way, we need to
+ // have a date...
+ QDateTime date = QDateTime::currentDateTime();
+ if (theMail.dated)
+ {
+ date = readTm(theMail.date);
+ }
+
+ QString dateString = date.toString(DATE_FORMAT);
+
+ mailPipe << "Date: " << dateString << "\r\n";
+
+ mailPipe << "X-mailer: " << "Popmail-Conduit " << KPILOT_VERSION << "\r\n";
+ mailPipe << "\r\n";
+
+
+ DEBUGKPILOT << fname << ": To: " << theMail.to << endl;
+
+
+ if(theMail.body)
+ {
+ DEBUGKPILOT << fname << ": Sent body." << endl;
+ mailPipe << theMail.body << "\r\n";
+ }
+
+ //insert the real signature file from disk
+ QString signature = MailConduitSettings::signature();
+ if(!signature.isEmpty())
+ {
+ DEBUGKPILOT << fname << ": Reading signature" << endl;
+
+ QFile f(signature);
+ if ( f.open(IO_ReadOnly) )
+ { // file opened successfully
+ mailPipe << "-- \r\n";
+ QTextStream t( &f ); // use a text stream
+ while ( !t.eof() )
+ { // until end of file...
+ mailPipe << t.readLine() << "\r\n";
+ }
+ f.close();
+ }
+ }
+ mailPipe << "\r\n";
+
+ DEBUGKPILOT << fname << ": Done" << endl;
+}
+
+
+/* virtual */ void PopMailConduit::doTest()
+{
+ FUNCTIONSETUP;
+
+ QString outbox = getKMailOutbox();
+
+ DEBUGKPILOT << fname
+ << ": KMail's outbox is "
+ << outbox
+ << endl;
+
+ QDateTime date = QDateTime::currentDateTime();
+ QString dateString = date.toString(DATE_FORMAT);
+
+ DEBUGKPILOT << fname << ": Date format example: [" << dateString
+ << "]" << endl;
+}
+
+/* virtual */ bool PopMailConduit::exec()
+{
+ FUNCTIONSETUP;
+
+ if (syncMode().isTest())
+ {
+ doTest();
+ }
+ else if (syncMode() == SyncMode::eBackup)
+ {
+ emit logError(i18n("Cannot perform backup of mail database"));
+ }
+ else
+ {
+ fDatabase = deviceLink()->database( CSL1("MailDB") );
+
+ if (!fDatabase || !fDatabase->isOpen())
+ {
+ emit logError(i18n("Unable to open mail database on handheld"));
+ KPILOT_DELETE(fDatabase);
+ return false;
+ }
+
+ doSync();
+ fDatabase->resetSyncFlags();
+ KPILOT_DELETE(fDatabase);
+ }
+ delayDone();
+ return true;
+}
diff --git a/kpilot/conduits/popmail/popmail-conduit.desktop b/kpilot/conduits/popmail/popmail-conduit.desktop
new file mode 100644
index 000000000..b4cdc0175
--- /dev/null
+++ b/kpilot/conduits/popmail/popmail-conduit.desktop
@@ -0,0 +1,109 @@
+[Desktop Entry]
+Type=Service
+Comment=Send mail from your handheld through KMail.
+Comment[af]=Stuur pos vanaf jou draagbare toestel deur KMail.
+Comment[bg]=Изпращане на поща от мобилно устройство чрез KMail.
+Comment[ca]=Envia correu des de la vostra agenda electrònica a través de KMail.
+Comment[cs]=Odeslání zprávy z PDA přes KMail.
+Comment[da]=Send post fra din håndholdte gennem KMail.
+Comment[de]=Zum Versenden von E-Mails mit dem Taschencomputer via KMail.
+Comment[el]=Αποστολή αλληλογραφίας από τον υπολογιστή παλάμης σας μέσω του KMail.
+Comment[eo]=Sendu poŝton de via poŝkomputilo per KMail.
+Comment[es]=Envía el correo de la agenda electrónica a través de KMail.
+Comment[et]=Saadab pihuseadmest KMaili vahendusel e-kirja.
+Comment[eu]=Bidali posta zure agenda elektronikotik KMail-en bidez.
+Comment[fa]=ارسال نامه از طریق KMail، از دستی شما.
+Comment[fi]=Lähetä sähköpostia taskutietokoneelta KMailin kautta.
+Comment[fr]=Permet d'envoyer des messages du Palm vers KMail
+Comment[fy]=Dit conduit ferstjoerd e-post fan jo handheld mei help fan KMail.
+Comment[gl]=Enviar correo dende o seu aparello de man a través de KMail.
+Comment[hu]=Ezzel a csatolóval kézi számítógépről lehet levelet küldeni a KMailen keresztül.
+Comment[is]=Sendu tölvupóst frá lófatölvunni þinni gegnum KMail.
+Comment[it]=Invia la posta dal tuo palmare tramite KMail.
+Comment[ja]=KMail 経由でハンドヘルドからメールを送信します。
+Comment[ka]= ფოსტის გაგზავნა პორტატიული მოწყობილობიდან KMail-ის საშუალებით.
+Comment[kk]=Қалта құрылғының поштасын KMail арқылы жіберу.
+Comment[km]=ផ្ញើ​សំបុត្រ​ទៅ​ឧបករណ៍​យួរដៃ​របស់​អ្នក​តាម​រយៈ KMail ។
+Comment[lt]=Siųsti paštą iš nešiojamo įrenginio per KMail.
+Comment[ms]=Menghantar mel dari komputer telapak melalui KMail.
+Comment[nb]=Send e-post fra PDA-en gjennom KMail.
+Comment[nds]=Nettbreven vun Dien Handreekner över KMail afsennen
+Comment[ne]=तपाईँको ह्यान्डहेल्डबाट केडीई मेलहुदै पत्र पठाउनुहोस् ।
+Comment[nl]=Dit conduit verzendt mail van uw handheld met behulp van KMail.
+Comment[pl]=Wysyła pocztę z palmtopa za pomocą KMail.
+Comment[pt]=Enviar e-mail do seu dispositivo móvel através do KMail.
+Comment[pt_BR]=Envia e-mail do seu handheld através do Kmail.
+Comment[ru]=Отправка почты с КПК через KMail.
+Comment[sk]=Pošle poštu z prenosného zariadenia cez KMail.
+Comment[sl]=Pošljite pošto z vašega ročnega računalnika preko KMaila.
+Comment[sr]=Пошаљите пошту са вашег ручног рачунара кроз KMail.
+Comment[sr@Latn]=Pošaljite poštu sa vašeg ručnog računara kroz KMail.
+Comment[sv]=Skicka e-post från handdatorn via Kmail.
+Comment[ta]=இந்த காப்புக்குழாய் உங்கள் கையேட்டில் இருந்து தேதி புத்தகத்தை கேஅமைபாளருக்கு ஒத்திசைக்கிறது
+Comment[tr]=El bilgisayarınızdan KMail aracılığı ile e-posta gönderir.
+Comment[uk]=Відсилання пошти з кишенькового пристрою через KMail.
+Comment[zh_CN]=通过 KMail 从您的手持设备发送邮件。
+Comment[zh_TW]=透過 KMail 送出您 handheld 的信件。
+Name=Mail
+Name[af]=Pos
+Name[ar]=البريد
+Name[be]=Пошта
+Name[bg]=Поща
+Name[br]=Lizher
+Name[ca]=Correu
+Name[cs]=Pošta
+Name[cy]=Ebost
+Name[da]=Brev
+Name[de]=E-Mail
+Name[eo]=Retpoŝto
+Name[es]=Correo
+Name[et]=E-post
+Name[eu]=Posta
+Name[fa]=نامه
+Name[fi]=Sähköposti
+Name[fr]=Messages
+Name[fy]=E-post
+Name[ga]=Ríomhphost
+Name[gl]=Correo-e
+Name[he]=דוא"ל
+Name[hi]=डाक
+Name[hr]=Pošta
+Name[hu]=E-mail
+Name[is]=Póstur
+Name[it]=Posta
+Name[ja]=メール
+Name[ka]=ფოსტა
+Name[kk]=Пошта
+Name[km]=សំបុត្រ
+Name[lt]=Paštas
+Name[mk]=Е-пошта
+Name[ms]=Mel
+Name[nb]=E-post
+Name[nds]=Nettpost
+Name[ne]=पत्र
+Name[nl]=E-mail
+Name[nn]=E-post
+Name[pa]=ਪੱਤਰ
+Name[pl]=Poczta
+Name[pt]=E-mail
+Name[pt_BR]=Correio
+Name[ro]=E-Mail
+Name[ru]=Почта
+Name[se]=E-boasta
+Name[sk]=Pošta
+Name[sl]=Pošta
+Name[sr]=Пошта
+Name[sr@Latn]=Pošta
+Name[sv]=Brev
+Name[ta]=அஞ்சல்
+Name[tg]=Мактуб
+Name[th]=จดหมาย
+Name[tr]=Posta
+Name[uk]=Пошта
+Name[uz]=Xat-xabar
+Name[uz@cyrillic]=Хат-хабар
+Name[zh_CN]=邮件
+Name[zh_TW]=郵件
+Implemented=file
+ServiceTypes=KPilotConduit
+X-KDE-Library=conduit_popmail
diff --git a/kpilot/conduits/popmail/popmail-conduit.h b/kpilot/conduits/popmail/popmail-conduit.h
new file mode 100644
index 000000000..1df1a6912
--- /dev/null
+++ b/kpilot/conduits/popmail/popmail-conduit.h
@@ -0,0 +1,74 @@
+#ifndef _KPILOT_POPMAIL_CONDUIT_H
+#define _KPILOT_POPMAIL_CONDUIT_H
+/* popmail-conduit.h KPilot
+**
+** Copyright (C) 1998,1999,2000 Dan Pilone
+** Copyright (C) 1999,2000 Michael Kropfberger
+**
+** This file is part of the popmail conduit, a conduit for KPilot that
+** synchronises the Pilot's email application with the outside world,
+** which currently means:
+** -- sendmail or SMTP for outgoing mail
+** -- POP or mbox for incoming mail
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "plugin.h"
+
+class KSocket;
+
+class PilotRecord;
+class PilotDatabase;
+
+class PopMailConduit : public ConduitAction
+{
+public:
+ PopMailConduit(KPilotLink *d,
+ const char *n=0L,
+ const QStringList &l=QStringList());
+ virtual ~PopMailConduit();
+
+protected:
+ virtual bool exec();
+
+ // static PilotRecord *readMessage(FILE *mailbox,
+ // char *buffer,int bufferSize);
+
+protected:
+ void doSync();
+ void doTest();
+
+ // Pilot -> Sendmail
+ //
+ //
+ int sendPendingMail(int mode /* unused */);
+ // int sendViaSendmail();
+ int sendViaKMail();
+ // int sendViaSMTP();
+ void writeMessageToFile(FILE* sendf, struct Mail& theMail);
+ QString getKMailOutbox() const;
+
+};
+
+#endif
diff --git a/kpilot/conduits/popmail/popmail-factory.cc b/kpilot/conduits/popmail/popmail-factory.cc
new file mode 100644
index 000000000..dc2a0cd13
--- /dev/null
+++ b/kpilot/conduits/popmail/popmail-factory.cc
@@ -0,0 +1,47 @@
+/* KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2006 by Adriaan de Groot <[email protected]>
+**
+** This file defines the factory for the popmail-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+
+#include "setupDialog.h"
+#include "popmail-conduit.h"
+#include "pluginfactory.h"
+
+
+extern "C"
+{
+
+void *init_conduit_popmail()
+{
+ return new ConduitFactory<PopMailWidgetConfig,PopMailConduit>;
+}
+
+}
+
diff --git a/kpilot/conduits/popmail/popmail-factory.h b/kpilot/conduits/popmail/popmail-factory.h
new file mode 100644
index 000000000..2cab4d840
--- /dev/null
+++ b/kpilot/conduits/popmail/popmail-factory.h
@@ -0,0 +1,37 @@
+#ifndef _KPILOT_POPMAIL_FACTORY_H
+#define _KPILOT_POPMAIL_FACTORY_H
+/* popmail-factory.h KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the factory for the popmail-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+extern "C"
+{
+void *init_conduit_popmail();
+}
+
+#endif
diff --git a/kpilot/conduits/popmail/popmail.kcfg b/kpilot/conduits/popmail/popmail.kcfg
new file mode 100644
index 000000000..65056cb56
--- /dev/null
+++ b/kpilot/conduits/popmail/popmail.kcfg
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+<kcfgfile name="kpilot_mailconduitrc"/>
+<group name="General">
+ <entry name="SyncOutgoing" type="UInt">
+ <label>Selects the way in which mail is sent: none (0), kmail (1).</label>
+ <default>0</default>
+ </entry>
+ <entry name="EmailAddress" type="String">
+ <label>The email address entered in the To: field of outgoing messages.</label>
+ <default></default>
+ </entry>
+ <entry name="Signature" type="Path">
+ <label>The pathname of your .signature file.</label>
+ <default>$HOME/.signature</default>
+ </entry>
+ <entry name="OutboxFolder" type="String">
+ <label>The name of KMail's outbox - use with caution.</label>
+ <default></default>
+ </entry>
+</group>
+</kcfg>
diff --git a/kpilot/conduits/popmail/popmailSettings.kcfgc b/kpilot/conduits/popmail/popmailSettings.kcfgc
new file mode 100644
index 000000000..1ac6276fc
--- /dev/null
+++ b/kpilot/conduits/popmail/popmailSettings.kcfgc
@@ -0,0 +1,7 @@
+File=popmail.kcfg
+ClassName=MailConduitSettings
+Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/conduits/popmail/setup-dialog.ui b/kpilot/conduits/popmail/setup-dialog.ui
new file mode 100644
index 000000000..e10f0e4b8
--- /dev/null
+++ b/kpilot/conduits/popmail/setup-dialog.ui
@@ -0,0 +1,141 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>PopMailWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PopMailWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>363</width>
+ <height>281</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>fTabWidget</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Send Mail</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="5" column="1">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Send method:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select the method KPilot will use to send the mail from your Handheld to the recipients here. Depending on the method you choose, the other fields in the dialog may be enabled or disabled. Currently, the only &lt;i&gt;working&lt;/i&gt; method is through KMail.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Email address:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter the email address you want to send messages as here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>fEmailFrom</cstring>
+ </property>
+ <property name="text">
+ <string>$USER</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter the email address you want to send messages as here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Signature file:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;If you want to add a signature file, enter the location of your signature file (usually, &lt;i&gt;.signature&lt;/i&gt;, located in your home folder) here, or select it clicking the file picker button. The signature file contains the text that is added to the end of your outgoing mail messages.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="2" column="1">
+ <property name="name">
+ <cstring>fSignature</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;If you want to add a signature file, enter the location of your signature file (usually, &lt;i&gt;.signature&lt;/i&gt;, located in your home folder) here, or select it clicking the file picker button. The signature file contains the text that is added to the end of your outgoing mail messages.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>Do Not Send Mail</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Use KMail</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fSendMode</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select the method KPilot will use to send the mail from your Handheld to the recipients here. Depending on the method you choose, the other fields in the dialog may be enabled or disabled. Currently, the only &lt;i&gt;working&lt;/i&gt; method is through KMail.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includes>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+ <include location="global" impldecl="in implementation">kurlrequester.h</include>
+ <include location="global" impldecl="in implementation">kpushbutton.h</include>
+</includes>
+</UI>
diff --git a/kpilot/conduits/popmail/setupDialog.cc b/kpilot/conduits/popmail/setupDialog.cc
new file mode 100644
index 000000000..64553562b
--- /dev/null
+++ b/kpilot/conduits/popmail/setupDialog.cc
@@ -0,0 +1,158 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 Dan Pilone
+**
+** This file is part of the popmail conduit, a conduit for KPilot that
+** synchronises the Pilot's email application with the outside world,
+** which currently means:
+** -- sendmail or SMTP for outgoing mail
+** -- POP or mbox for incoming mail
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <klineedit.h>
+#include <kaboutdata.h>
+
+#include <qcheckbox.h>
+#include <qdir.h>
+#include <qcombobox.h>
+
+#include "kfiledialog.h"
+
+#include <kurlrequester.h>
+
+
+#include "popmail-factory.h"
+#include "setup-dialog.h"
+#include "setupDialog.moc"
+#include "popmailSettings.h"
+
+
+
+PopMailWidgetConfig::PopMailWidgetConfig(QWidget *p,const char *n) :
+ ConduitConfigBase(p,n),
+ fConfigWidget(new PopMailWidget(p,"PopMailWidget"))
+{
+ FUNCTIONSETUP;
+ fConduitName = i18n("KMail");
+ KAboutData *fAbout = new KAboutData("popmailConduit",
+ I18N_NOOP("Mail Conduit for KPilot"),
+ KPILOT_VERSION,
+ I18N_NOOP("Configures the Mail Conduit for KPilot"),
+ KAboutData::License_GPL,
+ "(C) 2001, Dan Pilone, Michael Kropfberger, Adriaan de Groot");
+ fAbout->addAuthor("Adriaan de Groot",
+ I18N_NOOP("Maintainer"),
+ "http://www.kpilot.org/");
+ fAbout->addAuthor("Dan Pilone",
+ I18N_NOOP("Original Author"));
+ fAbout->addCredit("Michael Kropfberger",
+ I18N_NOOP("POP3 code"));
+ fAbout->addCredit("Marko Gr&ouml;nroos",
+ I18N_NOOP("SMTP support and redesign"),
+ "http://www.iki.fi/magi/");
+
+ ConduitConfigBase::addAboutPage(fConfigWidget->fTabWidget,fAbout);
+ fWidget=fConfigWidget;
+
+#define CM(a,b) connect(fConfigWidget->a,b,this,SLOT(modified()));
+ CM(fSendMode,SIGNAL(activated(int)));
+ CM(fEmailFrom,SIGNAL(textChanged(const QString &)));
+ CM(fSignature,SIGNAL(textChanged(const QString &)));
+#undef CM
+
+ connect(fConfigWidget->fSendMode,SIGNAL(activated(int)),
+ this,SLOT(toggleSendMode(int)));
+
+}
+
+void PopMailWidgetConfig::commit()
+{
+ FUNCTIONSETUP;
+
+ MailConduitSettings::self()->readConfig();
+#define WR(a,b,c) MailConduitSettings::set##a(fConfigWidget->b->c);
+ WR(SyncOutgoing,fSendMode,currentItem());
+ WR(EmailAddress,fEmailFrom,text());
+ WR(Signature,fSignature,url());
+#undef WR
+
+ MailConduitSettings::self()->writeConfig();
+ unmodified();
+}
+
+void PopMailWidgetConfig::load()
+{
+ FUNCTIONSETUP;
+ MailConduitSettings::self()->config()->sync();
+ MailConduitSettings::self()->readConfig();
+
+#define RD(a,b,c) fConfigWidget->a->b(MailConduitSettings::c())
+ RD(fSendMode,setCurrentItem,syncOutgoing);
+ RD(fEmailFrom,setText,emailAddress);
+ RD(fSignature,setURL,signature);
+#undef RD
+
+ toggleSendMode(fConfigWidget->fSendMode->currentItem());
+
+ MailConduitSettings::self()->writeConfig();
+ unmodified();
+}
+
+
+/* slot */ void PopMailWidgetConfig::toggleSendMode(int i)
+{
+ FUNCTIONSETUP;
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Got mode " << i << endl;
+#endif
+
+#define E(a,b) fConfigWidget->a->setEnabled(b)
+ switch(i)
+ {
+ case SendKMail :
+ E(fEmailFrom,true);
+ E(fSignature,true);
+ break;
+ case NoSend : /* FALLTHRU */
+ default :
+ E(fEmailFrom,false);
+ E(fSignature,false);
+ break;
+ }
+#undef E
+}
+
+
+
diff --git a/kpilot/conduits/popmail/setupDialog.h b/kpilot/conduits/popmail/setupDialog.h
new file mode 100644
index 000000000..248b4ecbf
--- /dev/null
+++ b/kpilot/conduits/popmail/setupDialog.h
@@ -0,0 +1,62 @@
+#ifndef _POPMAIL_SETUPDIALOG_H
+#define _POPMAIL_SETUPDIALOG_H
+/* setupDialog.h KPilot
+**
+** Copyright (C) 1998-2001 Dan Pilone
+**
+** This file is part of the popmail conduit, a conduit for KPilot that
+** synchronises the Pilot's email application with the outside world,
+** which currently means:
+** -- sendmail or SMTP for outgoing mail
+** -- POP or mbox for incoming mail
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "plugin.h"
+
+class PopMailWidget; // From setup-dialog.ui
+
+class PopMailWidgetConfig : public ConduitConfigBase
+{
+Q_OBJECT
+public:
+ PopMailWidgetConfig(QWidget *, const char *);
+ virtual void load();
+ virtual void commit();
+
+ static ConduitConfigBase *create(QWidget *w, const char *n)
+ { return new PopMailWidgetConfig(w,n); } ;
+
+ // These enums must follow the order of items in the combo box
+ enum SendMode { NoSend=0, SendKMail=1 } ;
+
+protected:
+ PopMailWidget *fConfigWidget;
+
+public slots:
+ void toggleSendMode(int);
+} ;
+
+
+#endif
diff --git a/kpilot/conduits/recordconduit/Makefile.am b/kpilot/conduits/recordconduit/Makefile.am
new file mode 100644
index 000000000..33ceb8540
--- /dev/null
+++ b/kpilot/conduits/recordconduit/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES= $(PISOCK_INCLUDE) -I$(top_srcdir)/kpilot/lib $(all_includes)
+
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = record-conduit.desktop
+
+kde_module_LTLIBRARIES = conduit_record.la
+
+
+conduit_record_la_SOURCES = settings.kcfgc setup_base.ui factory.cc
+conduit_record_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+conduit_record_la_LIBADD = ../../lib/libkpilot.la $(LIB_KDEUI)
+
+kde_kcfg_DATA = settings.kcfg
diff --git a/kpilot/conduits/recordconduit/factory.cc b/kpilot/conduits/recordconduit/factory.cc
new file mode 100644
index 000000000..8015763d1
--- /dev/null
+++ b/kpilot/conduits/recordconduit/factory.cc
@@ -0,0 +1,144 @@
+/* KPilot
+**
+** Copyright (C) 2005 by Adriaan de Groot
+**
+** This file defines the factory for the recordconduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qtabwidget.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+
+#include <kconfig.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+
+#include "pluginfactory.h"
+#include "pilotDatabase.h"
+#include "recordConduit.h"
+
+#include "setup_base.h"
+#include "factory.h"
+#include "settings.h"
+
+
+class ConduitConfig : public ConduitConfigBase
+{
+public:
+ ConduitConfig(QWidget *parent=0L, const char *n=0L);
+ virtual void commit();
+ virtual void load();
+protected:
+ RecordWidget *fConfigWidget;
+ KAboutData *fAbout;
+} ;
+
+ConduitConfig::ConduitConfig(QWidget *p, const char *n) :
+ ConduitConfigBase(p,n),
+ fConfigWidget(new RecordWidget(p))
+{
+ FUNCTIONSETUP;
+ fConduitName = i18n("Record Conduit");
+ fAbout = new KAboutData("recordConduit",
+ I18N_NOOP("Record Conduit for KPilot"),
+ KPILOT_VERSION,
+ I18N_NOOP("Configures the Record Conduit for KPilot"),
+ KAboutData::License_GPL,
+ "(C) 2005, Adriaan de Groot");
+ fAbout->addAuthor("Adriaan de Groot",
+ I18N_NOOP("Primary Author"),
+ "http://people.fruitsalad.org/adridg/");
+
+ ConduitConfigBase::addAboutPage(fConfigWidget->tabWidget,fAbout);
+ fWidget=fConfigWidget;
+ QObject::connect(fConfigWidget->fLogMessage,SIGNAL(textChanged(const QString&)),
+ this,SLOT(modified()));
+ QObject::connect(fConfigWidget->fDatabases,SIGNAL(textChanged(const QString&)),
+ this,SLOT(modified()));
+ QObject::connect(fConfigWidget->fFailImmediately,SIGNAL(toggled(bool)),
+ this,SLOT(modified()));
+}
+
+/* virtual */ void ConduitConfig::commit()
+{
+ FUNCTIONSETUP;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Message="
+ << fConfigWidget->fLogMessage->text()
+ << endl;
+ DEBUGKPILOT << fname
+ << ": Databases="
+ << fConfigWidget->fDatabases->text()
+ << endl;
+#endif
+
+ ConduitSettings::setLogMessage( fConfigWidget->fLogMessage->text() );
+ ConduitSettings::setDatabases( fConfigWidget->fDatabases->text() );
+ ConduitSettings::setFailImmediately( fConfigWidget->fFailImmediately->isChecked());
+ ConduitSettings::self()->writeConfig();
+ unmodified();
+}
+
+/* virtual */ void ConduitConfig::load()
+{
+ FUNCTIONSETUP;
+ ConduitSettings::self()->readConfig();
+
+ fConfigWidget->fLogMessage->setText( ConduitSettings::logMessage() );
+ fConfigWidget->fDatabases->setText( ConduitSettings::databases().join(",") );
+ fConfigWidget->fFailImmediately->setChecked( ConduitSettings::failImmediately() );
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Read Message="
+ << fConfigWidget->fLogMessage->text()
+ << endl;
+ DEBUGKPILOT << fname
+ << ": Read Database="
+ << fConfigWidget->fDatabases->text()
+ << endl;
+#endif
+
+ unmodified();
+}
+
+typedef PilotDatabase PilotDatabaseContainer;
+
+typedef RecordConduit<PilotRecord, PilotDatabaseContainer, PilotRecord, PilotAppInfoBase, NullMapper<PilotRecord> > RecordAction;
+
+extern "C"
+{
+
+void *init_conduit_record()
+{
+ return new ConduitFactory<ConduitConfig,RecordAction>(0,"recordconduit");
+}
+
+}
+
diff --git a/kpilot/conduits/recordconduit/factory.h b/kpilot/conduits/recordconduit/factory.h
new file mode 100644
index 000000000..6d35d4db1
--- /dev/null
+++ b/kpilot/conduits/recordconduit/factory.h
@@ -0,0 +1,40 @@
+#ifndef KPILOT_RECORD_FACTORY_H
+#define KPILOT_RECORD_FACTORY_H
+/* factory.h KPilot
+**
+** Copyright (C) 2005 by Adriaan de Groot
+**
+** This is the factory for the recordconduit, which uses the
+** template class RecordConduit for demonstration purposes.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+extern "C"
+{
+
+void *init_conduit_record();
+
+}
+
+#endif
diff --git a/kpilot/conduits/recordconduit/record-conduit.desktop b/kpilot/conduits/recordconduit/record-conduit.desktop
new file mode 100644
index 000000000..55c953d17
--- /dev/null
+++ b/kpilot/conduits/recordconduit/record-conduit.desktop
@@ -0,0 +1,93 @@
+[Desktop Entry]
+Type=Service
+Name=Records (Experimental)
+Name[af]=Rekords (Eksperimenteel)
+Name[bg]=Записи (Експериментално)
+Name[ca]=Registres (Experimental)
+Name[cs]=Záznamy (experimentální)
+Name[da]=Indspilninger (eksperimentel)
+Name[de]=Einträge (Experimentell)
+Name[el]=Εγγραφές (Πειραματικό)
+Name[es]=Registros (Experimental)
+Name[et]=Kirjed (eksperimentaalne)
+Name[fr]=Enregistrements (expérimental)
+Name[fy]=Opnames (eksperimenteel)
+Name[gl]=Grava (Experimental)
+Name[hu]=Rekordok (kísérleti)
+Name[is]=Færslur (á tilraunastigi)
+Name[it]=Record (sperimentale)
+Name[ja]=レコード (実験中)
+Name[kk]=Жазулар (Эксперименталдық)
+Name[km]=កំណត់​ត្រា (ពិសោធន៍)
+Name[lt]=Įrašai (eksperimentinis)
+Name[nb]=Records (Eksperimentell)
+Name[nds]=Logbook (warrt utprobeert)
+Name[ne]=रेकर्ड (प्रयोगात्मक)
+Name[nl]=Opnames (experimenteel)
+Name[pl]=Wpisy (eksperymentalne)
+Name[pt]=Registos (Experimental)
+Name[pt_BR]=Registros (Experimental)
+Name[ru]=Записи (экспериментально)
+Name[sk]=Záznamy (Experimentálne)
+Name[sl]=Zapisi (poskusno)
+Name[sr]=Слогови (експериментално)
+Name[sr@Latn]=Slogovi (eksperimentalno)
+Name[sv]=Inspelningar (experimentell)
+Name[tr]=Kayıtlar (Deneysel)
+Name[uk]=Записи (експериментальний)
+Name[zh_CN]=记录(试验性)
+Name[zh_TW]=紀錄(實驗性)
+Comment=This conduit does nothing.
+Comment[af]=Hierdie pad doen niks
+Comment[bg]=Това нещо прави нищо
+Comment[bs]=Ovaj conduit ne radi ništa.
+Comment[ca]=Aquest conducte no fa res.
+Comment[cs]=Toto propojení nedělá nic.
+Comment[cy]=Nid yw'r cwndid yma yn gwneud unrhyw beth.
+Comment[da]=Denne kanal gør ingenting.
+Comment[de]=Diese Erweiterung (Conduit) ist ohne Funktion
+Comment[el]=Αυτός ο σύνδεσμος δεν κάνει τίποτα.
+Comment[eo]=Tiu kanalo faras nenion.
+Comment[et]=See kanal ei tee mitte kui midagi.
+Comment[eu]=Kanal honek ez du ezer egiten.
+Comment[fa]=این لوله هیچ چیز ندارد.
+Comment[fi]=Tämä yhdyskäytävä ei tee mitään.
+Comment[fr]=Ce canal ne fait rien.
+Comment[fy]=Dit conduit docht neat.
+Comment[ga]=Ní dhéanann an seoladán seo faic.
+Comment[gl]=Este conducto non fai nada.
+Comment[hi]=यह कन्ड्यूइट कुछ नहीं करता है.
+Comment[hu]=Ez a csatoló üres, csak tesztelési célokat szolgál
+Comment[is]=Þessi rás gerir ekki neitt.
+Comment[it]=Questo conduit non fa nulla.
+Comment[ja]=このコンジットは未知です。
+Comment[ka]=ეს არხი არაფერს არ აკეთებს.
+Comment[kk]=Ештеңе істемейтін арна.
+Comment[km]=បំពង់​នេះ​មិន​ធ្វើ​អ្វី​ទាំងអស់ ។
+Comment[lt]=Šis kanalas nieko neatlieka.
+Comment[mk]=Овој канал не прави ништо.
+Comment[ms]=Saluran ini tidak berbuat apa-apa.
+Comment[nb]=Denne kanalen gjør ingenting.
+Comment[nds]=Disse Kanaal deit gor nix.
+Comment[ne]=यो कन्ड्युटले केही पनि गर्दैन ।
+Comment[nl]=Dit conduit doet niets.
+Comment[nn]=Denne koplinga gjer ingenting.
+Comment[pl]=Ten łącznik nic nie robi.
+Comment[pt]=Esta conduta não faz nada.
+Comment[pt_BR]=Este conduíte não faz coisa alguma.
+Comment[ro]=Această conductă nu face nimic.
+Comment[ru]=Канал, который ничего не делает.
+Comment[sk]=Táto spojka nič nerobí.
+Comment[sl]=Ta veznik ne počne ničesar.
+Comment[sr]=Овај провод не ради ништа.
+Comment[sr@Latn]=Ovaj provod ne radi ništa.
+Comment[sv]=Den här kanalen gör ingenting.
+Comment[ta]=இந்த காப்புக் குழாய் ஒன்றும் செய்யாது
+Comment[tg]=Канале, ки дар ҳолати шурӯъ нест.
+Comment[tr]=Bu kanal herhangi bir işlem yapmaz.
+Comment[uk]=Цей акведук нічого не робить.
+Comment[zh_CN]=此管道不做任何事。
+Comment[zh_TW]=不做任何事。
+Implemented=file
+ServiceTypes=KPilotConduit
+X-KDE-Library=conduit_record
diff --git a/kpilot/conduits/recordconduit/settings.kcfg b/kpilot/conduits/recordconduit/settings.kcfg
new file mode 100644
index 000000000..7fc2180df
--- /dev/null
+++ b/kpilot/conduits/recordconduit/settings.kcfg
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kpilotrc"/>
+ <group name="RecordConduit">
+ <entry name="FailImmediately" key="FailNow" type="Bool">
+ <label>Whether the conduit should immediately bail out with an error</label>
+ <default>false</default>
+ </entry>
+ <entry name="LogMessage" type="String">
+ <label>The error message if the null conduit is supposed to fail</label>
+ <default>KPilot was here.</default>
+ </entry>
+ <entry name="Databases" type="StringList">
+ <label>Databases that are skipped on sync</label>
+ <default></default>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kpilot/conduits/recordconduit/settings.kcfgc b/kpilot/conduits/recordconduit/settings.kcfgc
new file mode 100644
index 000000000..8a2b4f356
--- /dev/null
+++ b/kpilot/conduits/recordconduit/settings.kcfgc
@@ -0,0 +1,7 @@
+File=settings.kcfg
+ClassName= ConduitSettings
+Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/conduits/recordconduit/setup_base.ui b/kpilot/conduits/recordconduit/setup_base.ui
new file mode 100644
index 000000000..126d3ff20
--- /dev/null
+++ b/kpilot/conduits/recordconduit/setup_base.ui
@@ -0,0 +1,158 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>RecordWidget</class>
+<comment>A tabWidget for configuring
+the Record-conduit settings.</comment>
+<author>Adriaan de Groot</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Form1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>342</width>
+ <height>163</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>570</width>
+ <height>270</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>Null-Conduit Options</string>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>Widget2</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>fLogMessage</cstring>
+ </property>
+ <property name="text">
+ <string>KPilot was here.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter the message to add to the Sync Log on your Pilot here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Log message:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fLogMessage</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Databases:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fDatabases</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>fDatabases</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;The Null-conduit can be attached to several databases, effectively preventing them from Syncing. Enter the database names here.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <spacer row="3" column="1">
+ <property name="name">
+ <cstring>Spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="2" column="1">
+ <property name="name">
+ <cstring>fFailImmediately</cstring>
+ </property>
+ <property name="text">
+ <string>Simulate failure</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Force the conduit to simulate a failure to perform the HotSync.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>tabWidget</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpilot/conduits/sysinfoconduit/CMakeLists.txt b/kpilot/conduits/sysinfoconduit/CMakeLists.txt
new file mode 100644
index 000000000..cae6d89f1
--- /dev/null
+++ b/kpilot/conduits/sysinfoconduit/CMakeLists.txt
@@ -0,0 +1,50 @@
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+set(conduit_sysinfo_SRCS
+ sysinfo-setup.cc
+ sysinfo-factory.cc
+ sysinfo-conduit.cc
+)
+
+set(conduit_sysinfo_UIS
+ sysinfo-setup_dialog.ui
+)
+
+set(conduit_sysinfo_KCFGS
+ sysinfoSettings.kcfgc
+)
+
+kde3_add_kcfg_files(conduit_sysinfo_SRCS ${conduit_sysinfo_KCFGS})
+kde3_add_ui_files(conduit_sysinfo_SRCS ${conduit_sysinfo_UIS})
+kde3_automoc(${conduit_sysinfo_SRCS})
+add_library(conduit_sysinfo SHARED ${conduit_sysinfo_SRCS})
+
+set_target_properties(
+ conduit_sysinfo PROPERTIES LOCATION ${KDE3_PLUGIN_INSTALL_DIR}
+ INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib
+ PREFIX ""
+)
+
+kde3_install_libtool_file(conduit_sysinfo)
+
+install(
+ TARGETS conduit_sysinfo
+ LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR}
+)
+
+install(
+ FILES sysinfo_conduit.desktop DESTINATION ${KDE3_SERVICES_DIR}
+)
+
+install(
+ FILES sysinfoSettings.kcfgc sysinfoconduit.kcfg
+ DESTINATION ${KDE3_KCFG_DIR}
+)
+
+install(
+ FILES Template.html Template.txt
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/apps/kpilot/sysinfoconduit
+)
+
diff --git a/kpilot/conduits/sysinfoconduit/Makefile.am b/kpilot/conduits/sysinfoconduit/Makefile.am
new file mode 100644
index 000000000..eb7f7aa92
--- /dev/null
+++ b/kpilot/conduits/sysinfoconduit/Makefile.am
@@ -0,0 +1,24 @@
+### Makefile for the sysinfo conduit
+###
+### The sysinfo conduit is Copyright (C) 2003 by Reinhold Kainhofer
+
+INCLUDES= $(PISOCK_INCLUDE) -I$(top_srcdir)/kpilot/lib $(all_includes)
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = sysinfo_conduit.desktop
+
+kde_module_LTLIBRARIES = conduit_sysinfo.la
+
+conduit_sysinfo_la_SOURCES = sysinfoSettings.kcfgc \
+ sysinfo-factory.cc \
+ sysinfo-setup.cc \
+ sysinfo-conduit.cc \
+ sysinfo-setup_dialog.ui
+conduit_sysinfo_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+conduit_sysinfo_la_LIBADD = ../../lib/libkpilot.la $(LIB_KDEUI) $(LIB_KIO)
+
+kpilot_sysinfo_data_DATA = Template.html Template.txt
+kpilot_sysinfo_datadir = $(kde_datadir)/kpilot/sysinfoconduit
+EXTRA_DIST = $(kpilot_sysinfo_data_DATA)
+kde_kcfg_DATA = sysinfoconduit.kcfg
diff --git a/kpilot/conduits/sysinfoconduit/Template.html b/kpilot/conduits/sysinfoconduit/Template.html
new file mode 100644
index 000000000..e5a33e0fd
--- /dev/null
+++ b/kpilot/conduits/sysinfoconduit/Template.html
@@ -0,0 +1,184 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<head>
+ <title>KPilot System Information Page</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-15">
+ <meta name="GENERATOR" content="KPilot SysInfo conduit">
+ <style type="text/css">
+ h1 {
+ font-family: sans-serif;
+ font-size: xx-large;
+ font-style: italic;
+ font-variant: small-caps;
+ font-weight: bolder;
+ color: darkBlue;
+ border-bottom: thick solid darkBlue;
+ margin: 30;
+ }
+ h2 {
+ font-family: sans-serif;
+ font-size: large;
+ color: darkRed;
+ margin-top: 40;
+ border-top: thin solid darkRed;
+ display: list-item;
+ list-style-type: circle;
+ margin: 40;
+ }
+ th {
+ font-style: italic;
+ font-weight: bold;
+ background-color: #DFC370;
+ text-align: center;
+ }
+ </style>
+</head>
+<body bgcolor="#FFE080">
+ <h1>KPilot System Information</h1>
+ <center>
+<p><!--#ifhardware#<a href="#Hardware">Hardware info</a> - #endifhardware#-->
+<!--#ifuser#<a href="#User">User info</a> - #endifuser#-->
+<!--#ifmemory#<a href="#Memory">Memory info</a> - #endifmemory#-->
+<!--#ifstorage#<a href="#Storage">Storage info</a> - #endifstorage#-->
+<!--#ifdblist#<a href="#DBList">Database list</a> - #endifdblist#-->
+<!--#ifrecords#<a href="#Records">Addresses, to-dos, events, and memos</a> - #endifrecords#-->
+<!--#ifsync#<a href="#Sync">Sync info</a> - #endifsync#-->
+<!--#ifpcversion#<a href="#Version">PC Version info</a> - #endifpcversion#-->
+<!--#ifpalmversion#<a href="#PalmVersion">Palm Version info</a> - #endifpalmversion#-->
+<!--#ifdebug#<a href="#Debug">Debug info</a>#endifdebug#--></p>
+ </center>
+
+
+<!--#ifhardware#<h2><a name="Hardware">Hardware Information</a></h2>
+ <center>
+ <table border=1>
+ <tbody>
+ <tr><td><b>DeviceID:</b></td><td>#deviceid#</td></tr>
+ <tr><td><b>Device name:</b></td><td>#devicename#</td></tr>
+ <tr><td><b>Device model:</b></td><td>#devicemodel#</td></tr>
+ <tr><td><b>Manufacturer:</b></td><td>#manufacturer#</td></tr>
+ <tr><td><b>Connected via:</b></td><td>#devicetype#</td></tr>
+ </tbody>
+ </table>
+ </center>#endifhardware#-->
+
+
+<!--#ifuser#<h2><a name="User">User Information</a></h2>
+ <center>
+ <table border=1>
+ <tbody>
+ <tr><td><b>Handheld User Name:</b></td><td>#username#</td></tr>
+ <tr><td><b>Handheld Password:</b></td><td>#pw#</td></tr>
+ <tr><td><b>Handheld User ID:</b></td><td>#uid#</td></tr>
+ <tr><td><b>Viewer ID:</b></td><td>#viewerid#</td></tr>
+ </tbody>
+ </table>
+ </center>#endifuser#-->
+
+
+<!--#ifmemory#<h2><a name="Memory">Memory Information</a></h2>
+ <center>
+ <table border=1>
+ <tbody>
+ <tr><td><b>ROM:</b></td><td>#rom# kB total</td></tr>
+ <tr><td><b>Total RAM:</b></td><td>#totalmem# kB total</td></tr>
+ <tr><td><b>Free RAM:</b></td><td>#freemem# kB free</td></tr>
+ </tbody>
+ </table>
+ </center>#endifmemory#-->
+
+
+<!--#ifstorage#<h2><a name="Storage">Storage Information</a></h2>
+ <center>
+ <table border=1>
+ <tbody>
+ <tr><td><b>Cards:</b></td><td>#cards#</td></tr>
+ </tbody>
+ </table>
+ </center>#endifstorage#-->
+
+
+<!--#ifdblist#<h2><a name="DBList">List of Databases on Handheld</a></h2>
+ <center>
+ <table border=1>
+ <tr><th>DB name</th><th>type, creator</th><th>index</th><th>flags</th>
+ <th>created</th><th>modified</th><th>version</th></tr>
+ #dblist[<tr><td>%0</td><td>%1,%2</td><td>%3</td><td>%4/%5</td>
+ <td>%7</td><td>%8</td><td>%6</td></tr>
+ ]#
+ </table>
+ </center>#endifdblist#-->
+
+
+
+<!--#ifrecords#<h2><a name="Records">Number of addresses, to-dos, events, and memos</a></h2>
+ <center>
+ <table border=1>
+ <thead>
+ <tr><th scope=col>Record type</th><th scope=col># of recs</th></tr>
+ </thead>
+ <tbody>
+ <tr><td><b>Addresses:</b></td><td>#addresses# entries in Addressbook</td></tr>
+ <tr><td><b>Events:</b></td><td>#events# entries in Calendar</td></tr>
+ <tr><td><b>To-dos:</b></td><td>#todos# entries in To-do list</td></tr>
+ <tr><td><b>Memos:</b></td><td>#memos# memos</td></tr>
+ </tbody>
+ </table>
+ </center>#endifrecords#-->
+
+
+<!--#ifsync#<h2><a name="Sync">Synchronization Information</a></h2>
+ <center>
+ <table border=1>
+ <tbody>
+ <tr><td><b>Last sync attempt:</b></td><td>#lastsync#</td></tr>
+ <tr><td><b>Last successful sync:</b></td><td>#lastsuccsync#</td></tr>
+ <tr><td><b>Last sync with PC (ID):</b></td><td>#lastsyncpc#</td></tr>
+ </tbody>
+ </table>
+ </center>#endifsync#-->
+
+
+<!--#ifpcversion#<h2><a name="Version">Version Information (Desktop)</a></h2>
+ <center>
+ <table border=1>
+ <thead>
+ <tr><th scope=col>Application</th><th scope=col>Version</th></tr>
+ </thead>
+ <tbody>
+ <tr><td><b>Operating System:</b></td><td>#os#</td></tr>
+ <tr><td><b>Hostname:</b></td><td>#hostname#</td></tr>
+ <tr><td><b>Qt Version:</b></td><td>#qt#</td></tr>
+ <tr><td><b>KDE Libraries Version:</b></td><td>#kde#</td></tr>
+ <tr><td><b>KPilot Version:</b></td><td>#kpilot#</td></tr>
+ <tr><td><b>Pilot-Link Version:</b></td><td>#pilotlink#</td></tr>
+ </tbody>
+ </table>
+ </center>#endifpcversion#-->
+
+
+<!--#ifpalmversion#<h2><a name="PalmVersion">Version Information (Handheld)</a></h2>
+ <center>
+ <table border=1>
+ <thead>
+ <tr><th scope=col>Application</th><th scope=col>Version</th></tr>
+ </thead>
+ <tbody>
+ <tr><td><b>PalmOS:</b></td><td>#palmos#</td></tr>
+ </tbody>
+ </table>
+ </center>#endifpalmversion#-->
+
+
+<!--#ifdebug#<h2><a name="Debug">Debug Information</a></h2>
+ <center>
+ <table border=1>
+ <tr><td><pre>#debug#</pre></td></tr>
+ </table>
+ </center>#endifdebug#-->
+
+
+ <p>&nbsp;</p>
+ <hr>
+ <font size="-1">Page created #date# by the SysInfo conduit of <a href="http://www.kpilot.org/">KPilot</a>.</font>
+</body>
+</html>
diff --git a/kpilot/conduits/sysinfoconduit/Template.txt b/kpilot/conduits/sysinfoconduit/Template.txt
new file mode 100644
index 000000000..8796e44a1
--- /dev/null
+++ b/kpilot/conduits/sysinfoconduit/Template.txt
@@ -0,0 +1,76 @@
+KPilot System Information Page
+==============================
+
+<!--#ifhardware#
+-) Hardware Information
+ DeviceID: #deviceid#
+ Device name: #devicename#
+ Device model: #devicemodel#
+ Manufacturer: #manufacturer#
+ Connected via: #devicetype#
+#endifhardware#-->
+
+<!--#ifuser#
+-) User Information
+ Handheld User Name: #username#
+ Handheld Password: #pw#
+ Handheld User ID: #uid#
+ Viewer ID: #viewerid#
+#endifuser#-->
+
+<!--#ifmemory#
+-) Memory Information
+ ROM: #rom# kB total
+ Total RAM: #totalmem# kB total
+ Free RAM: #freemem# kB fre
+#endifmemory#-->
+
+<!--#ifstorage#
+-) Storage Information
+ Cards: #cards#
+#endifstorage#-->
+
+<!--#ifdblist#
+-) List of Databases on Handheld
+ Available Databases: #dblist[
+ %0 (%1, %2)]#
+#endifdblist#-->
+
+<!--#ifrecords#
+-) Number of addresses, todos, events, and memos
+ Addresses: #addresses# entries in Addressbook
+ Events: #events# entries in Calendar
+ Todos: #todos# entries in ToDo list
+ Memos: #memos# memos
+#endifrecords#-->
+
+<!--#ifsync#
+-) Synchronization Information
+ Last sync attempt: #lastsync#
+ Last successful sync: #lastsuccsync#
+ Last sync with PC (ID): #lastsyncpc#
+#endifsync#-->
+
+<!--#ifpcversion#
+-) Version Information (Desktop)
+ Operating System: #os#
+ Hostname: #hostname#
+ Qt Version: #qt#
+ KDE Version: #kde#
+ KPilot Version: #kpilot#
+ Pilot-Link Version: #pilotlink#
+#endifpcversion#-->
+
+<!--#ifpalmversion#
+-) Version Information (Handheld)
+ PalmOS: #palmos#
+#endifpalmversion#-->
+
+<!--#ifdebug#
+-) Debug Information
+ #debug#
+#endifdebug#-->
+
+
+------------------------------------------------------------
+Page created #date# by the SysInfo conduit of KPilot.
diff --git a/kpilot/conduits/sysinfoconduit/sysinfo-conduit.cc b/kpilot/conduits/sysinfoconduit/sysinfo-conduit.cc
new file mode 100644
index 000000000..b3e69b65c
--- /dev/null
+++ b/kpilot/conduits/sysinfoconduit/sysinfo-conduit.cc
@@ -0,0 +1,611 @@
+/* KPilot
+**
+** Copyright (C) 2003 by Reinhold Kainhofer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected].
+*/
+
+#include "options.h"
+
+#include <pi-version.h>
+
+#include <qtimer.h>
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <kconfig.h>
+#include <kdebug.h>
+
+#include <pilotSysInfo.h>
+#include <pilotUser.h>
+#include <pilotCard.h>
+#include <kpilotlink.h>
+#include <kstandarddirs.h>
+#include <pilotSerialDatabase.h>
+
+#include <sys/utsname.h>
+
+#include "sysinfo-factory.h"
+#include "sysinfo-conduit.moc"
+#include "sysinfoSettings.h"
+
+const QString SysInfoConduit::defaultpage = CSL1("KPilot System Information Page\n"
+"==============================\n"
+"(Kpilot was unable to find the correct template file, \n"
+"so this simple template was used.)\n\n"
+"<!--#ifhardware#\n"
+"-) Hardware Information\n"
+" DeviceID: #deviceid#\n"
+" Device name: #devicename#\n"
+" Device model: #devicemodel#\n"
+" Manufacturer: #manufacturer#\n"
+" Connected via: #devicetype#\n"
+"#endifhardware#-->\n"
+"\n"
+"<!--#ifuser#\n"
+"-) User Information\n"
+" Handheld User Name: #username#\n"
+" Handheld Password: #pw#\n"
+" Handheld User ID: #uid#\n"
+" Viewer ID: #viewerid#\n"
+"#endifuser#-->\n"
+"\n"
+"<!--#ifmemory#\n"
+"-) Memory Information\n"
+" ROM: #rom# kB total\n"
+" Total RAM: #totalmem# kB total\n"
+" Free RAM: #freemem# kB free\n"
+"#endifmemory#-->\n"
+"\n"
+"<!--#ifstorage#\n"
+"-) Storage Information\n"
+" Number of cards: #cards#\n"
+" Memory on cards: #storagemem#\n"
+"#endifstorage#-->\n"
+"\n"
+"<!--#ifdblist#\n"
+"-) List of Databases on Handheld\n"
+" Available Databases: #dblist(%1,)#\n"
+"#endifdblist#-->\n"
+"\n"
+"<!--#ifrecords#\n"
+"-) Number of addresses, to-dos, events, and memos\n"
+" Addresses: #addresses# entries in Addressbook\n"
+" Events: #events# entries in Calendar\n"
+" To-dos: #todos# entries in To-do list\n"
+" Memos: #memos# memos\n"
+"#endifrecords#-->\n"
+"\n"
+"<!--#ifsync#\n"
+"-) Synchronization Information\n"
+" Last sync attempt: #lastsync#\n"
+" Last successful sync: #lastsuccsync#\n"
+" Last sync with PC (ID): #lastsyncpc#\n"
+"#endifsync#-->\n"
+"\n"
+"<!--#ifpcversion#\n"
+"-) Version Information (Desktop)\n"
+" Operating System: #os#\n"
+" Hostname: #hostname#\n"
+" Qt Version: #qt#\n"
+" KDE Version: #kde#\n"
+" KPilot Version: #kpilot#\n"
+" Pilot-Link Version: #pilotlink#\n"
+"#endifpcversion#-->\n"
+"\n"
+"<!--#ifpalmversion#\n"
+"-) Version Information (Handheld)\n"
+" PalmOS: #palmos#\n"
+"#endifpalmversion#-->\n"
+"\n"
+"<!--#ifdebug#\n"
+"-) Debug Information\n"
+" #debug#\n"
+"#endifdebug#-->\n"
+"\n"
+"------------------------------------------------------------\n"
+"Page created <!--#date#--> by the KPilot System Information conduit.\n"
+"");
+
+
+ /** possible fields in the templates are:
+ * - hardware
+ * - user
+ * - memory
+ * - storage
+ * - dblist
+ * - recnumber
+ * - syncinfo
+ * - pcversion
+ * - palmversion
+ * - debug
+ */
+
+
+// Something to allow us to check what revision
+// the modules are that make up a binary distribution.
+
+extern "C"
+{
+
+unsigned long version_conduit_sysinfo = Pilot::PLUGIN_API;
+
+}
+
+
+
+SysInfoConduit::SysInfoConduit(KPilotLink * o,
+ const char *n,
+ const QStringList & a) :
+ ConduitAction(o, n, a)
+{
+ FUNCTIONSETUP;
+ fConduitName=i18n("System Information");
+}
+
+
+
+SysInfoConduit::~SysInfoConduit()
+{
+ FUNCTIONSETUP;
+}
+
+
+
+void SysInfoConduit::readConfig()
+{
+ fOutputFile = SysinfoSettings::outputFile();
+ fOutputType = (eOutputTypeEnum) SysinfoSettings::outputFormat();
+ fTemplateFile = SysinfoSettings::templateFile();
+ fHardwareInfo = SysinfoSettings::hardwareInfo();
+ fUserInfo = SysinfoSettings::userInfo();
+ fMemoryInfo = SysinfoSettings::memoryInfo();
+ fStorageInfo = SysinfoSettings::storageInfo();
+ fDBList = SysinfoSettings::databaseList();
+ fRecordNumber = SysinfoSettings::recordNumbers();
+ fSyncInfo = SysinfoSettings::syncInfo();
+ fKDEVersion = SysinfoSettings::kDEVersion();
+ fPalmOSVersion = SysinfoSettings::palmOSVersion();
+ fDebugInfo = SysinfoSettings::debugInformation();
+}
+
+
+/* virtual */ bool SysInfoConduit::exec()
+{
+ FUNCTIONSETUP;
+
+ readConfig();
+
+ QTimer::singleShot(0, this, SLOT(hardwareInfo()));
+ return true;
+}
+
+void SysInfoConduit::hardwareInfo()
+{
+ FUNCTIONSETUP;
+ if (fHardwareInfo) {
+ QString unknown = i18n("unknown");
+
+ /* Retrieve values for
+ * - #deviceid#
+ * - #devicename#
+ * - #devicemodel#
+ * - #manufactorer#
+ * - #devicetype#
+ */
+ KPilotSysInfo sysinfo = fHandle->getSysInfo();
+ fValues[CSL1("deviceid")] = QString::fromLatin1(sysinfo.getProductID());
+
+ const KPilotCard *device = fHandle->getCardInfo();
+ if (device)
+ {
+ fValues[CSL1("devicename")] = QString::fromLatin1(device->getCardName());
+ fValues[CSL1("devicemodel")] = unknown; // TODO
+ fValues[CSL1("manufacturer")] = QString::fromLatin1(device->getCardManufacturer());
+ }
+ else
+ {
+ fValues[CSL1("devicename")] = unknown;
+ fValues[CSL1("devicemodel")] = unknown;
+ fValues[CSL1("manufacturer")] = unknown;
+ }
+
+ fValues[CSL1("devicetype")] = unknown;
+
+ KPILOT_DELETE(device);
+ keepParts.append(CSL1("hardware"));
+ } else removeParts.append(CSL1("hardware"));
+ QTimer::singleShot(0, this, SLOT(userInfo()));
+}
+
+void SysInfoConduit::userInfo()
+{
+ FUNCTIONSETUP;
+ if (fUserInfo)
+ {
+ /* Retrieve values for
+ * - #username#
+ * - #uid#
+ */
+ KPilotUser user=fHandle->getPilotUser();
+ fValues[CSL1("username")] = user.name();
+ if (user.passwordLength()>0)
+ {
+ fValues[CSL1("pw")] = i18n("Password set");
+ }
+ else
+ {
+ fValues[CSL1("pw")] = i18n("No password set");
+ }
+ fValues[CSL1("uid")] = QString::number(user.data()->userID);
+ fValues[CSL1("viewerid")] = QString::number(user.data()->viewerID);
+ keepParts.append(CSL1("user"));
+ }
+ else
+ {
+ removeParts.append(CSL1("user"));
+ }
+ QTimer::singleShot(0, this, SLOT(memoryInfo()));
+}
+
+void SysInfoConduit::memoryInfo()
+{
+ FUNCTIONSETUP;
+ if (fMemoryInfo) {
+ /* Retrieve values for
+ * - #rom#
+ * - #totalmem#
+ * - #freemem#
+ */
+ const KPilotCard *device = fHandle->getCardInfo();
+ if (device)
+ {
+ fValues[CSL1("rom")] = QString::number(device->getRomSize()/1024);
+ fValues[CSL1("totalmem")] = QString::number(device->getRamSize()/1024);
+ fValues[CSL1("freemem")] = QString::number(device->getRamFree()/1024);
+ }
+ keepParts.append(CSL1("memory"));
+ } else removeParts.append(CSL1("memory"));
+ QTimer::singleShot(0, this, SLOT(storageInfo()));
+}
+
+void SysInfoConduit::storageInfo()
+{
+ FUNCTIONSETUP;
+ if (fStorageInfo) {
+ /* Retrieve values for
+ * - $cards$
+ */
+ const KPilotCard *device = fHandle->getCardInfo(1);
+ if (device) {
+ fValues[CSL1("cards")] = CSL1("%1 (%2, %3 kB of %3 kB free)")
+ .arg(QString::fromLatin1(device->getCardName()))
+ .arg(QString::fromLatin1(device->getCardManufacturer()))
+ .arg(device->getRamFree()/1024)
+ .arg(device->getRamSize()/1024);
+ KPILOT_DELETE(device);
+ } else {
+ fValues[CSL1("cards")] = i18n("No Cards available via pilot-link");
+ }
+ keepParts.append(CSL1("storage"));
+ } else removeParts.append(CSL1("storage"));
+ QTimer::singleShot(0, this, SLOT(dbListInfo()));
+}
+
+void SysInfoConduit::dbListInfo()
+{
+ FUNCTIONSETUP;
+ if (fDBList) {
+ /* Retrieve values for
+ * - #dblist(structure)#
+ */
+ dblist=deviceLink()->getDBList();
+ keepParts.append(CSL1("dblist"));
+ } else removeParts.append(CSL1("dblist"));
+ QTimer::singleShot(0, this, SLOT(recNumberInfo()));
+}
+
+void SysInfoConduit::recNumberInfo()
+{
+ FUNCTIONSETUP;
+ if (fRecordNumber) {
+ /* Retrieve values for
+ * - #addresses#
+ * - #events#
+ * - #todos#
+ * - #memos#
+ */
+ PilotDatabase *fDatabase = 0L;
+ QString ERROR = CSL1("ERROR");
+ fValues[CSL1("addresses")] = ERROR;
+ fValues[CSL1("events")] = ERROR;
+ fValues[CSL1("todos")] = ERROR;
+ fValues[CSL1("memos")] = ERROR;
+ fDatabase = deviceLink()->database(CSL1("AddressDB"));
+ if (fDatabase) {
+ fValues[CSL1("addresses")] = QString::number(fDatabase->recordCount());
+ KPILOT_DELETE(fDatabase);
+ }
+ fDatabase = deviceLink()->database(CSL1("DatebookDB"));
+ if (fDatabase) {
+ fValues[CSL1("events")] = QString::number(fDatabase->recordCount());
+ KPILOT_DELETE(fDatabase);
+ }
+ fDatabase = deviceLink()->database(CSL1("ToDoDB"));
+ if (fDatabase) {
+ fValues[CSL1("todos")] = QString::number(fDatabase->recordCount());
+ KPILOT_DELETE(fDatabase);
+ }
+ fDatabase = deviceLink()->database(CSL1("MemoDB"));
+ if (fDatabase) {
+ fValues[CSL1("memos")] = QString::number(fDatabase->recordCount());
+ KPILOT_DELETE(fDatabase);
+ }
+ keepParts.append(CSL1("records"));
+ } else removeParts.append(CSL1("records"));
+ QTimer::singleShot(0, this, SLOT(syncInfo()));
+}
+
+void SysInfoConduit::syncInfo()
+{
+ FUNCTIONSETUP;
+ if (fSyncInfo) {
+ /* Retrieve values for
+ * - #lastsync#
+ * - #lastsuccsync#
+ * - #lastsyncpc#
+ */
+ KPilotUser user = deviceLink()->getPilotUser();
+ time_t lastsync = user.getLastSyncDate();
+ QDateTime qlastsync;
+ qlastsync.setTime_t(lastsync);
+ fValues[CSL1("lastsync")] = qlastsync.toString(Qt::LocalDate);
+ lastsync = user.getLastSuccessfulSyncDate();
+ qlastsync.setTime_t(lastsync);
+ fValues[CSL1("lastsuccsync")] = qlastsync.toString(Qt::LocalDate);
+ fValues[CSL1("lastsyncpc")] = QString::number(user.getLastSyncPC());
+ keepParts.append(CSL1("sync"));
+ } else removeParts.append(CSL1("sync"));
+ QTimer::singleShot(0, this, SLOT(pcVersionInfo()));
+}
+
+void SysInfoConduit::pcVersionInfo()
+{
+ FUNCTIONSETUP;
+ if (fKDEVersion) {
+ /* Retrieve values for
+ * - #os#
+ * - #qt#
+ * - #kde#
+ * - #kpilot#
+ * - #pilotlink#
+ */
+ fValues[CSL1("kpilot")] = QString::fromLatin1(KPILOT_VERSION);
+ fValues[CSL1("kde")] = i18n("unknown");
+ fValues[CSL1("qt")] = i18n("unknown");
+ fValues[CSL1("os")] = i18n("unknown");
+ fValues[CSL1("hostname")] = i18n("unknown");
+ struct utsname name;
+ if (uname (&name) >= 0) {
+ fValues[CSL1("os")] = CSL1("%1 %3, %5")
+ .arg(QString::fromLatin1(name.sysname))
+ .arg(QString::fromLatin1(name.release))
+ .arg(QString::fromLatin1(name.machine));
+ fValues[CSL1("hostname")] = CSL1("%2").arg(QString::fromLatin1(name.nodename));
+ }
+#ifdef KDE_VERSION_STRING
+ fValues[CSL1("kde")] = QString::fromLatin1(KDE_VERSION_STRING);
+#endif
+#ifdef QT_VERSION_STR
+ fValues[CSL1("qt")] = QString::fromLatin1(QT_VERSION_STR);
+#endif
+ fValues[CSL1("pilotlink")] = CSL1("%1.%2.%3%4")
+ .arg(PILOT_LINK_VERSION)
+ .arg(PILOT_LINK_MAJOR)
+ .arg(PILOT_LINK_MINOR)
+#ifdef PILOT_LINK_PATCH
+ .arg(QString::fromLatin1(PILOT_LINK_PATCH));
+#else
+ .arg(QString());
+#endif
+ keepParts.append(CSL1("pcversion"));
+ } else removeParts.append(CSL1("pcversion"));
+ QTimer::singleShot(0, this, SLOT(palmVersionInfo()));
+}
+
+void SysInfoConduit::palmVersionInfo()
+{
+ FUNCTIONSETUP;
+ if (fPalmOSVersion) {
+ /* Retrieve values for
+ * - #palmos#
+ */
+/* fValues["palmos"] = QString("PalmOS %1.%2 (compat %3.%4)")
+ .arg(fHandle->getSysInfo()->getMajorVersion())
+ .arg(fHandle->getSysInfo()->getMinorVersion())
+ .arg(fHandle->getSysInfo()->getCompatMajorVersion())
+ .arg(fHandle->getSysInfo()->getCompatMinorVersion());*/
+ KPilotSysInfo i = deviceLink()->getSysInfo();
+ fValues[CSL1("palmos")] = CSL1("PalmOS %1.%2").arg(i.getMajorVersion()).arg(i.getMinorVersion());
+
+ keepParts.append(CSL1("palmversion"));
+ } else removeParts.append(CSL1("palmversion"));
+ QTimer::singleShot(0, this, SLOT(debugInfo()));
+}
+
+void SysInfoConduit::debugInfo()
+{
+ FUNCTIONSETUP;
+ if (fDebugInfo) {
+ /* Retrieve values for
+ * - #debug#
+ */
+ fValues[CSL1("debug")] = i18n("No debug data");
+ keepParts.append(CSL1("debug"));
+ } else removeParts.append(CSL1("debug"));
+ QTimer::singleShot(0, this, SLOT(writeFile()));
+}
+
+void SysInfoConduit::writeFile()
+{
+ FUNCTIONSETUP;
+
+ fValues[CSL1("date")] = QDateTime::currentDateTime().toString(Qt::LocalDate);
+
+ QString output;
+ // Open the template file
+ QString templatefile;
+ switch(fOutputType)
+ {
+ case eOutputText:
+ templatefile=locate("data", CSL1("kpilot/sysinfoconduit/Template.txt"));
+ break;
+ case eOutputTemplate:
+ templatefile=fTemplateFile;
+ break;
+ case eOutputHTML:
+ default:
+ templatefile=locate("data", CSL1("kpilot/sysinfoconduit/Template.html"));
+ break;
+ }
+
+ // Read in the template, close the file
+ bool loaded=false;
+ if (!templatefile.isEmpty()){
+#ifdef DEBUG
+ DEBUGKPILOT<<"Loading template file "<<templatefile<<endl;
+#endif
+ QFile infile(templatefile);
+ if (infile.open(IO_ReadOnly)) {
+ QTextStream instream(&infile);
+ output = instream.read();
+ infile.close();
+ loaded=true;
+ }
+ }
+
+ if (!loaded)
+ {
+ WARNINGKPILOT << "Loading template file " << templatefile
+ <<" failed. Using default template instead." << endl;
+ output=defaultpage;
+ }
+
+ // Remove all parts not extracted
+ for ( QStringList::Iterator it = removeParts.begin(); it != removeParts.end(); ++it ) {
+ QRegExp re(CSL1("<!--#if%1#.*#endif%1#-->").arg(*it).arg(*it));
+ re.setMinimal(true);
+ output.remove(re);
+ }
+ for ( QStringList::Iterator it = keepParts.begin(); it != keepParts.end(); ++it ) {
+ QRegExp re(CSL1("<!--#if%1#(.*)#endif%1#-->").arg(*it).arg(*it));
+ re.setMinimal(true);
+ output.replace(re, CSL1("\\1"));
+ }
+
+ // Do a loop through all keys in fValues
+ QMap<QString,QString>::Iterator it;
+ for ( it = fValues.begin(); it != fValues.end(); ++it ) {
+ output.replace(CSL1("#%1#").arg(it.key()), it.data());
+ }
+
+ // Insert the list of databases
+ QRegExp re(CSL1("#dblist\\[(.*)\\]#"));
+ re.setMinimal(true);
+ while (re.search(output)>=0){
+ QString dbstring;
+ QString subpatt=re.cap(1);
+ for (KPilotLink::DBInfoList::ConstIterator i = dblist.begin(); i != dblist.end(); ++i ) {
+ DBInfo dbi = *i;
+ QString newpatt(subpatt);
+ char tmpchr[5];
+ ::memset(&tmpchr[0], 0, 5);
+ /* Patterns for the dblist argument:
+ * %0 .. Database name
+ * %1 .. type
+ * %2 .. creator
+ * %3 .. index
+ * %4 .. flags
+ * %5 .. miscFlags
+ * %6 .. version
+ * %7 .. createDate
+ * %8 .. modifyDate
+ * %9 .. backupDate
+ */
+ newpatt.replace(CSL1("%0"), QString::fromLatin1(dbi.name));
+ set_long(&tmpchr[0],dbi.type);
+ newpatt.replace(CSL1("%1"), QString::fromLatin1(tmpchr));
+ set_long(&tmpchr[0],dbi.creator);
+ newpatt.replace(CSL1("%2"), QString::fromLatin1(tmpchr));
+ newpatt.replace(CSL1("%3"), QString::number(dbi.index));
+ newpatt.replace(CSL1("%4"), QString::number(dbi.flags));
+ newpatt.replace(CSL1("%5"), QString::number(dbi.miscFlags));
+ newpatt.replace(CSL1("%6"), QString::number(dbi.version));
+ QDateTime tm;
+ tm.setTime_t(dbi.createDate);
+ newpatt.replace(CSL1("%7"), tm.toString(Qt::LocalDate));
+ tm.setTime_t(dbi.modifyDate);
+ newpatt.replace(CSL1("%8"), tm.toString(Qt::LocalDate));
+ tm.setTime_t(dbi.backupDate);
+ newpatt.replace(CSL1("%9"), tm.toString(Qt::LocalDate));
+
+ dbstring.append(newpatt);
+ }
+ // Now, just replace the whole found pattern by the string we just constructed.
+ output.replace(re.cap(0), dbstring);
+ }
+
+ // Write out the result
+ QFile outfile(fOutputFile);
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Writing file <" << fOutputFile << ">" << endl;
+#endif
+ if (fOutputFile.isEmpty() || (!outfile.open(IO_WriteOnly)) ) {
+ QFileInfo fi(QDir::home(), CSL1("KPilotSysInfo.")+QFileInfo(templatefile).extension() );
+ fOutputFile=fi.absFilePath();
+ WARNINGKPILOT << "Unable to open output file, using " << fOutputFile << " instead." << endl;
+ emit logMessage(i18n("Unable to open output file, using %1 instead.").arg(fOutputFile));
+ outfile.setName(fOutputFile);
+ if (!outfile.open(IO_WriteOnly)) {
+ WARNINGKPILOT<< "Unable to open " << fOutputFile << endl;
+ emit logError(i18n("Unable to open %1").arg(fOutputFile));
+ QTimer::singleShot(0, this, SLOT(cleanup()));
+ return;
+ }
+ }
+
+ // Finally, write the actual text out to the file.
+ QTextStream outstream(&outfile);
+ outstream<<output;
+ outfile.close();
+
+ emit logMessage(i18n("Handheld system information written to the file %1").arg(fOutputFile));
+ QTimer::singleShot(0, this, SLOT(cleanup()));
+}
+
+void SysInfoConduit::cleanup()
+{
+ FUNCTIONSETUP;
+ // Nothing to clean up so far (Do I have memory leaks somewhere?)
+ emit syncDone(this);
+}
diff --git a/kpilot/conduits/sysinfoconduit/sysinfo-conduit.h b/kpilot/conduits/sysinfoconduit/sysinfo-conduit.h
new file mode 100644
index 000000000..05bc395d3
--- /dev/null
+++ b/kpilot/conduits/sysinfoconduit/sysinfo-conduit.h
@@ -0,0 +1,79 @@
+#ifndef _SysInfo_CONDUIT_H
+#define _SysInfo_CONDUIT_H
+/* sysinfo-conduit.h KPilot
+**
+** Copyright (C) 2003 by Reinhold Kainhofer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include <plugin.h>
+
+class SysInfoConduit : public ConduitAction
+{
+ Q_OBJECT
+public:
+ SysInfoConduit(
+ KPilotLink *o,
+ const char *n = 0L,
+ const QStringList &a = QStringList() );
+ virtual ~SysInfoConduit();
+ virtual bool exec();
+
+public slots:
+ void hardwareInfo();
+ void userInfo();
+ void memoryInfo();
+ void storageInfo();
+ void dbListInfo();
+ void recNumberInfo();
+ void syncInfo();
+ void pcVersionInfo();
+ void palmVersionInfo();
+ void debugInfo();
+ void writeFile();
+ void cleanup();
+
+protected:
+ void readConfig();
+private:
+ QMap<QString,QString> fValues;
+
+ bool fHardwareInfo, fUserInfo, fMemoryInfo, fStorageInfo,
+ fDBList, fRecordNumber, fSyncInfo,
+ fKDEVersion, fPalmOSVersion, fDebugInfo;
+ QString fOutputFile, fTemplateFile;
+ enum eOutputTypeEnum {
+ eOutputHTML=0,
+ eOutputText,
+ eOutputTemplate
+ } fOutputType;
+
+ KPilotLink::DBInfoList dblist;
+ QStringList removeParts;
+ QStringList keepParts;
+ static const QString defaultpage;
+} ;
+
+#endif
diff --git a/kpilot/conduits/sysinfoconduit/sysinfo-factory.cc b/kpilot/conduits/sysinfoconduit/sysinfo-factory.cc
new file mode 100644
index 000000000..d03dc0b04
--- /dev/null
+++ b/kpilot/conduits/sysinfoconduit/sysinfo-factory.cc
@@ -0,0 +1,43 @@
+/* SysInfo-factory.cc KPilot
+**
+** Copyright (C) 2003 by Reinhold Kainhofer
+**
+** This file defines the factory for the SysInfo-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+#include "pluginfactory.h"
+
+#include "sysinfo-conduit.h"
+#include "sysinfo-setup.h"
+
+extern "C"
+{
+
+void *init_conduit_sysinfo()
+{
+ return new ConduitFactory<SysInfoWidgetConfig,SysInfoConduit>;
+}
+
+}
diff --git a/kpilot/conduits/sysinfoconduit/sysinfo-factory.h b/kpilot/conduits/sysinfoconduit/sysinfo-factory.h
new file mode 100644
index 000000000..66ae5ae38
--- /dev/null
+++ b/kpilot/conduits/sysinfoconduit/sysinfo-factory.h
@@ -0,0 +1,36 @@
+#ifndef _SYSINFO_FACTORY_H
+#define _SYSINFO_FACTORY_H
+/* SysInfo-factory.h KPilot
+**
+** Copyright (C) 2003 by Reinhold Kainhofer
+**
+** This file defines the factory for the SysInfo-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+extern "C"
+{
+ void *init_libsysinfoconduit();
+}
+
+#endif
diff --git a/kpilot/conduits/sysinfoconduit/sysinfo-setup.cc b/kpilot/conduits/sysinfoconduit/sysinfo-setup.cc
new file mode 100644
index 000000000..ed7419ab3
--- /dev/null
+++ b/kpilot/conduits/sysinfoconduit/sysinfo-setup.cc
@@ -0,0 +1,198 @@
+/* SysInfo-setup.cc KPilot
+**
+** Copyright (C) 2003 by Reinhold Kainhofer
+**
+** This file defines the setup dialog for the SysInfo-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qtabwidget.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qbuttongroup.h>
+#include <qlistview.h>
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kurlrequester.h>
+
+#include "sysinfo-setup_dialog.h"
+
+#include "sysinfo-factory.h"
+#include "sysinfo-setup.h"
+#include "sysinfoSettings.h"
+
+
+typedef struct { const char *name; bool (*accessor)(); void (*mutator)(bool); } sysinfoEntry_t;
+
+const sysinfoEntry_t sysinfoEntries[] =
+{
+ { I18N_NOOP("HardwareInfo"), SysinfoSettings::hardwareInfo, SysinfoSettings::setHardwareInfo },
+ { I18N_NOOP("UserInfo"), SysinfoSettings::userInfo, SysinfoSettings::setUserInfo },
+ { I18N_NOOP("MemoryInfo"), SysinfoSettings::memoryInfo, SysinfoSettings::setMemoryInfo },
+ { I18N_NOOP("StorageInfo"), SysinfoSettings::storageInfo, SysinfoSettings::setStorageInfo },
+ { I18N_NOOP("DatabaseList"), SysinfoSettings::databaseList, SysinfoSettings::setDatabaseList },
+ { I18N_NOOP("RecordNumbers"), SysinfoSettings::recordNumbers, SysinfoSettings::setRecordNumbers},
+ { I18N_NOOP("SyncInfo"), SysinfoSettings::syncInfo, SysinfoSettings::setSyncInfo },
+ { I18N_NOOP("KDEVersion"), SysinfoSettings::kDEVersion, SysinfoSettings::setKDEVersion },
+ { I18N_NOOP("PalmOSVersion"), SysinfoSettings::palmOSVersion, SysinfoSettings::setPalmOSVersion },
+ { I18N_NOOP("DebugInformation"), SysinfoSettings::debugInformation, SysinfoSettings::setDebugInformation },
+ { 0L, 0L, 0L }
+} ;
+
+
+/*
+** The QCheckListItems used in the list of parts to print have
+** several text fields with special meanings.
+** 0: The text displayed in the list.
+** 1: The index of the item in the sysinfoEntries array.
+** 2: This string is empty if the part was originally not checked,
+** and non-empty (probably "1") if the part was originally checked.
+** This is used to detect changes in the configuration.
+** We introduce some defines for these numbers.
+*/
+
+#define PART_NAME (0)
+#define PART_KEY (1)
+#define PART_SETTING (2)
+
+/*
+** This is a convenience define to update an item's "original setting".
+*/
+#define updateSetting(i) { QCheckListItem *ubbu=(i); \
+ ubbu->setText(PART_SETTING,(ubbu->isOn() ? CSL1("1") : QString::null)); }
+
+
+SysInfoWidgetConfig::SysInfoWidgetConfig(QWidget *w, const char *n) :
+ ConduitConfigBase(w,n),
+ fConfigWidget(new SysInfoWidget(w))
+{
+ FUNCTIONSETUP;
+
+ KAboutData *fAbout = new KAboutData("SysInfoConduit",
+ I18N_NOOP("KPilot System Information conduit"),
+ KPILOT_VERSION,
+ I18N_NOOP("Retrieves System, Hardware, and User Info from the Handheld and stores them to a file."),
+ KAboutData::License_GPL,
+ "(C) 2003, Reinhold Kainhofer");
+ fAbout->addAuthor("Reinhold Kainhofer",
+ I18N_NOOP("Primary Author"), "[email protected]", "http://reinhold.kainhofer.com/");
+
+ ConduitConfigBase::addAboutPage(fConfigWidget->tabWidget,fAbout);
+ fWidget=fConfigWidget;
+
+ QObject::connect(fConfigWidget->fOutputFile,SIGNAL(textChanged(const QString&)),
+ this,SLOT(modified()));
+ QObject::connect(fConfigWidget->fTemplateFile,SIGNAL(textChanged(const QString&)),
+ this,SLOT(modified()));
+ QObject::connect(fConfigWidget->fOutputType,SIGNAL(clicked(int)),
+ this,SLOT(modified()));
+ fConduitName=i18n("System Information");
+}
+
+void SysInfoWidgetConfig::commit()
+{
+ FUNCTIONSETUP;
+
+ SysinfoSettings::setOutputFile(
+ fConfigWidget->fOutputFile->url() );
+ SysinfoSettings::setTemplateFile(
+ fConfigWidget->fTemplateFile->url() );
+ SysinfoSettings::setOutputFormat(
+ fConfigWidget->fOutputType->id(fConfigWidget->fOutputType->selected()));
+
+ QListViewItem *i = fConfigWidget->fPartsList->firstChild();
+ QCheckListItem *ci = dynamic_cast<QCheckListItem *>(i);
+ while(ci)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Saving " << ci->text(PART_NAME)
+ << (ci->isOn() ? " on" : " off") << endl;
+#endif
+ int index=ci->text(PART_KEY).toInt();
+ if (0<=index && index<=10)
+ {
+ const sysinfoEntry_t *p = sysinfoEntries+index;
+ p->mutator(ci->isOn());
+ }
+ updateSetting(ci);
+ i=i->nextSibling();
+ ci = dynamic_cast<QCheckListItem *>(i);
+ }
+ SysinfoSettings::self()->writeConfig();
+ unmodified();
+}
+
+void SysInfoWidgetConfig::load()
+{
+ FUNCTIONSETUP;
+ SysinfoSettings::self()->readConfig();
+
+ const sysinfoEntry_t *p = sysinfoEntries;
+ QCheckListItem *i = 0L;
+ while (p && p->name)
+ {
+ i = new QCheckListItem(fConfigWidget->fPartsList,i18n(p->name),QCheckListItem::CheckBox);
+ // by default let the sysinfo conduit write out all available information
+ i->setOn( p->accessor() );
+ i->setText(PART_KEY, QString::number(p-sysinfoEntries)); // store index there
+ updateSetting(i);
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Loaded " << p->name
+ << (i->isOn() ? " on" : " off") << endl;
+#endif
+
+ p++;
+ }
+ fConfigWidget->fOutputFile->setURL( SysinfoSettings::outputFile() );
+ fConfigWidget->fTemplateFile->setURL( SysinfoSettings::templateFile() );
+ fConfigWidget->fOutputType->setButton( SysinfoSettings::outputFormat() );
+ unmodified();
+}
+
+/* virtual */ bool SysInfoWidgetConfig::isModified() const
+{
+ FUNCTIONSETUP;
+ if (fModified) return true;
+
+ QListViewItem *i = fConfigWidget->fPartsList->firstChild();
+ QCheckListItem *ci = dynamic_cast<QCheckListItem *>(i);
+
+ while(ci)
+ {
+ bool current = ci->isOn();
+ bool original = !ci->text(PART_SETTING).isEmpty();
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Checking " << ci->text(PART_KEY)
+ << " was " << (original ? " on" : " off")
+ << " now " << (current ? " on" : " off") << endl;
+#endif
+
+ if (current!=original) return true;
+ i=i->nextSibling();
+ ci = dynamic_cast<QCheckListItem *>(i);
+ }
+ return false;
+}
diff --git a/kpilot/conduits/sysinfoconduit/sysinfo-setup.h b/kpilot/conduits/sysinfoconduit/sysinfo-setup.h
new file mode 100644
index 000000000..41e55eb86
--- /dev/null
+++ b/kpilot/conduits/sysinfoconduit/sysinfo-setup.h
@@ -0,0 +1,47 @@
+#ifndef _SysInfo_SysInfo_SETUP_H
+#define _SysInfo_SysInfo_SETUP_H
+/* sysinfo-setup.h KPilot
+**
+** Copyright (C) 2003 by Reinhold Kainhofer
+**
+** This file defines the widget and behavior for the config dialog
+** of the KNotes conduit.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "plugin.h"
+
+class SysInfoWidget;
+
+class SysInfoWidgetConfig : public ConduitConfigBase
+{
+public:
+ SysInfoWidgetConfig(QWidget *parent, const char *);
+ virtual void commit();
+ virtual void load();
+ virtual bool isModified() const;
+protected:
+ SysInfoWidget *fConfigWidget;
+} ;
+
+#endif
diff --git a/kpilot/conduits/sysinfoconduit/sysinfo-setup_dialog.ui b/kpilot/conduits/sysinfoconduit/sysinfo-setup_dialog.ui
new file mode 100644
index 000000000..e4502bb1e
--- /dev/null
+++ b/kpilot/conduits/sysinfoconduit/sysinfo-setup_dialog.ui
@@ -0,0 +1,214 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>SysInfoWidget</class>
+<author>Reinhold Kainhofer</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Form2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>330</width>
+ <height>232</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="3" column="1">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>51</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KURLRequester" row="0" column="1">
+ <property name="name">
+ <cstring>fOutputFile</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter here, or select by clicking the file picker button, the location and file name of the output file used to store the handheld's system information.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Output &amp;file:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fOutputFile</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter here, or select by clicking the file picker button, the location and file name of the output file used to store the handheld's system information.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fOutputType</cstring>
+ </property>
+ <property name="title">
+ <string>Type of Output</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>radioButton3</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;HTML</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to output the system information data as a HTML document.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>radioButton4</cstring>
+ </property>
+ <property name="text">
+ <string>Te&amp;xt file</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to output the system information data as a text document.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="2" column="1">
+ <property name="name">
+ <cstring>fTemplateFile</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter here, or select by clicking on the file picker button, the location of the template to be used if you select the Custom template option.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="2" column="0">
+ <property name="name">
+ <cstring>radioButton5</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Custom template:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to output the system information data as defined by a custom template. Enter the location of the template in the edit box, or select it clicking on the file picker button.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Parts Included</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QListView" row="0" column="0">
+ <column>
+ <property name="text">
+ <string>Output Type</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>fPartsList</cstring>
+ </property>
+ <property name="resizeMode">
+ <enum>LastColumn</enum>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check on this list the types of information about your system and handheld you want to display in the output file.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>radioButton5</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>fTemplateFile</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>tabWidget</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includes>
+ <include location="global" impldecl="in implementation">kurlrequester.h</include>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+ <include location="global" impldecl="in implementation">kpushbutton.h</include>
+</includes>
+</UI>
diff --git a/kpilot/conduits/sysinfoconduit/sysinfoSettings.kcfgc b/kpilot/conduits/sysinfoconduit/sysinfoSettings.kcfgc
new file mode 100644
index 000000000..09337f301
--- /dev/null
+++ b/kpilot/conduits/sysinfoconduit/sysinfoSettings.kcfgc
@@ -0,0 +1,7 @@
+File=sysinfoconduit.kcfg
+ClassName=SysinfoSettings
+Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/conduits/sysinfoconduit/sysinfo_conduit.desktop b/kpilot/conduits/sysinfoconduit/sysinfo_conduit.desktop
new file mode 100644
index 000000000..7e7b04380
--- /dev/null
+++ b/kpilot/conduits/sysinfoconduit/sysinfo_conduit.desktop
@@ -0,0 +1,111 @@
+[Desktop Entry]
+Type=Service
+Comment=This conduit writes information about your handheld and the sync to a file.
+Comment[af]=Hierdie pad skryf informasie aangaande die draagbare toestel en sinkronisasie na 'n lêer.
+Comment[bg]=Запис на информацията относно мобилното устройство във файл
+Comment[bs]=Ovaj conduit ispisuje informacije o ručnom računaru i sinhronizuje ih sa datotekom.
+Comment[ca]=Aquest conducte escriu informació a un fitxer a sobre de la vostra agenda electrònica i la sincronització.
+Comment[cs]=Toto propojení zapisuje informace o vašem handheldu a synchronizaci do souboru.
+Comment[cy]=Mae'r cwndid yma yn ysgrifennu gwybodaeth ynglyn â'ch llawiadur a'r cydamseriad i ffeil.
+Comment[da]=Denne kanal skriver information om din håndholdte og synkroniseringen til en fil.
+Comment[de]=Schreibt Daten zum Taschencomputer und den Abgleich in eine Datei
+Comment[el]=Αυτός ο σύνδεσμος γράφει πληροφορίες σχετικά με τον υπολογιστή παλάμης σας και το συγχρονισμό προς ένα αρχείο.
+Comment[es]=Este conducto escribe la información subre su agenda electrónica y la sincronización a un archivo.
+Comment[et]=See kanal salvestab info pihuarvuti kohta failina.
+Comment[eu]=Kanal honek zure agenda elektronikoari buruzko informazioa eta sinkronizazio fitxategi batean gordetzen ditu.
+Comment[fa]=این لوله، اطلاعات دربارۀ دستی شما و ترکیب‌دهی به پرونده را می‌نویسد.
+Comment[fi]=Tämä yhdyskäytävä kirjoittaa tietoja taskutietokoneelta ja synkronoi ne tiedostoon.
+Comment[fr]=Ce canal écrit des informations sur votre périphérique et la synchronisation dans un fichier.
+Comment[fy]=Dit conduit bewarret ynformaasje oer jo handheld en syngronosaasje yn in triem.
+Comment[gl]=Este conducto escribe a información sobre o seu aparello portátil e a sincronización a un ficheiro.
+Comment[hi]=यह कन्ड्यूइट आपके हैंण्डहेल्ड के बारे में जानकारी लिखता है तथा एक फ़ाइल में सिंक करता है.
+Comment[hu]=Ezzel a csatolóval fájlba lehet kiíratni a kéziszámítógép és a szinkronizálás jellemzőit
+Comment[is]=Þessi rás skrifar upplýsingar um lófatölvuna þína og samstillinguna í skrá.
+Comment[it]=Questo conduit scrive in un file informazioni sul tuo palmare.
+Comment[ja]=このコンジットはあなたのハンドヘルドの情報を書き出し、ファイルに同期します。
+Comment[ka]=ეს არხი ინფორმაციას წერს თქვენი პორტატიული მოწყობილობის შესახებ და ახდენს მის სინქრონიზაციას ფაილთან.
+Comment[kk]=Қалта құрылғыңыз туралы мәліметті файла жазу арнасы.
+Comment[km]=បំពង់​នេះ​សរសេរ​ព័ត៌មាន​អំពី​ឧបករណ៍​យួរដៃ​របស់​អ្នក និង​ការ​ធ្វើ​សមកាលកម្ម ទៅ​ឯកសារ​មួយ ។
+Comment[lt]=Šis kanalas įrašo informaciją apie delninuką ir sinchronizavimą į bylą.
+Comment[ms]=Saluran ini menulis maklumat tentang komputer telapak dan segerakan ke fail.
+Comment[nb]=Denne kanalen skriver informasjon om PDA-en og synkroniseringen til en fil.
+Comment[nds]=De Kanaal schrifft Informatschonen över den Handreekner un de Synkroniseren na en Datei.
+Comment[ne]=यो कन्ड्युटले ह्यान्डहेल्ड बारेमा सूचना लेख्दछ र फाइलमा सिन्क गर्दछ ।
+Comment[nl]=Dit conduit slaat informatie over uw handheld en de synchronisatie op in een bestand.
+Comment[nn]=Denne koplinga skriv informasjon om den handheldte eininga di og synkroniseringa til ei fil.
+Comment[pl]=Ten łącznik zapisuje informacje o twoim palmtopie i przebiegu synchronizacji do pliku.
+Comment[pt]=Esta conduta escreve informações sobre o seu dispositivo e a sincronização para um ficheiro.
+Comment[pt_BR]=Este conduíte escreve informação sobre o seu handheld e a sincronização em um arquivo.
+Comment[ru]=Канал передачи системной информации с КПК и записи в файл.
+Comment[sk]=Táto spojka zobrazuje informácie o vašom prenosnom zariadení a ukladá ich do súboru.
+Comment[sl]=Ta veznik zapiše podatke o vašem ročnem računalniku in usklajevanju v datoteko.
+Comment[sr]=Овај провод записује информације о вашем ручном рачунару и синхронизује са фајлом.
+Comment[sr@Latn]=Ovaj provod zapisuje informacije o vašem ručnom računaru i sinhronizuje sa fajlom.
+Comment[sv]=Den här kanalen skriver information om handdatorn och synkroniseringen till en fil.
+Comment[ta]=இந்த காப்புக் குழாய் உங்கள் கையேட்டைப் பற்றிய தகவல்களையும் ஒத்திசைவையும் கோப்புக்கு எழுதுகிறது
+Comment[tg]=Канали таҳвили иттилооти системавӣ аз Pilot ва қайдкунӣ ба файл
+Comment[tr]=Bu bileşen, el bilgisayarınızın bilgilerini bir dosyaya yazar.
+Comment[uk]=Цей акведук записує інформацію про кишеньковий пристрій і синхронізацію у файл.
+Comment[zh_CN]=此管道写入您手持设备的信息,并同步至一文件。
+Comment[zh_TW]=此軟體將您的 handheld 資訊寫入檔案。
+Name=System Information
+Name[af]=Stelsel informasie
+Name[ar]=معلومات عن النظام
+Name[be]=Сыстэмная інфармацыя
+Name[bg]=Системна информация
+Name[br]=Titouroù diwar-benn ar reizhiad
+Name[bs]=Sistemske informacije
+Name[ca]=Sistema d'informació
+Name[cs]=Informace o systému
+Name[cy]=Gwybodaeth Gysawd
+Name[da]=Systeminformation
+Name[de]=System-Information
+Name[el]=Πληροφορίες συστήματος
+Name[eo]=Sisteminformoj
+Name[es]=Información del sistema
+Name[et]=Süsteemi info
+Name[eu]=Sistemaren informazioa
+Name[fa]=اطلاعات سیستم
+Name[fi]=Järjestelmätiedot
+Name[fr]=Informations sur le système
+Name[fy]=Systeemynformaasje
+Name[ga]=Faisnéis Córais
+Name[gl]=Información do Sistema
+Name[hi]=तंत्र जानकारी
+Name[hu]=Rendszerinformáció
+Name[is]=Kerfisupplýsingar
+Name[it]=Informazioni di sistema
+Name[ja]=システム情報
+Name[ka]=სისტემის ინფორმაცია
+Name[kk]=Жүйелік мәлімет
+Name[km]=ព័ត៌មាន​អំពី​ប្រព័ន្ធ
+Name[lt]=Sistemos informacija
+Name[mk]=Информации за системот
+Name[ms]=Maklumat Sistem
+Name[nb]=Systeminformasjon
+Name[nds]=Systeem-Informatschoon
+Name[ne]=प्रणाली सूचना
+Name[nl]=Systeeminformatie
+Name[nn]=Systeminformasjon
+Name[pl]=Informacja systemowa
+Name[pt]=Informação do Sistema
+Name[pt_BR]=Informação do Sistema
+Name[ro]=Informaţii de sistem
+Name[ru]=Информация о системе
+Name[se]=Vuogádatdieđut
+Name[sk]=Informácie o systéme
+Name[sl]=Sistemske informacije
+Name[sr]=Информације о систему
+Name[sr@Latn]=Informacije o sistemu
+Name[sv]=Systeminformation
+Name[ta]=அமைப்பு தகவல்
+Name[tg]=Иттилоот дар бораи система
+Name[tr]=Sistem Bilgisi
+Name[uk]=Системна інформація
+Name[uz]=Tizim haqida maʼlumot
+Name[uz@cyrillic]=Тизим ҳақида маълумот
+Name[zh_CN]=系统信息
+Name[zh_TW]=系統資訊
+Implemented=file
+ServiceTypes=KPilotConduit
+X-KDE-Library=conduit_sysinfo
diff --git a/kpilot/conduits/sysinfoconduit/sysinfoconduit.kcfg b/kpilot/conduits/sysinfoconduit/sysinfoconduit.kcfg
new file mode 100644
index 000000000..20d8cc24d
--- /dev/null
+++ b/kpilot/conduits/sysinfoconduit/sysinfoconduit.kcfg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kpilot_sysinfoconduitrc"/>
+ <group name="General">
+ <entry name="OutputFile" key="Output file" type="Path">
+ <default>$HOME/kpilot-syslog.html</default>
+ </entry>
+ <entry name="OutputFormat" key="Output format" type="Enum">
+ <choices>
+ <choice name="eSysInfoHTML"/>
+ <choice name="eSysInfoText"/>
+ <choice name="eSysInfoTemplate"/>
+ </choices>
+ <default>eSysInfoHTML</default>
+ </entry>
+ <entry name="TemplateFile" key="Template file" type="Path">
+ <default></default>
+ </entry>
+ <entry name="DebugInformation" key="Debug Information" type="Bool">
+ <label>Debug information (for KPilot developers)</label>
+ <default>true</default>
+ </entry>
+ <entry name="HardwareInfo" key="Hardware Info" type="Bool">
+ <label>Hardware information</label>
+ <default>true</default>
+ </entry>
+ <entry name="DatabaseList" key="Database List" type="Bool">
+ <label>List of databases on handheld (takes long!)</label>
+ <default>true</default>
+ </entry>
+ <entry name="MemoryInfo" key="Memory Info" type="Bool">
+ <label>Memory information</label>
+ <default>true</default>
+ </entry>
+ <entry name="RecordNumbers" key="Record Numbers" type="Bool">
+ <label>Number of addresses, todos, events and memos</label>
+ <default>true</default>
+ </entry>
+ <entry name="PalmOSVersion" key="PalmOS Version" type="Bool">
+ <label>PalmOS version</label>
+ <default>true</default>
+ </entry>
+ <entry name="StorageInfo" key="Storage Info" type="Bool">
+ <label>Storage info (SD card, memory stick, ...)</label>
+ <default>true</default>
+ </entry>
+ <entry name="SyncInfo" key="Sync Info" type="Bool">
+ <label>Synchronization information</label>
+ <default>true</default>
+ </entry>
+ <entry name="UserInfo" key="User Info" type="Bool">
+ <label>User information</label>
+ <default>true</default>
+ </entry>
+ <entry name="KDEVersion" key="KDE Version" type="Bool">
+ <label>Version of KPilot, pilot-link and KDE</label>
+ <default>true</default>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kpilot/conduits/timeconduit/CMakeLists.txt b/kpilot/conduits/timeconduit/CMakeLists.txt
new file mode 100644
index 000000000..e980e724f
--- /dev/null
+++ b/kpilot/conduits/timeconduit/CMakeLists.txt
@@ -0,0 +1,44 @@
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+set(conduit_time_SRCS
+ time-conduit.cc
+ time-factory.cc
+ time-setup.cc
+)
+
+set(conduit_time_UIS
+ time-setup_dialog.ui
+)
+
+set(conduit_time_KCFGS
+ timeConduitSettings.kcfgc
+)
+
+kde3_add_kcfg_files(conduit_time_SRCS ${conduit_time_KCFGS})
+kde3_add_ui_files(conduit_time_SRCS ${conduit_time_UIS})
+kde3_automoc(${conduit_time_SRCS})
+add_library(conduit_time SHARED ${conduit_time_SRCS})
+
+kpilot_rpath(conduit_time)
+
+set_target_properties(
+ conduit_time PROPERTIES LOCATION ${KDE3_PLUGIN_INSTALL_DIR}
+ PREFIX ""
+)
+
+kde3_install_libtool_file(conduit_time)
+
+install(
+ TARGETS conduit_time
+ LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR}
+)
+
+install(
+ FILES time_conduit.desktop DESTINATION ${KDE3_SERVICES_DIR}
+)
+
+install(
+ FILES timeconduit.kcfg DESTINATION ${KDE3_KCFG_DIR}
+)
diff --git a/kpilot/conduits/timeconduit/Makefile.am b/kpilot/conduits/timeconduit/Makefile.am
new file mode 100644
index 000000000..6a58716a5
--- /dev/null
+++ b/kpilot/conduits/timeconduit/Makefile.am
@@ -0,0 +1,22 @@
+### Makefile for the time conduit
+###
+### The time conduit is Copyright (C) 2002 by Reinhold Kainhofer
+
+INCLUDES= $(PISOCK_INCLUDE) -I$(top_srcdir)/kpilot/lib $(all_includes)
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = time_conduit.desktop
+
+kde_module_LTLIBRARIES = conduit_time.la
+
+
+conduit_time_la_SOURCES = timeConduitSettings.kcfgc \
+ time-factory.cc \
+ time-setup.cc \
+ time-conduit.cc \
+ time-setup_dialog.ui
+conduit_time_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+conduit_time_la_LIBADD = ../../lib/libkpilot.la $(LIB_KDEUI)
+
+kde_kcfg_DATA = timeconduit.kcfg
diff --git a/kpilot/conduits/timeconduit/time-conduit.cc b/kpilot/conduits/timeconduit/time-conduit.cc
new file mode 100644
index 000000000..c1455b359
--- /dev/null
+++ b/kpilot/conduits/timeconduit/time-conduit.cc
@@ -0,0 +1,121 @@
+/* KPilot
+**
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected].
+*/
+
+#include "options.h"
+
+#include <time.h>
+
+#include <pilotSysInfo.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+
+#include "time-factory.h"
+#include "time-conduit.h"
+#include "timeConduitSettings.h"
+
+
+// Something to allow us to check what revision
+// the modules are that make up a binary distribution.
+extern "C"
+{
+unsigned long version_conduit_time = Pilot::PLUGIN_API ;
+}
+
+
+
+TimeConduit::TimeConduit(KPilotLink * o,
+ const char *n,
+ const QStringList & a) :
+ ConduitAction(o, n, a)
+{
+ FUNCTIONSETUP;
+ fConduitName=i18n("Time");
+}
+
+
+
+TimeConduit::~TimeConduit()
+{
+ FUNCTIONSETUP;
+}
+
+
+
+void TimeConduit::readConfig()
+{
+ FUNCTIONSETUP;
+ TimeConduitSettings::self()->readConfig();
+}
+
+
+/* virtual */ bool TimeConduit::exec()
+{
+ FUNCTIONSETUP;
+
+ readConfig();
+
+ if (syncMode().isLocal())
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Would have set time to "
+ << QDateTime::currentDateTime().toString() << endl;
+#endif
+ return delayDone();
+ }
+
+ emit logMessage(i18n("Setting the clock on the handheld"));
+ syncHHfromPC();
+ return delayDone();
+}
+
+
+void TimeConduit::syncHHfromPC()
+{
+ FUNCTIONSETUP;
+ time_t ltime;
+ time(&ltime);
+
+ long int major=fHandle->getSysInfo().getMajorVersion(),
+ minor=fHandle->getSysInfo().getMinorVersion();
+
+ if (major==3 && (minor==25 || minor==30))
+ {
+ emit logMessage(i18n("PalmOS 3.25 and 3.3 do not support setting the system time. Skipping the time conduit..."));
+ return;
+ }
+
+ int sd = pilotSocket();
+ if ( sd > 0 )
+ {
+ dlp_SetSysDateTime( sd, ltime );
+ }
+ else
+ {
+ WARNINGKPILOT << "Link is not a real device." << endl;
+ }
+}
diff --git a/kpilot/conduits/timeconduit/time-conduit.h b/kpilot/conduits/timeconduit/time-conduit.h
new file mode 100644
index 000000000..8a6a57a50
--- /dev/null
+++ b/kpilot/conduits/timeconduit/time-conduit.h
@@ -0,0 +1,49 @@
+#ifndef _Time_CONDUIT_H
+#define _Time_CONDUIT_H
+/* time-conduit.h KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include <plugin.h>
+
+class TimeConduit : public ConduitAction
+{
+public:
+ TimeConduit(
+ KPilotLink *o,
+ const char *n = 0L,
+ const QStringList &a = QStringList() );
+ virtual ~TimeConduit();
+ virtual bool exec();
+
+ void syncHHfromPC();
+
+protected:
+ void readConfig();
+} ;
+
+#endif
diff --git a/kpilot/conduits/timeconduit/time-factory.cc b/kpilot/conduits/timeconduit/time-factory.cc
new file mode 100644
index 000000000..28548fe50
--- /dev/null
+++ b/kpilot/conduits/timeconduit/time-factory.cc
@@ -0,0 +1,46 @@
+/* Time-factory.cc KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This file defines the factory for the Time-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+#include "pluginfactory.h"
+
+#include "time-conduit.h"
+#include "time-setup.h"
+
+
+extern "C"
+{
+
+void *init_conduit_time()
+{
+ return new ConduitFactory<TimeWidgetConfig,TimeConduit>(0,"Timeconduit");
+}
+
+}
+
+
diff --git a/kpilot/conduits/timeconduit/time-factory.h b/kpilot/conduits/timeconduit/time-factory.h
new file mode 100644
index 000000000..2b53c7c11
--- /dev/null
+++ b/kpilot/conduits/timeconduit/time-factory.h
@@ -0,0 +1,41 @@
+#ifndef _TIME_FACTORY_H
+#define _TIME_FACTORY_H
+/* Time-factory.h KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This file defines the factory for the Time-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#define DIR_PCToPalm 0
+#define DIR_PalmToPC 1
+
+extern "C"
+{
+
+void *init_conduit_time();
+
+}
+
+#endif
diff --git a/kpilot/conduits/timeconduit/time-setup.cc b/kpilot/conduits/timeconduit/time-setup.cc
new file mode 100644
index 000000000..ce562d7dd
--- /dev/null
+++ b/kpilot/conduits/timeconduit/time-setup.cc
@@ -0,0 +1,86 @@
+/* Time-setup.cc KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This file defines the setup dialog for the Time-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qtabwidget.h>
+#include <qradiobutton.h>
+#include <qbuttongroup.h>
+
+#include <kapplication.h>
+#include <kaboutdata.h>
+
+#include "time-setup_dialog.h"
+
+#include "time-setup.moc"
+#include "timeConduitSettings.h"
+
+
+
+static KAboutData *createAbout()
+{
+ KAboutData *fAbout = new KAboutData("Timeconduit",
+ I18N_NOOP("Time Synchronization Conduit for KPilot"),
+ KPILOT_VERSION,
+ I18N_NOOP("Synchronizes the Time on the Handheld and the PC"),
+ KAboutData::License_GPL,
+ "(C) 2002, Reinhold Kainhofer");
+ fAbout->addAuthor("Reinhold Kainhofer",
+ I18N_NOOP("Primary Author"), "[email protected]", "http://reinhold.kainhofer.com/");
+ return fAbout;
+}
+
+
+
+TimeWidgetConfig::TimeWidgetConfig(QWidget *w, const char *n) :
+ ConduitConfigBase(w,n),
+ fConfigWidget(new TimeWidget(w))
+{
+ FUNCTIONSETUP;
+ fAbout = createAbout();
+ ConduitConfigBase::addAboutPage(fConfigWidget->tabWidget,fAbout);
+ fWidget=fConfigWidget;
+ fConduitName=i18n("Time");
+}
+
+void TimeWidgetConfig::commit()
+{
+ FUNCTIONSETUP;
+ TimeConduitSettings::setDirection(
+ fConfigWidget->directionGroup->id(fConfigWidget->directionGroup->selected()) );
+ TimeConduitSettings::self()->writeConfig();
+}
+
+void TimeWidgetConfig::load()
+{
+ FUNCTIONSETUP;
+ TimeConduitSettings::self()->readConfig();
+
+ fConfigWidget->directionGroup->setButton( TimeConduitSettings::direction() );
+}
+
diff --git a/kpilot/conduits/timeconduit/time-setup.h b/kpilot/conduits/timeconduit/time-setup.h
new file mode 100644
index 000000000..7552c12d6
--- /dev/null
+++ b/kpilot/conduits/timeconduit/time-setup.h
@@ -0,0 +1,50 @@
+#ifndef _Time_Time_SETUP_H
+#define _Time_Time_SETUP_H
+/* knotes-setup.h KPilot
+**
+** Copyright (C) 2002 by Reinhold Kainhofer
+**
+** This file defines the widget and behavior for the config dialog
+** of the KNotes conduit.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "plugin.h"
+
+class TimeWidget;
+class KAboutData;
+
+class TimeWidgetConfig : public ConduitConfigBase
+{
+Q_OBJECT
+public:
+ TimeWidgetConfig(QWidget *parent, const char *);
+ virtual void commit();
+ virtual void load();
+ static ConduitConfigBase *create(QWidget *,const char *);
+protected:
+ TimeWidget *fConfigWidget;
+ KAboutData *fAbout;
+} ;
+
+#endif
diff --git a/kpilot/conduits/timeconduit/time-setup_dialog.ui b/kpilot/conduits/timeconduit/time-setup_dialog.ui
new file mode 100644
index 000000000..b419b9250
--- /dev/null
+++ b/kpilot/conduits/timeconduit/time-setup_dialog.ui
@@ -0,0 +1,122 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>TimeWidget</class>
+<author>Reinhold Kainhofer</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Form2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>399</width>
+ <height>293</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ <widget class="QButtonGroup" row="0" column="0">
+ <property name="name">
+ <cstring>directionGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Direction</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>RadioButton1</cstring>
+ </property>
+ <property name="text">
+ <string>Set the &amp;handheld time from the time on the PC</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to synchronize the handheld time with the PC time, by using the PC time on both.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>RadioButton1_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Set the &amp;PC time from the time on the handheld</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to synchronize the handheld time with the PC time, by using the handheld time on both.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;qt&gt;PalmOS Version 3.25 and 3.3 do not support setting the system time, so this conduit will be skipped for handhelds that run either of these operating systems.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>tabWidget</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpilot/conduits/timeconduit/timeConduitSettings.kcfgc b/kpilot/conduits/timeconduit/timeConduitSettings.kcfgc
new file mode 100644
index 000000000..3487b6a68
--- /dev/null
+++ b/kpilot/conduits/timeconduit/timeConduitSettings.kcfgc
@@ -0,0 +1,7 @@
+File=timeconduit.kcfg
+ClassName=TimeConduitSettings
+Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/conduits/timeconduit/time_conduit.desktop b/kpilot/conduits/timeconduit/time_conduit.desktop
new file mode 100644
index 000000000..cbdafc9f4
--- /dev/null
+++ b/kpilot/conduits/timeconduit/time_conduit.desktop
@@ -0,0 +1,107 @@
+[Desktop Entry]
+Type=Service
+Comment=This conduit sets the time on your handheld from the PC clock.
+Comment[af]=Hierdie pad stel die tyd op jou draagbare toestel vanaf die PC horlosie.
+Comment[bg]=Синхронизация на датата и часа на мобилно устройство с часовника на компютъра
+Comment[bs]=Ovaj conduit postavlja vrijeme na vašem ručnom računaru prema PC satu.
+Comment[ca]=Aquest conducte estableix l'hora en la vostra agenda electrònica des del rellotge del PC.
+Comment[cs]=Toto propojení nastaví čas na vašem handheldu podle PC.
+Comment[cy]=Mae'r cwndid yma yn gosod yr amser ar eich llawiadur o gloc y CP.
+Comment[da]=Denne kanal sætter tiden på din håndholdte fra PC'ens ur.
+Comment[de]=Überträgt die Zeit vom PC auf das mobile Gerät
+Comment[el]=Αυτός ο σύνδεσμος ρυθμίζει την ώρα στον υπολογιστή παλάμης σας από το ρολόι του υπολογιστή σας.
+Comment[es]=Este conducto fija la hora de su agenda electrónica según el reloj de su PC.
+Comment[et]=See kanal sünkroniseerib pihuarvuti aja PC kellaga.
+Comment[eu]=Kanal honek zure agenda elektronikoko ordua PC-aren ordura ezartzen du.
+Comment[fa]=این لوله، از طریق ساعت PC زمان دستی شما را تنظیم می‌کند.
+Comment[fi]=Tämä yhdyskäytävä asettaa taskutietokoneen kellonajan PC:n kellosta.
+Comment[fr]=Ce canal règle l'heure de votre périphérique depuis celle du PC.
+Comment[fy]=Dit conduit set de tiid fan jo handheld oan d ehân fan de pc-klok.
+Comment[gl]=Este conducto pon a hora do seu aparello portátil dende o reloxo do seu PC.
+Comment[hi]=यह कन्ड्यूइट आपके हैंण्डहेल्ड में पीसी घड़ी द्वारा समय नियत करता है.
+Comment[hu]=Ez a csatoló beállítja a kéziszámítógép óráját a számítógépé alapján
+Comment[is]=Þessi rás stillir klukku lófatölvunnar eftir klukku PC tölvunnar.
+Comment[it]=Questo conduit imposta l'ora sul tuo palmare prendendola dall'orologio del PC
+Comment[ja]=このコンジットはハンドヘルドの時間をPCの時計に合わせます。
+Comment[ka]=დროის მითითება კომპიუტერის საათისთვის.
+Comment[km]=បំពង់​នេះ​កំណត់​ពេលវេលា​នៅ​លើ​ឧបករណ៍​យួរដៃ​របស់​អ្នក ពី​នាឡិកា​កុំព្យូទ័រ ។
+Comment[lt]=Šis kanalas nustato delninuko laiką pagal PC laiką.
+Comment[mk]=Овој канал го поставува времето на рачниот уред според времето на компјутерот.
+Comment[ms]=Saluran ini mengeset waktu pada komputer telapak anda dari jam PC.
+Comment[nb]=Denne kanalen stiller klokka på PDA-en fra PC-klokka.
+Comment[nds]=Synkroniseert stellt Handreekner-Klock na de PC-Klock.
+Comment[ne]=यो कन्ड्युटले पीसी घडीबाट ह्यान्डहेल्डमा समय सेट गर्दछ ।
+Comment[nl]=Dit conduit stelt de tijd van uw handheld in aan de hand van de pc-klok.
+Comment[nn]=Denne koplinga set tida på den handheldte eininga di frå PC-klokka.
+Comment[pl]=Ten łącznik ustawia zegar na palmtopie zgodnie z zegarem komputera.
+Comment[pt]=Esta conduta acerta a hora do seu dispositivo a partir do relógio do PC.
+Comment[pt_BR]=Este conduíte define o horário no seu hendheld a partir do relógio do PC.
+Comment[ru]=Канал синхронизации времени
+Comment[sk]=Táto spojka nastavuje čas na vašom prenosnom zariadení podľa PC.
+Comment[sl]=Ta veznik nastavi čas na ročnem računalniku glede na sistemsko uro osebnega računalnika.
+Comment[sr]=Овај провод поставља време на вашем ручном рачунару према PC часовнику.
+Comment[sr@Latn]=Ovaj provod postavlja vreme na vašem ručnom računaru prema PC časovniku.
+Comment[sv]=Den här kanalen ställer in tiden på handdatorn från datorns klocka.
+Comment[ta]=இந்த காப்புக்குழாய் பிசி கடிகாரத்தில் இருந்து உங்கள் கையேட்டில் நேரத்தை அமைக்கும்
+Comment[tg]=Канали синзронизатсияи муддат
+Comment[tr]=Bu bileşen, el bilgisayarınızın saatini PC saatine bakarak ayarlar.
+Comment[uk]=Цей акведук синхронізує час у кишеньковому пристрої з часом комп'ютера.
+Comment[zh_CN]=此管道把您手持设备的时间与电脑同步。
+Comment[zh_TW]=此軟體經由 PC 時間設定您的 handheld 時間。
+Name=Time Synchronization
+Name[af]=Tyd sinkronisasie
+Name[ar]=مزامنة الوقت
+Name[be]=Сынхранізацыя часу
+Name[bg]=Синхронизация
+Name[bs]=Sinhronizacija vremena
+Name[ca]=Sincronització horària
+Name[cs]=Synchronizace času
+Name[cy]=Cydamseriad Amser
+Name[da]=Tidsynkronisering
+Name[de]=Zeit-Abgleich
+Name[el]=Συγχρονισμός ώρας
+Name[en_GB]=Time Synchronisation
+Name[eo]=Temposinkronigo
+Name[es]=Sincronización de hora
+Name[et]=Aja sünkroniseerimine
+Name[eu]=Ordu sinkronizazioa
+Name[fa]=همگام‌سازی زمان
+Name[fi]=Ajan synkronointi
+Name[fr]=Synchronisation de l'heure
+Name[fy]=Tiidssyngronisaasje
+Name[gl]=Sincronización Horaria
+Name[hi]=समय सिंक्रोनाइज़ेशन
+Name[hu]=Időszinkronizálás
+Name[is]=Tíma samstilling
+Name[it]=Sincronizzazione temporale
+Name[ja]=時間同期
+Name[ka]=დროის სინქრონიზაცია
+Name[kk]=Уақытты қадамдастыру
+Name[km]=សមកាលកម្ម​ពេលវេលា
+Name[lt]=Laiko sinchronizavimas
+Name[mk]=Синхронизација на време
+Name[ms]=Segerakan waktu
+Name[nb]=Tidsynkronisering
+Name[nds]=Tietsynkroniseren
+Name[ne]=समय समक्रमण
+Name[nl]=Tijdsynchronisatie
+Name[nn]=Tidsynkronisering
+Name[pl]=Synchronizacja czasu
+Name[pt]=Sincronização Horária
+Name[pt_BR]=Sincronização de Horário
+Name[ro]=Sincronizare timp
+Name[ru]=Синхронизация времени
+Name[sk]=Synchronizácia času
+Name[sl]=Usklajevanje časa
+Name[sr]=Синхронизација времена
+Name[sr@Latn]=Sinhronizacija vremena
+Name[sv]=Tidssynkronisering
+Name[ta]=நேர ஒத்தியக்கம்
+Name[tg]=Синхронизатсияи муддат
+Name[tr]=Zaman Senkronizasyonu
+Name[uk]=Синхронізація часу
+Name[zh_CN]=时间同步
+Name[zh_TW]=時刻同步化
+Implemented=file
+ServiceTypes=KPilotConduit
+X-KDE-Library=conduit_time
diff --git a/kpilot/conduits/timeconduit/timeconduit.kcfg b/kpilot/conduits/timeconduit/timeconduit.kcfg
new file mode 100644
index 000000000..aafa23fc9
--- /dev/null
+++ b/kpilot/conduits/timeconduit/timeconduit.kcfg
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kpilot_timeconduitrc"/>
+ <group name="Time-conduit">
+ <entry name="Direction" type="Enum">
+ <choices>
+ <choice name="eSetHHfromPC"/>
+ <choice name="eSetPCfromHH"/>
+ </choices>
+ <default>eSetHHfromPC</default>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kpilot/conduits/vcalconduit/CMakeLists.txt b/kpilot/conduits/vcalconduit/CMakeLists.txt
new file mode 100644
index 000000000..21482355f
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/CMakeLists.txt
@@ -0,0 +1,75 @@
+set(conduit_LIBS kcal)
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+set(conduit_SHARED
+ vcal-setupbase.cc
+ vcal-conduitbase.cc
+ teststate.cc
+ initstate.cc
+ pctohhstate.cc
+ hhtopcstate.cc
+ cleanupstate.cc
+ deleteunsyncedpcstate.cc
+ deleteunsyncedhhstate.cc
+ kcalRecord.cc
+ vcalRecord.cc
+ todoRecord.cc
+)
+
+kde3_add_kcfg_files(conduit_SHARED vcalconduitSettings.kcfgc)
+kde3_add_ui_files(conduit_SHARED korganizerConduit.ui)
+
+set(conduit_vcal_SRCS
+ ${conduit_SHARED}
+ vcal-conduit.cc
+ vcal-factory.cc
+ vcal-setup.cc
+)
+
+kde3_automoc(${conduit_vcal_SRCS})
+add_library(conduit_vcal SHARED ${conduit_vcal_SRCS})
+target_link_libraries(conduit_vcal kcal)
+
+set(conduit_todo_SRCS
+ ${conduit_SHARED}
+ todo-factory.cc
+ todo-setup.cc
+ todo-conduit.cc
+)
+
+kde3_automoc(${conduit_todo_SRCS})
+add_library(conduit_todo SHARED ${conduit_todo_SRCS})
+target_link_libraries(conduit_todo kcal)
+
+set_target_properties(
+ conduit_vcal PROPERTIES LOCATION ${KDE3_PLUGIN_INSTALL_DIR}
+ INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib
+ PREFIX ""
+)
+set_target_properties(
+ conduit_todo PROPERTIES LOCATION ${KDE3_PLUGIN_INSTALL_DIR}
+ INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib
+ PREFIX ""
+)
+
+kde3_install_libtool_file(conduit_vcal)
+
+install(
+ TARGETS conduit_vcal conduit_todo
+ LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR}
+ LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR}
+)
+
+kde3_install_libtool_file(conduit_todo)
+
+install(
+ FILES vcal-conduit.desktop todo-conduit.desktop
+ DESTINATION ${KDE3_SERVICES_DIR}
+)
+
+install(
+ FILES vcalconduitbase.kcfg DESTINATION ${KDE3_KCFG_DIR}
+)
diff --git a/kpilot/conduits/vcalconduit/Makefile.am b/kpilot/conduits/vcalconduit/Makefile.am
new file mode 100644
index 000000000..546789e17
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/Makefile.am
@@ -0,0 +1,43 @@
+###
+### Makefile for vcal and todo conduits. These two conduits share most code,
+### so it seems logical to put them in one place.
+###
+
+INCLUDES= -I$(top_srcdir)/kpilot/lib -I$(top_srcdir) \
+ $(PISOCK_INCLUDE) $(all_includes)
+
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = vcal-conduit.desktop todo-conduit.desktop
+
+kde_module_LTLIBRARIES = conduit_vcal.la conduit_todo.la
+noinst_LTLIBRARIES = libvcalconduit_shared.la
+
+libvcalconduit_shared_la_SOURCES = vcalconduitSettings.kcfgc \
+ korganizerConduit.ui \
+ kcalRecord.cc \
+ vcal-setupbase.cc \
+ vcal-conduitbase.cc \
+ cleanupstate.cc deleteunsyncedhhstate.cc deleteunsyncedpcstate.cc \
+ hhtopcstate.cc initstate.cc pctohhstate.cc teststate.cc
+
+conduit_vcal_la_SOURCES = vcal-conduit.cc vcalRecord.cc \
+ vcal-factory.cc vcal-setup.cc
+conduit_vcal_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+conduit_vcal_la_LIBADD = ../../lib/libkpilot.la \
+ ../../../libkcal/libkcal.la \
+ libvcalconduit_shared.la
+conduit_vcal_la_COMPILE_FIRST = vcalconduitSettings.h korganizerConduit.h
+
+conduit_todo_la_SOURCES = todo-conduit.cc todoRecord.cc \
+ todo-factory.cc todo-setup.cc
+conduit_todo_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+conduit_todo_la_LIBADD = ../../lib/libkpilot.la \
+ ../../../libkcal/libkcal.la \
+ libvcalconduit_shared.la
+conduit_todo_la_COMPILE_FIRST = vcalconduitSettings.h korganizerConduit.h
+
+
+kde_kcfg_DATA = vcalconduitbase.kcfg
+
diff --git a/kpilot/conduits/vcalconduit/README b/kpilot/conduits/vcalconduit/README
new file mode 100644
index 000000000..8d4ea49ab
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/README
@@ -0,0 +1,11 @@
+KPilot vCal KOrganizer conduit version 3.0
+(c) 1998 Dan Pilone, Preston Brown, Herwin Jan Steehouwer
+
+This conduit works with KPilot and KOrganizer.
+
+Things to remember:
+* When deleting from yout PalmPilot set
+ 'Save Archive Copy On PC' OFF !!!
+
+Preston Brown and Herwin Jan Steehouwer
diff --git a/kpilot/conduits/vcalconduit/cleanupstate.cc b/kpilot/conduits/vcalconduit/cleanupstate.cc
new file mode 100644
index 000000000..29b1f6ea5
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/cleanupstate.cc
@@ -0,0 +1,132 @@
+/* KPilot
+**
+** Copyright (C) 2006 by Bertjan Broeksema <[email protected]>
+**
+** This file is the implementation of the CleanUpState.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <options.h>
+
+#include <kio/netaccess.h>
+#include <qfile.h>
+
+#include "pilotDatabase.h"
+
+#include "vcal-conduitbase.h"
+#include "vcalconduitSettings.h"
+#include "cleanupstate.h"
+
+
+CleanUpState::CleanUpState()
+{
+ fState = eCleanUp;
+}
+
+CleanUpState::~CleanUpState()
+{
+}
+
+void CleanUpState::startSync( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Starting CleanUpState." << endl;
+
+ vccb->addLogMessage( i18n( "Cleaning up ..." ) );
+ vccb->postSync();
+
+ if ( vccb->database() )
+ {
+ vccb->database()->resetSyncFlags();
+ vccb->database()->cleanup();
+ }
+ if ( vccb->localDatabase() )
+ {
+ vccb->localDatabase()->resetSyncFlags();
+ vccb->localDatabase()->cleanup();
+ }
+
+ KCal::Calendar *fCalendar = vccb->calendar();
+ QString fCalendarFile = vccb->calendarFile();
+
+ if ( fCalendar )
+ {
+ KURL kurl( vccb->config()->calendarFile() );
+ switch( vccb->config()->calendarType() )
+ {
+ case VCalConduitSettings::eCalendarLocal:
+ dynamic_cast<KCal::CalendarLocal*>(fCalendar)->save( fCalendarFile );
+ if(!kurl.isLocalFile())
+ {
+ if( !KIO::NetAccess::upload( fCalendarFile
+ , vccb->config()->calendarFile(), 0L) )
+ {
+ vccb->addLogError( i18n( "An error occurred while uploading"
+ " \"%1\". You can try to upload "
+ "the temporary local file \"%2\" manually.")
+ .arg(vccb->config()->calendarFile()).arg(fCalendarFile));
+ }
+ else {
+ KIO::NetAccess::removeTempFile( fCalendarFile );
+ }
+ QFile backup( fCalendarFile + CSL1( "~" ) );
+ backup.remove();
+ }
+ break;
+ case VCalConduitSettings::eCalendarResource:
+ fCalendar->save();
+ break;
+ default:
+ break;
+ }
+ fCalendar->close();
+ }
+
+ vccb->setHasNextRecord( false );
+}
+
+void CleanUpState::handleRecord( ConduitAction * )
+{
+ FUNCTIONSETUP;
+}
+
+void CleanUpState::finishSync( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Finished CleanUpState." << endl;
+ vccb->setState( 0L );
+}
diff --git a/kpilot/conduits/vcalconduit/cleanupstate.h b/kpilot/conduits/vcalconduit/cleanupstate.h
new file mode 100644
index 000000000..4d599cdf7
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/cleanupstate.h
@@ -0,0 +1,49 @@
+#ifndef _KPILOT_CLEANUPSTATE_H
+#define _KPILOT_CLEANUPSTATE_H
+/* cleanupstate.h KPilot
+**
+** Copyright (C) 2006 Bertjan Broeksema
+**
+** This file defines the cleanupstate for vcal-conduitbase.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "conduitstate.h"
+
+class ConduitAction;
+
+/**
+ * State to Cleanup after all sync actions are finished. @see vcal-conduitstate.h
+ */
+class CleanUpState : public ConduitState
+{
+public:
+ CleanUpState();
+ virtual ~CleanUpState();
+
+ virtual void startSync( ConduitAction* );
+ virtual void handleRecord( ConduitAction* );
+ virtual void finishSync( ConduitAction* );
+};
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/conduitstate.h b/kpilot/conduits/vcalconduit/conduitstate.h
new file mode 100644
index 000000000..447ce1c5a
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/conduitstate.h
@@ -0,0 +1,86 @@
+#ifndef _KPILOT_CONDUITSTATE_H
+#define _KPILOT_CONDUITSTATE_H
+/* vcal-conduitstate.h KPilot
+**
+** Copyright (C) 2006 Bertjan Broeksema
+**
+** This file defines the vcal-conduitstate.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "plugin.h"
+
+/**
+ * This class defines the current state of the vcal-conduitbase. Subclasses of
+ * this class can do the things that are needed, in methods defined here, for
+ * the state that they define.
+ */
+class ConduitState
+{
+public:
+ enum state_t {
+ eTest,
+ eInit,
+ ePCToHH,
+ eHHToPC,
+ eDeleteUnsyncedHH,
+ eDeleteUnsyncedPC,
+ eCleanUp
+ };
+
+protected:
+ state_t fState;
+ bool fStarted;
+
+public:
+ ConduitState(){ fState = eInit; fStarted = false; };
+ virtual ~ConduitState() {};
+
+ /**
+ * Prepare for a sync in the current state. Don't forget to set fState to
+ * true in this method. Otherwise the state won't handle records.
+ */
+ virtual void startSync( ConduitAction * ) = 0;
+
+ /**
+ * Sync the next record in row.
+ */
+ virtual void handleRecord( ConduitAction * ) = 0;
+
+ /**
+ * Clean up after all records are synced and enter next state.
+ */
+ virtual void finishSync( ConduitAction * ) = 0;
+
+ /**
+ * Returns the state type.
+ */
+ state_t state() { return fState; };
+
+ /**
+ * Returns wether or not this state has started.
+ */
+ bool started() { return fStarted; };
+};
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/deleteunsyncedhhstate.cc b/kpilot/conduits/vcalconduit/deleteunsyncedhhstate.cc
new file mode 100644
index 000000000..78fb67807
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/deleteunsyncedhhstate.cc
@@ -0,0 +1,115 @@
+/* KPilot
+**
+** Copyright (C) 2006 by Bertjan Broeksema <[email protected]>
+**
+** This file is the implementation of the DeleteUnsyncedHHState.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <options.h>
+#include <plugin.h>
+
+#include "pilotDatabase.h"
+#include "pilotRecord.h"
+
+#include "vcal-conduitbase.h"
+#include "deleteunsyncedhhstate.h"
+#include "deleteunsyncedpcstate.h"
+#include "cleanupstate.h"
+
+DeleteUnsyncedHHState::DeleteUnsyncedHHState()
+{
+ fState = eDeleteUnsyncedHH;
+}
+
+DeleteUnsyncedHHState::~DeleteUnsyncedHHState()
+{
+}
+
+void DeleteUnsyncedHHState::startSync( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Starting DeleteUnsyncedHHState." << endl;
+
+ fPilotIndex = 0;
+ fNextState = new DeleteUnsyncedPCState();
+
+ vccb->setHasNextRecord( true );
+ fStarted = true;
+}
+
+void DeleteUnsyncedHHState::handleRecord( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ PilotRecord *r = vccb->localDatabase()->readRecordByIndex( fPilotIndex++ );
+ // if either we don't have a record, or if we're copying everything
+ // from the handheld to the pc, then we don't have anything to do
+ // here. the latter is because if we're copying HH->PC, then by
+ // definition, we will have everything from the HH on the PC and
+ // therefore can't possibly have anything that needs to be deleted
+ // from it.
+ if ( !r
+ || ( vccb->syncMode().mode() == ConduitAction::SyncMode::eCopyHHToPC ) )
+ {
+ vccb->setHasNextRecord( false );
+ return;
+ }
+
+ KCal::Incidence *e = vccb->privateBase()->findIncidence( r->id() );
+ if ( !e )
+ {
+ DEBUGKPILOT << "Didn't find incidence with id = " << r->id()
+ << ", deleting it" << endl;
+ vccb->deletePalmRecord( NULL, r );
+ }
+
+ KPILOT_DELETE( r );
+}
+
+void DeleteUnsyncedHHState::finishSync( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Finishing DeleteUnsyncedHHState." << endl;
+ vccb->setState( fNextState );
+}
diff --git a/kpilot/conduits/vcalconduit/deleteunsyncedhhstate.h b/kpilot/conduits/vcalconduit/deleteunsyncedhhstate.h
new file mode 100644
index 000000000..df9b721fa
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/deleteunsyncedhhstate.h
@@ -0,0 +1,53 @@
+#ifndef _KPILOT_DUSHHSTATE_H
+#define _KPILOT_DUSHHSTATE_H
+/* deleteunsyncedhhstate.h KPilot
+**
+** Copyright (C) 2006 Bertjan Broeksema
+**
+** This file defines the deleteunsyncedpcstate for vcal-conduitbase.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "conduitstate.h"
+
+class VCalConduitBase;
+
+/**
+ * State to handle delete unsynced pc records. @see vcal-conduitstate.h
+ */
+class DeleteUnsyncedHHState : public ConduitState
+{
+private:
+ ConduitState *fNextState;
+ int fPilotIndex;
+
+public:
+ DeleteUnsyncedHHState();
+ virtual ~DeleteUnsyncedHHState();
+
+ virtual void startSync( ConduitAction* );
+ virtual void handleRecord( ConduitAction* );
+ virtual void finishSync( ConduitAction* );
+};
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/deleteunsyncedpcstate.cc b/kpilot/conduits/vcalconduit/deleteunsyncedpcstate.cc
new file mode 100644
index 000000000..26a0a0824
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/deleteunsyncedpcstate.cc
@@ -0,0 +1,135 @@
+/* KPilot
+**
+** Copyright (C) 2006 by Bertjan Broeksema <[email protected]>
+**
+** This file is the implementation of the DeleteUnsyncedPCState.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <options.h>
+#include <plugin.h>
+
+#include "pilotDatabase.h"
+#include "pilotRecord.h"
+
+#include "vcal-conduitbase.h"
+#include "deleteunsyncedpcstate.h"
+#include "cleanupstate.h"
+
+DeleteUnsyncedPCState::DeleteUnsyncedPCState()
+{
+ fState = eDeleteUnsyncedPC;
+}
+
+DeleteUnsyncedPCState::~DeleteUnsyncedPCState()
+{
+}
+
+void DeleteUnsyncedPCState::startSync( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Starting DeleteUnsyncedPCState." << endl;
+
+ fPilotIndex = 0;
+ fNextState = new CleanUpState();
+
+ vccb->setHasNextRecord( true );
+ fStarted = true;
+}
+
+void DeleteUnsyncedPCState::handleRecord( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ KCal::Incidence *e = 0L;
+ e = vccb->privateBase()->getNextIncidence();
+
+ // if we don't have a record, then we can't do anything. also, if
+ // we're copying everything from the PC to our handheld, then we're
+ // guaranteed not to have anything extra on our PC that's not on
+ // our handheld that needs to get deleted, so we can return in that
+ // case too...
+
+ if( !e || ( vccb->syncMode().mode() == ConduitAction::SyncMode::eCopyPCToHH ) )
+ {
+ vccb->setHasNextRecord( false );
+ return;
+ }
+
+
+ // try to find the corresponding index on the palm. if we can't
+ // find it, then we have a pc record that needs to be deleted.
+ recordid_t id = e->pilotId();
+
+ PilotRecord *s = 0L;
+
+ if( id > 0 )
+ {
+ s = vccb->database()->readRecordById( id );
+ }
+
+ // if we either have a pc record with no palm id or if we can't
+ // find a palm record that matches, then we need to delete this PC
+ // record.
+ if ( id <=0 || !s )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": found PC entry with pilotID: [" << id
+ << "], Description: [" << e->summary()
+ << "], Time: ["<< e->dtStart().toString() << "] until: ["
+ << e->dtEnd().toString() << "]. Can't find it on Palm, "
+ << "so I'm deleting it from the local calendar." << endl;
+#endif
+ vccb->privateBase()->removeIncidence(e);
+ }
+
+ KPILOT_DELETE( s );
+
+}
+
+void DeleteUnsyncedPCState::finishSync( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Finishing DeleteUnsyncedPCState." << endl;
+ vccb->setState( fNextState );
+}
diff --git a/kpilot/conduits/vcalconduit/deleteunsyncedpcstate.h b/kpilot/conduits/vcalconduit/deleteunsyncedpcstate.h
new file mode 100644
index 000000000..854b2a626
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/deleteunsyncedpcstate.h
@@ -0,0 +1,53 @@
+#ifndef _KPILOT_DUSPCSTATE_H
+#define _KPILOT_DUSPCSTATE_H
+/* deleteunsyncedpcstate.h KPilot
+**
+** Copyright (C) 2006 Bertjan Broeksema
+**
+** This file defines the deleteunsyncedpcstate for vcal-conduitbase.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "conduitstate.h"
+
+class VCalConduitBase;
+
+/**
+ * State to handle delete unsynced pc records. @see vcal-conduitstate.h
+ */
+class DeleteUnsyncedPCState : public ConduitState
+{
+private:
+ ConduitState *fNextState;
+ int fPilotIndex;
+
+public:
+ DeleteUnsyncedPCState();
+ virtual ~DeleteUnsyncedPCState();
+
+ virtual void startSync( ConduitAction* );
+ virtual void handleRecord( ConduitAction* );
+ virtual void finishSync( ConduitAction* );
+};
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/hhtopcstate.cc b/kpilot/conduits/vcalconduit/hhtopcstate.cc
new file mode 100644
index 000000000..79089671d
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/hhtopcstate.cc
@@ -0,0 +1,249 @@
+/* KPilot
+**
+** Copyright (C) 2006 by Bertjan Broeksema <[email protected]>
+**
+** This file is the implementation of the HHtoPCState
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <options.h>
+
+#include "pilotDatabase.h"
+#include "pilotRecord.h"
+
+#include "vcalconduitSettings.h"
+#include "vcal-conduitbase.h"
+#include "hhtopcstate.h"
+#include "pctohhstate.h"
+#include "cleanupstate.h"
+
+HHToPCState::HHToPCState()
+{
+ fState = eHHToPC;
+ fPilotindex = 0;
+}
+
+HHToPCState::~HHToPCState()
+{
+}
+
+void HHToPCState::startSync( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Starting HHToPCState." << endl;
+
+ if ( vccb->syncMode() == ConduitAction::SyncMode::eCopyHHToPC )
+ {
+ fNextState = new CleanUpState();
+ }
+ else
+ {
+ fNextState = new PCToHHState();
+ }
+
+ fStarted = true;
+ vccb->setHasNextRecord( true );
+}
+
+void HHToPCState::handleRecord( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ PilotRecord *r = 0L;
+ PilotRecord *s = 0L;
+
+ if ( vccb->isFullSync() )
+ {
+ r = vccb->database()->readRecordByIndex( fPilotindex++ );
+ }
+ else
+ {
+ r = vccb->database()->readNextModifiedRec();
+ }
+
+ if (!r)
+ {
+ vccb->privateBase()->updateIncidences();
+ vccb->setHasNextRecord( false );
+ return;
+ }
+
+ // let subclasses do something with the record before we try to sync
+ vccb->preRecord( r );
+
+ bool archiveRecord = ( r->isArchived() );
+ s = vccb->localDatabase()->readRecordById( r->id() );
+
+ if ( !s || vccb->isFirstSync() )
+ {
+#ifdef DEBUG
+ if ( r->id() > 0 && !s )
+ {
+ DEBUGKPILOT << "-------------------------------------------------";
+ DEBUGKPILOT << "--------------------------" << endl;
+ DEBUGKPILOT << fname << ": Could not read palm record with ID ";
+ DEBUGKPILOT << r->id() << endl;
+ }
+#endif
+ if ( !r->isDeleted()
+ || ( vccb->config()->syncArchived() && archiveRecord ) )
+ {
+ KCal::Incidence *e = vccb->addRecord( r );
+ if ( vccb->config()->syncArchived() && archiveRecord ) {
+ e->setSyncStatus( KCal::Incidence::SYNCDEL );
+ }
+ }
+ }
+ else
+ {
+ if ( r->isDeleted() )
+ {
+ if ( vccb->config()->syncArchived() && archiveRecord )
+ {
+ vccb->changeRecord( r, s );
+ }
+ else
+ {
+ vccb->deleteRecord( r, s );
+ }
+ }
+ else
+ {
+ vccb->changeRecord( r, s );
+ }
+ }
+
+ KPILOT_DELETE(r);
+ KPILOT_DELETE(s);
+}
+
+void HHToPCState::finishSync( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Finished HHToPCState." << endl;
+ vccb->setState( fNextState );
+}
+
+/*
+void VCalConduitBase::slotPalmRecToPC()
+{
+ FUNCTIONSETUP;
+
+ PilotRecord *r;
+ if (isFullSync())
+ {
+ r = fDatabase->readRecordByIndex(pilotindex++);
+ }
+ else
+ {
+ r = fDatabase->readNextModifiedRec();
+ }
+ PilotRecord *s = 0L;
+
+ if (!r)
+ {
+ fP->updateIncidences();
+ if ( syncMode()==SyncMode::eCopyHHToPC )
+ {
+ emit logMessage(i18n("Cleaning up ..."));
+ QTimer::singleShot(0, this, SLOT(cleanup()));
+ return;
+ }
+ else
+ {
+ emit logMessage(i18n("Copying records to Pilot ..."));
+ QTimer::singleShot(0 ,this,SLOT(slotPCRecToPalm()));
+ return;
+ }
+ }
+
+ // let subclasses do something with the record before we try to sync
+ preRecord(r);
+
+// DEBUGKPILOT<<fname<<": Event: "<<e->dtStart()<<" until "<<e->dtEnd()<<endl;
+// DEBUGKPILOT<<fname<<": Time: "<<e->dtStart()<<" until "<<e->dtEnd()<<endl;
+ bool archiveRecord=(r->isArchived());
+
+ s = fLocalDatabase->readRecordById(r->id());
+ if (!s || isFirstSync())
+ {
+#ifdef DEBUG
+ if (r->id()>0 && !s)
+ {
+ DEBUGKPILOT<<"---------------------------------------------------------------------------"<<endl;
+ DEBUGKPILOT<< fname<<": Could not read palm record with ID "<<r->id()<<endl;
+ }
+#endif
+ if (!r->isDeleted() || (config()->syncArchived() && archiveRecord))
+ {
+ KCal::Incidence*e=addRecord(r);
+ if (config()->syncArchived() && archiveRecord) {
+ e->setSyncStatus(KCal::Incidence::SYNCDEL);
+ }
+ }
+ }
+ else
+ {
+ if (r->isDeleted())
+ {
+ if (config()->syncArchived() && archiveRecord)
+ {
+ changeRecord(r,s);
+ }
+ else
+ {
+ deleteRecord(r,s);
+ }
+ }
+ else
+ {
+ changeRecord(r,s);
+ }
+ }
+
+ KPILOT_DELETE(r);
+ KPILOT_DELETE(s);
+
+ QTimer::singleShot(0,this,SLOT(slotPalmRecToPC()));
+}
+*/
diff --git a/kpilot/conduits/vcalconduit/hhtopcstate.h b/kpilot/conduits/vcalconduit/hhtopcstate.h
new file mode 100644
index 000000000..838828e61
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/hhtopcstate.h
@@ -0,0 +1,55 @@
+#ifndef _KPILOT_HHTOPCSTATE_H
+#define _KPILOT_HHTOPCSTATE_H
+/* hhtopcstate.h KPilot
+**
+** Copyright (C) 2006 Bertjan Broeksema
+**
+** This file defines the teststate for vcal-conduitbase.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <libkcal/calendarlocal.h>
+
+#include "conduitstate.h"
+
+class VCalConduitBase;
+
+/**
+ * State to test the vcal-conduit. @see vcal-conduitstate.h
+ */
+class HHToPCState : public ConduitState
+{
+private:
+ ConduitState *fNextState;
+ int fPilotindex;
+
+public:
+ HHToPCState();
+ virtual ~HHToPCState();
+
+ virtual void startSync( ConduitAction* );
+ virtual void handleRecord( ConduitAction* );
+ virtual void finishSync( ConduitAction* );
+};
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/initstate.cc b/kpilot/conduits/vcalconduit/initstate.cc
new file mode 100644
index 000000000..23257ff35
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/initstate.cc
@@ -0,0 +1,109 @@
+/* KPilot
+**
+** Copyright (C) 2006 by Bertjan Broeksema <[email protected]>
+**
+** This file is the implementation of the InitState.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <options.h>
+#include <plugin.h>
+
+#include "vcal-conduitbase.h"
+#include "initstate.h"
+#include "teststate.h"
+#include "pctohhstate.h"
+#include "hhtopcstate.h"
+
+InitState::InitState()
+{
+ fState = eInit;
+}
+
+InitState::~InitState()
+{
+}
+
+void InitState::startSync( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Starting InitState." << endl;
+
+ vccb->addLogMessage( i18n( "Initializing conduit ..." ) );
+ vccb->preSync();
+
+ if ( vccb->syncMode().isTest() )
+ {
+ fNextState = new TestState();
+ }
+ else
+ {
+ switch( vccb->syncMode().mode() )
+ {
+ case ConduitAction::SyncMode::eCopyPCToHH:
+ // TODO: Clear the palm and backup database??? Or just add the
+ // new items ignore the Palm->PC side and leave the existing items
+ // on the palm?
+ fNextState = new PCToHHState();
+ break;
+ case ConduitAction::SyncMode::eCopyHHToPC:
+ // TODO: Clear the backup database and the calendar, update fP
+ // or just add the palm items and leave the PC ones there????
+ fNextState = new HHToPCState();
+ break;
+ default:
+ fNextState = new HHToPCState();
+ break;
+ }
+ }
+
+ fStarted = true;
+ vccb->setHasNextRecord( false );
+}
+
+void InitState::handleRecord( ConduitAction *vccb )
+{
+ FUNCTIONSETUP;
+ Q_UNUSED(vccb);
+}
+
+void InitState::finishSync( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Finished InitState." << endl;
+ vccb->setState( fNextState );
+}
diff --git a/kpilot/conduits/vcalconduit/initstate.h b/kpilot/conduits/vcalconduit/initstate.h
new file mode 100644
index 000000000..83042ba2a
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/initstate.h
@@ -0,0 +1,52 @@
+#ifndef _KPILOT_INITSTATE_H
+#define _KPILOT_INITSTATE_H
+/* initstate.h KPilot
+**
+** Copyright (C) 2006 Bertjan Broeksema
+**
+** This file defines the teststate for vcal-conduitbase.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "conduitstate.h"
+
+class VCalConduitBase;
+
+/**
+ * State to test the vcal-conduit. @see vcal-conduitstate.h
+ */
+class InitState : public ConduitState
+{
+private:
+ ConduitState *fNextState;
+
+public:
+ InitState();
+ virtual ~InitState();
+
+ virtual void startSync( ConduitAction *vccb );
+ virtual void handleRecord( ConduitAction *vccb );
+ virtual void finishSync( ConduitAction *vccb );
+};
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/kcalRecord.cc b/kpilot/conduits/vcalconduit/kcalRecord.cc
new file mode 100644
index 000000000..f12d9b8c3
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/kcalRecord.cc
@@ -0,0 +1,143 @@
+/* kcalRecord.cc KPilot
+**
+** Copyright (C) 2006 by Adriaan de Groot <[email protected]>
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <libkcal/calendar.h>
+#include <libkcal/calendarlocal.h>
+#include <libkcal/recurrence.h>
+#include <libkcal/vcalformat.h>
+
+#include "pilot.h"
+#include "pilotRecord.h"
+#include "kcalRecord.h"
+
+void KCalSync::setCategory(PilotRecordBase *de,
+ const KCal::Incidence *e,
+ const CategoryAppInfo &info)
+{
+ FUNCTIONSETUP;
+
+ if (!de || !e)
+ {
+ return;
+ }
+
+ QString deCategory;
+ QStringList eventCategories = e->categories();
+ if (eventCategories.size() < 1)
+ {
+ // This event has no categories.
+ de->setCategory(Pilot::Unfiled);
+ return;
+ }
+
+ // Quick check: does the record (not unfiled) have an entry
+ // in the categories list? If so, use that.
+ if (de->category() != Pilot::Unfiled)
+ {
+ deCategory = Pilot::categoryName(&info,de->category());
+ if (eventCategories.contains(deCategory))
+ {
+ // Found, so leave the category unchanged.
+ return;
+ }
+ }
+
+ QStringList availableHandheldCategories = Pilot::categoryNames(&info);
+
+ // Either the record is unfiled, and should be filed, or
+ // it has a category set which is not in the list of
+ // categories that the event has. So go looking for
+ // a category that is available both for the event
+ // and on the handheld.
+ for ( QStringList::ConstIterator it = eventCategories.begin();
+ it != eventCategories.end(); ++it )
+ {
+ // Odd, an empty category string.
+ if ( (*it).isEmpty() )
+ {
+ continue;
+ }
+
+ if (availableHandheldCategories.contains(*it))
+ {
+ // Since the string is in the list of available categories,
+ // this *can't* fail.
+ int c = Pilot::findCategory(&info,*it,false);
+ Q_ASSERT( Pilot::validCategory(c) );
+ de->setCategory(c);
+ return;
+ }
+ }
+
+ de->setCategory(Pilot::Unfiled);
+}
+
+void KCalSync::setCategory(KCal::Incidence *e,
+ const PilotRecordBase *de,
+ const CategoryAppInfo &info)
+{
+ FUNCTIONSETUP;
+
+ if (!e || !de)
+ {
+ DEBUGKPILOT << fname << ": error. unable to set kcal category. e: ["
+ << (void *)e << "], de: [" << (void *)de << "]" << endl;
+ return;
+ }
+
+ QStringList cats=e->categories();
+ int cat = de->category();
+ QString newcat = Pilot::categoryName(&info,cat);
+
+ DEBUGKPILOT << fname << ": palm category id: [" << cat <<
+ "], label: [" << newcat << "]" << endl;
+
+ if ( Pilot::validCategory(cat) && (cat != Pilot::Unfiled))
+ {
+ if (!cats.contains(newcat))
+ {
+ // if this event only has one category associated with it, then we can
+ // safely assume that what we should be doing here is changing it to match
+ // the palm. if there's already more than one category in the event, however, we
+ // won't cause data loss--we'll just append what the palm has to the
+ // event's categories
+ if (cats.count() <=1)
+ {
+ cats.clear();
+ }
+
+ cats.append( newcat );
+ e->setCategories(cats);
+ }
+ }
+
+ DEBUGKPILOT << fname << ": kcal categories now: [" << cats.join(",") << "]" << endl;
+}
diff --git a/kpilot/conduits/vcalconduit/kcalRecord.h b/kpilot/conduits/vcalconduit/kcalRecord.h
new file mode 100644
index 000000000..efd916e81
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/kcalRecord.h
@@ -0,0 +1,49 @@
+#ifndef _KPILOT_KCALRECORD_H
+#define _KPILOT_KCALRECORD_H
+/*
+** Copyright (C) 2006 by Adriaan de Groot <[email protected]>
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+class PilotRecordBase;
+
+namespace KCal
+{
+ class Incidence;
+}
+
+namespace KCalSync
+{
+ void setCategory(PilotRecordBase *de,
+ const KCal::Incidence *incidence,
+ const CategoryAppInfo &info);
+ void setCategory(KCal::Incidence *e,
+ const PilotRecordBase *de,
+ const CategoryAppInfo &info);
+}
+
+#endif
+
diff --git a/kpilot/conduits/vcalconduit/korganizerConduit.ui b/kpilot/conduits/vcalconduit/korganizerConduit.ui
new file mode 100644
index 000000000..1a9d6557b
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/korganizerConduit.ui
@@ -0,0 +1,275 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>VCalWidget</class>
+<author>Adriaan de Groot</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>Form1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>593</width>
+ <height>209</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>570</width>
+ <height>270</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>Calendar-Conduit Options</string>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>Widget2</cstring>
+ </property>
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>Spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QButtonGroup" row="0" column="0">
+ <property name="name">
+ <cstring>fSyncDestination</cstring>
+ </property>
+ <property name="title">
+ <string>Sync Destination</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fSyncStdCalendar</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Standard calendar</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to synchronize with the calendar specified by the KDE calendar settings.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>fSyncFile</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Calendar &amp;file:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to use a specific calendar file, instead of the standard KDE calendar. This file must be in the in the vCalendar or iCalendar format. Enter the location of this file in the edit box or select it clicking the file picker button.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="1">
+ <property name="name">
+ <cstring>fCalendarFile</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter here the location and filename of the calendar file or select it clicking the file picker button. This file must be in the iCalendar or vCalendar format.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>fArchive</cstring>
+ </property>
+ <property name="text">
+ <string>Store &amp;archived records in the KDE calendar</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>When this box is checked, archived records will still
+be saved in the calendar on the PC.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Conflicts</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>fTextLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Conflict &amp;resolution:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fConflictResolution</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>Use KPilot's Global Setting</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Ask User</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Do Nothing</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Handheld Overrides</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>PC Overrides</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Values From Last Sync (if possible)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Use Both Entries</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fConflictResolution</cstring>
+ </property>
+ <property name="currentItem">
+ <number>6</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select in this list how conflicting entries (entries which were edited both on your handheld and on the PC) are resolved. Possibly values are "Use KPilot's Global Setting" to use the settings defined in KPilot HotSync configuration, "Ask User" to let you decide case by case, "Do Nothing" to allow the entries to be different, "PC overrides", "Handheld overrides", "Use values from last sync" and "Use both entries" to create a new entry on both the PC and handheld. Note that this does &lt;i&gt;not&lt;/i&gt; handle double-scheduling conflicts.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <spacer row="1" column="1">
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>fSyncFile</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>fCalendarFile</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>tabWidget</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includes>
+ <include location="global" impldecl="in implementation">kurlrequester.h</include>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+ <include location="global" impldecl="in implementation">kpushbutton.h</include>
+</includes>
+</UI>
diff --git a/kpilot/conduits/vcalconduit/pctohhstate.cc b/kpilot/conduits/vcalconduit/pctohhstate.cc
new file mode 100644
index 000000000..b68771f13
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/pctohhstate.cc
@@ -0,0 +1,159 @@
+/* KPilot
+**
+** Copyright (C) 2006 by Bertjan Broeksema <[email protected]>
+**
+** This file is the implementation of the PCToHHState.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <options.h>
+
+#include "pilotDatabase.h"
+#include "pilotRecord.h"
+
+#include "vcal-conduitbase.h"
+#include "pctohhstate.h"
+#include "cleanupstate.h"
+#include "deleteunsyncedhhstate.h"
+
+PCToHHState::PCToHHState()
+{
+ fState = ePCToHH;
+}
+
+PCToHHState::~PCToHHState()
+{
+}
+
+void PCToHHState::startSync( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Starting PCToHHState." << endl;
+
+ // if we are asked to copy HH to PC, we shouldn't look for deleted records
+ // on the Palm, since we've just copied them all. =:) Otherwise, look for
+ // data on the palm that shouldn't be there and delete it if we find it....
+ if ( vccb->syncMode() == ConduitAction::SyncMode::eCopyHHToPC )
+ {
+ fNextState = new CleanUpState();
+ }
+ else
+ {
+ fNextState = new DeleteUnsyncedHHState();
+ }
+
+ vccb->addLogMessage( i18n( "Copying records to Pilot ..." ) );
+
+ fStarted = true;
+ vccb->setHasNextRecord( true );
+}
+
+void PCToHHState::handleRecord( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ KCal::Incidence *e = 0L;
+
+ if( vccb->isFullSync() )
+ {
+ e = vccb->privateBase()->getNextIncidence();
+ }
+ else
+ {
+ e = vccb->privateBase()->getNextModifiedIncidence();
+ }
+
+ // No more incidences to sync
+ if( !e )
+ {
+ vccb->setHasNextRecord( false );
+ return;
+ }
+
+ // let subclasses do something with the event
+ vccb->preIncidence( e );
+
+ // find the corresponding index on the palm and sync. If there is none,
+ // create it.
+ recordid_t id = e->pilotId();
+
+ DEBUGKPILOT << fname << ": found PC entry with pilotID " << id <<endl;
+ DEBUGKPILOT << fname << ": Description: " << e->summary() << endl;
+
+ QDateTime start_time = e->dtStart();
+ QDateTime end_time = e->dtEnd();
+ DEBUGKPILOT << fname << ": Time: "<< start_time.toString() << " until "
+ << end_time.toString() << endl;
+
+ PilotRecord *s = 0L;
+
+ if( id > 0 && ( s = vccb->database()->readRecordById( id ) ) )
+ {
+ if( e->syncStatus() == KCal::Incidence::SYNCDEL )
+ {
+ vccb->deletePalmRecord( e, s );
+ }
+ else
+ {
+ vccb->changePalmRecord( e, s );
+ }
+
+ KPILOT_DELETE( s );
+ } else {
+#ifdef DEBUG
+ if (id > 0 )
+ {
+ DEBUGKPILOT << "-------------------------------------------------"
+ << "--------------------------" << endl;
+ DEBUGKPILOT << fname << ": Could not read palm record with ID "
+ << id << endl;
+ }
+#endif
+ vccb->addPalmRecord( e );
+ }
+}
+
+void PCToHHState::finishSync( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Finished PCToHHState." << endl;
+ vccb->setState( fNextState );
+}
diff --git a/kpilot/conduits/vcalconduit/pctohhstate.h b/kpilot/conduits/vcalconduit/pctohhstate.h
new file mode 100644
index 000000000..44f929d68
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/pctohhstate.h
@@ -0,0 +1,54 @@
+#ifndef _KPILOT_PCTOHHSTATE_H
+#define _KPILOT_PCTOHHSTATE_H
+/* pctohhstate.h KPilot
+**
+** Copyright (C) 2006 Bertjan Broeksema
+**
+** This file defines the pctohhstate for vcal-conduitbase.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "conduitstate.h"
+
+class VCalConduitBase;
+
+/**
+ * State that handles copying of records from pc to handheld.
+ * @see vcal-conduitstate.h
+ */
+class PCToHHState : public ConduitState
+{
+private:
+ ConduitState *fNextState;
+ int fPilotindex;
+
+public:
+ PCToHHState();
+ virtual ~PCToHHState();
+
+ virtual void startSync( ConduitAction* );
+ virtual void handleRecord( ConduitAction* );
+ virtual void finishSync( ConduitAction* );
+};
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/teststate.cc b/kpilot/conduits/vcalconduit/teststate.cc
new file mode 100644
index 000000000..d8c8e56cc
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/teststate.cc
@@ -0,0 +1,127 @@
+/* KPilot
+**
+** Copyright (C) 2006 by Bertjan Broeksema <[email protected]>
+**
+** This file is the implementation of the TestState.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <options.h>
+
+#include <qdatetime.h>
+#include <qfile.h>
+
+#include "pilotSerialDatabase.h"
+#include "pilotLocalDatabase.h"
+#include "pilotDateEntry.h"
+
+#include "teststate.h"
+#include "vcal-conduitbase.h"
+
+TestState::TestState() : fCalendar( QString::null )
+{
+ fState = eTest;
+}
+
+TestState::~TestState()
+{
+ FUNCTIONSETUP;
+}
+
+void TestState::startSync( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Starting teststate." << endl;
+
+ vccb->setHasNextRecord( true );
+ fPilotindex = 0;
+ fStarted = true;
+}
+
+void TestState::handleRecord( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Handling record " << fPilotindex << endl;
+
+ PilotRecord *record = vccb->readRecordByIndex( fPilotindex );
+
+ if( record )
+ {
+ KCal::Incidence *i = vccb->incidenceFromRecord( record );
+ fCalendar.addIncidence( i );
+
+ KPILOT_DELETE(record);
+
+ // Schedule more work.
+ ++fPilotindex;
+ }
+ else
+ {
+ vccb->setHasNextRecord( false );
+ }
+}
+
+void TestState::finishSync( ConduitAction *ca )
+{
+ FUNCTIONSETUP;
+
+ VCalConduitBase *vccb = dynamic_cast<VCalConduitBase*>(ca);
+ if( !vccb )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": finishing teststate." << endl;
+
+ // No more records present on the device so lets dump the
+ // readed records in a file.
+ QFile f( CSL1("dump.ics") );
+ if( !f.exists() )
+ {
+ f.open( IO_WriteOnly );
+ f.close();
+ }
+
+ if( !fCalendar.save( CSL1("dump.ics") ) )
+ {
+ DEBUGKPILOT << fname << ": Can't save calendar file." << endl;
+ }
+
+ fCalendar.close();
+
+ vccb->setState( 0L );
+}
diff --git a/kpilot/conduits/vcalconduit/teststate.h b/kpilot/conduits/vcalconduit/teststate.h
new file mode 100644
index 000000000..76361e36a
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/teststate.h
@@ -0,0 +1,55 @@
+#ifndef _KPILOT_TESTSTATE_H
+#define _KPILOT_TESTSTATE_H
+/* teststate.h KPilot
+**
+** Copyright (C) 2006 Bertjan Broeksema
+**
+** This file defines the teststate for vcal-conduitbase.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <libkcal/calendarlocal.h>
+
+#include "conduitstate.h"
+
+class VCalConduitBase;
+
+/**
+ * State to test the vcal-conduit. @see vcal-conduitstate.h
+ */
+class TestState : public ConduitState
+{
+private:
+ KCal::CalendarLocal fCalendar;
+ int fPilotindex;
+
+public:
+ TestState();
+ virtual ~TestState();
+
+ virtual void startSync( ConduitAction* );
+ virtual void handleRecord( ConduitAction* );
+ virtual void finishSync( ConduitAction* );
+};
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/todo-conduit.cc b/kpilot/conduits/vcalconduit/todo-conduit.cc
new file mode 100644
index 000000000..302ada565
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/todo-conduit.cc
@@ -0,0 +1,373 @@
+/* Todo-Conduit for syncing KPilot and KOrganizer
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 1998-2001 Dan Pilone
+** Copyright (C) 1998-2000 Preston Brown <[email protected]>
+** Copyright (C) 1998 Herwin-Jan Steehouwer
+** Copyright (C) 2001 Cornelius Schumacher
+**
+** This file is part of the todo conduit, a conduit for KPilot that
+** synchronises the Pilot's todo application with the outside world,
+** which currently means KOrganizer.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qdatetime.h>
+#include <qtextcodec.h>
+
+#include <libkcal/calendar.h>
+#include <libkcal/todo.h>
+
+#include <pilotLocalDatabase.h>
+
+#include "todo-conduit.moc"
+#include "vcalconduitSettings.h"
+#include "todo-factory.h"
+
+#include "kcalRecord.h"
+#include "todoRecord.h"
+
+// define conduit versions, one for the version when categories were synced for the first time, and the current version number
+#define CONDUIT_VERSION_CATEGORYSYNC 10
+#define CONDUIT_VERSION 10
+
+extern "C"
+{
+unsigned long version_conduit_todo = Pilot::PLUGIN_API;
+}
+
+
+TodoConduitPrivate::TodoConduitPrivate(KCal::Calendar *b) :
+ VCalConduitPrivateBase(b)
+{
+ fAllTodos.setAutoDelete(false);
+}
+
+void TodoConduitPrivate::addIncidence(KCal::Incidence*e)
+{
+ fAllTodos.append(static_cast<KCal::Todo*>(e));
+ fCalendar->addTodo(static_cast<KCal::Todo*>(e));
+}
+
+int TodoConduitPrivate::updateIncidences()
+{
+ fAllTodos = fCalendar->todos();
+ fAllTodos.setAutoDelete(false);
+ return fAllTodos.count();
+}
+
+
+void TodoConduitPrivate::removeIncidence(KCal::Incidence *e)
+{
+ fAllTodos.remove(static_cast<KCal::Todo*>(e));
+ if (!fCalendar) return;
+ fCalendar->deleteTodo(static_cast<KCal::Todo*>(e));
+ // now just in case we're in the middle of reading through our list
+ // and we delete something, set reading to false so we start at the
+ // top again next time and don't have problems with our iterator
+ reading = false;
+}
+
+
+
+KCal::Incidence *TodoConduitPrivate::findIncidence(recordid_t id)
+{
+ KCal::Todo::List::ConstIterator it;
+ for( it = fAllTodos.begin(); it != fAllTodos.end(); ++it ) {
+ KCal::Todo *todo = *it;
+ if ((recordid_t)(todo->pilotId()) == id) return todo;
+ }
+
+ return 0L;
+}
+
+
+
+KCal::Incidence *TodoConduitPrivate::findIncidence(PilotRecordBase *tosearch)
+{
+ PilotTodoEntry*entry=dynamic_cast<PilotTodoEntry*>(tosearch);
+ if (!entry) return 0L;
+
+ QString title=entry->getDescription();
+ QDateTime dt=readTm( entry->getDueDate() );
+
+ KCal::Todo::List::ConstIterator it;
+ for( it = fAllTodos.begin(); it != fAllTodos.end(); ++it ) {
+ KCal::Todo *event = *it;
+ if ( (event->dtDue().date() == dt.date()) && (event->summary() == title) ) return event;
+ }
+ return 0L;
+}
+
+
+
+KCal::Incidence *TodoConduitPrivate::getNextIncidence()
+{
+ FUNCTIONSETUP;
+ if (reading) {
+ ++fAllTodosIterator;
+ }
+ else {
+ reading=true;
+ fAllTodosIterator = fAllTodos.begin();
+ }
+
+ return(fAllTodosIterator == fAllTodos.end()) ? 0L : *fAllTodosIterator;
+}
+
+
+
+KCal::Incidence *TodoConduitPrivate::getNextModifiedIncidence()
+{
+ FUNCTIONSETUP;
+ KCal::Todo*e=0L;
+ if (!reading)
+ {
+ reading=true;
+ fAllTodosIterator = fAllTodos.begin();
+ }
+ else
+ {
+ ++fAllTodosIterator;
+ }
+ if ( fAllTodosIterator != fAllTodos.end() ) e=*fAllTodosIterator;
+ while (fAllTodosIterator != fAllTodos.end() &&
+ e && e->syncStatus()!=KCal::Incidence::SYNCMOD && e->pilotId())
+ {
+ e = (++fAllTodosIterator != fAllTodos.end()) ? *fAllTodosIterator : 0L;
+
+#ifdef DEBUG
+ if(e)
+ DEBUGKPILOT<< e->summary()<<" had SyncStatus="<<e->syncStatus()<<endl;
+#endif
+
+ }
+
+ return (fAllTodosIterator == fAllTodos.end()) ? 0L : *fAllTodosIterator;
+}
+
+
+
+/****************************************************************************
+ * TodoConduit class *
+ ****************************************************************************/
+
+TodoConduit::TodoConduit(KPilotLink *d,
+ const char *n,
+ const QStringList &a) : VCalConduitBase(d,n,a),
+ fTodoAppInfo( 0L )
+{
+ FUNCTIONSETUP;
+ fConduitName=i18n("To-do");
+}
+
+
+
+TodoConduit::~TodoConduit()
+{
+// FUNCTIONSETUP;
+}
+
+
+
+void TodoConduit::_setAppInfo()
+{
+ FUNCTIONSETUP;
+ // get the address application header information
+
+ if( !fTodoAppInfo )
+ {
+ DEBUGKPILOT << fname << ": fTodoAppInfo is NULL" << endl;
+ return;
+ }
+ if( !fDatabase )
+ {
+ DEBUGKPILOT << fname << ": fDatabase is NULL" << endl;
+ return;
+ }
+
+ fTodoAppInfo->writeTo(fDatabase);
+}
+
+void TodoConduit::_getAppInfo()
+{
+ FUNCTIONSETUP;
+ // get the address application header information
+
+ KPILOT_DELETE( fTodoAppInfo );
+ fTodoAppInfo = new PilotToDoInfo(fDatabase);
+ fTodoAppInfo->dump();
+}
+
+
+
+const QString TodoConduit::getTitle(PilotRecordBase *de)
+{
+ PilotTodoEntry*d=dynamic_cast<PilotTodoEntry*>(de);
+ if (d)
+ {
+ return QString(d->getDescription());
+ }
+ return QString::null;
+}
+
+
+
+void TodoConduit::readConfig()
+{
+ FUNCTIONSETUP;
+ VCalConduitBase::readConfig();
+ // determine if the categories have ever been synce. Needed to prevent loosing
+ // the categories on the desktop. Also use a full sync for the first time to
+ // make sure the palm categories are really transferred to the desktop.
+ //
+ categoriesSynced = config()->conduitVersion()>=CONDUIT_VERSION_CATEGORYSYNC;
+ if (!categoriesSynced && !isFullSync() )
+ {
+ changeSync(SyncMode::eFullSync);
+ }
+ DEBUGKPILOT<<"categoriesSynced=" << categoriesSynced << endl;
+}
+
+void TodoConduit::preSync()
+{
+ FUNCTIONSETUP;
+ VCalConduitBase::preSync();
+ _getAppInfo();
+}
+
+void TodoConduit::postSync()
+{
+ FUNCTIONSETUP;
+ VCalConduitBase::postSync();
+ // after this successful sync the categories have been synced for sure
+ config()->setConduitVersion( CONDUIT_VERSION );
+ config()->writeConfig();
+ _setAppInfo();
+}
+
+
+
+PilotRecord *TodoConduit::recordFromIncidence(PilotRecordBase *de, const KCal::Incidence *e)
+{
+ FUNCTIONSETUP;
+
+ if (!de || !e)
+ {
+ DEBUGKPILOT << fname
+ << ": got NULL entry or NULL incidence." << endl;
+ return 0L;
+ }
+
+ PilotTodoEntry *todoEntry = dynamic_cast<PilotTodoEntry*>(de);
+ if (!todoEntry)
+ {
+ // Secretly wasn't a todo entry after all
+ return 0L;
+ }
+
+ const KCal::Todo *todo = dynamic_cast<const KCal::Todo *>(e);
+ if (!todo)
+ {
+ DEBUGKPILOT << fname << ": Incidence is not a todo." << endl;
+ return 0L;
+ }
+
+ // don't need to check for null pointers here, the recordFromIncidence(PTE*, KCal::Todo*) will do that.
+ if (KCalSync::setTodoEntry(todoEntry,todo,*fTodoAppInfo->categoryInfo()))
+ {
+ return todoEntry->pack();
+ }
+ else
+ {
+ return 0L;
+ }
+}
+
+KCal::Incidence *TodoConduit::incidenceFromRecord(KCal::Incidence *e, const PilotRecordBase *de)
+{
+ FUNCTIONSETUP;
+
+ if (!de || !e)
+ {
+ DEBUGKPILOT << fname
+ << ": Got NULL entry or NULL incidence." << endl;
+ return 0L;
+ }
+
+ const PilotTodoEntry *todoEntry = dynamic_cast<const PilotTodoEntry *>(de);
+ if (!todoEntry)
+ {
+ DEBUGKPILOT << fname << ": HH record not a todo entry." << endl;
+ return 0L;
+ }
+
+ KCal::Todo *todo = dynamic_cast<KCal::Todo *>(e);
+ if (!todo)
+ {
+ DEBUGKPILOT << fname << ": Incidence is not a todo." << endl;
+ return 0L;
+ }
+
+ KCalSync::setTodo(todo, todoEntry,*fTodoAppInfo->categoryInfo());
+ return e;
+}
+
+
+
+
+
+void TodoConduit::preRecord(PilotRecord*r)
+{
+ FUNCTIONSETUP;
+ if (!categoriesSynced && r)
+ {
+ const PilotRecordBase *de = newPilotEntry(r);
+ KCal::Incidence *e = fP->findIncidence(r->id());
+ KCalSync::setCategory(dynamic_cast<KCal::Todo*>(e),
+ dynamic_cast<const PilotTodoEntry*>(de),
+ *fTodoAppInfo->categoryInfo());
+ }
+}
+
+
+
+
+
+
+static VCalConduitSettings *config_vcal = 0L;
+
+VCalConduitSettings *TodoConduit::theConfig() {
+ if (!config_vcal)
+ {
+ config_vcal = new VCalConduitSettings(CSL1("Calendar"));
+ }
+
+ return config_vcal;
+}
+
+VCalConduitSettings *TodoConduit::config() {
+ return theConfig();
+}
diff --git a/kpilot/conduits/vcalconduit/todo-conduit.desktop b/kpilot/conduits/vcalconduit/todo-conduit.desktop
new file mode 100644
index 000000000..dcf7c2225
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/todo-conduit.desktop
@@ -0,0 +1,107 @@
+[Desktop Entry]
+Type=Service
+Comment=This conduit syncs the ToDo list from your handheld to KOrganizer.
+Comment[af]=Hierdie pad sinkroniseer die Te-doen lys vanaf jou draagbare toestel na KOrganizer.
+Comment[bg]=Синхронизация на списъка със задачи на мобилно устройство с организатора в KDE
+Comment[bs]=Ovaj conduit sinhronizuje listu Zadataka na ručnom računaru sa KOrganizerom.
+Comment[ca]=Aquest conducte sincronitza la llista de pendents des de la vostra agenda electrònica a KOrganizer.
+Comment[cs]=Toto propojení synchronizuje seznam úkolů s KOrganizérem
+Comment[cy]=Mae'r cwndid yma yn cydamseru'r rhestr I-Wneud o'ch llawiadur i KTrefnydd.
+Comment[da]=Denne kanal synkroniserer din gøremålsliste fra din håndholdte til KOrganizer.
+Comment[de]=Abgleich der Aufgabenlisten von Taschencomputer und KOrganizer
+Comment[el]=Αυτός ο σύνδεσμος συγχρονίζει τη λίστα προς υλοποίηση από τον υπολογιστή παλάμης σας στο KOrganizer.
+Comment[eo]=Tiu kanalo sinkronigas la farendaĵliston de via poŝkomputilo kun KOrganizilo.
+Comment[es]=Este conducto sincroniza la lista de tareas pendientes de su agenda electrónica con KOrganizer.
+Comment[et]=See kanal sünkroniseerib pihuarvuti ja KOrganizeri ülesannete nimekirja.
+Comment[eu]=Kanal honek zure agenda elektronikoko egitekoen zerrenda KOrganizer-era sinkronizatzen du.
+Comment[fa]=این لوله، فهرست کارهایی که باید انجام شود را از دستی شما با KOrganizer همگام‌سازی می‌کند.
+Comment[fi]=Tämä yhdyskäytävä synkronoi taskutietokoneen tehtävälistan KOrganizeriin.
+Comment[fr]=Ce canal synchronise la liste des tâches de votre Palm sur KOrganizer.
+Comment[fy]=Dit conduit syngronisearret de takenlist fan jo handheld mei KOrganizer.
+Comment[gl]=Este conducto sincroniza a lista de tarefas pendentes dende o seu aparello portátil a KOrganizer.
+Comment[hi]=यह कन्ड्यूइट आपके हैंण्डहेल्ड से टू-डू सूची को के-आर्गेनाइज़र में सिंक करता है
+Comment[hu]=Ezzel a csatolóval a Pilot tennivalólistája és a KOrganizer tennivalói között lehet szinkronizálást végezni.
+Comment[is]=Þessi rás samstillir verkþáttalista lófatölvunnar þinnar og KOrganizer.
+Comment[it]=Questo condotto sincronizza il tuo Pilot con la lista delle cose da fare di KOrganizer.
+Comment[ja]=このコンジットはハンドヘルドの To-Do と KOrganizer を同期させます。
+Comment[ka]=ამოცანათა სიების სინქრონიზაცია KOrganizer-ისთვის.
+Comment[kk]=Қалта құрылғыдағы жоспар тізімін KOrganizer-мен қадамдастыру арнасы.
+Comment[km]=បំពង់​នេះ​ធ្វើ​សមកាលកម្ម​បញ្ជី​ការងារ​ត្រូវ​ធ្វើ​ពី​ឧបករណ៍​យួរ​ដៃ​របស់​អ្នកទៅ KOrganizer ។
+Comment[lt]=Šis kanalas sinchronizuoja Jūsų darbų sąrašą iš delninuko su su KOrganizer sąrašu.
+Comment[ms]=Saluran ini mensegerakkan senarai tugasan dari komputer telapak anda ke KOrganizer.
+Comment[nb]=Denne kanalen synkroniserer gjørelista fra PDA-en til KOrganizer.
+Comment[nds]=Synkroniseert de Opgavenlist vun den Handreekner mit KOrganizer.
+Comment[ne]=यो कन्डयुटले केडीई आयोजकमा ह्यान्डहेल्डबाट कार्य गर्ने सूचि सिन्क गर्दछ ।
+Comment[nl]=Dit conduit synchroniseert de takenlijst van uw handheld met KOrganizer.
+Comment[nn]=Denne koplinga synkroniserer oppgåvelista frå den handheldte eininga di til KOrganizer.
+Comment[pl]=Ten łącznik synchronizuje listę zadań z palmtopa z KOrganizerem.
+Comment[pt]=Esta conduta sincroniza a lista de 'A Fazer' do seu dispositivo com o KOrganizer.
+Comment[pt_BR]=Este conduíte sincroniza a lista de tarefas do seu handheld com o KOrganizer.
+Comment[ru]=Канал синхронизации списка задач КПК и органайзера KDE.
+Comment[sk]=Táto spojka synchronizuje zoznam ToDo s KOrganizer.
+Comment[sl]=Ta veznik usklajuje seznam čakajočih opravil z vašega ročnega računalnika s KOrganizerjem.
+Comment[sr]=Овај провод синхронизује листу обавеза из вашег ручног рачунара са KOrganizer-ом.
+Comment[sr@Latn]=Ovaj provod sinhronizuje listu obaveza iz vašeg ručnog računara sa KOrganizer-om.
+Comment[sv]=Den här kanalen synkroniserar uppgiftslistan i handdatorn med Korganizer.
+Comment[ta]=இந்த காப்புக்குழாய் உங்கள் கையேட்டில் இருந்து செய்யவேண்டிய பட்டியலை கேஅமைபாளருக்கு ஒத்திசைக்கிறது
+Comment[tg]=Канали синхронизатсияи рӯйхати вазифоти Pilot ва органайзери KDE.
+Comment[tr]=Bu bileşen el bilgisayarınızdaki Yapılacaklar Listesini KOrganizer ile birleştirir.
+Comment[uk]=Цей акведук синхронізує список завдань кишенькового пристрою з тижневиком KOrganizer.
+Comment[zh_CN]=此管道会将您的待办列表与 KOrganizer 同步。
+Comment[zh_TW]=此軟體將您的 handheld 與 KOrganizer 的待辦事項清單同步。
+Name=ToDos (KOrganizer)
+Name[af]=Te-doen (KOrganizer)
+Name[ar]=الواجبات (KOrganizer)
+Name[be]=Заданні (K Арганізатар)
+Name[bg]=Задачи (KOrganizer)
+Name[br]=Traoù d'ober (KOrganizer)
+Name[bs]=Zadaci (KOrganizer)
+Name[ca]=Pendents (KOrganizer)
+Name[cs]=Úkoly (KOrganizer)
+Name[da]=Gøremål (KOrganizer)
+Name[de]=Aufgaben (KOrganizer)
+Name[el]=Προς υλοποίηση εργασίες (KOrganizer)
+Name[eo]=Farendaĵoj (KOrganizilo)
+Name[es]=Tareas pendientes (KOrganizer)
+Name[et]=Ülesanded (KOrganizer)
+Name[eu]=Egitekoak (KOrganizer)
+Name[fa]=کارهای انجامی (KOrganizer)
+Name[fi]=Tehtävät (KOrganizer)
+Name[fr]=Tâches (KOrganizer)
+Name[fy]=Taken (KOrganizer)
+Name[ga]=Tascanna (KOrganizer)
+Name[gl]=Pendentes (KOrganizer)
+Name[he]=מטלות (ארגונית)
+Name[hu]=Feladatok (KOrganizer)
+Name[is]=Verkþáttalistar (KOrganizer)
+Name[it]=Cose da fare (KOrganizer)
+Name[ja]=To-Do (KOrganizer)
+Name[ka]=ამოცანები (KOrganizer)
+Name[kk]=Жоспарлар (KOrganizer)
+Name[km]=ការងារ​ត្រូវ​ធ្វើ (KOrganizer)
+Name[lt]=Darbai (KOrganizer)
+Name[ms]=Tugsan (KOrganizer)
+Name[nb]=Gjøreliste (KOrganizer)
+Name[nds]=Opgaven (KOrganizer)
+Name[ne]=गर्नुपर्ने कार्यहरू (केडीई आयोजक)
+Name[nl]=Taken (KOrganizer)
+Name[nn]=Oppgåveliste (KOrganizer)
+Name[pl]=Do zrobienia (Korganizer)
+Name[pt]=Por Fazer (KOrganizer)
+Name[pt_BR]=Tarefas (KOrganizer)
+Name[ru]=Задачи (KOrganizer)
+Name[se]=Barggut (KOrganizer)
+Name[sk]=Úlohy (KOrganizer)
+Name[sl]=Čakajoča opravila (KOrganizer)
+Name[sr]=Обавезе (KOrganizer)
+Name[sr@Latn]=Obaveze (KOrganizer)
+Name[sv]=Uppgifter (Korganizer)
+Name[ta]=செய்ய வேண்டியவை(கேஅமைப்பாளர்)
+Name[tg]=Вазифот (KOrganizer)
+Name[tr]=Yapılacaklar (KOrganizer)
+Name[uk]=Завдання (KOrganizer)
+Name[zh_CN]=待办事项 (KOrganizer)
+Name[zh_TW]=待辦事項(KOrganizer)
+Implemented=file
+ServiceTypes=KPilotConduit
+X-KDE-Library=conduit_todo
diff --git a/kpilot/conduits/vcalconduit/todo-conduit.h b/kpilot/conduits/vcalconduit/todo-conduit.h
new file mode 100644
index 000000000..3364d61f2
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/todo-conduit.h
@@ -0,0 +1,108 @@
+#ifndef _KPILOT_TODO_CONDUIT_H
+#define _KPILOT_TODO_CONDUIT_H
+/* todo-conduit.h KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 1998-2001 Dan Pilone
+** Copyright (C) 1998-2000 Preston Brown <[email protected]>
+** Copyright (C) 1998 Herwin-Jan Steehouwer
+**
+** This file is part of the todo conduit, a conduit for KPilot that
+** synchronises the Pilot's todo application with the outside world,
+** which currently means KOrganizer.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <libkcal/todo.h>
+#include <pilotTodoEntry.h>
+#include "vcal-conduitbase.h"
+
+class PilotSerialDatabase;
+class PilotLocalDatabase;
+
+class TodoConduitPrivate : public VCalConduitPrivateBase
+{
+public:
+ TodoConduitPrivate(KCal::Calendar *buddy);
+ virtual ~TodoConduitPrivate() {};
+
+ KCal::Todo::List fAllTodos;
+ KCal::Todo::List::ConstIterator fAllTodosIterator;
+
+ virtual int updateIncidences();
+ virtual void addIncidence(KCal::Incidence*);
+ virtual void removeIncidence(KCal::Incidence *);
+ virtual KCal::Incidence *findIncidence(recordid_t);
+ virtual KCal::Incidence *findIncidence(PilotRecordBase *tosearch);
+ virtual KCal::Incidence *getNextIncidence();
+ virtual KCal::Incidence *getNextModifiedIncidence();
+ virtual int count() {return fAllTodos.count();};
+} ;
+
+
+
+class TodoConduit : public VCalConduitBase
+{
+Q_OBJECT
+public:
+ TodoConduit(KPilotLink *,
+ const char *name=0L,
+ const QStringList &args = QStringList());
+ virtual ~TodoConduit();
+
+protected:
+ virtual const QString getTitle(PilotRecordBase *de);
+
+ virtual const QString dbname() { return CSL1("ToDoDB"); };
+ virtual void preSync();
+ virtual VCalConduitPrivateBase *createPrivateCalendarData(KCal::Calendar *fCalendar)
+ {
+ return new TodoConduitPrivate(fCalendar);
+ };
+
+ virtual void readConfig();
+ void _getAppInfo();
+ void _setAppInfo();
+ virtual void postSync();
+
+ virtual PilotRecordBase *newPilotEntry(PilotRecord*r)
+ {
+ return new PilotTodoEntry(r);
+ };
+ virtual KCal::Incidence*newIncidence() { return new KCal::Todo; };
+
+ virtual void preRecord(PilotRecord*r);
+ virtual VCalConduitSettings *config();
+public:
+ static VCalConduitSettings *theConfig();
+
+protected:
+
+ virtual PilotRecord *recordFromIncidence(PilotRecordBase *de, const KCal::Incidence *e);
+ virtual KCal::Incidence *incidenceFromRecord(KCal::Incidence *e, const PilotRecordBase *de);
+
+ PilotToDoInfo *fTodoAppInfo;
+ bool categoriesSynced;
+} ;
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/todo-factory.cc b/kpilot/conduits/vcalconduit/todo-factory.cc
new file mode 100644
index 000000000..fad8841f2
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/todo-factory.cc
@@ -0,0 +1,46 @@
+/* KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the factory for the todo-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include "pluginfactory.h"
+
+#include "todo-setup.h"
+#include "todo-conduit.h"
+
+extern "C"
+{
+
+void *init_conduit_todo()
+{
+ return new ConduitFactory<ToDoWidgetSetup,TodoConduit>;
+}
+
+}
+
diff --git a/kpilot/conduits/vcalconduit/todo-factory.h b/kpilot/conduits/vcalconduit/todo-factory.h
new file mode 100644
index 000000000..52a2d5e4b
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/todo-factory.h
@@ -0,0 +1,40 @@
+#ifndef _KPILOT_TODO_FACTORY_H
+#define _KPILOT_TODO_FACTORY_H
+/* todo-factory.h KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the factory for the todo-conduit plugin.
+** It also defines the class for the behavior of the setup dialog.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+extern "C"
+{
+
+void *init_libtodoconduit();
+
+}
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/todo-setup.cc b/kpilot/conduits/vcalconduit/todo-setup.cc
new file mode 100644
index 000000000..eb1c98c91
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/todo-setup.cc
@@ -0,0 +1,86 @@
+/* KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the factory for the todo-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qbuttongroup.h>
+#include <kaboutdata.h>
+
+#include "korganizerConduit.h"
+#include "todo-conduit.h"
+#include "todo-setup.h"
+
+
+
+ToDoWidgetSetup::ToDoWidgetSetup(QWidget *w, const char *n) :
+ VCalWidgetSetupBase(w,n)
+{
+ FUNCTIONSETUP;
+ fConduitName = i18n("To-do");
+ KAboutData *fAbout = new KAboutData("todoConduit",
+ I18N_NOOP("To-do Conduit for KPilot"),
+ KPILOT_VERSION,
+ I18N_NOOP("Configures the To-do Conduit for KPilot"),
+ KAboutData::License_GPL,
+ "(C) 2001, Adriaan de Groot\n(C) 2002-2003, Reinhold Kainhofer");
+ fAbout->addAuthor("Dan Pilone",
+ I18N_NOOP("Original Author"));
+ fAbout->addAuthor("Preston Brown",
+ I18N_NOOP("Original Author"));
+ fAbout->addAuthor("Herwin-Jan Steehouwer",
+ I18N_NOOP("Original Author"));
+ fAbout->addAuthor("Adriaan de Groot",
+ I18N_NOOP("Maintainer"),
+ "http://www.cs.kun.nl/~adridg/kpilot");
+ fAbout->addAuthor("Reinhold Kainhofer",
+ I18N_NOOP("Maintainer"),
+ "http://reinhold.kainhofer.com/Linux/");
+
+ ConduitConfigBase::addAboutPage(fConfigWidget->tabWidget,fAbout);
+
+ fConfigWidget->fSyncDestination->setTitle(i18n("To-do Destination"));
+}
+
+ToDoWidgetSetup::~ToDoWidgetSetup()
+{
+ FUNCTIONSETUP;
+}
+
+/* static */ ConduitConfigBase *ToDoWidgetSetup::create(QWidget *w, const char *n)
+{
+ return new ToDoWidgetSetup(w,n);
+}
+
+VCalConduitSettings*ToDoWidgetSetup::config()
+{
+ return TodoConduit::theConfig();
+}
+
diff --git a/kpilot/conduits/vcalconduit/todo-setup.h b/kpilot/conduits/vcalconduit/todo-setup.h
new file mode 100644
index 000000000..9eebd3a3d
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/todo-setup.h
@@ -0,0 +1,44 @@
+#ifndef _KPILOT_TODO_SETUP_H
+#define _KPILOT_TODO_SETUP_H
+/* todo-setup.h KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the class for the behavior of the setup dialog.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "vcal-setup.h"
+
+class ToDoWidgetSetup : public VCalWidgetSetupBase
+{
+public:
+ ToDoWidgetSetup(QWidget *,const char *);
+ virtual ~ToDoWidgetSetup();
+
+ virtual VCalConduitSettings*config();
+ static ConduitConfigBase *create(QWidget *, const char *);
+} ;
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/todoRecord.cc b/kpilot/conduits/vcalconduit/todoRecord.cc
new file mode 100644
index 000000000..7db753fb5
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/todoRecord.cc
@@ -0,0 +1,141 @@
+/* vcalRecord.cc KPilot
+**
+** Copyright (C) 2006 by Adriaan de Groot <[email protected]>
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <libkcal/calendar.h>
+#include <libkcal/calendarlocal.h>
+#include <libkcal/recurrence.h>
+#include <libkcal/vcalformat.h>
+
+#include "pilot.h"
+#include "pilotTodoEntry.h"
+
+#include "kcalRecord.h"
+#include "todoRecord.h"
+
+bool KCalSync::setTodoEntry(PilotTodoEntry *de,
+ const KCal::Todo *todo,
+ const CategoryAppInfo &info)
+{
+ FUNCTIONSETUP;
+ if (!de || !todo) {
+ DEBUGKPILOT << fname << ": NULL todo given... Skipping it" << endl;
+ return false;
+ }
+
+ // set secrecy, start/end times, alarms, recurrence, exceptions, summary and description:
+ if (todo->secrecy()!=KCal::Todo::SecrecyPublic)
+ {
+ de->setSecret( true );
+ }
+
+ // update it from the iCalendar Todo.
+
+ if (todo->hasDueDate()) {
+ struct tm t = writeTm(todo->dtDue());
+ de->setDueDate(t);
+ de->setIndefinite(0);
+ } else {
+ de->setIndefinite(1);
+ }
+
+ // TODO: take recurrence (code in VCAlConduit) from ActionNames
+
+ setCategory(de, todo, info);
+
+ // TODO: sync the alarm from ActionNames. Need to extend PilotTodoEntry
+ de->setPriority(todo->priority());
+
+ de->setComplete(todo->isCompleted());
+
+ // what we call summary pilot calls description.
+ de->setDescription(todo->summary());
+
+ // what we call description pilot puts as a separate note
+ de->setNote(todo->description());
+
+ DEBUGKPILOT << "-------- " << todo->summary() << endl;
+ return de->pack();
+}
+
+bool KCalSync::setTodo(KCal::Todo *e,
+ const PilotTodoEntry *de,
+ const CategoryAppInfo &info)
+{
+ FUNCTIONSETUP;
+
+ if (!e)
+ {
+ DEBUGKPILOT << fname
+ << ": null todo entry given. skipping..." << endl;
+ return false;
+ }
+ if (!de)
+ {
+ DEBUGKPILOT << fname
+ << "! NULL todo entry given... Skipping it" << endl;
+ return false;
+ }
+
+
+ e->setPilotId(de->id());
+ DEBUGKPILOT<<fname<<": set KCal item to pilotId: [" << e->pilotId() << "] ..."<<endl;
+
+ e->setSecrecy(de->isSecret() ? KCal::Todo::SecrecyPrivate : KCal::Todo::SecrecyPublic);
+
+ if (de->getIndefinite()) {
+ e->setHasDueDate(false);
+ } else {
+ e->setDtDue(readTm(de->getDueDate()));
+ e->setHasDueDate(true);
+ }
+
+ // Categories
+ setCategory(e, de, info);
+
+ // PRIORITY //
+ e->setPriority(de->getPriority());
+
+ // COMPLETED? //
+ e->setCompleted(de->getComplete());
+ if ( de->getComplete() && !e->hasCompletedDate() ) {
+ e->setCompleted( QDateTime::currentDateTime() );
+ }
+
+ e->setSummary(de->getDescription());
+ e->setDescription(de->getNote());
+
+ // NOTE: This MUST be done last, since every other set* call
+ // calls updated(), which will trigger an
+ // setSyncStatus(SYNCMOD)!!!
+ e->setSyncStatus(KCal::Incidence::SYNCNONE);
+
+ return true;
+}
diff --git a/kpilot/conduits/vcalconduit/todoRecord.h b/kpilot/conduits/vcalconduit/todoRecord.h
new file mode 100644
index 000000000..85ffd6aaf
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/todoRecord.h
@@ -0,0 +1,49 @@
+#ifndef _KPILOT_TODORECORD_H
+#define _KPILOT_TODORECORD_H
+/*
+** Copyright (C) 2006 by Adriaan de Groot <[email protected]>
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+namespace KCal
+{
+ class Todo;
+}
+
+class PilotTodoEntry;
+
+namespace KCalSync
+{
+ bool setTodo(KCal::Todo *e,
+ const PilotTodoEntry *de,
+ const CategoryAppInfo &info);
+ bool setTodoEntry(PilotTodoEntry *de,
+ const KCal::Todo *e,
+ const CategoryAppInfo &info);
+}
+
+#endif
+
diff --git a/kpilot/conduits/vcalconduit/vcal-conduit.cc b/kpilot/conduits/vcalconduit/vcal-conduit.cc
new file mode 100644
index 000000000..0eea42733
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcal-conduit.cc
@@ -0,0 +1,309 @@
+/* KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the vcal-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <libkcal/calendar.h>
+#include <libkcal/calendarlocal.h>
+#include <libkcal/recurrence.h>
+#include <libkcal/vcalformat.h>
+
+#include "pilotDateEntry.h"
+#include "pilotDatabase.h"
+
+#include "vcal-conduit.moc"
+#include "vcalconduitSettings.h"
+
+#include "kcalRecord.h"
+#include "vcalRecord.h"
+
+
+extern "C"
+{
+
+unsigned long version_conduit_vcal = Pilot::PLUGIN_API;
+
+}
+
+
+
+
+VCalConduitPrivate::VCalConduitPrivate(KCal::Calendar *b) :
+ VCalConduitPrivateBase(b)
+{
+ fAllEvents.setAutoDelete(false);
+}
+
+void VCalConduitPrivate::addIncidence(KCal::Incidence*e)
+{
+ fAllEvents.append(dynamic_cast<KCal::Event*>(e));
+ fCalendar->addEvent(dynamic_cast<KCal::Event*>(e));
+}
+
+int VCalConduitPrivate::updateIncidences()
+{
+ FUNCTIONSETUP;
+ if (!fCalendar) return 0;
+ fAllEvents = fCalendar->events();
+ fAllEvents.setAutoDelete(false);
+ return fAllEvents.count();
+}
+
+
+void VCalConduitPrivate::removeIncidence(KCal::Incidence *e)
+{
+ // use dynamic_cast which returns a null pointer if the class does not match...
+ fAllEvents.remove(dynamic_cast<KCal::Event*>(e));
+ if (!fCalendar) return;
+ fCalendar->deleteEvent(dynamic_cast<KCal::Event*>(e));
+ // now just in case we're in the middle of reading through our list
+ // and we delete something, set reading to false so we start at the
+ // top again next time and don't have problems with our iterator
+ reading = false;
+}
+
+
+KCal::Incidence *VCalConduitPrivate::findIncidence(recordid_t id)
+{
+ KCal::Event::List::ConstIterator it;
+ for( it = fAllEvents.begin(); it != fAllEvents.end(); ++it ) {
+ KCal::Event *event = *it;
+ if ((recordid_t)event->pilotId() == id) return event;
+ }
+ return 0L;
+}
+
+KCal::Incidence *VCalConduitPrivate::findIncidence(PilotRecordBase *tosearch)
+{
+ PilotDateEntry*entry=dynamic_cast<PilotDateEntry*>(tosearch);
+ if (!entry) return 0L;
+
+ QString title=entry->getDescription();
+ QDateTime dt=readTm( entry->getEventStart() );
+
+ KCal::Event::List::ConstIterator it;
+ for( it = fAllEvents.begin(); it != fAllEvents.end(); ++it ) {
+ KCal::Event *event = *it;
+ if ( (event->dtStart() == dt) && (event->summary() == title) ) return event;
+ }
+ return 0L;
+}
+
+
+
+KCal::Incidence *VCalConduitPrivate::getNextIncidence()
+{
+ FUNCTIONSETUP;
+
+ if (reading) {
+ ++fAllEventsIterator;
+ } else {
+ reading=true;
+ fAllEventsIterator = fAllEvents.begin();
+ }
+ // At end of list, or empty list.
+ return (fAllEventsIterator == fAllEvents.end()) ? 0L : *fAllEventsIterator;
+}
+
+/** Find the next incidence in the list which ddoes not have the SYNCNONE flag set. The
+ * current position is always stored in the iteratoor fAllEventsIterator, so we can just
+ * start from there. Only if reading==false, we haven't yet started goind through the
+ * incidents, so start at fAllEvents.begin() in that case */
+KCal::Incidence *VCalConduitPrivate::getNextModifiedIncidence()
+{
+ FUNCTIONSETUP;
+ KCal::Event*e=0L;
+ if (!reading)
+ {
+ // Start from the top
+ reading=true;
+ fAllEventsIterator = fAllEvents.begin();
+ }
+ else
+ {
+ // Move on from current position
+ ++fAllEventsIterator;
+ }
+
+ // Fetch (new) current if possible.
+ if ( fAllEventsIterator != fAllEvents.end() ) e = *fAllEventsIterator;
+ // Then walk the list until we find an unsynced entry
+ while ( fAllEventsIterator != fAllEvents.end() &&
+ e && e->syncStatus()!=KCal::Incidence::SYNCMOD && e->pilotId() > 0)
+ {
+ e = (++fAllEventsIterator != fAllEvents.end()) ? *fAllEventsIterator : 0L;
+ }
+ return (fAllEventsIterator == fAllEvents.end()) ? 0L : *fAllEventsIterator;
+}
+
+
+
+/****************************************************************************
+ * VCalConduit class *
+ ****************************************************************************/
+
+VCalConduit::VCalConduit(KPilotLink *d,
+ const char *n,
+ const QStringList &a) :
+ VCalConduitBase(d,n,a),
+ fAppointmentAppInfo( 0L )
+{
+ FUNCTIONSETUP;
+ fConduitName=i18n("Calendar");
+}
+
+
+VCalConduit::~VCalConduit()
+{
+// FUNCTIONSETUP;
+}
+
+VCalConduitPrivateBase *VCalConduit::createPrivateCalendarData(KCal::Calendar *fCalendar) {
+ return new VCalConduitPrivate(fCalendar);
+}
+
+void VCalConduit::_getAppInfo()
+{
+ FUNCTIONSETUP;
+ // get the address application header information
+ KPILOT_DELETE(fAppointmentAppInfo);
+ fAppointmentAppInfo = new PilotDateInfo( fDatabase );
+}
+
+const QString VCalConduit::getTitle(PilotRecordBase *de)
+{
+ PilotDateEntry*d=dynamic_cast<PilotDateEntry*>(de);
+ if (d) return QString(d->getDescription());
+ return QString::null;
+}
+
+
+
+PilotRecord *VCalConduit::recordFromIncidence(PilotRecordBase *de, const KCal::Incidence*e)
+{
+ FUNCTIONSETUP;
+ if (!de || !e)
+ {
+ DEBUGKPILOT << fname
+ << ": got NULL entry or NULL incidence." << endl;
+ return 0L;
+ }
+
+ if ( (e->recurrenceType() == KCal::Recurrence::rYearlyDay) ||
+ (e->recurrenceType() == KCal::Recurrence::rYearlyPos) )
+ {
+ // Warn ahead of time
+ emit logMessage(i18n("Event \"%1\" has a yearly recurrence other than by month, will change this to recurrence by month on handheld.").arg(e->summary()));
+ }
+
+ PilotDateEntry *dateEntry = dynamic_cast<PilotDateEntry*>(de);
+ if (!dateEntry)
+ {
+ // Secretly wasn't a date entry after all
+ return 0L;
+ }
+
+ const KCal::Event *event = dynamic_cast<const KCal::Event *>(e);
+ if (!event)
+ {
+ DEBUGKPILOT << fname << ": Incidence is not an event." << endl;
+ return 0L;
+ }
+
+ if (KCalSync::setDateEntry(dateEntry, event,*fAppointmentAppInfo->categoryInfo()))
+ {
+ return dateEntry->pack();
+ }
+ else
+ {
+ return 0L;
+ }
+}
+
+KCal::Incidence *VCalConduit::incidenceFromRecord(KCal::Incidence *e, const PilotRecordBase *de)
+{
+ FUNCTIONSETUP;
+
+ if (!de || !e)
+ {
+ DEBUGKPILOT << fname
+ << ": Got NULL entry or NULL incidence." << endl;
+ return 0L;
+ }
+
+ const PilotDateEntry *dateEntry = dynamic_cast<const PilotDateEntry *>(de);
+ if (!dateEntry)
+ {
+ DEBUGKPILOT << fname << ": HH record not a date entry." << endl;
+ return 0L;
+ }
+
+ KCal::Event *event = dynamic_cast<KCal::Event *>(e);
+ if (!event)
+ {
+ DEBUGKPILOT << fname << ": Incidence is not an event." << endl;
+ return 0L;
+ }
+
+ KCalSync::setEvent(event, dateEntry,*fAppointmentAppInfo->categoryInfo());
+ return e;
+}
+
+
+
+PilotRecordBase * VCalConduit::newPilotEntry(PilotRecord*r)
+{
+ return new PilotDateEntry(r);
+}
+
+KCal::Incidence* VCalConduit::newIncidence()
+{
+ return new KCal::Event;
+}
+
+static VCalConduitSettings *config_vcal = 0L;
+
+VCalConduitSettings *VCalConduit::theConfig()
+{
+ if (!config_vcal)
+ {
+ config_vcal = new VCalConduitSettings(CSL1("Calendar"));
+ }
+
+ return config_vcal;
+}
+
+VCalConduitSettings *VCalConduit::config() {
+ return theConfig();
+}
+
+
+
+// vim: ts=4:sw=4:noexpandtab:
+
diff --git a/kpilot/conduits/vcalconduit/vcal-conduit.desktop b/kpilot/conduits/vcalconduit/vcal-conduit.desktop
new file mode 100644
index 000000000..e0a84c55f
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcal-conduit.desktop
@@ -0,0 +1,105 @@
+[Desktop Entry]
+Type=Service
+Name=Calendar (KOrganizer)
+Name[af]=Kalender (KOrganizer)
+Name[ar]=التقويم (KOrganizer)
+Name[be]=Каляндар (K Арганізатар)
+Name[bg]=Календар (KOrganizer)
+Name[br]=Deiziadur (KOrganizer)
+Name[bs]=Kalendar (KOrganizer)
+Name[ca]=Calendari (KOrganizer)
+Name[cs]=Kalendář (KOrganizer)
+Name[da]=Kalender (KOrganizer)
+Name[de]=Kalender (KOrganizer)
+Name[el]=Ημερολόγιο (KOrganizer)
+Name[eo]=Kalendaro (KOrganizilo)
+Name[es]=Calendario (KOrganizer)
+Name[et]=Kalender (KOrganizer)
+Name[eu]=Egutegia (KOrganizer)
+Name[fa]=تقویم (KOrganizer)
+Name[fi]=Kalenteri (KOrganizer)
+Name[fr]=Agenda (KOrganizer)
+Name[fy]=Aginda (KOrganizer)
+Name[ga]=Féilire (KOrganizer)
+Name[gl]=Calendario (KOrganizer)
+Name[he]=לוח שנה (ארגונית)
+Name[hu]=Naptár (KOrganizer)
+Name[is]=Dagbók (KOrganizer)
+Name[it]=Calendario (KOrganizer)
+Name[ja]=カレンダー (KOrganizer)
+Name[ka]=კალენდარი (KOrganizer)
+Name[kk]=Күнтізбе (KOrganizer)
+Name[km]=ប្រតិទិន (KOrganizer)
+Name[lt]=Kalendorius (KOrganizer)
+Name[mk]=Календар (КОрганизатор)
+Name[ms]=Kalendar (KOrganizer)
+Name[nb]=Kalender (KOrganizer)
+Name[nds]=Kalenner (KOrganizer)
+Name[ne]=क्यालेन्डर (केडीई आयोजक)
+Name[nl]=Agenda (KOrganizer)
+Name[nn]=Kalender (KOrganizer)
+Name[pl]=Kalendarz (Korganizer)
+Name[pt]=Calendário (KOrganizer)
+Name[pt_BR]=Calendário (KOrganizer)
+Name[ru]=Календарь (KOrganizer)
+Name[se]=Kaleandar (KOrganizer)
+Name[sk]=Kalendár (KOrganizer)
+Name[sl]=Koledar (KOrganizer)
+Name[sr]=Календар (KOrganizer)
+Name[sr@Latn]=Kalendar (KOrganizer)
+Name[sv]=Kalender (Korganizer)
+Name[ta]=நாள்காட்டி(கேஅமைப்பாளர்)
+Name[tg]=Тақвимот (KOrganizer)
+Name[tr]=Takvim (KOrganizer)
+Name[uk]=Календар (KOrganizer)
+Name[zh_CN]=日历 (KOrganizer)
+Name[zh_TW]=行事曆(KOrganizer)
+Comment=This conduit synchronizes your handheld with the KOrganizer datebook.
+Comment[af]=Hierdie pad sinkroniseer jou draagbare toestel met die KOrganizer datum boek.
+Comment[bg]=Синхронизация на календара на мобилно устройство с организатора в KDE.
+Comment[ca]=Aquest conducte sincronitza la vostra agenda electrònica amb la llibreta de dates de KOrganizer.
+Comment[cs]=Toto propojení synchronizuje seznam úkolů s KOrganizérem.
+Comment[da]=Denne kanal synkroniserer din håndholdte med KOrganizer-datobogen.
+Comment[de]=Abgleich des Taschencomputers mit dem KOrganizer-Terminkalender
+Comment[el]=Αυτός ο σύνδεσμος συγχρονίζει τον υπολογιστή παλάμης σας με το βιβλίο ημερομηνιών του KOrganizer.
+Comment[en_GB]=This conduit synchronises your handheld with the KOrganizer datebook.
+Comment[eo]=Tiu kanalo sinkronigas vian poŝkomputilon kun la datlibro de KOrganizilo.
+Comment[es]=Este conducto sincroniza su agenda electrónica con la libreta de fechas de KOrganizer.
+Comment[et]=See kanal sünkroniseerib pihuseadme ja KOrganizeri kalendri.
+Comment[eu]=Kanal honek zure agenda elektronikoa KOrganizer-en data-liburuarekin sinkronizatzen du.
+Comment[fa]=این لوله، دستی شما را با کتاب دادۀ KOrganizer همگام می‌سازد.
+Comment[fi]=Tämä yhdyskäytävä synkronoi taskutietokoneen KOrganizerin päiväkirjaan.
+Comment[fr]=Ce canal synchronise votre Palm avec l'agenda KOrganizer.
+Comment[fy]=Dit conduit syngronisearret jo handheld mei KOrganizer's datumboek.
+Comment[gl]=Este conducto sincroniza o seu aparello portátil co libro de datos de KOrganizer.
+Comment[hu]=Ezzel a csatolóval szinkronizálhatók a kézi számítógép és a KOrganizer dátumai.
+Comment[is]=Þessi rás samstillir lófatölvuna þína við dagbók KOrganizer.
+Comment[it]=Questo conduit sincronizza il tuo palmare con il calendario di KOrganizer.
+Comment[ja]=このコンジットはハンドヘルドを KOrganizer の手帳と同期させます。
+Comment[ka]=სინქრონიზაცია KOrganizer-ისთვის.
+Comment[kk]=Қалта құрылғыдағы күнтізбені KOrganizer-мен қадамдастыру арнасы.
+Comment[km]=បំពង់​នេះ​ធ្វើ​សមកាលកម្ម​ឧបករណ៍​យួរ​ដៃ​របស់​អ្នក​ជាមួយ​នឹង​សៀវភៅ​កាលបរិច្ឆេទ KOrganizer ។
+Comment[lt]=Šis kanalas sinchronizuoja jūsų delninuką su KOrganizer datų knyga.
+Comment[mk]=Овој канал ги синхронизира рачниот уред и датумите од KОрганизатор.
+Comment[ms]=Saluran ini mensegerakkan komputer telapak dengan buku tarikh KOrganizer.
+Comment[nb]=Denne kanalen synkroniserer PDA-en med KOrganizers almanakk.
+Comment[nds]=Synkroniseert den Mötenkalenner vun den Handreekner mit KOrganizer.
+Comment[ne]=यो कन्ड्युटले केडीई आयोजक मिति पुस्तिकामा ह्यान्डहेल्ड समक्रमण गर्छ ।
+Comment[nl]=Dit conduit synchroniseert uw handheld met KOrganizer's datumboek.
+Comment[pl]=Ten łącznik synchronizuje palmtopa z terminarzem KOrganizera.
+Comment[pt]=Esta conduta sincroniza o seu dispositivo móvel com a agenda do KOrganizer.
+Comment[pt_BR]=Este Conduíte sincroniza seu handheld com a agenda do KOrganizer.
+Comment[ru]=Канал синхронизации календаря КПК и органайзера KDE.
+Comment[sk]=Táto spojka synchronizuje prenosné zariadenie s KOrganizer.
+Comment[sl]=Ta veznik uskladni vaš ročni računalnik z dnevnikom KOrganizerja.
+Comment[sr]=Овај провод синхронизује ваш ручни рачунар са KOrganizer-овом књигом датума.
+Comment[sr@Latn]=Ovaj provod sinhronizuje vaš ručni računar sa KOrganizer-ovom knjigom datuma.
+Comment[sv]=Den här kanalen synkroniserar din handdator med Korganizers kalender.
+Comment[ta]=இந்த குழாய் உங்கள் பைலட்டை கேஅமைப்பாளர் தேதிபுத்தகத்துடன் ஒத்திசைக்கிறது
+Comment[tr]=Bu bileşen el bilgisayarınızı KOrganizer'daki randevu defteriyle senkronize eder.
+Comment[uk]=Цей акведук синхронізує ваш кишеньковий пристрій з тижневиком KOrganizer.
+Comment[zh_CN]=此管道会将您的手持设备与 KOrganizer 的日程安排同步。
+Comment[zh_TW]=此軟體將您的 handheld 日期與 KOrganizer 同步。
+Implemented=file
+ServiceTypes=KPilotConduit
+X-KDE-Library=conduit_vcal
diff --git a/kpilot/conduits/vcalconduit/vcal-conduit.h b/kpilot/conduits/vcalconduit/vcal-conduit.h
new file mode 100644
index 000000000..c41ceb906
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcal-conduit.h
@@ -0,0 +1,101 @@
+#ifndef _KPILOT_VCAL_CONDUIT_H
+#define _KPILOT_VCAL_CONDUIT_H
+/* vcal-conduit.h KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the vcal-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <libkcal/event.h>
+
+#include "pilotDateEntry.h"
+
+#include "vcal-conduitbase.h"
+
+class PilotRecord;
+class PilotSerialDatabase;
+class PilotLocalDatabase;
+
+class VCalConduitPrivate : public VCalConduitPrivateBase
+{
+public:
+ VCalConduitPrivate(KCal::Calendar *buddy);
+ virtual ~VCalConduitPrivate() {};
+
+ KCal::Event::List fAllEvents;
+ KCal::Event::List::ConstIterator fAllEventsIterator;
+
+ virtual int updateIncidences();
+ virtual void addIncidence(KCal::Incidence*);
+ virtual void removeIncidence(KCal::Incidence *);
+ virtual KCal::Incidence *findIncidence(recordid_t);
+ /**
+ * Find the incidence based on tosearch's description and date information.
+ * Returns 0L if no incidence could be found.
+ */
+ virtual KCal::Incidence *findIncidence(PilotRecordBase *tosearch);
+ virtual KCal::Incidence *getNextIncidence();
+ virtual KCal::Incidence *getNextModifiedIncidence();
+ virtual int count() {return fAllEvents.count();};
+} ;
+
+
+
+class VCalConduit : public VCalConduitBase
+{
+Q_OBJECT
+public:
+ VCalConduit(KPilotLink *,
+ const char *name=0L,
+ const QStringList &args = QStringList());
+ virtual ~VCalConduit();
+
+protected:
+ virtual const QString dbname() { return CSL1("DatebookDB"); };
+
+ virtual void preSync() {VCalConduitBase::preSync(); _getAppInfo(); };
+ virtual VCalConduitPrivateBase *createPrivateCalendarData(KCal::Calendar *fCalendar);
+
+ void _getAppInfo();
+ void _setAppInfo();
+
+ virtual PilotRecordBase *newPilotEntry(PilotRecord*r);
+ virtual KCal::Incidence*newIncidence();
+ virtual const QString getTitle(PilotRecordBase *de);
+ virtual VCalConduitSettings *config();
+public:
+ static VCalConduitSettings *theConfig();
+
+protected:
+ virtual PilotRecord *recordFromIncidence(PilotRecordBase *de,
+ const KCal::Incidence *e);
+ virtual KCal::Incidence *incidenceFromRecord(KCal::Incidence *e,
+ const PilotRecordBase *de);
+
+ PilotDateInfo *fAppointmentAppInfo;
+};
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/vcal-conduitbase.cc b/kpilot/conduits/vcalconduit/vcal-conduitbase.cc
new file mode 100644
index 000000000..a9fc6376b
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcal-conduitbase.cc
@@ -0,0 +1,622 @@
+/* KPilot
+**
+** Copyright (C) 2002-3 by Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** Contributions:
+** Copyright (c) 2001 David Jarvie <[email protected]>
+** Copyright (C) 2006 by Bertjan Broeksema <[email protected]>
+**
+** This file defines the vcal-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <options.h>
+
+#include <qtimer.h>
+#include <qfile.h>
+
+#include <kmessagebox.h>
+#include <kio/netaccess.h>
+
+#include "libkcal/calendar.h"
+#include "libkcal/calendarlocal.h"
+#include "libkcal/calendarresources.h"
+#include <kstandarddirs.h>
+
+#include "pilotSerialDatabase.h"
+#include "pilotLocalDatabase.h"
+#include "pilotDateEntry.h"
+
+#include "vcal-conduitbase.moc"
+#include "vcalconduitSettings.h"
+
+#ifndef LIBKCAL_IS_VERSION
+#warning "Using an old version of libkcal with timezone bug."
+#define LIBKCAL_IS_VERSION(a,b,c) (0)
+#endif
+
+#include "conduitstate.h"
+#include "initstate.h"
+
+
+/****************************************************************************
+ * VCalConduitBase class *
+ ****************************************************************************/
+
+VCalConduitBase::VCalConduitBase(KPilotLink *d,
+ const char *n,
+ const QStringList &a) :
+ ConduitAction(d,n,a),
+ fCalendar(0L),
+ fP(0L)
+{
+ FUNCTIONSETUP;
+
+ fState = new InitState();
+}
+
+VCalConduitBase::~VCalConduitBase()
+{
+ FUNCTIONSETUP;
+
+ KPILOT_DELETE(fP);
+ KPILOT_DELETE(fState);
+ KPILOT_DELETE(fCalendar);
+ KPILOT_DELETE(fDatabase);
+ KPILOT_DELETE(fLocalDatabase);
+}
+
+
+/*
+ There are several different scenarios for a record on the Palm and its PC
+ counterpart. N means a new record, M flags a modified record, D a deleted
+ and - an unmodified record. First is the Palm record, second the
+ corresponding PC record:
+ (-,-) unchanged, just sync if first time or full sync
+ (N,-) no rec matching the Palm ID in the backupDB/calendar yet => add
+ KCal::Event
+ (M,-) record is in backupDB, unchanged in calendar => modify in calendar and
+ in backupDB
+ (D,-) deleted on Palm, exists in backupDB and calendar => just delete from
+ calendar and backupDB
+ (-,N) no or invalid pilotID set for the KCal::Event => just add to palm and
+ backupDB
+ (-,M) valid PilotID set => just modify on Palm
+ (-,D) Record in backupDB, but not in calendar => delete from Palm and
+ backupDB
+ (N,N) Can't find out (the two records are not correlated in any way, they
+ just have the same data!!
+ (M,M),(M,L),(L,M) (Record exists on Palm and the Event has the ID) CONFLICT,
+ ask the user what to do or use a config setting
+ (L,L) already deleted on both, no need to do anything.
+
+ The sync process is as follows (for a fast sync):
+ 1) HHToPCState goes through all records on Palm (just the modified one
+ are necessary), find it in the backupDB. The following handles ([NMD],*)
+ a) if it doesn't exist and was not deleted, add it to the calendar and
+ the backupDB
+ b) if it exists, is unchanged in the calendar and was not deleted,
+ just modify in the calendar
+ c) if it exists and was deleted, delete it from the calendar if
+ necessary
+ 2) PCToHHState goes through all KCale::Events in the calendar (just
+ modified, this is the modification time is later than the last sync time
+ ). This handles (-,N),(-,M)
+ a) if it does not have a pilotID, add it to the palm and backupDB,
+ store the PalmID
+ b) if it has a valid pilotID, update the Palm record and the backup
+ 3) DeletedUnsyncedHHState goes through all palm records (which don't
+ have the deleted flag) of the palm db and if one does not exist in the
+ Calendar, it was deleted there, so delete it from the Palm and backup,
+ too. This handles the case of (-,D)
+ 4) DeletedUnsyncedPCState goes through all KCal::Events in the calendar and
+ looks for a corresponding event in the palm database. If it does not
+ exist, that means that it was deleted on the palm, so we need to also
+ delete it from the local calendar. This handles the case of (D,-).
+
+ In addition to the fast sync, where the last sync was done with this very
+ PC and calendar file, there are two special cases: a full and a first sync.
+ -) a full sync goes through all records, not just the modified ones. The
+ pilotID setting of the calendar records is used to determine if the
+ record already exists. if yes, the record is just modified.
+ -) a first sync completely ignores the pilotID setting of the calendar
+ events. All records are added, so there might be duplicates. The add
+ function for the calendar should check if a similar record already
+ exists, but this is not done yet.
+
+ -) a full sync is done if
+ a) there is a backupdb and a calendar, but the PC id number changed
+ b) it was explicitly requested by pressing the full sync button in KPilot
+ c) the setting "always full sync" was selected in the configuration dlg
+ -) a first sync is done if
+ a) either the calendar or the backup DB does not exist.
+ b) the calendar and the backup DB exists, but the sync is done for a
+ different User name
+ c) it was explicitly requested in KPilot
+*/
+
+/* virtual */ bool VCalConduitBase::exec()
+{
+ FUNCTIONSETUP;
+
+ readConfig();
+
+ // don't do a first sync by default in any case, only when explicitly
+ // requested, or the backup database or the alendar are empty.
+ setFirstSync( false );
+
+ // TODO: Check Full sync and First sync
+ bool retrieved = false;
+ if ( !openDatabases( dbname(), &retrieved ) ) goto error;
+ setFirstSync( retrieved );
+
+ // If we are in testmode we don't need the local calendar. Else a
+ // calendar *must* be opened, we want to sync something don't we?
+ if (!syncMode().isTest() && !openCalendar() ) goto error;
+
+ // Start processing the sync
+ QTimer::singleShot(0, this, SLOT(slotProcess()));
+ return true;
+
+error:
+ emit logError( i18n( "Could not open the calendar databases." ) );
+
+ KPILOT_DELETE(fCalendar);
+ KPILOT_DELETE(fP);
+ KPILOT_DELETE(fState);
+ return false;
+}
+
+void VCalConduitBase::slotProcess() {
+ FUNCTIONSETUP;
+
+ // start the current state if necessary
+ if( fState && !fState->started() ) {
+ fState->startSync( this );
+ }
+
+ // Process next record if applicable
+ if( hasNextRecord )
+ {
+ fState->handleRecord( this );
+ QTimer::singleShot( 0, this, SLOT( slotProcess() ) );
+ }
+ // Else finish the current state if there is one
+ else if( fState )
+ {
+ fState->finishSync( this );
+ QTimer::singleShot( 0, this, SLOT( slotProcess() ) );
+ }
+ // No state so sync is finished
+ else
+ {
+ DEBUGKPILOT << fname << ": Sync finished." << endl;
+ delayDone();
+ }
+}
+
+/* virtual */ void VCalConduitBase::readConfig()
+{
+ config()->readConfig();
+ SyncAction::ConflictResolution res = (SyncAction::ConflictResolution)
+ (config()->conflictResolution());
+ setConflictResolution( res );
+}
+
+static void listResources( KCal::CalendarResources *p )
+{
+ FUNCTIONSETUP;
+ KCal::CalendarResourceManager *manager = p->resourceManager();
+
+ DEBUGKPILOT << fname << ": Resources in calendar:" << endl;
+ KCal::CalendarResourceManager::Iterator it;
+ for( it = manager->begin(); it != manager->end(); ++it )
+ {
+ DEBUGKPILOT << fname << ": " << (*it)->resourceName() << endl;
+ }
+}
+
+/* virtual */ bool VCalConduitBase::openCalendar()
+{
+ FUNCTIONSETUP;
+
+ KConfig korgcfg( locate( "config", CSL1("korganizerrc") ) );
+
+ // this part taken from adcalendarbase.cpp:
+ korgcfg.setGroup( "Time & Date" );
+ QString tz(korgcfg.readEntry( "TimeZoneId" ) );
+
+ DEBUGKPILOT << fname << ": KOrganizer's time zone = " << tz << endl;
+
+ // Need a subclass ptr. for the ResourceCalendar methods
+ KCal::CalendarResources *rescal = 0L;
+
+ DEBUGKPILOT << fname << ": Got calendar type " << config()->calendarType()
+ << endl;
+
+ switch(config()->calendarType())
+ {
+ case VCalConduitSettings::eCalendarLocal:
+ {
+ DEBUGKPILOT << fname << "Using CalendarLocal, file = "
+ << config()->calendarFile() << endl;
+
+ if ( config()->calendarFile().isEmpty() )
+ {
+ DEBUGKPILOT << fname << "Empty calendar file name." << endl;
+
+ emit logError( i18n( "You selected to sync with an iCalendar"
+ " file, but did not give a filename. Please select a"
+ " valid file name in the conduit's configuration"
+ " dialog" ) );
+ return false;
+ }
+
+ fCalendar = new KCal::CalendarLocal( tz );
+ if ( !fCalendar )
+ {
+ WARNINGKPILOT
+ << "Cannot initialize calendar object for file "
+ << config()->calendarFile() << endl;
+ return false;
+ }
+
+ DEBUGKPILOT << fname << "Calendar's timezone: "
+ << fCalendar->timeZoneId() << endl;
+ DEBUGKPILOT << fname << "Calendar is local time: "
+ << fCalendar->isLocalTime() << endl;
+
+ emit logMessage( fCalendar->isLocalTime() ?
+ i18n( "Using local time zone: %1" ).arg( tz ) :
+ i18n( "Using non-local time zone: %1" ).arg( tz ) );
+
+ KURL kurl( config()->calendarFile() );
+ if( !KIO::NetAccess::download( config()->calendarFile(),
+ fCalendarFile, 0L ) && !kurl.isLocalFile() )
+ {
+ emit logError(i18n( "You chose to sync with the file \"%1\", which "
+ "cannot be opened. Please make sure to supply a "
+ "valid file name in the conduit's configuration dialog. "
+ "Aborting the conduit." ).arg( config()->calendarFile() ) );
+ KIO::NetAccess::removeTempFile( fCalendarFile );
+ return false;
+ }
+
+ // if there is no calendar yet, use a first sync..
+ // the calendar is initialized, so nothing more to do...
+ if (!dynamic_cast<KCal::CalendarLocal*>(fCalendar)->load(fCalendarFile) )
+ {
+ DEBUGKPILOT << fname << "Calendar file " << fCalendarFile
+ << " could not be opened. Will create a new one" << endl;
+
+ // Try to create empty file. if it fails,
+ // no valid file name was given.
+ QFile fl(fCalendarFile);
+ if (!fl.open(IO_WriteOnly | IO_Append))
+ {
+ DEBUGKPILOT << fname << "Invalid calendar file name "
+ << fCalendarFile << endl;
+
+ emit logError( i18n( "You chose to sync with the file \"%1\", which "
+ "cannot be opened or created. Please make sure to supply a "
+ "valid file name in the conduit's configuration dialog. "
+ "Aborting the conduit." ).arg( config()->calendarFile() ) );
+ return false;
+ }
+ fl.close();
+ setFirstSync( true );
+ }
+ addSyncLogEntry( i18n( "Syncing with file \"%1\"" )
+ .arg( config()->calendarFile() ) );
+ break;
+ }
+
+ case VCalConduitSettings::eCalendarResource:
+ DEBUGKPILOT << "Using CalendarResource!" << endl;
+
+ rescal = new KCal::CalendarResources( tz );
+ listResources(rescal);
+ fCalendar = rescal;
+ if ( !fCalendar)
+ {
+ WARNINGKPILOT << "Cannot initialize calendar " <<
+ "object for ResourceCalendar" << endl;
+ return false;
+ }
+
+#if LIBKCAL_IS_VERSION(1,1,0)
+ rescal->readConfig();
+ rescal->load();
+#else
+#warning "Timezone bug is present."
+#endif
+ addSyncLogEntry( i18n( "Syncing with standard calendar resource." ) );
+ emit logMessage( fCalendar->isLocalTime() ?
+ i18n( "Using local time zone: %1" ).arg( tz ) :
+ i18n( "Using non-local time zone: %1" ).arg( tz ) );
+ break;
+ default:
+ break;
+ }
+
+ if ( !fCalendar )
+ {
+ WARNINGKPILOT << "Unable to initialize calendar object."
+ << " Please check the conduit's setup." << endl;
+ emit logError( i18n( "Unable to initialize the calendar object. Please"
+ " check the conduit's setup") );
+ return false;
+ }
+ fP = createPrivateCalendarData( fCalendar );
+ if ( !fP )
+ {
+ return false;
+ }
+ int rc = fP->updateIncidences();
+ DEBUGKPILOT << fname << ": return from updateIncidences: [" << rc
+ << "]" << endl;
+
+ if ( fP->count() < 1 )
+ {
+ setFirstSync( true );
+ }
+
+ return true;
+}
+
+KCal::Incidence* VCalConduitBase::addRecord( PilotRecord *r )
+{
+ FUNCTIONSETUP;
+
+ recordid_t id = fLocalDatabase->writeRecord( r );
+ DEBUGKPILOT<<fname<<": Pilot Record ID = " << r->id() << ", backup ID = "
+ << id << endl;
+
+ PilotRecordBase *de = newPilotEntry( r );
+ KCal::Incidence*e = 0L;
+
+ if ( de )
+ {
+ e = fP->findIncidence( r->id() );
+ if ( !e )
+ {
+ // no corresponding entry found, so create, copy and insert it.
+ e = newIncidence();
+ incidenceFromRecord( e, de );
+ fP->addIncidence( e );
+ fCtrPC->created();
+ }
+ else
+ {
+ // similar entry found, so just copy, no need to insert again
+ incidenceFromRecord( e, de );
+ fCtrPC->updated();
+ }
+ }
+ KPILOT_DELETE( de );
+ return e;
+}
+
+int VCalConduitBase::resolveConflict( KCal::Incidence *e, PilotRecordBase *de ) {
+ if ( getConflictResolution() == SyncAction::eAskUser )
+ {
+ // TODO: This is messed up!!!
+ QString query = i18n( "The following item was modified "
+ "both on the Handheld and on your PC:\nPC entry:\n\t" );
+ query += e->summary();
+ query += i18n( "\nHandheld entry:\n\t" );
+ query += getTitle( de );
+ query += i18n( "\n\nWhich entry do you want to keep? It will "
+ "overwrite the other entry." );
+
+ return KMessageBox::No == questionYesNo(
+ query,
+ i18n( "Conflicting Entries" ),
+ QString::null,
+ 0 /* Never timeout */,
+ i18n( "Handheld" ), i18n( "PC" ));
+ }
+ return getConflictResolution();
+}
+
+KCal::Incidence*VCalConduitBase::changeRecord(PilotRecord *r,PilotRecord *)
+{
+ FUNCTIONSETUP;
+
+ PilotRecordBase *de = newPilotEntry( r );
+ KCal::Incidence *e = fP->findIncidence( r->id() );
+
+ DEBUGKPILOT << fname << ": Pilot Record ID: [" << r->id() << "]" << endl;
+
+ if ( e && de )
+ {
+ // TODO: check for conflict, and if there is one, ask for resolution
+ if ( ( e->syncStatus() != KCal::Incidence::SYNCNONE )
+ && r->isModified() )
+ {
+ // TODO: I have not yet found a way to complete ignore an item
+ if (resolveConflict( e, de ) )
+ {
+ // PC record takes precedence:
+ KPILOT_DELETE( de );
+ return e;
+ }
+ }
+ // no conflict or conflict resolution says, Palm overwrites, so do it:
+ incidenceFromRecord( e, de );
+
+ // NOTE: This MUST be done last, since every other set* call
+ // calls updated(), which will trigger an
+ // setSyncStatus(SYNCMOD)!!!
+ e->setSyncStatus(KCal::Incidence::SYNCNONE);
+ fLocalDatabase->writeRecord( r );
+ }
+ else
+ {
+ WARNINGKPILOT
+ << "While changing record -- not found in iCalendar" << endl;
+ addRecord( r );
+ }
+
+ KPILOT_DELETE( de );
+ return e;
+}
+
+
+KCal::Incidence*VCalConduitBase::deleteRecord( PilotRecord *r, PilotRecord * )
+{
+ FUNCTIONSETUP;
+
+ KCal::Incidence *e = fP->findIncidence(r->id());
+ if (e)
+ {
+ // RemoveEvent also takes it out of the calendar.
+ fP->removeIncidence(e);
+ fCtrPC->deleted();
+ }
+ fLocalDatabase->writeRecord( r );
+ return NULL;
+}
+
+
+void VCalConduitBase::addPalmRecord( KCal::Incidence *e )
+{
+ FUNCTIONSETUP;
+
+ PilotRecordBase *de = newPilotEntry( 0L );
+ updateIncidenceOnPalm( e, de );
+ fCtrHH->created();
+ KPILOT_DELETE( de );
+}
+
+
+void VCalConduitBase::changePalmRecord(KCal::Incidence*e, PilotRecord*s)
+{
+ PilotRecordBase *de = newPilotEntry( s );
+ updateIncidenceOnPalm( e, de );
+ fCtrHH->updated();
+ KPILOT_DELETE( de );
+}
+
+
+void VCalConduitBase::deletePalmRecord( KCal::Incidence *e, PilotRecord *s )
+{
+ FUNCTIONSETUP;
+ if ( s )
+ {
+ DEBUGKPILOT << fname << ": deleting record " << s->id() << endl;
+ s->setDeleted();
+ fDatabase->writeRecord( s );
+ fLocalDatabase->writeRecord( s );
+ fCtrHH->deleted();
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": could not find record to delete (";
+ DEBUGKPILOT << e->pilotId() << ")" << endl;
+ }
+
+ Q_UNUSED(e);
+}
+
+/* I have to use a pointer to an existing PilotDateEntry so that I can handle
+ new records as well (and to prevent some crashes concerning the validity
+ domain of the PilotRecord*r). In syncEvent this PilotDateEntry is created. */
+void VCalConduitBase::updateIncidenceOnPalm( KCal::Incidence *e,
+ PilotRecordBase *de )
+{
+ FUNCTIONSETUP;
+ if ( !de || !e ) {
+ DEBUGKPILOT << fname << ": NULL event given... Skipping it" << endl;
+ return;
+ }
+
+ if ( e->syncStatus() == KCal::Incidence::SYNCDEL )
+ {
+ DEBUGKPILOT << fname << ": don't write deleted incidence "
+ << e->summary() << " to the palm" << endl;
+ return;
+ }
+
+ PilotRecord *r = recordFromIncidence( de, e );
+
+ // TODO: Check for conflict!
+ if ( r )
+ {
+ recordid_t id=fDatabase->writeRecord(r);
+ r->setID(id);
+// r->setAttrib(r->getAttrib() & ~dlpRecAttrDeleted);
+ fLocalDatabase->writeRecord( r );
+// fDatabase->writeRecord(r);
+ e->setPilotId( id );
+
+ // NOTE: This MUST be done last, since every other set* call
+ // calls updated(), which will trigger an
+ // setSyncStatus(SYNCMOD)!!!
+ e->setSyncStatus(KCal::Incidence::SYNCNONE);
+ KPILOT_DELETE( r );
+ }
+}
+
+const QString VCalConduitBase::dbname()
+{
+ return QString::null;
+}
+
+PilotRecord *VCalConduitBase::readRecordByIndex( int index )
+{
+ FUNCTIONSETUP;
+ return fDatabase->readRecordByIndex( index );
+}
+
+KCal::Incidence *VCalConduitBase::incidenceFromRecord( PilotRecord *r )
+{
+ FUNCTIONSETUP;
+ PilotRecordBase *pac = newPilotEntry( r );
+ KCal::Incidence *i = newIncidence();
+ incidenceFromRecord( i, pac );
+
+ KPILOT_DELETE( pac );
+ return i;
+}
+
+void VCalConduitBase::setState( ConduitState *s )
+{
+ KPILOT_DELETE( fState );
+ fState = s;
+}
+
+/* virtual */ void VCalConduitBase::postSync( )
+{
+ FUNCTIONSETUP;
+ if (fCtrPC && fP)
+ fCtrPC->setEndCount(fP->count());
+}
+
+/* virtual */ void VCalConduitBase::preSync( )
+{
+ FUNCTIONSETUP;
+ if (fCtrPC && fP)
+ fCtrPC->setStartCount(fP->count());
+}
diff --git a/kpilot/conduits/vcalconduit/vcal-conduitbase.h b/kpilot/conduits/vcalconduit/vcal-conduitbase.h
new file mode 100644
index 000000000..7d2fc6588
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcal-conduitbase.h
@@ -0,0 +1,202 @@
+#ifndef _KPILOT_VCAL_CONDUITBASE_H
+#define _KPILOT_VCAL_CONDUITBASE_H
+/* vcal-conduit.h KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the vcal-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include <qstring.h>
+
+#include <libkcal/calendarlocal.h>
+
+#include <plugin.h>
+#include <pilotRecord.h>
+
+namespace KCal
+{
+class Calendar;
+class Incidence;
+}
+
+class PilotSerialDatabase;
+class PilotLocalDatabase;
+class VCalConduitSettings;
+
+class ConduitState;
+
+class VCalConduitPrivateBase
+{
+protected:
+ bool reading;
+ KCal::Calendar *fCalendar;
+public:
+ VCalConduitPrivateBase(KCal::Calendar *buddy) : fCalendar(buddy)
+ {
+ reading = false;
+ };
+
+ virtual ~VCalConduitPrivateBase() { } ;
+
+ virtual int updateIncidences() = 0;
+ virtual void addIncidence(KCal::Incidence*) = 0;
+ virtual void removeIncidence(KCal::Incidence*) = 0;
+ virtual KCal::Incidence *findIncidence(recordid_t) = 0;
+ virtual KCal::Incidence *findIncidence(PilotRecordBase *tosearch) = 0;
+ virtual KCal::Incidence *getNextIncidence() = 0;
+ virtual KCal::Incidence *getNextModifiedIncidence() = 0;
+ virtual int count()=0;
+} ;
+
+class VCalConduitBase : public ConduitAction
+{
+ Q_OBJECT
+public:
+ VCalConduitBase(KPilotLink *,
+ const char *name = 0L,
+ const QStringList &args = QStringList());
+ virtual ~VCalConduitBase();
+
+/*********************************************************************
+ D A T A M E M B E R S , S E T T I N G S
+ *********************************************************************/
+protected:
+ KCal::Calendar *fCalendar;
+ QString fCalendarFile;
+ VCalConduitPrivateBase *fP;
+ ConduitState *fState;
+ bool hasNextRecord;
+
+ virtual const QString dbname() = 0;
+ virtual const QString getTitle(PilotRecordBase *de) = 0;
+ virtual void readConfig();
+
+ virtual bool exec();
+
+protected slots:
+ /**
+ * This slot is used to execute the actions applicable to this conduit. What
+ * happens in this method is defined by the state the conduit has at the
+ * moment that this method is called. For more information about the actions
+ * that are executed, look at the classes that are implementing ConduitState.
+ */
+ void slotProcess();
+
+public:
+ /**
+ * Method used by state classes to indicatie if there are more records to
+ * deal with.
+ */
+ void setHasNextRecord( bool b )
+ {
+ hasNextRecord = b;
+ }
+
+ /**
+ * Change the current state of the conduit. The state that the conduit has
+ * at the moment of the call will be deleted. The last state *must* set the
+ * state to 0L when finished.
+ */
+ void setState( ConduitState *s );
+
+ /**
+ * Returns the privatebase, that is used to for accessing the local calendar.
+ */
+ VCalConduitPrivateBase *privateBase() const
+ {
+ return fP;
+ }
+
+ /**
+ * Returns the record at index from the palm or 0L if there is no record at
+ * index.
+ */
+ PilotRecord *readRecordByIndex( int index );
+
+ /**
+ * Returns a KCal::Incidence constructed from PilotRecord r. If r is 0L the
+ * it will return a KCal::Incidence that is empty.
+ */
+ KCal::Incidence *incidenceFromRecord( PilotRecord *r );
+
+ virtual void preIncidence( KCal::Incidence* ) {};
+
+ // Getters
+ KCal::Calendar *calendar() const { return fCalendar; };
+ QString calendarFile() const { return fCalendarFile; };
+
+ virtual VCalConduitSettings *config() = 0;
+ virtual PilotDatabase *database() const { return fDatabase; };
+ virtual PilotDatabase *localDatabase() const { return fLocalDatabase; };
+
+ // add, change or delete records from the palm
+ virtual void addPalmRecord( KCal::Incidence *e );
+ virtual void changePalmRecord( KCal::Incidence *e, PilotRecord *s );
+ virtual void deletePalmRecord( KCal::Incidence *e, PilotRecord *s );
+
+ // add, change or delete events from the calendar
+ virtual KCal::Incidence* changeRecord( PilotRecord*, PilotRecord* );
+ virtual KCal::Incidence* deleteRecord( PilotRecord*, PilotRecord* );
+ virtual KCal::Incidence* addRecord( PilotRecord * );
+
+/*********************************************************************
+ P R E - A N D P O S T S Y N C F U N C T I O N S
+ *********************************************************************/
+ virtual void preSync();
+ virtual void postSync();
+ virtual void preRecord(PilotRecord*) {};
+
+protected:
+ virtual void updateIncidenceOnPalm(KCal::Incidence *e, PilotRecordBase *de);
+
+/*********************************************************************
+ S Y N C F U N C T I O N S
+ for creating events from Palm records or vice versa
+ *********************************************************************/
+ virtual PilotRecord *recordFromIncidence(PilotRecordBase *de,
+ const KCal::Incidence *e) = 0;
+ virtual PilotRecordBase *newPilotEntry(PilotRecord *r) = 0;
+
+ virtual KCal::Incidence *newIncidence() = 0;
+ virtual KCal::Incidence *incidenceFromRecord(KCal::Incidence *e,
+ const PilotRecordBase *de) = 0;
+
+/*********************************************************************
+ M I S C F U N C T I O N S
+ *********************************************************************/
+ /**
+ * Return how to resolve conflicts. For now
+ * PalmOverrides=0=false,
+ * PCOverrides=1=true,
+ * Ask=2-> ask the user using a messagebox
+ */
+ virtual int resolveConflict(KCal::Incidence *e, PilotRecordBase *de);
+ virtual bool openCalendar();
+ virtual VCalConduitPrivateBase *createPrivateCalendarData(KCal::Calendar *fCalendar) = 0;
+} ;
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/vcal-factory.cc b/kpilot/conduits/vcalconduit/vcal-factory.cc
new file mode 100644
index 000000000..2e157818f
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcal-factory.cc
@@ -0,0 +1,50 @@
+/* KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the factory for the vcal-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <kaboutdata.h>
+
+#include "pluginfactory.h"
+
+#include "vcal-setup.h"
+#include "vcal-conduit.h"
+
+extern "C"
+{
+
+void *init_conduit_vcal()
+{
+ return new ConduitFactory<VCalWidgetSetup,VCalConduit>;
+}
+
+}
+
+
+
diff --git a/kpilot/conduits/vcalconduit/vcal-factory.h b/kpilot/conduits/vcalconduit/vcal-factory.h
new file mode 100644
index 000000000..5cd4a611b
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcal-factory.h
@@ -0,0 +1,41 @@
+#ifndef _KPILOT_VCAL_FACTORY_H
+#define _KPILOT_VCAL_FACTORY_H
+/* vcal-factory.h KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the factory for the vcal-conduit plugin.
+** It also defines the class for the behavior of the setup dialog.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+extern "C"
+{
+
+void *init_libvcalconduit();
+
+}
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/vcal-factorybase.h b/kpilot/conduits/vcalconduit/vcal-factorybase.h
new file mode 100644
index 000000000..5a1d2a5d6
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcal-factorybase.h
@@ -0,0 +1,44 @@
+#ifndef _KPILOT_VCAL_FACTORYBASE_H
+#define _KPILOT_VCAL_FACTORYBASE_H
+/* vcal-factory.h KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the factory for the vcal-conduit plugin.
+** It also defines the class for the behavior of the setup dialog.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#define RES_PALMOVERRIDES 0
+#define RES_PCOVERRIDES 1
+#define RES_ASK 2
+
+#define SYNC_FIRST 0
+#define SYNC_FAST 1
+#define SYNC_FULL 2
+#define SYNC_MAX SYNC_FULL
+
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/vcal-setup.cc b/kpilot/conduits/vcalconduit/vcal-setup.cc
new file mode 100644
index 000000000..666e9ee0a
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcal-setup.cc
@@ -0,0 +1,78 @@
+/* KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the setup dialog for the vcal-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qbuttongroup.h>
+#include <kaboutdata.h>
+
+#include "korganizerConduit.h"
+#include "vcal-conduit.h"
+#include "vcal-setup.h"
+
+
+VCalWidgetSetup::VCalWidgetSetup(QWidget *w, const char *n) :
+ VCalWidgetSetupBase(w,n)
+{
+ KAboutData *fAbout = new KAboutData("vcalConduit",
+ I18N_NOOP("VCal Conduit for KPilot"),
+ KPILOT_VERSION,
+ I18N_NOOP("Configures the VCal Conduit for KPilot"),
+ KAboutData::License_GPL,
+ "(C) 2001, Adriaan de Groot\n(C) 2002-2003, Reinhold Kainhofer");
+ fAbout->addAuthor("Adriaan de Groot",
+ I18N_NOOP("Maintainer"),
+ "http://www.kpilot.org/");
+ fAbout->addAuthor("Reinhold Kainhofer",
+ I18N_NOOP("Maintainer"),
+ "http://reinhold.kainhofer.com/Linux/");
+ fAbout->addAuthor("Dan Pilone",
+ I18N_NOOP("Original Author"));
+ fAbout->addAuthor("Preston Brown",
+ I18N_NOOP("Original Author"));
+ fAbout->addAuthor("Herwin-Jan Steehouwer",
+ I18N_NOOP("Original Author"));
+ fAbout->addCredit("Cornelius Schumacher",
+ I18N_NOOP("iCalendar port"));
+ fAbout->addCredit("Philipp Hullmann",
+ I18N_NOOP("Bugfixer"));
+
+ ConduitConfigBase::addAboutPage(fConfigWidget->tabWidget, fAbout);
+ fConfigWidget->fSyncDestination->setTitle(i18n("Calendar Destination"));
+ fConduitName=i18n("Calendar");
+
+}
+
+/* static */ ConduitConfigBase *VCalWidgetSetup::create(QWidget *w,const char *n)
+{
+ return new VCalWidgetSetup(w,n);
+}
+VCalConduitSettings*VCalWidgetSetup::config() { return VCalConduit::theConfig(); }
diff --git a/kpilot/conduits/vcalconduit/vcal-setup.h b/kpilot/conduits/vcalconduit/vcal-setup.h
new file mode 100644
index 000000000..407c0d99f
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcal-setup.h
@@ -0,0 +1,46 @@
+#ifndef _KPILOT_VCAL_SETUP_H
+#define _KPILOT_VCAL_SETUP_H
+/* vcal-setup.h KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** It also defines the class for the behavior of the setup dialog.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "vcal-setupbase.h"
+
+class VCalWidget;
+class VCalConduitSettings;
+
+class VCalWidgetSetup : public VCalWidgetSetupBase
+{
+public:
+ VCalWidgetSetup(QWidget *, const char *);
+ static ConduitConfigBase *create(QWidget *, const char *);
+protected:
+ virtual VCalConduitSettings*config();
+} ;
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/vcal-setupbase.cc b/kpilot/conduits/vcalconduit/vcal-setupbase.cc
new file mode 100644
index 000000000..3e97987fa
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcal-setupbase.cc
@@ -0,0 +1,110 @@
+/* vcal-setup.cc KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the setup dialog for the vcal-conduit plugin.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qcheckbox.h>
+#include <qbuttongroup.h>
+#include <qcombobox.h>
+
+#include <kurlrequester.h>
+
+#include "korganizerConduit.h"
+#include "vcalconduitSettings.h"
+#include "vcal-setupbase.h"
+
+VCalWidgetSetupBase::VCalWidgetSetupBase(QWidget *w, const char *n) :
+ ConduitConfigBase(w,n),
+ fConfigWidget(new VCalWidget(w))
+{
+ FUNCTIONSETUP;
+ fWidget=fConfigWidget;
+
+ fConfigWidget->fCalendarFile->setMode(KFile::File);
+ fConfigWidget->fCalendarFile->setFilter(CSL1("*.vcs *.ics|ICalendars\n*.*|All Files (*.*)"));
+
+#define CM(a,b) connect(fConfigWidget->a,b,this,SLOT(modified()));
+ CM(fSyncDestination,SIGNAL(clicked(int)));
+ CM(fCalendarFile,SIGNAL(textChanged(const QString &)));
+ CM(fArchive,SIGNAL(toggled(bool)));
+ CM(fConflictResolution,SIGNAL(activated(int)));
+#undef CM
+}
+
+VCalWidgetSetupBase::~VCalWidgetSetupBase()
+{
+ FUNCTIONSETUP;
+}
+
+/* virtual */ void VCalWidgetSetupBase::commit()
+{
+ FUNCTIONSETUP;
+ config()->readConfig();
+
+ // General page
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Selected type="
+ << fConfigWidget->fSyncDestination->selected()
+ << " with id="
+ << fConfigWidget->fSyncDestination->id(fConfigWidget->fSyncDestination->selected())
+ << endl;
+#endif
+ config()->setCalendarType( fConfigWidget->fSyncDestination->id(
+ fConfigWidget->fSyncDestination->selected()));
+ config()->setCalendarFile( fConfigWidget->fCalendarFile->url());
+
+ config()->setSyncArchived( fConfigWidget->fArchive->isChecked() );
+
+ // Conflicts page
+ config()->setConflictResolution(
+ fConfigWidget->fConflictResolution->currentItem()+SyncAction::eCROffset);
+
+ config()->writeConfig();
+ unmodified();
+}
+
+/* virtual */ void VCalWidgetSetupBase::load()
+{
+ FUNCTIONSETUP;
+ config()->readConfig();
+
+ // General page
+ fConfigWidget->fSyncDestination->setButton( config()->calendarType());
+ fConfigWidget->fCalendarFile->setURL( config()->calendarFile() );
+
+ fConfigWidget->fArchive->setChecked( config()->syncArchived() );
+
+ // Conflicts page
+ fConfigWidget->fConflictResolution->setCurrentItem(
+ config()->conflictResolution() - SyncAction::eCROffset);
+
+ config()->writeConfig();
+ unmodified();
+}
+
diff --git a/kpilot/conduits/vcalconduit/vcal-setupbase.h b/kpilot/conduits/vcalconduit/vcal-setupbase.h
new file mode 100644
index 000000000..7863659bd
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcal-setupbase.h
@@ -0,0 +1,51 @@
+#ifndef _KPILOT_VCAL_SETUPBASE_H
+#define _KPILOT_VCAL_SETUPBASE_H
+/* vcal-setup.h KPilot
+**
+** Copyright (C) 2002-2003 Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+** It also defines the class for the behavior of the setup dialog.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "plugin.h"
+
+class VCalWidget;
+class VCalConduitSettings;
+
+class VCalWidgetSetupBase : public ConduitConfigBase
+{
+public:
+ VCalWidgetSetupBase(QWidget *, const char *);
+ virtual ~VCalWidgetSetupBase();
+
+ virtual void load();
+ virtual void commit();
+
+protected:
+ virtual VCalConduitSettings*config()=0;
+ VCalWidget *fConfigWidget;
+} ;
+
+#endif
diff --git a/kpilot/conduits/vcalconduit/vcalRecord.cc b/kpilot/conduits/vcalconduit/vcalRecord.cc
new file mode 100644
index 000000000..f9866d91a
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcalRecord.cc
@@ -0,0 +1,548 @@
+/* vcalRecord.cc KPilot
+**
+** Copyright (C) 2006 by Adriaan de Groot <[email protected]>
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <libkcal/calendar.h>
+#include <libkcal/calendarlocal.h>
+#include <libkcal/recurrence.h>
+#include <libkcal/vcalformat.h>
+
+#include "pilot.h"
+#include "pilotDateEntry.h"
+
+#include "kcalRecord.h"
+#include "vcalRecord.h"
+
+
+static void setStartEndTimes(KCal::Event *e, const PilotDateEntry *de)
+{
+ FUNCTIONSETUP;
+ DEBUGKPILOT << fname
+ << "# Start time on Palm: "
+ << readTm(de->getEventStart()).toString() << endl;
+
+ e->setDtStart(readTm(de->getEventStart()));
+ e->setFloats(de->isEvent());
+
+ if (de->isMultiDay())
+ {
+ e->setDtEnd(readTm(de->getRepeatEnd()));
+ }
+ else
+ {
+ e->setDtEnd(readTm(de->getEventEnd()));
+ }
+}
+
+static void setAlarms(KCal::Event *e, const PilotDateEntry *de)
+{
+ FUNCTIONSETUP;
+
+ if (!e) return;
+ // Delete all the alarms now and add them one by one later on.
+ e->clearAlarms();
+ if (!de->isAlarmEnabled()) return;
+
+// QDateTime alarmDT = readTm(de->getEventStart());
+ int advanceUnits = de->getAdvanceUnits();
+
+ switch (advanceUnits)
+ {
+ case advMinutes:
+ advanceUnits = 1;
+ break;
+ case advHours:
+ advanceUnits = 60;
+ break;
+ case advDays:
+ advanceUnits = 60*24;
+ break;
+ default:
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Unknown advance units "
+ << advanceUnits
+ << endl;
+#endif
+ advanceUnits=1;
+ }
+
+ KCal::Duration adv(-60*advanceUnits*de->getAdvance());
+ KCal::Alarm*alm=e->newAlarm();
+ if (!alm) return;
+
+ alm->setStartOffset(adv);
+ alm->setEnabled(true);
+}
+
+static void setRecurrence(KCal::Event *event,const PilotDateEntry *dateEntry)
+{
+ FUNCTIONSETUP;
+
+ if ((dateEntry->getRepeatType() == repeatNone) || dateEntry->isMultiDay())
+ {
+#ifdef DEBUG
+ DEBUGKPILOT<<fname<<": no recurrence to set"<<endl;
+#endif
+ return;
+ }
+
+ KCal::Recurrence *recur = event->recurrence();
+ int freq = dateEntry->getRepeatFrequency();
+ bool repeatsForever = dateEntry->getRepeatForever();
+ QDate endDate, evt;
+
+ if (!repeatsForever)
+ {
+ endDate = readTm(dateEntry->getRepeatEnd()).date();
+#ifdef DEBUG
+ DEBUGKPILOT << fname << "-- end " << endDate.toString() << endl;
+ }
+ else
+ {
+ DEBUGKPILOT << fname << "-- noend" << endl;
+#endif
+ }
+
+ QBitArray dayArray(7);
+
+ switch(dateEntry->getRepeatType())
+ {
+ case repeatDaily:
+ recur->setDaily(freq);
+ break;
+ case repeatWeekly:
+ {
+ const int *days = dateEntry->getRepeatDays();
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Got repeat-weekly entry, by-days="
+ << days[0] << " "<< days[1] << " "<< days[2] << " "
+ << days[3] << " "
+ << days[4] << " "<< days[5] << " "<< days[6] << " "
+ << endl;
+#endif
+
+ // Rotate the days of the week, since day numbers on the Pilot and
+ // in vCal / Events are different.
+ //
+ if (days[0]) dayArray.setBit(6);
+ for (int i = 1; i < 7; i++)
+ {
+ if (days[i]) dayArray.setBit(i-1);
+ }
+ recur->setWeekly( freq, dayArray );
+ }
+ break;
+ case repeatMonthlyByDay: {
+ // Palm: Day=0(sun)-6(sat); week=0-4, 4=last week; pos=week*7+day
+ // libkcal: day=bit0(mon)-bit6(sun); week=-5to-1(from end) and 1-5 (from beginning)
+ // Palm->PC: w=pos/7
+ // week: if w=4 -> week=-1, else week=w+1;
+ // day: day=(pos-1)%7 (rotate by one day!)
+ recur->setMonthly( freq );
+
+ int day=dateEntry->getRepeatDay();
+ int week=day/7;
+ // week=4 means last, otherwise convert to 0-based
+ if (week==4) week=-1; else week++;
+ dayArray.setBit((day+6) % 7);
+ recur->addMonthlyPos(week, dayArray);
+ break;}
+ case repeatMonthlyByDate:
+ recur->setMonthly( freq );
+ recur->addMonthlyDate( dateEntry->getEventStart().tm_mday );
+ break;
+ case repeatYearly:
+ recur->setYearly( freq );
+ evt=readTm(dateEntry->getEventStart()).date();
+ recur->addYearlyMonth( evt.month() );
+// dayArray.setBit((evt.day()-1) % 7);
+// recur->addYearlyMonthPos( ( (evt.day()-1) / 7) + 1, dayArray );
+ break;
+ case repeatNone:
+ default :
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Can't handle repeat type "
+ << dateEntry->getRepeatType()
+ << endl;
+#endif
+ break;
+ }
+ if (!repeatsForever)
+ {
+ recur->setEndDate(endDate);
+ }
+}
+
+static void setExceptions(KCal::Event *vevent,const PilotDateEntry *dateEntry)
+{
+ FUNCTIONSETUP;
+
+ // Start from an empty exception list, and if necessary, add exceptions.
+ // At the end of the function, apply the (possibly empty) exception list.
+ KCal::DateList dl;
+
+ if ( !(dateEntry->isMultiDay() ) && dateEntry->getExceptionCount()>0 )
+ {
+ for (int i = 0; i < dateEntry->getExceptionCount(); i++)
+ {
+// vevent->addExDate(readTm(dateEntry->getExceptions()[i]).date());
+ dl.append(readTm(dateEntry->getExceptions()[i]).date());
+ }
+ }
+ else
+ {
+#ifdef DEBUG
+ if (dateEntry->getExceptionCount()>0)
+ DEBUGKPILOT << fname
+ << ": WARNING Exceptions ignored for multi-day event "
+ << dateEntry->getDescription()
+ << endl ;
+#endif
+ return;
+ }
+ vevent->recurrence()->setExDates(dl);
+}
+
+static void setStartEndTimes(PilotDateEntry*de, const KCal::Event *e)
+{
+ FUNCTIONSETUP;
+ struct tm ttm=writeTm(e->dtStart());
+ de->setEventStart(ttm);
+ de->setFloats( e->doesFloat() );
+
+ if (e->hasEndDate() && e->dtEnd().isValid())
+ {
+ ttm=writeTm(e->dtEnd());
+ }
+ else
+ {
+ ttm=writeTm(e->dtStart());
+ }
+ de->setEventEnd(ttm);
+}
+
+
+
+
+static void setAlarms(PilotDateEntry*de, const KCal::Event *e)
+{
+ FUNCTIONSETUP;
+
+ if (!de || !e )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": NULL entry given to setAlarms. "<<endl;
+#endif
+ return;
+ }
+
+ if ( !e->isAlarmEnabled() )
+ {
+ de->setAlarmEnabled( false );
+ return;
+ }
+
+ // find the first enabled alarm
+ KCal::Alarm::List alms=e->alarms();
+ KCal::Alarm* alm=0;
+ KCal::Alarm::List::ConstIterator it;
+ for ( it = alms.begin(); it != alms.end(); ++it ) {
+ if ((*it)->enabled()) alm=*it;
+ }
+
+ if (!alm )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": no enabled alarm found (should exist!!!)"<<endl;
+#endif
+ de->setAlarmEnabled( false );
+ return;
+ }
+
+ // palm and PC offsets have a different sign!!
+ int aoffs=-alm->startOffset().asSeconds()/60;
+ int offs=(aoffs>0)?aoffs:-aoffs;
+
+ // find the best Advance Unit
+ if (offs>=100 || offs==60)
+ {
+ offs/=60;
+ if (offs>=48 || offs==24)
+ {
+ offs/=24;
+ de->setAdvanceUnits(advDays);
+ }
+ else
+ {
+ de->setAdvanceUnits(advHours);
+ }
+ }
+ else
+ {
+ de->setAdvanceUnits(advMinutes);
+ }
+ de->setAdvance((aoffs>0)?offs:-offs);
+ de->setAlarmEnabled( true );
+}
+
+
+
+static void setRecurrence(PilotDateEntry*dateEntry, const KCal::Event *event)
+{
+ FUNCTIONSETUP;
+ bool isMultiDay=false;
+
+ // first we have 'fake type of recurrence' when a multi-day event is passed to the pilot, it is converted to an event
+ // which recurs daily a number of times. if the event itself recurs, this will be overridden, and
+ // only the first day will be included in the event!!!!
+ QDateTime startDt(readTm(dateEntry->getEventStart())), endDt(readTm(dateEntry->getEventEnd()));
+ if (startDt.daysTo(endDt))
+ {
+ isMultiDay=true;
+ dateEntry->setRepeatType(repeatDaily);
+ dateEntry->setRepeatFrequency(1);
+ dateEntry->setRepeatEnd(dateEntry->getEventEnd());
+#ifdef DEBUG
+ DEBUGKPILOT << fname <<": Setting single-day recurrence (" << startDt.toString() << " - " << endDt.toString() << ")" <<endl;
+#endif
+ }
+
+
+ KCal::Recurrence*r=event->recurrence();
+ if (!r) return;
+ ushort recType=r->recurrenceType();
+ if ( recType==KCal::Recurrence::rNone )
+ {
+ if (!isMultiDay) dateEntry->setRepeatType(repeatNone);
+ return;
+ }
+
+
+ int freq=r->frequency();
+ QDate endDate=r->endDate();
+
+ if ( r->duration() < 0 || !endDate.isValid() )
+ {
+ dateEntry->setRepeatForever();
+ }
+ else
+ {
+ dateEntry->setRepeatEnd(writeTm(endDate));
+ }
+ dateEntry->setRepeatFrequency(freq);
+#ifdef DEBUG
+ DEBUGKPILOT<<" Event: "<<event->summary()<<" ("<<event->description()<<")"<<endl;
+ DEBUGKPILOT<< "duration: "<<r->duration() << ", endDate: "<<endDate.toString()<< ", ValidEndDate: "<<endDate.isValid()<<", NullEndDate: "<<endDate.isNull()<<endl;
+#endif
+
+ QBitArray dayArray(7), dayArrayPalm(7);
+ switch(recType)
+ {
+ case KCal::Recurrence::rDaily:
+ dateEntry->setRepeatType(repeatDaily);
+ break;
+ case KCal::Recurrence::rWeekly:
+ dateEntry->setRepeatType(repeatWeekly);
+ dayArray=r->days();
+ // rotate the bits by one
+ for (int i=0; i<7; i++)
+ {
+ dayArrayPalm.setBit( (i+1)%7, dayArray[i]);
+ }
+ dateEntry->setRepeatDays(dayArrayPalm);
+ break;
+ case KCal::Recurrence::rMonthlyPos:
+ // Palm: Day=0(sun)-6(sat); week=0-4, 4=last week; pos=week*7+day
+ // libkcal: day=bit0(mon)-bit6(sun); week=-5to-1(from end) and 1-5 (from beginning)
+ // PC->Palm: pos=week*7+day
+ // week: if w=-1 -> week=4, else week=w-1
+ // day: day=(daybit+1)%7 (rotate because of the different offset)
+ dateEntry->setRepeatType(repeatMonthlyByDay);
+ if (r->monthPositions().count()>0)
+ {
+ // Only take the first monthly position, as the palm allows only one
+ QValueList<KCal::RecurrenceRule::WDayPos> mps=r->monthPositions();
+ KCal::RecurrenceRule::WDayPos mp=mps.first();
+ int week = mp.pos();
+ int day = (mp.day()+1) % 7; // rotate because of different offset
+ // turn to 0-based and include starting from end of month
+ // TODO: We don't handle counting from the end of the month yet!
+ if (week==-1) week=4; else week--;
+ dateEntry->setRepeatDay(static_cast<DayOfMonthType>(7*week + day));
+ }
+ break;
+ case KCal::Recurrence::rMonthlyDay:
+ dateEntry->setRepeatType(repeatMonthlyByDate);
+//TODO: is this needed? dateEntry->setRepeatDay(static_cast<DayOfMonthType>(startDt.day()));
+ break;
+ case KCal::Recurrence::rYearlyDay:
+ case KCal::Recurrence::rYearlyPos:
+ DEBUGKPILOT << fname
+ << "! Unsupported yearly recurrence type." << endl;
+ case KCal::Recurrence::rYearlyMonth:
+ dateEntry->setRepeatType(repeatYearly);
+ break;
+ case KCal::Recurrence::rNone:
+ if (!isMultiDay) dateEntry->setRepeatType(repeatNone);
+ break;
+ default:
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Unknown recurrence type "<< recType << " with frequency "
+ << freq << " and duration " << r->duration() << endl;
+#endif
+ break;
+ }
+}
+
+
+static void setExceptions(PilotDateEntry *dateEntry, const KCal::Event *vevent )
+{
+ FUNCTIONSETUP;
+ struct tm *ex_List;
+
+ if (!dateEntry || !vevent)
+ {
+ WARNINGKPILOT << "NULL dateEntry or NULL vevent given for exceptions. Skipping exceptions" << endl;
+ return;
+ }
+ // first, we need to delete the old exceptions list, if it existed...
+ // This is no longer needed, as I fixed PilotDateEntry::setExceptions to do this automatically
+/* ex_List=const_cast<structdateEntry->getExceptions();
+ if (ex_List)
+ KPILOT_DELETE(ex_List);*/
+
+ KCal::DateList exDates = vevent->recurrence()->exDates();
+ size_t excount = exDates.size();
+ if (excount<1)
+ {
+ dateEntry->setExceptionCount(0);
+ dateEntry->setExceptions(0);
+ return;
+ }
+
+ // we have exceptions, so allocate mem and copy them there...
+ ex_List=new struct tm[excount];
+ if (!ex_List)
+ {
+ WARNINGKPILOT << "Couldn't allocate memory for the exceptions" << endl;
+ dateEntry->setExceptionCount(0);
+ dateEntry->setExceptions(0);
+ return;
+ }
+
+ size_t n=0;
+
+ KCal::DateList::ConstIterator dit;
+ for (dit = exDates.begin(); dit != exDates.end(); ++dit ) {
+ struct tm ttm=writeTm(*dit);
+ ex_List[n++]=ttm;
+ }
+ dateEntry->setExceptionCount(excount);
+ dateEntry->setExceptions(ex_List);
+}
+
+
+bool KCalSync::setEvent(KCal::Event *e,
+ const PilotDateEntry *de,
+ const CategoryAppInfo &info)
+{
+ FUNCTIONSETUP;
+ if (!e)
+ {
+ DEBUGKPILOT << fname
+ << "! NULL event given... Skipping it" << endl;
+ return false;
+ }
+ if (!de)
+ {
+ DEBUGKPILOT << fname
+ << "! NULL date entry given... Skipping it" << endl;
+ return false;
+ }
+
+
+ e->setSecrecy(de->isSecret() ?
+ KCal::Event::SecrecyPrivate :
+ KCal::Event::SecrecyPublic);
+
+ e->setPilotId(de->id());
+
+ setStartEndTimes(e,de);
+ setAlarms(e,de);
+ setRecurrence(e,de);
+ setExceptions(e,de);
+
+ e->setSummary(de->getDescription());
+ e->setDescription(de->getNote());
+ e->setLocation(de->getLocation());
+
+ // used by e.g. Agendus and Datebk
+ setCategory(e, de, info);
+
+ // NOTE: This MUST be done last, since every other set* call
+ // calls updated(), which will trigger an
+ // setSyncStatus(SYNCMOD)!!!
+ e->setSyncStatus(KCal::Incidence::SYNCNONE);
+
+ return true;
+}
+
+bool KCalSync::setDateEntry(PilotDateEntry *de,
+ const KCal::Event *e,
+ const CategoryAppInfo &info)
+{
+ FUNCTIONSETUP;
+ if (!de || !e) {
+ DEBUGKPILOT << fname
+ << ": NULL event given... Skipping it" << endl;
+ return false;
+ }
+
+ // set secrecy, start/end times, alarms, recurrence, exceptions, summary and description:
+ if (e->secrecy()!=KCal::Event::SecrecyPublic)
+ {
+ de->setSecret( true );
+ }
+
+ setStartEndTimes(de, e);
+ setAlarms(de, e);
+ setRecurrence(de, e);
+ setExceptions(de, e);
+ de->setDescription(e->summary());
+ de->setNote(e->description());
+ de->setLocation(e->location());
+ setCategory(de, e, info);
+ return true;
+}
+
diff --git a/kpilot/conduits/vcalconduit/vcalRecord.h b/kpilot/conduits/vcalconduit/vcalRecord.h
new file mode 100644
index 000000000..4cad14b51
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcalRecord.h
@@ -0,0 +1,51 @@
+#ifndef _KPILOT_VCALRECORD_H
+#define _KPILOT_VCALRECORD_H
+/* vcal-conduit.h KPilot
+**
+** Copyright (C) 2006 by Adriaan de Groot <[email protected]>
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+** Copyright (C) 2001 by Dan Pilone
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+class PilotDateEntry;
+
+namespace KCal
+{
+ class Event;
+}
+
+namespace KCalSync
+{
+ bool setEvent( KCal::Event *e,
+ const PilotDateEntry *de,
+ const CategoryAppInfo &info);
+ bool setDateEntry(PilotDateEntry *de,
+ const KCal::Event *e,
+ const CategoryAppInfo &info);
+}
+
+#endif
+
+
diff --git a/kpilot/conduits/vcalconduit/vcalconduitSettings.kcfgc b/kpilot/conduits/vcalconduit/vcalconduitSettings.kcfgc
new file mode 100644
index 000000000..7855ad246
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcalconduitSettings.kcfgc
@@ -0,0 +1,7 @@
+File=vcalconduitbase.kcfg
+ClassName=VCalConduitSettings
+#Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/conduits/vcalconduit/vcalconduitbase.kcfg b/kpilot/conduits/vcalconduit/vcalconduitbase.kcfg
new file mode 100644
index 000000000..c35e79074
--- /dev/null
+++ b/kpilot/conduits/vcalconduit/vcalconduitbase.kcfg
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kpilot_vcalconduitsrc">
+ <parameter name="conduit" />
+ </kcfgfile>
+
+ <group name="$(conduit)-Conduit">
+ <entry name="ConduitVersion" type="UInt">
+ </entry>
+ <entry name="CalendarType" type="Enum">
+ <choices>
+ <choice name="eCalendarResource"/>
+ <choice name="eCalendarLocal"/>
+ </choices>
+ <default>eCalendarLocal</default>
+ </entry>
+ <entry name="CalendarFile" key="CalFile" type="Path">
+ <default>$HOME/.kde/share/apps/korganizer/std.ics</default>
+ </entry>
+ <entry name="SyncArchived" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry name="ConflictResolution" type="Int">
+ <default>0</default>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kpilot/config.h.cmake b/kpilot/config.h.cmake
new file mode 100644
index 000000000..7d1be45af
--- /dev/null
+++ b/kpilot/config.h.cmake
@@ -0,0 +1,43 @@
+#cmakedefine HAVE_STDINT_H
+#cmakedefine HAVE_ALLOCA_H
+#cmakedefine HAVE_SYS_TIME_H
+#cmakedefine HAVE_SYS_STAT_H
+#cmakedefine HAVE_CFSETSPEED
+#cmakedefine HAVE_STRDUP
+#cmakedefine HAVE_SETENV
+#cmakedefine HAVE_UNSETENV
+#cmakedefine HAVE_USLEEP
+#cmakedefine HAVE_RANDOM
+#cmakedefine HAVE_PUTENV
+#cmakedefine HAVE_SETEUID
+#cmakedefine HAVE_MKSTEMPS
+#cmakedefine HAVE_MKSTEMP
+#cmakedefine HAVE_MKDTEMP
+#cmakedefine HAVE_REVOKE
+#cmakedefine HAVE_STRLCPY
+#cmakedefine HAVE_STRLCAT
+#cmakedefine HAVE_INET_ATON
+
+#if !defined(HAVE_STRLCAT)
+#ifdef __cplusplus
+extern "C" {
+#endif
+unsigned long strlcat(char*, const char*, unsigned long);
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
+
+#if !defined(HAVE_STRLCPY)
+#ifdef __cplusplus
+extern "C" {
+#endif
+unsigned long strlcpy(char*, const char*, unsigned long);
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
diff --git a/kpilot/configure b/kpilot/configure
new file mode 100755
index 000000000..48706b277
--- /dev/null
+++ b/kpilot/configure
@@ -0,0 +1,213 @@
+#!/bin/sh
+
+# simple configure script for user-friendliness
+
+# file to put output into for cmake to read in...
+OUTFILE=$(dirname $0)/Makefile.cmake.in
+CMAKEOUTFILE=$(dirname $0)/CMakeOptions.txt
+
+# --- FUNCTIONS ---
+
+usage()
+{
+echo "
+
+Hi there. You can use this script to configure parameters used by cmake.
+Currently, understood parameters are as follows:
+
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ --enable-debug=ARG enables debug symbols (yes|no) default=no
+ --enable-tests=ARG enable test suite (yes|no) default=no
+ --with-pilot-link=PATH set prefix for pilot-link files [default=check]
+ --with-mal=PATH set path for libmal files [default=check]
+
+ --show show existing configuration values
+
+More obscure options:
+
+ --with-simple-builddir=ARG use 'build' instead of longer name (yes|no) default=no
+ --with-pilot-link-includes=PATH set include directory for pilot-link
+ --with-pilot-link-lib=PATH set full path to libpisock.so
+
+"
+}
+
+getvalue()
+{
+ KEY="$1"
+ # use dynamic variable...
+ eval VAL='$'$KEY
+
+ ECHO="$2"
+
+ if test -n "$VAL"
+ then
+ CMAKE_FLAGS="${CMAKE_FLAGS}set(${KEY} \"${VAL}\")
+"
+ if [ "$ECHO" = "y" ]
+ then
+ echo "$KEY=\"$VAL\""
+ fi
+ fi
+
+}
+
+outputCmakeValues()
+{
+
+# only include what we're passed
+CMAKE_FLAGS=""
+
+getvalue CMAKE_INSTALL_PREFIX n
+getvalue CMAKE_BUILD_TYPE n
+getvalue ENABLE_TESTS n
+#getvalue BUILD_DIR y
+getvalue PILOTLINK_BASE n
+getvalue MAL_BASE n
+getvalue PILOTLINK_INCLUDE_DIR n
+getvalue PILOTLINK_LIBRARY n
+
+echo "$CMAKE_FLAGS"
+}
+
+outputMakeValues()
+{
+getvalue BUILD_DIR y
+}
+
+# --- MAIN ---
+
+# first, if there's no args, don't lose what we had stored (badness).
+# simply show what available arguments are and exit...
+if test -z "$1"; then
+ usage
+ exit
+fi
+
+CMAKE_BUILD_TYPE="normal"
+ENABLE_TESTS="NO"
+BUILD_DIR=build-`uname -sr | tr -d [:space:] | tr -Cs a-zA-Z0-9 _`
+
+while test -n "$1"
+do
+ case "$1" in
+ --prefix=*)
+ CMAKE_INSTALL_PREFIX=$(echo $1 | cut -d "=" -f2)
+ ;;
+ --enable-debug*)
+ T=$(echo $1 | cut -d "=" -f2 | tr '[A-Z]' '[a-z]')
+ if test "$T" = "$1" || test "yes" = "$T" || test "full" = "$T" ; then
+ CMAKE_BUILD_TYPE=debug
+ else
+ CMAKE_BUILD_TYPE=normal
+ fi
+ ;;
+ --enable-test*)
+ T=$(echo "$1" | cut -d = -f2 | tr '[A-Z]' '[a-z]')
+ if test "$T" = "$1" || test "yes" = "$T" ; then
+ ENABLE_TESTS=YES
+ else
+ ENABLE_TESTS=NO
+ fi
+ ;;
+ --with-simple-builddir*)
+ T=$(echo "$1" | cut -d = -f2 | tr '[A-Z]' '[a-z]')
+ if test "$T" = "$1" || test "yes" = "$T" ; then
+ BUILD_DIR=build
+ fi
+ ;;
+ --with-pilot-link-includes=*)
+ PILOTLINK_INCLUDE_DIR=$(echo $1 | cut -d = -f2)
+ ;;
+ --with-pilot-link-lib=*)
+ PILOTLINK_LIBRARY=$(echo $1 | cut -d = -f2)
+ ;;
+ --with-pilot-link=*)
+ PILOTLINK_BASE=$(echo $1 | cut -d "=" -f2)
+ ;;
+ --with-mal=*)
+ MAL_BASE=$(echo $1 | cut -d "=" -f2)
+ ;;
+ --show)
+ echo "Existing configuration values:"
+ echo "-----------"
+ cat "$OUTFILE" 2>/dev/null
+ sed 's/^set(\([A-Z_]*\) "\(.*\)")/\1="\2"/' "$CMAKEOUTFILE" 2>/dev/null
+ echo "-----------"
+ exit
+ ;;
+ *)
+ usage
+ exit
+ ;;
+ esac
+
+ shift
+
+done
+
+###
+#
+# BSD uses gmake for the GNU make which we need ...
+#
+if uname -s | grep BSD > /dev/null 2>&1 ; then
+ MAKE=gmake
+else
+ MAKE=make
+fi
+
+outputCmakeValues > "$CMAKEOUTFILE.new"
+outputMakeValues > "$OUTFILE.new"
+
+
+###
+#
+# If the configure values have changed, then we should update the
+# CMakeLists.txt in order to prompt a re-run of cmake.
+#
+update=no
+failed=no
+if test -f "$CMAKEOUTFILE" ; then
+ diff -q "$CMAKEOUTFILE" "$CMAKEOUTFILE.new" > /dev/null 2>&1 || update=yes
+else
+ update=yes
+fi
+
+if test -f "$OUTFILE" ; then
+ diff -q "$OUTFILE" "$OUTFILE.new" > /dev/null 2>&1 || update=yes
+else
+ update=yes
+fi
+
+if test yes = "$update" ; then
+ cp "$CMAKEOUTFILE.new" "$CMAKEOUTFILE"
+ cp "$OUTFILE.new" "$OUTFILE"
+ touch CMakeLists.txt
+ $MAKE -f Makefile.cmake build-check || failed=yes
+fi
+
+rm -f "$CMAKEOUTFILE.new"
+rm -f "$OUTFILE.new"
+rm -f build*/CMakeCache.txt
+
+###
+#
+# Inform user and create settings file.
+#
+echo "
+Thanks. Here are the values I will be using...
+
+$(outputCmakeValues)
+
+$(outputMakeValues)
+
+To compile KPilot, now run GNU make, like so:
+
+ $MAKE -f Makefile.cmake
+
+"
+
+if test "yes" = "$failed" ; then
+ echo "Configuration failed, so take a good look at the build output."
+fi
+
diff --git a/kpilot/configure.in.bot b/kpilot/configure.in.bot
new file mode 100644
index 000000000..aca4de560
--- /dev/null
+++ b/kpilot/configure.in.bot
@@ -0,0 +1,18 @@
+if test "$HAVE_PISOCK" = "0" ; then
+ echo ""
+ echo "You're missing a compatible version of pilot-link for KPilot."
+ echo "KPilot will not be built."
+ echo ""
+ all_tests=bad
+else
+ if test "x$HAVE_BAD_PISOCK" = "xYES" ; then
+ echo ""
+ echo "You have a version of pilot-link < 0.12.0."
+ echo "This version is old and is known to cause problems"
+ echo "with KPilot. Please compile KPilot with "
+ echo "pilot-link version 0.12.0 or greater."
+ echo "KPilot will not be built."
+ echo ""
+ all_tests=bad
+ fi
+fi
diff --git a/kpilot/configure.in.in b/kpilot/configure.in.in
new file mode 100644
index 000000000..863e3e4c1
--- /dev/null
+++ b/kpilot/configure.in.in
@@ -0,0 +1,256 @@
+dnl Configure.in.in for KPilot.
+dnl
+dnl Copyright (C) 2000,2001 Adriaan de Groot
+dnl
+dnl This file is released under the terms of the Gnu General Public
+dnl Licence (GPL) Version 2.
+
+dnl
+dnl Check to see if pisock header and library are available
+dnl
+
+dnl
+dnl Questions and comments can be sent to [email protected]
+dnl
+
+dnl Check for the headers first. The first test is the somewhat-
+dnl sophisticated one AC uses, and incorporates all the extra-includes
+dnl and whatnot stuff.
+dnl
+dnl We need to explicitly use the --with-extra-includes passed in,
+dnl since AC_CHECK_HEADER does not do so.
+dnl
+
+
+AC_DEFUN([KPILOT_CHECK_PISOCK],
+[
+AC_REQUIRE([KDE_CHECK_LIB64])
+
+AC_MSG_CHECKING(for pilot-link (for KPilot))
+AC_ARG_WITH(pilot_link,
+[ --with-pilot-link=PATH set prefix for pilot-link files @<:@default=check@:>@],
+[
+ case "$withval" in
+ yes)
+ with_pilot_link=CHECK
+ ;;
+ esac ],
+[ with_pilot_link=CHECK ]
+)dnl
+
+case "$with_pilot_link" in
+CHECK)
+ AC_MSG_RESULT([autodetect])
+ ;;
+*)
+ if test -d "$with_pilot_link" ; then
+ AC_MSG_RESULT([$with_pilot_link])
+ else
+ AC_MSG_RESULT([autodetect])
+ with_pilot_link=CHECK
+ AC_MSG_WARN([The path provided for pilot-link, $with_pilot_link, does not exist.])
+ fi
+ ;;
+esac
+
+
+
+AC_LANG_PUSH(C++)
+
+kpilot_save_cflags="$CPPFLAGS"
+kpilot_save_ldflags="$LDFLAGS"
+
+
+CPPFLAGS="$CPPFLAGS $all_includes"
+LDFLAGS="$LDFLAGS $all_libraries"
+
+HAVE_PISOCK=0
+HAVE_BAD_PISOCK=NO
+
+PISOCK_LIB=""
+PISOCK_LDFLAGS=""
+PISOCK_INCLUDE=""
+pisock_path=""
+
+dnl Try looking normally
+dnl
+dnl
+if test "x$with_pilot_link" = "xCHECK" ; then
+AC_CHECK_HEADER(pi-file.h,[HAVE_PISOCK=1], )
+fi
+
+dnl If nothing found, try some other places that might have
+dnl pilot-link installed. These can be extended for particular
+dnl distro's; /vol/kde is where I install stuff on Suns and BSD.
+dnl
+dnl
+if test "$HAVE_PISOCK" = "0" ; then
+ pisock_path=""
+ AC_MSG_CHECKING([for pi-file.h alternate])
+ if test "x$with_pilot_link" = "xCHECK" ; then
+ for i in /usr/local/pilot/include /usr/local/include /vol/kde/support/include /usr/include /usr/include/libpisock ; do
+ test -f $i/pi-file.h && HAVE_PISOCK=1
+ test -f $i/pi-file.h && PISOCK_INCLUDE="-I$i"
+ test -f $i/pi-file.h && pisock_path="$i"
+ done
+ else
+ test -f "$with_pilot_link/include/pi-file.h" && HAVE_PISOCK=1
+ test -f "$with_pilot_link/include/pi-file.h" && PISOCK_INCLUDE="-I$with_pilot_link/include"
+ test -f "$with_pilot_link/include/pi-file.h" && pisock_path="$with_pilot_link/include"
+ fi
+
+ if test "$pisock_path" ; then
+ AC_MSG_RESULT([found $pisock_path])
+ else
+ AC_MSG_RESULT([still not found])
+ HAVE_PISOCK="0"
+ fi
+
+fi
+
+dnl Next, check the version of pilot-link to make sure it's sufficiently new.
+dnl
+dnl
+if test -z "$pisock_path" ; then
+ AC_CHECK_HEADER(pi-version.h,[HAVE_PISOCK=1], )
+else
+ test -d "$pisock_path" || HAVE_PISOCK="0"
+ test -f "$pisock_path/pi-version.h" || HAVE_PISOCK="0"
+fi
+
+dnl Now we know where the includes are, we need to
+dnl check the version more closely.
+dnl
+dnl
+CPPFLAGS="$CPPFLAGS $PISOCK_INCLUDE"
+if test "$HAVE_PISOCK" = "1" ; then
+ AC_MSG_CHECKING([pilot-link version])
+ AC_TRY_RUN([
+ #include <pi-version.h>
+ int main()
+ { if (PILOT_LINK_VERSION==0) {
+ if ((PILOT_LINK_MAJOR==12) && (PILOT_LINK_MINOR>=0)) return (0);
+ }
+ return (1);
+ }
+ ]
+ ,
+ [AC_MSG_RESULT([pilot-link version >= 0.12.0 found])],
+ [AC_MSG_RESULT([Your version of pilot-link won't work with KPilot])]
+ HAVE_PISOCK="0"
+ ,
+ [AC_MSG_RESULT([Cross-compiling KPilot is doomed])
+ HAVE_PISOCK="0"
+ ])
+fi
+
+if test "x$with_pilot_link" = "xCHECK" ; then
+
+# Fairly random collection of possible extra libraries needed
+# to link pilot-link against.
+if test "$HAVE_PISOCK" = "1" ; then
+ HAVE_PISOCK=0
+
+ AC_CHECK_LIB(pisock,
+ pi_accept,
+ [PISOCK_LIB="-lpisock"
+ HAVE_PISOCK=1
+ ],
+ [
+ unset ac_cv_lib_pisock_pi_accept
+ AC_CHECK_LIB(pisock,
+ pi_accept,
+ [PISOCK_LIB="-lpisock -lsocket"
+ HAVE_PISOCK=1
+ ],
+ [
+ unset ac_cv_lib_pisock_pi_accept
+ AC_CHECK_LIB(pisock,
+ pi_accept,
+ [PISOCK_LIB="-lpisock -lsocket -lxnet"
+ HAVE_PISOCK=1
+ ],
+ [
+ AC_CHECK_LIB(pisock,
+ pi_accept,
+ [PISOCK_LIB="-lpisock -lnsl -lsocket"
+ HAVE_PISOCK=1
+ ],
+ [HAVE_PISOCK=0
+ ])
+ ],
+ [-lsocket -lxnet]
+ )
+ ],
+ [-lsocket]
+ )
+ ]
+ )
+fi
+fi
+
+# No libpisock found yet, but the headers have been found
+if test -z "$PISOCK_LIB" ; then
+if test "$HAVE_PISOCK" = "1" ; then
+
+HAVE_PISOCK=0
+
+if test "x$with_pilot_link" = "xCHECK" ; then
+dnl Run through the loop *anyway*, even if we've already found
+dnl the library. The inner if makes sure that we only check until
+dnl we've found the library once.
+dnl
+dnl
+for i in /usr/local/pilot/lib /usr/local/lib /vol/kde/support/lib ; do
+ if test "$HAVE_PISOCK" = "0" ; then
+ CPPFLAGS="$kpilot_save_cflags $all_includes $PISOCK_INCLUDE"
+ LDFLAGS="$kpilot_save_ldflags $all_libraries -L$i -R$i"
+
+ unset ac_cv_lib_pisock_pi_accept
+ AC_CHECK_LIB(pisock,pi_accept,
+ [PISOCK_LDFLAGS="-L$i -R$i"
+ PISOCK_LIB="-lpisock"
+ HAVE_PISOCK=1],[],[])
+ fi
+done
+else
+ CPPFLAGS="$kpilot_save_cflags $all_includes $PISOCK_INCLUDE"
+ LDFLAGS="$kpilot_save_ldflags $all_libraries -L$with_pilot_link/lib -R$with_pilot_link/lib"
+
+ unset ac_cv_lib_pisock_pi_accept
+ AC_CHECK_LIB(pisock,pi_accept,
+ [PISOCK_LDFLAGS="-L$with_pilot_link/lib -R$with_pilot_link/lib"
+ PISOCK_LIB="-lpisock"
+ HAVE_PISOCK=1],[],[])
+fi
+fi
+fi
+
+
+if test "$HAVE_PISOCK" = "0" ; then
+ PISOCK_LIB=""
+ PISOCK_LDFLAGS=""
+ PISOCK_INCLUDE=""
+ DO_NOT_COMPILE="$DO_NOT_COMPILE kpilot"
+fi
+
+AC_SUBST(PISOCK_LIB)
+AC_SUBST(PISOCK_LDFLAGS)
+AC_SUBST(PISOCK_INCLUDE)
+AM_CONDITIONAL(compile_kpilot, test "$HAVE_PISOCK" = 1)
+
+
+CPPFLAGS="$kpilot_save_cflags"
+LDFLAGS="$kpilot_save_ldflags"
+unset kpilot_save_cflags
+unset kpilot_save_ldflags
+
+AC_LANG_POP(C++)
+
+dnl Remainder is for standalone use
+AC_HEADER_TIME
+AC_CHECK_GETDOMAINNAME
+
+])
+KPILOT_CHECK_PISOCK
+
diff --git a/kpilot/kpilot/CMakeLists.txt b/kpilot/kpilot/CMakeLists.txt
new file mode 100644
index 000000000..9be244678
--- /dev/null
+++ b/kpilot/kpilot/CMakeLists.txt
@@ -0,0 +1,180 @@
+link_directories(${CMAKE_BINARY_DIR}/lib ${CMAKE_CURRENT_BINARY_DIR})
+
+# Don't forget to include output directory, otherwise
+# the UI file won't be wrapped!
+include_directories(
+ ${CMAKE_BINARY_DIR}/lib
+ ${CMAKE_SOURCE_DIR}/lib
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+
+###
+#
+# Settings (KConfigXT) shared between various parts of KPilot
+#
+set(settings_SRC
+ kpilotConfig.cc
+)
+
+kde3_add_kcfg_files(settings_SRC kpilotSettings.kcfgc)
+
+###
+#
+# The KCM for KPilot, used by the config dialog and the embedding in Kontact
+#
+set(kcmpilot_SRCS
+ ${settings_SRC}
+ kpilotConfigWizard.cc
+ dbSelectionDialog.cc
+ kpilotConfigDialog.cc
+ conduitConfigDialog.cc
+ kpilotProbeDialog.cc
+)
+
+set(kcmpilot_KCFGS
+ kpilotConfigWizard_address.kcfgc
+ kpilotConfigWizard_notes.kcfgc
+ kpilotConfigWizard_vcal.kcfgc
+)
+
+set(kcmpilot_UIS
+ kpilotConfigDialog_device.ui
+ kpilotConfigDialog_sync.ui
+ kpilotConfigDialog_startup.ui
+ kpilotConfigDialog_viewers.ui
+ kpilotConfigDialog_backup.ui
+ kpilotConfigWizard_user.ui
+ kpilotConfigWizard_app.ui
+ dbSelection_base.ui
+)
+
+kde3_add_ui_files(kcmpilot_SRCS ${kcmpilot_UIS})
+kde3_add_kcfg_files(kcmpilot_SRCS ${kcmpilot_KCFGS})
+kde3_add_dcop_stubs(kcmpilot_SRCS pilotDaemonDCOP.h)
+kde3_automoc(${kcmpilot_SRCS})
+
+# Now add these generated files to the ADD_LIBRARY step
+# If this is NOT done, then the ui_*.h files will not be generated
+add_library(kcm_kpilot SHARED ${kcmpilot_SRCS})
+set_target_properties(kcm_kpilot PROPERTIES
+ LOCATION ${KDE3_PLUGIN_INSTALL_DIR}
+ PREFIX ""
+)
+
+###
+#
+# Most simple daemon-like application: kpilotTest, which
+# runs whatever the command-line tells it to.
+#
+set(kpilotTest_SRCS
+ ${settings_SRC}
+ hotSync.cc
+ logWidget.cc
+ pilotComponent.cc
+ main-test.cc
+)
+# Acts as a receiver for DCOP log messages
+kde3_add_dcop_skels(kpilotTest_SRCS loggerDCOP.h)
+
+kde3_automoc(${kpilotTest_SRCS})
+add_executable(kpilotTest ${kpilotTest_SRCS})
+target_link_libraries(kpilotTest ${QT_LIBRARIES} kpilot kdeui kio)
+kpilot_rpath(kpilotTest)
+
+###
+#
+# The real KPilot daemon.
+#
+set(kpilotDaemon_SRCS
+ ${settings_SRC}
+ hotSync.cc
+ fileInstaller.cc
+ internalEditorAction.cc
+ logFile.cc
+ pilotDaemon.cc
+)
+# Both sends and receives DCOP log messages. Talks to KPilot.
+kde3_add_dcop_skels(kpilotDaemon_SRCS loggerDCOP.h pilotDaemonDCOP.h)
+kde3_add_dcop_stubs(kpilotDaemon_SRCS loggerDCOP.h kpilotDCOP.h)
+kde3_automoc(${kpilotDaemon_SRCS})
+add_executable(kpilotDaemon ${kpilotDaemon_SRCS})
+target_link_libraries(kpilotDaemon ${QT_LIBRARIES} kpilot kdeui kio)
+kpilot_rpath(kpilotDaemon)
+
+###
+#
+# The KPilot executable (viewer / editor / configuration).
+#
+set(kpilot_SRCS
+ ${settings_SRC}
+ logWidget.cc
+ kpilot.cc
+ dbviewerWidget.cc
+ dbFlagsEditor.cc
+ dbRecordEditor.cc
+ dbAppInfoEditor.cc
+ pilotComponent.cc
+ memoWidget.cc
+ addressWidget.cc
+ addressEditor.cc
+ datebookWidget.cc
+ todoWidget.cc
+ todoEditor.cc
+ fileInstaller.cc
+ fileInstallWidget.cc
+ listItems.cc
+)
+
+set(kpilot_UIS
+ dbFlagsEditor_base.ui
+ todoEditor_base.ui
+)
+
+kde3_add_ui_files(kpilot_SRCS ${kpilot_UIS})
+# Talks to the daemon. Listens as itself.
+kde3_add_dcop_skels(kpilot_SRCS loggerDCOP.h kpilotDCOP.h)
+kde3_add_dcop_stubs(kpilot_SRCS pilotDaemonDCOP.h)
+kde3_automoc(${kpilot_SRCS})
+add_executable(kpilot_bin ${kpilot_SRCS})
+target_link_libraries(kpilot_bin ${QT_LIBRARIES} kpilot kutils kdeui kio)
+kpilot_rpath(kpilot_bin)
+set_target_properties(kpilot_bin PROPERTIES
+ OUTPUT_NAME kpilot
+)
+
+######################### INSTALL STUFF #######################################
+
+kde3_install_libtool_file(kcm_kpilot)
+
+install(
+ TARGETS kcm_kpilot kpilot_bin kpilotDaemon
+ LIBRARY DESTINATION ${KDE3_PLUGIN_INSTALL_DIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
+ RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
+)
+
+install( FILES kpilotui.rc DESTINATION ${CMAKE_INSTALL_PREFIX}/share/apps/kpilot)
+
+install(
+ FILES kpilot.desktop kpilotdaemon.desktop DESTINATION ${KDE3_XDG_APPS_DIR}
+)
+
+install(
+ FILES kpilotconduit.desktop DESTINATION ${KDE3_SERVICETYPES_DIR}
+)
+
+install(
+ FILES kpilot_config.desktop DESTINATION ${KDE3_SERVICES_DIR}
+)
+
+install (
+ FILES kpilot.upd
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/apps/kconf_update
+)
+
+install(
+ FILES kpilot.kcfg DESTINATION ${KDE3_KCFG_DIR}
+)
+
+add_subdirectory(Icons)
diff --git a/kpilot/kpilot/Icons/CMakeLists.txt b/kpilot/kpilot/Icons/CMakeLists.txt
new file mode 100644
index 000000000..b0be5caa0
--- /dev/null
+++ b/kpilot/kpilot/Icons/CMakeLists.txt
@@ -0,0 +1,4 @@
+
+kde3_install_icons_custom( hicolor )
+
+install( FILES kpilot-splash.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/apps/kpilot/pics/)
diff --git a/kpilot/kpilot/Icons/Makefile.am b/kpilot/kpilot/Icons/Makefile.am
new file mode 100644
index 000000000..9dc8ffccc
--- /dev/null
+++ b/kpilot/kpilot/Icons/Makefile.am
@@ -0,0 +1,19 @@
+METASOURCES = AUTO
+
+kpilotDaemonicondir = $(kde_datadir)/kpilot/icons
+kpilotDaemonicon_ICON = hotsync busysync nosync
+
+kpiloticondir = $(kde_datadir)/kpilot/icons
+kpiloticon_ICON = backup fastsync fullsync listsync restore \
+ kpilotaddress \
+ kpilotknotes \
+ kpilotfileinstaller \
+ kpilotdb \
+ kpilotcalendar \
+ kpilottodo \
+ kpilotbhotsync
+
+KDE_ICON = kpilot kpilotDaemon
+
+kpilotpicsdir = $(kde_datadir)/kpilot/pics
+kpilotpics_DATA = kpilot-splash.png
diff --git a/kpilot/kpilot/Icons/busysync.png b/kpilot/kpilot/Icons/busysync.png
new file mode 100644
index 000000000..189ec1b12
--- /dev/null
+++ b/kpilot/kpilot/Icons/busysync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr16-action-backup.png b/kpilot/kpilot/Icons/cr16-action-backup.png
new file mode 100644
index 000000000..da55d07d4
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr16-action-backup.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr16-action-busysync.png b/kpilot/kpilot/Icons/cr16-action-busysync.png
new file mode 100644
index 000000000..66e8837cb
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr16-action-busysync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr16-action-fastsync.png b/kpilot/kpilot/Icons/cr16-action-fastsync.png
new file mode 100644
index 000000000..6eca11fa9
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr16-action-fastsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr16-action-fullsync.png b/kpilot/kpilot/Icons/cr16-action-fullsync.png
new file mode 100644
index 000000000..d6501b5b3
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr16-action-fullsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr16-action-hotsync.png b/kpilot/kpilot/Icons/cr16-action-hotsync.png
new file mode 100644
index 000000000..bdcaf824e
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr16-action-hotsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr16-action-listsync.png b/kpilot/kpilot/Icons/cr16-action-listsync.png
new file mode 100644
index 000000000..817f34cad
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr16-action-listsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr16-action-nosync.png b/kpilot/kpilot/Icons/cr16-action-nosync.png
new file mode 100644
index 000000000..61bf3bdab
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr16-action-nosync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr16-action-restore.png b/kpilot/kpilot/Icons/cr16-action-restore.png
new file mode 100644
index 000000000..69af2c817
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr16-action-restore.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr16-app-kpilotDaemon.png b/kpilot/kpilot/Icons/cr16-app-kpilotDaemon.png
new file mode 100644
index 000000000..f37c5ffc5
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr16-app-kpilotDaemon.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr22-action-backup.png b/kpilot/kpilot/Icons/cr22-action-backup.png
new file mode 100644
index 000000000..d1ab921d3
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr22-action-backup.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr22-action-busysync.png b/kpilot/kpilot/Icons/cr22-action-busysync.png
new file mode 100644
index 000000000..71f5ba9cd
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr22-action-busysync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr22-action-fastsync.png b/kpilot/kpilot/Icons/cr22-action-fastsync.png
new file mode 100644
index 000000000..926b3bf55
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr22-action-fastsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr22-action-fullsync.png b/kpilot/kpilot/Icons/cr22-action-fullsync.png
new file mode 100644
index 000000000..ea3b8d52c
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr22-action-fullsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr22-action-hotsync.png b/kpilot/kpilot/Icons/cr22-action-hotsync.png
new file mode 100644
index 000000000..11eceb43b
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr22-action-hotsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr22-action-listsync.png b/kpilot/kpilot/Icons/cr22-action-listsync.png
new file mode 100644
index 000000000..3453a1f74
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr22-action-listsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr22-action-nosync.png b/kpilot/kpilot/Icons/cr22-action-nosync.png
new file mode 100644
index 000000000..3728404f3
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr22-action-nosync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr22-action-restore.png b/kpilot/kpilot/Icons/cr22-action-restore.png
new file mode 100644
index 000000000..8b183f8d4
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr22-action-restore.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr22-app-kpilotDaemon.png b/kpilot/kpilot/Icons/cr22-app-kpilotDaemon.png
new file mode 100644
index 000000000..4a1baeba7
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr22-app-kpilotDaemon.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr32-action-fastsync.png b/kpilot/kpilot/Icons/cr32-action-fastsync.png
new file mode 100644
index 000000000..f6a07151b
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr32-action-fastsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr32-action-fullsync.png b/kpilot/kpilot/Icons/cr32-action-fullsync.png
new file mode 100644
index 000000000..158b23e93
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr32-action-fullsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr32-action-hotsync.png b/kpilot/kpilot/Icons/cr32-action-hotsync.png
new file mode 100644
index 000000000..8316a1612
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr32-action-hotsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr32-action-listsync.png b/kpilot/kpilot/Icons/cr32-action-listsync.png
new file mode 100644
index 000000000..a6b5268b6
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr32-action-listsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr32-app-kpilotDaemon.png b/kpilot/kpilot/Icons/cr32-app-kpilotDaemon.png
new file mode 100644
index 000000000..5b44f689a
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr32-app-kpilotDaemon.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr48-action-fastsync.png b/kpilot/kpilot/Icons/cr48-action-fastsync.png
new file mode 100644
index 000000000..23d353f7b
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr48-action-fastsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr48-action-fullsync.png b/kpilot/kpilot/Icons/cr48-action-fullsync.png
new file mode 100644
index 000000000..d1be74d1f
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr48-action-fullsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr48-action-hotsync.png b/kpilot/kpilot/Icons/cr48-action-hotsync.png
new file mode 100644
index 000000000..dfc98ff41
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr48-action-hotsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr48-action-listsync.png b/kpilot/kpilot/Icons/cr48-action-listsync.png
new file mode 100644
index 000000000..b3384e4b2
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr48-action-listsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr48-app-kpilotDaemon.png b/kpilot/kpilot/Icons/cr48-app-kpilotDaemon.png
new file mode 100644
index 000000000..85710e5fe
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr48-app-kpilotDaemon.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr64-action-kpilotaddress.png b/kpilot/kpilot/Icons/cr64-action-kpilotaddress.png
new file mode 100644
index 000000000..a73e14822
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr64-action-kpilotaddress.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr64-action-kpilotbhotsync.png b/kpilot/kpilot/Icons/cr64-action-kpilotbhotsync.png
new file mode 100644
index 000000000..c01b6e8e8
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr64-action-kpilotbhotsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr64-action-kpilotcalendar.png b/kpilot/kpilot/Icons/cr64-action-kpilotcalendar.png
new file mode 100644
index 000000000..6bbe65dbe
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr64-action-kpilotcalendar.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr64-action-kpilotdb.png b/kpilot/kpilot/Icons/cr64-action-kpilotdb.png
new file mode 100644
index 000000000..f14bd8584
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr64-action-kpilotdb.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr64-action-kpilotfileinstaller.png b/kpilot/kpilot/Icons/cr64-action-kpilotfileinstaller.png
new file mode 100644
index 000000000..39837225b
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr64-action-kpilotfileinstaller.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr64-action-kpilotknotes.png b/kpilot/kpilot/Icons/cr64-action-kpilotknotes.png
new file mode 100644
index 000000000..ecf902784
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr64-action-kpilotknotes.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/cr64-action-kpilottodo.png b/kpilot/kpilot/Icons/cr64-action-kpilottodo.png
new file mode 100644
index 000000000..2d5275c55
--- /dev/null
+++ b/kpilot/kpilot/Icons/cr64-action-kpilottodo.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/fastsync.png b/kpilot/kpilot/Icons/fastsync.png
new file mode 100644
index 000000000..926b3bf55
--- /dev/null
+++ b/kpilot/kpilot/Icons/fastsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/hi16-app-kpilot.png b/kpilot/kpilot/Icons/hi16-app-kpilot.png
new file mode 100644
index 000000000..f37c5ffc5
--- /dev/null
+++ b/kpilot/kpilot/Icons/hi16-app-kpilot.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/hi22-app-kpilot.png b/kpilot/kpilot/Icons/hi22-app-kpilot.png
new file mode 100644
index 000000000..4a1baeba7
--- /dev/null
+++ b/kpilot/kpilot/Icons/hi22-app-kpilot.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/hi32-app-kpilot.png b/kpilot/kpilot/Icons/hi32-app-kpilot.png
new file mode 100644
index 000000000..5b44f689a
--- /dev/null
+++ b/kpilot/kpilot/Icons/hi32-app-kpilot.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/hi48-app-kpilot.png b/kpilot/kpilot/Icons/hi48-app-kpilot.png
new file mode 100644
index 000000000..85710e5fe
--- /dev/null
+++ b/kpilot/kpilot/Icons/hi48-app-kpilot.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/hotsync.png b/kpilot/kpilot/Icons/hotsync.png
new file mode 100644
index 000000000..62025ef71
--- /dev/null
+++ b/kpilot/kpilot/Icons/hotsync.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/kpilot-splash.png b/kpilot/kpilot/Icons/kpilot-splash.png
new file mode 100644
index 000000000..fadf0d21e
--- /dev/null
+++ b/kpilot/kpilot/Icons/kpilot-splash.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/mini-kpilot.png b/kpilot/kpilot/Icons/mini-kpilot.png
new file mode 100644
index 000000000..550c8f377
--- /dev/null
+++ b/kpilot/kpilot/Icons/mini-kpilot.png
Binary files differ
diff --git a/kpilot/kpilot/Icons/nosync.png b/kpilot/kpilot/Icons/nosync.png
new file mode 100644
index 000000000..61bf3bdab
--- /dev/null
+++ b/kpilot/kpilot/Icons/nosync.png
Binary files differ
diff --git a/kpilot/kpilot/Makefile-standalone b/kpilot/kpilot/Makefile-standalone
new file mode 100644
index 000000000..fbaa7a77a
--- /dev/null
+++ b/kpilot/kpilot/Makefile-standalone
@@ -0,0 +1,167 @@
+# Makefile for a standalone kpilotConfig
+
+QTDIR=/usr/lib/qt-2.3.0
+KDEDIR=/vol/kde/kde-2.2
+
+MOC=$(QTDIR)/bin/moc
+UIC=$(QTDIR)/bin/uic
+DCOPIDL=$(KDEDIR)/bin/dcopidl
+DCOPIDL2CPP=$(KDEDIR)/bin/dcopidl2cpp
+
+CXX=g++
+CXXFLAGS=-DDEBUG -DDEBUG_CERR
+# INCLUDES=-I$(QTDIR)/include -I$(KDEDIR)/include
+#
+# Or, for stupid RH 7.1 systems:
+INCLUDES=-I$(QTDIR)/include -I$(KDEDIR)/include -I../lib
+LDFLAGS=-L$(KDEDIR)/lib -Wl,-R -Wl,$(KDEDIR)/lib \
+ -L$(QTDIR)/lib -Wl,-R -Wl,$(QTDIR)/lib \
+ -L../lib/.libs
+
+CONFIG_DISTDIR=kpilotConfig-0.2
+CONFIG_OBJS=kpilotConfig.o \
+ kpilotConfigDialog.o kpilotConfigDialog_base.o \
+ conduitConfigDialog.o conduitConfigDialog_base.o \
+ main-config.o
+CONFIG_MOCS=kpilotConfigDialog_base.moc kpilotConfigDialog.moc \
+ conduitConfigDialog.moc conduitConfigDialog_base.moc
+
+CONFIG_EXTRA=kpilotConfigDialog_base.ui conduitConfigDialog_base.ui
+CONFIG_LIBS=-lkdeui -lkfile -lkdecore -lqt -lkpilot
+
+TEST_DISTDIR=kpilotTest-0.2
+TEST_OBJS=kpilotConfig.o \
+ pilotComponent.o logWidget.o \
+ hotSync.o interactiveSync.o main-test.o
+TEST_MOCS= pilotComponent.moc logWidget.moc \
+ interactiveSync.moc hotSync.moc
+TEST_EXTRA=pilotUser.h
+TEST_LIBS=-lkpilot -lkfile -lkdeui -lqt -lpisock
+
+KPILOT_DISTDIR=kpilot-4.2.9
+KPILOT_OBJS= pilotDaemonDCOP_stub.o \
+ kpilotDCOP_skel.o \
+ kpilot.o kpilotConfig.o \
+ kpilotConfigDialog.o kpilotConfigDialog_base.o \
+ pilotComponent.o logWidget.o memoWidget.o addressWidget.o \
+ addressEditor.o \
+ listItems.o \
+ fileInstaller.o fileInstallWidget.o \
+ conduitConfigDialog.o conduitConfigDialog_base.o
+KPILOT_MOCS=pilotComponent.moc logWidget.moc memoWidget.moc addressWidget.moc \
+ fileInstaller.moc addressEditor.moc \
+ fileInstallWidget.moc \
+ kpilotConfigDialog_base.moc kpilotConfigDialog.moc \
+ kpilot.moc
+KPILOT_EXTRA=kpilotConfigDialog_base.ui conduitConfigDialog_base.ui \
+ pilotDaemonDCOP.h kpilotDCOP.h \
+ pilotAppCategory.h pilotDatabase.h kpilot_on_pp.h
+KPILOT_LIBS=-lkfile -lkdeui -lqt -lkpilot -lpisock
+
+DAEMON_DISTDIR=kpilotDaemon-4.2.9
+DAEMON_OBJS= pilotDaemonDCOP_skel.o kpilotDCOP_stub.o \
+ pilotDaemon.o kpilotConfig.o \
+ fileInstaller.o \
+ hotSync.o interactiveSync.o
+DAEMON_MOCS=pilotDaemon.moc \
+ fileInstaller.moc
+DAEMON_EXTRA=pilotDaemonDCOP.h kpilotDCOP.h pilotUser.h \
+ hotsync.h busysync.h
+DAEMON_LIBS=-lkfile -lkdeui -lqt -lkpilot -lpisock
+
+DISTFILES=kpilotConfig.tar.gz kpilotTest.tar.gz kpilot.tar.gz kpilotDaemon.tar.gz
+
+all : kpilotConfig kpilotTest kpilot kpilotDaemon
+
+kpilotConfig : $(CONFIG_MOCS) $(CONFIG_OBJS)
+ g++ -o $@ $(CONFIG_OBJS) $(LDFLAGS) $(CONFIG_LIBS)
+
+kpilotTest : $(TEST_MOCS) $(TEST_OBJS)
+ g++ -o $@ $(TEST_OBJS) $(LDFLAGS) $(TEST_LIBS)
+
+kpilot : $(KPILOT_MOCS) $(KPILOT_OBJS)
+ g++ -o $@ $(KPILOT_OBJS) $(LDFLAGS) $(KPILOT_LIBS)
+
+kpilotDaemon : $(DAEMON_MOCS) $(DAEMON_OBJS)
+ g++ -o $@ $(DAEMON_OBJS) $(LDFLAGS) $(DAEMON_LIBS)
+
+clean :
+ rm -f $(CONFIG_OBJS) $(CONFIG_MOCS) $(KPILOT_OBJS) $(DAEMON_OBJS)
+ rm -f $(TEST_OBJS) $(TEST_MOCS) $(KPILOT_MOCS) $(DAEMON_MOCS)
+ rm -f $(DISTFILES)
+
+dist : $(DISTFILES)
+
+kpilotConfig.tar.gz :
+ test -d $(CONFIG_DISTDIR) || mkdir $(CONFIG_DISTDIR)
+ sed -e 's/^all *:.*/all : kpilotConfig/' Makefile-standalone \
+ > $(CONFIG_DISTDIR)/Makefile
+ -cp $(CONFIG_OBJS:%.o=%.cc) $(CONFIG_OBJS:%.o=%.h) $(CONFIG_DISTDIR)
+ -cp $(CONFIG_EXTRA) $(CONFIG_DISTDIR)
+ tar cvzf $@ $(CONFIG_DISTDIR)
+ -rm -f $(CONFIG_DISTDIR)/*
+ -rmdir $(CONFIG_DISTDIR)
+
+kpilotTest.tar.gz :
+ test -d $(TEST_DISTDIR) || mkdir $(TEST_DISTDIR)
+ sed -e 's/^all *:.*/all : kpilotTest/' Makefile-standalone \
+ > $(TEST_DISTDIR)/Makefile
+ -cp $(TEST_OBJS:%.o=%.cc) $(TEST_OBJS:%.o=%.h) $(TEST_DISTDIR)
+ -cp $(TEST_EXTRA) $(TEST_DISTDIR)
+ tar cvzf $@ $(TEST_DISTDIR)
+ -rm -f $(TEST_DISTDIR)/*
+ -rmdir $(TEST_DISTDIR)
+
+kpilot.tar.gz :
+ test -d $(KPILOT_DISTDIR) || mkdir $(KPILOT_DISTDIR)
+ sed -e 's/^all *:.*/all : kpilot/' Makefile-standalone \
+ > $(KPILOT_DISTDIR)/Makefile
+ -cp $(KPILOT_OBJS:%.o=%.cc) $(KPILOT_OBJS:%.o=%.h) $(KPILOT_DISTDIR)
+ -cp $(KPILOT_EXTRA) $(KPILOT_DISTDIR)
+ tar cvzf $@ $(KPILOT_DISTDIR)
+ -rm -f $(KPILOT_DISTDIR)/*
+ -rmdir $(KPILOT_DISTDIR)
+
+kpilotDaemon.tar.gz :
+ test -d $(DAEMON_DISTDIR) || mkdir $(DAEMON_DISTDIR)
+ sed -e 's/^all *:.*/all : kpilotDaemon/' Makefile-standalone \
+ > $(DAEMON_DISTDIR)/Makefile
+ -cp $(DAEMON_OBJS:%.o=%.cc) $(DAEMON_OBJS:%.o=%.h) $(DAEMON_DISTDIR)
+ -cp $(DAEMON_EXTRA) $(DAEMON_DISTDIR)
+ tar cvzf $@ $(DAEMON_DISTDIR)
+ -rm -f $(DAEMON_DISTDIR)/*
+ -rmdir $(DAEMON_DISTDIR)
+
+conduitConfigDialog_base.cc : conduitConfigDialog_base.h conduitConfigDialog_base.ui
+ echo '#include <klocale.h>' > $@
+ $(UIC) -tr i18n -i conduitConfigDialog_base.h conduitConfigDialog_base.ui | \
+ sed -e "s,i18n( \"\" ),QString::null,g" >> $@
+ echo '#include "conduitConfigDialog_base.moc"' >> $@
+
+conduitConfigDialog_base.h : conduitConfigDialog_base.ui
+ $(UIC) -o $@ $<
+
+kpilotConfigDialog_base.cc : kpilotConfigDialog_base.h kpilotConfigDialog_base.ui
+ echo '#include <klocale.h>' > $@
+ $(UIC) -tr i18n -i kpilotConfigDialog_base.h kpilotConfigDialog_base.ui | \
+ sed -e "s,i18n( \"\" ),QString::null,g" >> $@
+ echo '#include "kpilotConfigDialog_base.moc"' >> $@
+
+kpilotConfigDialog_base.h : kpilotConfigDialog_base.ui
+ $(UIC) -o $@ $<
+
+
+%.kidl : %.h
+ $(DCOPIDL) $< > $@ || ( rm -f $@ ; /bin/false )
+
+%_stub.cc : %.kidl
+ $(DCOPIDL2CPP) --c++-suffix cc --no-skel $<
+
+%_skel.cc : %.kidl
+ $(DCOPIDL2CPP) --c++-suffix cc --no-stub $<
+
+%.o : %.cc
+ g++ -c $(CXXFLAGS) $(INCLUDES) -o $@ $<
+
+%.moc : %.h
+ $(MOC) -o $@ $<
diff --git a/kpilot/kpilot/Makefile.am b/kpilot/kpilot/Makefile.am
new file mode 100644
index 000000000..a5b49091e
--- /dev/null
+++ b/kpilot/kpilot/Makefile.am
@@ -0,0 +1,104 @@
+### Makefile.am for KPilot
+###
+### This is a bit of a mess, but that's partly because we build two
+### executables and one library from the sources in this dir.
+###
+###
+###
+
+SUBDIRS = Icons
+
+noinst_LTLIBRARIES = libconfiguration.la
+noinst_PROGRAMS = kpilotTest
+bin_PROGRAMS = kpilot kpilotDaemon
+kde_module_LTLIBRARIES = kcm_kpilot.la
+
+METASOURCES = AUTO
+
+INCLUDES= $(PISOCK_INCLUDE) -I$(top_srcdir)/kpilot/lib $(all_includes)
+
+libconfiguration_la_SOURCES = kpilotConfig.cc kpilotSettings.kcfgc
+libconfiguration_la_LDFLAGS = $(PISOCK_LDFLAGS) $(all_libraries)
+
+kcm_kpilot_la_SOURCES = pilotDaemonDCOP.stub kpilotConfigDialog.cc \
+ kpilotConfigDialog_device.ui \
+ kpilotConfigDialog_sync.ui \
+ kpilotConfigDialog_startup.ui \
+ kpilotConfigDialog_viewers.ui \
+ kpilotConfigDialog_backup.ui \
+ conduitConfigDialog.cc \
+ kpilotProbeDialog.cc \
+ kpilotConfigWizard_address.kcfgc \
+ kpilotConfigWizard_notes.kcfgc \
+ kpilotConfigWizard_vcal.kcfgc \
+ kpilotConfigWizard_user.ui \
+ kpilotConfigWizard_app.ui \
+ kpilotConfigWizard.cc \
+ dbSelectionDialog.cc dbSelection_base.ui
+kcm_kpilot_la_LDFLAGS = $(PISOCK_LDFLAGS) $(all_libraries) -module -avoid-version -no-undefined
+kcm_kpilot_la_LIBADD = $(LIB_KFILE) $(PISOCK_LIB) \
+ ../lib/libkpilot.la \
+ libconfiguration.la
+
+
+kpilot_SOURCES = \
+ pilotDaemonDCOP.stub kpilotDCOP.skel loggerDCOP.skel \
+ kpilot.cc \
+ pilotComponent.cc logWidget.cc memoWidget.cc \
+ addressWidget.cc addressEditor.cc \
+ dbviewerWidget.cc dbFlagsEditor.cc dbFlagsEditor_base.ui \
+ dbRecordEditor.cc dbAppInfoEditor.cc \
+ datebookWidget.cc \
+ todoWidget.cc todoEditor.cc todoEditor_base.ui \
+ fileInstaller.cc fileInstallWidget.cc \
+ listItems.cc
+kpilot_COMPILE_FIRST = kpilotSettings.h
+
+
+kpilotDaemon_SOURCES = \
+ pilotDaemonDCOP.skel kpilotDCOP.stub loggerDCOP.stub loggerDCOP.skel \
+ pilotDaemon.cc logFile.cc \
+ hotSync.cc internalEditorAction.cc \
+ fileInstaller.cc
+
+kpilotTest_SOURCES = \
+ logWidget.cc pilotComponent.cc \
+ hotSync.cc internalEditorAction.cc \
+ loggerDCOP.skel \
+ main-test.cc
+
+
+kpilot_LDFLAGS = $(PISOCK_LDFLAGS) $(all_libraries) $(KDE_RPATH)
+kpilotDaemon_LDFLAGS = $(PISOCK_LDFLAGS) $(all_libraries) $(KDE_RPATH)
+kpilotTest_LDFLAGS = $(PISOCK_LDFLAGS) $(all_libraries) $(KDE_RPATH)
+
+
+# the libraries to link against. Be aware of the order. First the libraries,
+# that depend on the following ones.
+kpilot_LDADD = $(LIB_KFILE) $(PISOCK_LIB) -lkutils \
+ ../lib/libkpilot.la libconfiguration.la
+kpilotDaemon_LDADD = $(LIB_KFILE) $(PISOCK_LIB) \
+ ../lib/libkpilot.la libconfiguration.la
+kpilotTest_LDADD = $(LIB_KFILE) $(PISOCK_LIB) \
+ ../lib/libkpilot.la libconfiguration.la
+
+xdg_apps_DATA = kpilot.desktop kpilotdaemon.desktop
+kde_kcfg_DATA = kpilot.kcfg
+kde_services_DATA = kpilot_config.desktop
+
+servicetypedir = $(kde_servicetypesdir)
+servicetype_DATA = kpilotconduit.desktop
+
+rcdir = $(kde_datadir)/kpilot
+rc_DATA = kpilotui.rc
+
+update_DATA = kpilot.upd
+updatedir = $(kde_datadir)/kconf_update
+
+DOXYGEN_REFERENCES = kdeui kpilot/lib
+include $(top_srcdir)/admin/Doxyfile.am
+
+### Some additional dependencies:
+
+kpilotConfigDialog.lo : kpilotSettings.h
+
diff --git a/kpilot/kpilot/addressEditor.cc b/kpilot/kpilot/addressEditor.cc
new file mode 100644
index 000000000..0ea0032bf
--- /dev/null
+++ b/kpilot/kpilot/addressEditor.cc
@@ -0,0 +1,271 @@
+// -*- C++ -*-
+/* KPilot
+**
+** Copyright (C) 2000 by Dan Pilone
+**
+** This is a dialog window that edits one single address record.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#ifndef _KPILOT_OPTIONS_H
+#include "options.h"
+#endif
+
+#ifndef QLINEEDIT_H
+#include <qlineedit.h>
+#endif
+#ifndef QLAYOUT_H
+#include <qlayout.h>
+#endif
+#ifndef QLABEL_H
+#include <qlabel.h>
+#endif
+#ifndef _KDEBUG_H
+#include <kdebug.h>
+#endif
+
+#ifndef _KPILOT_PILOTADDRESS_H
+#include "pilotAddress.h"
+#endif
+
+#include "addressEditor.moc"
+
+
+AddressEditor::AddressEditor(PilotAddress * p,
+ PilotAddressInfo *appInfo,
+ QWidget * parent,
+ const char *name) :
+ KDialogBase(KDialogBase::Plain,
+ i18n("Address Editor"),
+ Ok | Cancel, Cancel,
+ parent, name, false /* non-modal */ ),
+ fDeleteOnCancel(p == 0L),
+ fAddress(p),
+ fAppInfo(appInfo)
+{
+ FUNCTIONSETUP;
+
+ initLayout();
+ fillFields();
+
+ connect(parent, SIGNAL(recordChanged(PilotAddress *)),
+ this, SLOT(updateRecord(PilotAddress *)));
+
+}
+
+AddressEditor::~AddressEditor()
+{
+ FUNCTIONSETUP;
+
+ if (fDeleteOnCancel && fAddress)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Deleting private address record." << endl;
+#endif
+
+ delete fAddress;
+
+ fAddress = 0L;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Help! I'm deleting!" << endl;
+#endif
+}
+
+
+
+/*
+ * Return phone label from AddressAppInfo + some sanity checking
+ */
+QString AddressEditor::phoneLabelText(PilotAddress * addr, const PhoneSlot &i)
+{
+ FUNCTIONSETUP;
+ if (!addr)
+ {
+ return i18n("Phone");
+ }
+
+ PilotAddressInfo::EPhoneType idx = addr->getPhoneType(i);
+ QString ret = fAppInfo->phoneLabel(idx) + CSL1(":");
+
+ return ret;
+}
+
+
+
+void AddressEditor::fillFields()
+{
+ FUNCTIONSETUP;
+
+ if (fAddress == 0L)
+ {
+ fAddress = new PilotAddress();
+ fDeleteOnCancel = true;
+ }
+
+ // phone labels
+ unsigned int index = 0;
+ for ( PhoneSlot i = PhoneSlot::begin(); i.isValid(); ++i,++index )
+ {
+ m_phoneLabel[index]->setText(phoneLabelText(fAddress, i));
+ fPhoneField[index]->setText(fAddress->getField(i));
+ }
+
+ // fields
+ fLastNameField->setText(fAddress->getField(entryLastname));
+ fFirstNameField->setText(fAddress->getField(entryFirstname));
+ fCompanyField->setText(fAddress->getField(entryCompany));
+ fAddressField->setText(fAddress->getField(entryAddress));
+ fCityField->setText(fAddress->getField(entryCity));
+ fStateField->setText(fAddress->getField(entryState));
+ fZipField->setText(fAddress->getField(entryZip));
+ fCountryField->setText(fAddress->getField(entryCountry));
+ fTitleField->setText(fAddress->getField(entryTitle));
+ fCustom1Field->setText(fAddress->getField(entryCustom1));
+ fCustom2Field->setText(fAddress->getField(entryCustom2));
+ fCustom3Field->setText(fAddress->getField(entryCustom3));
+ fCustom4Field->setText(fAddress->getField(entryCustom4));
+}
+
+
+
+
+#define MakeField(text,field,row,column) \
+ t=new QLabel(text,p); \
+ field = new QLineEdit(p); \
+ field->setMinimumWidth(20*SPACING); \
+ t->setBuddy(field); \
+ grid->addWidget(t,row,column); \
+ grid->addWidget(field,row,column+1);
+
+#define MakeFieldL(text,label,field,row,column) \
+ label = new QLabel(text,p); \
+ field = new QLineEdit(p); \
+ field->setMinimumWidth(20*SPACING); \
+ label->setBuddy(field); \
+ grid->addWidget(label,row,column); \
+ grid->addWidget(field,row,column+1);
+
+void AddressEditor::initLayout()
+{
+ FUNCTIONSETUP;
+
+ QFrame *p = plainPage();
+ QGridLayout *grid = new QGridLayout(p, 10, 5, 0, SPACING);
+
+ QLabel *t;
+
+ MakeField(i18n("Last name:"), fLastNameField, 0, 0);
+ MakeField(i18n("First name:"), fFirstNameField, 1, 0);
+ MakeField(i18n("Title:"), fTitleField, 2, 0);
+ MakeField(i18n("Company:"), fCompanyField, 3, 0);
+
+ PhoneSlot slot = PhoneSlot::begin();
+ for (int i = 0; slot.isValid(); ++i,++slot)
+ {
+ MakeFieldL(phoneLabelText(NULL, slot),
+ m_phoneLabel[i], fPhoneField[i], 4 + i, 0);
+ }
+
+ MakeField(i18n("Address:"), fAddressField, 0, 4);
+ MakeField(i18n("City:"), fCityField, 1, 4);
+ MakeField(i18n("State:"), fStateField, 2, 4);
+ MakeField(i18n("Zip code:"), fZipField, 3, 4);
+ MakeField(i18n("Country:"), fCountryField, 4, 4);
+ MakeField(i18n("Custom 1:"), fCustom1Field, 5, 4);
+ MakeField(i18n("Custom 2:"), fCustom2Field, 6, 4);
+ MakeField(i18n("Custom 3:"), fCustom3Field, 7, 4);
+ MakeField(i18n("Custom 4:"), fCustom4Field, 8, 4);
+
+ grid->addRowSpacing(9, SPACING);
+ grid->addColSpacing(2, SPACING);
+ grid->setRowStretch(9, 100);
+ grid->setColStretch(2, 50);
+}
+
+/* slot */ void AddressEditor::slotCancel()
+{
+ FUNCTIONSETUP;
+
+ if (fDeleteOnCancel && fAddress)
+ {
+ delete fAddress;
+
+ fAddress = 0L;
+ }
+ KDialogBase::slotCancel();
+}
+
+/* slot */ void AddressEditor::slotOk()
+{
+ FUNCTIONSETUP;
+
+ // Commit changes here
+ fAddress->setField(entryLastname, fLastNameField->text());
+ fAddress->setField(entryFirstname, fFirstNameField->text());
+ fAddress->setField(entryCompany, fCompanyField->text());
+ fAddress->setField(entryPhone1, fPhoneField[0]->text());
+ fAddress->setField(entryPhone2, fPhoneField[1]->text());
+ fAddress->setField(entryPhone3, fPhoneField[2]->text());
+ fAddress->setField(entryPhone4, fPhoneField[3]->text());
+ fAddress->setField(entryPhone5, fPhoneField[4]->text());
+ fAddress->setField(entryAddress, fAddressField->text());
+ fAddress->setField(entryCity, fCityField->text());
+ fAddress->setField(entryState, fStateField->text());
+ fAddress->setField(entryZip, fZipField->text());
+ fAddress->setField(entryCountry, fCountryField->text());
+ fAddress->setField(entryTitle, fTitleField->text());
+ fAddress->setField(entryCustom1, fCustom1Field->text());
+ fAddress->setField(entryCustom2, fCustom2Field->text());
+ fAddress->setField(entryCustom3, fCustom3Field->text());
+ fAddress->setField(entryCustom4, fCustom4Field->text());
+
+ emit(recordChangeComplete(fAddress));
+ KDialogBase::slotOk();
+}
+
+/* slot */ void AddressEditor::updateRecord(PilotAddress * p)
+{
+ FUNCTIONSETUP;
+ if (p != fAddress)
+ {
+ // Not meant for me
+ //
+ //
+ return;
+ }
+
+ if (p->isDeleted())
+ {
+ delayedDestruct();
+ return;
+ }
+ else
+ {
+ fillFields();
+ }
+}
+
diff --git a/kpilot/kpilot/addressEditor.h b/kpilot/kpilot/addressEditor.h
new file mode 100644
index 000000000..67132b104
--- /dev/null
+++ b/kpilot/kpilot/addressEditor.h
@@ -0,0 +1,87 @@
+// -*- C++ -*-
+/* addressEditor.h KPilot
+**
+** Copyright (C) 1998-2000 by Dan Pilone
+**
+** This is a dialog window that is used to edit a single address record.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#ifndef _KPILOT_ADDRESSEDITOR_H
+#define _KPILOT_ADDRESSEDITOR_H
+
+#include <kdialogbase.h>
+
+#include "pilotAddress.h"
+
+class QLineEdit;
+
+class AddressEditor : public KDialogBase
+{
+ Q_OBJECT
+
+
+public:
+ AddressEditor(PilotAddress *address,
+ PilotAddressInfo *appInfo,
+ QWidget *parent, const char *name=0L);
+ ~AddressEditor();
+
+
+signals:
+ void recordChangeComplete ( PilotAddress* );
+
+public slots:
+ void slotOk();
+ void slotCancel();
+ void updateRecord(PilotAddress *);
+
+private:
+ bool fDeleteOnCancel;
+
+ PilotAddress* fAddress;
+ PilotAddressInfo *fAppInfo;
+ // entry fields
+ QLineEdit *fCustom4Field;
+ QLineEdit *fCustom3Field;
+ QLineEdit *fCustom2Field;
+ QLineEdit *fCustom1Field;
+ QLineEdit *fCountryField;
+ QLineEdit *fZipField;
+ QLineEdit *fStateField;
+ QLineEdit *fCityField;
+ QLineEdit *fAddressField;
+ QLineEdit *fPhoneField[5];
+ QLineEdit *fCompanyField;
+ QLineEdit *fTitleField;
+ QLineEdit *fFirstNameField;
+ QLineEdit *fLastNameField;
+ // phone labels (changing!)
+ QLabel *m_phoneLabel[5];
+
+ void initLayout();
+ void fillFields();
+ QString phoneLabelText(PilotAddress *, const PhoneSlot &i);
+};
+#endif
+
diff --git a/kpilot/kpilot/addressWidget.cc b/kpilot/kpilot/addressWidget.cc
new file mode 100644
index 000000000..4b900abb2
--- /dev/null
+++ b/kpilot/kpilot/addressWidget.cc
@@ -0,0 +1,733 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2004 by Adriaan de Groot
+**
+** This file defines the addressWidget, that part of KPilot that
+** displays address records from the Pilot.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#ifndef _KPILOT_OPTIONS_H
+#include "options.h"
+#endif
+
+#include <iostream>
+#include <cstring>
+#include <cstdlib>
+
+#include <qptrlist.h>
+#include <qlistbox.h>
+#include <qfile.h>
+#include <qpushbutton.h>
+#include <qtextstream.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qmultilineedit.h>
+#include <qcombobox.h>
+#include <qwhatsthis.h>
+#include <qtextview.h>
+#include <qtextcodec.h>
+#include <qregexp.h>
+
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+
+#include "kpilotConfig.h"
+#include "listItems.h"
+#include "addressEditor.h"
+#include "pilotLocalDatabase.h"
+
+#include "addressWidget.moc"
+
+
+AddressWidget::AddressWidget(QWidget * parent,
+ const QString & path) :
+ PilotComponent(parent, "component_address", path),
+ fAddrInfo(0L),
+ fAddressAppInfo(0L),
+ fPendingAddresses(0)
+{
+ FUNCTIONSETUP;
+
+ setupWidget();
+ fAddressList.setAutoDelete(true);
+}
+
+AddressWidget::~AddressWidget()
+{
+ FUNCTIONSETUP;
+}
+
+int AddressWidget::getAllAddresses(PilotDatabase * addressDB)
+{
+ FUNCTIONSETUP;
+
+ int currentRecord = 0;
+ PilotRecord *pilotRec;
+ PilotAddress *address;
+
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Reading AddressDB..." << endl;
+#endif
+
+ while ((pilotRec = addressDB->readRecordByIndex(currentRecord)) != 0L)
+ {
+ if (!(pilotRec->isDeleted()) &&
+ (!(pilotRec->isSecret()) || KPilotSettings::showSecrets()))
+ {
+ address = new PilotAddress(pilotRec);
+ if (address == 0L)
+ {
+ WARNINGKPILOT << "Couldn't allocate record "
+ << currentRecord++
+ << endl;
+ break;
+ }
+ fAddressList.append(address);
+ }
+ delete pilotRec;
+
+ currentRecord++;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Total " << currentRecord << " records" << endl;
+#endif
+
+ return currentRecord;
+}
+
+void AddressWidget::showComponent()
+{
+ FUNCTIONSETUP;
+ if ( fPendingAddresses>0 ) return;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Reading from directory " << dbPath() << endl;
+#endif
+
+ PilotDatabase *addressDB =
+ new PilotLocalDatabase(dbPath(), CSL1("AddressDB"));
+
+ fAddressList.clear();
+
+ if (addressDB->isOpen())
+ {
+ KPILOT_DELETE(fAddressAppInfo);
+ fAddressAppInfo = new PilotAddressInfo(addressDB);
+ populateCategories(fCatList, fAddressAppInfo->categoryInfo());
+ getAllAddresses(addressDB);
+
+ }
+ else
+ {
+ populateCategories(fCatList, 0L);
+ WARNINGKPILOT << "Could not open local AddressDB" << endl;
+ }
+
+ KPILOT_DELETE( addressDB );
+
+ updateWidget();
+}
+
+void AddressWidget::hideComponent()
+{
+ FUNCTIONSETUP;
+ if (fPendingAddresses==0 )
+ {
+ fAddressList.clear();
+ fListBox->clear();
+
+ updateWidget();
+ }
+}
+
+/* virtual */ bool AddressWidget::preHotSync(QString &s)
+{
+ FUNCTIONSETUP;
+
+ if ( fPendingAddresses )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": fPendingAddress="
+ << fPendingAddresses
+ << endl;
+#endif
+
+#if KDE_VERSION<220
+ s = i18n("There are still %1 address editing windows open.")
+ .arg(QString::number(fPendingAddresses));
+#else
+ s = i18n("There is still an address editing window open.",
+ "There are still %n address editing windows open.",
+ fPendingAddresses);
+#endif
+ return false;
+ }
+
+ return true;
+}
+
+void AddressWidget::postHotSync()
+{
+ FUNCTIONSETUP;
+
+ if ( shown )
+ {
+ fAddressList.clear();
+ showComponent();
+ }
+}
+
+
+void AddressWidget::setupWidget()
+{
+ FUNCTIONSETUP;
+
+ QLabel *label;
+ QGridLayout *grid = new QGridLayout(this, 6, 4, SPACING);
+
+ fCatList = new QComboBox(this);
+ grid->addWidget(fCatList, 0, 1);
+ connect(fCatList, SIGNAL(activated(int)),
+ this, SLOT(slotSetCategory(int)));
+ QWhatsThis::add(fCatList,
+ i18n("<qt>Select the category of addresses to display here.</qt>"));
+
+ label = new QLabel(i18n("Category:"), this);
+ label->setBuddy(fCatList);
+ grid->addWidget(label, 0, 0);
+
+ fListBox = new QListBox(this);
+ grid->addMultiCellWidget(fListBox, 1, 1, 0, 1);
+ connect(fListBox, SIGNAL(highlighted(int)),
+ this, SLOT(slotShowAddress(int)));
+ connect(fListBox, SIGNAL(selected(int)),
+ this, SLOT(slotEditRecord()));
+ QWhatsThis::add(fListBox,
+ i18n("<qt>This list displays all the addresses "
+ "in the selected category. Click on "
+ "one to display it to the right.</qt>"));
+
+ label = new QLabel(i18n("Address info:"), this);
+ grid->addWidget(label, 0, 2);
+
+ // address info text view
+ fAddrInfo = new QTextView(this);
+ grid->addMultiCellWidget(fAddrInfo, 1, 4, 2, 2);
+
+ QPushButton *button;
+ QString wt;
+
+ fEditButton = new QPushButton(i18n("Edit Record..."), this);
+ grid->addWidget(fEditButton, 2, 0);
+ connect(fEditButton, SIGNAL(clicked()), this, SLOT(slotEditRecord()));
+ wt = KPilotSettings::internalEditors() ?
+ i18n("<qt>You can edit an address when it is selected.</qt>") :
+ i18n("<qt><i>Editing is disabled by the 'internal editors' setting.</i></qt>");
+ QWhatsThis::add(fEditButton,wt);
+
+ button = new QPushButton(i18n("New Record..."), this);
+ grid->addWidget(button, 2, 1);
+ connect(button, SIGNAL(clicked()), this, SLOT(slotCreateNewRecord()));
+ wt = KPilotSettings::internalEditors() ?
+ i18n("<qt>Add a new address to the address book.</qt>") :
+ i18n("<qt><i>Adding is disabled by the 'internal editors' setting.</i></qt>") ;
+ QWhatsThis::add(button, wt);
+ button->setEnabled(KPilotSettings::internalEditors());
+
+
+ fDeleteButton = new QPushButton(i18n("Delete Record"), this);
+ grid->addWidget(fDeleteButton, 3, 0);
+ connect(fDeleteButton, SIGNAL(clicked()),
+ this, SLOT(slotDeleteRecord()));
+ wt = KPilotSettings::internalEditors() ?
+ i18n("<qt>Delete the selected address from the address book.</qt>") :
+ i18n("<qt><i>Deleting is disabled by the 'internal editors' setting.</i></qt>") ;
+
+ button = new QPushButton(i18n("Export addresses to file","Export..."), this);
+ grid->addWidget(button, 3,1);
+ connect(button, SIGNAL(clicked()), this, SLOT(slotExport()));
+ QWhatsThis::add(button,
+ i18n("<qt>Export all addresses in the selected category to CSV format.</qt>") );
+
+ QWhatsThis::add(fDeleteButton,wt);
+}
+
+void AddressWidget::updateWidget()
+{
+ FUNCTIONSETUP;
+
+ if( !fAddressAppInfo )
+ return;
+ int addressDisplayMode = KPilotSettings::addressDisplayMode();
+
+ int listIndex = 0;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Display Mode=" << addressDisplayMode << endl;
+#endif
+
+ int currentCatID = findSelectedCategory(fCatList,
+ fAddressAppInfo->categoryInfo());
+
+ fListBox->clear();
+ fAddressList.first();
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Adding records..." << endl;
+#endif
+
+ while (fAddressList.current())
+ {
+ if ((currentCatID == -1) ||
+ (fAddressList.current()->category() == currentCatID))
+ {
+ QString title = createTitle(fAddressList.current(),
+ addressDisplayMode);
+
+ if (!title.isEmpty())
+ {
+ title.remove(QRegExp(CSL1("\n.*")));
+ PilotListItem *p = new PilotListItem(title,
+ listIndex,
+ fAddressList.current());
+
+ fListBox->insertItem(p);
+ }
+ }
+ listIndex++;
+ fAddressList.next();
+ }
+
+ fListBox->sort();
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": " << listIndex << " records" << endl;
+#endif
+
+ slotUpdateButtons();
+}
+
+
+
+QString AddressWidget::createTitle(PilotAddress * address, int displayMode)
+{
+ // FUNCTIONSETUP;
+
+ QString title;
+
+ switch (displayMode)
+ {
+ case 1:
+ if (!address->getField(entryCompany).isEmpty())
+ {
+ title.append(address->getField(entryCompany));
+ }
+ if (!address->getField(entryLastname).isEmpty())
+ {
+ if (!title.isEmpty())
+ {
+ title.append( CSL1(", "));
+ }
+
+ title.append(address->getField(entryLastname));
+ }
+ break;
+ case 0:
+ default:
+ if (!address->getField(entryLastname).isEmpty())
+ {
+ title.append(address->getField(entryLastname));
+ }
+
+ if (!address->getField(entryFirstname).isEmpty())
+ {
+ if (!title.isEmpty())
+ {
+ title.append( CSL1(", "));
+ }
+ title.append(address->getField(entryFirstname));
+ }
+ break;
+ }
+
+ if (title.isEmpty()) // One last try
+ {
+ if (!fAddressList.current()->getField(entryCompany).isEmpty())
+ {
+ title.append(fAddressList.current()->
+ getField(entryCompany));
+ }
+ if (title.isEmpty())
+ {
+ title = i18n("[unknown]");
+ }
+ }
+
+ return title;
+}
+
+
+/* slot */ void AddressWidget::slotUpdateButtons()
+{
+ FUNCTIONSETUP;
+
+ bool enabled = (fListBox->currentItem() != -1);
+
+ enabled &= KPilotSettings::internalEditors();
+ fEditButton->setEnabled(enabled);
+ fDeleteButton->setEnabled(enabled);
+}
+
+void AddressWidget::slotSetCategory(int)
+{
+ FUNCTIONSETUP;
+
+ updateWidget();
+}
+
+void AddressWidget::slotEditRecord()
+{
+ FUNCTIONSETUP;
+ if ( !shown ) return;
+
+ int item = fListBox->currentItem();
+
+ if (item == -1)
+ return;
+
+ PilotListItem *p = (PilotListItem *) fListBox->item(item);
+ PilotAddress *selectedRecord = (PilotAddress *) p->rec();
+
+ if (selectedRecord->id() == 0)
+ {
+ KMessageBox::error(0L,
+ i18n("Cannot edit new records until "
+ "HotSynced with Pilot."),
+ i18n("HotSync Required"));
+ return;
+ }
+
+ AddressEditor *editor = new AddressEditor(selectedRecord,
+ fAddressAppInfo, this);
+
+ connect(editor, SIGNAL(recordChangeComplete(PilotAddress *)),
+ this, SLOT(slotUpdateRecord(PilotAddress *)));
+ connect(editor, SIGNAL(cancelClicked()),
+ this, SLOT(slotEditCancelled()));
+ editor->show();
+
+ fPendingAddresses++;
+}
+
+void AddressWidget::slotCreateNewRecord()
+{
+ FUNCTIONSETUP;
+ if ( !shown ) return;
+
+ // Response to bug 18072: Don't even try to
+ // add records to an empty or unopened database,
+ // since we don't have the DBInfo stuff to deal with it.
+ //
+ //
+ PilotDatabase *myDB = new PilotLocalDatabase(dbPath(), CSL1("AddressDB"));
+
+ if (!myDB || !myDB->isOpen())
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Tried to open "
+ << dbPath()
+ << "/AddressDB"
+ << " and got pointer @"
+ << (long) myDB
+ << " with status "
+ << ( myDB ? myDB->isOpen() : false )
+ << endl;
+#endif
+
+ KMessageBox::sorry(this,
+ i18n("You cannot add addresses to the address book "
+ "until you have done a HotSync at least once "
+ "to retrieve the database layout from your Pilot."),
+ i18n("Cannot Add New Address"));
+
+ if (myDB)
+ KPILOT_DELETE( myDB );
+
+ return;
+ }
+
+ AddressEditor *editor = new AddressEditor(0L,
+ fAddressAppInfo, this);
+
+ connect(editor, SIGNAL(recordChangeComplete(PilotAddress *)),
+ this, SLOT(slotAddRecord(PilotAddress *)));
+ connect(editor, SIGNAL(cancelClicked()),
+ this, SLOT(slotEditCancelled()));
+ editor->show();
+
+ fPendingAddresses++;
+}
+
+void AddressWidget::slotAddRecord(PilotAddress * address)
+{
+ FUNCTIONSETUP;
+ if ( !shown && fPendingAddresses==0 ) return;
+
+ int currentCatID = findSelectedCategory(fCatList,
+ fAddressAppInfo->categoryInfo(), true);
+
+
+ address->PilotRecordBase::setCategory(currentCatID);
+ fAddressList.append(address);
+ writeAddress(address);
+ // TODO: Just add the new record to the lists
+ updateWidget();
+
+ // k holds the item number of the address just added.
+ //
+ //
+ int k = fListBox->count() - 1;
+
+ fListBox->setCurrentItem(k); // Show the newest one
+ fListBox->setBottomItem(k);
+
+ fPendingAddresses--;
+ if ( !shown && fPendingAddresses==0 ) hideComponent();
+}
+
+void AddressWidget::slotUpdateRecord(PilotAddress * address)
+{
+ FUNCTIONSETUP;
+ if ( !shown && fPendingAddresses==0 ) return;
+
+ writeAddress(address);
+ int currentRecord = fListBox->currentItem();
+
+ // TODO: Just change the record
+ updateWidget();
+ fListBox->setCurrentItem(currentRecord);
+
+ emit(recordChanged(address));
+
+ fPendingAddresses--;
+ if ( !shown && fPendingAddresses==0 ) hideComponent();
+}
+
+void AddressWidget::slotEditCancelled()
+{
+ FUNCTIONSETUP;
+
+ fPendingAddresses--;
+ if ( !shown && fPendingAddresses==0 ) hideComponent();
+}
+
+void AddressWidget::slotDeleteRecord()
+{
+ FUNCTIONSETUP;
+ if ( !shown ) return;
+
+ int item = fListBox->currentItem();
+
+ if (item == -1)
+ return;
+
+ PilotListItem *p = (PilotListItem *) fListBox->item(item);
+ PilotAddress *selectedRecord = (PilotAddress *) p->rec();
+
+ if (selectedRecord->id() == 0)
+ {
+ KMessageBox::error(this,
+ i18n("New records cannot be deleted until "
+ "HotSynced with pilot."),
+ i18n("HotSync Required"));
+ return;
+ }
+
+ if (KMessageBox::questionYesNo(this,
+ i18n("Delete currently selected record?"),
+ i18n("Delete Record?"), KStdGuiItem::del(), KStdGuiItem::cancel()) == KMessageBox::No)
+ return;
+
+ selectedRecord->setDeleted( true );
+ writeAddress(selectedRecord);
+ emit(recordChanged(selectedRecord));
+ showComponent();
+}
+
+
+
+void AddressWidget::slotShowAddress(int which)
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ PilotListItem *p = (PilotListItem *) fListBox->item(which);
+ PilotAddress *addr = (PilotAddress *) p->rec();
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Showing "
+ << addr->getField(entryLastname)
+ << " "
+ << addr->getField(entryFirstname)
+ << endl;
+#endif
+
+ QString text(CSL1("<qt>"));
+ text += addr->getTextRepresentation(fAddressAppInfo,Qt::RichText);
+ text += CSL1("</qt>\n");
+ fAddrInfo->setText(text);
+
+ slotUpdateButtons();
+}
+
+
+
+void AddressWidget::writeAddress(PilotAddress * which,
+ PilotDatabase * addressDB)
+{
+ FUNCTIONSETUP;
+
+ // Open a database (myDB) only if needed,
+ // i.e. only if the passed-in addressDB
+ // isn't valid.
+ //
+ //
+ PilotDatabase *myDB = addressDB;
+ bool usemyDB = false;
+
+ if (myDB == 0L || !myDB->isOpen())
+ {
+ myDB = new PilotLocalDatabase(dbPath(), CSL1("AddressDB"));
+ usemyDB = true;
+ }
+
+ // Still no valid address database...
+ //
+ //
+ if (!myDB->isOpen())
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Address database is not open" <<
+ endl;
+#endif
+ return;
+ }
+
+
+ // Do the actual work.
+ PilotRecord *pilotRec = which->pack();
+
+ myDB->writeRecord(pilotRec);
+ markDBDirty(CSL1("AddressDB"));
+ delete pilotRec;
+
+ // Clean up in the case that we allocated our own DB.
+ //
+ //
+ if (usemyDB)
+ {
+ KPILOT_DELETE( myDB );
+ }
+}
+
+#define plu_quiet 1
+#include "pilot-addresses.c"
+
+void AddressWidget::slotExport()
+{
+ FUNCTIONSETUP;
+ if( !fAddressAppInfo ) return;
+ int currentCatID = findSelectedCategory(fCatList,
+ fAddressAppInfo->categoryInfo());
+
+ QString prompt = (currentCatID==-1) ?
+ i18n("Export All Addresses") :
+ i18n("Export Address Category %1").arg(fAddressAppInfo->categoryName(currentCatID)) ;
+
+
+ QString saveFile = KFileDialog::getSaveFileName(
+ QString::null,
+ CSL1("*.csv|Comma Separated Values"),
+ this,
+ prompt
+ );
+ if (saveFile.isEmpty())
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": No save file selected." << endl;
+#endif
+ return;
+ }
+ if (QFile::exists(saveFile) &&
+ KMessageBox::warningContinueCancel(this,
+ i18n("The file <i>%1</i> exists. Overwrite?").arg(saveFile),
+ i18n("Overwrite File?"),
+ i18n("Overwrite"))!=KMessageBox::Continue)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Overwrite file canceled." << endl;
+#endif
+ return;
+ }
+
+ FILE *f = fopen(QFile::encodeName(saveFile),"w");
+ if (!f)
+ {
+ KMessageBox::sorry(this,
+ i18n("The file <i>%1</i> could not be opened for writing.").arg(saveFile));
+ return;
+ }
+ fAddressList.first();
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Adding records..." << endl;
+#endif
+
+ while (fAddressList.current())
+ {
+ const PilotAddress *a = fAddressList.current();
+ if ((currentCatID == -1) ||
+ (a->category() == currentCatID))
+ {
+ write_record_CSV(f, fAddressAppInfo->info(), a->address(),
+ a->attributes(), a->category(), 0);
+ }
+ fAddressList.next();
+ }
+
+ fclose(f);
+}
+
diff --git a/kpilot/kpilot/addressWidget.h b/kpilot/kpilot/addressWidget.h
new file mode 100644
index 000000000..289b49e33
--- /dev/null
+++ b/kpilot/kpilot/addressWidget.h
@@ -0,0 +1,144 @@
+/* addressWidget.h KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003 Reinhold Kainhofer <[email protected]>
+**
+** This file defines the address-viewing widget used in KPilot
+** to display the Pilot's address records.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+#ifndef _KPILOT_ADDRESSWIDGET_H
+#define _KPILOT_ADDRESSWIDGET_H
+
+class QMultiLineEdit;
+class QListBox;
+class QComboBox;
+class QTextView;
+
+class PilotDatabase;
+
+
+#include "pilotComponent.h"
+#include "pilotAddress.h"
+
+class AddressWidget : public PilotComponent
+{
+Q_OBJECT
+
+public:
+ AddressWidget(QWidget* parent,const QString& dbpath);
+ ~AddressWidget();
+
+ // Pilot Component Methods:
+ virtual void showComponent();
+ virtual void hideComponent();
+ virtual bool preHotSync(QString &);
+ virtual void postHotSync();
+
+public slots:
+ /**
+ * Called when a particular address is selected. This slot displays
+ * it in the viewer widget.
+ */
+ void slotShowAddress(int);
+ void slotEditRecord();
+ void slotCreateNewRecord();
+ void slotDeleteRecord();
+ void slotEditCancelled();
+ void slotExport();
+
+ void slotUpdateButtons(); // Enable/disable buttons
+
+signals:
+ void recordChanged(PilotAddress *);
+
+protected slots:
+ /**
+ * When an edit window is closed, the corresponding record
+ * is updated and possibly re-displayed.
+ */
+ void slotUpdateRecord(PilotAddress*);
+
+ /**
+ * Pop up an edit window for a new record.
+ */
+ void slotAddRecord(PilotAddress*);
+
+ /**
+ * Change category. This means that the display should be
+ * cleared and that the list should be repopulated.
+ */
+ void slotSetCategory(int);
+
+private:
+ void setupWidget();
+ void updateWidget(); // Called with the lists have changed..
+ void writeAddress(PilotAddress* which,PilotDatabase *db=0L);
+
+ /**
+ * getAllAddresses reads the database and places all
+ * the addresses from the database in the list
+ * in memory --- not the list on the screen.
+ * @see fAddressList
+ */
+ int getAllAddresses(PilotDatabase *addressDB);
+
+ /**
+ * Create a sensible "title" for an address, composed
+ * of first + last name if possible.
+ */
+ QString createTitle(PilotAddress *,int displayMode);
+
+ /**
+ * We use a QComboBox fCatList to hold the user-visible names
+ * of all the categories. The QTextView fAddrInfo is for
+ * displaying the currently selected address, if any.
+ * The QListBox fListBox lists all the addresses in the
+ * currently selected category.
+ *
+ * The entire address database is read into memory in the
+ * QList fAddressList. We need the appinfo block from the
+ * database to determine which categories there are; this
+ * is held in fAddressAppInfo.
+ *
+ * The two buttons should speak for themselves.
+ */
+ QComboBox *fCatList;
+ QTextView *fAddrInfo;
+ PilotAddressInfo *fAddressAppInfo;
+ QPtrList<PilotAddress> fAddressList;
+ QListBox *fListBox;
+ QPushButton *fEditButton,*fDeleteButton;
+
+protected:
+ /**
+ * Keep track of how many open address editing windows there
+ * are. You can't sync when there are open windows.
+ */
+ int fPendingAddresses;
+
+public:
+ typedef enum { PhoneNumberLength=16 } Constants ;
+};
+
+#endif
diff --git a/kpilot/kpilot/conduitConfigDialog.cc b/kpilot/kpilot/conduitConfigDialog.cc
new file mode 100644
index 000000000..6e4f0fc94
--- /dev/null
+++ b/kpilot/kpilot/conduitConfigDialog.cc
@@ -0,0 +1,849 @@
+/* KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2002-2004 by Adriaan de Groot
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines a .ui-based configuration dialog for conduits.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qlistview.h>
+#include <qlabel.h>
+#include <qtooltip.h>
+#include <qfile.h>
+#include <qpushbutton.h>
+#include <qhbox.h>
+#include <qlayout.h>
+#include <qwidgetstack.h>
+#include <qvbox.h>
+#include <qsplitter.h>
+#include <qheader.h>
+#include <qtimer.h>
+
+#include <kservice.h>
+#include <kservicetype.h>
+#include <kuserprofile.h>
+#include <kprocess.h>
+#include <kmessagebox.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <klibloader.h>
+#include <kseparator.h>
+#include <kconfigskeleton.h>
+#include <kdialogbase.h>
+
+#include "plugin.h"
+#include "kpilotConfig.h"
+#include "kpilotConfigDialog.h"
+
+#include "kpilotConfigWizard.h"
+
+#include "conduitConfigDialog.moc"
+
+#define CONDUIT_NAME (0)
+#define CONDUIT_COMMENT (1)
+#define CONDUIT_DESKTOP (2)
+#define CONDUIT_LIBRARY (3)
+#define CONDUIT_ORDER (4)
+
+
+extern "C"
+{
+ KDE_EXPORT KCModule *create_kpilotconfig( QWidget *parent, const char * )
+ {
+ FUNCTIONSETUP;
+ return new ConduitConfigWidget( parent, "kcmkpilotconfig" );
+ }
+
+ KDE_EXPORT ConfigWizard *create_wizard(QWidget *parent, int m)
+ {
+ FUNCTIONSETUP;
+ return new ConfigWizard(parent,"Wizard", m);
+ }
+}
+
+
+class ConduitTip : public QToolTip
+{
+public:
+ ConduitTip(QListView *parent);
+ virtual ~ConduitTip();
+
+protected:
+ virtual void maybeTip(const QPoint &);
+
+ QListView *fListView;
+} ;
+
+
+ConduitTip::ConduitTip(QListView *p) :
+ QToolTip(p->viewport(),0L),
+ fListView(p)
+{
+ FUNCTIONSETUP;
+}
+
+ConduitTip::~ConduitTip()
+{
+ FUNCTIONSETUP;
+}
+
+/* virtual */ void ConduitTip::maybeTip(const QPoint &p)
+{
+ FUNCTIONSETUP;
+
+ QListViewItem *l = fListView->itemAt(p);
+
+ if (!l) return;
+
+ // ConduitListItem *q = static_cast<ConduitListItem *>(l);
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Tip over "
+ << l->text(CONDUIT_NAME)
+ << " with text "
+ << l->text(CONDUIT_COMMENT)
+ << endl;
+#endif
+
+ QString s = l->text(CONDUIT_COMMENT);
+
+ if (s.isEmpty()) return;
+ if (s.find(CSL1("<qt>"),0,false) == -1)
+ {
+ s.prepend(CSL1("<qt>"));
+ s.append(CSL1("</qt>"));
+ }
+
+ tip(fListView->itemRect(l),s);
+}
+
+// implement our own check list items so we can detect if a given item was checked/unchecked. We need
+// this to prevent the modified signal if one only wants to display a conduit's config widget. Currently,
+// KListView doesn't provide any signal that indicates that the checked state of a checklist item was changed.
+class KPilotCheckListItem : public QCheckListItem
+{
+public:
+ KPilotCheckListItem ( QListViewItem * parent, const QString & text, Type tt = RadioButtonController ) : QCheckListItem(parent, text, tt),mOriginalState(false) {}
+ ~KPilotCheckListItem() {}
+
+ void setOriginalState(bool state) { mOriginalState=state; setOn(state);}
+ bool isOriginalState() { return isOn() == mOriginalState; }
+
+protected:
+ bool mOriginalState;
+};
+
+
+// Page numbers in the widget stack
+#define OLD_CONDUIT (1)
+#define BROKEN_CONDUIT (2)
+#define INTERNAL_CONDUIT (3)
+#define INTERNAL_EXPLN (4)
+#define CONDUIT_EXPLN (5)
+#define GENERAL_EXPLN (6)
+#define GENERAL_ABOUT (7)
+#define NEW_CONDUIT (8)
+
+
+/*
+** Create a page in the widget stack @p parent on page @p pageno,
+** bearing the given @p text. The remainder of the parameters are
+** for esoteric things like:
+** @p buttons set to non-null to include (and return) a QHBox suitable
+** for displaying a row of buttons in on the page.
+** @p label set to non-null to return the QLabel used to display @p text.
+*/
+static void addDescriptionPage(QWidgetStack *parent,
+ int pageno,
+ const QString &text,
+ QHBox **buttons = 0L,
+ QLabel **label = 0L)
+{
+ QVBox *v = new QVBox(parent);
+ QLabel *l = 0L;
+
+ v->setFrameShape(QLabel::NoFrame);
+ v->setMargin(SPACING);
+
+ l = new QLabel(v);
+ l->setText(text);
+ l->setAlignment(Qt::AlignLeft | Qt::AlignVCenter | Qt::ExpandTabs | Qt::WordBreak);
+
+ if (label) { *label = l; }
+
+ if (buttons)
+ {
+ *buttons = new QHBox(v);
+ l = new QLabel(v);
+ }
+
+ parent->addWidget(v,pageno);
+}
+
+
+ConduitConfigWidgetBase::ConduitConfigWidgetBase(QWidget *parent, const char *n) :
+ KCModule(parent, n),
+ fConduitList(0L),
+ fStack(0L),
+ fConfigureButton(0L),
+ fConfigureWizard(0L),
+ fConfigureKontact(0L),
+ fActionDescription(0L)
+{
+ FUNCTIONSETUP;
+
+ QWidget *w = 0L; // For spacing purposes only.
+ QHBox *btns = 0L;
+
+ QHBoxLayout *mainLayout = new QHBoxLayout(this);
+ mainLayout->setSpacing(10);
+
+ // Create the left hand column
+ fConduitList = new QListView(this ,"ConduitList");
+ fConduitList->addColumn(QString::null);
+ fConduitList->header()->hide();
+ fConduitList->setSizePolicy(
+ QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred));
+ mainLayout->addWidget(fConduitList);
+
+ // Create the title
+ QVBoxLayout *vbox = new QVBoxLayout(this, 0, KDialog::spacingHint());
+ // String below is just to make space; no need to translate.
+ fTitleText = new QLabel(CSL1("Conduit Setup - Addressbook"), this);
+ QFont titleFont(fTitleText->font());
+ titleFont.setBold(true);
+ fTitleText->setFont(titleFont);
+ vbox->addWidget(fTitleText, 0, AlignLeft);
+ vbox->addWidget(new KSeparator(QFrame::HLine|QFrame::Plain, this));
+
+ // Right hand column
+ fStack = new QWidgetStack(this, "RightPart");
+ vbox->addWidget(fStack, 10);
+
+ mainLayout->addLayout(vbox);
+
+ // First page in stack (right hand column)
+ addDescriptionPage(fStack,BROKEN_CONDUIT,
+ i18n("<qt>This conduit appears to be broken and cannot "
+ "be configured.</qt>"));
+
+ // Second page, now with layout in a single column
+ //
+ // Probably deprecated.
+ //
+ addDescriptionPage(fStack,OLD_CONDUIT,
+ i18n("<qt>This is an old-style conduit.</qt>"),&btns);
+ w = new QWidget(btns);
+ btns->setStretchFactor(w,50);
+ fConfigureButton = new QPushButton(btns);
+ fConfigureButton->setText(i18n("Configure..."));
+ w = new QWidget(btns);
+ btns->setStretchFactor(w,50);
+
+ // Page 3
+ addDescriptionPage(fStack,INTERNAL_CONDUIT,
+ QString::null,0L,&fActionDescription);
+
+ // Page 5 - explanation about conduits
+ addDescriptionPage(fStack,CONDUIT_EXPLN,
+ i18n("<qt><i>Conduits</i> are external (possibly third-party) "
+ "programs that perform synchronization actions. They may "
+ "have individual configurations. Select a conduit to configure it, "
+ "and enable it by clicking on its checkbox. "
+ "</qt>"));
+
+ // Page 6 - explanation about general setup
+ addDescriptionPage(fStack,GENERAL_EXPLN,
+ i18n("<qt><p>The <i>general</i> portion of KPilot's setup "
+ "contains settings for your hardware and the way KPilot "
+ "should display your data. For the basic setup, which should fulfill "
+ "the need of most users, just use the setup wizard below.</p>"
+ "If you need some special settings, this dialog provides all the options "
+ "for fine-tuning KPilot. But be warned: The HotSync settings are "
+ "various esoteric things.</p>"
+ "<p>You can enable an action or conduit by clicking on its checkbox. "
+ "Checked conduits will be run during a HotSync. "
+ "Select a conduit to configure it.</p>"
+ "</qt>"),&btns);
+ w = new QWidget(btns);
+ btns->setStretchFactor(w,50);
+ fConfigureWizard = new QPushButton(i18n("Configuration Wizard"),btns);
+ w = new QWidget(btns);
+ btns->setStretchFactor(w,50);
+
+
+ fStack->addWidget(ConduitConfigBase::aboutPage(fStack,0L),GENERAL_ABOUT);
+}
+
+ConduitConfigWidget::ConduitConfigWidget(QWidget *parent, const char *n,
+ bool) :
+ ConduitConfigWidgetBase(parent,n),
+ fConfigure(0L),
+ fCurrentConduit(0L),
+ fGeneralPage(0L),
+ fCurrentConfig(0L)
+{
+ FUNCTIONSETUP;
+
+ fConduitList->setSorting(-1);
+ fConduitList->setRootIsDecorated(true);
+ fConduitList->setTreeStepSize(10);
+ // fConduitList->removeColumn(CONDUIT_COMMENT);
+ fillLists();
+
+ fConduitList->resize(fConduitList->sizeHint());
+ fConduitList->setMinimumSize(fConduitList->sizeHint());
+ fConduitList->setColumnWidth(0, fConduitList->sizeHint().width());
+ fConduitList->setResizeMode(QListView::AllColumns);
+
+ fStack->resize(fStack->sizeHint()+QSize(10,40));
+ fStack->setMinimumSize(fStack->sizeHint()+QSize(10,40));
+
+ QObject::connect(fConduitList,
+ SIGNAL(selectionChanged(QListViewItem *)),
+ this,SLOT(selected(QListViewItem *)));
+ QObject::connect(fConduitList,
+ SIGNAL(clicked(QListViewItem*)),
+ this, SLOT(conduitsChanged(QListViewItem*)));
+
+ // Deprecated?
+ QObject::connect(fConfigureButton,
+ SIGNAL(clicked()),
+ this,SLOT(configure()));
+
+ QObject::connect(fConfigureWizard,SIGNAL(clicked()),
+ this,SLOT(configureWizard()));
+
+ fGeneralPage->setSelected(true);
+ fConduitList->setCurrentItem(fGeneralPage);
+ selected(fGeneralPage);
+
+ (void) new ConduitTip(fConduitList);
+ setButtons(Apply);
+
+}
+
+ConduitConfigWidget::~ConduitConfigWidget()
+{
+ FUNCTIONSETUP;
+ release();
+}
+
+void ConduitConfigWidget::fillLists()
+{
+ FUNCTIONSETUP;
+
+ // 3 QListViewItems for the three headings in the list
+ QListViewItem *general,*conduits;
+
+ // And two generic pointers for the rest.
+ QListViewItem *q = 0L;
+ KPilotCheckListItem *p = 0L;
+
+ q = new QListViewItem(fConduitList, i18n("About"));
+ q->setText(CONDUIT_COMMENT, i18n("About KPilot. Credits."));
+ q->setText(CONDUIT_LIBRARY, CSL1("general_about"));
+
+ conduits = new QListViewItem(fConduitList, i18n("Conduits"));
+
+ general = new QListViewItem( fConduitList, i18n("General Setup" ) );
+ fGeneralPage = general;
+
+ // Give them identifiers so they can be handled specially when selected.
+ conduits->setText(CONDUIT_LIBRARY,CSL1("expln_conduits"));
+ general->setText( CONDUIT_LIBRARY, CSL1("expln_general") );
+
+ general->setText( CONDUIT_COMMENT,
+ i18n("General setup of KPilot (User name, port, general sync settings)") );
+ conduits->setText( CONDUIT_COMMENT,
+ i18n("Actions for HotSync with individual configuration."));
+
+ conduits->setOpen(true);
+ general->setOpen(true);
+
+
+ // Create entries under general.
+#define CE(a,b,c) q = new QListViewItem(general,a) ; \
+ q->setText(CONDUIT_COMMENT,b) ; \
+ q->setText(CONDUIT_LIBRARY,c) ;
+
+ CE(i18n("Startup and Exit"), i18n("Behavior at startup and exit."), CSL1("general_startexit") );
+ CE(i18n("Viewers"), i18n("Viewer settings."), CSL1("general_view") );
+ CE(i18n("Backup"),i18n("Special settings for backup."),CSL1("general_backup"));
+ CE(i18n("HotSync"),i18n("Special behavior during HotSync."),CSL1("general_sync"));
+ CE(i18n("Device"),i18n("Hardware settings and startup and exit options."),CSL1("general_setup"));
+
+#undef CE
+
+
+ // List of installed (enabled) actions and conduits.
+ QStringList potentiallyInstalled = KPilotSettings::installedConduits();
+
+ // Create internal conduits.
+ //
+ //
+
+#define IC(a,b,c) p = new KPilotCheckListItem(conduits,i18n(a),QCheckListItem::CheckBox); \
+ p->setText(CONDUIT_COMMENT,i18n(c)); \
+ p->setText(CONDUIT_LIBRARY,CSL1("internal_" b)); \
+ p->setText(CONDUIT_DESKTOP,CSL1("internal_" b)); \
+ if (potentiallyInstalled.findIndex(p->text(CONDUIT_DESKTOP))>=0) \
+ p->setOriginalState(true);
+
+ IC("Install Files","fileinstall",
+ "Install files that are dragged to KPilot onto the handheld.");
+#undef IC
+
+
+
+ KServiceTypeProfile::OfferList offers =
+ KServiceTypeProfile::offers(CSL1("KPilotConduit"));
+
+ QValueListIterator < KServiceOffer > availList(offers.begin());
+ while (availList != offers.end())
+ {
+ KSharedPtr < KService > o = (*availList).service();
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": "
+ << o->desktopEntryName()
+ << " = " << o->name() << endl;
+#endif
+
+ if (!o->exec().isEmpty())
+ {
+ WARNINGKPILOT << "Old-style conduit found "
+ << o->name()
+ << endl;
+ }
+
+ p = new KPilotCheckListItem(conduits,
+ o->name(),
+ QCheckListItem::CheckBox);
+ p->setMultiLinesEnabled(true);
+ p->setText(CONDUIT_COMMENT,o->comment());
+ p->setText(CONDUIT_DESKTOP,o->desktopEntryName());
+ p->setText(CONDUIT_LIBRARY,o->library());
+
+ if (potentiallyInstalled.findIndex(o->desktopEntryName()) < 0)
+ {
+ p->setOriginalState(false);
+ }
+ else
+ {
+ p->setOriginalState(true);
+ }
+
+ ++availList;
+ }
+}
+
+static void dumpConduitInfo(const KLibrary *lib)
+{
+#ifdef DEBUG
+ FUNCTIONSETUP;
+ DEBUGKPILOT << "Plugin version = " << PluginUtility::pluginVersion(lib) << endl;
+ DEBUGKPILOT << "Plugin id = " << PluginUtility::pluginVersionString(lib) << endl;
+#endif
+}
+
+static ConduitConfigBase *handleGeneralPages(QWidget *w, QListViewItem *p)
+{
+ ConduitConfigBase *o = 0L;
+
+ QString s = p->text(CONDUIT_LIBRARY) ;
+
+ if (s.startsWith(CSL1("general_setup")))
+ {
+ o = new DeviceConfigPage( w, "generalSetup" );
+ }
+ else if (s.startsWith(CSL1("general_sync")))
+ {
+ o = new SyncConfigPage( w, "syncSetup" );
+ }
+ else if (s.startsWith(CSL1("general_view")))
+ {
+ o = new ViewersConfigPage( w, "viewSetup" );
+ }
+ else if (s.startsWith(CSL1("general_startexit")))
+ {
+ o = new StartExitConfigPage(w,"startSetup");
+ }
+ else if (s.startsWith(CSL1("general_backup")))
+ {
+ o = new BackupConfigPage(w,"backupSetup");
+ }
+
+ return o;
+}
+
+void ConduitConfigWidget::loadAndConfigure(QListViewItem *p) // ,bool exec)
+{
+ FUNCTIONSETUP;
+
+ if (!p)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Executed NULL conduit?"
+ << endl;
+#endif
+ fStack->raiseWidget(GENERAL_EXPLN);
+ return;
+ }
+
+ QString libraryName = p->text(CONDUIT_LIBRARY);
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Executing conduit "
+ << p->text(CONDUIT_NAME)
+ << " (library " << libraryName << ")"
+ << endl;
+#endif
+
+
+ if (libraryName.isEmpty())
+ {
+ fStack->raiseWidget(BROKEN_CONDUIT);
+ warnNoExec(p);
+ return;
+ }
+
+ if (libraryName.startsWith(CSL1("internal_")))
+ {
+ fStack->raiseWidget(INTERNAL_CONDUIT);
+ fActionDescription->setText(
+ i18n("<qt>This is an internal action which has no "
+ "configuration options. "
+ "The action's description is: <i>%1</i> "
+ "</qt>").arg(p->text(CONDUIT_COMMENT)));
+ return;
+ }
+
+ if (libraryName == CSL1("expln_conduits"))
+ {
+ fStack->raiseWidget(CONDUIT_EXPLN);
+ return;
+ }
+ if (libraryName == CSL1("expln_general"))
+ {
+ fStack->raiseWidget(GENERAL_EXPLN);
+ return;
+ }
+
+ if (libraryName == CSL1("general_about"))
+ {
+ fStack->raiseWidget(GENERAL_ABOUT);
+ return;
+ }
+
+ QObject *o = 0L;
+
+ // Page 4: General setup
+ if (libraryName.startsWith(CSL1("general_")))
+ {
+ o = handleGeneralPages(fStack,p);
+ }
+ else
+ {
+ QCString library = QFile::encodeName(libraryName);
+
+ KLibFactory *f = KLibLoader::self()->factory(library);
+ if (!f)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": No conduit library "
+ << library.data()
+ << " [" << library.size() << "]"
+ << " (" << libraryName << ")"
+ << " found."
+ << endl;
+#endif
+ fStack->raiseWidget(BROKEN_CONDUIT);
+ warnNoLibrary(p);
+ return;
+ }
+
+ dumpConduitInfo(KLibLoader::self()->library(library));
+
+ QStringList a;
+ a.append(CSL1("modal"));
+
+ o = f->create(fStack, 0L, "ConduitConfigBase", a);
+
+ if (!o)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Can't create ConduitConfigBase - must be old conduit."
+ << endl;
+#endif
+
+ KLibLoader::self()->unloadLibrary(
+ library);
+ fStack->raiseWidget(BROKEN_CONDUIT);
+ warnNoLibrary(p);
+ return;
+ }
+ }
+
+ ConduitConfigBase *d = dynamic_cast<ConduitConfigBase *>(o);
+
+ if (!d)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Can't cast to config base object."
+ << endl;
+#endif
+ fStack->raiseWidget(BROKEN_CONDUIT);
+ warnNoLibrary(p);
+ return;
+ }
+
+ // Remove the config widget from the stack before we can add the new one
+ QWidget *oldConfigWidget = fStack->widget( NEW_CONDUIT );
+ if ( oldConfigWidget )
+ {
+ fStack->removeWidget( oldConfigWidget );
+ KPILOT_DELETE( oldConfigWidget );
+ }
+ if (fStack->addWidget(d->widget(),NEW_CONDUIT)<0)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Can't add config widget to stack."
+ << endl;
+#endif
+ }
+ else
+ {
+ d->load();
+ fStack->raiseWidget(NEW_CONDUIT);
+ d->widget()->show();
+ fCurrentConfig=d;
+ // make sure the changed signal is propagated to the KCM*Dialog
+ // and the apply button is enabled correspondingly.
+ connect(d, SIGNAL(changed(bool)), this, SIGNAL(changed(bool)));
+ }
+}
+
+bool ConduitConfigWidget::release()
+{
+ FUNCTIONSETUP;
+ if (fCurrentConfig)
+ {
+ if (!fCurrentConfig->maybeSave())
+ return false;
+ fStack->raiseWidget(0);
+ delete fCurrentConfig;
+ }
+ if (fCurrentConduit)
+ {
+ KLibLoader::self()->unloadLibrary(
+ QFile::encodeName(fCurrentConduit->text(CONDUIT_LIBRARY)));
+ }
+ fCurrentConduit=0L;
+ fCurrentConfig=0L;
+ return true;
+}
+
+void ConduitConfigWidget::unselect()
+{
+ fConduitList->setSelected( fCurrentConduit, true );
+ fConduitList->setCurrentItem( fCurrentConduit );
+}
+
+void ConduitConfigWidget::selected(QListViewItem *p)
+{
+ FUNCTIONSETUP;
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": "
+ << ( p ? p->text(CONDUIT_NAME) : CSL1("None") )
+ << endl;
+#endif
+ if (p!=fCurrentConduit)
+ {
+ if (!release())
+ {
+ fConduitList->blockSignals(true);
+ QTimer::singleShot(1,this,SLOT(unselect()));
+ return;
+ }
+ }
+ fCurrentConduit=p;
+ loadAndConfigure(p);
+// fStack->adjustSize();
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": New widget size "
+ << fStack->size().width() << "x" << fStack->size().height() << endl;
+ DEBUGKPILOT << fname << ": Current size "
+ << size().width() << "x"
+ << size().height() << endl;
+#endif
+ emit sizeChanged();
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": New size "
+ << size().width() << "x"
+ << size().height() << endl;
+#endif
+
+ // set the dialog title to the selected item
+ QListViewItem *pParent = p->parent();
+ QString title;
+ title = pParent ? pParent->text(CONDUIT_NAME) + CSL1(" - ") : QString() ;
+ title += p ? p->text(CONDUIT_NAME) : i18n("KPilot Setup");
+ fTitleText->setText(title);
+}
+
+void ConduitConfigWidget::configure()
+{
+ loadAndConfigure(fConduitList->selectedItem());
+}
+
+void ConduitConfigWidget::warnNoExec(const QListViewItem * p)
+{
+ FUNCTIONSETUP;
+
+ QString msg = i18n("<qt>No library could be "
+ "found for the conduit %1. This means that the "
+ "conduit was not installed properly.</qt>")
+ .arg(p->text(CONDUIT_NAME));
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": No library for "
+ << p->text(CONDUIT_NAME) << endl;
+#endif
+
+ KMessageBox::error(this, msg, i18n("Conduit Error"));
+}
+
+void ConduitConfigWidget::warnNoLibrary(const QListViewItem *p)
+{
+ FUNCTIONSETUP;
+
+ QString msg = i18n("<qt>There was a problem loading the library "
+ "for the conduit %1. This means that the "
+ "conduit was not installed properly.</qt>")
+ .arg(p->text(CONDUIT_NAME));
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Can't load library for "
+ << p->text(CONDUIT_NAME) << endl;
+#endif
+
+ KMessageBox::error(this, msg, i18n("Conduit Error"));
+}
+
+void ConduitConfigWidget::save()
+{
+ FUNCTIONSETUP;
+
+ // Only new-style conduits and the general setup have changes that need to be commited
+ // old-style conduits have their own config dlg which commits them itself
+ if ( fStack->id( fStack->visibleWidget())==NEW_CONDUIT )
+ {
+ if (fCurrentConfig) fCurrentConfig->commit();
+ }
+
+ QStringList activeConduits;
+ QListViewItemIterator it( fConduitList );
+ while ( it.current() ) {
+ KPilotCheckListItem*p = dynamic_cast<KPilotCheckListItem*>(it.current());
+ if ( p )
+ {
+ p->setOriginalState( p->isOn() );
+ if ( p->isOn() )
+ activeConduits.append(p->text(CONDUIT_DESKTOP));
+ }
+ ++it;
+ }
+ KPilotSettings::setInstalledConduits(activeConduits);
+ KPilotSettings::self()->writeConfig();
+}
+
+
+void ConduitConfigWidget::load()
+{
+ FUNCTIONSETUP;
+ KPilotSettings::self()->readConfig();
+
+ QStringList potentiallyInstalled = KPilotSettings::installedConduits();
+ QListViewItem*p = fConduitList->firstChild();
+ while (p)
+ {
+ QListViewItem*q = p->firstChild();
+ while (q)
+ {
+ QCheckListItem*qq=dynamic_cast<QCheckListItem*>(q);
+ if (qq)
+ {
+ qq->setOn(! (potentiallyInstalled.findIndex(qq->text(CONDUIT_DESKTOP))<0) );
+ }
+ q = q->nextSibling();
+ }
+ p=p->nextSibling();
+ }
+
+
+ // Only new-style conduits and the general setup have changes that need to be commited
+ // old-style conduits have their own config dlg which commits them itself
+ if ( fStack->id( fStack->visibleWidget())==NEW_CONDUIT )
+ {
+ if (fCurrentConfig) fCurrentConfig->load();
+ }
+}
+
+
+void ConduitConfigWidget::conduitsChanged(QListViewItem*item)
+{
+ KPilotCheckListItem*i=dynamic_cast<KPilotCheckListItem*>(item);
+ if (i)
+ {
+ if (!i->isOriginalState()) emit changed(true);
+ }
+}
+
+void ConduitConfigWidget::reopenItem(QListViewItem *i)
+{
+ i->setOpen(true);
+}
+
+void ConduitConfigWidget::configureWizard()
+{
+ FUNCTIONSETUP;
+ ConfigWizard wiz(this, "Wizard");
+ if (wiz.exec()) {
+ KPilotSettings::self()->readConfig();
+ load();
+ }
+}
+
+
diff --git a/kpilot/kpilot/conduitConfigDialog.h b/kpilot/kpilot/conduitConfigDialog.h
new file mode 100644
index 000000000..697251fab
--- /dev/null
+++ b/kpilot/kpilot/conduitConfigDialog.h
@@ -0,0 +1,112 @@
+#ifndef _KPILOT_CONDUITCONFIGDIALOG_H
+#define _KPILOT_CONDUITCONFIGDIALOG_H
+/* conduitConfigDialog.h KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines a dialog that uses the .ui-defined widget for
+** configuring conduits.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+// #include "conduitConfigDialog_base.h"
+#include "kcmodule.h"
+
+class QListView;
+class QListViewItem;
+class QPushButton;
+class QLabel;
+class QWidgetStack;
+class KProcess;
+class ConduitConfigBase;
+class ConduitConfig;
+
+class ConduitConfigWidgetBase : public KCModule
+{
+Q_OBJECT
+public:
+ ConduitConfigWidgetBase(QWidget *p=0L,const char *n=0L);
+
+ QListView *fConduitList;
+ QWidgetStack *fStack;
+ QPushButton *fConfigureButton;
+ QPushButton *fConfigureWizard,*fConfigureKontact;
+ QLabel *fActionDescription;
+ QLabel *fTitleText; // Dialog title above fStack
+} ;
+
+class ConduitConfigWidget : public ConduitConfigWidgetBase
+{
+Q_OBJECT
+public:
+ ConduitConfigWidget(QWidget *,
+ const char *name=0L, bool ownButtons=false);
+ virtual ~ConduitConfigWidget();
+
+protected:
+ void fillLists();
+
+ void warnNoExec(const QListViewItem *);
+ void warnNoLibrary(const QListViewItem *);
+
+ void loadAndConfigure(QListViewItem *); // ,bool);
+
+public:
+ /**
+ * Get rid of the current conduit configuration widget,
+ * saving changes if necessary. Returns false if the user
+ * selects cancel for the action that is supposed to
+ * release the conduit (ie. selecting a different one,
+ * or closing the dialog.)
+ */
+ bool release();
+ bool validate() {return release(); }
+
+public slots:
+ virtual void save();
+ virtual void load();
+// void slotOk();
+// void slotApply();
+
+signals:
+ void selectionChanged(QListViewItem *);
+ void sizeChanged();
+
+protected slots:
+ void configure();
+ void configureWizard();
+
+ void unselect(); // Helper slot when cancelling a change in selection
+ void selected(QListViewItem *);
+ void conduitsChanged(QListViewItem*);
+ void reopenItem(QListViewItem *);
+
+private:
+ QPushButton *fConfigure;
+ QListViewItem *fCurrentConduit;
+ QListViewItem *fGeneralPage;
+ ConduitConfigBase *fCurrentConfig;
+};
+
+#endif
diff --git a/kpilot/kpilot/datebookWidget.cc b/kpilot/kpilot/datebookWidget.cc
new file mode 100644
index 000000000..64888560c
--- /dev/null
+++ b/kpilot/kpilot/datebookWidget.cc
@@ -0,0 +1,133 @@
+/* KPilot
+**
+** Copyright (C) 2003 by Dan Pilone.
+** Authored by Adriaan de Groot
+**
+** This is the viewer for datebook data.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "options.h"
+
+
+#include <qlayout.h>
+#include <qdir.h>
+#include <qpushbutton.h>
+
+#include <klistview.h>
+#include <kdatepicker.h>
+#include <kmessagebox.h>
+
+#include "datebookWidget.moc"
+
+DatebookWidget::DatebookWidget(QWidget *parent, const QString &dbpath) :
+ PilotComponent(parent,"component_generic",dbpath)
+{
+ FUNCTIONSETUP;
+
+ QGridLayout *g = new QGridLayout(this,1,1,SPACING);
+
+ fDatePicker = new KDatePicker( this, "fDatePicker" );
+ fDatePicker->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)4, (QSizePolicy::SizeType)5, 0, 0, fDatePicker->sizePolicy().hasHeightForWidth() ) );
+ g->addMultiCellWidget(fDatePicker,0,0,0,2);
+
+ QSpacerItem* spacer = new QSpacerItem( 20, 180, QSizePolicy::Minimum, QSizePolicy::Expanding );
+ g->addItem( spacer, 1, 1 );
+
+ fAddButton = new QPushButton( i18n( "&Add..." ), this, "pushButton1" );
+ g->addWidget( fAddButton, 2, 0 );
+
+ fEditButton = new QPushButton( i18n( "&Edit..." ), this, "pushButton2" );
+ g->addWidget( fEditButton, 2, 1 );
+
+ fDeleteButton = new QPushButton( i18n( "&Delete..." ), this, "pushButton3" );
+ g->addWidget( fDeleteButton, 2, 2 );
+
+ fEventList = new KListView( this, "kListView1" );
+ fEventList->addColumn( i18n( "Time" ) );
+ fEventList->addColumn( i18n( "Al" ) );
+ fEventList->addColumn( i18n( "Rec" ) );
+ fEventList->addColumn( i18n( "Description" ) );
+// fEventList->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)7, (QSizePolicy::SizeType)7, 0, 0, fEventList->sizePolicy().hasHeightForWidth() ) );
+ fEventList->setAllColumnsShowFocus( TRUE );
+ fEventList->setShowSortIndicator( TRUE );
+ fEventList->setResizeMode( KListView::/*LastColumn*/AllColumns );
+ fEventList->setFullWidth( TRUE );
+// fEventList->setAlternateBackground( QColor( 221, 146, 240 ) );
+ g->addMultiCellWidget(fEventList, 0, 2, 3, 3);
+
+ connect(fDatePicker, SIGNAL(dateChanged()), SLOT(slotDayChanged()));
+ connect(fAddButton, SIGNAL(clicked()), SLOT(slotAddEvent()));
+ connect(fEditButton, SIGNAL(clicked()), SLOT(slotEditEvent()));
+ connect(fDeleteButton, SIGNAL(clicked()), SLOT(slotDeleteEvent()));
+}
+
+DatebookWidget::~DatebookWidget()
+{
+ FUNCTIONSETUP;
+}
+
+
+void DatebookWidget::showComponent()
+{
+ FUNCTIONSETUP;
+
+ // TODO: Open the calendar database
+ // TODO: Initialize the current month
+ // TODO: Fill the calendar and the event list
+}
+
+void DatebookWidget::hideComponent()
+{
+ FUNCTIONSETUP;
+
+ // TODO: Close the calendar database if open
+ // TODO: clear the calendar and the event list
+}
+
+void DatebookWidget::slotDayChanged()
+{
+ FUNCTIONSETUP;
+ KMessageBox::information(this, CSL1("slotDayChanged"));
+}
+
+void DatebookWidget::slotAddEvent()
+{
+ FUNCTIONSETUP;
+ KMessageBox::information(this, CSL1("slotAddEvent"));
+}
+
+void DatebookWidget::slotEditEvent()
+{
+ FUNCTIONSETUP;
+ KMessageBox::information(this, CSL1("slotEditEvent"));
+}
+
+void DatebookWidget::slotDeleteEvent()
+{
+ FUNCTIONSETUP;
+ KMessageBox::information(this, CSL1("slotDeleteEvent"));
+}
+
+
diff --git a/kpilot/kpilot/datebookWidget.h b/kpilot/kpilot/datebookWidget.h
new file mode 100644
index 000000000..28ff0799a
--- /dev/null
+++ b/kpilot/kpilot/datebookWidget.h
@@ -0,0 +1,66 @@
+#ifndef _KPILOT_DATEBOOKWIDGET_H
+#define _KPILOT_DATEBOOKWIDGET_H
+/* datebookWidget.h KPilot
+**
+** Copyright (C) 2003 by Dan Pilone.
+** Authored by Adriaan de Groot
+**
+** This is the viewer widget for viewing datebook entries in
+** a marginally useful form.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "pilotComponent.h"
+
+class KDatePicker;
+class QPushButton;
+class KListView;
+
+class DatebookWidget : public PilotComponent
+{
+Q_OBJECT
+
+public:
+ DatebookWidget(QWidget* parent, const QString& dbpath);
+ virtual ~DatebookWidget();
+
+ // Pilot component methods
+ void hideComponent();
+ void showComponent();
+
+protected slots:
+ void slotDayChanged();
+ void slotAddEvent();
+ void slotEditEvent();
+ void slotDeleteEvent();
+
+private:
+ KDatePicker*fDatePicker;
+ QPushButton*fAddButton;
+ QPushButton*fEditButton;
+ QPushButton*fDeleteButton;
+ KListView*fEventList;
+};
+
+
+#endif
diff --git a/kpilot/kpilot/dbAppInfoEditor.cc b/kpilot/kpilot/dbAppInfoEditor.cc
new file mode 100644
index 000000000..ab5516fca
--- /dev/null
+++ b/kpilot/kpilot/dbAppInfoEditor.cc
@@ -0,0 +1,105 @@
+/* dbRecordEditor.cc KPilot
+**
+** Copyright (C) 2003 Reinhold Kainhofer <[email protected]>
+**
+**/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qtextedit.h>
+#include <qlabel.h>
+#include <kdialogbase.h>
+#include <kmessagebox.h>
+
+#include "dbAppInfoEditor.h"
+
+#include <khexedit/byteseditinterface.h>
+using namespace KHE;
+
+
+/*************************************************
+**************************************************/
+
+DBAppInfoEditor::DBAppInfoEditor(char*appInfoData, int l, QWidget *parent) :
+ KDialogBase(parent, "AppBlock Editor",false,
+ i18n("Edit AppInfo Block"),
+ Ok|Cancel),
+ appInfo(appInfoData),
+ len(l)
+{
+ fAppInfoEdit = KHE::createBytesEditWidget( this, "fAppInfoEdit" );
+ if( fAppInfoEdit )
+ {
+ // fetch the editor interface
+ KHE::BytesEditInterface* fAppInfoEditIf = KHE::bytesEditInterface( fAppInfoEdit );
+ Q_ASSERT( fAppInfoEditIf ); // This should not fail!
+ if( fAppInfoEditIf )
+ {
+ fAppInfoEditIf->setData( (char*)appInfoData, l );
+ fAppInfoEditIf->setMaxDataSize( l );
+ // TODO_RK: Make the app info editable. I need to find a way
+ // to sync the appInfoBlock to the handheld
+ fAppInfoEditIf->setReadOnly( true );
+ }
+ }
+ else
+ {
+ QLabel*tmpW = new QLabel( i18n("To view the Application info block data, please install a hex editor (e.g. khexedit from kdeutils)."), this );
+ tmpW->setBackgroundMode( Qt::PaletteMid );
+ tmpW->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter | Qt::WordBreak);
+ tmpW->setFrameShape( QFrame::Panel );
+ tmpW->setFrameShadow( QFrame::Sunken );
+ fAppInfoEdit = tmpW;
+ }
+ setMainWidget( fAppInfoEdit );
+ fillWidgets();
+}
+
+
+DBAppInfoEditor::~DBAppInfoEditor()
+{
+}
+
+void DBAppInfoEditor::slotOk()
+{
+ KMessageBox::sorry(this, i18n("Changing the AppInfo block isn't yet supported by KPilot!"));
+/* if (KMessageBox::questionYesNo(this, i18n("Changing the AppInfo block "
+ "might corrupt the whole database. \n\nReally assign the new AppInfo "
+ "block?"), i18n("Changing AppInfo Block"), i18n("Assign"), KStdGuiItem::cancel())==KMessageBox::Yes)
+ {
+ // TODO: Copy the data over
+ // TODO: set the length
+ // (*len)=..;
+ }*/
+ KDialogBase::slotOk();
+}
+
+void DBAppInfoEditor::fillWidgets()
+{
+ // FUNCTIONSETUP
+}
+
+
+
+#include "dbAppInfoEditor.moc"
diff --git a/kpilot/kpilot/dbAppInfoEditor.h b/kpilot/kpilot/dbAppInfoEditor.h
new file mode 100644
index 000000000..5a0896d82
--- /dev/null
+++ b/kpilot/kpilot/dbAppInfoEditor.h
@@ -0,0 +1,51 @@
+#ifndef _KPILOT_DBAPPINFOEDITOR_H
+#define _KPILOT_DBAPPINFOEDITOR_H
+/* dbAppInfoEditor.h KPilot
+**
+** Copyright (C) 2003 Reinhold Kainhofer <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+#include <kdialogbase.h>
+
+class QWidget;
+
+class DBAppInfoEditor : public KDialogBase
+{
+Q_OBJECT
+public:
+ DBAppInfoEditor(char*appInfoData, int l, QWidget *parent = 0);
+ ~DBAppInfoEditor();
+ char*appInfo;
+ int len;
+protected:
+ void fillWidgets();
+ QWidget*fAppInfoEdit;
+protected slots:
+ virtual void slotOk();
+};
+
+
+#endif
diff --git a/kpilot/kpilot/dbFlagsEditor.cc b/kpilot/kpilot/dbFlagsEditor.cc
new file mode 100644
index 000000000..0d6adeb99
--- /dev/null
+++ b/kpilot/kpilot/dbFlagsEditor.cc
@@ -0,0 +1,157 @@
+/* KPilot
+**
+** Copyright (C) 2003 Reinhold Kainhofer <[email protected]>
+**
+**/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <pi-dlp.h>
+
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <kdatewidget.h>
+#include <ktimewidget.h>
+#include <kmessagebox.h>
+
+#include "pilotRecord.h"
+#include "dbFlagsEditor.h"
+#include "dbFlagsEditor_base.h"
+
+
+DBFlagsEditor::DBFlagsEditor(DBInfo*dbinfo, QWidget *parent) :
+ KDialogBase(parent, "FlagsEditor",false,
+ i18n("Edit Database Flags"), Ok|Cancel),
+ dbi(dbinfo)
+{
+ widget=new DBFlagsEditorWidget(this);
+ setMainWidget(widget);
+ fillWidgets();
+}
+
+
+DBFlagsEditor::~DBFlagsEditor()
+{
+}
+
+void DBFlagsEditor::slotOk()
+{
+ if (KMessageBox::questionYesNo(this, i18n("Changing the database flags might corrupt the whole database, or make the data unusable. Do not change the values unless you are absolutely sure you know what you are doing.\n\nReally assign these new flags?"), i18n("Changing Database Flags"),i18n("Assign"),KStdGuiItem::cancel())==KMessageBox::Yes)
+ {
+ Pilot::toPilot(widget->fDBName->text(),dbi->name,33);
+
+ char buff[5];
+ strlcpy(buff, widget->fType->text().latin1(), 5);
+ dbi->type=get_long(buff);
+
+ strlcpy(buff, widget->fCreator->text().latin1(), 5);
+ dbi->creator=get_long(buff);
+
+
+#define setflag(ctrl, flag) if (widget->ctrl->isChecked()) dbi->flags |=flag;\
+ else dbi->flags &= ~flag;
+
+ setflag(fRessourceDB, dlpDBFlagResource);
+ setflag(fReadOnly, dlpDBFlagReadOnly);
+ setflag(fBackupDB, dlpDBFlagBackup);
+ setflag(fCopyProtect, dlpDBFlagCopyPrevention);
+ setflag(fReset, dlpDBFlagReset);
+#undef setflag
+
+ if (widget->fExcludeDB->isChecked())
+ dbi->miscFlags |= dlpDBMiscFlagExcludeFromSync;
+ else dbi->miscFlags &= ~dlpDBMiscFlagExcludeFromSync;
+
+ QDateTime ttime;
+ ttime.setDate(widget->fCreationDate->date());
+#if KDE_IS_VERSION(3,1,9)
+ ttime.setTime(widget->fCreationTime->time());
+#endif
+ dbi->createDate=ttime.toTime_t();
+
+ ttime.setDate(widget->fModificationDate->date());
+#if KDE_IS_VERSION(3,1,9)
+ ttime.setTime(widget->fModificationTime->time());
+#endif
+ dbi->modifyDate=ttime.toTime_t();
+
+ ttime.setDate(widget->fBackupDate->date());
+#if KDE_IS_VERSION(3,1,9)
+ ttime.setTime(widget->fBackupTime->time());
+#endif
+ dbi->backupDate=ttime.toTime_t();
+
+ KDialogBase::slotOk();
+ }
+}
+
+void DBFlagsEditor::slotCancel()
+{
+ KDialogBase::slotCancel();
+}
+
+void DBFlagsEditor::fillWidgets()
+{
+ // FUNCTIONSETUP
+
+ widget->fDBName->setText(QString::fromLatin1(dbi->name));
+
+ char buff[5];
+ set_long(buff, dbi->type);
+ buff[4]='\0';
+ widget->fType->setText(QString::fromLatin1(buff));
+ set_long(buff, dbi->creator);
+ buff[4]='\0';
+ widget->fCreator->setText(QString::fromLatin1(buff));
+
+ widget->fRessourceDB->setChecked(dbi->flags & dlpDBFlagResource);
+ widget->fReadOnly->setChecked(dbi->flags & dlpDBFlagReadOnly);
+ widget->fBackupDB->setChecked(dbi->flags & dlpDBFlagBackup);
+ widget->fCopyProtect->setChecked(dbi->flags & dlpDBFlagCopyPrevention);
+
+ widget->fReset->setChecked(dbi->flags & dlpDBFlagReset);
+ widget->fExcludeDB->setChecked(dbi->miscFlags & dlpDBMiscFlagExcludeFromSync);
+
+ QDateTime ttime;
+ ttime.setTime_t(dbi->createDate);
+ widget->fCreationDate->setDate(ttime.date());
+#if KDE_IS_VERSION(3,1,9)
+ widget->fCreationTime->setTime(ttime.time());
+#endif
+
+ ttime.setTime_t(dbi->modifyDate);
+ widget->fModificationDate->setDate(ttime.date());
+#if KDE_IS_VERSION(3,1,9)
+ widget->fModificationTime->setTime(ttime.time());
+#endif
+
+ ttime.setTime_t(dbi->backupDate);
+ widget->fBackupDate->setDate(ttime.date());
+#if KDE_IS_VERSION(3,1,9)
+ widget->fBackupTime->setTime(ttime.time());
+#endif
+}
+
+
+#include "dbFlagsEditor.moc"
diff --git a/kpilot/kpilot/dbFlagsEditor.h b/kpilot/kpilot/dbFlagsEditor.h
new file mode 100644
index 000000000..d4c7c6948
--- /dev/null
+++ b/kpilot/kpilot/dbFlagsEditor.h
@@ -0,0 +1,56 @@
+#ifndef _KPILOT_DBFLAGSEDITOR_H
+#define _KPILOT_DBFLAGSEDITOR_H
+/* dbFlagsEditor.h KPilot
+**
+** Copyright (C) 2003 Reinhold Kainhofer <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+#include <kdialogbase.h>
+
+class DBFlagsEditorWidget;
+struct DBInfo;
+/**
+@author Reinhold Kainhofer
+*/
+class DBFlagsEditor : public KDialogBase
+{
+Q_OBJECT
+public:
+ DBFlagsEditor(DBInfo*dbinfo=0L, QWidget *parent = 0);
+ ~DBFlagsEditor();
+
+protected:
+ void fillWidgets();
+ DBInfo*dbi;
+ DBFlagsEditorWidget*widget;
+protected slots:
+ virtual void slotOk();
+ virtual void slotCancel();
+
+
+};
+
+#endif
diff --git a/kpilot/kpilot/dbFlagsEditor_base.ui b/kpilot/kpilot/dbFlagsEditor_base.ui
new file mode 100644
index 000000000..ce00cf3ba
--- /dev/null
+++ b/kpilot/kpilot/dbFlagsEditor_base.ui
@@ -0,0 +1,376 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>DBFlagsEditorWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>DBFlagsEditorWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>465</width>
+ <height>353</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fDBNameLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Database &amp;name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fDBName</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="3">
+ <property name="name">
+ <cstring>fCreatorLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Creator:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fCreator</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>fTypeLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Type:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fType</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fType</cstring>
+ </property>
+ <property name="maxLength">
+ <number>4</number>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="4" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fCreator</cstring>
+ </property>
+ <property name="maxLength">
+ <number>4</number>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="2" column="0" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>fDBFlagsGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Database Flags</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>fRessourceDB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Ressource database</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>fReadOnly</cstring>
+ </property>
+ <property name="text">
+ <string>Rea&amp;d-only</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>fBackupDB</cstring>
+ </property>
+ <property name="text">
+ <string>Database is &amp;backed up</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="0">
+ <property name="name">
+ <cstring>fCopyProtect</cstring>
+ </property>
+ <property name="text">
+ <string>Copy &amp;protected</string>
+ </property>
+ </widget>
+ <spacer row="4" column="0">
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup" row="2" column="5" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fMiscFlagsGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Misc Flags</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>60</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>fReset</cstring>
+ </property>
+ <property name="text">
+ <string>Reset after &amp;installation</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>fExcludeDB</cstring>
+ </property>
+ <property name="text">
+ <string>E&amp;xclude from sync</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="3" column="0" rowspan="1" colspan="7">
+ <property name="name">
+ <cstring>fTimeStampGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Time Stamps</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>fCreationLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Cr&amp;eation time:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fCreationDate</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>fModificationlabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Modification time:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fModificationDate</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>fBackupLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Back&amp;up time:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fBackupDate</cstring>
+ </property>
+ </widget>
+ <widget class="KTimeWidget" row="0" column="2">
+ <property name="name">
+ <cstring>fCreationTime</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ </widget>
+ <widget class="KTimeWidget" row="1" column="2">
+ <property name="name">
+ <cstring>fModificationTime</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ </widget>
+ <widget class="KTimeWidget" row="2" column="2">
+ <property name="name">
+ <cstring>fBackupTime</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ </widget>
+ <widget class="KDateWidget" row="2" column="1">
+ <property name="name">
+ <cstring>fBackupDate</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ </widget>
+ <widget class="KDateWidget" row="1" column="1">
+ <property name="name">
+ <cstring>fModificationDate</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ </widget>
+ <widget class="KDateWidget" row="0" column="1">
+ <property name="name">
+ <cstring>fCreationDate</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="1" column="6">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>180</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLineEdit" row="0" column="2" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>fDBName</cstring>
+ </property>
+ <property name="maxLength">
+ <number>34</number>
+ </property>
+ </widget>
+ <spacer row="4" column="5">
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>70</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>fDBName</tabstop>
+ <tabstop>fType</tabstop>
+ <tabstop>fCreator</tabstop>
+ <tabstop>fRessourceDB</tabstop>
+ <tabstop>fReadOnly</tabstop>
+ <tabstop>fBackupDB</tabstop>
+ <tabstop>fCopyProtect</tabstop>
+ <tabstop>fReset</tabstop>
+ <tabstop>fExcludeDB</tabstop>
+ <tabstop>fCreationDate</tabstop>
+ <tabstop>fCreationTime</tabstop>
+ <tabstop>fModificationDate</tabstop>
+ <tabstop>fModificationTime</tabstop>
+ <tabstop>fBackupDate</tabstop>
+ <tabstop>fBackupTime</tabstop>
+</tabstops>
+<includes>
+ <include location="local" impldecl="in implementation">dbFlagsEditor_base.ui.h</include>
+ <include location="system" impldecl="in implementation">kdatewidget.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpilot/kpilot/dbFlagsEditor_base.ui.h b/kpilot/kpilot/dbFlagsEditor_base.ui.h
new file mode 100644
index 000000000..0186648c0
--- /dev/null
+++ b/kpilot/kpilot/dbFlagsEditor_base.ui.h
@@ -0,0 +1,24 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+#ifndef KDE_VERSION
+#include <kdeversion.h>
+#endif
+
+#if KDE_IS_VERSION(3,1,90)
+#include <ktimewidget.h>
+#else
+#warning "Workaround for KTimeWidget in KDE 3.1"
+class KTimeWidget : public QWidget
+{
+public:
+ KTimeWidget(QWidget *p, const char *n) : QWidget(p,n) {};
+} ;
+
+
+#endif
diff --git a/kpilot/kpilot/dbRecordEditor.cc b/kpilot/kpilot/dbRecordEditor.cc
new file mode 100644
index 000000000..2b2d5b39a
--- /dev/null
+++ b/kpilot/kpilot/dbRecordEditor.cc
@@ -0,0 +1,235 @@
+/* KPilot
+**
+** Copyright (C) 2003 Reinhold Kainhofer <[email protected]>
+**
+**/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+#include <qbuttongroup.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+
+#include <kmessagebox.h>
+
+#include "pilotRecord.h"
+#include "dbRecordEditor.h"
+//#include "dbRecordEditor_base.h"
+
+#include <khexedit/byteseditinterface.h>
+#include <khexedit/valuecolumninterface.h>
+#include <khexedit/charcolumninterface.h>
+using namespace KHE;
+
+
+
+DBRecordEditor::DBRecordEditor(PilotRecord*r, int n, QWidget *parent)
+ : KDialogBase(parent, "RecordEditor",false,i18n("Edit Record"),
+ Ok|Cancel), rec(r), nr(n)
+{
+// fWidget=new DBRecordEditorBase(this);
+ fWidget=new QWidget(this);
+ setMainWidget(fWidget);
+ fBuffer = new char[4096];
+
+ initWidgets();
+ fillWidgets();
+}
+
+
+DBRecordEditor::~DBRecordEditor()
+{
+ KPILOT_DELETE( fBuffer );
+}
+
+
+void DBRecordEditor::slotOk()
+{
+ FUNCTIONSETUP;
+ if (KMessageBox::questionYesNo(this, i18n("Changing the record data and flags might corrupt the whole record, or even make the database unusable. Do not change the values unless you are absolutely sure you know what you are doing.\n\nReally assign these new flags?"), i18n("Changing Record"),i18n("Assign"),KStdGuiItem::cancel())==KMessageBox::Yes)
+ {
+ int att=rec->attributes();
+#define setFlag(ctrl, flag) if (ctrl->isChecked()) att|=flag; else att &= ~flag;
+ setFlag(fDirty, dlpRecAttrDirty);
+ setFlag(fDeleted, dlpRecAttrDeleted);
+ setFlag(fBusy, dlpRecAttrBusy);
+ setFlag(fSecret, dlpRecAttrSecret);
+ setFlag(fArchived, dlpRecAttrArchived);
+ rec->setAttributes(att);
+#undef setFlag
+
+ if ( fRecordDataIf->isModified() )
+ {
+ DEBUGKPILOT << "record data changed, new Length of record: " <<
+ fRecordDataIf->dataSize() << endl;
+ // take over data
+ rec->setData( fRecordDataIf->data(), fRecordDataIf->dataSize() );
+ }
+
+ KDialogBase::slotOk();
+ }
+}
+
+void DBRecordEditor::slotCancel()
+{
+ KDialogBase::slotCancel();
+}
+
+void DBRecordEditor::languageChange()
+{
+ fRecordIndexLabel->setText( tr2i18n( "Record index:" ) );
+ fRecordIDLabel->setText( tr2i18n( "Record ID:" ) );
+ fRecordIndex->setText( tr2i18n( "1" ) );
+ fRecordID->setText( tr2i18n( "1" ) );
+ fFlagsGroup->setTitle( tr2i18n( "Flags" ) );
+ fDirty->setText( tr2i18n( "&Dirty" ) );
+ fDeleted->setText( tr2i18n( "De&leted" ) );
+ fBusy->setText( tr2i18n( "&Busy" ) );
+ fSecret->setText( tr2i18n( "&Secret" ) );
+ fArchived->setText( tr2i18n( "&Archived" ) );
+}
+
+void DBRecordEditor::initWidgets()
+{
+ // FUNCTIONSETUP
+
+ DBRecordEditorBaseLayout = new QGridLayout( fWidget, 1, 1, 11, 6, "DBRecordEditorBaseLayout");
+
+ fRecordIndexLabel = new QLabel( fWidget, "fRecordIndexLabel" );
+ DBRecordEditorBaseLayout->addWidget( fRecordIndexLabel, 0, 0 );
+
+ fRecordIDLabel = new QLabel( fWidget, "fRecordIDLabel" );
+ DBRecordEditorBaseLayout->addWidget( fRecordIDLabel, 0, 2 );
+
+ fRecordIndex = new QLineEdit( fWidget, "fRecordIndex" );
+ fRecordIndex->setReadOnly( TRUE );
+
+ DBRecordEditorBaseLayout->addWidget( fRecordIndex, 0, 1 );
+
+ fRecordID = new QLineEdit( fWidget, "fRecordID" );
+ fRecordID->setReadOnly( TRUE );
+
+ DBRecordEditorBaseLayout->addWidget( fRecordID, 0, 3 );
+
+ fFlagsGroup = new QButtonGroup( fWidget, "fFlagsGroup" );
+ fFlagsGroup->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)5,
+ (QSizePolicy::SizeType)4, 0, 0, fFlagsGroup->sizePolicy().hasHeightForWidth() ) );
+ fFlagsGroup->setColumnLayout(0, Qt::Vertical );
+ fFlagsGroup->layout()->setSpacing( 6 );
+ fFlagsGroup->layout()->setMargin( 11 );
+ fFlagsGroupLayout = new QGridLayout( fFlagsGroup->layout() );
+ fFlagsGroupLayout->setAlignment( Qt::AlignTop );
+
+ fDirty = new QCheckBox( fFlagsGroup, "fDirty" );
+ fFlagsGroupLayout->addWidget( fDirty, 0, 0 );
+
+ fDeleted = new QCheckBox( fFlagsGroup, "fDeleted" );
+ fFlagsGroupLayout->addWidget( fDeleted, 1, 0 );
+
+ fBusy = new QCheckBox( fFlagsGroup, "fBusy" );
+ fFlagsGroupLayout->addWidget( fBusy, 0, 1 );
+
+ fSecret = new QCheckBox( fFlagsGroup, "fSecret" );
+ fFlagsGroupLayout->addMultiCellWidget( fSecret, 1, 1, 1, 2 );
+
+ fArchived = new QCheckBox( fFlagsGroup, "fArchived" );
+ fFlagsGroupLayout->addWidget( fArchived, 0, 2 );
+
+ DBRecordEditorBaseLayout->addMultiCellWidget( fFlagsGroup, 1, 1, 0, 3 );
+
+ fRecordData = KHE::createBytesEditWidget( fWidget, "fRecordData" );
+ if( fRecordData )
+ {
+ // fetch the editor interface
+ fRecordDataIf = KHE::bytesEditInterface( fRecordData );
+ Q_ASSERT( fRecordDataIf ); // This should not fail!
+
+ KHE::ValueColumnInterface *ValueColumn = valueColumnInterface( fRecordData );
+ if( ValueColumn )
+ {
+ ValueColumn->setNoOfBytesPerLine( 16 );
+ ValueColumn->setResizeStyle( KHE::ValueColumnInterface::LockGrouping );
+// ValueColumn->setCoding( ValueColumnInterface::HexadecimalCoding );
+// ValueColumn->setByteSpacingWidth( 2 );
+ ValueColumn->setNoOfGroupedBytes( 4 );
+ ValueColumn->setGroupSpacingWidth( 8 );
+ }
+
+ KHE::CharColumnInterface *CharColumn = charColumnInterface( fRecordData );
+ if( CharColumn )
+ {
+ CharColumn->setShowUnprintable( false );
+// CharColumn->setSubstituteChar( '*' );
+ }
+ }
+ else
+ {
+ QLabel*tmpW = new QLabel( i18n("To view and edit the record data, please install a hex editor (e.g. kbytesedit from kdeutils)."), fWidget );
+ tmpW->setBackgroundMode( Qt::PaletteMid );
+ tmpW->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter | Qt::WordBreak);
+ tmpW->setFrameShape( QFrame::Panel );
+ tmpW->setFrameShadow( QFrame::Sunken );
+ fRecordData = tmpW;
+ fRecordDataIf = 0;
+ }
+
+ DBRecordEditorBaseLayout->addMultiCellWidget( fRecordData, 2, 2, 0, 3 );
+
+ languageChange();
+ resize( QSize(600, 561).expandedTo(minimumSizeHint()) );
+}
+
+void DBRecordEditor::fillWidgets()
+{
+ // FUNCTIONSETUP
+
+ fRecordIndex->setText(QString::number(nr));
+ fRecordID->setText(QString::number(rec->id()));
+
+ int att=rec->attributes();
+ fDirty->setChecked(att & dlpRecAttrDirty);
+ fDeleted->setChecked(att & dlpRecAttrDeleted);
+ fBusy->setChecked(att & dlpRecAttrBusy);
+ fSecret->setChecked(att & dlpRecAttrSecret);
+ fArchived->setChecked(att & dlpRecAttrArchived);
+
+ if( fRecordDataIf )
+ {
+ int len = rec->size();
+ memcpy( fBuffer, rec->data(), len );
+ fRecordDataIf->setData( fBuffer, len, 4096 );
+ fRecordDataIf->setMaxDataSize( 4096 );
+ fRecordDataIf->setReadOnly( false );
+ // We are managing the buffer ourselves:
+ fRecordDataIf->setAutoDelete( false );
+ }
+}
+
+
+#include "dbRecordEditor.moc"
diff --git a/kpilot/kpilot/dbRecordEditor.h b/kpilot/kpilot/dbRecordEditor.h
new file mode 100644
index 000000000..97bea4ed6
--- /dev/null
+++ b/kpilot/kpilot/dbRecordEditor.h
@@ -0,0 +1,94 @@
+#ifndef _KPILOT_DBRECORDEDITOR_H
+#define _KPILOT_DBRECORDEDITOR_H
+/* dbRecordEditor.h KPilot
+**
+** Copyright (C) 2003 Reinhold Kainhofer <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+#include <kdialogbase.h>
+
+class QVBoxLayout;
+class QHBoxLayout;
+class QGridLayout;
+
+namespace KHE {
+class BytesEditInterface;
+}
+using namespace KHE;
+
+class QButtonGroup;
+class QCheckBox;
+class QLabel;
+class QLineEdit;
+
+class DBRecordEditorBase;
+class PilotRecord;
+
+/**
+@author Reinhold Kainhofer
+*/
+class DBRecordEditor : public KDialogBase
+{
+Q_OBJECT
+public:
+ DBRecordEditor(PilotRecord*r=0L, int n=-1, QWidget *parent = 0);
+ ~DBRecordEditor();
+
+protected:
+ QLabel* fRecordIndexLabel;
+ QLabel* fRecordIDLabel;
+ QLineEdit* fRecordIndex;
+ QLineEdit* fRecordID;
+ QButtonGroup* fFlagsGroup;
+ QCheckBox* fDirty;
+ QCheckBox* fDeleted;
+ QCheckBox* fBusy;
+ QCheckBox* fSecret;
+ QCheckBox* fArchived;
+ QWidget* fRecordData;
+ KHE::BytesEditInterface*fRecordDataIf;
+
+protected:
+ QGridLayout* DBRecordEditorBaseLayout;
+ QGridLayout* fFlagsGroupLayout;
+
+protected:
+// DBRecordEditorBase*fWidget;
+ QWidget*fWidget;
+ char*fBuffer;
+protected slots:
+ virtual void languageChange();
+protected:
+ void initWidgets();
+ void fillWidgets();
+ PilotRecord*rec;
+ int nr;
+protected slots:
+ virtual void slotOk();
+ virtual void slotCancel();
+};
+
+#endif
diff --git a/kpilot/kpilot/dbRecordEditor_base.ui b/kpilot/kpilot/dbRecordEditor_base.ui
new file mode 100644
index 000000000..c9983743b
--- /dev/null
+++ b/kpilot/kpilot/dbRecordEditor_base.ui
@@ -0,0 +1,151 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>DBRecordEditorBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>DBRecordEditorBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>561</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>fRecordIndexLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Record index:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>fRecordIDLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Record ID:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>fRecordIndex</cstring>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="3">
+ <property name="name">
+ <cstring>fRecordID</cstring>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="1" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>fFlagsGroup</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Flags</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>fDirty</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Dirty</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>fDeleted</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Deleted</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>fBusy</cstring>
+ </property>
+ <property name="text">
+ <string>Busy</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fSecret</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Secret</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="2">
+ <property name="name">
+ <cstring>fArchived</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Archived</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="KHE::KHexEdit" row="2" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>fRecordData</cstring>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>KHE::KHexEdit</class>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="XPM.GZ" length="2926">789c9d95594f32591086effd15c4ba3393fae895ee4ce6824540141011b7c95cf406a202caa6f065fefb549faaea0b24996fc623cb937aeb3d55754e871f67a587eb6ee9ecc7c96a1dada74929798e96a5b374339bedfefceb8f9f27a7b65da27fcb724bf6e96f27a783752929f516f32c070402289b3fc39d8203c3136157e276c1260eac0f0ade0907927f2d9c58261f929cad72be0cef8535ff5959e277c201ef0fa02cf1ae7022f9efca12ff301ca81e87c21a5f32db5acf95b0eebfcdd92e2be3a5b0fa7986435bfd6e981d99278c0ae6795c288b3e2b98e3036157d8f839961308af985df51b1b0e9dc0098ddf5a3811fd7dceaee52a370d475e28f9b7ca1c07539f67173c144e65be2fcae2d763f62d89df2acb7cc282393e57b6b9ff58d893fca632c7d1ccc78bbcd48b4c7cc2ec4bfdf0aa2cfbf50be6fa2c65d9af2aacfd2c94e53cccf9fa7645eb7794a59ebdb027fe5565895f09cb7e981a267f9febaf3117fab6702af599e7a5e2049e6dce1377c25affa6608e4786e34a58894dfc8b59f5f890731087e28f2de648fbdb16ccfd6c9465bf7365c732f12f61ed3f5016fd4a59f4e6790fddd00a5d137f638eb4bfa532df5ffc148ea4be5ac17c5ea9b2ecd72b98efff403893fa1accb12d5c5696fd4d7f6152c41f95c53f2a98f56b6597fbf3857da9b75e30fb5584b59fa78239de5596fd3e0be6fdccf311b99115f1fcdaccb12fe77927ac7e2365f1c382793e63e14cfccdf3132571e69b1f07e83327d23fbac2bee4d785d57f2a9c89de9c6fecaa1fce98135bf845b9e2189e2a07e6fee287b0cfcf3bce9525ff5d38927a1bcca9cc1b66ca528ff93d89d338e3f9e182b9c86f31a752ff609d2f847f5f83b5ea31c218137a4f8fac0cc738e10cd6d3b7189f718a2ff88a6f38c339ad05adfcf31d3f7089ab037d42ea356e708b9ff8853bdc6395de6b58c706ad736c1ee823f2de608b146dbcc08e8976f012afb04b3975ec1de853aa2457f749d5c16b1ce00d0ecdf75b1ce1dd11fd1b55d236cef7f8808ff88465b4d02676d03da29f51dd9e513fa28f150c3004246d07002288bfe9e7d45f0712f22635a490d15ef730361e3b389c67aedf2390ea3157e73dc333e9a6f042d13ebc7ed32f6882405d3ee1c678030ee10d6630a76f162c8ee8f37adeb14c0aaa0b3e68b725ac80a2b039a29f630db6e46bc127d5fd45de4b5226b0833d8ea07a445f871ae96dacc218ead08073c835136842eba8be016db830e77a419f21aca143f76c025b9ae7e5813ea35bd5a0731fd1c4877a7f614fde57d085deb7f31ad31dccf54fd087883ab7a88f6baabb45fdf760003707fa09ddd826f66048af1826f00a0bb3aa7009b73082bb03fd2faeffa7fff58cfffcbcfffdfbc93f7f7d62d7</data>
+ </image>
+</images>
+<includes>
+ <include location="local" impldecl="in implementation">dbRecordEditor_base.ui.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpilot/kpilot/dbSelectionDialog.cc b/kpilot/kpilot/dbSelectionDialog.cc
new file mode 100644
index 000000000..7a875515f
--- /dev/null
+++ b/kpilot/kpilot/dbSelectionDialog.cc
@@ -0,0 +1,144 @@
+/* KPilot
+**
+** Copyright (C) 2003 Reinhold Kainhofer <[email protected]>
+**
+** This file defines a dialog box that lets the
+** user select a set of databases (e.g. which databases
+** should be ignored when doing a backup)
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qlistview.h>
+#include <qpushbutton.h>
+#include <klistview.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <klineedit.h>
+
+#include "dbSelection_base.h"
+#include "dbSelectionDialog.moc"
+
+
+KPilotDBSelectionDialog::KPilotDBSelectionDialog(QStringList &selectedDBs, QStringList &deviceDBs,
+ QStringList &addedDBs, QWidget *w, const char *n) :
+ KDialogBase(w, n, true, QString::null, KDialogBase::Ok | KDialogBase::Cancel,
+ KDialogBase::Ok, false),
+ fSelectedDBs(selectedDBs),
+ fAddedDBs(addedDBs),
+ fDeviceDBs(deviceDBs)
+{
+ FUNCTIONSETUP;
+
+ fSelectionWidget = new KPilotDBSelectionWidget(this);
+ setMainWidget(fSelectionWidget);
+
+ // Fill the encodings list
+ QStringList items(deviceDBs);
+ for ( QStringList::Iterator it = fAddedDBs.begin(); it != fAddedDBs.end(); ++it ) {
+ if (items.contains(*it)==0) items << (*it);
+ }
+ for ( QStringList::Iterator it = fSelectedDBs.begin(); it != fSelectedDBs.end(); ++it ) {
+ if (items.contains(*it)==0) items << (*it);
+ }
+ items.sort();
+
+ for ( QStringList::Iterator it = items.begin(); it != items.end(); ++it ) {
+ QCheckListItem*checkitem=new QCheckListItem(fSelectionWidget->fDatabaseList,
+ *it, QCheckListItem::CheckBox);
+ if (fSelectedDBs.contains(*it)) checkitem->setOn(true);
+ }
+
+ connect(fSelectionWidget->fNameEdit, SIGNAL(textChanged( const QString & )),
+ this, SLOT(slotTextChanged( const QString &)));
+ connect(fSelectionWidget->fAddButton, SIGNAL(clicked()),
+ this, SLOT(addDB()));
+ connect(fSelectionWidget->fRemoveButton, SIGNAL(clicked()),
+ this, SLOT(removeDB()));
+}
+
+KPilotDBSelectionDialog::~KPilotDBSelectionDialog()
+{
+ FUNCTIONSETUP;
+}
+
+void KPilotDBSelectionDialog::addDB()
+{
+ FUNCTIONSETUP;
+ QString dbname(fSelectionWidget->fNameEdit->text());
+ if (!dbname.isEmpty())
+ {
+ fSelectionWidget->fNameEdit->clear();
+ new QCheckListItem(fSelectionWidget->fDatabaseList, dbname,
+ QCheckListItem::CheckBox);
+ fAddedDBs << dbname;
+ }
+}
+
+void KPilotDBSelectionDialog::removeDB()
+{
+ FUNCTIONSETUP;
+ QListViewItem*item(fSelectionWidget->fDatabaseList->selectedItem());
+ if (item)
+ {
+ QString dbname=item->text(0);
+ if (fDeviceDBs.contains(dbname))
+ {
+ KMessageBox::error(this, i18n("This is a database that exists on the device. It was not added manually, so it can not removed from the list."), i18n("Database on Device"));
+ }
+ else
+ {
+ fSelectedDBs.remove(dbname);
+ fAddedDBs.remove(dbname);
+ KPILOT_DELETE(item);
+ }
+ }
+ else
+ {
+ KMessageBox::information(this, i18n("You need to select a database to delete in the list."),i18n("No Database Selected"), CSL1("NoDBSelected"));
+ }
+}
+
+QStringList KPilotDBSelectionDialog::getSelectedDBs()
+{
+ fSelectedDBs.clear();
+
+ // update the list of selected databases
+ QListViewItemIterator it( fSelectionWidget->fDatabaseList );
+ while ( it.current() ) {
+ QCheckListItem *item = dynamic_cast<QCheckListItem*>(it.current());
+ ++it;
+
+ if ( item && item->isOn() )
+ fSelectedDBs << item->text();
+ }
+
+ return fSelectedDBs;
+}
+
+void KPilotDBSelectionDialog::slotTextChanged( const QString& dbname)
+{
+ FUNCTIONSETUP;
+ fSelectionWidget->fAddButton->setDisabled(dbname.isEmpty());
+}
diff --git a/kpilot/kpilot/dbSelectionDialog.h b/kpilot/kpilot/dbSelectionDialog.h
new file mode 100644
index 000000000..5be8a85b8
--- /dev/null
+++ b/kpilot/kpilot/dbSelectionDialog.h
@@ -0,0 +1,60 @@
+#ifndef _KPILOT_DBSELECTIONDIALOG_H
+#define _KPILOT_DBSELECTIONDIALOG_H
+/* dbSelectionDialog.h KPilot
+**
+** Copyright (C) 2003 Reinhold Kainhofer <[email protected]>
+**
+** This file defines a dialog box that lets the
+** user select a set of databases (e.g. which databases
+** should be ignored when doing a backup)
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <kdialogbase.h>
+
+class KPilotDBSelectionWidget;
+
+class KPilotDBSelectionDialog : public KDialogBase
+{
+Q_OBJECT
+public:
+ KPilotDBSelectionDialog(QStringList &selectedDBs, QStringList &deviceDBs,
+ QStringList &addedDBs, QWidget *, const char *);
+ virtual ~KPilotDBSelectionDialog();
+
+ QStringList getSelectedDBs();
+ QStringList getAddedDBs() const {return fAddedDBs; };
+private:
+ QStringList fSelectedDBs;
+ QStringList fAddedDBs;
+ QStringList fDeviceDBs;
+protected slots:
+ void addDB();
+ void removeDB();
+ void slotTextChanged( const QString& dbname);
+
+private:
+ KPilotDBSelectionWidget *fSelectionWidget;
+} ;
+
+#endif
diff --git a/kpilot/kpilot/dbSelection_base.ui b/kpilot/kpilot/dbSelection_base.ui
new file mode 100644
index 000000000..d692ca34b
--- /dev/null
+++ b/kpilot/kpilot/dbSelection_base.ui
@@ -0,0 +1,80 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>KPilotDBSelectionWidget</class>
+<author>Reinhold Kainhofer</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>DBSelectionWidgetForm</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>318</width>
+ <height>218</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView" row="0" column="0" rowspan="1" colspan="3">
+ <column>
+ <property name="text">
+ <string>Database</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>fDatabaseList</cstring>
+ </property>
+ <property name="resizeMode">
+ <enum>LastColumn</enum>
+ </property>
+ <property name="itemsRenameable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="1" column="2">
+ <property name="name">
+ <cstring>fRemoveButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Remove</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="0">
+ <property name="name">
+ <cstring>fNameEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>fAddButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Add</string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>fNameEdit</sender>
+ <signal>returnPressed()</signal>
+ <receiver>fAddButton</receiver>
+ <slot>animateClick()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includes>
+ <include location="system" impldecl="in implementation">klistview.h</include>
+ <include location="system" impldecl="in implementation">kpushbutton.h</include>
+ <include location="system" impldecl="in implementation">klineedit.h</include>
+ <include location="system" impldecl="in implementation">kpushbutton.h</include>
+</includes>
+</UI>
diff --git a/kpilot/kpilot/dbviewerWidget.cc b/kpilot/kpilot/dbviewerWidget.cc
new file mode 100644
index 000000000..fa7a5ab23
--- /dev/null
+++ b/kpilot/kpilot/dbviewerWidget.cc
@@ -0,0 +1,440 @@
+/* dbViewerWidget.cc KPilot
+**
+** Copyright (C) 2003 by Dan Pilone.
+** Copyright (C) 2003 Reinhold Kainhofer <[email protected]>
+** Written 2003 by Reinhold Kainhofer and Adriaan de Groot
+**
+** This is the generic DB viewer widget.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "options.h"
+
+#include <unistd.h>
+#include <stdio.h>
+
+#include <pi-file.h>
+#include <pi-dlp.h>
+
+#include <qlayout.h>
+#include <qdir.h>
+#include <qregexp.h>
+#include <qlistview.h>
+
+#include <klistbox.h>
+#include <ktextedit.h>
+#include <kpushbutton.h>
+#include <kcombobox.h>
+#include <kmessagebox.h>
+
+#include "listCat.h"
+#include "listItems.h"
+
+#include "dbviewerWidget.h"
+#include "pilotLocalDatabase.h"
+#include "pilotDatabase.h"
+#include "pilotRecord.h"
+#include "dbFlagsEditor.h"
+#include "dbRecordEditor.h"
+#include "dbAppInfoEditor.h"
+#include "kpilotConfig.h"
+
+
+#include "dbviewerWidget.moc"
+
+
+GenericDBWidget::GenericDBWidget(QWidget *parent, const QString &dbpath) :
+ PilotComponent(parent,"component_generic",dbpath), fDB(0L)
+{
+ FUNCTIONSETUP;
+ setupWidget();
+ fRecList.setAutoDelete(true);
+}
+
+
+void GenericDBWidget::setupWidget()
+{
+ QGridLayout *g = new QGridLayout( this, 1, 1, SPACING);
+
+ fDBList = new KListBox( this );
+ g->addWidget( fDBList, 0, 0 );
+ fDBType = new KComboBox( FALSE, this );
+ g->addWidget( fDBType, 1, 0 );
+ fDBType->insertItem( i18n( "All Databases" ) );
+ fDBType->insertItem( i18n( "Only Applications (*.prc)" ) );
+ fDBType->insertItem( i18n( "Only Databases (*.pdb)" ) );
+
+ QGridLayout *g1 = new QGridLayout( 0, 1, 1);
+ fDBInfo = new KTextEdit( this );
+ fDBInfo->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)3, (QSizePolicy::SizeType)0, 0, 0, fDBInfo->sizePolicy().hasHeightForWidth() ) );
+ fDBInfo->setReadOnly( TRUE );
+ g1->addWidget( fDBInfo, 0, 0 );
+ fDBInfoButton = new KPushButton( i18n( "General Database &Information" ), this );
+ g1->addWidget( fDBInfoButton, 1, 0 );
+ fAppInfoButton = new KPushButton( i18n( "&Application Info Block (Categories etc.)" ), this );
+ g1->addWidget( fAppInfoButton, 2, 0 );
+
+ QGridLayout *g2 = new QGridLayout( 0, 1, 1);
+ fRecordList = new KListView( this );
+ g2->addMultiCellWidget( fRecordList, 0, 0, 0, 2 );
+ fRecordList->addColumn(i18n("Rec. Nr."));
+ fRecordList->addColumn(i18n("Length"));
+ fRecordList->addColumn(i18n("Record ID"));
+ fRecordList->setAllColumnsShowFocus(true);
+ fRecordList->setResizeMode( KListView::LastColumn );
+ fRecordList->setFullWidth( TRUE );
+ fRecordList->setItemsMovable( FALSE );
+
+ fAddRecord = new KPushButton( i18n("&Add..."), this );
+ g2->addWidget( fAddRecord, 1, 0 );
+ fEditRecord = new KPushButton( i18n("&Edit..."), this );
+ g2->addWidget( fEditRecord, 1, 1 );
+ fDeleteRecord = new KPushButton( i18n("&Delete"), this );
+ g2->addWidget( fDeleteRecord, 1, 2 );
+
+ g1->addLayout( g2, 3, 0 );
+
+
+ g->addMultiCellLayout( g1, 0, 1, 1, 1 );
+ resize( QSize(682, 661).expandedTo(minimumSizeHint()) );
+
+ connect(fDBList, SIGNAL(highlighted(const QString &)),
+ this, SLOT(slotSelected(const QString &)));
+ connect(fDBType, SIGNAL(activated(int)),
+ this, SLOT(slotDBType(int)));
+ connect(fDBInfoButton, SIGNAL(clicked()),
+ this, SLOT(slotShowDBInfo()));
+ connect(fAppInfoButton, SIGNAL(clicked()),
+ this, SLOT(slotShowAppInfo()));
+ connect(fAddRecord, SIGNAL(clicked()),
+ this, SLOT(slotAddRecord()));
+ connect(fEditRecord, SIGNAL(clicked()),
+ this, SLOT(slotEditRecord()));
+ connect(fDeleteRecord, SIGNAL(clicked()),
+ this, SLOT(slotDeleteRecord()));
+ connect(fRecordList, SIGNAL(executed(QListViewItem*)),
+ this, SLOT(slotEditRecord(QListViewItem*)));
+
+}
+
+GenericDBWidget::~GenericDBWidget()
+{
+ FUNCTIONSETUP;
+ if (fDB) KPILOT_DELETE(fDB);
+}
+
+
+void GenericDBWidget::showComponent()
+{
+ FUNCTIONSETUP;
+ fDBInfo->setText(QString::null);
+ slotDBType(0);
+
+ fDBList->show();
+ fDBInfo->show();
+}
+
+void GenericDBWidget::hideComponent()
+{
+ reset();
+}
+
+void GenericDBWidget::slotSelected(const QString &dbname)
+{
+ FUNCTIONSETUP;
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Selected DB " << dbname << endl;
+#endif
+ struct DBInfo dbinfo;
+ QString display;
+ fRecList.clear();
+ fRecordList->clear();
+
+ if (fDB) KPILOT_DELETE(fDB);
+ currentDB=dbname;
+
+ if (!shown) return;
+
+ if (dbname.endsWith(CSL1(".pdb")) || dbname.endsWith(CSL1(".PDB")))
+ {
+ // We are dealing with a database
+ currentDBtype=eDatabase;
+
+ currentDB.remove( QRegExp(CSL1(".(pdb|PDB)$")) );
+
+ fDB=new PilotLocalDatabase(dbPath(), currentDB, false);
+ if (!fDB || !fDB->isOpen())
+ {
+ fDBInfo->setText(i18n("<B>Warning:</B> Cannot read "
+ "database file %1.").arg(currentDB));
+ return;
+ }
+ dbinfo=fDB->getDBInfo();
+ display.append(i18n("<B>Database:</B> %1, %2 records<BR>")
+ .arg(QString::fromLatin1(dbinfo.name)).arg(fDB->recordCount()));
+ char buff[5];
+ set_long(buff, dbinfo.type);
+ buff[4]='\0';
+ QString tp = QString::fromLatin1(buff);
+ set_long(buff, dbinfo.creator);
+ buff[4]='\0';
+ QString cr = QString::fromLatin1(buff);
+ display.append(i18n("<B>Type:</B> %1, <B>Creator:</B> %2<br><br>").arg(tp).arg(cr));
+
+ int currentRecord = 0;
+ PilotRecord *pilotRec;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Reading database "<<dbname<<"..." << endl;
+#endif
+
+ while ((pilotRec = fDB->readRecordByIndex(currentRecord)) != 0L)
+ {
+// if (!(pilotRec->isDeleted()) )
+ {
+ PilotListViewItem*item=new PilotListViewItem(fRecordList,
+ QString::number(currentRecord), QString::number(pilotRec->size()),
+ QString::number(pilotRec->id()),
+ QString::null,
+ pilotRec->id(), pilotRec);
+ item->setNumericCol(0, true);
+ item->setNumericCol(1, true);
+ item->setNumericCol(2, true);
+ }
+ fRecList.append(pilotRec);
+
+ currentRecord++;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Total " << currentRecord << " records" << endl;
+#endif
+
+ }
+ else
+ {
+ // we are dealing with an application
+ currentDBtype=eApplication;
+
+ QCString filename = QFile::encodeName(dbPath() + CSL1("/") + dbname);
+ const char *s = filename;
+ struct pi_file *pf = pi_file_open(const_cast<char *>(s));
+ if (!pf)
+ {
+ fDBInfo->setText(i18n("<B>Warning:</B> Cannot read "
+ "application file %1.").arg(dbname));
+ return;
+ }
+#if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
+ if (pi_file_get_info(pf,&dbinfo))
+ {
+ fDBInfo->setText(i18n("<B>Warning:</B> Cannot read "
+ "application file %1.").arg(dbname));
+ return;
+ }
+#else
+ pi_file_get_info(pf,&dbinfo);
+#endif
+ display.append(i18n("<B>Application:</B> %1<BR><BR>").arg(dbname));
+ }
+ enableWidgets(currentDBtype==eDatabase);
+
+ QDateTime ttime;
+
+ ttime.setTime_t(dbinfo.createDate);
+ display.append(i18n("Created: %1<BR>").arg(ttime.toString()));
+
+ ttime.setTime_t(dbinfo.modifyDate);
+ display.append(i18n("Modified: %1<BR>").arg(ttime.toString()));
+
+ ttime.setTime_t(dbinfo.backupDate);
+ display.append(i18n("Backed up: %1<BR>").arg(ttime.toString()));
+
+ fDBInfo->setText(display);
+}
+
+void GenericDBWidget::slotDBType(int mode)
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ reset();
+
+ QDir dir(dbPath());
+ switch (mode)
+ {
+ case 1:
+ dir.setNameFilter(CSL1("*.prc")); break;
+ case 2:
+ dir.setNameFilter(CSL1("*.pdb")); break;
+ case 0:
+ default:
+ dir.setNameFilter(CSL1("*.pdb;*.prc")); break;
+ }
+ QStringList l = dir.entryList();
+ fDBList->insertStringList(l);
+}
+
+void GenericDBWidget::reset()
+{
+ FUNCTIONSETUP;
+ fDBList->clear();
+ fDBInfo->clear();
+ fRecordList->clear();
+ if (fDB) KPILOT_DELETE(fDB);
+ currentDB=QString::null;
+}
+
+void GenericDBWidget::slotAddRecord()
+{
+ FUNCTIONSETUP;
+ pi_buffer_t *b = pi_buffer_new(0);
+ PilotRecord *rec=new PilotRecord(b, 0, 0, 0);
+ PilotListViewItem*item=new PilotListViewItem(fRecordList,
+ QString::number(-1), QString::number(rec->size()),
+ QString::number(rec->id()), QString::null,
+ rec->id(), rec);
+ if (slotEditRecord(item))
+ {
+ fRecList.append(rec);
+ }
+ else
+ {
+ KPILOT_DELETE(item);
+ KPILOT_DELETE(rec);
+ }
+}
+
+bool GenericDBWidget::slotEditRecord(QListViewItem*item)
+{
+ FUNCTIONSETUP;
+ PilotListViewItem*currRecItem=dynamic_cast<PilotListViewItem*>(item);
+ if (currRecItem)
+ {
+ PilotRecord*rec=(PilotRecord*)currRecItem->rec();
+ int nr=currRecItem->text(0).toInt();
+ DBRecordEditor*dlg=new DBRecordEditor(rec, nr, this);
+ if (dlg->exec())
+ {
+ currRecItem->setText(1, QString::number(rec->size()));
+ currRecItem->setText(2, QString::number(rec->id()));
+ fRecordList->triggerUpdate();
+ writeRecord(rec);
+ KPILOT_DELETE(dlg);
+ return true;
+ }
+ KPILOT_DELETE(dlg);
+ }
+ else
+ {
+ // Either nothing selected, or some error occurred...
+ KMessageBox::information(this, i18n("You must select a record for editing."), i18n("No Record Selected"), CSL1("norecordselected"));
+ }
+ return false;
+}
+void GenericDBWidget::slotEditRecord()
+{
+ slotEditRecord(fRecordList->selectedItem());
+}
+
+void GenericDBWidget::slotDeleteRecord()
+{
+ FUNCTIONSETUP;
+ PilotListViewItem*currRecItem=dynamic_cast<PilotListViewItem*>(fRecordList->selectedItem());
+ if (currRecItem && (KMessageBox::questionYesNo(this, i18n("<qt>Do you really want to delete the selected record? This cannot be undone.<br><br>Delete record?<qt>"), i18n("Deleting Record"), KStdGuiItem::del(), KStdGuiItem::cancel())==KMessageBox::Yes) )
+ {
+ PilotRecord*rec=(PilotRecord*)currRecItem->rec();
+ rec->setDeleted();
+ writeRecord(rec);
+ // fRecordList->triggerUpdate();
+ KPILOT_DELETE(currRecItem);
+ }
+}
+
+void GenericDBWidget::slotShowAppInfo()
+{
+ FUNCTIONSETUP;
+ if (!fDB) return;
+ char*appBlock=new char[0xFFFF];
+ int len=fDB->readAppBlock((unsigned char*)appBlock, 0xFFFF);
+ DBAppInfoEditor*dlg=new DBAppInfoEditor(appBlock, len, this);
+ if (dlg->exec())
+ {
+ fDB->writeAppBlock( (unsigned char*)(dlg->appInfo), dlg->len );
+
+ KPilotConfig::addAppBlockChangedDatabase(getCurrentDB());
+ KPilotSettings::writeConfig();
+ }
+ KPILOT_DELETE(dlg);
+ delete[] appBlock;
+}
+
+void GenericDBWidget::slotShowDBInfo()
+{
+ FUNCTIONSETUP;
+ if ( !fDB || !shown ) return;
+ DBInfo db=fDB->getDBInfo();
+ DBFlagsEditor*dlg=new DBFlagsEditor(&db, this);
+ if (dlg->exec())
+ {
+#ifdef DEBUG
+ DEBUGKPILOT<<"OK pressed, assiging DBInfo, flags="<<
+ db.flags<<", miscFlag="<<db.miscFlags<<endl;
+#endif
+ fDB->setDBInfo(db);
+
+ KPilotConfig::addFlagsChangedDatabase(getCurrentDB());
+ KPilotSettings::writeConfig();
+
+ slotSelected(fDBList->currentText());
+ }
+ KPILOT_DELETE(dlg);
+}
+
+void GenericDBWidget::enableWidgets(bool enable)
+{
+ //FUNCTIONSETUP;
+ fDBInfoButton->setEnabled(enable);
+ fAppInfoButton->setEnabled(enable);
+ fRecordList->setEnabled(enable);
+ fAddRecord->setEnabled(enable);
+ fEditRecord->setEnabled(enable);
+ fDeleteRecord->setEnabled(enable);
+}
+
+void GenericDBWidget::writeRecord(PilotRecord*r)
+{
+ // FUNCTIONSETUP;
+ if (fDB && r)
+ {
+ fDB->writeRecord(r);
+ markDBDirty(getCurrentDB());
+ }
+}
+
+
+
+
+
diff --git a/kpilot/kpilot/dbviewerWidget.h b/kpilot/kpilot/dbviewerWidget.h
new file mode 100644
index 000000000..9ef3ad8da
--- /dev/null
+++ b/kpilot/kpilot/dbviewerWidget.h
@@ -0,0 +1,91 @@
+#ifndef _KPILOT_DBVIEWERWIDGET_H
+#define _KPILOT_DBVIEWERWIDGET_H
+/* dbViewerWidget.h KPilot
+**
+** Copyright (C) 2003 by Dan Pilone.
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Written 2003 by Reinhold Kainhofer and Adriaan de Groot
+**
+** This is the generic DB viewer widget.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "pilotComponent.h"
+
+class KListBox;
+class KTextEdit;
+class KPushButton;
+class KComboBox;
+class PilotLocalDatabase;
+class PilotRecord;
+class KListView;
+
+class GenericDBWidget : public PilotComponent
+{
+Q_OBJECT
+
+public:
+ GenericDBWidget(QWidget* parent, const QString& dbpath);
+ virtual ~GenericDBWidget();
+
+ // Pilot component methods
+ /* virtual */ void showComponent();
+ /* virtual */ void hideComponent();
+
+ QString getCurrentDB() const { return currentDB; }
+protected:
+ void setupWidget();
+
+protected slots:
+ void slotSelected(const QString &dbname);
+ void slotDBType(int mode);
+ void reset();
+ void slotAddRecord();
+ void slotEditRecord();
+ bool slotEditRecord(QListViewItem*);
+ void slotDeleteRecord();
+ void slotShowAppInfo();
+ void slotShowDBInfo();
+ void enableWidgets(bool enable);
+ void writeRecord(PilotRecord*r);
+
+private:
+ KListBox*fDBList;
+ KComboBox*fDBType;
+ KTextEdit*fDBInfo;
+ KPushButton*fDBInfoButton, *fAppInfoButton;
+ KListView*fRecordList;
+ KPushButton*fAddRecord, *fEditRecord, *fDeleteRecord;
+
+ enum eDBType {
+ eDatabase,
+ eApplication
+ } currentDBtype;
+
+ PilotLocalDatabase*fDB;
+ QString currentDB;
+ QPtrList<PilotRecord> fRecList;
+};
+
+
+#endif
diff --git a/kpilot/kpilot/fileInstallWidget.cc b/kpilot/kpilot/fileInstallWidget.cc
new file mode 100644
index 000000000..e8111ce87
--- /dev/null
+++ b/kpilot/kpilot/fileInstallWidget.cc
@@ -0,0 +1,304 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+**
+** This file defines the internal conduit "File Installer"
+** that accepts drags of URLs containing Palm DBs, prcs, and
+** such. It also does the HotSync part of installing files
+** on the Pilot.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#ifndef _KPILOT_OPTIONS_H
+#include "options.h"
+#endif
+
+#include <unistd.h>
+
+#include <qlistbox.h>
+#include <qstring.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qwhatsthis.h>
+#include <qmultilineedit.h>
+#include <qpixmap.h>
+#include <qpopupmenu.h>
+
+#include <kfiledialog.h>
+#include <kurldrag.h>
+#include <kiconloader.h>
+#include <kiconview.h>
+#include <kglobal.h>
+#include <kurl.h>
+
+#include "kpilotConfig.h"
+#include "fileInstaller.h"
+
+
+#include "fileInstallWidget.moc"
+
+FileInstallWidget::FileInstallWidget(QWidget * parent,
+ const QString & path) :
+ PilotComponent(parent, "component_files", path),
+ fSaveFileList(false),
+ fInstaller(0L)
+{
+ FUNCTIONSETUP;
+
+ QGridLayout *grid = new QGridLayout(this, 5, 5, SPACING);
+
+ QLabel *label = new QLabel(i18n("Files to install:"), this);
+
+ grid->addWidget(label, 1, 1);
+
+ QPushButton *abutton;
+
+ abutton = addButton = new QPushButton(i18n("Add File..."), this);
+ connect(abutton, SIGNAL(clicked()), this, SLOT(slotAddFile()));
+ grid->addWidget(abutton, 3, 1);
+ QWhatsThis::add(abutton,
+ i18n("<qt>Choose a file to add to the list of files to install.</qt>"));
+
+ abutton = clearButton= new QPushButton(i18n("Clear List"), this);
+ connect(abutton, SIGNAL(clicked()), this, SLOT(slotClearButton()));
+ grid->addWidget(abutton, 4, 1);
+ QWhatsThis::add(abutton,
+ i18n("<qt>Clear the list of files to install. No files will be installed.</qt>"));
+
+ fIconView = new KIconView(this);
+ connect(fIconView, SIGNAL(dropped(QDropEvent *, const QValueList<QIconDragItem> &)),
+ this, SLOT(slotDropEvent(QDropEvent *, const QValueList<QIconDragItem> &)));
+ grid->addMultiCellWidget(fIconView, 1, 4, 2, 3);
+ QWhatsThis::add(fIconView,
+ i18n
+ ("<qt>This lists files that will be installed on the Pilot during the next HotSync. Drag files here or use the Add button.</qt>"));
+ fIconView->setAcceptDrops(true);
+ fIconView->setSelectionMode(QIconView::Extended);
+ fIconView->viewport()->installEventFilter(this);
+
+ grid->setRowStretch(2, 100);
+ grid->setColStretch(2, 50);
+ grid->setColStretch(2, 50);
+ grid->addColSpacing(4, SPACING);
+ grid->addRowSpacing(5, SPACING);
+
+ fInstaller = new FileInstaller;
+ connect(fInstaller, SIGNAL(filesChanged()),
+ this, SLOT(refreshFileInstallList()));
+
+}
+
+FileInstallWidget::~FileInstallWidget()
+{
+ KPILOT_DELETE(fInstaller);
+}
+
+static inline bool pdbOrPrc(const QString &s)
+{
+ return s.endsWith(CSL1(".pdb"),false) || s.endsWith(CSL1(".prc"),false) ;
+}
+
+void FileInstallWidget::dragEnterEvent(QDragEnterEvent *event)
+{
+ FUNCTIONSETUP;
+
+ KURL::List urls;
+ if(!KURLDrag::decode(event, urls)) {
+ event->accept(false);
+ return;
+ }
+
+ KURL::List::const_iterator it;
+ QString filename;
+ for ( it = urls.begin(); it != urls.end(); ++it ) {
+ filename = (*it).fileName();
+ if(!pdbOrPrc(filename)) {
+ event->accept(false);
+ return;
+ }
+ }
+ event->accept(true);
+}
+
+bool FileInstallWidget::eventFilter(QObject *watched, QEvent *event)
+{
+ FUNCTIONSETUP;
+
+ if(watched == fIconView->viewport())
+ {
+ if(event->type() == QEvent::DragEnter) {
+ dragEnterEvent(static_cast<QDragEnterEvent*>(event));
+ return true;
+ }
+
+ // We have to skip the DragMove event, because it seems to override the
+ // accept state, when it is set to false by dragEnterEvent() (event->accept(false);)
+ if(event->type() == QEvent::DragMove) {
+ return true;
+ }
+
+ if(event->type() == QEvent::MouseButtonPress) {
+ contextMenu(static_cast<QMouseEvent*>(event));
+ }
+ }
+
+ return false;
+}
+
+void FileInstallWidget::dropEvent(QDropEvent * drop)
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ KURL::List list;
+
+ if (!KURLDrag::decode(drop, list) || list.isEmpty())
+ return;
+
+#ifdef DEBUG
+ DEBUGKPILOT << ": Got " << list.first().prettyURL() << endl;
+#endif
+
+ QStringList files;
+ for(KURL::List::ConstIterator it = list.begin(); it != list.end(); ++it)
+ {
+ if ((*it).isLocalFile())
+ files << (*it).path();
+ }
+
+ fInstaller->addFiles(files, this );
+}
+
+void FileInstallWidget::slotDropEvent(QDropEvent * drop, const QValueList<QIconDragItem> & /*lst*/)
+{
+ FUNCTIONSETUP;
+ dropEvent(drop);
+}
+
+void FileInstallWidget::slotClearButton()
+{
+ FUNCTIONSETUP;
+ fInstaller->clearPending();
+}
+
+void FileInstallWidget::showComponent()
+{
+ FUNCTIONSETUP;
+ refreshFileInstallList();
+}
+
+void FileInstallWidget::slotAddFile()
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ QStringList fileNames = KFileDialog::getOpenFileNames(
+ QString::null, i18n("*.pdb *.prc|PalmOS Databases (*.pdb *.prc)"));
+
+ for (QStringList::Iterator fileName = fileNames.begin(); fileName != fileNames.end(); ++fileName)
+ {
+ fInstaller->addFile(*fileName, this );
+ }
+}
+
+bool FileInstallWidget::preHotSync(QString &)
+{
+ FUNCTIONSETUP;
+
+ fIconView->setEnabled(false);
+ fInstaller->setEnabled(false);
+ addButton->setEnabled(false);
+ clearButton->setEnabled(false);
+
+ return true;
+}
+
+void FileInstallWidget::postHotSync()
+{
+ FUNCTIONSETUP;
+
+ fInstaller->setEnabled(true);
+ fIconView->setEnabled(true);
+ addButton->setEnabled(true);
+ clearButton->setEnabled(true);
+ if (shown) refreshFileInstallList();
+}
+
+
+void FileInstallWidget::refreshFileInstallList()
+{
+ FUNCTIONSETUP;
+
+ QStringList fileNames = fInstaller->fileNames();
+ QPixmap kpilotIcon = KGlobal::iconLoader()->loadIcon(CSL1("kpilot"), KIcon::Desktop);
+
+ fIconView->clear();
+
+ for (QStringList::Iterator fileName = fileNames.begin(); fileName != fileNames.end(); ++fileName)
+ {
+ if(pdbOrPrc(*fileName))
+ {
+ new KIconViewItem(fIconView, *fileName, kpilotIcon);
+ }
+ else
+ {
+ new KIconViewItem(fIconView, *fileName);
+ }
+ }
+}
+
+void FileInstallWidget::contextMenu(QMouseEvent *event)
+{
+ FUNCTIONSETUP;
+
+ if(event->button() == Qt::LeftButton)
+ return;
+
+ QIconViewItem *item;
+ QStringList files;
+ for(item = fIconView->firstItem(); item; item = item->nextItem())
+ {
+ if(item->isSelected())
+ files.append(item->text());
+ }
+
+ QPopupMenu popup(fIconView);
+
+ item = fIconView->findItem(event->pos());
+ if(item) {
+ // Popup for the right clicked item
+ popup.insertItem(i18n("Delete a single file item","Delete"), 10);
+ }
+
+ popup.insertItem(i18n("Delete selected files"), 11);
+ if(files.empty())
+ popup.setItemEnabled(11, false);
+
+ int id = popup.exec(fIconView->viewport()->mapToGlobal(event->pos()));
+ if(id == 10)
+ fInstaller->deleteFile(item->text());
+ else if(id == 11)
+ fInstaller->deleteFiles(files);
+
+}
diff --git a/kpilot/kpilot/fileInstallWidget.h b/kpilot/kpilot/fileInstallWidget.h
new file mode 100644
index 000000000..b4bd205c9
--- /dev/null
+++ b/kpilot/kpilot/fileInstallWidget.h
@@ -0,0 +1,92 @@
+#ifndef _KPILOT_FILEINSTALLWIDGET_H
+#define _KPILOT_FILEINSTALLWIDGET_H
+/* fileInstallWidget.h KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+**
+** This file defines the file install widget, which is the thing
+** that accepts file drags for later installation into the Pilot.
+**
+** This file also defines the log window widget, which logs
+** sync-messages during a HotSync.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "pilotComponent.h"
+
+class QMultiLineEdit;
+class QPushButton;
+class QIconDragItem;
+
+class KIconView;
+class KPilotInstaller;
+class FileInstaller;
+
+class FileInstallWidget : public PilotComponent
+{
+Q_OBJECT
+
+public:
+ FileInstallWidget(QWidget* parent, const QString& dbPath);
+ virtual ~FileInstallWidget();
+
+ // Pilot Component Methods:
+ void showComponent();
+ bool preHotSync(QString &);
+ void postHotSync();
+
+
+signals:
+ void fileInstallWidgetDone();
+
+protected:
+ void setSaveFileList(bool saveIt) { fSaveFileList = saveIt; }
+ bool getSaveFileList() { return fSaveFileList; }
+
+ /* virtual */ void dragEnterEvent(QDragEnterEvent* event);
+ /* virtual */ void dropEvent(QDropEvent* drop);
+ /* virtual */ bool eventFilter (QObject *watched, QEvent *event );
+
+ void contextMenu(QMouseEvent *event);
+
+ KPilotInstaller* getPilotInstallerApp() { return fKPilotInstaller; }
+
+private:
+ KIconView *fIconView;
+ bool fSaveFileList;
+
+ KPilotInstaller* fKPilotInstaller;
+ FileInstaller *fInstaller;
+ QPushButton *clearButton,*addButton;
+
+protected slots:
+ void slotClearButton();
+ void slotAddFile();
+
+ void slotDropEvent(QDropEvent * drop, const QValueList<QIconDragItem> & lst);
+
+public slots:
+ void refreshFileInstallList();
+};
+
+#endif
diff --git a/kpilot/kpilot/fileInstaller.cc b/kpilot/kpilot/fileInstaller.cc
new file mode 100644
index 000000000..6c26a79f4
--- /dev/null
+++ b/kpilot/kpilot/fileInstaller.cc
@@ -0,0 +1,184 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+**
+** This is a class that does "the work" of adding and deleting
+** files in the pending_install directory of KPilot. It is used
+** by the fileInstallWidget and by the daemon's drag-and-drop
+** file accepter.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "options.h"
+
+#include <unistd.h>
+
+#include <qstring.h>
+#include <qstrlist.h>
+#include <qdir.h>
+
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+#include <kmessagebox.h>
+
+#include "fileInstaller.moc"
+
+FileInstaller::FileInstaller() :
+ enabled(true)
+{
+ FUNCTIONSETUP;
+
+ fDirName = KGlobal::dirs()->saveLocation("data",
+ CSL1("kpilot/pending_install/"));
+ fPendingCopies = 0;
+
+}
+
+/* virtual */ FileInstaller::~FileInstaller()
+{
+ FUNCTIONSETUP;
+}
+
+
+void FileInstaller::clearPending()
+{
+ FUNCTIONSETUP;
+
+ unsigned int i;
+
+ QDir installDir(fDirName);
+
+ // Start from 2 to skip . and ..
+ //
+ for (i = 2; i < installDir.count(); i++)
+ {
+ QFile::remove(fDirName + installDir[i]);
+ }
+
+ if (i > 2)
+ {
+ emit filesChanged();
+ }
+}
+
+void FileInstaller::deleteFile(const QString &file)
+{
+ QFile::remove(fDirName + file);
+ emit filesChanged();
+}
+
+void FileInstaller::deleteFiles(const QStringList &files)
+{
+ if(files.empty())
+ return;
+
+ for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it)
+ QFile::remove(fDirName + *it);
+
+ emit filesChanged();
+}
+
+/* virtual */ bool FileInstaller::runCopy(const QString & s, QWidget* w )
+{
+ FUNCTIONSETUP;
+
+ if(!(s.endsWith(CSL1(".pdb"), false) || s.endsWith(CSL1(".prc"), false))) {
+ KMessageBox::detailedSorry(w, i18n("Cannot install %1").arg(s),
+ i18n("Only PalmOS database files (like *.pdb and *.prc) can be installed by the file installer."));
+ return false;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Copying " << s << endl;
+#endif
+
+ KURL srcName;
+ srcName.setPath(s);
+ KURL destDir(fDirName + CSL1("/") + srcName.fileName());
+
+#if KDE_IS_VERSION(3,1,9)
+ return KIO::NetAccess::copy(srcName, destDir, w);
+#else
+ return KIO::NetAccess::copy(srcName,destDir);
+#endif
+}
+
+
+void FileInstaller::addFiles(const QStringList & fileList, QWidget* w)
+{
+ FUNCTIONSETUP;
+
+ if (!enabled) return;
+
+ unsigned int succ = 0;
+
+ for(QStringList::ConstIterator it = fileList.begin();
+ it != fileList.end(); ++it)
+ {
+ if (runCopy( *it, w ))
+ succ++;
+ }
+
+ if (succ)
+ {
+ emit filesChanged();
+ }
+}
+
+void FileInstaller::addFile( const QString & file, QWidget* w )
+{
+ FUNCTIONSETUP;
+
+ if (!enabled) return;
+
+ if (runCopy(file, w))
+ {
+ emit(filesChanged());
+ }
+}
+
+/* slot */ void FileInstaller::copyCompleted()
+{
+ FUNCTIONSETUP;
+}
+
+const QStringList FileInstaller::fileNames() const
+{
+ FUNCTIONSETUP;
+
+ QDir installDir(fDirName);
+
+ return installDir.entryList(QDir::Files |
+ QDir::NoSymLinks | QDir::Readable);
+}
+
+/* slot */ void FileInstaller::setEnabled(bool b)
+{
+ FUNCTIONSETUP;
+ enabled=b;
+}
+
+
diff --git a/kpilot/kpilot/fileInstaller.h b/kpilot/kpilot/fileInstaller.h
new file mode 100644
index 000000000..3c23f5712
--- /dev/null
+++ b/kpilot/kpilot/fileInstaller.h
@@ -0,0 +1,82 @@
+/* fileInstaller.h KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This is a class that does "the work" of adding and deleting
+** files in the pending_install directory of KPilot. It is used
+** by the fileInstallWidget and by the daemon's drag-and-drop
+** file accepter.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#ifndef _KPILOT_FILEINSTALLER_H
+#define _KPILOT_FILEINSTALLER_H
+
+#include <qobject.h>
+
+
+class QStringList;
+class QString;
+
+class FileInstaller : public QObject
+{
+ Q_OBJECT
+public:
+ FileInstaller();
+ virtual ~FileInstaller();
+
+ void clearPending();
+
+ void addFiles( const QStringList&, QWidget* w );
+ void addFile( const QString&, QWidget* w );
+
+ void deleteFile(const QString &);
+ void deleteFiles(const QStringList &);
+
+ /**
+ * Returns information about this installer. Note particularly
+ * that fileNames() returns only filenames, not paths. In particular,
+ * you'll need to prepend dir()+"/" to get pathnames.
+ */
+ const QString &dir() const { return fDirName; } ;
+ const QStringList fileNames() const ;
+
+
+
+protected:
+ virtual bool runCopy( const QString &src, QWidget*w );
+
+public slots:
+ void copyCompleted();
+ void setEnabled(bool);
+
+signals:
+ void filesChanged();
+private:
+ QString fDirName;
+ int fPendingCopies;
+ bool enabled;
+} ;
+
+#endif
diff --git a/kpilot/kpilot/hotSync.cc b/kpilot/kpilot/hotSync.cc
new file mode 100644
index 000000000..60bb9356b
--- /dev/null
+++ b/kpilot/kpilot/hotSync.cc
@@ -0,0 +1,1156 @@
+/* KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2006 Adriaan de Groot <[email protected]>
+**
+** This file defines SyncActions, which are used to perform some specific
+** task during a HotSync. Conduits are not included here, nor are
+** sync actions requiring user interaction. Those can be found in the
+** conduits subdirectory or interactiveSync.h.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected].
+*/
+
+
+#include "options.h"
+
+#include <time.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <pi-file.h>
+#include <pi-util.h>
+
+#include <qtimer.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qvaluelist.h>
+#include <qregexp.h>
+#include <qstringlist.h>
+#include <qthread.h>
+
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+
+#include "pilotUser.h"
+#include "pilotRecord.h"
+#include "actionQueue.h"
+#include "pilotSerialDatabase.h"
+#include "pilotLocalDatabase.h"
+#include "pilotDatabase.h"
+#include "kpilotSettings.h"
+
+#include "hotSync.moc"
+
+class BackupAction::Thread : public QThread
+{
+public:
+ Thread( BackupAction *parent,
+ KPilotLink *link,
+ const QString &filename,
+ const DBInfo *info );
+
+ enum {
+ TerminateOK = QEvent::User,
+ TerminateFailure
+ } ;
+
+protected:
+ virtual void run();
+private:
+ BackupAction *fParent;
+ KPilotLink *fLink;
+ QString fFilename;
+ struct DBInfo fDBInfo;
+} ;
+
+class BackupAction::Private
+{
+public:
+ bool fFullBackup; ///< Is this a full backup (all DBs, not just changed ones)?
+ QStringList fNoBackupDBs;
+ QValueList<unsigned long> fNoBackupCreators;
+ QStringList fDeviceDBs;
+
+ QString fPreferBackupDir; ///< Directory to write backup in, overrides default
+
+ // Remainder is used to hand around info during sync
+
+ int fDBIndex; ///< Database number we're now doing
+ QString fBackupDir; ///< Directory to write backup in.
+
+ /**
+ * Add the database described by the info block to the list of
+ * databases definitely found on the handheld.
+ */
+ void addDBInfo( const DBInfo *info )
+ {
+ FUNCTIONSETUP;
+ fDBIndex = info->index + 1;
+
+ // Each character of buff[] is written to
+ char buff[7];
+ buff[0] = '[';
+ set_long( &buff[1], info->creator );
+ buff[5] = ']';
+ buff[6] = '\0';
+ QString creator = QString::fromLatin1( buff );
+
+ QString dbname = Pilot::fromPilot( info->name, 32 );
+
+ if ( !fDeviceDBs.contains( creator ) )
+ {
+ fDeviceDBs << creator;
+ }
+ if ( !fDeviceDBs.contains( dbname ) )
+ {
+ fDeviceDBs << dbname;
+ }
+
+ DEBUGKPILOT << fname << ": Added <" << dbname
+ << "> " << creator << endl;
+ }
+
+
+ /**
+ * Check if this database, described by @p info , should
+ * be backed up (i.e. is allowed to be backed up by the
+ * user settings for no-backup DBs).
+ *
+ * @return @c true if the database may be backed up.
+ */
+ bool allowBackup( const DBInfo *info ) const
+ {
+ // Special case - skip database Unsaved Preferences
+ if ( (info->creator == pi_mktag('p','s','y','s')) &&
+ (info->type == pi_mktag('p','r','e','f')) )
+ {
+ return false;
+ }
+
+ if (fNoBackupCreators.findIndex(info->creator) != -1)
+ {
+ return false;
+ }
+
+ // Now take wildcards into account
+ QString db = Pilot::fromPilot(info->name);
+ for (QStringList::const_iterator i = fNoBackupDBs.begin();
+ i != fNoBackupDBs.end(); ++i)
+ {
+ QRegExp re(*i,true,true); // Wildcard match
+ if (re.exactMatch(db))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+} ;
+
+BackupAction::BackupAction(KPilotLink * p, bool full) :
+ SyncAction(p, "backupAction"),
+ fP( new Private ),
+ fBackupThread( 0L )
+{
+ FUNCTIONSETUP;
+
+ fP->fFullBackup = full;
+}
+
+/* virtual */ QString BackupAction::statusString() const
+{
+ FUNCTIONSETUP;
+ QString s(CSL1("BackupAction="));
+
+ switch (status())
+ {
+ case Init:
+ s.append(CSL1("Init"));
+ break;
+ case Error:
+ s.append(CSL1("Error"));
+ break;
+ case FullBackup:
+ s.append(CSL1("FullBackup"));
+ break;
+ case FastBackup:
+ s.append(CSL1("FastBackup"));
+ break;
+ case BackupEnded:
+ s.append(CSL1("BackupEnded"));
+ break;
+ case BackupIncomplete:
+ s.append(CSL1("BackupIncomplete"));
+ break;
+ case BackupComplete:
+ s.append(CSL1("BackupComplete"));
+ break;
+ default:
+ s.append(CSL1("(unknown "));
+ s.append(QString::number(status()));
+ s.append(CSL1(")"));
+ }
+
+ return s;
+}
+
+void BackupAction::setDirectory( const QString &p )
+{
+ fP->fPreferBackupDir = p;
+ if (!p.endsWith(CSL1("/")))
+ {
+ fP->fPreferBackupDir.append(CSL1("/"));
+ }
+}
+
+static inline void initNoBackup(QStringList &dbnames,
+ QValueList<unsigned long> &dbcreators)
+{
+ FUNCTIONSETUP;
+ dbnames.clear();
+ dbcreators.clear();
+
+ QStringList configuredSkip = KPilotSettings::skipBackupDB();
+ QStringList::const_iterator e = configuredSkip.end();
+ for (QStringList::const_iterator i = configuredSkip.begin();
+ i!= e; ++i)
+ {
+ QString s = *i;
+ if (s.startsWith(CSL1("[")) && s.endsWith(CSL1("]")))
+ {
+ if (s.length() != 6)
+ {
+ WARNINGKPILOT << "Creator ID " << s << " is malformed." << endl;
+ }
+ else
+ {
+ QCString data = s.mid(1,4).latin1();
+ unsigned long creator = pi_mktag(data[0],data[1],data[2],data[3]);
+ dbcreators.append(creator);
+ }
+ }
+ else
+ {
+ dbnames.append(s);
+ }
+ }
+
+ DEBUGKPILOT << fname << ": Will skip databases "
+ << dbnames.join(CSL1(",")) << endl;
+ QString creatorids;
+ char buf[5];
+ for (QValueList<unsigned long>::const_iterator i = dbcreators.begin();
+ i != dbcreators.end(); ++i)
+ {
+ unsigned long tag = *i;
+ pi_untag(buf,tag);
+ buf[4]=0;
+ creatorids.append(CSL1("[%1]").arg(buf));
+ }
+ DEBUGKPILOT << fname << ": Will skip creators " << creatorids << endl;
+}
+
+/** Make sure that the backup directory @p backupDir
+* exists and is a directory; returns @c false
+* if this is not the case. This method will try
+* to create the directory if it doesn't exist yet.
+*/
+static inline bool checkBackupDirectory( const QString &backupDir )
+{
+ FUNCTIONSETUP;
+ QFileInfo fi(backupDir);
+
+ if (fi.exists() && fi.isDir())
+ {
+ return true;
+ }
+
+ if (fi.exists() && !fi.isDir())
+ {
+ WARNINGKPILOT << "Requested backup directory "
+ << backupDir
+ << " exists but is not a directory."
+ << endl;
+ return false;
+ }
+
+ if ( !backupDir.endsWith("/") )
+ {
+ WARNINGKPILOT << "Backup dir does not end with a / "
+ << endl;
+ return false;
+ }
+
+ Q_ASSERT(!fi.exists());
+
+ DEBUGKPILOT << fname
+ << ": Creating directory " << backupDir << endl;
+
+ KStandardDirs::makeDir( backupDir );
+
+ fi = QFileInfo(backupDir);
+
+ return fi.exists() && fi.isDir();
+}
+
+
+/* virtual */ bool BackupAction::exec()
+{
+ FUNCTIONSETUP;
+
+ fP->fDeviceDBs = KPilotSettings::deviceDBs();
+
+ if (fP->fPreferBackupDir.isEmpty())
+ {
+ fP->fBackupDir =
+ KGlobal::dirs()->saveLocation("data",CSL1("kpilot/DBBackup/")) +
+ deviceLink()->getPilotUser().name() + '/';
+ }
+ else
+ {
+ fP->fBackupDir = fP->fPreferBackupDir;
+ }
+
+ logMessage(i18n("Backup directory: %1.").arg(fP->fBackupDir));
+
+ DEBUGKPILOT << fname
+ << ": This Pilot user's name is \""
+ << deviceLink()->getPilotUser().name() << "\"" << endl;
+ DEBUGKPILOT << fname
+ << ": Using backup dir: " << fP->fBackupDir << endl;
+ DEBUGKPILOT << fname
+ << ": Full Backup? " << fP->fFullBackup << endl;
+
+
+ if (fP->fFullBackup)
+ {
+ fActionStatus = FullBackup;
+ addSyncLogEntry(i18n("Full backup started."));
+ }
+ else
+ {
+ fActionStatus = FastBackup;
+ addSyncLogEntry(i18n("Fast backup started"));
+ }
+
+ if (!checkBackupDirectory(fP->fBackupDir))
+ {
+ fActionStatus=BackupIncomplete;
+ // Don't issue an error message, checkBackupDirectory
+ // did this already...
+ return false;
+ }
+
+ initNoBackup( fP->fNoBackupDBs, fP->fNoBackupCreators );
+
+ fP->fDBIndex = 0;
+ QTimer::singleShot(0,this,SLOT(backupOneDB()));
+ return true;
+}
+
+/* slot */ void BackupAction::backupOneDB()
+{
+ FUNCTIONSETUP;
+
+ struct DBInfo info;
+
+ // TODO: make the progress reporting more accurate
+ emit logProgress(QString::null, fP->fDBIndex);
+
+ if (openConduit() < 0)
+ {
+ addSyncLogEntry(i18n("Exiting on cancel."));
+ endBackup();
+ fActionStatus = BackupIncomplete;
+ return;
+ }
+
+ // TODO: Is there a way to skip unchanged databases?
+ int res = deviceLink()->getNextDatabase( fP->fDBIndex, &info );
+ if (res < 0)
+ {
+ if ( fP->fFullBackup )
+ {
+ addSyncLogEntry( i18n("Full backup complete.") );
+ }
+ else
+ {
+ addSyncLogEntry( i18n("Fast backup complete.") );
+ }
+ endBackup();
+ fActionStatus = BackupComplete;
+ return;
+ }
+
+ fP->addDBInfo( &info );
+
+ // see if user told us not to back this creator or database up...
+ if (fP->allowBackup(&info))
+ {
+ // back up DB if this is a full backup *or* in non-full backups,
+ // only backup data, not applications.
+ if ( (fP->fFullBackup) || !PilotDatabase::isResource(&info) )
+ {
+ addSyncLogEntry(i18n("Backing up: %1").arg(Pilot::fromPilot(info.name)));
+
+ if (!startBackupThread(&info))
+ {
+ WARNINGKPILOT << "Could not create local database for <"
+ << info.name << ">" << endl;
+ }
+ else
+ {
+ // The thread has started, so we will be woken
+ // up by it eventually when it is done. Do *NOT*
+ // fall through to the single-shot timer below,
+ // because that would return us to the backup
+ // function too soon.
+ return;
+ }
+ }
+ else
+ {
+ // Just skip resource DBs during an update hotsync.
+ DEBUGKPILOT << fname << ": Skipping database <" << info.name
+ << "> (resource database)" << endl;
+ }
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": Skipping database <" << info.name
+ << "> (no-backup list)" << endl;
+ QString s = i18n("Skipping %1")
+ .arg(Pilot::fromPilot(info.name));
+ addSyncLogEntry(s);
+ }
+ QTimer::singleShot(0,this,SLOT(backupOneDB()));
+}
+
+/**
+ * This method will back up a single database from the Pilot to a directory on
+ * our filesystem. If our user asks us to do a full backup, then we will unconditionally
+ * copy the database file from the Pilot into the backup directory. Otherwise, we will
+ * check to see if the database has any modified records in it on the pilot. If the
+ * database has not changed on the Pilot, then there's nothing to backup and we return.
+ *
+ * @return @c true if the backup has started (in another thread).
+ * You must wait on the thread to end with a User or User+1
+ * type event and not start another backup thread.
+ * @return @c false if there is no backup to do. Diagnostic messages
+ * will already have been printed.
+ */
+bool BackupAction::startBackupThread(DBInfo *info)
+{
+ FUNCTIONSETUP;
+
+ // now we look to see if the database on the pilot has at least one changed record
+ // in it. we do this so that we don't waste time backing up a database that has
+ // not changed. note: don't bother with this check if we're doing a full backup.
+ if (!fP->fFullBackup)
+ {
+ // Check if this DB has modified records.
+ PilotDatabase *serial=deviceLink()->database(info);
+ if (!serial->isOpen())
+ {
+ WARNINGKPILOT << "Unable to open database <" << info->name << ">" << endl;
+ KPILOT_DELETE(serial);
+ addSyncLogEntry(i18n("Backup of %1 failed.\n")
+ .arg(Pilot::fromPilot(info->name)));
+ return false;
+ }
+
+ int index=0;
+ PilotRecord*rec=serial->readNextModifiedRec(&index);
+ if (!rec)
+ {
+ DEBUGKPILOT << fname << ": No modified records." << endl;
+ KPILOT_DELETE(serial);
+ return false;
+ }
+ // Exists, with modified records.
+ KPILOT_DELETE(rec);
+ KPILOT_DELETE(serial);
+ }
+
+
+ // if we're here then we are going to back this database up. do some basic sanity
+ // checks and proceed....
+ QString databaseName(Pilot::fromPilot(info->name));
+ databaseName.replace('/', '_');
+
+ QString fullBackupName = fP->fBackupDir + databaseName;
+
+ if (PilotDatabase::isResource(info))
+ {
+ fullBackupName.append(CSL1(".prc"));
+ }
+ else
+ {
+ fullBackupName.append(CSL1(".pdb"));
+ }
+
+ DEBUGKPILOT << fname
+ << ": Backing up database to: [" << fullBackupName << "]" << endl;
+
+ /* Ensure that DB-open flag is not kept */
+ info->flags &= ~dlpDBFlagOpen;
+
+ if (fBackupThread)
+ {
+ WARNINGKPILOT << "Starting new backup thread before the old one is done." << endl;
+ return false;
+ }
+
+ fBackupThread = new Thread(this,deviceLink(),fullBackupName,info);
+ fBackupThread->start();
+ return true;
+}
+
+/* virtual */ bool BackupAction::event( QEvent *e )
+{
+ if (e->type() == (QEvent::Type)Thread::TerminateOK)
+ {
+ KPILOT_DELETE(fBackupThread);
+ // This was a successful termination.
+ addSyncLogEntry( i18n("... OK.\n"), false );
+ QTimer::singleShot(0,this,SLOT(backupOneDB()));
+ return true;
+ }
+ if (e->type() == (QEvent::Type)Thread::TerminateFailure)
+ {
+ KPILOT_DELETE(fBackupThread);
+ // Unsuccessful termination.
+ addSyncLogEntry( i18n("Backup failed.") );
+ QTimer::singleShot(0,this,SLOT(backupOneDB()));
+ return true;
+ }
+ return SyncAction::event(e);
+}
+
+void BackupAction::endBackup()
+{
+ FUNCTIONSETUP;
+
+ fP->fDBIndex = (-1);
+ fActionStatus = BackupEnded;
+ fP->fDeviceDBs.sort();
+ QString old( QString::null );
+ QStringList::Iterator itr = fP->fDeviceDBs.begin();
+ while ( itr != fP->fDeviceDBs.end() ) {
+ if ( old == *itr ) {
+ itr = fP->fDeviceDBs.remove( itr );
+ } else {
+ old = *itr;
+ ++itr;
+ }
+ }
+ KPilotSettings::setDeviceDBs( fP->fDeviceDBs );
+
+ emit syncDone(this);
+}
+
+FileInstallAction::FileInstallAction(KPilotLink * p,
+ const QString & d) :
+ SyncAction(p, "fileInstall"),
+ fDBIndex(-1),
+ fTimer(0L),
+ fDir(d)
+{
+ FUNCTIONSETUP;
+}
+
+FileInstallAction::~FileInstallAction()
+{
+ FUNCTIONSETUP;
+
+ KPILOT_DELETE(fTimer);
+}
+
+/* virtual */ bool FileInstallAction::exec()
+{
+ FUNCTIONSETUP;
+
+ QDir installDir(fDir);
+ fList = installDir.entryList(QDir::Files |
+ QDir::NoSymLinks | QDir::Readable);
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Installing " << fList.count() << " files" << endl;
+#endif
+
+ fDBIndex = 0;
+ emit logMessage(i18n("[File Installer]"));
+
+ // Possibly no files to install?
+ if (!fList.count())
+ {
+ emit logMessage(i18n("No Files to install"));
+ delayDone();
+ return true;
+ }
+
+ fTimer = new QTimer(this);
+ QObject::connect(fTimer, SIGNAL(timeout()),
+ this, SLOT(installNextFile()));
+
+ fTimer->start(0, false);
+
+ emit logProgress(i18n("Installing one file",
+ "Installing %n Files",fList.count()), 0);
+ return true;
+}
+
+/* slot */ void FileInstallAction::installNextFile()
+{
+ FUNCTIONSETUP;
+
+ Q_ASSERT(fDBIndex >= 0);
+ Q_ASSERT((unsigned) fDBIndex <= fList.count());
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Installing file index "
+ << fDBIndex << " (of " << fList.count() << ")" << endl;
+#endif
+
+ if ((!fList.count()) || ((unsigned) fDBIndex >= fList.count()))
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Peculiar file index, bailing out." << endl;
+#endif
+ KPILOT_DELETE(fTimer);
+ fDBIndex = (-1);
+ emit logProgress(i18n("Done Installing Files"), 100);
+ delayDone();
+ return;
+ }
+
+ const QString filePath = fDir + fList[fDBIndex];
+ const QString fileName = fList[fDBIndex];
+
+ fDBIndex++;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Installing file " << filePath << endl;
+#endif
+
+ QString m = i18n("Installing %1").arg(fileName);
+ emit logProgress(m,(100 * fDBIndex) / (fList.count()+1));
+ m+=CSL1("\n");
+ emit addSyncLogEntry(m,false /* Don't print in KPilot's log. */ );
+
+ struct pi_file *f = 0L;
+
+ // Check DB is ok, return false after warning user
+ if (!resourceOK(fileName,filePath)) goto nextFile;
+
+ f = pi_file_open(const_cast <char *>
+ ((const char *) QFile::encodeName(filePath)));
+
+
+#if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
+ if (pi_file_install(f, pilotSocket(), 0) < 0)
+#else
+ if (pi_file_install(f, pilotSocket(), 0, NULL) < 0)
+#endif
+ {
+ WARNINGKPILOT << "Failed to install." << endl;
+
+
+ emit logError(i18n("Cannot install file &quot;%1&quot;.").
+ arg(fileName));
+ }
+ else
+ {
+ QFile::remove(filePath);
+ }
+
+
+nextFile:
+ if (f) pi_file_close(f);
+ if (fDBIndex == -1)
+ {
+ fTimer->stop();
+ delayDone();
+ // emit syncDone(this);
+ }
+}
+
+// Check that the given file path is a good resource
+// file - in particular that the resource name is ok.
+bool FileInstallAction::resourceOK(const QString &fileName, const QString &filePath)
+{
+ FUNCTIONSETUP;
+
+ if (!QFile::exists(filePath))
+ {
+ emit logError(i18n("Unable to open file &quot;%1&quot;.").
+ arg(fileName));
+ return false;
+ }
+
+ struct pi_file *f = pi_file_open(const_cast <char *>
+ ((const char *) QFile::encodeName(filePath)));
+
+ if (!f)
+ {
+ emit logError(i18n("Unable to open file &quot;%1&quot;.").
+ arg(fileName));
+ return false;
+ }
+
+ struct DBInfo info;
+#if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
+ if (pi_file_get_info(f,&info) < 0)
+ {
+ emit logError(i18n("Unable to read file &quot;%1&quot;.").
+ arg(fileName));
+ return false;
+ }
+#else
+ pi_file_get_info(f,&info);
+#endif
+
+ // Looks like strlen, but we can't be sure of a NUL
+ // termination.
+ info.name[sizeof(info.name)-1]=0;
+ bool r = (strlen(info.name) < 32);
+ pi_file_close(f);
+
+ if (!r)
+ {
+ emit logError(i18n("The database in &quot;%1&quot; has a "
+ "resource name that is longer than 31 characters. "
+ "This suggests a bug in the tool used to create the database. "
+ "KPilot cannot install this database.").arg(fileName));
+ }
+
+ return r;
+}
+
+/* virtual */ QString FileInstallAction::statusString() const
+{
+ FUNCTIONSETUP;
+ if (fDBIndex < 0)
+ {
+ return QString(CSL1("Idle"));
+ }
+ else
+ {
+ if ((unsigned) fDBIndex >= fList.count())
+ {
+ return QString(CSL1("Index out of range"));
+ }
+ else
+ {
+ return QString(CSL1("Installing %1")).arg(fList[fDBIndex]);
+ }
+ }
+}
+
+CheckUser::CheckUser(KPilotLink * p, QWidget * vp):
+ SyncAction(p, vp, "userCheck")
+{
+ FUNCTIONSETUP;
+
+}
+
+CheckUser::~CheckUser()
+{
+ FUNCTIONSETUP;
+}
+
+/* virtual */ bool CheckUser::exec()
+{
+ FUNCTIONSETUP;
+
+ QString guiUserName = KPilotSettings::userName();
+ QString pilotUserName = fHandle->getPilotUser().name();
+ bool pilotUserEmpty = pilotUserName.isEmpty();
+ // 4 cases to handle:
+ // guiUserName empty / not empty
+ // pilotUserName empty / not empty
+ //
+ //
+ if (guiUserName.isEmpty())
+ {
+ if (pilotUserEmpty)
+ {
+ QString defaultUserName =
+ i18n("A common name", "John Doe");
+
+ QString q = i18n("<qt>Neither KPilot nor the "
+ "handheld have a username set. "
+ "They <i>should</i> be set. "
+ "Should KPilot set them to a default value "
+ "(<i>%1</i>)?</qt>").arg(defaultUserName);
+
+ if (questionYesNo(q, i18n("User Unknown") /* ,"askUserNone" */) ==
+ KMessageBox::Yes)
+ {
+ KPilotSettings::setUserName(defaultUserName);
+ fHandle->getPilotUser().setName(defaultUserName);
+ guiUserName=defaultUserName;
+ pilotUserName=defaultUserName;
+ }
+
+ }
+ else
+ {
+ QString q = i18n("<qt>The handheld has a username set "
+ "(<i>%1</i>) but KPilot does not. Should "
+ "KPilot use this username in future?</qt>").
+ arg(pilotUserName);
+
+ if (questionYesNo(q, i18n("User Unknown") /* ,"askUserSome" */ ) ==
+ KMessageBox::Yes)
+ {
+ KPilotSettings::setUserName(pilotUserName);
+ guiUserName=pilotUserName;
+ }
+ }
+ }
+ else
+ {
+ if (pilotUserEmpty)
+ {
+ QString q = CSL1("<qt>");
+ q += i18n("KPilot has a username set "
+ "(<i>%1</i>) but the handheld does not. "
+ "Should KPilot's username be set in the "
+ "handheld as well?").arg(guiUserName);
+ q += i18n("<br/>(<i>Note:</i> If your handheld "
+ "has been reset to factory defaults, you "
+ "should use <i>Restore</i> instead of a "
+ "regular HotSync. Click on Cancel to "
+ "stop this sync.)");
+ q += CSL1("</qt>");
+
+ int r = questionYesNoCancel(q, i18n("User Unknown"));
+ switch (r)
+ {
+ case KMessageBox::Yes:
+ DEBUGKPILOT << fname
+ << ": Setting user name in pilot to "
+ << guiUserName << endl;
+ fHandle->getPilotUser().setName(guiUserName);
+ pilotUserName=guiUserName;
+ break;
+ case KMessageBox::No:
+ // Nothing to do .. continue with sync
+ break;
+ case KMessageBox::Cancel:
+ default:
+ return false;
+ }
+ }
+ else
+ {
+ if (guiUserName != pilotUserName)
+ {
+ QString q = i18n("<qt>The handheld thinks that "
+ "the username is %1; "
+ "however, KPilot says you are %2."
+ "Which of these is the correct name?\n"
+ "If you click on Cancel, the sync will proceed, "
+ "but the usernames will not be changed.</qt>").
+ arg(pilotUserName).
+ arg(guiUserName);
+
+ int r = questionYesNoCancel(q,
+ i18n("User Mismatch"),
+ QString::null,
+ 20,
+ i18n("Use KPilot Name"),
+ i18n("Use Handheld Name"));
+ switch (r)
+ {
+ case KMessageBox::Yes:
+ fHandle->getPilotUser().setName(guiUserName);
+ pilotUserName=guiUserName;
+ break;
+ case KMessageBox::No:
+ KPilotSettings::setUserName(pilotUserName);
+ guiUserName=pilotUserName;
+ break;
+ case KMessageBox::Cancel:
+ default:
+ // TODO: cancel the sync... Or just don't change any user name?
+ break;
+ }
+ }
+ }
+ }
+
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": User name set to pc <"
+ << guiUserName
+ << "> hh <"
+ << fHandle->getPilotUser().name() << ">" << endl;
+#endif
+
+ KPilotSettings::writeConfig();
+
+ // Now we've established which user will be used,
+ // fix the database location for local databases.
+ //
+ //
+ QString pathName = KGlobal::dirs()->saveLocation("data",
+ CSL1("kpilot/DBBackup/"));
+ if (!guiUserName.isEmpty())
+ {
+ pathName.append(guiUserName);
+ pathName.append(CSL1("/"));
+ }
+ PilotLocalDatabase::setDBPath(pathName);
+
+ delayDone();
+ return true;
+}
+
+class RestoreInfo
+{
+public:
+ struct DBInfo DBInfo;
+ QString path;
+} ;
+
+class RestoreAction::Private
+{
+public:
+ QString fPreferRestoreDir; /**< Preference setting where to get data from. */
+
+ QValueList<RestoreInfo> fDBList;
+ QTimer fTimer;
+ QValueList<RestoreInfo>::ConstIterator fDBIterator;
+ int fDBIndex;
+};
+
+
+RestoreAction::RestoreAction(KPilotLink * p, QWidget * visible ) :
+ SyncAction(p, visible, "restoreAction")
+{
+ FUNCTIONSETUP;
+
+ fP = new Private;
+}
+
+void RestoreAction::setDirectory( const QString &path )
+{
+ fP->fPreferRestoreDir = path;
+}
+
+/* virtual */ bool RestoreAction::exec()
+{
+ FUNCTIONSETUP;
+
+ QString dirname;
+ if (fP->fPreferRestoreDir.isEmpty())
+ {
+ dirname = PilotLocalDatabase::getDBPath();
+ }
+ else
+ {
+ dirname = fP->fPreferRestoreDir;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Restoring user " << dirname << endl;
+#endif
+
+ QDir dir(dirname, QString::null, QDir::Name,
+ QDir::Files | QDir::Readable | QDir::NoSymLinks);
+
+ if (!dir.exists())
+ {
+ WARNINGKPILOT << "Restore directory "
+ << dirname << " does not exist." << endl;
+ fActionStatus = Error;
+ addSyncLogEntry(i18n("Restore directory does not exist.") +
+ CSL1(" ") + i18n("Restore not performed."));
+ return false;
+ }
+
+ dirname = dir.absPath();
+ if (questionYesNo(i18n("<qt>Are you sure you want to completely "
+ "restore your Pilot from the backup directory "
+ "(<i>%1</i>)? This will erase any information "
+ "you currently have on your Pilot.</qt>").
+ arg(dirname),
+ i18n("Restore Pilot")) != KMessageBox::Yes)
+ {
+ emit logError(i18n("Restore <i>not</i> performed."));
+
+ addSyncLogEntry(i18n("Canceled by user.") + CSL1(" ") +
+ i18n("Restore not performed."));
+
+ // You might call this an error, but that causes
+ // a frightening message in the log .. and the
+ // user already _knows_ the restore didn't happen.
+ // So instead, act as if everything was ok.
+ delayDone();
+ return true;
+ }
+
+
+ emit logProgress(i18n("Restoring %1...").arg(QString::null),1);
+
+ for (unsigned int i = 0; i < dir.count(); i++)
+ {
+ QString s;
+ RestoreInfo info;
+
+ s = dirname + QDir::separator() + dir[i];
+
+ DEBUGKPILOT << fname
+ << ": Adding " << s << " to restore list." << endl;
+
+ if ( PilotLocalDatabase::infoFromFile( s, &info.DBInfo ) )
+ {
+ info.path = s;
+ fP->fDBList.append(info);
+ }
+ else
+ {
+ WARNINGKPILOT << "Can't open " << s << endl;
+ logMessage(i18n("File '%1' cannot be read.").arg(s));
+ }
+ }
+
+ fP->fDBIndex = 0;
+ fP->fDBIterator = fP->fDBList.begin();
+ fActionStatus = InstallingFiles;
+
+ QObject::connect(&(fP->fTimer), SIGNAL(timeout()),
+ this, SLOT(installNextFile()));
+
+ fP->fTimer.start(0, false);
+ return true;
+}
+
+/* slot */ void RestoreAction::installNextFile()
+{
+ FUNCTIONSETUP;
+
+ Q_ASSERT(fActionStatus == InstallingFiles);
+
+
+ if (fP->fDBIterator == fP->fDBList.end())
+ {
+ fP->fTimer.stop();
+
+ fActionStatus = Done;
+ addSyncLogEntry(i18n("OK."));
+ delayDone();
+ return;
+ }
+
+ const RestoreInfo dbi = *(fP->fDBIterator);
+ ++(fP->fDBIterator);
+ ++(fP->fDBIndex);
+
+ DEBUGKPILOT << fname << ": Trying to install " << dbi.path << endl;
+
+ if (openConduit() < 0)
+ {
+ WARNINGKPILOT << "Restore apparently canceled." << endl;
+ logMessage(i18n("Restore incomplete."));
+ fActionStatus = Done;
+ emit syncDone(this);
+
+ return;
+ }
+
+ QFileInfo databaseInfo(dbi.path);
+ addSyncLogEntry(databaseInfo.fileName());
+ emit logProgress(i18n("Restoring %1...").arg(databaseInfo.fileName()),
+ (100*fP->fDBIndex) / (fP->fDBList.count()+1)) ;
+
+ if ( !deviceLink()->installFiles( dbi.path, false /* don't delete */ ) )
+ {
+ WARNINGKPILOT << "Couldn't restore " << dbi.path << endl;
+ logError(i18n("Cannot restore file `%1'.")
+ .arg(databaseInfo.fileName()));
+ }
+}
+
+/* virtual */ QString RestoreAction::statusString() const
+{
+ FUNCTIONSETUP;
+ QString s;
+
+ switch (status())
+ {
+ case InstallingFiles:
+ s.append(CSL1("Installing Files ("));
+ s.append(QString::number(fP->fDBIndex));
+ s.append(CSL1(")"));
+ break;
+ case GettingFileInfo:
+ s.append(CSL1("Getting File Info ("));
+ s.append(QString::number(fP->fDBIndex));
+ s.append(CSL1(")"));
+ break;
+ default:
+ return SyncAction::statusString();
+ }
+
+ return s;
+}
+
+
+
+BackupAction::Thread::Thread( BackupAction *parent,
+ KPilotLink *link,
+ const QString &filename,
+ const DBInfo *info )
+{
+ fParent = parent;
+ fLink = link;
+ fFilename = filename;
+ memcpy(&fDBInfo,info,sizeof(DBInfo));
+}
+
+void BackupAction::Thread::run()
+{
+ if (fLink->retrieveDatabase(fFilename,&fDBInfo))
+ {
+ // Successful.
+ QApplication::postEvent( fParent, new QEvent( (QEvent::Type)TerminateOK ) );
+ }
+ else
+ {
+ // Failed
+ QApplication::postEvent( fParent, new QEvent( (QEvent::Type)TerminateFailure ) );
+ }
+}
+
+
diff --git a/kpilot/kpilot/hotSync.h b/kpilot/kpilot/hotSync.h
new file mode 100644
index 000000000..580c2d616
--- /dev/null
+++ b/kpilot/kpilot/hotSync.h
@@ -0,0 +1,175 @@
+#ifndef _KPILOT_HOTSYNC_H
+#define _KPILOT_HOTSYNC_H
+/* hotSync.h KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2006 Adriaan de Groot <[email protected]>
+**
+** This file defines SyncActions, which are used to perform some specific
+** task during a HotSync. Conduits are not included here, nor are
+** sync actions requiring user interaction. Those can be found in the
+** conduits subdirectory or interactiveSync.h.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+class QTimer;
+
+#include "syncAction.h"
+
+class CheckUser : public SyncAction
+{
+public:
+ CheckUser(KPilotLink *p,QWidget *w=0L);
+ virtual ~CheckUser();
+
+protected:
+ virtual bool exec();
+} ;
+
+
+class BackupAction : public SyncAction
+{
+Q_OBJECT
+
+public:
+ /** Constructor. Back up all the databases on
+ * the link to a directory on the local disk.
+ * If @p full is @c true, then a full backup,
+ * including applications, is done. Otherwise,
+ * only user data is backed-up.
+ *
+ * @see setDirectory()
+ */
+ BackupAction(KPilotLink *, bool full);
+
+ enum Status { Init,
+ Error,
+ FastBackup,
+ FullBackup,
+ BackupIncomplete,
+ BackupEnded,
+ BackupComplete
+ } ;
+ virtual QString statusString() const;
+
+ /** By default, a path based on the user name (either
+ * on the handheld or set in KPilot) is used to
+ * determine the backup directory name ( generally
+ * $KDEHOME/share/apps/kpilot/DBBackup/_user_name_ ).
+ * Use setDirectory() to change that and use a given
+ * @p path as target for the backup. Use an empty
+ * @p path to restore the default behavior of using
+ * the username.
+ */
+ void setDirectory( const QString &path );
+
+ // Reimplemented to support threaded backup.
+ virtual bool event( QEvent *e );
+
+protected:
+ virtual bool exec();
+
+private:
+ /** Finish the backup and clean up resources. */
+ void endBackup();
+
+ /** Copy the database indicated by @p info to the local
+ * disk; returns @c false on failure.
+ */
+ bool startBackupThread(DBInfo *info);
+
+private slots:
+ /** Implementation detail: databases get backed-up
+ * one at a time because the backup function in
+ * pilot-link isn't threaded.
+ */
+ void backupOneDB();
+
+private:
+ class Private;
+ Private *fP;
+ class Thread;
+ Thread *fBackupThread;
+} ;
+
+class FileInstallAction : public SyncAction
+{
+Q_OBJECT
+public:
+ FileInstallAction(KPilotLink *,
+ const QString &fileDir);
+ virtual ~FileInstallAction();
+
+ virtual QString statusString() const;
+
+protected:
+ virtual bool exec();
+
+protected slots:
+ void installNextFile();
+
+private:
+ int fDBIndex;
+ QTimer *fTimer;
+ QString fDir;
+ QStringList fList;
+
+ // TODO: not const because it calls logError(), which is
+ // non-const (but might be - can signals be const, anyway?)
+ bool resourceOK(const QString &, const QString &) /* const */ ;
+} ;
+
+class RestoreAction : public SyncAction
+{
+Q_OBJECT
+public:
+ RestoreAction(KPilotLink *,QWidget *w=0L);
+
+ typedef enum { InstallingFiles, GettingFileInfo,Done } Status;
+ virtual QString statusString() const;
+
+ /** By default, a path based on the user name (either
+ * on the handheld or set in KPilot) is used to
+ * determine the restory directory name ( generally
+ * $KDEHOME/share/apps/kpilot/DBBackup/_user_name_ ).
+ * Use setDirectory() to change that and use a given
+ * @p path as target for the source. Use an empty
+ * @p path to restore the default behavior of using
+ * the username.
+ */
+ void setDirectory( const QString &path );
+
+protected:
+ virtual bool exec();
+
+protected slots:
+ void installNextFile();
+
+private:
+ class Private;
+ Private *fP;
+} ;
+
+#endif
diff --git a/kpilot/kpilot/internalEditorAction.cc b/kpilot/kpilot/internalEditorAction.cc
new file mode 100644
index 000000000..cee58ba21
--- /dev/null
+++ b/kpilot/kpilot/internalEditorAction.cc
@@ -0,0 +1,394 @@
+/* KPilot
+**
+** Copyright (C) 2003 Reinhold Kainhofer <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <options.h>
+
+#include <qtimer.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <kmessagebox.h>
+#include <kdialog.h>
+#include <ktextedit.h>
+#include <kdialogbase.h>
+
+#include <pilotRecord.h>
+#include <pilotLocalDatabase.h>
+#include <pilotDatabase.h>
+#include <pilotSerialDatabase.h>
+#include "kpilotConfig.h"
+#include "internalEditorAction.h"
+
+#include <pilotAddress.h>
+#include <pilotMemo.h>
+#include <pilotDateEntry.h>
+#include <pilotTodoEntry.h>
+
+#include "khexedit/byteseditinterface.h"
+using namespace KHE;
+
+InternalEditorAction::InternalEditorAction(KPilotLink * p) :
+ SyncAction(p, "internalSync")
+{
+ FUNCTIONSETUP;
+}
+
+bool InternalEditorAction::exec()
+{
+ FUNCTIONSETUP;
+ emit logMessage(i18n("[Internal Editors]"));
+ fInternalEditorSyncStatus=eSyncStarted;
+ QTimer::singleShot(0, this, SLOT(syncDirtyDB()));
+ return true;
+}
+
+void InternalEditorAction::syncDirtyDB()
+{
+ FUNCTIONSETUP;
+
+ if (fInternalEditorSyncStatus!=eSyncDirtyDB)
+ {
+ fInternalEditorSyncStatus=eSyncDirtyDB;
+ dirtyDBs=KPilotSettings::dirtyDatabases();
+ emit logMessage(i18n("Databases with changed records: %1").arg(dirtyDBs.join(CSL1(", "))));
+ dbIter=dirtyDBs.begin();
+ }
+ else
+ {
+ dbIter++;
+ }
+ if (dbIter==dirtyDBs.end())
+ {
+ KPilotSettings::setDirtyDatabases(QStringList());
+ KPilotConfig::sync();
+ QTimer::singleShot(0, this, SLOT(syncFlagsChangedDB()));
+ return;
+ }
+#ifdef DEBUG
+ DEBUGKPILOT<<"syncDirtyDB for DB "<<(*dbIter)<<endl;
+#endif
+ // open the local and the serial database and copy every
+ // changed record from the PC to the handheld
+
+ PilotRecord*rec=0L;
+ PilotLocalDatabase*localDB=new PilotLocalDatabase(*dbIter, false);
+ PilotDatabase *serialDB= deviceLink()->database(*dbIter);
+ if (!localDB->isOpen() || !serialDB->isOpen())
+ {
+ emit logError(i18n("Unable to open the serial or local database for %1. "
+ "Skipping it.").arg(*dbIter));
+ goto nextDB;
+ }
+ while ( (rec=localDB->readNextModifiedRec()) )
+ {
+ int id=rec->id();
+#ifdef DEBUG
+ DEBUGKPILOT<<"ID of modified record is "<<id<<endl;
+ DEBUGKPILOT<<endl<<endl;
+#endif
+ if (id>0)
+ {
+ PilotRecord*serrec=serialDB->readRecordById(id);
+ if (serrec && (serrec->isModified()) )
+ {
+ bool kpilotOverrides=queryUseKPilotChanges(*dbIter, id, rec, serrec, localDB);
+ if (kpilotOverrides)
+ serialDB->writeRecord(rec);
+ else
+ localDB->writeRecord(serrec);
+ }
+ else
+ serialDB->writeRecord(rec);
+ }
+ else
+ {
+#ifdef DEBUG
+ DEBUGKPILOT<<"Generating ID for Record "<<rec->id()<<" with data "<<endl;
+ DEBUGKPILOT<<rec->data()<<endl;
+ DEBUGKPILOT<<"-----------------------------------------"<<endl;
+#endif
+ int id=serialDB->writeRecord(rec);
+ rec->setID(id);
+#ifdef DEBUG
+ DEBUGKPILOT<<"New ID is "<<id<<endl;
+ DEBUGKPILOT<<endl<<endl<<endl;
+#endif
+ //localDB->writeRecord(rec);
+ localDB->updateID(id);
+ }
+ KPILOT_DELETE(rec);
+ }
+
+nextDB:
+ localDB->resetSyncFlags();
+ KPILOT_DELETE(localDB);
+ KPILOT_DELETE(serialDB);
+ QTimer::singleShot(0, this, SLOT(syncDirtyDB()));
+}
+
+bool InternalEditorAction::queryUseKPilotChanges(QString dbName, recordid_t id, PilotRecord*localrec, PilotRecord*serialrec, PilotDatabase*db)
+{
+ FUNCTIONSETUP;
+ bool knownDB=true;
+ QString localEntry, serialEntry, recType(i18n("record"));
+
+ if (dbName==CSL1("AddressDB") && db)
+ {
+ PilotAddressInfo info(db);
+
+ PilotAddress localAddr(localrec);
+ PilotAddress serialAddr(serialrec);
+ localEntry=localAddr.getTextRepresentation(&info,Qt::RichText);
+ serialEntry=serialAddr.getTextRepresentation(&info,Qt::RichText);
+ recType=i18n("address");
+ }
+ else
+ if (dbName==CSL1("ToDoDB") && db)
+ {
+ PilotToDoInfo info(db);
+
+ PilotTodoEntry localTodo(localrec);
+ PilotTodoEntry serialTodo(serialrec);
+ localEntry=localTodo.getTextRepresentation(Qt::RichText);
+ serialEntry=serialTodo.getTextRepresentation(Qt::RichText);
+ recType=i18n("to-do entry");
+ }
+ else
+ if (dbName==CSL1("MemoDB"))
+ {
+ PilotMemo localMemo(localrec);
+ PilotMemo serialMemo(serialrec);
+ localEntry=localMemo.getTextRepresentation(Qt::RichText);
+ serialEntry=serialMemo.getTextRepresentation(Qt::RichText);
+ recType=i18n("memo");
+ }
+ else
+ if (dbName==CSL1("DatebookDB"))
+ {
+ PilotDateInfo info(db);
+
+ PilotDateEntry localEvent(localrec);
+ PilotDateEntry serialEvent(serialrec);
+ localEntry=localEvent.getTextRepresentation(Qt::RichText);
+ serialEntry=serialEvent.getTextRepresentation(Qt::RichText);
+ recType=i18n("calendar entry");
+ }
+ else
+ {
+ knownDB=false;
+ }
+
+ QString dialogText(i18n("The %1 with ID %2 of the database \"%3\" was changed "
+ "on the handheld and in the internal editor. Shall the changes in KPilot be copied to the handheld, and so override the changes there?").
+ arg(recType).arg(id).arg(dbName));
+
+ KDialogBase*resdlg=new KDialogBase(0L, "internalresolutiondialog", true,
+ i18n("Conflict in database %1").arg(*dbIter),
+ KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true,
+ i18n("Use KPilot"), i18n("Use Handheld") );
+ resdlg->setButtonText(KDialogBase::Ok, i18n("Use &KPilot"));
+ resdlg->setButtonText(KDialogBase::Cancel, i18n("Use &Handheld"));
+
+ QWidget*page=new QWidget(resdlg);
+ resdlg->setMainWidget(page);
+ QGridLayout*layout = new QGridLayout( page, 1, 1);
+
+ QLabel *label=new QLabel(dialogText, page);
+ label->setAlignment( QLabel::WordBreak );
+ layout->addMultiCellWidget( label, 0,0, 0,1 );
+
+ layout->addItem( new QSpacerItem( 20, 10, QSizePolicy::Minimum,
+ QSizePolicy::Fixed ), 1, 0 );
+
+ if (knownDB)
+ {
+ label=new QLabel(i18n("Entry in KPilot"), page);
+ layout->addWidget( label, 2,0);
+
+ KTextEdit*textBrowser = new KTextEdit(CSL1("<qt>")+localEntry+CSL1("</qt>"), QString::null, page);
+ textBrowser->setReadOnly(true);
+ layout->addWidget( textBrowser, 3,0);
+
+ label=new QLabel(i18n("Entry on Handheld"), page);
+ layout->addWidget( label, 2,1);
+
+ textBrowser = new KTextEdit(CSL1("<qt>")+serialEntry+CSL1("</qt>"), QString::null, page);
+ textBrowser->setReadOnly(true);
+ layout->addWidget( textBrowser, 3,1);
+ }
+ else
+ {
+ label=new QLabel(i18n("Entry in KPilot"), page);
+ layout->addMultiCellWidget( label, 2,2,0,1);
+
+ // directly display the record's data:
+ QWidget *hexEdit = KHE::createBytesEditWidget( page, "LocalBufferEdit" );
+ if( hexEdit )
+ {
+ KHE::BytesEditInterface* hexEditIf = KHE::bytesEditInterface( hexEdit );
+ Q_ASSERT( hexEditIf ); // This should not fail!
+ if( hexEditIf )
+ {
+ hexEditIf->setData( localrec->data(), localrec->size() );
+// Do we need the following call at all???
+// hexEditIf->setMaxDataSize( localrec->getLen() );
+ hexEditIf->setReadOnly( true );
+ }
+ }
+ else
+ {
+ QLabel*tmpW = new QLabel( i18n("To view and edit the record data, please install a hex editor (e.g. khexedit from kdeutils)."), page );
+ tmpW->setBackgroundMode( Qt::PaletteMid );
+ tmpW->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter | Qt::WordBreak);
+ tmpW->setFrameShape( QFrame::Panel );
+ tmpW->setFrameShadow( QFrame::Sunken );
+ hexEdit = tmpW;
+ }
+ layout->addMultiCellWidget( hexEdit, 3,3,0,1);
+
+ label=new QLabel(i18n("Entry on Handheld"), page);
+ layout->addMultiCellWidget( label, 4,4,0,1);
+
+ // directly display the record's data:
+ hexEdit = KHE::createBytesEditWidget( page, "SerialBufferEdit" );
+ if( hexEdit )
+ {
+ KHE::BytesEditInterface* hexEditIf = KHE::bytesEditInterface( hexEdit );
+ Q_ASSERT( hexEditIf ); // This should not fail!
+ if( hexEditIf )
+ {
+ hexEditIf->setData( serialrec->data(), serialrec->size() );
+// Do we need the following call at all???
+// hexEditIf->setMaxDataSize( serialrec->getLen() );
+ hexEditIf->setReadOnly( true );
+ }
+ }
+ else
+ {
+ QLabel*tmpW = new QLabel( i18n("To view and edit the record data, please install a hex editor (e.g. khexedit from kdeutils)."), page );
+ tmpW->setBackgroundMode( Qt::PaletteMid );
+ tmpW->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter | Qt::WordBreak);
+ tmpW->setFrameShape( QFrame::Panel );
+ tmpW->setFrameShadow( QFrame::Sunken );
+ hexEdit = tmpW;
+ }
+ layout->addMultiCellWidget( hexEdit, 5,5,0,1);
+ }
+
+ int res=resdlg->exec();
+ KPILOT_DELETE(resdlg);
+
+ return res==KDialogBase::Accepted;
+}
+
+
+void InternalEditorAction::syncFlagsChangedDB()
+{
+ FUNCTIONSETUP;
+ if (fInternalEditorSyncStatus!=eSyncFlagsChangedDB)
+ {
+ fInternalEditorSyncStatus=eSyncFlagsChangedDB;
+ dirtyDBs=KPilotSettings::flagsChangedDatabases();
+ emit logMessage(i18n("Databases with changed flags: %1").arg(dirtyDBs.join(CSL1(", "))));
+ dbIter=dirtyDBs.begin();
+ }
+ else
+ {
+ dbIter++;
+ }
+ if (dbIter==dirtyDBs.end())
+ {
+ KPilotSettings::setFlagsChangedDatabases(QStringList());
+ KPilotConfig::sync();
+ QTimer::singleShot(0, this, SLOT(syncAppBlockChangedDB()));
+ return;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT<<"syncFlagsChangedDB for DB "<<(*dbIter)<<endl;
+#endif
+emit logError(i18n("Setting the database flags on the handheld is not yet supported."));
+QTimer::singleShot(0, this, SLOT(syncAppBlockChangedDB()));
+return;
+
+ PilotLocalDatabase*localDB=new PilotLocalDatabase(*dbIter, false);
+ PilotDatabase *serialDB=deviceLink()->database(*dbIter);
+
+ // open the local and the serial database and copy the flags over
+ // TODO: Implement the copying
+ // TODO: Is there a way to detect if the flags were changed on the handheld?
+
+ KPILOT_DELETE(localDB);
+ KPILOT_DELETE(serialDB);
+ QTimer::singleShot(0, this, SLOT(syncAppBlockChangedDB()));
+}
+
+void InternalEditorAction::syncAppBlockChangedDB()
+{
+ FUNCTIONSETUP;
+ if (fInternalEditorSyncStatus!=eSyncAppBlockChangedDB)
+ {
+ fInternalEditorSyncStatus=eSyncAppBlockChangedDB;
+ dirtyDBs=KPilotSettings::appBlockChangedDatabases();
+ emit logMessage(i18n("Databases with changed AppBlock: %1").arg(dirtyDBs.join(CSL1(", "))));
+ dbIter=dirtyDBs.begin();
+ }
+ else
+ {
+ dbIter++;
+ }
+ if (dbIter==dirtyDBs.end())
+ {
+ KPilotSettings::setAppBlockChangedDatabases(QStringList());
+ KPilotConfig::sync();
+ QTimer::singleShot(0, this, SLOT(cleanup()));
+ return;
+ }
+#ifdef DEBUG
+ DEBUGKPILOT<<"syncAppBlockChangedDB for DB "<<(*dbIter)<<endl;
+#endif
+
+ PilotLocalDatabase*localDB=new PilotLocalDatabase(*dbIter, false);
+ PilotDatabase *serialDB=deviceLink()->database(*dbIter);
+
+ unsigned char*appBlock=new unsigned char[0xFFFF];
+ int len=localDB->readAppBlock(appBlock, 0xFFFF);
+ // TODO: Check if the app block was changed on the handheld, and if so, do conflict resolution
+ serialDB->writeAppBlock(appBlock, len);
+
+ KPILOT_DELETE(localDB);
+ KPILOT_DELETE(serialDB);
+ QTimer::singleShot(0, this, SLOT(syncAppBlockChangedDB()));
+}
+
+void InternalEditorAction::cleanup()
+{
+ FUNCTIONSETUP;
+ fInternalEditorSyncStatus=eSyncFinished;
+ emit syncDone(this);
+}
+
+#include "internalEditorAction.moc"
diff --git a/kpilot/kpilot/internalEditorAction.h b/kpilot/kpilot/internalEditorAction.h
new file mode 100644
index 000000000..8e988348d
--- /dev/null
+++ b/kpilot/kpilot/internalEditorAction.h
@@ -0,0 +1,68 @@
+#ifndef _INTERNALEDITORACTION_H_
+#define _INTERNALEDITORACTION_H_
+/* internalEditorAction.h KPilot
+**
+** Copyright (C) 2003 Reinhold Kainhofer <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include <qstringlist.h>
+
+#include "syncAction.h"
+
+
+class InternalEditorAction : public SyncAction
+{
+Q_OBJECT
+
+public:
+ InternalEditorAction(KPilotLink *);
+ ~InternalEditorAction() {}
+
+protected:
+ virtual bool exec();
+
+private:
+private slots:
+ void syncDirtyDB();
+ void syncFlagsChangedDB();
+ void syncAppBlockChangedDB();
+ void cleanup();
+
+private:
+ bool queryUseKPilotChanges(QString dbName, recordid_t id,
+ PilotRecord*localrec, PilotRecord*serialrec, PilotDatabase*db);
+ QStringList dirtyDBs;
+ QStringList::Iterator dbIter;
+ enum eInternalEditorSyncStatus {
+ eSyncStarted,
+ eSyncDirtyDB,
+ eSyncFlagsChangedDB,
+ eSyncAppBlockChangedDB,
+ eSyncFinished
+ } fInternalEditorSyncStatus;
+} ;
+
+#endif
diff --git a/kpilot/kpilot/kpilot.cc b/kpilot/kpilot/kpilot.cc
new file mode 100644
index 000000000..9207db02a
--- /dev/null
+++ b/kpilot/kpilot/kpilot.cc
@@ -0,0 +1,1136 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This is the main program in KPilot.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "options.h"
+
+#include <qfile.h>
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qvbox.h>
+#include <qtimer.h>
+
+#include <kjanuswidget.h>
+#include <kurl.h>
+#include <kmessagebox.h>
+#include <kstatusbar.h>
+#include <kconfig.h>
+#include <kwin.h>
+#include <kcombobox.h>
+#include <kmenubar.h>
+#include <kstandarddirs.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <kaction.h>
+#include <kactionclasses.h>
+#include <kstdaction.h>
+#include <kuniqueapplication.h>
+#include <kkeydialog.h>
+#include <kedittoolbar.h>
+#include <kcmultidialog.h>
+#include <kprogress.h>
+#include <klibloader.h>
+
+
+#include "kpilotConfigDialog.h"
+#include "kpilotConfig.h"
+#include "kpilotConfigWizard.h"
+
+#include "pilotComponent.h"
+#include "pilotDatabase.h"
+
+#include "addressWidget.h"
+#include "memoWidget.h"
+#include "fileInstallWidget.h"
+#include "logWidget.h"
+#include "dbviewerWidget.h"
+#include "datebookWidget.h"
+#include "todoWidget.h"
+
+#include "conduitConfigDialog.h"
+
+#include "pilotDaemonDCOP.h"
+#include "pilotDaemonDCOP_stub.h"
+
+#include "kpilot.moc"
+
+class KPilotInstaller::KPilotPrivate
+{
+public:
+ typedef QPtrList<PilotComponent> ComponentList;
+
+private:
+ ComponentList fPilotComponentList;
+
+public:
+ ComponentList &list() { return fPilotComponentList; } ;
+} ;
+
+KPilotInstaller::KPilotInstaller() :
+ DCOPObject("KPilotIface"),
+ KMainWindow(0),
+ fDaemonStub(new PilotDaemonDCOP_stub("kpilotDaemon",
+ "KPilotDaemonIface")),
+ fP(new KPilotPrivate),
+ fQuitAfterCopyComplete(false),
+ fManagingWidget(0L),
+ fDaemonWasRunning(true),
+ fAppStatus(Startup),
+ fFileInstallWidget(0L),
+ fLogWidget(0L)
+{
+ FUNCTIONSETUP;
+
+ readConfig();
+ setupWidget();
+
+ PilotRecord::allocationInfo();
+ fConfigureKPilotDialogInUse = false;
+}
+
+KPilotInstaller::~KPilotInstaller()
+{
+ FUNCTIONSETUP;
+ killDaemonIfNeeded();
+ delete fDaemonStub;
+ PilotRecord::allocationInfo();
+ (void) PilotDatabase::instanceCount();
+}
+
+void KPilotInstaller::killDaemonIfNeeded()
+{
+ FUNCTIONSETUP;
+ if (KPilotSettings::killDaemonAtExit())
+ {
+ if (!fDaemonWasRunning)
+ {
+ DEBUGKPILOT << fname << ": Killing daemon." << endl;
+ getDaemon().quitNow();
+ }
+ }
+}
+
+void KPilotInstaller::startDaemonIfNeeded()
+{
+ FUNCTIONSETUP;
+
+ fAppStatus=WaitingForDaemon;
+
+ QString daemonError;
+ QCString daemonDCOP;
+ int daemonPID;
+
+ QString s = getDaemon().statusString();
+
+ DEBUGKPILOT << fname << ": Daemon status is "
+ << ( s.isEmpty() ? CSL1("<none>") : s ) << endl;
+
+ if ((s.isEmpty()) || (!getDaemon().ok()))
+ {
+ DEBUGKPILOT << fname
+ << ": Daemon not responding, trying to start it."
+ << endl;
+ fLogWidget->addMessage(i18n("Starting the KPilot daemon ..."));
+ fDaemonWasRunning = false;
+ }
+ else
+ {
+ fDaemonWasRunning = true;
+ }
+
+ if (!fDaemonWasRunning && KApplication::startServiceByDesktopName(
+ CSL1("kpilotdaemon"),
+ QString::null, &daemonError, &daemonDCOP, &daemonPID
+ , "0" /* no notify */
+ ))
+ {
+ WARNINGKPILOT << ": Can't start daemon : " << daemonError << endl;
+ if (fLogWidget)
+ {
+ fLogWidget->addMessage(i18n("Could not start the "
+ "KPilot daemon. The system error message "
+ "was: &quot;%1&quot;").arg(daemonError));
+ }
+ fAppStatus=Error;
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": Daemon status is " << s << endl;
+ if (fLogWidget)
+ {
+ int wordoffset;
+ s.remove(0,12);
+ wordoffset=s.find(';');
+ if (wordoffset>0) s.truncate(wordoffset);
+
+ fLogWidget->addMessage(
+ i18n("Daemon status is `%1'")
+ .arg(s.isEmpty() ? i18n("not running") : s ));
+ }
+ fAppStatus=Normal;
+ }
+}
+
+void KPilotInstaller::readConfig()
+{
+ FUNCTIONSETUP;
+
+ KPilotSettings::self()->readConfig();
+
+ (void) Pilot::setupPilotCodec(KPilotSettings::encoding());
+ (void) Pilot::setupPilotCodec(KPilotSettings::encoding());
+
+ if (fLogWidget)
+ {
+ fLogWidget->addMessage(i18n("Using character set %1 on "
+ "the handheld.")
+ .arg(Pilot::codecName()));
+ }
+}
+
+
+void KPilotInstaller::setupWidget()
+{
+ FUNCTIONSETUP;
+
+ setCaption(CSL1("KPilot"));
+ setMinimumSize(500, 405);
+
+
+ fManagingWidget = new KJanusWidget(this,"mainWidget",
+ KJanusWidget::IconList);
+ fManagingWidget->setMinimumSize(fManagingWidget->sizeHint());
+ fManagingWidget->show();
+ setCentralWidget(fManagingWidget);
+ connect( fManagingWidget, SIGNAL( aboutToShowPage ( QWidget* ) ),
+ this, SLOT( slotAboutToShowComponent( QWidget* ) ) );
+
+ initIcons();
+ initMenu();
+ initComponents();
+
+ setMinimumSize(sizeHint() + QSize(10,60));
+
+ createGUI(CSL1("kpilotui.rc"), false);
+ setAutoSaveSettings();
+}
+
+void KPilotInstaller::initComponents()
+{
+ FUNCTIONSETUP;
+
+ QString defaultDBPath = KPilotConfig::getDefaultDBPath();
+
+ QPixmap pixmap;
+ QString pixfile;
+ QWidget *w;
+
+#define ADDICONPAGE(a,b) \
+ pixmap = KGlobal::iconLoader()->loadIcon(b, KIcon::Desktop, 64); \
+ w = getManagingWidget()->addVBoxPage(a,QString::null, pixmap) ;
+
+ ADDICONPAGE(i18n("HotSync"),CSL1("kpilotbhotsync"));
+ fLogWidget = new LogWidget(w);
+ addComponentPage(fLogWidget, i18n("HotSync"));
+ fLogWidget->setShowTime(true);
+
+ ADDICONPAGE(i18n("To-do Viewer"),CSL1("kpilottodo"));
+ addComponentPage(new TodoWidget(w,defaultDBPath),
+ i18n("To-do Viewer"));
+
+ ADDICONPAGE(i18n("Address Viewer"),CSL1("kpilotaddress"));
+ addComponentPage(new AddressWidget(w,defaultDBPath),
+ i18n("Address Viewer"));
+
+ ADDICONPAGE(i18n("Memo Viewer"),CSL1("kpilotknotes"));
+ addComponentPage(new MemoWidget(w, defaultDBPath),
+ i18n("Memo Viewer"));
+
+ ADDICONPAGE(i18n("File Installer"),CSL1("kpilotfileinstaller"));
+ fFileInstallWidget = new FileInstallWidget(
+ w,defaultDBPath);
+ addComponentPage(fFileInstallWidget, i18n("File Installer"));
+
+ ADDICONPAGE(i18n("Generic DB Viewer"),CSL1("kpilotdb"));
+ addComponentPage(new GenericDBWidget(w,defaultDBPath),
+ i18n("Generic DB Viewer"));
+
+#undef ADDICONPAGE
+
+ QTimer::singleShot(500,this,SLOT(initializeComponents()));
+}
+
+
+
+void KPilotInstaller::initIcons()
+{
+ FUNCTIONSETUP;
+
+}
+
+
+
+void KPilotInstaller::slotAboutToShowComponent( QWidget *c )
+{
+ FUNCTIONSETUP;
+ int ix = fManagingWidget->pageIndex( c );
+ PilotComponent*compToShow = fP->list().at(ix);
+ for ( PilotComponent *comp = fP->list().first(); comp; comp = fP->list().next() )
+ {
+ // Load/Unload the data needed
+ comp->showKPilotComponent( comp == compToShow );
+ }
+}
+
+void KPilotInstaller::slotSelectComponent(PilotComponent *c)
+{
+ FUNCTIONSETUP;
+ if (!c)
+ {
+ WARNINGKPILOT << "Not a widget." << endl;
+ return;
+ }
+
+ QObject *o = c->parent();
+ if (!o)
+ {
+ WARNINGKPILOT << "Widget has no parent." << endl;
+ return;
+ }
+
+ QWidget *parent = dynamic_cast<QWidget *>(o);
+ if (!parent)
+ {
+ WARNINGKPILOT << "Widget's parent is not a widget." << endl;
+ return;
+ }
+
+ int index = fManagingWidget->pageIndex(parent);
+
+ if (index < 0)
+ {
+ WARNINGKPILOT << "Bogus index " << index << endl;
+ return;
+ }
+
+ for ( PilotComponent *comp = fP->list().first(); comp; comp = fP->list().next() )
+ {
+ // Load/Unload the data needed
+ comp->showKPilotComponent( comp == c );
+ }
+ fManagingWidget->showPage(index);
+}
+
+
+
+
+void KPilotInstaller::slotBackupRequested()
+{
+ FUNCTIONSETUP;
+ setupSync(SyncAction::SyncMode::eBackup,
+ i18n("Next sync will be a backup. ") +
+ i18n("Please press the HotSync button."));
+}
+
+void KPilotInstaller::slotRestoreRequested()
+{
+ FUNCTIONSETUP;
+ setupSync(SyncAction::SyncMode::eRestore,
+ i18n("Next sync will restore the Pilot from backup. ") +
+ i18n("Please press the HotSync button."));
+}
+
+void KPilotInstaller::slotHotSyncRequested()
+{
+ FUNCTIONSETUP;
+ setupSync(SyncAction::SyncMode::eHotSync,
+ i18n("Next sync will be a regular HotSync. ") +
+ i18n("Please press the HotSync button."));
+}
+
+void KPilotInstaller::slotFullSyncRequested()
+{
+ FUNCTIONSETUP;
+ setupSync(SyncAction::SyncMode::eFullSync,
+ i18n("Next sync will be a Full Sync. ") +
+ i18n("Please press the HotSync button."));
+}
+
+void KPilotInstaller::slotHHtoPCRequested()
+{
+ FUNCTIONSETUP;
+ setupSync(SyncAction::SyncMode::eCopyHHToPC,
+ i18n("Next sync will copy Handheld data to PC. ") +
+ i18n("Please press the HotSync button."));
+}
+
+void KPilotInstaller::slotPCtoHHRequested()
+{
+ FUNCTIONSETUP;
+ setupSync(SyncAction::SyncMode::eCopyPCToHH,
+ i18n("Next sync will copy PC data to Handheld. ") +
+ i18n("Please press the HotSync button."));
+}
+
+/* virtual DCOP */ ASYNC KPilotInstaller::daemonStatus(int i)
+{
+ FUNCTIONSETUP;
+ DEBUGKPILOT << fname << ": Received daemon message " << i << endl;
+
+ switch(i)
+ {
+ case KPilotDCOP::StartOfHotSync :
+ if (fAppStatus==Normal)
+ {
+ fAppStatus=WaitingForDaemon;
+ componentPreSync();
+ }
+ break;
+ case KPilotDCOP::EndOfHotSync :
+ if (fAppStatus==WaitingForDaemon)
+ {
+ componentPostSync();
+ fAppStatus=Normal;
+ }
+ break;
+ case KPilotDCOP::DaemonQuit :
+ if (fLogWidget)
+ {
+ fLogWidget->logMessage(i18n("The daemon has exited."));
+ fLogWidget->logMessage(i18n("No further HotSyncs are possible."));
+ fLogWidget->logMessage(i18n("Restart the daemon to HotSync again."));
+ }
+ fAppStatus=WaitingForDaemon;
+ break;
+ case KPilotDCOP::None :
+ WARNINGKPILOT << "Unhandled status message " << i << endl;
+ break;
+ }
+}
+
+/* virtual DCOP*/ int KPilotInstaller::kpilotStatus()
+{
+ return status();
+}
+
+bool KPilotInstaller::componentPreSync()
+{
+ FUNCTIONSETUP;
+
+ QString reason;
+ QString rprefix(i18n("Cannot start a Sync now. %1"));
+
+ for (fP->list().first();
+ fP->list().current(); fP->list().next())
+ {
+ if (!fP->list().current()->preHotSync(reason))
+ break;
+ }
+
+ if (!reason.isNull())
+ {
+ KMessageBox::sorry(this,
+ rprefix.arg(reason),
+ i18n("Cannot start Sync"));
+ return false;
+ }
+ return true;
+}
+
+void KPilotInstaller::componentPostSync()
+{
+ FUNCTIONSETUP;
+
+ for (fP->list().first();
+ fP->list().current(); fP->list().next())
+ {
+ fP->list().current()->postHotSync();
+ }
+}
+
+void KPilotInstaller::setupSync(int kind, const QString & message)
+{
+ FUNCTIONSETUP;
+
+ if (!componentPreSync())
+ {
+ return;
+ }
+ if (!message.isEmpty())
+ {
+ QString m(message);
+ if (fLogWidget)
+ {
+ fLogWidget->logMessage(m);
+ }
+ }
+ getDaemon().requestSync(kind);
+}
+
+void KPilotInstaller::closeEvent(QCloseEvent * e)
+{
+ FUNCTIONSETUP;
+
+ quit();
+ e->accept();
+}
+
+void KPilotInstaller::initMenu()
+{
+ FUNCTIONSETUP;
+
+ KAction *a;
+
+ KActionMenu *syncPopup;
+
+ syncPopup = new KActionMenu(i18n("HotSync"), CSL1("kpilot"),
+ actionCollection(), "popup_hotsync");
+ syncPopup->setToolTip(i18n("Select the kind of HotSync to perform next."));
+ syncPopup->setWhatsThis(i18n("Select the kind of HotSync to perform next. "
+ "This applies only to the next HotSync; to change the default, use "
+ "the configuration dialog."));
+ connect(syncPopup, SIGNAL(activated()),
+ this, SLOT(slotHotSyncRequested()));
+
+ // File actions, keep this list synced with kpilotui.rc and pilotDaemon.cc
+ a = new KAction(i18n("&HotSync"), CSL1("hotsync"), 0,
+ this, SLOT(slotHotSyncRequested()),
+ actionCollection(), "file_hotsync");
+ a->setToolTip(i18n("Next HotSync will be normal HotSync."));
+ a->setWhatsThis(i18n("Tell the daemon that the next HotSync "
+ "should be a normal HotSync."));
+ syncPopup->insert(a);
+
+ a = new KAction(i18n("Full&Sync"), CSL1("fullsync"), 0,
+ this, SLOT(slotFullSyncRequested()),
+ actionCollection(), "file_fullsync");
+ a->setToolTip(i18n("Next HotSync will be a FullSync."));
+ a->setWhatsThis(i18n("Tell the daemon that the next HotSync "
+ "should be a FullSync (check data on both sides)."));
+ syncPopup->insert(a);
+
+ a = new KAction(i18n("&Backup"), CSL1("backup"), 0,
+ this, SLOT(slotBackupRequested()),
+ actionCollection(), "file_backup");
+ a->setToolTip(i18n("Next HotSync will be backup."));
+ a->setWhatsThis(i18n("Tell the daemon that the next HotSync "
+ "should back up the Handheld to the PC."));
+ syncPopup->insert(a);
+
+ a = new KAction(i18n("&Restore"), CSL1("restore"), 0,
+ this, SLOT(slotRestoreRequested()),
+ actionCollection(), "file_restore");
+ a->setToolTip(i18n("Next HotSync will be restore."));
+ a->setWhatsThis(i18n("Tell the daemon that the next HotSync "
+ "should restore the Handheld from data on the PC."));
+ syncPopup->insert(a);
+
+ a = new KAction(i18n("Copy Handheld to PC"), QString::null, 0,
+ this, SLOT(slotHHtoPCRequested()),
+ actionCollection(), "file_HHtoPC");
+ a->setToolTip(i18n("Next HotSync will be backup."));
+ a->setWhatsThis(i18n("Tell the daemon that the next HotSync "
+ "should copy all data from the Handheld to the PC, "
+ "overwriting entries on the PC."));
+ syncPopup->insert(a);
+
+ a = new KAction(i18n("Copy PC to Handheld"), QString::null, 0,
+ this, SLOT(slotPCtoHHRequested()),
+ actionCollection(), "file_PCtoHH");
+ a->setToolTip(i18n("Next HotSync will copy PC to Handheld."));
+ a->setWhatsThis(i18n("Tell the daemon that the next HotSync "
+ "should copy all data from the PC to the Handheld, "
+ "overwriting entries on the Handheld."));
+ syncPopup->insert(a);
+
+
+#if 0
+ a = new KAction(i18n("&List Only"),CSL1("listsync"),0,
+ this,SLOT(slotTestSyncRequested()),
+ actionCollection(), "file_list");
+ a->setToolTip(i18n("Next HotSync will list databases."));
+ a->setWhatsThis(i18n("Tell the daemon that the next HotSync "
+ "should just list the files on the Handheld and do nothing "
+ "else."));
+ syncPopup->insert(a);
+#endif
+
+
+ a = new KAction(i18n("Rese&t Link"),CSL1("reload"), 0,
+ this, SLOT(slotResetLink()),
+ actionCollection(),"file_reload");
+ a->setToolTip(i18n("Reset the device connection."));
+ a->setWhatsThis(i18n("Try to reset the daemon and its connection "
+ "to the Handheld."));
+
+
+ a = KStdAction::quit(this, SLOT(quit()), actionCollection());
+ a->setWhatsThis(i18n("Quit KPilot, (and stop the daemon "
+ "if configured that way)."));
+
+ // View actions
+
+ // Options actions
+ createStandardStatusBarAction();
+ setStandardToolBarMenuEnabled(true);
+
+ (void) KStdAction::keyBindings(this, SLOT(optionsConfigureKeys()),
+ actionCollection());
+ (void) KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()),
+ actionCollection());
+ (void) KStdAction::preferences(this, SLOT(configure()),
+ actionCollection());
+
+ a = new KAction(i18n("Configuration &Wizard..."), CSL1("wizard"), 0,
+ this, SLOT(configureWizard()),
+ actionCollection(), "options_configure_wizard");
+ a->setWhatsThis(i18n("Configure KPilot using the configuration wizard."));
+
+}
+
+void KPilotInstaller::fileInstalled(int)
+{
+ FUNCTIONSETUP;
+}
+
+void KPilotInstaller::quit()
+{
+ FUNCTIONSETUP;
+
+ for (fP->list().first();
+ fP->list().current(); fP->list().next())
+ {
+ QString reason;
+ if (!fP->list().current()->preHotSync(reason))
+ {
+ WARNINGKPILOT
+ << "Couldn't save "
+ << fP->list().current()->name()
+ << endl;
+ }
+ }
+
+ killDaemonIfNeeded();
+ kapp->quit();
+}
+
+void KPilotInstaller::addComponentPage(PilotComponent * p,
+ const QString & name)
+{
+ FUNCTIONSETUP;
+
+ if (!p)
+ {
+ WARNINGKPILOT << "Adding NULL component?" << endl;
+ return;
+ }
+
+ fP->list().append(p);
+
+ // The first component added gets id 1, while the title
+ // screen -- added elsewhere -- has id 0.
+ //
+ // fManagingWidget->addWidget(p, fP->list().count());
+
+
+ const char *componentname = p->name("(none)");
+ char *actionname = 0L;
+ int actionnameLength = 0;
+
+ if (strncmp(componentname, "component_", 10) == 0)
+ {
+ actionnameLength = strlen(componentname) - 10 + 8;
+ actionname = new char[actionnameLength];
+
+ strlcpy(actionname, "view_", actionnameLength);
+ strlcat(actionname, componentname + 10, actionnameLength);
+ }
+ else
+ {
+ actionnameLength = strlen(componentname) + 8;
+ actionname = new char[actionnameLength];
+
+ strlcpy(actionname, "view_", actionnameLength);
+ strlcat(actionname, componentname, actionnameLength);
+ }
+
+ KToggleAction *pt =
+ new KToggleAction(name, /* "kpilot" -- component icon, */ 0,
+ p, SLOT(slotShowComponent()),
+ actionCollection(), actionname);
+
+ pt->setExclusiveGroup(CSL1("view_menu"));
+
+ connect(p, SIGNAL(showComponent(PilotComponent *)),
+ this, SLOT(slotSelectComponent(PilotComponent *)));
+}
+
+/* slot */ void KPilotInstaller::initializeComponents()
+{
+ FUNCTIONSETUP;
+
+/* for (PilotComponent *p = fP->list().first();
+ p ; p = fP->list().next())
+ {
+ p->initialize();
+ }*/
+}
+
+
+void KPilotInstaller::optionsConfigureKeys()
+{
+ FUNCTIONSETUP;
+ KKeyDialog::configure( actionCollection() );
+}
+
+void KPilotInstaller::optionsConfigureToolbars()
+{
+ FUNCTIONSETUP;
+ // use the standard toolbar editor
+ // This was added in KDE 3.1
+ saveMainWindowSettings( KGlobal::config(), autoSaveGroup() );
+ KEditToolbar dlg(actionCollection());
+ connect(&dlg, SIGNAL(newToolbarConfig()), this, SLOT(slotNewToolbarConfig()));
+ dlg.exec();
+}
+
+
+void KPilotInstaller::slotNewToolbarConfig()
+{
+ FUNCTIONSETUP;
+ // recreate our GUI
+ createGUI();
+ applyMainWindowSettings( KGlobal::config(), autoSaveGroup() );
+}
+
+void KPilotInstaller::slotResetLink()
+{
+ FUNCTIONSETUP;
+ getDaemon().reloadSettings();
+}
+
+/*
+** Can't be a member function because it needs to be called even with no KPilotInstaller.
+*/
+static bool runConfigure(PilotDaemonDCOP_stub &daemon,QWidget *parent)
+{
+ FUNCTIONSETUP;
+ bool ret = false;
+
+ // Display the (modal) options page.
+ //
+ //
+ int rememberedSync = daemon.nextSyncType();
+ daemon.requestSync(0);
+
+ KPilotSettings::self()->readConfig();
+
+ KCMultiDialog *options = new KCMultiDialog( KDialogBase::Plain, i18n("Configuration"), parent, "KPilotPreferences", true );
+ options->addModule( CSL1("kpilot_config.desktop") );
+
+ if (!options)
+ {
+ WARNINGKPILOT << "Can't allocate KPilotOptions object" << endl;
+ daemon.requestSync(rememberedSync);
+ return false;
+ }
+
+ int r = options->exec();
+
+ if ( r && options->result() )
+ {
+ DEBUGKPILOT << fname << ": Updating settings." << endl;
+
+ // The settings are changed in the external module!!!
+ KPilotSettings::self()->config()->sync();
+ KPilotSettings::self()->readConfig();
+
+ // Update the daemon to reflect new settings.
+ // @TODO: This should also be done when pressing apply without
+ // closing the dialog.
+ //
+ daemon.reloadSettings();
+ ret = true;
+ }
+
+ KPILOT_DELETE(options);
+ daemon.requestSync(rememberedSync);
+
+ KPilotConfig::sync();
+ return ret;
+}
+
+/*
+ * Run the config wizard -- this takes a little library magic, and
+ * it might fail entirely; returns false if no wizard could be run,
+ * or true if the wizard runs (says nothing about it being OK'ed or
+ * canceled, though).
+ */
+typedef enum { Failed, OK, Cancel } WizardResult;
+static WizardResult runWizard(PilotDaemonDCOP_stub &daemon,QWidget *parent)
+{
+ FUNCTIONSETUP;
+ WizardResult ret = Failed ;
+ int rememberedSync = daemon.nextSyncType();
+ daemon.requestSync(0);
+
+ KPilotSettings::self()->readConfig();
+ // Declarations at top because of goto's in this function
+ ConfigWizard *(* f) (QWidget *, int) = 0L ;
+ ConfigWizard *w = 0L;
+ KLibrary *l = KLibLoader::self()->library("kcm_kpilot");
+
+ if (!l)
+ {
+ WARNINGKPILOT << "Couldn't load library!" << endl;
+ goto sorry;
+ }
+
+ if (l->hasSymbol("create_wizard"))
+ {
+ f = ( ConfigWizard * (*) (QWidget *, int) ) (l->symbol("create_wizard")) ;
+ }
+
+ if (!f)
+ {
+ WARNINGKPILOT << "No create_wizard() in library." << endl;
+ goto sorry;
+ }
+
+ w = f(parent,ConfigWizard::Standalone);
+ if (!w)
+ {
+ WARNINGKPILOT << "Can't create wizard." << endl;
+ goto sorry;
+ }
+
+ if (w->exec())
+ {
+ KPilotSettings::self()->readConfig();
+ ret = OK;
+ }
+ else
+ {
+ ret = Cancel;
+ }
+ KPILOT_DELETE(w);
+
+sorry:
+ if (Failed == ret)
+ {
+ KMessageBox::sorry(parent,
+ i18n("The library containing the configuration wizard for KPilot "
+ "could not be loaded, and the wizard is not available. "
+ "Please try to use the regular configuration dialog."),
+ i18n("Wizard Not Available"));
+ }
+
+ if (OK == ret)
+ {
+ KPilotConfig::updateConfigVersion();
+ KPilotSettings::writeConfig();
+ KPilotConfig::sync();
+ }
+
+ daemon.requestSync(rememberedSync);
+ return ret;
+}
+
+void KPilotInstaller::componentUpdate()
+{
+ FUNCTIONSETUP;
+
+ QString defaultDBPath = KPilotConfig::getDefaultDBPath();
+ bool dbPathChanged = false;
+
+ for (fP->list().first();
+ fP->list().current();
+ fP->list().next())
+ {
+// TODO_RK: update the current component to use the new settings
+// fP->list().current()->initialize();
+ PilotComponent *p = fP->list().current();
+ if (p && (p->dbPath() != defaultDBPath))
+ {
+ dbPathChanged = true;
+ p->setDBPath(defaultDBPath);
+ }
+ }
+
+ if (!dbPathChanged) // done if the username didn't change
+ {
+ return;
+ }
+
+ // Otherwise, need to re-load the databases
+ //
+ if (fLogWidget)
+ {
+ fLogWidget->logMessage(i18n("Changed username to `%1'.")
+ .arg(KPilotSettings::userName()));
+ fManagingWidget->showPage(0);
+ slotAboutToShowComponent(fLogWidget);
+ }
+ else
+ {
+ int ix = fManagingWidget->activePageIndex();
+ PilotComponent *component = 0L;
+ if (ix>=0)
+ {
+ component = fP->list().at(ix);
+ }
+ if (component)
+ {
+ component->hideComponent(); // Throw away current data
+ component->showComponent(); // Reload
+ }
+ }
+}
+
+/* virtual DCOP */ ASYNC KPilotInstaller::configureWizard()
+{
+ FUNCTIONSETUP;
+
+ if ( fAppStatus!=Normal || fConfigureKPilotDialogInUse )
+ {
+ if (fLogWidget)
+ {
+ fLogWidget->addMessage(i18n("Cannot run KPilot's configuration wizard right now (KPilot's UI is already busy)."));
+ }
+ return;
+ }
+ fAppStatus=UIBusy;
+ fConfigureKPilotDialogInUse = true;
+
+ if (runWizard(getDaemon(),this) == OK)
+ {
+ componentUpdate();
+ }
+
+ fConfigureKPilotDialogInUse = false;
+ fAppStatus=Normal;
+}
+
+/* virtual DCOP */ ASYNC KPilotInstaller::configure()
+{
+ FUNCTIONSETUP;
+
+ if ( fAppStatus!=Normal || fConfigureKPilotDialogInUse )
+ {
+ if (fLogWidget)
+ {
+ fLogWidget->addMessage(i18n("Cannot configure KPilot right now (KPilot's UI is already busy)."));
+ }
+ return;
+ }
+ fAppStatus=UIBusy;
+ fConfigureKPilotDialogInUse = true;
+ if (runConfigure(getDaemon(),this))
+ {
+ componentUpdate();
+ }
+
+ fConfigureKPilotDialogInUse = false;
+ fAppStatus=Normal;
+}
+
+
+/* static */ const char *KPilotInstaller::version(int kind)
+{
+ FUNCTIONSETUP;
+ // I don't think the program title needs to be translated. (ADE)
+ //
+ //
+ if (kind)
+ {
+ return "kpilot.cc";
+ }
+ else
+ {
+ return "KPilot v" KPILOT_VERSION;
+ }
+}
+
+// Command line options descriptions.
+//
+//
+//
+//
+static KCmdLineOptions kpilotoptions[] = {
+ {"s", 0, 0},
+ {"setup",
+ I18N_NOOP("Setup the Pilot device, conduits and other parameters"),
+ 0L},
+ {"debug <level>", I18N_NOOP("Set debugging level"), "0"},
+ KCmdLineLastOption
+};
+
+
+
+
+// "Regular" mode == 0
+// setup mode == 's'
+//
+// This is only changed by the --setup flag --
+// kpilot still does a setup the first time it is run.
+//
+//
+KPilotConfig::RunMode run_mode = KPilotConfig::Normal;
+
+
+
+int main(int argc, char **argv)
+{
+ FUNCTIONSETUP;
+
+ KAboutData about("kpilot", I18N_NOOP("KPilot"),
+ KPILOT_VERSION,
+ "KPilot - HotSync software for KDE\n\n",
+ KAboutData::License_GPL,
+ "(c) 1998-2000,2001, Dan Pilone (c) 2000-2006, Adriaan de Groot",
+ 0L,
+ "http://www.kpilot.org/"
+ );
+ about.addAuthor("Dan Pilone",
+ I18N_NOOP("Project Leader"),
+ about.addAuthor("Adriaan de Groot",
+ I18N_NOOP("Maintainer"),
+ "[email protected]", "http://www.kpilot.org/");
+ about.addAuthor("Reinhold Kainhofer",
+ I18N_NOOP("Core and conduits developer"), "[email protected]", "http://reinhold.kainhofer.com/Linux/");
+ about.addAuthor("Jason 'vanRijn' Kasper",
+ I18N_NOOP("Core and conduits developer"),
+ "[email protected]", "http://movingparts.net/");
+ about.addCredit("Preston Brown", I18N_NOOP("VCal conduit"));
+ about.addCredit("Greg Stern", I18N_NOOP("Abbrowser conduit"));
+ about.addCredit("Chris Molnar", I18N_NOOP("Expenses conduit"));
+ about.addCredit("Jörn Ahrens", I18N_NOOP("Notepad conduit, Bugfixer"));
+ about.addCredit("Heiko Purnhagen", I18N_NOOP("Bugfixer"));
+ about.addCredit("Jörg Habenicht", I18N_NOOP("Bugfixer"));
+ about.addCredit("Martin Junius",
+ I18N_NOOP("XML GUI"),
+ "[email protected]", "http://www.m-j-s.net/kde/");
+ about.addCredit("David Bishop",
+ I18N_NOOP(".ui files"));
+ about.addCredit("Aaron J. Seigo",
+ I18N_NOOP("Bugfixer, coolness"));
+ about.addCredit("Bertjan Broeksema",
+ I18N_NOOP("VCalconduit state machine, CMake"));
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions(kpilotoptions, "kpilot");
+ KUniqueApplication::addCmdLineOptions();
+ KCmdLineArgs *p = KCmdLineArgs::parsedArgs();
+
+#ifdef DEBUG
+ KPilotConfig::getDebugLevel(p);
+#endif
+
+
+ if (!KUniqueApplication::start())
+ {
+ return 0;
+ }
+ KUniqueApplication a(true, true);
+
+
+ if (p->isSet("setup"))
+ {
+ run_mode = KPilotConfig::ConfigureKPilot;
+ }
+ else if (KPilotSettings::configVersion() < KPilotConfig::ConfigurationVersion)
+ {
+ WARNINGKPILOT << "KPilot configuration version "
+ << KPilotConfig::ConfigurationVersion
+ << " newer than stored version "
+ << KPilotSettings::configVersion() << endl;
+ // Only force a reconfigure and continue if the
+ // user is expecting normal startup. Otherwise,
+ // do the configuration they're explicitly asking for.
+ run_mode = KPilotConfig::interactiveUpdate();
+ if (run_mode == KPilotConfig::Cancel) return 1;
+ }
+
+
+ if ( (run_mode == KPilotConfig::ConfigureKPilot) ||
+ (run_mode == KPilotConfig::ConfigureAndContinue) ||
+ (run_mode == KPilotConfig::WizardAndContinue) )
+ {
+ DEBUGKPILOT << fname
+ << ": Running setup first."
+ << " (mode " << run_mode << ")" << endl;
+ PilotDaemonDCOP_stub *daemon = new PilotDaemonDCOP_stub("kpilotDaemon","KPilotDaemonIface");
+ bool r = false;
+ if (run_mode == KPilotConfig::WizardAndContinue)
+ {
+ r = ( runWizard(*daemon,0L) == OK );
+ }
+ else
+ {
+ r = runConfigure(*daemon,0L);
+ }
+ delete daemon;
+ if (!r) return 1;
+ // User expected configure only.
+ if (run_mode == KPilotConfig::ConfigureKPilot)
+ {
+ return 0;
+ }
+ }
+
+ if (KPilotSettings::configVersion() < KPilotConfig::ConfigurationVersion)
+ {
+ WARNINGKPILOT << "Still not configured for use." << endl;
+ KPilotConfig::sorryVersionOutdated( KPilotSettings::configVersion());
+ return 1;
+ }
+
+
+ KPilotInstaller *tp = new KPilotInstaller();
+
+ if (tp->status() == KPilotInstaller::Error)
+ {
+ KPILOT_DELETE(tp);
+ return 1;
+ }
+
+ QTimer::singleShot(0,tp,SLOT(startDaemonIfNeeded()));
+
+ KGlobal::dirs()->addResourceType("pilotdbs",
+ CSL1("share/apps/kpilot/DBBackup"));
+ tp->show();
+ a.setMainWidget(tp);
+ return a.exec();
+}
+
+
diff --git a/kpilot/kpilot/kpilot.desktop b/kpilot/kpilot/kpilot.desktop
new file mode 100644
index 000000000..b3a9bdbb4
--- /dev/null
+++ b/kpilot/kpilot/kpilot.desktop
@@ -0,0 +1,87 @@
+# KDE Config File
+[Desktop Entry]
+Name=KPilot
+Name[af]=Kpilot
+Name[eo]=Palm-Piloto
+Name[fr]=Palm Pilot
+Name[hi]=के-पायलट
+Name[lv]=KPilots
+Name[mk]=КПилот
+Name[ne]=केडीई पाइलट
+Name[pt_BR]=Ferramenta para PalmPilot
+Name[sv]=Kpilot
+Name[ta]=கேபைலட்
+Name[ven]=Mufhufhisi wa K
+Name[zu]=KUmshayeli webhanoyi
+GenericName=PalmPilot Tool
+GenericName[af]=Palmpilot Program
+GenericName[be]=Інструмэнт Palm Pilot
+GenericName[bg]=Връзка с PalmPilot
+GenericName[br]=Ostilh PalmPilot
+GenericName[bs]=Alati za PalmPilot
+GenericName[ca]=Eina PalmPilot
+GenericName[cs]=Nástroj pro PalmPilot
+GenericName[cy]=Erfyn PalmPilot
+GenericName[da]=Palm Pilot-værktøj
+GenericName[de]=Palm Pilot-Dienstprogramm
+GenericName[el]=Εργαλείο PalmPilot
+GenericName[eo]=Ilo por Palmpiloto
+GenericName[es]=Herramienta para Palm Pilot
+GenericName[et]=PalmPiloti rakendus
+GenericName[eu]=PalmPilot tresna
+GenericName[fa]=ابزار PalmPilot
+GenericName[fi]=Palm Pilot -työkalu
+GenericName[fr]=Outil pour le Palm Pilot
+GenericName[fy]=Palm Pilot-syngronisaasje
+GenericName[ga]=Uirlis PalmPilot
+GenericName[gl]=Ferramenta de PalmPilot
+GenericName[he]=כלי פאלם-פיילוט
+GenericName[hi]=पाम-पायलट औज़ार
+GenericName[hr]=Alat za Palm Pilota
+GenericName[hu]=PalmPilot-kezelő
+GenericName[is]=PalmPilot tól
+GenericName[it]=Strumento per PalmPilot
+GenericName[ja]=PalmPilot ツール
+GenericName[ka]=Palm Pilot ხელსაწყო
+GenericName[kk]=PalmPilot құрылғысы
+GenericName[km]=ឧបករណ៍ PalmPilot
+GenericName[lt]=PalmPilot įrankis
+GenericName[lv]=PalmPilota Rīks
+GenericName[mk]=Алатка за PalmPilot
+GenericName[ms]=Alat PalmPilot
+GenericName[mt]=Għodda għall-Palm Pilot
+GenericName[nb]=PalmPilot-verktøy
+GenericName[nds]=PalmPilot-Warktüüch
+GenericName[ne]=पाल्म पाइलट उपकरण
+GenericName[nl]=Palm Pilot-synchronisatie
+GenericName[nn]=Palm Pilot-verktøy
+GenericName[nso]=Sebereka sa PalmPilot
+GenericName[pl]=Palm Pilot
+GenericName[pt]=Ferramenta para o PalmPilot
+GenericName[pt_BR]=Ferramenta para o Palm Pilot
+GenericName[ro]=Utilitar PalmPilot
+GenericName[ru]=Синхронизация данных с Palm Pilot
+GenericName[sk]=Nástroj pre PalmPilot
+GenericName[sl]=Orodje za Palm Pilot
+GenericName[sr]=Алат за PalmPilot
+GenericName[sr@Latn]=Alat za PalmPilot
+GenericName[sv]=Verktyg för Palm Pilot
+GenericName[ta]=பாம் பைலட் கருவி
+GenericName[tg]=Синхронизатсияи маълумот аз PalmPilot
+GenericName[th]=เครื่องมือของเครื่องปาล์มไพล็อต
+GenericName[tr]=Palm Pilot Aracı
+GenericName[uk]=Засіб для PalmPilot
+GenericName[ven]=Tshishimuswa tsha mureili wa palm
+GenericName[vi]=Công cụ PalmPilot
+GenericName[xh]=Isixhobo se PalmPilot
+GenericName[zh_CN]=PalmPilot 工具
+GenericName[zh_TW]=PalmPilot 工具
+GenericName[zu]=Ithuluzi lesandla soMshayeli webhanoyi
+Exec=kpilot
+Icon=kpilot
+Type=Application
+DocPath=kpilot/index.html
+Terminal=false
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Unique
+Categories=Qt;KDE;Utility;X-KDE-Utilities-Peripherals;Office;PDA;
diff --git a/kpilot/kpilot/kpilot.gif b/kpilot/kpilot/kpilot.gif
new file mode 100644
index 000000000..9cfe04ce4
--- /dev/null
+++ b/kpilot/kpilot/kpilot.gif
Binary files differ
diff --git a/kpilot/kpilot/kpilot.h b/kpilot/kpilot/kpilot.h
new file mode 100644
index 000000000..64bc770cb
--- /dev/null
+++ b/kpilot/kpilot/kpilot.h
@@ -0,0 +1,214 @@
+#ifndef _KPILOT_KPILOT_H
+#define _KPILOT_KPILOT_H
+/* kpilot.h KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This is the main program in KPilot.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <kmainwindow.h>
+
+
+class QPopupMenu;
+class QComboBox;
+class KAction;
+class KProgress;
+class KJanusWidget;
+
+class PilotDaemonDCOP_stub;
+class PilotComponent;
+class FileInstallWidget;
+class LogWidget;
+
+
+#include "kpilotDCOP.h"
+
+
+
+class KPilotInstaller : public KMainWindow, public KPilotDCOP
+{
+Q_OBJECT
+
+public:
+ KPilotInstaller();
+ KPilotInstaller(QStrList& fileList);
+ ~KPilotInstaller();
+
+ /**
+ * Return a string with the version identifier (ie.
+ * "KPilot v3.1b11") if kind == 0; otherwise return
+ * a "long" string about KPilot -- currently the
+ * id of kpilot.o
+ */
+ static const char *version(int kind);
+
+
+ // Adds 'name' to the pull down menu of components
+ void addComponentPage(PilotComponent *, const QString &name);
+
+
+ KPilotStatus status() const { return fAppStatus; } ;
+
+
+protected:
+ void closeEvent(QCloseEvent *e);
+ KJanusWidget *getManagingWidget() { return fManagingWidget; }
+
+ /**
+ * Provide access to the daemon's DCOP interface
+ * through an object of the stub class.
+ */
+protected:
+ PilotDaemonDCOP_stub &getDaemon() { return *fDaemonStub; } ;
+private:
+ PilotDaemonDCOP_stub *fDaemonStub;
+
+ /**
+ * Handle the functionality of kill-daemon-on-exit and
+ * kill-daemon-if-started-by-my by killing it in those
+ * cases.
+ */
+protected:
+ void killDaemonIfNeeded();
+
+public slots:
+ /**
+ * These are slots for the menu actions for each kind of
+ * sync that can be requested.
+ */
+ void slotRestoreRequested();
+ void slotBackupRequested();
+ void slotHotSyncRequested();
+ void slotFullSyncRequested();
+ void slotHHtoPCRequested();
+ void slotPCtoHHRequested();
+
+ void startDaemonIfNeeded();
+
+ /**
+ * These are slots for the standard Configure ...
+ * actions and not interesting. The show toolbar
+ * functionality is in kdelibs starting with KDE 3.1,
+ * but we need to remain backwards compatible.
+ */
+ void optionsConfigureKeys();
+ void optionsConfigureToolbars();
+
+
+public:
+ /**
+ * This is the DCOP interface from the daemon to KPilot.
+ */
+ virtual ASYNC daemonStatus(int);
+ virtual int kpilotStatus();
+
+public slots:
+ /**
+ * This is the DCOP interface from the daemon to KPilot
+ * to configure KPilot.
+ */
+ virtual ASYNC configure();
+ virtual ASYNC configureWizard();
+
+protected:
+ void readConfig();
+
+
+ /**
+ * Run all the internal conduits' presync functions.
+ */
+ bool componentPreSync();
+ void setupSync(int kind,const QString& msg);
+ void componentPostSync();
+ /**
+ * Run after a configuration change to force
+ * the viewers to re-load data.
+ */
+ void componentUpdate();
+
+ void initIcons();
+ void initMenu();
+ void setupWidget();
+ void initComponents();
+
+ /**
+ * This is the private-d-pointer, KPilot style. Not everything
+ * has moved there yet.
+ */
+ class KPilotPrivate;
+ KPilotPrivate *fP;
+
+private:
+ bool fQuitAfterCopyComplete; // Used for GUI-less interface
+ KJanusWidget *fManagingWidget;
+ bool fDaemonWasRunning;
+
+ KPilotStatus fAppStatus;
+
+ FileInstallWidget *fFileInstallWidget;
+ LogWidget *fLogWidget;
+
+ // Used to track if dialog is visible - needed for new DCOP calls
+ bool fConfigureKPilotDialogInUse;
+
+
+protected slots:
+ void quit();
+ void fileInstalled(int which);
+ void slotNewToolbarConfig();
+
+ /**
+ * Get the daemon to reset the link. This uses reloadSettings()
+ * to achieve this result - the daemon calls reset() in there.
+ */
+ void slotResetLink();
+
+ /**
+ * Indicate that a particular component has been selected (through
+ * whatever mechanism). This will make that component visible and
+ * adjust any other user-visible state to indicate that that component
+ * is now active.
+ *
+ * This should be called (possibly by the component itself!)
+ * or activated through the signal mechanism.
+ * */
+ void slotSelectComponent( PilotComponent *c );
+ void slotAboutToShowComponent( QWidget *c );
+
+ /**
+ * Delayed initialization of the components.
+ * This improves perceived startup time.
+ */
+ void initializeComponents();
+
+signals:
+ void modeSelected(int selected);
+};
+
+
+
+
+#endif
diff --git a/kpilot/kpilot/kpilot.kcfg b/kpilot/kpilot/kpilot.kcfg
new file mode 100644
index 000000000..6b5ba7237
--- /dev/null
+++ b/kpilot/kpilot/kpilot.kcfg
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <include>kstandarddirs.h</include>
+ <kcfgfile name="kpilotrc"/>
+ <group name="General">
+ <entry name="Debug" type="UInt">
+ <label>
+ </label>
+ <default>0</default>
+ </entry>
+ <entry name="ConfigVersion" key="Configured" type="UInt">
+ <label>
+ </label>
+ <default>0</default>
+ </entry>
+ <entry name="LastSyncTime" type="DateTime">
+ <label>
+ </label>
+ <default>QDateTime()</default>
+ </entry>
+
+ <entry name="PilotDevice" type="String">
+ <label>
+ </label>
+ <default>/dev/pilot</default>
+ </entry>
+ <entry name="PilotSpeed" type="UInt">
+ <label>
+ </label>
+ <default>0</default>
+ </entry>
+ <entry name="Encoding" type="String">
+ <label>
+ </label>
+ <default></default>
+ </entry>
+ <entry name="UserName" type="String">
+ <label>
+ </label>
+ <default></default>
+ </entry>
+ <entry name="Workarounds" type="Enum">
+ <choices>
+ <choice name="eWorkaroundNone"/>
+ <choice name="eWorkaroundUSB"/>
+ </choices>
+ <label></label>
+ <default>eWorkaroundNone</default>
+ </entry>
+
+ <entry name="LogFileName" type="String">
+ <label>
+ </label>
+ <default code="true">KGlobal::dirs()->saveLocation("data", "kpilot/").append("lastsync.log")</default>
+ </entry>
+ <entry name="StartDaemonAtLogin" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="KillDaemonAtExit" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="DockDaemon" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="QuitAfterSync" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+
+
+ <entry name="SyncType" type="UInt">
+ <label>
+ </label>
+ <default>6</default>
+ </entry>
+ <entry name="FullSyncOnPCChange" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="ConflictResolution" type="UInt">
+ <label>
+ </label>
+ <default>0</default>
+ </entry>
+
+
+
+ <entry name="InternalEditors" key="InternalEditorsWritable" type="Bool">
+ <label>
+ </label>
+ <default>true</default>
+ </entry>
+ <entry name="ShowSecrets" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ <entry name="SkipBackupDB" type="StringList">
+ <label>Which databases not to backup.</label>
+ <default>[Arng],[PmDB],[lnch],[a86k],FATFS,ImgFile-Foto,Jpeg-Foto,WifiCoreLib</default>
+ </entry>
+ <entry name="SkipRestoreDB" type="StringList">
+ <label>
+ </label>
+ <default>[AvGo]</default>
+ </entry>
+ <entry name="BackupFrequency" type="UInt">
+ <label></label>
+ <default>0</default>
+ </entry>
+ <entry name="RunConduitsWithBackup" type="Bool">
+ <label></label>
+ <default>false</default>
+ </entry>
+ <entry name="DeviceDBs" type="StringList">
+ <label>
+ </label>
+ <default></default>
+ </entry>
+ <entry name="AddedDBs" type="StringList">
+ <label>
+ </label>
+ <default></default>
+ </entry>
+ <entry name="ScreenlockSecure" type="Bool">
+ <label>Prevent HotSync when screen locked</label>
+ <whatsthis>Turning this option on prevents syncing
+ when the screen is locked. This is a security measure
+ to prevent people from stealing your data through physical
+ access to a Pilot device link to your machine.
+ It doesn't work with screensavers other than KDE, though,
+ so you will need to turn it off for other environments.</whatsthis>
+ <default>true</default>
+ </entry>
+ </group>
+
+ <group name="Conduit Names">
+ <entry name="InstalledConduits" type="StringList">
+ <label>
+ </label>
+ <default>abbrowser_conduit,internal_fileinstall,knotes-conduit,vcal-conduit,todo-conduit,mal_conduit,sysinfo_conduit</default>
+ </entry>
+ </group>
+
+ <group name="Internal Editors">
+ <entry name="AppBlockChangedDatabases" key="AppBlock Changed" type="StringList">
+ <label>
+ </label>
+ </entry>
+ <entry name="DirtyDatabases" key="Changed Databases" type="StringList">
+ <label>
+ </label>
+ </entry>
+ <entry name="FlagsChangedDatabases" key="Flags Changed" type="StringList">
+ <label>
+ </label>
+ </entry>
+ </group>
+
+
+ <group name="Address Widget">
+ <entry name="AddressDisplayMode" key="AddressDisplay" type="UInt">
+ <label>
+ </label>
+ <default>0</default>
+ </entry>
+ <entry name="UseKeyField" type="Bool">
+ <label>
+ </label>
+ <default>false</default>
+ </entry>
+ </group>
+
+
+</kcfg>
diff --git a/kpilot/kpilot/kpilot.magic b/kpilot/kpilot/kpilot.magic
new file mode 100644
index 000000000..4871f0f27
--- /dev/null
+++ b/kpilot/kpilot/kpilot.magic
@@ -0,0 +1,12 @@
+# start kpilot.magic
+# This must go at the end of $(kde_mimedir)/magic
+# PalmPilot Files
+0 string >\0
+>0x20 beshort&0xffe7 0 palmpilot/database
+>0x20 beshort&0xffe7 1
+>>0x3c string appl palmpilot/application
+>>0x3c string HACK palmpilot/hack
+>>0x3c string libr palmpilot/library
+>>0x3c string >\0 palmpilot/database
+# stop kpilot.magic
+
diff --git a/kpilot/kpilot/kpilot.upd b/kpilot/kpilot/kpilot.upd
new file mode 100644
index 000000000..1fbc36a6d
--- /dev/null
+++ b/kpilot/kpilot/kpilot.upd
@@ -0,0 +1,34 @@
+Id=kdepim_3.3
+File=kpilotrc
+Group=<default>,General
+AllKeys
+# split up the kpilotrc into several config files, so the different processes
+# don't step on each other's toes
+Id=kdepim_3.3_SplitConfig
+File=kpilotrc,kpilot_addressconduitrc
+Group=Abbrowser-conduit,General
+AllKeys
+File=kpilotrc,kpilot_docconduitrc
+Group=DOC-conduit,General
+AllKeys
+File=kpilotrc,kpilot_notesconduitrc
+Group=KNotes-conduit,General
+AllKeys
+File=kpilotrc,kpilot_malconduitrc
+Group=MAL-conduit,General
+AllKeys
+File=kpilotDaemonrc,kpilot_malconduitrc
+Group=MAL-conduit,General
+AllKeys
+File=kpilotrc,kpilot_mailconduitrc
+Group=Popmail-conduit,General
+AllKeys
+File=kpilotrc,kpilot_sysinfoconduitrc
+Group=SysInfo-conduit,General
+AllKeys
+File=kpilotrc,kpilot_vcalconduitsrc
+Group=todoOptions,ToDo-Conduit
+AllKeys
+Group=vcalOptions,Calendar-Conduit
+AllKeys
+RemoveGroup=YAPS-conduit
diff --git a/kpilot/kpilot/kpilotConfig.cc b/kpilot/kpilot/kpilotConfig.cc
new file mode 100644
index 000000000..72acdb9b4
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfig.cc
@@ -0,0 +1,346 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This is all of KPilot's config-handling stuff.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <stdlib.h>
+
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+
+#include <kstandarddirs.h>
+#include <kconfig.h>
+#include <ksimpleconfig.h>
+#include <kcmdlineargs.h>
+#include <kmessagebox.h>
+#include <kglobalsettings.h>
+
+#include "kpilotSettings.h"
+#include "kpilotConfig.h"
+
+
+// This is a number indicating what configuration version
+// we're dealing with. Whenever new configuration options are
+// added that make it imperative for the user to take a
+// look at the configuration of KPilot (for example the
+// skipDB setting really needs user attention) we can change
+// (increase) this number.
+//
+//
+/* static */ const uint KPilotConfig::ConfigurationVersion = 443;
+
+/* static */ int KPilotConfig::getConfigVersion()
+{
+ FUNCTIONSETUP;
+
+ uint version = KPilotSettings::configVersion();
+
+ if (version < ConfigurationVersion)
+ {
+ WARNINGKPILOT << "Config file has old version " << version << endl;
+ }
+ else
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Config file has version " << version << endl;
+#endif
+ }
+
+ return version;
+}
+
+/* static */ void KPilotConfig::updateConfigVersion()
+{
+ FUNCTIONSETUP;
+ KPilotSettings::setConfigVersion( ConfigurationVersion );
+}
+
+/* static */ QString KPilotConfig::getDefaultDBPath()
+{
+ FUNCTIONSETUP;
+ QString lastUser = KPilotSettings::userName();
+ QString dbsubpath = CSL1("kpilot/DBBackup/");
+ QString defaultDBPath = KGlobal::dirs()->
+ saveLocation("data", dbsubpath + lastUser + CSL1("/"));
+ return defaultDBPath;
+}
+
+/* static */ int KPilotConfig::getDebugLevel(KCmdLineArgs *p)
+{
+ FUNCTIONSETUP;
+
+ if (p)
+ {
+ if (p->isSet("debug"))
+ {
+ debug_level = p->getOption("debug").toInt();
+ }
+ }
+
+ return debug_level;
+}
+
+static QFont *thefont = 0L;
+
+/* static */ const QFont & KPilotConfig::fixed()
+{
+ FUNCTIONSETUP;
+
+ if (!thefont)
+ thefont = new QFont(KGlobalSettings::fixedFont());
+
+ return *thefont;
+}
+
+
+void KPilotConfig::addDirtyDatabase(QString db)
+{
+ FUNCTIONSETUP;
+ QStringList l(KPilotSettings::dirtyDatabases());
+ if (!l.contains(db))
+ {
+ l.append(db);
+ KPilotSettings::setDirtyDatabases(l);
+ }
+}
+
+
+void KPilotConfig::addAppBlockChangedDatabase(QString db)
+{
+ QStringList l(KPilotSettings::appBlockChangedDatabases());
+ if (!l.contains(db))
+ {
+ l.append(db);
+ KPilotSettings::setAppBlockChangedDatabases(l);
+ }
+}
+
+void KPilotConfig::addFlagsChangedDatabase(QString db)
+{
+ QStringList l(KPilotSettings::flagsChangedDatabases());
+ if (!l.contains(db))
+ {
+ l.append(db);
+ KPilotSettings::setFlagsChangedDatabases(l);
+ }
+}
+
+
+
+
+/* static */ QString KPilotConfig::versionDetails(int fileversion, bool run)
+{
+ FUNCTIONSETUP;
+ QString s = CSL1("<qt><p>");
+ s += i18n("The configuration file is outdated.");
+ s += ' ';
+ s += i18n("The configuration file has version %1, while KPilot "
+ "needs version %2.").arg(fileversion).arg(ConfigurationVersion);
+ if (run)
+ {
+ s += ' ';
+ s += i18n("Please run KPilot and check the configuration carefully "
+ "to update the file.");
+ }
+ s += CSL1("</p><p>");
+ s += i18n("Important changes to watch for are:");
+ s += ' ';
+ if (fileversion < 440)
+ {
+ s += i18n("Renamed conduits, Kroupware and file installer have "
+ "been made conduits as well.");
+ s += ' ';
+ s += i18n("Conflict resolution is now a global setting.");
+ s += ' ';
+ }
+ if (fileversion < 443)
+ {
+ s += i18n("Changed format of no-backup databases.");
+ s += ' ';
+ }
+ // Insert more recent additions here
+
+
+ return s;
+}
+
+/* static */ void KPilotConfig::sorryVersionOutdated(int fileversion)
+{
+ FUNCTIONSETUP;
+ KMessageBox::detailedSorry(0L,
+ i18n("The configuration file for KPilot is out-of "
+ "date. Please run KPilot to update it."),
+ KPilotConfig::versionDetails(fileversion,true),
+ i18n("Configuration File Out-of Date"));
+}
+
+static void update440()
+{
+ // Try to update conduit list
+ {
+ QStringList conduits( KPilotSettings::installedConduits() );
+ KConfig*c = KPilotSettings::self()->config();
+/// c->resetGroup();
+ c->setGroup( QString::null );
+ bool installFiles = c->readBoolEntry("SyncFiles",true);
+ if (installFiles) conduits.append( CSL1("internal_fileinstall") );
+ c->deleteEntry("SyncFiles");
+ KPilotSettings::setInstalledConduits(conduits);
+ c->sync();
+ if (installFiles)
+ KMessageBox::information(0L,
+ i18n("The settings for the file installer have been moved to the "
+ "conduits configuration. Check the installed "
+ "conduits list."),
+ i18n("Settings Updated"));
+
+ }
+
+ // Check if individual conduits have conflict settings?
+
+ // Search for old conduit libraries.
+ {
+ QStringList foundlibs ;
+ static const char *oldconduits[] = { "null", "address", "doc",
+ "knotes", "sysinfo", "time", "todo", "vcal", 0L } ;
+ const char **s = oldconduits;
+ while (*s)
+ {
+ QString libname = CSL1("kde3/lib%1conduit.so").arg(QString::fromLatin1(*s));
+ QString foundlib = ::locate("lib",libname);
+ if (!foundlib.isEmpty())
+ {
+ foundlibs.append(foundlib);
+ }
+ s++;
+ }
+
+ if (!foundlibs.isEmpty())
+ KMessageBox::informationList(0L,
+ i18n("<qt>The following old conduits were found on "
+ "your system. It is a good idea to remove "
+ "them and the associated <tt>.la</tt> "
+ "and <tt>.so.0</tt> files.</qt>"),
+ foundlibs,
+ i18n("Old Conduits Found"));
+ }
+}
+
+static void update443()
+{
+ FUNCTIONSETUP;
+
+ QStringList skip = KPilotSettings::skipBackupDB();
+ QStringList fixSkip;
+ bool fixedSome = false;
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Skip databases are: "
+ << skip.join(CSL1(",")) << endl;
+#endif
+
+ for (QStringList::const_iterator i = skip.begin(); i!=skip.end(); ++i)
+ {
+ if ((*i).length()==4)
+ {
+ fixSkip.append(CSL1("[%1]").arg(*i));
+ fixedSome = true;
+ }
+ else
+ {
+ fixSkip.append(*i);
+ }
+ }
+
+ if (fixedSome)
+ {
+ KMessageBox::informationList(0L,
+ i18n("<qt>The no backup databases listed in your configuration file "
+ "have been adjusted to the new format. Database creator IDs "
+ "have been changed to use square brackets []."),
+ fixSkip,
+ i18n("No Backup Databases Updated"));
+ }
+}
+
+/* static */ KPilotConfig::RunMode KPilotConfig::interactiveUpdate()
+{
+ FUNCTIONSETUP;
+
+ int res = 0;
+ unsigned int fileVersion = KPilotSettings::configVersion();
+ // FIXME better config handling -> Move the config entries using kconf_update
+
+ // It's OK if we're already at the required level.
+ if (fileVersion >= KPilotConfig::ConfigurationVersion)
+ {
+ return Normal;
+ }
+
+ if (0 == fileVersion) // No config file at all
+ {
+ res = KMessageBox::questionYesNoCancel(0L,
+ i18n("KPilot is not configured for use. You may use "
+ "the configuration wizard or the normal configure dialog "
+ "to configure KPilot."),
+ i18n("Not Configured"),
+ i18n("Use &Wizard"),
+ i18n("Use &Dialog"));
+ if (res == KMessageBox::Yes) return WizardAndContinue;
+ if (res == KMessageBox::No) return ConfigureAndContinue;
+
+ return Cancel;
+ }
+
+ res = KMessageBox::warningContinueCancel(0L,
+ i18n("The configuration file for KPilot is out-of "
+ "date. KPilot can update some parts of the "
+ "configuration automatically. Do you wish to "
+ "continue?"),
+ i18n("Configuration File Out-of Date"));
+ if (res!=KMessageBox::Continue) return Cancel;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Updating from "
+ << fileVersion << " to " << ConfigurationVersion << endl;
+#endif
+
+ if (fileVersion < 440) update440();
+ if (fileVersion < 443) update443();
+
+ KPilotConfig::updateConfigVersion();
+ KPilotSettings::writeConfig();
+ return ConfigureAndContinue;
+}
+
+void KPilotConfig::sync()
+{
+ KPilotSettings::self()->config()->sync();
+}
diff --git a/kpilot/kpilot/kpilotConfig.h b/kpilot/kpilot/kpilotConfig.h
new file mode 100644
index 000000000..6b260bf7f
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfig.h
@@ -0,0 +1,126 @@
+#ifndef _KPILOT_KPILOTCONFIG_H
+#define _KPILOT_KPILOTCONFIG_H
+/* kpilotConfig.h KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This class concentrates all the configuration
+** information for the various parts of KPilot.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "kpilotSettings.h"
+
+class KCmdLineArgs;
+
+
+class KPilotConfig
+{
+public:
+ typedef enum
+ {
+ Cancel=0,
+ Normal,
+ ConfigureKPilot,
+ ConfigureConduits,
+ ConfigureAndContinue,
+ WizardAndContinue
+ } RunMode;
+
+ /**
+ * @return QString of default path for the BackupDB files
+ * are located
+ */
+ static QString getDefaultDBPath();
+
+
+ // Conduit configuration information
+ static void addDirtyDatabase(QString db);
+ static void addAppBlockChangedDatabase(QString db);
+ static void addFlagsChangedDatabase(QString db);
+
+ /**
+ * This number can be changed every time a new
+ * KPilot version is released that absolutely requires
+ * the user to take a look at the configuration of
+ * KPilot.
+ */
+ static const uint ConfigurationVersion;
+
+ /**
+ * Reads the configuration version from a configuration file.
+ * TODO: Make this use the *standard* location.
+ */
+ static int getConfigVersion();
+
+ /**
+ * Write the current configuration version to the standard
+ * location. @em Only call this after the KApplication object
+ * is created, or crashes will result.
+ */
+ static void updateConfigVersion();
+
+ /**
+ * Warn the user that the config file is outdated.
+ * versionDetails() returns a descriptive string. Pass in the
+ * actual version of the config file. Set @p run to true to add an
+ * admonition to run kpilot in config mode to fix this.
+ * sorryVersionOutdated() uses KMessageBox to display it.
+ */
+ static QString versionDetails(int fileversion, bool run);
+ static void sorryVersionOutdated(int fileversion);
+ /**
+ * Update the config file as best we can, and inform the user.
+ * Returns a suggested run mode if it's ok (ie. update finished, or
+ * file was already up-to-date) and Cancel if the user cancels.
+ * If the user cancels, it's probably best to _not_ continue with
+ * anything, since the config is bogus.
+ *
+ * The suggested run mode might be anything - usually normal,
+ * but might return ConfigureAndContinue as well.
+ *
+ * This function can call functions to update from different versions
+ * to current; these are static in kpilotConfig.cc.
+ */
+ static RunMode interactiveUpdate();
+
+ /**
+ * Deal with --debug options.
+ * @ret resulting debug level
+ */
+ static int getDebugLevel(KCmdLineArgs *p);
+
+ /**
+ * Returns the user's preference for the system-wide
+ * fixed font.
+ */
+ static const QFont& fixed() ;
+
+ static void sync();
+} ;
+
+
+
+#endif
diff --git a/kpilot/kpilot/kpilotConfigDialog.cc b/kpilot/kpilot/kpilotConfigDialog.cc
new file mode 100644
index 000000000..1cb12c163
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfigDialog.cc
@@ -0,0 +1,528 @@
+/* KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2002-2004 by Adriaan de Groot
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines a specialization of KPilotDeviceLink
+** that can actually handle some HotSync tasks, like backup
+** and restore. It does NOT do conduit stuff.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <pi-version.h>
+
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+#include <qpushbutton.h>
+#include <qbuttongroup.h>
+#include <qlineedit.h>
+#include <qtabwidget.h>
+#include <qspinbox.h>
+#include <qfile.h>
+
+#include <kmessagebox.h>
+#include <kcharsets.h>
+#include <kstandarddirs.h>
+#include <kglobal.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+
+#include "kpilotConfig.h"
+#include "kpilotSettings.h"
+
+#include "kpilotConfigDialog_device.h"
+#include "kpilotConfigDialog_sync.h"
+#include "kpilotConfigDialog_startup.h"
+#include "kpilotConfigDialog_viewers.h"
+#include "kpilotConfigDialog_backup.h"
+#include "kpilotConfigDialog.moc"
+#include "syncAction.h"
+#include "dbSelectionDialog.h"
+
+/* virtual */ QString ConfigPage::maybeSaveText() const
+{
+ return i18n("<qt>The settings for configuration page <i>%1</i> have been changed. Do you "
+ "want to save the changes before continuing?</qt>").arg(this->conduitName());
+}
+
+DeviceConfigPage::DeviceConfigPage(QWidget * w, const char *n ) : ConfigPage( w, n )
+{
+ FUNCTIONSETUP;
+
+ fConfigWidget = new DeviceConfigWidget( w );
+ // Fill the encodings list
+ {
+ QStringList l = KGlobal::charsets()->descriptiveEncodingNames();
+ for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it )
+ {
+ fConfigWidget->fPilotEncoding->insertItem(*it);
+ }
+ }
+
+ fConfigWidget->resize(fConfigWidget->size());
+ fWidget = fConfigWidget;
+
+#if PILOT_LINK_NUMBER < PILOT_LINK_0_10_0
+ fConfigWidget->fPilotDevice->setMaxLength(13);
+#endif
+
+
+#define CM(a,b) connect(fConfigWidget->a,b,this,SLOT(modified()));
+ CM(fPilotDevice, SIGNAL(textChanged(const QString &)));
+ CM(fPilotSpeed, SIGNAL(activated(int)));
+ CM(fPilotEncoding, SIGNAL(textChanged(const QString &)));
+ CM(fUserName, SIGNAL(textChanged(const QString &)));
+ CM(fWorkaround, SIGNAL(activated(int)));
+#undef CM
+
+ fConduitName = i18n("Device");
+}
+
+void DeviceConfigPage::load()
+{
+ FUNCTIONSETUP;
+ KPilotSettings::self()->readConfig();
+
+ /* General tab in the setup dialog */
+ fConfigWidget->fPilotDevice->setText(KPilotSettings::pilotDevice());
+ fConfigWidget->fPilotSpeed->setCurrentItem(KPilotSettings::pilotSpeed());
+ getEncoding();
+ fConfigWidget->fUserName->setText(KPilotSettings::userName());
+
+ switch(KPilotSettings::workarounds())
+ {
+ case KPilotSettings::eWorkaroundNone :
+ fConfigWidget->fWorkaround->setCurrentItem(0);
+ break;
+ case KPilotSettings::eWorkaroundUSB :
+ fConfigWidget->fWorkaround->setCurrentItem(1);
+ break;
+ default:
+ WARNINGKPILOT << "Unknown workaround number "
+ << (int) KPilotSettings::workarounds()
+ << endl;
+ KPilotSettings::setWorkarounds(KPilotSettings::eWorkaroundNone);
+ fConfigWidget->fWorkaround->setCurrentItem(0);
+ }
+ unmodified();
+}
+
+/* virtual */ bool DeviceConfigPage::validate()
+{
+ int r = KMessageBox::Yes;
+
+#if PILOT_LINK_NUMBER < PILOT_LINK_0_10_0
+ QString d = fConfigWidget->fPilotDevice->text();
+
+ if (d.length() > 13)
+ {
+ r = KMessageBox::questionYesNo(
+ fConfigWidget,
+ i18n("<qt>The device name you entered (<i>%1</i>) "
+ "is longer than 13 characters. This is "
+ "probably unsupported and can cause problems. "
+ "Are you sure you want to use this device name?</qt>")
+ .arg(d),
+ i18n("Device Name too Long"), i18n("Use"), i18n("Do Not Use")
+ ) ;
+ }
+#endif
+
+ return KMessageBox::Yes == r;
+}
+
+/* virtual */ void DeviceConfigPage::commit()
+{
+ FUNCTIONSETUP;
+
+ // General page
+ KPilotSettings::setPilotDevice(fConfigWidget->fPilotDevice->text());
+ KPilotSettings::setPilotSpeed(fConfigWidget->fPilotSpeed->currentItem());
+ setEncoding();
+ KPilotSettings::setUserName(fConfigWidget->fUserName->text());
+
+ switch(fConfigWidget->fWorkaround->currentItem())
+ {
+ case 0 : KPilotSettings::setWorkarounds(KPilotSettings::eWorkaroundNone); break;
+ case 1 : KPilotSettings::setWorkarounds(KPilotSettings::eWorkaroundUSB); break;
+ default :
+ WARNINGKPILOT << "Unknown workaround number "
+ << fConfigWidget->fWorkaround->currentItem()
+ << endl;
+ KPilotSettings::setWorkarounds(KPilotSettings::eWorkaroundNone);
+
+ }
+ KPilotConfig::updateConfigVersion();
+ KPilotSettings::self()->writeConfig();
+ unmodified();
+}
+
+/* slot */ void DeviceConfigPage::changePortType(int i)
+{
+ FUNCTIONSETUP;
+
+ switch (i)
+ {
+ case 0:
+ fConfigWidget->fPilotSpeed->setEnabled(true);
+ break;
+ case 1:
+ case 2:
+ fConfigWidget->fPilotSpeed->setEnabled(false);
+ break;
+ default:
+ WARNINGKPILOT << "Unknown port type " << i << endl;
+ }
+}
+
+void DeviceConfigPage::getEncoding()
+{
+ FUNCTIONSETUP;
+ QString e = KPilotSettings::encoding();
+ if (e.isEmpty())
+ fConfigWidget->fPilotEncoding->setCurrentText(CSL1("ISO8859-15"));
+ else
+ fConfigWidget->fPilotEncoding->setCurrentText(e);
+}
+
+void DeviceConfigPage::setEncoding()
+{
+ FUNCTIONSETUP;
+
+ QString enc = fConfigWidget->fPilotEncoding->currentText();
+ if (enc.isEmpty())
+ {
+ WARNINGKPILOT << "Empty encoding. Will ignore it." << endl;
+ }
+ else
+ {
+ KPilotSettings::setEncoding(enc);
+ }
+}
+
+SyncConfigPage::SyncConfigPage(QWidget * w, const char *n ) : ConfigPage( w, n )
+{
+ FUNCTIONSETUP;
+
+ fConfigWidget = new SyncConfigWidget( w );
+ fConfigWidget->resize(fConfigWidget->size());
+ fWidget = fConfigWidget;
+
+#define CM(a,b) connect(fConfigWidget->a,b,this,SLOT(modified()));
+ CM(fSpecialSync, SIGNAL(activated(int)));
+ CM(fFullSyncCheck, SIGNAL(toggled(bool)));
+ CM(fScreenlockSecure, SIGNAL(toggled(bool)));
+ CM(fConflictResolution, SIGNAL(activated(int)));
+#undef CM
+
+ fConduitName = i18n("HotSync");
+}
+
+#define MENU_ITEM_COUNT (4)
+static SyncAction::SyncMode::Mode syncTypeMap[MENU_ITEM_COUNT] = {
+ SyncAction::SyncMode::eHotSync,
+ SyncAction::SyncMode::eFullSync,
+ SyncAction::SyncMode::eCopyPCToHH,
+ SyncAction::SyncMode::eCopyHHToPC
+ } ;
+
+void SyncConfigPage::load()
+{
+ FUNCTIONSETUP;
+ KPilotSettings::self()->readConfig();
+
+ /* Sync tab */
+ int synctype=KPilotSettings::syncType();
+ if (synctype<0) synctype=(int) SyncAction::SyncMode::eHotSync;
+ for (unsigned int i=0; i<MENU_ITEM_COUNT; ++i)
+ {
+ if (syncTypeMap[i] == synctype)
+ {
+ fConfigWidget->fSpecialSync->setCurrentItem(i);
+ synctype=-1;
+ break;
+ }
+ }
+ if (synctype != -1)
+ {
+ fConfigWidget->fSpecialSync->setCurrentItem(0); /* HotSync */
+ }
+
+ fConfigWidget->fFullSyncCheck->setChecked(KPilotSettings::fullSyncOnPCChange());
+ fConfigWidget->fConflictResolution->setCurrentItem(KPilotSettings::conflictResolution());
+ fConfigWidget->fScreenlockSecure->setChecked(KPilotSettings::screenlockSecure());
+
+ unmodified();
+}
+
+/* virtual */ void SyncConfigPage::commit()
+{
+ FUNCTIONSETUP;
+
+ /* Sync tab */
+ int synctype = -1;
+ unsigned int selectedsync = fConfigWidget->fSpecialSync->currentItem();
+ if (selectedsync < MENU_ITEM_COUNT)
+ {
+ synctype = syncTypeMap[selectedsync];
+ }
+ if (synctype < 0)
+ {
+ synctype = SyncAction::SyncMode::eHotSync;
+ }
+
+ KPilotSettings::setSyncType(synctype);
+ KPilotSettings::setFullSyncOnPCChange(fConfigWidget->fFullSyncCheck->isChecked());
+ KPilotSettings::setConflictResolution(fConfigWidget->fConflictResolution->currentItem());
+ KPilotSettings::setScreenlockSecure(fConfigWidget->fScreenlockSecure->isChecked());
+
+ KPilotConfig::updateConfigVersion();
+ KPilotSettings::self()->writeConfig();
+ unmodified();
+}
+
+
+BackupConfigPage::BackupConfigPage(QWidget * w, const char *n ) : ConfigPage( w, n )
+{
+ FUNCTIONSETUP;
+
+ fConfigWidget = new BackupConfigWidget( w );
+ fConfigWidget->resize(fConfigWidget->size());
+ fWidget = fConfigWidget;
+
+ connect(fConfigWidget->fBackupOnlyChooser, SIGNAL( clicked() ),
+ SLOT( slotSelectNoBackupDBs() ) );
+ connect(fConfigWidget->fSkipDBChooser, SIGNAL(clicked()),
+ SLOT(slotSelectNoRestoreDBs()));
+
+#define CM(a,b) connect(fConfigWidget->a,b,this,SLOT(modified()));
+ CM(fBackupOnly, SIGNAL(textChanged(const QString &)));
+ CM(fSkipDB, SIGNAL(textChanged(const QString &)));
+ CM(fBackupFrequency, SIGNAL(activated(int)));
+#undef CM
+
+ fConduitName = i18n("Backup");
+}
+
+void BackupConfigPage::load()
+{
+ FUNCTIONSETUP;
+ KPilotSettings::self()->readConfig();
+
+ /* Backup tab */
+ fConfigWidget->fBackupOnly->setText(KPilotSettings::skipBackupDB().join(CSL1(",")));
+ fConfigWidget->fSkipDB->setText(KPilotSettings::skipRestoreDB().join(CSL1(",")));
+ fConfigWidget->fRunConduitsWithBackup->setChecked(KPilotSettings::runConduitsWithBackup());
+
+ int backupfreq=KPilotSettings::backupFrequency();
+
+ fConfigWidget->fBackupFrequency->setCurrentItem(backupfreq);
+
+ unmodified();
+}
+
+/* virtual */ void BackupConfigPage::commit()
+{
+ FUNCTIONSETUP;
+
+ /* Backup tab */
+ KPilotSettings::setSkipBackupDB(
+ QStringList::split(CSL1(","),fConfigWidget->fBackupOnly->text()));
+ KPilotSettings::setSkipRestoreDB(
+ QStringList::split(CSL1(","),fConfigWidget->fSkipDB->text()));
+ KPilotSettings::setRunConduitsWithBackup(fConfigWidget->fRunConduitsWithBackup->isChecked());
+ KPilotSettings::setBackupFrequency(fConfigWidget->fBackupFrequency->currentItem());
+
+ KPilotConfig::updateConfigVersion();
+ KPilotSettings::self()->writeConfig();
+ unmodified();
+}
+
+void BackupConfigPage::slotSelectNoBackupDBs()
+{
+ FUNCTIONSETUP;
+
+ QStringList selectedDBs(QStringList::split(',', fConfigWidget->fBackupOnly->text() ));
+
+ QStringList deviceDBs=KPilotSettings::deviceDBs();
+ QStringList addedDBs=KPilotSettings::addedDBs();
+ KPilotDBSelectionDialog*dlg=new KPilotDBSelectionDialog(selectedDBs, deviceDBs, addedDBs, 0, "NoBackupDBs");
+ if (dlg && (dlg->exec()==QDialog::Accepted) )
+ {
+ fConfigWidget->fBackupOnly->setText(
+ dlg->getSelectedDBs().join(CSL1(",")));
+ KPilotSettings::setAddedDBs( dlg->getAddedDBs() );
+ }
+ KPILOT_DELETE(dlg);
+}
+
+void BackupConfigPage::slotSelectNoRestoreDBs()
+{
+ FUNCTIONSETUP;
+
+ QStringList selectedDBs(QStringList::split(',', fConfigWidget->fSkipDB->text() ));
+
+ QStringList deviceDBs=KPilotSettings::deviceDBs();
+ QStringList addedDBs=KPilotSettings::addedDBs();
+ KPilotDBSelectionDialog*dlg=new KPilotDBSelectionDialog(selectedDBs, deviceDBs, addedDBs, 0, "NoRestoreDBs");
+ if (dlg && (dlg->exec()==QDialog::Accepted) )
+ {
+ fConfigWidget->fSkipDB->setText(
+ dlg->getSelectedDBs().join(CSL1(",")));
+ KPilotSettings::setAddedDBs( dlg->getAddedDBs() );
+ }
+ KPILOT_DELETE(dlg);
+}
+
+
+
+ViewersConfigPage::ViewersConfigPage(QWidget * w, const char *n ) : ConfigPage( w, n )
+{
+ FUNCTIONSETUP;
+
+ fConfigWidget = new ViewersConfigWidget( w );
+ fConfigWidget->resize(fConfigWidget->size());
+ fWidget = fConfigWidget;
+
+#define CM(a,b) connect(fConfigWidget->a,b,this,SLOT(modified()));
+ CM(fInternalEditors, SIGNAL(toggled(bool)));
+ CM(fUseSecret, SIGNAL(toggled(bool)));
+ CM(fAddressGroup, SIGNAL(clicked(int)));
+ CM(fUseKeyField, SIGNAL(toggled(bool)));
+#undef CM
+
+ fConduitName = i18n("Viewers");
+}
+
+void ViewersConfigPage::load()
+{
+ FUNCTIONSETUP;
+ KPilotSettings::self()->readConfig();
+
+ fConfigWidget->fInternalEditors->setChecked( false /* KPilotSettings::internalEditors() */ );
+ fConfigWidget->fUseSecret->setChecked(KPilotSettings::showSecrets());
+ fConfigWidget->fAddressGroup->setButton(KPilotSettings::addressDisplayMode());
+ fConfigWidget->fUseKeyField->setChecked(KPilotSettings::useKeyField());
+ unmodified();
+}
+
+/* virtual */ void ViewersConfigPage::commit()
+{
+ FUNCTIONSETUP;
+
+ KPilotSettings::setInternalEditors( fConfigWidget->fInternalEditors->isChecked());
+ KPilotSettings::setShowSecrets(fConfigWidget->fUseSecret->isChecked());
+ KPilotSettings::setAddressDisplayMode(fConfigWidget->fAddressGroup->id(
+ fConfigWidget->fAddressGroup->selected()));
+ KPilotSettings::setUseKeyField(fConfigWidget->fUseKeyField->isChecked());
+ KPilotConfig::updateConfigVersion();
+ KPilotSettings::self()->writeConfig();
+ unmodified();
+}
+
+
+
+
+
+
+
+
+
+StartExitConfigPage::StartExitConfigPage(QWidget * w, const char *n ) : ConfigPage( w, n )
+{
+ FUNCTIONSETUP;
+
+ fConfigWidget = new StartExitConfigWidget( w );
+ fConfigWidget->resize(fConfigWidget->size());
+ fWidget = fConfigWidget;
+
+#define CM(a,b) connect(fConfigWidget->a,b,this,SLOT(modified()));
+ CM(fStartDaemonAtLogin, SIGNAL(toggled(bool)));
+ CM(fKillDaemonOnExit, SIGNAL(toggled(bool)));
+ CM(fDockDaemon, SIGNAL(toggled(bool)));
+ CM(fQuitAfterSync, SIGNAL(toggled(bool)));
+#undef CM
+
+ fConduitName = i18n("Startup and Exit");
+}
+
+void StartExitConfigPage::load()
+{
+ FUNCTIONSETUP;
+ KPilotSettings::self()->readConfig();
+
+ fConfigWidget->fStartDaemonAtLogin->setChecked(KPilotSettings::startDaemonAtLogin());
+ fConfigWidget->fDockDaemon->setChecked(KPilotSettings::dockDaemon());
+ fConfigWidget->fKillDaemonOnExit->setChecked(KPilotSettings::killDaemonAtExit());
+ fConfigWidget->fQuitAfterSync->setChecked(KPilotSettings::quitAfterSync());
+ unmodified();
+}
+
+
+/* virtual */ void StartExitConfigPage::commit()
+{
+ FUNCTIONSETUP;
+
+ QString autostart = KGlobalSettings::autostartPath();
+ QString desktopfile = CSL1("kpilotdaemon.desktop");
+ QString desktopcategory = CSL1("kde/");
+ QString location = KGlobal::dirs()->findResource("xdgdata-apps",desktopcategory + desktopfile);
+ if (location.isEmpty()) // Fallback to KDE 3.0?
+ {
+ location = KGlobal::dirs()->findResource("apps",desktopfile);
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Autostart=" << autostart << endl;
+ DEBUGKPILOT << fname << ": desktop=" << desktopfile << endl;
+ DEBUGKPILOT << fname << ": location=" << location << endl;
+#endif
+
+ KPilotSettings::setStartDaemonAtLogin(fConfigWidget->fStartDaemonAtLogin->isChecked());
+ if (KPilotSettings::startDaemonAtLogin())
+ {
+ if (!location.isEmpty())
+ {
+ KURL src;
+ src.setPath(location);
+ KURL dst;
+ dst.setPath(autostart+desktopfile);
+ KIO::NetAccess::file_copy(src,dst,-1 /* 0666? */,true /* overwrite */);
+ }
+ }
+ else
+ {
+ QFile::remove(autostart+desktopfile);
+ }
+ KPilotSettings::setDockDaemon(fConfigWidget->fDockDaemon->isChecked());
+ KPilotSettings::setKillDaemonAtExit(fConfigWidget->fKillDaemonOnExit->isChecked());
+ KPilotSettings::setQuitAfterSync(fConfigWidget->fQuitAfterSync->isChecked());
+ KPilotConfig::updateConfigVersion();
+ KPilotSettings::self()->writeConfig();
+ unmodified();
+}
+
diff --git a/kpilot/kpilot/kpilotConfigDialog.h b/kpilot/kpilot/kpilotConfigDialog.h
new file mode 100644
index 000000000..50a182dfa
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfigDialog.h
@@ -0,0 +1,134 @@
+#ifndef _KPILOT_KPILOTCONFIGDIALOG_H
+#define _KPILOT_KPILOTCONFIGDIALOG_H
+/* kpilotConfigDialog.h KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines a specialization of KPilotDeviceLink
+** that can actually handle some HotSync tasks, like backup
+** and restore. It does NOT do conduit stuff.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "plugin.h"
+
+
+// class KPilotConfigWidget;
+class StartExitConfigWidget;
+class SyncConfigWidget;
+class DeviceConfigWidget;
+class ViewersConfigWidget;
+class BackupConfigWidget;
+
+class ConfigPage : public ConduitConfigBase
+{
+public:
+ ConfigPage( QWidget *w, const char *n ) : ConduitConfigBase(w,n) { } ;
+protected:
+ // Override base class virtual function.
+ virtual QString maybeSaveText() const;
+} ;
+
+class DeviceConfigPage : public ConfigPage
+{
+Q_OBJECT
+public:
+ DeviceConfigPage( QWidget *, const char * );
+
+protected:
+ virtual bool validate();
+ virtual void load();
+ virtual void commit();
+
+protected slots:
+ void changePortType(int);
+
+private:
+ DeviceConfigWidget *fConfigWidget;
+
+ // Read and write the values of Encoding
+ // and EncodingDD.
+ void getEncoding();
+ void setEncoding();
+} ;
+
+
+class KDE_EXPORT SyncConfigPage : public ConfigPage
+{
+public:
+ SyncConfigPage( QWidget *, const char * );
+
+protected:
+ virtual void load();
+ virtual void commit();
+
+private:
+ SyncConfigWidget *fConfigWidget;
+} ;
+
+class BackupConfigPage : public ConfigPage
+{
+Q_OBJECT
+public:
+ BackupConfigPage( QWidget *, const char * );
+
+protected:
+ virtual void load();
+ virtual void commit();
+
+protected slots:
+ void slotSelectNoBackupDBs();
+ void slotSelectNoRestoreDBs();
+
+private:
+ BackupConfigWidget *fConfigWidget;
+} ;
+
+class StartExitConfigPage : public ConfigPage
+{
+public:
+ StartExitConfigPage( QWidget *, const char * );
+
+protected:
+ virtual void load();
+ virtual void commit();
+
+private:
+ StartExitConfigWidget *fConfigWidget;
+} ;
+
+class ViewersConfigPage : public ConfigPage
+{
+public:
+ ViewersConfigPage( QWidget *, const char * );
+
+protected:
+ virtual void load();
+ virtual void commit();
+
+private:
+ ViewersConfigWidget *fConfigWidget;
+} ;
+
+#endif
diff --git a/kpilot/kpilot/kpilotConfigDialog_backup.ui b/kpilot/kpilot/kpilotConfigDialog_backup.ui
new file mode 100644
index 000000000..9591c6c5c
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfigDialog_backup.ui
@@ -0,0 +1,207 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>BackupConfigWidget</class>
+<comment>A widget for editing HotSync-specific settings.</comment>
+<author>David Bishop</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>BackupConfigForm</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>549</width>
+ <height>424</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>KPilot Options</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox23_2</cstring>
+ </property>
+ <property name="title">
+ <string>Backup Frequency</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel5_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Do &amp;backup:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fBackupFrequency</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <item>
+ <property name="text">
+ <string>On every HotSync</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>On request only</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fBackupFrequency</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox23</cstring>
+ </property>
+ <property name="title">
+ <string>Databases</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>&amp;No backup:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fBackupOnly</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;Enter the databases types you wish to exclude from the backup operation here. Use this setting if backing up some databases crashes the handheld, or if you do not want a backup of some databases (like AvantGo pages).&lt;/p&gt;&lt;p&gt;Entries with square brackets [] are &lt;i&gt;creator codes&lt;/i&gt; like &lt;tt&gt;[lnch]&lt;/tt&gt; and can exclude a whole range of databases. Entries without the brackets list database names, and may include shell-style wildcards, like &lt;tt&gt;*_a68k&lt;/tt&gt;.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel6</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Not &amp;restored:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fSkipDB</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;Enter the databases types you wish to exclude from the restore operation here (like AvantGo databases). They will be skipped even if they exist in the set of backup databases on the handheld. If you still want to install an ignored database to the handheld, you can always manually install it to the handheld.&lt;/p&gt;&lt;p&gt;Entries with square brackets [] are &lt;i&gt;creator codes&lt;/i&gt; like &lt;tt&gt;[lnch]&lt;/tt&gt; and can exclude a whole range of databases. Entries without the brackets list database names, and may include shell-style wildcards, like &lt;tt&gt;*_a68k&lt;/tt&gt;.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>fBackupOnly</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;Enter the databases types you wish to exclude from the backup operation here. Use this setting if backing up some databases crashes the handheld, or if you do not want a backup of some databases (like AvantGo pages).&lt;/p&gt;&lt;p&gt;Entries with square brackets [] are &lt;i&gt;creator codes&lt;/i&gt; like &lt;tt&gt;[lnch]&lt;/tt&gt; and can exclude a whole range of databases. Entries without the brackets list database names, and may include shell-style wildcards, like &lt;tt&gt;*_a68k&lt;/tt&gt;.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>fSkipDB</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;&lt;p&gt;Enter the databases types you wish to exclude from the restore operation here (like AvantGo databases). They will be skipped even if they exist in the set of backup databases on the handheld. If you still want to install an ignored database to the handheld, you can always manually install it to the handheld.&lt;/p&gt;&lt;p&gt;Entries with square brackets [] are &lt;i&gt;creator codes&lt;/i&gt; like &lt;tt&gt;[lnch]&lt;/tt&gt; and can exclude a whole range of databases. Entries without the brackets list database names, and may include shell-style wildcards, like &lt;tt&gt;*_a68k&lt;/tt&gt;.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="0" column="2">
+ <property name="name">
+ <cstring>fBackupOnlyChooser</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Click here to open the database selection dialog. This dialog allows you to check the databases you want to exclude from the backup from a list.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="1" column="2">
+ <property name="name">
+ <cstring>fSkipDBChooser</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Click here to open the database selection dialog. This dialog allows you to select the databases you want to exclude from the restore operation from a list.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>fRunConduitsWithBackup</cstring>
+ </property>
+ <property name="text">
+ <string>Run conduits durin&amp;g a backup sync</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to run the selected conduits before every backup. This makes sure the backup is up to date with the last changes from your PC.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>41</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpilot/kpilot/kpilotConfigDialog_device.ui b/kpilot/kpilot/kpilotConfigDialog_device.ui
new file mode 100644
index 000000000..20f840e8a
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfigDialog_device.ui
@@ -0,0 +1,189 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>DeviceConfigWidget</class>
+<comment>A widget for configuring the hardware device.</comment>
+<author>David Bishop</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>DeviceForm</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>383</width>
+ <height>334</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>KPilot Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Pilot &amp;device:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fPilotDevice</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter the device the Pilot is attached to (for instance a serial or USB port) here. You can also use &lt;i&gt;/dev/pilot&lt;/i&gt;, and make that a symlink to the correct device. You need write permission to successfully synchronize with the handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fPilotDevice</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter the device the Pilot is attached to (for instance a serial or USB port) here. You can also use &lt;i&gt;/dev/pilot&lt;/i&gt;, and make that a symlink to the correct device. You need write permission to successfully synchronize with the handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Speed:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fPilotSpeed</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select the speed of the serial connection to your handheld here. This has no meaning for USB devices. For an older model, choose 9600. Newer models may be able to handle speeds up to the maximum listed, 115200. You can experiment with the connection speed: the manual suggests starting at a speed of 19200 and trying faster speeds to see if they work.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="4" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fUserName</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter your name here, as it appears in the Pilot's &amp;quot;Owner&amp;quot; setting.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <spacer row="5" column="2">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>90</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>9600</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>19200</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>38400</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>57600</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>115200</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fPilotSpeed</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select the speed of the serial connection to your handheld here. This has no meaning for USB devices. For an older model, choose 9600. Newer models may be able to handle speeds up to the maximum listed, 115200. You can experiment with the connection speed: the manual suggests starting at a speed of 19200 and trying faster speeds to see if they work.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>En&amp;coding:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fPilotEncoding</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;PalmOS devices are available in many different languages. If your device uses a different encoding than ISO-latin1 (ISO8859-1), select the correct encoding here, in order to display special characters correctly.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Pilot &amp;user:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fUserName</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter your name here, as it appears in the Pilot's &amp;quot;Owner&amp;quot; setting.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="3" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fPilotEncoding</cstring>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;PalmOS devices are available in many different languages. If your device uses a different encoding than ISO-latin1 (ISO8859-1), select the correct encoding here, in order to display special characters correctly.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Workarounds:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fWorkaround</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="1" rowspan="1" colspan="2">
+ <item>
+ <property name="text">
+ <string>None</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Zire 31, 72, Tungsten T5</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fWorkaround</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Workarounds enable special handling for specific devices. Most devices do not need special handling. However, the Zire&tm; 31, Zire 72 and Tungsten T5 &lt;i&gt;do&lt;/i&gt; have special needs, so if you are connecting such a device, please select the workaround for them.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="0"/>
+</UI>
diff --git a/kpilot/kpilot/kpilotConfigDialog_startup.ui b/kpilot/kpilot/kpilotConfigDialog_startup.ui
new file mode 100644
index 000000000..6445e6eae
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfigDialog_startup.ui
@@ -0,0 +1,118 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>StartExitConfigWidget</class>
+<comment>A tabWidget for configuring
+KPilot's settings.</comment>
+<author>David Bishop</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>StartExitForm</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>593</width>
+ <height>323</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>KPilot Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox" row="1" column="0">
+ <property name="name">
+ <cstring>groupBox4</cstring>
+ </property>
+ <property name="title">
+ <string>Exit Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>fKillDaemonOnExit</cstring>
+ </property>
+ <property name="text">
+ <string>S&amp;top KPilot's system tray application on exit</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to stop the KPilot daemon when you quit KPilot (only if KPilot started the daemon itself).&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>fQuitAfterSync</cstring>
+ </property>
+ <property name="text">
+ <string>Quit &amp;after HotSync</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to stop both KPilot and the KPilot daemon after the HotSync finishes. This may be useful for systems where KPilot is started by the USB daemon.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>GroupBox1_2</cstring>
+ </property>
+ <property name="title">
+ <string>Startup Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>fStartDaemonAtLogin</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Start KPilot at login</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to start up the KPilot daemon every time you log in to KDE.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>fDockDaemon</cstring>
+ </property>
+ <property name="text">
+ <string>S&amp;how KPilot in system tray</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to place a Kpilot icon in the system tray, which shows the daemon's status, and allows you to select the next sync type and to configure KPilot.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpilot/kpilot/kpilotConfigDialog_sync.ui b/kpilot/kpilot/kpilotConfigDialog_sync.ui
new file mode 100644
index 000000000..7571b1971
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfigDialog_sync.ui
@@ -0,0 +1,171 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>SyncConfigWidget</class>
+<comment>A widget for editing HotSync-specific settings.</comment>
+<author>David Bishop</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>SyncConfigForm</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>593</width>
+ <height>332</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>KPilot Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QCheckBox" row="1" column="1">
+ <property name="name">
+ <cstring>fFullSyncCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Do full sync when chan&amp;ging PCs</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to perform a full sync when your last sync was performed with another PC or system, to guarantee the completeness of your data.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>HotSync (sync all changes)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>FullSync (sync also unchanged records)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Copy PC to Handheld</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Copy Handheld to PC</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fSpecialSync</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select in this list the synchronization type that KPilot will use as default. Possible values are:&lt;br&gt;"HotSync", to run all selected conduits, and sync the databases with a modified flag set, updating the modified records only;&lt;br&gt;"FullSync" to run all selected conduits, and sync all databases, reading all records, and performing a full backup;&lt;br&gt;"Copy PC to handheld" to run all conduits and sync all databases, but instead of merging the information from both sources, copy the PC data to the handheld;&lt;br&gt;"Copy handheld to PC" to run all conduits and sync all databases, but instead of merging the information from both sources, copy the handheld data to the PC.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Default sync:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fSpecialSync</cstring>
+ </property>
+ </widget>
+ <spacer row="4" column="1">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>170</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QComboBox" row="3" column="1">
+ <item>
+ <property name="text">
+ <string>Ask User</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Do Nothing</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Handheld Overrides</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>PC Overrides</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Values From Last Sync (if possible)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Use Both Entries</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fConflictResolution</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select in this list how conflicting entries (entries which were edited both on your handheld and on the PC) are resolved. Possibly values are "Ask User" to let you decide case by case, "Do Nothing" to allow the entries to be different, "PC overrides", "Handheld overrides", "Use values from last sync" and "Use both entries" to create a new entry on both the PC and handheld. Note that the conflict resolution option selected here can be overridden by conduits that have their own conflict resolution configuration.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Conflict &amp;resolution:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fConflictResolution</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="1">
+ <property name="name">
+ <cstring>fScreenlockSecure</cstring>
+ </property>
+ <property name="text">
+ <string>Do not sync when screensaver is active</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to prevent KPilot from syncing your handheld while the screensaver is active: this is a security measure to prevent others from syncing &lt;i&gt;their&lt;/i&gt; handhelds with your data. This option must be disabled when you use a different desktop, since KPilot is not aware of screensavers other than KDE's.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpilot/kpilot/kpilotConfigDialog_viewers.ui b/kpilot/kpilot/kpilotConfigDialog_viewers.ui
new file mode 100644
index 000000000..1be8b4081
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfigDialog_viewers.ui
@@ -0,0 +1,149 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>ViewersConfigWidget</class>
+<comment>A tabWidget for configuring
+KPilot's settings.</comment>
+<author>David Bishop</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ViewersForm</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>610</width>
+ <height>325</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>KPilot Options</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Viewers</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>fInternalEditors</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Make internal viewers &amp;editable</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;The internal viewers can be read only or editable. The editable mode allows you to add new records, delete or edit the existing records and sync your modifications back to the handheld. Check this box to set the internal viewers to editable mode, uncheck to set them to read only mode.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>fUseSecret</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Show private records</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to display in the internal viewers records that are marked &amp;quot;Private&amp;quot; in the Pilot.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>fAddressGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Address Viewer</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>fNormalDisplay</cstring>
+ </property>
+ <property name="text">
+ <string>Show as "&amp;Last, first"</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to display addresses in the internal address viewer sorted by last name, first name.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>fCompanyDisplay</cstring>
+ </property>
+ <property name="text">
+ <string>Show as "&amp;Company, last"</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select this option to display addresses in the internal address viewer sorted by company name, last name.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="Line" row="2" column="0">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="0">
+ <property name="name">
+ <cstring>fUseKeyField</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Use key field</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to combine all entries with the same last name in the internal address viewer.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>41</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpilot/kpilot/kpilotConfigWizard.cc b/kpilot/kpilot/kpilotConfigWizard.cc
new file mode 100644
index 000000000..d21ec5d81
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfigWizard.cc
@@ -0,0 +1,233 @@
+/* KPilot
+**
+** Copyright (C) 2004 by Reinhold Kainhofer
+**
+** A simple configuration wizard.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+//#include "options.h"
+
+#include <qpushbutton.h>
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qlineedit.h>
+
+#include <kmessagebox.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kconfigskeleton.h>
+
+#include "kpilotConfig.h"
+#include "options.h"
+
+#include "kpilotConfigWizard_app.h"
+#include "kpilotConfigWizard_user.h"
+#include "kpilotConfigWizard_address.h"
+#include "kpilotConfigWizard_notes.h"
+#include "kpilotConfigWizard_vcal.h"
+
+
+#include "kpilotConfigWizard.moc"
+#include "kpilotProbeDialog.h"
+
+
+ConfigWizard::ConfigWizard(QWidget *parent, const char *n, int m) :
+ KWizard(parent, n),
+ fMode((Mode)m)
+{
+// page1=new ConfigWizard_base1(this);
+// addPage( page1, i18n("Select Connection Type") );
+ page2=new ConfigWizard_base2(this);
+ addPage( page2, i18n("Pilot Info") );
+ page3=new ConfigWizard_base3(this);
+ addPage( page3, i18n("Application to Sync With") );
+ setFinishEnabled( page3, true );
+
+ setHelpEnabled( page2, false );
+ setHelpEnabled( page3, false );
+
+ connect( page2->fProbeButton, SIGNAL( pressed() ),
+ this, SLOT( probeHandheld() ) );
+
+ KPilotSettings::self()->readConfig();
+ page2->fUserName->setText( KPilotSettings::userName() );
+ page2->fDeviceName->setText( KPilotSettings::pilotDevice() );
+ page2->fPilotRunningPermanently->setChecked( KPilotSettings::startDaemonAtLogin() );
+
+}
+
+ConfigWizard::~ConfigWizard()
+{
+}
+
+void ConfigWizard::accept()
+{
+ FUNCTIONSETUP;
+ QString username( page2->fUserName->text() );
+ QString devicename( page2->fDeviceName->text() );
+// int devicetype( page1->fConnectionType->selectedId() );
+ enum eSyncApp {
+ eAppKDE=0,
+ //eAppKontact,
+ eAppEvolution,
+ eAppNone
+ } app;
+ app=(eSyncApp)( page3->fAppType->selectedId() );
+ bool keepPermanently( page2->fPilotRunningPermanently->isChecked() );
+#ifdef DEBUG
+ DEBUGKPILOT<<fname<<"Keep permanently: "<<keepPermanently<<endl;
+#endif
+
+ KPilotSettings::setPilotDevice( devicename );
+ KPilotSettings::setUserName(username);
+// KPilotSettings::setEncoding("iso 8859-15");
+ KPilotSettings::setDockDaemon( true );
+ KPilotSettings::setKillDaemonAtExit( !keepPermanently);
+ KPilotSettings::setQuitAfterSync( !keepPermanently );
+ KPilotSettings::setStartDaemonAtLogin( keepPermanently );
+ KPilotSettings::setSyncType(0);
+ KPilotSettings::setFullSyncOnPCChange( true );
+ KPilotSettings::setConflictResolution(0);
+ if ( !mDBs.isEmpty() )
+ KPilotSettings::setDeviceDBs( mDBs );
+
+ KPilotWizard_vcalConfig*calendarConfig = new KPilotWizard_vcalConfig("Calendar");
+ KPilotWizard_vcalConfig*todoConfig = new KPilotWizard_vcalConfig("ToDo");
+ KPilotWizard_addressConfig*addressConfig = new KPilotWizard_addressConfig();
+ KPilotWizard_notesConfig*notesConfig = new KPilotWizard_notesConfig();
+ addressConfig->readConfig();
+ notesConfig->readConfig();
+ todoConfig->readConfig();
+ calendarConfig->readConfig();
+
+ QStringList conduits = KPilotSettings::installedConduits();
+ int version(0);
+#define APPEND_CONDUIT(a) if (!conduits.contains(a)) conduits.append(a)
+ QString applicationName(i18n("general KDE-PIM"));
+ APPEND_CONDUIT("internal_fileinstall");
+ APPEND_CONDUIT("todo-conduit");
+ APPEND_CONDUIT("vcal-conduit");
+ switch (app) {
+ case eAppEvolution:
+ applicationName=i18n("Gnome's PIM suite", "Evolution");
+
+ // TODO: Once the Evolution abook resource is finished, enable it...
+ conduits.remove("abbrowser_conduit");
+ // addressConfig->setDefaults();
+ // addressConfig->setAddressbookType( KPilotWizard_addressConfig::eAbookResource );
+ //// addressConfig->revertToDefault("ArchiveDeleted");
+ //// addressConfig->revertToDefault("ConflictResolution");
+
+ // nothing to do for knotes conduit yet (evolution doesn't have notes)
+ conduits.remove("knotes-conduit");
+
+ // the vcalconduits use the same config file, so set the correct groups
+ version = calendarConfig->conduitVersion();
+ calendarConfig->setDefaults();
+ calendarConfig->setCalendarType( KPilotWizard_vcalConfig::eCalendarLocal );
+ calendarConfig->setCalendarFile( "$HOME/evolution/local/Calendar/calendar.ics" );
+ calendarConfig->setConduitVersion( version );
+ version = todoConfig->conduitVersion();
+ todoConfig->setDefaults();
+ todoConfig->setCalendarType( KPilotWizard_vcalConfig::eCalendarLocal );
+ todoConfig->setCalendarFile( "$HOME/evolution/local/Tasks/tasks.ics" );
+ todoConfig->setConduitVersion( version );
+
+ KMessageBox::information(this, i18n("KPilot cannot yet synchronize the addressbook with Evolution, so the addressbook conduit was disabled.\nWhen syncing the calendar or to-do list using KPilot please quit Evolution before the sync, otherwise you will lose data."), i18n("Restrictions with Evolution"));
+ break;
+ case eAppNone:
+ conduits.clear();
+ APPEND_CONDUIT("internal_fileinstall");
+ applicationName=i18n("Kpilot will sync with nothing","nothing (it will backup only)");
+ break;
+// case eAppKontact:
+ case eAppKDE:
+ applicationName=i18n("KDE's PIM suite", "Kontact");
+ default:
+ APPEND_CONDUIT("knotes-conduit");
+ APPEND_CONDUIT("abbrowser_conduit");
+ // Set to the stdaddressbook, reset others to defaults
+ addressConfig->setAddressbookType( KPilotWizard_addressConfig::eAbookResource );
+ addressConfig->setArchiveDeleted( true );
+ addressConfig->setConflictResolution( -1 );
+ // nothing to do for knotes conduit yet
+ // notesConfig->set...
+ // the vcalconduits use the same config file, so set the correct groups
+ int version = calendarConfig->conduitVersion();
+ calendarConfig->setDefaults();
+ calendarConfig->setCalendarType( KPilotWizard_vcalConfig::eCalendarResource );
+ calendarConfig->setConduitVersion( version );
+ version = todoConfig->conduitVersion();
+ todoConfig->setDefaults();
+ todoConfig->setCalendarType( KPilotWizard_vcalConfig::eCalendarResource );
+ todoConfig->setConduitVersion( version );
+ break;
+ }
+ addressConfig->writeConfig();
+ notesConfig->writeConfig();
+ todoConfig->writeConfig();
+ calendarConfig->writeConfig();
+
+ KPILOT_DELETE(addressConfig);
+ KPILOT_DELETE(notesConfig);
+ KPILOT_DELETE(todoConfig);
+ KPILOT_DELETE(calendarConfig);
+
+ KPilotSettings::setInstalledConduits( conduits );
+#undef APPEND_CONDUIT
+
+ QString finishMessage = i18n("KPilot is now configured to sync with %1.").arg(applicationName);
+ if (fMode == InDialog)
+ {
+ finishMessage.append(CSL1("\n"));
+ finishMessage.append(i18n(
+ "The remaining options in the config dialog are advanced options and can "
+ "be used to fine-tune KPilot."));
+ }
+
+ KMessageBox::information(this, finishMessage,
+ i18n("Automatic Configuration Finished"));
+ KPilotSettings::self()->writeConfig();
+ QDialog::accept();
+}
+
+void ConfigWizard::probeHandheld()
+{
+ if ( KMessageBox::warningContinueCancel( this, i18n("Please put the handheld "
+ "in the cradle, press the hotsync button and click on \"Continue\".\n\nSome "
+ "kernel versions (Linux 2.6.x) have problems with the visor kernel module "
+ "(for Sony Clie devices). Running an autodetection in that case might block "
+ "the computer from doing hotsyncs until it is rebooted. In that case it might "
+ "be advisable not to continue."),
+ i18n("Handheld Detection") ) == KMessageBox::Continue ) {
+ ProbeDialog *probeDialog = new ProbeDialog( this );
+ if ( probeDialog->exec() && probeDialog->detected() ) {
+ page2->fUserName->setText( probeDialog->userName() );
+ page2->fDeviceName->setText( probeDialog->device() );
+ mDBs = probeDialog->dbs();
+ }
+ KPILOT_DELETE(probeDialog);
+ }
+}
+
diff --git a/kpilot/kpilot/kpilotConfigWizard.h b/kpilot/kpilot/kpilotConfigWizard.h
new file mode 100644
index 000000000..3a448c4fa
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfigWizard.h
@@ -0,0 +1,58 @@
+#ifndef _KPILOT_CONFIGWIZARD_H
+#define _KPILOT_CONFIGWIZARD_H
+/* kpilotConfigWizard.h KPilot
+**
+** Copyright (C) 2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines kpilot's configuration wizard
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "kwizard.h"
+
+class ConfigWizard_base1;
+class ConfigWizard_base2;
+class ConfigWizard_base3;
+
+class ConfigWizard : public KWizard
+{
+Q_OBJECT
+public:
+ enum Mode { InDialog=0, Standalone=1 } ;
+
+ ConfigWizard(QWidget *p=0L,const char *n=0L, int mode=(int)InDialog);
+ ~ConfigWizard();
+
+protected slots:
+ void probeHandheld();
+protected:
+ void accept();
+// ConfigWizard_base1 *page1;
+ ConfigWizard_base2 *page2;
+ ConfigWizard_base3 *page3;
+
+ Mode fMode;
+ QStringList mDBs;
+} ;
+
+#endif
diff --git a/kpilot/kpilot/kpilotConfigWizard_address.kcfgc b/kpilot/kpilot/kpilotConfigWizard_address.kcfgc
new file mode 100644
index 000000000..884fd3af6
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfigWizard_address.kcfgc
@@ -0,0 +1,7 @@
+File=../conduits/abbrowserconduit/abbrowserconduit.kcfg
+ClassName=KPilotWizard_addressConfig
+Singleton=False
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/kpilot/kpilotConfigWizard_app.ui b/kpilot/kpilot/kpilotConfigWizard_app.ui
new file mode 100644
index 000000000..7a690f869
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfigWizard_app.ui
@@ -0,0 +1,112 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>ConfigWizard_base3</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ConfigWizard_base3</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>462</width>
+ <height>404</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>Finally, you can configure KPilot specifically for some PIM applications, like Kontact (KDE's integrated PIM application) or Evolution (GNOME's integrated PIM application).
+
+Press "Finish" to setup KPilot according to the settings in this configuration Wizard.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="2" column="0">
+ <property name="name">
+ <cstring>fAppType</cstring>
+ </property>
+ <property name="title">
+ <string>Set Default Values for Syncing With</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton6</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;KDE-PIM suite (Kontact)</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton8</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;GNOME-PIM (Evolution)</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton4</cstring>
+ </property>
+ <property name="text">
+ <string>No sync, just backup</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>120</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer5_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>12</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>radioButton6</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpilot/kpilot/kpilotConfigWizard_notes.kcfgc b/kpilot/kpilot/kpilotConfigWizard_notes.kcfgc
new file mode 100644
index 000000000..c343514ff
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfigWizard_notes.kcfgc
@@ -0,0 +1,7 @@
+File=../conduits/knotes/knotesconduit.kcfg
+ClassName=KPilotWizard_notesConfig
+Singleton=false
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/kpilot/kpilotConfigWizard_user.ui b/kpilot/kpilot/kpilotConfigWizard_user.ui
new file mode 100644
index 000000000..b894cbba7
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfigWizard_user.ui
@@ -0,0 +1,168 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>ConfigWizard_base2</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ConfigWizard_base2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>512</width>
+ <height>298</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>This wizard will help you configure KPilot.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>As a first step, we need to determine the user name and how the handheld is connected to the computer.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Handheld &amp;&amp; User Name</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;You can either let KPilot detect these values automatically (for this you need your handheld ready and connected to the PC) or enter them manually.&lt;/p&gt;
+&lt;p&gt;Please enter the username exactly as set on the handheld. &lt;/p&gt;
+&lt;p&gt;If setting the device type manually (i.e., if automatic detection did not work for you), please look below for tips on choosing the right device name. {0...n} means a number from 0 up to a very large number, though usually just 255.
+&lt;p&gt;
+Serial Port: an old method of connection, used primarily by the original line of Palm Pilots, and various Palm-based cellphones. Device name will look like /dev/ttyS{0...n} (Linux) or /dev/cuaa{0...n} (FreeBSD).&lt;/p&gt;
+&lt;p&gt;
+USB Port: A newer style of connection, used by most newer Palms, Handsprings, and Sony Clies. Device name will look like /dev/ttyUSB{0...n} or /dev/usb/tts/{0...n} (Linux) or /dev/ucom{0...n} (FreeBSD). On Linux, definitely check both 0 and 1: newer devices tend to use 1; older devices tend to use 0.&lt;/p&gt;
+&lt;p&gt;
+Infrared: (pronounced infra-red) is a relatively slow connection type used solely as a last resort. Device name will be /dev/ircomm0 or /dev/ttyS{0...n} (Linux), or /dev/sio{0...n} (FreeBSD).&lt;/p&gt;
+&lt;p&gt;
+Bluetooth: A new connection method, this is used almost exclusively on new, high-end devices, like the Tungsten T3 or the Zire 72. Device name will be /dev/usb/ttub/{0...n} or /dev/ttyUB{0...n} (Linux), or /dev/ttyp{0...n} (FreeBSD).&lt;/p&gt;
+&lt;p&gt;
+Network: This has not been tested by any of the KPilot developers themselves (hardware donations always accepted!), but it has been reported that setting the device to "net:any" will work for network-enabled devices. However, this has also been known to lock KPilot up when doing anything other than just syncing. Use it with caution.
+&lt;/p&gt;</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Device:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fDeviceName</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter the device the Pilot is attached to (for instance a serial or USB port) here. You can also use &lt;i&gt;/dev/pilot&lt;/i&gt;, and make that a symlink to the correct device. Use the button below to automatically detect the device. You need write permission to successfully synchronize with the handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fProbeButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Automatically Detect Handheld &amp;&amp; User Name</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Click this button to open the detection dialog. The wizard will try to automatically find and display the correct device and username for your handheld. If the wizard cannot retrieve this information, check if you have write permission for the device.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>fDeviceName</cstring>
+ </property>
+ <property name="text">
+ <string>/dev/pilot</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter the device the Pilot is attached to (for instance a serial or USB port) here. You can also use &lt;i&gt;/dev/pilot&lt;/i&gt;, and make that a symlink to the correct device. Use the button below to automatically detect the device. You need write permission to successfully synchronize with the handheld.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>fUserName</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter your username here, as it appears in the Pilot's &amp;quot;Owner&amp;quot; setting, or use the button below to automatically detect it.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>User na&amp;me:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fUserName</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Enter your username here, as it appears in the Pilot's &amp;quot;Owner&amp;quot; setting, or use the button below to automatically detect it.&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>fPilotRunningPermanently</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Start KPilot at login</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Check this box to make the kpilot daemon load when you first log in until you log out. That means (in theory), that you should not have to do anything other than connect your handheld and push "sync", and kpilot will appear and magically do your bidding. &lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>70</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<tabstops>
+ <tabstop>fUserName</tabstop>
+ <tabstop>fDeviceName</tabstop>
+ <tabstop>fProbeButton</tabstop>
+ <tabstop>fPilotRunningPermanently</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpilot/kpilot/kpilotConfigWizard_vcal.kcfgc b/kpilot/kpilot/kpilotConfigWizard_vcal.kcfgc
new file mode 100644
index 000000000..36141b8ac
--- /dev/null
+++ b/kpilot/kpilot/kpilotConfigWizard_vcal.kcfgc
@@ -0,0 +1,7 @@
+File=../conduits/vcalconduit/vcalconduitbase.kcfg
+ClassName=KPilotWizard_vcalConfig
+Singleton=false
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/kpilot/kpilotDCOP.h b/kpilot/kpilot/kpilotDCOP.h
new file mode 100644
index 000000000..a17e8a292
--- /dev/null
+++ b/kpilot/kpilot/kpilotDCOP.h
@@ -0,0 +1,75 @@
+#ifndef _KPILOT_KPILOTDCOP_H
+#define _KPILOT_KPILOTDCOP_H
+/* kpilotDCOP.h KPilotDaemon
+**
+** Copyright (C) 2000 by Adriaan de Groot
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines the DCOP interface for KPilot.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include <dcopobject.h>
+
+
+class KPilotDCOP : virtual public DCOPObject
+{
+ K_DCOP
+
+public:
+ enum DaemonMessages {
+ None=0,
+ StartOfHotSync=1,
+ EndOfHotSync=2,
+ DaemonQuit=4 } ;
+ enum KPilotStatus {
+ Startup=1,
+ WaitingForDaemon=2,
+ Normal=10,
+ UIBusy=100,
+ Error=101 } ;
+
+k_dcop:
+ /**
+ * This is the method the daemon uses to report
+ * changes in its state.
+ */
+ virtual ASYNC daemonStatus(int) = 0;
+
+ /**
+ * This is the method the daemon uses to popup
+ * the configure dialog.
+ */
+ virtual ASYNC configure() = 0;
+ virtual ASYNC configureWizard() = 0;
+
+ /**
+ * Report KPilot's state back to the daemon.
+ */
+ virtual int kpilotStatus() = 0;
+} ;
+
+
+
+#endif
diff --git a/kpilot/kpilot/kpilotProbeDialog.cc b/kpilot/kpilot/kpilotProbeDialog.cc
new file mode 100644
index 000000000..f7e04268b
--- /dev/null
+++ b/kpilot/kpilot/kpilotProbeDialog.cc
@@ -0,0 +1,363 @@
+/* conduitConfigDialog.cc KPilot
+**
+** Copyright (C) 2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines a .ui-based configuration dialog for conduits.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qvbox.h>
+#include <qtimer.h>
+#include <qptrlist.h>
+#include <qmap.h>
+#include <qvaluelist.h>
+
+#include <kmessagebox.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kconfigskeleton.h>
+#include <kapplication.h>
+#include <kprogress.h>
+
+#include "kpilotConfig.h"
+#include "pilotUser.h"
+#include "pilotSysInfo.h"
+#include "options.h"
+#include "kpilotdevicelink.h"
+
+#include "kpilotProbeDialog.moc"
+#include "pilotDaemonDCOP_stub.h"
+
+/*
+We can't connect to /dev/ttyUSB0 and /dev/ttyUSB1 at the same time, because that
+will lock up kpilot completely. In particular, it gets a connection on /dev/ttyUSB0,
+which it processes, and while processing, a connection on USB1 is also detected.
+However, when kpilot gets 'round to process it, the link is already closed, and
+pi_connect hangs forever.
+
+Now, I split up the list of devices to probe into three list, one holding /dev/pilot,
+the second holding all /dev/xxx0 and /dev/xxx2 (e.g. /dev/ttyUSB0 and /dev/ttyUSB2),
+and finally a third holding the remaining /dev/xxx1 and /dev/xxx3 devices. Each of
+these three sets of devices is activated for a few seconds, and then the next set is
+probed. This way, I ensure that kpilot never listens on /dev/ttyUSB0 and /dev/ttyUSB1
+at the same time.
+
+Now the first detection works fine. However, it seems the Linux kernel has another
+problem with /dev/ttyUSB0. I have a Clie, which uses ttyUSB0, and as soon as the
+wizard tries to listen on ttyUSB1 (after it detected the handheld on ttyUSB0 already),
+the kernel writes a warning message to the syslog:
+visor ttyUSB1: Device lied about number of ports, please use a lower one.
+
+If I continue autodetection once again afterwards, the visor module kind of crashes.
+lsmod shows an impossible usage count for the module:
+
+reinhold@einstein:/kde/builddir$ lsmod
+Module Size Used by
+visor 17164 4294967294
+usbserial 30704 1 visor
+
+After that, the kernel doesn't detect the device ever again (until the computer is rebooted),
+and the module can't be unloaded.
+*/
+
+
+ProbeDialog::ProbeDialog(QWidget *parent, const char *n) :
+ KDialogBase(parent, n, true, i18n("Autodetecting Your Handheld"), KDialogBase::Ok|KDialogBase::Cancel|KDialogBase::User1, KDialogBase::Cancel, true, i18n("Restart Detection")),
+ mDetected(false), mUserName(), mDevice()
+{
+ FUNCTIONSETUP;
+
+ QVBox *mainWidget = makeVBoxMainWidget();
+
+ fInfoText = new QLabel( i18n( "KPilot is now trying to automatically detect the device of your handheld. Please press the hotsync button if you have not done so already." ), mainWidget, "fInfoText" );
+ fInfoText->setAlignment( QLabel::WordBreak );
+
+ fStatusGroup = new QGroupBox( i18n("Status"), mainWidget, "fStatusGroup" );
+ fStatusGroup->setColumnLayout(0, Qt::Vertical );
+ fStatusGroupLayout = new QGridLayout( fStatusGroup->layout() );
+
+ fStatus = new QLabel( i18n("Autodetection not yet started..."), fStatusGroup, "fStatus" );
+ fStatus->setAlignment( QLabel::WordBreak );
+ fStatusGroupLayout->addWidget( fStatus, 0, 0 );
+
+ fProgress = new KProgress( 100, fStatusGroup, "fProgress" );
+ fStatusGroupLayout->addWidget( fProgress, 1, 0 );
+
+
+
+ fResultsGroup = new QGroupBox( i18n( "Detected Values" ), mainWidget, "fResultsGroup" );
+ fResultsGroup->setEnabled( FALSE );
+ fResultsGroup->setColumnLayout(0, Qt::Vertical );
+ fResultsGroupLayout = new QGridLayout( fResultsGroup->layout() );
+ fResultsGroupLayout->setAlignment( Qt::AlignTop );
+
+ fUserLabel = new QLabel( i18n( "Handheld user:" ), fResultsGroup, "fUserLabel" );
+ fUserLabel->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)4, (QSizePolicy::SizeType)5, 0, 0, fUserLabel->sizePolicy().hasHeightForWidth() ) );
+ fResultsGroupLayout->addWidget( fUserLabel, 0, 0 );
+
+ fDeviceLabel = new QLabel( i18n( "Device:" ), fResultsGroup, "fDeviceLabel" );
+ fResultsGroupLayout->addWidget( fDeviceLabel, 1, 0 );
+
+ fUser = new QLabel( i18n("[Not yet known]"), fResultsGroup, "fUser" );
+ fResultsGroupLayout->addWidget( fUser, 0, 1 );
+
+ fDevice = new QLabel( i18n("[Not yet known]"), fResultsGroup, "fDevice" );
+ fResultsGroupLayout->addWidget( fDevice, 1, 1 );
+
+
+ resize( QSize(459, 298).expandedTo(minimumSizeHint()) );
+ clearWState( WState_Polished );
+ enableButtonOK(false);
+
+ mDevicesToProbe[0] << "/dev/pilot";
+ mDevicesToProbe[1] <<"/dev/ttyS0"<<"/dev/ttyS2"
+ <<"/dev/tts/0"<<"/dev/tts/2"
+ <<"/dev/ttyUSB0"<<"/dev/ttyUSB2"
+ <<"/dev/usb/tts/0"<<"/dev/usb/tts/2"
+ <<"/dev/cuaa0"<<"/dev/cuaa2"
+ <<"/dev/cuad0"<<"/dev/cuad2"
+ <<"/dev/ucom0"<<"/dev/ucom2";
+ mDevicesToProbe[2] <<"/dev/ttyS1"<<"/dev/ttyS3"
+ <<"/dev/tts/1"<<"/dev/tts/3"
+ <<"/dev/ttyUSB1"<<"/dev/ttyUSB3"
+ <<"/dev/usb/tts/1"<<"/dev/usb/tts/3"
+ <<"/dev/cuaa1"<<"/dev/cuaa3"
+ <<"/dev/cuad1"<<"/dev/cuad3"
+ <<"/dev/ucom1"<<"/dev/ucom3";
+
+ fProcessEventsTimer = new QTimer( this );
+ fTimeoutTimer = new QTimer( this );
+ fProgressTimer = new QTimer( this );
+ fRotateLinksTimer = new QTimer( this );
+ connect( fProcessEventsTimer, SIGNAL(timeout()), this, SLOT(processEvents()) );
+ connect( fTimeoutTimer, SIGNAL(timeout()), this, SLOT(timeout()) );
+ connect( fProgressTimer, SIGNAL(timeout()), this, SLOT( progress()) );
+ connect( fRotateLinksTimer, SIGNAL(timeout()), this, SLOT( detect()) );
+ connect( this, SIGNAL(finished()), this, SLOT(disconnectDevices()) );
+}
+
+ProbeDialog::~ProbeDialog()
+{
+ FUNCTIONSETUP;
+}
+
+void ProbeDialog::processEvents()
+{
+ FUNCTIONSETUP;
+ KApplication::kApplication()->processEvents();
+}
+
+void ProbeDialog::progress()
+{
+ fProgress->advance(1);
+}
+
+int ProbeDialog::exec()
+{
+ mDetected = false;
+ mUserName = QString();
+ mDevice = QString();
+ QTimer::singleShot( 0, this, SLOT( startDetection() ) );
+ return KDialogBase::exec();
+}
+
+void ProbeDialog::startDetection()
+{
+ FUNCTIONSETUP;
+
+ disconnectDevices();
+ fProgress->setProgress(0);
+ fStatus->setText( i18n("Starting detection...") );
+ QTimer::singleShot(0, this, SLOT(processEvents()) );
+ processEvents();
+ PilotDaemonDCOP_stub *daemonStub = new PilotDaemonDCOP_stub("kpilotDaemon", "KPilotDaemonIface");
+ if (daemonStub) {
+ daemonStub->stopListening();
+ }
+ KPILOT_DELETE(daemonStub);
+ processEvents();
+ if (!fTimeoutTimer->start( 30000, true ) )
+ {
+ WARNINGKPILOT << "Could not start fTimeoutTimer" << endl;
+ }
+ if (!fProcessEventsTimer->start( 100, false ) )
+ {
+ WARNINGKPILOT << "Could not start fProcessEventsTimer" << endl;
+ }
+ if (!fProgressTimer->start( 300, false) )
+ {
+ WARNINGKPILOT << "Could not start Progress timer" << endl;
+ }
+
+ KPilotDeviceLink*link;
+ for (int i=0; i<3; i++)
+ {
+ QStringList::iterator end(mDevicesToProbe[i].end());
+ for (QStringList::iterator it=mDevicesToProbe[i].begin(); it!=end; ++it)
+ {
+ link = new KPilotDeviceLink();
+ link->setDevice((*it));
+#ifdef DEBUG
+ DEBUGKPILOT<<"new kpilotDeviceLink for "<<(*it)<<endl;
+#endif
+ mDeviceLinks[i].append( link );
+ connect( link, SIGNAL(deviceReady(KPilotDeviceLink*)), this, SLOT(connection(KPilotDeviceLink*)) );
+ processEvents();
+ }
+ }
+ fStatus->setText( i18n("Waiting for handheld to connect...") );
+ mProbeDevicesIndex=0;
+
+ detect();
+ if (!fRotateLinksTimer->start( 3000, false) )
+ {
+ WARNINGKPILOT << "Could not start Device link rotation timer" << endl;
+ }
+}
+
+
+void ProbeDialog::detect(int i)
+{
+ FUNCTIONSETUP;
+
+ mProbeDevicesIndex = i;
+ PilotLinkList::iterator end(mDeviceLinks[mProbeDevicesIndex].end());
+
+ for (PilotLinkList::iterator it=mDeviceLinks[mProbeDevicesIndex].begin(); it!=end; ++it)
+ {
+ if (*it) (*it)->reset();
+ }
+}
+
+void ProbeDialog::detect()
+{
+ detect( (mProbeDevicesIndex+1)%3 );
+}
+
+void ProbeDialog::timeout()
+{
+ disconnectDevices();
+ if (!mDetected) {
+ fStatus->setText( i18n("Timeout reached, could not detect a handheld.") );
+ KMessageBox::information ( this, i18n("<qt>A handheld could not be detected. Possible check the following things:</p>"
+ "<ul><li> Have you pressed the hotsync button on the handheld?\n"
+ "<li> Make sure the device sits in the cradle correctly.\n"
+ "<li> Make sure the cradle is correctly plugged in to the computer.\n"
+ "<li> Have you checked that your device is actually supported by kpilot (see http://www.kpilot.org).\n"
+ "</ul>"
+ ), i18n("Automatic Detection Failed"), "AutoDetectionFailed");
+ }
+}
+
+void ProbeDialog::connection( KPilotDeviceLink*lnk)
+{
+ FUNCTIONSETUP;
+
+ mActiveLink = lnk;
+ if ( !mActiveLink ) return;
+ const KPilotUser &usr( mActiveLink->getPilotUser() );
+
+ mUserName = usr.name();
+ mDevice = mActiveLink->pilotPath();
+
+ fStatus->setText( i18n("Found a connected device on %1").arg(mDevice) );
+ fUser->setText( mUserName );
+ fDevice->setText( mDevice );
+ mDetected = true;
+
+ fResultsGroup->setEnabled( true );
+ enableButtonOK(true);
+
+ QTimer::singleShot(0, this, SLOT(retrieveDBList()));
+}
+
+void ProbeDialog::retrieveDBList()
+{
+ KPilotLink::DBInfoList dbs = mActiveLink->getDBList();
+ mDBs.clear();
+ char buff[7];
+ buff[0] = '[';
+
+ for ( KPilotLink::DBInfoList::ConstIterator i = dbs.begin();
+ i != dbs.end(); ++i )
+ {
+ set_long( &buff[1], (*i).creator );
+ buff[5] = ']';
+ buff[6] = '\0';
+ QString cr( buff );
+ mDBs << cr;
+ mDBs << QString( (*i).name );
+ }
+ mDBs.sort();
+
+ QString old( QString::null );
+ QStringList::Iterator itr = mDBs.begin();
+ while ( itr != mDBs.end() ) {
+ if ( old == *itr ) {
+ itr = mDBs.remove( itr );
+ } else {
+ old = *itr;
+ ++itr;
+ }
+ }
+
+ // End sync gracefully, but don't change settings on the handheld.
+ mActiveLink->endSync( KPilotLink::NoUpdate );
+
+ QTimer::singleShot(0, this, SLOT(disconnectDevices()));
+}
+void ProbeDialog::disconnectDevices()
+{
+ FUNCTIONSETUP;
+
+ if (!mDetected) fStatus->setText( i18n("Disconnected from all devices") );
+ fProcessEventsTimer->stop( );
+ fTimeoutTimer->stop();
+ fProgressTimer->stop();
+ fRotateLinksTimer->stop();
+ fProgress->setProgress(fProgress->totalSteps());
+ for (int i=0; i<3; ++i)
+ {
+ PilotLinkList::iterator end(mDeviceLinks[i].end());
+ for (PilotLinkList::iterator it=mDeviceLinks[i].begin(); it!=end; ++it)
+ {
+ (*it)->close();
+ KPILOT_DELETE(*it);
+ }
+ mDeviceLinks[i].clear();
+ }
+
+
+ PilotDaemonDCOP_stub *daemonStub = new PilotDaemonDCOP_stub("kpilotDaemon", "KPilotDaemonIface");
+ if (daemonStub)
+ {
+ daemonStub->startListening();
+ }
+ KPILOT_DELETE(daemonStub);
+}
+
diff --git a/kpilot/kpilot/kpilotProbeDialog.h b/kpilot/kpilot/kpilotProbeDialog.h
new file mode 100644
index 000000000..be02dff6e
--- /dev/null
+++ b/kpilot/kpilot/kpilotProbeDialog.h
@@ -0,0 +1,102 @@
+#ifndef _KPILOT_PROBEDIALOG_H
+#define _KPILOT_PROBEDIALOG_H
+/* kpilotConfigWizard.h KPilot
+**
+** Copyright (C) 2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines kpilot's configuration wizard
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "kdialogbase.h"
+
+class KPilotDeviceLink;
+class QLabel;
+class QGroupBox;
+class KProgress;
+class QTimer;
+class QGridLayout;
+template <class T> class QValueList;
+template<class Key, class T> class QMap;
+
+typedef QValueList<KPilotDeviceLink*> PilotLinkList;
+
+typedef QMap<QString, KPilotDeviceLink*> PilotLinkMap;
+
+class ProbeDialog : public KDialogBase
+{
+Q_OBJECT
+public:
+ ProbeDialog(QWidget *p=0L,const char *n=0L);
+ ~ProbeDialog();
+
+ bool detected() const { return mDetected; }
+ QString userName() const { return mUserName; }
+ QString device() const { return mDevice; }
+ QStringList dbs() const { return mDBs; }
+
+
+protected slots:
+ void startDetection();
+ void timeout();
+ void connection(KPilotDeviceLink*lnk);
+ void retrieveDBList();
+ void disconnectDevices();
+ void processEvents();
+ void progress();
+ void detect();
+ void detect(int i);
+public slots:
+ int exec();
+ void slotUser1 () { startDetection(); }
+protected:
+ QLabel* fInfoText;
+ QGroupBox* fResultsGroup;
+ QLabel* fUserLabel;
+ QLabel* fDeviceLabel;
+ QLabel* fUser;
+ QLabel* fDevice;
+ QGroupBox* fStatusGroup;
+ QLabel* fStatus;
+ KProgress* fProgress;
+
+ QTimer* fProcessEventsTimer;
+ QTimer* fTimeoutTimer;
+ QTimer* fProgressTimer;
+ QTimer* fRotateLinksTimer;
+protected:
+ QGridLayout* fResultsGroupLayout;
+ QGridLayout* fStatusGroupLayout;
+
+ QStringList mDevicesToProbe[3];
+ PilotLinkList mDeviceLinks[3];
+ int mProbeDevicesIndex;
+ KPilotDeviceLink *mActiveLink;
+
+ bool mDetected;
+ QString mUserName;
+ QString mDevice;
+ QStringList mDBs;
+} ;
+
+#endif
diff --git a/kpilot/kpilot/kpilotSettings.kcfgc b/kpilot/kpilot/kpilotSettings.kcfgc
new file mode 100644
index 000000000..5ee06e630
--- /dev/null
+++ b/kpilot/kpilot/kpilotSettings.kcfgc
@@ -0,0 +1,7 @@
+File=kpilot.kcfg
+ClassName=KPilotSettings
+Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/kpilot/kpilot_config.desktop b/kpilot/kpilot/kpilot_config.desktop
new file mode 100644
index 000000000..58cc75d5e
--- /dev/null
+++ b/kpilot/kpilot/kpilot_config.desktop
@@ -0,0 +1,159 @@
+[Desktop Entry]
+Icon=kpilot
+Type=Service
+ServiceTypes=KCModule
+
+X-KDE-ModuleType=Library
+X-KDE-Library=kpilot
+X-KDE-FactoryName=kpilotconfig
+X-KDE-HasReadOnlyMode=false
+X-KDE-ParentApp=kpilot
+X-KDE-ParentComponents=kpilot,kpilotDaemon,kontact_kpilotplugin
+
+Name=KPilot Configuration
+Name[af]=KPilot opstelling
+Name[ar]=إعداد KPilot
+Name[be]=Канфігурацыя KPilot
+Name[bg]=Настройване на KPilot
+Name[br]=Kefluniadur KPilot
+Name[bs]=KPilot podešavanje
+Name[ca]=Configuració de KPilot
+Name[cs]=Nastavení KPilotu
+Name[da]=KPilot indstilling
+Name[de]=KPilot-Einrichtung
+Name[el]=Ρύθμιση KPilot
+Name[eo]=KPilot-Agordo
+Name[es]=Configuración de KPilot
+Name[et]=KPiloti seadistamine
+Name[eu]=KPilot-en konfigurazioa
+Name[fa]=پیکربندی KPilot
+Name[fi]=KPilot-asetukset
+Name[fr]=Configuration de KPilot
+Name[fy]=KPilot ynstellings
+Name[ga]=Cumraíocht KPilot
+Name[gl]=Configuración de KPilot
+Name[hu]=A KPilot beállításai
+Name[is]=KPilot stillingar
+Name[it]=Configurazione KPilot
+Name[ja]=KPilot の設定
+Name[ka]=KPilot კონფიგურაცია
+Name[kk]=KPilot параметрлері
+Name[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ KPilot
+Name[lt]=Kpilot konfigūracija
+Name[mk]=Конфигурација на КПилот
+Name[ms]=Konfigurasi KPilot
+Name[nb]=KPilot oppsett
+Name[nds]=KPilot instellen
+Name[ne]=केडीई पाइलट कन्फिगरेसन
+Name[nl]=KPilot instellingen
+Name[nn]=KPilot-oppsett
+Name[pl]=konfiguracja KPilota
+Name[pt]=Configuração do KPilot
+Name[pt_BR]=Configuração do KPilot
+Name[ru]=Синхронизация с КПК
+Name[se]=KPilot-heivehus
+Name[sk]=Nastavenie KPilot
+Name[sl]=Nastavitve KPilota
+Name[sr]=KPilot подешавање
+Name[sr@Latn]=KPilot podešavanje
+Name[sv]=Inställning av Kpilot
+Name[ta]=Kபைலட் கட்டமைப்பு
+Name[tg]=Танзимоти KPilot
+Name[tr]=KPilot Yapılandırması
+Name[uk]=Налаштування KPilot
+Name[zh_CN]=KPilot 配置
+Name[zh_TW]=KPilot 設定
+Comment=KPilot Main Configuration
+Comment[af]=KPilot hoof opstelling
+Comment[bg]=Общи настройки на KPilot
+Comment[br]=Kefluniadur kentañ KPilot
+Comment[bs]=KPilot glavno podešavanje
+Comment[ca]=Configuració principal de KPilot
+Comment[cs]=Hlavní nastavení KPilotu
+Comment[da]=KPilot hovedindstilling
+Comment[de]=Grundeinrichtung für KPilot
+Comment[el]=Κύρια ρύθμιση του KPilot
+Comment[eo]=KPilot-Ĉefagordo
+Comment[es]=Configuración principal de KPilot
+Comment[et]=KPiloti põhiseadistused
+Comment[eu]=KPilot-en konfigurazio nagusia
+Comment[fa]=پیکربندی اصلی KPilot
+Comment[fi]=KPilotin pääasetukset
+Comment[fr]=Configuration principale de KPilot
+Comment[fy]=KPilot algemiene ynstellings
+Comment[ga]=Príomhchumraíocht KPilot
+Comment[gl]=Configuración Principal de KPilot
+Comment[hu]=A KPilot legfontosabb beállításai
+Comment[is]=Aðalstillingar KPilot
+Comment[it]=Configurazione principale di KPilot
+Comment[ja]=KPilot 主要設定
+Comment[ka]=KPilot ძირითადი კონფიგურაცია
+Comment[kk]=KPilot негізгі параметрлері
+Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​សំខាន់ៗ​របស់ KPilot
+Comment[lt]=KPilot bendrasis konfigūravimas
+Comment[mk]=Главна конфигурација
+Comment[ms]=Konfigurasi Utama KPilot
+Comment[nb]=KPilot hovedoppsett
+Comment[nds]=Hööftinstellen för KPilot
+Comment[ne]=केडीई पाइलट मुख्य कन्फिगरेसन
+Comment[nl]=KPilot algemene instellingen
+Comment[nn]=KPilot hovudoppsett
+Comment[pl]=Główna konfiguracja KPilota
+Comment[pt]=Configuração Principal do KPilot
+Comment[pt_BR]=Configuração Principal do KPilot
+Comment[ru]=Общие параметры KPilot
+Comment[sk]=Hlavné nastavenie KPilot
+Comment[sl]=Glavne nastavitve KPilota
+Comment[sr]=Главна подешавања у KPilot-у
+Comment[sr@Latn]=Glavna podešavanja u KPilot-u
+Comment[sv]=Kpilots huvudinställning
+Comment[ta]=கேபைலட் முக்கிய கட்டமைப்பு
+Comment[tg]=Параметрҳои умумии KPilot
+Comment[tr]=KPilot Ana Yapılandırması
+Comment[uk]=Загальні параметри KPilot
+Comment[zh_CN]=KPilot 主要配置
+Comment[zh_TW]=KPilot 主設定
+Keywords=kpilot,main
+Keywords[bg]=общи, настройки, мобилен, мобилни, устройство, устройства, kpilot, main
+Keywords[ca]=kpilot,principal
+Keywords[cs]=kpilot,hlavní
+Keywords[da]=kpilot,hoved
+Keywords[de]=KPilot
+Keywords[el]=kpilot,κύρια
+Keywords[eo]=reto,dosieroj,dosierujoj
+Keywords[es]=kpilot,principal
+Keywords[et]=kpilot,peamine
+Keywords[eu]=kpilot,nagusia
+Keywords[fa]=kpilot ،اصلی
+Keywords[fi]=kpilot
+Keywords[fr]=kpilot,principal
+Keywords[fy]=kpilot,algemien
+Keywords[ga]=kpilot,príomh
+Keywords[gl]=kpilot,principal
+Keywords[hu]=kpilot,alap
+Keywords[is]=kpilot,aðal
+Keywords[it]=kpilot,principale
+Keywords[ja]=kpilot,主要
+Keywords[ka]=kpilot,ძირითადი
+Keywords[km]=kpilot,សំខាន់
+Keywords[lt]=kpilot,main,pagrindinis
+Keywords[mk]=kpilot,main.кпилот,главно
+Keywords[ms]=kpilot,utama
+Keywords[nb]=kpilot,hoved
+Keywords[nds]=KPilot,Hööft,Hööftinstellen,instellen
+Keywords[ne]=केडीई पाइलट, मुख्य
+Keywords[nl]=kpilot,algemeen
+Keywords[nn]=kpilot,hovud
+Keywords[pl]=kpilot,główna,konfiguracja
+Keywords[pt]=kpilot,principal
+Keywords[pt_BR]=kpilot,principal
+Keywords[ru]=kpilot,main,общие,настройки
+Keywords[sk]=kpilot,hlavné
+Keywords[sl]=kpilot,glavne
+Keywords[sr]=kpilot,главно
+Keywords[sr@Latn]=kpilot,glavno
+Keywords[sv]=kpilot, huvudinställning
+Keywords[ta]=கேபைலட்,முக்கிய
+Keywords[tg]=kpilot,main,умумӣ,танзимот
+Keywords[tr]=kpilot,ana
+Keywords[zh_CN]=kpilot,main,主要
diff --git a/kpilot/kpilot/kpilotconduit.desktop b/kpilot/kpilot/kpilotconduit.desktop
new file mode 100644
index 000000000..75eeaab19
--- /dev/null
+++ b/kpilot/kpilot/kpilotconduit.desktop
@@ -0,0 +1,60 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KPilotConduit
+Comment=KPilot Conduit
+Comment[af]=Kpilot Pad
+Comment[az]=KPilot
+Comment[be]=Канал KPilot
+Comment[bg]=Приставка на KPilot
+Comment[ca]=Conducte KPilot
+Comment[cs]=Propojení Palm Pilota
+Comment[cy]=Cwndid KPilot
+Comment[da]=KPilot-kanal
+Comment[de]=KPilot-Abgleich (Conduit)
+Comment[el]=Σύνδεσμος KPilot
+Comment[eo]=KPiloto - kanalo
+Comment[es]=Conducto KPilot
+Comment[et]=KPiloti kanal
+Comment[eu]=KPilot kanala
+Comment[fa]=لولۀ KPilot
+Comment[fi]=KPilot-yhdyskäytävä
+Comment[fr]=Canal de KPilot
+Comment[ga]=Seoladán KPilot
+Comment[gl]=Conducto de KPilot
+Comment[he]=ממשק של KPilot
+Comment[hi]=के-पायलट कन्ड्यूइट
+Comment[hr]=KPilot veza
+Comment[hu]=KPilot-csatoló
+Comment[is]=KPilot rásir
+Comment[it]=Conduit KPilot
+Comment[ja]=KPilot コンジット
+Comment[ka]=არხი KPilot
+Comment[kk]=KPilot арнасы
+Comment[km]=បំពង់ KPilot
+Comment[lt]=KPilot kanalas
+Comment[lv]=KPilot Ķēde
+Comment[mk]=Канал за КПилот
+Comment[ms]=Saluran KPilot
+Comment[nb]=KPilot-kanal
+Comment[nds]=KPilot-Kanaal (Synkroniseren)
+Comment[ne]=केडीई पाइलट कन्ड्युट
+Comment[nn]=KPilot-kopling
+Comment[nso]=Conduit ya KPilot
+Comment[pl]=Łącznik KPilota
+Comment[pt]=Conduta do KPilot
+Comment[pt_BR]=Conduíte do KPilot
+Comment[ro]=Conductă KPilot
+Comment[ru]=Канал KPilot
+Comment[sk]=KPilot rúra
+Comment[sl]=Veznik za KPilot
+Comment[sr]=KPilot провод
+Comment[sr@Latn]=KPilot provod
+Comment[sv]=Kpilot-kanal
+Comment[ta]=கேபைலட் காப்புக்குழாய்
+Comment[tg]=Канали KPilot
+Comment[tr]=KPilot Kanalı
+Comment[uk]=Акведук KPilot
+Comment[ven]=Conduit ya mureili wa K
+Comment[vi]=Truyền dẫn KPilot
+Comment[zh_CN]=KPilot 管道
+Comment[zu]=KUmshayeli webhanoyi Conduit
diff --git a/kpilot/kpilot/kpilotdaemon.desktop b/kpilot/kpilot/kpilotdaemon.desktop
new file mode 100644
index 000000000..cbeb9dada
--- /dev/null
+++ b/kpilot/kpilot/kpilotdaemon.desktop
@@ -0,0 +1,43 @@
+# KDE Config File
+[Desktop Entry]
+Name=KPilotDaemon
+Name[af]=Kpilotdaemon
+Name[ar]=مراقب KPilot
+Name[az]=KPilotProgramı
+Name[da]=KPilotDæmon
+Name[de]=KPilot-Dienst
+Name[el]=Δαίμονας KPilot
+Name[eo]=KPiloto-demono
+Name[es]=Demonio de KPilot
+Name[et]=KPiloti deemon
+Name[he]=תהליך הרקע של KPilot
+Name[hi]=के-पायलट-डेमन
+Name[is]=KPilot þjónn
+Name[it]=Demone KPilot
+Name[ja]=KPilot デーモン
+Name[ka]=KPilot-ის დემონი
+Name[lt]=KPilot tarnyba
+Name[lv]=KPilotDēmons
+Name[ms]=Daemon KPilot
+Name[nds]=KPilot-Dämoon
+Name[ne]=केडीई पाइलट डेइमन
+Name[nso]=Daemon ya KPilot
+Name[pl]=demon KPilota
+Name[pt_BR]=Servidor do KPilot
+Name[ro]=Demon KPilot
+Name[ru]=Служба синхронизации КПК
+Name[sk]=KPilotDémon
+Name[sr]=KPilot демон
+Name[sr@Latn]=KPilot demon
+Name[sv]=Kpilotdemon
+Name[ta]=கேபைலட் டெமன்
+Name[tg]=Демони KPilot
+Name[ven]=Daemon ya Mureili wa K
+Name[zu]=KUmshayeli webhanoyi Daemon
+Exec=kpilotDaemon
+NoDisplay=true
+Icon=kpilot.xpm
+Type=Application
+Terminal=false
+X-DCOP-ServiceType=Unique
+Categories=Qt;KDE;Utility;Office;PDA;
diff --git a/kpilot/kpilot/kpilotui.rc b/kpilot/kpilot/kpilotui.rc
new file mode 100644
index 000000000..d5e6ac427
--- /dev/null
+++ b/kpilot/kpilot/kpilotui.rc
@@ -0,0 +1,53 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+
+<kpartgui name="kpilot" version="5">
+<MenuBar>
+ <Menu name="file" noMerge="1"><text>&amp;File</text>
+ <!-- Keep this list synchronized with pilotDaemon.cc and kpilot.cc -->
+ <Action name="file_hotsync" />
+ <Action name="file_fullsync" />
+ <Action name="file_backup" />
+ <Action name="file_restore" />
+ <Action name="file_HHtoPC" />
+ <Action name="file_PCtoHH" />
+ <Separator />
+ <Action name="file_quit" />
+ </Menu>
+ <Menu name="settings" noMerge="1"><text>&amp;Settings</text>
+ <Action name="options_show_statusbar" />
+ <Action name="options_show_toolbar" />
+ <Merge name="StandardToolBarMenuHandler" />
+ <Separator />
+ <Action name="options_configure_keybinding" />
+ <Action name="options_configure_toolbars" />
+ <Action name="options_configure" />
+ <Action name="options_configure_wizard" />
+ </Menu>
+</MenuBar>
+
+<Menu name="rb_popup">
+ <Action name="file_hotsync" />
+ <Action name="file_backup" />
+ <Action name="file_restore" />
+ <Separator />
+</Menu>
+
+<ToolBar name="mainToolBar"><text>Main Toolbar</text>
+ <Action name="popup_hotsync" />
+ <Action name="file_backup" />
+ <Action name="file_reload" />
+ <Separator />
+</ToolBar>
+
+</kpartgui>
+
+
+<!--
+Local Variables:
+mode: xml
+sgml-omittag: nil
+sgml-shorttag: t
+sgml-general-insert-case: lower
+End:
+-->
+
diff --git a/kpilot/kpilot/kroupware.cc b/kpilot/kpilot/kroupware.cc
new file mode 100644
index 000000000..fc57b4b5c
--- /dev/null
+++ b/kpilot/kpilot/kroupware.cc
@@ -0,0 +1,311 @@
+/* KPilot
+**
+** Copyright still to be determined.
+**
+** This file defines the actions taken when KPilot
+** is Kroupware-enabled. Basically it just does a
+** little communication with the local Kroupware agent (KMail).
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qfile.h>
+
+#include <dcopclient.h>
+#include <ktempfile.h>
+
+
+#include <kapplication.h>
+#include "kroupware.h"
+#include "kpilotConfig.h"
+
+KroupwareSync::KroupwareSync(bool pre,int parts,KPilotDeviceLink *p) :
+ SyncAction(p,pre ? "KroupwarePreSync" : "KroupwarePostSync"),
+ fPre(pre),
+ fParts(parts)
+{
+
+}
+
+/* virtual */ bool KroupwareSync::exec()
+{
+ FUNCTIONSETUP;
+ if (fPre)
+ {
+ preSync();
+ }
+ else
+ {
+ postSync();
+ }
+ // delayDone();
+ emit syncDone(this);
+ return true;
+}
+
+void KroupwareSync::cleanupConfig()
+{
+ // tempfile check in case app has terminated during sync
+ // TODO!!! Use sensitive groups/keys for the kroupware branch...
+ KConfig* c = KPilotSettings::self()->config();
+ c->setGroup("todoOptions");
+ if ( c->hasKey( "CalFileBackup") ) {
+ QString fn = c->readPathEntry( "CalFileBackup" );
+ if ( fn != CSL1("empty") ) {
+ c->writePathEntry( "CalFile" ,fn );
+ c->writeEntry( "CalFileBackup" , "empty" );
+ }
+ }
+ c->setGroup("vcalOptions");
+ if ( c->hasKey( "CalFileBackup") ) {
+ QString fn = c->readPathEntry( "CalFileBackup" );
+ if ( fn != CSL1("empty") ) {
+ c->writePathEntry( "CalFile" ,fn );
+ c->writeEntry( "CalFileBackup" , "empty" );
+ }
+ }
+ c->setGroup("Abbrowser-conduit");
+ c->writeEntry( "KMailTempFile" , "empty" );
+ KPilotSettings::writeConfig();
+}
+
+// For the log messages, I've added i18n to the
+// ones I consider relevant for the user. The rest is
+// really debug info, and shouldn't go to the normal
+// sync log for the user.
+//
+// TODO!!! better way to read the config options!
+void KroupwareSync::start_syncCal_TodosWithKMail( bool cal, bool todos )
+{
+ if ( !cal && ! todos )
+ return;
+ KConfig*c = KPilotSettings::self()->config();
+ DCOPClient *client = kapp->dcopClient();
+ KTempFile tempfile;
+ QString filename = tempfile.name();
+ QByteArray data, reply_data;
+ QCString reply_type;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << filename;
+ if (!client->call( "kmail" ,
+ "KOrganizerSyncIface",
+ "pullSyncData(QString)",
+ data,
+ reply_type,
+ reply_data)) {
+ logMessage( CSL1("Calling KMail over DCOP failed!" ));
+ logMessage(CSL1("Not syncing calendars with KMail"));
+ logMessage(CSL1("Not syncing to-dos with KMail"));
+ }
+ else {
+ logMessage(CSL1("Calling Cal/Todo over DCOP succeeded"));
+ // now prepare for syncing
+ _syncWithKMail = true;
+ if ( todos ) {
+ logMessage( i18n("Syncing to-dos with KMail" ));
+ c->setGroup("todoOptions");
+ QString fn = c->readPathEntry( "CalFile" );
+ c->writePathEntry( "CalFileBackup" ,fn );
+ c->writePathEntry( "CalFile" ,filename );
+ }
+ else
+ logMessage( CSL1("Not syncing todos with KMail" ));
+ if ( cal ) {
+ logMessage( i18n("Syncing calendar with KMail" ));
+ c->setGroup("vcalOptions");
+ QString fn = c->readPathEntry( "CalFile" );
+ c->writePathEntry( "CalFileBackup" ,fn );
+ c->writePathEntry( "CalFile" ,filename );
+ }
+ else
+ logMessage( CSL1("Not syncing calendar with KMail" ));
+ }
+ KPilotSettings::self()->writeConfig();
+}
+
+void KroupwareSync::start_syncAddWithKMail()
+{
+ logMessage( CSL1("Syncing Addresses with KMail" ));
+ DCOPClient *client = kapp->dcopClient();
+ KTempFile tempfile;
+ QString filename = tempfile.name();
+ QByteArray data, reply_data;
+ QCString reply_type;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << filename;
+ if (!client->call( "kmail" ,
+ "KMailIface",
+ "requestAddresses(QString)",
+ data,
+ reply_type,
+ reply_data)) {
+ logMessage(CSL1("Calling KMail over DCOP failed!" ));
+ logMessage(CSL1("Not syncing Addresses with KMail"));
+ }
+ else {
+ // TODO!!! better config handling!
+ KConfig*c = KPilotSettings::self()->config();
+ logMessage(CSL1("Calling addresses over DCOP succeeded"));
+ c->setGroup("Abbrowser-conduit");
+ c->writePathEntry( "KMailTempFile" , filename );
+ KPilotSettings::self()->writeConfig();
+ }
+}
+void KroupwareSync::start_syncNotesWithKMail()
+{
+ logMessage( i18n("Syncing Notes with Mail" ));
+ logMessage( CSL1("Syncing Notes-sorry not implemented" ));
+}
+
+void KroupwareSync::end_syncCal_TodosWithKMail( bool cal, bool todos)
+{
+ if ( !cal && ! todos )
+ return;
+ QString filename;
+ KConfig*c=KPilotSettings::self()->config();
+ if ( todos ) {
+ logMessage( i18n("Rewriting to-dos to KMail..." ));
+ c->setGroup("todoOptions");
+ filename = c->readPathEntry( "CalFile" );
+ c->writePathEntry( "CalFile", c->readPathEntry( "CalFileBackup" ) );
+ c->writeEntry( "CalFileBackup", "empty");
+ }
+ if ( cal ) {
+ logMessage( i18n("Rewriting Calendar to KMail" ));
+ c->setGroup("vcalOptions");
+ filename = c->readPathEntry( "CalFile" );
+ QString tf = c->readPathEntry( "CalFileBackup" ) ;
+ c->writePathEntry( "CalFile" , tf );
+ c->writeEntry( "CalFileBackup" ,"empty");
+ }
+ KPilotSettings::writeConfig();
+ if ( !filename.isEmpty() ) {
+ logMessage(CSL1("Try to call KMail via DCOP to finish sync..."));
+ // try DCOP connection to KMail
+ DCOPClient *client = kapp->dcopClient();
+ QByteArray data, reply_data;
+ QCString reply_type;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << filename;
+ if (!client->call( "kmail" /*"korganizer" kmdcop */,
+ "KOrganizerSyncIface",
+ "pushSyncData(QString)",
+ data,
+ reply_type,
+ reply_data)) {
+ logMessage( CSL1("Calling KMail over DCOP failed!" ));
+ logMessage( CSL1("Sync is not complete"));
+ logMessage( CSL1("Data from Palm stored in file:"));
+ logMessage(filename);
+ } else {
+ logMessage(CSL1("Calling over DCOP succeeded"));
+ logMessage(CSL1("Sync to KMail has finished successfully"));
+ }
+ QFile::remove( filename );
+ }
+}
+void KroupwareSync::end_syncAddWithKMail()
+{
+ logMessage( i18n("Syncing KMail with Addresses " ));
+ DCOPClient *client = kapp->dcopClient();
+ // TODO!! better config handling (KConfig XT)
+ KConfig*c = KPilotSettings::self()->config();
+ c->setGroup("Abbrowser-conduit");
+ QString filename = c->readPathEntry( "KMailTempFile" );
+ c->writeEntry( "KMailTempFile" , "empty" );
+ KPilotSettings::writeConfig();
+ QByteArray data, reply_data;
+ QCString reply_type;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << filename;
+ arg << QStringList();
+ if (!client->call( "kmail" ,
+ "KMailIface",
+ "storeAddresses(QString, QStringList)",
+ data,
+ reply_type,
+ reply_data)) {
+ logMessage(CSL1("Calling KMail over DCOP failed!" ));
+ logMessage(CSL1("Not syncing Addresses with KMail"));
+ }
+ else {
+ logMessage(CSL1("Calling store addresses over DCOP succeeded"));
+ }
+ //QFile::remove( filename );
+}
+void KroupwareSync::end_syncNotesWithKMail()
+{
+ logMessage( i18n("Syncing KMail with Notes" ));
+ logMessage( CSL1("Syncing Notes-sorry not implemented" ));
+}
+
+
+
+/* static */ bool KroupwareSync::startKMail(QString *error)
+{
+ FUNCTIONSETUP;
+
+ QCString kmdcop;
+ QString mess;
+ int pid;
+
+ return KApplication::startServiceByDesktopName(CSL1("kmail"),
+ QString::null,
+ error,
+ &kmdcop,
+ &pid
+ )==0;
+}
+
+
+void KroupwareSync::preSync()
+{
+ cleanupConfig();
+ start_syncCal_TodosWithKMail( fParts & Cal, fParts & Todo );
+ if (fParts & Notes)
+ {
+ start_syncNotesWithKMail();
+ }
+ if (fParts & Address)
+ {
+ start_syncAddWithKMail();
+ }
+}
+
+void KroupwareSync::postSync()
+{
+ cleanupConfig();
+ end_syncCal_TodosWithKMail( fParts & Cal, fParts & Todo );
+ if (fParts & Notes)
+ {
+ end_syncNotesWithKMail();
+ }
+ if (fParts & Address)
+ {
+ end_syncAddWithKMail();
+ }
+}
+
+
+
diff --git a/kpilot/kpilot/kroupware.h b/kpilot/kpilot/kroupware.h
new file mode 100644
index 000000000..8cce32eaf
--- /dev/null
+++ b/kpilot/kpilot/kroupware.h
@@ -0,0 +1,87 @@
+#ifndef _KPILOT_KROUPWARE_H
+#define _KPILOT_KROUPWARE_H
+/* kroupware.h KPilot
+**
+** Copyright still to be determined.
+**
+** This file defines the actions taken when KPilot
+** is Kroupware-enabled. Basically it just does a
+** little communication with the local Kroupware agent (KMail).
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "syncAction.h"
+
+class QString;
+
+class KroupwareSync : public SyncAction
+{
+public:
+ // Creates a pre- or post-sync action
+ // depending on @p pre (pre==true makes
+ // it a pre-sync action, pre==false makes
+ // it a post-sync action).
+ //
+ // Which things it syncs is based on
+ // @p parts, which is a bitwise OR of
+ // values from the KroupwareParts enum.
+ //
+ KroupwareSync(bool pre,int parts,KPilotDeviceLink *p);
+
+ enum KroupwareParts
+ {
+ Cal=1,
+ Todo=2,
+ Notes=4,
+ Address=8
+ } ;
+
+protected:
+ virtual bool exec();
+
+ void preSync(); // Functions to collect all the actions
+ void postSync(); // together. Call {start,end}*().
+
+protected:
+ bool fPre;
+ int fParts;
+
+private:
+ bool _syncWithKMail;
+
+ void cleanupConfig();
+ void start_syncCal_TodosWithKMail( bool cal, bool todos);
+ void start_syncAddWithKMail();
+ void start_syncNotesWithKMail();
+ void end_syncCal_TodosWithKMail( bool cal, bool todos);
+ void end_syncAddWithKMail();
+ void end_syncNotesWithKMail();
+
+
+public:
+ /* Try to start KMail. Returns true on success. */
+ static bool startKMail(QString *errormessage);
+} ;
+
+#endif
+
diff --git a/kpilot/kpilot/listCat.cc b/kpilot/kpilot/listCat.cc
new file mode 100644
index 000000000..281bfe001
--- /dev/null
+++ b/kpilot/kpilot/listCat.cc
@@ -0,0 +1,272 @@
+/* KPilot
+**
+** Copyright (C) 2000-2001 by Adriaan de Groot
+**
+** This file defines a specialization of KListView that can
+** be used to sort some fixed set of object into some fixed
+** set of categories.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qpainter.h>
+#include <klocale.h>
+
+#include "listCat.moc"
+
+
+ListCategorizer::ListCategorizer(QWidget * parent,
+ const char *name) :
+ KListView(parent, name),
+ fStartOpen(false)
+{
+ FUNCTIONSETUP;
+ setupWidget();
+}
+
+ListCategorizer::ListCategorizer(const QStringList & i,
+ bool startOpen,
+ QWidget * parent,
+ const char *name) :
+ KListView(parent, name),
+ fStartOpen(startOpen)
+{
+ FUNCTIONSETUP;
+ addCategories(i);
+}
+
+void ListCategorizer::addCategories(const QStringList & l)
+{
+ FUNCTIONSETUP;
+ QStringList::ConstIterator i;
+
+ for (i = l.begin(); i != l.end(); ++i)
+ {
+ (void) addCategory(*i);
+ }
+}
+
+QListViewItem *ListCategorizer::addCategory(const QString & name,
+ const QString & desc)
+{
+ FUNCTIONSETUP;
+ QListViewItem *m = new QListViewItem(this, name, desc);
+
+ m->setSelectable(false);
+ m->setOpen(fStartOpen);
+ return m;
+}
+
+void ListCategorizer::setupWidget()
+{
+ FUNCTIONSETUP;
+ addColumn(i18n("Category"));
+ addColumn(i18n("Description"));
+ setItemsMovable(false);
+ setDragEnabled(true);
+ setAcceptDrops(true);
+ setDropVisualizer(true);
+ setRootIsDecorated(true);
+}
+
+/* virtual */ bool ListCategorizer::acceptDrag(QDropEvent * event) const
+{
+ FUNCTIONSETUP;
+ if (!(event->source()))
+ return false;
+ QListViewItem *p = itemAt(event->pos());
+
+ if (!p)
+ return false;
+
+ return true;
+}
+
+/* virtual */ void ListCategorizer::contentsDropEvent(QDropEvent * e)
+{
+ FUNCTIONSETUP;
+ cleanDropVisualizer();
+
+ if (!acceptDrag(e))
+ return;
+ e->accept();
+
+ QListViewItem *p = itemAt(e->pos());
+ QListViewItem *selection = currentItem();
+
+ if (!p)
+ {
+ WARNINGKPILOT << "Drop without a category!" << endl;
+ return;
+ }
+
+ QListViewItem *category = p->parent();
+
+ if (!category)
+ {
+ category = p;
+ }
+
+ moveItem(selection, category, 0L);
+}
+
+/* virtual */ void ListCategorizer::startDrag()
+{
+ FUNCTIONSETUP;
+ QListViewItem *p = currentItem();
+
+ if (!p || !p->parent())
+ return;
+
+ KListView::startDrag();
+}
+
+QStringList ListCategorizer::listSiblings(const QListViewItem * p, int column) const
+{
+ FUNCTIONSETUP;
+ QStringList l;
+
+ while (p)
+ {
+ l.append(p->text(column));
+ p = p->nextSibling();
+ }
+
+ return l;
+}
+
+QListViewItem *ListCategorizer::findCategory(const QString & category) const
+{
+ FUNCTIONSETUP;
+ QListViewItem *p = firstChild();
+
+ while (p)
+ {
+ if (p->text(0) == category)
+ return p;
+ p = p->nextSibling();
+ }
+
+ return 0L;
+}
+
+QListViewItem *ListCategorizer::addItem(const QString & category,
+ const QString & name, const QString & description)
+{
+ FUNCTIONSETUP;
+ QListViewItem *p = findCategory(category);
+
+ if (!p)
+ return 0L;
+
+ return new QListViewItem(p, name, description);
+}
+
+#define RVPAD (4)
+
+RichListViewItem::RichListViewItem(QListViewItem *p,
+ QString l,
+ int c) :
+ QListViewItem(p,l)
+{
+ FUNCTIONSETUP;
+
+ fColumns=c;
+ fIsRich = new bool[c];
+ fRect = new QRect[c];
+
+ for (int i=0; i<c; i++)
+ {
+ fIsRich[i]=false;
+ }
+}
+
+RichListViewItem::~RichListViewItem()
+{
+ FUNCTIONSETUP;
+
+ delete[] fIsRich;
+ delete[] fRect;
+}
+
+void RichListViewItem::computeHeight(int c)
+{
+ FUNCTIONSETUP;
+
+ if (!fIsRich[c]) return;
+
+ QListView *v = listView();
+
+ fRect[c] = v->fontMetrics().boundingRect(v->itemMargin()+RVPAD,0+RVPAD,
+ v->columnWidth(c)-v->itemMargin()-RVPAD,300,
+ AlignLeft | AlignTop | WordBreak,
+ text(c));
+}
+
+
+/* virtual */ void RichListViewItem::setup()
+{
+ FUNCTIONSETUP;
+
+ QListViewItem::setup();
+
+ int h = height();
+
+ for (int i=0; i<fColumns; i++)
+ {
+ computeHeight(i);
+ h = kMax(h,fRect[i].height()+2*RVPAD);
+ }
+
+ setHeight(h);
+}
+
+
+/* virtual */ void RichListViewItem::paintCell(QPainter *p,
+ const QColorGroup &gc,
+ int column,
+ int width,
+ int alignment)
+{
+ FUNCTIONSETUP;
+
+ if ((!column) || (!fIsRich[column]))
+ {
+ QListViewItem::paintCell(p,gc,column,width,alignment);
+ return;
+ }
+
+ QListView *v = listView();
+
+ p->eraseRect(0,0,width,height());
+ p->setBackgroundColor(gc.background());
+ p->eraseRect(RVPAD,RVPAD,width-RVPAD,height()-RVPAD);
+ p->setPen(gc.text());
+ p->drawText(v->itemMargin()+RVPAD,0+RVPAD,
+ width-v->itemMargin()-RVPAD,height()-RVPAD,
+ AlignTop | AlignLeft | WordBreak,
+ text(column),
+ -1,
+ &fRect[column]);
+}
diff --git a/kpilot/kpilot/listCat.h b/kpilot/kpilot/listCat.h
new file mode 100644
index 000000000..fd53413b7
--- /dev/null
+++ b/kpilot/kpilot/listCat.h
@@ -0,0 +1,229 @@
+#ifndef LISTCAT_H
+#define LISTCAT_H
+/* listCat.h KPilot
+**
+** Copyright (C) 2000-2001 by Adriaan de Groot
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+*/
+
+/** @file
+** This is a specialization of KListView to allow the user to
+** DnD a fixed set of objects into a fixed set of categories
+** (categories set at construction time). @em Deprecated, do not use.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <klistview.h>
+class QStringList;
+
+/**
+ * This Widget extends KListView for a particular purpose:
+ * sorting some items into some bins. This can be useful
+ * for putting items in an enabled / disabled state, or
+ * into categories, or configuring toolbars (putting
+ * icons onto toolbars).
+ *
+ * You can use all of the standard KListView signals and
+ * slots. You may in particular want to change the names
+ * of the columns, for example:
+ * @code
+ * ListCategorizer *lc = new ListCategorizer(this,colors);
+ * lc->setColumnText(0,i18n("Color"));
+ * lc->setColumnText(1,i18n("HTML"));
+ * QListViewItem *stdKDE = lc->addCategory(i18n("Standard KDE"));
+ * (void) new QListViewItem(stdKDE,i18n("red"),"#FF0000");
+ * @endcode
+ * to set sensible column headers for a list of colors
+ * and their HTML equivalents (although why you would want
+ * to categorize colors is beyond me).
+ *
+ * @version $Id$
+ */
+
+class ListCategorizer : public KListView
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ *
+ * This creates a new empty ListCategorizer with
+ * startOpen set to false. The parameters
+ * @p parent and @p name are the usual Qt ones.
+ */
+ ListCategorizer(QWidget *parent,
+ const char *name = 0);
+ /**
+ * Constructor.
+ *
+ * This creates a ListCategorizer with the given @p categories
+ * already inserted. In addition, this constructor lets you
+ * specify whether or not startOpen is set.
+ */
+ ListCategorizer(const QStringList& categories,
+ bool startOpen,
+ QWidget *parent,
+ const char *name = 0);
+
+ /**
+ * Add a list of categories to the ListCategorizer.
+ * All the categories are added without descriptions;
+ * use addCategory on a per-category basis for that.
+ */
+ void addCategories(const QStringList&);
+ /**
+ * Add a category with name @p name and optional
+ * @p description. This can be useful if you want
+ * either a description for the category or want to
+ * refer to this category in the future without
+ * using findCategory().
+ *
+ * @return the QListViewItem created for the category
+ */
+ QListViewItem *addCategory(const QString& name,
+ const QString& description = QString::null);
+ /**
+ * Returns the list of names of the categories in
+ * the ListCategorizer.
+ */
+ QStringList categories() const
+ {
+ return listSiblings(firstChild());
+ } ;
+
+ /**
+ * Add a single item to the category named @p category,
+ * with name @p name and description set to @p description.
+ * This might be a convenience function, but it's probably
+ * more convenient to just use QListViewItem's
+ * constructor. That way you can also hide more data in
+ * the remaining columns.
+ */
+ QListViewItem *addItem(const QString& category,
+ const QString& name,
+ const QString& description = QString::null);
+ /**
+ * Returns the list of strings in column @p column under
+ * category @p category. You can do this to get, for example
+ * the names of all the items categorized under a given
+ * category, or, more usefully, set @p column to something
+ * other that 0 (name) or 1 (description) to return the
+ * QStringList hidden in the non-visible columns.
+ */
+ QStringList items(const QString& category,int column=0) const
+ {
+ return listSiblings(findCategory(category),column);
+ }
+
+ /**
+ * Given a category categoryName return the QListViewItem
+ * that represents that category. Probably a useless function,
+ * since just remembering the pointer addCategory gives
+ * you is faster and uses hardly any memory.
+ */
+ QListViewItem *findCategory(const QString& categoryName) const;
+ /**
+ * Return the list of strings in column @p column of all siblings
+ * of the given item @p p. If you remembered a pointer to a
+ * category, you can use
+ * @code
+ * QStringList l = lc->listSiblings(stdKDE->firstChild(),2);
+ * @endcode
+ * to get the list of strings in hidden column 2 under
+ * the category you remembered.
+ */
+ QStringList listSiblings(const QListViewItem *p,int column=0) const;
+
+ /**
+ * @return whether new categories are inserted in an
+ * open state or not.
+ *
+ * @see setStartOpen
+ */
+ bool startOpen() const { return fStartOpen; } ;
+ /**
+ * Enable categories being inserted in an open state.
+ * It is disabled by default but may be set from the
+ * constructor.
+ */
+ void setStartOpen(bool b) { fStartOpen=b; } ;
+
+protected:
+ /**
+ * Reimplemented to prevent categories from being dragged.
+ */
+ virtual bool acceptDrag (QDropEvent* event) const;
+ /**
+ * Reimplemented to prevent categories from being dragged.
+ */
+ virtual void startDrag();
+ /**
+ * Reimplemented to prevent categories from being dragged.
+ */
+ virtual void contentsDropEvent (QDropEvent*);
+
+
+
+private:
+ /**
+ * Call several KListView functions to set up useful
+ * behavior for this particular class.
+ */
+ void setupWidget();
+
+ bool fStartOpen:1;
+} ;
+
+
+class RichListViewItem : public QListViewItem
+{
+public:
+ RichListViewItem(QListViewItem *parent,
+ QString,
+ int);
+ virtual ~RichListViewItem();
+
+ virtual void paintCell(QPainter *,
+ const QColorGroup &,
+ int column,
+ int width,
+ int alignment);
+
+ virtual void setup();
+
+ bool isRich(int c) const { return fIsRich[c]; } ;
+ void setRich(int c,bool b) { fIsRich[c]=b; } ;
+
+protected:
+ void computeHeight(int c);
+
+protected:
+ bool *fIsRich;
+ QRect *fRect;
+ int fColumns;
+
+} ;
+
+#endif
diff --git a/kpilot/kpilot/listItems.cc b/kpilot/kpilot/listItems.cc
new file mode 100644
index 000000000..1c8315b86
--- /dev/null
+++ b/kpilot/kpilot/listItems.cc
@@ -0,0 +1,242 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003 by Reinhold Kainhofer
+**
+** Program description
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+
+#include <qstring.h>
+#include <qlistbox.h>
+#include <qlistview.h>
+
+
+#ifndef _KPILOT_LISTITEMS_H
+#include "listItems.h"
+#endif
+
+#ifdef DEBUG
+/* static */ int PilotListItem::crt = 0;
+/* static */ int PilotListItem::del = 0;
+/* static */ int PilotListItem::count = 0;
+
+/* static */ void PilotListItem::counts()
+{
+ FUNCTIONSETUP;
+ DEBUGKPILOT << fname
+ << ": created=" << crt << " deletions=" << del << endl;
+}
+#endif
+
+PilotListItem::PilotListItem(const QString & text,
+ recordid_t pilotid, void *r) :
+ QListBoxText(text),
+ fid(pilotid),
+ fr(r)
+{
+ // FUNCTIONSETUP;
+#ifdef DEBUG
+ crt++;
+ count++;
+ if (!(count & 0xff))
+ counts();
+#endif
+}
+
+PilotListItem::~PilotListItem()
+{
+ // FUNCTIONSETUP;
+#ifdef DEBUG
+ del++;
+ count++;
+ if (!(count & 0xff))
+ counts();
+#endif
+}
+
+
+
+
+#ifdef DEBUG
+/* static */ int PilotCheckListItem::crt = 0;
+/* static */ int PilotCheckListItem::del = 0;
+/* static */ int PilotCheckListItem::count = 0;
+
+/* static */ void PilotCheckListItem::counts()
+{
+ FUNCTIONSETUP;
+ DEBUGKPILOT << fname
+ << ": created=" << crt << " deletions=" << del << endl;
+}
+#endif
+
+PilotCheckListItem::PilotCheckListItem(QListView * parent, const QString & text, recordid_t pilotid, void *r) :
+ QCheckListItem(parent, text, QCheckListItem::CheckBox),
+ fid(pilotid),
+ fr(r)
+{
+ // FUNCTIONSETUP;
+#ifdef DEBUG
+ crt++;
+ count++;
+ if (!(count & 0xff))
+ counts();
+#endif
+}
+
+PilotCheckListItem::~PilotCheckListItem()
+{
+ // FUNCTIONSETUP;
+#ifdef DEBUG
+ del++;
+ count++;
+ if (!(count & 0xff))
+ counts();
+#endif
+}
+
+void PilotCheckListItem::stateChange ( bool on)
+{
+ // FUNCTIONSETUP;
+ QCheckListItem::stateChange(on);
+
+}
+
+
+
+
+#ifdef DEBUG
+/* static */ int PilotListViewItem::crt = 0;
+/* static */ int PilotListViewItem::del = 0;
+/* static */ int PilotListViewItem::count = 0;
+
+/* static */ void PilotListViewItem::counts()
+{
+ FUNCTIONSETUP;
+ DEBUGKPILOT << fname
+ << ": created=" << crt << " deletions=" << del << endl;
+}
+#endif
+
+PilotListViewItem::PilotListViewItem( QListView * parent,
+ QString label1, QString label2, QString label3, QString label4,
+ recordid_t pilotid, void *r):
+ QListViewItem(parent, label1, label2, label3, label4,
+ QString::null, QString::null, QString::null, QString::null),
+ fid(pilotid),
+ fr(r),
+ d(new PilotListViewItemData)
+{
+ // FUNCTIONSETUP;
+ if (d) d->valCol=-1;
+#ifdef DEBUG
+ crt++;
+ count++;
+ if (!(count & 0xff))
+ counts();
+#endif
+}
+
+PilotListViewItem::~PilotListViewItem()
+{
+ // FUNCTIONSETUP;
+#ifdef DEBUG
+ del++;
+ count++;
+ if (!(count & 0xff))
+ counts();
+#endif
+}
+void PilotListViewItem::setNumericCol(int col, bool numeric)
+{
+ // FUNCTIONSETUP;
+ if (numeric)
+ {
+ if (!numericCols.contains(col))
+ numericCols.append(col);
+ }
+ else
+ {
+ if (numericCols.contains(col))
+ numericCols.remove(col);
+ }
+}
+
+unsigned long PilotListViewItem::colValue(int col, bool *ok) const
+{
+// FUNCTIONSETUP;
+/* if (!d)
+ {
+ d=new PilotListViewItemData;
+ d->valCol=-1;
+ }*/
+ if (d->valCol!=col)
+ {
+ // Use true for ascending for now...
+ d->val=key(col, true).toULong(&d->valOk);
+ d->valCol=col;
+ }
+ if (ok) (*ok)=d->valOk;
+ return d->val;
+}
+
+int PilotListViewItem::compare( QListViewItem *i, int col, bool ascending ) const
+{
+// FUNCTIONSETUP;
+ PilotListViewItem*item=dynamic_cast<PilotListViewItem*>(i);
+/*#ifdef DEBUG
+ DEBUGKPILOT<<"Item of dyn cast: "<<item<<endl;
+#endif*/
+ if (item && numericCols.contains(col))
+ {
+/*#ifdef DEBUG
+ DEBUGKPILOT<<"Comparing: col "<<col<<", Ascending: "<<ascending<<endl;
+#endif*/
+ bool ok1, ok2;
+ /// Do the toULong call just once if the sorting column changed:
+ unsigned long l1=colValue(col, &ok1);
+ unsigned long l2=item->colValue(col, &ok2);
+/*#ifdef DEBUG
+ DEBUGKPILOT<<"l1="<<l1<<"(ok: "<<ok1<<"), l2="<<l2<<"(ok: "<<ok2<<")"<<endl;
+#endif*/
+ if (ok1 && ok2)
+ {
+ // Returns -1 if this item is less than i, 0 if they are
+ // equal and 1 if this item is greater than i.
+ int res=0;
+ if (l1<l2) res=-1;
+ else if (l1>l2) res=1;
+ //else res=0;
+/*#ifdef DEBUG
+ DEBUGKPILOT<<"RESULT="<<res<<endl;
+#endif*/
+ return res;
+ }
+ }
+ return QListViewItem::compare(i, col, ascending);
+}
+
diff --git a/kpilot/kpilot/listItems.h b/kpilot/kpilot/listItems.h
new file mode 100644
index 000000000..914d4b006
--- /dev/null
+++ b/kpilot/kpilot/listItems.h
@@ -0,0 +1,114 @@
+/* listItems.h KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines a subclasse of QListBoxText that carries
+** additional information useful for Pilot records. In particular it
+** carries an int (for the pilot's uid?) and a void * (for pilotrecord?)
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#ifndef _KPILOT_LISTITEMS_H
+#define _KPILOT_LISTITEMS_H
+
+#include <qlistview.h>
+#include <pi-dlp.h>
+
+class PilotListItem : public QListBoxText
+{
+public:
+ PilotListItem(const QString &text, recordid_t pilotid=0, void *r=0);
+ virtual ~PilotListItem();
+ recordid_t id() const {return fid;};
+ const void *rec() const {return fr;};
+
+
+protected:
+ recordid_t fid;
+ void *fr;
+
+#ifdef DEBUG
+public:
+ static void counts();
+private:
+ static int crt,del,bal,count;
+#endif
+};
+
+class PilotCheckListItem : public QCheckListItem
+{
+public:
+ PilotCheckListItem( QListView * parent, const QString & text, recordid_t pilotid=0, void *r=0);
+ virtual ~PilotCheckListItem();
+ recordid_t id() const {return fid;};
+ const void *rec() const {return fr;};
+protected:
+ virtual void stateChange ( bool );
+ recordid_t fid;
+ void *fr;
+#ifdef DEBUG
+public:
+ static void counts();
+private:
+ static int crt, del, bal, count;
+#endif
+};
+
+struct PilotListViewItemData
+{
+ int valCol;
+ bool valOk;
+ unsigned long val;
+};
+
+class PilotListViewItem : public QListViewItem
+{
+public:
+ PilotListViewItem( QListView * parent,
+ QString label1, QString label2 = QString::null,
+ QString label3 = QString::null, QString label4 = QString::null,
+ recordid_t pilotid=0, void *r=0);
+ virtual ~PilotListViewItem();
+ recordid_t id() const {return fid;};
+ const void *rec() const {return fr;};
+public:
+ void setNumericCol(int col, bool numeric);
+ int compare( QListViewItem *i, int col, bool ascending ) const;
+protected:
+ QValueList<int> numericCols;
+ recordid_t fid;
+ void *fr;
+ // Caching to make sorting faster:
+ PilotListViewItemData*d;
+ unsigned long colValue(int col, bool *ok) const;
+#ifdef DEBUG
+public:
+ static void counts();
+private:
+ static int crt, del, bal, count;
+#endif
+};
+
+
+#endif
diff --git a/kpilot/kpilot/logFile.cc b/kpilot/kpilot/logFile.cc
new file mode 100644
index 000000000..b93b060ce
--- /dev/null
+++ b/kpilot/kpilot/logFile.cc
@@ -0,0 +1,128 @@
+/* KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2004 by Reinhold Kainhofer
+**
+** This file defines the log file class, which logs
+** sync-messages during a HotSync to a file.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected].
+*/
+
+#include "options.h"
+
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qdatetime.h>
+
+#include <pi-version.h>
+
+#ifndef PILOT_LINK_PATCH
+#define PILOT_LINK_PATCH "unknown"
+#endif
+#include "logFile.h"
+#include "kpilotConfig.h"
+
+#include "logFile.moc"
+
+
+LogFile::LogFile() : DCOPObject("LogIface"), QObject(), fOutfile(0L), fSyncing(false)
+{
+ FUNCTIONSETUP;
+}
+
+
+/* DCOP */ ASYNC LogFile::logStartSync()
+{
+ FUNCTIONSETUP;
+ // If a sync is already running (something went wrong then!), close that old log
+ if (fSyncing) logEndSync();
+
+ fOutfile = new QFile(KPilotSettings::logFileName());
+
+ if (!fOutfile || !fOutfile->open(IO_WriteOnly))
+ {
+ WARNINGKPILOT << "Unable to open log file " << KPilotSettings::logFileName() << endl;
+ KPILOT_DELETE( fOutfile );
+ fSyncing = false;
+ return;
+ }
+
+ fSyncing = true;
+ fLogStream.setDevice(fOutfile);
+
+ fLogStream<<(CSL1("KPilot HotSync log, %1").arg(QDateTime::currentDateTime().toString()))<<endl<<endl<<endl;
+ fLogStream<<(CSL1("Version: KPilot %1").arg(QString::fromLatin1(KPILOT_VERSION)))<<endl;
+ fLogStream<<(CSL1("Version: pilot-link %1.%2.%3%4" )
+ .arg(PILOT_LINK_VERSION).arg(PILOT_LINK_MAJOR).arg(PILOT_LINK_MINOR)
+#ifdef PILOT_LINK_PATCH
+ .arg(QString::fromLatin1(PILOT_LINK_PATCH))
+#else
+ .arg(QString())
+#endif
+ )<<endl;
+#ifdef KDE_VERSION_STRING
+ fLogStream<<(CSL1("Version: KDE %1" ).arg(QString::fromLatin1(KDE_VERSION_STRING)) )<<endl;
+#endif
+#ifdef QT_VERSION_STR
+ fLogStream<<(CSL1("Version: Qt %1" ).arg(QString::fromLatin1(QT_VERSION_STR)) )<<endl;
+#endif
+ fLogStream<<endl<<endl;
+
+}
+
+/* DCOP */ ASYNC LogFile::logEndSync()
+{
+ if (fSyncing)
+ {
+ logMessage(i18n("HotSync finished."));
+ fLogStream.unsetDevice();
+ if (fOutfile) fOutfile->close();
+ KPILOT_DELETE(fOutfile)
+ fSyncing=false;
+ }
+}
+
+/* DCOP */ ASYNC LogFile::logMessage(QString s)
+{
+ addMessage(s);
+}
+
+/* DCOP */ ASYNC LogFile::logError(QString s)
+{
+ addMessage(s);
+}
+
+/* DCOP */ ASYNC LogFile::logProgress(QString, int)
+{
+}
+
+
+void LogFile::addMessage(const QString & s)
+{
+ FUNCTIONSETUP;
+ if ( fSyncing && !s.isEmpty() )
+ {
+ fLogStream<<QTime::currentTime().toString()<<" "<<s<<endl;
+ }
+}
+
diff --git a/kpilot/kpilot/logFile.h b/kpilot/kpilot/logFile.h
new file mode 100644
index 000000000..5ed93d43a
--- /dev/null
+++ b/kpilot/kpilot/logFile.h
@@ -0,0 +1,64 @@
+#ifndef _KPILOT_LOGFILE_H
+#define _KPILOT_LOGFILE_H
+/* logFile.h KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2004 by Reinhold Kainhofer
+**
+** This file defines the log window widget, which logs
+** sync-messages during a HotSync.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected].
+*/
+
+#include "loggerDCOP.h"
+#include "qobject.h"
+
+class QFile;
+class QTextStream;
+
+class LogFile : public QObject, public LoggerDCOP
+{
+Q_OBJECT
+
+public:
+ LogFile();
+ ~LogFile() { } ;
+
+ /**
+ * DCOP interface.
+ */
+ virtual ASYNC logStartSync();
+ virtual ASYNC logEndSync();
+ virtual ASYNC logError(QString);
+ virtual ASYNC logMessage(QString);
+ virtual ASYNC logProgress(QString,int);
+
+ void addMessage(const QString &);
+
+private:
+ QFile*fOutfile;
+ bool fSyncing;
+ QTextStream fLogStream;
+} ;
+
+#endif
diff --git a/kpilot/kpilot/logWidget.cc b/kpilot/kpilot/logWidget.cc
new file mode 100644
index 000000000..b64ed4a87
--- /dev/null
+++ b/kpilot/kpilot/logWidget.cc
@@ -0,0 +1,396 @@
+/* KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the log window widget, which logs
+** sync-messages during a HotSync.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected].
+*/
+
+#include "options.h"
+
+#include <qfile.h>
+#include <qlayout.h>
+#include <qtextedit.h>
+#include <qwhatsthis.h>
+#include <qdatetime.h>
+#include <qlabel.h>
+#include <qpixmap.h>
+#include <qtimer.h>
+#include <qpushbutton.h>
+#include <qhbox.h>
+#include <qtextstream.h>
+#include <qpainter.h>
+
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kprogress.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+
+#include <pi-version.h>
+
+#ifndef PILOT_LINK_PATCH
+#define PILOT_LINK_PATCH "unknown"
+#endif
+
+#include "logWidget.moc"
+
+#if QT_VERSION < 0x030100
+#define TE_EOL "<br/>"
+#else
+#define TE_EOL "\n"
+#endif
+
+
+LogWidget::LogWidget(QWidget * parent) :
+ DCOPObject("LogIface"),
+ PilotComponent(parent, "component_log", QString::null),
+ fLog(0L),
+ fShowTime(false),
+ fSplash(0L),
+ fLabel(0L),
+ fProgress(0L),
+ fButtonBox(0L)
+{
+ FUNCTIONSETUP;
+ QGridLayout *grid = new QGridLayout(this, 4, 4, SPACING);
+
+ grid->addRowSpacing(0, SPACING);
+ grid->addRowSpacing(1, 100);
+ grid->addColSpacing(2, 100);
+ grid->addRowSpacing(3, SPACING);
+ grid->addColSpacing(0, SPACING);
+ grid->addColSpacing(3, SPACING);
+ grid->setRowStretch(1, 50);
+ grid->setColStretch(2, 50);
+
+ fLog = new QTextEdit(this);
+ fLog->setReadOnly(true);
+ fLog->setWordWrap(QTextEdit::WidgetWidth);
+ fLog->setWrapPolicy(QTextEdit::AtWordOrDocumentBoundary);
+#if QT_VERSION < 0x030100
+ /* nothing, use AutoText */
+#else
+ fLog->setTextFormat(Qt::LogText);
+#endif
+
+ QWhatsThis::add(fLog, i18n("<qt>This lists all the messages received "
+ "during the current HotSync</qt>"));
+ grid->addMultiCellWidget(fLog, 1, 1,1,2);
+
+
+ QString initialText ;
+
+ initialText.append(CSL1("<b>Version:</b> KPilot %1" TE_EOL)
+ .arg(QString::fromLatin1(KPILOT_VERSION)));
+ initialText.append(CSL1("<b>Version:</b> pilot-link %1.%2.%3%4" TE_EOL)
+ .arg(PILOT_LINK_VERSION)
+ .arg(PILOT_LINK_MAJOR)
+ .arg(PILOT_LINK_MINOR)
+#ifdef PILOT_LINK_PATCH
+ .arg(QString::fromLatin1(PILOT_LINK_PATCH))
+#else
+ .arg(QString())
+#endif
+ );
+#ifdef KDE_VERSION_STRING
+ initialText.append(CSL1("<b>Version:</b> KDE %1" TE_EOL)
+ .arg(QString::fromLatin1(KDE_VERSION_STRING)));
+#endif
+#ifdef QT_VERSION_STR
+ initialText.append(CSL1("<b>Version:</b> Qt %1" TE_EOL)
+ .arg(QString::fromLatin1(QT_VERSION_STR)));
+#endif
+
+ initialText.append(CSL1(TE_EOL));
+ initialText.append(i18n("<qt><b>HotSync Log</b></qt>"));
+ initialText.append(CSL1(TE_EOL));
+
+#if KDE_IS_VERSION(3,3,0)
+#else
+ initialText.append(CSL1(TE_EOL "<qt><b>KDE 3.2 is no longer supported. Please update to KDE 3.3 or later.</b></qt>" TE_EOL));
+ initialText.append(CSL1(TE_EOL "<qt><b>You may be unable to do conflict resolution.</b></qt>" TE_EOL));
+#endif
+
+ fLog->setText(initialText);
+ fLog->scrollToBottom();
+
+ QHBox *h = new QHBox(this);
+ h->setSpacing(SPACING);
+ QPushButton *b = new QPushButton(
+ i18n("Clear the text of HotSync messages","Clear Log"),
+ h);
+ QWhatsThis::add(b,i18n("<qt>Clears the list of messages from the "
+ "current HotSync.</qt>"));
+ connect(b,SIGNAL(clicked()),this,SLOT(clearLog()));
+
+ b = new QPushButton(i18n("Save Log..."),h);
+ QWhatsThis::add(b,i18n("<qt>You can save the list of messages received "
+ "during this HotSync to a file (for example for use in a "
+ "bug report) by clicking here.</qt>"));
+ connect(b,SIGNAL(clicked()),this,SLOT(saveLog()));
+
+ fButtonBox = h;
+
+ grid->addMultiCellWidget(h,2,2,1,2);
+
+ fLabel = new QLabel(i18n("Sync progress:"),this);
+ grid->addWidget(fLabel,3,1);
+ fProgress = new KProgress(this);
+ QWhatsThis::add(fProgress,i18n("<qt>The (estimated) percentage "
+ "completed in the current HotSync.</qt>"));
+ grid->addWidget(fProgress,3,2);
+
+
+ QString splashPath =
+ KGlobal::dirs()->findResource("data",
+ CSL1("kpilot/kpilot-splash.png"));
+
+ if (!splashPath.isEmpty() && QFile::exists(splashPath))
+ {
+ fLog->hide();
+ fLabel->hide();
+ fProgress->hide();
+
+ QPixmap splash(splashPath);
+ QPainter painter(&splash);
+ painter.setPen(QColor(0, 255, 0));
+
+ // This latin1() is ok; KPILOT_VERSION is a #define
+ // of a constant string.
+ int textWidth =fontMetrics().width(
+ QString::fromLatin1(KPILOT_VERSION)) ;
+ int textHeight = fontMetrics().height();
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Using text size "
+ << textWidth << "x" << textHeight
+ << endl;
+#endif
+
+ painter.fillRect(splash.width() - 28 - textWidth,
+ splash.height() - 6 - textHeight,
+ textWidth + 6,
+ textHeight + 4,
+ black);
+ painter.drawText(splash.width() - 25 - textWidth,
+ splash.height() - 8,
+ QString::fromLatin1(KPILOT_VERSION));
+ fSplash = new QLabel(this);
+ fSplash->setPixmap(splash);
+ fSplash->setAlignment(AlignCenter);
+ QTimer::singleShot(3000,this,SLOT(hideSplash()));
+ grid->addMultiCellWidget(fSplash,1,3,1,2);
+ grid->addColSpacing(0,10);
+ grid->setColStretch(1,50);
+ grid->setColStretch(2,50);
+ grid->addColSpacing(3,10);
+ }
+
+}
+
+void LogWidget::addMessage(const QString & s)
+{
+ FUNCTIONSETUP;
+
+ if (s.isEmpty()) return;
+ if (!fLog) return;
+ QString t;
+
+ if (fShowTime)
+ {
+ t.append(CSL1("<b>"));
+ t.append(QTime::currentTime().toString());
+ t.append(CSL1("</b> "));
+ }
+
+ t.append(s);
+
+#if QT_VERSION < 0x030100
+ t.append(TE_EOL);
+ fLog->setText(fLog->text() + t);
+#else
+ fLog->append(t);
+#endif
+ fLog->scrollToBottom();
+}
+
+void LogWidget::addError(const QString & s)
+{
+ FUNCTIONSETUP;
+
+ if (s.isEmpty()) return;
+
+ WARNINGKPILOT << "KPilot error: " << s << endl;
+
+ if (!fLog) return;
+
+ QString t;
+
+ t.append(CSL1("<i>"));
+ t.append(s);
+ t.append(CSL1("</i>"));
+
+ addMessage(t);
+}
+
+void LogWidget::addProgress(const QString &s,int i)
+{
+ FUNCTIONSETUP;
+
+ if (!s.isEmpty()) logMessage(s);
+
+ if ((i >= 0) && (i <= 100))
+ {
+ // setValue seems to be in both KDE2 and
+ // KDE3, but is marked deprecated in KDE3.
+ //
+ //
+#ifdef KDE2
+ fProgress->setValue(i);
+#else
+ fProgress->setProgress(i);
+#endif
+ }
+}
+
+void LogWidget::syncDone()
+{
+ FUNCTIONSETUP;
+
+ addMessage(i18n("<b>HotSync Finished.</b>"));
+}
+
+void LogWidget::hideSplash()
+{
+ FUNCTIONSETUP;
+
+ if (fSplash)
+ {
+ fSplash->hide();
+ KPILOT_DELETE(fSplash);
+ }
+
+ fLog->show();
+ fLabel->show();
+ fProgress->show();
+}
+
+
+/* DCOP */ ASYNC LogWidget::logMessage(QString s)
+{
+ addMessage(s);
+}
+
+/* DCOP */ ASYNC LogWidget::logError(QString s)
+{
+ addError(s);
+}
+
+/* DCOP */ ASYNC LogWidget::logProgress(QString s, int i)
+{
+ addProgress(s,i);
+}
+
+/* DCOP */ ASYNC LogWidget::logStartSync()
+{
+}
+
+/* DCOP */ ASYNC LogWidget::logEndSync()
+{
+}
+
+/* slot */ void LogWidget::clearLog()
+{
+ FUNCTIONSETUP;
+
+ if (fLog)
+ {
+ fLog->setText(QString::null);
+ }
+}
+
+/* slot */ void LogWidget::saveLog()
+{
+ FUNCTIONSETUP;
+
+ bool finished = false;
+
+ while (!finished)
+ {
+ QString saveFileName = KFileDialog::getSaveFileName(
+ QString::null, /* default */
+ CSL1("*.log"), /* show log files by default */
+ this,
+ i18n("Save Log"));
+
+ if (saveFileName.isEmpty()) return;
+ if (QFile::exists(saveFileName))
+ {
+ int r = KMessageBox::warningYesNoCancel(
+ this,
+ i18n("The file exists. Do you want to "
+ "overwrite it?"),
+ i18n("File Exists"), i18n("Overwrite"), i18n("Do Not Overwrite"));
+ if (r==KMessageBox::Yes)
+ {
+ finished=saveFile(saveFileName);
+ }
+
+ if (r==KMessageBox::Cancel) return;
+ }
+ else
+ {
+ finished=saveFile(saveFileName);
+ }
+ }
+}
+
+
+bool LogWidget::saveFile(const QString &saveFileName)
+{
+ FUNCTIONSETUP;
+
+ QFile f(saveFileName);
+ if (!f.open(IO_WriteOnly))
+ {
+ int r = KMessageBox::questionYesNo(this,
+ i18n("<qt>Cannot open the file &quot;%1&quot; "
+ "for writing; try again?</qt>"),
+ i18n("Cannot Save"), i18n("Try Again"), i18n("Do Not Try"));
+
+ if (r==KMessageBox::Yes) return false;
+ return true;
+ }
+ else
+ {
+ QTextStream t(&f);
+ t << fLog->text();
+ }
+
+ f.close();
+ return true;
+}
+
diff --git a/kpilot/kpilot/logWidget.h b/kpilot/kpilot/logWidget.h
new file mode 100644
index 000000000..4c89c7185
--- /dev/null
+++ b/kpilot/kpilot/logWidget.h
@@ -0,0 +1,90 @@
+#ifndef _KPILOT_LOGWIDGET_H
+#define _KPILOT_LOGWIDGET_H
+/* logWidget.h KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+**
+** This file defines the log window widget, which logs
+** sync-messages during a HotSync.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected].
+*/
+
+#include "loggerDCOP.h"
+#include "pilotComponent.h"
+
+class QLabel;
+class QTextEdit;
+class QHBox;
+class KProgress;
+
+class LogWidget : public PilotComponent , public LoggerDCOP
+{
+Q_OBJECT
+
+public:
+ LogWidget(QWidget *);
+ ~LogWidget() { } ;
+
+ // Pilot Component Methods:
+ //
+ bool showTime() const { return fShowTime; } ;
+ void setShowTime(bool b) { fShowTime=b; } ;
+
+ /**
+ * DCOP interface.
+ */
+ virtual ASYNC logError(QString);
+ virtual ASYNC logMessage(QString);
+ virtual ASYNC logProgress(QString,int);
+ virtual ASYNC logStartSync();
+ virtual ASYNC logEndSync();
+
+ // GUI customization hooks
+ //
+ //
+ QHBox *buttonBox() const { return fButtonBox; } ;
+
+public slots:
+ void addMessage(const QString &);
+ void addError(const QString &);
+ void addProgress(const QString &,int);
+ void syncDone();
+
+private slots:
+ void hideSplash();
+ void clearLog();
+ void saveLog();
+
+private:
+ bool saveFile(const QString &);
+
+private:
+ QTextEdit *fLog;
+ bool fShowTime;
+ QLabel *fSplash;
+ QLabel *fLabel;
+ KProgress *fProgress;
+ QHBox *fButtonBox;
+} ;
+
+#endif
diff --git a/kpilot/kpilot/loggerDCOP.h b/kpilot/kpilot/loggerDCOP.h
new file mode 100644
index 000000000..9d8462343
--- /dev/null
+++ b/kpilot/kpilot/loggerDCOP.h
@@ -0,0 +1,58 @@
+#ifndef _KPILOT_LOGWIDGETDCOP_H
+#define _KPILOT_LOGWIDGETDCOP_H
+/* logWidgetDCOP.h KPilotDaemon
+**
+** Copyright (C) 2000 by Adriaan de Groot
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines the DCOP interface for the generalized log widget.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include <dcopobject.h>
+
+
+class LoggerDCOP : virtual public DCOPObject
+{
+ K_DCOP
+
+k_dcop:
+ // Indicates the start of a sync process
+ virtual ASYNC logStartSync() = 0 ;
+ // Indicates the end of a sync process
+ virtual ASYNC logEndSync() = 0 ;
+ // Adds a single message to the log, with formatting
+ // showing it's an error message.
+ virtual ASYNC logError(QString) = 0 ;
+ // Adds a regular message.
+ virtual ASYNC logMessage(QString) = 0 ;
+ // Adds a message if the string is non-null, and
+ // sets the progress bar to @p n%. Limit @p n
+ // to the range 0 .. 100.
+ virtual ASYNC logProgress(QString,int n) = 0 ;
+} ;
+
+
+
+#endif
diff --git a/kpilot/kpilot/main-config.cc b/kpilot/kpilot/main-config.cc
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/kpilot/kpilot/main-config.cc
diff --git a/kpilot/kpilot/main-test.cc b/kpilot/kpilot/main-test.cc
new file mode 100644
index 000000000..ad57bdabc
--- /dev/null
+++ b/kpilot/kpilot/main-test.cc
@@ -0,0 +1,437 @@
+/* KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2001,2002,2003,2004 by Adriaan de Groot
+**
+** This is the main program for kpilotTest, which shows a SyncLog and
+** exercises the KPilotDeviceLink class. It's intended to test if the
+** Palm hardware and the KPilot software are functioning correctly to
+** some extent.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected].
+*/
+
+#include "options.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <iostream>
+
+#include <qpushbutton.h>
+#include <qhbox.h>
+#include <qtimer.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <kservice.h>
+#include <kservicetype.h>
+#include <kuserprofile.h>
+
+#include <pi-version.h>
+
+#include "actionQueue.h"
+#include "actions.h"
+#include "kpilotdevicelink.h"
+#include "kpilotlocallink.h"
+#include "pilot.h"
+
+#include "kpilotConfig.h"
+#include "hotSync.h"
+
+
+static KCmdLineOptions generalOptions[] = {
+ {"p",0,0},
+ {"port <device>",
+ I18N_NOOP("Path to Pilot device node"),
+ "/dev/pilot"},
+ {"l",0,0},
+ {"list", I18N_NOOP("List DBs"), 0},
+ {"b",0,0},
+ {"backup <dest dir>", I18N_NOOP("Backup Pilot to <dest dir>"), 0},
+ {"r",0,0},
+ {"restore <src dir>", I18N_NOOP("Restore Pilot from backup"), 0},
+ {"e",0,0},
+ { "exec <filename>",
+ I18N_NOOP("Run conduit from desktop file <filename>"),
+ 0 },
+ {"c",0,0},
+ { "check <what>",
+ I18N_NOOP("Run a specific check (with the device)"), "help"},
+ {"s",0,0},
+ { "show <what>",
+ I18N_NOOP("Show KPilot configuration information"), "help"},
+#ifdef DEBUG
+ { "debug <level>",
+ I18N_NOOP("Set the debug level"), "1" },
+#endif
+ KCmdLineLastOption
+} ;
+
+static KCmdLineOptions conduitOptions[] = {
+ { "T",0,0},
+ { "notest",
+ I18N_NOOP("*Really* run the conduit, not in test mode."),
+ 0 } ,
+ { "F",0,0},
+ { "local",
+ I18N_NOOP("Run the conduit in file-test mode."),
+ 0 } ,
+ { "HHtoPC",
+ I18N_NOOP("Copy Pilot to Desktop."),
+ 0 } ,
+ { "PCtoHH",
+ I18N_NOOP("Copy Desktop to Pilot."),
+ 0 } ,
+ { "loop",
+ I18N_NOOP("Repeated perform action - only useful for --list"),
+ 0 } ,
+ KCmdLineLastOption
+} ;
+
+/**
+*** Conduits - sync actions - for testing specific scenarios.
+**/
+
+
+
+KPilotLink *createLink( bool local )
+{
+ FUNCTIONSETUP;
+ if (!local)
+ {
+ return new KPilotDeviceLink(0, "deviceLink");
+ }
+ else
+ {
+ return new KPilotLocalLink(0, "localLink");
+ }
+}
+
+/** If @p loop is true, then instead of quitting at end of
+* sync, wait for a new sync just like the real daemon does.
+*/
+void connectStack( KPilotLink *l, ActionQueue *a, bool loop = false )
+{
+ FUNCTIONSETUP;
+
+ if (l && a)
+ {
+ QObject::connect(a, SIGNAL(syncDone(SyncAction *)),
+ l, SLOT(close()));
+ if (!loop)
+ {
+ QObject::connect(a, SIGNAL(syncDone(SyncAction *)),
+ kapp, SLOT(quit()));
+ }
+ else
+ {
+ QObject::connect(a, SIGNAL(syncDone(SyncAction *)),
+ l, SLOT(reset()));
+ }
+ QObject::connect(l, SIGNAL(deviceReady(KPilotLink*)),
+ a, SLOT(execConduit()));
+ }
+}
+
+
+
+int exec(const QString &device, const QString &what, KCmdLineArgs *p)
+{
+ FUNCTIONSETUP;
+
+ // get --exec-conduit value
+ if (what.isEmpty()) return 1;
+ QStringList l;
+ l.append(what);
+
+ SyncAction::SyncMode::Mode syncMode = SyncAction::SyncMode::eHotSync;
+ if (p->isSet("HHtoPC")) syncMode = SyncAction::SyncMode::eCopyHHToPC;
+ if (p->isSet("PCtoHH")) syncMode = SyncAction::SyncMode::eCopyPCToHH;
+ SyncAction::SyncMode mode(syncMode,p->isSet("test"),p->isSet("local"));
+
+ KPilotLink *link = createLink( p->isSet("local") );
+ ActionQueue *syncStack = new ActionQueue( link );
+ syncStack->queueInit();
+ syncStack->addAction(new CheckUser( link ));
+ syncStack->queueConduits(l,mode);
+ syncStack->queueCleanup();
+ connectStack(link,syncStack);
+ link->reset(device);
+ return kapp->exec();
+}
+
+int backup(const QString &device, const QString &what, KCmdLineArgs *p)
+{
+ FUNCTIONSETUP;
+ KPilotLink *link = createLink( p->isSet("local") );
+ ActionQueue *syncStack = new ActionQueue( link );
+ syncStack->queueInit();
+ BackupAction *ba = new BackupAction( link, true /* full backup */ );
+ ba->setDirectory( what );
+ syncStack->addAction( ba );
+ syncStack->queueCleanup();
+ connectStack(link,syncStack);
+ link->reset(device);
+ return kapp->exec();
+}
+
+int restore(const QString &device, const QString &what, KCmdLineArgs *p)
+{
+ FUNCTIONSETUP;
+ KPilotLink *link = createLink( p->isSet("local") );
+ ActionQueue *syncStack = new ActionQueue( link );
+ syncStack->queueInit();
+ RestoreAction *ra = new RestoreAction( link );
+ ra->setDirectory( what );
+ syncStack->addAction( ra );
+ syncStack->queueCleanup();
+ connectStack(link,syncStack);
+ link->reset(device);
+ return kapp->exec();
+}
+
+int listDB(const QString &device, KCmdLineArgs *p)
+{
+ FUNCTIONSETUP;
+ KPilotLink *link = createLink( p->isSet("local") );
+ ActionQueue *syncStack = new ActionQueue( link );
+ syncStack->queueInit();
+ syncStack->addAction( new TestLink( link ) );
+ syncStack->queueCleanup();
+ connectStack(link,syncStack, p->isSet("loop") );
+ link->reset(device);
+ return kapp->exec();
+}
+
+int check( const QString &device, const QString &what, KCmdLineArgs *p )
+{
+ FUNCTIONSETUP;
+
+ if ( "help" == what )
+ {
+ std::cout <<
+"You can use the --check option to kpilotTest to run various\n"
+"small checks that require the use of the device. These are:\n"
+"\thelp - show this help\n"
+"\tuser - check the user name on the handheld\n"
+ << std::endl;
+ return 0;
+ }
+
+ if ( "user" == what )
+ {
+ KPilotLink *link = createLink( p->isSet("local") );
+ ActionQueue *syncStack = new ActionQueue( link );
+ syncStack->queueInit();
+ syncStack->addAction( new CheckUser( link ) );
+ syncStack->queueCleanup();
+ connectStack(link,syncStack);
+ link->reset(device);
+ return kapp->exec();
+ }
+
+ return 0;
+}
+
+void listConduits()
+{
+ FUNCTIONSETUP;
+
+ KServiceTypeProfile::OfferList offers =
+ KServiceTypeProfile::offers(CSL1("KPilotConduit"));
+
+ // Now actually fill the two list boxes, just make
+ // sure that nothing gets listed in both.
+ //
+ //
+ QValueListIterator < KServiceOffer > availList(offers.begin());
+ while (availList != offers.end())
+ {
+ KSharedPtr < KService > o = (*availList).service();
+
+ std::cout << "File: " << o->desktopEntryName() << std::endl;
+ std::cout << " Desc: " << o->name() << std::endl;
+ if (!o->library().isEmpty())
+ {
+ std::cout << " Lib : "
+ << o->library()
+ << std::endl;
+ }
+
+ ++availList;
+ }
+}
+
+int show( const QString &what )
+{
+ FUNCTIONSETUP;
+
+ if ( "help" == what )
+ {
+ std::cout <<
+"Displays various bits of KPilot's internal settings. This\n"
+"does not require a device connection or a running KDE desktop.\n"
+"No change to data takes place. The following options are available\n"
+"for display:\n"
+"\thelp - displays this help\n"
+"\tconduits - displays the list of available conduits\n"
+"\tuser - displays the user name KPilot expects\n"
+"\tdevice - displays the device settings in KPilot\n"
+"\tdebug - displays internal numbers\n"
+ << std::endl;
+ return 0;
+ }
+
+ if ( "conduits" == what )
+ {
+ listConduits();
+ return 0;
+ }
+
+ if ( "user" == what )
+ {
+ std::cout << "User: " << KPilotSettings::userName() << std::endl;
+ return 0;
+ }
+
+ if ( "device" == what )
+ {
+ std::cout << "Device: " << KPilotSettings::pilotDevice()
+ << "\nSpeed: " << KPilotSettings::pilotSpeed()
+ << "\nEncoding: " << KPilotSettings::encoding()
+ << "\nQuirks: " << KPilotSettings::workarounds()
+ << std::endl;
+ return 0;
+ }
+
+ if ( "debug" == what )
+ {
+ std::cout << "Debug: " << KPilotSettings::debug()
+ << "\nConfig: " << KPilotSettings::configVersion()
+ << std::endl;
+ return 0;
+ }
+
+ std::cerr << "Unknown --show argument, use --show help for help.\n";
+ return 1;
+}
+
+int main(int argc, char **argv)
+{
+#ifdef DEBUG
+ debug_level = 1;
+#endif
+ FUNCTIONSETUP;
+ KAboutData about("kpilotTest",
+ I18N_NOOP("KPilotTest"),
+ KPILOT_VERSION,
+ "KPilot Tester",
+ KAboutData::License_GPL, "(C) 2001-2004, Adriaan de Groot");
+ about.addAuthor("Adriaan de Groot",
+ I18N_NOOP("KPilot Maintainer"),
+ "[email protected]", "http://www.kpilot.org/");
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions(generalOptions,
+ I18N_NOOP("General"));
+ KCmdLineArgs::addCmdLineOptions(conduitOptions,
+ I18N_NOOP("Conduit Actions"),"conduit");
+
+ KApplication::addCmdLineOptions();
+
+ KCmdLineArgs *p = KCmdLineArgs::parsedArgs();
+
+ bool needGUI = false;
+
+ // Some versions need a GUI
+ needGUI |= (p->isSet("check"));
+ needGUI |= (p->isSet("exec")); // assume worst wrt. conduits
+ needGUI |= (p->isSet("restore"));
+
+ KApplication a(needGUI,needGUI);
+#ifdef DEBUG
+ KPilotConfig::getDebugLevel(p);
+ DEBUGKPILOT << fname << "Created KApplication." << endl;
+#endif
+
+ Pilot::setupPilotCodec(KPilotSettings::encoding());
+
+ QString device( "/dev/pilot" );
+
+ if ( p->isSet("port") )
+ {
+ device = p->getOption("port");
+ }
+
+ if ( p->isSet("check") )
+ {
+ return check( device, p->getOption("check"),
+ KCmdLineArgs::parsedArgs("conduit") );
+ }
+
+ if ( p->isSet("show") )
+ {
+ return show( p->getOption("show") );
+ }
+
+ if ( p->isSet("exec") )
+ {
+ return exec( device, p->getOption("exec"),
+ KCmdLineArgs::parsedArgs("conduit") );
+ }
+
+ if ( p->isSet("list") )
+ {
+ return listDB( device,
+ KCmdLineArgs::parsedArgs("conduit") );
+ }
+
+ if ( p->isSet("backup") )
+ {
+ return backup( device, p->getOption("backup"),
+ KCmdLineArgs::parsedArgs("conduit") );
+ }
+
+ if ( p->isSet("restore") )
+ {
+ return restore( device, p->getOption("restore"),
+ KCmdLineArgs::parsedArgs("conduit") );
+ }
+
+
+
+ std::cout <<
+"Usage: kpilotTest [--port devicename] action\n\n"
+"Where action can be one of:\n"
+"\t--list - list the databases on the handheld\n"
+"\t--show (help | conduits | ...) - show configuration\n"
+"\t--check (help | user | ...) - check device\n"
+"\t--exec conduit - run a single conduit\n"
+"\t--backup - backup the device\n"
+"\t--restore - restore the device from backup\n"
+ << std::endl;
+ return 1;
+}
+
+
diff --git a/kpilot/kpilot/memoWidget.cc b/kpilot/kpilot/memoWidget.cc
new file mode 100644
index 000000000..0b5e16b42
--- /dev/null
+++ b/kpilot/kpilot/memoWidget.cc
@@ -0,0 +1,803 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2001 by David Bishop (XML stuff)
+** Copyright (C) 2004 by Adriaan de Groot
+**
+** This is the memo-viewing widget (internal conduit) used by KPilot.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <time.h>
+
+#include <pi-macros.h>
+#include <pi-dlp.h>
+
+#include <qdir.h>
+#include <qptrlist.h>
+#include <qlistbox.h>
+#include <qfile.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qdom.h>
+#include <qtextstream.h>
+#include <qwhatsthis.h>
+#include <qlabel.h>
+#include <qdatetime.h>
+#include <qptrlist.h>
+
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <kdeversion.h>
+#include <ktextedit.h>
+
+#include "kpilot.h"
+#include "kpilotConfig.h"
+#include "listItems.h"
+#include "pilotLocalDatabase.h"
+#include "pilotMemo.h"
+
+#include "memoWidget.moc"
+
+
+class MemoWidget::Private
+{
+public:
+ Private() : fMemoAppInfo(0L) { } ;
+ ~Private() { KPILOT_DELETE(fMemoAppInfo); } ;
+
+ PilotMemoInfo *fMemoAppInfo;
+ QPtrList<PilotMemo> fMemoList;
+} ;
+
+
+MemoWidget::MemoWidget(QWidget * parent,
+ const QString & path) :
+ PilotComponent(parent, "component_memo", path),
+ fTextWidget(0L),
+ d(new Private()),
+ lastSelectedMemo(-1)
+{
+ FUNCTIONSETUP;
+
+ setGeometry(0, 0,
+ parent->geometry().width(), parent->geometry().height());
+ setupWidget();
+ d->fMemoList.setAutoDelete(true);
+ slotUpdateButtons();
+}
+
+MemoWidget::~MemoWidget()
+{
+ FUNCTIONSETUP;
+ saveChangedMemo();
+ KPILOT_DELETE(d);
+}
+
+
+// void MemoWidget::initializeMemos(PilotDatabase *memoDB)
+//
+// Reads all the memos from the local database and places them
+// in the selection screen.
+//
+
+void MemoWidget::initializeMemos(PilotDatabase * memoDB)
+{
+ FUNCTIONSETUP;
+
+
+ // ShowSecrets tells us to also list memos with an attribute of "Secret"
+ // or "Private"
+ //
+ bool showSecrets = KPilotSettings::showSecrets();
+
+ d->fMemoList.clear();
+
+
+ int currentRecord = 0;
+ PilotRecord *pilotRec;
+ PilotMemo *memo;
+
+ while ((pilotRec = memoDB->readRecordByIndex(currentRecord)) != NULL)
+ {
+ if (!pilotRec->isDeleted())
+ {
+ if ((!pilotRec->isSecret()) || showSecrets)
+ {
+ memo = new PilotMemo(pilotRec);
+ d->fMemoList.append(memo);
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname <<
+ ": Added memo "
+ << currentRecord << endl;
+#endif
+ }
+ else
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname <<
+ ": Skipped secret record " <<
+ currentRecord << endl;
+#endif
+ }
+ }
+ else
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname <<
+ ": Skipped deleted record " <<
+ currentRecord << endl;
+#endif
+ }
+
+ delete pilotRec;
+
+ currentRecord++;
+ }
+}
+
+
+void MemoWidget::showComponent()
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ // Get the local database - assume the call may fail and return
+ // NULL, or the database object may be returned but unopened.
+ //
+ //
+ PilotLocalDatabase *memoDB =
+ new PilotLocalDatabase(dbPath(), CSL1("MemoDB"));
+ if (memoDB == NULL || !memoDB->isOpen())
+ {
+ WARNINGKPILOT << "Can't open local database MemoDB\n";
+
+ populateCategories(fCatList, 0L);
+ updateWidget();
+ return;
+ }
+
+ KPILOT_DELETE(d->fMemoAppInfo);
+ d->fMemoAppInfo = new PilotMemoInfo(memoDB);
+
+ d->fMemoAppInfo->dump();
+ populateCategories(fCatList, d->fMemoAppInfo->categoryInfo());
+ initializeMemos(memoDB);
+
+ KPILOT_DELETE( memoDB );
+
+ updateWidget();
+}
+
+void MemoWidget::hideComponent()
+{
+ FUNCTIONSETUP;
+ saveChangedMemo();
+ fCatList->clear();
+ fTextWidget->clear();
+ d->fMemoList.clear();
+ fListBox->clear();
+ lastSelectedMemo = -1;
+}
+
+void MemoWidget::postHotSync()
+{
+ FUNCTIONSETUP;
+ d->fMemoList.clear();
+ showComponent();
+}
+
+
+// void MemoWidget::setupWidget()
+//
+// Setup all the GUI components by allocating them.
+//
+//
+void MemoWidget::setupWidget()
+{
+ FUNCTIONSETUP;
+
+ QLabel *label = NULL;
+ QPushButton *button = NULL;
+ QGridLayout *grid = new QGridLayout(this, 5, 4, SPACING);
+ QString wt;
+
+ fCatList = new QComboBox(this);
+ grid->addWidget(fCatList, 0, 1);
+ connect(fCatList, SIGNAL(activated(int)),
+ this, SLOT(slotSetCategory(int)));
+ QWhatsThis::add(fCatList,
+ i18n("Select the category of addresses\n"
+ "to display here."));
+
+ (void) i18n("Memos:");
+ label = new QLabel(i18n("Category:"), this);
+ label->setBuddy(fCatList);
+ grid->addWidget(label, 0, 0);
+
+ fListBox = new QListBox(this);
+ grid->addMultiCellWidget(fListBox, 1, 1, 0, 1);
+ connect(fListBox, SIGNAL(highlighted(int)),
+ this, SLOT(slotShowMemo(int)));
+ connect(fListBox, SIGNAL(selectionChanged()),
+ this,SLOT(slotUpdateButtons()));
+ QWhatsThis::add(fListBox,
+ i18n("This list displays all the memos\n"
+ "in the selected category. Click on\n"
+ "one to display it to the right."));
+
+ label = new QLabel(i18n("Memo text:"), this);
+ grid->addWidget(label, 0, 2);
+
+ fTextWidget = new KTextEdit(this, "textArea");
+ fTextWidget->setWordWrap(KTextEdit::WidgetWidth);
+ fTextWidget->setTextFormat(Qt::PlainText);
+ grid->addMultiCellWidget(fTextWidget, 1, 4, 2, 2);
+ QWhatsThis::add(fTextWidget,
+ i18n("The text of the selected memo appears here."));
+ fTextWidget->setReadOnly(!KPilotSettings::internalEditors());
+
+ button = new QPushButton(i18n("Import Memo..."), this);
+ grid->addWidget(button, 2, 0);
+ connect(button, SIGNAL(clicked()), this, SLOT(slotImportMemo()));
+ wt = KPilotSettings::internalEditors() ?
+ i18n ("Read a text file and add it to the Pilot's memo database.") :
+ i18n("<qt><i>Import is disabled by the 'internal editors' setting.</i></qt>");
+ QWhatsThis::add(button,wt);
+
+ fExportButton = new QPushButton(i18n("Export Memo..."), this);
+ grid->addWidget(fExportButton, 2, 1);
+ connect(fExportButton, SIGNAL(clicked()), this,
+ SLOT(slotExportMemo()));
+ QWhatsThis::add(fExportButton,
+ i18n("Write the selected memo to a file."));
+
+ fDeleteButton = new QPushButton(i18n("Delete Memo"), this);
+ grid->addWidget(fDeleteButton, 3, 1);
+ connect(fDeleteButton, SIGNAL(clicked()), this,
+ SLOT(slotDeleteMemo()));
+ wt = KPilotSettings::internalEditors() ?
+ i18n("Delete the selected memo.") :
+ i18n("<qt><i>Deleting is disabled by the 'internal editors' setting.</i></qt>") ;
+ QWhatsThis::add(fDeleteButton, wt);
+
+ button = new QPushButton(i18n("Add Memo"), this);
+ grid->addWidget(button, 3, 0);
+ connect(button, SIGNAL(clicked()), this, SLOT(slotAddMemo()));
+ QWhatsThis::add(button,i18n("Add a new memo to the database."));
+}
+
+void MemoWidget::slotUpdateButtons()
+{
+ FUNCTIONSETUP;
+
+ bool highlight = false;
+
+ if ((fListBox->currentItem() != -1) &&
+ (fListBox->isSelected(fListBox->currentItem())))
+ highlight=true;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Selected items " << highlight << endl;
+#endif
+
+ if (fExportButton)
+ {
+ fExportButton->setEnabled(highlight);
+ }
+
+ // The remaining buttons are relevant only if the
+ // internal editors are editable.
+ highlight &= KPilotSettings::internalEditors() ;
+ if (fDeleteButton)
+ {
+ fDeleteButton->setEnabled(highlight);
+ }
+}
+
+void MemoWidget::slotSetCategory(int)
+{
+ FUNCTIONSETUP;
+ updateWidget();
+}
+
+void MemoWidget::slotDeleteMemo()
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ int item = fListBox->currentItem();
+
+ if (item == -1)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": No current item selected\n";
+#endif
+ return;
+ }
+ if (KMessageBox::questionYesNo(this,
+ i18n("Delete currently selected memo?"),
+ i18n("Delete Memo?"), KStdGuiItem::del(), KStdGuiItem::cancel()) != KMessageBox::Yes)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname <<
+ ": User decided not to delete memo.\n";
+#endif
+ return;
+ }
+
+ PilotListItem *p = (PilotListItem *) fListBox->item(item);
+ PilotMemo *selectedMemo = (PilotMemo *) p->rec();
+
+ if (selectedMemo->id() == 0x0)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Searching for record to delete (it's fresh)" << endl;
+#endif
+ PilotLocalDatabase *memoDB = new PilotLocalDatabase(dbPath(), CSL1("MemoDB"));
+ if (!memoDB || (!memoDB->isOpen()))
+ {
+ // Err.. peculiar.
+ WARNINGKPILOT << "Can't open MemoDB" << endl;
+ KMessageBox::sorry(this,
+ i18n("Cannot open MemoDB to delete record."),
+ i18n("Cannot Delete Memo"));
+ return;
+ }
+ memoDB->resetDBIndex();
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Searching for new record." << endl;
+#endif
+ const PilotRecord *r = 0L;
+ while ((r = memoDB->findNextNewRecord()))
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": got record " << (void *) r << endl;
+#endif
+ PilotMemo m(r);
+ if (m.text() == selectedMemo->text())
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": I think I found the memo." << endl;
+#endif
+ (const_cast<PilotRecord *>(r))->setDeleted(true);
+ break;
+ }
+ }
+ delete memoDB;
+ }
+ else
+ {
+ selectedMemo->setDeleted(true);
+ writeMemo(selectedMemo);
+ }
+ d->fMemoList.remove(selectedMemo);
+ delete p;
+}
+
+
+void MemoWidget::updateWidget()
+{
+ FUNCTIONSETUP;
+ if (!shown || !d->fMemoAppInfo ) return;
+
+ if (fCatList->currentItem() == -1)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": No category selected.\n";
+#endif
+ return;
+ }
+
+ int listIndex = 0;
+ int currentCatID = findSelectedCategory(fCatList,
+ d->fMemoAppInfo->categoryInfo(), false);
+
+
+ fListBox->clear();
+ d->fMemoList.first();
+
+
+ // Iterate through all the memos and insert each memo
+ // only if the category of the memo matches the selected category
+ // (using -1 to mean "All")
+ //
+ //
+ while (d->fMemoList.current())
+ {
+ PilotMemo *curr = d->fMemoList.current();
+ if ((curr->category() == currentCatID) ||
+ (currentCatID == -1))
+ {
+ PilotListItem *p =
+ new PilotListItem(curr->shortTitle(),
+ listIndex,
+ curr);
+
+ // List will delete the title of the memo,
+ // so there's no memory leak here.
+ //
+ //
+ fListBox->insertItem(p);
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Added memo "
+ << curr->getTitle() << endl;
+#endif
+ }
+ else
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Skipped memo "
+ << curr->getTitle() << endl;
+#endif
+ }
+
+ listIndex++;
+ d->fMemoList.next();
+ }
+
+ fTextWidget->clear();
+
+ slotUpdateButtons();
+
+ lastSelectedMemo=-1;
+}
+
+void MemoWidget::showMemo(const PilotMemo *m)
+{
+ FUNCTIONSETUP;
+
+ int index = fListBox->count();
+ for (int x = 0; x < index; x++)
+ {
+ PilotMemo *p = (PilotMemo *) ((PilotListItem *)fListBox->item(x))->rec();
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Memo @" << (void *) p <<endl;
+ DEBUGKPILOT << fname << " :" << fListBox->item(x)->text() << endl;
+#endif
+ if (m==p)
+ {
+ fListBox->setSelected(x,true);
+ slotShowMemo(x);
+ break;
+ }
+ }
+
+}
+
+void MemoWidget::slotShowMemo(int which)
+{
+ FUNCTIONSETUP;
+ if ( which == -1 ) return;
+ if (!shown) return;
+
+ slotUpdateButtons();
+ if ( !fListBox->isSelected(which) )
+ {
+ // Handle unselecting a memo. This is easy.
+ fTextWidget->blockSignals(true);
+ fTextWidget->clear();
+ fTextWidget->blockSignals(false);
+ return;
+ }
+
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Displaying memo " << which << endl;
+#endif
+ fTextWidget->blockSignals(true);
+ PilotListItem *p = (PilotListItem *) fListBox->item(which);
+ PilotMemo *theMemo = (PilotMemo *) p->rec();
+ fTextWidget->setText(theMemo->text());
+ fTextWidget->blockSignals(false);
+}
+
+
+void MemoWidget::writeMemo(PilotMemo * which)
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+ PilotRecord *pilotRec = which->pack();
+ PilotDatabase *memoDB = new PilotLocalDatabase(dbPath(), CSL1("MemoDB"));
+ memoDB->writeRecord(pilotRec);
+ markDBDirty(CSL1("MemoDB"));
+ KPILOT_DELETE( memoDB );
+ KPILOT_DELETE( pilotRec );
+}
+
+void MemoWidget::saveChangedMemo()
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ if (-1 == lastSelectedMemo) return;
+ if (!fTextWidget->isModified()) return;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Saving changed memo " << lastSelectedMemo << endl;
+#endif
+
+ PilotListItem *p =
+ (PilotListItem *) fListBox->item(lastSelectedMemo);
+ PilotMemo *currentMemo = (PilotMemo *) p->rec();
+
+// TODO: overload setText in PilotMemo
+ currentMemo->setText(Pilot::toPilot(fTextWidget->text()));
+ writeMemo(currentMemo);
+}
+
+/* virtual */ bool MemoWidget::preHotSync(QString &)
+{
+ FUNCTIONSETUP;
+ saveChangedMemo();
+ return true;
+}
+
+bool MemoWidget::addMemo(const QString &s, int category)
+{
+ FUNCTIONSETUP;
+
+ if (s.length() >= MemoWidget::MAX_MEMO_LEN)
+ {
+ return false;
+ }
+ if ((category<0) || (category>=(int)Pilot::CATEGORY_COUNT))
+ {
+ category=Pilot::Unfiled;
+ }
+
+ PilotMemo *aMemo = new PilotMemo();
+ aMemo->setCategory(category);
+ aMemo->setText(s);
+
+ d->fMemoList.append(aMemo);
+ writeMemo(aMemo);
+ updateWidget();
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": New memo @" << (void *)aMemo << endl;
+#endif
+ showMemo(aMemo);
+ return true;
+}
+
+void MemoWidget::slotAddMemo()
+{
+ FUNCTIONSETUP;
+ int currentCatID = findSelectedCategory(fCatList,
+ d->fMemoAppInfo->categoryInfo(), true);
+ addMemo(QDateTime::currentDateTime().toString(), currentCatID);
+}
+
+void MemoWidget::slotImportMemo()
+{
+ FUNCTIONSETUP;
+ if (!shown || !d->fMemoAppInfo ) return;
+
+ int currentCatID = findSelectedCategory(fCatList,
+ d->fMemoAppInfo->categoryInfo(), true);
+
+ QString fileName = KFileDialog::getOpenFileName();
+
+ if (!fileName.isEmpty())
+ {
+ QFile importFile(fileName);
+
+ if (importFile.open(IO_ReadOnly) == FALSE)
+ {
+ // show error!
+ return;
+ }
+
+ if (importFile.size() > MemoWidget::MAX_MEMO_LEN)
+ {
+ // Perhaps read first 64k?
+ return;
+ }
+
+ QTextStream stream(&importFile);
+ QString memoText = stream.read();
+ addMemo(memoText, currentCatID);
+ }
+}
+
+void MemoWidget::slotExportMemo()
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ int index = fListBox->numRows();
+ if (index == 0)
+ return;
+
+ QString data;
+
+ const QString filter = CSL1("*|Plain text output\n*.xml|XML output");
+ QString fileName;
+
+ KFileDialog kfile( QString::null , filter, fExportButton , "memoSave" , true );
+ kfile.setOperationMode( KFileDialog::Saving );
+
+ if ( kfile.exec() == QDialog::Accepted ) {
+ fileName = kfile.selectedFile();
+ }
+
+ if (fileName.isEmpty())
+ return;
+
+ QPtrList<PilotListItem> menu_items;
+
+ for (int x = 0; x < index; x++){
+ if (fListBox->item(x)->isSelected()){
+ menu_items.append((PilotListItem *) fListBox->item(x));
+ }
+ }
+
+ if (kfile.currentFilter() == CSL1("*.xml") )
+ {
+ MemoWidget::saveAsXML( fileName , menu_items );
+ }
+ else
+ {
+ MemoWidget::saveAsText( fileName , menu_items );
+ }
+
+
+ return;
+}
+
+bool MemoWidget::saveAsText(const QString &fileName,const QPtrList<PilotListItem> &memo_list)
+{
+ QFile f( fileName );
+ QTextStream stream(&f);
+
+ if ( QFile::exists( fileName ) )
+ {
+ if( !f.open(IO_ReadWrite | IO_Append) )
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if( !f.open(IO_WriteOnly) )
+ {
+ return false;
+ }
+ }
+
+ QPtrListIterator<PilotListItem> it(memo_list);
+ for ( ; it.current(); ++it )
+ {
+ PilotListItem *p = it.current();
+ PilotMemo *theMemo = (PilotMemo *) p->rec();
+ stream << theMemo->text() << endl;
+ }
+
+
+ return true;
+}
+
+bool MemoWidget::saveAsXML(const QString &fileName,const QPtrList<PilotListItem> &memo_list)
+{
+ QDomDocument doc( CSL1("kpilotmemos") );
+ QFile f( fileName );
+ QTextStream stream( &f );
+ QDomElement memos;
+ int append = 0;
+
+
+ if ( f.exists() )
+ {
+ if ( !f.open(IO_ReadOnly ) ) return false;
+
+ if ( doc.setContent( &f ) )
+ {
+ //
+ //
+ //Only if QDom can read the .xml file and set the doc object to be populated with it's contents
+ memos = doc.documentElement();
+ if ( memos.tagName()!= CSL1("memos") )
+ {
+ return false;
+ }
+ //
+ //
+ //This is an XML Document but it isn't a valid KPilot-Memo xml document
+ else
+ {
+ append = 1;
+ }
+ //
+ //
+ //This is a valid KPilot memo, and we will append the current memo to the xml
+ }
+ else
+ {
+ //
+ //
+ //We *couldn't* understand the xml. Return false!
+ return false;
+ }
+ }
+ else
+ {
+ if ( !f.open(IO_ReadWrite ) ) return false;
+ //
+ //
+ //If there's no such file, we are not appending, just opening the file to read/write.
+ }
+
+ f.close();
+ // These are temporary, and should be retrieved from the pilot stuff
+ QString mpilotid;
+ mpilotid = "1";
+ // End of temp variables
+
+ if (append == 1)
+ {
+ memos = doc.documentElement();
+ }
+ else
+ {
+ memos = doc.createElement( CSL1("memos") );
+ doc.appendChild ( memos );
+ }
+
+ QPtrListIterator<PilotListItem> it(memo_list);
+ for ( ; it.current(); ++it )
+ {
+ PilotListItem *p = it.current();
+ PilotMemo *theMemo = (PilotMemo *) p->rec();
+
+
+ QDomElement memo = doc.createElement( CSL1("memo") );
+ memo.setAttribute ( CSL1("pilotid") , mpilotid );
+ memos.appendChild ( memo );
+
+ //QDomElement category = doc.createElement( "category" );
+ //head.appendChild ( category );
+ //
+ //QDomText categorytext = doc.createTextNode( memo->category() );
+ //category.appendChild ( categorytext );
+ //FIXME
+
+ QDomElement title = doc.createElement(CSL1("title" ));
+ memo.appendChild ( title );
+
+ QDomText titletext = doc.createTextNode( theMemo->shortTitle() );
+ title.appendChild ( titletext );
+
+ QDomText body = doc.createTextNode( theMemo->text() );
+ memo.appendChild ( body );
+ }
+ if ( !f.open(IO_WriteOnly ) ) return false;
+ stream << doc.toString();
+ return true;
+}
+
diff --git a/kpilot/kpilot/memoWidget.h b/kpilot/kpilot/memoWidget.h
new file mode 100644
index 000000000..837d25cd8
--- /dev/null
+++ b/kpilot/kpilot/memoWidget.h
@@ -0,0 +1,112 @@
+#ifndef _KPILOT_MEMOWIDGET_H
+#define _KPILOT_MEMOWIDGET_H
+/* memoWidget.h KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+**
+** This is the memo viewer widget.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "pilotComponent.h"
+
+class KPilotInstaller;
+class QListBox;
+class QComboBox;
+class QPushButton;
+class KTextEdit;
+
+class PilotMemo;
+class PilotListItem;
+
+class MemoWidget : public PilotComponent
+{
+Q_OBJECT
+
+public:
+ MemoWidget(QWidget* parent, const QString& dbpath);
+ virtual ~MemoWidget();
+
+ // Pilot Component Methods:
+ /* virtual */ void showComponent();
+ /* virtual */ void hideComponent();
+ /* virtual */ bool preHotSync(QString &);
+ /* virtual */ void postHotSync();
+
+ // Added by David Bishop, please move to correct location!
+ bool saveAsXML(const QString &fileName,const QPtrList<PilotListItem> &menu_item );
+ bool saveAsText(const QString &fileName,const QPtrList<PilotListItem> &menu_item );
+
+ typedef enum {
+ MAX_MEMO_LEN = 8192
+ } Constants ;
+
+protected:
+ void initializeCategories(PilotDatabase *);
+ void initializeMemos(PilotDatabase *);
+
+ void saveChangedMemo();
+
+ bool addMemo(const QString &text, int category);
+
+public slots:
+ /**
+ * Called whenever the selected memo changes in order to:
+ * - display it if necessary
+ * - update which buttons are active, to prevent the delete
+ * button from being active when it can't do anything.
+ *
+ */
+ void slotShowMemo(int);
+ void slotUpdateButtons();
+
+ void slotImportMemo();
+ void slotExportMemo();
+ void slotDeleteMemo();
+ void slotAddMemo();
+ void slotSetCategory(int);
+
+protected:
+ void showMemo(const PilotMemo *);
+
+
+private:
+ void setupWidget();
+ void updateWidget(); // Called with the lists have changed..
+ void writeMemo(PilotMemo* which);
+
+ class Private;
+
+ QComboBox* fCatList;
+
+ KTextEdit* fTextWidget;
+ Private *d;
+ QListBox* fListBox;
+
+ QPushButton *fExportButton,*fDeleteButton;
+
+ int lastSelectedMemo;
+};
+
+
+#endif
diff --git a/kpilot/kpilot/pilot-addresses.c b/kpilot/kpilot/pilot-addresses.c
new file mode 100644
index 000000000..823a6825a
--- /dev/null
+++ b/kpilot/kpilot/pilot-addresses.c
@@ -0,0 +1,362 @@
+/*
+ * pilot-addresses.c: Palm address transfer utility
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "pi-socket.h"
+#include "pi-dlp.h"
+#include "pi-address.h"
+#include "pi-header.h"
+
+/* These are indexes in the tabledelims array */
+enum terminators { term_newline=0,
+ term_comma=1,
+ term_semi=2,
+ term_tab=3 } ;
+terminators tabledelim = term_comma;
+char tabledelims[4] = { '\n', ',', ';', '\t' };
+
+
+
+int realentry[21] =
+ { 0, 1, 13, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20 };
+
+const char *tableheads[21] = {
+ "Last name", /* 0 */
+ "First name", /* 1 */
+ "Title", /* 2 (real entry 13)*/
+ "Company", /* 3 */
+ "Phone1", /* 4 */
+ "Phone2", /* 5 */
+ "Phone3", /* 6 */
+ "Phone4", /* 7 */
+ "Phone5", /* 8 */
+ "Address", /* 9 */
+ "City", /* 10 */
+ "State", /* 11 */
+ "Zip Code", /* 12 */
+ "Country", /* 13 */
+ "Custom 1", /* 14 */
+ "Custom 2", /* 15 */
+ "Custom 3", /* 16 */
+ "Custom 4", /* 17 */
+ "Note", /* 18 */
+ "Private", /* 19 */
+ "Category" /* 20 */
+};
+
+int
+ augment = 0,
+ defaultcategory = 0;
+
+
+
+/***********************************************************************
+ *
+ * Function: inchar
+ *
+ * Summary: Turn the protected name back into the "original"
+ * characters
+ *
+ * Parameters:
+ *
+ * Returns: Modified character, 'c'
+ *
+ ***********************************************************************/
+int inchar(FILE * in)
+{
+ int c; /* switch */
+
+ c = getc(in);
+ if (c == '\\') {
+ c = getc(in);
+ switch (c) {
+ case 'b':
+ c = '\b';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 'v':
+ c = '\v';
+ break;
+ case '\\':
+ c = '\\';
+ break;
+ default:
+ ungetc(c, in);
+ c = '\\';
+ break;
+ }
+ }
+ return c;
+}
+
+
+/***********************************************************************
+ *
+ * Function: read_field
+ *
+ * Summary: Reach each field of the CSV during read_file
+ *
+ * Parameters: dest <-> Buffer for storing field contents
+ * in --> Inbound filehandle
+ * length --> Size of buffer
+ *
+ * Returns: 0 for end of line
+ * 1 for , termination
+ * 2 for ; termination
+ * 3 for \t termination
+ * -1 on end of file
+ *
+ * Note that these correspond to indexes in the tabledelims
+ * array, and should be preserved.
+ *
+ ***********************************************************************/
+int read_field(char *dest, FILE *in, size_t length)
+{
+ int c;
+
+ if (length<=1) return -1;
+ /* reserve space for trailing NUL */
+ length--;
+
+ do { /* Absorb whitespace */
+ c = getc(in);
+ if(c == '\n') {
+ *dest = 0;
+ return term_newline;
+ }
+
+ } while ((c != EOF) && ((c == ' ') || (c == '\t') || (c == '\r')));
+
+ if (c == '"') {
+ c = inchar(in);
+
+ while (c != EOF) {
+ if (c == '"') {
+ c = inchar(in);
+ if (c != '"')
+ break;
+ }
+ *dest++ = c;
+ if (!(--length))
+ break;
+ c = inchar(in);
+ }
+ } else {
+ while (c != EOF) {
+ if ((c == '\n') || (c == tabledelims[tabledelim])) {
+ break;
+ }
+ *dest++ = c;
+ if (!(--length))
+ break;
+ c = inchar(in);
+ }
+ }
+ *dest++ = '\0';
+
+ /* Absorb whitespace */
+ while ((c != EOF) && ((c == ' ') || (c == '\t')))
+ c = getc(in);
+
+ if (c == ',')
+ return term_comma;
+
+ else if (c == ';')
+ return term_semi;
+
+ else if (c == '\t')
+ return term_tab;
+
+ else if (c == EOF)
+ return -1; /* No more */
+ else
+ return term_newline;
+}
+
+
+/***********************************************************************
+ *
+ * Function: outchar
+ *
+ * Summary: Protect each of the 'illegal' characters in the output
+ *
+ * Parameters: filehandle
+ *
+ * Returns: Nothing
+ *
+ ***********************************************************************/
+void outchar(char c, FILE * out)
+{
+ switch (c) {
+ case '"':
+ putc('"', out);
+ putc('"', out);
+ break;
+ case '\b':
+ putc('\\', out);
+ putc('b', out);
+ break;
+ case '\f':
+ putc('\\', out);
+ putc('f', out);
+ break;
+ case '\n':
+ putc('\\', out);
+ putc('n', out);
+ break;
+ case '\t':
+ putc('\\', out);
+ putc('t', out);
+ break;
+ case '\r':
+ putc('\\', out);
+ putc('r', out);
+ break;
+ case '\v':
+ putc('\\', out);
+ putc('v', out);
+ break;
+ case '\\':
+ putc('\\', out);
+ putc('\\', out);
+ break;
+ default:
+ putc(c, out);
+ break;
+ }
+}
+
+
+/***********************************************************************
+ *
+ * Function: write_field
+ *
+ * Summary: Write out each field in the CSV
+ *
+ * Parameters: out --> output file handle
+ * source --> NUL-terminated data to output
+ * more --> delimiter number
+ *
+ * Returns:
+ *
+ ***********************************************************************/
+int write_field(FILE * out, const char *source, enum terminators more)
+{
+ putc('"', out);
+
+ while (*source) {
+ outchar(*source, out);
+ source++;
+ }
+ putc('"', out);
+
+ putc(tabledelims[more], out);
+ return 0;
+}
+
+
+
+
+/***********************************************************************
+ *
+ * Function: match_phone
+ *
+ * Summary: Find and match the 'phone' entries in 'buf'
+ *
+ * Parameters:
+ *
+ * Returns:
+ *
+ ***********************************************************************/
+int match_phone(char *buf, struct AddressAppInfo *aai)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ if (strncasecmp(buf, aai->phoneLabels[i], sizeof(aai->phoneLabels[0])) == 0)
+ return i;
+ return atoi(buf); /* 0 is default */
+}
+
+
+
+/***********************************************************************
+ *
+ * Function: write_file
+ *
+ * Summary: Writes Address records in CSV format to <file>
+ *
+ * Parameters: filehandle
+ *
+ * Returns: 0
+ *
+ ***********************************************************************/
+
+void write_record_CSV(FILE *out, const struct AddressAppInfo *aai, const struct Address *addr, const int attribute, const int category, const int augment)
+{
+ int j;
+ char buffer[16];
+
+ if (augment && (category || addr->showPhone)) {
+ write_field(out,
+ aai->category.name[category],
+ term_semi);
+ write_field(out,
+ aai->phoneLabels[addr->phoneLabel[addr->showPhone]],
+ term_semi);
+ }
+
+ for (j = 0; j < 19; j++) {
+ if (addr->entry[realentry[j]]) {
+ if (augment && (j >= 4) && (j <= 8)) {
+ write_field(out,
+ aai->phoneLabels[addr->phoneLabel
+ [j - 4]], term_semi);
+ }
+ write_field(out, addr->entry[realentry[j]],
+ tabledelim);
+ } else {
+ write_field(out, "", tabledelim);
+ }
+ }
+
+ snprintf(buffer, sizeof(buffer), "%d", (attribute & dlpRecAttrSecret) ? 1 : 0);
+ write_field(out, buffer, tabledelim);
+
+ write_field(out,
+ aai->category.name[category],
+ term_newline);
+}
diff --git a/kpilot/kpilot/pilotComponent.cc b/kpilot/kpilot/pilotComponent.cc
new file mode 100644
index 000000000..414db70e9
--- /dev/null
+++ b/kpilot/kpilot/pilotComponent.cc
@@ -0,0 +1,190 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines a base class for components -- internal conduits --
+** in KPilot. This includes a number of general utility functions.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "options.h"
+
+#include <time.h>
+
+#include <pi-appinfo.h>
+
+#include <qwidget.h>
+#include <qcombobox.h>
+
+#include <kdebug.h>
+
+#include "kpilotConfig.h"
+#include "pilotRecord.h"
+#include "pilot.h"
+
+#include "pilotComponent.moc"
+
+PilotComponent::PilotComponent(QWidget * parent,
+ const char *id,
+ const QString & path) :
+ QWidget(parent, id),
+ fDBPath(path),
+ shown(false)
+{
+ FUNCTIONSETUP;
+
+ if (parent)
+ {
+ resize(parent->geometry().width(),
+ parent->geometry().height());
+ }
+
+}
+
+
+
+int PilotComponent::findSelectedCategory(QComboBox * fCatList,
+ struct CategoryAppInfo *info, bool AllIsUnfiled)
+{
+ FUNCTIONSETUP;
+
+ // Semantics of currentCatID are:
+ //
+ // >=0 is a specific category based on the text ->
+ // category number mapping defined by the Pilot,
+ // ==-1 means "All" category selected when
+ // AllIsUnfiled is true.
+ // == 0 == Unfiled means "All" category selected when
+ // AllIsUnfiled is false.
+ //
+ //
+ int currentCatID = 0;
+
+ // If a category is deleted after others have been added, none of the
+ // category numbers are changed. So we need to find the category number
+ // for this category (this category is represented by the selected
+ // *text*).
+ //
+ //
+ // The top entry in the list is "All", so if the top item is
+ // selected we can indicate that we are using the "All" category.
+ //
+ //
+ if (fCatList->currentItem() == 0)
+ {
+ currentCatID = (-1);
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Category 'All' selected.\n";
+#endif
+ }
+ else
+ {
+ QString selectedCategory =
+ fCatList->text(fCatList->currentItem());
+ currentCatID = Pilot::findCategory(info, selectedCategory, AllIsUnfiled);
+ }
+
+ if ((currentCatID == -1) && AllIsUnfiled)
+ currentCatID = 0;
+ return currentCatID;
+}
+
+
+void PilotComponent::populateCategories(QComboBox * c,
+ struct CategoryAppInfo *info)
+{
+ FUNCTIONSETUP;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Combo box @"
+ << (long) c << " and info @" << (long) info << endl;
+#endif
+
+ c->clear();
+
+ if (!info)
+ goto CategoryAll;
+
+ // Fill up the categories list box with
+ // the categories defined by the user.
+ // These presumably are in the language
+ // the user uses, so no translation is necessary.
+ //
+ //
+ for (unsigned int i = 0; i < Pilot::CATEGORY_COUNT; i++)
+ {
+ if (info->name[i][0])
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Adding category: "
+ << info->name[i]
+ << " with ID: " << (int) info->ID[i] << endl;
+#endif
+
+ c->insertItem(Pilot::fromPilot(info->name[i]));
+ }
+ }
+
+CategoryAll:
+ c->insertItem(i18n("All"), 0);
+}
+
+
+void PilotComponent::slotShowComponent()
+{
+ FUNCTIONSETUP;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Showing component @" << (long) this << endl;
+#endif
+
+ emit showComponent(this);
+}
+
+/* virtual */ bool PilotComponent::preHotSync(QString &)
+{
+ FUNCTIONSETUP;
+
+ return true;
+}
+
+void PilotComponent::markDBDirty(const QString db)
+{
+ FUNCTIONSETUP;
+ KPilotConfig::addDirtyDatabase(db);
+ KPilotConfig::sync();
+}
+
+void PilotComponent::showKPilotComponent( bool toShow )
+{
+ if ( toShow != shown )
+ {
+ shown = toShow;
+ if (shown) showComponent();
+ else hideComponent();
+ }
+}
diff --git a/kpilot/kpilot/pilotComponent.h b/kpilot/kpilot/pilotComponent.h
new file mode 100644
index 000000000..f96093a2b
--- /dev/null
+++ b/kpilot/kpilot/pilotComponent.h
@@ -0,0 +1,141 @@
+#ifndef _KPILOT_PILOTCOMPONENT_H
+#define _KPILOT_PILOTCOMPONENT_H
+/* pilotComponent.h KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** See the .cc file for an explanation of what this file is for.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+/**
+ * Base class for any module to KPilot
+ */
+#include <qwidget.h>
+
+struct CategoryAppInfo;
+class QComboBox;
+class QString;
+
+class PilotComponent : public QWidget
+{
+Q_OBJECT
+friend class KPilotInstaller;
+
+public:
+ PilotComponent(QWidget* parent,
+ const char *id,
+ const QString& dbPath);
+
+ /**
+ * Called when the component is shown in kpilot. It should
+ * load the database and populate the widgets.
+ */
+ virtual void showComponent() {}
+ /**
+ * Called when the component is hidden in kpilot. It should
+ * unload the databases and clean up to save memory. This method
+ * can be called even if the component is not visible.
+ * If there are some editing dlgs open, this needs to be deferred
+ * until they are all closed. Then, one can explicitly call hideComponent().
+ */
+ virtual void hideComponent() {}
+
+ /**
+ * Set the shown variable to true or false, then call showComponent
+ * or hideComponent.
+ */
+ void showKPilotComponent( bool toShow );
+
+
+ /**
+ * Get ready for a hotsync -- write any unflushed records
+ * to disk, close windows, whatever. Returns false if it
+ * is impossible to go into a sync now (due to open windows
+ * or strange state.).
+ *
+ * The default implementation returns true.
+ *
+ * If the function returns false, it can also put a string
+ * stating the reason why into @p s. This string will be
+ * displayed to the user:
+ * "Can't start HotSync. %1"
+ * where %1 is replaced by s.
+ */
+ virtual bool preHotSync(QString &s) ;
+
+ /**
+ * Reload data (possibly changed by the hotsync) etc. etc.
+ */
+ virtual void postHotSync() { } ;
+
+
+protected:
+ /**
+ * Look up the selected category from the combo box in the
+ * Pilot's register of categories. We need this functon because
+ * the combo box doesn't contain any reference to the category
+ * ID, and we need that ID to do anything with the Pilot.
+ *
+ * If AllIsUnfiled is true, then when the user selects the
+ * category "All" in the combo box (always the first category),
+ * Unfiled (0) is returned. Otherwise if the category "All"
+ * is selected -1 is returned. For all other categories
+ * selected, their ID is returned. If nothing is selected,
+ * behave as if "All" is selected.
+ */
+ int findSelectedCategory(QComboBox *,
+ CategoryAppInfo *,
+ bool AllIsUnfiled=false);
+
+ /**
+ * Populate the combo box with the categories found in
+ * the Pilot's application categories block. Erases
+ * combo box's contents first.
+ *
+ * Always includes the category "All" as the first
+ * entry in the combo box.
+ *
+ * If info is a NULL pointer, just put "All" in the combo box.
+ */
+ void populateCategories(QComboBox *,
+ CategoryAppInfo *info=0);
+
+ void setDBPath(const QString &path) { fDBPath = path; } ;
+ const QString& dbPath() const { return fDBPath; } ;
+ void markDBDirty(const QString db);
+
+public slots:
+ void slotShowComponent();
+
+signals:
+ void showComponent(PilotComponent *);
+
+private:
+ QString fDBPath;
+protected:
+ bool shown;
+} ;
+
+#endif
diff --git a/kpilot/kpilot/pilotDaemon.cc b/kpilot/kpilot/pilotDaemon.cc
new file mode 100644
index 000000000..6eea2f7e8
--- /dev/null
+++ b/kpilot/kpilot/pilotDaemon.cc
@@ -0,0 +1,1404 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2001-2004 by Adriaan de Groot
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This is the KPilot Daemon, which does the actual communication with
+** the Pilot and with the conduits.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <stdlib.h>
+
+#include <qtimer.h>
+#include <qtooltip.h>
+#include <qpixmap.h>
+
+#include <kuniqueapplication.h>
+#include <kaboutapplication.h>
+#include <kcmdlineargs.h>
+#include <kwin.h>
+#include <kurl.h>
+#include <kpopupmenu.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <kprocess.h>
+#include <dcopclient.h>
+#include <kurldrag.h>
+#include <kservice.h>
+#include <kapplication.h>
+#include <khelpmenu.h>
+
+#include "pilotRecord.h"
+
+#include "fileInstaller.h"
+#include "pilotUser.h"
+#include "pilotDatabase.h"
+#include "kpilotlink.h"
+#include "kpilotdevicelink.h"
+#include "actionQueue.h"
+#include "actions.h"
+
+#include "hotSync.h"
+#include "internalEditorAction.h"
+#include "logFile.h"
+
+#include "kpilotConfig.h"
+
+
+#include "kpilotDCOP_stub.h"
+#include "kpilotDCOP.h"
+#include "loggerDCOP_stub.h"
+
+#include "pilotDaemon.moc"
+
+static KAboutData *aboutData = 0L;
+
+PilotDaemonTray::PilotDaemonTray(PilotDaemon * p) :
+ KSystemTray(0, "pilotDaemon"),
+ fSyncTypeMenu(0L),
+ daemon(p),
+ kap(0L),
+ fBlinkTimer(0L)
+{
+ FUNCTIONSETUP;
+ setupWidget();
+ setAcceptDrops(true);
+}
+
+/* virtual */ void PilotDaemonTray::dragEnterEvent(QDragEnterEvent * e)
+{
+ FUNCTIONSETUP;
+ e->accept(KURLDrag::canDecode(e));
+}
+
+/* virtual */ void PilotDaemonTray::dropEvent(QDropEvent * e)
+{
+ FUNCTIONSETUP;
+
+ KURL::List list;
+
+ KURLDrag::decode(e, list);
+
+ QStringList files;
+ for(KURL::List::ConstIterator it = list.begin(); it != list.end(); ++it)
+ {
+ if ((*it).isLocalFile())
+ files << (*it).path();
+ }
+
+ daemon->addInstallFiles(files);
+}
+
+/* virtual */ void PilotDaemonTray::mousePressEvent(QMouseEvent * e)
+{
+ FUNCTIONSETUP;
+
+ switch (e->button())
+ {
+ case RightButton:
+ {
+ KPopupMenu *menu = contextMenu();
+ contextMenuAboutToShow(menu);
+ menu->popup(e->globalPos());
+ }
+ break;
+ case LeftButton:
+ if (daemon) daemon->slotRunKPilot();
+ break;
+ default:
+ KSystemTray::mousePressEvent(e);
+ }
+}
+
+/* virtual */ void PilotDaemonTray::closeEvent(QCloseEvent *)
+{
+ FUNCTIONSETUP;
+ daemon->quitNow();
+}
+
+void PilotDaemonTray::setupWidget()
+{
+ FUNCTIONSETUP;
+
+ KGlobal::iconLoader()->addAppDir( CSL1("kpilot") );
+ icons[Normal] = loadIcon( CSL1("kpilotDaemon") );
+ icons[Busy] = loadIcon( CSL1("busysync") );
+ icons[NotListening] = loadIcon( CSL1("nosync") );
+
+ slotShowNotListening();
+ QTimer::singleShot(2000,this,SLOT(slotShowNormal()));
+
+ KPopupMenu *menu = contextMenu();
+
+ menuKPilotItem = menu->insertItem(i18n("Start &KPilot"), daemon,
+ SLOT(slotRunKPilot()));
+ menuConfigureConduitsItem = menu->insertItem(i18n("&Configure KPilot..."),
+ daemon, SLOT(slotRunConfig()));
+ menu->insertSeparator();
+
+ fSyncTypeMenu = new KPopupMenu(menu,"sync_type_menu");
+ QString once = i18n("Appended to names of sync types to indicate the sync will happen just one time"," (once)");
+#define MI(a) fSyncTypeMenu->insertItem( \
+ SyncAction::SyncMode::name(SyncAction::SyncMode::a) + once, \
+ (int)(SyncAction::SyncMode::a));
+ fSyncTypeMenu->insertItem(i18n("Default (%1)")
+ .arg(SyncAction::SyncMode::name((SyncAction::SyncMode::Mode)KPilotSettings::syncType())),
+ 0);
+ fSyncTypeMenu->insertSeparator();
+
+ // Keep this synchronized with kpilotui.rc and kpilot.cc if at all possible.
+ MI(eHotSync);
+ MI(eFullSync);
+ MI(eBackup);
+ MI(eRestore);
+ MI(eCopyHHToPC);
+ MI(eCopyPCToHH);
+
+ fSyncTypeMenu->setCheckable(true);
+ fSyncTypeMenu->setItemChecked(0,true);
+#undef MI
+ connect(fSyncTypeMenu,SIGNAL(activated(int)),daemon,SLOT(requestSync(int)));
+ menu->insertItem(i18n("Next &Sync"),fSyncTypeMenu);
+
+ KHelpMenu *help = new KHelpMenu(menu,aboutData);
+ menu->insertItem(
+ KGlobal::iconLoader()->loadIconSet(CSL1("help"),KIcon::Small,0,true),
+ i18n("&Help"),help->menu(),false /* no whatsthis */);
+
+
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Finished getting icons" << endl;
+#endif
+}
+
+void PilotDaemonTray::slotShowAbout()
+{
+ FUNCTIONSETUP;
+
+ if (!kap)
+ {
+ kap = new KAboutApplication(0, "kpdab", false);
+ }
+
+ kap->show();
+}
+
+
+void PilotDaemonTray::enableRunKPilot(bool b)
+{
+ FUNCTIONSETUP;
+ contextMenu()->setItemEnabled(menuKPilotItem, b);
+ contextMenu()->setItemEnabled(menuConfigureConduitsItem, b);
+}
+
+
+void PilotDaemonTray::changeIcon(IconShape i)
+{
+ FUNCTIONSETUP;
+ if (icons[i].isNull())
+ {
+ WARNINGKPILOT << "Icon #"<<i<<" is NULL!" << endl;
+ }
+ setPixmap(icons[i]);
+ fCurrentIcon = i;
+}
+
+void PilotDaemonTray::slotShowNormal()
+{
+ FUNCTIONSETUP;
+ changeIcon(Normal);
+}
+
+void PilotDaemonTray::slotShowBusy()
+{
+ FUNCTIONSETUP;
+ changeIcon(Busy);
+}
+
+void PilotDaemonTray::slotShowNotListening()
+{
+ FUNCTIONSETUP;
+ changeIcon( NotListening );
+}
+
+void PilotDaemonTray::slotBusyTimer()
+{
+ if (fCurrentIcon == Busy) changeIcon(Normal);
+ else if (fCurrentIcon == Normal) changeIcon(Busy);
+}
+
+void PilotDaemonTray::startHotSync()
+{
+ changeIcon(Busy);
+ if (!fBlinkTimer)
+ {
+ fBlinkTimer = new QTimer(this,"blink timer");
+ }
+ if (fBlinkTimer)
+ {
+ connect(fBlinkTimer,SIGNAL(timeout()),
+ this,SLOT(slotBusyTimer()));
+ fBlinkTimer->start(750,false);
+ }
+}
+
+void PilotDaemonTray::endHotSync()
+{
+ changeIcon(Normal);
+ if (fBlinkTimer)
+ {
+ fBlinkTimer->stop();
+ }
+}
+
+
+PilotDaemon::PilotDaemon() :
+ DCOPObject("KPilotDaemonIface"),
+ fDaemonStatus(INIT),
+ fPostSyncAction(None),
+ fPilotLink(0L),
+ fNextSyncType(SyncAction::SyncMode::eHotSync,true),
+ fSyncStack(0L),
+ fTray(0L),
+ fInstaller(0L),
+ fLogFile(0L),
+ fLogStub(new LoggerDCOP_stub("kpilot", "LogIface")),
+ fLogFileStub(new LoggerDCOP_stub("kpilotDaemon", "LogIface")),
+ fKPilotStub(new KPilotDCOP_stub("kpilot", "KPilotIface")),
+ fTempDevice(QString::null)
+{
+ FUNCTIONSETUP;
+
+ setupPilotLink();
+ reloadSettings();
+
+ if (fDaemonStatus == ERROR)
+ {
+ WARNINGKPILOT << "Connecting to device failed." << endl;
+ return;
+ }
+
+ fInstaller = new FileInstaller;
+ fLogFile = new LogFile;
+ connect(fInstaller, SIGNAL(filesChanged()),
+ this, SLOT(slotFilesChanged()));
+
+ fNextSyncType.setMode( KPilotSettings::syncType() );
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": The daemon is ready with status "
+ << statusString() << " (" << (int) fDaemonStatus << ")" << endl;
+#endif
+}
+
+PilotDaemon::~PilotDaemon()
+{
+ FUNCTIONSETUP;
+
+ KPILOT_DELETE(fPilotLink);
+ KPILOT_DELETE(fSyncStack);
+ KPILOT_DELETE(fInstaller);
+
+ (void) PilotDatabase::instanceCount();
+}
+
+void PilotDaemon::addInstallFiles(const QStringList &l)
+{
+ FUNCTIONSETUP;
+
+ fInstaller->addFiles( l, fTray );
+}
+
+int PilotDaemon::getPilotSpeed()
+{
+ FUNCTIONSETUP;
+
+ int speed = KPilotSettings::pilotSpeed();
+
+ // Translate the speed entry in the
+ // config file to something we can
+ // put in the environment (for who?)
+ //
+ //
+ const char *speedname = 0L;
+
+ switch (speed)
+ {
+ case 0:
+ speedname = "PILOTRATE=9600";
+ break;
+ case 1:
+ speedname = "PILOTRATE=19200";
+ break;
+ case 2:
+ speedname = "PILOTRATE=38400";
+ break;
+ case 3:
+ speedname = "PILOTRATE=57600";
+ break;
+ case 4:
+ speedname = "PILOTRATE=115200";
+ break;
+ default:
+ speedname = "PILOTRATE=9600";
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Speed set to "
+ << speedname << " (" << speed << ")" << endl;
+#endif
+
+ putenv((char *) speedname);
+
+ return speed;
+}
+
+
+void PilotDaemon::showTray()
+{
+ FUNCTIONSETUP;
+
+ if (!fTray)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": No tray icon to display!" << endl;
+#endif
+
+ return;
+ }
+
+ // Copied from Klipper
+ KWin::setSystemTrayWindowFor(fTray->winId(), 0);
+ fTray->setGeometry(-100, -100, 42, 42);
+ fTray->show();
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Tray icon displayed." << endl;
+#endif
+
+ updateTrayStatus();
+}
+
+/* DCOP ASYNC */ void PilotDaemon::setTempDevice(QString d)
+{
+ if ( !d.isEmpty() ){
+ fTempDevice = d;
+ if (fPilotLink)
+ fPilotLink->setTempDevice( fTempDevice );
+ reloadSettings();
+ }
+}
+
+/* DCOP ASYNC */ void PilotDaemon::reloadSettings()
+{
+ FUNCTIONSETUP;
+
+ switch (fDaemonStatus)
+ {
+ case INIT:
+ case HOTSYNC_END:
+ case ERROR:
+ case READY:
+ case NOT_LISTENING:
+ // It's OK to reload settings in these states.
+ break;
+ case HOTSYNC_START:
+ case FILE_INSTALL_REQ:
+ // Postpone the reload till the sync finishes.
+ fPostSyncAction |= ReloadSettings;
+ return;
+ break;
+ }
+
+ // TODO: Is this bunch of calls really necessary to reload the settings???
+ delete KPilotSettings::self();
+ KPilotSettings::self()->config()->reparseConfiguration();
+ KPilotSettings::self()->readConfig();
+ getPilotSpeed();
+
+ (void) Pilot::setupPilotCodec(KPilotSettings::encoding());
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Got configuration "
+ << KPilotSettings::pilotDevice()
+ << endl;
+ DEBUGKPILOT << fname
+ << ": Got conduit list "
+ << (KPilotSettings::installedConduits().join(CSL1(",")))
+ << endl;
+#endif
+
+ requestSync(0);
+
+
+ if (fPilotLink)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Resetting with device "
+ << KPilotSettings::pilotDevice()
+ << endl;
+#endif
+
+ fPilotLink->reset( KPilotSettings::pilotDevice() );
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Using workarounds "
+ << KPilotSettings::workarounds()
+ << endl;
+#endif
+ if ( KPilotSettings::workarounds() == KPilotSettings::eWorkaroundUSB )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Using Zire31 USB workaround." << endl;
+#endif
+ fPilotLink->setWorkarounds(true);
+ }
+ }
+
+ if (KPilotSettings::dockDaemon())
+ {
+ if (!fTray)
+ {
+ fTray = new PilotDaemonTray(this);
+ fTray->show();
+ }
+ else
+ {
+ fTray->show();
+ }
+ }
+ else
+ {
+ if (fTray)
+ {
+ fTray->hide();
+ delete fTray;
+
+ fTray = 0L;
+ }
+ }
+
+ updateTrayStatus();
+ logProgress(QString::null,0);
+}
+
+/* DCOP */ void PilotDaemon::stopListening()
+{
+ fIsListening=false;
+ fTray->changeIcon(PilotDaemonTray::NotListening);
+ fDaemonStatus=NOT_LISTENING;
+ fPilotLink->close();
+}
+
+/* DCOP */ void PilotDaemon::startListening()
+{
+ fIsListening=true;
+ fTray->changeIcon(PilotDaemonTray::Normal);
+ fDaemonStatus=INIT;
+ fPilotLink->reset();
+}
+
+/* DCOP */ QString PilotDaemon::statusString()
+{
+ FUNCTIONSETUP;
+
+ QString s = CSL1("PilotDaemon=");
+ s.append(shortStatusString());
+
+ s.append(CSL1("; NextSync="));
+ s.append(fNextSyncType.name());
+
+ s.append(CSL1(" ("));
+ if (fPilotLink)
+ {
+ s.append(fPilotLink->statusString());
+ }
+ s.append(CSL1(");"));
+
+ return s;
+}
+
+/* DCOP */ QString PilotDaemon::shortStatusString()
+{
+ QString s;
+
+ switch (status())
+ {
+ case INIT:
+ s.append(CSL1("Waiting for sync"));
+ break;
+ case READY:
+ s.append(CSL1("Listening on device"));
+ break;
+ case ERROR:
+ s=CSL1("Error");
+ break;
+ case FILE_INSTALL_REQ:
+ s=CSL1("Installing File");
+ break;
+ case HOTSYNC_END:
+ s=CSL1("End of Hotsync");
+ break;
+ case HOTSYNC_START:
+ s=CSL1("Syncing");
+ break;
+ case NOT_LISTENING:
+ s.append(CSL1("Not Listening (stopped manually)"));
+ break;
+ }
+
+ return s;
+}
+
+
+
+bool PilotDaemon::setupPilotLink()
+{
+ FUNCTIONSETUP;
+
+ KPILOT_DELETE(fPilotLink);
+ fPilotLink = new KPilotDeviceLink( 0, 0, fTempDevice );
+ if (!fPilotLink)
+ {
+ WARNINGKPILOT << "Can't get pilot link." << endl;
+ return false;
+ }
+
+ QObject::connect(fPilotLink, SIGNAL(deviceReady(KPilotLink*)),
+ this, SLOT(startHotSync(KPilotLink*)));
+ // connect the signals emitted by the pilotDeviceLink
+ QObject::connect(fPilotLink, SIGNAL(logError(const QString &)),
+ this, SLOT(logError(const QString &)));
+ QObject::connect(fPilotLink, SIGNAL(logMessage(const QString &)),
+ this, SLOT(logMessage(const QString &)));
+ QObject::connect(fPilotLink,
+ SIGNAL(logProgress(const QString &,int)),
+ this, SLOT(logProgress(const QString &,int)));
+
+
+ return true;
+}
+
+
+/* DCOP ASYNC */ void PilotDaemon::quitNow()
+{
+ FUNCTIONSETUP;
+ // Using switch to make sure we cover all the cases.
+ //
+ //
+ switch (fDaemonStatus)
+ {
+ case INIT:
+ case HOTSYNC_END:
+ case ERROR:
+ case NOT_LISTENING:
+ getKPilot().daemonStatus(KPilotDCOP::DaemonQuit);
+ kapp->quit();
+ break;
+ case READY:
+ case HOTSYNC_START:
+ case FILE_INSTALL_REQ:
+ fPostSyncAction |= Quit;
+ break;
+ }
+ emitDCOPSignal( "kpilotDaemonStatusChanged()", QByteArray() );
+}
+
+/* DCOP ASYNC */ void PilotDaemon::requestRegularSyncNext()
+{
+ requestSync(SyncAction::SyncMode::eHotSync);
+}
+
+
+/* DCOP ASYNC */ void PilotDaemon::requestSync(int mode)
+{
+ FUNCTIONSETUP;
+
+ if ( 0==mode )
+ {
+ mode = KPilotSettings::syncType();
+ }
+
+ if ( !fNextSyncType.setMode(mode) )
+ {
+ WARNINGKPILOT << "Ignored fake sync type " << mode << endl;
+ return;
+ }
+
+ updateTrayStatus();
+
+ if (fTray && (fTray->fSyncTypeMenu))
+ {
+ for (int i=((int)SyncAction::SyncMode::eHotSync);
+ i<=((int)SyncAction::SyncMode::eRestore) /* Restore */ ;
+ ++i)
+ {
+ fTray->fSyncTypeMenu->setItemChecked(i,mode==i);
+ }
+ }
+
+ getLogger().logMessage(i18n("Next HotSync will be: %1. ").arg(fNextSyncType.name()) +
+ i18n("Please press the HotSync button."));
+}
+
+/* DCOP ASYNC */ void PilotDaemon::requestSyncType(QString s)
+{
+ FUNCTIONSETUP;
+
+ // This checks unique prefixes of the names of the various sync types.
+ if (s.startsWith(CSL1("H"))) requestSync(SyncAction::SyncMode::eHotSync);
+ else if (s.startsWith(CSL1("Fu"))) requestSync(SyncAction::SyncMode::eFullSync);
+ else if (s.startsWith(CSL1("B"))) requestSync(SyncAction::SyncMode::eBackup);
+ else if (s.startsWith(CSL1("R"))) requestSync(SyncAction::SyncMode::eRestore);
+ else if (s.startsWith(CSL1("T"))) { fNextSyncType.setOptions(true,false); }
+ else if (s.startsWith(CSL1("CopyHHToPC"))) requestSync(SyncAction::SyncMode::eCopyHHToPC);
+ else if (s.startsWith(CSL1("CopyPCToHH"))) requestSync(SyncAction::SyncMode::eCopyPCToHH);
+ else if (s.startsWith(CSL1("D"))) requestSync(0);
+ else
+ {
+ WARNINGKPILOT << "Unknown sync type " << ( s.isEmpty() ? CSL1("<none>") : s )
+ << endl;
+ }
+}
+
+/* DCOP ASYNC */ void PilotDaemon::requestSyncOptions(bool test, bool local)
+{
+ if ( !fNextSyncType.setOptions(test,local) )
+ {
+ WARNINGKPILOT << "Nonsensical request for "
+ << (test ? "test" : "notest")
+ << ' '
+ << (local ? "local" : "nolocal")
+ << " in mode "
+ << fNextSyncType.name() << endl;
+ }
+}
+
+/* DCOP */ int PilotDaemon::nextSyncType() const
+{
+ return fNextSyncType.mode();
+}
+
+/**
+* DCOP Functions reporting some status data, e.g. for the kontact plugin.
+*/
+QDateTime PilotDaemon::lastSyncDate()
+{
+ return KPilotSettings::lastSyncTime();
+}
+
+
+static QDict<QString> *conduitNameMap = 0L;
+
+static void fillConduitNameMap()
+{
+ if ( !conduitNameMap )
+ {
+ conduitNameMap = new QDict<QString>;
+ conduitNameMap->setAutoDelete(true);
+ }
+ conduitNameMap->clear();
+
+ QStringList l = KPilotSettings::installedConduits();
+ // Fill with internal settings.
+ if ( l.find( CSL1("internal_fileinstall") ) != l.end() ) {
+ conduitNameMap->insert( CSL1("internal_fileinstall"),
+ new QString(i18n("File Installer")) );
+ }
+
+ QStringList::ConstIterator end = l.end();
+ for (QStringList::ConstIterator i = l.begin(); i != end; ++i)
+ {
+ if (!conduitNameMap->find(*i))
+ {
+ QString readableName = CSL1("<unknown>");
+ KSharedPtr < KService > o = KService::serviceByDesktopName(*i);
+ if (!o)
+ {
+ WARNINGKPILOT << "No service for " << *i << endl;
+ }
+ else
+ {
+ readableName = o->name();
+ }
+ conduitNameMap->insert( *i, new QString(readableName) );
+ }
+ }
+}
+
+
+QStringList PilotDaemon::configuredConduitList()
+{
+ fillConduitNameMap();
+
+ QStringList keys;
+
+ QDictIterator<QString> it(*conduitNameMap);
+ for ( ; *it; ++it)
+ {
+ keys << it.currentKey();
+ }
+ keys.sort();
+
+ QStringList::ConstIterator end = keys.end();
+ QStringList result;
+ for (QStringList::ConstIterator i = keys.begin(); i != end; ++i)
+ {
+ result << *(conduitNameMap->find(*i));
+ }
+
+ return result;
+}
+
+QString PilotDaemon::logFileName()
+{
+ return KPilotSettings::logFileName();
+}
+
+QString PilotDaemon::userName()
+{
+ return KPilotSettings::userName();
+}
+QString PilotDaemon::pilotDevice()
+{
+ return KPilotSettings::pilotDevice();
+}
+
+bool PilotDaemon::killDaemonOnExit()
+{
+ return KPilotSettings::killDaemonAtExit();
+}
+
+typedef enum { NotLocked=0, Locked=1, DCOPError=2 } KDesktopLockStatus;
+static KDesktopLockStatus isKDesktopLockRunning()
+{
+ if (!KPilotSettings::screenlockSecure()) return NotLocked;
+
+ DCOPClient *dcopptr = KApplication::kApplication()->dcopClient();
+
+ // Can't tell, very weird, err on the side of safety.
+ if (!dcopptr || !dcopptr->isAttached())
+ {
+ WARNINGKPILOT << "Could not make DCOP connection. "
+ << "Assuming screensaver is active." << endl;
+ return DCOPError;
+ }
+
+ QByteArray data,returnValue;
+ QCString returnType;
+
+ if (!dcopptr->call("kdesktop","KScreensaverIface","isBlanked()",
+ data,returnType,returnValue,true))
+ {
+ WARNINGKPILOT << "Check for screensaver failed."
+ << "Assuming screensaver is active." << endl;
+ // Err on the side of safety again.
+ return DCOPError;
+ }
+
+ if (returnType == "bool")
+ {
+ bool b;
+ QDataStream reply(returnValue,IO_ReadOnly);
+ reply >> b;
+ return (b ? Locked : NotLocked);
+ }
+ else
+ {
+ WARNINGKPILOT << "Strange return value from screensaver. "
+ << "Assuming screensaver is active." << endl;
+ // Err on the side of safety.
+ return DCOPError;
+ }
+}
+
+
+static void informOthers(KPilotDCOP_stub &kpilot,
+ LoggerDCOP_stub &log,
+ LoggerDCOP_stub &filelog)
+{
+ kpilot.daemonStatus(KPilotDCOP::StartOfHotSync);
+ log.logStartSync();
+ filelog.logStartSync();
+}
+
+static bool isSyncPossible(ActionQueue *fSyncStack,
+ KPilotLink *pilotLink,
+ KPilotDCOP_stub &kpilot)
+{
+ FUNCTIONSETUP;
+
+ /**
+ * If KPilot is busy with something - like configuring
+ * conduit - then we shouldn't run a real sync, but
+ * just tell the user that the sync couldn't run because
+ * of that.
+ */
+ int kpilotstatus = kpilot.kpilotStatus();
+ DCOPStub::Status callstatus = kpilot.status();
+
+#ifdef DEBUG
+ if (callstatus != DCOPStub::CallSucceeded)
+ {
+ DEBUGKPILOT << fname <<
+ ": Could not call KPilot for status." << endl;
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": KPilot status " << kpilotstatus << endl;
+ }
+#endif
+ /**
+ * If the call fails, then KPilot is probably not running
+ * and we can behave normally.
+ */
+ if ((callstatus == DCOPStub::CallSucceeded) &&
+ (kpilotstatus != KPilotDCOP::WaitingForDaemon))
+ {
+ WARNINGKPILOT << "KPilot returned status " << kpilotstatus << endl;
+
+ fSyncStack->queueInit();
+ fSyncStack->addAction(new SorryAction(pilotLink));
+ return false;
+ }
+
+ switch (isKDesktopLockRunning())
+ {
+ case NotLocked :
+ break; /* Fall through to return true below */
+ case Locked :
+ fSyncStack->queueInit();
+ fSyncStack->addAction(new SorryAction(pilotLink,
+ i18n("HotSync is disabled while the screen is locked.")));
+ return false;
+ case DCOPError :
+ fSyncStack->queueInit();
+ fSyncStack->addAction(new SorryAction(pilotLink,
+ i18n("HotSync is disabled because KPilot could not "
+ "determine the state of the screen saver. You "
+ "can disable this security feature by unchecking "
+ "the 'do not sync when screensaver is active' box "
+ "in the HotSync page of the configuration dialog.")));
+ return false;
+ }
+
+ return true;
+}
+
+static void queueInstaller(ActionQueue *fSyncStack,
+ KPilotLink *pilotLink,
+ FileInstaller *fInstaller,
+ const QStringList &c)
+{
+ if (c.findIndex(CSL1("internal_fileinstall")) >= 0)
+ {
+ fSyncStack->addAction(new FileInstallAction(pilotLink,fInstaller->dir()));
+ }
+}
+
+static void queueEditors(ActionQueue *fSyncStack, KPilotLink *pilotLink)
+{
+ if (KPilotSettings::internalEditors())
+ {
+ fSyncStack->addAction(new InternalEditorAction(pilotLink));
+ }
+}
+
+static void queueConduits(ActionQueue *fSyncStack,
+ const QStringList &conduits,
+ SyncAction::SyncMode e)
+{
+ if (conduits.count() > 0)
+ {
+ fSyncStack->queueConduits(conduits,e);
+ // QString s = i18n("Conduit flags: ");
+ // s.append(ConduitProxy::flagsForMode(e).join(CSL1(" ")));
+ // logMessage(s);
+ }
+}
+
+bool PilotDaemon::shouldBackup()
+{
+
+ FUNCTIONSETUP;
+
+ bool ret = false;
+ int backupfreq = KPilotSettings::backupFrequency();
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Backup Frequency is: [" << backupfreq <<
+ "]. " << endl;
+#endif
+
+ if ( (fNextSyncType == SyncAction::SyncMode::eHotSync) ||
+ (fNextSyncType == SyncAction::SyncMode::eFullSync) )
+ {
+ /** If we're doing a Hot or Full sync, see if our user has
+ * configured us to or to not always do a backup.
+ */
+ if ( backupfreq == SyncAction::eOnRequestOnly )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Should not do backup..." << endl;
+#endif
+ ret = false;
+ }
+ else if ( backupfreq == SyncAction::eEveryHotSync )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Should do backup..." << endl;
+#endif
+ ret = true;
+ }
+ }
+
+ return ret;
+
+}
+
+
+/* slot */ void PilotDaemon::startHotSync(KPilotLink *pilotLink)
+{
+ FUNCTIONSETUP;
+
+ bool pcchanged=false; // If last PC to sync was a different one (implies full sync, normally)
+ QStringList conduits ; // list of conduits to run
+ QString s; // a generic string for stuff
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Starting Sync with type "
+ << fNextSyncType.name() << endl;
+ DEBUGKPILOT << fname << ": Status is " << shortStatusString() << endl;
+ (void) PilotDatabase::instanceCount();
+#endif
+
+ fDaemonStatus = HOTSYNC_START ;
+ if (fTray)
+ {
+ fTray->startHotSync();
+ }
+ informOthers(getKPilot(),getLogger(),getFileLogger());
+
+
+ // Queue to add all the actions for this sync to.
+ fSyncStack = new ActionQueue(pilotLink);
+
+ // Check if the sync is possible at all.
+ if (!isSyncPossible(fSyncStack,pilotLink,getKPilot()))
+ {
+ // Sync is not possible now, sorry action was added to
+ // the queue, and we run that -- skipping all the rest of the sync stuff.
+ goto launch;
+ }
+
+ // Except when the user has requested a Restore, in which case she knows she doesn't
+ // want to sync with a blank palm and then back up the result over her stored backup files,
+ // do a Full Sync when changing the PC or using a different Palm Desktop app.
+ if (fNextSyncType.mode() != SyncAction::SyncMode::eRestore)
+ { // Use gethostid to determine , since JPilot uses 1+(2000000000.0*random()/(RAND_MAX+1.0))
+ // as PC_ID, so using JPilot and KPilot is the same as using two different PCs
+ KPilotUser &usr = pilotLink->getPilotUser();
+ pcchanged = usr.getLastSyncPC() !=(unsigned long) gethostid();
+
+ if (pcchanged)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": PC changed. Last sync PC: [" << usr.getLastSyncPC()
+ << "], me: [" << (unsigned long) gethostid() << "]" << endl;
+#endif
+ if ( KPilotSettings::fullSyncOnPCChange() )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Setting sync mode to full sync. " << endl;
+#endif
+ fNextSyncType = SyncAction::SyncMode::eFullSync;
+ }
+ else
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Not changing sync mode because of settings. " << endl;
+#endif
+ }
+ }
+ }
+
+ // Normal case: regular sync.
+ fSyncStack->queueInit();
+ fSyncStack->addAction(new CheckUser(pilotLink));
+
+ conduits = KPilotSettings::installedConduits() ;
+
+ if (fNextSyncType.isTest())
+ {
+ fSyncStack->addAction(new TestLink(pilotLink));
+ }
+ else
+ {
+ switch (fNextSyncType.mode())
+ {
+ case SyncAction::SyncMode::eBackup:
+ if (KPilotSettings::runConduitsWithBackup() && (conduits.count() > 0))
+ {
+ queueConduits(fSyncStack,conduits,fNextSyncType);
+ }
+ fSyncStack->addAction(new BackupAction(pilotLink,true));
+ break;
+ case SyncAction::SyncMode::eRestore:
+ fSyncStack->addAction(new RestoreAction(pilotLink));
+ queueInstaller(fSyncStack,pilotLink,fInstaller,conduits);
+ break;
+ case SyncAction::SyncMode::eFullSync:
+ case SyncAction::SyncMode::eHotSync:
+ // first install the files, and only then do the conduits
+ // (conduits might want to sync a database that will be installed
+ queueInstaller(fSyncStack,pilotLink,fInstaller,conduits);
+ queueEditors(fSyncStack,pilotLink);
+ queueConduits(fSyncStack,conduits,fNextSyncType);
+ // After running the conduits, install new databases
+ queueInstaller(fSyncStack,pilotLink,fInstaller,conduits);
+ // And sync the remaining databases if needed.
+ if (shouldBackup())
+ {
+ fSyncStack->addAction(new BackupAction(pilotLink, (fNextSyncType == SyncAction::SyncMode::eFullSync)));
+ }
+ break;
+ case SyncAction::SyncMode::eCopyPCToHH:
+ queueConduits(fSyncStack,conduits,SyncAction::SyncMode::eCopyPCToHH);
+ break;
+ case SyncAction::SyncMode::eCopyHHToPC:
+ queueConduits(fSyncStack,conduits,SyncAction::SyncMode::eCopyHHToPC);
+ break;
+ }
+ }
+
+// Jump here to finalize the connections to the sync action
+// queue and start the actual sync.
+launch:
+ fSyncStack->queueCleanup();
+
+ QObject::connect(fSyncStack, SIGNAL(logError(const QString &)),
+ this, SLOT(logError(const QString &)));
+ QObject::connect(fSyncStack, SIGNAL(logMessage(const QString &)),
+ this, SLOT(logMessage(const QString &)));
+ QObject::connect(fSyncStack,
+ SIGNAL(logProgress(const QString &,int)),
+ this, SLOT(logProgress(const QString &,int)));
+
+ QObject::connect(fSyncStack, SIGNAL(syncDone(SyncAction *)),
+ this, SLOT(endHotSync()));
+
+ QTimer::singleShot(0,fSyncStack,SLOT(execConduit()));
+
+ updateTrayStatus();
+}
+
+/* slot */ void PilotDaemon::logMessage(const QString & s)
+{
+ FUNCTIONSETUPL(2);
+
+ getLogger().logMessage(s);
+ getFileLogger().logMessage(s);
+ updateTrayStatus(s);
+}
+
+/* slot */ void PilotDaemon::logError(const QString & s)
+{
+ FUNCTIONSETUP;
+
+ getLogger().logError(s);
+ getFileLogger().logError(s);
+ updateTrayStatus(s);
+}
+
+/* slot */ void PilotDaemon::logProgress(const QString & s, int i)
+{
+ FUNCTIONSETUPL(2);
+
+ getLogger().logProgress(s, i);
+ getFileLogger().logProgress(s, i);
+ if (!s.isEmpty()) updateTrayStatus(s);
+}
+
+/* slot */ void PilotDaemon::endHotSync()
+{
+ FUNCTIONSETUP;
+
+ if (fTray)
+ {
+ fTray->endHotSync();
+ }
+
+ KPILOT_DELETE(fSyncStack);
+ fPilotLink->close();
+
+ getLogger().logProgress(i18n("HotSync Completed.<br>"), 100);
+ getFileLogger().logProgress(i18n("HotSync Completed.<br>"), 100);
+ getLogger().logEndSync();
+ getFileLogger().logEndSync();
+ getKPilot().daemonStatus(KPilotDCOP::EndOfHotSync);
+ KPilotSettings::setLastSyncTime(QDateTime::currentDateTime());
+ KPilotSettings::self()->writeConfig();
+
+ fDaemonStatus = HOTSYNC_END;
+
+ if (fPostSyncAction & Quit)
+ {
+ getKPilot().daemonStatus(KPilotDCOP::DaemonQuit);
+ kapp->quit();
+ }
+ if (fPostSyncAction & ReloadSettings)
+ {
+ reloadSettings();
+ }
+ else
+ {
+ QTimer::singleShot(10000,fPilotLink,SLOT(reset()));
+ }
+
+ fPostSyncAction = None;
+ requestSync(0);
+
+ (void) PilotDatabase::instanceCount();
+
+ updateTrayStatus();
+}
+
+
+void PilotDaemon::slotFilesChanged()
+{
+ FUNCTIONSETUP;
+}
+
+void PilotDaemon::slotRunKPilot()
+{
+ FUNCTIONSETUP;
+
+ QString kpilotError;
+ QCString kpilotDCOP;
+ int kpilotPID;
+
+ if (KApplication::startServiceByDesktopName(CSL1("kpilot"),
+ QString::null, &kpilotError, &kpilotDCOP, &kpilotPID
+#if (KDE_VERSION >= 220)
+ // Startup notification added in 2.2
+ , ""
+#endif
+ ))
+ {
+ WARNINGKPILOT << "Couldn't start KPilot! " << kpilotError << endl;
+ }
+ else
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Started KPilot with DCOP name "
+ << kpilotDCOP << " (pid " << kpilotPID << ")" << endl;
+#endif
+ }
+}
+
+void PilotDaemon::slotRunConfig()
+{
+ FUNCTIONSETUP;
+
+ // This function tries to send the raise() DCOP call to kpilot.
+ // If it succeeds, we can assume kpilot is running and then try
+ // to send the configure() DCOP call.
+ // If it fails (probably because kpilot isn't running) it tries
+ // to call kpilot via KProcess (using a command line switch to
+ // only bring up the configure dialog).
+ //
+ // Implementing the function this way catches all cases.
+ // ie 1 KPilot running with configure dialog open (raise())
+ // 2 KPilot running with dialog NOT open (configureConduits())
+ // 3 KPilot NOT running (KProcess)
+
+ DCOPClient *client = kapp->dcopClient();
+
+ // This DCOP call to kpilot's raise function solves the final case
+ // ie when kpilot already has the dialog open
+
+ if ( client->isApplicationRegistered( "kpilot" ) )
+ {
+ client->send("kpilot", "kpilot-mainwindow#1", "raise()",QString::null);
+ client->send("kpilot", "KPilotIface", "configure()", QString::null);
+ }
+ else
+ {
+ // KPilot not running
+ KProcess *p = new KProcess;
+ *p << "kpilot" << "-s";
+
+ p->start();
+ }
+}
+
+void PilotDaemon::updateTrayStatus(const QString &s)
+{
+ if (!fTray) return;
+
+ QString tipText = CSL1("<qt>");
+ tipText.append( s );
+ tipText.append( CSL1(" ") );
+ tipText.append( i18n("Next sync is %1.")
+ .arg( fNextSyncType.name() ) );
+ tipText.append( CSL1("</qt>") );
+
+ QToolTip::remove(fTray);
+ QToolTip::add(fTray,tipText);
+ emitDCOPSignal( "kpilotDaemonStatusChanged()", QByteArray() );
+ // emit the same dcop signal but including the information needed by Kontact to update its kpilot summary widget
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << lastSyncDate();
+ arg << shortStatusString();
+ arg << configuredConduitList();
+ arg << logFileName();
+ arg << userName();
+ arg << pilotDevice();
+ arg << killDaemonOnExit();
+ emitDCOPSignal( "kpilotDaemonStatusDetails(QDateTime,QString,QStringList,QString,QString,QString,bool)", data );
+}
+
+static KCmdLineOptions daemonoptions[] = {
+#ifdef DEBUG
+ {"debug <level>", I18N_NOOP("Set debugging level"), "0"},
+#endif
+ { "device <device>", I18N_NOOP("Device to try first"), ""},
+ {"fail-silently", I18N_NOOP("Exit instead of complaining about bad configuration files"), 0},
+ KCmdLineLastOption
+} ;
+
+
+int main(int argc, char **argv)
+{
+ FUNCTIONSETUP;
+
+ KLocale::setMainCatalogue("kpilot");
+
+ KAboutData about("kpilotDaemon",
+ I18N_NOOP("KPilot Daemon"),
+ KPILOT_VERSION,
+ "KPilot - HotSync software for KDE\n\n",
+ KAboutData::License_GPL,
+ "(c) 1998-2000,2001, Dan Pilone (c) 2000-2004, Adriaan de Groot",
+ 0L,
+ "http://www.kpilot.org/"
+ );
+ about.addAuthor("Dan Pilone",
+ I18N_NOOP("Project Leader"),
+ about.addAuthor("Adriaan de Groot",
+ I18N_NOOP("Maintainer"),
+ "[email protected]", "http://www.kpilot.org/");
+ about.addAuthor("Reinhold Kainhofer",
+ I18N_NOOP("Developer"),
+ "[email protected]", "http://reinhold.kainhofer.com/Linux/");
+ aboutData = &about;
+
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions(daemonoptions,"kpilotconfig");
+ KUniqueApplication::addCmdLineOptions();
+ KCmdLineArgs *p = KCmdLineArgs::parsedArgs();
+
+#ifdef DEBUG
+ KPilotConfig::getDebugLevel(p);
+#endif
+ if (!KUniqueApplication::start())
+ {
+ if (p->isSet("device")){
+ // tell the running kpilotDaemon to use
+ // this device now
+ DCOPClient d;
+ QString dev(p->getOption("device"));
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << dev;
+ if (d.attach()){
+ d.send("kpilotDaemon", "KPilotDaemonIface", "setTempDevice(QString)", data );
+ d.detach();
+ }
+ }
+ return 0;
+ }
+ KUniqueApplication a(true, true);
+
+ // A block just to keep variables local.
+ //
+ //
+ {
+// KPilotSettings::self()->config()->setReadOnly(false);
+
+ if (KPilotSettings::configVersion() < KPilotConfig::ConfigurationVersion)
+ {
+ WARNINGKPILOT << "Is still not configured for use."
+ << endl;
+ if (!p->isSet("fail-silently"))
+ {
+ KPilotConfig::sorryVersionOutdated(KPilotSettings::configVersion());
+ }
+ return 1;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Configuration version "
+ << KPilotSettings::configVersion() << endl;
+#endif
+ }
+
+
+ PilotDaemon *gPilotDaemon = new PilotDaemon();
+
+ if (p->isSet("device"))
+ gPilotDaemon->setTempDevice(p->getOption("device"));
+
+ if (gPilotDaemon->status() == PilotDaemon::ERROR)
+ {
+ delete gPilotDaemon;
+
+ gPilotDaemon = 0;
+ WARNINGKPILOT << "Failed to start up daemon "
+ "due to errors constructing it." << endl;
+ return 2;
+ }
+
+ gPilotDaemon->showTray();
+
+ return a.exec();
+}
+
+
+
diff --git a/kpilot/kpilot/pilotDaemon.h b/kpilot/kpilot/pilotDaemon.h
new file mode 100644
index 000000000..c7ccd7eda
--- /dev/null
+++ b/kpilot/kpilot/pilotDaemon.h
@@ -0,0 +1,279 @@
+#ifndef _KPILOT_PILOTDAEMON_H
+#define _KPILOT_PILOTDAEMON_H
+/* pilotDaemon.h KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** See the .cc file for an explanation of what this file is for.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include <ksystemtray.h>
+
+#include "kpilotlink.h"
+#include "syncAction.h"
+#include "pilotDaemonDCOP.h"
+
+class QPixmap;
+class QTimer;
+class KAboutApplication;
+class QPopupMenu;
+
+class PilotDaemon;
+class ActionQueue;
+class FileInstaller;
+class LoggerDCOP_stub;
+class KPilotDCOP_stub;
+class LogFile;
+
+class KPilotLink;
+class KPilotDeviceLink;
+
+class PilotDaemonTray : public KSystemTray
+{
+ Q_OBJECT
+
+friend class PilotDaemon;
+
+public:
+ PilotDaemonTray(PilotDaemon *p);
+
+ typedef enum { Normal, Busy, NotListening } IconShape ;
+ void changeIcon(IconShape);
+
+ void enableRunKPilot(bool);
+
+ virtual void dragEnterEvent(QDragEnterEvent *);
+ virtual void dropEvent(QDropEvent *);
+
+
+protected:
+ void setupWidget();
+ /**
+ * Menu of sync types.
+ */
+ QPopupMenu *fSyncTypeMenu;
+
+protected slots:
+ void slotShowAbout();
+ void slotShowBusy();
+ void slotShowNormal();
+ void slotShowNotListening();
+ void slotBusyTimer();
+
+ // "Regular" QT actions
+ //
+ //
+ virtual void mousePressEvent(QMouseEvent* e);
+ virtual void closeEvent(QCloseEvent *e);
+
+protected:
+ void startHotSync();
+ void endHotSync();
+
+private:
+ QPixmap icons[((int) NotListening) + 1];
+ IconShape fCurrentIcon;
+ PilotDaemon *daemon;
+
+ /**
+ * Remember which item in the context menu
+ * is "Run KPilot" so we can enable / disable
+ * it as necessary.
+ */
+ int menuKPilotItem;
+
+ /**
+ * Remember which item in the context menu
+ * is "Configure Conduits" so we can enable / disable
+ * it as necessary.
+ */
+ int menuConfigureConduitsItem;
+
+ /**
+ * Window for the "About KPilot" information.
+ */
+ KAboutApplication *kap;
+
+ /**
+ * Timer for blinking.
+ */
+ QTimer *fBlinkTimer;
+
+} ;
+
+class PilotDaemon : public QObject, virtual public PilotDaemonDCOP
+{
+Q_OBJECT
+
+// The tray must be our friend so that we can let it stop the daemon.
+friend class PilotDaemonTray;
+
+
+public:
+ PilotDaemon();
+ ~PilotDaemon();
+
+ enum DaemonStatus
+ {
+ HOTSYNC_START, // Hotsync is running
+ HOTSYNC_END, // Hotsync is cleaning up
+ FILE_INSTALL_REQ, // A file is being saved for installation
+ ERROR,
+ READY, // Connected to device and ready for Sync
+ INIT,
+ NOT_LISTENING
+ };
+
+ DaemonStatus status() const { return fDaemonStatus; } ;
+ /* DCOP */ virtual QString statusString();
+ /* DCOP */ virtual QString shortStatusString();
+
+ /**
+ * Display the daemon's system tray icon
+ * (if there is one, depending on the DockDaemon
+ * setting in the config file)
+ */
+ void showTray();
+ virtual void addInstallFiles(const QStringList &);
+
+ // The next few functions are the DCOP interface.
+ // Some are also slots.
+ //
+public slots:
+ virtual ASYNC requestSync(int);
+public:
+ virtual ASYNC requestSyncType(QString);
+ virtual ASYNC requestRegularSyncNext();
+ virtual int nextSyncType() const;
+ virtual ASYNC requestSyncOptions(bool,bool);
+
+ virtual ASYNC quitNow();
+ virtual ASYNC reloadSettings();
+ virtual ASYNC setTempDevice(QString d);
+
+ virtual void stopListening();
+ virtual void startListening();
+ virtual bool isListening() { return fIsListening; }
+ /**
+ * Functions reporting same status data, e.g. for the kontact plugin.
+ */
+ virtual QDateTime lastSyncDate();
+ virtual QStringList configuredConduitList();
+ virtual QString logFileName();
+ virtual QString userName();
+ virtual QString pilotDevice();
+ virtual bool killDaemonOnExit();
+
+protected:
+ DaemonStatus fDaemonStatus;
+
+ enum postSyncActions {
+ None=0,
+ ReloadSettings = 1,
+ Quit = 2
+ } ;
+ int fPostSyncAction;
+
+protected slots:
+ void startHotSync( KPilotLink* lnk );
+ void endHotSync();
+
+ void logMessage(const QString &);
+ void logError(const QString &);
+ void logProgress(const QString &,int);
+
+private:
+ int getPilotSpeed();
+
+ /**
+ * Check whether we should do a backup. This is based on the
+ * KPilotSettings::backupFrequency and uses
+ * SyncAction::BackupFrequency. This will be expanded, hopefully,
+ * to provide backup scheduling at some point.
+ */
+ bool shouldBackup();
+
+ bool setupPilotLink();
+
+ KPilotDeviceLink &getPilotLink() { return *fPilotLink; }
+ KPilotDeviceLink *fPilotLink;
+
+ SyncAction::SyncMode fNextSyncType;
+
+ ActionQueue *fSyncStack;
+
+ /**
+ * This is a pointer to the (optional) docked
+ * system tray icon for the daemon.
+ */
+ PilotDaemonTray *fTray;
+
+ /**
+ * Set or change the tooltip displayed by the tray icon.
+ */
+ void updateTrayStatus(const QString &s=QString::null);
+
+ FileInstaller *fInstaller;
+
+protected slots:
+ /**
+ * Called after a file has been installed to notify any observers, like
+ * KPilot, that files have been installed. [Here that means: copied
+ * to the pending_install directory and thus *waiting* for
+ * installation on the Palm]
+ */
+ void slotFilesChanged();
+
+ /**
+ * Start up KPilot.
+ */
+ void slotRunKPilot();
+
+ /**
+ * Run conduit configuration using "kpilot -c"
+ */
+ void slotRunConfig();
+
+ /**
+ * Provide access to KPilot's DCOP interface through a stub.
+ */
+protected:
+ LoggerDCOP_stub &getLogger() { return *fLogStub; } ;
+ LoggerDCOP_stub &getFileLogger() { return *fLogFileStub; } ;
+ KPilotDCOP_stub &getKPilot() { return *fKPilotStub; } ;
+
+ LogFile *fLogFile;
+ bool fIsListening;
+
+private:
+ LoggerDCOP_stub *fLogStub;
+ LoggerDCOP_stub *fLogFileStub;
+ KPilotDCOP_stub *fKPilotStub;
+ QString fTempDevice;
+};
+
+
+#endif
diff --git a/kpilot/kpilot/pilotDaemonDCOP.h b/kpilot/kpilot/pilotDaemonDCOP.h
new file mode 100644
index 000000000..07f92bf63
--- /dev/null
+++ b/kpilot/kpilot/pilotDaemonDCOP.h
@@ -0,0 +1,103 @@
+#ifndef PILOTDAEMONDCOP_H
+#define PILOTDAEMONDCOP_H
+/* pilotDaemonDCOP.h KPilotDaemon
+**
+** Copyright (C) 2000 by Adriaan de Groot
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines the DCOP interface for
+** the KPilotDaemon. The daemon has *two* interfaces:
+** one belonging with KUniqueApplication and this one.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include <dcopobject.h>
+#include <qdatetime.h>
+#include <qstringlist.h>
+
+class PilotDaemonDCOP : virtual public DCOPObject
+{
+ K_DCOP
+public:
+k_dcop:
+ /**
+ * Start a HotSync. What kind of HotSync is determined
+ * by the int parameter (use the enum in kpilot.kcfg, or
+ * better yet, use requestSyncType and pass the name).
+ * Using a value of 0 (zero, which isn't a legal mode for
+ * sync actions) uses the configuration file default.
+ */
+ virtual ASYNC requestSync(int) = 0;
+ /**
+ * Request a particular kind of sync next; pass in the name
+ * of a sync type instead.
+ */
+ virtual ASYNC requestSyncType(QString) = 0;
+ /** Shortcut for using requestSync(1) */
+ virtual ASYNC requestRegularSyncNext() = 0;
+ /** Query what type is set most recently. */
+ virtual int nextSyncType() const = 0;
+ /** Set the mix-ins (see SyncAction::SyncMode for details). */
+ virtual ASYNC requestSyncOptions(bool test, bool local) = 0;
+
+ /**
+ * Functions for the KPilot UI, indicating what the daemon
+ * should do.
+ */
+ virtual ASYNC quitNow() = 0;
+ virtual ASYNC reloadSettings() = 0; // Indicate changed config file.
+ virtual ASYNC setTempDevice(QString d) =0; // use this device
+ virtual void stopListening() = 0;
+ virtual void startListening() = 0;
+ virtual bool isListening() =0 ;
+
+ /**
+ * Functions requesting the status of the daemon.
+ */
+ virtual QString statusString() = 0;
+ virtual QString shortStatusString() = 0;
+
+ /**
+ * Functions reporting same status data, e.g. for the kontact plugin.
+ */
+ virtual QDateTime lastSyncDate() = 0;
+ virtual QStringList configuredConduitList() = 0;
+ virtual QString logFileName() = 0;
+ virtual QString userName() = 0;
+ virtual QString pilotDevice() = 0;
+ virtual bool killDaemonOnExit() = 0;
+
+ /**
+ * Some other useful functionality
+ */
+ virtual void addInstallFiles(const QStringList &) = 0;
+
+
+k_dcop_signals:
+ void kpilotDaemonStatusChanged();
+ // used to push status information
+ void kpilotDaemonStatusDetails( QDateTime, QString, QStringList, QString, QString, QString, bool );
+} ;
+
+#endif
diff --git a/kpilot/kpilot/stamp-h.in b/kpilot/kpilot/stamp-h.in
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/kpilot/kpilot/stamp-h.in
diff --git a/kpilot/kpilot/syncCalendar.cc b/kpilot/kpilot/syncCalendar.cc
new file mode 100644
index 000000000..7587ddebc
--- /dev/null
+++ b/kpilot/kpilot/syncCalendar.cc
@@ -0,0 +1,87 @@
+/* KPilot
+**
+** Copyright (C) 2005 by Adriaan de Groot <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected].
+*/
+
+#include "options.h"
+
+#include <kpilotlink.h>
+#include <pilotDatabase.h>
+#include <pilotDateEntry.h>
+
+#include <libkcal/calendarlocal.h>
+#include <libkcal/event.h>
+
+
+typedef DatabaseInterpreter<KCal::Event,PilotDateEntry,PilotDateEntry::Mapper> DatebookDB;
+
+class CalendarDumper
+{
+public:
+ CalendarDumper() {}
+
+ KCal::CalendarLocal *retrieve(int fd);
+ KCal::CalendarLocal *retrieve(const QString &filename);
+
+protected:
+ KCal::CalendarLocal *retrieve(DatebookDB *db);
+} ;
+
+
+
+KCal::CalendarLocal *CalendarDumper::retrieve(int fd)
+{
+ PilotSerialDatabase sdb( fd, CSL1("DatebookDB") );
+ DatebookDB db(&sdb);
+ return retrieve(db);
+}
+
+KCal::CalendarLocal *CalendarDumped::retrieve(const QString &fn)
+{
+ PilotLocalDatabase ldb( fn );
+ DatebookDB db(&ldb);
+ return retrieve(db);
+}
+
+KCal::CalendarLocal *retrieve(DatebookDB *db)
+{
+ KCal::CalendarLocal *cal = new CalendarLocal( QString::null );
+
+ int count = db->db()->recordCount();
+
+ if (count < 1)
+ {
+ return cal;
+ }
+
+ for (int i=0; i<count; i++)
+ {
+ KCal::Event *e = db->readRecordByIndex(i);
+ if (!e) continue;
+ cal->addEvent(e);
+ }
+
+ return cal;
+}
diff --git a/kpilot/kpilot/todoEditor.cc b/kpilot/kpilot/todoEditor.cc
new file mode 100644
index 000000000..34a3b65df
--- /dev/null
+++ b/kpilot/kpilot/todoEditor.cc
@@ -0,0 +1,173 @@
+// -*- C++ -*-
+/* KPilot
+**
+** Copyright (C) 2000 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This is a dialog window that edits one single todo record.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "options.h"
+
+#include <qcombobox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qtextedit.h>
+#include <qcheckbox.h>
+
+#include <kdatewidget.h>
+
+#include "pilotTodoEntry.h"
+#include "todoEditor_base.h"
+#include "todoEditor.moc"
+
+
+TodoEditor::TodoEditor(PilotTodoEntry * p, struct ToDoAppInfo *appInfo,
+ QWidget * parent, const char *name) :
+ KDialogBase(parent, name, false, i18n("To-do Editor"), Ok|Cancel),
+ fDeleteOnCancel(p == 0L),
+ fTodo(p),
+ fAppInfo(appInfo)
+{
+ FUNCTIONSETUP;
+
+ fWidget=new TodoEditorBase(this);
+ setMainWidget(fWidget);
+ fillFields();
+
+ connect(parent, SIGNAL(recordChanged(PilotTodoEntry *)),
+ this, SLOT(updateRecord(PilotTodoEntry *)));
+
+}
+
+TodoEditor::~TodoEditor()
+{
+ FUNCTIONSETUP;
+
+ if (fDeleteOnCancel && fTodo)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Deleting private todo record." << endl;
+#endif
+ delete fTodo;
+ fTodo = 0L;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Help! I'm deleting!" << endl;
+#endif
+}
+
+
+
+void TodoEditor::fillFields()
+{
+ FUNCTIONSETUP;
+
+ if (fTodo == 0L)
+ {
+ fTodo = new PilotTodoEntry();
+ fDeleteOnCancel = true;
+ }
+
+ fWidget->fDescription->setText(fTodo->getDescription());
+ fWidget->fCompleted->setChecked(fTodo->getComplete());
+ if (fTodo->getIndefinite())
+ {
+ fWidget->fHasEndDate->setChecked(false);
+ }
+ else
+ {
+ fWidget->fHasEndDate->setChecked(true);
+ fWidget->fEndDate->setDate(readTm(fTodo->getDueDate()).date());
+ }
+ fWidget->fPriority->setCurrentItem(fTodo->getPriority());
+// fCategory->setCurrentItem(fTodo->getCategory()));
+ fWidget->fNote->setText(fTodo->getNote());
+}
+
+
+
+/* slot */ void TodoEditor::slotCancel()
+{
+ FUNCTIONSETUP;
+
+ if (fDeleteOnCancel && fTodo)
+ {
+ delete fTodo;
+
+ fTodo = 0L;
+ }
+ KDialogBase::slotCancel();
+}
+
+/* slot */ void TodoEditor::slotOk()
+{
+ FUNCTIONSETUP;
+
+ // Commit changes here
+ fTodo->setDescription(fWidget->fDescription->text());
+ fTodo->setComplete(fWidget->fCompleted->isChecked());
+ if (fWidget->fHasEndDate->isChecked())
+ {
+ fTodo->setIndefinite(false);
+ struct tm duedate=writeTm(fWidget->fEndDate->date());
+ fTodo->setDueDate(duedate);
+ }
+ else
+ {
+ fTodo->setIndefinite(true);
+ }
+ fTodo->setPriority(fWidget->fPriority->currentItem());
+// fTodo->setCategory(fWidget->fCategory->currentItem());
+ fTodo->setNote(fWidget->fNote->text());
+
+ emit(recordChangeComplete(fTodo));
+ KDialogBase::slotOk();
+}
+
+/* slot */ void TodoEditor::updateRecord(PilotTodoEntry * p)
+{
+ FUNCTIONSETUP;
+ if (p != fTodo)
+ {
+ // Not meant for me
+ //
+ //
+ return;
+ }
+
+ if (p->isDeleted())
+ {
+ delayedDestruct();
+ return;
+ }
+ else
+ {
+ fillFields();
+ }
+}
+
diff --git a/kpilot/kpilot/todoEditor.h b/kpilot/kpilot/todoEditor.h
new file mode 100644
index 000000000..d982e3f54
--- /dev/null
+++ b/kpilot/kpilot/todoEditor.h
@@ -0,0 +1,74 @@
+// -*- C++ -*-
+/* todoEditor.h KPilot
+**
+** Copyright (C) 1998-2000 by Dan Pilone
+**
+** This is a dialog window that is used to edit a single todo record.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#ifndef _KPILOT_TODOEDITOR_H
+#define _KPILOT_TODOEDITOR_H
+
+#include <kdialogbase.h>
+
+class PilotTodoEntry;
+struct ToDoAppInfo;
+
+class QComboBox;
+class QTextEdit;
+class QCheckBox;
+class KDateWidget;
+class TodoEditorBase;
+
+class TodoEditor : public KDialogBase
+{
+ Q_OBJECT
+
+
+public:
+ TodoEditor(PilotTodoEntry *todo,
+ struct ToDoAppInfo *appInfo,
+ QWidget *parent, const char *name=0L);
+ ~TodoEditor();
+
+
+signals:
+ void recordChangeComplete ( PilotTodoEntry* );
+
+public slots:
+ void slotOk();
+ void slotCancel();
+ void updateRecord(PilotTodoEntry *);
+
+private:
+ TodoEditorBase*fWidget;
+ bool fDeleteOnCancel;
+
+ PilotTodoEntry* fTodo;
+ struct ToDoAppInfo *fAppInfo;
+
+ void fillFields();
+};
+#endif
+
diff --git a/kpilot/kpilot/todoEditor_base.ui b/kpilot/kpilot/todoEditor_base.ui
new file mode 100644
index 000000000..9ed2d5699
--- /dev/null
+++ b/kpilot/kpilot/todoEditor_base.ui
@@ -0,0 +1,180 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>TodoEditorBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>TodoEditorBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>399</width>
+ <height>263</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>fDescriptionLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Description:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fDescription</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>fNoteLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Note:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fNote</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>fCategoryLabel</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Ca&amp;tegory:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fCategory</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="3">
+ <property name="name">
+ <cstring>fCategory</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>fPriorityLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Priority:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>fPriority</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="3">
+ <item>
+ <property name="text">
+ <string>1</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>2</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>3</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>4</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>5</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>fPriority</cstring>
+ </property>
+ </widget>
+ <widget class="QTextEdit" row="0" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>fDescription</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>80</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="QTextEdit" row="4" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>fNote</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fCompleted</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Completed</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fHasEndDate</cstring>
+ </property>
+ <property name="text">
+ <string>Has &amp;end date:</string>
+ </property>
+ </widget>
+ <widget class="KDateWidget" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>fEndDate</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>fHasEndDate</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>fEndDate</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includes>
+ <include location="system" impldecl="in implementation">kdatewidget.h</include>
+</includes>
+</UI>
diff --git a/kpilot/kpilot/todoWidget.cc b/kpilot/kpilot/todoWidget.cc
new file mode 100644
index 000000000..7f2ec137d
--- /dev/null
+++ b/kpilot/kpilot/todoWidget.cc
@@ -0,0 +1,608 @@
+/* KPilot
+**
+** Copyright (C) 2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines the todoWidget, that part of KPilot that
+** displays todo records from the Pilot.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qptrlist.h>
+#include <klistview.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qtextview.h>
+#include <qcombobox.h>
+#include <qwhatsthis.h>
+#include <qtextcodec.h>
+
+#include <kmessagebox.h>
+
+#include "kpilotConfig.h"
+#include "todoEditor.h"
+#include "pilotLocalDatabase.h"
+#include "todoWidget.moc"
+
+
+
+
+TodoCheckListItem::TodoCheckListItem(QListView*parent, const QString&text,
+ recordid_t pilotid, void*r):PilotCheckListItem(parent, text, pilotid, r)
+{
+
+}
+
+void TodoCheckListItem::stateChange(bool state)
+{
+ TodoListView*par=dynamic_cast<TodoListView*>(listView());
+ if (par) par->itemWasChecked(this, state);
+}
+
+
+
+TodoWidget::TodoWidget(QWidget * parent,
+ const QString & path) :
+ PilotComponent(parent, "component_todo", path),
+ fTodoInfo(0L),
+ fTodoAppInfo(0L),
+ fTodoDB(0L),
+ fPendingTodos(0)
+{
+ FUNCTIONSETUP;
+
+ setupWidget();
+ fTodoList.setAutoDelete(true);
+
+}
+
+TodoWidget::~TodoWidget()
+{
+ FUNCTIONSETUP;
+ KPILOT_DELETE( fTodoDB );
+}
+
+int TodoWidget::getAllTodos(PilotDatabase * todoDB)
+{
+ FUNCTIONSETUP;
+
+ int currentRecord = 0;
+ PilotRecord *pilotRec;
+ PilotTodoEntry *todo;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Reading ToDoDB..." << endl;
+#endif
+
+ while ((pilotRec = todoDB->readRecordByIndex(currentRecord)) != 0L)
+ {
+ if (!(pilotRec->isDeleted()) &&
+ (!(pilotRec->isSecret()) || KPilotSettings::showSecrets()))
+ {
+ todo = new PilotTodoEntry(pilotRec);
+ if (todo == 0L)
+ {
+ WARNINGKPILOT << "Couldn't allocate record "
+ << currentRecord++
+ << endl;
+ break;
+ }
+ fTodoList.append(todo);
+ }
+ KPILOT_DELETE( pilotRec );
+
+ currentRecord++;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Total " << currentRecord << " records" << endl;
+#endif
+
+ return currentRecord;
+}
+
+void TodoWidget::showComponent()
+{
+ FUNCTIONSETUP;
+ if ( fPendingTodos>0 ) return;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Reading from directory " << dbPath() << endl;
+#endif
+
+ fTodoDB = new PilotLocalDatabase(dbPath(), CSL1("ToDoDB"));
+
+ fTodoList.clear();
+
+ if (fTodoDB->isOpen())
+ {
+ KPILOT_DELETE(fTodoAppInfo);
+ fTodoAppInfo = new PilotToDoInfo(fTodoDB);
+ populateCategories(fCatList, fTodoAppInfo->categoryInfo());
+ getAllTodos(fTodoDB);
+
+ }
+ else
+ {
+ populateCategories(fCatList, 0L);
+ WARNINGKPILOT << "Could not open local TodoDB" << endl;
+ }
+
+ KPILOT_DELETE( fTodoDB );
+
+ updateWidget();
+}
+
+/* virtual */ bool TodoWidget::preHotSync(QString &s)
+{
+ FUNCTIONSETUP;
+
+ if (fPendingTodos)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": fPendingTodo="
+ << fPendingTodos
+ << endl;
+#endif
+
+#if KDE_VERSION<220
+ s = i18n("There are still %1 to-do editing windows open.")
+ .arg(QString::number(fPendingTodos));
+#else
+ s = i18n("There is still a to-do editing window open.",
+ "There are still %n to-do editing windows open.",
+ fPendingTodos);
+#endif
+ return false;
+ }
+
+ return true;
+}
+
+void TodoWidget::postHotSync()
+{
+ FUNCTIONSETUP;
+
+ fTodoList.clear();
+ showComponent();
+}
+
+void TodoWidget::hideComponent()
+{
+ FUNCTIONSETUP;
+ if ( fPendingTodos==0 )
+ {
+ fTodoList.clear();
+ fListBox->clear();
+ KPILOT_DELETE( fTodoDB );
+ }
+}
+
+void TodoWidget::setupWidget()
+{
+ FUNCTIONSETUP;
+
+ QLabel *label;
+ QGridLayout *grid = new QGridLayout(this, 6, 4, SPACING);
+
+ fCatList = new QComboBox(this);
+ grid->addWidget(fCatList, 0, 1);
+ connect(fCatList, SIGNAL(activated(int)),
+ this, SLOT(slotSetCategory(int)));
+ QWhatsThis::add(fCatList,
+ i18n("<qt>Select the category of to-dos to display here.</qt>"));
+
+ label = new QLabel(i18n("Category:"), this);
+ label->setBuddy(fCatList);
+ grid->addWidget(label, 0, 0);
+
+ fListBox = new TodoListView(this);
+ fListBox->addColumn( i18n( "To-do Item" ) );
+ fListBox->setAllColumnsShowFocus( TRUE );
+ fListBox->setResizeMode( KListView::LastColumn );
+ fListBox->setFullWidth( TRUE );
+ fListBox->setItemsMovable( FALSE );
+ fListBox->setItemsRenameable (TRUE);
+ grid->addMultiCellWidget(fListBox, 1, 1, 0, 1);
+ connect(fListBox, SIGNAL(selectionChanged(QListViewItem*)),
+ this, SLOT(slotShowTodo(QListViewItem*)));
+ connect(fListBox, SIGNAL(doubleClicked(QListViewItem*)),
+ this, SLOT(slotEditRecord(QListViewItem*)));
+ connect(fListBox, SIGNAL(returnPressed(QListViewItem*)),
+ this, SLOT(slotEditRecord(QListViewItem*)));
+ connect(fListBox, SIGNAL(itemChecked(QCheckListItem*, bool)),
+ this, SLOT(slotItemChecked(QCheckListItem*, bool)));
+ connect(fListBox, SIGNAL(itemRenamed(QListViewItem*, const QString &, int)),
+ this, SLOT(slotItemRenamed(QListViewItem*, const QString &, int)));
+ QWhatsThis::add(fListBox,
+ i18n("<qt>This list displays all the to-dos "
+ "in the selected category. Click on "
+ "one to display it to the right.</qt>"));
+
+ label = new QLabel(i18n("To-do info:"), this);
+ grid->addWidget(label, 0, 2);
+
+ // todo info text view
+ fTodoInfo = new QTextView(this);
+ grid->addMultiCellWidget(fTodoInfo, 1, 4, 2, 2);
+
+ QPushButton *button;
+ QString wt;
+
+ fEditButton = new QPushButton(i18n("Edit Record..."), this);
+ grid->addWidget(fEditButton, 2, 0);
+ connect(fEditButton, SIGNAL(clicked()), this, SLOT(slotEditRecord()));
+
+ wt = KPilotSettings::internalEditors() ?
+ i18n("<qt>You can edit a to-do when it is selected.</qt>") :
+ i18n("<qt><i>Editing is disabled by the 'internal editors' setting.</i></qt>");
+ QWhatsThis::add(fEditButton,wt);
+
+ button = new QPushButton(i18n("New Record..."), this);
+ grid->addWidget(button, 2, 1);
+ connect(button, SIGNAL(clicked()), this, SLOT(slotCreateNewRecord()));
+ wt = KPilotSettings::internalEditors() ?
+ i18n("<qt>Add a new to-do to the to-do list.</qt>") :
+ i18n("<qt><i>Adding new to-dos is disabled by the 'internal editors' setting.</i></qt>");
+ QWhatsThis::add(button, wt);
+ button->setEnabled(KPilotSettings::internalEditors());
+
+ fDeleteButton = new QPushButton(i18n("Delete Record"), this);
+ grid->addWidget(fDeleteButton, 3, 0);
+ connect(fDeleteButton, SIGNAL(clicked()),
+ this, SLOT(slotDeleteRecord()));
+ wt = KPilotSettings::internalEditors() ?
+ i18n("<qt>Delete the selected to-do from the to-do list.</qt>") :
+ i18n("<qt><i>Deleting is disabled by the 'internal editors' setting.</i></qt>") ;
+ QWhatsThis::add(fDeleteButton,wt);
+}
+
+void TodoWidget::updateWidget()
+{
+ FUNCTIONSETUP;
+ if (!shown || !fTodoAppInfo ) return;
+
+ int listIndex = 0;
+
+ int currentCatID = findSelectedCategory(fCatList,
+ fTodoAppInfo->categoryInfo());
+
+ fListBox->clear();
+ fTodoList.first();
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Adding records..." << endl;
+#endif
+
+ PilotTodoEntry*todo;
+ while (fTodoList.current())
+ {
+ todo=fTodoList.current();
+ if ((currentCatID == -1) ||
+ (todo->category() == currentCatID))
+ {
+ QString title = todo->getDescription();
+
+ TodoCheckListItem*item=new TodoCheckListItem(fListBox, title,
+ listIndex, todo);
+ item->setOn(todo->getComplete());
+ }
+ listIndex++;
+ fTodoList.next();
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": " << listIndex << " records" << endl;
+#endif
+
+ slotUpdateButtons();
+}
+
+
+
+/* slot */ void TodoWidget::slotUpdateButtons()
+{
+ FUNCTIONSETUP;
+
+ bool enabled = (fListBox->currentItem() != 0L);
+
+ enabled &= KPilotSettings::internalEditors() ;
+
+ fEditButton->setEnabled(enabled);
+ fDeleteButton->setEnabled(enabled);
+}
+
+void TodoWidget::slotSetCategory(int)
+{
+ FUNCTIONSETUP;
+
+ updateWidget();
+}
+
+void TodoWidget::slotEditRecord()
+{
+ slotEditRecord(fListBox->currentItem());
+}
+void TodoWidget::slotEditRecord(QListViewItem*item)
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ TodoCheckListItem*p = static_cast<TodoCheckListItem*>(item);
+ if (!p) return;
+ PilotTodoEntry *selectedRecord = (PilotTodoEntry *) p->rec();
+
+ if (selectedRecord->id() == 0)
+ {
+ KMessageBox::error(0L,
+ i18n("Cannot edit new records until "
+ "HotSynced with Pilot."),
+ i18n("HotSync Required"));
+ return;
+ }
+
+ TodoEditor *editor = new TodoEditor(selectedRecord,
+ fTodoAppInfo->info(), this);
+
+ connect(editor, SIGNAL(recordChangeComplete(PilotTodoEntry *)),
+ this, SLOT(slotUpdateRecord(PilotTodoEntry *)));
+ connect(editor, SIGNAL(cancelClicked()),
+ this, SLOT(slotEditCancelled()));
+ editor->show();
+
+ fPendingTodos++;
+}
+
+void TodoWidget::slotCreateNewRecord()
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ // Response to bug 18072: Don't even try to
+ // add records to an empty or unopened database,
+ // since we don't have the DBInfo stuff to deal with it.
+ //
+ //
+ PilotDatabase *myDB = new PilotLocalDatabase(dbPath(), CSL1("ToDoDB"));
+
+ if (!myDB || !myDB->isOpen())
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Tried to open "
+ << dbPath()
+ << "/ToDoDB"
+ << " and got pointer @"
+ << (void *) myDB
+ << " with status "
+ << ( myDB ? myDB->isOpen() : false )
+ << endl;
+#endif
+
+ KMessageBox::sorry(this,
+ i18n("You cannot add to-dos to the to-do list "
+ "until you have done a HotSync at least once "
+ "to retrieve the database layout from your Pilot."),
+ i18n("Cannot Add New To-do"));
+
+ if (myDB)
+ KPILOT_DELETE( myDB );
+
+ return;
+ }
+
+ TodoEditor *editor = new TodoEditor(0L,
+ fTodoAppInfo->info(), this);
+
+ connect(editor, SIGNAL(recordChangeComplete(PilotTodoEntry *)),
+ this, SLOT(slotAddRecord(PilotTodoEntry *)));
+ connect(editor, SIGNAL(cancelClicked()),
+ this, SLOT(slotEditCancelled()));
+ editor->show();
+
+ fPendingTodos++;
+}
+
+void TodoWidget::slotAddRecord(PilotTodoEntry * todo)
+{
+ FUNCTIONSETUP;
+ if ( !shown && fPendingTodos==0 ) return;
+
+ int currentCatID = findSelectedCategory(fCatList,
+ fTodoAppInfo->categoryInfo(), true);
+
+
+ todo->PilotRecordBase::setCategory(currentCatID);
+ fTodoList.append(todo);
+ writeTodo(todo);
+ // TODO: Just add the new record to the lists
+ updateWidget();
+
+ // k holds the item number of the todo just added.
+ //
+// int k = fListBox->count() - 1;
+//
+// fListBox->setCurrentItem(k); // Show the newest one
+// fListBox->setBottomItem(k);
+
+ fPendingTodos--;
+ if ( !shown && fPendingTodos==0 ) hideComponent();
+}
+
+void TodoWidget::slotUpdateRecord(PilotTodoEntry * todo)
+{
+ FUNCTIONSETUP;
+ if ( !shown && fPendingTodos==0 ) return;
+
+ writeTodo(todo);
+ TodoCheckListItem* currentRecord = static_cast<TodoCheckListItem*>(fListBox->currentItem());
+
+ // TODO: Just change the record
+ updateWidget();
+ fListBox->setCurrentItem(currentRecord);
+
+ emit(recordChanged(todo));
+
+ fPendingTodos--;
+ if ( !shown && fPendingTodos==0 ) hideComponent();
+}
+
+void TodoWidget::slotEditCancelled()
+{
+ FUNCTIONSETUP;
+
+ fPendingTodos--;
+ if ( !shown && fPendingTodos==0 ) hideComponent();
+}
+
+void TodoWidget::slotDeleteRecord()
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ TodoCheckListItem* p = static_cast<TodoCheckListItem*>(fListBox->currentItem());
+ if (p == 0L) return;
+
+ PilotTodoEntry *selectedRecord = (PilotTodoEntry *) p->rec();
+
+ if (selectedRecord->id() == 0)
+ {
+ KMessageBox::error(this,
+ i18n("New records cannot be deleted until "
+ "HotSynced with pilot."),
+ i18n("HotSync Required"));
+ return;
+ }
+
+ if (KMessageBox::questionYesNo(this,
+ i18n("Delete currently selected record?"),
+ i18n("Delete Record?"), KStdGuiItem::del(), KStdGuiItem::cancel()) == KMessageBox::No)
+ return;
+
+ selectedRecord->setDeleted(true);
+ writeTodo(selectedRecord);
+ emit(recordChanged(selectedRecord));
+ showComponent();
+}
+
+
+
+void TodoWidget::slotShowTodo(QListViewItem*item)
+{
+ FUNCTIONSETUP;
+ if (!shown) return;
+
+ TodoCheckListItem *p = dynamic_cast<TodoCheckListItem*>(item);
+ if (!p) return;
+ PilotTodoEntry *todo = (PilotTodoEntry *) p->rec();
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Showing "<< todo->getDescription()<<endl;
+#endif
+
+ QString text(CSL1("<qt>"));
+ text += todo->getTextRepresentation(Qt::RichText);
+ text += CSL1("</qt>\n");
+ fTodoInfo->setText(text);
+
+ slotUpdateButtons();
+}
+
+
+
+void TodoWidget::writeTodo(PilotTodoEntry * which,
+ PilotDatabase * todoDB)
+{
+ FUNCTIONSETUP;
+
+ // Open a database (myDB) only if needed,
+ // i.e. only if the passed-in todoDB
+ // isn't valid.
+ //
+ //
+ PilotDatabase *myDB = todoDB;
+ bool usemyDB = false;
+
+ if (myDB == 0L || !myDB->isOpen())
+ {
+ myDB = new PilotLocalDatabase(dbPath(), CSL1("ToDoDB"));
+ usemyDB = true;
+ }
+
+ // Still no valid todo database...
+ //
+ //
+ if (!myDB->isOpen())
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Todo database is not open" <<
+ endl;
+#endif
+ return;
+ }
+
+
+ // Do the actual work.
+ PilotRecord *pilotRec = which->pack();
+
+ myDB->writeRecord(pilotRec);
+ markDBDirty(CSL1("ToDoDB"));
+ KPILOT_DELETE(pilotRec);
+
+
+ // Clean up in the case that we allocated our own DB.
+ //
+ //
+ if (usemyDB)
+ {
+ KPILOT_DELETE(myDB);
+ }
+}
+
+void TodoWidget::slotItemChecked(QCheckListItem*item, bool on)
+{
+ TodoCheckListItem*p = static_cast<TodoCheckListItem*>(item);
+ if (!p) return;
+ PilotTodoEntry *selectedRecord = (PilotTodoEntry *) p->rec();
+ if (!selectedRecord) return;
+ selectedRecord->setComplete(on);
+ slotShowTodo(item);
+}
+
+void TodoWidget::slotItemRenamed(QListViewItem*item, const QString &txt, int nr)
+{
+ TodoCheckListItem*p = static_cast<TodoCheckListItem*>(item);
+ if (!p) return;
+ PilotTodoEntry *selectedRecord = (PilotTodoEntry *) p->rec();
+ if (!selectedRecord) return;
+ if (nr==0)
+ {
+ selectedRecord->setDescription(txt);
+ slotShowTodo(item);
+ }
+}
diff --git a/kpilot/kpilot/todoWidget.h b/kpilot/kpilot/todoWidget.h
new file mode 100644
index 000000000..14a139e51
--- /dev/null
+++ b/kpilot/kpilot/todoWidget.h
@@ -0,0 +1,167 @@
+/* todoWidget.h KPilot
+**
+** Copyright (C) 2004 Reinhold Kainhofer <[email protected]>
+**
+
+** This file defines the todo-viewing widget used in KPilot
+** to display the Pilot's todo records.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+#ifndef _KPILOT_TODOWIDGET_H
+#define _KPILOT_TODOWIDGET_H
+
+class QComboBox;
+class QPushButton;
+class QTextView;
+
+#include "pilotComponent.h"
+#include "pilotTodoEntry.h"
+#include "listItems.h"
+
+class TodoListView : public KListView
+{
+Q_OBJECT
+public:
+ TodoListView(QWidget * parent = 0, const char * name = 0 ):KListView(parent, name){};
+ ~TodoListView() {};
+signals:
+ void itemChecked(QCheckListItem*item);
+ void itemChecked(QCheckListItem*item, bool on);
+//protected:
+public:
+ void itemWasChecked(QCheckListItem*item, bool on) {
+ emit itemChecked(item);
+ emit itemChecked(item, on);
+ }
+};
+
+class TodoCheckListItem : public PilotCheckListItem
+{
+public:
+ TodoCheckListItem(QListView*parent, const QString&text, recordid_t pilotid, void*r);
+ ~TodoCheckListItem() {};
+ virtual void stateChange(bool state);
+};
+
+class TodoWidget : public PilotComponent
+{
+Q_OBJECT
+
+public:
+ TodoWidget(QWidget* parent,const QString& dbpath);
+ ~TodoWidget();
+
+ // Pilot Component Methods:
+ virtual bool preHotSync(QString &);
+ virtual void postHotSync();
+ virtual void showComponent();
+ virtual void hideComponent();
+
+public slots:
+ /**
+ * Called when a particular todo is selected. This slot displays
+ * it in the viewer widget.
+ */
+ void slotShowTodo(QListViewItem*);
+ void slotEditRecord(QListViewItem*item);
+ void slotEditRecord();
+ void slotCreateNewRecord();
+ void slotDeleteRecord();
+ void slotEditCancelled();
+
+ void slotUpdateButtons(); // Enable/disable buttons
+
+signals:
+ void recordChanged(PilotTodoEntry *);
+
+protected slots:
+ /**
+ * When an edit window is closed, the corresponding record
+ * is updated and possibly re-displayed.
+ */
+ void slotUpdateRecord(PilotTodoEntry*);
+
+ /**
+ * Pop up an edit window for a new record.
+ */
+ void slotAddRecord(PilotTodoEntry*);
+
+ /**
+ * Change category. This means that the display should be
+ * cleared and that the list should be repopulated.
+ */
+ void slotSetCategory(int);
+
+
+ void slotItemChecked(QCheckListItem*item, bool on);
+ void slotItemRenamed(QListViewItem*item, const QString &txt, int nr);
+private:
+ void setupWidget();
+ void updateWidget(); // Called with the lists have changed..
+ void writeTodo(PilotTodoEntry* which,PilotDatabase *db=0L);
+
+ /**
+ * getAllTodos reads the database and places all
+ * the todos from the database in the list
+ * in memory --- not the list on the screen.
+ * @see fTodoList
+ */
+ int getAllTodos(PilotDatabase *todoDB);
+
+ /**
+ * Create a sensible "title" for an todo, composed
+ * of first + last name if possible.
+ */
+ QString createTitle(PilotTodoEntry *,int displayMode);
+
+ /**
+ * We use a QComboBox fCatList to hold the user-visible names
+ * of all the categories. The QTextView fTodoInfo is for
+ * displaying the currently selected todo, if any.
+ * The QListView fListBox lists all the todoes in the
+ * currently selected category.
+ *
+ * The entire todo database is read into memory in the
+ * QList fTodoList. We need the appinfo block from the
+ * database to determine which categories there are; this
+ * is held in fTodoAppInfo.
+ *
+ * The two buttons should speak for themselves.
+ */
+ QComboBox *fCatList;
+ QTextView *fTodoInfo;
+ PilotToDoInfo *fTodoAppInfo;
+ QPtrList<PilotTodoEntry> fTodoList;
+ TodoListView *fListBox;
+ QPushButton *fEditButton,*fDeleteButton;
+ PilotDatabase *fTodoDB;
+protected:
+ /**
+ * Keep track of how many open todo editing windows there
+ * are. You can't sync when there are open windows.
+ */
+ int fPendingTodos;
+
+};
+
+#endif
diff --git a/kpilot/lib/CMakeLists.txt b/kpilot/lib/CMakeLists.txt
new file mode 100644
index 000000000..efc36ce59
--- /dev/null
+++ b/kpilot/lib/CMakeLists.txt
@@ -0,0 +1,90 @@
+include(CheckIncludeFiles)
+include(CheckFunctionExists)
+
+check_include_files( stdint.h HAVE_STDINT_H )
+check_include_files( alloca.h HAVE_ALLOCA_H )
+check_include_files( "sys/time.h" HAVE_SYS_TIME_H )
+check_include_files( "sys/stat.h" HAVE_SYS_STAT_H )
+check_function_exists( cfsetspeed HAVE_CFSETSPEED )
+check_function_exists( strdup HAVE_STRDUP )
+check_function_exists( setenv HAVE_SETENV )
+check_function_exists( unsetenv HAVE_UNSETENV )
+check_function_exists( usleep HAVE_USLEEP )
+check_function_exists( random HAVE_RANDOM )
+check_function_exists( putenv HAVE_PUTENV )
+check_function_exists( seteuid HAVE_SETEUID )
+check_function_exists( mkstemps HAVE_MKSTEMPS )
+check_function_exists( mkstemp HAVE_MKSTEMP )
+check_function_exists( mkdtemp HAVE_MKDTEMP )
+check_function_exists( revoke HAVE_REVOKE )
+check_function_exists( strlcpy HAVE_STRLCPY )
+check_function_exists( strlcat HAVE_STRLCAT )
+check_function_exists( inet_aton HAVE_INET_ATON )
+
+configure_file(
+ ${CMAKE_SOURCE_DIR}/config.h.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/config.h
+)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+set(lib_SRCS
+ options.cc
+ plugin.cc
+ syncAction.cc
+ actions.cc
+ actionQueue.cc
+ idmapping.cc
+ idmapperxml.cc
+ idmapper.cc
+ kpilotlink.cc
+ kpilotdevicelink.cc
+ kpilotlocallink.cc
+ pilot.cc
+ pilotAppInfo.cc
+ pilotRecord.cc
+ pilotDatabase.cc
+ pilotLocalDatabase.cc
+ pilotSerialDatabase.cc
+ pilotMemo.cc
+ pilotAddress.cc
+ pilotDateEntry.cc
+ pilotTodoEntry.cc
+)
+
+kde3_automoc(${lib_SRCS})
+kde3_add_kcfg_files(lib_SRCS kpilotlibSettings.kcfgc)
+add_library(kpilot SHARED ${lib_SRCS})
+target_link_libraries(kpilot ${PILOTLINK_LIBRARY} ${QT_LIBRARIES} kdeui kio)
+kpilot_rpath(kpilot)
+
+#---------- INSTALL -----------------------*
+set(kpilotinclude_HEADERS
+ kpilotlink.h
+ kpilotdevicelink.h
+ kpilotlocallink.h
+ pilot.h
+ pilotDatabase.h
+ pilotLinkVersion.h
+ pilotLocalDatabase.h
+ pilotRecord.h
+ pilotSerialDatabase.h
+ plugin.h
+ pluginfactory.h
+ syncAction.h
+)
+
+install(
+ TARGETS kpilot
+ LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
+)
+
+install(
+ FILES ${kpilotinclude_HEADERS}
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/include/kpilot
+)
+
+install(
+ FILES kpilotlib.kcfg DESTINATION ${KDE3_KCFG_DIR}
+)
+
diff --git a/kpilot/lib/COPYING b/kpilot/lib/COPYING
new file mode 100644
index 000000000..7bbb8e8bd
--- /dev/null
+++ b/kpilot/lib/COPYING
@@ -0,0 +1,509 @@
+[This license applies only to the contents of the lib/ directory,
+whereas the rest of KPilot is under the regular GNU GENERAL PUBLIC
+LICENSE. This has been done to ensure that non-GPL yet LGPL-compatibly
+licensed plugins may be written for KPilot.]
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/kpilot/lib/Makefile.am b/kpilot/lib/Makefile.am
new file mode 100644
index 000000000..b2ceadf1f
--- /dev/null
+++ b/kpilot/lib/Makefile.am
@@ -0,0 +1,60 @@
+### Makefile.am for kpilot/lib
+###
+###
+
+METASOURCES = AUTO
+
+INCLUDES = $(PISOCK_INCLUDE) -I$(top_srcdir) $(all_includes)
+
+### If you must get debugging output on a platform where
+### the libs are built without debugging support, define
+### DEBUG_CERR. Define DEBUG to get debugging support anywhere.
+###
+### KDE_CXXFLAGS=-DDEBUG -DDEBUG_CERR
+##KDE_CXXFLAGS=-DNDEBUG -UDEBUG
+##KDE_CXXFLAGS=-DDEBUG
+
+lib_LTLIBRARIES = libkpilot.la
+
+libkpilot_la_SOURCES = kpilotlibSettings.kcfgc \
+ options.cc plugin.cc syncAction.cc \
+ kpilotlink.cc kpilotdevicelink.cc kpilotlocallink.cc \
+ actions.cc actionQueue.cc \
+ pilot.cc \
+ pilotAppInfo.cc pilotRecord.cc pilotDatabase.cc \
+ pilotLocalDatabase.cc pilotSerialDatabase.cc \
+ pilotMemo.cc \
+ pilotAddress.cc \
+ pilotDateEntry.cc \
+ pilotTodoEntry.cc
+
+libkpilot_la_LDFLAGS = $(PISOCK_LDFLAGS) -no-undefined $(all_libraries) $(KDE_EXTRA_RPATH) $(KDE_RPATH)
+libkpilot_la_LIBADD = $(PISOCK_LIB) $(LIB_KDEUI) $(LIB_KABC) $(top_builddir)/libkcal/libkcal.la
+
+kpilotincludedir = $(includedir)/kpilot
+kpilotinclude_HEADERS = \
+ kpilotlink.h kpilotlocallink.h kpilotdevicelink.h \
+ pilot.h \
+ pilotDatabase.h \
+ pilotLinkVersion.h \
+ pilotLocalDatabase.h \
+ pilotRecord.h \
+ pilotSerialDatabase.h \
+ plugin.h \
+ pluginfactory.h \
+ syncAction.h
+
+
+kde_kcfg_DATA = kpilotlib.kcfg
+
+check-local:
+ rm -f FAILED
+ for i in $(srcdir)/*.h ; do \
+ ( echo "#include <kdemacros.h>" ; echo "#include \"$$i\"" ; echo "int main(int argc,char **argv){return 0;}" ) > header-test.cc; \
+ echo "$$i" ; \
+ g++ $(all_includes) -I$(top_builddir) -DQT_THREAD_SUPPORT -c header-test.cc || echo "$$i" >> FAILED; \
+ done
+ test ! -e FAILED
+
+DOXYGEN_REFERENCES=libkcal kdecore
+include $(top_srcdir)/admin/Doxyfile.am
diff --git a/kpilot/lib/actionQueue.cc b/kpilot/lib/actionQueue.cc
new file mode 100644
index 000000000..e4770d369
--- /dev/null
+++ b/kpilot/lib/actionQueue.cc
@@ -0,0 +1,172 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This defines the "ActionQueue", which is the pile of actions
+** that will occur during a HotSync.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+#include "options.h"
+
+#include <qtimer.h>
+
+#include "actions.h"
+#include "plugin.h"
+
+#include "actionQueue.moc"
+
+
+
+
+ActionQueue::ActionQueue(KPilotLink *d) :
+ SyncAction(d,"ActionQueue")
+ // The string lists have default constructors
+{
+ FUNCTIONSETUP;
+}
+
+ActionQueue::~ActionQueue()
+{
+ FUNCTIONSETUP;
+ clear();
+}
+
+void ActionQueue::clear()
+{
+ SyncAction *del = 0L;
+ while ( (del = nextAction()) )
+ {
+ delete del;
+ }
+
+ Q_ASSERT(isEmpty());
+}
+
+void ActionQueue::queueInit()
+{
+ FUNCTIONSETUP;
+
+ addAction(new WelcomeAction(fHandle));
+}
+
+void ActionQueue::queueConduits(const QStringList &l,
+ const SyncAction::SyncMode &m)
+{
+ FUNCTIONSETUP;
+
+ // Add conduits here ...
+ //
+ //
+ for (QStringList::ConstIterator it = l.begin();
+ it != l.end();
+ ++it)
+ {
+ if ((*it).startsWith(CSL1("internal_")))
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname <<
+ ": Ignoring conduit " << *it << endl;
+#endif
+ continue;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Creating proxy with mode=" << m.name() << endl;
+#endif
+ ConduitProxy *cp = new ConduitProxy(fHandle,*it,m);
+ addAction(cp);
+ }
+}
+
+void ActionQueue::queueCleanup()
+{
+ addAction(new CleanupAction(fHandle));
+}
+
+bool ActionQueue::exec()
+{
+ actionCompleted(0L);
+ return true;
+}
+
+void ActionQueue::actionCompleted(SyncAction *b)
+{
+ FUNCTIONSETUP;
+
+ if (b)
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Completed action "
+ << b->name()
+ << endl;
+#endif
+ delete b;
+ }
+
+ if (isEmpty())
+ {
+ delayDone();
+ return;
+ }
+ if ( deviceLink() && (!deviceLink()->tickle()) )
+ {
+ emit logError(i18n("The connection to the handheld "
+ "was lost. Synchronization cannot continue."));
+ clear();
+ delayDone();
+ return;
+ }
+
+ SyncAction *a = nextAction();
+
+ if (!a)
+ {
+ WARNINGKPILOT << "NULL action on stack."
+ << endl;
+ return;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname
+ << ": Will run action "
+ << a->name()
+ << endl;
+#endif
+
+ QObject::connect(a, SIGNAL(logMessage(const QString &)),
+ this, SIGNAL(logMessage(const QString &)));
+ QObject::connect(a, SIGNAL(logError(const QString &)),
+ this, SIGNAL(logMessage(const QString &)));
+ QObject::connect(a, SIGNAL(logProgress(const QString &, int)),
+ this, SIGNAL(logProgress(const QString &, int)));
+ QObject::connect(a, SIGNAL(syncDone(SyncAction *)),
+ this, SLOT(actionCompleted(SyncAction *)));
+
+ // Run the action picked from the queue when we get back
+ // to the event loop.
+ QTimer::singleShot(0,a,SLOT(execConduit()));
+}
+
diff --git a/kpilot/lib/actionQueue.h b/kpilot/lib/actionQueue.h
new file mode 100644
index 000000000..bc8b11560
--- /dev/null
+++ b/kpilot/lib/actionQueue.h
@@ -0,0 +1,162 @@
+#ifndef _KPILOT_ACTIONQUEUE_H
+#define _KPILOT_ACTIONQUEUE_H
+/*
+**
+** Copyright (C) 1998-2001,2003 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <qptrqueue.h>
+
+#include "syncAction.h"
+
+/** @file
+* This file defines the ActionQueue.
+*
+* This used to be called SyncStack, and while a stack is cool
+* for some things, it actually rather confuses the issue because
+* you _use_ this class for specifying "do this, then that, then ..."
+* and in program code you need to reverse that order when adding
+* items to a stack. So now it's a Queue, FIFO, and program
+* code looks more normal.
+*/
+
+/**
+* The ActionQueue is a meta-action, which handles running a bunch of
+* SyncActions in sequence. It is a SyncAction itself, so it can even
+* be queued on another ActionQueue.
+*
+* An ActionQueue is constructed with a @p device. As usual, you should
+* connect the device's deviceReady() signal with the exec() slot --
+* or something to that effect. The ActionQueue will then run all the
+* actions in the queue in sequence.
+*
+*/
+KDE_EXPORT class ActionQueue : public SyncAction
+{
+Q_OBJECT
+public:
+ /**
+ * Constructor. Pass in a KPilot device link for it to act on.
+ * It is legal to pass in 0 (NULL) as a device. Ownership of
+ * the device is unchanged.
+ */
+ ActionQueue(KPilotLink *device);
+
+ /** Destructor. */
+ virtual ~ActionQueue();
+
+ /** Is the queue empty? Returns @c true if it is. */
+ bool isEmpty() const
+ {
+ return SyncActionQueue.isEmpty();
+ };
+
+ /**
+ * You can push your own action @p a onto the queue. Ownership
+ * of the action is given to the ActionQueue object.
+ */
+ void addAction(SyncAction *a)
+ {
+ SyncActionQueue.enqueue(a);
+ };
+
+public:
+ /*
+ * Call these queue*() functions to append standard functional
+ * blocks. You should at least call queueInit() and
+ * queueCleanup() to add the welcome and cleanup actions to
+ * the queue (unless you do that yourself.)
+ *
+ * For queueInit, a WelcomeAction is added.
+ * For queueConduits, whatever is relevant for the conduits
+ * can be used, usually things in the FlagMask and ActionMask.
+ * The list of conduits in @p conduits is queued automatically.
+ */
+
+ /**
+ * Initialize the queue. This empties it out and adds a
+ * welcome action (see WelcomeAction in actions.h) so that
+ * the user knows what is happening when the ActionQueue
+ * begins to execute. Equivalent to
+ * @code
+ * clear(); addAction(new WelcomeAction);
+ * @endcode
+ */
+ void queueInit();
+
+ /**
+ * Queue a (series) of conduits @p conduits with a given
+ * sync mode @p mode. Each of the conduits named is called
+ * through a ConduitProxy object which handles loading the
+ * conduit's shared library and creating the actual SyncAction
+ * for that conduit. Actions named "internal_*" are silently
+ * ignored since those names are used by KPilot internally
+ * for administrative purposes.
+ */
+ void queueConduits(const QStringList &conduits,
+ const SyncAction::SyncMode &mode);
+
+ /**
+ * Convenience function for adding a cleanup action (see
+ * CleanupAction in actions.h) to the queue. Should be the
+ * last action added to the queue because a HotSync can only
+ * have @em one cleanup.
+ */
+ void queueCleanup();
+
+protected:
+ /**
+ * Remove all the actions from the queue and delete them
+ * (the queue owns the actions, after all).
+ */
+ void clear();
+
+ /**
+ * Dequeue the next action in the queue, ready for processing.
+ * This takes the action off the queue, so remember to delete it
+ * eventually.
+ */
+ SyncAction *nextAction()
+ {
+ return SyncActionQueue.dequeue();
+ };
+
+ /** Reimplemented from SyncAction. */
+ virtual bool exec();
+
+protected slots:
+ /**
+ * When one action finishes, start the next one.
+ */
+ void actionCompleted(SyncAction *);
+
+private:
+ /** A queue of actions to take. */
+ QPtrQueue < SyncAction > SyncActionQueue;
+};
+
+
+#endif
diff --git a/kpilot/lib/actions.cc b/kpilot/lib/actions.cc
new file mode 100644
index 000000000..6cd88273b
--- /dev/null
+++ b/kpilot/lib/actions.cc
@@ -0,0 +1,137 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2006 Adriaan de Groot <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+#include "options.h"
+
+#include <qapplication.h>
+#include <qdir.h>
+#include <qfile.h>
+
+#include <ksavefile.h>
+
+#include "pilot.h"
+#include "pilotUser.h"
+
+#include "actions.h"
+
+
+
+WelcomeAction::WelcomeAction(KPilotLink *p) :
+ SyncAction(p,"welcomeAction")
+{
+ FUNCTIONSETUP;
+}
+
+/* virtual */ bool WelcomeAction::exec()
+{
+ FUNCTIONSETUP;
+
+ addSyncLogEntry(i18n("KPilot %1 HotSync starting...\n")
+ .arg(QString::fromLatin1(KPILOT_VERSION)));
+ emit logMessage( i18n("Using encoding %1 on the handheld.").arg(Pilot::codecName()) );
+ emit syncDone(this);
+ return true;
+}
+
+SorryAction::SorryAction(KPilotLink *p, const QString &s) :
+ SyncAction(p,"sorryAction"),
+ fMessage(s)
+{
+ if (fMessage.isEmpty())
+ {
+ fMessage = i18n("KPilot is busy and cannot process the "
+ "HotSync right now.");
+ }
+}
+
+bool SorryAction::exec()
+{
+ FUNCTIONSETUP;
+
+ addSyncLogEntry(fMessage);
+ return delayDone();
+}
+
+CleanupAction::CleanupAction(KPilotLink *p) : SyncAction(p,"cleanupAction")
+{
+ FUNCTIONSETUP;
+}
+
+/* virtual */ bool CleanupAction::exec()
+{
+ FUNCTIONSETUP;
+
+ if (deviceLink())
+ {
+ deviceLink()->endSync( KPilotLink::UpdateUserInfo );
+ }
+ emit syncDone(this);
+ return true;
+}
+
+
+TestLink::TestLink(KPilotLink * p) :
+ SyncAction(p, "testLink")
+{
+ FUNCTIONSETUP;
+
+}
+
+/* virtual */ bool TestLink::exec()
+{
+ FUNCTIONSETUP;
+
+ int i;
+ int dbindex = 0;
+ int count = 0;
+ struct DBInfo db;
+
+ addSyncLogEntry(i18n("Testing.\n"));
+
+ while ((i = deviceLink()->getNextDatabase(dbindex,&db)) > 0)
+ {
+ count++;
+ dbindex = db.index + 1;
+
+ DEBUGKPILOT << fname
+ << ": Read database " << db.name
+ << " with index " << db.index
+ << endl;
+
+ // Let the Pilot User know what's happening
+ openConduit();
+ // Let the KDE User know what's happening
+ // Pretty sure all database names are in latin1.
+ emit logMessage(i18n("Syncing database %1...")
+ .arg(Pilot::fromPilot(db.name)));
+ }
+
+ emit logMessage(i18n("HotSync finished."));
+ emit syncDone(this);
+ return true;
+}
diff --git a/kpilot/lib/actions.h b/kpilot/lib/actions.h
new file mode 100644
index 000000000..ee353551f
--- /dev/null
+++ b/kpilot/lib/actions.h
@@ -0,0 +1,115 @@
+#ifndef _KPILOT_ACTIONS_H
+#define _KPILOT_ACTIONS_H
+/*
+**
+** Copyright (C) 1998-2001,2003 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2006 Adriaan de Groot <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "syncAction.h"
+
+/** @file
+* This file defines some simple standard actions. None of these
+* actions require much in the way of configuration; none provide
+* particularly complicated functionality.
+*/
+
+/**
+* This action puts "Welcome to KPilot" in the sync log of the handheld.
+* It is added automatically to a ActionQueue by queueInit() in order
+* to inform the user of the sync.
+*/
+KDE_EXPORT class WelcomeAction : public SyncAction
+{
+public:
+ /** Constructor. */
+ WelcomeAction(KPilotLink *);
+
+protected:
+ /** Reimplemented from SyncAction. */
+ virtual bool exec();
+} ;
+
+/**
+* This one just says "sorry, can't sync now". This is used
+* in cases when the hotsync starts while KPilot is busy configuring
+* something and can't be interrupted.
+*/
+KDE_EXPORT class SorryAction : public SyncAction
+{
+public:
+ /**
+ * Constructor. The action will be executed on the given
+ * link @p device . If the given string @p s is non-empty,
+ * print that message (it must be i18n()ed already) instead of
+ * the standard message.
+ */
+ SorryAction(KPilotLink *device, const QString &s=QString::null);
+
+protected:
+ /** Reimplemented from SyncAction. */
+ virtual bool exec();
+
+ /** Message to print to the sync log. */
+ QString fMessage;
+} ;
+
+/**
+* End the HotSync. This action cleans up the handheld and
+* removes cruft. There should be exactly @em one CleanupAction
+* executed during a HotSync. Since this action informs the
+* device that the HotSync is over, it should be the last
+* action executed.
+*/
+KDE_EXPORT class CleanupAction : public SyncAction
+{
+public:
+ /** Constructor. */
+ CleanupAction(KPilotLink *device);
+
+protected:
+ /** Reimplemented from SyncAction. */
+ virtual bool exec();
+} ;
+
+/**
+* This action is intended to test the link with the handheld
+* and not do anything spectacular. It lists all the databases
+* on the handheld in the sync log.
+*/
+KDE_EXPORT class TestLink : public SyncAction
+{
+public:
+ /** Constructor. */
+ TestLink(KPilotLink *device);
+
+protected:
+ /** Reimplemented from SyncAction. */
+ virtual bool exec();
+} ;
+
+
+#endif
diff --git a/kpilot/lib/idmapper.cc b/kpilot/lib/idmapper.cc
new file mode 100644
index 000000000..6e1031efe
--- /dev/null
+++ b/kpilot/lib/idmapper.cc
@@ -0,0 +1,247 @@
+/*
+** Copyright (C) 2006 Bertjan Broeksema <[email protected]>
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "idmapper.h"
+#include "idmapperxml.h"
+#include "options.h"
+
+#include <qsqldatabase.h>
+#include <qfile.h>
+
+#include <kglobal.h>
+#include <kstandarddirs.h>
+
+class IDMapperPrivate
+{
+public:
+ IDMapperPrivate()
+ {
+ fXmlSource = 0L;
+ }
+
+ ~IDMapperPrivate()
+ {
+ FUNCTIONSETUP;
+
+ KPILOT_DELETE(fXmlSource);
+ }
+
+ IDMapperXml *fXmlSource;
+};
+
+IDMapper::IDMapper()
+{
+ FUNCTIONSETUP;
+
+ fP = new IDMapperPrivate();
+
+ QString dbPath = KGlobal::dirs()->
+ saveLocation("data", CSL1("kpilot/") );
+ QString dbFile = dbPath + CSL1("mapping.xml");
+
+ if( !openDatasource( dbFile ) )
+ {
+ DEBUGKPILOT << fname << "Could not open or create xml file." << endl;
+ }
+}
+
+IDMapper::IDMapper( const QString &file)
+{
+ FUNCTIONSETUP;
+
+ fP = new IDMapperPrivate();
+
+ if( !openDatasource( file ) )
+ {
+ DEBUGKPILOT << fname << "Could not open or create xml file." << endl;
+ }
+}
+
+IDMapper::~IDMapper()
+{
+ KPILOT_DELETE(fP);
+}
+
+bool IDMapper::openDatasource( const QString &file )
+{
+ FUNCTIONSETUP;
+
+ fP->fXmlSource = new IDMapperXml( file );
+ return fP->fXmlSource->open();
+}
+
+void IDMapper::registerPCObjectId( const QString &conduit, const QString &uid )
+{
+ FUNCTIONSETUP;
+
+ IDMapping mapping = IDMapping( conduit );
+ mapping.setUid( uid );
+
+ fP->fXmlSource->addMapping( mapping );
+ fP->fXmlSource->save();
+}
+
+void IDMapper::registerHHObjectId( const QString &conduit, recordid_t pid )
+{
+ FUNCTIONSETUP;
+
+ IDMapping mapping = IDMapping( conduit );
+ mapping.setPid( pid );
+
+ fP->fXmlSource->addMapping( mapping );
+ fP->fXmlSource->save();
+}
+
+QValueList<QString> IDMapper::getPCObjectIds( const QString &conduit )
+{
+ FUNCTIONSETUP;
+
+ QValueList<IDMapping> &mappings = fP->fXmlSource->mappings();
+ QValueList<IDMapping>::iterator it;
+ QValueList<QString> uids;
+
+ DEBUGKPILOT << fname << ": total " << mappings.count() << endl;
+
+ for ( it = mappings.begin(); it != mappings.end(); ++it )
+ {
+ IDMapping &mapping = (*it);
+
+ DEBUGKPILOT << fname << ": mapping.conduit() = " << mapping.conduit() << endl;
+ DEBUGKPILOT << fname << ": conduit = " << conduit << endl;
+
+ if( (mapping.conduit() == conduit) && !mapping.uid().isNull() )
+ {
+ DEBUGKPILOT << fname << ": mapping.conduit() == conduit" << endl;
+ uids.append( mapping.uid() );
+ }
+ }
+
+ return uids;
+}
+
+QValueList<recordid_t> IDMapper::getHHObjectIds( const QString &conduit )
+{
+ FUNCTIONSETUP;
+
+ QValueList<IDMapping> &mappings = fP->fXmlSource->mappings();
+ QValueList<IDMapping>::iterator it;
+ QValueList<recordid_t> pids;
+
+ for ( it = mappings.begin(); it != mappings.end(); ++it )
+ {
+ IDMapping &mapping = *it;
+ DEBUGKPILOT << fname << ": mapping.conduit() = " << mapping.conduit() << endl;
+ DEBUGKPILOT << fname << ": " << mapping.pid() << endl;
+ if( mapping.conduit() == conduit && mapping.pid() != 0 )
+ {
+ DEBUGKPILOT << fname << ": mapping.conduit() == conduit" << endl;
+ pids.append( mapping.pid() );
+ }
+ }
+
+ return pids;
+}
+
+bool IDMapper::hasPCId( const QString &conduit, recordid_t pid )
+{
+ FUNCTIONSETUP;
+
+ QValueList<IDMapping> &mappings = fP->fXmlSource->mappings();
+ QValueList<IDMapping>::iterator it;
+
+ for ( it = mappings.begin(); it != mappings.end(); ++it )
+ {
+ IDMapping &mapping = *it;
+ if( mapping.conduit() == conduit && mapping.pid() == pid )
+ {
+ return !mapping.uid().isNull();
+ }
+ }
+
+ return false;
+}
+
+bool IDMapper::hasHHId( const QString &conduit, const QString &uid )
+{
+ FUNCTIONSETUP;
+
+ QValueList<IDMapping> &mappings = fP->fXmlSource->mappings();
+ QValueList<IDMapping>::iterator it;
+
+ for ( it = mappings.begin(); it != mappings.end(); ++it )
+ {
+ IDMapping &mapping = *it;
+ if( mapping.conduit() == conduit && mapping.uid() == uid )
+ {
+ return mapping.pid() != 0;
+ }
+ }
+
+ return false;
+}
+
+void IDMapper::setHHObjectId( const QString &conduit, const QString &uid
+ , recordid_t pid )
+{
+ FUNCTIONSETUP;
+
+ bool modified = false;
+
+ QValueList<IDMapping> &mappings = fP->fXmlSource->mappings();
+ QValueList<IDMapping>::iterator it;
+
+ for ( it = mappings.begin(); it != mappings.end(); ++it )
+ {
+ IDMapping &mapping = *it;
+ if( mapping.conduit() == conduit && mapping.uid() == uid )
+ {
+ mapping.setPid( pid );
+ fP->fXmlSource->save();
+ modified = true;
+ }
+ }
+}
+
+void IDMapper::setPCObjectId( const QString &conduit, recordid_t pid
+ , const QString &uid )
+{
+ FUNCTIONSETUP;
+
+ bool modified = false;
+
+ QValueList<IDMapping> &mappings = fP->fXmlSource->mappings();
+ QValueList<IDMapping>::iterator it;
+
+ for ( it = mappings.begin(); it != mappings.end(); ++it )
+ {
+ IDMapping &mapping = *it;
+ if( mapping.conduit() == conduit && mapping.pid() == pid )
+ {
+ mapping.setUid( uid );
+ fP->fXmlSource->save();
+ modified = true;
+ }
+ }
+}
diff --git a/kpilot/lib/idmapper.h b/kpilot/lib/idmapper.h
new file mode 100644
index 000000000..0364dbc93
--- /dev/null
+++ b/kpilot/lib/idmapper.h
@@ -0,0 +1,159 @@
+#ifndef _KPILOT_IDMAPPER_H
+#define _KPILOT_IDMAPPER_H
+/*
+** Copyright (C) 2006 Bertjan Broeksema <[email protected]>
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qvaluelist.h>
+
+#include "pi-macros.h"
+
+#include <kconfig.h>
+
+class IDMapperPrivate;
+
+/**
+ * Much of the conduits are recordbased. This class can be used bij the conduits
+ * to keep track of the mapping between records on the handheld and records on
+ * the pc.
+ */
+class IDMapper
+{
+public:
+ /**
+ * Creates a new IDMapper with default datasource.
+ */
+ IDMapper();
+
+ /**
+ * Creates a new IDMapper with file as datasource.
+ */
+ IDMapper( const QString &file );
+
+ ~IDMapper();
+
+ /**
+ * Adds an uid for PC objects to the database.
+ */
+ void registerPCObjectId( const QString &conduit, const QString &uid );
+
+ /**
+ * Returns all known uid's for given conduit.
+ */
+ QValueList<QString> getPCObjectIds( const QString &conduit );
+
+ /**
+ * Adds a pid for HH objects to the database.
+ */
+ void registerHHObjectId( const QString &conduit, recordid_t pid );
+
+ /**
+ * Returns all know pids for given conduit.
+ */
+ QValueList<recordid_t> getHHObjectIds( const QString &conduit );
+
+ /**
+ * Sets the PC uid for the handheld record with pid. Does nothing when
+ * there is no handheld record with pid.
+ */
+ void setPCObjectId( const QString &conduit, recordid_t pid
+ , const QString &uid );
+
+ /**
+ * Sets the PC uid for the handheld record with pid. Does nothing when
+ * there is no handheld record with pid.
+ */
+ void setHHObjectId( const QString &conduit, const QString &uid
+ , recordid_t pid );
+
+ /**
+ * Returns the PC uid for the handheld record with pid. Returns 0 when no
+ * pid exists for given uid.
+ */
+ recordid_t getHHObjectId( const QString &conduit, const QString &uid );
+
+ /**
+ * Returns the HH pid for the PC record with uid. Returns an empty string
+ * when no uid exists for given pid.
+ */
+ QString getHHObjectId( const QString &conduit, recordid_t pid );
+
+ /**
+ * Returns true when there is a uid set for given pid. The conduit itself
+ * must determine if the two objects are in sync if this function returns
+ * true.
+ */
+ bool hasPCId( const QString &conduit, recordid_t pid );
+
+ /**
+ * Returns true when there is a pid set for given uid. The conduit itself
+ * must determine if the two objects are in sync if this function returns
+ * true.
+ */
+ bool hasHHId( const QString &conduit, const QString &uid );
+
+ /**
+ * Sets the time that the two objects where last synced. The conduits
+ * should call this method (or the pid version) when two objects are synced.
+ * When the uid does not exist nothing happens.
+ */
+ void setLastSyncTime( const QString &conduit, const QString &uid,
+ const QDateTime &date );
+
+ /**
+ * Sets the time that the two objects where last synced. The conduits
+ * should call this (or the uid version) method when two objects are synced.
+ * When the pid does not exist nothing happens.
+ */
+ void setLastSyncTime( const QString &conduit, recordid_t pid
+ , const QDateTime &date );
+
+ /**
+ * Returns the date/time for the last time that the item with uid was
+ * synced. This date is set by:
+ * - setLastSyncTime (uid/pid)
+ *
+ * Returns a null datetime when the pid does not excist.
+ */
+ QDateTime lastTimeSynced( const QString &conduit, const QString &uid );
+
+ /**
+ * Returns the date/time for the last time that the item with pid was
+ * synced. This date is set by:
+ * - setLastSyncTime (uid/pid)
+ *
+ * Returns a null datetime when the pid does not excist.
+ */
+ QDateTime lastTimeSynced( const QString &conduit, recordid_t pid );
+
+protected:
+ bool openDatasource( const QString &file );
+
+private:
+ IDMapperPrivate *fP;
+};
+
+#endif
diff --git a/kpilot/lib/idmapperxml.cc b/kpilot/lib/idmapperxml.cc
new file mode 100644
index 000000000..a2a78a0c9
--- /dev/null
+++ b/kpilot/lib/idmapperxml.cc
@@ -0,0 +1,213 @@
+/*
+** Copyright (C) 2006 Bertjan Broeksema <[email protected]>
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "idmapperxml.h"
+
+#include "options.h"
+
+IDMapperXml::IDMapperXml( const QString &file ) : fFile(file)
+ , fCurrentMapping( 0l )
+{
+}
+
+IDMapperXml::~IDMapperXml()
+{
+ FUNCTIONSETUP;
+}
+
+bool IDMapperXml::open()
+{
+ FUNCTIONSETUP;
+
+ root = doc.createElement( CSL1("mappings") );
+ QDomNode node = doc.createProcessingInstruction(CSL1("xml")
+ ,CSL1("version=\"1.0\" encoding=\"UTF-8\""));
+
+ doc.appendChild( node );
+ doc.appendChild( root );
+
+ if( !fFile.exists() )
+ {
+ DEBUGKPILOT << fname << ": Creating " << fFile.name() << endl;
+
+ if( fFile.open( IO_ReadWrite ) )
+ {
+ QTextStream out( &fFile );
+ doc.save( out, 4 );
+ fFile.close();
+ return true;
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": Could not create " << fFile.name() << endl;
+ return false;
+ }
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": Parsing file " << fFile.name() << endl;
+ QXmlSimpleReader reader;
+ reader.setContentHandler( this );
+
+ // Make sure that the file is closed after parsing.
+ bool result = reader.parse( fFile );
+ fFile.close();
+
+ return result;
+ }
+}
+
+void IDMapperXml::save()
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname << ": Saving " << fMappings.count()
+ << " mappings..." << endl;
+ DEBUGKPILOT << fname << ": ";
+
+ QValueList<IDMapping>::const_iterator it;
+ for ( it = fMappings.begin(); it != fMappings.end(); ++it )
+ {
+ DEBUGKPILOT << ".";
+
+ IDMapping mapping = (*it);
+
+ DEBUGKPILOT << fname << ": " << mapping.conduit();
+
+ QDomElement mappingElement = doc.createElement( CSL1("mapping") );
+ mappingElement.setAttribute( CSL1("conduit"), mapping.conduit() );
+
+ if( !mapping.uid().isNull() )
+ {
+ QDomElement uidElement = doc.createElement( CSL1("uid") );
+ uidElement.setAttribute( CSL1("value"), mapping.uid() );
+ mappingElement.appendChild( uidElement );
+ }
+
+ if( mapping.pid() != 0 )
+ {
+ QDomElement uidElement = doc.createElement( CSL1("pid") );
+ uidElement.setAttribute( CSL1("value"), mapping.pid() );
+ mappingElement.appendChild( uidElement );
+ }
+
+ if( !mapping.lastSyncTime().isNull() )
+ {
+ QDomElement uidElement = doc.createElement( CSL1("pid") );
+ uidElement.setAttribute( CSL1("value"), QString::number( mapping.pid() ) );
+ mappingElement.appendChild( uidElement );
+ }
+
+ root.appendChild( mappingElement );
+ }
+
+ if( fFile.open( IO_ReadWrite ) )
+ {
+ QTextStream out( &fFile );
+ doc.save( out, 4 );
+ fFile.close();
+
+ DEBUGKPILOT << endl << fname << ": finished saving." << endl;
+ }
+}
+
+void IDMapperXml::addMapping( const IDMapping &mapping )
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname << ": " << mapping.conduit() << endl;
+
+ fMappings.append( mapping );
+
+ DEBUGKPILOT << fname << ": " << fMappings.first().conduit() << endl;
+}
+
+QValueList<IDMapping>& IDMapperXml::mappings()
+{
+ return fMappings;
+}
+
+bool IDMapperXml::startElement( const QString &namespaceURI
+ , const QString &localName, const QString &qName
+ , const QXmlAttributes &attribs )
+{
+ FUNCTIONSETUP;
+ Q_UNUSED(namespaceURI);
+ Q_UNUSED(localName);
+
+ if( qName == CSL1("mapping") )
+ {
+ QString conduit( attribs.value( CSL1("conduit") ) );
+
+ fCurrentMapping = new IDMapping( conduit );
+ }
+ else if( qName == CSL1("uid") )
+ {
+ fCurrentMapping->setUid( attribs.value( CSL1("value") ) );
+ }
+ else if( qName == CSL1("pid") )
+ {
+ fCurrentMapping->setPid( attribs.value( CSL1("value") ).toULong() );
+ }
+ else if( qName == CSL1("lastsync") )
+ {
+ // NOTE: this isn't very robuust!
+ // Parses only dates in the form: dd-mm-yyyy hh:mm:ss
+ QString date = attribs.value( CSL1("value") );
+ int day = date.left(2).toInt();
+ int month = date.mid(3,2).toInt();
+ int year = date.mid(6, 4).toInt();
+
+ int hour = date.mid(11,2).toInt();
+ int minute = date.mid(14,2).toInt();
+ int second = date.mid(17,2).toInt();
+
+ QDate tmpDate = QDate( year, month, day );
+ QTime tmpTime = QTime( hour, minute, second );
+
+ fCurrentMapping->setLastSyncTime( QDateTime( tmpDate, tmpTime ) );
+ }
+
+ return true;
+}
+
+bool IDMapperXml::endElement( const QString &namespaceURI
+ , const QString &localName, const QString &qName )
+{
+ FUNCTIONSETUP;
+
+ Q_UNUSED(namespaceURI);
+ Q_UNUSED(localName);
+ Q_UNUSED(qName);
+
+ if( qName == CSL1("mapping") )
+ {
+ addMapping( *fCurrentMapping );
+ delete fCurrentMapping;
+ fCurrentMapping = 0l;
+ }
+
+ return true;
+}
diff --git a/kpilot/lib/idmapperxml.h b/kpilot/lib/idmapperxml.h
new file mode 100644
index 000000000..455673888
--- /dev/null
+++ b/kpilot/lib/idmapperxml.h
@@ -0,0 +1,84 @@
+#ifndef _KPILOT_IDMAPPERXML_H
+#define _KPILOT_IDMAPPERXML_H
+/*
+** Copyright (C) 2006 Bertjan Broeksema <[email protected]>
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "idmapping.h"
+
+#include <qxml.h>
+#include <qdom.h>
+#include <qstring.h>
+#include <qptrcollection.h>
+
+class IDMapperXml : public QXmlDefaultHandler
+{
+public:
+ IDMapperXml( const QString &file );
+
+ ~IDMapperXml();
+
+ /**
+ * Opens and parses the file or creates a new one if the file does not exist.
+ */
+ bool open();
+
+ /**
+ * Saves the current mappings to the xml-file. Note this function must be
+ * called after changes and before deleting the IDMapperXml object. Otherwise
+ * the changes won't be saved.
+ */
+ void save();
+
+ /**
+ * Adds a mapping to the collection of mappings.
+ */
+ void addMapping( const IDMapping &mapping );
+
+ /**
+ * Returns the collection of mappings.
+ */
+ QValueList<IDMapping> &mappings();
+
+ /**
+ * Overloaded function to parse the xml file.
+ */
+ bool startElement( const QString &namespaceURI, const QString &localName
+ , const QString &qName, const QXmlAttributes &attribs );
+
+ /**
+ * Overloaded function to parse the xml file.
+ */
+ bool endElement( const QString &namespaceURI, const QString &localName
+ , const QString &qName );
+
+private:
+ QFile fFile;
+ QDomDocument doc;
+ QDomElement root;
+ IDMapping *fCurrentMapping;
+ QValueList<IDMapping> fMappings;
+};
+
+#endif
diff --git a/kpilot/lib/idmapping.cc b/kpilot/lib/idmapping.cc
new file mode 100644
index 000000000..7a49e9e3e
--- /dev/null
+++ b/kpilot/lib/idmapping.cc
@@ -0,0 +1,89 @@
+/*
+** Copyright (C) 2006 Bertjan Broeksema <[email protected]>
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "idmapping.h"
+
+IDMapping::IDMapping()
+{
+}
+
+IDMapping::IDMapping( const QString &conduit )
+{
+ fConduit = conduit;
+ fPid = 0;
+}
+
+IDMapping::IDMapping( const IDMapping &m )
+{
+ fConduit = m.fConduit;
+ fUid = m.fUid;
+ fPid = m.fPid;
+ fLastSync = m.fLastSync;
+}
+
+IDMapping IDMapping::operator=( const IDMapping &m )
+{
+ IDMapping local( m.fConduit );
+ local.fUid = m.fUid;
+ local.fPid = m.fPid;
+ local.fLastSync = m.fLastSync;
+
+ return local;
+}
+
+void IDMapping::setUid( const QString &uid )
+{
+ fUid = uid;
+}
+
+void IDMapping::setPid( recordid_t pid )
+{
+ fPid = pid;
+}
+
+void IDMapping::setLastSyncTime( const QDateTime &datetime )
+{
+ fLastSync = datetime;
+}
+
+QString IDMapping::conduit() const
+{
+ return fConduit;
+}
+
+QString IDMapping::uid() const
+{
+ return fUid;
+}
+
+recordid_t IDMapping::pid() const
+{
+ return fPid;
+}
+
+QDateTime IDMapping::lastSyncTime() const
+{
+ return fLastSync;
+}
diff --git a/kpilot/lib/idmapping.h b/kpilot/lib/idmapping.h
new file mode 100644
index 000000000..acb17dc8a
--- /dev/null
+++ b/kpilot/lib/idmapping.h
@@ -0,0 +1,66 @@
+#ifndef _KPILOT_IDMAPPING_H
+#define _KPILOT_IDMAPPING_H
+/*
+** Copyright (C) 2006 Bertjan Broeksema <[email protected]>
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "pi-macros.h"
+
+#include <qstring.h>
+#include <qdatetime.h>
+
+class IDMapping
+{
+public:
+ IDMapping();
+
+ IDMapping( const QString &conduit );
+
+ IDMapping( const IDMapping &m );
+
+ IDMapping operator=( const IDMapping &m );
+
+ void setUid( const QString &uid );
+
+ void setPid( recordid_t uid );
+
+ void setLastSyncTime( const QDateTime &datetime );
+
+ QString conduit() const;
+
+ QString uid() const;
+
+ recordid_t pid() const;
+
+ QDateTime lastSyncTime() const;
+
+private:
+ QString fConduit;
+ QString fUid;
+ recordid_t fPid;
+ QDateTime fLastSync;
+};
+
+#endif
diff --git a/kpilot/lib/kpilotdevicelink.cc b/kpilot/lib/kpilotdevicelink.cc
new file mode 100644
index 000000000..55027d763
--- /dev/null
+++ b/kpilot/lib/kpilotdevicelink.cc
@@ -0,0 +1,966 @@
+/* KPilot
+ **
+ ** Copyright (C) 1998-2001 by Dan Pilone
+ ** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+ ** Copyright (C) 2006-2007 Adriaan de Groot <[email protected]>
+ ** Copyright (C) 2007 Jason 'vanRijn' Kasper <[email protected]>
+ **
+ */
+
+/*
+ ** This program is free software; you can redistribute it and/or modify
+ ** it under the terms of the GNU Lesser General Public License as published by
+ ** the Free Software Foundation; either version 2.1 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU Lesser General Public License for more details.
+ **
+ ** You should have received a copy of the GNU Lesser General Public License
+ ** along with this program in a file called COPYING; if not, write to
+ ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ ** MA 02110-1301, USA.
+ */
+
+/*
+ ** Bug reports and questions can be sent to [email protected]
+ */
+
+#include "options.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <iostream>
+
+#include <pi-source.h>
+#include <pi-socket.h>
+#include <pi-dlp.h>
+#include <pi-file.h>
+#include <pi-buffer.h>
+
+#include <qdir.h>
+#include <qtimer.h>
+#include <qdatetime.h>
+#include <qthread.h>
+#include <qsocketnotifier.h>
+
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+
+#include "pilotUser.h"
+#include "pilotSysInfo.h"
+#include "pilotCard.h"
+#include "pilotSerialDatabase.h"
+#include "pilotLocalDatabase.h"
+
+#include "kpilotlink.h"
+#include "kpilotdevicelinkPrivate.moc"
+#include "kpilotdevicelink.moc"
+
+
+DeviceMap *DeviceMap::mThis = 0L;
+
+
+static inline void startOpenTimer(DeviceCommThread *dev, QTimer *&t)
+{
+ if ( !t)
+ {
+ t = new QTimer(dev);
+ QObject::connect(t, SIGNAL(timeout()), dev, SLOT(openDevice()));
+ }
+ // just a single-shot timer. we'll know when to start it again...
+ t->start(1000, true);
+}
+
+DeviceCommThread::DeviceCommThread(KPilotDeviceLink *d) :
+ QThread(),
+ fDone(true),
+ fHandle(d),
+ fOpenTimer(0L),
+ fSocketNotifier(0L),
+ fSocketNotifierActive(false),
+ fWorkaroundUSBTimer(0L),
+ fPilotSocket(-1),
+ fTempSocket(-1),
+ fAcceptedCount(0)
+{
+ FUNCTIONSETUP;
+}
+
+
+DeviceCommThread::~DeviceCommThread()
+{
+ FUNCTIONSETUPL(2);
+ close();
+ KPILOT_DELETE(fWorkaroundUSBTimer);
+}
+
+void DeviceCommThread::close()
+{
+ FUNCTIONSETUPL(2);
+
+ KPILOT_DELETE(fWorkaroundUSBTimer);
+ KPILOT_DELETE(fOpenTimer);
+ KPILOT_DELETE(fSocketNotifier);
+ fSocketNotifierActive=false;
+
+ if (fTempSocket != -1)
+ {
+ DEBUGKPILOT << fname
+ << ": device comm thread closing socket: ["
+ << fTempSocket << "]" << endl;
+
+ pi_close(fTempSocket);
+ }
+
+ if (fPilotSocket != -1)
+ {
+ DEBUGKPILOT << fname
+ << ": device comm thread closing socket: ["
+ << fPilotSocket << "]" << endl;
+
+ pi_close(fPilotSocket);
+ }
+
+ fTempSocket = (-1);
+ fPilotSocket = (-1);
+
+ DeviceMap::self()->unbindDevice(link()->fRealPilotPath);
+}
+
+void DeviceCommThread::reset()
+{
+ FUNCTIONSETUP;
+
+ if (link()->fMessages->shouldPrint(Messages::OpenFailMessage))
+ {
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogMessage,
+ i18n("Could not open device: %1 (will retry)")
+ .arg(link()->pilotPath() )));
+ }
+
+ link()->fMessages->reset();
+ close();
+
+ // Timer already deleted by close() call.
+ startOpenTimer(this,fOpenTimer);
+
+ link()->fLinkStatus = WaitingForDevice;
+}
+
+/**
+ * This is an asyncronous process. We try to create a socket with the Palm
+ * and then bind to it (in open()). If we're able to do those 2 things, then
+ * we do 2 things: we set a timeout timer (which will tell us that X amount of
+ * time has transpired before we get into the meat of the sync transaction), and
+ * we also set up a QSocketNotifier, which will tell us when data is available
+ * to be read from the Palm socket. If we were unable to create a socket
+ * and/or bind to the Palm in this method, we'll start our timer again.
+ */
+void DeviceCommThread::openDevice()
+{
+ FUNCTIONSETUPL(2);
+
+ bool deviceOpened = false;
+
+ // This transition (from Waiting to Found) can only be
+ // taken once.
+ //
+ if (link()->fLinkStatus == WaitingForDevice)
+ {
+ link()->fLinkStatus = FoundDevice;
+ }
+
+ if (link()->fMessages->shouldPrint(Messages::OpenMessage))
+ {
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogMessage,
+ i18n("Trying to open device %1...")
+ .arg(link()->fPilotPath)));
+ }
+
+ // if we're not supposed to be done, try to open the main pilot
+ // path...
+ if (!fDone && link()->fPilotPath.length() > 0)
+ {
+ DEBUGKPILOT << fname << ": Opening main pilot path: ["
+ << link()->fPilotPath << "]." << endl;
+ deviceOpened = open(link()->fPilotPath);
+ }
+
+ // only try the temp device if our earlier attempt didn't work and the temp
+ // device is different than the main device, and it's a non-empty
+ // string
+ bool tryTemp = !deviceOpened && (link()->fTempDevice.length() > 0) && (link()->fPilotPath != link()->fTempDevice);
+
+ // if we're not supposed to be done, and we should try the temp
+ // device, try the temp device...
+ if (!fDone && tryTemp)
+ {
+ DEBUGKPILOT << fname << ": Couldn't open main pilot path. "
+ << "Now trying temp device: ["
+ << link()->fTempDevice << "]." << endl;
+ deviceOpened = open(link()->fTempDevice);
+ }
+
+ // if we couldn't connect, try to connect again...
+ if (!fDone && !deviceOpened)
+ {
+ startOpenTimer(this, fOpenTimer);
+ }
+}
+
+bool DeviceCommThread::open(const QString &device)
+{
+ FUNCTIONSETUPL(2);
+
+ int ret;
+ int e = 0;
+ QString msg;
+
+ if (fTempSocket != -1)
+ {
+ pi_close(fTempSocket);
+ }
+ fTempSocket = (-1);
+
+ link()->fRealPilotPath
+ = KStandardDirs::realFilePath(device.isEmpty() ? link()->fPilotPath : device);
+
+ if ( !DeviceMap::self()->canBind(link()->fRealPilotPath) )
+ {
+ msg = i18n("Already listening on that device");
+
+ WARNINGKPILOT << "Pilot Path: ["
+ << link()->fRealPilotPath << "] already connected." << endl;
+ WARNINGKPILOT << msg << endl;
+
+ link()->fLinkStatus = PilotLinkError;
+
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogError, msg));
+
+ return false;
+ }
+
+ DEBUGKPILOT << fname << ": Trying to create socket." << endl;
+
+ fTempSocket = pi_socket(PI_AF_PILOT, PI_SOCK_STREAM, PI_PF_DLP);
+
+ if (fTempSocket < 0)
+ {
+ e = errno;
+ msg = i18n("Cannot create socket for communicating "
+ "with the Pilot (%1)").arg(errorMessage(e));
+ DEBUGKPILOT << msg << endl;
+ DEBUGKPILOT << "(" << strerror(e) << ")" << endl;
+
+ link()->fLinkStatus = PilotLinkError;
+
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogError, msg));
+
+ return false;
+ }
+
+ DEBUGKPILOT << fname << ": Got socket: [" << fTempSocket << "]" << endl;
+
+ link()->fLinkStatus = CreatedSocket;
+
+ DEBUGKPILOT << fname << ": Binding to path: ["
+ << link()->fRealPilotPath << "]" << endl;
+
+ ret = pi_bind(fTempSocket, QFile::encodeName(link()->fRealPilotPath));
+
+ if (ret < 0)
+ {
+ DEBUGKPILOT << fname
+ << ": pi_bind error: ["
+ << strerror(errno) << "]" << endl;
+
+ e = errno;
+ msg = i18n("Cannot open Pilot port \"%1\". ").arg(link()->fRealPilotPath);
+
+ DEBUGKPILOT << msg << endl;
+ DEBUGKPILOT << "(" << strerror(e) << ")" << endl;
+
+ link()->fLinkStatus = PilotLinkError;
+
+ if (link()->fMessages->shouldPrint(Messages::OpenFailMessage))
+ {
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogError, msg));
+ }
+
+ return false;
+ }
+
+ link()->fLinkStatus = DeviceOpen;
+ DeviceMap::self()->bindDevice(link()->fRealPilotPath);
+
+ fSocketNotifier = new QSocketNotifier(fTempSocket,
+ QSocketNotifier::Read, this);
+ QObject::connect(fSocketNotifier, SIGNAL(activated(int)),
+ this, SLOT(acceptDevice()));
+ fSocketNotifierActive=true;
+
+ /**
+ * We _always_ want to set a maximum amount of time that we will wait
+ * for the sync process to start. In the case where our user
+ * has told us that he has a funky USB device, set the workaround timeout
+ * for shorter than normal.
+ */
+ int timeout=20000;
+ if (link()->fWorkaroundUSB)
+ {
+ timeout=5000;
+ }
+
+ fWorkaroundUSBTimer = new QTimer(this);
+ connect(fWorkaroundUSBTimer, SIGNAL(timeout()), this, SLOT(workaroundUSB()));
+ fWorkaroundUSBTimer->start(timeout, true);
+
+ return true;
+}
+
+/**
+ * We've been notified by our QSocketNotifier that we have data available on the
+ * socket. Try to go through the remaining steps of the connnection process.
+ * Note: If we return at all from this before the very end without a successful
+ * connection, we need to make sure we restart our connection open timer, otherwise
+ * it won't be restarted.
+ */
+void DeviceCommThread::acceptDevice()
+{
+ FUNCTIONSETUP;
+
+ int ret;
+
+ /**
+ * Our socket notifier should be the only reason that we end up here.
+ * If we're here without him being active, we have a problem. Try to clean
+ * up and get out.
+ */
+ if (!fSocketNotifierActive)
+ {
+ if (!fAcceptedCount)
+ {
+ kdWarning() << k_funcinfo << ": Accidentally in acceptDevice()"
+ << endl;
+ }
+ fAcceptedCount++;
+ if (fAcceptedCount>10)
+ {
+ // Damn the torpedoes
+ KPILOT_DELETE(fSocketNotifier);
+ }
+ return;
+ }
+
+ if (fSocketNotifier)
+ {
+ // fSocketNotifier->setEnabled(false);
+ fSocketNotifierActive=false;
+ KPILOT_DELETE(fSocketNotifier);
+ }
+
+ DEBUGKPILOT << fname << ": Found connection on device: ["
+ << link()->pilotPath().latin1() << "]." <<endl;
+
+ DEBUGKPILOT << fname
+ << ": Current status: ["
+ << link()->statusString()
+ << "] and socket: [" << fTempSocket << "]" << endl;
+
+ ret = pi_listen(fTempSocket, 1);
+ if (ret < 0)
+ {
+ char *s = strerror(errno);
+
+ WARNINGKPILOT << "pi_listen returned: [" << s << "]" << endl;
+
+ // Presumably, strerror() returns things in
+ // local8Bit and not latin1.
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogError,
+ i18n("Cannot listen on Pilot socket (%1)").
+ arg(QString::fromLocal8Bit(s))));
+ reset();
+ return;
+ }
+
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogProgress, QString::null, 10));
+
+ DEBUGKPILOT << fname <<
+ ": Listening to pilot. Now trying accept..." << endl;
+
+ int timeout = 20;
+ fPilotSocket = pi_accept_to(fTempSocket, 0, 0, timeout);
+
+ if (fPilotSocket < 0)
+ {
+ char *s = strerror(errno);
+
+ WARNINGKPILOT << "pi_accept returned: [" << s << "]" << endl;
+
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogError, i18n("Cannot accept Pilot (%1)")
+ .arg(QString::fromLocal8Bit(s))));
+
+ link()->fLinkStatus = PilotLinkError;
+ reset();
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Link accept done." << endl;
+
+ if ((link()->fLinkStatus != DeviceOpen) || (fPilotSocket == -1))
+ {
+ link()->fLinkStatus = PilotLinkError;
+ WARNINGKPILOT << "Already connected or unable to connect!" << endl;
+
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogError, i18n("Cannot accept Pilot (%1)")
+ .arg(i18n("already connected"))));
+
+ reset();
+ return;
+ }
+
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogProgress, QString::null, 30));
+
+ DEBUGKPILOT << fname << ": doing dlp_ReadSysInfo..." << endl;
+
+ struct SysInfo sys_info;
+ if (dlp_ReadSysInfo(fPilotSocket, &sys_info) < 0)
+ {
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogError,
+ i18n("Unable to read system information from Pilot")));
+
+ link()->fLinkStatus=PilotLinkError;
+ reset();
+ return;
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": dlp_ReadSysInfo successful..." << endl;
+
+ KPILOT_DELETE(link()->fPilotSysInfo);
+ link()->fPilotSysInfo = new KPilotSysInfo(&sys_info);
+ DEBUGKPILOT << fname
+ << ": RomVersion: [" << link()->fPilotSysInfo->getRomVersion()
+ << "] Locale: [" << link()->fPilotSysInfo->getLocale()
+ << "] Product: [" << link()->fPilotSysInfo->getProductID()
+ << "]" << endl;
+ }
+
+ // If we've made it this far, make sure our USB workaround timer doesn't fire!
+ fWorkaroundUSBTimer->stop();
+ KPILOT_DELETE(fWorkaroundUSBTimer);
+
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogProgress, QString::null, 60));
+
+ KPILOT_DELETE(link()->fPilotUser);
+ link()->fPilotUser = new KPilotUser;
+
+ DEBUGKPILOT << fname << ": doing dlp_ReadUserInfo..." << endl;
+
+ /* Ask the pilot who it is. And see if it's who we think it is. */
+ dlp_ReadUserInfo(fPilotSocket, link()->fPilotUser->data());
+
+ QString n = link()->getPilotUser().name();
+ DEBUGKPILOT << fname
+ << ": Read user name: [" << n << "]" << endl;
+
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogProgress, i18n("Checking last PC..."), 90));
+
+ /* Tell user (via Pilot) that we are starting things up */
+ if ((ret=dlp_OpenConduit(fPilotSocket)) < 0)
+ {
+ DEBUGKPILOT << fname
+ << ": dlp_OpenConduit returned: [" << ret << "]" << endl;
+
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogError,
+ i18n("Could not read user information from the Pilot. "
+ "Perhaps you have a password set on the device?")));
+
+ }
+ link()->fLinkStatus = AcceptedDevice;
+
+ QApplication::postEvent(link(), new DeviceCommEvent(EventLogProgress, QString::null, 100));
+
+ DeviceCommEvent * ev = new DeviceCommEvent(EventDeviceReady);
+ ev->setCurrentSocket(fPilotSocket);
+ QApplication::postEvent(link(), ev);
+
+}
+
+void DeviceCommThread::workaroundUSB()
+{
+ FUNCTIONSETUP;
+
+ reset();
+}
+
+void DeviceCommThread::run()
+{
+ FUNCTIONSETUP;
+ fDone = false;
+
+ startOpenTimer(this, fOpenTimer);
+
+ int sleepBetweenPoll = 2;
+ // keep the thread alive until we're supposed to be done
+ while (!fDone)
+ {
+ QThread::sleep(sleepBetweenPoll);
+ }
+
+ close();
+ // now sleep one last bit to make sure the pthread inside
+ // pilot-link (potentially, if it's libusb) is done before we exit
+ QThread::sleep(1);
+
+ DEBUGKPILOT << fname << ": comm thread now done..." << endl;
+}
+
+KPilotDeviceLink::KPilotDeviceLink(QObject * parent, const char *name,
+ const QString &tempDevice) :
+ KPilotLink(parent, name), fLinkStatus(Init), fWorkaroundUSB(false),
+ fPilotSocket(-1), fTempDevice(tempDevice), fMessages(new Messages(this)), fDeviceCommThread(0L)
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname
+ << ": Pilot-link version: [" << PILOT_LINK_NUMBER
+ << "]" << endl;
+}
+
+KPilotDeviceLink::~KPilotDeviceLink()
+{
+ FUNCTIONSETUP;
+ close();
+ KPILOT_DELETE(fPilotSysInfo);
+ KPILOT_DELETE(fPilotUser);
+ KPILOT_DELETE(fMessages);
+}
+
+/* virtual */bool KPilotDeviceLink::isConnected() const
+{
+ return fLinkStatus == AcceptedDevice;
+}
+
+/* virtual */bool KPilotDeviceLink::event(QEvent *e)
+{
+ FUNCTIONSETUP;
+
+ bool handled = false;
+
+ if ((int)e->type() == EventDeviceReady)
+ {
+ DeviceCommEvent* t = static_cast<DeviceCommEvent*>(e);
+ fPilotSocket = t->currentSocket();
+ emit deviceReady( this);
+ handled = true;
+ }
+ else if ((int)e->type() == EventLogMessage)
+ {
+ DeviceCommEvent* t = static_cast<DeviceCommEvent*>(e);
+ emit logMessage(t->message());
+ handled = true;
+ }
+ else if ((int)e->type() == EventLogError)
+ {
+ DeviceCommEvent* t = static_cast<DeviceCommEvent*>(e);
+ emit logError(t->message());
+ handled = true;
+ }
+ else if ((int)e->type() == EventLogProgress)
+ {
+ DeviceCommEvent* t = static_cast<DeviceCommEvent*>(e);
+ emit logProgress(t->message(), t->progress());
+ handled = true;
+ }
+ else
+ {
+ handled = KPilotLink::event(e);
+ }
+
+ return handled;
+}
+
+void KPilotDeviceLink::stopCommThread()
+{
+ FUNCTIONSETUP;
+ if (fDeviceCommThread)
+ {
+ fDeviceCommThread->setDone(true);
+
+ // try to wait for our thread to finish, but don't
+ // block the main thread forever
+ if (fDeviceCommThread->running())
+ {
+ DEBUGKPILOT << fname
+ << ": comm thread still running. "
+ << "waiting for it to complete." << endl;
+ bool done = fDeviceCommThread->wait(5000);
+ if (!done)
+ {
+ DEBUGKPILOT << fname
+ << ": comm thread still running "
+ << "after wait(). "
+ << "going to have to terminate it."
+ << endl;
+ // not normally to be done, but we must make sure
+ // that this device doesn't come back alive
+ fDeviceCommThread->terminate();
+ fDeviceCommThread->wait();
+ }
+ }
+
+ fDeviceCommThread->close();
+
+ KPILOT_DELETE(fDeviceCommThread);
+ }
+}
+
+void KPilotDeviceLink::close()
+{
+ FUNCTIONSETUP;
+
+ stopCommThread();
+
+ fPilotSocket = (-1);
+}
+
+void KPilotDeviceLink::reset(const QString & dP)
+{
+ FUNCTIONSETUP;
+
+ fLinkStatus = Init;
+
+ // Release all resources
+ //
+ close();
+ fPilotPath = QString::null;
+
+ fPilotPath = dP;
+ if (fPilotPath.isEmpty())
+ fPilotPath = fTempDevice;
+ if (fPilotPath.isEmpty())
+ return;
+
+ reset();
+}
+
+void KPilotDeviceLink::startCommThread()
+{
+ FUNCTIONSETUP;
+
+ stopCommThread();
+
+ if (fTempDevice.isEmpty() && pilotPath().isEmpty())
+ {
+ WARNINGKPILOT << "No point in trying empty device."
+ << endl;
+
+ QString msg = i18n("The Pilot device is not configured yet.");
+ WARNINGKPILOT << msg << endl;
+
+ fLinkStatus = PilotLinkError;
+
+ emit logError(msg);
+ return;
+ }
+
+ fDeviceCommThread = new DeviceCommThread(this);
+ fDeviceCommThread->start();
+}
+
+void KPilotDeviceLink::reset()
+{
+ FUNCTIONSETUP;
+
+ fMessages->reset();
+ close();
+
+ checkDevice();
+
+ fLinkStatus = WaitingForDevice;
+
+ startCommThread();
+}
+
+void KPilotDeviceLink::checkDevice()
+{
+ // If the device exists yet doesn't have the right
+ // permissions, complain and then continue anyway.
+ //
+ QFileInfo fi(fPilotPath);
+ if (fi.exists())
+ {
+ // If it exists, it ought to be RW already.
+ //
+ if (!(fi.isReadable() && fi.isWritable()))
+ {
+ emit logError(i18n("Pilot device %1 is not read-write.")
+ .arg(fPilotPath));
+ }
+ }
+ else
+ {
+ // It doesn't exist, mention this in the log
+ // (relevant as long as we use only one device type)
+ //
+ emit
+ logError(i18n("Pilot device %1 does not exist. "
+ "Probably it is a USB device and will appear during a HotSync.")
+ .arg(fPilotPath));
+ // Suppress all normal and error messages about opening the device.
+ fMessages->block(Messages::OpenMessage | Messages::OpenFailMessage,
+ true);
+ }
+}
+
+void KPilotDeviceLink::setTempDevice(const QString &d)
+{
+ fTempDevice = d;
+ DeviceMap::self()->bindDevice(fTempDevice);
+}
+
+/* virtual */bool KPilotDeviceLink::tickle()
+{
+ // No FUNCTIONSETUP here because it may be called from
+ // a separate thread.
+ return pi_tickle(pilotSocket()) >= 0;
+}
+
+/* virtual */void KPilotDeviceLink::addSyncLogEntryImpl(const QString &entry)
+{
+ dlp_AddSyncLogEntry(fPilotSocket,
+ const_cast<char *>((const char *)Pilot::toPilot(entry)));
+}
+
+bool KPilotDeviceLink::installFile(const QString & f, const bool deleteFile)
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname << ": Installing file " << f << endl;
+
+ if (!QFile::exists(f))
+ return false;
+
+ char buffer[PATH_MAX];
+ memset(buffer, 0, PATH_MAX);
+ strlcpy(buffer, QFile::encodeName(f), PATH_MAX);
+ struct pi_file *pf = pi_file_open(buffer);
+
+ if (!f)
+ {
+ WARNINGKPILOT << "Cannot open file " << f << endl;
+ emit logError(i18n
+ ("<qt>Cannot install the file &quot;%1&quot;.</qt>").
+ arg(f));
+ return false;
+ }
+
+ if (pi_file_install(pf, fPilotSocket, 0, 0L) < 0)
+ {
+ WARNINGKPILOT << "Cannot pi_file_install " << f << endl;
+ emit logError(i18n
+ ("<qt>Cannot install the file &quot;%1&quot;.</qt>").
+ arg(f));
+ return false;
+ }
+
+ pi_file_close(pf);
+ if (deleteFile)
+ QFile::remove(f);
+
+ return true;
+}
+
+int KPilotDeviceLink::openConduit()
+{
+ return dlp_OpenConduit(fPilotSocket);
+}
+
+QString KPilotDeviceLink::statusString(LinkStatus l)
+{
+ QString s= CSL1("KPilotDeviceLink=");
+
+ switch (l)
+ {
+ case Init:
+ s.append(CSL1("Init"));
+ break;
+ case WaitingForDevice:
+ s.append(CSL1("WaitingForDevice"));
+ break;
+ case FoundDevice:
+ s.append(CSL1("FoundDevice"));
+ break;
+ case CreatedSocket:
+ s.append(CSL1("CreatedSocket"));
+ break;
+ case DeviceOpen:
+ s.append(CSL1("DeviceOpen"));
+ break;
+ case AcceptedDevice:
+ s.append(CSL1("AcceptedDevice"));
+ break;
+ case SyncDone:
+ s.append(CSL1("SyncDone"));
+ break;
+ case PilotLinkError:
+ s.append(CSL1("PilotLinkError"));
+ break;
+ case WorkaroundUSB:
+ s.append(CSL1("WorkaroundUSB"));
+ break;
+ }
+
+ return s;
+}
+
+QString KPilotDeviceLink::statusString() const
+{
+ return statusString(status() );
+}
+
+void KPilotDeviceLink::endSync(EndOfSyncFlags f)
+{
+ FUNCTIONSETUP;
+
+ if (UpdateUserInfo == f)
+ {
+ getPilotUser().setLastSyncPC((unsigned long) gethostid());
+ getPilotUser().setLastSyncDate(time(0));
+
+ DEBUGKPILOT << fname << ": Writing username " << getPilotUser().name() << endl;
+
+ dlp_WriteUserInfo(pilotSocket(), getPilotUser().data());
+ addSyncLogEntry(i18n("End of HotSync\n"));
+ }
+ dlp_EndOfSync(pilotSocket(), 0);
+ KPILOT_DELETE(fPilotSysInfo);
+ KPILOT_DELETE(fPilotUser);
+}
+
+int KPilotDeviceLink::getNextDatabase(int index, struct DBInfo *dbinfo)
+{
+ FUNCTIONSETUP;
+
+ pi_buffer_t buf = { 0, 0, 0 };
+ int r = dlp_ReadDBList(pilotSocket(), 0, dlpDBListRAM, index, &buf);
+ if (r >= 0)
+ {
+ memcpy(dbinfo, buf.data, sizeof(struct DBInfo));
+ }
+ return r;
+}
+
+// Find a database with the given name. Info about the DB is stored into dbinfo (e.g. to be used later on with retrieveDatabase).
+int KPilotDeviceLink::findDatabase(const char *name, struct DBInfo *dbinfo,
+ int index, unsigned long type, unsigned long creator)
+{
+ FUNCTIONSETUP;
+ return dlp_FindDBInfo(pilotSocket(), 0, index, const_cast<char *>(name),
+ type, creator, dbinfo);
+}
+
+bool KPilotDeviceLink::retrieveDatabase(const QString &fullBackupName,
+ DBInfo *info)
+{
+ FUNCTIONSETUP;
+
+ if (fullBackupName.isEmpty() || !info)
+ {
+ // Don't even bother trying to convert or retrieve.
+ return false;
+ }
+
+ DEBUGKPILOT << fname << ": Writing DB <" << info->name << "> "
+ << " to " << fullBackupName << endl;
+
+ QCString encodedName = QFile::encodeName(fullBackupName);
+ struct pi_file *f = pi_file_create(encodedName, info);
+
+ if (!f)
+ {
+ WARNINGKPILOT << "Failed, unable to create file" << endl;
+ return false;
+ }
+
+ if (pi_file_retrieve(f, pilotSocket(), 0, 0L) < 0)
+ {
+ WARNINGKPILOT << "Failed, unable to back up database" << endl;
+
+ pi_file_close(f);
+ return false;
+ }
+
+ pi_file_close(f);
+ return true;
+}
+
+KPilotLink::DBInfoList KPilotDeviceLink::getDBList(int cardno, int flags)
+{
+ bool cont=true;
+ DBInfoList dbs;
+ int index=0;
+ while (cont)
+ {
+ pi_buffer_t buf = { 0, 0, 0 };
+ pi_buffer_clear(&buf);
+ // DBInfo*dbi=new DBInfo();
+ if (dlp_ReadDBList(pilotSocket(), cardno, flags | dlpDBListMultiple,
+ index, &buf)<0)
+ {
+ cont=false;
+ }
+ else
+ {
+ DBInfo db_n;
+ DBInfo *db_it = (DBInfo *)buf.data;
+ int info_count = buf.used / sizeof(struct DBInfo);
+
+ while (info_count>0)
+ {
+ memcpy(&db_n, db_it, sizeof(struct DBInfo));
+ ++db_it;
+ info_count--;
+ dbs.append(db_n);
+ }
+ index=db_n.index+1;
+ }
+ }
+ return dbs;
+}
+
+const KPilotCard *KPilotDeviceLink::getCardInfo(int card)
+{
+ KPilotCard *cardinfo=new KPilotCard();
+ if (dlp_ReadStorageInfo(pilotSocket(), card, cardinfo->cardInfo())<0)
+ {
+ WARNINGKPILOT << "Could not get info for card " << card << endl;
+
+ KPILOT_DELETE(cardinfo);
+ return 0L;
+ }
+ return cardinfo;
+}
+
+PilotDatabase *KPilotDeviceLink::database(const QString &name)
+{
+ return new PilotSerialDatabase( this, name );
+}
+
+PilotDatabase *KPilotDeviceLink::database(const DBInfo *info)
+{
+ return new PilotSerialDatabase( this, info );
+}
+
diff --git a/kpilot/lib/kpilotdevicelink.h b/kpilot/lib/kpilotdevicelink.h
new file mode 100644
index 000000000..d2527aee4
--- /dev/null
+++ b/kpilot/lib/kpilotdevicelink.h
@@ -0,0 +1,220 @@
+#ifndef _KPILOT_KPILOTDEVICELINK_H
+#define _KPILOT_KPILOTDEVICELINK_H
+/*
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2006 Adriaan de Groot <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "kpilotlink.h"
+
+class QThread;
+
+class DeviceMap; ///< Globally tracks all devices that have a link assigned
+class Messages; ///< Tracks which messages have been printed
+class DeviceCommThread; ///< Thread for doing all palm device communications
+
+/**
+* The link behaves like a state machine most of the time:
+* it waits for the actual device to become available, and
+* then becomes ready to handle syncing.
+*/
+enum LinkStatus {
+ Init,
+ WaitingForDevice,
+ FoundDevice,
+ CreatedSocket,
+ DeviceOpen,
+ AcceptedDevice,
+ SyncDone,
+ PilotLinkError,
+ WorkaroundUSB
+} ;
+
+/**
+* Custom events we can be handling...
+*/
+enum DeviceCustomEvents {
+ EventLogMessage = QEvent::User + 777,
+ EventLogError,
+ EventLogProgress,
+ EventDeviceReady
+};
+
+/**
+* Definition of the device link class for physical
+* handheld devices, which communicate with the PC
+* using DLP / SLP via the pilot-link library.
+*/
+class KDE_EXPORT KPilotDeviceLink : public KPilotLink
+{
+friend class PilotSerialDatabase;
+friend class DeviceCommThread;
+
+Q_OBJECT
+
+public:
+ /**
+ * Constructor. Creates a link that can sync to a physical handheld.
+ * Call reset() on it to start looking for a device.
+ *
+ * @param parent Parent object.
+ * @param name Name of this object.
+ * @param tempDevice Path to device node to use as an alternative
+ * to the "normal" one set by KPilot.
+ */
+ KPilotDeviceLink( QObject *parent = 0,
+ const char *name = 0,
+ const QString &tempDevice = QString::null );
+
+ /**
+ * Destructor. This rudely ends the communication with the handheld.
+ * It is best to call endOfSync() or finishSync() before destroying
+ * the device.
+ */
+ virtual ~KPilotDeviceLink();
+
+ /**
+ * Get the status (state enum) of this link.
+ * @return The LinkStatus enum for the link's current state.
+ */
+ LinkStatus status() const
+ {
+ return fLinkStatus;
+ }
+
+ /** Get a human-readable string for the given status @p l. */
+ static QString statusString(LinkStatus l);
+
+ // The following API is the actual implementation of
+ // the KPilotLink API, for documentation see that file.
+ //
+ virtual QString statusString() const;
+ virtual bool isConnected() const;
+ virtual void reset( const QString & );
+ virtual void close();
+ virtual void reset();
+ virtual bool event(QEvent *e);
+ virtual bool tickle();
+ virtual const KPilotCard *getCardInfo(int card);
+ virtual void endSync( EndOfSyncFlags f );
+ virtual int openConduit();
+ virtual int getNextDatabase(int index,struct DBInfo *);
+ virtual int findDatabase(const char *name, struct DBInfo*,
+ int index=0, unsigned long type=0, unsigned long creator=0);
+ virtual bool retrieveDatabase(const QString &path, struct DBInfo *db);
+ virtual DBInfoList getDBList(int cardno=0, int flags=dlpDBListRAM);
+ virtual PilotDatabase *database( const QString &name );
+ virtual PilotDatabase *database( const DBInfo *info );
+
+protected:
+ virtual bool installFile(const QString &, const bool deleteFile);
+ virtual void addSyncLogEntryImpl( const QString &s );
+ virtual int pilotSocket() const
+ {
+ return fPilotSocket;
+ }
+
+
+private:
+ LinkStatus fLinkStatus;
+
+
+public:
+
+ /**
+ * Special-cases. Call this after a reset to set device-
+ * specific workarounds; the only one currently known
+ * is the Zire 31/72 T5 quirk of doing a non-HotSync
+ * connect when it's switched on.
+ */
+ void setWorkarounds(bool usb)
+ {
+ fWorkaroundUSB = usb;
+ }
+
+ /**
+ * Sets an additional device, which should be tried as fallback.
+ * Useful for hotplug enviroments, this device is used @em once
+ * for accepting a connection.
+ */
+ void setTempDevice( const QString &device );
+
+ /**
+ * Sets the device to use. Used by probe dialog, since we know
+ * what device to use, but we don't want to start the detection
+ * immediately.
+ */
+ void setDevice( const QString &device )
+ {
+ fPilotPath = device;
+ }
+
+
+protected:
+ /** Should we work around the Zire31/72 quirk? @see setWorkarounds() */
+ bool fWorkaroundUSB;
+
+
+ /**
+ * Check for device permissions and existence, emitting
+ * warnings for weird situations. This is primarily intended
+ * to inform the user.
+ */
+ void checkDevice();
+
+protected:
+ /**
+ * Path with resolved symlinks, to prevent double binding
+ * to the same device.
+ */
+ QString fRealPilotPath;
+
+ /**
+ * Pilot-link library handles for the device once it's opened.
+ */
+ int fPilotSocket;
+ QString fTempDevice;
+
+ /**
+ * Handle cases where we can't accept or open the device,
+ * and data remains available on the pilot socket.
+ */
+ int fAcceptedCount;
+
+ /**
+ * Start/Stop our device communication thread.
+ */
+ void startCommThread();
+ void stopCommThread();
+
+protected:
+ Messages *fMessages;
+ DeviceCommThread *fDeviceCommThread;
+} ;
+
+#endif
+
diff --git a/kpilot/lib/kpilotdevicelinkPrivate.h b/kpilot/lib/kpilotdevicelinkPrivate.h
new file mode 100644
index 000000000..be2bbda35
--- /dev/null
+++ b/kpilot/lib/kpilotdevicelinkPrivate.h
@@ -0,0 +1,330 @@
+#ifndef _KPILOT_KPILOTDEVICELINKPRIVATE_H
+#define _KPILOT_KPILOTDEVICELINKPRIVATE_H
+/*
+**
+** Copyright (C) 2007 by Jason 'vanRijn' Kasper <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <errno.h>
+
+#include <qstringlist.h>
+#include <qthread.h>
+
+#include "kpilotdevicelink.h"
+#include "options.h"
+
+class QTimer;
+class QSocketNotifier;
+
+// singleton helper class
+class DeviceMap
+{
+public:
+ static DeviceMap *self()
+ {
+ if (!mThis)
+ mThis = new DeviceMap();
+ return mThis;
+ }
+
+ bool canBind(const QString &device)
+ {
+ FUNCTIONSETUPL(5);
+ DEBUGKPILOT << fname << ": device: ["
+ << device << "]" << endl;
+
+ showList();
+ return !mBoundDevices.contains(device);
+ }
+
+ void bindDevice(const QString &device)
+ {
+ FUNCTIONSETUPL(5);
+ DEBUGKPILOT << fname << ": device: ["
+ << device << "]" << endl;
+
+ mBoundDevices.append(device);
+ showList();
+ }
+
+ void unbindDevice(const QString &device)
+ {
+ FUNCTIONSETUPL(5);
+ DEBUGKPILOT << fname << ": device: ["
+ << device << "]" << endl;
+
+ mBoundDevices.remove(device);
+ showList();
+ }
+
+protected:
+ DeviceMap()
+ {
+ mBoundDevices.clear();
+ }
+ ~DeviceMap()
+ {
+ }
+
+ QStringList mBoundDevices;
+ static DeviceMap *mThis;
+
+private:
+ void showList() const
+ {
+ FUNCTIONSETUPL(5);
+
+ if ( !(mBoundDevices.count() > 0))
+ return;
+
+ DEBUGKPILOT << fname << ": Bound devices: ["
+ << ((mBoundDevices.count() > 0) ?
+ mBoundDevices.join(CSL1(", ")) : CSL1("<none>"))
+ << "]" << endl;
+ }
+};
+
+class Messages
+{
+public:
+ Messages(KPilotDeviceLink *parent) :
+ fDeviceLink(parent)
+ {
+ reset();
+ }
+
+ void reset()
+ {
+ messages = 0;
+ messagesMask = ~messageIsError; // Never block errors
+ }
+
+ void block(unsigned int m, bool force=false)
+ {
+ if (force)
+ {
+ // Force blocking this message, even if it's an error msg.
+ messages |= m;
+ }
+ else
+ {
+ messages |= (m & messagesMask);
+ }
+ }
+
+ /**
+ * Some messages are only printed once and are suppressed
+ * after that. These are indicated by flag bits in
+ * messages. The following enum is a bitfield.
+ */
+ enum
+ {
+ OpenMessage=1, ///< Trying to open device ..
+ OpenFailMessage=2 ///< Failed to open device ...
+ };
+ int messages;
+ int messagesMask;
+ static const int messageIsError = 0;
+
+ /** Determines whether message @p s which has an id of @p msgid (one of
+ * the enum values mentioned above) should be printed, which is only if that
+ * message has not been suppressed through messagesMask.
+ * If return is true, this method also adds it to the messagesMask.
+ */
+ bool shouldPrint(int msgid)
+ {
+ if (!(messages & msgid))
+ {
+ block(msgid);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+protected:
+ KPilotDeviceLink *fDeviceLink;
+};
+
+class DeviceCommEvent : public QEvent
+{
+public:
+ DeviceCommEvent(DeviceCustomEvents type, QString msg = QString::null,
+ int progress = 0) :
+ QEvent( (QEvent::Type)type ), fMessage(msg), fProgress(progress),
+ fPilotSocket(-1)
+ {
+ }
+ QString message() const
+ {
+ return fMessage;
+ }
+ int progress()
+ {
+ return fProgress;
+ }
+
+ inline void setCurrentSocket(int i)
+ {
+ fPilotSocket = i;
+ }
+
+ inline int currentSocket()
+ {
+ return fPilotSocket;
+ }
+private:
+ QString fMessage;
+ int fProgress;
+ /**
+ * Pilot-link library handles for the device once it's opened.
+ */
+ int fPilotSocket;
+};
+
+/** Class that handles all device communications. We do this
+ in a different thread so that we do not block the main Qt
+ Event thread (similar to Swing's AWT event dispatch thread).
+ */
+
+class DeviceCommThread : public QObject, public QThread
+{
+friend class KPilotDeviceLink;
+
+Q_OBJECT
+
+public:
+ DeviceCommThread(KPilotDeviceLink *d);
+ virtual ~DeviceCommThread();
+
+ virtual void run();
+
+ void setDone(bool b)
+ {
+ FUNCTIONSETUP;
+ fDone = b;
+ }
+
+protected:
+
+ void close();
+
+ void reset();
+
+ /**
+ * Does the low-level opening of the device and handles the
+ * pilot-link library initialisation.
+ */
+ bool open(const QString &device = QString::null);
+
+protected slots:
+ /**
+ * Attempt to open the device. Called regularly to check
+ * if the device exists (to handle USB-style devices).
+ */
+ void openDevice();
+
+ /**
+ * Called when the device is opened *and* activity occurs on the
+ * device. This indicates the beginning of a hotsync.
+ */
+ void acceptDevice();
+
+ /**
+ * This slot fires whenever we've been trying to establish a hotsync with
+ * the device for longer than a given amount of time. When this slot is
+ * fired, we will tear down the communications process and start over again.
+ */
+ void workaroundUSB();
+
+private:
+ volatile bool fDone;
+
+ KPilotDeviceLink *fHandle;
+ inline KPilotDeviceLink *link()
+ {
+ if (fHandle)
+ {
+ return fHandle;
+ }
+ else
+ {
+ FUNCTIONSETUP;
+ WARNINGKPILOT << "Link asked for, but either I'm "
+ << "done or I don't have a valid handle. "
+ << "Shutting down comm thread." << endl;
+ QThread::exit();
+ return 0;
+ }
+ }
+
+ /**
+ * Timers and Notifiers for detecting activity on the device.
+ */
+ QTimer *fOpenTimer;
+ QSocketNotifier *fSocketNotifier;
+ bool fSocketNotifierActive;
+
+ /** Timer used to check for a badly-connected Z31/72 */
+ QTimer *fWorkaroundUSBTimer;
+
+ /**
+ * Pilot-link library handles for the device once it's opened.
+ */
+ int fPilotSocket;
+ int fTempSocket;
+
+ inline QString errorMessage(int e)
+ {
+ switch (e)
+ {
+ case ENOENT:
+ return i18n(" The port does not exist.");
+ break;
+ case ENODEV:
+ return i18n(" There is no such device.");
+ break;
+ case EPERM:
+ return i18n(" You do not have permission to open the "
+ "Pilot device.");
+ break;
+ default:
+ return i18n(" Check Pilot path and permissions.");
+ }
+ }
+
+ /**
+ * Handle cases where we can't accept or open the device,
+ * and data remains available on the pilot socket.
+ */
+ int fAcceptedCount;
+
+};
+
+
+#endif
+
diff --git a/kpilot/lib/kpilotlib.kcfg b/kpilot/lib/kpilotlib.kcfg
new file mode 100644
index 000000000..09e829216
--- /dev/null
+++ b/kpilot/lib/kpilotlib.kcfg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kpilotrc"/>
+ <group name="Notification Messages">
+ </group>
+</kcfg>
diff --git a/kpilot/lib/kpilotlibSettings.kcfgc b/kpilot/lib/kpilotlibSettings.kcfgc
new file mode 100644
index 000000000..d3b0d1352
--- /dev/null
+++ b/kpilot/lib/kpilotlibSettings.kcfgc
@@ -0,0 +1,7 @@
+File=kpilotlib.kcfg
+ClassName=KPilotLibSettings
+Singleton=true
+ItemAccessors=true
+Mutators=true
+GlobalEnums=true
+SetUserTexts=true
diff --git a/kpilot/lib/kpilotlink.cc b/kpilot/lib/kpilotlink.cc
new file mode 100644
index 000000000..9c0b85ee9
--- /dev/null
+++ b/kpilot/lib/kpilotlink.cc
@@ -0,0 +1,272 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2006-2007 Adriaan de Groot <[email protected]>
+** Copyright (C) 2007 Jason 'vanRijn' Kasper <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <iostream>
+
+#include <pi-source.h>
+#include <pi-socket.h>
+#include <pi-dlp.h>
+#include <pi-file.h>
+#include <pi-buffer.h>
+
+#include <qdir.h>
+#include <qtimer.h>
+#include <qdatetime.h>
+#include <qthread.h>
+
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+
+#include "pilotUser.h"
+#include "pilotSysInfo.h"
+#include "pilotCard.h"
+#include "pilotSerialDatabase.h"
+#include "pilotLocalDatabase.h"
+
+#include "kpilotlink.moc"
+
+/** Class that handles periodically tickling the handheld through
+* the virtual tickle() method; deals with cancels through the
+* shared fDone variable.
+*/
+class TickleThread : public QThread
+{
+public:
+ TickleThread(KPilotLink *d, bool *done, int timeout) :
+ QThread(),
+ fHandle(d),
+ fDone(done),
+ fTimeout(timeout)
+ { };
+ virtual ~TickleThread();
+
+ virtual void run();
+
+ static const int ChecksPerSecond = 5;
+ static const int SecondsPerTickle = 5;
+
+private:
+ KPilotLink *fHandle;
+ bool *fDone;
+ int fTimeout;
+} ;
+
+TickleThread::~TickleThread()
+{
+}
+
+void TickleThread::run()
+{
+ FUNCTIONSETUP;
+ int subseconds = ChecksPerSecond;
+ int ticktock = SecondsPerTickle;
+ int timeout = fTimeout;
+ DEBUGKPILOT << fname << ": Running for "
+ << timeout << " seconds." << endl;
+ DEBUGKPILOT << fname << ": Done @" << (void *) fDone << endl;
+
+ while (!(*fDone))
+ {
+ QThread::msleep(1000/ChecksPerSecond);
+ if (!(--subseconds))
+ {
+ if (timeout)
+ {
+ if (!(--timeout))
+ {
+ QApplication::postEvent(fHandle, new QEvent(static_cast<QEvent::Type>(KPilotLink::EventTickleTimeout)));
+ break;
+ }
+ }
+ subseconds=ChecksPerSecond;
+ if (!(--ticktock))
+ {
+ ticktock=SecondsPerTickle;
+ fHandle->tickle();
+ }
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+KPilotLink::KPilotLink( QObject *parent, const char *name ) :
+ QObject( parent, name ),
+ fPilotPath(QString::null),
+ fPilotUser(0L),
+ fPilotSysInfo(0L),
+ fTickleDone(true),
+ fTickleThread(0L)
+
+{
+ FUNCTIONSETUP;
+
+ fPilotUser = new KPilotUser();
+ strncpy( fPilotUser->data()->username, "Henk Westbroek",
+ sizeof(fPilotUser->data()->username)-1);
+ fPilotUser->setLastSuccessfulSyncDate( 1139171019 );
+
+ fPilotSysInfo = new KPilotSysInfo();
+ memset(fPilotSysInfo->sysInfo()->prodID, 0,
+ sizeof(fPilotSysInfo->sysInfo()->prodID));
+ strncpy(fPilotSysInfo->sysInfo()->prodID, "LocalLink",
+ sizeof(fPilotSysInfo->sysInfo()->prodID)-1);
+ fPilotSysInfo->sysInfo()->prodIDLength =
+ strlen(fPilotSysInfo->sysInfo()->prodID);
+}
+
+KPilotLink::~KPilotLink()
+{
+ FUNCTIONSETUP;
+ KPILOT_DELETE(fPilotUser);
+ KPILOT_DELETE(fPilotSysInfo);
+}
+
+/* virtual */ bool KPilotLink::event(QEvent *e)
+{
+ if ((int)e->type() == EventTickleTimeout)
+ {
+ stopTickle();
+ emit timeout();
+ return true;
+ }
+ else return QObject::event(e);
+}
+
+/*
+Start a tickle thread with the indicated timeout.
+*/
+void KPilotLink::startTickle(unsigned int timeout)
+{
+ FUNCTIONSETUP;
+
+ Q_ASSERT(fTickleDone);
+
+ /*
+ ** We've told the thread to finish up, but it hasn't
+ ** done so yet - so wait for it to do so, should be
+ ** only 200ms at most.
+ */
+ if (fTickleDone && fTickleThread)
+ {
+ fTickleThread->wait();
+ KPILOT_DELETE(fTickleThread);
+ }
+
+ DEBUGKPILOT << fname << ": Done @" << (void *) (&fTickleDone) << endl;
+
+ fTickleDone = false;
+ fTickleThread = new TickleThread(this,&fTickleDone,timeout);
+ fTickleThread->start();
+}
+
+void KPilotLink::stopTickle()
+{
+ FUNCTIONSETUP;
+ fTickleDone = true;
+ if (fTickleThread)
+ {
+ fTickleThread->wait();
+ KPILOT_DELETE(fTickleThread);
+ }
+}
+
+unsigned int KPilotLink::installFiles(const QStringList & l, const bool deleteFiles)
+{
+ FUNCTIONSETUP;
+
+ QStringList::ConstIterator i,e;
+ unsigned int k = 0;
+ unsigned int n = 0;
+ unsigned int total = l.count();
+
+ for (i = l.begin(), e = l.end(); i != e; ++i)
+ {
+ emit logProgress(QString::null,
+ (int) ((100.0 / total) * (float) n));
+
+ if (installFile(*i, deleteFiles))
+ k++;
+ n++;
+ }
+ emit logProgress(QString::null, 100);
+
+ return k;
+}
+
+void KPilotLink::addSyncLogEntry(const QString & entry, bool log)
+{
+ FUNCTIONSETUP;
+ if (entry.isEmpty()) return;
+
+ addSyncLogEntryImpl(entry);
+ if (log)
+ {
+ emit logMessage(entry);
+ }
+}
+
+
+/* virtual */ int KPilotLink::openConduit()
+{
+ return 0;
+}
+
+/* virtual */ int KPilotLink::pilotSocket() const
+{
+ return -1;
+}
+
+/* virtual */ PilotDatabase *KPilotLink::database( const DBInfo *info )
+{
+ FUNCTIONSETUP;
+ return database( Pilot::fromPilot( info->name ) );
+}
+
diff --git a/kpilot/lib/kpilotlink.h b/kpilot/lib/kpilotlink.h
new file mode 100644
index 000000000..5c3865c3e
--- /dev/null
+++ b/kpilot/lib/kpilotlink.h
@@ -0,0 +1,501 @@
+#ifndef _KPILOT_KPILOTLINK_H
+#define _KPILOT_KPILOTLINK_H
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2006 Adriaan de Groot <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <pi-dlp.h>
+
+#include <qobject.h>
+#include <qvaluelist.h>
+
+/** @file
+* Encapsulates all the communication with the handheld. Also
+* does daemon-like polling of the handheld. Interesting status
+* changes are signalled.
+*/
+
+class QThread;
+class KPilotUser;
+class KPilotSysInfo;
+class KPilotCard;
+class PilotDatabase;
+
+
+
+/**
+* KPilotLink handles some aspects of
+* communication with a Handheld. A KPilotLink object represents a
+* connection to a device (which may be active or inactive -- the latter in
+* cases where the link is @e waiting for a device to show up). The object
+* handles waiting, protocol initialization and some general
+* tasks such as getting system information or user data.
+*
+* The actual communication with the handheld should use the
+* PilotDatabase methods or use pilot-link dlp_* functions directly
+* on the file descriptor returned by handle().
+*
+* Implementations of this abstract class are KPilotDeviceLink
+* (for real physical devices) and KPilotLocalLink (for devices
+* represented by an on-disk directory).
+*
+*
+* @section General
+*
+* A KPilotLink object (or one of its subclasses) represents a single
+* (potential) link to a handheld device. The handheld device may be
+* a real physical one (subclass KPilotDeviceLink) or a virtual one
+* (subclass KPilotLocalLink). Every KPilotLink is associated with exactly
+* one identifier for @em what device it is attached to. Physical devices
+* have physical locations as interpreted by libpisock -- /dev/ttyUSB0 for
+* instance, or net:any -- while virtual devices are associated with a location
+* in the filesystem.
+*
+* A particular KPilotLink object may be connected -- communicating with
+* a device -- or not. For physical devices, that means that the device is
+* attached to the system (for USB-connected devices, think of it as a
+* metaphor in the case of net:any) and that the HotSync button has been
+* pressed. Virtual devices are immediately connected on creation, since there
+* is no sensible "not connected" state. A connected KPilotLink has access to the
+* data on the handheld and can give that data to the rest of the application.
+*
+* The data access API is divided into roughly three parts, with tickle handling
+* being a special fourth part (see section below). These are:
+*
+* - Message logging
+* - System information access
+* - Database access
+*
+* @section Lifecycle
+*
+* The life-cycle of a KPilotLink object is as follows:
+*
+* # Object is created (one of the concrete subclasses, anyway)
+* # Object gets a location assigned through reset(const QString &)
+* # Object is connected to the handheld device (somehow, depends on subclass)
+* # Object emits signal deviceReady()
+*
+* After this, the application is free to use the API to access the information from
+* the handheld. When the device connection is no longer needed, call either
+* endOfSync() or finishSync() to wrap up the communications. The object remains
+* alive and may be re-used by calling reset() to use the same location or
+* reset(const QString &) to give it a new location.
+*
+* @section Tickle handling.
+*
+* During a HotSync, the Pilot expects to be kept awake by (nearly)
+* continuous communication with the PC. The Pilot doesn't like
+* long periods of inactivity, since they drain the batteries while
+* the communications hardware is kept powered up. If the period of
+* inactivity is too long, the Pilot times out, shuts down the
+* communication, and the HotSync is broken.
+
+* Sometimes, however, periods of inactivity cannot be avoided --
+* for instance, if you _have_ to ask the user something during a
+* sync, or if you are fetching a large amount of data from a slow
+* source (libkabc can do that, if your addressbook is on an LDAP
+* server). During these periods of inactivity (as far as the Pilot
+* can tell), you can "tickle" the Pilot to keep it awake. This
+* prevents the communications from being shut down. It's not
+* a good idea to do this all the time -- battery life and possible
+* corruption of the dlp_ communications streams. Hence, you should
+* start and stop tickling the Pilot around any computation which:
+* - may take a long time
+* - does not in itself @em ever communicate directly with the Pilot
+*
+*
+*
+* You can call slot tickle() whenever you like just to do a
+* dlp_tickle() call on the Pilot. It will return true if the
+* tickle was successful, false otherwise (this can be used to
+* detect if the communication with the Pilot has shut down for
+* some reason).
+*
+* The protected methods startTickle() and stopTickle() are intended
+* to be called only from SyncActions -- I can't think of any other
+* legitimate use, since everything being done during a HotSync is
+* done via subclasses of SyncActions anyway, and SyncAction provides
+* access to these methods though its own start- and stopTickle().
+*
+* Call startTickle with a timeout in seconds, or 0 for no timeout.
+* This timeout is _unrelated_ to the timeout in the Pilot's
+* communications. Instead, it indicates how long to continue
+* tickling the Pilot before emitting the timeout() signal. This
+* can be useful for placing an upper bound on the amount of
+* time to wait for, say, user interaction -- you don't want an
+* inattentive user to drain the batteries during a sync because
+* he doesn't click on "Yes" for some question. If you pass a
+* timeout of 0, the Pilot will continue to be tickled until you
+* call stopTickle().
+*
+* Call stopTickle() to stop tickling the Pilot and continue with
+* normal operation. You @em must call stopTickle() before calling
+* anything else that might communicate with the Pilot, to avoid
+* corrupting the dlp_ communications stream. (TODO: Mutex the heck
+* out of this to avoid this problem). Note that stopTickle() may
+* hang up the caller for a small amount of time (up to 200ms)
+* before returning.
+*
+* event() and TickleTimeoutEvent are part of the implementation
+* of tickling, and are only accidentally visible.
+*
+* Signal timeout() is emitted if startTickle() has been called
+* with a non-zero timeout and that timeout has elapsed. The
+* tickler is stopped before timeout is emitted.
+*/
+class KDE_EXPORT KPilotLink : public QObject
+{
+Q_OBJECT
+friend class SyncAction;
+public:
+ /** A list of DBInfo structures. */
+ typedef QValueList<struct DBInfo> DBInfoList;
+
+ /** Constructor. Use reset() to start looking for a device. */
+ KPilotLink( QObject *parent = 0, const char *name = 0 );
+
+ /** Destructor. This rudely interrupts any communication in progress.
+ * It is best to call endOfSync() or finishSync() before destroying
+ * the device.
+ */
+ virtual ~KPilotLink();
+
+
+ /** Provides a human-readable status string. */
+ virtual QString statusString() const = 0;
+
+ /**
+ * True if HotSync has been started but not finished yet
+ * (ie. the physical Pilot is waiting for sync commands)
+ */
+ virtual bool isConnected() const = 0;
+
+
+ /**
+ * Information on what kind of device we're dealing with.
+ * A link is associated with a path -- either the node in
+ * /dev that the physical device is attached to, or an
+ * IP address, or a filesystem path for local links.
+ * Whichever is being used, this function returns its
+ * name in a human-readable form.
+ */
+ QString pilotPath() const
+ {
+ return fPilotPath;
+ }
+
+ /**
+ * Return the device link to the Init state and try connecting
+ * to the given device path (if it's non-empty). What the
+ * path means depends on the kind of link we're instantiating.
+ *
+ * @see reset()
+ * @see pilotPath()
+ */
+ virtual void reset(const QString &pilotPath) = 0;
+
+ /** Allows our class to receive custom events that our threads
+ * will be giving to us, including tickle timeouts and
+ * device communication events.
+ */
+ virtual bool event(QEvent *e);
+
+ /**
+ * Install the list of files (full paths!) named by @p l
+ * onto the handheld (or whatever this link represents).
+ * If @p deleteFiles is true, the source files are removed.
+ *
+ * @return the number of files successfully installed.
+ */
+ unsigned int installFiles(const QStringList &l, const bool deleteFiles);
+
+ /**
+ * Write a log entry to the handheld. If @p log is true,
+ * then the signal logMessage() is also emitted. This
+ * function is supposed to @em only write to the handheld's
+ * log (with a physical device, that is what appears on
+ * screen at the end of a sync).
+ */
+ void addSyncLogEntry(const QString &entry,bool log=true);
+
+ /**
+ * Find a database with the given @p name (and optionally,
+ * type @p type and creator ID (from pi_mktag) @p creator,
+ * on searching from index @p index on the handheld.
+ * Fills in the DBInfo structure @p info if found.
+ *
+ * @return >=0 on success. See the documentation for each
+ * subclass for particular meanings.
+ * @return < 0 on error.
+ */
+ virtual int findDatabase(const char *name,
+ struct DBInfo *info,
+ int index=0,
+ unsigned long type=0,
+ unsigned long creator=0) = 0;
+
+ /**
+ * Retrieve the database indicated by DBInfo @p *db into the
+ * local file @p path. This copies all the data, and you can
+ * create a PilotLocalDatabase from the resulting @p path .
+ *
+ * @return @c true on success
+ */
+ virtual bool retrieveDatabase(const QString &path, struct DBInfo *db) = 0;
+
+ /**
+ * Fill the DBInfo structure @p db with information about
+ * the next database (in some ordering) counting from
+ * @p index.
+ *
+ * @return < 0 on error
+ */
+ virtual int getNextDatabase(int index,struct DBInfo *db) = 0;
+
+ /**
+ * Returns a list of DBInfo structures describing all the
+ * databases available on the link (ie. device) with the
+ * given card number @p cardno and flags @p flags. No known
+ * handheld uses a cardno other than 0; use flags to
+ * indicate what kind of databases to fetch -- @c dlpDBListRAM
+ * or @c dlpDBListROM.
+ *
+ * @return list of DBInfo objects, one for each database
+ * @note ownership of the DBInfo objects is passed to the
+ * caller, who must delete the objects.
+ */
+ virtual DBInfoList getDBList(int cardno=0, int flags=dlpDBListRAM) = 0;
+
+ /**
+ * Return a database object for manipulating the database with
+ * name @p name on the link. This database may be local or
+ * remote, depending on the kind of link in use.
+ *
+ * @return pointer to database object, or 0 on error.
+ * @note ownership of the database object is given to the caller,
+ * who must delete the object in time.
+ */
+ virtual PilotDatabase *database( const QString &name ) = 0;
+
+ /**
+ * Return a database object for manipulating the database with
+ * the name stored in the DBInfo structure @p info . The default
+ * version goes through method database( const QString & ), above.
+ *
+ * @return pointer to database object, or 0 on error.
+ * @note ownership of the database object is given to the caller.
+ */
+ virtual PilotDatabase *database( const DBInfo *info );
+
+ /**
+ * Retrieve the user information from the device. Ownership
+ * is kept by the link, and at the end of a sync the user
+ * information is synced back to the link -- so it may be
+ * modified, but don't make local copies of it.
+ *
+ * @note Do not call this before the sync begins!
+ */
+ KPilotUser &getPilotUser()
+ {
+ return *fPilotUser;
+ }
+
+ /**
+ * System information about the handheld. Ownership is kept
+ * by the link. For non-device links, something fake is
+ * returned.
+ *
+ * @note Do not call this before the sync begins!
+ */
+ const KPilotSysInfo &getSysInfo()
+ {
+ return *fPilotSysInfo;
+ }
+
+ /**
+ * Retrieve information about the data card @p card;
+ * I don't think that any pilot supports card numbers
+ * other than 0. Non-device links return something fake.
+ *
+ * This function may return NULL (non-device links or
+ * on error).
+ *
+ * @note Ownership of the KPilotCard object is given
+ * to the caller, who must delete it.
+ */
+ virtual const KPilotCard *getCardInfo(int card=0) = 0;
+
+ /**
+ * When ending the sync, you can do so gracefully, updating the
+ * last-sync time to indicate a successful sync and setting the
+ * user name on the device, or you can skip that (for unsuccessful
+ * syncs, generally).
+ */
+ enum EndOfSyncFlags {
+ NoUpdate, ///< Do not update the user info
+ UpdateUserInfo ///< Update user info and last successful sync date
+ } ;
+
+ /**
+ * Custom events we can be handling...
+ */
+ enum CustomEvents {
+ EventTickleTimeout = 1066
+ };
+
+ /**
+ * End the sync in a gracuful manner. If @p f is UpdateUserInfo,
+ * the sync was successful and the user info and last successful sync
+ * timestamp are updated.
+ */
+ virtual void endSync( EndOfSyncFlags f ) = 0;
+
+signals:
+ /**
+ * A timeout associated with tickling has occurred. Each
+ * time startTickle() is called, you can state how long
+ * tickling should last (at most) before timing out.
+ *
+ * You can only get a timeout when the Qt event loop is
+ * running, which somewhat limits the usefulness of timeouts.
+ */
+ void timeout();
+
+ /** Signal that a message has been written to the sync log. */
+ void logMessage(const QString &);
+
+ /** Signal that an error has occurred, for logging. */
+ void logError(const QString &);
+
+ /**
+ * Signal that progress has been made, for logging purposes.
+ * @p p is the percentage completed (0 <= s <= 100).
+ * The string @p s is logged as well, if non-Null.
+ */
+ void logProgress(const QString &s, int p);
+
+ /**
+ * Emitted once the user information has been read and
+ * the HotSync is really ready to go.
+ */
+ void deviceReady( KPilotLink * );
+
+
+public slots:
+ /**
+ * Release all resources, including the master pilot socket,
+ * timers, etc.
+ */
+ virtual void close() = 0;
+
+ /**
+ * Assuming things have been set up at least once already by
+ * a call to reset() with parameters, use this slot to re-start
+ * with the same settings.
+ */
+ virtual void reset() = 0;
+
+ /** Tickle the underlying device exactly once. */
+ virtual bool tickle() = 0;
+
+protected:
+ /**
+ * Path of the device special file that will be used.
+ * Usually /dev/pilot, /dev/ttySx, or /dev/usb/x. May be
+ * a filesystem path for local links.
+ */
+ QString fPilotPath;
+
+ /**
+ * Start tickling the Handheld (every few seconds). This
+ * lasts until @p timeout seconds have passed (or forever
+ * if @p timeout is zero).
+ *
+ * @note Do not call startTickle() twice with no intervening
+ * stopTickle().
+ */
+ void startTickle(unsigned int timeout=0);
+
+ /**
+ * Stop tickling the Handheld. This may block for some
+ * time (less than a second) to allow the tickle thread
+ * to finish.
+ */
+ void stopTickle();
+
+ /**
+ * Install a single file onto the device link. Full pathname
+ * @p f is used; in addition, if @p deleteFile is true remove
+ * the source file. Returns @c true if the install succeeded.
+ */
+ virtual bool installFile( const QString &f, const bool deleteFile ) = 0;
+
+ /**
+ * Notify the Pilot user that a conduit is running now.
+ * On real devices, this prints out (on screen) which database
+ * is now opened; useful for progress reporting.
+ *
+ * @return -1 on error
+ * @note the default implementation returns 0
+ */
+ virtual int openConduit();
+
+ /**
+ * Returns a file handle for raw operations. Not recommended.
+ * On links with no physical device backing, returns -1.
+ *
+ * @note the default implementation returns -1
+ */
+ virtual int pilotSocket() const;
+
+ /**
+ * Actually write an entry to the device link. The message
+ * @p s must be guaranteed non-empty.
+ */
+ virtual void addSyncLogEntryImpl( const QString &s ) = 0;
+
+ /**
+ * User information structure. Should be filled in when a sync
+ * starts, so that conduits can use the information.
+ */
+ KPilotUser *fPilotUser;
+
+ /**
+ * System information about the device. Filled in when the
+ * sync starts. Non-device links need to fake something.
+ */
+ KPilotSysInfo *fPilotSysInfo;
+
+
+private:
+ bool fTickleDone;
+ QThread *fTickleThread;
+
+} ;
+
+#endif
diff --git a/kpilot/lib/kpilotlocallink.cc b/kpilot/lib/kpilotlocallink.cc
new file mode 100644
index 000000000..c3af1d342
--- /dev/null
+++ b/kpilot/lib/kpilotlocallink.cc
@@ -0,0 +1,368 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2006-2007 Adriaan de Groot <[email protected]>
+** Copyright (C) 2007 Jason 'vanRijn' Kasper <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <iostream>
+
+#include <pi-source.h>
+#include <pi-socket.h>
+#include <pi-dlp.h>
+#include <pi-file.h>
+#include <pi-buffer.h>
+
+#include <qdir.h>
+#include <qtimer.h>
+#include <qdatetime.h>
+#include <qthread.h>
+
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+
+#include "pilotSerialDatabase.h"
+#include "pilotLocalDatabase.h"
+
+#include "kpilotlink.h"
+#include "kpilotlocallink.moc"
+
+
+typedef QPair<QString, struct DBInfo> DatabaseDescriptor;
+typedef QValueList<DatabaseDescriptor> DatabaseDescriptorList;
+
+class KPilotLocalLink::Private
+{
+public:
+ DatabaseDescriptorList fDBs;
+} ;
+
+unsigned int KPilotLocalLink::findAvailableDatabases( KPilotLocalLink::Private &info, const QString &path )
+{
+ FUNCTIONSETUP;
+
+ info.fDBs.clear();
+
+ QDir d(path);
+ if (!d.exists())
+ {
+ // Perhaps return an error?
+ return 0;
+ }
+
+ // Use this to fake indexes in the list of DBInfo structs
+ unsigned int counter = 0;
+
+ QStringList dbs = d.entryList( CSL1("*.pdb"), QDir::Files | QDir::NoSymLinks | QDir::Readable );
+ for ( QStringList::ConstIterator i = dbs.begin(); i != dbs.end() ; ++i)
+ {
+ struct DBInfo dbi;
+
+ // Remove the trailing 4 characters
+ QString dbname = (*i);
+ dbname.remove(dbname.length()-4,4);
+
+ QString dbnamecheck = (*i).left((*i).findRev(CSL1(".pdb")));
+ Q_ASSERT(dbname == dbnamecheck);
+
+ if (PilotLocalDatabase::infoFromFile( path + CSL1("/") + (*i), &dbi))
+ {
+ DEBUGKPILOT << fname << ": Loaded "
+ << dbname << endl;
+ dbi.index = counter;
+ info.fDBs.append( DatabaseDescriptor(dbname,dbi) );
+ ++counter;
+ }
+ }
+
+ DEBUGKPILOT << fname << ": Total " << info.fDBs.count()
+ << " databases." << endl;
+ return info.fDBs.count();
+}
+
+
+KPilotLocalLink::KPilotLocalLink( QObject *parent, const char *name ) :
+ KPilotLink(parent,name),
+ fReady(false),
+ d( new Private )
+{
+ FUNCTIONSETUP;
+}
+
+KPilotLocalLink::~KPilotLocalLink()
+{
+ FUNCTIONSETUP;
+ KPILOT_DELETE(d);
+}
+
+/* virtual */ QString KPilotLocalLink::statusString() const
+{
+ return fReady ? CSL1("Ready") : CSL1("Waiting") ;
+}
+
+/* virtual */ bool KPilotLocalLink::isConnected() const
+{
+ return fReady;
+}
+
+/* virtual */ void KPilotLocalLink::reset( const QString &p )
+{
+ FUNCTIONSETUP;
+ fPath = p;
+ reset();
+}
+
+/* virtual */ void KPilotLocalLink::reset()
+{
+ FUNCTIONSETUP;
+ QFileInfo info( fPath );
+ fReady = !fPath.isEmpty() && info.exists() && info.isDir() ;
+ if (fReady)
+ {
+ findAvailableDatabases(*d, fPath);
+ QTimer::singleShot(500,this,SLOT(ready()));
+ }
+ else
+ {
+ WARNINGKPILOT << "The local link path <"
+ << fPath
+ << "> does not exist or is not a directory. No sync can be done."
+ << endl;
+ }
+}
+
+/* virtual */ void KPilotLocalLink::close()
+{
+ fReady = false;
+}
+
+/* virtual */ bool KPilotLocalLink::tickle()
+{
+ return true;
+}
+
+/* virtual */ const KPilotCard *KPilotLocalLink::getCardInfo(int)
+{
+ return 0;
+}
+
+/* virtual */ void KPilotLocalLink::endSync( EndOfSyncFlags f )
+{
+ Q_UNUSED(f);
+ fReady = false;
+}
+
+/* virtual */ int KPilotLocalLink::openConduit()
+{
+ FUNCTIONSETUP;
+ return 0;
+}
+
+
+/* virtual */ int KPilotLocalLink::getNextDatabase( int index, struct DBInfo *info )
+{
+ FUNCTIONSETUP;
+
+ if ( (index<0) || (index>=(int)d->fDBs.count()) )
+ {
+ WARNINGKPILOT << "Index out of range." << endl;
+ return -1;
+ }
+
+ DatabaseDescriptor dd = d->fDBs[index];
+
+ DEBUGKPILOT << fname << ": Getting database " << dd.first << endl;
+
+ if (info)
+ {
+ *info = dd.second;
+ }
+
+ return index+1;
+}
+
+/* virtual */ int KPilotLocalLink::findDatabase(const char *name, struct DBInfo*info,
+ int index, unsigned long type, unsigned long creator)
+{
+ FUNCTIONSETUP;
+
+ if ( (index<0) || (index>=(int)d->fDBs.count()) )
+ {
+ WARNINGKPILOT << "Index out of range." << endl;
+ return -1;
+ }
+
+ if (!name)
+ {
+ WARNINGKPILOT << "NULL name." << endl;
+ return -1;
+ }
+
+ QString desiredName = Pilot::fromPilot(name);
+ DEBUGKPILOT << fname << ": Looking for DB " << desiredName << endl;
+ for ( DatabaseDescriptorList::ConstIterator i = d->fDBs.at(index);
+ i != d->fDBs.end(); ++i)
+ {
+ const DatabaseDescriptor &dd = *i;
+ if (dd.first == desiredName)
+ {
+ if ( (!type || (type == dd.second.type)) &&
+ (!creator || (creator == dd.second.creator)) )
+ {
+ if (info)
+ {
+ *info = dd.second;
+ }
+ return index;
+ }
+ }
+
+ ++index;
+ }
+
+ return -1;
+}
+
+/* virtual */ void KPilotLocalLink::addSyncLogEntryImpl(QString const &s)
+{
+ FUNCTIONSETUP;
+ DEBUGKPILOT << fname << ": " << s << endl ;
+}
+
+/* virtual */ bool KPilotLocalLink::installFile(QString const &path, bool deletefile)
+{
+ FUNCTIONSETUP;
+
+ QFileInfo srcInfo(path);
+ QString canonicalSrcPath = srcInfo.dir().canonicalPath() + CSL1("/") + srcInfo.fileName() ;
+ QString canonicalDstPath = fPath + CSL1("/") + srcInfo.fileName();
+
+ if (canonicalSrcPath == canonicalDstPath)
+ {
+ // That's a cheap copy operation
+ return true;
+ }
+
+ KURL src = KURL::fromPathOrURL( canonicalSrcPath );
+ KURL dst = KURL::fromPathOrURL( canonicalDstPath );
+
+ KIO::NetAccess::file_copy(src,dst,-1,true);
+
+ if (deletefile)
+ {
+ KIO::NetAccess::del(src, 0L);
+ }
+
+ return true;
+}
+
+/* virtual */ bool KPilotLocalLink::retrieveDatabase( const QString &path, struct DBInfo *db )
+{
+ FUNCTIONSETUP;
+
+ QString dbname = Pilot::fromPilot(db->name) + CSL1(".pdb") ;
+ QString sourcefile = fPath + CSL1("/") + dbname ;
+ QString destfile = path ;
+
+ DEBUGKPILOT << fname << ": src=" << sourcefile << endl;
+ DEBUGKPILOT << fname << ": dst=" << destfile << endl;
+
+ QFile in( sourcefile );
+ if ( !in.exists() )
+ {
+ WARNINGKPILOT << "Source file " << sourcefile << " doesn't exist." << endl;
+ return false;
+ }
+ if ( !in.open( IO_ReadOnly | IO_Raw ) )
+ {
+ WARNINGKPILOT << "Can't read source file " << sourcefile << endl;
+ return false;
+ }
+
+ QFile out( destfile );
+ if ( !out.open( IO_WriteOnly | IO_Truncate | IO_Raw ) )
+ {
+ WARNINGKPILOT << "Can't write destination file " << destfile << endl;
+ return false;
+ }
+
+ const Q_ULONG BUF_SIZ = 8192 ;
+ char buf[BUF_SIZ];
+ Q_LONG r;
+
+ while ( (r=in.readBlock(buf,BUF_SIZ))>0 )
+ {
+ out.writeBlock(buf,r);
+ }
+ out.flush();
+ in.close();
+
+ return out.exists();
+}
+
+KPilotLink::DBInfoList KPilotLocalLink::getDBList( int, int )
+{
+ FUNCTIONSETUP;
+ DBInfoList l;
+ for ( DatabaseDescriptorList::ConstIterator i=d->fDBs.begin();
+ i != d->fDBs.end(); ++i)
+ {
+ l.append( (*i).second );
+ }
+ return l;
+}
+
+
+/* virtual */ PilotDatabase *KPilotLocalLink::database( const QString &name )
+{
+ FUNCTIONSETUP;
+ return new PilotLocalDatabase( fPath, name );
+}
+
+
+
+/* slot */ void KPilotLocalLink::ready()
+{
+ if (fReady)
+ {
+ emit deviceReady(this);
+ }
+}
+
diff --git a/kpilot/lib/kpilotlocallink.h b/kpilot/lib/kpilotlocallink.h
new file mode 100644
index 000000000..f18556b3c
--- /dev/null
+++ b/kpilot/lib/kpilotlocallink.h
@@ -0,0 +1,95 @@
+#ifndef _KPILOT_KPILOTLOCALLINK_H
+#define _KPILOT_KPILOTLOCALLINK_H
+/*
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2006 Adriaan de Groot <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "kpilotlink.h"
+
+/** @file
+* Definition of the local link class; implemented in kpilotlink.cc .
+*/
+
+
+/**
+* Implementation of the device link for file-system backed (ie. local, fake)
+* devices. Uses a directory specified in the reset() call to serve databases.
+*/
+class KDE_EXPORT KPilotLocalLink : public KPilotLink
+{
+Q_OBJECT
+public:
+ KPilotLocalLink( QObject *parent=0L, const char *name=0L );
+ virtual ~KPilotLocalLink();
+
+ virtual QString statusString() const;
+ virtual bool isConnected() const;
+ virtual void reset( const QString & );
+ virtual void close();
+ virtual void reset();
+ virtual bool tickle();
+ virtual const KPilotCard *getCardInfo(int card);
+ virtual void endSync( EndOfSyncFlags f );
+ virtual int openConduit();
+ virtual int getNextDatabase(int index,struct DBInfo *);
+ virtual int findDatabase(const char *name, struct DBInfo*,
+ int index=0, unsigned long type=0, unsigned long creator=0);
+ virtual bool retrieveDatabase(const QString &path, struct DBInfo *db);
+ virtual DBInfoList getDBList(int cardno=0, int flags=dlpDBListRAM);
+ virtual PilotDatabase *database( const QString &name );
+
+public slots:
+ void ready();
+
+protected:
+ virtual bool installFile(const QString &, const bool deleteFile);
+ virtual void addSyncLogEntryImpl( const QString &s );
+ virtual int pilotSocket() const
+ {
+ return -1;
+ }
+
+protected:
+ bool fReady;
+ QString fPath;
+
+ class Private;
+ Private *d;
+
+ /**
+ * Pre-process the directory @p path to find out which databases
+ * live there.
+ *
+ * @return Number of database in @p path.
+ */
+ unsigned int findAvailableDatabases( Private &, const QString &path );
+} ;
+
+
+#endif
+
diff --git a/kpilot/lib/options.cc b/kpilot/lib/options.cc
new file mode 100644
index 000000000..0eb1babf7
--- /dev/null
+++ b/kpilot/lib/options.cc
@@ -0,0 +1,157 @@
+/* KPilot
+**
+** Copyright (C) 2000-2001 by Adriaan de Groot
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This is a file of odds and ends, with debugging functions and stuff.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "options.h"
+
+
+#include <iostream>
+
+#include <qsize.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kcmdlineargs.h>
+
+#ifdef DEBUG
+int debug_level = 1;
+#else
+int debug_level = 0;
+#endif
+
+// The daemon also has a debug level; debug_spaces is 60 spaces,
+// to align FUNCTIONSETUP output. The one byte extra is for the NUL.
+//
+//
+static const char debug_spaces[61] =
+ " "
+ " "
+ " ";
+
+
+QString rtExpand(const QString &s, Qt::TextFormat richText)
+{
+ if (richText == Qt::RichText)
+ {
+ QString t(s);
+ return t.replace(CSL1("\n"), CSL1("<br/>\n"));
+ }
+ else
+ {
+ return s;
+ }
+
+}
+
+QDateTime readTm(const struct tm &t)
+{
+ QDateTime dt;
+ dt.setDate(QDate(1900 + t.tm_year, t.tm_mon + 1, t.tm_mday));
+ dt.setTime(QTime(t.tm_hour, t.tm_min, t.tm_sec));
+ return dt;
+}
+
+
+
+struct tm writeTm(const QDateTime &dt)
+{
+ struct tm t;
+
+ t.tm_wday = 0; // unimplemented
+ t.tm_yday = 0; // unimplemented
+ t.tm_isdst = 0; // unimplemented
+#ifdef HAVE_STRUCT_TM_TM_ZONE
+ t.tm_zone = 0; // unimplemented
+#endif
+
+ t.tm_year = dt.date().year() - 1900;
+ t.tm_mon = dt.date().month() - 1;
+ t.tm_mday = dt.date().day();
+ t.tm_hour = dt.time().hour();
+ t.tm_min = dt.time().minute();
+ t.tm_sec = dt.time().second();
+
+ return t;
+}
+
+
+
+struct tm writeTm(const QDate &d)
+{
+ QDateTime dt(d);
+ return writeTm(dt);
+}
+
+KPilotDepthCount::KPilotDepthCount(int, int level, const char *s) :
+ fDepth(depth),
+ fLevel(level),
+ fName(s)
+{
+ DEBUGKPILOT << "! DEPRECATED Depth call.\n! "
+ << kdBacktrace(4) << endl;
+
+ if (debug_level>=fLevel)
+ {
+ DEBUGKPILOT << indent() << ">" << name() << endl;
+ }
+ depth++;
+}
+
+KPilotDepthCount::KPilotDepthCount(int level, const char *s) :
+ fDepth(depth),
+ fLevel(level),
+ fName(s)
+{
+ if (debug_level>=fLevel)
+ {
+ DEBUGKPILOT << indent() << ">" << name() << endl;
+ }
+ depth++;
+}
+
+KPilotDepthCount::~KPilotDepthCount()
+{
+ depth--;
+ std::cerr.clear(std::ios_base::goodbit);
+}
+
+const char *KPilotDepthCount::indent() const
+{
+ if (fDepth < 30)
+ {
+ return debug_spaces + 60-fDepth*2;
+ }
+ else
+ {
+ return debug_spaces;
+ }
+}
+
+int KPilotDepthCount::depth = 0;
+
diff --git a/kpilot/lib/options.h b/kpilot/lib/options.h
new file mode 100644
index 000000000..6e036e82d
--- /dev/null
+++ b/kpilot/lib/options.h
@@ -0,0 +1,199 @@
+#ifndef _KPILOT_OPTIONS_H
+#define _KPILOT_OPTIONS_H
+/* options.h KPilot
+**
+** Copyright (C) 1998-2001,2002,2003 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines some global constants and macros for KPilot.
+** In particular, KDE2 is defined when KDE2 seems to be the environment
+** (is there a better way to do this?). Use of KDE2 to #ifdef sections
+** of code is deprecated though.
+**
+** Many debug functions are defined as well.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "config.h"
+
+#include <qglobal.h>
+#include <qnamespace.h>
+#include <qstring.h>
+
+#if (QT_VERSION < 0x030300)
+#error "This is KPilot for KDE3.5 and won't compile with Qt < 3.3.0"
+#endif
+
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <klocale.h>
+
+#if !(KDE_IS_VERSION(3,4,0))
+#error "This is KPilot for (really) KDE 3.5 and won't compile with KDE < 3.4.0"
+#endif
+
+#if !(KDE_IS_VERSION(3,5,0))
+#warning "This is KPilot for KDE 3.5 and might not compile with KDE < 3.5.0"
+#endif
+
+#include "pilotLinkVersion.h"
+
+#include <iostream>
+
+using namespace std;
+inline std::ostream& operator <<(std::ostream &o, const QString &s)
+ { if (s.isEmpty()) return o<<"<empty>"; else return o<<s.latin1(); }
+inline std::ostream& operator <<(std::ostream &o, const QCString &s)
+ { if (s.isEmpty()) return o<<"<empty>"; else return o << *s; }
+
+
+#ifndef NDEBUG
+#define DEBUG (1)
+#endif
+
+extern KDE_EXPORT int debug_level;
+
+class KDE_EXPORT KPilotDepthCount
+{
+public:
+ KPilotDepthCount(int, int level, const char *s);
+ KPilotDepthCount(int level, const char *s);
+ ~KPilotDepthCount();
+ const char *indent() const;
+ inline const char *name() const { return fName; } ;
+ inline int level() const { return fLevel; } ;
+
+protected:
+ static int depth;
+ int fDepth;
+ int fLevel;
+ const char *fName;
+} ;
+
+
+#ifdef DEBUG
+#ifdef __GNUC__
+#define KPILOT_FNAMEDEF(l) KPilotDepthCount fname(l,__FUNCTION__)
+#else
+#define KPILOT_FNAMEDEF(l) KPilotDepthCount fname(l,__FILE__ ":" "__LINE__")
+#endif
+
+#define FUNCTIONSETUP KPILOT_FNAMEDEF(1)
+#define FUNCTIONSETUPL(l) KPILOT_FNAMEDEF(l)
+
+// stderr / iostream-based debugging.
+//
+//
+#define DEBUGKPILOT std::cerr
+#define WARNINGKPILOT std::cerr.clear(std::ios_base::goodbit),\
+ std::cerr << "! " << k_funcinfo << std::endl << "! "
+
+
+
+
+inline std::ostream& operator <<(std::ostream &o, const KPilotDepthCount &d)
+{
+ if (debug_level >= d.level())
+ {
+ o.clear(std::ios_base::goodbit);
+ return o << d.indent() << ' ' << d.name();
+ }
+ else
+ {
+ o.setstate(std::ios_base::badbit | std::ios_base::failbit);
+ return o;
+ }
+}
+
+#else
+
+// no debugging at all
+//
+#define DEBUGSTREAM kndbgstream
+#define DEBUGKPILOT kndDebug()
+#define WARNINGKPILOT kndDebug()
+
+// With debugging turned off, FUNCTIONSETUP doesn't do anything.
+//
+//
+#define FUNCTIONSETUP const int fname = 0; Q_UNUSED(fname);
+#define FUNCTIONSETUPL(a) const int fname = a; Q_UNUSED(fname);
+#endif
+
+#define KPILOT_VERSION "4.9.4-3510 (elsewhere)"
+
+
+// Function to expand newlines in rich text to <br>\n
+QString rtExpand(const QString &s, Qt::TextFormat richText);
+
+
+
+/**
+ * Convert a struct tm from the pilot-link package to a QDateTime
+ */
+KDE_EXPORT QDateTime readTm(const struct tm &t);
+/**
+ * Convert a QDateTime to a struct tm for use with the pilot-link package
+ */
+KDE_EXPORT struct tm writeTm(const QDateTime &dt);
+KDE_EXPORT struct tm writeTm(const QDate &dt);
+
+
+// Some layout macros
+//
+// SPACING is a generic distance between visual elements;
+// 10 seems reasonably good even at high resolutions.
+//
+//
+#define SPACING (10)
+
+// Semi-Standard safe-free expression. Argument a may be evaluated more
+// than once though, so be careful.
+//
+//
+#define KPILOT_FREE(a) { if (a) { ::free(a); a=0L; } }
+#define KPILOT_DELETE(a) { if (a) { delete a; a=0L; } }
+
+
+// This marks strings that need to be i18n()ed in future,
+// but cannot be done now due to message freeze. The _P
+// variant is to handle plurals and is wrong, but unavoidable.
+//
+//
+#define TODO_I18N(a) QString::fromLatin1(a)
+#define TODO_I18N_P(a,b,c) ((c>1) ? a : b)
+
+// Handle some cases for QT_NO_CAST_ASCII and NO_ASCII_CAST.
+// Where possible in the source, known constant strings in
+// latin1 encoding are marked with CSL1(), to avoid gobs
+// of latin1() or fromlatin1() calls which might obscure
+// those places where the code really is translating
+// user data from latin1.
+//
+// The extra "" in CSL1 is to enforce that it's only called
+// with constant strings.
+//
+//
+#define CSL1(a) QString::fromLatin1(a "")
+
+#endif
diff --git a/kpilot/lib/pilot.cc b/kpilot/lib/pilot.cc
new file mode 100644
index 000000000..2585445c1
--- /dev/null
+++ b/kpilot/lib/pilot.cc
@@ -0,0 +1,264 @@
+/* pilot.cc KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2003-2006 Adriaan de Groot <[email protected]>
+**
+** These are the base class structures that reside on the
+** handheld device -- databases and their parts.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qtextcodec.h>
+#include <qmutex.h>
+#include <kcharsets.h>
+#include <kglobal.h>
+
+#include "pilot.h"
+#include "pilotDatabase.h"
+#include "pilotAppInfo.h"
+#include "pilotRecord.h"
+
+
+namespace Pilot
+{
+static QTextCodec *codec = 0L;
+static QMutex* mutex = 0L;
+
+
+QString fromPilot( const char *c, int len )
+{
+ mutex->lock();
+ QString str = codec->toUnicode(c,len);
+ mutex->unlock();
+ return str;
+}
+
+QString fromPilot( const char *c )
+{
+ mutex->lock();
+ QString str = codec->toUnicode(c);
+ mutex->unlock();
+ return str;
+}
+
+QCString toPilot( const QString &s )
+{
+ mutex->lock();
+ QCString str = codec->fromUnicode(s);
+ mutex->unlock();
+ return str;
+}
+
+int toPilot( const QString &s, char *buf, int len)
+{
+ mutex->lock();
+ // See toPilot() below.
+ memset( buf, 0, len );
+ int used = len;
+ QCString cbuf = codec->fromUnicode(s,used);
+ if (used > len)
+ {
+ used=len;
+ }
+ memcpy( buf, cbuf.data(), used );
+ mutex->unlock();
+ return used;
+}
+
+int toPilot( const QString &s, unsigned char *buf, int len)
+{
+ mutex->lock();
+ // Clear the buffer
+ memset( buf, 0, len );
+
+ // Convert to 8-bit encoding
+ int used = len;
+ QCString cbuf = codec->fromUnicode(s,used);
+
+ // Will it fit in the buffer?
+ if (used > len)
+ {
+ // Ought to be impossible, anyway, since 8-bit encodings
+ // are shorter than the UTF-8 encodings (1 byte per character
+ // vs. 1-or-more byte per character).
+ used=len;
+ }
+
+ // Fill the buffer with encoded data.
+ memcpy( buf, cbuf.data(), used );
+ mutex->unlock();
+ return used;
+}
+
+bool setupPilotCodec(const QString &s)
+{
+ FUNCTIONSETUP;
+ mutex = new QMutex();
+ mutex->lock();
+ QString encoding(KGlobal::charsets()->encodingForName(s));
+
+ DEBUGKPILOT << fname << ": Using codec name " << s << endl;
+ DEBUGKPILOT << fname << ": Creating codec " << encoding << endl;
+
+ // if the desired codec can't be found, latin1 will be returned anyway, no need to do this manually
+ codec = KGlobal::charsets()->codecForName(encoding);
+
+ if (codec)
+ {
+ DEBUGKPILOT << fname << ": Got codec " << codec->name() << endl;
+ }
+
+ mutex->unlock();
+ return codec;
+}
+
+QString codecName()
+{
+ return QString::fromLatin1(codec->name());
+}
+
+QString category(const struct CategoryAppInfo *info, unsigned int i)
+{
+ if (!info || (i>=CATEGORY_COUNT))
+ {
+ return QString::null;
+ }
+
+ mutex->lock();
+ QString str = codec->toUnicode(info->name[i],
+ MIN(strlen(info->name[i]), CATEGORY_SIZE-1));
+ mutex->unlock();
+ return str;
+}
+
+
+int findCategory(const struct CategoryAppInfo *info,
+ const QString &selectedCategory,
+ bool unknownIsUnfiled)
+{
+ FUNCTIONSETUP;
+
+ if (!info)
+ {
+ WARNINGKPILOT << "Bad CategoryAppInfo pointer" << endl;
+ return -1;
+ }
+
+ int currentCatID = -1;
+ for (unsigned int i=0; i<CATEGORY_COUNT; i++)
+ {
+ if (!info->name[i][0]) continue;
+ if (selectedCategory == category(info, i))
+ {
+ currentCatID = i;
+ break;
+ }
+ }
+
+ if (-1 == currentCatID)
+ {
+ DEBUGKPILOT << fname << ": Category name "
+ << selectedCategory << " not found." << endl;
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": Matched category " << currentCatID << endl;
+ }
+
+ if ((currentCatID == -1) && unknownIsUnfiled)
+ currentCatID = 0;
+ return currentCatID;
+}
+
+int insertCategory(struct CategoryAppInfo *info,
+ const QString &label,
+ bool unknownIsUnfiled)
+{
+ FUNCTIONSETUP;
+
+ if (!info)
+ {
+ WARNINGKPILOT << "Bad CategoryAppInfo pointer" << endl;
+ return -1;
+ }
+
+
+ int c = findCategory(info,label,unknownIsUnfiled);
+ if (c<0)
+ {
+ // This is the case when the category is not known
+ // and unknownIsUnfiled is false.
+ for (unsigned int i=0; i<CATEGORY_COUNT; i++)
+ {
+ if (!info->name[i][0])
+ {
+ c = i;
+ break;
+ }
+ }
+
+ if ((c>0) && (c < (int)CATEGORY_COUNT))
+ {
+ // 0 is always unfiled, can't change that.
+ toPilot(label,info->name[c],CATEGORY_SIZE);
+ }
+ else
+ {
+ WARNINGKPILOT << "Category name "
+ << label
+ << " could not be added." << endl;
+ c = -1;
+ }
+ }
+
+ return c;
+}
+
+void dumpCategories(const struct CategoryAppInfo *info)
+{
+ FUNCTIONSETUP;
+
+ if (!info)
+ {
+ WARNINGKPILOT << "Dumping bad pointer." << endl;
+ return;
+ }
+
+ DEBUGKPILOT << fname << " lastUniqueId: "
+ << (int) info->lastUniqueID << endl;
+ for (unsigned int i = 0; i < CATEGORY_COUNT; i++)
+ {
+ if (!info->name[i][0]) continue;
+ DEBUGKPILOT << fname << ": " << i << " = "
+ << (int)(info->ID[i]) << " <"
+ << info->name[i] << ">" << endl;
+ }
+}
+
+
+}
+
+
diff --git a/kpilot/lib/pilot.h b/kpilot/lib/pilot.h
new file mode 100644
index 000000000..d4fec82b2
--- /dev/null
+++ b/kpilot/lib/pilot.h
@@ -0,0 +1,410 @@
+#ifndef _KPILOT_PILOT_H
+#define _KPILOT_PILOT_H
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2003-2006 Adriaan de Groot <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <sys/types.h>
+
+#include <pi-appinfo.h>
+#include <pi-buffer.h>
+#include <pi-dlp.h>
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+
+#include "pilotLinkVersion.h"
+
+
+/** @file
+* These are some base structures that reside on the
+* handheld device -- strings and binary data.
+*/
+
+class PilotDatabase; // A database
+class PilotRecord; // ... has records
+class PilotCategoryInfo; // ... and category information
+
+#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+
+/**
+* The Pilot namespace holds constants that are global for
+* the handheld data structures. Also contains some global
+* functions that deal with pilot-link structures as well
+* as mapping user-visible strings from UTF8 (KDE side) to
+* the encoding used on the handheld.
+*/
+namespace Pilot
+{
+ /** Maximum size of an AppInfo block, taken roughly from the pilot-link source. */
+ static const int MAX_APPINFO_SIZE=8192;
+
+ /** Maximum number of categories the handheld has */
+ static const unsigned int CATEGORY_COUNT=16;
+
+ /** Maximum size of a category label */
+ static const unsigned int CATEGORY_SIZE=16;
+
+ /** Category number for unfiled records */
+ static const int Unfiled = 0;
+
+ /** Maximum size (in bytes) of a record's data */
+ static const int MAX_RECORD_SIZE = 65535;
+
+ typedef QValueList<recordid_t> RecordIDList;
+
+ /** Static translation function that maps handheld native (8 bit,
+ * usually latin1 but sometimes someting else) encoded data to
+ * a Unicode string. Converts the @p len characters in @p c
+ * to a Unicode string.
+ */
+ QString fromPilot( const char *c, int len );
+
+ /** Static translation function mapping a NUL-terminated
+ * string from the handheld's encoding to UTF-8.
+ * @param c the NUL-terminated string to decode
+ * @return QString (UTF-8) value of @p c
+ * @note NUL-terminated strings are rare on the handheld.
+ */
+ QString fromPilot( const char *c );
+
+ /** Static translation function that maps a QString onto the
+ * native 8 bit encoding of the handheld. Writes the result into
+ * the buffer @p buf which has size @p len. Returns the length
+ * of the result. Zero-fills the buffer as needed.
+ */
+ int toPilot( const QString &s, char *buf, int len);
+ int toPilot( const QString &s, unsigned char *buf, int len);
+
+ /** Static translation function that maps a QString onto the
+ * native 8 bit encoding of the handheld.
+ *
+ * @param s String to encode
+ * @return Encoded string in a QCString
+ */
+ QCString toPilot( const QString &s );
+
+ /** Create a codec for translating handheld native 8 bit to Unicode,
+ * using the given codec @p name -- this will often be latin1, but
+ * might be something else for, say, Russian-language Pilots.
+ * If @p name is empty, use latin1.
+ *
+ * @return @c true on success, @c false otherwise
+ */
+ bool setupPilotCodec(const QString &name);
+
+ /** Returns the name of the codec being used. */
+ QString codecName();
+
+ /** For debugging, display category names for the given AppInfo
+ * structure. Called by dump(). You must pass a valid reference.
+ */
+ void dumpCategories(const struct CategoryAppInfo *info);
+
+ /** Check that a given category number is valid. This
+ * restricts the range of integers to [0..CATEGORY_COUNT-1]
+ * (i.e. [0..15]) which is what the handheld supports.
+ */
+ inline bool validCategory(int c)
+ {
+ if (c<0)
+ {
+ return false;
+ }
+ return ((unsigned int)c<CATEGORY_COUNT);
+ }
+
+ /** Returns the QString for the requested category @p i
+ * in the category structure @p info. Returns @c QString::null
+ * on error (bad pointer or bad category number). May also
+ * return @c QString::null if the category name is empty.
+ */
+ inline QString categoryName(const struct CategoryAppInfo *info, unsigned int i)
+ {
+ if ( ( i < CATEGORY_COUNT ) && ( info->name[i][0] ) )
+ {
+ /*
+ * Seems to be important that we try to pass the real length here
+ * to the codec.
+ */
+ return fromPilot( info->name[i], MIN(strlen(info->name[i]),CATEGORY_SIZE) );
+ }
+ else
+ {
+ return QString::null;
+ }
+ }
+
+ /** Returns a list of all the category names available on the
+ * handheld. This list is neither ordered nor does it contain
+ * all sixteen categories -- empty category names on the
+ * handheld are skipped.
+ */
+ inline QStringList categoryNames(const struct CategoryAppInfo *info)
+ {
+ QStringList l;
+ if (!info)
+ {
+ return l;
+ }
+ for (unsigned int i=0; i<CATEGORY_COUNT; ++i)
+ {
+ QString s = categoryName(info,i);
+ if (!s.isEmpty())
+ {
+ l.append(s);
+ }
+ }
+ return l;
+ }
+
+ /** Search for the given category @p name in the list
+ * of categories; returns the category number. If @p unknownIsUnfiled
+ * is true, then map unknown categories to Unfiled instead of returning
+ * an error number.
+ *
+ * @return >=0 is a specific category based on the text-to-
+ * category number mapping defined by the Pilot,
+ * where 0 is always the 'unfiled' category.
+ * @return -1 means unknown category selected when
+ * @p unknownIsUnfiled is false.
+ * @return 0 == Unfiled means unknown category selected when
+ * @p unknownIsUnfiled is true.
+ *
+ */
+ int findCategory(const struct CategoryAppInfo *info, const QString &name, bool unknownIsUnfiled);
+
+ /** Search for the given category @p name in the list
+ * of categories; returns the category number. If @p unknownIsUnfiled
+ * is @c true, then map unknown categories to Unfiled.
+ * If @p unknownIsUnfiled is @c false, insert a @em new
+ * category into the structure and return the category
+ * number of the new category. Return -1 if (and only if)
+ * @p unknownIsUnfiled is false and the category structure
+ * is already full.
+ *
+ * @return >=0 is a specific category based on the text-to-
+ * category number mapping defined by the Pilot,
+ * where 0 is always the 'unfiled' category.
+ * @return 0 Unknown category and @p unknownIsUnfiled is @c true
+ * @return -1 means unknown category selected when
+ * @p unknownIsUnfiled is false and categories
+ * are all full.
+ *
+ */
+ int insertCategory(struct CategoryAppInfo *info, const QString &label, bool unknownIsUnfiled);
+
+ /** The handheld also holds data about each database
+ * in a DBInfo structure; check if the database described
+ * by this structure is a resource database.
+ */
+ static inline bool isResource(struct DBInfo *info)
+ {
+ return (info->flags & dlpDBFlagResource);
+ }
+
+
+/** @section Binary blob handling
+*
+* For reading and writing binary blobs -- which has to happen to
+* pack data into the format that the handheld needs -- it is important
+* to remember that the handheld has only four data types (as far
+* as I can tell: byte, short (a 2 byte integer), long (a 4 byte integer)
+* and string (NUL terminated). The sizes of the types on the handheld
+* do not necessarily correspond to the sizes of the same-named types
+* on the desktop. This means that 'reading a long' from a binary
+* blob must always be 4 bytes -- not sizeof(long).
+*
+* The following templates help out in manipulating the blobs.
+* Instantiate them with the type @em name you need (char, short, long or
+* char *) and you get a ::size enum specifying the number of bytes
+* (where applicable) and ::append and ::read methods for appending
+* a value of the given type to a pi_buffer_t or reading one from
+* the buffer, respectively.
+*
+* The usage of ::read and ::append is straightforward:
+*
+* append(pi_buffer_t *b, TYPE_VALUE v) Appends the type value @p v to the
+* buffer @p b , extending the buffer as needed.
+*
+* TYPE_VALUE read(pi_buffer_t *b, unsigned int &offset) Read a value from
+* the buffer @p b at position @p offset and return it. The offset value
+* is increased by the number of bytes read from the buffer.
+*
+* To write a binary blob, a sequence of ::append calls constructs the
+* blob. To read the same blob, a sequence of ::read calls with the
+* @em same type parameters is sufficient.
+*
+* The calls may vary a little: the exact interface differs depending
+* on the needs of the type of data to be written to the blob.
+*/
+template<typename t> struct dlp { } ;
+
+template<> struct dlp<char>
+{
+ enum { size = 1 };
+
+ static void append(pi_buffer_t *b, char v)
+ {
+ pi_buffer_append(b,&v,size);
+ }
+
+ /**
+ * Returns next byte from buffer or 0 on error (0 is also a
+ * valid return value, though).
+ */
+ static char read(const pi_buffer_t *b, unsigned int &offset)
+ {
+ if (offset+size > b->used)
+ {
+ return 0;
+ }
+ char c = b->data[offset];
+ offset+=size;
+ return c;
+ }
+} ;
+
+template<> struct dlp<short>
+{
+ enum { size = 2 };
+
+ static void append(pi_buffer_t *b, short v)
+ {
+ char buf[size];
+ set_short(buf,v);
+ pi_buffer_append(b,buf,size);
+ }
+
+ /**
+ * Returns the next short (2 byte) value from the buffer, or
+ * -1 on error (which is also a valid return value).
+ */
+ static int read(const pi_buffer_t *b, unsigned int &offset)
+ {
+ if (offset+size > b->used)
+ {
+ return -1;
+ }
+ else
+ {
+ int r = get_short(b->data + offset);
+ offset+=size;
+ return r;
+ }
+ }
+
+ /**
+ * Overload to read from a data buffer instead of a real pi_buffer;
+ * does no bounds checking.
+ */
+ static int read(const unsigned char *b, unsigned int &offset)
+ {
+ int r = get_short(b+offset);
+ offset+=size;
+ return r;
+ }
+} ;
+
+template<> struct dlp<long>
+{
+ enum { size = 4 };
+
+ static void append(pi_buffer_t *b, int v)
+ {
+ char buf[size];
+ set_long(buf,v);
+ pi_buffer_append(b,buf,size);
+ }
+
+ /**
+ * Returns the next long (4 byte) value from the buffer or
+ * -1 on error (which is also a valid value).
+ */
+ static int read(const pi_buffer_t *b, unsigned int &offset)
+ {
+ if (offset+size > b->used)
+ {
+ return -1;
+ }
+ else
+ {
+ int r = get_long(b->data + offset);
+ offset+=size;
+ return r;
+ }
+ }
+
+ /**
+ * Overload to read a long value from a data buffer; does
+ * no bounds checking.
+ */
+ static int read(const unsigned char *b, unsigned int &offset)
+ {
+ int r = get_long(b+offset);
+ offset+=size;
+ return r;
+ }
+} ;
+
+template<> struct dlp<char *>
+{
+ // No size enum, doesn't make sense
+ // No append, use pi_buffer_append
+ /**
+ * Read a fixed-length string from the buffer @p b into data buffer
+ * @p v which has size (including terminating NUL) of @p s.
+ * Returns the number of bytes read (which will normally be @p s
+ * but will be less than @p s on error).
+ */
+ static int read(const pi_buffer_t *b,
+ unsigned int &offset,
+ unsigned char *v,
+ size_t s)
+ {
+ if ( s+offset > b->used )
+ {
+ s = b->allocated - offset;
+ }
+ memcpy(v, b->data + offset, s);
+ offset+=s;
+ return s;
+ }
+
+ /** Overload for signed char. */
+ inline static int read(const pi_buffer_t *b, unsigned int &offset, char *v, size_t s)
+ {
+ return read(b,offset,(unsigned char *)v,s);
+ }
+} ;
+
+}
+
+#endif
+
diff --git a/kpilot/lib/pilotAddress.cc b/kpilot/lib/pilotAddress.cc
new file mode 100644
index 000000000..418c705b4
--- /dev/null
+++ b/kpilot/lib/pilotAddress.cc
@@ -0,0 +1,636 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2007 by Adriaan de Groot <[email protected]>
+**
+** This is a C++ wrapper for the pilot's address database structures.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "options.h"
+
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include <qnamespace.h>
+#include <qstringlist.h>
+
+#include "pilotAddress.h"
+
+static const char *default_address_category_names[] = {
+ "Unfiled",
+ "Business",
+ "Personal",
+ "Quicklist",
+ 0L
+} ;
+
+static const char *default_address_field_labels[] = {
+ "Last name",
+ "First name",
+ "Company",
+ "Work",
+ "Home",
+ "Fax",
+ "Other",
+ "E-mail",
+ "Addr(W)",
+ "City",
+ "State",
+ "Zip Code",
+ "Country",
+ "Title",
+ "Custom 1",
+ "Custom 2",
+ "Custom 3",
+ "Custom 4",
+ "Note",
+ 0L
+} ;
+
+void PilotAddressInfo::resetToDefault()
+{
+ FUNCTIONSETUP;
+ // Reset to all 0s
+ memset(&fInfo,0,sizeof(fInfo));
+ // Fill up default categories
+ for (unsigned int i=0; (i<4) && default_address_category_names[i]; ++i)
+ {
+ strncpy(fInfo.category.name[i],default_address_category_names[i],sizeof(fInfo.category.name[0]));
+ }
+ // Weird hack, looks like there's an extra copy of Unfiled
+ strncpy(fInfo.category.name[15],default_address_category_names[0],sizeof(fInfo.category.name[0]));
+
+ // And fill up the default labels.
+ for (unsigned int i=0; (i<19) && default_address_field_labels[i]; ++i)
+ {
+ strncpy(fInfo.labels[i],default_address_field_labels[i],sizeof(fInfo.labels[0]));
+ }
+}
+
+QString PilotAddressInfo::phoneLabel(EPhoneType i) const
+{
+ if (i<=eMobile)
+ {
+ return Pilot::fromPilot(info()->phoneLabels[i]);
+ }
+ else
+ {
+ return QString();
+ }
+}
+
+PhoneSlot::PhoneSlot( const int v )
+{
+ i = entryPhone1;
+ operator=(v);
+}
+
+const PhoneSlot &PhoneSlot::operator=( const int &v )
+{
+ if ( (entryPhone1 <= v) && (v <= entryPhone5) )
+ {
+ i = v;
+ }
+ else
+ {
+ i = invalid;
+ }
+ return *this;
+}
+
+const PhoneSlot &PhoneSlot::operator++()
+{
+ if ( (i!=invalid) && (i<entryPhone5) )
+ {
+ ++i;
+ }
+ else
+ {
+ i = invalid;
+ }
+ return *this;
+}
+
+/* static */ const PhoneSlot PhoneSlot::begin()
+{
+ return PhoneSlot( entryPhone1 );
+}
+
+/* static */ const PhoneSlot PhoneSlot::end()
+{
+ return PhoneSlot( invalid );
+}
+
+unsigned int PhoneSlot::toOffset() const
+{
+ if ( isValid() )
+ {
+ return i-entryPhone1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+unsigned int PhoneSlot::toField() const
+{
+ if ( isValid() )
+ {
+ return i;
+ }
+ else
+ {
+ return entryPhone1;
+ }
+}
+
+PhoneSlot::operator QString() const
+{
+ return QString("%1,%2").arg(toOffset()).arg(toField());
+}
+
+#define MAXFIELDS 19
+
+PilotAddress::PilotAddress(PilotRecord *rec) :
+ PilotRecordBase(rec),
+ fAddressInfo()
+{
+ FUNCTIONSETUPL(4);
+ memset(&fAddressInfo,0,sizeof(fAddressInfo));
+
+ if (rec)
+ {
+ pi_buffer_t b;
+ b.data = (unsigned char *) rec->data();
+ b.allocated = b.used = rec->size();
+ unpack_Address(&fAddressInfo, &b, address_v1);
+ }
+ else
+ {
+ fAddressInfo.phoneLabel[0] = (int) PilotAddressInfo::eWork;
+ fAddressInfo.phoneLabel[1] = (int) PilotAddressInfo::eHome;
+ fAddressInfo.phoneLabel[2] = (int) PilotAddressInfo::eOther;
+ fAddressInfo.phoneLabel[3] = (int) PilotAddressInfo::eMobile;
+ fAddressInfo.phoneLabel[4] = (int) PilotAddressInfo::eEmail;
+ }
+}
+
+PilotAddress::PilotAddress(const PilotAddress & copyFrom) :
+ PilotRecordBase(copyFrom),
+ fAddressInfo()
+{
+ FUNCTIONSETUPL(4);
+ _copyAddressInfo(copyFrom.fAddressInfo);
+}
+
+PilotAddress & PilotAddress::operator = (const PilotAddress & copyFrom)
+{
+ FUNCTIONSETUPL(4);
+ PilotRecordBase::operator = (copyFrom);
+ _copyAddressInfo(copyFrom.fAddressInfo);
+ return *this;
+}
+
+bool PilotAddress::operator==(const PilotAddress &compareTo)
+{
+ FUNCTIONSETUPL(4);
+
+ // now compare all the fields stored in the fAddressInfo.entry array of char*[19]
+ for (int i=0; i<MAXFIELDS; i++) {
+ // if one is NULL, and the other non-empty, they are not equal for sure
+ if ( !getFieldP(i) && compareTo.getFieldP(i))
+ {
+ return false;
+ }
+ if ( getFieldP(i) && !compareTo.getFieldP(i))
+ {
+ return false;
+ }
+
+ // test for getField(i)!=... to prevent strcmp or NULL strings! None or both can be zero, but not a single one.
+ if ( (getFieldP(i) != compareTo.getFieldP(i)) && ( strcmp(getFieldP(i), compareTo.getFieldP(i)) ) )
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+void PilotAddress::_copyAddressInfo(const struct Address &copyFrom)
+{
+ FUNCTIONSETUPL(4);
+ fAddressInfo.showPhone = copyFrom.showPhone;
+
+ for (int labelLp = 0; labelLp < 5; labelLp++)
+ {
+ fAddressInfo.phoneLabel[labelLp] =
+ copyFrom.phoneLabel[labelLp];
+ }
+
+ for (unsigned int i = 0; i< MAXFIELDS; ++i)
+ {
+ if (copyFrom.entry[i])
+ {
+ fAddressInfo.entry[i] = qstrdup(copyFrom.entry[i]);
+ }
+ else
+ {
+ fAddressInfo.entry[i] = 0L;
+ }
+ }
+}
+
+
+PilotAddress::~PilotAddress()
+{
+ FUNCTIONSETUPL(4);
+ free_Address(&fAddressInfo);
+}
+
+QString PilotAddress::getTextRepresentation(const PilotAddressInfo *info, Qt::TextFormat richText) const
+{
+ QString text, tmp;
+
+ QString par = (richText==Qt::RichText) ?CSL1("<p>"): QString();
+ QString ps = (richText==Qt::RichText) ?CSL1("</p>"):CSL1("\n");
+ QString br = (richText==Qt::RichText) ?CSL1("<br/>"):CSL1("\n");
+
+ // title + name
+ text += par;
+ if (!getField(entryTitle).isEmpty())
+ {
+ text += rtExpand(getField(entryTitle), richText);
+ text += CSL1(" ");
+ }
+
+ tmp = richText ? CSL1("<b><big>%1 %2</big></b>") : CSL1("%1 %2");
+ QString firstName = getField(entryFirstname);
+ if (firstName.isEmpty())
+ {
+ // So replace placeholder for first name (%1) with empty
+ tmp = tmp.arg(QString());
+ }
+ else
+ {
+ tmp = tmp.arg(rtExpand(firstName,richText));
+ }
+ tmp=tmp.arg(rtExpand(getField(entryLastname), richText));
+ text += tmp;
+ text += ps;
+
+ // company
+ if (!getField(entryCompany).isEmpty())
+ {
+ text += par;
+ text += rtExpand(getField(entryCompany), richText);
+ text += ps;
+ }
+
+ // phone numbers (+ labels)
+ text += par;
+ for ( PhoneSlot i = PhoneSlot::begin(); i.isValid(); ++i )
+ {
+ if (!getField(i.toField()).isEmpty())
+ {
+ if (richText)
+ {
+ if (getShownPhone() == i)
+ {
+ tmp=CSL1("<small>%1: </small><b>%2</b>");
+ }
+ else
+ {
+ tmp=CSL1("<small>%1: </small>%2");
+ }
+ }
+ else
+ {
+ tmp=CSL1("%1: %2");
+ }
+ if (info)
+ {
+ tmp=tmp.arg(info->phoneLabel( getPhoneType( i ) ));
+ }
+ else
+ {
+ tmp=tmp.arg(CSL1("Contact: "));
+ }
+ tmp=tmp.arg(rtExpand(getField(i.toField()), richText));
+ text += tmp;
+ text += br;
+ }
+ }
+ text += ps;
+
+ // address, city, state, country
+ text += par;
+ if (!getField(entryAddress).isEmpty())
+ {
+ text += rtExpand(getField(entryAddress), richText);
+ text += br;
+ }
+ if (!getField(entryCity).isEmpty())
+ {
+ text += rtExpand(getField(entryCity), richText);
+ text += CSL1(" ");
+ }
+ if (!getField(entryState).isEmpty())
+ {
+ text += rtExpand(getField(entryState), richText);
+ text += CSL1(" ");
+ }
+ if (!getField(entryZip).isEmpty())
+ {
+ text += rtExpand(getField(entryZip), richText);
+ }
+ text += br;
+ if (!getField(entryCountry).isEmpty())
+ {
+ text += rtExpand(getField(entryCountry), richText);
+ text += br;
+ }
+ text += ps;
+
+ // custom fields
+ text += par;
+ for (int i = entryCustom1; i <= entryCustom4; i++)
+ {
+ if (!getField(i).isEmpty())
+ {
+ text += rtExpand(getField(i), richText);
+ text += br;
+ }
+ }
+ text += ps;
+
+ // category
+ if (info)
+ {
+ QString categoryName = info->categoryName( category() );
+ if (!categoryName.isEmpty())
+ {
+ text += par;
+ text += rtExpand(categoryName, richText);
+ text += ps;
+ }
+ }
+
+ // note
+ if (!getField(entryNote).isEmpty())
+ {
+ text += richText?CSL1("<hr/>"):CSL1("-----------------------------\n");
+ text += par;
+ text += rtExpand(getField(entryNote), richText);
+ text += ps;
+ }
+
+ return text;
+}
+
+QStringList PilotAddress::getEmails() const
+{
+ QStringList list;
+
+ for ( PhoneSlot i = PhoneSlot::begin(); i.isValid(); ++i)
+ {
+ PilotAddressInfo::EPhoneType t = getPhoneType( i );
+ if ( t == PilotAddressInfo::eEmail )
+ {
+ QString s = getField(i.toField());
+ if (!s.isEmpty())
+ {
+ list.append(s);
+ }
+ }
+ }
+
+ return list;
+}
+
+void PilotAddress::setEmails(const QStringList &list)
+{
+ FUNCTIONSETUPL(4);
+ QString test;
+
+ // clear all e-mails first
+ for ( PhoneSlot i = PhoneSlot::begin(); i.isValid(); ++i )
+ {
+ PilotAddressInfo::EPhoneType t = getPhoneType( i );
+ if (t == PilotAddressInfo::eEmail)
+ {
+ setField(i.toField(), QString() );
+ }
+ }
+
+ for(QStringList::ConstIterator listIter = list.begin();
+ listIter != list.end(); ++listIter)
+ {
+ QString email = *listIter;
+ if (!setPhoneField(PilotAddressInfo::eEmail, email, NoFlags).isValid())
+ {
+ WARNINGKPILOT << "Email accounts overflowed, silently dropped." << endl;
+ }
+ }
+}
+
+QString PilotAddress::getField(int field) const
+{
+ if ( (entryLastname <= field) && (field <= entryNote) )
+ {
+ return Pilot::fromPilot(fAddressInfo.entry[field]);
+ }
+ else
+ {
+ return QString();
+ }
+}
+
+PhoneSlot PilotAddress::_getNextEmptyPhoneSlot() const
+{
+ FUNCTIONSETUPL(4);
+ for (PhoneSlot i = PhoneSlot::begin(); i.isValid(); ++i)
+ {
+ const char *phoneField = getFieldP(i.toField());
+
+ if (!phoneField || !phoneField[0])
+ {
+ return i;
+ }
+ }
+ return PhoneSlot();
+}
+
+PhoneSlot PilotAddress::setPhoneField(PilotAddressInfo::EPhoneType type,
+ const QString &field,
+ PhoneHandlingFlags flags)
+{
+ FUNCTIONSETUPL(4);
+
+ const bool overwriteExisting = (flags == Replace);
+ PhoneSlot fieldSlot;
+ if (overwriteExisting)
+ {
+ fieldSlot = _findPhoneFieldSlot(type);
+ }
+
+ if ( !fieldSlot.isValid() )
+ {
+ fieldSlot = _getNextEmptyPhoneSlot();
+ }
+
+ // store the overflow phone
+ if ( !fieldSlot.isValid() )
+ {
+ DEBUGKPILOT << fname << ": Phone would overflow." << endl;
+ }
+ else // phone field 1 - 5; straight forward storage
+ {
+ setField(fieldSlot.toField(), field);
+ fAddressInfo.phoneLabel[fieldSlot.toOffset()] = (int) type;
+ }
+ return fieldSlot;
+}
+
+PhoneSlot PilotAddress::_findPhoneFieldSlot(PilotAddressInfo::EPhoneType t) const
+{
+ FUNCTIONSETUPL(4);
+ for ( PhoneSlot i = PhoneSlot::begin(); i.isValid(); ++i )
+ {
+ if ( getPhoneType(i) == t )
+ {
+ return i;
+ }
+ }
+
+ return PhoneSlot();
+}
+
+QString PilotAddress::getPhoneField(PilotAddressInfo::EPhoneType type) const
+{
+ FUNCTIONSETUPL(4);
+ PhoneSlot fieldSlot = _findPhoneFieldSlot(type);
+
+ if (fieldSlot.isValid())
+ {
+ return getField(fieldSlot.toField());
+ }
+
+ return QString();
+}
+
+PhoneSlot PilotAddress::getShownPhone() const
+{
+ // The slot is stored as an offset
+ return PhoneSlot(entryPhone1 + fAddressInfo.showPhone);
+}
+
+const PhoneSlot &PilotAddress::setShownPhone( const PhoneSlot &v )
+{
+ FUNCTIONSETUPL(4);
+ if (v.isValid())
+ {
+ fAddressInfo.showPhone = v.toOffset();
+ }
+ return v;
+}
+
+PhoneSlot PilotAddress::setShownPhone(PilotAddressInfo::EPhoneType type)
+{
+ FUNCTIONSETUPL(4);
+ PhoneSlot fieldSlot = _findPhoneFieldSlot(type);
+
+ // Did we find a slot with the requested type?
+ if (!fieldSlot.isValid())
+ {
+ // No, so look for first non-empty phone slot
+ for ( fieldSlot = PhoneSlot::begin(); fieldSlot.isValid(); ++fieldSlot )
+ {
+ const char *p = getFieldP(fieldSlot.toField());
+ if (p && p[0])
+ {
+ break;
+ }
+ }
+ // If all of them are empty, then use first slot instead
+ if (!fieldSlot.isValid())
+ {
+ fieldSlot = PhoneSlot::begin();
+ }
+ }
+ setShownPhone(fieldSlot);
+ return fieldSlot;
+}
+
+PilotAddressInfo::EPhoneType PilotAddress::getPhoneType( const PhoneSlot &field ) const
+{
+ if ( field.isValid() )
+ {
+ return (PilotAddressInfo::EPhoneType) fAddressInfo.phoneLabel[field.toOffset()];
+ }
+ else
+ {
+ return PilotAddressInfo::eNone;
+ }
+}
+
+void PilotAddress::setField(int field, const QString &text)
+{
+ FUNCTIONSETUPL(4);
+ // This will have either been created with unpack_Address, and/or will
+ // be released with free_Address, so use malloc/free here:
+ if (fAddressInfo.entry[field])
+ {
+ free(fAddressInfo.entry[field]);
+ fAddressInfo.entry[field]=0L;
+ }
+ if (!text.isEmpty())
+ {
+ fAddressInfo.entry[field] = (char *) malloc(text.length() + 1);
+ Pilot::toPilot(text, fAddressInfo.entry[field], text.length()+1);
+ }
+ else
+ {
+ fAddressInfo.entry[field] = 0L;
+ }
+}
+
+PilotRecord *PilotAddress::pack() const
+{
+ FUNCTIONSETUPL(4);
+ int i;
+
+ pi_buffer_t *b = pi_buffer_new( sizeof(fAddressInfo) );
+ i = pack_Address(const_cast<Address_t *>(&fAddressInfo), b, address_v1);
+ if (i<0)
+ {
+ return 0L;
+ }
+ // pack_Address sets b->used
+ return new PilotRecord( b, this );
+}
diff --git a/kpilot/lib/pilotAddress.h b/kpilot/lib/pilotAddress.h
new file mode 100644
index 000000000..d6dd20e45
--- /dev/null
+++ b/kpilot/lib/pilotAddress.h
@@ -0,0 +1,339 @@
+#ifndef _KPILOT_PILOTADDRESS_H
+#define _KPILOT_PILOTADDRESS_H
+/* pilotAddress.h KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2007 by Adriaan de Groot <[email protected]>
+**
+** This is a wrapper for pilot-link's address structures.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <pi-macros.h>
+#include <pi-address.h>
+
+#include <qnamespace.h>
+
+#include "pilotRecord.h"
+#include "pilotAppInfo.h"
+
+/** Interpreted form of the AppInfo block in the address database. */
+typedef PilotAppInfo<
+ AddressAppInfo,
+ unpack_AddressAppInfo,
+ pack_AddressAppInfo> PilotAddressInfo_;
+
+/** This class exists @em only to clear up the type mess that
+* is the field-numbers-and-indexes for phone numbers in the
+* handheld records. The standard address record has 19 fields,
+* five of which are phone fields. Those are fields 3..7 and they
+* are referred to as fields Phone1 .. Phone5. Sometimes we
+* need to act as if the phone field numbers are indeed the field
+* numbers (3..7) and sometimes we need to use those same field
+* numbers to index into a C array (0 based!) so then we map
+* field number 3 (Phone1) to a 0 index.
+*
+* Also handles iteration nicely.
+*
+* A phone slot value may be invalid. If so, operations on it will
+* fail (yielding invalid again) and isValid() will return @c false.
+*/
+class PhoneSlot
+{
+friend class PilotAddress;
+protected:
+ /** Constructor. Use the specified value for the phone slot.
+ * @p v is a field number (3..8).
+ */
+ explicit PhoneSlot( const int v );
+
+ /** Assignment operator. Set the value of the slot to
+ * the specified value @p v . This may yield an invalid
+ * phone slot.
+ */
+ const PhoneSlot &operator=(const int &v);
+
+ /** Map the slot to an offset (for use in finding the phone type
+ * for a given slot).
+ * @return Offset of this slot within the phone fields.
+ */
+ unsigned int toOffset() const;
+
+ /** Map the slot to a field number. */
+ unsigned int toField() const;
+
+public:
+ static const int invalid = -1; ///< Value for invalid slots. */
+
+ /** Constructor. The slot is invalid. */
+ PhoneSlot()
+ {
+ i = invalid;
+ }
+
+ /** Comparison operator. */
+ bool operator ==( const PhoneSlot &v ) const
+ {
+ return v.i == i;
+ }
+
+ /** Iterator operation. Go to the next slot (or invalid when
+ * the range runs out).
+ */
+ const PhoneSlot &operator++();
+
+ /** Begin value of an iteration through the phone slots. */
+ static const PhoneSlot begin();
+
+ /** When the slot range runs out (past entryPhone5) it
+ * is invalid, so the end compares with that.
+ */
+ static const PhoneSlot end();
+
+ /** Valid slots are entryPhone1 (3) through entryPhone5 (7).
+ * @return @c true if the slot is valid.
+ */
+ bool isValid() const
+ {
+ return (entryPhone1 <= i) && (i <= entryPhone5);
+ }
+
+ operator QString() const;
+private:
+ int i;
+} ;
+
+
+class PilotAddressInfo : public PilotAddressInfo_
+{
+public:
+ PilotAddressInfo(PilotDatabase *d) : PilotAddressInfo_(d)
+ {
+ }
+
+ /** This resets the entire AppInfo block to one as it would be
+ * in an English-language handheld, with 3 categories and
+ * default field labels for everything.
+ */
+ void resetToDefault();
+
+ enum EPhoneType {
+ eWork=0,
+ eHome,
+ eFax,
+ eOther,
+ eEmail,
+ eMain,
+ ePager,
+ eMobile,
+ eNone=-1
+ } ;
+
+ QString phoneLabel(EPhoneType i) const;
+} ;
+
+/** @brief A wrapper class around the Address struct provided by pi-address.h
+ *
+ * This class allows the user to set and get address field values.
+ * For everything but phone fields, the user can simply pass the
+ * the pi-address enum for the index for setField() and getField() such
+ * as entryLastname.
+ *
+ * Phone fields are a bit trickier. The structure allows for 8 possible
+ * phone fields with 5 possible slots. That means there could be three
+ * fields that don't have available storage. The setPhoneField() method
+ * will attempt to store the extra fields in a custom field if there
+ * is an overflow.
+ *
+ * There are eight possible fields for 5 view slots:
+ * - fields: Work, Home, Fax, Other, Pager, Mobile, E-mail, Main
+ * - slots: entryPhone1, entryPhone2, entryPhone3, entryPhone4, entryPhone5
+ *
+ * Internally in the pilot-link library, the AddressAppInfo phone
+ * array stores the strings for the eight possible phone values.
+ * Their English string values are :
+ * - phone[0] = Work
+ * - phone[1] = Home
+ * - phone[2] = Fax
+ * - phone[3] = Other
+ * - phone[4] = E-mail
+ * - phone[5] = Main
+ * - phone[6] = Pager
+ * - phone[7] = Mobile
+ *
+ * Apparently, this order is kept for all languages, just with localized
+ * strings. The implementation of the internal methods will assume
+ * this order is kept. In other languages, main can replaced with
+ * Corporation.
+ */
+class KDE_EXPORT PilotAddress : public PilotRecordBase
+{
+public:
+ PilotAddress(PilotRecord *rec = 0L);
+ PilotAddress(const PilotAddress &copyFrom);
+ PilotAddress& operator=( const PilotAddress &r );
+ bool operator==(const PilotAddress &r);
+
+ virtual ~PilotAddress();
+
+ /** Returns a text representation of the address. If @p richText is true, the
+ * text will be formatted with Qt-HTML tags. The AppInfo structure @p info
+ * is used to figure out the phone labels; if it is NULL then bogus labels are
+ * used to identify phone types.
+ */
+ QString getTextRepresentation(const PilotAddressInfo *info, Qt::TextFormat richText) const;
+
+ /**
+ * @param text set the field value
+ * @param field int values associated with the enum defined in
+ * pi-address.h.
+ * The copied possible enum's are: (copied from pi-address.h on 1/12/01)
+ * enum { entryLastname, entryFirstname, entryCompany,
+ * entryPhone1, entryPhone2, entryPhone3, entryPhone4, entryPhone5,
+ * entryAddress, entryCity, entryState, entryZip, entryCountry,
+ * entryTitle, entryCustom1, entryCustom2, entryCustom3, entryCustom4,
+ * entryNote };
+ */
+ void setField(int field, const QString &text);
+ /** Set a field @p i to a given text value. Uses the phone slots only. */
+ void setField(const PhoneSlot &i, const QString &t)
+ {
+ if (i.isValid())
+ {
+ setField(i.toField(),t);
+ }
+ }
+
+ /** Returns the text value of a given field @p field (or QString::null
+ * if there is no such field).
+ */
+ QString getField(int field) const;
+ /** Returns the value of the phone field @p i . */
+ QString getField(const PhoneSlot &i) const
+ {
+ return i.isValid() ? getField(i.toField()) : QString();
+ }
+
+ /**
+ * Return list of all email addresses. This will search through our "phone"
+ * fields and will return only those which are e-mail addresses.
+ */
+ QStringList getEmails() const;
+ void setEmails(const QStringList &emails);
+
+ enum PhoneHandlingFlags
+ {
+ NoFlags=0, ///< No special handling
+ Replace ///< Replace existing entries of same type
+ } ;
+
+ /**
+ * @param type is the type of phone
+ * @param checkCustom4 flag if true, checks the entryCustom4 field
+ * for extra phone fields
+ * @return the field associated with the type
+ */
+ QString getPhoneField(PilotAddressInfo::EPhoneType type) const;
+
+ /**
+ * @param type is the type of phone
+ * @param field is value to store
+ * @param overflowCustom is true, and entryPhone1 to entryPhone5 is full
+ * it will use entryCustom4 field to store the field
+ * @param overwriteExisting is true, it will overwrite an existing record-type
+ * with the field, else it will always search for the first available slot
+ * @return index of the field that this information was set to
+ */
+ PhoneSlot setPhoneField(PilotAddressInfo::EPhoneType type, const QString &value, PhoneHandlingFlags flags);
+
+ /**
+ * Returns the slot of the phone number
+ * selected by the user to be shown in the
+ * overview of addresses.
+ *
+ * @return Slot of phone entry (between entryPhone1 and entryPhone5)
+ */
+ PhoneSlot getShownPhone() const;
+
+ /**
+ * Set the shown phone (the one preferred by the user for display
+ * on the handheld's overview page) to the @em type (not index)
+ * indicated. Looks through the phone entries of this record to
+ * find the first one one of this type.
+ *
+ * @return Slot of phone entry.
+ *
+ * @note Sets the shown phone to the first entry if no field of
+ * type @p phoneType can be found @em and no Home phone
+ * field (the fallback) can be found either.
+ */
+ PhoneSlot setShownPhone(PilotAddressInfo::EPhoneType phoneType);
+
+ /**
+ * Set the shown phone (the one preferred by the user for display
+ * on the handheld's overview page) to the given @p slot .
+ *
+ * @return @p v
+ */
+ const PhoneSlot &setShownPhone(const PhoneSlot &v);
+
+ /** Get the phone type (label) for a given field @p field
+ * in the record. The @p field must be within the
+ * phone range (entryPhone1 .. entryPhone5).
+ *
+ * @return Phone type for phone field @p field .
+ * @return @c eNone (fake phone type) if @p field is invalid.
+ */
+ PilotAddressInfo::EPhoneType getPhoneType(const PhoneSlot &field) const;
+
+ PilotRecord *pack() const;
+
+ const struct Address *address() const { return &fAddressInfo; } ;
+
+
+protected:
+ // Get the pointers in cases where no conversion to
+ // unicode is desired.
+ //
+ const char *getFieldP(int field) const
+ {
+ return fAddressInfo.entry[field];
+ }
+
+private:
+ void _copyAddressInfo(const struct Address &copyFrom);
+ PhoneSlot _getNextEmptyPhoneSlot() const;
+
+ /** @return entryPhone1 to entryPhone5 if the appTypeNum number is
+ * found in the phoneLabel array; return -1 if not found
+ */
+ PhoneSlot _findPhoneFieldSlot(PilotAddressInfo::EPhoneType t) const;
+
+ struct Address fAddressInfo;
+};
+
+
+
+
+#endif
diff --git a/kpilot/lib/pilotAppInfo.cc b/kpilot/lib/pilotAppInfo.cc
new file mode 100644
index 000000000..e8caf6234
--- /dev/null
+++ b/kpilot/lib/pilotAppInfo.cc
@@ -0,0 +1,77 @@
+/* pilotAppInfo.cc KPilot
+**
+** Copyright (C) 2005-2006 Adriaan de Groot <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "options.h"
+
+#include <stdio.h>
+
+#include "pilotAppInfo.h"
+
+PilotAppInfoBase::PilotAppInfoBase(PilotDatabase *d) :
+ fC( 0L ),
+ fLen(0),
+ fOwn(true)
+{
+ FUNCTIONSETUP;
+ int appLen = Pilot::MAX_APPINFO_SIZE;
+ unsigned char buffer[Pilot::MAX_APPINFO_SIZE];
+
+ if (!d || !d->isOpen())
+ {
+ WARNINGKPILOT << "Bad database pointer." << endl;
+ fLen = 0;
+ KPILOT_DELETE( fC );
+ return;
+ }
+
+ fC = new struct CategoryAppInfo;
+ fLen = appLen = d->readAppBlock(buffer,appLen);
+ unpack_CategoryAppInfo(fC, buffer, appLen);
+}
+
+PilotAppInfoBase::~PilotAppInfoBase()
+{
+ if (fOwn)
+ {
+ delete fC;
+ }
+}
+
+bool PilotAppInfoBase::setCategoryName(unsigned int i, const QString &s)
+{
+ if ( (i>=Pilot::CATEGORY_COUNT) || // bad category number
+ (!categoryInfo())) // Nowhere to write to
+ {
+ return false;
+ }
+
+ (void) Pilot::toPilot(s, categoryInfo()->name[i], Pilot::CATEGORY_SIZE - 1);
+ return true;
+}
+
+
diff --git a/kpilot/lib/pilotAppInfo.h b/kpilot/lib/pilotAppInfo.h
new file mode 100644
index 000000000..d5db9e358
--- /dev/null
+++ b/kpilot/lib/pilotAppInfo.h
@@ -0,0 +1,216 @@
+#ifndef _KPILOT_PILOTAPPINFO_H
+#define _KPILOT_PILOTAPPINFO_H
+/* pilotAppInfo.h KPilot
+**
+** Copyright (C) 2005-2006 Adriaan de Groot <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "pilotLinkVersion.h"
+
+#include "pilot.h"
+#include "pilotDatabase.h"
+
+/**
+* A database on the handheld has an "AppInfo" block at the beginning
+* with some database-specific information and a common part.
+* This base class deals with the common part, the categories.
+*
+* Most data in the handheld is stored in @em categories ; every
+* record in every database, for instance, has a category assigned
+* to it (perhaps "Unfiled", but that's just another category).
+*
+* Every database has a category table assigning labels to the
+* categories that exist. There are CATEGORY_COUNT (16) categories
+* available for each database; labels may vary per database.
+*
+* This class encapsulates the basic category table manipulations.
+*/
+class KDE_EXPORT PilotAppInfoBase
+{
+protected:
+ /** Initialize class members after reading header, to alias data elsewhere.
+ * Only for use by the (derived) template classes below.
+ */
+ void init(struct CategoryAppInfo *c, int len)
+ {
+ fC = c;
+ fLen = len ;
+ } ;
+
+public:
+ /** Constructor. This is for use by derived classes (using the template below
+ * only, and says that the category info in the base class aliases data in
+ * the derived class. Remember to call init()!
+ */
+ PilotAppInfoBase() : fC(0L), fLen(0), fOwn(false) { } ;
+
+ /** Constructor, intended for untyped access to the AppInfo only. This throws
+ * away everything but the category information. In this variety, the
+ * CategoryAppInfo structure is owned by the PilotAppInfoBase object.
+ */
+ PilotAppInfoBase(PilotDatabase *d);
+
+ /** Destructor. */
+ virtual ~PilotAppInfoBase();
+
+ /** Retrieve the most basic part of the AppInfo block -- the category
+ * information which is guaranteed to be the first 240-odd bytes of
+ * a database.
+ */
+ struct CategoryAppInfo *categoryInfo()
+ {
+ return fC;
+ } ;
+
+ /** Const version of the above function. */
+ inline const struct CategoryAppInfo *categoryInfo() const
+ {
+ return fC;
+ } ;
+
+ /** Returns the length of the (whole) AppInfo block. */
+ inline PI_SIZE_T length() const
+ {
+ return fLen;
+ } ;
+
+ /** @see findCategory(const QString &name, bool unknownIsUnfiled, struct CategoryAppInfo *info). */
+ inline int findCategory(const QString &name, bool unknownIsUnfiled = false) const
+ {
+ return Pilot::findCategory(fC,name,unknownIsUnfiled);
+ } ;
+
+ /** Gets a single category name. Returns QString::null if there is no
+ * such category number @p i . */
+ inline QString categoryName(unsigned int i) const
+ {
+ return Pilot::categoryName(fC,i);
+ }
+
+ /** Sets a category name. @return true if this succeeded. @return false
+ * on failure, e.g. the index @p i was out of range or the category name
+ * was invalid. Category names that are too long are truncated to 15 characters.
+ */
+ bool setCategoryName(unsigned int i, const QString &s);
+
+ /** For debugging, display all the category names */
+ inline void dump() const
+ {
+ Pilot::dumpCategories(fC);
+ };
+
+protected:
+ struct CategoryAppInfo *fC;
+ PI_SIZE_T fLen;
+
+ bool fOwn;
+} ;
+
+/** A template class for reading and interpreting AppInfo blocks;
+* the idea is that it handles all the boilerplate code for reading
+* the app block, converting it to the right kind, and then unpacking
+* it. Template parameters are the type (struct, from pilot-link probably)
+* of the interpreted appinfo, and the pack and unpack functions for it
+* (again, from pilot-link).
+*/
+template <typename appinfo,
+#if PILOT_LINK_IS(0,12,2)
+ /* There are additional consts introduced in 0.12.2 */
+ int(*unpack)(appinfo *, const unsigned char *, PI_SIZE_T),
+ int(*pack)(const appinfo *, unsigned char *, PI_SIZE_T)
+#else
+ int(*unpack)(appinfo *, unsigned char *, PI_SIZE_T),
+ int(*pack)(appinfo *, unsigned char *, PI_SIZE_T)
+#endif
+ >
+class PilotAppInfo : public PilotAppInfoBase
+{
+public:
+ /** Constructor. Read the appinfo from database @p d and
+ * interpret it.
+ */
+ PilotAppInfo(PilotDatabase *d) : PilotAppInfoBase()
+ {
+ int appLen = Pilot::MAX_APPINFO_SIZE;
+ unsigned char buffer[Pilot::MAX_APPINFO_SIZE];
+
+ memset(&fInfo,0,sizeof(fInfo));
+ if (d && d->isOpen())
+ {
+ appLen = d->readAppBlock(buffer,appLen);
+ (*unpack)(&fInfo, buffer, appLen);
+ // fInfo is just a struct, so we can point to it anyway.
+ init(&fInfo.category,appLen);
+ }
+ else
+ {
+ delete fC;
+ fC = 0L;
+ fLen = 0;
+ init(&fInfo.category,sizeof(fInfo));
+ }
+ } ;
+
+ PilotAppInfo()
+ {
+ memset(&fInfo,0,sizeof(fInfo));
+ init(&fInfo.category,sizeof(fInfo));
+ }
+
+
+ /** Write this appinfo block to the database @p d; returns
+ * the number of bytes written or -1 on failure. This
+ * function is robust when called with a NULL database @p d.
+ */
+ int writeTo(PilotDatabase *d)
+ {
+ unsigned char buffer[Pilot::MAX_APPINFO_SIZE];
+ if (!d || !d->isOpen())
+ {
+ return -1;
+ }
+ int appLen = (*pack)(&fInfo, buffer, length());
+ if (appLen > 0)
+ {
+ d->writeAppBlock(buffer,appLen);
+ }
+ return appLen;
+ } ;
+
+ /** Returns a (correctly typed) pointer to the interpreted
+ * appinfo block.
+ */
+ appinfo *info() { return &fInfo; } ;
+ /** Returns a const (correctly typed) pointer to the interpreted
+ * appinfo block.
+ */
+ const appinfo *info() const { return &fInfo; } ;
+
+protected:
+ appinfo fInfo;
+} ;
+
+
+#endif
diff --git a/kpilot/lib/pilotCard.h b/kpilot/lib/pilotCard.h
new file mode 100644
index 000000000..86d1f70c6
--- /dev/null
+++ b/kpilot/lib/pilotCard.h
@@ -0,0 +1,65 @@
+#ifndef _KPILOT_PILOTCARD_H
+#define _KPILOT_PILOTCARD_H
+/* pilotCard.h KPilot
+**
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This class is a wrapper around pilot-link's CardInfo structure
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef _PILOT_DLP_H_
+#include <pi-dlp.h>
+#endif
+
+class KPilotCard
+{
+public:
+ KPilotCard() { ::memset(&fCard,0,sizeof(struct CardInfo)); }
+ KPilotCard(const CardInfo* card) { fCard = *card; }
+
+ CardInfo *cardInfo() { return &fCard; }
+
+ /**
+ * Ensures the names are properly terminated. Needed incase we
+ * are syncing a new and bogus pilot.
+ */
+ void boundsCheck() {}
+
+ const int getCardIndex() const { return fCard.card; }
+ const int getCardVersion() const { return fCard.version; }
+ unsigned long getRomSize() const { return fCard.romSize; }
+ unsigned long getRamSize() const { return fCard.ramSize; }
+ unsigned long getRamFree() const { return fCard.ramFree; }
+ const char* getCardName() const { return fCard.name; }
+ const char* getCardManufacturer() const { return fCard.manufacturer; }
+
+private:
+ struct CardInfo fCard;
+};
+
+#endif
diff --git a/kpilot/lib/pilotDatabase.cc b/kpilot/lib/pilotDatabase.cc
new file mode 100644
index 000000000..fd568b703
--- /dev/null
+++ b/kpilot/lib/pilotDatabase.cc
@@ -0,0 +1,112 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2005-2006 Adriaan de Groot <[email protected]>
+**
+** This is the abstract base class for databases, which is used both
+** by local databases and by the serial databases held in the Pilot.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <time.h> // Needed by pilot-link include
+#include <pi-appinfo.h>
+
+#include <qstringlist.h>
+
+#include <kglobal.h>
+
+#include "pilotDatabase.h"
+#include "pilotRecord.h"
+
+static int creationCount = 0;
+static QStringList *createdNames = 0L;
+
+PilotDatabase::PilotDatabase(const QString &s) :
+ fDBOpen(false),
+ fName(s)
+{
+ FUNCTIONSETUP;
+ creationCount++;
+ if (!createdNames)
+ {
+ createdNames = new QStringList();
+ }
+ createdNames->append(s.isEmpty() ? CSL1("<empty>") : s);
+}
+
+/* virtual */ PilotDatabase::~PilotDatabase()
+{
+ FUNCTIONSETUP;
+ creationCount--;
+ if (createdNames)
+ {
+ createdNames->remove(fName.isEmpty() ? CSL1("<empty>") : fName);
+ }
+}
+
+/* static */ int PilotDatabase::instanceCount()
+{
+ FUNCTIONSETUP;
+ DEBUGKPILOT << fname << ": " << creationCount << " databases." << endl;
+ if (createdNames)
+ {
+ DEBUGKPILOT << fname << ": "
+ << createdNames->join(CSL1(",")) << endl;
+ }
+ return creationCount;
+}
+
+/* virtual */ Pilot::RecordIDList PilotDatabase::idList()
+{
+ Pilot::RecordIDList l;
+
+ for (unsigned int i = 0 ; ; i++)
+ {
+ PilotRecord *r = readRecordByIndex(i);
+ if (!r) break;
+ l.append(r->id());
+ delete r;
+ }
+
+ return l;
+}
+
+/* virtual */ Pilot::RecordIDList PilotDatabase::modifiedIDList()
+{
+ Pilot::RecordIDList l;
+
+ resetDBIndex();
+ while(1)
+ {
+ PilotRecord *r = readNextModifiedRec();
+ if (!r) break;
+ l.append(r->id());
+ delete r;
+ }
+
+ return l;
+}
+
diff --git a/kpilot/lib/pilotDatabase.h b/kpilot/lib/pilotDatabase.h
new file mode 100644
index 000000000..84c922ed4
--- /dev/null
+++ b/kpilot/lib/pilotDatabase.h
@@ -0,0 +1,272 @@
+#ifndef _KPILOT_PILOTDATABASE_H
+#define _KPILOT_PILOTDATABASE_H
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2005-2006 Adriaan de Groot <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "pilot.h"
+
+
+/** @file
+* This is the abstract base class for databases, which is used both
+* by local databases and by the serial databases held in the Pilot.
+*/
+
+
+/**
+ * Methods to access a database on the pilot.
+ *
+ * NOTE: It is the users responsibility
+ * to delete PilotRecords returned by
+ * PilotDatabase methods when finished with them!
+ */
+
+class KDE_EXPORT PilotDatabase
+{
+public:
+ PilotDatabase(const QString &name = QString::null);
+ virtual ~PilotDatabase();
+
+
+ QString name() const { return fName; } ;
+
+ /**
+ * Debugging information: tally how many databases are created
+ * or destroyed. Returns the count of currently existing databases.
+ */
+ static int instanceCount();
+
+ /* -------------------- Abstract interface for subclasses ----------------- */
+
+ /**
+ * Creates the database with the given creator, type and flags
+ * on the given card (default is RAM). If the database already
+ * exists, this function does nothing.
+ */
+ virtual bool createDatabase(long creator=0, long type=0,
+ int cardno=0, int flags=0, int version=0) = 0;
+
+ /**
+ * Deletes the database (by name, as given in the constructor,
+ * the database name is stored depending on the implementation
+ * of PilotLocalDatabase and PilotSerialDatabas)
+ */
+ virtual int deleteDatabase()=0;
+
+ /** Reads the application block info, returns size. */
+ virtual int readAppBlock(unsigned char* buffer, int maxLen) = 0;
+
+ /** Writes the application block info. */
+ virtual int writeAppBlock(unsigned char* buffer, int len) = 0;
+
+ /** Returns the number of records in the database.
+ * If the database is not open, return -1.
+ */
+ virtual unsigned int recordCount() const=0;
+
+ /** Returns a QValueList of all record ids in the database.
+ This implementation is really bad. */
+ virtual Pilot::RecordIDList idList();
+
+ /** Returns a list of all record ids that have been modified in the
+ database. This implementation is really bad. */
+ virtual Pilot::RecordIDList modifiedIDList();
+
+
+ /** Reads a record from database by id, returns record length */
+ virtual PilotRecord* readRecordById(recordid_t id) = 0;
+
+ /** Reads a record from database, returns the record length */
+ virtual PilotRecord* readRecordByIndex(int index) = 0;
+
+ /** Reads the next record from database in category 'category' */
+ virtual PilotRecord* readNextRecInCategory(int category) = 0;
+
+ /**
+ * Reads the next record from database that has the dirty flag set.
+ * If @p ind is non-NULL, *ind is set to the index of the current
+ * record (i.e. before the record pointer moves to the next
+ * modified record).
+ */
+ virtual PilotRecord* readNextModifiedRec(int *ind=NULL) = 0;
+
+ /**
+ * Writes a new record to database (if 'id' == 0, one will be
+ * assigned to newRecord)
+ */
+ virtual recordid_t writeRecord(PilotRecord* newRecord) = 0;
+
+ /**
+ * Deletes a record with the given recordid_t from the database,
+ * or all records, if @p all is set to true. The recordid_t will
+ * be ignored in this case.
+ *
+ * Return value is negative on error, 0 otherwise.
+ */
+ virtual int deleteRecord(recordid_t id, bool all=false) = 0;
+
+ /** Resets all records in the database to not dirty. */
+ virtual int resetSyncFlags() = 0;
+
+ /** Resets next record index to beginning */
+ virtual int resetDBIndex() = 0;
+
+ /** Purges all Archived/Deleted records from Palm Pilot database */
+ virtual int cleanup() = 0;
+
+ bool isOpen() const { return fDBOpen; }
+
+ /** Returns some sensible human-readable identifier for
+ * the database. Serial databases get Pilot:, local
+ * databases return the full path.
+ */
+ virtual QString dbPathName() const = 0;
+
+ /**
+ * Use this instead of RTTI to determine the type of a
+ * PilotDatabase, for those cases where it's important.
+ */
+ typedef enum { eNone=0,
+ eLocalDB=1,
+ eSerialDB=2 } DBType;
+ virtual DBType dbType() const = 0;
+
+ static inline bool isResource(struct DBInfo *info)
+ {
+ return (info->flags & dlpDBFlagResource);
+ }
+
+protected:
+ virtual void openDatabase() = 0;
+ virtual void closeDatabase() = 0;
+
+ void setDBOpen(bool yesno) { fDBOpen = yesno; }
+
+private:
+ bool fDBOpen;
+ QString fName;
+};
+
+/** A template class for reading and interpreting a database. This removes
+* the need for a lot of boilerplate code that does the conversions.
+* Parameters are two interpretation classes: one for the KDE side of
+* things (e.g. Event) and one that interprets the Pilot's records into
+* a more sensible structure (e.g. PilotDatebookEntry). The mapping from
+* the KDE type to the Pilot type and vice-versa is done by the mapper
+* class's convert() functions.
+*
+* To interpret a database as pilot-link interpretations (e.g. as
+* PilotDatebookEntry records, not as Events) use the NullMapper class
+* below in combination with a template instantiation with kdetype==pilottype.
+*
+* The database interpreter intentionally has an interface similar to
+* that of a PilotDatabase, but it isn't one.
+*/
+template <class kdetype, class pilottype, class mapper>
+class DatabaseInterpreter
+{
+private:
+ /** Interpret a PilotRecord as an object of type kdetype. */
+ kdetype *interpret(PilotRecord *r)
+ {
+ // NULL records return NULL kde objects.
+ if (!r) return 0;
+ // Interpret the binary blob as a pilot-link object.
+ pilottype *a = new pilottype(r);
+ // The record is now obsolete.
+ delete r;
+ // Interpretation failed.
+ if (!a) { return 0; }
+ // Now convert to KDE type.
+ kdetype *t = mapper::convert(a);
+ // The NULL mapper just returns the pointer a, so we
+ // need to check if anything has changed before deleting.
+ if ( (void *)t != (void *)a )
+ {
+ delete a;
+ }
+ return t;
+ }
+public:
+ /** Constructor. Interpret the database @p d. */
+ DatabaseInterpreter(PilotDatabase *d) : fDB(d) { } ;
+
+ /** Reads a record from database by @p id */
+ kdetype *readRecordById(recordid_t id)
+ {
+ return interpret(fDB->readRecordById(id));
+ }
+
+ /** Reads a record from database with index @p index */
+ kdetype *readRecordByIndex(int index)
+ {
+ return interpret(fDB->readRecordByIndex(index));
+ }
+
+ /** Reads the next record from database in category @p category */
+ kdetype *readNextRecInCategory(int category)
+ {
+ return interpret(fDB->readNextRecInCategory(category));
+ }
+
+ /**
+ * Reads the next record from database that has the dirty flag set.
+ * If @p ind is non-NULL, *ind is set to the index of the current
+ * record (i.e. before the record pointer moves to the next
+ * modified record).
+ */
+ kdetype *readNextModifiedRec(int *ind=NULL)
+ {
+ return interpret(fDB->readNextModifiedRec(ind));
+ }
+
+
+ /** Retrieve the database pointer; this is useful to just pass
+ * around DatabaseInterpreter objects as if they are databases,
+ * and then perform DB operations on the database it wraps.
+ */
+ PilotDatabase *db() const { return fDB; }
+
+protected:
+ PilotDatabase *fDB;
+} ;
+
+/** NULL mapper class; the conversions here don't @em do anything,
+* so you can use this when you only need 1 conversion step (from
+* PilotRecord to PilotDatebookEntry, for instance) instead of 2.
+*/
+template <class T>
+class NullMapper
+{
+public:
+ /** NULL Conversion function. */
+ static T *convert(T *t) { return t; }
+} ;
+
+#endif
diff --git a/kpilot/lib/pilotDateEntry.cc b/kpilot/lib/pilotDateEntry.cc
new file mode 100644
index 000000000..4fa93eac6
--- /dev/null
+++ b/kpilot/lib/pilotDateEntry.cc
@@ -0,0 +1,478 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This is a C++ wrapper for the Pilot's datebook structures.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <stdlib.h>
+
+#include <qdatetime.h>
+#include <qnamespace.h>
+#include <qregexp.h>
+
+#include <kglobal.h>
+
+#include "pilotDateEntry.h"
+
+static const char *default_date_category_names[] = {
+ "Unfiled",
+ "Business",
+ "Personal",
+ 0L
+} ;
+
+void PilotDateInfo::resetToDefault()
+{
+ FUNCTIONSETUP;
+ // Reset to all 0s
+ memset(&fInfo,0,sizeof(fInfo));
+ // Fill up default categories
+ for (unsigned int i=0; (i<4) && default_date_category_names[i]; ++i)
+ {
+ strncpy(fInfo.category.name[i],default_date_category_names[i],sizeof(fInfo.category.name[0]));
+ }
+
+ fInfo.startOfWeek = 0;
+
+}
+
+
+PilotDateEntry::PilotDateEntry():PilotRecordBase()
+{
+ ::memset(&fAppointmentInfo, 0, sizeof(struct Appointment));
+}
+
+/* initialize the entry from another one. If rec==NULL, this constructor does the same as PilotDateEntry()
+*/
+PilotDateEntry::PilotDateEntry(PilotRecord * rec) :
+ PilotRecordBase(rec)
+{
+ ::memset(&fAppointmentInfo, 0, sizeof(fAppointmentInfo));
+ if (rec)
+ {
+ // Construct a fake pi_buffer for unpack_Appointment.
+ // No ownership changes occur here.
+ pi_buffer_t b = { (unsigned char *) rec->data(), rec->size(), rec->size() } ;
+ unpack_Appointment(&fAppointmentInfo, &b, datebook_v1);
+ }
+ return;
+
+}
+
+void PilotDateEntry::_copyExceptions(const PilotDateEntry & e)
+{
+ if (e.fAppointmentInfo.exceptions > 0)
+ {
+ size_t blocksize = e.fAppointmentInfo.exceptions *
+ sizeof(struct tm);
+
+ fAppointmentInfo.exception = (struct tm *)::malloc(blocksize);
+
+ if (fAppointmentInfo.exception)
+ {
+ fAppointmentInfo.exceptions =
+ e.fAppointmentInfo.exceptions;
+ ::memcpy(fAppointmentInfo.exception,
+ e.fAppointmentInfo.exception, blocksize);
+ }
+ else
+ {
+ WARNINGKPILOT << "malloc() failed, exceptions not copied" << endl;
+ fAppointmentInfo.exceptions = 0;
+ }
+ }
+ else
+ {
+ fAppointmentInfo.exceptions = 0;
+ fAppointmentInfo.exception = 0L;
+ }
+}
+
+
+PilotDateEntry::PilotDateEntry(const PilotDateEntry & e) :
+ PilotRecordBase(e)
+{
+ ::memcpy(&fAppointmentInfo, &e.fAppointmentInfo,
+ sizeof(struct Appointment));
+ // See operator = for explanation
+ fAppointmentInfo.exception = 0L;
+ fAppointmentInfo.description = 0L;
+ fAppointmentInfo.note = 0L;
+
+ _copyExceptions(e);
+ setDescriptionP(e.fAppointmentInfo.description);
+ setNoteP(e.fAppointmentInfo.note);
+}
+
+
+PilotDateEntry & PilotDateEntry::operator = (const PilotDateEntry & e)
+{
+ if (this != &e) // Pointer equality!
+ {
+ KPILOT_FREE(fAppointmentInfo.exception);
+ KPILOT_FREE(fAppointmentInfo.description);
+ KPILOT_FREE(fAppointmentInfo.note);
+ ::memcpy(&fAppointmentInfo, &e.fAppointmentInfo,
+ sizeof(fAppointmentInfo));
+
+ // The original pointers were already freed; since we're now
+ // got the pointers from the new structure and we're going
+ // to use the standard set functions make sure that
+ // we don't free() the copies-of-pointers from e, which
+ // would be disastrous.
+ //
+ //
+ fAppointmentInfo.exception = 0L;
+ fAppointmentInfo.description = 0L;
+ fAppointmentInfo.note = 0L;
+
+ _copyExceptions(e);
+ setDescriptionP(e.fAppointmentInfo.description);
+ setNoteP(e.fAppointmentInfo.note);
+ }
+
+ return *this;
+} // end of assignment operator
+
+
+QString PilotDateEntry::getTextRepresentation(Qt::TextFormat richText)
+{
+ QString text, tmp;
+ QString par = (richText==Qt::RichText) ?CSL1("<p>"):QString::null;
+ QString ps = (richText==Qt::RichText) ?CSL1("</p>"):CSL1("\n");
+ QString br = (richText==Qt::RichText) ?CSL1("<br/>"):CSL1("\n");
+
+ // title + name
+ text += par;
+ tmp=richText?CSL1("<b><big>%1</big></b>"):CSL1("%1");
+ text += tmp.arg(rtExpand(getDescription(), richText));
+ text += ps;
+
+ QDateTime dt(readTm(getEventStart()));
+ QString startDate(dt.toString(Qt::LocalDate));
+ text+=par;
+ text+=i18n("Start date: %1").arg(startDate);
+ text+=ps;
+
+ if (isEvent())
+ {
+ text+=par;
+ text+=i18n("Whole-day event");
+ text+=ps;
+ }
+ else
+ {
+ dt=readTm(getEventEnd());
+ QString endDate(dt.toString(Qt::LocalDate));
+ text+=par;
+ text+=i18n("End date: %1").arg(endDate);
+ text+=ps;
+ }
+
+ if ( isAlarmEnabled() )
+ {
+ text+=par;
+ tmp=i18n("%1 is the duration, %2 is the time unit", "Alarm: %1 %2 before event starts").
+ arg(getAdvance());
+ switch (getAdvanceUnits())
+ {
+ case advMinutes: tmp=tmp.arg(i18n("minutes")); break;
+ case advHours: tmp=tmp.arg(i18n("hours")); break;
+ case advDays: tmp=tmp.arg(i18n("days")); break;
+ default: tmp=tmp.arg(QString::null); break;;
+ }
+ text+=tmp;
+ text+=ps;
+ }
+
+ if (getRepeatType() != repeatNone)
+ {
+ text+=par;
+ tmp=i18n("Recurrence: every %1 %2");
+ int freq = getRepeatFrequency();
+ tmp=tmp.arg(freq);
+
+ switch(getRepeatType())
+ {
+ case repeatDaily: tmp=tmp.arg(i18n("day(s)")); break;
+ case repeatWeekly: tmp=tmp.arg(i18n("week(s)")); break;
+ case repeatMonthlyByDay:
+ case repeatMonthlyByDate: tmp=tmp.arg(i18n("month(s)")); break;
+ case repeatYearly: tmp=tmp.arg(i18n("year(s)")); break;
+ default: tmp=tmp.arg(QString::null); break;
+ }
+ text+=tmp;
+ text+=br;
+
+ bool repeatsForever = getRepeatForever();
+ if (repeatsForever)
+ {
+ text+=i18n("Repeats indefinitely");
+ }
+ else
+ {
+ dt = readTm(getRepeatEnd()).date();
+ text+=i18n("Until %1").arg(dt.toString(Qt::LocalDate));
+ }
+ text+=br;
+
+ if (getRepeatType()==repeatMonthlyByDay) text+=i18n("Repeating on the i-th day of week j")+br;
+ if (getRepeatType()==repeatMonthlyByDate) text+=i18n("Repeating on the n-th day of the month")+br;
+ // TODO: show the dayArray when repeating weekly
+ /*QBitArray dayArray(7);
+ if (getRepeatType()==repeatWeekly) text+=i18n("Repeat day flags: %1").arg(getRepeatDays
+ const int *days = dateEntry->getRepeatDays();
+ // Rotate the days of the week, since day numbers on the Pilot and
+ // in vCal / Events are different.
+ if (days[0]) dayArray.setBit(6);
+ for (int i = 1; i < 7; i++)
+ {
+ if (days[i]) dayArray.setBit(i-1);
+ }*/
+ text+=ps;
+ }
+
+ if (getExceptionCount()>0 )
+ {
+ text+=par;
+ text+=i18n("Exceptions:")+br;
+ for (int i = 0; i < getExceptionCount(); i++)
+ {
+ QDate exdt=readTm(getExceptions()[i]).date();
+ text+=exdt.toString(Qt::LocalDate);
+ text+=br;
+ }
+ text+=ps;
+ }
+
+ if (!getNote().isEmpty())
+ {
+ text += richText?CSL1("<hr/>"):CSL1("-------------------------\n");
+ text+=par;
+ text+=richText?i18n("<b><em>Note:</em></b><br>"):i18n("Note:\n");
+ text+=rtExpand(getNote(), richText);
+ text+=ps;
+ }
+
+ return text;
+}
+
+QDateTime PilotDateEntry::dtStart() const
+{
+ FUNCTIONSETUP;
+ return readTm( getEventStart() );
+}
+
+QDateTime PilotDateEntry::dtEnd() const
+{
+ FUNCTIONSETUP;
+ return readTm( getEventEnd() );
+}
+
+QDateTime PilotDateEntry::dtRepeatEnd() const
+{
+ FUNCTIONSETUP;
+ return readTm( getRepeatEnd() );
+}
+
+unsigned int PilotDateEntry::alarmLeadTime() const
+{
+ FUNCTIONSETUP;
+ if (!isAlarmEnabled()) return 0;
+
+ int adv = getAdvance();
+ if ( adv < 0 )
+ {
+ return 0; // Not possible to enter on the pilot
+ }
+ unsigned int t = adv;
+ int u = getAdvanceUnits();
+
+
+ switch(u)
+ {
+ case advMinutes : t *= 60; break;
+ case advHours : t *= 3600; break;
+ case advDays : t *= 3600 * 24; break;
+ default: t = 0;
+ }
+
+ return t;
+}
+
+PilotRecord *PilotDateEntry::pack() const
+{
+ int i;
+
+ pi_buffer_t *b = pi_buffer_new( sizeof(fAppointmentInfo) );
+ i = pack_Appointment(const_cast<Appointment_t *>(&fAppointmentInfo), b, datebook_v1);
+ if (i<0)
+ {
+ // Generic error from the pack_*() functions.
+ return 0;
+ }
+
+ // pack_Appointment sets b->used
+ return new PilotRecord( b, this );
+}
+
+/* setExceptions sets a new set of exceptions. Note that
+ PilotDateEntry assumes ownership of the array and will
+ delete the old one. */
+void PilotDateEntry::setExceptions(struct tm *e) {
+ if (fAppointmentInfo.exception != e)
+ {
+ KPILOT_FREE(fAppointmentInfo.exception);
+ }
+ fAppointmentInfo.exception=e;
+}
+
+
+void PilotDateEntry::setDescriptionP(const char *desc, int l)
+{
+ FUNCTIONSETUP;
+ KPILOT_FREE(fAppointmentInfo.description);
+
+ if (desc && *desc)
+ {
+ if (-1 == l) l=::strlen(desc);
+ fAppointmentInfo.description =
+ (char *) ::malloc(l + 1);
+ if (fAppointmentInfo.description)
+ {
+ strlcpy(fAppointmentInfo.description, desc, l+1);
+ }
+ else
+ {
+ WARNINGKPILOT << "malloc() failed, description not set" << endl;
+ }
+ }
+ else
+ {
+ fAppointmentInfo.description = 0L;
+ }
+}
+
+void PilotDateEntry::setNoteP(const char *note, int l)
+{
+ FUNCTIONSETUP;
+ KPILOT_FREE(fAppointmentInfo.note);
+
+ if (note && *note)
+ {
+ if (-1 == l) l=::strlen(note);
+ fAppointmentInfo.note = (char *)::malloc(l + 1);
+ if (fAppointmentInfo.note)
+ {
+ strlcpy(fAppointmentInfo.note, note,l+1);
+ }
+ else
+ {
+ WARNINGKPILOT << "malloc() failed, note not set" << endl;
+ }
+ }
+ else
+ {
+ fAppointmentInfo.note = 0L;
+ }
+}
+
+void PilotDateEntry::setNote(const QString &s)
+{
+ QCString t = Pilot::toPilot(s);
+ setNoteP( t.data(),t.length() );
+}
+
+void PilotDateEntry::setLocation(const QString &s)
+{
+ QString note = Pilot::fromPilot(getNoteP());
+ QRegExp rxp = QRegExp("^[Ll]ocation:[^\n]+\n");
+
+ // per QString docs, this covers null and 0 length
+ if( s.isEmpty() )
+ {
+ note.replace(rxp,"");
+ }
+ else
+ {
+ QString location = "Location: " + s + "\n";
+ int pos = note.find(rxp);
+
+ if(pos >= 0)
+ {
+ note.replace( rxp, location );
+ }
+ else
+ {
+ note = location + note;
+ setNote( note );
+ }
+ }
+}
+
+QString PilotDateEntry::getLocation() const
+{
+ // Read the complete note here and not the filtered
+ // one from PilotDateEntry::getNote();
+ QString note = Pilot::fromPilot(getNoteP());
+ QRegExp rxp = QRegExp("^[Ll]ocation:[^\n]+\n");
+ int pos = note.find(rxp, 0);
+
+ if(pos >= 0)
+ {
+ QString location = rxp.capturedTexts().first();
+ rxp = QRegExp("^[Ll]ocation:[\\s|\t]*");
+ location.replace(rxp,"");
+ location.replace("\n", "");
+ return location;
+ }
+ else
+ {
+ return "";
+ }
+}
+
+void PilotDateEntry::setDescription(const QString &s)
+{
+ QCString t = Pilot::toPilot(s);
+ setDescriptionP( t.data(),t.length() );
+}
+
+QString PilotDateEntry::getNote() const
+{
+ QString note = Pilot::fromPilot(getNoteP());
+ QRegExp rxp = QRegExp("^[Ll]ocation:[^\n]+\n");
+ note.replace(rxp, "" );
+ return note;
+}
+
+QString PilotDateEntry::getDescription() const
+{
+ return Pilot::fromPilot(getDescriptionP());
+}
+
diff --git a/kpilot/lib/pilotDateEntry.h b/kpilot/lib/pilotDateEntry.h
new file mode 100644
index 000000000..d9d5db2a6
--- /dev/null
+++ b/kpilot/lib/pilotDateEntry.h
@@ -0,0 +1,388 @@
+#ifndef _KPILOT_PILOTDATEENTRY_H
+#define _KPILOT_PILOTDATEENTRY_H
+/* pilotDateEntry.h -*- C++ -*- KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** See the .cc file for an explanation of what this file is for.
+*/
+
+/** @file pilotDateEntry.h defines a wrapper for datebook entries. */
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <pi-macros.h>
+#include <pi-datebook.h>
+
+#include <qbitarray.h>
+#include <qdatetime.h>
+#include <qnamespace.h>
+
+#include "pilotRecord.h"
+#include "pilotAppInfo.h"
+
+namespace KCal
+{
+class Event;
+}
+
+/** Interpreted form of the AppInfo block in the datebook database. */
+typedef PilotAppInfo<
+ AppointmentAppInfo,
+ unpack_AppointmentAppInfo,
+ pack_AppointmentAppInfo> PilotDateInfo_;
+
+
+class PilotDateInfo : public PilotDateInfo_
+{
+public:
+ PilotDateInfo(PilotDatabase *d) : PilotDateInfo_(d)
+ {
+ }
+
+ /** This resets the entire AppInfo block to one as it would be
+ * in an English-language handheld, with 3 categories and
+ * default field labels for everything.
+ */
+ void resetToDefault();
+
+};
+
+/** This class is a wrapper for pilot-link's datebook entries (struct Appointment). */
+class KDE_EXPORT PilotDateEntry : public PilotRecordBase
+{
+public:
+ /** Constructor. Zeroes out the appointment. */
+ PilotDateEntry();
+
+ /** Constructor. Interprets the given record as an appointment. */
+ PilotDateEntry(PilotRecord *rec);
+
+ /** Copy constructor. */
+ PilotDateEntry(const PilotDateEntry &e);
+
+ /** Destructor. */
+ ~PilotDateEntry()
+ {
+ free_Appointment(&fAppointmentInfo);
+ }
+
+ /** Assignment operator. */
+ PilotDateEntry& operator=(const PilotDateEntry &e);
+
+ /** Create a textual representation (human-readable) of this appointment.
+ * If @p richText is true, then the text representation uses qt style
+ * tags as well.
+ */
+ QString getTextRepresentation(Qt::TextFormat richText);
+
+ /** Is this appointment a "floating" appointment?
+ *
+ * Floating appointments are those that have a day assigned, but no time
+ * in that day (birthday appointments are like that). You can think of these
+ * as "events", which don't have a time associated with them for a given day,
+ * as opposed to a regular "appointment", which does normally have a time
+ * associated with it.
+ */
+ inline bool doesFloat() const
+ {
+ return fAppointmentInfo.event;
+ }
+
+ /** Is this a non-time-related event as opposed to an appointment that has a
+ * time associated with it?.
+ */
+ inline bool isEvent() const
+ {
+ return doesFloat();
+ }
+
+ /** Sets this appointment's floating status.
+ *
+ * Floating appointments are those that have a day assigned, but no time
+ * in that day (birthday appointments are like that). You can think of these
+ * as "events", which don't have a time associated with them for a given day,
+ * as opposed to a regular "appointment", which does normally have a time
+ * associated with it.
+ */
+ inline void setFloats(bool f)
+ {
+ fAppointmentInfo.event = (f ? 1 : 0) /* Force 1 or 0 */ ;
+ }
+
+ /** Get the start time of this appointment. See dtStart() for caveats. */
+ inline struct tm getEventStart() const { return fAppointmentInfo.begin; }
+
+ /** Get a pointer to the start time of this appointment. See dtStart() for caveats. */
+ inline const struct tm *getEventStart_p() const
+ {
+ return &fAppointmentInfo.begin;
+ }
+
+ /** Sets the start time of this appointment. */
+ inline void setEventStart(struct tm& start)
+ {
+ fAppointmentInfo.begin = start;
+ }
+
+ /** Get the start time of this appointment. For floating appointments, the
+ * time is undefined (perhaps 1 minute past midnight).
+ *
+ * Floating appointments are those that have a day assigned, but no time
+ * in that day (birthday appointments are like that).
+ */
+ QDateTime dtStart() const;
+
+ /** Get the end time of this appointment. See dtEnd() for caveats. */
+ inline struct tm getEventEnd() const
+ {
+ return fAppointmentInfo.end;
+ }
+
+ /** Get a pointer to the end time of this appointment. See dtEnd() for caveats. */
+ inline const struct tm *getEventEnd_p() const
+ {
+ return &fAppointmentInfo.end;
+ }
+
+ /** Set the end time of this appointment. */
+ inline void setEventEnd(struct tm& end)
+ {
+ fAppointmentInfo.end = end;
+ }
+
+ /** Get the end time of this appointment. For floating appointments, the
+ * time is undefined (perhaps 1 minute past midnight).
+ *
+ * Floating appointments are those that have a day assigned, but no time
+ * in that day (birthday appointments are like that).
+ */
+ QDateTime dtEnd() const;
+
+ /** Does this appointment have an alarm set? On the Pilot, an event
+ * may have an alarm (or not). If it has one, it is also enabled and
+ * causes the Pilot to beep (or whatever is set in the system preferences).
+ */
+ inline bool isAlarmEnabled() const
+ {
+ return fAppointmentInfo.alarm;
+ }
+
+ /** Set whether this appointment has an alarm. */
+ inline void setAlarmEnabled(bool b)
+ {
+ fAppointmentInfo.alarm = (b?1:0) /* Force to known int values */ ;
+ }
+
+ /** Get the numeric part of "alarm: __ (v) minutes" on the pilot -- you
+ * set the alarm time in two parts, a number and a unit type to use; unit
+ * types are minutes, hours, days and the number is whatever you like.
+ *
+ * If alarms are not enabled for this appointment, returns garbage.
+ *
+ * @see alarmLeadTime()
+ * @see dtAlarm()
+ */
+ inline int getAdvance() const
+ {
+ return fAppointmentInfo.advance;
+ }
+
+ /** Set the numeric part of the alarm setting. See getAdvance for details. */
+ inline void setAdvance(int advance)
+ {
+ fAppointmentInfo.advance = advance;
+ }
+
+ /** Returns the units part of the alarm time. See getAdvance . */
+ inline int getAdvanceUnits() const
+ {
+ return fAppointmentInfo.advanceUnits;
+ }
+
+ /** Sets the unites part of the alarm time. See getAdvance . */
+ inline void setAdvanceUnits(int units)
+ {
+ fAppointmentInfo.advanceUnits = units;
+ }
+
+ /** Returns the number of @em seconds "lead time" the alarm should sound
+ * before the actual appointment. This interprets the advance number and units.
+ * The value is always positive, 0 if no alarms are enabled.
+ */
+ unsigned int alarmLeadTime() const;
+
+ /** Returns the absolute date and time that the alarm should sound for
+ * this appointment.
+ */
+ inline QDateTime dtAlarm() const
+ {
+ return dtStart().addSecs(-alarmLeadTime());
+ }
+
+ // The following need set routines written
+ inline repeatTypes getRepeatType() const
+ {
+ return fAppointmentInfo.repeatType;
+ }
+ inline void setRepeatType(repeatTypes r)
+ {
+ fAppointmentInfo.repeatType = r;
+ }
+
+ inline int getRepeatForever() const
+ {
+ return fAppointmentInfo.repeatForever;
+ }
+ inline void setRepeatForever(int f = 1)
+ {
+ fAppointmentInfo.repeatForever = f;
+ }
+
+ inline struct tm getRepeatEnd() const
+ {
+ return fAppointmentInfo.repeatEnd;
+ }
+ inline void setRepeatEnd(struct tm tm)
+ {
+ fAppointmentInfo.repeatEnd = tm;
+ }
+
+ /** Returns the date and time that the repeat ends. If there is no repeat,
+ * returns an invalid date and time.
+ */
+ QDateTime dtRepeatEnd() const;
+
+ inline int getRepeatFrequency() const
+ {
+ return fAppointmentInfo.repeatFrequency;
+ }
+ inline void setRepeatFrequency(int f)
+ {
+ fAppointmentInfo.repeatFrequency = f;
+ }
+
+ inline DayOfMonthType getRepeatDay() const
+ {
+ return fAppointmentInfo.repeatDay;
+ }
+ inline void setRepeatDay(DayOfMonthType rd)
+ {
+ fAppointmentInfo.repeatDay = rd;
+ };
+
+ inline const int *getRepeatDays() const
+ {
+ return fAppointmentInfo.repeatDays;
+ }
+ inline void setRepeatDays(int *rd)
+ {
+ for (int i = 0; i < 7; i++)
+ {
+ fAppointmentInfo.repeatDays[i] = rd[i];
+ }
+ }
+ inline void setRepeatDays(QBitArray rba)
+ {
+ for (int i = 0; i < 7; i++)
+ {
+ fAppointmentInfo.repeatDays[i] = (rba[i] ? 1 : 0);
+ }
+ }
+
+ inline int getExceptionCount() const
+ {
+ return fAppointmentInfo.exceptions;
+ }
+ inline void setExceptionCount(int e)
+ {
+ fAppointmentInfo.exceptions = e;
+ }
+
+ inline const struct tm *getExceptions() const
+ {
+ return fAppointmentInfo.exception;
+ }
+ void setExceptions(struct tm *e);
+
+ /** Sets the description of the appointment. This is the short string
+ * entered in the day view on the handheld, and it is called the summary
+ * in libkcal.
+ */
+ void setDescription(const QString &);
+ /** Gets the description of the appointment. See setDescription for meaning. */
+ QString getDescription() const;
+
+ /** Sets the note for the appointment. The note is the long text entry
+ * that is possible - but clumsy - on the handheld. It is called the
+ * description in libkcal.
+ */
+ void setNote(const QString &);
+ /** Gets the note for this appointment. See setNote for meaning. */
+ QString getNote() const;
+
+ /**
+ * Sets the location for the appointment. For now it will be placed within
+ * the notes on the handheld. It will be placed on one line and starts with:
+ * Location: {location}. Everything on that line will be counted as location.
+ * TODO: Make distinguish between handhelds that support the location field
+ * and the ones that don't. (Shouldn't this be done in the pilot-link lib?)
+ */
+ void setLocation(const QString &);
+
+ /** Gets the location for this appointment. See setNote for meaning. */
+ QString getLocation() const;
+
+protected:
+ void setDescriptionP(const char* desc, int l=-1);
+ const char* getDescriptionP() const
+ {
+ return fAppointmentInfo.description;
+ }
+
+ void setNoteP(const char* note, int l=-1);
+ const char* getNoteP() const
+ {
+ return fAppointmentInfo.note;
+ }
+
+public:
+ bool isMultiDay() const
+ {
+ return ((fAppointmentInfo.repeatType == repeatDaily) &&
+ (fAppointmentInfo.repeatFrequency == 1) &&
+ ( !getRepeatForever() ) &&
+ !doesFloat() );
+ }
+
+ PilotRecord *pack() const;
+
+private:
+ struct Appointment fAppointmentInfo;
+ void _copyExceptions(const PilotDateEntry &e);
+};
+
+
+
+#endif
+
diff --git a/kpilot/lib/pilotLinkVersion.h b/kpilot/lib/pilotLinkVersion.h
new file mode 100644
index 000000000..1255baade
--- /dev/null
+++ b/kpilot/lib/pilotLinkVersion.h
@@ -0,0 +1,60 @@
+#ifndef _KPILOT_PILOTLINKVERSION_H
+#define _KPILOT_PILOTLINKVERSION_H
+/* KPilot
+**
+** Copyright (C) 2005 by Adriaan de Groot
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include <pi-version.h>
+
+/** @file
+* Checks the pilot-link version and defines some convenience macros.
+* The main point of this file is to complain if you have a version
+* of pilot-link before 0.12, which no longer work with KPilot.
+*/
+
+#ifndef PILOT_LINK_VERSION
+#error "You need at least pilot-link version 0.12.0"
+#endif
+
+
+#define PILOT_LINK_NUMBER ((10000*PILOT_LINK_VERSION) + \
+ (100*PILOT_LINK_MAJOR)+PILOT_LINK_MINOR)
+#define PILOT_LINK_0_10_0 (1000)
+#define PILOT_LINK_0_11_0 (1100)
+#define PILOT_LINK_0_11_8 (1108)
+#define PILOT_LINK_0_12_0 (1200)
+#define PILOT_LINK_0_12_1 (1201)
+
+#if PILOT_LINK_NUMBER < PILOT_LINK_0_12_0
+#error "You need at least pilot-link version 0.12.0 for KPilot"
+#endif
+
+#define PI_SIZE_T size_t
+
+
+#endif
+
diff --git a/kpilot/lib/pilotLocalDatabase.cc b/kpilot/lib/pilotLocalDatabase.cc
new file mode 100644
index 000000000..9f2d5e8a4
--- /dev/null
+++ b/kpilot/lib/pilotLocalDatabase.cc
@@ -0,0 +1,762 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This defines an interface to Pilot databases on the local disk.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "options.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <iostream>
+
+#include <pi-file.h>
+
+#include <qstring.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <qdatetime.h>
+#include <qvaluevector.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <ksavefile.h>
+
+#include "pilotRecord.h"
+#include "pilotLocalDatabase.h"
+
+typedef QValueVector<PilotRecord *> Records;
+
+class PilotLocalDatabase::Private : public Records
+{
+public:
+ static const int DEFAULT_SIZE = 128;
+ Private(int size=DEFAULT_SIZE) : Records(size) { resetIndex(); }
+ ~Private() { deleteRecords(); }
+
+ void deleteRecords()
+ {
+ for (unsigned int i=0; i<size(); i++)
+ {
+ delete at(i);
+ }
+ clear();
+ resetIndex();
+ }
+
+ void resetIndex()
+ {
+ current = 0;
+ pending = -1;
+ }
+
+ unsigned int current;
+ int pending;
+} ;
+
+PilotLocalDatabase::PilotLocalDatabase(const QString & path,
+ const QString & dbName, bool useDefaultPath) :
+ PilotDatabase(dbName),
+ fPathName(path),
+ fDBName(dbName),
+ fAppInfo(0L),
+ fAppLen(0),
+ d(0L)
+{
+ FUNCTIONSETUP;
+ fixupDBName();
+ openDatabase();
+
+ if (!isOpen() && useDefaultPath)
+ {
+ if (fPathBase && !fPathBase->isEmpty())
+ {
+ fPathName = *fPathBase;
+ }
+ else
+ {
+ fPathName = KGlobal::dirs()->saveLocation("data",
+ CSL1("kpilot/DBBackup/"));
+ }
+ fixupDBName();
+ openDatabase();
+ if (!isOpen())
+ {
+ fPathName=path;
+ }
+ }
+
+}
+
+PilotLocalDatabase::PilotLocalDatabase(const QString &dbName) :
+ PilotDatabase( QString() ),
+ fPathName( QString() ),
+ fDBName( QString() ),
+ fAppInfo(0L),
+ fAppLen(0),
+ d(0L)
+{
+ FUNCTIONSETUP;
+
+ int p = dbName.findRev( '/' );
+ if (p<0)
+ {
+ // No slash
+ fPathName = CSL1(".");
+ fDBName = dbName;
+ }
+ else
+ {
+ fPathName = dbName.left(p);
+ fDBName = dbName.mid(p+1);
+ }
+ openDatabase();
+}
+
+PilotLocalDatabase::~PilotLocalDatabase()
+{
+ FUNCTIONSETUP;
+
+ closeDatabase();
+ delete[]fAppInfo;
+ delete d;
+}
+
+// Changes any forward slashes to underscores
+void PilotLocalDatabase::fixupDBName()
+{
+ FUNCTIONSETUP;
+ fDBName = fDBName.replace(CSL1("/"),CSL1("_"));
+}
+
+bool PilotLocalDatabase::createDatabase(long creator, long type, int, int flags, int version)
+{
+ FUNCTIONSETUP;
+
+ // if the database is already open, we cannot create it again.
+ // How about completely resetting it? (i.e. deleting it and then
+ // creating it again)
+ if (isOpen())
+ {
+ DEBUGKPILOT << fname << ": Database " << fDBName
+ << " already open. Cannot recreate it." << endl;
+ return true;
+ }
+
+ DEBUGKPILOT << fname << ": Creating database " << fDBName << endl;
+
+ // Database names seem to be latin1.
+ Pilot::toPilot(fDBName, fDBInfo.name, sizeof(fDBInfo.name));
+ fDBInfo.creator=creator;
+ fDBInfo.type=type;
+ fDBInfo.more=0;
+ fDBInfo.flags=flags;
+ fDBInfo.miscFlags=0;
+ fDBInfo.version=version;
+ fDBInfo.modnum=0;
+ fDBInfo.index=0;
+ fDBInfo.createDate=(QDateTime::currentDateTime()).toTime_t();
+ fDBInfo.modifyDate=(QDateTime::currentDateTime()).toTime_t();
+ fDBInfo.backupDate=(QDateTime::currentDateTime()).toTime_t();
+
+ delete[] fAppInfo;
+ fAppInfo=0L;
+ fAppLen=0;
+
+ d = new Private;
+
+ // TODO: Do I have to open it explicitly???
+ setDBOpen(true);
+ return true;
+}
+
+int PilotLocalDatabase::deleteDatabase()
+{
+ FUNCTIONSETUP;
+ if (isOpen())
+ {
+ closeDatabase();
+ }
+
+ QString dbpath=dbPathName();
+ QFile fl(dbpath);
+ if (QFile::remove(dbPathName()))
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+
+
+// Reads the application block info
+int PilotLocalDatabase::readAppBlock(unsigned char *buffer, int size)
+{
+ FUNCTIONSETUP;
+
+ size_t m = kMin((size_t)size,(size_t)fAppLen);
+
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open!" << endl;
+ memset(buffer,0,m);
+ return -1;
+ }
+
+ memcpy((void *) buffer, fAppInfo, m);
+ return fAppLen;
+}
+
+int PilotLocalDatabase::writeAppBlock(unsigned char *buffer, int len)
+{
+ FUNCTIONSETUP;
+
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open!" << endl;
+ return -1;
+ }
+ delete[]fAppInfo;
+ fAppLen = len;
+ fAppInfo = new char[fAppLen];
+
+ memcpy(fAppInfo, (void *) buffer, fAppLen);
+ return 0;
+}
+
+
+// returns the number of records in the database
+unsigned int PilotLocalDatabase::recordCount() const
+{
+ if (d && isOpen())
+ {
+ return d->size();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+// Returns a QValueList of all record ids in the database.
+QValueList<recordid_t> PilotLocalDatabase::idList()
+{
+ int idlen=recordCount();
+ QValueList<recordid_t> idlist;
+ if (idlen<=0)
+ {
+ return idlist;
+ }
+
+ // now create the QValue list from the idarr:
+ for (int i=0; i<idlen; i++)
+ {
+ idlist.append((*d)[i]->id());
+ }
+
+ return idlist;
+}
+
+// Reads a record from database by id, returns record length
+PilotRecord *PilotLocalDatabase::readRecordById(recordid_t id)
+{
+ FUNCTIONSETUP;
+
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "Database '" << fDBName << " not open!" << endl;
+ return 0L;
+ }
+
+ d->pending = -1;
+
+ for (unsigned int i = 0; i < d->size(); i++)
+ {
+ if ((*d)[i]->id() == id)
+ {
+ PilotRecord *newRecord = new PilotRecord((*d)[i]);
+ d->current = i;
+ return newRecord;
+ }
+ }
+ return 0L;
+}
+
+// Reads a record from database, returns the record
+PilotRecord *PilotLocalDatabase::readRecordByIndex(int index)
+{
+ FUNCTIONSETUP;
+
+ if (index < 0)
+ {
+ DEBUGKPILOT << fname << ": Index " << index << " is bogus." << endl;
+ return 0L;
+ }
+
+ d->pending = -1;
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open!" << endl;
+ return 0L;
+ }
+
+ DEBUGKPILOT << fname << ": Index=" << index << " Count=" << recordCount() << endl;
+
+ if ( (unsigned int)index >= recordCount() )
+ {
+ return 0L;
+ }
+ PilotRecord *newRecord = new PilotRecord((*d)[index]);
+ d->current = index;
+
+ return newRecord;
+}
+
+// Reads the next record from database in category 'category'
+PilotRecord *PilotLocalDatabase::readNextRecInCategory(int category)
+{
+ FUNCTIONSETUP;
+ d->pending = -1;
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open!" << endl;
+ return 0L;
+ }
+
+ while ((d->current < d->size())
+ && ((*d)[d->current]->category() != category))
+ {
+ d->current++;
+ }
+
+ if (d->current >= d->size())
+ return 0L;
+ PilotRecord *newRecord = new PilotRecord((*d)[d->current]);
+
+ d->current++; // so we skip it next time
+ return newRecord;
+}
+
+const PilotRecord *PilotLocalDatabase::findNextNewRecord()
+{
+ FUNCTIONSETUP;
+
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open!" << endl;
+ return 0L;
+ }
+ DEBUGKPILOT << fname << ": looking for new record from " << d->current << endl;
+ // Should this also check for deleted?
+ while ((d->current < d->size())
+ && ((*d)[d->current]->id() != 0 ))
+ {
+ d->current++;
+ }
+
+ if (d->current >= d->size())
+ return 0L;
+
+ d->pending = d->current; // Record which one needs the new id
+ d->current++; // so we skip it next time
+ return (*d)[d->pending];
+}
+
+PilotRecord *PilotLocalDatabase::readNextModifiedRec(int *ind)
+{
+ FUNCTIONSETUP;
+
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open!" << endl;
+ return 0L;
+ }
+
+ d->pending = -1;
+ // Should this also check for deleted?
+ while ((d->current < d->size())
+ && !((*d)[d->current]->isModified()) && ((*d)[d->current]->id()>0 ))
+ {
+ d->current++;
+ }
+
+ if (d->current >= d->size())
+ {
+ return 0L;
+ }
+ PilotRecord *newRecord = new PilotRecord((*d)[d->current]);
+ if (ind)
+ {
+ *ind=d->current;
+ }
+
+ d->pending = d->current; // Record which one needs the new id
+ d->current++; // so we skip it next time
+ return newRecord;
+}
+
+// Writes a new ID to the record specified the index. Not supported on Serial connections
+recordid_t PilotLocalDatabase::updateID(recordid_t id)
+{
+ FUNCTIONSETUP;
+
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open!" << endl;
+ return 0;
+ }
+ if (d->pending < 0)
+ {
+ WARNINGKPILOT << "Last call was NOT readNextModifiedRec()" << endl;
+ return 0;
+ }
+ (*d)[d->pending]->setID(id);
+ d->pending = -1;
+ return id;
+}
+
+// Writes a new record to database (if 'id' == 0, it is assumed that this is a new record to be installed on pilot)
+recordid_t PilotLocalDatabase::writeRecord(PilotRecord * newRecord)
+{
+ FUNCTIONSETUP;
+
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open!" << endl;
+ return 0;
+ }
+
+ d->pending = -1;
+ if (!newRecord)
+ {
+ WARNINGKPILOT << "Record to be written is invalid!" << endl;
+ return 0;
+ }
+
+ // Instead of making the app do it, assume that whenever a record is
+ // written to the database it is dirty. (You can clean up the database with
+ // resetSyncFlags().) This will make things get copied twice during a hot-sync
+ // but shouldn't cause any other major headaches.
+ newRecord->setModified( true );
+
+ // First check to see if we have this record:
+ if (newRecord->id() != 0)
+ {
+ for (unsigned int i = 0; i < d->size(); i++)
+ if ((*d)[i]->id() == newRecord->id())
+ {
+ delete (*d)[i];
+
+ (*d)[i] = new PilotRecord(newRecord);
+ return 0;
+ }
+ }
+ // Ok, we don't have it, so just tack it on.
+ d->append( new PilotRecord(newRecord) );
+ return newRecord->id();
+}
+
+// Deletes a record with the given recordid_t from the database, or all records, if all is set to true. The recordid_t will be ignored in this case
+int PilotLocalDatabase::deleteRecord(recordid_t id, bool all)
+{
+ FUNCTIONSETUP;
+ if (!isOpen())
+ {
+ WARNINGKPILOT <<"DB not open"<<endl;
+ return -1;
+ }
+ d->resetIndex();
+ if (all)
+ {
+ d->deleteRecords();
+ d->clear();
+ return 0;
+ }
+ else
+ {
+ Private::Iterator i;
+ for ( i=d->begin() ; i!=d->end(); ++i)
+ {
+ if ((*i) && (*i)->id() == id) break;
+ }
+ if ( (i!=d->end()) && (*i) && (*i)->id() == id)
+ {
+ d->erase(i);
+ }
+ else
+ {
+ // Record with this id does not exist!
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+// Resets all records in the database to not dirty.
+int PilotLocalDatabase::resetSyncFlags()
+{
+ FUNCTIONSETUP;
+
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open!" << endl;
+ return -1;
+ }
+ d->pending = -1;
+ for (unsigned int i = 0; i < d->size(); i++)
+ {
+ (*d)[i]->setModified( false );
+ }
+ return 0;
+}
+
+// Resets next record index to beginning
+int PilotLocalDatabase::resetDBIndex()
+{
+ FUNCTIONSETUP;
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open!" << endl;
+ return -1;
+ }
+ d->resetIndex();
+ return 0;
+}
+
+// Purges all Archived/Deleted records from Palm Pilot database
+int PilotLocalDatabase::cleanup()
+{
+ FUNCTIONSETUP;
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open!" << endl;
+ return -1;
+ }
+ d->resetIndex();
+
+ /* Not the for loop one might expect since when we erase()
+ * a record the iterator changes too.
+ */
+ Private::Iterator i = d->begin();
+ while ( i!=d->end() )
+ {
+ if ( (*i)->isDeleted() || (*i)->isArchived() )
+ {
+ delete (*i);
+ i = d->erase(i);
+ }
+ else
+ {
+ ++i;
+ }
+ }
+
+ // Don't have to do anything. Will be taken care of by closeDatabase()...
+ // Changed!
+ return 0;
+}
+
+QString PilotLocalDatabase::dbPathName() const
+{
+ FUNCTIONSETUP;
+ QString tempName(fPathName);
+ QString slash = CSL1("/");
+
+ if (!tempName.endsWith(slash)) tempName += slash;
+ tempName += getDBName();
+ tempName += CSL1(".pdb");
+ return tempName;
+}
+
+void PilotLocalDatabase::openDatabase()
+{
+ FUNCTIONSETUP;
+
+ pi_file *dbFile;
+
+ setDBOpen(false);
+
+ dbFile = pi_file_open( QFile::encodeName(dbPathName()) );
+ if (dbFile == 0L)
+ {
+ QString path = dbPathName();
+ DEBUGKPILOT << fname << ": Failed to open " << path << endl;
+ return;
+ }
+
+
+ PI_SIZE_T size = 0;
+ void *tmpBuffer;
+ pi_file_get_info(dbFile, &fDBInfo);
+ pi_file_get_app_info(dbFile, &tmpBuffer, &size);
+ fAppLen = size;
+ fAppInfo = new char[fAppLen];
+ memcpy(fAppInfo, tmpBuffer, fAppLen);
+
+ int count;
+ pi_file_get_entries(dbFile, &count);
+ if (count >= 0)
+ {
+ KPILOT_DELETE(d);
+ d = new Private(count);
+ }
+
+ int attr, cat;
+ recordid_t id;
+ unsigned int i = 0;
+ while (pi_file_read_record(dbFile, i,
+ &tmpBuffer, &size, &attr, &cat, &id) == 0)
+ {
+ pi_buffer_t *b = pi_buffer_new(size);
+ memcpy(b->data,tmpBuffer,size);
+ b->used = size;
+ (*d)[i] = new PilotRecord(b, attr, cat, id);
+ i++;
+ }
+ pi_file_close(dbFile); // We done with it once we've read it in.
+
+ KSaveFile::backupFile( dbPathName() );
+
+ setDBOpen(true);
+}
+
+void PilotLocalDatabase::closeDatabase()
+{
+ FUNCTIONSETUP;
+ pi_file *dbFile;
+
+ if (!isOpen())
+ {
+ DEBUGKPILOT << fname << ": Database " << fDBName
+ << " is not open. Cannot close and write it"
+ << endl;
+ return;
+ }
+
+ QString newName = dbPathName() + CSL1(".new");
+ QString path = dbPathName();
+ DEBUGKPILOT << fname
+ << ": Creating temp file " << newName
+ << " for the database file " << path << endl;
+
+ dbFile = pi_file_create(QFile::encodeName(newName),&fDBInfo);
+ pi_file_set_app_info(dbFile, fAppInfo, fAppLen);
+
+ for (unsigned int i = 0; i < d->size(); i++)
+ {
+ // How did a NULL pointer sneak in here?
+ if (!(*d)[i])
+ {
+ continue;
+ }
+
+ if (((*d)[i]->id() == 0) && ((*d)[i]->isDeleted()))
+ {
+ // Just ignore it
+ }
+ else
+ {
+ pi_file_append_record(dbFile,
+ (*d)[i]->data(),
+ (*d)[i]->size(),
+ (*d)[i]->attributes(), (*d)[i]->category(),
+ (*d)[i]->id());
+ }
+ }
+
+ pi_file_close(dbFile);
+ QFile::remove(dbPathName());
+ rename((const char *) QFile::encodeName(newName),
+ (const char *) QFile::encodeName(dbPathName()));
+ setDBOpen(false);
+}
+
+
+QString *PilotLocalDatabase::fPathBase = 0L;
+
+void PilotLocalDatabase::setDBPath(const QString &s)
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname
+ << ": Setting default DB path to "
+ << s
+ << endl;
+
+ if (!fPathBase)
+ {
+ fPathBase = new QString(s);
+ }
+ else
+ {
+ *fPathBase = s;
+ }
+}
+
+/* virtual */ PilotDatabase::DBType PilotLocalDatabase::dbType() const
+{
+ return eLocalDB;
+}
+
+
+/* static */ bool PilotLocalDatabase::infoFromFile( const QString &path, DBInfo *d )
+{
+ FUNCTIONSETUP;
+
+ pi_file *f = 0L;
+
+ if (!d)
+ {
+ return false;
+ }
+ if (!QFile::exists(path))
+ {
+ return false;
+ }
+
+ QCString fileName = QFile::encodeName( path );
+ f = pi_file_open( fileName );
+ if (!f)
+ {
+ WARNINGKPILOT << "Can't open " << path << endl;
+ return false;
+ }
+
+ pi_file_get_info(f,d);
+ pi_file_close(f);
+
+ return true;
+}
+
diff --git a/kpilot/lib/pilotLocalDatabase.h b/kpilot/lib/pilotLocalDatabase.h
new file mode 100644
index 000000000..c33455800
--- /dev/null
+++ b/kpilot/lib/pilotLocalDatabase.h
@@ -0,0 +1,201 @@
+#ifndef _KPILOT_PILOTLOCALDATABASE_H
+#define _KPILOT_PILOTLOCALDATABASE_H
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2006 Adriaan de Groot <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "pilotDatabase.h"
+
+/** @file
+* Defines the PilotLocalDatabase class, for databases stored
+* on disk (as opposed to in a handheld).
+*/
+
+/**
+* PilotLocalDatabase represents databases in the same binary format
+* as on the handheld but which are stored on local disk.
+*/
+class KDE_EXPORT PilotLocalDatabase : public PilotDatabase
+{
+public:
+ /**
+ * Opens the local database. If the database cannot be found at the
+ * given position, a default path is used
+ * ($KDEHOME/share/apps/kpilot/DBBackup)
+ * and if the file is found there, it is opened. In some cases this should
+ * not be done, so the parameter useDefaultPath controls this behavior.
+ * If it is set to true, the default path is used if the file cannot be
+ * found in the explicitly given location. If it is set to false and
+ * the database cannot be found, no database is opened. It can then be
+ * created explicitly at the specified location.
+ */
+ PilotLocalDatabase( const QString& path,
+ const QString& name, bool useDefaultPath=true);
+
+ /**
+ * Opens the local database. This is primarily for testing
+ * purposes; only tries the given path.
+ */
+ PilotLocalDatabase(const QString &name);
+
+ virtual ~PilotLocalDatabase();
+
+ /** Creates the database with the given creator, type and flags on
+ * the given card (default is RAM). If the database already exists,
+ * this function does nothing.
+ */
+ virtual bool createDatabase(long creator=0,
+ long type=0, int cardno=0, int flags=0, int version=0);
+
+
+
+ /** Deletes the database (by name, as given in the constructor
+ * and stored in the fDBName field. )
+ */
+ virtual int deleteDatabase();
+
+ // Reads the application block info
+ virtual int readAppBlock(unsigned char* buffer, int maxLen);
+ // Writes the application block info.
+ virtual int writeAppBlock(unsigned char* buffer, int len);
+ // returns the number of records in the database, 0 if not open
+ virtual unsigned int recordCount() const;
+ // Returns a QValueList of all record ids in the database.
+ virtual QValueList<recordid_t> idList();
+ // Reads a record from database by id, returns record
+ virtual PilotRecord* readRecordById(recordid_t id);
+ // Reads a record from database, returns the record
+ virtual PilotRecord* readRecordByIndex(int index);
+ // Reads the next record from database in category 'category'
+ virtual PilotRecord* readNextRecInCategory(int category);
+ /**
+ * Returns the next "new" record, ie. the next record
+ * that has not been synced yet. These records all have ID=0, so are
+ * not easy to find with the other methods. The record is the one
+ * contained in the database, not a copy like the read*() functions
+ * give you -- so be careful with it. Don't delete it, in any case.
+ * Casting it to non-const and marking it deleted is OK, though,
+ * which is mostly its intended use.
+ */
+ const PilotRecord *findNextNewRecord();
+
+ /**
+ * Reads the next record from database that has the dirty flag set.
+ * ind (if a valid pointer is given) will receive the index of the
+ * returned record.
+ */
+ virtual PilotRecord* readNextModifiedRec(int *ind=0L);
+ // Writes a new record to database (if 'id' == 0, none is assigned, either)
+ virtual recordid_t writeRecord(PilotRecord* newRecord);
+ /**
+ * Deletes a record with the given recordid_t from the database,
+ * or all records, if all is set to true. The recordid_t will be
+ * ignored in this case. Return value is negative on error, 0 otherwise.
+ */
+ virtual int deleteRecord(recordid_t id, bool all=false);
+ // Resets all records in the database to not dirty.
+ virtual int resetSyncFlags();
+ // Resets next record index to beginning
+ virtual int resetDBIndex();
+ // Purges all Archived/Deleted records from Palm Pilot database
+ virtual int cleanup();
+
+
+ /** Update the ID of the current record in the database with
+ * the specified @param id . This is allowed only after
+ * reading or writing a modified or new record.
+ */
+ virtual recordid_t updateID(recordid_t id);
+
+
+ /** Return the name of the database (as it would be on the handheld). */
+ QString getDBName() const { return fDBName; }
+
+ /**
+ * Returns the full path of the current database, based on
+ * the path and dbname passed to the constructor, and including
+ * the .pdb extension.
+ */
+ virtual QString dbPathName() const;
+
+ /**
+ * Accessor functions for the application info block.
+ */
+ int appInfoSize() const
+ { if (isOpen()) return fAppLen; else return -1; } ;
+ char *appInfo() { return fAppInfo; } ;
+
+ const struct DBInfo &getDBInfo() const { return fDBInfo; }
+ void setDBInfo(const struct DBInfo &dbi) {fDBInfo=dbi; }
+
+ virtual DBType dbType() const;
+
+ /** Reads local file @p path and fills in the DBInfo
+ * structure @p d with the DBInfo from the file.
+ *
+ * @return @c false if d is NULL
+ * @return @c false if the file @p path does not exist
+ * @return @c true if reading the DBInfo succeeds
+ *
+ * @note Relatively expensive operation, since the pilot-link
+ * library doesn't provide a cheap way of getting this
+ * information.
+ */
+ static bool infoFromFile( const QString &path, DBInfo *d );
+
+protected:
+ // Changes any forward slashes to underscores
+ void fixupDBName();
+ virtual void openDatabase();
+ virtual void closeDatabase();
+
+private:
+ struct DBInfo fDBInfo;
+ QString fPathName,fDBName;
+ char* fAppInfo;
+ size_t fAppLen;
+
+ class Private;
+ Private *d;
+
+public:
+ /**
+ * For databases opened by name only (constructor 2 -- which is the
+ * preferred one, too) try this path first before the default path.
+ * Set statically so it's shared for all local databases.
+ */
+ static void setDBPath(const QString &);
+ /**
+ * Accessor for the extra search path.
+ */
+ static const QString &getDBPath() { return *fPathBase; } ;
+private:
+ static QString *fPathBase;
+};
+
+#endif
diff --git a/kpilot/lib/pilotMemo.cc b/kpilot/lib/pilotMemo.cc
new file mode 100644
index 000000000..0ce09f8a7
--- /dev/null
+++ b/kpilot/lib/pilotMemo.cc
@@ -0,0 +1,135 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+**
+** This is a C++ wrapper for the Pilot's Memo Pad structures.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <qnamespace.h>
+
+#include "pilotMemo.h"
+#include "pilotDatabase.h"
+
+
+
+PilotMemo::PilotMemo(const PilotRecord * rec) : PilotRecordBase(rec)
+{
+ FUNCTIONSETUP;
+ fText = Pilot::fromPilot((const char *)(rec->data()),rec->size());
+}
+
+PilotRecord *PilotMemo::pack()
+{
+ FUNCTIONSETUPL(4);
+ int i;
+
+ int len = fText.length() + 8;
+ struct Memo buf;
+ buf.text = new char[len];
+
+ // put our text into buf
+ i = Pilot::toPilot(fText, buf.text, len);
+
+ pi_buffer_t *b = pi_buffer_new(len);
+ i = pack_Memo(&buf, b, memo_v1);
+
+ DEBUGKPILOT << fname << ": original text: [" << fText
+ << "], buf.text: [" << buf.text
+ << "], b->data: [" << b->data << "]" << endl;
+
+ if (i<0)
+ {
+ // Generic error from the pack_*() functions.
+ delete[] buf.text;
+ return 0;
+ }
+
+ // pack_Appointment sets b->used
+ PilotRecord *r = new PilotRecord(b, this);
+ delete[] buf.text;
+ return r;
+}
+
+
+QString PilotMemo::getTextRepresentation(Qt::TextFormat richText)
+{
+ if (richText==Qt::RichText)
+ {
+ return i18n("<i>Title:</i> %1<br>\n<i>MemoText:</i><br>%2").
+ arg(rtExpand(getTitle(), richText)).arg(rtExpand(text(), richText));
+ }
+ else
+ {
+ return i18n("Title: %1\nMemoText:\n%2").arg(getTitle()).arg(text());
+ }
+}
+
+
+QString PilotMemo::getTitle() const
+{
+ if (fText.isEmpty()) return QString::null;
+
+ int memoTitleLen = fText.find('\n');
+ if (-1 == memoTitleLen) memoTitleLen=fText.length();
+ return fText.left(memoTitleLen);
+}
+
+QString PilotMemo::shortTitle() const
+{
+ FUNCTIONSETUP;
+ QString t = QString(getTitle()).simplifyWhiteSpace();
+
+ if (t.length() < 32)
+ return t;
+ t.truncate(40);
+
+ int spaceIndex = t.findRev(' ');
+
+ if (spaceIndex > 32)
+ {
+ t.truncate(spaceIndex);
+ }
+
+ t += CSL1("...");
+
+ return t;
+}
+
+QString PilotMemo::sensibleTitle() const
+{
+ FUNCTIONSETUP;
+ QString s = getTitle();
+
+ if (!s.isEmpty())
+ {
+ return s;
+ }
+ else
+ {
+ return i18n("[unknown]");
+ }
+}
+
diff --git a/kpilot/lib/pilotMemo.h b/kpilot/lib/pilotMemo.h
new file mode 100644
index 000000000..6897a0417
--- /dev/null
+++ b/kpilot/lib/pilotMemo.h
@@ -0,0 +1,105 @@
+#ifndef _KPILOT_PILOTMEMO_H
+#define _KPILOT_PILOTMEMO_H
+/* pilotMemo.h KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+**
+** See the .cc file for an explanation of what this file is for.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <qnamespace.h>
+#include <qstring.h>
+
+#include <pi-memo.h>
+
+#include "pilotRecord.h"
+#include "pilotAppInfo.h"
+
+class KDE_EXPORT PilotMemo : public PilotRecordBase
+{
+public:
+ /**
+ * Constructor. Create an empty memo.
+ */
+ PilotMemo(void) : PilotRecordBase() { } ;
+
+ /**
+ * Constructor. Create a memo in the Unfiled category with
+ * text @p s .
+ */
+ PilotMemo(const QString &s) : PilotRecordBase()
+ {
+ setText(s);
+ } ;
+
+ /**
+ * Constructor. Create a memo with the category and
+ * attributes of the given record @p rec, and extract
+ * the text from that record as if it comes from the MemoDB.
+ */
+ PilotMemo(const PilotRecord* rec);
+
+ /**
+ * Constructor. Create a memo with category and
+ * attributes from the argument @p r, and set the
+ * text of the memo from string @p s.
+ */
+ PilotMemo(const PilotRecordBase *r, const QString &s) :
+ PilotRecordBase(r)
+ {
+ setText(s);
+ }
+
+ ~PilotMemo() { } ;
+
+ virtual QString getTextRepresentation(Qt::TextFormat richText);
+ QString text(void) const { return fText; } ;
+ void setText(const QString &text) { fText = text.left(MAX_MEMO_LEN); } ;
+ QString getTitle(void) const ;
+ PilotRecord* pack();
+
+ static const int MAX_MEMO_LEN=8192;
+
+ /**
+ * Return a "short but sensible" title. getTitle() returns the
+ * first line of the memo, which may be very long
+ * and inconvenient. shortTitle() returns about 30
+ * characters.
+ */
+ QString shortTitle() const;
+
+ /**
+ * Returns a (complete) title if there is one and [unknown]
+ * otherwise.
+ */
+ QString sensibleTitle() const;
+
+private:
+ QString fText;
+
+};
+
+typedef PilotAppInfo<struct MemoAppInfo,unpack_MemoAppInfo, pack_MemoAppInfo> PilotMemoInfo;
+
+#endif
diff --git a/kpilot/lib/pilotRecord.cc b/kpilot/lib/pilotRecord.cc
new file mode 100644
index 000000000..44ae4f7be
--- /dev/null
+++ b/kpilot/lib/pilotRecord.cc
@@ -0,0 +1,132 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This is a wrapper for pilot-link's general
+** Pilot database structures. These records are
+*** just collections of bits. See PilotAppCategory
+** for interpreting the bits in a meaningful way.
+**
+** As a crufty hack, the non-inline parts of
+** PilotAppCategory live in this file as well.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+#include "options.h"
+
+#include <string.h>
+
+#include <qregexp.h>
+
+#include <kglobal.h>
+#include <kcharsets.h>
+
+#include "pilot.h"
+#include "pilotRecord.h"
+
+
+
+/* virtual */ QString PilotRecordBase::textRepresentation() const
+{
+ return CSL1("[ %1,%2,%3 ]") . arg(attributes(),category(),id());
+}
+
+/* virtual */ QString PilotRecord::textRepresentation() const
+{
+ return CSL1("[ %1,%2 ]")
+ .arg(PilotRecordBase::textRepresentation())
+ .arg(size());
+}
+
+
+
+/* static */ int PilotRecord::fAllocated = 0;
+/* static */ int PilotRecord::fDeleted = 0;
+
+/* static */ void PilotRecord::allocationInfo()
+{
+ FUNCTIONSETUP;
+ DEBUGKPILOT << fname
+ << ": Allocated " << fAllocated
+ << " Deleted " << fDeleted << endl;
+}
+
+PilotRecord::PilotRecord(void *data, int len, int attrib, int cat, recordid_t uid) :
+ PilotRecordBase(attrib,cat,uid),
+ fData(0L),
+ fLen(len),
+ fBuffer(0L)
+{
+ FUNCTIONSETUPL(4);
+ fData = new char[len];
+
+ memcpy(fData, data, len);
+
+ fAllocated++;
+}
+
+PilotRecord::PilotRecord(PilotRecord * orig) :
+ PilotRecordBase( orig->attributes(), orig->category(), orig->id() ) ,
+ fBuffer(0L)
+{
+ FUNCTIONSETUPL(4);
+ fData = new char[orig->size()];
+
+ memcpy(fData, orig->data(), orig->size());
+ fLen = orig->size();
+ fAllocated++;
+}
+
+PilotRecord & PilotRecord::operator = (PilotRecord & orig)
+{
+ FUNCTIONSETUP;
+ if (fBuffer)
+ {
+ pi_buffer_free(fBuffer);
+ fBuffer=0L;
+ fData=0L;
+ }
+
+ if (fData)
+ delete[]fData;
+ fData = new char[orig.size()];
+
+ memcpy(fData, orig.data(), orig.size());
+ fLen = orig.size();
+ setAttributes( orig.attributes() );
+ setCategory( orig.category() );
+ setID( orig.id() );
+ return *this;
+}
+
+void PilotRecord::setData(const char *data, int len)
+{
+ FUNCTIONSETUP;
+ if (fData)
+ delete[]fData;
+ fData = new char[len];
+
+ memcpy(fData, data, len);
+ fLen = len;
+}
+
diff --git a/kpilot/lib/pilotRecord.h b/kpilot/lib/pilotRecord.h
new file mode 100644
index 000000000..a3812b333
--- /dev/null
+++ b/kpilot/lib/pilotRecord.h
@@ -0,0 +1,355 @@
+#ifndef _KPILOT_PILOTRECORD_H
+#define _KPILOT_PILOTRECORD_H
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2006 Adriaan de Groot <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "pilot.h"
+
+/**
+* @file This file defines the lowest- denominator representation(s)
+*of the bits used in a Pilot-based database record.
+*/
+
+
+/**
+* All entries in the Handheld -- whether interpreted or binary blobs --
+* have some common characteristics, viz. an ID number, a category,
+* and some attributes defined by the handheld. PilotRecordBase is
+* a common base class collecting methods to manipulate those
+* common characteristics.
+*/
+class KDE_EXPORT PilotRecordBase
+{
+public:
+ /** Constructor. Initialize the characteristics to the
+ * given values.
+ *
+ * @param attrib Attributes (bitfield) for this entry.
+ * @param cat Category for this entry. Should be in the
+ * range 0 <= cat < Pilot::CATEGORY_COUNT . Using an
+ * invalid category means 0 (unfiled) is used.
+ * @param id Unique ID for this entry. May be 0 (non-unique) as well.
+ */
+ PilotRecordBase(int attrib=0, int cat=0, recordid_t id=0) :
+ fAttrib(attrib),fCat(0),fID(id)
+ {
+ setCategory(cat);
+ }
+
+ /** Constructor. Initializes the characteristics from
+ * the values the given record @p b has. When @p b is
+ * NULL (which is allowed), everything is assumed zero.
+ * No ownership is transferred.
+ *
+ * @param b Record to take characteristics from.
+ */
+ PilotRecordBase( const PilotRecordBase *b ) :
+ fAttrib( b ? b->attributes() : 0 ),
+ fCat( 0 ),
+ fID( b ? b->id() : 0 )
+ {
+ if (b)
+ {
+ setCategory( b->category() );
+ }
+ }
+
+ /** Destructor. Nothing to do for it. */
+ virtual ~PilotRecordBase() { } ;
+
+ /** Attributes of this record (deleted, secret, ...);
+ * it's a bitfield.
+ */
+ inline int attributes() const
+ {
+ return fAttrib;
+ }
+
+ /** Set the attributes of this record. */
+ inline void setAttributes(int attrib)
+ {
+ fAttrib = attrib;
+ }
+
+ /** Returns the category number [ 0 .. Pilot::CATEGORY_COUNT-1]
+ * of this record.
+ */
+ inline int category() const
+ {
+ return fCat;
+ }
+
+ /** Sets the category number [ 0 .. Pilot::CATEGORY_COUNT-1]
+ * of this record.
+ * Trying to set an illegal category number files this one under
+ * "Unfiled" (which is 0).
+ */
+ inline void setCategory(int cat)
+ {
+ if ( (cat<0) || (cat>=(int)Pilot::CATEGORY_COUNT))
+ {
+ cat=0;
+ }
+ fCat = cat;
+ }
+
+ /** Sets the category number by looking up the string @p label
+ * in the category table @p info . Leaves the category unchanged
+ * if no match is found and returns @c false.
+ *
+ * @param info AppInfo structure containing the labels (in handheld
+ * native encoding).
+ * @param label The label to look for.
+ *
+ * @return @c true on success, @c false on failure
+ */
+ bool setCategory(const struct CategoryAppInfo *info, const QString &label)
+ {
+ if (!info)
+ {
+ return false;
+ }
+
+ int cat = Pilot::findCategory( info, label, false );
+ if ( (cat<0) || (cat>=(int)Pilot::CATEGORY_COUNT) )
+ {
+ return false;
+ }
+ else
+ {
+ setCategory( cat );
+ return true;
+ }
+ }
+
+ /** Returns the record ID for this record. Record IDs are unique for a given
+ * handheld and database.
+ */
+ inline recordid_t id() const
+ {
+ return fID;
+ }
+
+ /** Sets the record ID for this record. Use with caution -- you ca confuse
+ * the handheld by doing weird things here.
+ */
+ void setID(recordid_t id)
+ {
+ fID = id;
+ }
+
+ /** Accessor for one bit of the record's attributes. Is this record marked
+ * deleted (on the handheld) ? Deleted records are not removed from the
+ * database until a HotSync is done (which normally calls purge deleted
+ * or so to really get rid of the records from storage.
+ */
+ inline bool isDeleted() const
+ {
+ return fAttrib & dlpRecAttrDeleted;
+ }
+
+ /** Accessor for one bit of the record's attributes. Is this record secret?
+ * Secret records are not displayed on the desktop by default.
+ */
+ inline bool isSecret() const
+ {
+ return fAttrib & dlpRecAttrSecret;
+ }
+
+ /** Accessor for one bit of the record's attributes. Is this record a
+ * to-be-archived record? When a record is deleted, it may be marked
+ * as "archive on PC" which means the PC should keep a copy. The
+ * PC data correspondng to an archived-but-deleted record must not
+ * be deleted.
+ */
+ inline bool isArchived() const
+ {
+ return fAttrib & dlpRecAttrArchived;
+ }
+
+ /** Accessor for one bit of the record's attributes. Is this record modified?
+ * Modified records are those that have been modified since the last HotSync.
+ */
+ inline bool isModified() const
+ {
+ return fAttrib & dlpRecAttrDirty;
+ }
+
+#define SETTER(a) {\
+ if (d) { fAttrib |= a; } \
+ else { fAttrib &= ~a; } }
+
+ /** Mark a record as deleted (or not).*/
+ inline void setDeleted(bool d=true) SETTER(dlpRecAttrDeleted)
+
+ /** Mark a record as secret (or not). */
+ inline void setSecret(bool d=true) SETTER(dlpRecAttrSecret)
+
+ /** Mark a record as archived (or not). */
+ inline void setArchived(bool d=true) SETTER(dlpRecAttrArchived)
+
+ /** Mark a record as modified (or not). */
+ inline void setModified(bool d=true) SETTER(dlpRecAttrDirty)
+
+#undef SETTER
+
+ /** Returns a text representation of this record. */
+ virtual QString textRepresentation() const;
+
+private:
+ int fAttrib, fCat;
+ recordid_t fID;
+} ;
+
+/** An "uninterpreted" representation of the bits comprising a HH record.
+* This binary blob only exposes the data via the data() and size() functions,
+* and also exposes the common characteristics of all entries.
+*/
+class KDE_EXPORT PilotRecord : public PilotRecordBase
+{
+public:
+ /** Constructor. Using the given @p data and @p length, create
+ * a record. Give it the additional attributes and category numbers;
+ * the UID is a HH unique ID for identifying records.
+ *
+ * This constructor makes a copy of the data buffer (and owns that buffer).
+ */
+ PilotRecord(void* data, int length, int attrib, int cat, recordid_t uid) KDE_DEPRECATED;
+
+ /** Constructor. Using the given buffer @p buf (which carries its
+ * own data and length), create a record. Otherwise much like the
+ * above constructor @em except that this record assumes ownership
+ * of the buffer, and doesn't make an additional copy
+ * (In practice, this just saves copying around extra buffers).
+ */
+ PilotRecord(pi_buffer_t *buf, int attrib, int cat, recordid_t uid) :
+ PilotRecordBase(attrib,cat,uid),
+ fData((char *)buf->data),
+ fLen(buf->used),
+ fBuffer(buf)
+ {
+ fAllocated++;
+ }
+
+ /** Constructor. Like the above, only take the attributes, category
+ * and id from the given @p entry.
+ */
+ PilotRecord( pi_buffer_t *buf, const PilotRecordBase *entry ) :
+ PilotRecordBase( entry ),
+ fData((char *)buf->data),
+ fLen(buf->used),
+ fBuffer(buf)
+ {
+ fAllocated++;
+ }
+
+ /** Destructor. Dispose of the buffers in the right form. */
+ virtual ~PilotRecord()
+ {
+ if (fBuffer)
+ {
+ pi_buffer_free(fBuffer);
+ }
+ else
+ {
+ delete [] fData;
+ }
+ fDeleted++;
+ }
+
+ /** Constructor. Copies the data from the @p orig record. */
+ PilotRecord(PilotRecord* orig);
+
+ /** Retrieve the data buffer for this record. Note that trying
+ * to change this data is fraught with peril -- especially trying
+ * to lengthen it.
+ *
+ * @see setData
+ */
+ char *data() const
+ {
+ if (fBuffer)
+ {
+ return (char *)(fBuffer->data);
+ }
+ else
+ {
+ return fData;
+ }
+ }
+
+ /** Returns the size of the data for this record. */
+ int size() const
+ {
+ if (fBuffer) return fBuffer->used; else
+ return fLen;
+ }
+
+ /** Returns the data buffer associated with this record. */
+ const pi_buffer_t *buffer() const { return fBuffer; }
+
+ /** Set the data for this record. Frees old data. Assumes
+ * ownership of the passed in buffer @p b.
+ */
+ void setData(pi_buffer_t *b)
+ {
+ if (fBuffer) { pi_buffer_free(fBuffer); }
+ else { delete[] fData; } ;
+ fData = (char *)b->data;
+ fLen = b->used;
+ fBuffer = b;
+ }
+
+ /** Assignment operator. Makes a copy of the @p orig record. */
+ PilotRecord& operator=(PilotRecord& orig);
+
+ /** Sets the data for this record. Makes a copy of the data buffer. */
+ void setData(const char* data, int len);
+
+ /** Returns a text representation of this record. */
+ virtual QString textRepresentation() const;
+
+private:
+ char* fData;
+ int fLen;
+ pi_buffer_t *fBuffer;
+
+public:
+ /**
+ * This is an interface for tracking down memory leaks
+ * in the use of PilotRecords (for those without valgrind).
+ * Count the number of allocations and deallocations.
+ */
+ static void allocationInfo();
+private:
+ static int fAllocated,fDeleted;
+};
+
+#endif
diff --git a/kpilot/lib/pilotSerialDatabase.cc b/kpilot/lib/pilotSerialDatabase.cc
new file mode 100644
index 000000000..a38898d1d
--- /dev/null
+++ b/kpilot/lib/pilotSerialDatabase.cc
@@ -0,0 +1,432 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** Databases approached through DLP / Pilot-link look different,
+** so this file defines an API for them.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+#include "options.h"
+
+#include <time.h>
+#include <iostream>
+
+#include <pi-dlp.h>
+
+#include <qfile.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kglobal.h>
+
+#include "pilotRecord.h"
+#include "pilotSerialDatabase.h"
+#include "kpilotdevicelink.h"
+
+PilotSerialDatabase::PilotSerialDatabase(KPilotDeviceLink *l,
+ const QString &dbName) :
+ PilotDatabase(dbName),
+ fDBName( dbName ),
+ fDBHandle(-1),
+ fDBSocket(l->pilotSocket())
+{
+ FUNCTIONSETUP;
+ openDatabase();
+}
+
+PilotSerialDatabase::PilotSerialDatabase( KPilotDeviceLink *l, const DBInfo *info ) :
+ PilotDatabase( info ? Pilot::fromPilot( info->name ) : QString::null ),
+ fDBName( QString::null ),
+ fDBHandle( -1 ),
+ fDBSocket( l->pilotSocket() )
+{
+ // Rather unclear why both the base class and this one have separate names.
+ fDBName = name();
+ setDBOpen(false);
+ if (fDBName.isEmpty() || !info)
+ {
+ WARNINGKPILOT << "Bad database name requested." << endl;
+ return;
+ }
+
+ int db;
+ if (dlp_OpenDB(fDBSocket, 0, dlpOpenReadWrite, info->name, &db) < 0)
+ {
+ WARNINGKPILOT << "Cannot open database on handheld." << endl;
+ return;
+ }
+ setDBHandle(db);
+ setDBOpen(true);
+}
+
+PilotSerialDatabase::~PilotSerialDatabase()
+{
+ FUNCTIONSETUP;
+ closeDatabase();
+}
+
+QString PilotSerialDatabase::dbPathName() const
+{
+ QString s = CSL1("Pilot:");
+ s.append(fDBName);
+ return s;
+}
+
+// Reads the application block info
+int PilotSerialDatabase::readAppBlock(unsigned char *buffer, int maxLen)
+{
+ FUNCTIONSETUP;
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open" << endl;
+ return -1;
+ }
+ pi_buffer_t *buf = pi_buffer_new(maxLen);
+ int r = dlp_ReadAppBlock(fDBSocket, getDBHandle(), 0 /* offset */, maxLen, buf);
+ if (r>=0)
+ {
+ memcpy(buffer, buf->data, KMAX(maxLen, r));
+ }
+ pi_buffer_free(buf);
+ return r;
+}
+
+// Writes the application block info.
+int PilotSerialDatabase::writeAppBlock(unsigned char *buffer, int len)
+{
+ FUNCTIONSETUP;
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open" << endl;
+ return -1;
+ }
+ return dlp_WriteAppBlock(fDBSocket, getDBHandle(), buffer, len);
+}
+
+ // returns the number of records in the database
+unsigned int PilotSerialDatabase::recordCount() const
+{
+ int idlen;
+ // dlp_ReadOpenDBInfo returns the number of bytes read and sets idlen to the # of recs
+ if (isOpen() && dlp_ReadOpenDBInfo(fDBSocket, getDBHandle(), &idlen)>0)
+ {
+ return idlen;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+// Returns a QValueList of all record ids in the database.
+QValueList<recordid_t> PilotSerialDatabase::idList()
+{
+ QValueList<recordid_t> idlist;
+ int idlen=recordCount();
+ if (idlen<=0) return idlist;
+
+ recordid_t *idarr=new recordid_t[idlen];
+ int idlenread;
+ int r = dlp_ReadRecordIDList (fDBSocket, getDBHandle(), 0, 0, idlen, idarr, &idlenread);
+
+ if ( (r<0) || (idlenread<1) )
+ {
+ WARNINGKPILOT << "Failed to read ID list from database." << endl;
+ return idlist;
+ }
+
+ // now create the QValue list from the idarr:
+ for (idlen=0; idlen<idlenread; idlen++)
+ {
+ idlist.append(idarr[idlen]);
+ }
+ delete[] idarr;
+ return idlist;
+}
+
+
+// Reads a record from database by id, returns record length
+PilotRecord *PilotSerialDatabase::readRecordById(recordid_t id)
+{
+ FUNCTIONSETUPL(3);
+ int index, attr, category;
+
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open" << endl;
+ return 0L;
+ }
+ if (id>0xFFFFFF)
+ {
+ WARNINGKPILOT << "Encountered an invalid record id "
+ << id << endl;
+ return 0L;
+ }
+ pi_buffer_t *b = pi_buffer_new(InitialBufferSize);
+ if (dlp_ReadRecordById(fDBSocket,getDBHandle(),id,b,&index,&attr,&category) >= 0)
+ {
+ return new PilotRecord(b, attr, category, id);
+ }
+ return 0L;
+}
+
+// Reads a record from database, returns the record length
+PilotRecord *PilotSerialDatabase::readRecordByIndex(int index)
+{
+ FUNCTIONSETUPL(3);
+
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open" << endl;
+ return 0L;
+ }
+
+ int attr, category;
+ recordid_t id;
+ PilotRecord *rec = 0L;
+
+ pi_buffer_t *b = pi_buffer_new(InitialBufferSize);
+ if (dlp_ReadRecordByIndex(fDBSocket, getDBHandle(), index,
+ b, &id, &attr, &category) >= 0)
+ {
+ rec = new PilotRecord(b, attr, category, id);
+ }
+
+
+ return rec;
+}
+
+// Reads the next record from database in category 'category'
+PilotRecord *PilotSerialDatabase::readNextRecInCategory(int category)
+{
+ FUNCTIONSETUP;
+ int index, attr;
+ recordid_t id;
+
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open" << endl;
+ return 0L;
+ }
+ pi_buffer_t *b = pi_buffer_new(InitialBufferSize);
+ if (dlp_ReadNextRecInCategory(fDBSocket, getDBHandle(),
+ category,b,&id,&index,&attr) >= 0)
+ return new PilotRecord(b, attr, category, id);
+ return 0L;
+}
+
+// Reads the next record from database that has the dirty flag set.
+PilotRecord *PilotSerialDatabase::readNextModifiedRec(int *ind)
+{
+ FUNCTIONSETUP;
+ int index, attr, category;
+ recordid_t id;
+
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open" << endl;
+ return 0L;
+ }
+ pi_buffer_t *b = pi_buffer_new(InitialBufferSize);
+ if (dlp_ReadNextModifiedRec(fDBSocket, getDBHandle(), b, &id, &index, &attr, &category) >= 0)
+ {
+ if (ind) *ind=index;
+ return new PilotRecord(b, attr, category, id);
+ }
+ return 0L;
+}
+
+// Writes a new record to database (if 'id' == 0 or id>0xFFFFFF, one will be assigned and returned in 'newid')
+recordid_t PilotSerialDatabase::writeRecord(PilotRecord * newRecord)
+{
+ FUNCTIONSETUP;
+ recordid_t newid;
+ int success;
+
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open" << endl;
+ return 0;
+ }
+ // Do some sanity checking to prevent invalid UniqueIDs from being written
+ // to the handheld (RecordIDs are only 3 bytes!!!). Under normal conditions
+ // this check should never yield true, so write out an error to indicate
+ // someone messed up full time...
+ if (newRecord->id()>0xFFFFFF)
+ {
+ WARNINGKPILOT << "Encountered an invalid record id "
+ << newRecord->id() << ", resetting it to zero." << endl;
+ newRecord->setID(0);
+ }
+ success =
+ dlp_WriteRecord(fDBSocket, getDBHandle(),
+ newRecord->attributes(), newRecord->id(),
+ newRecord->category(), newRecord->data(),
+ newRecord->size(), &newid);
+ if ( (newRecord->id() != newid) && (newid!=0) )
+ newRecord->setID(newid);
+ return newid;
+}
+
+// Deletes a record with the given recordid_t from the database, or all records, if all is set to true. The recordid_t will be ignored in this case
+int PilotSerialDatabase::deleteRecord(recordid_t id, bool all)
+{
+ FUNCTIONSETUP;
+ if (!isOpen())
+ {
+ WARNINGKPILOT <<"DB not open"<<endl;
+ return -1;
+ }
+ return dlp_DeleteRecord(fDBSocket, getDBHandle(), all?1:0, id);
+}
+
+
+// Resets all records in the database to not dirty.
+int PilotSerialDatabase::resetSyncFlags()
+{
+ FUNCTIONSETUP;
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open" << endl;
+ return -1;
+ }
+ return dlp_ResetSyncFlags(fDBSocket, getDBHandle());
+}
+
+// Resets next record index to beginning
+int PilotSerialDatabase::resetDBIndex()
+{
+ FUNCTIONSETUP;
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open" << endl;
+ return -1;
+ }
+ return dlp_ResetDBIndex(fDBSocket, getDBHandle());
+}
+
+// Purges all Archived/Deleted records from Palm Pilot database
+int PilotSerialDatabase::cleanup()
+{
+ FUNCTIONSETUP;
+ if (!isOpen())
+ {
+ WARNINGKPILOT << "DB not open" << endl;
+ return -1;
+ }
+ return dlp_CleanUpDatabase(fDBSocket, getDBHandle());
+}
+
+void PilotSerialDatabase::openDatabase()
+{
+ FUNCTIONSETUP;
+ int db;
+
+ setDBOpen(false);
+
+ QString s = getDBName();
+ if (s.isEmpty())
+ {
+ WARNINGKPILOT << "Bad DB name, " << s << " string given." << endl;
+ return;
+ }
+
+ QCString encodedName = QFile::encodeName(s);
+ if (encodedName.isEmpty())
+ {
+ WARNINGKPILOT << "Bad DB name, "
+ << (encodedName.isNull() ? "null" : "empty")
+ << " string given."
+ << endl;
+ return;
+ }
+
+ char encodedNameBuffer[PATH_MAX];
+ strlcpy(encodedNameBuffer,(const char *)encodedName,PATH_MAX);
+
+ DEBUGKPILOT << fname << ": opening database: ["
+ << encodedNameBuffer << "]" << endl;
+
+ if (dlp_OpenDB(fDBSocket, 0, dlpOpenReadWrite,
+ encodedNameBuffer, &db) < 0)
+ {
+ WARNINGKPILOT << "Cannot open database on handheld." << endl;
+ return;
+ }
+ setDBHandle(db);
+ setDBOpen(true);
+}
+
+bool PilotSerialDatabase::createDatabase(long creator, long type, int cardno, int flags, int version)
+{
+ FUNCTIONSETUP;
+ int db;
+
+ // if the database is already open, we cannot create it again. How about completely resetting it? (i.e. deleting it and the createing it again)
+ if (isOpen()) return true;
+ // The latin1 seems ok, database names are latin1.
+ int res=dlp_CreateDB(fDBSocket,
+ creator, type, cardno, flags, version,
+ Pilot::toPilot(getDBName()), &db);
+ if (res<0) {
+ WARNINGKPILOT << "Cannot create database " << getDBName() << " on the handheld" << endl;
+ return false;
+ }
+ // TODO: Do I have to open it explicitly???
+ setDBHandle(db);
+ setDBOpen(true);
+ return true;
+}
+
+void PilotSerialDatabase::closeDatabase()
+{
+ FUNCTIONSETUP;
+ if (!isOpen() )
+ {
+ return;
+ }
+
+ DEBUGKPILOT << fname << ": Closing DB handle #" << getDBHandle() << endl;
+ dlp_CloseDB(fDBSocket, getDBHandle());
+ DEBUGKPILOT << fname << ": after closing" << endl;
+ setDBOpen(false);
+}
+
+int PilotSerialDatabase::deleteDatabase()
+{
+ FUNCTIONSETUP;
+
+ if (isOpen()) closeDatabase();
+
+ return dlp_DeleteDB(fDBSocket, 0, Pilot::toPilot(fDBName));
+}
+
+
+
+/* virtual */ PilotDatabase::DBType PilotSerialDatabase::dbType() const
+{
+ return eSerialDB;
+}
+
diff --git a/kpilot/lib/pilotSerialDatabase.h b/kpilot/lib/pilotSerialDatabase.h
new file mode 100644
index 000000000..51a6ba26d
--- /dev/null
+++ b/kpilot/lib/pilotSerialDatabase.h
@@ -0,0 +1,144 @@
+#ifndef _KPILOT_PILOTSERIALDATABASE_H
+#define _KPILOT_PILOTSERIALDATABASE_H
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2006 Adriaan de Groot <[email protected]>
+**
+** See the .cc file for an explanation of what this file is for.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+
+#include "pilotDatabase.h"
+#include "pilotRecord.h"
+
+/** @file
+* Database class for a database on the pilot connected
+* via the serial port (ie: hot-sync cradle)
+*/
+
+class KPilotDeviceLink;
+
+/**
+* PilotSerialDatabase represents databases stored on the handheld
+* and accessed through the SLP / DLP protocol.
+*/
+class KDE_EXPORT PilotSerialDatabase : public PilotDatabase
+{
+friend class KPilotDeviceLink;
+protected:
+ PilotSerialDatabase( KPilotDeviceLink *l, const QString &dbName );
+ PilotSerialDatabase( KPilotDeviceLink *l, const DBInfo *info );
+
+public:
+ virtual ~PilotSerialDatabase();
+
+ /** Reads the application block info, returns size */
+ virtual int readAppBlock(unsigned char* buffer, int maxLen);
+ /** Writes the application block info. */
+ virtual int writeAppBlock(unsigned char* buffer, int len);
+ /** returns the number of records in the database, 0 if not open */
+ virtual unsigned int recordCount() const;
+ /** Returns a QValueList of all record ids in the database. */
+ virtual QValueList<recordid_t> idList();
+ /** Reads a record from database by id, returns record length */
+ virtual PilotRecord* readRecordById(recordid_t id);
+ /** Reads a record from database, returns the record length */
+ virtual PilotRecord* readRecordByIndex(int index);
+ /** Reads the next record from database in category 'category' */
+ virtual PilotRecord* readNextRecInCategory(int category);
+ /**
+ * Reads the next record from database that has the dirty flag set.
+ * ind (if a valid pointer is given) will receive the index of the
+ * returned record.
+ */
+ virtual PilotRecord* readNextModifiedRec(int *ind=NULL);
+
+ /**
+ * Writes a new record to database (if 'id' == 0, one will be
+ * assigned to newRecord)
+ */
+ virtual recordid_t writeRecord(PilotRecord* newRecordb);
+
+ /**
+ * Deletes a record with the given recordid_t from the database,
+ * or all records, if all is set to true. The recordid_t will be
+ * ignored in this case. Return value is negative on error, 0 otherwise.
+ */
+ virtual int deleteRecord(recordid_t id, bool all=false);
+ /** Resets all records in the database to not dirty. */
+ virtual int resetSyncFlags();
+ /** Resets next record index to beginning */
+ virtual int resetDBIndex();
+ /** Purges all Archived/Deleted records from Palm Pilot database */
+ virtual int cleanup();
+
+ virtual QString dbPathName() const;
+
+ /**
+ * Deletes the database (by name, as given in the constructor and
+ * stored in the fDBName field).
+ */
+ virtual int deleteDatabase();
+
+ /**
+ * Creates the database with the given creator, type and flags on
+ * the given card (default is RAM). If the database already exists,
+ * this function does nothing.
+ */
+ virtual bool createDatabase(long creator=0,
+ long type=0, int cardno=0, int flags=0, int version=0);
+ QString getDBName() { return fDBName; }
+
+
+ virtual DBType dbType() const;
+
+protected:
+ virtual void openDatabase();
+ virtual void closeDatabase();
+ /** Returns the file handle used to communicate with the handheld.
+ * This is an internal value to be passed to DLP functions.
+ */
+ int getDBHandle() const
+ {
+ return fDBHandle;
+ }
+
+
+private:
+ void setDBHandle(int handle) { fDBHandle = handle; }
+
+ QString fDBName;
+ int fDBHandle;
+ int fDBSocket;
+ // Pilot-link 0.12 allocates buffers as needed and resizes them.
+ // Start with a buffer that is _probably_ big enough for most
+ // PIM records, but much smaller than the 64k that we use otherwise.
+ // Might want to add algorithm for trying to optimize the initial
+ // allocation for a given database.
+ static const int InitialBufferSize = 2048;
+};
+
+#endif
diff --git a/kpilot/lib/pilotSysInfo.h b/kpilot/lib/pilotSysInfo.h
new file mode 100644
index 000000000..4deb4f1b4
--- /dev/null
+++ b/kpilot/lib/pilotSysInfo.h
@@ -0,0 +1,144 @@
+#ifndef _KPILOT_SYSINFO_H
+#define _KPILOT_SYSINFO_H
+/* sysInfo.h KPilot
+**
+** Copyright (C) 2003 by Reinhold Kainhofer
+**
+** Wrapper for pilot-link's SysInfo Structure
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <pi-version.h>
+#include <pi-dlp.h>
+
+
+
+class KPilotSysInfo
+{
+public:
+ /** Constructor. Create an empty SysInfo structure. */
+ KPilotSysInfo()
+ {
+ ::memset(&fSysInfo,0,sizeof(struct SysInfo));
+ }
+
+ /** Constructor. Copy an existing pilot-link SysInfo structure.
+ * Ownership is not changed. @p sys_info may be NULL.
+ */
+ KPilotSysInfo(const SysInfo *sys_info)
+ {
+ ::memset(&fSysInfo,0,sizeof(struct SysInfo));
+ if (sys_info)
+ {
+ fSysInfo = *sys_info;
+ }
+ }
+
+ /** Access to the raw SysInfo structure. */
+ SysInfo *sysInfo()
+ {
+ return &fSysInfo;
+ }
+
+ /** Get the ROM version of the handheld. This is a pilot-link
+ * long value (4 bytes) with major, minor, bugfix version
+ * numbers encoded in the value.
+ */
+ const unsigned long getRomVersion() const
+ {
+ return fSysInfo.romVersion;
+ }
+
+ /** Get the locale number of the handheld.
+ * @note I do not know what this means.
+ */
+ const unsigned long getLocale() const
+ {
+ return fSysInfo.locale;
+ }
+ /** Set the locale number of the handheld.
+ * @note I do not know what this means.
+ */
+ void setLocale(unsigned long newval)
+ {
+ fSysInfo.locale=newval;
+ }
+
+ /** Get the length (in bytes) of the ProductID string. */
+ const int getProductIDLength() const
+ {
+ return fSysInfo.prodIDLength;
+ }
+ /** Get the ProductID string from the handheld. This is
+ * guaranteed to be NUL terminated.
+ */
+ const char* getProductID() const
+ {
+ return fSysInfo.prodID;
+ }
+
+ /** Accessor for the major version of the DLP protocol in use. */
+ const unsigned short getMajorVersion() const
+ {
+ return fSysInfo.dlpMajorVersion;
+ }
+ /** Accessor for the minor version of the DLP protocol in use. */
+ const unsigned short getMinorVersion() const
+ {
+ return fSysInfo.dlpMinorVersion;
+ }
+
+ /** Accessor for the major compatibility version of the handheld.
+ * @note I do not know what this means.
+ */
+ const unsigned short getCompatMajorVersion() const
+ {
+ return fSysInfo.compatMajorVersion;
+ }
+ /** Accessor for the minor compatibility version of the handheld.
+ * @note I do not know what this means.
+ */
+ const unsigned short getCompatMinorVersion() const
+ {
+ return fSysInfo.compatMinorVersion;
+ }
+
+
+ /** Returns the maximum record size that the handheld supports.
+ * Normally this is 65524 or so (which means that larger values
+ * don't necessarily @em fit in a short).
+ */
+ const unsigned short getMaxRecSize() const
+ {
+ return fSysInfo.maxRecSize;
+ }
+
+private:
+ struct SysInfo fSysInfo;
+};
+
+#endif
diff --git a/kpilot/lib/pilotTodoEntry.cc b/kpilot/lib/pilotTodoEntry.cc
new file mode 100644
index 000000000..f4c5596fb
--- /dev/null
+++ b/kpilot/lib/pilotTodoEntry.cc
@@ -0,0 +1,270 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This is a C++ wrapper for the todo-list entry structures.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+#include "options.h"
+
+
+#include <stdlib.h>
+
+#include <qdatetime.h>
+#include <qnamespace.h>
+
+#include <kglobal.h>
+#include <kdebug.h>
+
+
+#include "pilotTodoEntry.h"
+
+
+PilotTodoEntry::PilotTodoEntry() :
+ fDescriptionSize(0),
+ fNoteSize(0)
+{
+ FUNCTIONSETUP;
+ ::memset(&fTodoInfo, 0, sizeof(struct ToDo));
+}
+
+PilotTodoEntry::PilotTodoEntry(PilotRecord * rec) :
+ PilotRecordBase(rec),
+ fDescriptionSize(0),
+ fNoteSize(0)
+{
+ ::memset(&fTodoInfo, 0, sizeof(struct ToDo));
+ if (rec)
+ {
+ pi_buffer_t b;
+ b.data = (unsigned char *) rec->data();
+ b.allocated = b.used = rec->size();
+ unpack_ToDo(&fTodoInfo, &b, todo_v1);
+ if (fTodoInfo.description)
+ {
+ // Assume size of buffer allocated is just large enough;
+ // count trailing NUL as well.
+ fDescriptionSize = strlen(fTodoInfo.description)+1;
+ }
+ if (fTodoInfo.note)
+ {
+ // Same
+ fNoteSize = strlen(fTodoInfo.note)+1;
+ }
+ }
+
+}
+
+
+PilotTodoEntry::PilotTodoEntry(const PilotTodoEntry & e) :
+ PilotRecordBase( &e ),
+ fDescriptionSize(0),
+ fNoteSize(0)
+{
+ FUNCTIONSETUP;
+ ::memcpy(&fTodoInfo, &e.fTodoInfo, sizeof(fTodoInfo));
+ // See PilotDateEntry::operator = for details
+ fTodoInfo.description = 0L;
+ fTodoInfo.note = 0L;
+
+ setDescriptionP(e.getDescriptionP());
+ setNoteP(e.getNoteP());
+}
+
+
+PilotTodoEntry & PilotTodoEntry::operator = (const PilotTodoEntry & e)
+{
+ if (this != &e)
+ {
+ KPILOT_FREE(fTodoInfo.description);
+ KPILOT_FREE(fTodoInfo.note);
+
+ ::memcpy(&fTodoInfo, &e.fTodoInfo, sizeof(fTodoInfo));
+ // See PilotDateEntry::operator = for details
+ fTodoInfo.description = 0L;
+ fTodoInfo.note = 0L;
+ fDescriptionSize = 0;
+ fNoteSize = 0;
+
+ setDescriptionP(e.getDescriptionP());
+ setNoteP(e.getNoteP());
+
+ }
+
+ return *this;
+}
+
+QString PilotTodoEntry::getTextRepresentation(Qt::TextFormat richText)
+{
+ QString text, tmp;
+ QString par = (richText==Qt::RichText) ?CSL1("<p>"): QString();
+ QString ps = (richText==Qt::RichText) ?CSL1("</p>"):CSL1("\n");
+ QString br = (richText==Qt::RichText) ?CSL1("<br/>"):CSL1("\n");
+
+ // title + name
+ text += par;
+ tmp= (richText==Qt::RichText) ?CSL1("<b><big>%1</big></b>"):CSL1("%1");
+ text += tmp.arg(rtExpand(getDescription(), richText));
+ text += ps;
+
+ text += par;
+ if (getComplete())
+ text += i18n("Completed");
+ else
+ text += i18n("Not completed");
+ text += ps;
+
+ if (!getIndefinite())
+ {
+ QDate dt(readTm(getDueDate()).date());
+ QString dueDate(dt.toString(Qt::LocalDate));
+ text+=par;
+ text+=i18n("Due date: %1").arg(dueDate);
+ text+=ps;
+ }
+
+ text+=par;
+ text+=ps;
+
+ text+=par;
+ text+=i18n("Priority: %1").arg(getPriority());
+ text+=ps;
+
+ if (!getNote().isEmpty())
+ {
+ text += (richText==Qt::RichText) ?CSL1("<hr/>"):CSL1("-------------------------\n");
+ text+=par;
+ text+= (richText==Qt::RichText) ?i18n("<b><em>Note:</em></b><br>"):i18n("Note:\n");
+ text+=rtExpand(getNote(), richText);
+ text+=ps;
+ }
+
+ return text;
+}
+
+PilotRecord *PilotTodoEntry::pack() const
+{
+ int i;
+
+ pi_buffer_t *b = pi_buffer_new( sizeof(fTodoInfo) );
+ i = pack_ToDo(const_cast<ToDo_t *>(&fTodoInfo), b, todo_v1);
+ if (i<0)
+ {
+ return 0;
+ }
+ // pack_ToDo sets b->used
+ return new PilotRecord( b, this );
+}
+
+void PilotTodoEntry::setDescription(const QString &desc)
+{
+ if (desc.length() < fDescriptionSize)
+ {
+ Pilot::toPilot(desc, fTodoInfo.description, fDescriptionSize);
+ }
+ else
+ {
+ setDescriptionP(Pilot::toPilot(desc),desc.length());
+ }
+}
+
+void PilotTodoEntry::setDescriptionP(const char *desc, int len)
+{
+ KPILOT_FREE(fTodoInfo.description);
+ if (desc && *desc)
+ {
+ if (-1 == len)
+ {
+ len=::strlen(desc);
+ }
+
+ fDescriptionSize = len+1;
+ fTodoInfo.description = (char *)::malloc(len + 1);
+ if (fTodoInfo.description)
+ {
+ strncpy(fTodoInfo.description, desc, len);
+ fTodoInfo.description[len] = 0;
+ }
+ else
+ {
+ WARNINGKPILOT << "malloc() failed, description not set"
+ << endl;
+ }
+ }
+ else
+ {
+ fTodoInfo.description = 0L;
+ }
+}
+
+QString PilotTodoEntry::getDescription() const
+{
+ return Pilot::fromPilot(getDescriptionP());
+}
+
+void PilotTodoEntry::setNote(const QString &note)
+{
+ if (note.length() < fNoteSize)
+ {
+ Pilot::toPilot(note, fTodoInfo.note, fNoteSize);
+ }
+ else
+ {
+ setNoteP(Pilot::toPilot(note),note.length());
+ }
+}
+
+void PilotTodoEntry::setNoteP(const char *note, int len)
+{
+ KPILOT_FREE(fTodoInfo.note);
+ if (note && *note)
+ {
+ if (-1 == len)
+ {
+ len=::strlen(note);
+ }
+
+ fNoteSize = len+1;
+ fTodoInfo.note = (char *)::malloc(len + 1);
+ if (fTodoInfo.note)
+ {
+ strncpy(fTodoInfo.note, note, len);
+ fTodoInfo.note[len] = 0;
+ }
+ else
+ {
+ WARNINGKPILOT << "malloc() failed, note not set" << endl;
+ }
+ }
+ else
+ {
+ fTodoInfo.note = 0L;
+ }
+}
+
+QString PilotTodoEntry::getNote() const
+{
+ return Pilot::fromPilot(getNoteP());
+}
+
diff --git a/kpilot/lib/pilotTodoEntry.h b/kpilot/lib/pilotTodoEntry.h
new file mode 100644
index 000000000..3735771b6
--- /dev/null
+++ b/kpilot/lib/pilotTodoEntry.h
@@ -0,0 +1,166 @@
+#ifndef _KPILOT_PILOTTODOENTRY_H
+#define _KPILOT_PILOTTODOENTRY_H
+/* pilotTodoEntry.h -*- C++ -*- KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This is a wrapper around the pilot-link Memo structure. It is
+** the interpreted form of a Pilot database record.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <time.h>
+
+#include <pi-macros.h>
+#include <pi-todo.h>
+
+#include <qnamespace.h>
+#include <qstring.h>
+
+#include "pilotRecord.h"
+#include "pilotAppInfo.h"
+
+/** @file This file defines structures wrapped around the ToDo database
+* on the Pilot, based on pilot-link's ToDo stuff.
+*/
+
+/** A decoded ToDo item. */
+class KDE_EXPORT PilotTodoEntry : public PilotRecordBase
+{
+public:
+ /** Create an empty ToDo item. All attributes are 0. */
+ PilotTodoEntry();
+
+ /**
+ * Constructor. Create a ToDo item and fill it with data from the
+ * uninterpreted record @p rec. The record may be NULL, in which
+ * case the todo is empty and its category and ID are zero, as in
+ * the constructor above.
+ */
+ PilotTodoEntry(PilotRecord * rec);
+
+ /** Copy an existing ToDo item. */
+ PilotTodoEntry(const PilotTodoEntry &e);
+
+ /** Delete a ToDo item. */
+ ~PilotTodoEntry()
+ {
+ free_ToDo(&fTodoInfo);
+ }
+
+ /** Return a string for the ToDo item. If @param richText is true, then
+ * use qt style markup to make the string clearer when displayed.
+ */
+ QString getTextRepresentation(Qt::TextFormat richText);
+
+ /** Assign an existing ToDo item to this one. */
+ PilotTodoEntry& operator=(const PilotTodoEntry &e);
+
+ /** Accessor for the Due Date of the ToDo item. */
+ struct tm getDueDate() const { return fTodoInfo.due; }
+
+ /** Set the Due Date for the ToDo item. */
+ void setDueDate(struct tm& d)
+ {
+ fTodoInfo.due = d;
+ }
+
+ /** Return the indefinite status of the ToDo (? that is, whether it
+ * had a Due Date that is relevant or not). Return values are 0
+ * (not indefinite) or non-0.
+ */
+ int getIndefinite() const
+ {
+ return fTodoInfo.indefinite;
+ }
+
+ /** Set whether the ToDo is indefinite or not. */
+ void setIndefinite(int i)
+ {
+ fTodoInfo.indefinite = i;
+ }
+
+ /** Return the priority of the ToDo item. The priority ranges
+ * from 1-5 on the handheld, so this needs to be mapped (perhaps)
+ * onto KOrganizer's priority levels.
+ */
+ int getPriority() const
+ {
+ return fTodoInfo.priority;
+ }
+
+ /** Set the priority of the ToDo. */
+ void setPriority(int p)
+ {
+ fTodoInfo.priority = p;
+ }
+
+ /** Return whether the ToDo is complete (done, finished) or not. */
+ int getComplete() const
+ {
+ return fTodoInfo.complete;
+ }
+
+ /** Set whether the ToDo is done. */
+ void setComplete(int c)
+ {
+ fTodoInfo.complete = c;
+ }
+
+ /** Get the ToDo item's description (which is the title shown on
+ * the handheld, and the item's Title in KDE). This uses the default codec.
+ */
+ QString getDescription() const;
+ /** Set the ToDo item's description. */
+ void setDescription(const QString &);
+
+ /** Get the ToDo item's note (the longer text, not immediately accessible
+ * on the handheld). This uses the default codec.
+ */
+ QString getNote() const;
+
+ /** Set the ToDo item's note. */
+ void setNote(const QString &note);
+
+ /** Returns the label for the category this ToDo item is in. */
+ QString getCategoryLabel() const;
+
+ PilotRecord *pack() const;
+
+protected:
+ const char *getDescriptionP() const { return fTodoInfo.description; } ;
+ void setDescriptionP(const char *, int len=-1) ;
+ const char *getNoteP() const { return fTodoInfo.note; } ;
+ void setNoteP(const char *, int len=-1) ;
+
+private:
+ struct ToDo fTodoInfo;
+ unsigned int fDescriptionSize, fNoteSize;
+};
+
+typedef PilotAppInfo<ToDoAppInfo,unpack_ToDoAppInfo, pack_ToDoAppInfo> PilotToDoInfo;
+
+
+#endif
+
diff --git a/kpilot/lib/pilotUser.h b/kpilot/lib/pilotUser.h
new file mode 100644
index 000000000..6ba46b007
--- /dev/null
+++ b/kpilot/lib/pilotUser.h
@@ -0,0 +1,128 @@
+#ifndef _KPILOT_PILOTUSER_H
+#define _KPILOT_PILOTUSER_H
+/* pilotUser.h KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+**
+** Wrapper for the PilotUser struct from pilot-link, which describes
+** the user-data set in the Pilot.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <pi-dlp.h>
+
+#include "pilot.h"
+
+class KPilotUser
+{
+public:
+ /** Constructor. Create an empty PilotUser structure. */
+ KPilotUser()
+ {
+ ::memset(&fUser,0,sizeof(struct PilotUser));
+ }
+ /** Constructor. Use the given PilotUser structure.
+ * This creates a copy; no ownership is transferred.
+ */
+ KPilotUser(const PilotUser *user)
+ {
+ fUser = *user;
+ }
+
+ /** Accessor for the whole PilotUser structure. */
+ PilotUser *data()
+ {
+ return &fUser;
+ }
+
+ /** @return The username set on the handheld. */
+ QString name() const
+ {
+ return Pilot::fromPilot( fUser.username );
+ }
+ /** Set the user name to the given @p name , truncated
+ * if necessary to the size of the field on the handheld.
+ */
+ void setName( const QString &name )
+ {
+ Pilot::toPilot( name, fUser.username, sizeof(fUser.username) );
+ }
+
+ /** @return The length of the password on the handheld,
+ * in bytes.
+ */
+ const int passwordLength() const
+ {
+ return fUser.passwordLength;
+ }
+
+ /** @return the ID (4 bytes) of the last PC to sync this handheld.
+ * This is intended to help identify when the use has
+ * changed PCs and needs a new full sync.
+ */
+ unsigned long getLastSyncPC() const
+ {
+ return fUser.lastSyncPC;
+ }
+ /** Set the ID of the PC syncing the handheld to @p pc . This
+ * should be unique in some way (perhaps IP addresses can be
+ * used this way, or hostnames).
+ */
+ void setLastSyncPC(unsigned long pc)
+ {
+ fUser.lastSyncPC = pc;
+ }
+
+ /** @return the timestamp that the handheld was last synced
+ * successfully.
+ */
+ time_t getLastSuccessfulSyncDate()
+ {
+ return fUser.successfulSyncDate;
+ }
+ /** Set the timestamp for a successful sync. */
+ void setLastSuccessfulSyncDate(time_t when)
+ {
+ fUser.successfulSyncDate = when;
+ }
+
+ /** @return the timestamp of the last sync attempt. */
+ time_t getLastSyncDate()
+ {
+ return fUser.lastSyncDate;
+ }
+ /** Set the timestamp of the sync attempt. */
+ void setLastSyncDate(time_t when)
+ {
+ fUser.lastSyncDate = when;
+ }
+
+private:
+ struct PilotUser fUser;
+};
+
+#endif
diff --git a/kpilot/lib/plugin.cc b/kpilot/lib/plugin.cc
new file mode 100644
index 000000000..e9bcc9221
--- /dev/null
+++ b/kpilot/lib/plugin.cc
@@ -0,0 +1,760 @@
+/* KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+** This file defines the base class of all KPilot conduit plugins configuration
+** dialogs. This is necessary so that we have a fixed API to talk to from
+** inside KPilot.
+**
+** The factories used by KPilot plugins are also documented here.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <stdlib.h>
+
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qregexp.h>
+#include <qstringlist.h>
+#include <qtabwidget.h>
+#include <qtextview.h>
+#include <qtimer.h>
+
+#include <dcopclient.h>
+#include <kaboutapplication.h>
+#include <kactivelabel.h>
+#include <kapplication.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <klibloader.h>
+#include <kmessagebox.h>
+#include <kservice.h>
+#include <kservicetype.h>
+#include <kstandarddirs.h>
+
+#include "pilotSerialDatabase.h"
+#include "pilotLocalDatabase.h"
+
+#include "plugin.moc"
+
+ConduitConfigBase::ConduitConfigBase(QWidget *parent,
+ const char *name) :
+ QObject(parent,name),
+ fModified(false),
+ fWidget(0L),
+ fConduitName(i18n("Unnamed"))
+{
+ FUNCTIONSETUP;
+}
+
+ConduitConfigBase::~ConduitConfigBase()
+{
+ FUNCTIONSETUP;
+}
+
+/* slot */ void ConduitConfigBase::modified()
+{
+ fModified=true;
+ emit changed(true);
+}
+
+/* virtual */ QString ConduitConfigBase::maybeSaveText() const
+{
+ FUNCTIONSETUP;
+
+ return i18n("<qt>The <i>%1</i> conduit's settings have been changed. Do you "
+ "want to save the changes before continuing?</qt>").arg(this->conduitName());
+}
+
+/* virtual */ bool ConduitConfigBase::maybeSave()
+{
+ FUNCTIONSETUP;
+
+ if (!isModified()) return true;
+
+ int r = KMessageBox::questionYesNoCancel(fWidget,
+ maybeSaveText(),
+ i18n("%1 Conduit").arg(this->conduitName()), KStdGuiItem::save(), KStdGuiItem::discard());
+ if (r == KMessageBox::Cancel) return false;
+ if (r == KMessageBox::Yes) commit();
+ return true;
+}
+
+QWidget *ConduitConfigBase::aboutPage(QWidget *parent, KAboutData *ad)
+{
+ FUNCTIONSETUP;
+
+ QWidget *w = new QWidget(parent, "aboutpage");
+
+ QString s;
+ QLabel *text;
+ KIconLoader *l = KGlobal::iconLoader();
+ const KAboutData *p = ad ? ad : KGlobal::instance()->aboutData();
+
+ QGridLayout *grid = new QGridLayout(w, 5, 4, SPACING);
+
+ grid->addColSpacing(0, SPACING);
+ grid->addColSpacing(4, SPACING);
+
+
+ QPixmap applicationIcon =
+ l->loadIcon(QString::fromLatin1(p->appName()),
+ KIcon::Desktop,
+ 64, KIcon::DefaultState, 0L,
+ true);
+
+ if (applicationIcon.isNull())
+ {
+ applicationIcon = l->loadIcon(QString::fromLatin1("kpilot"),
+ KIcon::Desktop);
+ }
+
+ text = new QLabel(w);
+ // Experiment with a long non-<qt> string. Use that to find
+ // sensible widths for the columns.
+ //
+ text->setText(i18n("Send questions and comments to [email protected]"));
+ text->adjustSize();
+
+ int linewidth = text->size().width();
+ int lineheight = text->size().height();
+
+ // Use the label to display the applciation icon
+ text->setText(QString::null);
+ text->setPixmap(applicationIcon);
+ text->adjustSize();
+ grid->addWidget(text, 0, 1);
+
+
+ KActiveLabel *linktext = new KActiveLabel(w);
+ grid->addRowSpacing(1,kMax(100,6*lineheight));
+ grid->addRowSpacing(2,kMax(100,6*lineheight));
+ grid->addColSpacing(2,SPACING+linewidth/2);
+ grid->addColSpacing(3,SPACING+linewidth/2);
+ grid->setRowStretch(1,50);
+ grid->setRowStretch(2,50);
+ grid->setColStretch(2,50);
+ grid->setColStretch(3,50);
+ linktext->setMinimumSize(linewidth,kMax(260,60+12*lineheight));
+ linktext->setFixedHeight(kMax(260,60+12*lineheight));
+ linktext->setVScrollBarMode(QScrollView::Auto/*AlwaysOn*/);
+ text = new QLabel(w);
+ grid->addMultiCellWidget(text,0,0,2,3);
+ grid->addMultiCellWidget(linktext,1,2,1,3);
+
+ // Now set the program and copyright information.
+ s = CSL1("<qt><h3>");
+ s += p->programName();
+ s += ' ';
+ s += p->version();
+ s += CSL1("</h3>");
+ s += p->copyrightStatement() + CSL1("<br></qt>");
+ text->setText(s);
+
+ linktext->append(p->shortDescription() + CSL1("<br>"));
+
+ if (!p->homepage().isEmpty())
+ {
+ s = QString::null;
+ s += CSL1("<a href=\"%1\">").arg(p->homepage());
+ s += p->homepage();
+ s += CSL1("</a><br>");
+ linktext->append(s);
+ }
+
+ s = QString::null;
+ s += i18n("Send questions and comments to <a href=\"mailto:%1\">%2</a>.")
+ .arg( CSL1("[email protected]") )
+ .arg( CSL1("[email protected]") );
+ s += ' ';
+ s += i18n("Send bug reports to <a href=\"mailto:%1\">%2</a>.")
+ .arg(p->bugAddress())
+ .arg(p->bugAddress());
+ s += ' ';
+ s += i18n("For trademark information, see the "
+ "<a href=\"help:/kpilot/trademarks.html\">KPilot User's Guide</a>.");
+ s += CSL1("<br>");
+ linktext->append(s);
+ linktext->append(QString::null);
+
+
+
+ QValueList<KAboutPerson> pl = p->authors();
+ QValueList<KAboutPerson>::ConstIterator i;
+
+ s = i18n("<b>Authors:</b> ");
+
+ QString comma = CSL1(", ");
+
+ unsigned int count=1;
+ for (i=pl.begin(); i!=pl.end(); ++i)
+ {
+ s.append(CSL1("%1 (<i>%2</i>)%3")
+ .arg((*i).name())
+ .arg((*i).task())
+ .arg(count<pl.count() ? comma : QString::null)
+ );
+ count++;
+ }
+ linktext->append(s);
+
+ s = QString::null;
+ pl = p->credits();
+ if (pl.count()>0)
+ {
+ count=1;
+ s.append(i18n("<b>Credits:</b> "));
+ for (i=pl.begin(); i!=pl.end(); ++i)
+ {
+ s.append(CSL1("%1 (<i>%2</i>)%3")
+ .arg((*i).name())
+ .arg((*i).task())
+ .arg(count<pl.count() ? comma : QString::null)
+ );
+ count++;
+ }
+ }
+ linktext->append(s);
+ linktext->ensureVisible(0,0);
+
+ w->adjustSize();
+
+ return w;
+}
+
+/* static */ void ConduitConfigBase::addAboutPage(QTabWidget *tw,
+ KAboutData *ad)
+{
+ FUNCTIONSETUP;
+
+ Q_ASSERT(tw);
+
+ QWidget *w = aboutPage(tw,ad);
+ QSize sz = w->size();
+
+ if (sz.width() < tw->size().width())
+ {
+ sz.setWidth(tw->size().width());
+ }
+ if (sz.height() < tw->size().height())
+ {
+ sz.setHeight(tw->size().height());
+ }
+
+ tw->resize(sz);
+ tw->addTab(w, i18n("About"));
+ tw->adjustSize();
+}
+
+
+
+ConduitAction::ConduitAction(KPilotLink *p,
+ const char *name,
+ const QStringList &args) :
+ SyncAction(p,name),
+ fDatabase(0L),
+ fLocalDatabase(0L),
+ fCtrHH(0L),
+ fCtrPC(0L),
+ fSyncDirection(args),
+ fConflictResolution(SyncAction::eAskUser),
+ fFirstSync(false)
+{
+ FUNCTIONSETUP;
+
+ QString cResolution(args.grep(QRegExp(CSL1("--conflictResolution \\d*"))).first());
+ if (cResolution.isEmpty())
+ {
+ fConflictResolution=(SyncAction::ConflictResolution)
+ cResolution.replace(QRegExp(CSL1("--conflictResolution (\\d*)")), CSL1("\\1")).toInt();
+ }
+
+ for (QStringList::ConstIterator it = args.begin();
+ it != args.end();
+ ++it)
+ {
+ DEBUGKPILOT << fname << ": " << *it << endl;
+ }
+
+ DEBUGKPILOT << fname << ": Direction=" << fSyncDirection.name() << endl;
+ fCtrHH = new CUDCounter(i18n("Handheld"));
+ fCtrPC = new CUDCounter(i18n("PC"));
+}
+
+/* virtual */ ConduitAction::~ConduitAction()
+{
+ FUNCTIONSETUP;
+
+ KPILOT_DELETE(fDatabase);
+ KPILOT_DELETE(fLocalDatabase);
+
+ KPILOT_DELETE(fCtrHH);
+ KPILOT_DELETE(fCtrPC);
+}
+
+bool ConduitAction::openDatabases(const QString &name, bool *retrieved)
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname
+ << ": Trying to open database "
+ << name << endl;
+ DEBUGKPILOT << fname
+ << ": Mode="
+ << (syncMode().isTest() ? "test " : "")
+ << (syncMode().isLocal() ? "local " : "")
+ << endl ;
+
+ KPILOT_DELETE(fLocalDatabase);
+
+ QString localPathName = PilotLocalDatabase::getDBPath() + name;
+
+ // we always want to use the conduits/ directory for our local
+ // databases. this keeps our backups and data that our conduits use
+ // for record keeping separate
+ localPathName.replace(CSL1("DBBackup/"), CSL1("conduits/"));
+
+ DEBUGKPILOT << fname << ": localPathName: [" << localPathName
+ << "]" << endl;
+
+ PilotLocalDatabase *localDB = new PilotLocalDatabase( localPathName );
+
+ if (!localDB)
+ {
+ WARNINGKPILOT << "Could not initialize object for local copy of database \""
+ << name
+ << "\"" << endl;
+ if (retrieved) *retrieved = false;
+ return false;
+ }
+
+ // if there is no backup db yet, fetch it from the palm, open it and set the full sync flag.
+ if (!localDB->isOpen() )
+ {
+ QString dbpath(localDB->dbPathName());
+ KPILOT_DELETE(localDB);
+ DEBUGKPILOT << fname
+ << ": Backup database " << dbpath
+ << " not found." << endl;
+ struct DBInfo dbinfo;
+
+// TODO Extend findDatabase() with extra overload?
+ if (deviceLink()->findDatabase(Pilot::toPilot( name ), &dbinfo)<0 )
+ {
+ WARNINGKPILOT << "Could not get DBInfo for " << name << endl;
+ if (retrieved) *retrieved = false;
+ return false;
+ }
+
+ DEBUGKPILOT << fname
+ << ": Found Palm database: " << dbinfo.name <<endl
+ << fname << ": type = " << dbinfo.type
+ << " creator = " << dbinfo.creator
+ << " version = " << dbinfo.version
+ << " index = " << dbinfo.index << endl;
+ dbinfo.flags &= ~dlpDBFlagOpen;
+
+ // make sure the dir for the backup db really exists!
+ QFileInfo fi(dbpath);
+ QString path(QFileInfo(dbpath).dir(true).absPath());
+ if (!path.endsWith(CSL1("/"))) path.append(CSL1("/"));
+ if (!KStandardDirs::exists(path))
+ {
+ DEBUGKPILOT << fname << ": Trying to create path for database: <"
+ << path << ">" << endl;
+ KStandardDirs::makeDir(path);
+ }
+ if (!KStandardDirs::exists(path))
+ {
+ DEBUGKPILOT << fname << ": Database directory does not exist." << endl;
+ if (retrieved) *retrieved = false;
+ return false;
+ }
+
+ if (!deviceLink()->retrieveDatabase(dbpath, &dbinfo) )
+ {
+ WARNINGKPILOT << "Could not retrieve database "
+ << name << " from the handheld." << endl;
+ if (retrieved) *retrieved = false;
+ return false;
+ }
+ localDB = new PilotLocalDatabase( localPathName );
+ if (!localDB || !localDB->isOpen())
+ {
+ WARNINGKPILOT << "local backup of database " << name << " could not be initialized." << endl;
+ if (retrieved) *retrieved = false;
+ return false;
+ }
+ if (retrieved) *retrieved=true;
+ }
+ fLocalDatabase = localDB;
+
+ fDatabase = deviceLink()->database( name );
+
+ if (!fDatabase)
+ {
+ WARNINGKPILOT << "Could not open database \""
+ << name
+ << "\" on the pilot."
+ << endl;
+ }
+ else
+ {
+ fCtrHH->setStartCount(fDatabase->recordCount());
+ }
+
+ return (fDatabase && fDatabase->isOpen() &&
+ fLocalDatabase && fLocalDatabase->isOpen() );
+}
+
+
+bool ConduitAction::changeSync(SyncMode::Mode m)
+{
+ FUNCTIONSETUP;
+
+ if ( fSyncDirection.isSync() && SyncMode::eFullSync == m)
+ {
+ fSyncDirection.setMode(m);
+ return true;
+ }
+ return false;
+}
+
+void ConduitAction::finished()
+{
+ FUNCTIONSETUP;
+
+ if (fDatabase && fCtrHH)
+ fCtrHH->setEndCount(fDatabase->recordCount());
+
+ if (fCtrHH && fCtrPC)
+ {
+ addSyncLogEntry(fCtrHH->moo() +"\n",false);
+ DEBUGKPILOT << fname << ": " << fCtrHH->moo() << endl;
+ addSyncLogEntry(fCtrPC->moo() +"\n",false);
+ DEBUGKPILOT << fname << ": " << fCtrPC->moo() << endl;
+
+ // STEP2 of making sure we don't delete our little user's
+ // precious data...
+ // sanity checks for handheld...
+ int hhVolatility = fCtrHH->percentDeleted() +
+ fCtrHH->percentUpdated() +
+ fCtrHH->percentCreated();
+
+ int pcVolatility = fCtrPC->percentDeleted() +
+ fCtrPC->percentUpdated() +
+ fCtrPC->percentCreated();
+
+ // TODO: allow user to configure this...
+ // this is a percentage...
+ int allowedVolatility = 70;
+
+ QString caption = i18n("Large Changes Detected");
+ // args are already i18n'd
+ QString query = i18n("The %1 conduit has made a "
+ "large number of changes to your %2. Do you want "
+ "to allow this change?\nDetails:\n\t%3");
+
+ if (hhVolatility > allowedVolatility)
+ {
+ query = query.arg(fConduitName)
+ .arg(fCtrHH->type()).arg(fCtrHH->moo());
+
+ DEBUGKPILOT << fname << ": Yikes, lots of volatility "
+ << "caught. Check with user: [" << query
+ << "]." << endl;
+
+ /*
+ int rc = questionYesNo(query, caption,
+ QString::null, 0 );
+ if (rc == KMessageBox::Yes)
+ {
+ // TODO: add commit and rollback code.
+ // note: this will require some thinking,
+ // since we have to undo changes to the
+ // pilot databases, changes to the PC
+ // resources, changes to the mappings files
+ // (record id mapping, etc.)
+ }
+ */
+ }
+
+
+ }
+
+}
+
+
+ConduitProxy::ConduitProxy(KPilotLink *p,
+ const QString &name,
+ const SyncAction::SyncMode &m) :
+ ConduitAction(p,name.latin1(),m.list()),
+ fDesktopName(name)
+{
+ FUNCTIONSETUP;
+}
+
+/* virtual */ bool ConduitProxy::exec()
+{
+ FUNCTIONSETUP;
+
+ // query that service
+ KSharedPtr < KService > o = KService::serviceByDesktopName(fDesktopName);
+ if (!o)
+ {
+ WARNINGKPILOT << "Can't find desktop file for conduit "
+ << fDesktopName
+ << endl;
+ addSyncLogEntry(i18n("Could not find conduit %1.").arg(fDesktopName));
+ return false;
+ }
+
+
+ // load the lib
+ fLibraryName = o->library();
+ DEBUGKPILOT << fname
+ << ": Loading desktop "
+ << fDesktopName
+ << " with lib "
+ << fLibraryName
+ << endl;
+
+ KLibrary *library = KLibLoader::self()->library(
+ QFile::encodeName(fLibraryName));
+ if (!library)
+ {
+ WARNINGKPILOT << "Can't load library "
+ << fLibraryName
+ << " - "
+ << KLibLoader::self()->lastErrorMessage()
+ << endl;
+ addSyncLogEntry(i18n("Could not load conduit %1.").arg(fDesktopName));
+ return false;
+ }
+
+ unsigned long version = PluginUtility::pluginVersion(library);
+ if ( Pilot::PLUGIN_API != version )
+ {
+ WARNINGKPILOT << "Library "
+ << fLibraryName
+ << " has version "
+ << version
+ << endl;
+ addSyncLogEntry(i18n("Conduit %1 has wrong version (%2).").arg(fDesktopName).arg(version));
+ return false;
+ }
+
+ KLibFactory *factory = library->factory();
+ if (!factory)
+ {
+ WARNINGKPILOT << "Can't find factory in library "
+ << fLibraryName
+ << endl;
+ addSyncLogEntry(i18n("Could not initialize conduit %1.").arg(fDesktopName));
+ return false;
+ }
+
+ QStringList l = syncMode().list();
+
+ DEBUGKPILOT << fname << ": Flags: " << syncMode().name() << endl;
+
+ QObject *object = factory->create(fHandle,name(),"SyncAction",l);
+
+ if (!object)
+ {
+ WARNINGKPILOT << "Can't create SyncAction." << endl;
+ addSyncLogEntry(i18n("Could not create conduit %1.").arg(fDesktopName));
+ return false;
+ }
+
+ fConduit = dynamic_cast<ConduitAction *>(object);
+
+ if (!fConduit)
+ {
+ WARNINGKPILOT << "Can't cast to ConduitAction." << endl;
+ addSyncLogEntry(i18n("Could not create conduit %1.").arg(fDesktopName));
+ return false;
+ }
+
+ addSyncLogEntry(i18n("[Conduit %1]").arg(fDesktopName));
+
+ // Handle the syncDone signal properly & unload the conduit.
+ QObject::connect(fConduit,SIGNAL(syncDone(SyncAction *)),
+ this,SLOT(execDone(SyncAction *)));
+ // Proxy all the log and error messages.
+ QObject::connect(fConduit,SIGNAL(logMessage(const QString &)),
+ this,SIGNAL(logMessage(const QString &)));
+ QObject::connect(fConduit,SIGNAL(logError(const QString &)),
+ this,SIGNAL(logError(const QString &)));
+ QObject::connect(fConduit,SIGNAL(logProgress(const QString &,int)),
+ this,SIGNAL(logProgress(const QString &,int)));
+
+ QTimer::singleShot(0,fConduit,SLOT(execConduit()));
+ return true;
+}
+
+void ConduitProxy::execDone(SyncAction *p)
+{
+ FUNCTIONSETUP;
+
+ if (p!=fConduit)
+ {
+ WARNINGKPILOT << "Unknown conduit @"
+ << (void *) p
+ << " finished."
+ << endl;
+ emit syncDone(this);
+ return;
+ }
+
+ // give our worker a chance to sanity check the results...
+ fConduit->finished();
+
+ addSyncLogEntry(CSL1("\n"),false); // Put bits of the conduit logs on separate lines
+
+ KPILOT_DELETE(p);
+
+ emit syncDone(this);
+}
+
+
+namespace PluginUtility
+{
+
+QString findArgument(const QStringList &a, const QString &arg)
+{
+ FUNCTIONSETUP;
+
+ QString search;
+
+ if (arg.startsWith( CSL1("--") ))
+ {
+ search = arg;
+ }
+ else
+ {
+ search = CSL1("--") + arg;
+ }
+ search.append( CSL1("=") );
+
+
+ QStringList::ConstIterator end = a.end();
+ for (QStringList::ConstIterator i = a.begin(); i != end; ++i)
+ {
+ if ((*i).startsWith( search ))
+ {
+ QString s = (*i).mid(search.length());
+ return s;
+ }
+ }
+
+ return QString::null;
+}
+
+/* static */ bool isRunning(const QCString &n)
+{
+ DCOPClient *dcop = KApplication::kApplication()->dcopClient();
+ QCStringList apps = dcop->registeredApplications();
+ return apps.contains(n);
+}
+
+
+/* static */ unsigned long pluginVersion(const KLibrary *lib)
+{
+ QString symbol = CSL1("version_");
+ symbol.append(lib->name());
+
+ if (!lib->hasSymbol(symbol.latin1())) return 0;
+
+ unsigned long *p = (unsigned long *)(lib->symbol(symbol.latin1()));
+ return *p;
+}
+
+
+/* static */ QString pluginVersionString(const KLibrary *lib)
+{
+ QString symbol= CSL1("id_");
+ symbol.append(lib->name());
+
+ if (!lib->hasSymbol(symbol.latin1())) return QString::null;
+
+ return QString::fromLatin1(*((const char **)(lib->symbol(symbol.latin1()))));
+}
+
+
+}
+
+
+CUDCounter::CUDCounter(QString s) :
+ fC(0),fU(0),fD(0),fStart(0),fEnd(0),fType(s)
+{
+}
+
+void CUDCounter::created(unsigned int c)
+{
+ fC += c;
+}
+
+void CUDCounter::updated(unsigned int c)
+{
+ fU += c;
+}
+
+void CUDCounter::deleted(unsigned int c)
+{
+ fD += c;
+}
+
+void CUDCounter::setStartCount(unsigned int t)
+{
+ fStart = t;
+}
+
+void CUDCounter::setEndCount(unsigned int t)
+{
+ fEnd = t;
+}
+
+QString CUDCounter::moo() const
+{
+ QString result = fType + ": " +
+ i18n("Start: %1. End: %2. ").arg(fStart).arg(fEnd);
+
+ if (fC > 0) result += i18n("%1 new. ").arg(fC);
+ if (fU > 0) result += i18n("%1 changed. ").arg(fU);
+ if (fD > 0) result += i18n("%1 deleted. ").arg(fD);
+
+ if ( (fC+fU+fD) <= 0) result += i18n("No changes made. ");
+
+ return result;
+}
+
+
diff --git a/kpilot/lib/plugin.h b/kpilot/lib/plugin.h
new file mode 100644
index 000000000..b825b899f
--- /dev/null
+++ b/kpilot/lib/plugin.h
@@ -0,0 +1,476 @@
+#ifndef _KPILOT_PLUGIN_H
+#define _KPILOT_PLUGIN_H
+/* KPilot
+**
+** Copyright (C) 2001 by Dan Pilone
+** Copyright (C) 2002-2004,2006 Adriaan de Groot <[email protected]>
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <qstringlist.h>
+
+#include "syncAction.h"
+
+/** @file
+* This file defines the base class of all KPilot conduit plugins configuration
+* dialogs. This is necessary so that we have a fixed API to talk to from
+* inside KPilot.
+*
+* The factories used by KPilot plugins are also documented here.
+*/
+
+
+class QTabWidget;
+class KAboutData;
+class KLibrary;
+
+class PilotDatabase;
+
+namespace Pilot
+{
+ /**
+ * As the API for conduits may change in the course of time,
+ * identify them and refuse to load incompatible API versions.
+ * Bump this number every release to the current YYYYMMDD
+ * value.
+ */
+ static const unsigned int PLUGIN_API = 20061118;
+}
+
+/**
+* ConduitConfigBase is for configuration purposes.
+*
+* ConduitConfigBase: this is an object (with a widget!) that is embedded
+* in a dialog. This is the currently preferred form for configuration,
+* and it's what is used in the KPilot conduit configuration dialog.
+* The factory is asked for a "ConduitConfigBase" object.
+*
+* NB. The reason that this is a QObject which needs to create a
+* separate widget - instead of a QWidget subclass - has to do with
+* layouting. If you make the widget with designer then the easiest
+* thing to do is to use a grid layout there. Making ConduitConfigBase
+* a QWidget subclass would require an additional layout here, which
+* seems a little foolish.
+*
+*/
+class KDE_EXPORT ConduitConfigBase : public QObject
+{
+Q_OBJECT
+public:
+ /**
+ * Constructor. Creates a conduit configuration support object
+ * with the given parent @p parent and name (optional) @p n.
+ */
+ ConduitConfigBase(QWidget *parent=0L, const char *n=0L);
+
+ /** Destructor. */
+ virtual ~ConduitConfigBase();
+
+ /**
+ * This function is called to check whether the configuration
+ * of the conduit has changed -- and hence, whether the user
+ * needs to be prompted. By default, this just returns
+ * fModified, but you can do more complicated things.
+ */
+ virtual bool isModified() const
+ {
+ return fModified;
+ } ;
+
+ /** Accessor for the actual widget for the configuration. */
+ QWidget *widget() const
+ {
+ return fWidget;
+ } ;
+
+ /**
+ * Load or save the config widget's settings in the given
+ * KConfig object; leave the group unchanged. load() and
+ * commit() should both call unmodified() to indicate that
+ * the current settings match the on-disk ones.
+ */
+ virtual void commit() = 0;
+ virtual void load() = 0;
+ /**
+ * Called when the object is to be hidden again and might
+ * need to save changed settings. Should prompt the user
+ * and call commit() if needed. Override this function only
+ * if you need a very different kind of prompt window.
+ *
+ * Returns false if the change is to be canceled. Returns
+ * true otherwise, whether or not the changes were saved.
+ */
+ virtual bool maybeSave();
+
+ QString conduitName() const { return fConduitName; } ;
+
+ /**
+ * This is the function that does the work of adding an about
+ * page to a tabwidget. It is made public and static so that
+ * it can be used elsewhere wherever tabwidgets appear.
+ *
+ * The about tab is created using aboutPage(). The new about
+ * widget is added to the tab widget @p w with the heading
+ * "About".
+ *
+ * @param w The tab widget to which the about page is added.
+ * @param data The KAboutData that is used.
+ *
+ */
+ static void addAboutPage(QTabWidget *w,
+ KAboutData *data=0L);
+
+ /**
+ * This creates the actual about widget. Again, public & static so
+ * you can slap in an about widget wherever.
+ *
+ * An about widget is created that shows the contributors to
+ * the application, along with copyright information and the
+ * application's icon. This widget can be used pretty much
+ * anywhere. Copied from KAboutDialog, mostly.
+ *
+ * @param parent The widget that holds the about widget.
+ * @param data The KAboutData that is used to populate the widget.
+ */
+ static QWidget *aboutPage(QWidget *parent, KAboutData *data=0L);
+
+protected:
+ /**
+ * This function provides the string for the prompt used
+ * in maybeSave(). Override it to change the text.
+ */
+ virtual QString maybeSaveText() const;
+
+ void unmodified() { fModified=false; } ;
+
+ bool fModified;
+ QWidget *fWidget;
+ QString fConduitName;
+
+
+protected slots:
+ void modified();
+signals:
+ void changed(bool);
+
+} ;
+
+
+/**
+* Create-Update-Delete tracking of the plugin,
+* used for reporting purposes (in a consistent manner). The intent
+* is that this class is used by the conduit as it is syncing data.
+* For this to be useful (and be used properly), the conduit needs
+* to tell us how many creates, updates, and deletes it has made to
+* a data store (PC or HH). It also needs to tell us how many
+* records it started with and how many records it has at the
+* conclusion of its processing. Using this information, we can
+* report on it consistently as well as analyze the activity taken
+* by the conduit and offer rollback functionality if we think the
+* conduit has behaved improperly.
+*/
+class KDE_EXPORT CUDCounter
+{
+public:
+ /** Create new counter initialized to 0, and be told what
+ * kind of CUD we're counting (PC or Handheld, etc.) */
+ CUDCounter(QString s);
+
+ /** Track the creation of @p c items */
+ void created(unsigned int c=1);
+ /** Track updates to @p u items */
+ void updated(unsigned int u=1);
+ /** Track the destruction of @p d items */
+ void deleted(unsigned int d=1);
+ /** How many @p t items did we start with? */
+ void setStartCount(unsigned int t);
+ /** How many @p t items did we end with? */
+ void setEndCount(unsigned int t);
+
+ unsigned int countCreated() { return fC; }
+ unsigned int countUpdated() { return fU; }
+ unsigned int countDeleted() { return fD; }
+ unsigned int countStart() { return fStart; }
+ unsigned int countEnd() { return fEnd; }
+
+ /** percentage of changes. unfortunately, we have to rely on our
+ * developers (hi, self!) to correctly set total number of records
+ * conduits start with, so add a little protection...
+ */
+ unsigned int percentCreated() { return (fEnd > 0 ? fC/fEnd : 0); }
+ unsigned int percentUpdated() { return (fEnd > 0 ? fU/fEnd : 0); }
+ unsigned int percentDeleted() { return (fStart > 0 ? fD/fStart : 0); }
+
+ /** Measurement Of Objects -- report numbers of
+ * objects created, updated, deleted. This
+ * string is already i18n()ed.
+ */
+ QString moo() const;
+
+ /** Type of counter(Handheld or PC). This string is already
+ * i18n()ed.
+ */
+ QString type() const { return fType; }
+private:
+ /** keep track of Creates, Updates, Deletes, and Total
+ * number of records so we can detect abnormal behavior and
+ * hopefully prevent data loss.
+ */
+ unsigned int fC,fU,fD,fStart,fEnd;
+
+ /** What kind of CUD are we keeping track of so we can
+ * moo() it out later? (PC, Handheld, etc.)
+ */
+ QString fType;
+} ;
+
+
+/**
+* The SyncActions created by the factory should obey at least
+* the argument test, indicating a dry run. The device link is
+* the link where the sync should run -- don't get the pilotPort()
+* until the sync runs!
+*
+* setConfig() will be called before the sync starts so that the
+* conduit can read/write metadata and local settings.
+*/
+
+class KDE_EXPORT ConduitAction : public SyncAction
+{
+Q_OBJECT
+
+public:
+ ConduitAction(KPilotLink *,
+ const char *name=0L,
+ const QStringList &args = QStringList());
+ virtual ~ConduitAction();
+
+ /** ConduitAction is done doing work. Allow it to sanity-check the
+ * results
+ */
+ void finished();
+
+ QString conduitName() const { return fConduitName; } ;
+
+ /** Retrieve the sync mode set for this action. */
+ const SyncMode &syncMode() const { return fSyncDirection; };
+
+ /**
+ * A full sync happens for eFullSync, eCopyPCToHH and eCopyHHToPC. It
+ * completely ignores all modified flags and walks through all records
+ * in the database.
+ */
+ bool isFullSync() const
+ {
+ return fFirstSync || fSyncDirection.isFullSync() ;
+ }
+
+ /**
+ * A first sync (i.e. database newly fetched from the handheld )
+ * does not check for deleted records, but understands them as
+ * added on the other side. The flag is set by the conduits
+ * when opening the local database, or the calendar/addressbook
+ * (if it is empty). This also implies a full sync.
+ */
+ bool isFirstSync() const
+ {
+ return fFirstSync || fSyncDirection.isFirstSync() ;
+ }
+
+protected:
+ /** Retrieve the conflict resolution setting for this action. */
+ ConflictResolution getConflictResolution() const
+ { return fConflictResolution; };
+
+ /** Try to change the sync mode from what it is now to the mode @p m.
+ * This may fail (ie. changing a backup to a restore is not kosher) and
+ * changeSync() will return false then.
+ */
+ bool changeSync(SyncMode::Mode m);
+
+ // Set the conflict resolution, except if the resolution
+ // form is UseGlobalSetting, in which case nothing changes
+ // (assumes then that the resolution form is already set
+ // according to that global setting).
+ //
+ void setConflictResolution(ConflictResolution res)
+ {
+ if (SyncAction::eUseGlobalSetting != res)
+ fConflictResolution=res;
+ }
+
+ void setFirstSync(bool first) { fFirstSync=first; } ;
+
+ PilotDatabase *fDatabase;
+ PilotDatabase *fLocalDatabase; // Guaranteed to be a PilotLocalDatabase
+
+ /**
+ * Open both the local copy of database @p dbName
+ * and the version on the Pilot. Return true only
+ * if both opens succeed. If the local copy of the database
+ * does not exist, it is retrieved from the handheld. In this
+ * case, retrieved is set to true, otherwise it is left alone
+ * (i.e. retains its value and is not explicitly set to false).
+ *
+ * @param dbName database name to open.
+ * @param retrieved indicator whether the database had to be loaded
+ * from the handheld.
+ */
+ bool openDatabases(const QString &dbName, bool*retrieved=0L);
+
+ /**
+ * Name of the conduit; might be changed by subclasses. Should
+ * normally be set in the constructor.
+ */
+ QString fConduitName;
+
+ /** Every plugin has 2 CUDCounters--one for keeping track of
+ * changes made to PC data and one for keeping track of Palm data. */
+ CUDCounter *fCtrHH;
+ CUDCounter *fCtrPC;
+
+private:
+ SyncMode fSyncDirection;
+ ConflictResolution fConflictResolution;
+
+ bool fFirstSync;
+} ;
+
+/**
+* The ConduitProxy action delays loading the plugin for a conduit until the conduit
+* actually executes; the proxy then loads the file, creates a SyncAction for the conduit
+* and runs that. Once the conduit has finished, the proxy unloads everything
+* and emits syncDone().
+*/
+class ConduitProxy : public ConduitAction
+{
+Q_OBJECT
+
+public:
+ ConduitProxy(KPilotLink *,
+ const QString &desktopName,
+ const SyncAction::SyncMode &m);
+
+protected:
+ virtual bool exec();
+protected slots:
+ void execDone(SyncAction *);
+
+protected:
+ QString fDesktopName;
+ QString fLibraryName;
+ ConduitAction *fConduit;
+} ;
+
+/** A namespace containing only static helper methods. */
+namespace PluginUtility
+{
+ /** Searches the argument list for --foo=bar and returns bar, QString::null if not found.
+ * Don't include the -- in the argname. */
+ QString findArgument(const QStringList &a, const QString argname);
+
+ /**
+ * This function attempts to detect whether or not the given
+ * application is running. If it is, true is returned, otherwise
+ * false.
+ *
+ * The current approach is to ask the DCOP server if the application
+ * has registered.
+ */
+ bool isRunning(const QCString &appName);
+
+ /**
+ * Check a given library for its version, returning 0 if no
+ * version symbol is found.
+ */
+ unsigned long pluginVersion(const KLibrary *);
+ QString pluginVersionString(const KLibrary *);
+}
+
+/**
+* All KPilot conduits should subclass KLibFactory like this.
+*
+* Boilerplate for inheritance:
+*
+* <pre>
+* class KPilotPlugin : public KLibFactory
+* {
+* Q_OBJECT
+*
+* public:
+* KPilotPlugin(QObject * = 0L,const char * = 0L) ;
+* virtual ~KPilotPlugin();
+* </pre>
+*
+* You don't @em have to provide about information for the plugin,
+* but it's useful, particularly for the about box in a conduit.
+*
+*
+* <pre>
+* static KAboutData *about() { return fAbout; } ;
+* </pre>
+*
+*
+* This is what it's all about: creating objects for the plugin.
+* One classname that @em must be supported is ConduitConfig,
+* which is defined above. The other is SyncAction.
+*
+*
+* <pre>
+* protected:
+* virtual QObject* createObject( QObject* parent = 0,
+* const char* name = 0,
+* const char* classname = "QObject",
+* const QStringList &args = QStringList() );
+* </pre>
+*
+* More boilerplate, and support for an instance and about data, used
+* by about() above.
+*
+* <pre>
+* KInstance *fInstance;
+* static KAboutData *fAbout;
+* } ;
+* </pre>
+*
+*
+*
+* The implementation of a conduit needs an init_conduit_name() function,
+* just like any KLibLoader library that uses factories.
+*
+* The createObject() function needs to support at least two creation
+* calls: "ConduitConfigBase" and "SyncAction".
+* "ConduitConfigBase" should return a subclass of ConduitConfigBase,
+* "SyncAction" a subclass of SyncAction.
+*
+* Finally, a conduit should have a symbol version_conduit_name,
+* that returns a long; much like the init_conduit_name() function. This
+* should return the version of the plugin API (KPILOT_PLUGIN_VERSION)
+* the conduit was compiled against. Additionally, a plugin may have a
+* id_conduit_name, which should be a const char *.
+*
+*/
+
+#endif
diff --git a/kpilot/lib/pluginfactory.h b/kpilot/lib/pluginfactory.h
new file mode 100644
index 000000000..8eecc5584
--- /dev/null
+++ b/kpilot/lib/pluginfactory.h
@@ -0,0 +1,98 @@
+#ifndef _KPILOT_PLUGINFACTORY_H
+#define _KPILOT_PLUGINFACTORY_H
+/* KPilot
+**
+** Copyright (C) 2005-2006 by Adriaan de Groot <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <qwidget.h>
+
+#include <kdebug.h>
+#include <klibloader.h>
+
+#include "options.h"
+
+/** @file Defines a template class for factories for KPilot's conduits. */
+
+class KPilotLink;
+
+
+
+/** Template class that defines a conduit's factory. */
+
+template <class Widget, class Action> class ConduitFactory : public KLibFactory
+{
+public:
+ ConduitFactory(QObject *parent = 0, const char *name = 0) :
+ KLibFactory(parent,name)
+ { fInstance = new KInstance(name); } ;
+ virtual ~ConduitFactory()
+ { delete fInstance; } ;
+
+protected:
+ virtual QObject *createObject(
+ QObject* parent = 0,
+ const char* name = 0,
+ const char* classname = "QObject",
+ const QStringList &args = QStringList() )
+ {
+ if (qstrcmp(classname,"ConduitConfigBase")==0)
+ {
+ QWidget *w = dynamic_cast<QWidget *>(parent);
+ if (w) return new Widget(w,name);
+ else
+ {
+ WARNINGKPILOT << "Could not cast parent to widget." << endl;
+ return 0L;
+ }
+ }
+
+ if (qstrcmp(classname,"SyncAction")==0)
+ {
+ KPilotLink *d = 0L;
+ if (parent) d = dynamic_cast<KPilotLink *>(parent);
+
+ if (d || !parent)
+ {
+ if (!parent)
+ {
+ kdDebug() << k_funcinfo << ": Using NULL device." << endl;
+ }
+ return new Action(d,name,args);
+ }
+ else
+ {
+ WARNINGKPILOT << "Could not cast parent to KPilotLink" << endl;
+ return 0L;
+ }
+ }
+ return 0L;
+ }
+
+ KInstance *fInstance;
+} ;
+
+#endif
+
diff --git a/kpilot/lib/recordConduit.cc b/kpilot/lib/recordConduit.cc
new file mode 100644
index 000000000..f11b3b573
--- /dev/null
+++ b/kpilot/lib/recordConduit.cc
@@ -0,0 +1,1145 @@
+/* KPilot
+**
+** Copyright (C) 2004 by Reinhold Kainhofer
+** Based on the addressbook conduit:
+** Copyright (C) 2000,2001 by Dan Pilone
+** Copyright (C) 2000 Gregory Stern
+** Copyright (C) 2002-2003 by Reinhold Kainhofer
+**
+** This conduit is the base class for all record-based conduits.
+** all the sync logic is included in this class, and all child classes
+** just have to implement some specific copying and conflict resolution
+** methods.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected].
+*/
+
+
+
+#include "options.h"
+
+#include <qtimer.h>
+#include <qfile.h>
+
+#include "pilotAppCategory.h"
+#include "pilotSerialDatabase.h"
+#include "pilotLocalDatabase.h"
+#include "recordConduit.h"
+
+
+// Something to allow us to check what revision
+// the modules are that make up a binary distribution.
+//
+//
+extern "C"
+{
+long version_record_conduit = Pilot::PLUGIN_API;
+}
+
+
+/* virtual */ bool RecordConduitBase::exec()
+{
+ FUNCTIONSETUP;
+ fState = Initialize;
+
+ setFirstSync(false);
+
+ bool retrieved = false;
+ if (!openDatabases( fDBName, &retrieved))
+ {
+ emit logError(i18n("Unable to open the %1 database on the handheld.").arg( fDBName ) );
+ return false;
+ }
+ if (retrieved) setFirstSync(true);
+
+ if (isFirstSync()) fIDList=fDatabase->idList();
+ else fIDList=fDatabase->modifiedIDList();
+ fIDListIterator = fIDList.begin();
+
+ fTimer = new QTimer(this);
+ connect(fTimer,SIGNAL(timeout()),this,SLOT(process()));
+ fTimer->start(0,false); // Fire as often as possible to prompt processing
+ return true;
+}
+
+/* virtual */ void RecordConduitBase::process()
+{
+ FUNCTIONSETUP;
+ SyncProgress p = Error;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": From state " << name(fState) << endl;
+#endif
+
+ switch(fState)
+ {
+ case Initialize :
+ p = loadPC();
+ break;
+ case PalmToPC :
+ p = palmRecToPC();
+ break;
+ case PCToPalm :
+ p = pcRecToPalm();
+ break;
+ case Cleanup :
+ p = cleanup();
+ break;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Step returned " << name(p) << endl;
+#endif
+
+ switch(p)
+ {
+ case Error :
+ fTimer->stop();
+ delayDone();
+ return;
+ case NotDone :
+ // Return so we get called again.
+ return;
+ case Done :
+ // Get on with it.
+ break;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Step is done, moving to next state." << endl;
+#endif
+
+ // Here the previous call was done.
+ switch(fState)
+ {
+ case Initialize :
+ switch (syncMode().mode())
+ {
+ case SyncMode::eRestore :
+ case SyncMode::eCopyPCToHH : /* These two don't copy Palm records to the PC */
+ fState = PCToPalm;
+ break;
+ default :
+ fState = PalmToPC;
+ }
+ break;
+ case PalmToPC :
+ switch (syncMode().mode())
+ {
+ case SyncMode::eBackup :
+ case SyncMode::eCopyHHToPC : /* These modes don't copy PC records back */
+ fState = Cleanup;
+ break;
+ default :
+ fState = PCToPalm;
+ }
+ break;
+ case PCToPalm :
+ fState = Cleanup;
+ break;
+ case Cleanup :
+ fTimer->stop();
+ delayDone();
+ // No change in state, timer stopped and we're done.
+ break;
+ }
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Next state is " << name(fState) << endl;
+#endif
+
+}
+
+
+QString RecordConduitBase::name(RecordConduitBase::SyncProgress s)
+{
+ switch(s)
+ {
+ case RecordConduitBase::NotDone:
+ return CSL1("NotDone");
+ case RecordConduitBase::Done:
+ return CSL1("Done");
+ case RecordConduitBase::Error:
+ return CSL1("Error");
+ }
+}
+
+
+QString RecordConduitBase::name(RecordConduitBase::States s)
+{
+ switch(s)
+ {
+ case RecordConduitBase::Initialize:
+ return CSL1("Initialize");
+ case RecordConduitBase::PalmToPC:
+ return CSL1("Handheld-to-PC");
+ case RecordConduitBase::PCToPalm:
+ return CSL1("PC-to-Handheld");
+ case RecordConduitBase::Cleanup:
+ return CSL1("Cleanup");
+ }
+}
+
+
+#if 0
+/** make that entry on the pc archived (i.e. deleted on the handheld,
+ * while present on the pc, but not synced to the handheld */
+bool RecordConduit::PCData::makeArchived( RecordConduit::PCEntry *pcEntry )
+{
+ if ( pcEntry ) {
+ pcEntry->makeArchived();
+ setChanged( true );
+ return true;
+ } else return false;
+}
+
+
+/* Builds the map which links record ids to uid's of PCEntry. This is the slow implementation,
+ * that should always work. subclasses should reimplement it to speed things up.
+*/
+bool RecordConduit::PCData::mapContactsToPilot( QMap<recordid_t,QString> &idContactMap )
+{
+ FUNCTIONSETUP;
+
+ idContactMap.clear();
+
+ Iterator it = begin();
+ PCEntry *ent;
+ while ( !atEnd( it ) ) {
+ ent = *it;
+ recordid_t id( ent->recid() );
+ if ( id != 0 ) {
+ idContactMap.insert( id, ent->uid() );
+ }
+ ++it;
+ }
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Loaded " << idContactMap.size() <<
+ " Entries on the pc and mapped them to records on the handheld. " << endl;
+#endif
+ return true;
+}
+
+
+
+/*********************************************************************
+ C O N S T R U C T O R
+ *********************************************************************/
+
+
+
+bool RecordConduit::mArchiveDeleted = false;
+
+RecordConduit::RecordConduit(QString name, KPilotDeviceLink * o, const char *n, const QStringList & a):
+ ConduitAction(o, n, a),
+ mPCData(0), mPalmIndex(0),
+ mEntryMap(), mSyncedIds(), mAllIds()
+{
+ FUNCTIONSETUP;
+ fConduitName = name;
+}
+
+
+
+RecordConduit::~RecordConduit()
+{
+ if ( mPCData ) KPILOT_DELETE(mPCData);
+}
+
+
+
+
+
+
+/*********************************************************************
+ S Y N C S T R U C T U R E
+ *********************************************************************/
+
+
+
+/* virtual */ bool RecordConduit::exec()
+{
+ FUNCTIONSETUP;
+
+ if ( !_prepare() ) return false;
+
+ fFirstSync = false;
+ // Database names probably in latin1.
+ if( !openDatabases( dbName(), &fFirstSync ) )
+ {
+ emit logError(i18n("Unable to open the %1 database on the handheld.").arg( dbName() ) );
+ return false;
+ }
+ _getAppInfo();
+ if( !mPCData->loadData() )
+ {
+ emit logError( i18n("Unable to open %1.").arg( mPCData->description() ) );
+ return false;
+ }
+ // get the addresseMap which maps Pilot unique record(address) id's to
+ // a Abbrowser Addressee; allows for easy lookup and comparisons
+ if ( mPCData->isEmpty() )
+ fFirstSync = true;
+ else
+ mPCData->mapContactsToPilot( mEntryMap );
+ fFirstSync = fFirstSync || ( mPCData->isEmpty() );
+
+ // perform syncing from palm to abbrowser
+ // iterate through all records in palm pilot
+ mPalmIndex = 0;
+
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": fullsync=" << isFullSync() << ", firstSync=" << isFirstSync() << endl;
+ DEBUGKPILOT << fname << ": "
+ << "syncDirection=" << getSyncDirection() << ", "
+// << "archive = " << AbbrowserSettings::archiveDeleted()
+ << endl;
+ DEBUGKPILOT << fname << ": conflictRes="<< getConflictResolution() << endl;
+// DEBUGKPILOT << fname << ": PilotStreetHome=" << AbbrowserSettings::pilotStreet() << ", PilotFaxHOme" << AbbrowserSettings::pilotFax() << endl;
+#endif
+
+ if ( !isFirstSync() )
+ mAllIds=fDatabase->idList();
+
+ /* Note:
+ if eCopyPCToHH or eCopyHHToPC, first sync everything, then lookup
+ those entries on the receiving side that are not yet syncced and delete
+ them. Use slotDeleteUnsyncedPCRecords and slotDeleteUnsyncedHHRecords
+ for this, and no longer purge the whole addressbook before the sync to
+ prevent data loss in case of connection loss. */
+
+ QTimer::singleShot(0, this, SLOT(slotPalmRecToPC()));
+
+ return true;
+}
+
+
+
+void RecordConduit::slotPalmRecToPC()
+{
+ FUNCTIONSETUP;
+ PilotRecord *palmRec = 0L, *backupRec = 0L;
+
+ if ( getSyncDirection() == SyncAction::eCopyPCToHH )
+ {
+ mPCIter = mPCData->begin();
+ QTimer::singleShot(0, this, SLOT(slotPCRecToPalm()));
+ return;
+ }
+
+ if ( isFullSync() )
+ palmRec = fDatabase->readRecordByIndex( mPalmIndex++ );
+ else
+ palmRec = dynamic_cast <PilotSerialDatabase * >(fDatabase)->readNextModifiedRec();
+
+ if ( !palmRec )
+ {
+ mPCIter = mPCData->begin();
+ QTimer::singleShot( 0, this, SLOT( slotPCRecToPalm() ) );
+ return;
+ }
+
+ // already synced, so skip:
+ if ( mSyncedIds.contains( palmRec->id() ) )
+ {
+ KPILOT_DELETE( palmRec );
+ QTimer::singleShot( 0, this, SLOT( slotPalmRecToPC() ) );
+ return;
+ }
+
+ backupRec = fLocalDatabase->readRecordById( palmRec->id() );
+ PilotRecord *compareRec = backupRec ? backupRec : palmRec;
+ PilotAppCategory *compareEntry = createPalmEntry( compareRec );
+ PCEntry *pcEntry = findMatch( compareEntry );
+ KPILOT_DELETE( compareEntry );
+
+ PilotAppCategory *backupEntry=0L;
+ if ( backupRec )
+ backupEntry = createPalmEntry( backupRec );
+ PilotAppCategory *palmEntry=0L;
+ if ( palmRec )
+ palmEntry = createPalmEntry( palmRec );
+
+ syncEntry( pcEntry, backupEntry, palmEntry );
+
+ mSyncedIds.append( palmRec->id() );
+
+ KPILOT_DELETE( pcEntry );
+ KPILOT_DELETE( palmEntry );
+ KPILOT_DELETE( backupEntry );
+ KPILOT_DELETE( palmRec );
+ KPILOT_DELETE( backupRec );
+
+ QTimer::singleShot(0, this, SLOT(slotPalmRecToPC()));
+}
+
+
+
+void RecordConduit::slotPCRecToPalm()
+{
+ FUNCTIONSETUP;
+
+ if ( ( getSyncDirection()==SyncAction::eCopyHHToPC ) ||
+ mPCData->atEnd( mPCIter ) )
+ {
+ mPalmIndex = 0;
+ QTimer::singleShot( 0, this, SLOT( slotDeletedRecord() ) );
+ return;
+ }
+
+ PilotRecord *backupRec=0L;
+ PCEntry *pcEntry = *mPCIter;
+ ++mPCIter;
+
+ // If marked as archived, don't sync!
+ if ( isArchived( pcEntry ) )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": address with id " << pcEntry->uid() <<
+ " marked archived, so don't sync." << endl;
+#endif
+ KPILOT_DELETE( pcEntry );
+ QTimer::singleShot( 0, this, SLOT( slotPCRecToPalm() ) );
+ return;
+ }
+
+ recordid_t recID( pcEntry->recid() );
+ if ( recID == 0 )
+ {
+ // it's a new item(no record ID and not inserted by the Palm -> PC sync), so add it
+ syncEntry( pcEntry, 0L, 0L );
+ KPILOT_DELETE( pcEntry );
+ QTimer::singleShot( 0, this, SLOT( slotPCRecToPalm() ) );
+ return;
+ }
+
+ // look into the list of already synced record ids to see if the PCEntry hasn't already been synced
+ if ( mSyncedIds.contains( recID ) )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << ": address with id " << recID << " already synced." << endl;
+#endif
+ KPILOT_DELETE( pcEntry );
+ QTimer::singleShot( 0, this, SLOT( slotPCRecToPalm() ) );
+ return;
+ }
+
+
+ backupRec = fLocalDatabase->readRecordById( recID );
+ // only update if no backup record or the backup record is not equal to the PCEntry
+
+ PilotAppCategory*backupEntry=0L;
+ if ( backupRec )
+ backupEntry = createPalmEntry( backupRec );
+ if( !backupRec || isFirstSync() || !_equal( backupEntry, pcEntry ) )
+ {
+ PilotRecord *palmRec = fDatabase->readRecordById( recID );
+ PilotAppCategory *palmEntry=0L;
+ if (palmRec)
+ palmEntry = createPalmEntry( palmRec );
+ syncEntry( pcEntry, backupEntry, palmEntry );
+ // update the id just in case it changed
+ if ( palmRec )
+ recID = palmRec->id();
+ KPILOT_DELETE( palmRec );
+ KPILOT_DELETE( palmEntry );
+ }
+
+ KPILOT_DELETE( pcEntry );
+ KPILOT_DELETE( backupEntry );
+ KPILOT_DELETE( backupRec );
+ mSyncedIds.append( recID );
+
+ // done with the sync process, go on with the next one:
+ QTimer::singleShot( 0, this, SLOT( slotPCRecToPalm() ) );
+}
+
+
+
+void RecordConduit::slotDeletedRecord()
+{
+ FUNCTIONSETUP;
+
+ PilotRecord *backupRec = fLocalDatabase->readRecordByIndex( mPalmIndex++ );
+ if( !backupRec || isFirstSync() )
+ {
+ KPILOT_DELETE(backupRec);
+ QTimer::singleShot( 0, this, SLOT( slotDeleteUnsyncedPCRecords() ) );
+ return;
+ }
+
+ // already synced, so skip this record:
+ if ( mSyncedIds.contains( backupRec->id() ) )
+ {
+ KPILOT_DELETE( backupRec );
+ QTimer::singleShot( 0, this, SLOT( slotDeletedRecord() ) );
+ return;
+ }
+
+ QString uid = mEntryMap[ backupRec->id() ];
+ PCEntry *pcEntry = mPCData->findByUid( uid );
+ PilotRecord *palmRec = fDatabase->readRecordById( backupRec->id() );
+ PilotAppCategory *backupEntry = 0L;
+ if (backupRec)
+ backupEntry = createPalmEntry( backupRec );
+ PilotAppCategory*palmEntry=0L;
+ if (palmRec)
+ palmEntry = createPalmEntry( palmRec );
+
+ mSyncedIds.append( backupRec->id() );
+ syncEntry( pcEntry, backupEntry, palmEntry );
+
+ KPILOT_DELETE( pcEntry );
+ KPILOT_DELETE( palmEntry );
+ KPILOT_DELETE( backupEntry );
+ KPILOT_DELETE( palmRec );
+ KPILOT_DELETE( backupRec );
+ QTimer::singleShot( 0, this, SLOT( slotDeletedRecord() ) );
+}
+
+
+
+void RecordConduit::slotDeleteUnsyncedPCRecords()
+{
+ FUNCTIONSETUP;
+ if ( getSyncDirection() == SyncAction::eCopyHHToPC )
+ {
+ QStringList uids;
+ RecordIDList::iterator it;
+ QString uid;
+ for ( it = mSyncedIds.begin(); it != mSyncedIds.end(); ++it)
+ {
+ uid = mEntryMap[ *it ];
+ if ( !uid.isEmpty() ) uids.append( uid );
+ }
+ // TODO: Does this speed up anything?
+ // qHeapSort( uids );
+ const QStringList alluids( mPCData->uids() );
+ QStringList::ConstIterator uidit;
+ for ( uidit = alluids.constBegin(); uidit != alluids.constEnd(); ++uidit )
+ {
+ if ( !uids.contains( *uidit ) )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << "Deleting PCEntry with uid " << (*uidit) << " from PC (is not on HH, and syncing with HH->PC direction)" << endl;
+#endif
+ mPCData->removeEntry( *uidit );
+ }
+ }
+ }
+ QTimer::singleShot(0, this, SLOT(slotDeleteUnsyncedHHRecords()));
+}
+
+
+
+void RecordConduit::slotDeleteUnsyncedHHRecords()
+{
+ FUNCTIONSETUP;
+ if ( getSyncDirection() == SyncAction::eCopyPCToHH )
+ {
+ RecordIDList ids = fDatabase->idList();
+ RecordIDList::iterator it;
+ for ( it = ids.begin(); it != ids.end(); ++it )
+ {
+ if ( !mSyncedIds.contains(*it) )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << "Deleting record with ID " << *it << " from handheld (is not on PC, and syncing with PC->HH direction)" << endl;
+#endif
+ fDatabase->deleteRecord(*it);
+ fLocalDatabase->deleteRecord(*it);
+ }
+ }
+ }
+ QTimer::singleShot( 0, this, SLOT( slotCleanup() ) );
+}
+
+
+void RecordConduit::slotCleanup()
+{
+ FUNCTIONSETUP;
+
+ // Set the appInfoBlock, just in case the category labels changed
+ _setAppInfo();
+ doPostSync();
+ if(fDatabase)
+ {
+ fDatabase->resetSyncFlags();
+ fDatabase->cleanup();
+ }
+ if(fLocalDatabase)
+ {
+ fLocalDatabase->resetSyncFlags();
+ fLocalDatabase->cleanup();
+ }
+ KPILOT_DELETE( fDatabase );
+ KPILOT_DELETE( fLocalDatabase );
+ // TODO: do something if saving fails!
+ mPCData->saveData();
+ mPCData->cleanup();
+ emit syncDone(this);
+}
+
+
+/** Return the list of category names on the handheld
+ */
+const QStringList RecordConduit::categories() const
+{
+ QStringList cats;
+ for ( unsigned int j = 0; j < Pilot::CATEGORY_COUNT; j++ ) {
+ QString catName( category( j ) );
+ if ( !catName.isEmpty() ) cats << catName;
+ }
+ return cats;
+}
+int RecordConduit::findFlags() const
+{
+ return eqFlagsAlmostAll;
+}
+
+
+bool RecordConduit::isDeleted( const PilotAppCategory *palmEntry )
+{
+ if ( !palmEntry )
+ return true;
+ if ( palmEntry->isDeleted() && !palmEntry->isArchived() )
+ return true;
+ if ( palmEntry->isArchived() )
+ return !archiveDeleted();
+ return false;
+}
+bool RecordConduit::isArchived( const PilotAppCategory *palmEntry )
+{
+ if ( palmEntry && palmEntry->isArchived() )
+ return archiveDeleted();
+ else
+ return false;
+}
+
+
+
+
+/*********************************************************************
+ L O A D I N G T H E D A T A
+ *********************************************************************/
+
+
+
+bool RecordConduit::_prepare()
+{
+ FUNCTIONSETUP;
+
+ readConfig();
+ mSyncedIds.clear();
+ mPCData = initializePCData();
+
+ return mPCData && doPrepare();
+}
+
+
+void RecordConduit::_getAppInfo()
+{
+ FUNCTIONSETUP;
+ // get the address application header information
+ unsigned char *buffer = new unsigned char[Pilot::MAX_APPINFO_SIZE];
+ int appLen=fDatabase->readAppBlock(buffer, Pilot::MAX_APPINFO_SIZE);
+
+ doUnpackAppInfo( buffer, appLen );
+ delete[] buffer;
+ buffer = 0;
+}
+
+void RecordConduit::_setAppInfo()
+{
+ FUNCTIONSETUP;
+ // get the address application header information
+ int appLen = 0;
+ unsigned char *buffer = doPackAppInfo( &appLen );
+ if ( buffer )
+ { if (fDatabase)
+ fDatabase->writeAppBlock( buffer, appLen );
+ if (fLocalDatabase)
+ fLocalDatabase->writeAppBlock( buffer, appLen );
+ delete[] buffer;
+ }
+}
+
+
+int RecordConduit::compareStr( const QString & str1, const QString & str2 )
+{
+// FUNCTIONSETUP;
+ if ( str1.isEmpty() && str2.isEmpty() )
+ return 0;
+ else
+ return str1.compare( str2 );
+}
+
+
+/**
+ * _getCat returns the id of the category from the given categories list.
+ * If the address has no categories on the PC, QString::null is returned.
+ * If the current category exists in the list of cats, it is returned
+ * Otherwise the first cat in the list that exists on the HH is returned
+ * If none of the categories exists on the palm, QString::null is returned
+ */
+QString RecordConduit::getCatForHH( const QStringList cats, const QString curr ) const
+{
+ FUNCTIONSETUP;
+ if ( cats.size() < 1 )
+ return QString::null;
+ if ( cats.contains( curr ) )
+ return curr;
+ for ( QStringList::ConstIterator it = cats.begin(); it != cats.end(); ++it)
+ {
+ for ( unsigned int j = 0; j < Pilot::CATEGORY_COUNT; j++ )
+ {
+ QString catnm( category( j ) );
+ if ( !(*it).isEmpty() && ( (*it)==catnm ) )
+ {
+ return catnm;
+ }
+ }
+ }
+ // If we have a free label, return the first possible cat
+ QString lastCat( category( Pilot::CATEGORY_COUNT-1 ) );
+ return ( lastCat.isEmpty() ) ? ( cats.first() ) : ( QString::null );
+}
+
+void RecordConduit::setCategory(PCEntry * pcEntry, QString cat)
+{
+ if ( !cat.isEmpty() && cat!=category( 0 ) )
+ pcEntry->insertCategory(cat);
+}
+
+
+
+
+
+
+/*********************************************************************
+ G E N E R A L S Y N C F U N C T I O N
+ These functions modify the Handheld and the addressbook
+ *********************************************************************/
+
+
+
+bool RecordConduit::syncEntry( PCEntry *pcEntry, PilotAppCategory*backupEntry,
+ PilotAppCategory*palmEntry)
+{
+ FUNCTIONSETUP;
+
+ if ( getSyncDirection() == SyncAction::eCopyPCToHH )
+ {
+ if ( pcEntry->isEmpty() )
+ {
+ return pcDeleteEntry( pcEntry, backupEntry, palmEntry );
+ }
+ else
+ {
+ return pcCopyToPalm( pcEntry, backupEntry, palmEntry );
+ }
+ }
+
+ if ( getSyncDirection() == SyncAction::eCopyHHToPC )
+ {
+ if (!palmEntry)
+ return pcDeleteEntry(pcEntry, backupEntry, palmEntry);
+ else
+ return palmCopyToPC(pcEntry, backupEntry, palmEntry);
+ }
+
+ if ( !backupEntry || isFirstSync() )
+ {
+ /*
+ Resolution matrix (0..does not exist, E..exists, D..deleted flag set, A..archived):
+ HH PC | Resolution
+ ------------------------------------------------------------
+ 0 A | -
+ 0 E | PC -> HH, reset ID if not set correctly
+ D 0 | delete (error, should never occur!!!)
+ D E | CR (ERROR)
+ E/A 0 | HH -> PC
+ E/A E/A| merge/CR
+ */
+ if ( !palmEntry && isArchived( pcEntry ) )
+ {
+ return true;
+ }
+ else if ( !palmEntry && !pcEntry->isEmpty() )
+ {
+ // PC->HH
+ bool res = pcCopyToPalm( pcEntry, 0L, 0L );
+ return res;
+ }
+ else if ( !palmEntry && pcEntry->isEmpty() )
+ {
+ // everything's empty -> ERROR
+ return false;
+ }
+ else if ( ( isDeleted( palmEntry ) || isArchived( palmEntry ) ) && pcEntry->isEmpty())
+ {
+ if ( isArchived( palmEntry ) )
+ return palmCopyToPC( pcEntry, 0L, palmEntry );
+ else
+ // this happens if you add a record on the handheld and delete it again before you do the next sync
+ return pcDeleteEntry( pcEntry, 0L, palmEntry );
+ }
+ else if ( ( isDeleted(palmEntry) || isArchived( palmEntry ) ) && !pcEntry->isEmpty() )
+ {
+ // CR (ERROR)
+ return smartMergeEntry( pcEntry, 0L, palmEntry );
+ }
+ else if ( pcEntry->isEmpty() )
+ {
+ // HH->PC
+ return palmCopyToPC( pcEntry, 0L, palmEntry );
+ }
+ else
+ {
+ // Conflict Resolution
+ return smartMergeEntry( pcEntry, 0L, palmEntry );
+ }
+ } // !backupEntry
+ else
+ {
+ /*
+ Resolution matrix:
+ 1) if HH.(empty| (deleted &! archived) ) -> { if (PC==B) -> delete, else -> CR }
+ if HH.archived -> {if (PC==B) -> copyToPC, else -> CR }
+ if PC.empty -> { if (HH==B) -> delete, else -> CR }
+ if PC.archived -> {if (HH==B) -> delete on HH, else CR }
+ 2) if PC==HH -> { update B, update ID of PC if needed }
+ 3) if PC==B -> { HH!=PC, thus HH modified, so copy HH->PC }
+ if HH==B -> { PC!=HH, thus PC modified, so copy PC->HH }
+ 4) else: all three PCEntrys are different -> CR
+ */
+
+ if ( !palmEntry || isDeleted(palmEntry) )
+ {
+ if ( _equal( backupEntry, pcEntry ) || pcEntry->isEmpty() )
+ {
+ return pcDeleteEntry( pcEntry, backupEntry, 0L );
+ }
+ else
+ {
+ return smartMergeEntry( pcEntry, backupEntry, 0L );
+ }
+ }
+ else if ( pcEntry->isEmpty() )
+ {
+ if (*palmEntry == *backupEntry)
+ {
+ return pcDeleteEntry( pcEntry, backupEntry, palmEntry );
+ }
+ else
+ {
+ return smartMergeEntry( pcEntry, backupEntry, palmEntry );
+ }
+ }
+ else if ( _equal( palmEntry, pcEntry ) )
+ {
+ // update Backup, update ID of PC if neededd
+ return backupSaveEntry( palmEntry );
+ }
+ else if ( _equal( backupEntry, pcEntry ) )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << "Flags: " << palmEntry->getAttrib() << ", isDeleted=" <<
+ isDeleted( palmEntry ) << ", isArchived=" << isArchived( palmEntry )
+ << endl;
+#endif
+ if ( isDeleted( palmEntry ) )
+ {
+ return pcDeleteEntry( pcEntry, backupEntry, palmEntry );
+ }
+ else
+ {
+ return palmCopyToPC( pcEntry, backupEntry, palmEntry );
+ }
+ }
+ else if ( *palmEntry == *backupEntry )
+ {
+ return pcCopyToPalm( pcEntry, backupEntry, palmEntry );
+ }
+ else
+ {
+ // CR, since all are different
+ return smartMergeEntry( pcEntry, backupEntry, palmEntry );
+ }
+ } // backupEntry
+ return false;
+}
+
+bool RecordConduit::pcCopyToPalm( PCEntry *pcEntry, PilotAppCategory *backupEntry,
+ PilotAppCategory*palmEntry )
+{
+ FUNCTIONSETUP;
+
+ if ( pcEntry->isEmpty() ) return false;
+ PilotAppCategory *hhEntry = palmEntry;
+ bool hhEntryCreated = false;
+ if ( !hhEntry )
+ {
+ hhEntry = createPalmEntry( 0 );
+ hhEntryCreated=true;
+ }
+ _copy( hhEntry, pcEntry );
+#ifdef DEBUG
+ DEBUGKPILOT << "palmEntry->id=" << hhEntry->id() << ", pcEntry.ID=" <<
+ pcEntry->uid() << endl;
+#endif
+
+ if( palmSaveEntry( hhEntry, pcEntry ) )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << "Entry palmEntry->id=" <<
+ hhEntry->id() << "saved to palm, now updating pcEntry->uid()=" << pcEntry->uid() << endl;
+#endif
+ pcSaveEntry( pcEntry, backupEntry, hhEntry );
+ }
+ if ( hhEntryCreated ) KPILOT_DELETE( hhEntry );
+ return true;
+}
+
+
+
+
+bool RecordConduit::palmCopyToPC( PCEntry *pcEntry, PilotAppCategory *backupEntry,
+ PilotAppCategory *palmEntry )
+{
+ FUNCTIONSETUP;
+ if ( !palmEntry )
+ {
+ return false;
+ }
+ _copy( pcEntry, palmEntry );
+ pcSaveEntry( pcEntry, backupEntry, palmEntry );
+ backupSaveEntry( palmEntry );
+ return true;
+}
+
+
+
+/*********************************************************************
+ l o w - l e v e l f u n c t i o n s f o r
+ adding / removing palm/pc records
+ *********************************************************************/
+
+
+
+bool RecordConduit::palmSaveEntry( PilotAppCategory *palmEntry, PCEntry *pcEntry )
+{
+ FUNCTIONSETUP;
+
+#ifdef DEBUG
+ DEBUGKPILOT << "Saving to pilot " << palmEntry->id() << endl;
+#endif
+
+ PilotRecord *pilotRec = palmEntry->pack();
+ recordid_t pilotId = fDatabase->writeRecord(pilotRec);
+#ifdef DEBUG
+ DEBUGKPILOT << "PilotRec nach writeRecord (" << pilotId <<
+ ": ID=" << pilotRec->id() << endl;
+#endif
+ fLocalDatabase->writeRecord( pilotRec );
+ KPILOT_DELETE( pilotRec );
+
+ // pilotId == 0 if using local db, so don't overwrite the valid id
+ if ( pilotId != 0 )
+ {
+ palmEntry->setID( pilotId );
+ if ( !mSyncedIds.contains( pilotId ) )
+ {
+ mSyncedIds.append( pilotId );
+ }
+ }
+
+ recordid_t hhId( pcEntry->recid() );
+ if ( hhId != pilotId )
+ {
+ pcEntry->setRecid( pilotId );
+ return true;
+ }
+
+ return false;
+}
+
+
+
+bool RecordConduit::backupSaveEntry( PilotAppCategory *backup )
+{
+ FUNCTIONSETUP;
+ if ( !backup ) return false;
+
+
+#ifdef DEBUG
+// showPilotAppCategory( backup );
+#endif
+ PilotRecord *pilotRec = backup->pack();
+ fLocalDatabase->writeRecord( pilotRec );
+ KPILOT_DELETE( pilotRec );
+ return true;
+}
+
+
+
+bool RecordConduit::pcSaveEntry( PCEntry *pcEntry, PilotAppCategory *,
+ PilotAppCategory * )
+{
+ FUNCTIONSETUP;
+
+#ifdef DEBUG
+ DEBUGKPILOT << "Before _savepcEntry, pcEntry->uid()=" <<
+ pcEntry->uid() << endl;
+#endif
+ if ( pcEntry->recid() != 0 )
+ {
+ mEntryMap.insert( pcEntry->recid(), pcEntry->uid() );
+ }
+
+ mPCData->updateEntry( pcEntry );
+ return true;
+}
+
+
+
+bool RecordConduit::pcDeleteEntry( PCEntry *pcEntry, PilotAppCategory *backupEntry,
+ PilotAppCategory *palmEntry )
+{
+ FUNCTIONSETUP;
+
+ if ( palmEntry )
+ {
+ if ( !mSyncedIds.contains( palmEntry->id() ) )
+ {
+ mSyncedIds.append(palmEntry->id());
+ }
+ palmEntry->makeDeleted();
+ PilotRecord *pilotRec = palmEntry->pack();
+ pilotRec->setDeleted();
+ mPalmIndex--;
+ fDatabase->writeRecord( pilotRec );
+ fLocalDatabase->writeRecord( pilotRec );
+ mSyncedIds.append( pilotRec->id() );
+ KPILOT_DELETE( pilotRec );
+ }
+ else if ( backupEntry )
+ {
+ if ( !mSyncedIds.contains( backupEntry->id() ) )
+ {
+ mSyncedIds.append( backupEntry->id() );
+ }
+ backupEntry->makeDeleted();
+ PilotRecord *pilotRec = backupEntry->pack();
+ pilotRec->setDeleted();
+ mPalmIndex--;
+ fLocalDatabase->writeRecord( pilotRec );
+ mSyncedIds.append( pilotRec->id() );
+ KPILOT_DELETE( pilotRec );
+ }
+ if ( !pcEntry->isEmpty() )
+ {
+#ifdef DEBUG
+ DEBUGKPILOT << fname << " removing " << pcEntry->uid() << endl;
+#endif
+ mPCData->removeEntry( pcEntry );
+ }
+ return true;
+}
+
+
+
+/*********************************************************************
+ C O P Y R E C O R D S
+ *********************************************************************/
+
+
+
+
+
+/*********************************************************************
+ C O N F L I C T R E S O L U T I O N a n d M E R G I N G
+ *********************************************************************/
+
+
+
+
+// TODO: right now entries are equal if both first/last name and organization are
+// equal. This rules out two entries for the same person(e.g. real home and weekend home)
+// or two persons with the same name where you don't know the organization.!!!
+RecordConduit::PCEntry *RecordConduit::findMatch( PilotAppCategory *palmEntry ) const
+{
+ FUNCTIONSETUP;
+ if ( !palmEntry )
+ return 0;
+
+ // TODO: also search with the pilotID
+ // first, use the pilotID to UID map to find the appropriate record
+ if( !isFirstSync() && ( palmEntry->id() > 0) )
+ {
+ QString id( mEntryMap[palmEntry->id()] );
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": PilotRecord has id " << palmEntry->id() << ", mapped to " << id << endl;
+#endif
+ if( !id.isEmpty() )
+ {
+ PCEntry *res = mPCData->findByUid( id );
+ if ( !res && !res->isEmpty() ) return res;
+ KPILOT_DELETE( res );
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": PilotRecord has id " << palmEntry->id() <<
+ ", but could not be found on the PC side" << endl;
+#endif
+ }
+ }
+
+ for ( PCData::Iterator iter = mPCData->begin(); !mPCData->atEnd( iter ); ++iter )
+ {
+ PCEntry *abEntry = *iter;
+ recordid_t rid( abEntry->recid() );
+ if ( rid>0 )
+ {
+ if ( rid == palmEntry->id() )
+ return abEntry;// yes, we found it
+ // skip this PCEntry, as it has a different corresponding address on the handheld
+ //if ( mAllIds.contains( rid ) ) continue;
+ }
+
+ if ( _equal( palmEntry, abEntry, eqFlagsAlmostAll ) )
+ {
+ return abEntry;
+ }
+ KPILOT_DELETE( abEntry );
+ }
+#ifdef DEBUG
+ DEBUGKPILOT << fname << ": Could not find any entry matching Palm record with id " << QString::number( palmEntry->id() ) << endl;
+#endif
+ return 0;
+}
+
+#endif
+
+
+
+
+#include "recordConduit.moc"
+
diff --git a/kpilot/lib/recordConduit.h b/kpilot/lib/recordConduit.h
new file mode 100644
index 000000000..d12ceef2e
--- /dev/null
+++ b/kpilot/lib/recordConduit.h
@@ -0,0 +1,181 @@
+#ifndef _KPILOT_RECORDCONDUIT_H
+#define _KPILOT_RECORDCONDUIT_H
+/* record-conduit.h KPilot
+**
+** Copyright (C) 2005 by Adriaan de Groot
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <qtimer.h>
+#include <klocale.h>
+
+#include "plugin.h"
+#include "pilot.h"
+#include "pilotDatabase.h"
+#include "kpilotdevicelink.h"
+
+class KPilotDeviceLink;
+
+/** @file
+*
+* This file defines a generic syncing framework for Palm Pilot oriented data.
+* It is a lot like KitchenSync's Syncees and such. Basically, we define a
+* generic container for data on the PC side and give that container an API
+* for searching for a specific handheld record. Syncing consists of iterating
+* through the handheld's records and looking up the PC data for each record,
+* and then syncing.
+*
+*/
+
+/** An intermediate class that introduces the slots we need for our sync
+* implementation. This is here _only_ because mixing moc with template
+* classes sounds really scary.
+*/
+
+class RecordConduitBase : public ConduitAction
+{
+Q_OBJECT
+public:
+ /** Constructor. The QStringList @p a sets flags for the ConduitAction.
+ */
+ RecordConduitBase(KPilotDeviceLink *o,
+ const char *n,
+ const QStringList a = QStringList()) :
+ ConduitAction(o,n,a),
+ fTimer(0L)
+ {
+ } ;
+ /** Destructor. */
+ virtual ~RecordConduitBase()
+ {
+ // delete fTimer; // Timer is a child object
+ } ;
+
+ /** Return values for the processing functions. Each should return
+ * NotDone if it needs to be called again (e.g. to process another record),
+ * Done if it is finished and something else should be done, and
+ * Error if the sync cannot be completed.
+ */
+ enum SyncProgress { NotDone=0, Done=1, Error=2 } ;
+
+ /** Returns a human-readable name for the progress indicator @p s */
+ static QString name(SyncProgress s);
+
+ /** State of the conduit's sync. This is changed by process(). */
+ enum States { Initialize, PalmToPC, PCToPalm, Cleanup } ;
+
+ static QString name(States s);
+
+protected:
+ /** Function called at the beginning of a sync to load data from the PC.
+ * @return Done when the load has finished.
+ * @see process
+ */
+ virtual SyncProgress loadPC() = 0;
+
+ /** Function called repeatedly to fetch the next modified entry from the Palm and
+ * sync it with the PC by looking up the record, and calling the syncer for it.
+ *
+ * @return Dome when there are no more modified records on the Palm
+ * @see process()
+ */
+ virtual SyncProgress palmRecToPC() = 0;
+
+ /** Function called repeatedly to fetch the next modified entry from the PC and
+ * sync it with the Palm by looking up the record and calling the syncer for it.
+ *
+ * @return Done when there are no more modified records on the PC
+ * @see process()
+ */
+ virtual SyncProgress pcRecToPalm() = 0;
+
+ /** Function called at the end of this conduit's sync, which should reset DB flags
+ * and write changed config data out to disk.
+ *
+ * @return Done when the cleanup is complete.
+ * @see process()
+ */
+ virtual SyncProgress cleanup() = 0;
+
+protected slots:
+ /** Slot used for the implementation of a state machine: calls each of the
+ * relevant other slots (above) as needed until they return true.
+ */
+ void process();
+
+protected:
+ virtual bool exec();
+
+private:
+ /** Timer to signal the process() slot. Used to keep the UI responsive. */
+ QTimer *fTimer;
+
+ States fState;
+
+ Pilot::RecordIDList fIDList;
+ Pilot::RecordIDList::Iterator fIDListIterator;
+
+ QString fDBName;
+} ;
+
+template <class PCEntry, class PCContainer, class HHEntry, class HHAppInfo, class Syncer>
+class RecordConduit : public RecordConduitBase
+{
+public:
+ /** Construct a record conduit on a given device link. */
+ RecordConduit(
+ KPilotDeviceLink *o /**< Connection to HH */,
+ const char *n /**< Name for QObject */,
+ const QStringList a = QStringList() /**< Flags */) :
+ RecordConduitBase(o,n,a)
+ {
+ } ;
+ virtual ~RecordConduit()
+ {
+ } ;
+
+ virtual SyncProgress loadPC()
+ {
+ return Done;
+ } ;
+
+ virtual SyncProgress palmRecToPC()
+ {
+ return Done;
+ }
+
+ virtual SyncProgress pcRecToPalm()
+ {
+ return Done;
+ }
+
+ virtual SyncProgress cleanup()
+ {
+ return Done;
+ }
+} ;
+
+
+#endif
+
diff --git a/kpilot/lib/syncAction.cc b/kpilot/lib/syncAction.cc
new file mode 100644
index 000000000..818503807
--- /dev/null
+++ b/kpilot/lib/syncAction.cc
@@ -0,0 +1,512 @@
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2001 by Waldo Bastian (code in questionYesNo)
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <time.h>
+
+#include <pi-socket.h>
+#include <pi-dlp.h>
+
+#include <qtimer.h>
+#include <qvbox.h>
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qmessagebox.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qtl.h>
+#include <qstyle.h>
+
+#include <kdialogbase.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+
+#include "syncAction.moc"
+#include "kpilotlibSettings.h"
+
+SyncAction::SyncAction(KPilotLink *p,
+ const char *name) :
+ QObject(p, name),
+ fHandle(p),
+ fParent(0L)
+{
+ FUNCTIONSETUP;
+}
+
+SyncAction::SyncAction(KPilotLink *p,
+ QWidget * visibleparent,
+ const char *name) :
+ QObject(p, name),
+ fHandle(p),
+ fParent(visibleparent)
+{
+ FUNCTIONSETUP;
+}
+
+SyncAction::~SyncAction()
+{
+}
+
+/* virtual */ QString SyncAction::statusString() const
+{
+ FUNCTIONSETUP;
+ QString s = CSL1("status=");
+
+ s.append(QString::number(status()));
+ return s;
+}
+
+/* slot */ void SyncAction::execConduit()
+{
+ FUNCTIONSETUP;
+
+ DEBUGKPILOT << fname << ": Exec " << name() << endl;
+
+ bool r = this->exec();
+
+ DEBUGKPILOT << fname << ": Exec " << name()
+ << (r ? " is running" : " failed to start") << endl;
+
+ if (!r)
+ {
+ emit logError(i18n("The conduit %1 could not be executed.")
+ .arg(QString::fromLatin1(name())));
+ delayDone();
+ }
+}
+
+/* slot */ void SyncAction::delayedDoneSlot()
+{
+ emit syncDone(this);
+}
+
+bool SyncAction::delayDone()
+{
+ QTimer::singleShot(0,this,SLOT(delayedDoneSlot()));
+ return true;
+}
+
+static struct
+{
+ SyncAction::SyncMode::Mode mode;
+ const char *name;
+} maps[] =
+{
+ { SyncAction::SyncMode::eHotSync, "--hotsync" },
+ { SyncAction::SyncMode::eFullSync, "--full" },
+ { SyncAction::SyncMode::eCopyPCToHH, "--copyPCToHH" },
+ { SyncAction::SyncMode::eCopyHHToPC, "--copyHHToPC" },
+ { SyncAction::SyncMode::eBackup, "--backup" },
+ { SyncAction::SyncMode::eRestore, "--restore" },
+ { SyncAction::SyncMode::eFullSync, "--fullsync" },
+ { SyncAction::SyncMode::eHotSync, (const char *)0 }
+}
+;
+
+SyncAction::SyncMode::SyncMode(const QStringList &args) :
+ fMode(eHotSync),
+ fTest(args.contains("--test")),
+ fLocal(args.contains("--local"))
+{
+ int i = 0;
+ while(maps[i].name)
+ {
+ if (args.contains(QString::fromLatin1(maps[i].name)))
+ {
+ fMode = maps[i].mode;
+ break;
+ }
+ i++;
+ }
+
+ if (!maps[i].name)
+ {
+ WARNINGKPILOT << "No mode set by arguments ("
+ << args.join(",") << ") defaulting to HotSync." << endl;
+ }
+}
+
+SyncAction::SyncMode::SyncMode(Mode m, bool test, bool local) :
+ fMode(m),
+ fTest(test),
+ fLocal(local)
+{
+ if ( ((int)m<(int)eHotSync) || ((int)m>(int)eRestore) )
+ {
+ WARNINGKPILOT << "Mode value " << (int)m << " is illegal"
+ ", defaulting to HotSync." << endl;
+ fMode = eHotSync;
+ }
+}
+
+QStringList SyncAction::SyncMode::list() const
+{
+ FUNCTIONSETUPL(3);
+
+ QStringList l;
+ int i=0;
+
+ while(maps[i].name)
+ {
+ if ( fMode == maps[i].mode )
+ {
+ l.append(QString::fromLatin1(maps[i].name));
+ break;
+ }
+ i++;
+ }
+ if ( !maps[i].name )
+ {
+ WARNINGKPILOT << "Mode " << fMode << " does not have a name." << endl;
+ l.append(QString::fromLatin1(maps[0].name));
+ }
+
+ if (isTest()) l.append(CSL1("--test"));
+ if (isLocal()) l.append(CSL1("--local"));
+ return l;
+}
+
+/* static */ QString SyncAction::SyncMode::name(SyncAction::SyncMode::Mode e)
+{
+ switch(e)
+ {
+ case eHotSync : return i18n("HotSync");
+ case eFullSync : return i18n("Full Synchronization");
+ case eCopyPCToHH : return i18n("Copy PC to Handheld");
+ case eCopyHHToPC : return i18n("Copy Handheld to PC");
+ case eBackup : return i18n("Backup");
+ case eRestore : return i18n("Restore From Backup");
+ }
+ return CSL1("<unknown>");
+}
+
+QString SyncAction::SyncMode::name() const
+{
+ QString s = name(fMode);
+ if (isTest())
+ {
+
+ s.append(CSL1(" [%1]").arg(i18n("Test Sync")));
+ }
+ if (isLocal())
+ {
+ s.append(CSL1(" [%1]").arg(i18n("Local Sync")));
+ }
+ return s;
+}
+
+bool SyncAction::SyncMode::setMode(int mode)
+{
+ // Resets test and local flags too
+ fTest = fLocal = false;
+
+ if ( (mode>0) && (mode<=eRestore) )
+ {
+ fMode = (SyncAction::SyncMode::Mode) mode;
+ return true;
+ }
+ else
+ {
+ WARNINGKPILOT << "Bad sync mode " << mode << " requested." << endl ;
+ fMode = eHotSync;
+ return false;
+ }
+}
+
+bool SyncAction::SyncMode::setMode(SyncAction::SyncMode::Mode m)
+{
+ int i=0;
+ while ( maps[i].name )
+ {
+ if ( maps[i].mode == m )
+ {
+ fMode = m;
+ return true;
+ }
+ i++;
+ }
+
+ WARNINGKPILOT << "Bad sync mode " << m << " requested." << endl ;
+ fMode = eHotSync;
+ return false;
+}
+
+void SyncAction::startTickle(unsigned timeout)
+{
+ FUNCTIONSETUP;
+
+ if (!deviceLink())
+ {
+ WARNINGKPILOT << "Trying to tickle without a device." << endl;
+ }
+ else
+ {
+ connect(deviceLink(),SIGNAL(timeout()),this,SIGNAL(timeout()));
+ deviceLink()->startTickle(timeout);
+ }
+}
+
+void SyncAction::stopTickle()
+{
+ FUNCTIONSETUP;
+ if (!deviceLink())
+ {
+ WARNINGKPILOT << "Trying to tickle without a device." << endl;
+ }
+ else
+ {
+ disconnect(deviceLink(),SIGNAL(timeout()),this,SIGNAL(timeout()));
+ deviceLink()->stopTickle();
+ }
+}
+
+
+int SyncAction::questionYesNo(const QString & text,
+ const QString & caption,
+ const QString & key,
+ unsigned timeout,
+ const QString & yes,
+ const QString &no )
+{
+ FUNCTIONSETUP;
+
+ bool checkboxReturn = false;
+ int r;
+ KMessageBox::ButtonCode result;
+ if (!key.isEmpty())
+ {
+ if (!KMessageBox::shouldBeShownYesNo(key,result))
+ {
+ return result;
+ }
+ }
+
+ KDialogBase *dialog =
+ new KDialogBase(caption.isNull()? i18n("Question") : caption,
+ KDialogBase::Yes | KDialogBase::No,
+ KDialogBase::Yes, KDialogBase::No,
+ fParent, "questionYesNo", true, true,
+ yes.isEmpty() ? KStdGuiItem::yes() : yes,
+ no.isEmpty() ? KStdGuiItem::no() : no);
+
+ if ( (timeout > 0) && ( deviceLink() ) )
+ {
+ QObject::connect(deviceLink(), SIGNAL(timeout()),
+ dialog, SLOT(slotCancel()));
+ startTickle(timeout);
+ }
+
+#if KDE_IS_VERSION(3,3,0)
+ r = (KMessageBox::ButtonCode) KMessageBox::createKMessageBox(dialog,
+ QMessageBox::Question,
+ text,
+ QStringList(),
+ (key.isEmpty() ? QString::null : i18n("&Do not ask again")),
+ &checkboxReturn,
+ 0);
+
+#else
+ // The following code is taken from KDialogBase.cc,
+ // part of the KDE 2.2 libraries. Copyright 2001
+ // by Waldo Bastian.
+ //
+ //
+ QVBox *topcontents = new QVBox(dialog);
+
+ topcontents->setSpacing(KDialog::spacingHint() * 2);
+ topcontents->setMargin(KDialog::marginHint() * 2);
+
+ QWidget *contents = new QWidget(topcontents);
+ QHBoxLayout *lay = new QHBoxLayout(contents);
+
+ lay->setSpacing(KDialog::spacingHint() * 2);
+
+ lay->addStretch(1);
+ QLabel *label1 = new QLabel( contents);
+ label1->setPixmap(QMessageBox::standardIcon(QMessageBox::Information));
+ lay->add( label1 );
+ QLabel *label2 = new QLabel( text, contents);
+ label2->setMinimumSize(label2->sizeHint());
+ lay->add(label2);
+ lay->addStretch(1);
+
+ QSize extraSize = QSize(50, 30);
+
+ QCheckBox *checkbox = 0L;
+ if (!key.isEmpty())
+ {
+ checkbox = new QCheckBox(i18n("Do not ask again"),topcontents);
+ extraSize = QSize(50,0);
+ }
+
+ dialog->setMainWidget(topcontents);
+ dialog->enableButtonSeparator(false);
+ dialog->incInitialSize(extraSize);
+
+ r = dialog->exec();
+ if (checkbox)
+ {
+ checkboxReturn = checkbox->isChecked();
+ }
+#endif
+
+ switch(r)
+ {
+ case KDialogBase::Yes : result=KMessageBox::Yes ; break;
+ case KDialogBase::No : result=KMessageBox::No; break;
+ case KDialogBase::Cancel : result=KMessageBox::Cancel; break;
+ default : break;
+ }
+
+ stopTickle();
+
+ if (!key.isEmpty() && checkboxReturn)
+ {
+ KMessageBox::saveDontShowAgainYesNo(key,result);
+ }
+
+ return result;
+}
+
+
+int SyncAction::questionYesNoCancel(const QString & text,
+ const QString & caption,
+ const QString & key,
+ unsigned timeout,
+ const QString &yes,
+ const QString &no)
+{
+ FUNCTIONSETUP;
+
+ bool checkboxReturn = false;
+ int r;
+ KMessageBox::ButtonCode result;
+
+ if (!key.isEmpty())
+ {
+ if (!KMessageBox::shouldBeShownYesNo(key,result))
+ {
+ if (result != KMessageBox::Cancel)
+ {
+ return result;
+ }
+ }
+ }
+
+ KDialogBase *dialog =
+ new KDialogBase(caption.isNull()? i18n("Question") : caption,
+ KDialogBase::Yes | KDialogBase::No | KDialogBase::Cancel,
+ KDialogBase::Yes, KDialogBase::Cancel,
+ fParent, "questionYesNoCancel", true, true,
+ (yes.isEmpty() ? KStdGuiItem::yes() : yes),
+ (no.isEmpty() ? KStdGuiItem::no() : no),
+ KStdGuiItem::cancel());
+
+ if ( (timeout > 0) && (deviceLink()) )
+ {
+ QObject::connect(deviceLink(), SIGNAL(timeout()),
+ dialog, SLOT(slotCancel()));
+ startTickle(timeout);
+ }
+
+#if KDE_IS_VERSION(3,3,0)
+ r = KMessageBox::createKMessageBox(dialog,
+ QMessageBox::Question,
+ text,
+ QStringList(),
+ (key.isEmpty() ? QString::null : i18n("&Do not ask again")),
+ &checkboxReturn,
+ 0);
+#else
+ // The following code is taken from KDialogBase.cc,
+ // part of the KDE 2.2 libraries. Copyright 2001
+ // by Waldo Bastian.
+ //
+ //
+ QVBox *topcontents = new QVBox(dialog);
+
+ topcontents->setSpacing(KDialog::spacingHint() * 2);
+ topcontents->setMargin(KDialog::marginHint() * 2);
+
+ QWidget *contents = new QWidget(topcontents);
+ QHBoxLayout *lay = new QHBoxLayout(contents);
+
+ lay->setSpacing(KDialog::spacingHint() * 2);
+
+ lay->addStretch(1);
+ QLabel *label1 = new QLabel( contents);
+ label1->setPixmap(QMessageBox::standardIcon(QMessageBox::Information));
+ lay->add( label1 );
+ QLabel *label2 = new QLabel( text, contents);
+ label2->setMinimumSize(label2->sizeHint());
+ lay->add(label2);
+ lay->addStretch(1);
+
+ QSize extraSize = QSize(50, 30);
+
+ QCheckBox *checkbox = 0L;
+ if (!key.isEmpty())
+ {
+ checkbox = new QCheckBox(i18n("Do not ask again"),topcontents);
+ extraSize = QSize(50,0);
+ }
+
+ dialog->setMainWidget(topcontents);
+ dialog->enableButtonSeparator(false);
+ dialog->incInitialSize(extraSize);
+
+ r = dialog->exec();
+ if (checkbox)
+ {
+ checkboxReturn = checkbox->isChecked();
+ }
+#endif
+
+ switch(r)
+ {
+ case KDialogBase::Yes : result=KMessageBox::Yes ; break;
+ case KDialogBase::No : result=KMessageBox::No; break;
+ case KDialogBase::Cancel : result=KMessageBox::Cancel; break;
+ default : break;
+ }
+ stopTickle();
+
+ if (!key.isEmpty() && checkboxReturn)
+ {
+ KMessageBox::saveDontShowAgainYesNo(key,result);
+ }
+
+ return result;
+}
+
diff --git a/kpilot/lib/syncAction.h b/kpilot/lib/syncAction.h
new file mode 100644
index 000000000..a93bff99c
--- /dev/null
+++ b/kpilot/lib/syncAction.h
@@ -0,0 +1,410 @@
+#ifndef _KPILOT_SYNCACTION_H
+#define _KPILOT_SYNCACTION_H
+/* KPilot
+**
+** Copyright (C) 1998-2001 by Dan Pilone
+** Copyright (C) 2003-2004 Reinhold Kainhofer <[email protected]>
+** Copyright (C) 2006 Adriaan de Groot <[email protected]>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <time.h>
+
+#include <pi-dlp.h>
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include "kpilotlink.h"
+
+/** @file
+* SyncAction
+*/
+
+class QTimer;
+class KPilotUser;
+class SyncAction;
+
+class KDE_EXPORT SyncAction : public QObject
+{
+Q_OBJECT
+
+public:
+ SyncAction(KPilotLink *p,
+ const char *name=0L);
+ SyncAction(KPilotLink *p,
+ QWidget *visibleparent,
+ const char *name=0L);
+ ~SyncAction();
+
+ typedef enum { Error=-1 } Status;
+
+ /** A syncaction has a status, which can be expressed as an
+ * integer. Subclasses are expected to define their own status
+ * values as needed.
+ */
+ int status() const
+ {
+ return fActionStatus;
+ }
+ /** Return a human-readable representation of the status. */
+ virtual QString statusString() const;
+
+protected:
+ /**
+ * This function starts the actual processing done
+ * by the conduit. It should return false if the
+ * processing cannot be initiated, f.ex. because
+ * some parameters were not set or a needed library
+ * is missing. This will be reported to the user.
+ * It should return true if processing is started
+ * normally. If processing starts normally, it is
+ * the _conduit's_ responsibility to eventually
+ * emit syncDone(); if processing does not start
+ * normally (ie. exec() returns false) then the
+ * environment will deal with syncDone().
+ */
+ virtual bool exec() = 0;
+
+public slots:
+ /**
+ * This just calls exec() and deals with the
+ * return code.
+ */
+ void execConduit();
+
+signals:
+ void syncDone(SyncAction *);
+ void logMessage(const QString &);
+ void logError(const QString &);
+ void logProgress(const QString &,int);
+
+protected slots:
+ /** This slot emits syncDone(), and does nothing else. This
+ * is safe, since the method returns immediately after the
+ * emit -- even if syncDone() causes the SyncAction to be deleted.
+ */
+ void delayedDoneSlot();
+
+protected:
+ /**
+ * It might not be safe to emit syncDone() from exec().
+ * So instead, call delayDone() to wait for the main event
+ * loop to return if you manage to do all processing
+ * immediately.
+ *
+ * delayDone() returns true, so that return delayDone();
+ * is a sensible final statement in exec().
+ */
+ bool delayDone();
+
+public:
+ /** Public API for adding a sync log entry, see the implementation
+ * in KPilotLink::addSyncLogEntry().
+ * @param e Message to add to the sync log
+ * @param log If @c true, also add the entry to the log in KPilot
+ * @note Having messages appear on the handheld but not in KPilot
+ * should be a @em very rare occurrence.
+ */
+ void addSyncLogEntry(const QString &e,bool log=true)
+ {
+ if (deviceLink())
+ {
+ deviceLink()->addSyncLogEntry(e,log);
+ }
+ }
+ /** Public API for adding a message to the log in KPilot.
+ * Adds @p msg to the synclog maintained on the PC.
+ */
+ void addLogMessage( const QString &msg )
+ {
+ emit logMessage( msg );
+ }
+ /** Log an error message in KPilot (the PC side of things). */
+ void addLogError( const QString &msg )
+ {
+ emit logError( msg );
+ }
+ /** Log progress in KPilot (the PC side of things). */
+ void addLogProgress( const QString &msg, int prog )
+ {
+ emit logProgress( msg, prog );
+ }
+protected:
+ /** Connection to the device. @todo make private. */
+ KPilotLink *fHandle;
+ int fActionStatus;
+
+ /** Returns a pointer to the connection to the device. */
+ inline KPilotLink *deviceLink() const
+ {
+ return fHandle;
+ }
+
+ /** Returns the file descriptor for the device link -- that is,
+ * the raw handle to the OS's connection to the device. Use with care.
+ * May return -1 if there is no device.
+ */
+ int pilotSocket() const
+ {
+ return deviceLink() ? deviceLink()->pilotSocket() : -1 ;
+ }
+
+ /** Tells the handheld device that someone is talking to it now.
+ * Useful (repeatedly) to inform the user of what is going on.
+ * May return < 0 on error (or if there is no device attached).
+ */
+ int openConduit()
+ {
+ return deviceLink() ? deviceLink()->openConduit() : -1;
+ }
+public:
+ /**
+ * This class encapsulates the different sync modes that
+ * can be used, and enforces a little discipline in changing
+ * the mode and messing around in general. It replaces a
+ * simple enum by not much more, but it makes things like
+ * local test backups less likely to happen.
+ *
+ * Note that this could all be packed into a bitfield (5 bits needed)
+ * but that makes for messy code in the end.
+ */
+ class SyncMode
+ {
+ public:
+ /** Available modes for the sync. */
+ enum Mode {
+ eHotSync=1,
+ eFullSync=2,
+ eCopyPCToHH=3,
+ eCopyHHToPC=4,
+ eBackup=5,
+ eRestore=6
+ } ;
+
+ /** Create a mode with the given Mode @p m and
+ * the mix-ins @p test and @p local, which
+ * determine whether the sync should actually change
+ * anything at all (test mode) and whether the HH is
+ * to be simulated by local databases.
+ */
+ SyncMode(Mode m, bool test=false, bool local=false);
+
+ /** Create a mode by parsing the string list. This
+ * is used mostly by the conduit proxies, which use
+ * a string list to pass aparameters to the shared
+ * library loader.
+ */
+ SyncMode(const QStringList &l);
+
+ /** Returns the kind of sync; this is just incomplete
+ * information, since a test hot sync is very different from
+ * a non-test one. */
+ Mode mode() const
+ {
+ return fMode;
+ }
+
+ /** Sets a mode from an integer @p mode, if possible.
+ * If the @p mode is illegal, return false and set the
+ * mode to Hot Sync. As a side effect, options test and local
+ * are reset to false.
+ */
+ bool setMode(int);
+
+ /** Sets a mode from a @p mode, if possible. This leaves
+ * the options unchanged, so as to reward properly-typed programming.
+ */
+ bool setMode(Mode m);
+
+ /** Sets options. Returns false if the combination of mode
+ * and the options is impossible. */
+ bool setOptions(bool test, bool local)
+ {
+ fTest=test;
+ fLocal=local;
+ return true;
+ }
+
+ /** Shorthand to test for a specific mode enum. This disregards
+ * the mixings local and test.
+ */
+ bool operator ==(const Mode &m) const
+ {
+ return mode() == m;
+ }
+ /** Longhand comparison. Compares two modes for the same
+ * mode enum and mixins local and test.
+ */
+ bool operator ==(const SyncMode &m) const
+ {
+ return ( mode() == m.mode() ) &&
+ ( isTest() == m.isTest() ) &&
+ ( isLocal() == m.isLocal() );
+ } ;
+
+ /** Accessor for the test part of the mode. Test syncs should
+ * never actually modify data anywhere.
+ */
+ bool isTest() const
+ {
+ return fTest;
+ }
+
+ /** Accessor for the local part of the mode. Local syncs use a
+ * local database instead of one on the device link.
+ */
+ bool isLocal() const
+ {
+ return fLocal;
+ }
+
+ bool isFullSync() const
+ {
+ return ( fMode==eFullSync ) ||
+ ( fMode==eCopyPCToHH) ||
+ ( fMode==eCopyHHToPC) ;
+ } ;
+ bool isFirstSync() const
+ {
+ return ( fMode==eCopyHHToPC ) || ( fMode==eCopyPCToHH ) ;
+ };
+
+ /** Classify every mode as either a sync (two-way) or copy (one-way) mode. */
+ bool isSync() const
+ {
+ return ( fMode==eFullSync ) ||
+ ( fMode == eHotSync );
+ } ;
+
+ /** Classify every mode as either a sync (two-way) or copy (one-way) mode. */
+ bool isCopy() const
+ {
+ return ( fMode==eBackup ) ||
+ ( fMode==eRestore ) ||
+ ( fMode==eCopyPCToHH ) ||
+ ( fMode==eCopyHHToPC );
+ } ;
+
+ /**
+ * Returns a standard name for each of the sync modes.
+ */
+ static QString name(Mode);
+
+ /**
+ * Returns a (human readable) name for this particular mode,
+ * including extra information about test and local mode.
+ */
+ QString name() const;
+
+ /**
+ * Returns a QStringList that, when passed to the constructor
+ * of SyncMode, will re-create it. Used to pass modes into
+ * shared library factories.
+ */
+ QStringList list() const;
+
+ private:
+ Mode fMode;
+ bool fTest;
+ bool fLocal;
+ };
+
+
+ enum ConflictResolution
+ {
+ eUseGlobalSetting=-1,
+ eAskUser=0,
+ eDoNothing,
+ eHHOverrides,
+ ePCOverrides,
+ ePreviousSyncOverrides,
+ eDuplicate,
+ eDelete,
+ eCROffset=-1
+ };
+
+ /**
+ * This MUST stay in sync with the combobox in
+ * kpilotConfigDialog_backup.ui. If it does not, you need to
+ * either change this enum or the combobox.
+ */
+ enum BackupFrequency
+ {
+ eEveryHotSync=0,
+ eOnRequestOnly
+ };
+
+protected:
+ /**
+ * Call startTickle() some time before showing a dialog to the
+ * user (we're assuming a local event loop here) so that while
+ * the dialog is up and the user is thinking, the pilot stays
+ * awake. Afterwards, call stopTickle().
+ *
+ * The parameter to startTickle indicates the timeout, in
+ * seconds, before signal timeout is emitted. You can connect
+ * to that, again, to take down the user interface part if the
+ * user isn't reacting.
+ */
+ void startTickle(unsigned count=0);
+ void stopTickle();
+signals:
+ void timeout();
+
+
+
+
+protected:
+ QWidget *fParent;
+
+ /**
+ * Ask a yes-no question of the user. This has a timeout so that
+ * you don't wait forever for inattentive users. It's much like
+ * KMessageBox::questionYesNo(), but with this extra timeout-on-
+ * no-answer feature. Returns a KDialogBase::ButtonCode value - Yes,No or
+ * Cancel on timeout. If there is a key set and the user indicates not to ask again,
+ * the selected answer (Yes or No) is remembered for future reference.
+ *
+ * @p caption Message Box caption, uses "Question" if null.
+ * @p key Key for the "Don't ask again" code.
+ * @p timeout Timeout, in seconds.
+ */
+ int questionYesNo(const QString &question ,
+ const QString &caption = QString::null,
+ const QString &key = QString::null,
+ unsigned timeout = 20,
+ const QString &yes = QString::null,
+ const QString &no = QString::null );
+ int questionYesNoCancel(const QString &question ,
+ const QString &caption = QString::null,
+ const QString &key = QString::null,
+ unsigned timeout = 20,
+ const QString &yes = QString::null,
+ const QString &no = QString::null ) ;
+};
+
+
+#endif
diff --git a/kpilot/tests/CMakeLists.txt b/kpilot/tests/CMakeLists.txt
new file mode 100644
index 000000000..b38883c92
--- /dev/null
+++ b/kpilot/tests/CMakeLists.txt
@@ -0,0 +1,55 @@
+link_directories(${CMAKE_BINARY_DIR}/lib ${CMAKE_CURRENT_BINARY_DIR})
+include_directories(${CMAKE_SOURCE_DIR}/lib ${CMAKE_BINARY_DIR}/lib)
+
+# Tests don't need to go into toplevel/bin, they are fine in the current dir.
+set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
+
+# This can be used for finding data files in the source dir
+add_definitions( -DKDESRCDIR=\\"${CMAKE_CURRENT_SOURCE_DIR}\\" )
+
+
+set(testconstants_SRCS testconstants.cc)
+kde3_add_executable(testconstants ${testconstants_SRCS})
+target_link_libraries(testconstants kpilot ${QT_LIBRARIES})
+add_test(testconstants ${EXECUTABLE_OUTPUT_PATH}/testconstants)
+
+set(testcategories_SRCS testcategories.cc)
+kde3_add_executable(testcategories ${testcategories_SRCS})
+target_link_libraries(testcategories kpilot ${QT_LIBRARIES})
+add_test(testcategories ${EXECUTABLE_OUTPUT_PATH}/testcategories)
+
+set(testaddresses_SRCS testaddress.cc)
+kde3_add_executable(testaddresses ${testaddresses_SRCS})
+target_link_libraries(testaddresses kpilot ${QT_LIBRARIES})
+add_test(testaddresses ${EXECUTABLE_OUTPUT_PATH}/testaddresses)
+
+set(testdatebook_SRCS testdatebook.cc)
+kde3_add_executable(testdatebook ${testdatebook_SRCS})
+target_link_libraries(testdatebook kpilot ${QT_LIBRARIES})
+add_test(testdatebook ${EXECUTABLE_OUTPUT_PATH}/testdatebook)
+
+set(testidmapper_SRCS testidmapper.cc)
+kde3_add_executable(testidmapper ${testidmapper_SRCS})
+target_link_libraries(testidmapper kpilot ${QT_LIBRARIES})
+add_test(testidmapper ${EXECUTABLE_OUTPUT_PATH}/testidmapper)
+
+if (HAVE_CALENDARLOCAL_H)
+ set(importdatebook_SRCS importdatebook.cc)
+ set(exportdatebook_SRCS exportdatebook.cc)
+ set(mergecalendars_SRCS mergecalendars.cc)
+ kde3_add_executable(importdatebook ${importdatebook_SRCS})
+ kde3_add_executable(exportdatebook ${exportdatebook_SRCS})
+ kde3_add_executable(mergecalendars ${mergecalendars_SRCS})
+ target_link_libraries(importdatebook kpilot ${QT_LIBRARIES} kcal)
+ target_link_libraries(exportdatebook kpilot ${QT_LIBRARIES} kcal)
+ target_link_libraries(mergecalendars ${QT_LIBRARIES} kcal)
+ add_test(importdatebook ${EXECUTABLE_OUTPUT_PATH}/importdatebook)
+ add_test(exportdatebook ${EXECUTABLE_OUTPUT_PATH}/exportdatebook)
+ add_test(mergecalendars ${EXECUTABLE_OUTPUT_PATH}/mergecalendars)
+endif (HAVE_CALENDARLOCAL_H)
+
+set(importaddresses_SRCS importaddresses.cc)
+kde3_add_executable(importaddresses ${importaddresses_SRCS})
+target_link_libraries(importaddresses kpilot ${QT_LIBRARIES} kabc kabc_file)
+add_test(importaddresses ${EXECUTABLE_OUTPUT_PATH}/importaddresses)
+
diff --git a/kpilot/tests/conduits/vcalconduit/exampletest.cc b/kpilot/tests/conduits/vcalconduit/exampletest.cc
new file mode 100644
index 000000000..5d6ba40d5
--- /dev/null
+++ b/kpilot/tests/conduits/vcalconduit/exampletest.cc
@@ -0,0 +1,26 @@
+#include "options.h"
+#include "config.h"
+
+#include "exampletest.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION( VCalConduitTest );
+
+
+void VCalConduitTest::setUp()
+{
+ device = QString("testdevice");
+ link = new KPilotLocalLink(0, "localLink");
+ syncMode = SyncAction::SyncMode::eHotSync;
+}
+
+
+void VCalConduitTest::tearDown()
+{
+ delete link;
+}
+
+
+void VCalConduitTest::testConstructor()
+{
+ CPPUNIT_ASSERT( true == true );
+}
diff --git a/kpilot/tests/conduits/vcalconduit/exampletest.h b/kpilot/tests/conduits/vcalconduit/exampletest.h
new file mode 100644
index 000000000..137c31326
--- /dev/null
+++ b/kpilot/tests/conduits/vcalconduit/exampletest.h
@@ -0,0 +1,28 @@
+#ifndef EXAMPLETEST_H
+#define EXAMPLETEST_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <qstring.h>
+
+#include "kpilotlocallink.h"
+#include "syncAction.h"
+
+class VCalConduitTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE( VCalConduitTest );
+ CPPUNIT_TEST( testConstructor );
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ QString device;
+ KPilotLocalLink *link;
+ SyncAction::SyncMode::Mode syncMode;
+
+public:
+ void setUp();
+ void tearDown();
+
+ void testConstructor();
+};
+
+#endif
diff --git a/kpilot/tests/data/AddressDB.pdb b/kpilot/tests/data/AddressDB.pdb
new file mode 100644
index 000000000..cad6363b7
--- /dev/null
+++ b/kpilot/tests/data/AddressDB.pdb
Binary files differ
diff --git a/kpilot/tests/data/MailDB.pdb b/kpilot/tests/data/MailDB.pdb
new file mode 100644
index 000000000..33ca47372
--- /dev/null
+++ b/kpilot/tests/data/MailDB.pdb
Binary files differ
diff --git a/kpilot/tests/data/MemoDB.pdb b/kpilot/tests/data/MemoDB.pdb
new file mode 100644
index 000000000..94097b109
--- /dev/null
+++ b/kpilot/tests/data/MemoDB.pdb
Binary files differ
diff --git a/kpilot/tests/data/ToDoDB.pdb b/kpilot/tests/data/ToDoDB.pdb
new file mode 100644
index 000000000..fd4027f84
--- /dev/null
+++ b/kpilot/tests/data/ToDoDB.pdb
Binary files differ
diff --git a/kpilot/tests/data/bogus.pdb b/kpilot/tests/data/bogus.pdb
new file mode 100644
index 000000000..f90aef1d8
--- /dev/null
+++ b/kpilot/tests/data/bogus.pdb
@@ -0,0 +1,367 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2000 The KDE Project
+
+ unsetenv() taken from the GNU C Library.
+ Copyright (C) 1992,1995-1999,2000-2002 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include <config.h>
+
+#define KDE_open open
+#define KDE_mkdir mkdir
+
+#ifndef HAVE_SETENV
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int setenv(const char *name, const char *value, int overwrite) {
+ int i;
+ char * a;
+
+ if (!overwrite && getenv(name)) return 0;
+
+ i = strlen(name) + strlen(value) + 2;
+ a = (char*)malloc(i);
+ if (!a) return 1;
+
+ strcpy(a, name);
+ strcat(a, "=");
+ strcat(a, value);
+
+ return putenv(a);
+}
+#endif /* !HAVE_SETENV */
+
+#ifndef HAVE_UNSETENV
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#ifndef environ
+extern char ** environ;
+#endif
+
+ void unsetenv (name)
+ const char *name;
+{
+ size_t len;
+ char **ep;
+
+ if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
+ {
+ errno = EINVAL;
+ return;
+ }
+
+ len = strlen (name);
+
+ ep = environ;
+ while (*ep != NULL)
+ if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
+ {
+ /* Found it. Remove this pointer by moving later ones back. */
+ char **dp = ep;
+
+ do
+ dp[0] = dp[1];
+ while (*dp++);
+ /* Continue the loop in case NAME appears again. */
+ }
+ else
+ ++ep;
+
+}
+
+#endif /* !HAVE_UNSETENV */
+
+#ifndef HAVE_USLEEP
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if defined(HAVE_SYS_TIME_H)
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef __cplusplus /* this is supposed to be a C source file but still.. */
+extern "C" {
+#endif
+
+void usleep(unsigned int usec) {
+ struct timeval _usleep_tv;
+ _usleep_tv.tv_sec = usec/1000000;
+ _usleep_tv.tv_usec = usec%1000000;
+ select(0,0,0,0,&_usleep_tv);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !HAVE_USLEEP */
+
+#ifndef HAVE_RANDOM
+long int random()
+{
+ return lrand48();
+}
+
+void srandom(unsigned int seed)
+{
+ srand48(seed);
+}
+#endif
+
+#ifndef HAVE_SETEUID
+int seteuid(uid_t euid)
+{
+ setreuid(-1, euid); /* Well, if you have neither you are in trouble :) */
+}
+#endif
+
+#ifndef HAVE_MKSTEMPS
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+
+/* this is based on code taken from the GNU libc, distributed under the LGPL license */
+
+/* Generate a unique temporary file name from TEMPLATE.
+
+ TEMPLATE has the form:
+
+ <path>/ccXXXXXX<suffix>
+
+ SUFFIX_LEN tells us how long <suffix> is (it can be zero length).
+
+ The last six characters of TEMPLATE before <suffix> must be "XXXXXX";
+ they are replaced with a string that makes the filename unique.
+
+ Returns a file descriptor open on the file for reading and writing. */
+
+ int mkstemps (char* _template, int suffix_len)
+{
+ static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ char *XXXXXX;
+ int len;
+ int count;
+ int value;
+
+ len = strlen (_template);
+
+ if ((int) len < 6 + suffix_len || strncmp (&_template[len - 6 - suffix_len], "XXXXXX", 6))
+ return -1;
+
+ XXXXXX = &_template[len - 6 - suffix_len];
+
+ value = rand();
+ for (count = 0; count < 256; ++count)
+ {
+ int v = value;
+ int fd;
+
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % 62];
+ v /= 62;
+ XXXXXX[1] = letters[v % 62];
+ v /= 62;
+ XXXXXX[2] = letters[v % 62];
+ v /= 62;
+ XXXXXX[3] = letters[v % 62];
+ v /= 62;
+ XXXXXX[4] = letters[v % 62];
+ v /= 62;
+ XXXXXX[5] = letters[v % 62];
+
+ fd = KDE_open (_template, O_RDWR|O_CREAT|O_EXCL, 0600);
+ if (fd >= 0)
+ /* The file does not exist. */
+ return fd;
+
+ /* This is a random value. It is only necessary that the next
+ TMP_MAX values generated by adding 7777 to VALUE are different
+ with (module 2^32). */
+ value += 7777;
+ }
+ /* We return the null string if we can't find a unique file name. */
+ _template[0] = '\0';
+ return -1;
+}
+
+#endif /* !HAVE_MKSTEMPS */
+
+#ifndef HAVE_MKSTEMP
+ int mkstemp (char* _template)
+{
+ return mkstemps( _template, 0 );
+}
+#endif
+
+#ifndef HAVE_MKDTEMP
+
+#ifndef HAVE_MKSTEMPS
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#endif
+
+/* Generate a unique temporary directory name from TEMPLATE.
+
+ TEMPLATE has the form:
+
+ <path>/ccXXXXXX
+
+
+ The last six characters of TEMPLATE must be "XXXXXX";
+ they are replaced with a string that makes the filename unique.
+
+ Returns a file descriptor open on the file for reading and writing. */
+
+ char* mkdtemp (char* _template)
+{
+ static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ char *XXXXXX;
+ int len;
+ int count;
+ int value;
+
+ len = strlen (_template);
+
+ if ((int) len < 6 || strncmp (&_template[len - 6], "XXXXXX", 6))
+ return 0;
+
+ XXXXXX = &_template[len - 6];
+
+ value = rand();
+ for (count = 0; count < 256; ++count)
+ {
+ int v = value;
+
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % 62];
+ v /= 62;
+ XXXXXX[1] = letters[v % 62];
+ v /= 62;
+ XXXXXX[2] = letters[v % 62];
+ v /= 62;
+ XXXXXX[3] = letters[v % 62];
+ v /= 62;
+ XXXXXX[4] = letters[v % 62];
+ v /= 62;
+ XXXXXX[5] = letters[v % 62];
+
+ /* This is a random value. It is only necessary that the next
+ TMP_MAX values generated by adding 7777 to VALUE are different
+ with (module 2^32). */
+ value += 7777;
+
+ if (!KDE_mkdir(_template,0700))
+ return _template;
+ }
+ return 0;
+}
+#endif /* !HAVE_MKDTEMP */
+
+#ifndef HAVE_REVOKE
+#include <errno.h>
+#ifndef ENOTSUP
+#define ENOTSUP 134 /* Not supported */
+#endif
+ int revoke(const char *tty)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+#endif
+
+#ifndef HAVE_STRLCPY
+ unsigned long strlcpy(char* d, const char* s, unsigned long bufsize)
+{
+ unsigned long len, ret = strlen(s);
+
+ if (ret >= bufsize) {
+ if (bufsize) {
+ len = bufsize - 1;
+ memcpy(d, s, len);
+ d[len] = '\0';
+ }
+ } else
+ memcpy(d, s, ret + 1);
+
+ return ret;
+}
+#endif
+
+#ifndef HAVE_STRLCAT
+ unsigned long strlcat(char* d, const char* s, unsigned long bufsize)
+{
+ char *cp;
+ unsigned long ret, len1, len2 = strlen(s);
+
+ cp = (char *)memchr (d, '\0', bufsize);
+ if (!cp)
+ return bufsize + len2;
+ len1 = cp - d;
+ ret = len1 + len2;
+ if (ret >= bufsize) {
+ len2 = bufsize - len1 - 1;
+ memcpy(cp, s, len2);
+ cp[len2] = '\0';
+ } else
+ memcpy(cp, s, len2 + 1);
+
+ return ret;
+}
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
diff --git a/kpilot/tests/exportdatebook.cc b/kpilot/tests/exportdatebook.cc
new file mode 100644
index 000000000..fcc236cca
--- /dev/null
+++ b/kpilot/tests/exportdatebook.cc
@@ -0,0 +1,136 @@
+/* testaddresses KPilot
+**
+** Copyright (C) 2007 by Jason 'vanRijn' Kasper <[email protected])
+**
+** Test the functions related to address database handling.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <kconfigskeleton.h>
+
+#include <libkcal/calendar.h>
+#include <libkcal/calendarlocal.h>
+
+#include "pilot.h"
+#include "pilotDateEntry.h"
+#include "pilotLocalDatabase.h"
+#include "../conduits/vcalconduit/kcalRecord.cc"
+#include "../conduits/vcalconduit/vcalRecord.cc"
+
+static const KCmdLineOptions options[] =
+{
+ {"verbose", "Verbose output", 0},
+ {"data-dir <path>","Set data directory", "."},
+ {"vcal-file <path>","Set vcal file", 0},
+ KCmdLineLastOption
+};
+
+
+
+int main(int argc, char **argv)
+{
+ FUNCTIONSETUP;
+
+ KApplication::disableAutoDcopRegistration();
+
+ KAboutData aboutData("exportdatebook","Emport Date Book","0.1");
+ KCmdLineArgs::init(argc,argv,&aboutData);
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication app( false, false );
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ debug_level= (args->isSet("verbose")) ? 4 : 0;
+
+ QString datadir = args->getOption("data-dir");
+ QString vcalfile = args->getOption("vcal-file");
+
+ if (datadir.isEmpty())
+ {
+ WARNINGKPILOT << "! Must provide a data-directory." << endl;
+ }
+ if (vcalfile.isEmpty())
+ {
+ WARNINGKPILOT << "! Must provide a vcal-file to write to." << endl;
+ }
+ if (datadir.isEmpty() || vcalfile.isEmpty())
+ {
+ return 1;
+ }
+
+ /*
+ KConfig korgcfg( locate( "config", CSL1("korganizerrc") ) );
+
+ // this part taken from adcalendarbase.cpp:
+ korgcfg.setGroup( "Time & Date" );
+ QString tz(korgcfg.readEntry( "TimeZoneId" ) );
+
+ DEBUGKPILOT << fname << ": KOrganizer's time zone = " << tz << endl;
+
+ KCal::CalendarLocal *calendar = new KCal::CalendarLocal( tz );
+ */
+ KCal::CalendarLocal *calendar = new KCal::CalendarLocal( QString() );
+
+ if (!calendar)
+ {
+ WARNINGKPILOT << "! Can't create calendar object." << endl;
+ return 1;
+ }
+
+ Pilot::setupPilotCodec( CSL1("Latin1") );
+
+ PilotLocalDatabase db( datadir, "DatebookDB" );
+
+ PilotDateInfo *fAppointmentAppInfo = new PilotDateInfo( &db );
+
+ int currentRecord = 0;
+ PilotRecord *pilotRec = 0;
+ PilotDateEntry *d = 0;
+
+ while ((pilotRec = db.readRecordByIndex(currentRecord++)) != NULL)
+ {
+ d = new PilotDateEntry(pilotRec);
+
+ KCal::Event*event = new KCal::Event;
+
+ KCalSync::setEvent(event, d,*fAppointmentAppInfo->categoryInfo());
+
+ event->setSyncStatus( KCal::Incidence::SYNCNONE );
+
+ calendar->addEvent(event);
+
+ }
+
+ calendar->save(vcalfile);
+
+ return 0;
+}
+
diff --git a/kpilot/tests/importaddresses.cc b/kpilot/tests/importaddresses.cc
new file mode 100644
index 000000000..34250b2c1
--- /dev/null
+++ b/kpilot/tests/importaddresses.cc
@@ -0,0 +1,128 @@
+/* importaddresses KPilot
+**
+** Copyright (C) 2006 by Adriaan de Groot <[email protected])
+**
+** Create an address database (for the handheld) from PC data.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+
+#include <kabc/addressbook.h>
+#include <kabc/resourcefile.h>
+
+#include "pilot.h"
+#include "pilotLocalDatabase.h"
+#include "pilotAddress.h"
+#include "../conduits/abbrowserconduit/kabcRecord.h"
+#include "../conduits/abbrowserconduit/kabcRecord.cc"
+
+static const KCmdLineOptions options[] =
+{
+ {"verbose", "Verbose output", 0},
+ {"data-dir <path>","Set data directory", "."},
+ {"address-file <path>","Set addressbook file", 0},
+ KCmdLineLastOption
+};
+
+
+
+int main(int argc, char **argv)
+{
+ KAboutData aboutData("importaddresses","Import Address Book","0.1");
+ KCmdLineArgs::init(argc,argv,&aboutData);
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ // KApplication app( false, false );
+ KApplication app;
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+#ifdef DEBUG
+ debug_level= (args->isSet("verbose")) ? 4 : 0;
+#endif
+ QString datadir = args->getOption("data-dir");
+ QString addressfile = args->getOption("address-file");
+
+ if (datadir.isEmpty())
+ {
+ kdWarning() << "! Must provide a data-directory." << endl;
+ }
+ if (addressfile.isEmpty())
+ {
+ kdWarning() << "! Must provide an address-file to read." << endl;
+ }
+ if (datadir.isEmpty() || addressfile.isEmpty())
+ {
+ return 1;
+ }
+
+ KABC::ResourceFile *file = new KABC::ResourceFile( addressfile );
+ KABC::AddressBook book;
+ book.addResource( file );
+ if (!book.load())
+ {
+ kdWarning() << "! Failed to load the address-file <" << addressfile << ">" << endl;
+ return 1;
+ }
+
+ Pilot::setupPilotCodec( CSL1("Latin1") );
+
+ PilotLocalDatabase db( datadir, "AddressDB" );
+ db.createDatabase( 0xdead, 0xbeef );
+ PilotAddressInfo info(0L);
+ info.resetToDefault();
+ info.writeTo(&db);
+
+ KABCSync::Settings settings;
+
+ kdDebug() << "# Printing address book." << endl;
+ unsigned int count = 1;
+ KABC::AddressBook::ConstIterator it = book.begin();
+ while (it != book.end())
+ {
+ const KABC::Addressee &a = *it;
+ kdDebug() << "# Entry #" << count << endl;
+ kdDebug() << "# " << a.name() << endl;
+ kdDebug() << "# " << a.formattedName() << endl;
+ PilotAddress *p = new PilotAddress();
+ KABCSync::copy(*p,a,info,settings);
+ PilotRecord *r = p->pack();
+ if (r)
+ {
+ db.writeRecord(r);
+ delete r;
+ }
+ delete p;
+ ++it;
+ ++count;
+ }
+
+ return 0;
+}
diff --git a/kpilot/tests/importdatebook.cc b/kpilot/tests/importdatebook.cc
new file mode 100644
index 000000000..b7a66080d
--- /dev/null
+++ b/kpilot/tests/importdatebook.cc
@@ -0,0 +1,131 @@
+/* testaddresses KPilot
+**
+** Copyright (C) 2006 by Adriaan de Groot <[email protected])
+**
+** Test the functions related to address database handling.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+
+#include <libkcal/calendar.h>
+#include <libkcal/calendarlocal.h>
+
+#include "pilot.h"
+#include "pilotDateEntry.h"
+#include "pilotLocalDatabase.h"
+#include "../conduits/vcalconduit/kcalRecord.cc"
+#include "../conduits/vcalconduit/vcalRecord.cc"
+
+static const KCmdLineOptions options[] =
+{
+ {"verbose", "Verbose output", 0},
+ {"data-dir <path>","Set data directory", "."},
+ {"vcal-file <path>","Set vcal file", 0},
+ KCmdLineLastOption
+};
+
+
+
+int main(int argc, char **argv)
+{
+ KApplication::disableAutoDcopRegistration();
+
+ KAboutData aboutData("importdatebook","Import Date Book","0.1");
+ KCmdLineArgs::init(argc,argv,&aboutData);
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication app( false, false );
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ debug_level= (args->isSet("verbose")) ? 4 : 0;
+
+ QString datadir = args->getOption("data-dir");
+ QString vcalfile = args->getOption("vcal-file");
+
+ if (datadir.isEmpty())
+ {
+ WARNINGKPILOT << "! Must provide a data-directory." << endl;
+ }
+ if (vcalfile.isEmpty())
+ {
+ WARNINGKPILOT << "! Must provide a vcal-file to read." << endl;
+ }
+ if (datadir.isEmpty() || vcalfile.isEmpty())
+ {
+ return 1;
+ }
+
+ DEBUGKPILOT << "Using vcal-file: [" << vcalfile
+ << "], creating DatebookDB in: [" << datadir
+ << "]" << endl;
+
+ KCal::CalendarLocal *calendar = new KCal::CalendarLocal( QString::fromLatin1("UTC") );
+ if (!calendar || !calendar->load( vcalfile ))
+ {
+ return 1;
+ }
+
+ DEBUGKPILOT << "Opened calendar with: ["
+ << calendar->incidences().count() << "] incidences." << endl;
+
+ Pilot::setupPilotCodec( CSL1("Latin1") );
+
+ PilotLocalDatabase db( datadir, "DatebookDB" );
+ db.createDatabase( 0xdead, 0xbeef );
+ PilotDateInfo appInfo(0L);
+ appInfo.resetToDefault();
+ appInfo.writeTo(&db);
+
+ KCal::Event::List events = calendar->events();
+
+ for (KCal::Event::List::ConstIterator i = events.begin();
+ i != events.end(); ++i)
+ {
+ PilotDateEntry * d = new PilotDateEntry();
+
+ const KCal::Event *e = *i;
+ DEBUGKPILOT << "event: [" << e->summary() << "]" << endl;
+
+ if (KCalSync::setDateEntry(d,e,*appInfo.categoryInfo()))
+ {
+DEBUGKPILOT << "got here." << endl;
+ PilotRecord *r = d->pack();
+ if (r)
+ {
+ db.writeRecord(r);
+ delete r;
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/kpilot/tests/main.cc b/kpilot/tests/main.cc
new file mode 100644
index 000000000..c6ddd23c9
--- /dev/null
+++ b/kpilot/tests/main.cc
@@ -0,0 +1,17 @@
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+
+int main( int argc, char **argv)
+{
+ CppUnit::TestFactoryRegistry &registry =
+ CppUnit::TestFactoryRegistry::getRegistry();
+
+ CppUnit::TextUi::TestRunner runner;
+ runner.addTest( registry.makeTest() );
+
+ // Run the tests.
+ bool wasSucessful = runner.run();
+
+ // Return error code 1 if the one of test failed.
+ return wasSucessful ? 0 : 1;
+}
diff --git a/kpilot/tests/mergecalendars.cc b/kpilot/tests/mergecalendars.cc
new file mode 100644
index 000000000..221da26b0
--- /dev/null
+++ b/kpilot/tests/mergecalendars.cc
@@ -0,0 +1,228 @@
+/* mergecalendars KPilot
+**
+** Copyright (C) 2007 by Jason 'vanRijn' Kasper <[email protected])
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <kconfigskeleton.h>
+
+#include <libkcal/calendar.h>
+#include <libkcal/calendarlocal.h>
+
+#include "options.h"
+
+static const KCmdLineOptions options[] =
+{
+ {"korgfile <path>","KOrganizer master file", 0},
+ {"newfile <path>","Calendar file to merge into korganizer", 0},
+ {"category <string>","Category to remove from 'korgfile' and to add to events in 'newfile' for synch purposes", 0},
+ {"verbose", "Verbose debugging", 0},
+ KCmdLineLastOption
+};
+
+
+
+int main(int argc, char **argv)
+{
+
+ KApplication::disableAutoDcopRegistration();
+
+ KAboutData aboutData("mergecalendars","Merge libkcal Calendars","0.1");
+ KCmdLineArgs::init(argc,argv,&aboutData);
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication app( false, false );
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ int debug_level= (args->isSet("verbose")) ? 4 : 0;
+
+ QString korgfile = args->getOption("korgfile");
+ QString newfile = args->getOption("newfile");
+ QString category = args->getOption("category");
+
+ if (korgfile.isEmpty())
+ {
+ WARNINGKPILOT << "! Must provide a korganizer file." << endl;
+ }
+ if (newfile.isEmpty())
+ {
+ WARNINGKPILOT << "! Must provide a newfile file." << endl;
+ }
+ if (category.isEmpty())
+ {
+ WARNINGKPILOT << "! Must provide a category to use." << endl;
+ }
+ if (korgfile.isEmpty() || newfile.isEmpty() || category.isEmpty())
+ {
+ return 1;
+ }
+
+ QString korgsave = QString("%1.updated").arg(korgfile);
+ QString newfilesave = QString("%1.updated").arg(newfile);
+
+ DEBUGKPILOT << "Using korgfile: [" << korgfile
+ << "]" << endl;
+ DEBUGKPILOT << "Using newfile: [" << newfile
+ << "]" << endl;
+ DEBUGKPILOT << "Will save korgfile to: [" << korgsave
+ << "]" << endl;
+ DEBUGKPILOT << "Will save newfile to: [" << newfilesave
+ << "]" << endl << endl;
+
+ KCal::CalendarLocal *calkorg = new KCal::CalendarLocal( QString::fromLatin1("UTC") );
+ KCal::CalendarLocal *calnew = new KCal::CalendarLocal( QString::fromLatin1("UTC") );
+ if (!calkorg || !calnew)
+ {
+ WARNINGKPILOT << "Unable to create base calendar objects." << endl;
+ return 1;
+ }
+
+ if (!calkorg->load(korgfile) || !calnew->load(newfile))
+ {
+ WARNINGKPILOT << "Unable to load calendar files." << endl;
+ return 1;
+ }
+
+ int numkorgstart = calkorg->incidences().count();
+ int numnewstart = calnew->incidences().count();
+
+ DEBUGKPILOT << " - Opened korganizer calendar with: ["
+ << numkorgstart << "] incidences." << endl;
+ DEBUGKPILOT << " - Opened newfile calendar with: ["
+ << numnewstart << "] incidences." << endl;
+
+ KCal::Event::List korgEvents;
+ KCal::Event::List::ConstIterator korgIt;
+ korgEvents = calkorg->events();
+ korgEvents.setAutoDelete(false);
+
+ KCal::Event::List newEvents;
+ KCal::Event::List::ConstIterator newIt;
+ newEvents = calnew->events();
+ newEvents.setAutoDelete(false);
+
+ DEBUGKPILOT << "Looking for previous pilot ids for exchange events..." << endl;
+
+ // iterate through all events and try to find a korganizer event
+ // that matches up with this external event's UID
+ unsigned int numkorgpilotids = 0;
+ KCal::Event *ev = 0;
+ for (newIt = newEvents.begin(); newIt != newEvents.end(); ++newIt )
+ {
+ ev = *newIt;
+ QString uid = ev->uid();
+ if (debug_level)
+ DEBUGKPILOT << " - Looking at event: ["
+ << ev->summary() << "], uid: ["
+ << uid << "]" << endl;
+
+ KCal::Event * evkorg = calkorg->event(uid);
+ if ( evkorg && (evkorg->pilotId() > 0) )
+ {
+ unsigned long pilotId = evkorg->pilotId();
+
+ if (debug_level)
+ DEBUGKPILOT << "Found korg event for uid: ["
+ << uid << "], pilotId: ["
+ << pilotId << "]" << endl;
+
+ ev->setPilotId(pilotId);
+ ev->setSyncStatus(KCal::Incidence::SYNCMOD);
+
+ ++numkorgpilotids;
+ }
+ }
+
+ DEBUGKPILOT << "Matched: [" << numkorgpilotids << "] events."<< endl;
+
+ DEBUGKPILOT << "Now searching for previous events of category: [" << category << "] in korganizer's calendar." << endl;
+
+ // iterate through all events and try to find a korganizer event
+ // that matches up with this external event's UID
+ unsigned int numkorgremoved = 0;
+
+ QString categoryToken = category;
+
+ // careful iterating and removing...
+ KCal::Event *next = 0;
+
+ korgIt = korgEvents.begin();
+ for ( ev = *korgIt; ev != 0; ev = next )
+ {
+ if (++korgIt == korgEvents.end())
+ {
+ next = 0;
+ }
+ else
+ {
+ next = *korgIt;
+ }
+
+ if (ev->categoriesStr().contains(categoryToken))
+ {
+ if (debug_level)
+ DEBUGKPILOT << " - Found matching event: ["
+ << ev->summary() << "], uid: ["
+ << ev->uid() << "]. Removing." << endl;
+
+ korgEvents.remove(ev);
+ calkorg->deleteEvent(ev);
+
+ ++numkorgremoved;
+ }
+ }
+
+ DEBUGKPILOT << " - Found: [" << numkorgremoved
+ << "] prior: [" << categoryToken
+ << "] category events." << endl;
+
+ DEBUGKPILOT << "Merging new events into korganizer calendar..."
+ << endl;
+
+ for (newIt = newEvents.begin(); newIt != newEvents.end(); ++newIt )
+ {
+ ev = *newIt;
+ ev->setCategories(category);
+ korgEvents.append(ev);
+ calkorg->addEvent(ev);
+ }
+
+ DEBUGKPILOT << "Ended up with: [" << korgEvents.count()
+ << "] events in korganizer calendar." << endl;
+
+ DEBUGKPILOT << "Saving updated korganizer file..." << endl;
+ calkorg->save(korgsave);
+
+ DEBUGKPILOT << "Saving updated newfile file..." << endl;
+ calnew->save(newfilesave);
+
+ return 0;
+}
+
diff --git a/kpilot/tests/testactions.cc b/kpilot/tests/testactions.cc
new file mode 100644
index 000000000..51cb23685
--- /dev/null
+++ b/kpilot/tests/testactions.cc
@@ -0,0 +1,92 @@
+/* testactions KPilot
+**
+** Copyright (C) 2005 by Adriaan de Groot <[email protected])
+**
+** Test the functions related to sync actions.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+#include "syncAction.h"
+
+bool run_modes(bool test, bool local)
+{
+ bool ok = true;
+
+ kdDebug() << "***\n*** Sync Modes ("
+ << ( test ? "" : "no")
+ << "test, "
+ << ( local ? "" : "no")
+ << "local)\n***\n";
+
+
+ for (int m = (int)SyncAction::SyncMode::eHotSync;
+ m <= (int) SyncAction::SyncMode::eRestore ;
+ m++)
+ {
+ SyncAction::SyncMode mode((SyncAction::SyncMode::Mode)m,test,local);
+ kdDebug() << "* " << mode.name() << endl;
+ SyncAction::SyncMode mode2(mode.list());
+ if (!(mode==mode2)) {
+ kdDebug() << "E " << "Modes mismatch [" << mode.name() << "] ["
+ << mode2.name() << "]" << endl;
+ ok = false;
+ }
+ }
+
+ return ok;
+}
+
+bool single_mode(int m, bool test, bool local)
+{
+ SyncAction::SyncMode mode((SyncAction::SyncMode::Mode)m,test,local);
+
+ kdDebug() << "* " << m << " " << test << " " << local << endl;
+
+ if ((mode.mode() == m) && (mode.isTest() == test) && (mode.isLocal() == local))
+ {
+ return true;
+ }
+ else
+ {
+ kdDebug() << "E " << "Modes mismatch " << m << " " << test << " " << local
+ << "[" << mode.name() << "]" << endl;
+ return false;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ if (!run_modes(false,false)) return 1;
+ if (!run_modes(false,true)) return 1;
+ if (!run_modes(true,false)) return 1;
+ if (!run_modes(true,true)) return 1;
+
+ kdDebug() << "***\n*** Sync Modes - misc\n***\n";
+ if (!single_mode(3,false,false)) return 1;
+ if (!single_mode(1,true,true)) return 1;
+
+ return 0;
+}
+
+
diff --git a/kpilot/tests/testaddress.cc b/kpilot/tests/testaddress.cc
new file mode 100644
index 000000000..0919b8c0e
--- /dev/null
+++ b/kpilot/tests/testaddress.cc
@@ -0,0 +1,106 @@
+/* testaddresses KPilot
+**
+** Copyright (C) 2006 by Adriaan de Groot <[email protected])
+**
+** Test the functions related to address database handling.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+
+#include "pilot.h"
+#include "pilotAddress.h"
+#include "pilotLocalDatabase.h"
+
+static const KCmdLineOptions options[] =
+{
+ {"verbose", "Verbose output", 0},
+ {"data-dir <path>","Set data directory", "."},
+ KCmdLineLastOption
+};
+
+
+
+int main(int argc, char **argv)
+{
+ KApplication::disableAutoDcopRegistration();
+
+ KAboutData aboutData("testaddress","Test Addresses","0.1");
+ KCmdLineArgs::init(argc,argv,&aboutData);
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication app( false, false );
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+#ifdef DEBUG
+ debug_level= (args->isSet("verbose")) ? 4 : 0;
+#endif
+ QString datadir = args->getOption("data-dir");
+
+ DEBUGKPILOT << "### testaddresses\n#\n#" << endl;
+
+ Pilot::setupPilotCodec( CSL1("Latin1") );
+
+ PilotLocalDatabase db( datadir, "AddressDB" );
+ PilotAddressInfo appinfo( &db );
+
+ appinfo.dump();
+
+ for (unsigned int i=0; i<db.recordCount(); ++i)
+ {
+ PilotRecord *r = db.readRecordByIndex( i );
+
+ if (r)
+ {
+ DEBUGKPILOT << "# Record @" << (void *)r << " ID=" << r->id() << endl;
+ PilotAddress a( r );
+ DEBUGKPILOT << "# Text Representation:" << endl << a.getTextRepresentation(&appinfo,Qt::PlainText) << endl;
+ DEBUGKPILOT << "# Category#" << a.category() << endl;
+ DEBUGKPILOT << "# Category Label " << appinfo.categoryName(a.category()) << endl;
+ DEBUGKPILOT << "# ID " << a.id() << endl;
+
+ // With the given address database, where all the
+ // categories are already filled, this should fail
+ // (and give a useful error message).
+ //
+ a.setCategory( appinfo.findCategory(CSL1("Fake Cat")) );
+ DEBUGKPILOT << "# Category#" << a.category() << endl;
+ DEBUGKPILOT << "# Category Label " << appinfo.categoryName(a.category()) << endl;
+ // This category exists, so it should succeed
+ //
+ a.setCategory( appinfo.findCategory(CSL1("Business")) );
+ DEBUGKPILOT << "# Category#" << a.category() << endl;
+ DEBUGKPILOT << "# Category Label " << appinfo.categoryName(a.category()) << endl;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/kpilot/tests/testcategories.cc b/kpilot/tests/testcategories.cc
new file mode 100644
index 000000000..1ecfebf66
--- /dev/null
+++ b/kpilot/tests/testcategories.cc
@@ -0,0 +1,215 @@
+/* testcategories KPilot
+**
+** Copyright (C) 2005 by Adriaan de Groot <[email protected])
+**
+** Test the functions related to category handling.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+
+#include "pilotLocalDatabase.h"
+#include "pilotRecord.h"
+#include "pilotAppInfo.h"
+
+// Name of a bogus broken DB
+#define BOGUS_NAME "bogus"
+
+// Name of an actual DB
+#define MEMO_NAME "MemoDB"
+
+QStringList categories( const PilotAppInfoBase *appinfo )
+{
+ QStringList cats;
+
+ for (unsigned int i=0; i<Pilot::CATEGORY_COUNT; i++)
+ {
+ QString cat = appinfo->categoryName(i);
+ if (!cat.isEmpty())
+ {
+ QString s = CSL1("(%1:%2)").arg(i).arg(cat);
+ cats.append(s);
+ }
+ }
+
+ return cats;
+}
+
+QStringList listCategories( const QString &dir, const char *dbname )
+{
+ QStringList cats;
+ PilotLocalDatabase *database = new PilotLocalDatabase( dir, dbname );
+ if (!database->isOpen()) return cats;
+
+ PilotAppInfoBase *appinfo = new PilotAppInfoBase( database );
+ appinfo->dump();
+
+ cats = categories( appinfo );
+
+ delete appinfo;
+ delete database;
+ return cats;
+}
+
+void badAppInfoCreation()
+{
+ FUNCTIONSETUP;
+ PilotAppInfoBase *appinfo = new PilotAppInfoBase( 0L );
+ appinfo->dump();
+ KPILOT_DELETE( appinfo ) ;
+
+ PilotLocalDatabase *database = new PilotLocalDatabase( BOGUS_NAME );
+ appinfo = new PilotAppInfoBase( database );
+ appinfo->dump();
+ KPILOT_DELETE( appinfo );
+}
+
+void categoryNames( const QString &dir )
+{
+ PilotLocalDatabase *database = new PilotLocalDatabase( dir, MEMO_NAME );
+ if (!database->isOpen())
+ {
+ WARNINGKPILOT << "Can not open database '" << MEMO_NAME << "'" << endl;
+ return;
+ }
+
+ PilotAppInfoBase *appinfo = new PilotAppInfoBase( database );
+ appinfo->dump();
+
+ DEBUGKPILOT << "# Done dumping" << endl;
+
+ if (!appinfo->categoryInfo())
+ {
+ WARNINGKPILOT << "Could not read required database" << endl;
+ return;
+ }
+
+ const char *funnyname = "OneTwoThreeFourFiveSixSevenEight";
+ const int funnyname_length = strlen(funnyname);
+
+ if (funnyname_length < 20)
+ {
+ WARNINGKPILOT << "String of example category names is too short." << endl;
+ return;
+ }
+
+ DEBUGKPILOT << "# Updating category names with various lengths." << endl;
+ DEBUGKPILOT << "# Expect three truncation errors and two bad category numbers." << endl;
+ for (unsigned int i=0; i<Pilot::CATEGORY_COUNT+2; i++)
+ {
+ QString name = QString::fromLatin1(funnyname+funnyname_length-i-3);
+ if (!appinfo->setCategoryName(i,name))
+ {
+ WARNINGKPILOT << "Failed to set category " << i << " name to <" << name << ">" << endl;
+ }
+ else
+ {
+ QString categoryname = appinfo->categoryName(i);
+ if (categoryname != name)
+ {
+ WARNINGKPILOT << "Category name " << i
+ << " set to <" << name
+ << "> and returns <"
+ << categoryname << ">" << endl;
+ }
+ }
+ }
+
+ DEBUGKPILOT << "# Final categories\n# " << categories( appinfo ).join("\n# ") << endl;
+}
+
+static const KCmdLineOptions options[] =
+{
+ {"verbose", "Verbose output", 0},
+ {"data-dir <path>","Set data directory", "."},
+ KCmdLineLastOption
+};
+
+
+int main(int argc, char **argv)
+{
+ KApplication::disableAutoDcopRegistration();
+
+ KAboutData aboutData("testcategories","Test Categories","0.1");
+ KCmdLineArgs::init(argc,argv,&aboutData);
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication app( false, false );
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+#ifdef DEBUG
+ debug_level= (args->isSet("verbose")) ? 4 : 0;
+#endif
+
+ Q_UNUSED(argc);
+ Q_UNUSED(argv);
+
+ static const char *files[] = {
+ MEMO_NAME,
+ "AddressDB",
+ "MailDB",
+ "ToDoDB",
+ 0L
+ };
+
+ QString datadir = args->getOption("data-dir");
+
+ DEBUGKPILOT << "### testcategories\n#\n#" << endl;
+ DEBUGKPILOT << "# Listing categories from database files.\n#" << endl;
+
+ Pilot::setupPilotCodec( CSL1("Latin1") );
+
+ // Include arbitrary break-off point, in case
+ for (unsigned int i = 0; i<sizeof(files)/sizeof(const char *) ; i++)
+ {
+ if (!files[i])
+ {
+ break;
+ }
+ DEBUGKPILOT << "# Categories (" << files[i] << "): " << endl;
+ DEBUGKPILOT << "# " << listCategories( datadir, files[i] ).join("\n# ") << "\n#\n";
+ }
+ // Should bail, not crash
+ DEBUGKPILOT << "# Categories (nonexistent): " << endl;
+ (void) listCategories( datadir, "nonexistent" );
+
+ DEBUGKPILOT << "# Categories (bogus): " << endl;
+ (void) listCategories( datadir, BOGUS_NAME );
+
+ DEBUGKPILOT << "#\n# Trying to pass broken pointers to category functions.\n# Four errors are expected.\n#" << endl;
+ badAppInfoCreation();
+
+ DEBUGKPILOT << "#\n# Checking category names." << endl;
+ categoryNames( datadir );
+
+ DEBUGKPILOT << "# OK.\n" << endl;
+ return 0;
+}
+
diff --git a/kpilot/tests/testconstants.cc b/kpilot/tests/testconstants.cc
new file mode 100644
index 000000000..06e9fafa8
--- /dev/null
+++ b/kpilot/tests/testconstants.cc
@@ -0,0 +1,68 @@
+/* testconstants KPilot
+**
+** Copyright (C) 2005 by Adriaan de Groot <[email protected])
+**
+** Checks that various data structures are sized properly.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include "pilot.h"
+#include "pilotAppInfo.h"
+
+#include <pi-appinfo.h>
+
+int main(int, char **)
+{
+#ifdef DEBUG
+ debug_level = 1;
+#endif
+ PilotAppInfoBase info;
+
+
+ DEBUGKPILOT << "### testconstants\n#" << endl;
+ DEBUGKPILOT << "# Sizes of structures\n#" << endl;
+ DEBUGKPILOT << "# AppInfoBase: " << sizeof(PilotAppInfoBase) << endl;
+ DEBUGKPILOT << "# CategoryInfo: " << sizeof(info.categoryInfo()) << endl;
+ DEBUGKPILOT << "# CategoryInfo: " << sizeof(*info.categoryInfo()) << endl;
+ DEBUGKPILOT << "# Category names: " << sizeof(info.categoryInfo()->name) << endl;
+ DEBUGKPILOT << "# Single category: " << sizeof(info.categoryInfo()->name[0]) << endl;
+
+ DEBUGKPILOT << "#\n# Sanity checking structure sizes\n#" << endl;
+ if ( sizeof(info.categoryInfo()->name[0]) != Pilot::CATEGORY_SIZE )
+ {
+ WARNINGKPILOT << "! Category names are not 16 bytes." << endl;
+ return 1;
+ }
+ if ( sizeof(info.categoryInfo()->name) / sizeof(info.categoryInfo()->name[0]) != Pilot::CATEGORY_COUNT )
+ {
+ WARNINGKPILOT << "! There are not " << Pilot::CATEGORY_COUNT << " categories available." << endl;
+ return 1;
+ }
+
+ DEBUGKPILOT << "# OK.\n" << endl;
+ return 0;
+}
+
+
diff --git a/kpilot/tests/testdatabase.cc b/kpilot/tests/testdatabase.cc
new file mode 100644
index 000000000..b1a4ddbe0
--- /dev/null
+++ b/kpilot/tests/testdatabase.cc
@@ -0,0 +1,316 @@
+/* testdatabase KPilot
+**
+** Copyright (C) 2005 by Adriaan de Groot <[email protected])
+**
+** Test the functions related to local databases.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+
+#include "pilotLocalDatabase.h"
+#include "pilotRecord.h"
+#include "pilotMemo.h"
+
+
+/* Return values for the various check* functions. They
+ return OK if all is OK; ERR is for generic errors.
+ ERR_NO_EXIST is returned if something (usually a database
+ or other file) doesn't exist that should. The latter
+ error might be ignored.
+*/
+#define OK (0)
+#define ERR (1)
+#define ERR_NO_EXIST (2)
+
+
+/* Data about the records in a database. The id field is
+ interpreted specially for the first and last entries.
+*/
+typedef struct { int id,size; } recordInfo;
+
+/* Use END in the last recordInfo struct describing a database
+ to indicate you expect the database to end there. Use NO_EXIST
+ as the ID in the first struct to indicate that the database
+ is expected _not_ to exist.
+*/
+#define NO_EXIST (-2)
+#define END (-1)
+
+/* These tables of data are taken from various databases I have
+ (but which I cannot commit to SVN due to license issues).
+ The aesop listing is from an eBook of Aesop's fables.
+ The way to create these tables is to use a third-party
+ tool such as par to read the database:
+
+ ./par l /tmp/Aesop.pdb | awk '{print "{",$3,",",$4,"},";}'
+
+*/
+recordInfo nonexistent[] = {
+ { NO_EXIST, 0 }
+} ;
+
+recordInfo aesop[] = {
+{ 7307264 , 214 },
+{ 7307265 , 1564 },
+{ 7307266 , 1575 },
+{ 7307267 , 2214 },
+{ 7307268 , 2276 },
+{ 7307269 , 2148 },
+{ 7307270 , 2194 },
+{ 7307271 , 2178 },
+{ 7307272 , 2220 },
+{ 7307273 , 2216 },
+{ 7307274 , 2181 },
+{ 7307275 , 2183 },
+{ 7307276 , 2197 },
+{ 7307277 , 2010 },
+{ 7307278 , 2198 },
+{ 7307279 , 2196 },
+{ 7307280 , 2243 },
+{ 7307281 , 2211 },
+{ 7307282 , 2274 },
+{ 7307283 , 364 },
+{ 7307284 , 49124 },
+ { END, 0 }
+} ;
+
+int checkDatabase(const char *path, recordInfo *info)
+{
+ FUNCTIONSETUP;
+
+ PilotLocalDatabase db(QString::fromLatin1(path));
+ if (!db.isOpen())
+ {
+ kdDebug() << "No database " << path << endl;
+ if ( info[0].id == NO_EXIST )
+ {
+ kdDebug() << "This was expected" << endl;
+ return OK;
+ }
+ else
+ {
+ return ERR_NO_EXIST;
+ }
+ }
+
+ if ( info[0].id == NO_EXIST )
+ {
+ kdDebug() << "Database not expected" << endl;
+ return ERR;
+ }
+
+ int fail = 0;
+ int index = 0;
+ PilotRecord *r;
+ while( (r = db.readRecordByIndex(index) ) )
+ {
+ kdDebug() << "[" << index << "] id=" << r->id() << " size=" << r->size() << endl;
+ if ( ((recordid_t)info[index].id) != r->id() )
+ {
+ kdDebug() << "* Bad ID (expected" << r->id() << ")" << endl;
+ fail++;
+ }
+ else if ( info[index].size != r->size() )
+ {
+ kdDebug() << "* Bad size (expected " << info[index].size << ")" << endl;
+ fail++;
+ }
+ index++;
+ }
+ if ( info[index].id != END )
+ {
+ kdDebug() << "* End wasn't expected yet." << endl;
+ r++;
+ }
+
+ if (fail)
+ {
+ kdDebug() << "* " << fail << " failures." << endl;
+ return ERR;
+ }
+ return OK;
+}
+
+const char *categoryNames[4] =
+{
+ "aardvarks",
+ "toolongToBeaCategoryName",
+ "personal",
+ "impersonal"
+} ;
+
+QStringList listCategories()
+{
+ QStringList cats;
+ PilotLocalDatabase *l = new PilotLocalDatabase("./data/MemoDB");
+ PilotMemoInfo *m = new PilotMemoInfo(l);
+
+ if (!l->isOpen()) return cats;
+
+ cats.append(CSL1("Unfiled"));
+ m->dump();
+
+ for (int i=0; i<20; i++)
+ {
+ PilotRecord *r = l->readRecordByIndex(i);
+ kdDebug() << "Read record " << (void *)r << " with id=" << r->id() << endl;
+ if (!r) break;
+ }
+
+ for (int i=0; i<4; i++)
+ {
+ QString s = m->category(i);
+ kdDebug() << "Category " << i << ": " << (s.isEmpty() ? CSL1("<empty>") : s) << endl;
+ cats.append(s);
+/*
+ if (i<((sizeof(categoryNames) / sizeof(categoryNames[0]))))
+ m->setCategoryName(i,QString::fromLatin1(categoryNames[i]));
+*/
+ }
+
+ m->write(l);
+
+ delete m;
+ delete l;
+
+ return cats;
+}
+
+int checkCategories()
+{
+ QStringList l = listCategories();
+ QStringList m = listCategories();
+
+ if (l.isEmpty() || m.isEmpty()) return ERR;
+ if (l!=m) return ERR;
+ return OK;
+}
+
+int checkMemo()
+{
+ PilotLocalDatabase *l = new PilotLocalDatabase("./data/MemoDB");
+ if (!l->isOpen()) return ERR_NO_EXIST;
+
+ PilotMemoInfo *m = new PilotMemoInfo(l);
+ m->dump();
+
+ QString c = m->category(1);
+ if (c != CSL1("Business"))
+ {
+ kdDebug() << "* Category 1 is not 'Business' but " << c << endl;
+ return ERR;
+ }
+
+ m->setCategoryName(2,CSL1("Aardvark"));
+ m->dump();
+
+ c = m->category(2);
+ if (c != CSL1("Aardvark"))
+ {
+ kdDebug() << "* Category 2 is not 'Aardvark' but " << c << endl;
+ return ERR;
+ }
+
+
+ delete m;
+ delete l;
+ return OK;
+}
+
+static const KCmdLineOptions options[] =
+{
+ {"verbose", "Verbose output", 0},
+ KCmdLineLastOption
+};
+
+
+int main(int argc, char **argv)
+{
+ KApplication::disableAutoDcopRegistration();
+
+ KAboutData aboutData("testdatabase","Test Databases","0.1");
+ KCmdLineArgs::init(argc,argv,&aboutData);
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication app( false, false );
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ Q_UNUSED(args)
+
+ int r = 0;
+ int i = 0;
+#ifdef DEBUG
+ debug_level=4;
+#endif
+
+ Q_UNUSED(argc);
+ Q_UNUSED(argv);
+
+#define ALLOW_NO_EXIST (1)
+ static struct { const char *path; recordInfo *info; int flags; }
+ tests[] =
+ {
+ { "/tmp/nonexistant/nonexistent", nonexistent,0 },
+ { "/tmp/Aesop", aesop, ALLOW_NO_EXIST },
+ { 0L, 0L, 0 }
+ } ;
+
+ while ( tests[i].path )
+ {
+ kdDebug() << "*** Test " << i << endl;
+ int ret = checkDatabase( tests[i].path, tests[i].info );
+ if ( ret )
+ {
+ if ( (ret==ERR_NO_EXIST) &&
+ (tests[i].flags & ALLOW_NO_EXIST) )
+ {
+ kdDebug() << "* Test database doesn't exist, ignored." << endl;
+ }
+ else
+ {
+ r++;
+ }
+ }
+ i++;
+ }
+
+ kdDebug() << "*** Test " << i << endl;
+ if (checkMemo()) r++;
+ i++;
+
+ if (r)
+ {
+ kdDebug() << "***\n*** Failed " << r << " tests." << endl;
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/kpilot/tests/testdatebook.cc b/kpilot/tests/testdatebook.cc
new file mode 100644
index 000000000..5c1da9d21
--- /dev/null
+++ b/kpilot/tests/testdatebook.cc
@@ -0,0 +1,95 @@
+/* testaddresses KPilot
+**
+** Copyright (C) 2006 by Adriaan de Groot <[email protected])
+**
+** Test the functions related to address database handling.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "options.h"
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+
+#include "pilot.h"
+#include "pilotDateEntry.h"
+#include "pilotLocalDatabase.h"
+
+static const KCmdLineOptions options[] =
+{
+ {"verbose", "Verbose output", 0},
+ {"data-dir <path>","Set data directory", "."},
+ KCmdLineLastOption
+};
+
+
+
+int main(int argc, char **argv)
+{
+ KApplication::disableAutoDcopRegistration();
+
+ KAboutData aboutData("testdatebook","Test Date Book","0.1");
+ KCmdLineArgs::init(argc,argv,&aboutData);
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication app( false, false );
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+#ifdef DEBUG
+ debug_level= (args->isSet("verbose")) ? 4 : 0;
+#endif
+ QString datadir = args->getOption("data-dir");
+
+ DEBUGKPILOT << "### testdatebook\n#\n#" << endl;
+
+ Pilot::setupPilotCodec( CSL1("Latin1") );
+
+ PilotLocalDatabase db( datadir, "DatebookDB" );
+ PilotDateInfo appinfo( &db );
+
+ for (unsigned int i=0; i<db.recordCount(); ++i)
+ {
+ PilotRecord *r = db.readRecordByIndex( i );
+
+ if (r)
+ {
+ DEBUGKPILOT << "# Record @" << (void *)r << " ID=" << r->id() << endl;
+ PilotDateEntry a( r );
+ DEBUGKPILOT << "# Text Representation:" << endl << a.getTextRepresentation(Qt::PlainText) << endl;
+ DEBUGKPILOT << "# Category#" << a.category() << endl;
+ DEBUGKPILOT << "# Category Label " << appinfo.categoryName(a.category()) << endl;
+ DEBUGKPILOT << "# ID " << a.id() << endl;
+ int cat = appinfo.findCategory( CSL1("Fake Cat") );
+ a.setCategory( cat );
+ DEBUGKPILOT << "# Category#" << a.category() << endl;
+ DEBUGKPILOT << "# Category Label " << appinfo.categoryName(a.category()) << endl;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/kpilot/tests/testidmapper.cc b/kpilot/tests/testidmapper.cc
new file mode 100644
index 000000000..a694a4c38
--- /dev/null
+++ b/kpilot/tests/testidmapper.cc
@@ -0,0 +1,314 @@
+/* testactions KPilot
+**
+** Copyright (C) 2005 by Adriaan de Groot <[email protected])
+**
+** Test the functions related to sync actions.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU Lesser General Public License as published by
+** the Free Software Foundation; either version 2.1 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to [email protected]
+*/
+
+#include "idmapper.h"
+#include "options.h"
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+
+#include <qdir.h>
+#include <qfile.h>
+
+#define TESTFILE "Testing/mapping.xml"
+#define CONDUIT CSL1("knotes")
+
+/**
+ * If the file does not exist it should be created by the idmapper.
+ */
+bool test1()
+{
+ FUNCTIONSETUP;
+
+ IDMapper *mapper = new IDMapper( TESTFILE );
+
+ delete mapper;
+ mapper = 0l;
+
+ QFile f( TESTFILE );
+ bool result = f.exists();
+
+ if( result )
+ {
+ DEBUGKPILOT << fname << ": passed" << endl;
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": failed" << endl;
+ }
+
+ return result;
+}
+
+/**
+ * Test if a uid gets added when it's registered.
+ */
+bool test2()
+{
+ FUNCTIONSETUP;
+
+ IDMapper *mapper = new IDMapper( TESTFILE );
+ mapper->registerPCObjectId( CONDUIT, CSL1("testuid-1") );
+
+ delete mapper;
+ mapper = 0l;
+
+ // Creating a new mapper ensures that the file is readed. So we know if this
+ // test passess that the data is saved and readed from the xml file correctly.
+ mapper = new IDMapper( TESTFILE );
+
+ bool result1 = ( mapper->getPCObjectIds( CONDUIT ).size() == 1 );
+ bool result2 = false;
+
+ if( result1 )
+ result2 = ( mapper->getPCObjectIds( CONDUIT ).first() == "testuid-1" );
+
+
+ if( result1 && result2 )
+ {
+ DEBUGKPILOT << fname << ": passed" << endl;
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": " << result1 << " " << result2 << endl;
+ DEBUGKPILOT << fname << ": failed" << endl;
+ }
+
+ delete mapper;
+ mapper = 0l;
+
+ return (result1 && result2);
+}
+
+/**
+ * Set the pid for uid "testuid-1". getHHObjectIds should return 1 item now and
+ * that should be the same as the one which is set.
+ */
+bool test3()
+{
+ FUNCTIONSETUP;
+
+ IDMapper *mapper = new IDMapper( TESTFILE );
+ mapper->setHHObjectId( CONDUIT, "testuid-1", 100 );
+
+ delete mapper;
+ mapper = 0l;
+
+ // Creating a new mapper ensures that the file is readed. So we know if this
+ // test passess that the data is saved and readed from the xml file correctly.
+ mapper = new IDMapper( TESTFILE );
+
+ bool result1 = ( mapper->getHHObjectIds( CONDUIT ).size() == 1 );
+ bool result2 = false;
+
+ if( result1 )
+ result2 = ( mapper->getHHObjectIds( CONDUIT ).first() == 100 );
+
+
+ if( result1 && result2 )
+ {
+ DEBUGKPILOT << fname << ": passed" << endl;
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": " << result1 << " " << result2 << endl;
+ DEBUGKPILOT << fname << ": failed" << endl;
+ }
+
+ delete mapper;
+ mapper = 0l;
+
+ return (result1 && result2);
+}
+
+/**
+ * Test if a pid is stored correctly when it's registered.
+ */
+bool test4()
+{
+ FUNCTIONSETUP;
+
+ IDMapper *mapper = new IDMapper( TESTFILE );
+ mapper->registerHHObjectId( CONDUIT, 150 );
+
+ delete mapper;
+ mapper = 0l;
+
+ // Creating a new mapper ensures that the file is readed. So we know if this
+ // test passess that the data is saved and readed from the xml file correctly.
+ mapper = new IDMapper( TESTFILE );
+
+ // We have two pids registered at this moment
+ bool result1 = ( mapper->getHHObjectIds( CONDUIT ).size() == 2 );
+ bool result2 = false;
+
+ // This prevents the test from chrashing when getHHObjectIds.size is 0.
+ if( result1 )
+ result2 = ( mapper->getHHObjectIds( CONDUIT ).contains( 150 ) );
+
+ if( result1 && result2 )
+ {
+ DEBUGKPILOT << fname << ": passed" << endl;
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": " << result1 << " " << result2 << endl;
+ DEBUGKPILOT << fname << ": failed" << endl;
+ }
+
+ delete mapper;
+ mapper = 0l;
+
+ return (result1 && result2);
+}
+
+/**
+ * Set the uid for pid 150. getPcObjectIds should return 2 items now and
+ * it should contain the one which is just set.
+ */
+bool test5()
+{
+ FUNCTIONSETUP;
+
+ IDMapper *mapper = new IDMapper( TESTFILE );
+ mapper->setPCObjectId( CONDUIT, 150, "testuid-2" );
+
+ delete mapper;
+ mapper = 0l;
+
+ // Creating a new mapper ensures that the file is readed. So we know if this
+ // test passess that the data is saved and readed from the xml file correctly.
+ mapper = new IDMapper( TESTFILE );
+
+ bool result1 = ( mapper->getPCObjectIds( CONDUIT ).size() == 2 );
+ bool result2 = false;
+
+ if( result1 )
+ result2 = ( mapper->getPCObjectIds( CONDUIT ).contains( "testuid-2" ) );
+
+
+ if( result1 && result2 )
+ {
+ DEBUGKPILOT << fname << ": passed" << endl;
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": " << result1 << " " << result2 << endl;
+ DEBUGKPILOT << fname << ": failed" << endl;
+ }
+
+ delete mapper;
+ mapper = 0l;
+
+ return (result1 && result2);
+}
+
+
+/**
+ * Test for the hasPCId function.
+ */
+bool test6()
+{
+ FUNCTIONSETUP;
+
+ IDMapper *mapper = new IDMapper( TESTFILE );
+
+ // Should be true (PCId is set to "testuid-2").
+ bool result = mapper->hasPCId( CONDUIT, 150 );
+
+ delete mapper;
+ mapper = 0l;
+
+ if( result )
+ {
+ DEBUGKPILOT << fname << ": passed" << endl;
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": failed" << endl;
+ }
+
+ return result;
+}
+
+/**
+ * Test for the hasHHId function.
+ */
+bool test7()
+{
+ FUNCTIONSETUP;
+
+ IDMapper *mapper = new IDMapper( TESTFILE );
+
+ // Should be true (HHId is set to "150").
+ bool result = mapper->hasHHId( CONDUIT, "testuid-2" );
+
+ delete mapper;
+ mapper = 0l;
+
+ if( result )
+ {
+ DEBUGKPILOT << fname << ": passed" << endl;
+ }
+ else
+ {
+ DEBUGKPILOT << fname << ": failed" << endl;
+ }
+
+ return result;
+}
+
+int main(int argc, char **argv)
+{
+ KApplication::disableAutoDcopRegistration();
+ KAboutData aboutData("testidmapper","Test IDMapper","0.1");
+ KCmdLineArgs::init(argc,argv,&aboutData);
+
+ KApplication app( false, false );
+
+ // Remove file from previous test run
+ QDir test( "Testing" );
+ if( !test.exists() ) {
+ QDir current;
+ current.mkdir( "Testing" );
+ }
+
+ QFile f( TESTFILE );
+ if( f.exists() )
+ QFile::remove( TESTFILE );
+
+ if( test1() && test2() && test3() &&
+ test4() && test5() && test6() &&
+ test7() )
+ return 0;
+ else
+ return 1;
+}
+
+