barry-0.18.5/0000755001161500056700000000000012242254564012252 5ustar cdfreycdfreybarry-0.18.5/rpm/0000755001161500056700000000000012242254476013052 5ustar cdfreycdfreybarry-0.18.5/rpm/barry.spec0000644001161500056700000005735212242254476015061 0ustar cdfreycdfrey%dump # # Note: This spec file is intended to be as cross-platform as possible. # As such, it skips listing the BuildRequires lines, expecting to # be built on a system with rpmbuild -ba only, and dependencies # pre-installed. See the ../maintainer/depscripts/ directory # in the Barry source package for scripts to automate installation # of dependencies. # # enable GUI using: --with gui %define with_gui 0%{?_with_gui:1} # enable opensync 0.2x using: --with opensync %define with_opensync 0%{?_with_opensync:1} # enable opensync 0.4x using: --with opensync4x %define with_opensync4x 0%{?_with_opensync4x:1} # enable desktop using: --with desktop %define with_desktop 0%{?_with_desktop:1} # enable kdesu for desktop instead of beesu: --with kdesu %define with_kdesu 0%{?_with_kdesu:1} %if %{with_kdesu} %define guisu_name kdesu %define guisu_package kdebase4-runtime %else %define guisu_name beesu %define guisu_package beesu %endif Summary: BlackBerry(tm) Desktop for Linux Name: barry Version: 0.18.5 Release: 0 Group: Applications/Productivity License: GPLv2+ Source: %{name}-%{version}.tar.bz2 URL: http://www.netdirect.ca/software/packages/barry Vendor: Net Direct Inc. BuildRoot: %{_tmppath}/%{name}-%{release}-%{version}-root #BuildRequires: libusb-devel, gcc-c++, pkgconfig, boost-devel, fuse-devel, zlib-devel #%if %{with_gui} #BuildRequires: desktop-file-utils #%endif # desktop tree #%if %{with_desktop} #BuildRequires: wxGTK-devel, evolution-data-server-devel #%endif %define barryroot %{_builddir}/%{name}-%{version} %description Barry is a desktop toolset for managing your BlackBerry(tm) device. (BlackBerry is a registered trademark of Research in Motion Limited.) %package -n libbarry0 Summary: BlackBerry(tm) Desktop for Linux - libbarry libraries Group: Development/Libraries #Requires: libusb boost %description -n libbarry0 Barry is a desktop toolset for managing your BlackBerry(tm) device. (BlackBerry is a registered trademark of Research in Motion Limited.) This package contains the library files, license agreement, README file, and most other assorted documentation common to all sub-packages. You most likely want to also install barry-util and barry-gui. %package -n libbarry-devel Summary: BlackBerry(tm) Desktop for Linux - libbarry libraries Group: Development/Libraries Requires: libbarry0 boost-devel %description -n libbarry-devel Barry is a desktop toolset for managing your BlackBerry(tm) device. (BlackBerry is a registered trademark of Research in Motion Limited.) This package contains the development library files for Barry, libbarry. %package util Summary: BlackBerry(tm) Desktop for Linux - bcharge, btool, breset, bio and others Group: Applications/Productivity Requires: libbarry0 fuse Conflicts: barry-bcharge %description util Barry is a desktop toolset for managing your BlackBerry(tm) device. (BlackBerry is a registered trademark of Research in Motion Limited.) This package contains the commandline tools bcharge, btool, breset, bio and others which will enable you to charge your device with a proper 500mA and be able to access the data on the device in many ways. %if %{with_gui} %package gui Summary: BlackBerry(tm) Desktop for Linux - bcharge, btool, breset and others Group: Applications/Productivity Requires: libbarry0 #BuildRequires: gtkmm24-devel libglademm24-devel libtar-devel %description gui Barry is a desktop toolset for managing your BlackBerry(tm) device. (BlackBerry is a registered trademark of Research in Motion Limited.) This package contains the GUI applications built on top of libbarry. %endif # opensync 0.2x %if %{with_opensync} %package opensync Summary: BlackBerry(tm) Desktop for Linux - opensync plugin Group: Applications/Productivity Requires: libbarry0, libopensync >= 0.22 #BuildRequires: libopensync-devel %description opensync Barry is a desktop toolset for managing your BlackBerry(tm) device. (BlackBerry is a registered trademark of Research in Motion Limited.) This package contains the opensync plugin. %endif # opensync 0.4x %if %{with_opensync4x} %package opensync4x Summary: BlackBerry(tm) Desktop for Linux - opensync 0.4x plugin Group: Applications/Productivity Requires: libbarry0, libopensync1 >= 0.39 #BuildRequires: libopensync1-devel %description opensync4x Barry is a desktop toolset for managing your BlackBerry(tm) device. (BlackBerry is a registered trademark of Research in Motion Limited.) This package contains the opensync 0.4x plugin. %endif # desktop tree %if %{with_desktop} %package desktop Summary: BlackBerry(tm) Desktop Panel GUI for Linux Group: Applications/Productivity Requires: libbarry0 barry-util ppp xterm %{guisu_package} #BuildRequires: wxGTK-devel %description desktop Barry is a desktop toolset for managing your BlackBerry(tm) device. (BlackBerry is a registered trademark of Research in Motion Limited.) This package contains the desktop panel GUI. %endif %prep [ "%{buildroot}" != "/" ] && %{__rm} -rf %{buildroot} %setup -q %build # some systems have an rpath checker, and need their own versions of # configure built on the same system in order to pass... in particular, # Fedora 14's 64bit version needs its own configure, for some reason, # in order to recognize that /usr/lib64 is a system path and therefore # there is no reason to use an rpath... unfortunately, configure's # --disable-rpath option seems to have no effect whatsoever. :-( %if "%{?_lib}" == "lib64" ./buildgen.sh cleanall ./buildgen.sh %endif # Generate configure if it does not exist already (for binary-meta) if [ ! -f ./configure ] ; then ./buildgen.sh fi # setup the environment if there are additions (for binary-meta) export ORIG_PKG_CONFIG_PATH="$PKG_CONFIG_PATH" if [ -n "$ADD_TO_PKG_CONFIG_PATH" ] ; then export PKG_CONFIG_PATH="$ADD_TO_PKG_CONFIG_PATH:$ORIG_PKG_CONFIG_PATH" fi set # main tree %{configure} --enable-boost --enable-nls --with-zlib --with-libusb --enable-rpathhack %{__make} %{?_smp_mflags} # gui tree %if %{with_gui} cd gui/ %{configure} PKG_CONFIG_PATH="..:$PKG_CONFIG_PATH" CXXFLAGS="-I../.." LDFLAGS="-L../../src" --enable-nls --enable-rpathhack %{__make} %{?_smp_mflags} cd ../ %endif # opensync tree %if %{with_opensync} # if there is a special pkgconfig for opensync 0.2x, use it if [ -n "$OSYNC2X_PKG_CONFIG_PATH" ] ; then export PKG_CONFIG_PATH="$OSYNC2X_PKG_CONFIG_PATH:$ORIG_PKG_CONFIG_PATH" fi cd opensync-plugin/ %{configure} PKG_CONFIG_PATH="..:$PKG_CONFIG_PATH" CXXFLAGS="-I../.." LDFLAGS="-L../../src" --enable-nls --enable-rpathhack %{__make} %{?_smp_mflags} cd ../ %endif # opensync4x tree %if %{with_opensync4x} # if there is a special pkgconfig for opensync 0.4x, use it if [ -n "$OSYNC4X_PKG_CONFIG_PATH" ] ; then export PKG_CONFIG_PATH="$OSYNC4X_PKG_CONFIG_PATH:$ORIG_PKG_CONFIG_PATH" fi cd opensync-plugin-0.4x/ %{configure} PKG_CONFIG_PATH="..:$PKG_CONFIG_PATH" CXXFLAGS="-I../.." LDFLAGS="-L../../src" --enable-nls --enable-rpathhack %{__make} %{?_smp_mflags} cd ../ %endif # desktop tree %if %{with_desktop} # if there is a special pkgconfig for both opensync 0.4x and 0.2x, use it if [ -n "$OSYNCBOTH_PKG_CONFIG_PATH" ] ; then export PKG_CONFIG_PATH="$OSYNCBOTH_PKG_CONFIG_PATH:$ORIG_PKG_CONFIG_PATH" fi cd desktop/ %{configure} PKG_CONFIG_PATH="..:$PKG_CONFIG_PATH" CXXFLAGS="-I../.." LDFLAGS="-L../../src" --enable-nls --enable-rpathhack --with-evolution --with-guisu=/usr/bin/%{guisu_name} %{__make} %{?_smp_mflags} cd ../ %endif %install # main tree %{__make} DESTDIR=%{buildroot} install # delete some test-only programs %{__rm} -f %{buildroot}%{_bindir}/bdptest %{__rm} -f %{buildroot}%{_bindir}/bjvmdebug # delete the .la files %{__rm} -f %{buildroot}%{_libdir}/*.la # proceed as usual... %{__mkdir_p} %{buildroot}%{_sysconfdir}/udev/rules.d %{__cp} udev/10-blackberry.rules %{buildroot}%{_sysconfdir}/udev/rules.d/ %{__cp} udev/99-blackberry-perms.rules %{buildroot}%{_sysconfdir}/udev/rules.d/ %{__mkdir_p} %{buildroot}%{_sysconfdir}/modprobe.d %{__cp} modprobe/blacklist-berry_charge.conf %{buildroot}%{_sysconfdir}/modprobe.d/ %{__mkdir_p} %{buildroot}%{_sysconfdir}/ppp/peers %{__cp} ppp/barry-rogers %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-minimal %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-verizon %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-sprint %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-telus %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-o2ireland %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-emobile %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-tmobileus %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-att_cingular %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-chinamobile %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-kpn %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-orange-spain %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-orangeuk %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-mts %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-optus-au %{buildroot}%{_sysconfdir}/ppp/peers/ %{__cp} ppp/barry-vodafone-au %{buildroot}%{_sysconfdir}/ppp/peers/ %{__mkdir_p} %{buildroot}%{_sysconfdir}/chatscripts %{__cp} ppp/barry-rogers.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-minimal.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-verizon.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-sprint.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-telus.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-o2ireland.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-emobile.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-tmobileus.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-att_cingular.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-chinamobile.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-kpn.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-orange-spain.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-orangeuk.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-mts.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-optus-au.chat %{buildroot}%{_sysconfdir}/chatscripts/ %{__cp} ppp/barry-vodafone-au.chat %{buildroot}%{_sysconfdir}/chatscripts/ # Install hal fdi config %{__mkdir_p} %{buildroot}%{_datadir}/hal/fdi/information/10freedesktop %{__mkdir_p} %{buildroot}%{_datadir}/hal/fdi/policy/10osvendor %{__cp} hal/fdi/information/10freedesktop/10-blackberry.fdi %{buildroot}%{_datadir}/hal/fdi/information/10freedesktop %{__cp} hal/fdi/policy/10osvendor/19-blackberry-acl.fdi %{buildroot}%{_datadir}/hal/fdi/policy/10osvendor # Install hal support script %{__mkdir_p} %{buildroot}%{_libdir}/barry %{__cp} hal/hal-blackberry %{buildroot}%{_libdir}/barry # Install bash completion scripts %{__mkdir_p} %{buildroot}%{_sysconfdir}/bash_completion.d %{__cp} bash/bjavaloader %{buildroot}%{_sysconfdir}/bash_completion.d %{__cp} bash/btool %{buildroot}%{_sysconfdir}/bash_completion.d # gui tree %if %{with_gui} cd gui/ %{__make} DESTDIR=%{buildroot} install # Install barry logo icon (name of icon must match the *.desktop file!) cd ../ %{__mkdir_p} %{buildroot}%{_datadir}/pixmaps %{__cp} logo/barry_logo_icon.png %{buildroot}%{_datadir}/pixmaps/barry_backup_menu_icon.png desktop-file-install --vendor netdirect \ --dir %{buildroot}%{_datadir}/applications \ menu/barrybackup.desktop %endif # opensync tree %if %{with_opensync} cd opensync-plugin/ %{__make} DESTDIR=%{buildroot} install # remove .la files %{__rm} -f %{buildroot}%{_libdir}/opensync/plugins/*.la cd ../ %endif # opensync4x tree %if %{with_opensync4x} cd opensync-plugin-0.4x/ %{__make} DESTDIR=%{buildroot} install # remove .la files %{__rm} -f %{buildroot}%{_libdir}/libopensync1/plugins/*.la cd ../ %endif # desktop tree %if %{with_desktop} cd desktop/ %{__make} DESTDIR=%{buildroot} install # remove .la files %{__rm} -f %{buildroot}%{_libdir}/*.la cd ../ %{__mkdir_p} %{buildroot}%{_datadir}/pixmaps %{__cp} logo/barry_logo_icon.png %{buildroot}%{_datadir}/pixmaps/barry_desktop_menu_icon.png desktop-file-install --vendor netdirect \ --dir %{buildroot}%{_datadir}/applications \ menu/barrydesktop.desktop %endif %files -n libbarry0 %defattr(-,root,root) %attr(-,root,root) %{_libdir}/libbarry.so.* %attr(-,root,root) %{_libdir}/libbarrydp.so.* %attr(-,root,root) %{_libdir}/libbarryjdwp.so.* %attr(-,root,root) %{_libdir}/libbarrysync.so.* %attr(-,root,root) %{_libdir}/libbarrybackup.so.* %attr(-,root,root) %{_libdir}/libbarryalx.so.* %doc AUTHORS ChangeLog KnownBugs COPYING NEWS README %files -n libbarry-devel %defattr(-,root,root) %attr(0644,root,root) %{_includedir}/barry*/barry/* %attr(0644,root,root) %{_libdir}/libbarry.a %attr(0644,root,root) %{_libdir}/libbarry.so %attr(0644,root,root) %{_libdir}/libbarrydp.a %attr(0644,root,root) %{_libdir}/libbarrydp.so %attr(0644,root,root) %{_libdir}/libbarryjdwp.a %attr(0644,root,root) %{_libdir}/libbarryjdwp.so %attr(0644,root,root) %{_libdir}/libbarrysync.a %attr(0644,root,root) %{_libdir}/libbarrysync.so %attr(0644,root,root) %{_libdir}/libbarrybackup.a %attr(0644,root,root) %{_libdir}/libbarrybackup.so %attr(0644,root,root) %{_libdir}/libbarryalx.a %attr(0644,root,root) %{_libdir}/libbarryalx.so %attr(0644,root,root) %{_libdir}/pkgconfig/*.pc %doc COPYING TODO KnownBugs doc/* examples/*.cc %files util %defattr(-,root,root) %attr(0755,root,root) %{_sbindir}/bcharge %attr(0755,root,root) %{_sbindir}/breset %attr(0755,root,root) %{_sbindir}/pppob %attr(0755,root,root) %{_bindir}/btool %attr(0755,root,root) %{_bindir}/bwatch %attr(0755,root,root) %{_bindir}/bio %attr(0755,root,root) %{_bindir}/btardump %attr(0755,root,root) %{_bindir}/btarcmp %attr(0755,root,root) %{_bindir}/bfuse %attr(0755,root,root) %{_bindir}/bjavaloader %attr(0755,root,root) %{_bindir}/balxparse %attr(0755,root,root) %{_bindir}/bjdwp %attr(0755,root,root) %{_bindir}/brawchannel %attr(0755,root,root) %{_bindir}/bs11nread %attr(0755,root,root) %{_bindir}/bidentify %attr(0755,root,root) %{_bindir}/brecsum %attr(0755,root,root) %{_bindir}/upldif %attr(0755,root,root) %{_libdir}/barry/hal-blackberry %attr(0644,root,root) %{_mandir}/man1/btool* %attr(0644,root,root) %{_mandir}/man1/bwatch* %attr(0644,root,root) %{_mandir}/man1/bio* %attr(0644,root,root) %{_mandir}/man1/btardump* %attr(0644,root,root) %{_mandir}/man1/btarcmp* %attr(0644,root,root) %{_mandir}/man1/bfuse* %attr(0644,root,root) %{_mandir}/man1/bjavaloader* %attr(0644,root,root) %{_mandir}/man1/balxparse* %attr(0644,root,root) %{_mandir}/man1/bjdwp* %attr(0644,root,root) %{_mandir}/man1/brawchannel* %attr(0644,root,root) %{_mandir}/man1/bs11nread* %attr(0644,root,root) %{_mandir}/man1/bidentify* %attr(0644,root,root) %{_mandir}/man1/bcharge* %attr(0644,root,root) %{_mandir}/man1/pppob* %attr(0644,root,root) %{_mandir}/man1/brecsum* %attr(0644,root,root) %{_mandir}/man1/breset* %attr(0644,root,root) %{_mandir}/man1/upldif* %attr(0644,root,root) %{_datadir}/locale/*/LC_MESSAGES/barry.mo %attr(0644,root,root) %{_datadir}/hal/fdi/information/10freedesktop/10-blackberry.fdi %attr(0644,root,root) %{_datadir}/hal/fdi/policy/10osvendor/19-blackberry-acl.fdi %attr(0644,root,root) %config %{_sysconfdir}/udev/rules.d/* %attr(0644,root,root) %config %{_sysconfdir}/modprobe.d/blacklist-berry_charge.conf %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-rogers %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-minimal %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-verizon %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-sprint %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-telus %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-o2ireland %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-emobile %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-tmobileus %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-att_cingular %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-chinamobile %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-kpn %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-orange-spain %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-orangeuk %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-mts %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-optus-au %attr(0644,root,root) %config %{_sysconfdir}/ppp/peers/barry-vodafone-au %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-rogers.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-minimal.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-verizon.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-sprint.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-telus.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-o2ireland.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-emobile.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-tmobileus.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-att_cingular.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-chinamobile.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-kpn.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-orange-spain.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-orangeuk.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-mts.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-optus-au.chat %attr(0640,root,root) %config %{_sysconfdir}/chatscripts/barry-vodafone-au.chat %attr(0640,root,root) %config %{_sysconfdir}/bash_completion.d/bjavaloader %attr(0640,root,root) %config %{_sysconfdir}/bash_completion.d/btool %doc COPYING %doc zsh %doc ppp/README %if %{with_gui} %files gui %defattr(-,root,root) %attr(0755,root,root) %{_bindir}/barrybackup %attr(0644,root,root) %{_datadir}/barry/glade/*.glade %attr(0644,root,root) %{_datadir}/pixmaps/barry_backup_menu_icon.png %attr(0644,root,root) %{_datadir}/applications/*barrybackup.desktop %attr(0644,root,root) %{_mandir}/man1/barrybackup* %attr(0644,root,root) %{_datadir}/locale/*/LC_MESSAGES/barry-backup.mo %doc COPYING %endif %if %{with_opensync} %files opensync %defattr(-,root,root) %attr(0755,root,root) %{_libdir}/opensync/plugins/barry_sync.so %attr(0644,root,root) %{_datadir}/opensync/defaults/barry-sync %attr(0644,root,root) %{_datadir}/locale/*/LC_MESSAGES/barry-opensync-plugin.mo %doc COPYING %endif %if %{with_opensync4x} %files opensync4x %defattr(-,root,root) %attr(0755,root,root) %{_libdir}/libopensync1/plugins/barry_sync.so %attr(0644,root,root) %{_datadir}/libopensync1/defaults/barry-sync %attr(0644,root,root) %{_datadir}/locale/*/LC_MESSAGES/barry-opensync-plugin-0-4x.mo %doc COPYING %endif # desktop tree %if %{with_desktop} %files desktop %defattr(-,root,root) %attr(0755,root,root) %{_bindir}/barrydesktop %attr(0755,root,root) %{_libexecdir}/barrydesktop/bsyncjail %attr(0755,root,root) %{_libexecdir}/barrydesktop/blistevo %attr(0644,root,root) %{_datadir}/barry/desktop/0.22/* %attr(0644,root,root) %{_datadir}/barry/desktop/0.40/* %attr(0644,root,root) %{_datadir}/barry/desktop/images/*.png %attr(0644,root,root) %{_datadir}/pixmaps/barry_desktop_menu_icon.png %attr(0644,root,root) %{_datadir}/applications/*barrydesktop.desktop %attr(0644,root,root) %{_mandir}/man1/barrydesktop* %attr(0644,root,root) %{_datadir}/locale/*/LC_MESSAGES/barrydesktop.mo %attr(0644,root,root) %{_datadir}/locale/*/LC_MESSAGES/barryosyncwrap.mo %attr(-,root,root) %{_libdir}/libosyncwrap.so.* %attr(-,root,root) %{_libdir}/libosyncwrap.a %attr(-,root,root) %{_libdir}/libosyncwrap.so %attr(0644,root,root) %{_includedir}/barry*/osyncwrap/* %doc COPYING %endif %clean [ "%{buildroot}" != "/" ] && %{__rm} -rf %{buildroot} [ "%{barryroot}" != "/" ] && %{__rm} -rf %{barryroot} %post -n libbarry0 /sbin/ldconfig %postun -n libbarry0 /sbin/ldconfig %changelog * Sun Nov 17 2013 Chris Frey 0.18.5-0 - version bump * Mon Aug 20 2012 Chris Frey 0.18.4-0 - version bump - added spanish translation, and fixed locations of .mo files, so barry.mo goes to utils, and barry-backup.mo goes to backup - since we are building with binary-meta which contains depscripts, removed all BuildRequires lines, to make spec file more portable across Fedora and openSUSE - use kdesu for openSUSE builds, beesu for Fedora - added desktop's barrydesktop.mo and barryosyncwrap.mo files - added .mo files for both plugins - added ppp chatscripts for eMobile Ireland * Tue May 15 2012 Chris Frey 0.18.3-0 - version bump - renamed icon filenames to match .desktop file * Tue May 15 2012 Chris Frey 0.18.2-0 - version bump * Tue May 8 2012 Chris Frey 0.18.1-0 - version bump * Mon Aug 31 2011 Chris Frey 0.18.0-0 - version bump - removed dependency of libbarry-devel on libusb(-devel) - added osyncwrap headers - removed opensuse special cases - back to optional --with behaviour - added opensync 0.4x package support - removed .la files - split up dev libraries a little better (-devel should have the dev libs) - put desktop library in desktop package - added orangeuk and mts ppp chatscript files - added bwatch - added code to clean the buildroot at start - added evolution dependencies for desktop build - removed libopensync dependency from barry-desktop (can be either, both, or none) - renamed 0.4x plugin dependency to libopensync1 - removed extraneous library dependencies, which should be handled automatically - added btarcmp - removed brimtrans, bktrans, and btranslate (devel tools) - added beesu dependency for barrydesktop, for modem mode, to run pppd * Fri May 28 2010 Chris Frey 0.17.0-0 - version bump - added NLS support - cleaned up conditionals - added Fedora 13 support - added new ppp chat scripts for Orange Spain, Optus and Vodafone AU - added copy of barry-sprint as barry-telus - added brawchannel, btardump, bio, and balxparse - added desktop support - cleaned up desktop variables * Sat Sep 29 2009 Chris Frey 0.16-0 - version bump - added new ppp chat script for KPN Nederland - using new udev rules set - added bjdwp and manpage, and removed some test-only programs - added bash and zsh completion scripts - added .desktop file and icon for barrybackup * Fri Apr 10 2009 Chris Frey 0.15-0 - version bump - added HAL FDI scripts - added bjavaloader and bfuse - updated for udev directory reorganization in Barry source tree - added zlib-devel to BuildRequires list - added brimtrans * Wed Sep 24 2008 Chris Frey 0.14-0 - version bump - added new ppp chat script for T-Mobile US - renamed libbarry to libbarry0 * Thu May 29 2008 Chris Frey 0.13-1 - version bump - added brecsum - added ppp options and chat scripts - added manpages for pppob, brecsum, breset, upldif, barrybackup - spec file now assumes gui and opensync, with conditional checks depending on host * Fri Dec 07 2007 Chris Frey 0.12-1 - version bump * Fri Nov 30 2007 Chris Frey 0.11-1 - version bump * Fri Nov 30 2007 Chris Frey 0.10-1 - version bump - removed ktrans and translate from rpm package - added bidentify * Thu Aug 09 2007 Chris Frey 0.9-1 - version bump * Fri Aug 03 2007 Chris Frey 0.8-1 - version bump - changed tarball to bz2 * Tue May 01 2007 Chris Frey 0.7-2 - added pppob to utils * Thu Mar 08 2007 Chris Frey 0.7-1 - removed barry base package that only contained docs, and put docs in libbarry* - changed barrybackup reference to barry-gui - removed the patch step, as version 0.7 shouldn't need it - added license file to each package * Sun Mar 04 2007 Troy Engel 0.6-1 - initial build - adding udev and console perms patch for raw 0.6 barry-0.18.5/config.rpath0000755001161500056700000004401212242254476014565 0ustar cdfreycdfrey#! /bin/sh # Output a system dependent set of variables, describing how to set the # run time search path of shared libraries in an executable. # # Copyright 1996-2010 Free Software Foundation, Inc. # Taken from GNU libtool, 2001 # Originally by Gordon Matzigkeit , 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # The first argument passed to this file is the canonical host specification, # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld # should be set by the caller. # # The set of defined variables is at the end of this script. # Known limitations: # - On IRIX 6.5 with CC="cc", the run time search patch must not be longer # than 256 bytes, otherwise the compiler driver will dump core. The only # known workaround is to choose shorter directory names for the build # directory and/or the installation directory. # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a shrext=.so host="$1" host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` # Code taken from libtool.m4's _LT_CC_BASENAME. for cc_temp in $CC""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` # Code taken from libtool.m4's _LT_COMPILER_PIC. wl= if test "$GCC" = yes; then wl='-Wl,' else case "$host_os" in aix*) wl='-Wl,' ;; darwin*) case $cc_basename in xlc*) wl='-Wl,' ;; esac ;; mingw* | cygwin* | pw32* | os2* | cegcc*) ;; hpux9* | hpux10* | hpux11*) wl='-Wl,' ;; irix5* | irix6* | nonstopux*) wl='-Wl,' ;; newsos6) ;; linux* | k*bsd*-gnu) case $cc_basename in ecc*) wl='-Wl,' ;; icc* | ifort*) wl='-Wl,' ;; lf95*) wl='-Wl,' ;; pgcc | pgf77 | pgf90) wl='-Wl,' ;; ccc*) wl='-Wl,' ;; como) wl='-lopt=' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) wl='-Wl,' ;; esac ;; esac ;; osf3* | osf4* | osf5*) wl='-Wl,' ;; rdos*) ;; solaris*) wl='-Wl,' ;; sunos4*) wl='-Qoption ld ' ;; sysv4 | sysv4.2uw2* | sysv4.3*) wl='-Wl,' ;; sysv4*MP*) ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) wl='-Wl,' ;; unicos*) wl='-Wl,' ;; uts4*) ;; esac fi # Code taken from libtool.m4's _LT_LINKER_SHLIBS. hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_direct=no hardcode_minus_L=no case "$host_os" in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. # Unlike libtool, we use -rpath here, not --rpath, since the documented # option of GNU ld is called -rpath, not --rpath. hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' case "$host_os" in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no fi ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we cannot use # them. ld_shlibs=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then : else ld_shlibs=no fi ;; interix[3-9]*) hardcode_direct=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; gnu* | linux* | k*bsd*-gnu) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; netbsd*) ;; solaris*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs=no elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' else ld_shlibs=no fi ;; esac ;; sunos4*) hardcode_direct=yes ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then hardcode_libdir_flag_spec= fi else case "$host_os" in aix3*) # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac fi hardcode_direct=yes hardcode_libdir_separator=':' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac fi # Begin _LT_AC_SYS_LIBPATH_AIX. echo 'int main () { return 0; }' > conftest.c ${CC} ${LDFLAGS} conftest.c -o conftest aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` fi if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib" fi rm -f conftest.c conftest # End _LT_AC_SYS_LIBPATH_AIX. if test "$aix_use_runtimelinking" = yes; then hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' else hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" fi fi ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # see comment about different semantics on the GNU ld section ld_shlibs=no ;; bsdi[45]*) ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' libext=lib ;; darwin* | rhapsody*) hardcode_direct=no if test "$GCC" = yes ; then : else case $cc_basename in xlc*) ;; *) ld_shlibs=no ;; esac fi ;; dgux*) hardcode_libdir_flag_spec='-L$libdir' ;; freebsd1*) ld_shlibs=no ;; freebsd2.2*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; freebsd2*) hardcode_direct=yes hardcode_minus_L=yes ;; freebsd* | dragonfly*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; hpux9*) hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; hpux10*) if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no ;; *) hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; netbsd*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; newsos6) hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then hardcode_libdir_flag_spec='${wl}-rpath,$libdir' else case "$host_os" in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) hardcode_libdir_flag_spec='-R$libdir' ;; *) hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; osf3*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) if test "$GCC" = yes; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else # Both cc and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi hardcode_libdir_separator=: ;; solaris*) hardcode_libdir_flag_spec='-R$libdir' ;; sunos4*) hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes ;; sysv4) case $host_vendor in sni) hardcode_direct=yes # is this really true??? ;; siemens) hardcode_direct=no ;; motorola) hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac ;; sysv4.3*) ;; sysv4*MP*) if test -d /usr/nec; then ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) ;; sysv5* | sco3.2v5* | sco5v6*) hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' hardcode_libdir_separator=':' ;; uts4*) hardcode_libdir_flag_spec='-L$libdir' ;; *) ld_shlibs=no ;; esac fi # Check dynamic linker characteristics # Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER. # Unlike libtool.m4, here we don't care about _all_ names of the library, but # only about the one the linker finds when passed -lNAME. This is the last # element of library_names_spec in libtool.m4, or possibly two of them if the # linker has special search rules. library_names_spec= # the last element of library_names_spec in libtool.m4 libname_spec='lib$name' case "$host_os" in aix3*) library_names_spec='$libname.a' ;; aix[4-9]*) library_names_spec='$libname$shrext' ;; amigaos*) library_names_spec='$libname.a' ;; beos*) library_names_spec='$libname$shrext' ;; bsdi[45]*) library_names_spec='$libname$shrext' ;; cygwin* | mingw* | pw32* | cegcc*) shrext=.dll library_names_spec='$libname.dll.a $libname.lib' ;; darwin* | rhapsody*) shrext=.dylib library_names_spec='$libname$shrext' ;; dgux*) library_names_spec='$libname$shrext' ;; freebsd1*) ;; freebsd* | dragonfly*) case "$host_os" in freebsd[123]*) library_names_spec='$libname$shrext$versuffix' ;; *) library_names_spec='$libname$shrext' ;; esac ;; gnu*) library_names_spec='$libname$shrext' ;; hpux9* | hpux10* | hpux11*) case $host_cpu in ia64*) shrext=.so ;; hppa*64*) shrext=.sl ;; *) shrext=.sl ;; esac library_names_spec='$libname$shrext' ;; interix[3-9]*) library_names_spec='$libname$shrext' ;; irix5* | irix6* | nonstopux*) library_names_spec='$libname$shrext' case "$host_os" in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; *) libsuff= shlibsuff= ;; esac ;; esac ;; linux*oldld* | linux*aout* | linux*coff*) ;; linux* | k*bsd*-gnu) library_names_spec='$libname$shrext' ;; knetbsd*-gnu) library_names_spec='$libname$shrext' ;; netbsd*) library_names_spec='$libname$shrext' ;; newsos6) library_names_spec='$libname$shrext' ;; nto-qnx*) library_names_spec='$libname$shrext' ;; openbsd*) library_names_spec='$libname$shrext$versuffix' ;; os2*) libname_spec='$name' shrext=.dll library_names_spec='$libname.a' ;; osf3* | osf4* | osf5*) library_names_spec='$libname$shrext' ;; rdos*) ;; solaris*) library_names_spec='$libname$shrext' ;; sunos4*) library_names_spec='$libname$shrext$versuffix' ;; sysv4 | sysv4.3*) library_names_spec='$libname$shrext' ;; sysv4*MP*) library_names_spec='$libname$shrext' ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) library_names_spec='$libname$shrext' ;; uts4*) library_names_spec='$libname$shrext' ;; esac sed_quote_subst='s/\(["`$\\]\)/\\\1/g' escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` shlibext=`echo "$shrext" | sed -e 's,^\.,,'` escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <, 2009, French translation copyright # msgid "" msgstr "" "Project-Id-Version: barry 0.18.5\n" "Report-Msgid-Bugs-To: http://netdirect.ca/barry\n" "POT-Creation-Date: 2013-04-02 18:53-0400\n" "PO-Revision-Date: 2012-08-20 21:10+0100\n" "Last-Translator: Nicolas CARRIER \n" "Language-Team: Nicolas CARRIER \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Poedit-Language: French\n" "X-Poedit-Country: FRANCE\n" "X-Poedit-SourceCharset: utf-8\n" "X-Poedit-Basepath: ..\n" "X-Poedit-SearchPath-0: ..\n" #: src/a_application.cc:59 msgid " Application " msgstr " Application " #: src/a_application.cc:60 src/a_library.cc:60 msgid " ID : " msgstr " ID : " #: src/a_application.cc:61 src/a_library.cc:61 msgid " Description : " msgstr " Description : " #: src/a_application.cc:62 src/a_library.cc:62 msgid " Vendor : " msgstr " Vendeur : " #: src/a_application.cc:63 src/a_library.cc:63 msgid " Copyright : " msgstr " Copyright : " #: src/a_application.cc:64 src/a_library.cc:64 msgid " Required : " msgstr " Requis : " #: src/a_application.cc:64 src/a_library.cc:64 msgid "Yes" msgstr "Oui" #: src/a_application.cc:64 src/a_library.cc:64 msgid "No" msgstr "Non" #: src/a_application.cc:68 src/a_library.cc:68 msgid " Files : " msgstr " Fichiers : " #: src/a_library.cc:59 msgid " Library " msgstr " Bibliothèque " #: src/a_osloader.cc:74 msgid "Could not opendir: " msgstr "Échec d'opendir :" #: src/a_osloader.cc:97 msgid "Cannot open ALX file: " msgstr "Impossible d'ouvrir le fichier ALX :" #: src/a_osloader.cc:111 msgid "OS Properties :" msgstr "Propriétés du SE :" #: src/a_osloader.cc:123 msgid "SFI File :" msgstr "Fichier SFI :" #: src/a_osloader.cc:127 msgid "Applications :" msgstr "Applications :" #: src/a_osloader.cc:137 msgid "Libraries :" msgstr "Bibliothèques :" #: src/backup.cc:84 msgid "Backup: No database name available" msgstr "Sauvegarde : aucun nom de base de données disponibles" #: src/backup.cc:86 msgid "Backup: No unique ID available!" msgstr "Sauvegarde : aucun ID unique disponible !" #: src/bmp.cc:80 msgid "ScreenshotToRGB: depth must be 24 or 32" msgstr "ScreenshotToRGB : la profondeur doit être 24 ou 32" #: src/bmp.cc:100 msgid "" "ScreenshotToRGB: Screenshot data size is too small for given width+height" msgstr "" "ScreenshotToRGB : trop peu de données dans la capture d'écran, par rapport " "au format" #: src/bmp.cc:102 msgid "" "ScreenshotToRGB: Screenshot depth is not supported (Barry supports 2 byte or " "4 byte pixels in device screenshots)" msgstr "" "ScreenshotToRGB : profondeur de capture d'écran non supportée (Barry " "supporte 2 ou 4 octet par pixel)" #: src/bmp.cc:162 msgid "" "ScreenshotToRGB: bad switch value, should never happen. Double check the " "data_size check." msgstr "" "ScreenshotToRGB : mauvaise valeur de switch/case, ne devrait pas arriver. " "Vérifier data_size." #: src/bmp.cc:196 msgid "Screenshot data size is too small for given width+height" msgstr "Trop peu de données dans la capture d'écran, par rapport au format" #: src/builder.cc:54 msgid "DBDataBuilder: offset greater than size" msgstr "DBDataBuilder: offset plus grand que la taille" #: src/cod.cc:61 msgid "SeekNextCod: EOF while reading file signature" msgstr "" "SeekNextCod : fin de fichier prématurée lors de la lecture de la signature " "du fichier" #: src/cod.cc:70 msgid "SeekNextCod: EOF while reading PKZIP header" msgstr "" "SeekNextCod : fin de fichier prématurée lors de la lecture de l'en-tête PKZIP" #: src/cod.cc:76 msgid "SeekNextCod: EOF while skipping unused fields" msgstr "" "SeekNextCod : fin de fichier prématurée lors de la lecture des champs " "inutilisés" #: src/cod.cc:89 msgid "SeekNextCod: seek to end failed" msgstr "SeekNextCod : impossible de se rendre à la fin" #: src/cod.cc:95 msgid "SeekNextCod: seek to start failed" msgstr "SeekNextCod : impossible de se rendre au début" #: src/cod.cc:101 msgid "SeekNextCod: unknown COD file signature" msgstr "SeekNextCod : signature de fichier COD inconnue" #: src/common.cc:79 msgid "USB library failed to initialise with libusb error: " msgstr "" "L'initialisation de la bibliothèque USB a rencontré l'erreur suivante :" #: src/common.cc:80 msgid "Failed to initialise USB" msgstr "Impossible d'initialiser l'USB" #: src/configfile.cc:50 msgid "DBListType dump:\n" msgstr "Contenu de DBListType :\n" #: src/configfile.cc:77 src/configfile.cc:95 msgid "Configfile: empty pin" msgstr "Fichier de configuration : PIN vide" #: src/configfile.cc:193 src/configfile.cc:394 msgid "Unable to open file for writing: " msgstr "Impossible d'ouvrir le fichier en écriture :" #: src/configfile.cc:219 src/configfile.cc:411 msgid "Error during write. Config may be incomplete." msgstr "Erreur lord de l'écriture. La configuration risque d'être incomplète." #: src/configfile.cc:329 msgid "App name must have no spaces." msgstr "Le nom d'une application ne peut pas contenir d'espace." #: src/configfile.cc:420 src/configfile.cc:433 msgid "Cannot use SetKey() without specifying an appname in the constructor." msgstr "" "Impossible d'utiliser SetKey() dans spécifier de nom d'application dans le " "constructeur." #: src/configfile.cc:423 msgid "SetKey values may not contain newline characters." msgstr "Les valeurs de SetKey ne peuvent pas contenir de saut de ligne." #: src/configfileunix.cc:91 src/configfileunix.cc:151 msgid "BuildFilename: getpwuid failed" msgstr "BuildFilename : échec de getpwuid" #: src/configfileunix.cc:116 src/configfilewin32.cc:118 msgid "ConfigFile::CheckPath(): path is empty!" msgstr "ConfigFile::CheckPath(): le chemin est vide !" #: src/configfileunix.cc:130 msgid "mkdir() failed to create: " msgstr "mkdir() n'a pas réussi à créer :" #: src/configfileunix.cc:139 msgid "last mkdir() failed to create: " msgstr "Le dernier mkdir() a échoué à créer :" #: src/configfilewin32.cc:84 src/configfilewin32.cc:163 msgid "BuildFilename: SHGetSpecialFolderPath failed" msgstr "BuildFilename : SHGetSpecialFolderPath a échoué" #: src/configfilewin32.cc:87 src/configfilewin32.cc:104 #: src/configfilewin32.cc:166 msgid "BuildFilename: conversion failed" msgstr "BuildFilename : échec de la conversion" #: src/configfilewin32.cc:101 msgid "BuildDefaultPath: SHGetSpecialFolderPath failed" msgstr "BuildDefaultPath : SHGetSpecialFolderPath a échoué" #: src/configfilewin32.cc:125 msgid "Failed to convert to widechar" msgstr "La conversion en widechar a échoué" #: src/configfilewin32.cc:148 msgid "failed to create directory" msgstr "La création du répertoire a échoué" #: src/connector.cc:185 msgid "Timeout in Connector::Reconnect()... trying again" msgstr "Délai dépassé dans Connector::Reconnect()... Nouvelle tentative" #: src/controller.cc:52 msgid "Controller: Using non-threaded sockets" msgstr "Controller : utilisation de sockets non threadées" #: src/controller.cc:73 msgid "Controller: Using threaded socket router" msgstr "Controller : utilisation d'un routeur de socket threadé" #: src/controller.cc:86 msgid "Controller: GetConfiguration failed" msgstr "Controller : échec de GetConfiguration" #: src/controller.cc:91 msgid "Controller: SetConfiguration failed" msgstr "Controller : échec de SetConfiguration" #: src/controller.cc:146 msgid "Controller: explicit mode name too long" msgstr "Controller : nom de mode explicite trop long" #: src/controller.cc:179 msgid "Controller: No channel name given with RawChannel mode" msgstr "Controller : aucun nom de canal donné pour le mode RawChannel" #: src/controller.cc:183 msgid "Controller: Invalid mode in SelectMode" msgstr "Controller : mode invalide dans SelectMode" #: src/controller.cc:200 msgid "Controller: requested mode not supported" msgstr "Controller : le mode demandé n'est pas supporté" #: src/controller.cc:204 msgid "Controller: mode not selected" msgstr "Controller : pas de mode choisi" #: src/controller.cc:211 msgid "Controller: error setting desktop mode" msgstr "Controller : erreur lors de la définition du mode desktop" #: src/data.cc:293 msgid "Data::ReleaseBuffer() argument must be -1 or >= 0" msgstr "L'argument de Data::ReleaseBuffer() doit être -1 ou >= 0" #: src/data.cc:295 msgid "Data::ReleaseBuffer() must be called after GetBuffer()" msgstr "Data::ReleaseBuffer() doit être appelé après GetBuffer()" #: src/data.cc:297 msgid "" "Data::ReleaseBuffer() must be called with a size smaller than the original " "buffer requested" msgstr "" "Data::ReleaseBuffer() doit être appelé avec une taille plus petite que celle " "demandée pour le tampon original" #: src/data.cc:489 msgid "sizes differ: " msgstr "Les tailles sont différentes :" #: src/dp_codinfo.cc:171 src/m_jvmdebug.cc:89 msgid " UniqueID " msgstr " UniqueID " #: src/dp_codinfo.cc:172 msgid " Module Name " msgstr " Nom de Module " #: src/dp_codinfo.cc:173 msgid " File Name " msgstr " Nom de Fichier " #: src/error.cc:58 msgid "Bad packet size, not enough data: " msgstr "Mauvaise taille de paquet, pas assez de données :" #: src/error.cc:59 src/error.cc:68 msgid "DataSize(): " msgstr "DataSize() :" #: src/error.cc:60 src/error.cc:69 msgid "Required size: " msgstr "Taille requise :" #: src/error.cc:67 msgid "Bad packet size. Packet: " msgstr "Mauvaise taille de paquet. Paquet :" #: src/fifoargs.cc:105 msgid "Cannot open Barry argument fifo" msgstr "Impossible d'ouvrir la fifo passée en argument de Barry" #: src/j_jdwp.cc:94 msgid "Timeout in read" msgstr "Délai dépassé dans read" #: src/j_jdwp.cc:96 msgid "Error in read" msgstr "Erreur dans read" #: src/j_jdwp.cc:117 msgid "Timeout in write (1)" msgstr "Délai dépassé dans write (1)" #: src/j_jdwp.cc:119 msgid "Error in write (1)" msgstr "Erreur dans write (1)" #: src/j_jdwp.cc:137 msgid "Timeout in write (2)" msgstr "Délai dépassé dans write (2)" #: src/j_jdwp.cc:139 msgid "Error in write (2)" msgstr "Erreur dans write (2)" #: src/j_server.cc:91 msgid "HOST_NOT_FOUND: The specified host is unknown" msgstr "HOST_NOT_FOUND : l'hôte spécifié est inconnu" #: src/j_server.cc:94 msgid "NO_ADDRESS: The requested name is valid but does not have an IP address" msgstr "NO_ADDRESS : le nom requis est valide, mais n'a pas d'adresse IP" #: src/j_server.cc:97 msgid "NO_RECOVERY: A non-recoverable name server error occurred" msgstr "" "NO_RECOVERY : une erreur no récupérable, de serveur de nom est survenue" #: src/j_server.cc:100 msgid "" "TRY_AGAIN: A temporary error occurred on an authoritative name server. Try " "again later." msgstr "" "TRY_AGAIN : une erreur temporaire est survenue avec un serveur de nom " "faisant autorité. Réessayer plus tard." #: src/j_server.cc:103 msgid "Unknown network error code" msgstr "Erreur réseau de code inconnu." #: src/j_server.cc:142 msgid "JDWServer::Start: Cannot open socket." msgstr "JDWServer::Start : Impossible d'ouvrir la socket." #: src/j_server.cc:154 msgid "JDWServer::Start: Cannot bind socket" msgstr "JDWServer::Start : Impossible d'associer la socket." #: src/j_server.cc:164 msgid "JDWServer::Start: Cannot listen on socket" msgstr "JDWServer::Start : Impossible d'écouter sur la socket." #: src/j_server.cc:237 msgid "No debug information found for: " msgstr "Aucune information de débogage trouvée pour :" #: src/j_server.cc:321 src/j_server.cc:350 msgid "Packet size error !!!" msgstr "Taille de paquet erronée !!!" #: src/j_server.cc:491 msgid "Commandset unknown !!!" msgstr "Ensemble de commandes inconnu !!!" #: src/ldif.cc:39 msgid "Email address" msgstr "Adresse électronique" #: src/ldif.cc:41 src/r_calllog.cc:84 msgid "Phone number" msgstr "Numéro de téléphone" #: src/ldif.cc:43 msgid "Fax number" msgstr "Numéro de fax" #: src/ldif.cc:45 msgid "Work phone number" msgstr "Numéro de téléphone professionnel" #: src/ldif.cc:47 msgid "Home phone number" msgstr "Numéro de téléphone du domicile" #: src/ldif.cc:49 msgid "Mobile phone number" msgstr "Numéro de téléphone mobile" #: src/ldif.cc:51 msgid "Pager number" msgstr "Numéro de pager" #: src/ldif.cc:53 src/r_contact.cc:118 src/r_contact.cc:503 #: src/r_hhagent.cc:69 src/r_hhagent.cc:105 src/r_hhagent.cc:290 msgid "PIN" msgstr "PIN" #: src/ldif.cc:55 msgid "First name" msgstr "Prénom" #: src/ldif.cc:57 msgid "Last name" msgstr "Nom de famille" #: src/ldif.cc:59 msgid "Company name" msgstr "Nom de société" #: src/ldif.cc:61 msgid "Default communications method" msgstr "Méthode de communication par défaut" #: src/ldif.cc:63 msgid "Work Address, line 1" msgstr "Adresse professionnelle, ligne 1" #: src/ldif.cc:65 msgid "Work Address, line 2" msgstr "Adresse professionnelle, ligne 2" #: src/ldif.cc:67 msgid "Work Address, line 3" msgstr "Adresse professionnelle, ligne 3" #: src/ldif.cc:69 src/r_contact.cc:128 msgid "WorkCity" msgstr "Ville du lieu de travail" #: src/ldif.cc:71 msgid "WorkProvince / State" msgstr "Département / état du lieu de travail" #: src/ldif.cc:73 msgid "Work Postal / ZIP code" msgstr "Code postal / ZIP du lieu de travail" #: src/ldif.cc:75 src/r_contact.cc:131 msgid "WorkCountry" msgstr "Pays du lieu de travail" #: src/ldif.cc:77 src/r_contact.cc:487 msgid "Job Title" msgstr "Titre professionnel" #: src/ldif.cc:79 msgid "Public key" msgstr "Clef publique" #: src/ldif.cc:81 src/r_calendar.cc:107 src/r_calendar.cc:434 #: src/r_contact.cc:139 src/r_contact.cc:509 src/r_task.cc:108 #: src/r_task.cc:399 msgid "Notes" msgstr "Notes" #: src/ldif.cc:83 msgid "Contact photo" msgstr "Photo du contact" #: src/ldif.cc:85 msgid "" "Mailing Work address (includes address lines, city, province, country, and " "postal code)" msgstr "" "Adresse postale professionnelle (inclue les lignes d'adresse, la ville, le " "département, le pays et le code postal)" #: src/ldif.cc:87 msgid "" "Mailing home address (includes address lines, city, province, country, and " "postal code)" msgstr "" "Adresse postale personnelle (inclue les lignes d'adresse, la ville, le " "département, le pays et le code postal)" #: src/ldif.cc:89 msgid "First + Last names" msgstr "Prénom + Nom" #: src/ldif.cc:91 msgid "Fully qualified domain name" msgstr "Nom de domaine pleinement qualifié" #: src/ldif.cc:213 src/ldif.cc:222 msgid "" msgstr "" #: src/ldif.cc:437 src/r_calllog.cc:338 src/r_message_base.cc:391 msgid "unknown" msgstr "inconnu" #: src/ldif.cc:782 msgid "ContactLdif Mapping:\n" msgstr "Correspondance ContactLdif :\n" #: src/ldif.cc:801 msgid " >>> DN attribute: " msgstr " >>> Attribut DN : " #: src/m_desktop.cc:89 msgid "Desktop: error getting command table" msgstr "Desktop : échec lors de la récupération de la table des commandes" #: src/m_desktop.cc:139 msgid "Desktop: database name not found: " msgstr "Desktop : nom de base de données non trouvé :" #: src/m_desktop.cc:162 msgid "Desktop: unknown command type" msgstr "Desktop : type de commande inconnu" #: src/m_desktop.cc:167 msgid "Desktop: unable to get command code: " msgstr "Desktop : impossible d'obtenir le code de commande :" #: src/m_desktop.cc:188 src/m_desktop.cc:214 src/m_desktop.cc:251 #: src/m_desktop.cc:301 src/m_desktop.cc:336 src/m_desktop.cc:355 #: src/m_desktop.cc:406 src/m_desktop.cc:431 src/m_desktop.cc:440 #: src/m_desktop.cc:490 msgid "Database ID: " msgstr "ID de base de donnée :" #: src/m_desktop.cc:226 src/m_desktop.cc:316 src/m_desktop.cc:448 msgid "Desktop: device responded with unexpected packet command code: " msgstr "" "Desktop : le périphérique a répondu avec un code de commande de paquet " "inattendu :" #: src/m_desktop.cc:232 src/m_desktop.cc:322 src/m_desktop.cc:454 msgid "Desktop: device responded with error code (command: " msgstr "Desktop : le périphérique a répondu avec le code d'erreur (commande :" #: src/m_desktop.cc:233 src/m_desktop.cc:323 src/m_desktop.cc:417 #: src/m_desktop.cc:455 msgid "code: " msgstr "code :" #: src/m_desktop.cc:266 msgid "Desktop: invalid response packet size of: " msgstr "Desktop : taille de paquet invalide de :" #: src/m_desktop.cc:275 msgid "Desktop: unexpected command of " msgstr "Desktop : commande inattendue de :" #: src/m_desktop.cc:277 msgid " instead of expected " msgstr " au lieu de " #: src/m_desktop.cc:301 msgid "Index: " msgstr "Index :" #: src/m_desktop.cc:307 msgid "Desktop: no data available in SetRecord" msgstr "Desktop : Pas de données dans SetRecord" #: src/m_desktop.cc:415 msgid "Desktop: could not clear database: (command: " msgstr "" "Desktop : Impossible de réinitialiser la base de données : (commande : " #: src/m_desktop.cc:425 msgid "Desktop: error clearing database, bad response" msgstr "" "Desktop : erreur lors de la réinitialisation de la base de données, réponse " "incorrecte" #: src/m_desktop.cc:670 msgid "This database does not exist in device: " msgstr "Cette base de données n'existe pas sur le périphérique : " #: src/m_desktop.cc:670 msgid "Dropping record." msgstr "Enregistrement ignoré." #: src/m_desktop.cc:700 src/m_desktop.cc:757 msgid "DeviceParser: unknown mode" msgstr "DeviceParser : mode inconnu" #: src/m_ipmodem.cc:60 msgid "Exception caught in IpModem destructor, ignoring: " msgstr "Exception attrapée dans le destructeur d'IpModem, ignorée : " #: src/m_ipmodem.cc:68 msgid "Logic error: No password provided in SendPassword." msgstr "Erreur de logique : Pas de mot de passe fourni dans SendPassword." #: src/m_ipmodem.cc:80 msgid "No password provided." msgstr "Pas de mot de passe fourni." #: src/m_ipmodem.cc:149 src/socket.cc:481 msgid "Password rejected by device." msgstr "Mot de passe refusé par le périphérique." #: src/m_ipmodem.cc:198 msgid "Exception in IpModem::DataReadThread: " msgstr "Exception dans IpModem::DataReadThread : " #: src/m_ipmodem.cc:220 msgid "IP Modem not supported by this device: " msgstr "Modem IP non supporté par ce périphérique : " #: src/m_ipmodem.cc:260 src/socket.cc:467 #, c-format msgid "" "Fewer than %d password tries remaining in device. Refusing to proceed, to " "avoid device zapping itself. Use a Windows client, or re-cradle the device." msgstr "" "Moins de %d tentatives de mot de passe restantes avec ce périphérique. On " "refuse de continuer, pour éviter que le device ne se petit-suicide. Utilisez " "un client windows ou " #: src/m_ipmodem.cc:267 src/m_ipmodem.cc:299 src/m_ipmodem.cc:338 msgid "IpModem: Error sending password." msgstr "IpModem : erreur à l'envoi du mot de passe." #: src/m_ipmodem.cc:332 msgid "This device requested a password." msgstr "Ce périphérique a demandé un mot de passe." #: src/m_ipmodem.cc:346 msgid "This device requires a password." msgstr "Ce périphérique nécessite un mot de passe" #: src/m_ipmodem.cc:366 msgid "IpModem: Error creating USB read thread." msgstr "IpModem : erreur lors de la création du thread de lecture" #: src/m_javaloader.cc:242 msgid "JLEventlogEntry:Parse bad guid field" msgstr "JLEventlogEntry : décodage, mauvais champ guid" #: src/m_javaloader.cc:247 msgid "JLEventlogEntry:Parse bad time field" msgstr "JLEventlogEntry : décodage, mauvais champ time" #: src/m_javaloader.cc:254 msgid "JLEventlogEntry:Parse bad severity field" msgstr "JLEventlogEntry : décodage, mauvais champ severity" #: src/m_javaloader.cc:261 msgid "JLEventlogEntry:Parse bad type field" msgstr "JLEventlogEntry : décodage, mauvais champ type" #: src/m_javaloader.cc:266 msgid "JLEventlogEntry:Parse bad app field" msgstr "JLEventlogEntry : décodage, mauvais champ app" #: src/m_javaloader.cc:274 msgid "JLEventlogEntry:Parse bad data field" msgstr "JLEventlogEntry : décodage, mauvais champ data" #: src/m_javaloader.cc:301 msgid "Always Log" msgstr "Toujours afficher la sortie" #: src/m_javaloader.cc:302 msgid "Severe Error" msgstr "Erreur sévère" #: src/m_javaloader.cc:303 src/r_calllog.cc:266 msgid "Error" msgstr "Erreur" #: src/m_javaloader.cc:304 msgid "Warning" msgstr "avertissement" #: src/m_javaloader.cc:305 msgid "Information" msgstr "Information" #: src/m_javaloader.cc:306 msgid "Debug Info" msgstr "Information de débogage" #: src/m_javaloader.cc:310 msgid "Number" msgstr "Nombre" #: src/m_javaloader.cc:311 msgid "String" msgstr "Chaîne" #: src/m_javaloader.cc:312 msgid "Exception" msgstr "Exception" #: src/m_javaloader.cc:315 msgid "guid:" msgstr "guid : " #: src/m_javaloader.cc:316 msgid " time:" msgstr " moment : " #: src/m_javaloader.cc:317 msgid " severity:" msgstr " sévérité : " #: src/m_javaloader.cc:318 msgid " type:" msgstr " type : " #: src/m_javaloader.cc:319 msgid " app:" msgstr " application : " #: src/m_javaloader.cc:320 msgid " data:" msgstr " données : " #: src/m_javaloader.cc:331 msgid "Hardware Id:" msgstr "Id de matériel : " #: src/m_javaloader.cc:334 msgid "PIN:" msgstr "PIN : " #: src/m_javaloader.cc:337 msgid "OS Version:" msgstr "Version de SE : " #: src/m_javaloader.cc:340 msgid "VM Version:" msgstr "Version de VM : " #: src/m_javaloader.cc:343 msgid "Radio ID:" msgstr "ID Radio : " #: src/m_javaloader.cc:346 msgid "Vendor ID:" msgstr "ID de vendeur : " #: src/m_javaloader.cc:350 msgid "Active Wireless Access Families:" msgstr "Familles d'accès sans fil actives : " #: src/m_javaloader.cc:353 msgid "OS Metrics:" msgstr "Métriques du SE : " #: src/m_javaloader.cc:356 msgid "Bootrom Metrics:" msgstr "Métriques du bootrom : " #: src/m_javaloader.cc:409 msgid "JavaLoader::StartStream Hello" msgstr "JavaLoader::StartStream bonjour" #: src/m_javaloader.cc:416 msgid "JavaLoader::StartStream Unknown1" msgstr "JavaLoader::StartStream inconnu1" #: src/m_javaloader.cc:467 msgid "JavaLoader::SendStream: set code size first" msgstr "JavaLoader::SendStream : définir la taille du code en premier" #: src/m_javaloader.cc:475 msgid "JavaLoader::SendStream: input stream read failed" msgstr "JavaLoader::SendStream : erreur à la lecture du flux d'entrée" #: src/m_javaloader.cc:482 msgid "JavaLoader::SendStream: not enough memory to install the application" msgstr "" "JavaLoader::SendStream : plus assez de mémoire pour installer l'application" #: src/m_javaloader.cc:486 msgid "JavaLoader::SendStream: send data" msgstr "JavaLoader::SendStream : envoi de données" #: src/m_javaloader.cc:538 msgid "JavaLoader::StopStream error" msgstr "JavaLoader::StopStream erreur" #: src/m_javaloader.cc:552 msgid "JavaLoader::SetTime error" msgstr "JavaLoader::SetTime erreur" #: src/m_javaloader.cc:559 src/m_jvmdebug.cc:260 msgid "unexpected packet command code: " msgstr "Code de commande de paquet inattendu : " #: src/m_javaloader.cc:723 msgid "JavaLoader::GetScreenShot expect" msgstr "JavaLoader::GetScreenShot attend" #: src/m_javaloader.cc:746 msgid "JavaLoader::DoErase: module not found: " msgstr "JavaLoader::DoErase : module non trouvé : " #: src/m_javaloader.cc:754 msgid "JavaLoader::DoErase: expected code ID not available" msgstr "JavaLoader::DoErase : ID du code attendue non disponible" #: src/m_javaloader.cc:766 msgid "JavaLoader::DoErase: COD file in use." msgstr "JavaLoader::DoErase : fichier COD en cours d'utilisation." #: src/m_javaloader.cc:898 msgid "JavaLoader::Save: module not found: " msgstr "JavaLoader::Save : module non trouvé : " #: src/m_javaloader.cc:907 msgid "JavaLoader::Save: expected module ID, but not available" msgstr "JavaLoader::Save : ID de module attendu, mais non disponbile" #: src/m_jvmdebug.cc:88 msgid " ID " msgstr " ID " #: src/m_jvmdebug.cc:90 msgid " Module Name" msgstr " Nom de Module" #: src/m_jvmdebug.cc:152 msgid " Thread " msgstr " Thread " #: src/m_jvmdebug.cc:153 msgid " Address " msgstr " Adresse " #: src/m_jvmdebug.cc:154 msgid " Byte " msgstr " Octet " #: src/m_jvmdebug.cc:155 msgid " Unknown01 " msgstr " Inconnu01 " #: src/m_jvmdebug.cc:156 msgid " Unknown02 " msgstr " Inconnu02 " #: src/m_jvmdebug.cc:157 msgid " Unknown03 " msgstr " Inconnu03 " #: src/m_jvmdebug.cc:158 msgid " Unknown04 " msgstr " Inconnu04 " #: src/m_jvmdebug.cc:159 msgid " Unknown05 " msgstr " Inconnu05 " #: src/m_jvmdebug.cc:160 msgid " Unknown06 " msgstr " Inconnu06 " #: src/m_jvmdebug.cc:291 src/m_jvmdebug.cc:321 src/m_jvmdebug.cc:351 #: src/m_jvmdebug.cc:381 src/m_jvmdebug.cc:411 src/m_jvmdebug.cc:441 #: src/m_jvmdebug.cc:471 src/m_jvmdebug.cc:501 src/m_jvmdebug.cc:531 #: src/m_jvmdebug.cc:561 src/m_jvmdebug.cc:595 src/m_jvmdebug.cc:641 #: src/m_jvmdebug.cc:686 src/m_jvmdebug.cc:741 src/m_jvmdebug.cc:802 #: src/m_jvmdebug.cc:843 src/m_jvmdebug.cc:873 src/m_jvmdebug.cc:904 #: src/m_jvmdebug.cc:931 src/m_jvmdebug.cc:959 src/m_jvmdebug.cc:1001 #: src/m_jvmdebug.cc:1034 msgid "byte count mismatch" msgstr "nombre d'octets incohérent" #: src/m_mode_base.cc:142 msgid "Socket alreay open in RetryPassword" msgstr "Socket déjà ouverte dans RetryPasswort" #: src/m_raw_channel.cc:116 msgid "RawChannel: No routing queue set in controller" msgstr "RawChannel : pas de file de routage définie dans le contrôleur" #: src/m_raw_channel.cc:165 msgid "RawChannel: Got packet not for socket-zero" msgstr "RawChannel : non-paquet obtenu pour la socket zéro" #: src/m_raw_channel.cc:183 src/m_raw_channel.cc:186 msgid "RawChannel: Got unexpected socket zero packet" msgstr "RawChannel : paquet inattendu pour la socket zéro" #: src/m_raw_channel.cc:205 msgid "RawChannel: Received data to handle when in non-callback mode" msgstr "RawChannel : données à traiter reçues sans être en mode callback" #: src/m_raw_channel.cc:212 msgid "RawChannel: Socket error received, what: " msgstr "RawChannel : reçu une erreur de socket : " #: src/m_raw_channel.cc:245 msgid "RawChannel: send data size larger than MaximumPacketSize" msgstr "RawChannel : envoi de données de taille supérieure à MaximumPacketSize" #: src/m_raw_channel.cc:268 msgid "RawChannel: Receive called when channel was created with a callback" msgstr "" "RawChannel : Receive a été appelée alors que le canal a été créé avec une " "callback" #: src/m_raw_channel.cc:293 msgid "RawChannel: Data size doesn't match packet size" msgstr "" "RawChannel : la taille des données ne correspond pas à la taille du paquet" #: src/m_serial.cc:45 msgid "" "A SocketRoutingQueue is required in the Controller class when using Mode::" "Serial." msgstr "" "Une SocketRoutingQueue est requise dans la classe Controller en Mode::Serial." #: src/m_serial.cc:156 msgid "Must call Open() before Write() in Mode::Serial" msgstr "Appeler Open() avant Write() en Mode::Serial" #: src/packet.cc:465 msgid "Attempting to extract a return code from the wrong response packet type" msgstr "" "Tentative d'extraire un code de retour depuis un type de paquet réponse " "invalide" #: src/parser.cc:62 msgid "Records for database: " msgstr "Enregistrements pour la base de données : " #: src/parser.cc:66 tools/bfuse.cc:128 msgid "Raw record dump for record: " msgstr "Données brutes de l'enregistrement : " #: src/parser.cc:68 msgid "type: " msgstr "type : " #: src/parser.cc:70 msgid "offset: " msgstr "offset : " #: src/probe.cc:95 msgid "Probe: Parse data failure: " msgstr "Probe : échec de l'interprétation des données : " #: src/probe.cc:172 #, c-format msgid "Probe logged %u exception messages:" msgstr "Probe a enregistré %u messages d'exception :" #: src/probe.cc:195 msgid "Usb::Error exception caught: " msgstr "Exception Usb::Erreur attrapée : " #: src/probe.cc:224 msgid "Probe: No device descriptor for BlackBerry config (config id: " msgstr "" "Probe : pas de descripteur de périphérique pour la configuration BlackBerry " "(id de configuration : " #: src/probe.cc:236 #, c-format msgid "Probe: Interface with BLACKBERRY_DB_CLASS (%u) not found." msgstr "Probe : pas d'interface de classe BLACKBERRY_DB_CLASS (%u) trouvée." #: src/probe.cc:248 msgid "Probe: endpoint invalid." msgstr "Probe : endpoint invalide." #: src/probe.cc:250 msgid "true" msgstr "vrai" #: src/probe.cc:250 msgid "false" msgstr "faux" #: src/probe.cc:271 msgid "Probe: GetConfiguration failed" msgstr "Probe : échec de GetConfiguration" #: src/probe.cc:275 msgid "Probe: SetConfiguration failed" msgstr "Probe : échec de SetConfiguration" #: src/probe.cc:293 msgid "" "Probe: probing endpoints failed, retrying after setting alternate interface" msgstr "" "Probe : recherche d'endpoints infructueuse, nouvelle tentative sur " "l'interface alternative" #: src/probe.cc:318 msgid "Unable to discover endpoint pair for one device." msgstr "Pas de paire de endpoints trouve pour un périphérique." #: src/probe.cc:366 msgid "Probe: Skipping non-bulk endpoint pair (offset: " msgstr "Probe : paire de endpoints non-bulk ignorée (offset : " #: src/probe.cc:418 msgid "Probe: Intro(0) failed, retrying after clearing halt" msgstr "Détection : Intro(0) a échoué, nouvelle tentative après clear halt" #: src/probe.cc:426 msgid "Probe: Intro(0) still failed after clearing halt" msgstr "Probe : Intro(0) a échoué, malgré un clear halt" #: src/probe.cc:448 msgid "Probe: unable to fetch PIN" msgstr "Probe : impossible de récupérer le PIN" #: src/probe.cc:460 msgid "Probe: unable to fetch description" msgstr "Probe : impossible de récupérer la description" #: src/probe.cc:567 msgid "Device ID: " msgstr "ID du périphérique : " #: src/probe.cc:568 msgid "PIN: " msgstr "PIN : " #: src/probe.cc:569 msgid "Description: " msgstr "Description : " #: src/probe.cc:571 msgid "Name: " msgstr "Nom : " #: src/r_bookmark.cc:275 msgid "Bookmark::ParseField: BookmarkType is not 'D'" msgstr "Bookmark::ParseField : le BookmarkType n'est pas 'D'" #: src/r_bookmark.cc:325 src/r_bookmark.cc:331 src/r_bookmark.cc:337 #: src/r_bookmark.cc:418 src/r_bookmark.cc:424 msgid "Automatic" msgstr "Automatique" #: src/r_bookmark.cc:326 src/r_bookmark.cc:332 src/r_bookmark.cc:425 msgid "Enabled" msgstr "Activé" #: src/r_bookmark.cc:327 src/r_bookmark.cc:333 src/r_bookmark.cc:426 msgid "Disabled" msgstr "Désactivé" #: src/r_bookmark.cc:328 src/r_bookmark.cc:334 src/r_bookmark.cc:341 #: src/r_bookmark.cc:421 src/r_bookmark.cc:427 src/r_calllog.cc:276 #: src/r_calllog.cc:404 src/r_folder.cc:265 src/r_message_base.cc:361 #: src/r_message_base.cc:368 src/r_sms.cc:283 msgid "Unknown" msgstr "Inconnu" #: src/r_bookmark.cc:338 msgid "BlackBerry" msgstr "BlackBerry" #: src/r_bookmark.cc:339 msgid "FireFox" msgstr "FireFox" #: src/r_bookmark.cc:340 msgid "Internet Explorer" msgstr "Internet Explorer" #: src/r_bookmark.cc:344 msgid "Bookmark entry: " msgstr "Entrée de marque-page : " #: src/r_bookmark.cc:346 msgid "index " msgstr "index " #: src/r_bookmark.cc:349 msgid " Name: " msgstr " Nom : " #: src/r_bookmark.cc:351 msgid " Icon: " msgstr " Icône : " #: src/r_bookmark.cc:353 msgid " Url: " msgstr " Url : " #: src/r_bookmark.cc:354 msgid " Display mode: " msgstr " Mode d'affichage : " #: src/r_bookmark.cc:356 msgid " JavaScript mode: " msgstr " Mode JavaScript : " #: src/r_bookmark.cc:358 #, fuzzy msgid " Browser Identity: " msgstr " Nom du navigateur : " #: src/r_bookmark.cc:401 msgid "Record Type" msgstr "Type d'enregistrement" #: src/r_bookmark.cc:402 src/r_calendar.cc:430 src/r_calllog.cc:380 #: src/r_cstore.cc:229 src/r_folder.cc:210 src/r_hhagent.cc:284 #: src/r_memo.cc:268 src/r_message_base.cc:334 src/r_servicebook.cc:447 #: src/r_sms.cc:280 src/r_task.cc:396 src/r_timezone.cc:227 msgid "Unique Record ID" msgstr "ID unique d'enregistrement" #: src/r_bookmark.cc:404 msgid "Bookmark Field Index" msgstr "Indice de champ de marque-page" #: src/r_bookmark.cc:406 msgid "Site Name" msgstr "Nom du site" #: src/r_bookmark.cc:407 msgid "Site Icon" msgstr "Icône du site" #: src/r_bookmark.cc:408 msgid "Site URL" msgstr "URL du site" #: src/r_bookmark.cc:410 msgid "Browser Identity" msgstr "Identité du navigateur" #: src/r_bookmark.cc:411 msgid "Auto detect browser" msgstr "Détecter le navigateur automatiquement" #: src/r_bookmark.cc:412 msgid "BlackBerry browser" msgstr "Navigateur BlackBerry" #: src/r_bookmark.cc:413 msgid "FireFox browser" msgstr "Navigateur FireFox" #: src/r_bookmark.cc:414 msgid "Internet Explorer browser" msgstr "Navigateur Internet Explorer" #: src/r_bookmark.cc:415 msgid "Unknown browser" msgstr "Navigateur inconnu" #: src/r_bookmark.cc:417 msgid "Display Mode" msgstr "Mode d'affichage" #: src/r_bookmark.cc:419 msgid "Column" msgstr "Colonne" #: src/r_bookmark.cc:420 msgid "Page" msgstr "Page" #: src/r_bookmark.cc:423 msgid "JavaScript Mode" msgstr "Mode JavaScript" #: src/r_bookmark.cc:429 src/r_calendar.cc:458 src/r_calllog.cc:412 #: src/r_contact.cc:553 src/r_cstore.cc:236 src/r_folder.cc:231 #: src/r_hhagent.cc:298 src/r_memo.cc:274 src/r_message_base.cc:370 #: src/r_servicebook.cc:462 src/r_sms.cc:312 src/r_task.cc:425 #: src/r_timezone.cc:238 msgid "Unknown Fields" msgstr "Champs inconnus" #: src/r_calendar.cc:106 src/r_calendar.cc:433 src/r_message_base.cc:86 #: src/r_message_base.cc:342 msgid "Subject" msgstr "Sujet" #: src/r_calendar.cc:108 src/r_calendar.cc:435 msgid "Location" msgstr "Emplacement" #: src/r_calendar.cc:109 msgid "Notification Time" msgstr "Date de notification" #: src/r_calendar.cc:110 src/r_calendar.cc:438 src/r_task.cc:109 #: src/r_task.cc:403 msgid "Start Time" msgstr "Date de début" #: src/r_calendar.cc:111 src/r_calendar.cc:439 msgid "End Time" msgstr "Date de fin" #: src/r_calendar.cc:112 src/r_calendar.cc:440 msgid "Organizer" msgstr "Organiseur" #: src/r_calendar.cc:113 src/r_calendar.cc:441 msgid "Accepted By" msgstr "Accepté par" #: src/r_calendar.cc:114 src/r_calendar.cc:442 msgid "Invited" msgstr "Invité" #: src/r_calendar.cc:115 src/r_calllog.cc:86 src/r_folder.cc:85 #: src/r_hhagent.cc:71 src/r_hhagent.cc:76 src/r_hhagent.cc:81 #: src/r_hhagent.cc:90 src/r_hhagent.cc:95 src/r_hhagent.cc:108 #: src/r_memo.cc:52 src/r_message_base.cc:89 src/r_servicebook.cc:55 #: src/r_servicebook.cc:254 src/r_servicebook.cc:261 src/r_servicebook.cc:270 #: src/r_task.cc:112 src/r_timezone.cc:60 msgid "End of List" msgstr "Fin de liste" #: src/r_calendar.cc:212 msgid "Calendar::ParseField: unknown appointment type" msgstr "Calendar::ParseField : type de rendez-vous inconnu" #: src/r_calendar.cc:227 msgid "Calendar::ParseField: not enough data in time zone code field" msgstr "" "Calendar::ParseField : pas assez de données dans le champ de code de zone de " "temps" #: src/r_calendar.cc:233 msgid "Calendar::ParseField: FreeBusyFlag out of range" msgstr "Calendar::ParseField : FreeBusyFlag hors d'intervalle" #: src/r_calendar.cc:243 msgid "Calendar::ParseField: size data unknown in calendar field" msgstr "" "Calendar::ParseField : donnée de taille inconnue dans le champ de calendrier" #: src/r_calendar.cc:249 msgid "Calendar::ParseField: ClassFlag out of range" msgstr "Calendar::ParseField : ClassFlag hors d'intervalle" #: src/r_calendar.cc:429 src/r_calllog.cc:379 src/r_contact.cc:480 #: src/r_cstore.cc:228 src/r_folder.cc:209 src/r_hhagent.cc:283 #: src/r_memo.cc:267 src/r_message_base.cc:333 src/r_servicebook.cc:446 #: src/r_sms.cc:279 src/r_task.cc:395 src/r_timezone.cc:226 msgid "Record Type Code" msgstr "Code de type d'enregistrement" #: src/r_calendar.cc:432 msgid "All Day Event" msgstr "Événement sur toute une journée" #: src/r_calendar.cc:436 msgid "Notification Time (0 is off)" msgstr "Moment de la notification (0 pour désactivée)" #: src/r_calendar.cc:444 msgid "Free or Busy Flag" msgstr "Étiquette Libre ou Occupé" #: src/r_calendar.cc:445 src/r_calendar.cc:486 msgid "Free" msgstr "Libre" #: src/r_calendar.cc:446 src/r_calendar.cc:487 msgid "Tentative" msgstr "Provisoire" #: src/r_calendar.cc:447 src/r_calendar.cc:488 src/r_calllog.cc:265 #: src/r_calllog.cc:395 src/usbwrap_libusb_1_0.cc:103 msgid "Busy" msgstr "Occupé" #: src/r_calendar.cc:448 src/r_calendar.cc:489 msgid "Out of Office" msgstr "Parti du bureau" #: src/r_calendar.cc:450 msgid "Event Class" msgstr "Classe d'événement" #: src/r_calendar.cc:451 src/r_calendar.cc:481 msgid "Public" msgstr "Publique" #: src/r_calendar.cc:452 src/r_calendar.cc:482 src/r_message_base.cc:367 msgid "Confidential" msgstr "Confidentiel" #: src/r_calendar.cc:453 src/r_calendar.cc:483 src/r_message_base.cc:366 msgid "Private" msgstr "Privé" #: src/r_calendar.cc:455 src/r_task.cc:406 msgid "Time Zone Code" msgstr "Code de zone de temps" #: src/r_calendar.cc:456 msgid "Time Zone Validity" msgstr "Validité de la zone de temps" #: src/r_calendar.cc:463 src/r_calendar.cc:598 msgid "Calendar ID" msgstr "ID de calendrier" #: src/r_calendar.cc:492 msgid " Calendar ID: " msgstr " ID de calendrier : " #: src/r_calendar.cc:494 msgid " All Day Event: " msgstr " Évenement sur toute une journée : " #: src/r_calendar.cc:495 msgid " Class: " msgstr " Classe : " #: src/r_calendar.cc:496 msgid " Free/Busy: " msgstr " Libre/Occupé : " #: src/r_calendar.cc:498 src/r_task.cc:486 msgid " Time Zone: " msgstr " Zone de temps : " #: src/r_calendar.cc:509 msgid "Calendar entry: " msgstr "Entrée de calendrier : " #: src/r_calendar.cc:528 msgid "disabled" msgstr "désactivé" #: src/r_calendar.cc:601 msgid "Mail Account" msgstr "Compte de courriel" #: src/r_calendar.cc:640 msgid "CalendarAll::ParseField: size data unknown in calendar field" msgstr "" "CalendarAll::ParseField : donnée de taille inconnue dans le champ de " "calendrier" #: src/r_calendar.cc:653 msgid "CalendarAll::ParseHeader: size data unknown in calendar field" msgstr "" "CalendarAll::ParseHeader : donnée de taille inconnue dans le champ de " "calendrier" #: src/r_calendar.cc:673 msgid " Mail Account: " msgstr " Compte de courriel: " #: src/r_calllog.cc:85 msgid "Contact name" msgstr "Nom de contact" #: src/r_calllog.cc:114 msgid "CallLog::ParseField: CallLogType is not 'p'" msgstr "CallLog::ParseField : CallLogType n'est pas 'p'" #: src/r_calllog.cc:167 msgid "CallLog::ParseField: direction field out of bounds" msgstr "CallLog::ParseField: le champ direction est hors limites" #: src/r_calllog.cc:258 src/r_sms.cc:284 msgid "Received" msgstr "Reçu" #: src/r_calllog.cc:259 src/r_folder.cc:221 src/r_folder.cc:252 #: src/r_sms.cc:285 msgid "Sent" msgstr "Envoyé" #: src/r_calllog.cc:260 msgid "Call Missing (Messagerie)" msgstr "Appel manqué (Messagerie)" #: src/r_calllog.cc:261 msgid "Call Missing" msgstr "Appel manqué" #: src/r_calllog.cc:264 src/r_calllog.cc:394 msgid "OK" msgstr "OK" #: src/r_calllog.cc:267 src/r_calllog.cc:280 msgid "Not supported by Barry" msgstr "Non supporté dans Barry" #: src/r_calllog.cc:270 src/r_calllog.cc:400 src/r_calllog.cc:407 msgid "Undefined" msgstr "Indéfini" #: src/r_calllog.cc:271 msgid "Known phone number" msgstr "Numéro de téléphone connu" #: src/r_calllog.cc:272 msgid "Unknown phone number" msgstr "Numéro de téléphone inconnu" #: src/r_calllog.cc:273 msgid "Private phone number" msgstr "Numéro de téléphone privé" #: src/r_calllog.cc:277 src/r_calllog.cc:401 msgid "Office" msgstr "Bureau" #: src/r_calllog.cc:278 src/r_calllog.cc:402 msgid "Home" msgstr "Domicile" #: src/r_calllog.cc:279 src/r_calllog.cc:403 msgid "Mobile" msgstr "Mobile" #: src/r_calllog.cc:283 msgid "CallLog entry: " msgstr "Entrée de journal d'appel : " #: src/r_calllog.cc:287 msgid " Timestamp: " msgstr " Horodatage : " #: src/r_calllog.cc:288 msgid " Direction: " msgstr " Sens de l'appel : " #: src/r_calllog.cc:290 src/r_task.cc:481 msgid " Status: " msgstr " Statut : " #: src/r_calllog.cc:292 msgid " Phone info: " msgstr " Information sur le numéro : " #: src/r_calllog.cc:294 msgid " Phone type: " msgstr " Type de numéro : " #: src/r_calllog.cc:297 msgid " Duration: " msgstr " Durée : " #: src/r_calllog.cc:312 msgid " days " msgstr " jours " #: src/r_calllog.cc:314 msgid " day " msgstr " jour " #: src/r_calllog.cc:382 msgid "Duration of Call in Seconds" msgstr "Durée de l'appel en secondes" #: src/r_calllog.cc:383 msgid "Timestamp of Call in Milliseconds" msgstr "Durée de l'appel en millisecondes" #: src/r_calllog.cc:384 msgid "Contact Name" msgstr "Nom du contact" #: src/r_calllog.cc:385 msgid "Phone Number" msgstr "Numéro de télépone" #: src/r_calllog.cc:387 msgid "Direction of Call" msgstr "Sens de l'appel" #: src/r_calllog.cc:388 msgid "Received Call" msgstr "Appel entrant" #: src/r_calllog.cc:389 msgid "Placed the Call" msgstr "Appel sortant" #: src/r_calllog.cc:390 msgid "Failed Call" msgstr "Appel échoué" #: src/r_calllog.cc:391 msgid "Missed Call" msgstr "Appel manqué" #: src/r_calllog.cc:393 msgid "Status of Call" msgstr "Statut de l'appel" #: src/r_calllog.cc:396 msgid "Network Error" msgstr "Problème de réseau" #: src/r_calllog.cc:397 msgid "Unsupported Status" msgstr "Statut non supporté" #: src/r_calllog.cc:399 msgid "Phone Type" msgstr "Type de numéro" #: src/r_calllog.cc:406 msgid "Phone Info" msgstr "Information sur le numéro" #: src/r_calllog.cc:408 msgid "Phone Number is Set" msgstr "Numéro connu" #: src/r_calllog.cc:409 msgid "Phone Number Not Set" msgstr "Numéro inconnu" #: src/r_calllog.cc:410 msgid "Phone Number is Private" msgstr "Numéro privé" #: src/r_command.cc:99 msgid "Command table:\n" msgstr "Table de commandes :\n" #: src/r_command.cc:101 msgid " Command: " msgstr " Commande : " #: src/r_contact.cc:109 src/r_contact.cc:490 msgid "Nickname" msgstr "Surnom" #: src/r_contact.cc:110 msgid "Phone" msgstr "Numéro de téléphone" #: src/r_contact.cc:111 msgid "Fax" msgstr "Fax" #: src/r_contact.cc:112 msgid "HomeFax" msgstr "Fax du domicile" #: src/r_contact.cc:113 msgid "WorkPhone" msgstr "Numéro professionnel" #: src/r_contact.cc:114 msgid "HomePhone" msgstr "Numéro de domicile" #: src/r_contact.cc:115 msgid "MobilePhone" msgstr "Numéro de mobile" #: src/r_contact.cc:116 msgid "MobilePhone2" msgstr "Numéro de mobile 2" #: src/r_contact.cc:117 src/r_contact.cc:502 msgid "Pager" msgstr "Pager" #: src/r_contact.cc:119 src/r_contact.cc:504 msgid "Radio" msgstr "Radio" #: src/r_contact.cc:120 msgid "WorkPhone2" msgstr "Numéro de travail 2" #: src/r_contact.cc:121 msgid "HomePhone2" msgstr "Numéro de domicile 2" #: src/r_contact.cc:122 msgid "OtherPhone" msgstr "Autre numéro" #: src/r_contact.cc:123 src/r_contact.cc:486 msgid "Company" msgstr "Société" #: src/r_contact.cc:124 msgid "DefaultCommMethod" msgstr "Moyen de communication par défaut" #: src/r_contact.cc:125 msgid "WorkAddress1" msgstr "Adresse professionnelle 1" #: src/r_contact.cc:126 msgid "WorkAddress2" msgstr "Adresse professionnelle 2" #: src/r_contact.cc:127 msgid "WorkAddress3" msgstr "Adresse professionnelle 3" #: src/r_contact.cc:129 msgid "WorkProvince" msgstr "Département du lieu de travail" #: src/r_contact.cc:130 msgid "WorkPostalCode" msgstr "Code postal du lieu de travail" #: src/r_contact.cc:132 msgid "JobTitle" msgstr "Titre professionnel" #: src/r_contact.cc:133 msgid "PublicKey" msgstr "Clef publique" #: src/r_contact.cc:134 src/r_contact.cc:508 msgid "URL" msgstr "URL" #: src/r_contact.cc:135 src/r_contact.cc:488 msgid "Prefix" msgstr "Préfixe" #: src/r_contact.cc:136 msgid "HomeAddress1" msgstr "Adresse de domicile 1" #: src/r_contact.cc:137 msgid "HomeAddress2" msgstr "Adresse de domicile 2" #: src/r_contact.cc:138 msgid "HomeAddress3" msgstr "Adresse de domicile 3" #: src/r_contact.cc:140 msgid "UserDefined1" msgstr "Personnalisé1" #: src/r_contact.cc:141 msgid "UserDefined2" msgstr "Personnalisé2" #: src/r_contact.cc:142 msgid "UserDefined3" msgstr "Personnalisé3" #: src/r_contact.cc:143 msgid "UserDefined4" msgstr "Personnalisé4" #: src/r_contact.cc:144 msgid "HomeCity" msgstr "Ville du domicile" #: src/r_contact.cc:145 msgid "HomeProvince" msgstr "Département du domicile" #: src/r_contact.cc:146 msgid "HomePostalCode" msgstr "Code postal du domicile" #: src/r_contact.cc:147 msgid "HomeCountry" msgstr "Pays du domicile" #: src/r_contact.cc:148 src/r_contact.cc:514 msgid "Image" msgstr "Image" #: src/r_contact.cc:149 msgid "EndOfList" msgstr "Fin de liste" #: src/r_contact.cc:298 msgid "" "A contact record must contain either a First/Last name, or a Company name." msgstr "" "Un enregistrement de contact doit contenir soit un nom prénom, soit un nom " "de société." #: src/r_contact.cc:319 msgid "Contact must have name or company name." msgstr "Un contact doit avoir un nom ou un nom de société." #: src/r_contact.cc:481 src/r_servicebook.cc:454 src/r_servicebook.cc:496 msgid "Unique ID" msgstr "ID unique" #: src/r_contact.cc:482 msgid "Email Addresses" msgstr "Courriel" #: src/r_contact.cc:484 msgid "First Name" msgstr "Prénom" #: src/r_contact.cc:485 msgid "Last Name" msgstr "Nom de famille" #: src/r_contact.cc:491 msgid "Phone (deprecated)" msgstr "Phone (déprécié)" #: src/r_contact.cc:492 msgid "Work Fax" msgstr "Fax professionnel" #: src/r_contact.cc:493 msgid "Home Fax" msgstr "Fax du domicile" #: src/r_contact.cc:494 msgid "Work Phone" msgstr "Téléphone professionnel" #: src/r_contact.cc:496 msgid "Work Phone 2" msgstr "Téléphone professionnel 2" #: src/r_contact.cc:497 msgid "Home Phone" msgstr "Téléphone du domicile" #: src/r_contact.cc:498 msgid "Home Phone 2" msgstr "Téléphone du domicile 2" #: src/r_contact.cc:499 msgid "Mobile Phone" msgstr "Téléphone portable" #: src/r_contact.cc:500 msgid "Mobile Phone 2" msgstr "Téléphone portable 2" #: src/r_contact.cc:501 msgid "Other Phone" msgstr "Autre numéro de téléphone" #: src/r_contact.cc:505 msgid "Default Communications Method" msgstr "Méthode de communication par défaut" #: src/r_contact.cc:507 msgid "Public Key" msgstr "Clef publique" #: src/r_contact.cc:510 msgid "User Defined Field 1" msgstr "Champ personnalisé 1" #: src/r_contact.cc:511 msgid "User Defined Field 2" msgstr "Champ personnalisé 2" #: src/r_contact.cc:512 msgid "User Defined Field 3" msgstr "Champ personnalisé 3" #: src/r_contact.cc:513 msgid "User Defined Field 4" msgstr "Champ personnalisé 4" #: src/r_contact.cc:516 msgid "Birthday" msgstr "Date de naissance" #: src/r_contact.cc:517 msgid "Anniversary" msgstr "Anniversaire" #: src/r_contact.cc:519 msgid "Work Address" msgstr "Adresse professionnelle" #: src/r_contact.cc:520 msgid "Work Address 1" msgstr "Adresse professionnelle 1" #: src/r_contact.cc:522 msgid "Work Address 2" msgstr "Adresse professionnelle 2" #: src/r_contact.cc:524 msgid "Work Address 3" msgstr "Adresse professionnelle 3" #: src/r_contact.cc:526 msgid "Work City" msgstr "Ville du lieu de travail" #: src/r_contact.cc:528 msgid "Work Province" msgstr "Département du lieu de travail" #: src/r_contact.cc:530 msgid "Work Postal Code" msgstr "Code postal du lieu de travail" #: src/r_contact.cc:532 msgid "Work Country" msgstr "Pays du lieu de travail" #: src/r_contact.cc:535 msgid "Home Address" msgstr "Adresse du domicile" #: src/r_contact.cc:536 msgid "Home Address 1" msgstr "Adresse du domicile 1" #: src/r_contact.cc:538 msgid "Home Address 2" msgstr "Adresse du domicile 2" #: src/r_contact.cc:540 msgid "Home Address 3" msgstr "Adresse du domicile 3" #: src/r_contact.cc:542 msgid "Home City" msgstr "Ville du domicile" #: src/r_contact.cc:544 msgid "Home Province" msgstr "Département du domicile" #: src/r_contact.cc:546 msgid "Home Postal Code" msgstr "Code postal du domicile" #: src/r_contact.cc:548 msgid "Home Country" msgstr "Pays du domicile" #: src/r_contact.cc:551 src/r_memo.cc:272 src/r_task.cc:400 msgid "Categories" msgstr "Catégories" #: src/r_contact.cc:601 msgid "Contact: " msgstr "Contact : " #: src/r_contact.cc:605 msgid "FirstName" msgstr "Prénom" #: src/r_contact.cc:607 msgid "LastName" msgstr "Nom de famille" #: src/r_contact.cc:614 msgid " Email : " msgstr " Courriel : " #: src/r_contact.cc:646 msgid " Categories : " msgstr " Catégories : " #: src/r_contact.cc:651 msgid " Birthday : " msgstr " Date de naissance : " #: src/r_contact.cc:654 msgid " Anniversary : " msgstr " Anniversaire : " #: src/r_contact.cc:661 msgid " GroupLinks:\n" msgstr " Réseaux :\n" #: src/r_contact.cc:663 msgid " ID: " msgstr " ID : " #: src/r_contact.cc:669 msgid " Photo image:\n" msgstr " Photographie :\n" #: src/r_contact.cc:748 msgid "" "Error: Cannot convert complex name+address to a simple contact email " "address, skipping: " msgstr "" "Erreur : impossible de convertir un nom+adresse complexe en un simple " "courriel de contact, ignoré : " #: src/r_cstore.cc:150 msgid "Content Store must have a name." msgstr "Un stockage de contenu doit avoir un nom." #: src/r_cstore.cc:153 msgid "Content Store item without any data." msgstr "Élément de magasin de contenu sans données." #: src/r_cstore.cc:231 msgid "File or Folder Name" msgstr "Nom de fichier ou de répertoire" #: src/r_cstore.cc:232 msgid "Folder Flag" msgstr "Drapeau de dossier" #: src/r_cstore.cc:233 msgid "File Content" msgstr "Contenu de fichier" #: src/r_cstore.cc:234 msgid "File Descriptor" msgstr "Descripteur de fichier" #: src/r_cstore.cc:253 msgid "ContentStore: " msgstr "Stockage de contenu : " #: src/r_cstore.cc:256 msgid " Filename: " msgstr " Nom de fichier : " #: src/r_cstore.cc:257 msgid " Folder: " msgstr " Répertoire : " #: src/r_cstore.cc:258 msgid " BB Size: " msgstr " Taille sur le BB : " #: src/r_cstore.cc:259 msgid " Actual Size: " msgstr " Taille réelle : " #: src/r_cstore.cc:260 msgid " Descriptor:\n" msgstr " Descripteur :\n" #: src/r_cstore.cc:262 msgid " Content:\n" msgstr " Contenu :\n" #: src/r_dbdb.cc:118 msgid "DatabaseDatabase: not enough data for parsing" msgstr "DatabaseDatabase: pas assez de données pour l'analyse" #: src/r_dbdb.cc:123 msgid "Unknown protocol" msgstr "Protocole inconnu" #: src/r_dbdb.cc:197 msgid "Database database:\n" msgstr "Base de données base de données :\n" #: src/r_dbdb.cc:199 msgid " Database: " msgstr " Base de données : " #: src/r_dbdb.cc:200 msgid "records: " msgstr "Enregistrements :" #: src/r_folder.cc:84 msgid "FolderName" msgstr "Nom de dossier" #: src/r_folder.cc:212 msgid "Folder Name" msgstr "Nom de dossier" #: src/r_folder.cc:213 msgid "Order Number" msgstr "Numéro d'ordre" #: src/r_folder.cc:214 msgid "Folder Level" msgstr "Niveau de dossier" #: src/r_folder.cc:216 msgid "Folder Type" msgstr "Type de dossier" #: src/r_folder.cc:217 src/r_folder.cc:248 msgid "Subtree" msgstr "Sous-arbre" #: src/r_folder.cc:218 src/r_folder.cc:249 src/r_sms.cc:296 msgid "Deleted" msgstr "Supprimé" #: src/r_folder.cc:219 src/r_folder.cc:250 msgid "Inbox" msgstr "Boîte de réception" #: src/r_folder.cc:220 src/r_folder.cc:251 msgid "Outbox" msgstr "Boîte d'envoi" #: src/r_folder.cc:222 src/r_folder.cc:253 src/usbwrap_libusb_1_0.cc:117 msgid "Other" msgstr "Autre" #: src/r_folder.cc:223 src/r_sms.cc:286 msgid "Draft" msgstr "Brouillon" #: src/r_folder.cc:257 msgid "" "Folder Records\n" "\n" msgstr "" "Enregistrements de dossiers\n" "\n" #: src/r_folder.cc:258 msgid "Folder Name: " msgstr "Nom de dossier : " #: src/r_folder.cc:259 msgid "Folder Type: " msgstr "Type de dossier : " #: src/r_folder.cc:263 msgid "Draft\n" msgstr "Brouillon\n" #: src/r_folder.cc:266 msgid "Folder Number: " msgstr "Numéro de dossier : " #: src/r_folder.cc:267 msgid "Folder Level: " msgstr "Niveau de dossier : " #: src/r_hhagent.cc:65 src/r_hhagent.cc:86 src/r_hhagent.cc:100 #: src/r_hhagent.cc:288 msgid "Model" msgstr "Modèle" #: src/r_hhagent.cc:66 src/r_hhagent.cc:101 src/r_hhagent.cc:292 msgid "Network" msgstr "Réseau" #: src/r_hhagent.cc:67 src/r_hhagent.cc:103 src/r_hhagent.cc:289 msgid "Bands" msgstr "Bandes" #: src/r_hhagent.cc:68 src/r_hhagent.cc:104 src/r_hhagent.cc:287 msgid "MEID/ESN" msgstr "MEID/ESN" #: src/r_hhagent.cc:70 src/r_hhagent.cc:106 src/r_hhagent.cc:291 msgid "Version" msgstr "Version" #: src/r_hhagent.cc:87 src/r_hhagent.cc:102 src/r_hhagent.cc:296 msgid "Manufacturer" msgstr "Fabricant" #: src/r_hhagent.cc:88 msgid "Firmware" msgstr "Microprogramme" #: src/r_hhagent.cc:89 src/r_hhagent.cc:107 msgid "Platform" msgstr "Plateforme" #: src/r_hhagent.cc:140 msgid "HandheldAgent requires SetIds() to be called before ParseField()" msgstr "HandheldAgent requiert que SetIds() soit appelé avant ParseField()" #: src/r_hhagent.cc:295 msgid "Platform Version" msgstr "Version de plateforme" #: src/r_hhagent.cc:306 msgid "Handheld Agent: " msgstr "Périphérique : " #: src/r_hhagent.cc:314 msgid "HandheldAgent entry: " msgstr "Entrée HandeldAgent : " #: src/r_memo.cc:50 src/r_memo.cc:270 msgid "Title" msgstr "Titre" #: src/r_memo.cc:51 src/r_memo.cc:271 src/r_message_base.cc:87 #: src/r_message_base.cc:343 src/r_sms.cc:310 msgid "Body" msgstr "Corps" #: src/r_memo.cc:80 msgid "Memo::ParseField: MemoType is not 'm'" msgstr "Memo::ParseField: MemoType n'est pas 'm'" #: src/r_memo.cc:209 msgid "Memo entry: " msgstr "Entrée mémo :" #: src/r_memo.cc:211 msgid " Title: " msgstr " Titre : " #: src/r_memo.cc:212 msgid " Body: " msgstr " Corps : " #: src/r_memo.cc:227 msgid " Categories: " msgstr " Catégories : " #: src/r_message_base.cc:80 src/r_message_base.cc:337 msgid "To" msgstr "À" #: src/r_message_base.cc:81 msgid "Cc" msgstr "Cc" #: src/r_message_base.cc:82 msgid "Bcc" msgstr "Cci" #: src/r_message_base.cc:83 src/r_message_base.cc:340 msgid "Sender" msgstr "Expéditeur" #: src/r_message_base.cc:84 src/r_message_base.cc:336 msgid "From" msgstr "De" #: src/r_message_base.cc:85 msgid "ReplyTo" msgstr "Répondre à" #: src/r_message_base.cc:88 src/r_message_base.cc:344 msgid "Attachment" msgstr "Pièce jointe" #: src/r_message_base.cc:278 msgid "MessageBase::BuildHeader not yet implemented" msgstr "MessageBase::BuildHeader non implementé" #: src/r_message_base.cc:283 msgid "MessageBase::BuildFields not yet implemented" msgstr "MessageBase::BuildFields non implementé" #: src/r_message_base.cc:338 msgid "CC" msgstr "CC" #: src/r_message_base.cc:339 msgid "BCC" msgstr "CCI" #: src/r_message_base.cc:341 msgid "Reply To" msgstr "Répondre à" #: src/r_message_base.cc:346 msgid "Message Record ID" msgstr "ID d'enregistrement de message" #: src/r_message_base.cc:347 msgid "Message Reply To" msgstr "Champ Répondre à de message" #: src/r_message_base.cc:348 msgid "Date Sent" msgstr "Données envoyées" #: src/r_message_base.cc:349 msgid "Date Received" msgstr "Données reçues" #: src/r_message_base.cc:351 msgid "Truncated" msgstr "Tronqué" #: src/r_message_base.cc:352 msgid "Read" msgstr "Lu" #: src/r_message_base.cc:353 msgid "Reply" msgstr "Réponse" #: src/r_message_base.cc:354 src/r_sms.cc:295 msgid "Saved" msgstr "Enregistré" #: src/r_message_base.cc:355 msgid "Saved Deleted" msgstr "Enregistré supprimé" #: src/r_message_base.cc:357 src/r_task.cc:413 msgid "Priority" msgstr "Priorité" #: src/r_message_base.cc:358 src/r_task.cc:416 src/r_task.cc:445 msgid "Low" msgstr "Basse" #: src/r_message_base.cc:359 src/r_message_base.cc:364 src/r_task.cc:415 #: src/r_task.cc:444 msgid "Normal" msgstr "Normale" #: src/r_message_base.cc:360 src/r_task.cc:414 src/r_task.cc:443 msgid "High" msgstr "Haute" #: src/r_message_base.cc:363 msgid "Sensitivity" msgstr "Confidentialité" #: src/r_message_base.cc:365 msgid "Personal" msgstr "Personnel" #: src/r_recordstate.cc:131 msgid " Index RecordId Dirty RecType" msgstr " Index IdEnr Sale TypeEnr" #: src/r_recordstate.cc:141 src/r_recur_base.cc:279 tools/bjavaloader.cc:455 #: tools/bjavaloader.cc:471 msgid "yes" msgstr "oui" #: src/r_recordstate.cc:141 src/r_recur_base.cc:279 msgid "no" msgstr "non" #: src/r_recur_base.cc:91 msgid "RecurBase::ParseField: not enough data in recurrence data field" msgstr "RecurBase::ParseField: Pas assez de données dans le champ périodicité" #: src/r_recur_base.cc:157 msgid "Unknown recurrence data type" msgstr "Type de donnée de périodicité inconnu" #: src/r_recur_base.cc:172 msgid "" "RecurBase::BuildRecurrenceData: Attempting to build recurrence data on non-" "recurring record." msgstr "" "RecurBase::BuildRecurrenceData : tentative de créer une donnée de " "périodicité sur un enregistrement non périodique." #: src/r_recur_base.cc:226 msgid "RecurBase::BuildRecurrenceData: Unknown recurrence data type" msgstr "RecurBase::BuildRecurrenceData : type de donnée de périodicité inconnu" #: src/r_recur_base.cc:251 src/r_recur_base.cc:323 msgid "Sun" msgstr "Dim" #: src/r_recur_base.cc:252 src/r_recur_base.cc:324 msgid "Mon" msgstr "Lun" #: src/r_recur_base.cc:253 src/r_recur_base.cc:325 msgid "Tue" msgstr "Mar" #: src/r_recur_base.cc:254 src/r_recur_base.cc:326 msgid "Wed" msgstr "Mer" #: src/r_recur_base.cc:255 src/r_recur_base.cc:327 msgid "Thu" msgstr "Jeu" #: src/r_recur_base.cc:256 src/r_recur_base.cc:328 msgid "Fri" msgstr "Ven" #: src/r_recur_base.cc:257 src/r_recur_base.cc:329 msgid "Sat" msgstr "Sam" #: src/r_recur_base.cc:260 src/r_timezone.cc:257 msgid "Jan" msgstr "Jan" #: src/r_recur_base.cc:261 src/r_timezone.cc:258 msgid "Feb" msgstr "Fév" #: src/r_recur_base.cc:262 src/r_timezone.cc:259 msgid "Mar" msgstr "Mar" #: src/r_recur_base.cc:263 src/r_timezone.cc:260 msgid "Apr" msgstr "Avr" #: src/r_recur_base.cc:264 src/r_timezone.cc:261 msgid "May" msgstr "Mai" #: src/r_recur_base.cc:265 src/r_timezone.cc:262 msgid "Jun" msgstr "Juin" #: src/r_recur_base.cc:266 src/r_timezone.cc:263 msgid "Jul" msgstr "Juil" #: src/r_recur_base.cc:267 src/r_timezone.cc:264 msgid "Aug" msgstr "Aoû" #: src/r_recur_base.cc:268 src/r_timezone.cc:265 msgid "Sep" msgstr "Sep" #: src/r_recur_base.cc:269 src/r_timezone.cc:266 msgid "Oct" msgstr "Oct" #: src/r_recur_base.cc:270 src/r_timezone.cc:267 msgid "Nov" msgstr "Nov" #: src/r_recur_base.cc:271 src/r_timezone.cc:268 msgid "Dec" msgstr "Déc" #: src/r_recur_base.cc:279 msgid " Recurring: " msgstr " Périodicité : " #: src/r_recur_base.cc:284 msgid " Every day.\n" msgstr " Quotidienne\n" #. TRANSLATORS: to remove the 'th' ending on numbers, #. just replace the %s with %.0s in this string. #: src/r_recur_base.cc:290 #, c-format msgid " Every month on the %u%s" msgstr " Mensuelle, chaque %u%0s" #: src/r_recur_base.cc:300 #, c-format msgid " Every month on the %s of week %u" msgstr " Mensuelle, chaque %s semaine %u" #: src/r_recur_base.cc:307 #, c-format msgid " Every year on %s %u" msgstr " Annuelle, au %s %u" #: src/r_recur_base.cc:314 #, c-format msgid " Every year in %s on %s of week %u" msgstr " Annuelle, en %s le %s de la semaine %u" #: src/r_recur_base.cc:322 msgid " Every week on: " msgstr " Chaque semaine le : " #: src/r_recur_base.cc:334 msgid " Unknown recurrence type\n" msgstr " Type de périodicité inconnu\n" #: src/r_recur_base.cc:338 msgid " Interval: " msgstr " Intervalle : " #: src/r_recur_base.cc:341 msgid " Ends: never\n" msgstr " Se termine : jamais\n" #: src/r_recur_base.cc:343 msgid " Ends: " msgstr " Se termine : " #: src/r_servicebook.cc:182 msgid "ServiceBookConfig::Build not yet implemented" msgstr "ServiceBookConfig::Build non implémenté" #: src/r_servicebook.cc:195 msgid " ServiceBookConfig Format: " msgstr " ServiceBookConfig format : " #: src/r_servicebook.cc:216 msgid " ------------------- End of Config Field\n" msgstr " ------------------- Fin du champ de configuration\n" #: src/r_servicebook.cc:251 msgid "Old Name" msgstr "Ancien nom" #: src/r_servicebook.cc:252 msgid "Old Desc" msgstr "Ancienne description" #: src/r_servicebook.cc:253 msgid "Old UniqueId" msgstr "Ancien Id unique" #: src/r_servicebook.cc:258 src/r_servicebook.cc:449 src/r_servicebook.cc:492 #: src/r_timezone.cc:59 msgid "Name" msgstr "Nom" #: src/r_servicebook.cc:259 src/r_servicebook.cc:451 src/r_servicebook.cc:494 msgid "Description" msgstr "Description" #: src/r_servicebook.cc:260 msgid "UniqueId" msgstr "Id unique" #: src/r_servicebook.cc:266 src/r_servicebook.cc:450 src/r_servicebook.cc:493 msgid "Hidden Name" msgstr "Nom masqué" #: src/r_servicebook.cc:267 src/r_servicebook.cc:452 src/r_servicebook.cc:495 msgid "DSID" msgstr "DSID" #: src/r_servicebook.cc:268 msgid "ContentId" msgstr "Id de contenu" #: src/r_servicebook.cc:269 src/r_servicebook.cc:453 msgid "BES Domain" msgstr "Domaine BES" #: src/r_servicebook.cc:423 msgid "ServiceBook::BuildFields not yet implemented" msgstr "ServiceBook::BuildFields non implémenté" #: src/r_servicebook.cc:455 src/r_servicebook.cc:497 msgid "Content ID" msgstr "Id de contenu" #: src/r_servicebook.cc:489 msgid "ServiceBook entry: " msgstr "Entrée ServiceBook :" #: src/r_servicebook.cc:498 msgid "(BES) Domain" msgstr "Domaine (BES)" #: src/r_sms.cc:282 msgid "Message Status" msgstr "Statut du message" #: src/r_sms.cc:288 msgid "Delivery Status" msgstr "Statut d'acheminement" #: src/r_sms.cc:289 msgid "No Report" msgstr "Pas de rapport" #: src/r_sms.cc:290 msgid "Failed" msgstr "Échec" #: src/r_sms.cc:291 msgid "Succeeded" msgstr "Succès" #: src/r_sms.cc:293 msgid "Is New?" msgstr "Nouveau ?" #: src/r_sms.cc:294 msgid "New Conversation" msgstr "Nouvelle conversation" #: src/r_sms.cc:297 msgid "Opened" msgstr "Ouver" #: src/r_sms.cc:299 msgid "Timestamp in Milliseconds" msgstr "Horodatage en millisecondes" #: src/r_sms.cc:300 msgid "Service Center Timestamp" msgstr "Horodatage du centre de service" #: src/r_sms.cc:302 msgid "Data Coding Scheme" msgstr "Schéma de codage de données" #: src/r_sms.cc:303 msgid "7bit" msgstr "7 bits" #: src/r_sms.cc:304 msgid "8bit" msgstr "8 bits" #: src/r_sms.cc:305 msgid "UCS2" msgstr "UCS2" #: src/r_sms.cc:307 msgid "Error ID" msgstr "ID d'erreur" #: src/r_sms.cc:309 msgid "Addresses" msgstr "Adresses" #: src/r_sms.cc:322 msgid "Unknown destination" msgstr "Destination inconnue" #: src/r_sms.cc:329 msgid "SMS record: " msgstr "Enregistrement SMS :" #: src/r_sms.cc:332 msgid "Timestamp: " msgstr "Horodatage : " #: src/r_sms.cc:336 msgid "Service Center Timestamp: " msgstr "Horodatage du centre de service : " #: src/r_sms.cc:340 msgid "Send Error: " msgstr "Erreur d'envoi : " #: src/r_sms.cc:345 msgid "Received From:\n" msgstr "Reçu de :\n" #: src/r_sms.cc:348 msgid "Sent to:\n" msgstr "Envoyé à :\n" #: src/r_sms.cc:351 msgid "Draft for:\n" msgstr "Brouillon pour :\n" #: src/r_sms.cc:354 msgid "Unknown status for:\n" msgstr "Statut inconnu pour :\n" #: src/r_sms.cc:364 msgid "New " msgstr "Nouveau" #: src/r_sms.cc:366 msgid "Opened " msgstr "Ouvert" #: src/r_sms.cc:368 msgid "Saved " msgstr "Enregistré" #: src/r_sms.cc:370 msgid "Deleted " msgstr "Supprimé" #: src/r_sms.cc:371 msgid "Message" msgstr "Message" #: src/r_sms.cc:371 msgid " that starts a new conversation" msgstr " qui débute une nouvelle conversation" #: src/r_sms.cc:373 msgid "Content: " msgstr "Contenu : " #: src/r_task.cc:107 src/r_task.cc:398 msgid "Summary" msgstr "Résumé" #: src/r_task.cc:110 src/r_task.cc:404 msgid "Due Time" msgstr "Échéance" #: src/r_task.cc:111 src/r_task.cc:405 msgid "Alarm Time" msgstr "Date d'alerte" #: src/r_task.cc:140 msgid "Task::ParseField: Task Type is not 't'" msgstr "Task::ParseField : le type de tâche n'est pas 't'" #: src/r_task.cc:171 src/r_task.cc:180 msgid "Task::ParseField: priority field out of bounds" msgstr "Task::ParseField : le champ priorité est hors plage" #: src/r_task.cc:193 msgid "Task::ParseField: not enough data in time zone code field" msgstr "Task::ParseField : pas assez de données dans le champ de zone de temps" #: src/r_task.cc:213 msgid "Task::ParseField: AlarmType out of bounds" msgstr "Task::ParseField : type d'alarme hors plage" #: src/r_task.cc:401 msgid "UID" msgstr "UID" #: src/r_task.cc:407 msgid "Time Zone Code Valid" msgstr "Code de zone de temps valide" #: src/r_task.cc:409 msgid "Alarm Type" msgstr "Type d'alarme" #: src/r_task.cc:410 msgid "Date" msgstr "Date" #: src/r_task.cc:411 src/r_task.cc:457 msgid "Relative" msgstr "Relative" #: src/r_task.cc:418 msgid "Status" msgstr "Statut" #: src/r_task.cc:419 src/r_task.cc:448 msgid "Not Started" msgstr "Non commencée" #: src/r_task.cc:420 src/r_task.cc:449 msgid "In Progress" msgstr "En cours" #: src/r_task.cc:421 src/r_task.cc:450 msgid "Completed" msgstr "Complétée" #: src/r_task.cc:422 src/r_task.cc:451 msgid "Waiting" msgstr "En attente" #: src/r_task.cc:423 src/r_task.cc:452 msgid "Deferred" msgstr "Reportée" #: src/r_task.cc:455 msgid "None" msgstr "Aucun" #: src/r_task.cc:456 msgid "By Date" msgstr "Par date" #: src/r_task.cc:460 msgid "Task entry: " msgstr "Entrée de tâche : " #: src/r_task.cc:480 msgid " Priority: " msgstr " Priorité : " #: src/r_task.cc:483 msgid " Alarm Type: " msgstr " Type d'alarme : " #: src/r_task.cc:494 msgid " Categories: " msgstr " Catégories : " #: src/r_timezone.cc:111 msgid "TimeZone::ParseField: TimeZone Type is not valid" msgstr "TimeZone::ParseField : type de zone de temps invalide" #: src/r_timezone.cc:229 msgid "TimeZone Name" msgstr "Nom de zone de temps" #: src/r_timezone.cc:230 msgid "Index" msgstr "Index" #: src/r_timezone.cc:231 msgid "TimeZone Offset in Minutes" msgstr "Décalage de zone de temps en minutes" #: src/r_timezone.cc:232 msgid "Use DST?" msgstr "Passage à l'heure d'été ?" #: src/r_timezone.cc:233 msgid "DST Offset" msgstr "Décalage d'heure d'été" #: src/r_timezone.cc:234 msgid "Start Month" msgstr "Mois de début" #: src/r_timezone.cc:235 msgid "End Month" msgstr "Mois de fin" #: src/r_timezone.cc:236 msgid "TimeZone Type" msgstr "Type de zone de temps" #: src/r_timezone.cc:271 msgid "TimeZone entry: " msgstr "Entrée zone de temps : " #: src/r_timezone.cc:289 msgid " Desc: " msgstr " Desc : " #: src/r_timezone.cc:290 msgid " Index: " msgstr " Index : " #: src/r_timezone.cc:291 msgid " Type: " msgstr " Type : " #: src/r_timezone.cc:292 msgid " Offset: " msgstr " Offset : " #: src/r_timezone.cc:292 msgid " minutes " msgstr " minutes " #: src/r_timezone.cc:294 msgid " Split Offset: hours: " msgstr " Décalage détaillé : heures : " #: src/r_timezone.cc:295 msgid ", minutes: " msgstr ", minutes: " #: src/r_timezone.cc:296 msgid " Sample TZ: " msgstr " ZT exemple : " #: src/r_timezone.cc:297 msgid " Use DST: " msgstr " Heure d'été : " #: src/r_timezone.cc:299 msgid " DST Offset: " msgstr "Déc. heure été : " #: src/r_timezone.cc:301 msgid "Start Month: " msgstr " Mois de début :" #: src/r_timezone.cc:303 msgid "Start Month: unknown (" msgstr " Mois de début : inconnu (" #: src/r_timezone.cc:305 msgid " End Month: " msgstr " Mois de fin : " #: src/r_timezone.cc:307 msgid " End Month: unknown (" msgstr " Mois de fin : inconnu (" #: src/record.cc:253 msgid " Unknowns:\n" msgstr " Inconnus :\n" #: src/record.cc:255 msgid " Type: " msgstr " Type : " #: src/record.cc:257 msgid " Data:\n" msgstr " Données :\n" #: src/record.cc:459 msgid "NULL time pointer passed to Date::FromTm" msgstr "Pointeur de temps NULL passé à Date::FromTm" #: src/record.cc:591 msgid "Enum value not found in constant list" msgstr "Valeur d'enum non trouvée dans la liste de constantes" #: src/record.cc:642 msgid "Different database types in DBNamedFieldCmp" msgstr "Types de bases de données différents dans DBNamedFieldCmp" #: src/record.cc:647 msgid "Unknown database in DBNamedFieldCmp::operator()" msgstr "Base de données inconnue dans DBNamedFieldCmp::operator()" #: src/restore.cc:184 msgid "Skipping: " msgstr "Ignore :" #: src/restore.cc:298 msgid "Skipping invalid tar record: " msgstr "Enregistrement tar inconnu ignoré : " #: src/restore.cc:358 msgid "Invalid state in Restore::BuildRecord()" msgstr "État invalide dans Restore::BuildRecord()" #: src/restore.cc:410 msgid "Invalid state in Restore::FetchRecord()" msgstr "État invalide dans Restore::FetchRecord()" #: src/router.cc:198 msgid "SimpleReadThread received uncaught exception: " msgstr "SimpleReadThread a reçu une exception non attrapée : " #: src/router.cc:198 msgid " what: " msgstr " message : " #: src/router.cc:201 msgid "SimpleReadThread recevied uncaught exception of unknown type" msgstr "SimpleReadThread a reçu une exception non attrapée et de type inconnu" #: src/router.cc:211 msgid "SocketRoutingQueue Leftovers: " msgstr "SocketRoutingQueue paquet(s) en surplus : " #: src/router.cc:213 msgid " packet(s) for socket: " msgstr " pour la socket : " #: src/router.cc:343 msgid "RegisterInterest requesting a previously registered socket." msgstr "RegisterInterest sur une socket déjà enregistrée." #: src/router.cc:422 msgid "SocketRead requested data from unregistered socket." msgstr "Demande de données dans SocketRead sur une socket non enregistrée." #: src/router.cc:616 msgid "SocketRoutingQueue: Error creating USB read thread." msgstr "SocketRoutingQueue : erreur à la création du thread de lecture USB." #: src/socket.cc:123 msgid "Socket: Whole packet too short to fragment" msgstr "Socket : paquet entier trop petit pour être fragmenté" #: src/socket.cc:170 msgid "Socket: invalid sequence packet" msgstr "Socket: paquet de séquence invalide" #: src/socket.cc:183 #, c-format msgid "" "Socket 0x%x: out of sequence. (Global sequence: 0x%x. Packet sequence: 0x%x)" msgstr "" "Socket 0x%x : hors sequence. (Séquence Globale: 0x%x. Séquence du paquet : 0x" "%x)" #: src/socket.cc:293 msgid "SocketZero: No device available for RawSend" msgstr "SocketZero : pas de périphérique disponible pour un RawSend" #: src/socket.cc:324 msgid "" "SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)" msgstr "" "SocketZero::RawReceive : DefaultRead sur la file a retourné faux " "(probablement un délai dépassé)" #: src/socket.cc:338 msgid "Multiple pushbacks in SocketZero!" msgstr "Refoulements de données multiples dans SocketZero !" #: src/socket.cc:459 msgid "No password specified." msgstr "Pas de mot de passe donnée." #: src/socket.cc:504 msgid "" "Socket: Device closed socket when trying to open (can be caused by the wrong " "password, or if the device thinks the socket is already open... please try " "again)" msgstr "" "Socket : le périphérique a fermé la socket lors de la tentative d'ouverture " "(ceci peut être causé par un mot de passe erroné, ou bien le périphérique " "pense que la socket est déjà ouverte... Veuillez réessayer)" #: src/socket.cc:512 msgid "Socket: Bad OPENED packet in Open" msgstr "Socket : Mauvais paquet OPENED dans Open" #: src/socket.cc:528 msgid "Could not find mode's starting sequence packet" msgstr "Impossible trouver le paquet de début de séquence du mode" #: src/socket.cc:617 msgid "Socket: Bad CLOSED packet in Close" msgstr "Socket : Mauvais paquet CLOSED dans Close" #: src/socket.cc:628 msgid "Socket: Missing RESET_REPLY in Close" msgstr "Socket : Pas de RESET_REPLY dans Close" #: src/socket.cc:677 msgid "Socket: unknown send data in DBFragSend()" msgstr "Socket : données d'envoi inconnues dans DBFragSend()" #: src/socket.cc:781 src/socket.cc:870 msgid "Socket: (read) unhandled packet in Packet(): " msgstr "Socket : (lecture) paquet non géré dans Packet() : " #: src/socket.cc:794 src/socket.cc:887 src/socket.cc:970 msgid "Socket: 10 blank packets received" msgstr "Socket : 10 paquets vides reçus" #: src/socket.cc:840 msgid "Socket: unknown send data in PacketJVM()" msgstr "Socket : données d'envoi inconnues dans PacketJVM()" #: src/socket.cc:908 msgid "Socket: unknown send data in PacketData()" msgstr "Socket : données d'envoi inconnues dans PacketData()" #: src/socket.cc:950 msgid "file is not a valid Java code file" msgstr "le fichier n'est pas un fichier de code java valide" #: src/socket.cc:954 msgid "device does not support requested command" msgstr "le périphérique ne supporte pas la commande demandée" #: src/socket.cc:1072 msgid "Non-sequence packet in Socket::SyncSend()" msgstr "Le paquet n'est pas un paquet séquence dans Socket::SyncSend()" #: src/socket.cc:1081 msgid "Socket::Receive: queue SocketRead returned false (likely a timeout)" msgstr "" "Socket::RawReceive : DefaultRead sur la file a retourné faux (probablement " "un délai dépassé)" #: src/socket.cc:1084 msgid "NULL queue pointer in a registered socket read." msgstr "Pointeur de file NULL lors d'un read sur une socket enregistrée." #: src/socket.cc:1099 msgid "" "SocketRoutingQueue required in SocketZero in order to call Socket::" "RegisterInterest()" msgstr "" "Une SocketRoutingQueue est requise dans la SocketZero pour appeler Socket::" "RegisterInterest()" #: src/socket.cc:1102 #, c-format msgid "Socket (%u) already registered in Socket::RegisterInterest()!" msgstr "Socket (%u) déjà enregistrée dans Socket::RegisterInterest()!" #: src/tarfile.cc:55 msgid "Unable to open tar file: " msgstr "Impossible d'ouvrir le fichier tar" #: src/tarfile.cc:88 msgid "Unable to write eof" msgstr "Impossible d'écrire eof" #: src/tarfile.cc:92 msgid "Unable to close file" msgstr "Impossible de fermer le fichier" #: src/tarfile.cc:113 msgid "Unable to write tar header" msgstr "Impossible d'écrire l'en-tête tar" #: src/tarfile.cc:128 msgid "Unable to write block" msgstr "Impossible d'écrire le bloc" #: src/tarfile.cc:156 src/tarfile.cc:215 src/tarfile.cc:272 msgid "Only regular files are supported inside a tarball." msgstr "Seuls les fichiers réguliers sont supportés dans un tarball." #: src/tarfile.cc:184 src/tarfile.cc:243 msgid "Unable to read block" msgstr "Impossible de lire le bloc" #: src/tarfile.cc:281 msgid "Unable to skip tar file" msgstr "Impossible d'ignorer le fichier tar" #: src/threadwrap.cc:54 msgid "Thread: pthread_create failed." msgstr "Thread : échec de pthread_create." #: src/time.cc:154 msgid "Unknown time zone" msgstr "Zone de temps inconnue" #: src/usbwrap_libusb.cc:228 src/usbwrap_libusb_1_0.cc:336 msgid "invalid USB device ID" msgstr "ID de périphérique USB invalide" #: src/usbwrap_libusb.cc:231 src/usbwrap_libusb_1_0.cc:340 msgid "" "Failed to open USB device. Please check your system's USB device " "permissions." msgstr "" "Impossible d'ouvrir le périphérique USB. Veuillez vérifier les permissions " "de votre système." #: src/usbwrap_libusb.cc:275 msgid "Timeout in usb_bulk_read" msgstr "Délai dépassé dans usb_bulk_read" #: src/usbwrap_libusb.cc:278 msgid "Error in usb_bulk_read(" msgstr "Erreur dans usb_bulk_read(" #: src/usbwrap_libusb.cc:303 msgid "Timeout in usb_bulk_write (1)" msgstr "Délai dépassé dans usb_bulk_write (1)" #: src/usbwrap_libusb.cc:305 msgid "Error in usb_bulk_write (1)" msgstr "Erreur dans usb_bulk_read(1)" #: src/usbwrap_libusb.cc:327 msgid "Timeout in usb_bulk_write (2)" msgstr "Délai dépassé dans usb_bulk_write (1)" #: src/usbwrap_libusb.cc:329 msgid "Error in usb_bulk_write (2)" msgstr "Erreur dans usb_bulk_read(1)" #: src/usbwrap_libusb.cc:347 msgid "Timeout in usb_interrupt_read" msgstr "Délai dépassé dans usb_interrupt_read" #: src/usbwrap_libusb.cc:349 msgid "Error in usb_interrupt_read" msgstr "Erreur dans usb_interrupt_read" #: src/usbwrap_libusb.cc:370 msgid "Timeout in usb_interrupt_write" msgstr "Délai dépassé dans usb_interrupt_write" #: src/usbwrap_libusb.cc:372 msgid "Error in usb_interrupt_write" msgstr "Erreur dans usb_interrupt_write" #: src/usbwrap_libusb.cc:505 src/usbwrap_libusb_1_0.cc:688 msgid "claim interface failed" msgstr "échec de la réclamation d'interface" #: src/usbwrap_libusb_1_0.cc:91 msgid "Success" msgstr "Succès" #: src/usbwrap_libusb_1_0.cc:93 msgid "IO Error" msgstr "Erreur d'E/S" #: src/usbwrap_libusb_1_0.cc:95 msgid "Invalid parameter" msgstr "Paramètre invalide" #: src/usbwrap_libusb_1_0.cc:97 msgid "Access" msgstr "Droits d'accès" #: src/usbwrap_libusb_1_0.cc:99 msgid "No device" msgstr "Pas de périphérique" #: src/usbwrap_libusb_1_0.cc:101 msgid "Not found" msgstr "Non trouvé" #: src/usbwrap_libusb_1_0.cc:105 msgid "Timeout" msgstr "Délai dépassé" #: src/usbwrap_libusb_1_0.cc:107 msgid "Overflow" msgstr "Dépassement" #: src/usbwrap_libusb_1_0.cc:109 msgid "Pipe" msgstr "Tube" #: src/usbwrap_libusb_1_0.cc:111 msgid "Interrupted" msgstr "Interrompu" #: src/usbwrap_libusb_1_0.cc:113 msgid "No memory" msgstr "Plus de mémoire" #: src/usbwrap_libusb_1_0.cc:115 msgid "Not supported" msgstr "Non supporté" #: src/usbwrap_libusb_1_0.cc:119 msgid "Unknown LIBUSB error code" msgstr "Code d'erreur LIBUSB inconnu" #: src/usbwrap_libusb_1_0.cc:272 msgid "Failed to get device list" msgstr "Impossible d'obtenir la liste de périphériques" #: src/usbwrap_libusb_1_0.cc:391 msgid "Timeout in BulkRead" msgstr "Délai dépassé dans BulkRead" #: src/usbwrap_libusb_1_0.cc:397 msgid "Error in libusb_bulk_tranfer(" msgstr "Erreur dans libusb_bulk_transfer(" #: src/usbwrap_libusb_1_0.cc:432 msgid "Timeout in BulkWrite" msgstr "Délai dépassé dans BulkWrite" #: src/usbwrap_libusb_1_0.cc:434 msgid "Error in BulkWrite" msgstr "Erreur dans BulkWrite" #: src/usbwrap_libusb_1_0.cc:441 src/usbwrap_libusb_1_0.cc:477 #: src/usbwrap_libusb_1_0.cc:545 msgid "Failed to perform a complete write" msgstr "Impossible d'effectuer une écriture complète" #: src/usbwrap_libusb_1_0.cc:469 msgid "Timeout in BulkWrite (2)" msgstr "Délai dépassé dans BulkWrite (2)" #: src/usbwrap_libusb_1_0.cc:471 msgid "Error in BulkWrite (2)" msgstr "Erreur dans BulkWrite (2)" #: src/usbwrap_libusb_1_0.cc:503 msgid "Timeout in InterruptRead" msgstr "Délai dépassé dans InterruptRead" #: src/usbwrap_libusb_1_0.cc:508 msgid "Error in InterruptRead" msgstr "Erreur dans InterruptRead" #: src/usbwrap_libusb_1_0.cc:536 msgid "Timeout in InterruptWrite" msgstr "Délai dépassé dans InterruptWrite" #: src/usbwrap_libusb_1_0.cc:538 msgid "Error in InterruptWrite" msgstr "Erreur dans InterruptWrite" #: src/vbase.cc:47 msgid "gmtime_r() failed on time_t of: " msgstr "échec de gmtime_r() avec un time_t de : " #: src/vbase.cc:51 msgid "(null pointer)" msgstr "(pointeur null)" #: src/vbase.cc:255 msgid "Cannot construct vBase with null format" msgstr "Impossible de construire une vBase avec un format null" #: src/vbase.cc:269 msgid "Cannot set vBase with null format" msgstr "Impossible de définir une vBase avec un format null" #: src/vbase.cc:294 src/vbase.cc:315 msgid "resource error allocating vformat attribute" msgstr "Erreur d'allocation d'attribut de vformat" #: src/vcard.cc:141 src/vcard.cc:337 src/vevent.cc:595 src/vevent.cc:683 #: src/vjournal.cc:79 src/vtodo.cc:94 msgid "resource error allocating vformat" msgstr "Erreur d'allocation de vformat" #: src/vcard.cc:512 msgid "Unable to parse BDAY field" msgstr "Impossible de lire le champ BDAY" #: src/vcard.cc:544 msgid "FN and ORG fields both blank in VCARD data" msgstr "Champs FN et ORG tous les deux vide dans les données de VCARD" #: src/vevent.cc:72 #, c-format msgid "" "ERROR: recurrence rule contains %s, unsupported by Barry. MIME conversion " "will be incorrect." msgstr "" "ERREUR : la règle de périodicité contient %s, non supporté par Barry. La " "conversion MIME sera incorrecte." #: src/vevent.cc:73 src/vevent.cc:87 src/vevent.cc:110 src/vevent.cc:145 #: src/vevent.cc:150 src/vevent.cc:163 src/vevent.cc:469 src/vevent.cc:495 #: src/vevent.cc:556 msgid "Record data so far:\n" msgstr "Données d'enregistrement à ce point :\n" #: src/vevent.cc:86 #, c-format msgid "" "Warning: multiple items in BYDAY, not supported by device (%s). Using only " "the first item." msgstr "" "Attention : éléments multiples dans BYDAY, non supporté par le périphérique " "(%s). Seul le premier est utilisé." #: src/vevent.cc:109 #, c-format msgid "" "Warning: negative week in BYDAY (%d), unsupported by device. Converting to " "positive week, based on 4 week months: %d." msgstr "" "Attention : semaine négative dans BYDAY (%d), non supporté par le " "périphérique. Conversion en semaine positive, basée sur 4 semaines par " "mois : %d." #: src/vevent.cc:140 msgid "Called GetDayOfMonthFromBYMONTHDAY() without a BYMONTHDAY" msgstr "GetDayOfMonthFromBYMONTHDAY() appelé sans BYMONTHDAY" #: src/vevent.cc:144 msgid "Warning: BYMONTHDAY of 0, assuming 1.\n" msgstr "Attention : BYMONTHDAY vaut 0, valeur retenue : 1.\n" #: src/vevent.cc:149 #, c-format msgid "Warning: BYMONTHDAY larger than month (%d days). Assuming 1.\n" msgstr "" "Warning: BYMONTHDAY plus grand que le mois (%d jours). Valeur retenue : 1.\n" #: src/vevent.cc:162 #, c-format msgid "" "Warning: negative BYMONTHDAY (%d), unsupported by device. Converting to " "positive day of month: %d." msgstr "" "Attention : BYMONTHDAY négatif (%d), non supporté par le périphérique. " "Converti en jour de mois positif : %d." #: src/vevent.cc:274 msgid "Unknown RecurringType in Barry Calendar object" msgstr "RecurringType inconnu dans l'objet calendrier Barry" #: src/vevent.cc:414 msgid "Invalid COUNT in recurring rule: " msgstr "COUNT invalide dans la règle de récursivité :" #: src/vevent.cc:468 msgid "" "Warning: WEEKLY VEVENT without a day selected. Assuming day of start time." msgstr "" "Attention : WEEKLY VEVENT sans jour sélectionné. Utilisation du jour de " "début." #: src/vevent.cc:494 msgid "" "Warning: MONTHLY VEVENT without a day type specified (no BYMONTHDAY nor " "BYDAY). Assuming BYMONTHDAY, using day of start time." msgstr "" "Attention : MONTHLY VEVENT sans type de jour spécifié (ni BYMONTHDAY ni " "BYDAY). Utilisation de BYMONTHDAY, avec le jour de début." #: src/vevent.cc:555 msgid "" "Warning: YEARLY VEVENT without a day type specified (no BYMONTHDAY nor " "BYDAY). Assuming BYMONTHDAY, using day and month of start time." msgstr "" "Attention : MONTHLY VEVENT sans type de jour spécifié (ni BYMONTHDAY ni " "BYDAY). Utilisation de BYMONTHDAY, avec le jour et le mois de début." #: src/vevent.cc:672 msgid "vCalendar data contains more than one VEVENT block, unsupported" msgstr "" "Les données de vCalendar contiennent plus qu'un bloc VEVENT, non supporté" #: src/vevent.cc:723 msgid "Blank DTSTART" msgstr "DTSTART vide" #: src/vevent.cc:783 msgid "Unknown TRIGGER VALUE" msgstr "TRIGGER VALUE inconnue" #: src/vjournal.cc:124 msgid "vCalendar data contains more than one VJOURNAL block, unsupported" msgstr "" "Les données de vCalendar contiennent plus qu'un bloc VJOURNAL, non supporté" #: src/vjournal.cc:135 msgid "resource error allocating vjournal" msgstr "erreur lors de l'allocation de ressources pour un vjournal" #: src/vtodo.cc:168 msgid "vCalendar data contains more than one VTODO block, unsupported" msgstr "" "Les données de vCalendar contiennent plus qu'un bloc VTODO, non supporté" #: src/vtodo.cc:179 msgid "resource error allocating vtodo" msgstr "erreur lors de l'allocation de ressources pour un vtodo" #: tools/balxparse.cc:65 #, c-format msgid "" "balxparse - Command line ALX parser\n" " Copyright 2009-2010, Nicolas VIVIEN.\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -h This help\n" " -i lang Internationalization language\n" " -d path OS path with all ALX files\n" " -o file OS ALX filename (Platform.alx)\n" "\n" " ...\n" " Parse one or several ALX files.\n" "\n" " Language supported :\n" "\t" msgstr "" "balxparse - Analyseur lexicographique ALX en ligne de commandes\n" " Copyright 2009-2010, Nicolas VIVIEN.\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Utilise : %s\n" "\n" " -h Cette aide\n" " -i lang Langue\n" " -d chem Chemin système vers tous les fichiers ALX\n" " -o fich Nom système de fichier ALX (Platform.alx)\n" "\n" " ...\n" " Analyse un ou plusieurs fichiers ALX.\n" "\n" " Langues supportées :\n" "\t" #: tools/bcharge.cc:59 tools/bcharge_libusb_1_0.cc:60 #, c-format msgid "" "bcharge - Adjust Blackberry charging modes\n" " Copyright 2006-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" "\n" " -d Set to dual mode (0004)\n" " -o Set a Pearl to old Blackberry mode (0001)\n" " -g Set dual mode only if database interface class 255\n" " is not found\n" "\n" " -h This help message\n" " -p devpath The devpath argument from udev. If specified, will attempt\n" " to adjust USB suspend settings to keep the device charging.\n" " -s path The path where sysfs is mounted. Defaults to '/sys'\n" "\n" msgstr "" "bcharge - Définition du mode de charge Blackberry\n" " Copyright 2006-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" "\n" " -d Passer en mode dual (0004)\n" " -o Passer un pearl à l'ancien mode Blackberry (0001)\n" " -g Passer en mode double seulement si interface de base de\n" " données de classe 255 n'existe pas\n" "\n" " -h Ce message d'aide\n" " -p chemin Argument devpath udev. Si précisé, essaye d'ajuster les\n" " réglages d'USB suspend pour maintenir le périphérique en\n" " charge.\n" " If specified, will attempt\n" " -s chemin Le chemin du point de montage du sysfs . '/sys' par défaut.\n" "\n" #: tools/bcharge.cc:81 #, c-format msgid "" "\n" "usb_control_msg failed: code: %d, %s\n" msgstr "" "\n" "échec de usb_control_msg : code: %d, %s\n" #: tools/bcharge.cc:139 tools/bcharge_libusb_1_0.cc:149 #, c-format msgid "Can't find Mass Storage interface, assuming 0.\n" msgstr "Impossible de trouver l'interface Stockage de Masse, O utilisé.\n" #: tools/bcharge.cc:159 #, c-format msgid "usb_detach_kernel_driver_np() failed: %s\n" msgstr "échec de usb_detach_kernel_driver_np() : %s\n" #: tools/bcharge.cc:162 #, c-format msgid "usb_set_configuration() failed: %s\n" msgstr "échec de usb_set_configuration() : %s\n" #: tools/bcharge.cc:170 #, c-format msgid "Found device #%s..." msgstr "Périphérique #%s trouvé..." #: tools/bcharge.cc:175 #, c-format msgid "unable to open device\n" msgstr "impossible d'ouvrir le périphérique\n" #: tools/bcharge.cc:183 tools/bcharge_libusb_1_0.cc:196 #, c-format msgid "adjusting charge setting" msgstr "ajustement des réglages de charge" #: tools/bcharge.cc:188 tools/bcharge_libusb_1_0.cc:201 #, c-format msgid "already at 500mA" msgstr "déjà à 500mA" #: tools/bcharge.cc:196 tools/bcharge_libusb_1_0.cc:222 #, c-format msgid "...no Pearl mode adjustment" msgstr "...pas d'ajustement en mode Pearl" #: tools/bcharge.cc:201 tools/bcharge_libusb_1_0.cc:227 #, c-format msgid "...adjusting Pearl mode to single" msgstr "...ajustement du mode Pearl à simple" #: tools/bcharge.cc:206 tools/bcharge_libusb_1_0.cc:232 #, c-format msgid "...already in classic/single mode" msgstr "...déjà en mode classique / simple" #: tools/bcharge.cc:212 tools/bcharge_libusb_1_0.cc:238 #, c-format msgid "...adjusting Pearl mode to dual" msgstr "...ajustement du mode Pearl à double" #: tools/bcharge.cc:217 tools/bcharge_libusb_1_0.cc:243 #, c-format msgid "...already in dual mode" msgstr "...déjà en mode double" #: tools/bcharge.cc:223 tools/bcharge_libusb_1_0.cc:249 #, c-format msgid "...no database iface found, setting dual mode" msgstr "...pas d'interface de base de données, passage en mode double" #: tools/bcharge.cc:228 tools/bcharge_libusb_1_0.cc:254 #, c-format msgid "...found database iface, no change" msgstr "...interface de base de données trouvée, pas de changement" #: tools/bcharge.cc:260 #, c-format msgid "" "\n" "usb_reset failed: %s\n" msgstr "" "\n" "échec de usb_reset : %s\n" #: tools/bcharge.cc:264 tools/bcharge_libusb_1_0.cc:291 #, c-format msgid "...done" msgstr "...fait" #: tools/bcharge.cc:267 tools/bcharge_libusb_1_0.cc:294 #, c-format msgid "...no change" msgstr "...pas de changement" #: tools/bcharge.cc:281 tools/bcharge_libusb_1_0.cc:308 #, c-format msgid "autosuspend adjustment failure: (file: %s): %s\n" msgstr "échec du réglage d'autosuspend : (fichier : %s): %s\n" #: tools/bcharge.cc:292 tools/bcharge_libusb_1_0.cc:319 #, c-format msgid "autosuspend adjustment failure (write): (file: %s): %s\n" msgstr "échec du réglage d'autosuspend (écriture) : (fichier : %s): %s\n" #: tools/bcharge.cc:298 tools/bcharge_libusb_1_0.cc:325 #, c-format msgid "autosuspend adjustment: wrote %s to %s\n" msgstr "réglage d'autosuspend : écrit %s vers %s\n" #: tools/bcharge.cc:425 #, c-format msgid "" "\n" "Unable to scan devices: %s\n" msgstr "" "\n" "Impossible de chercher les périphériques : %s\n" #: tools/bcharge.cc:430 tools/bcharge_libusb_1_0.cc:460 tools/breset.cc:67 #: tools/breset_libusb_1_0.cc:82 #, c-format msgid "Scanning for Blackberry devices...\n" msgstr "Recherche d'appareil Blackberry...\n" #: tools/bcharge_libusb_1_0.cc:82 #, c-format msgid "" "\n" "usb_control_transfer failed: code: %d\n" msgstr "" "\n" "échec de usb_control_transfer : code : %d\n" #: tools/bcharge_libusb_1_0.cc:163 #, c-format msgid "Detecting possible kernel driver conflict, trying to resolve...\n" msgstr "Détection d'un possible conflit noyau, tentative de résolution...\n" #: tools/bcharge_libusb_1_0.cc:168 #, c-format msgid "libusb_detach_kernel_driver() failed: %d\n" msgstr "échec de libusb_detach_kernel_driver() : %d\n" #: tools/bcharge_libusb_1_0.cc:172 #, c-format msgid "libusb_set_configuration() failed: %d\n" msgstr "échec de libusb_set_configuration() : %d\n" #: tools/bcharge_libusb_1_0.cc:179 #, c-format msgid "Found device #%d-%d..." msgstr "Périphérique #%d-%d trouvé..." #: tools/bcharge_libusb_1_0.cc:187 #, c-format msgid "unable to open device, %d\n" msgstr "impossible d'ouvrir le périphérique, %d\n" #: tools/bcharge_libusb_1_0.cc:207 #, c-format msgid "failed to discover power level\n" msgstr "la découverte de niveau de courant a échoué\n" #: tools/bcharge_libusb_1_0.cc:214 #, c-format msgid "failed to get device descriptor: %d\n" msgstr "impossible de récupérer le descripteur de périphérique : %d\n" #: tools/bcharge_libusb_1_0.cc:287 #, c-format msgid "" "\n" "libusb_reset_device() failed: %d\n" msgstr "" "\n" "échec de libusb_reset_device() : %d\n" #: tools/bcharge_libusb_1_0.cc:453 #, c-format msgid "Failed to start up USB: %d\n" msgstr "Échec au démarrage de l'USB : %d\n" #: tools/bdptest.cc:60 msgid "List of debug files: " msgstr "Liste des fichiers de débogage :" #: tools/bfuse.cc:71 #, c-format msgid "" "bfuse - FUSE filesystem for Blackberry databases\n" " Copyright 2008-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" msgstr "" "bfuse - Système de fichiers pour bases de données Blackberry\n" " Copyright 2008-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Utilise : %s\n" #: tools/bfuse.cc:80 msgid "" "\n" "Barry specific options:\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" msgstr "" "\n" "Options spécifiques de Barry :\n" " -p pin PIN du périphérique auquel parler\n" " Si un seul périphérique est branché, ce paramètre est " "optionnel\n" " -P pass Méthode simple pour entrer le mot de passe\n" #: tools/bfuse.cc:434 tools/bfuse.cc:452 msgid "Constructed != name" msgstr "Constructed != name" #: tools/bfuse.cc:571 msgid "Hello FUSE world. This is Barry. Pleased to meet you.\n" msgstr "" "Bonjour le monde de FUSE. Ceci est Barry. Enchanté de faire ta " "connaissance.\n" #: tools/bidentify.cc:37 #, fuzzy, c-format msgid "" "bidentify - USB Blackberry Identifier Tool\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -B bus Specify which USB bus to search on\n" " -N dev Specify which system device, using system specific string\n" "\n" " -c If used with -m, show both hex and dec where possible\n" " -m Also show the device's ESN / MEID / IMEI\n" " -s Also show the device's USB serial number (same as shown by " "lsusb)\n" " -h This help\n" " -v Dump protocol data during operation\n" msgstr "" "bidentify - Outil USB d'identification de Blackberry\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Utilise : %s\n" "\n" " -B bus Indique le bus USB sur lequel chercher\n" " -N périph Indique le périphérique système, chaîne dépendant du système\n" "\n" " -c Si utilisé avec -m, afficher l'hexa et le décimal si possible\n" " -m Montrer aussi l'ESN / MEID / IMEI du périphérique\n" " -h Cette aide\n" " -v Afficher les données du protocole pendant les opérations\n" #: tools/bidentify.cc:162 msgid "Error on PIN: " msgstr "Erreur de PIN :" #: tools/bidentify.cc:178 tools/brawchannel.cc:341 msgid "exception caught: " msgstr "exception attrapée : " #: tools/bio.cc:68 tools/btool.cc:73 msgid "Compiled with Boost support" msgstr "Compilé avec le support de Boost" #: tools/bio.cc:70 msgid "" "\n" " Options to use for 'boost' type:\n" " -f file Boost serialization filename to read from or write to\n" " Can use - to specify stdin/stdout\n" msgstr "" "\n" " Option à utiliser avec le type 'boost' :\n" " -f fich Nom de fichier de sérialisation à lire ou écrire\n" " Utiliser - pour l'entrée et la sortie standards\n" #: tools/bio.cc:75 tools/btool.cc:76 msgid "Compiled without Boost support" msgstr "Compilé sans le support de Boost" #. TRANSLATORS: the i/o types, such as device, tar, mime, etc. must #. be exact. They are commands that the code tests for. Do not #. translate those particular words. Same with the -w write mode #. options. #: tools/bio.cc:85 #, c-format msgid "" "bio - Barry Input / Output\n" " Copyright 2010-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" " %s\n" "\n" " Usage: bio -i [options...] -o [options...]\n" "\n" " -i type The input type (Builder) to use for producing records\n" " Can be one of: device, tar, %sldif, mime\n" " -o type The output type (Parser) to use for processing records.\n" " Multiple outputs are allowed, as long as they don't\n" " conflict (such as two outputs writing to the same file\n" " or device).\n" " Can be one of: device, tar, %sldif, mime, dump, sha1, cstore\n" "\n" " Options to use for 'device' type:\n" " -d db Name of input database. Can be used multiple times.\n" " -A Add all available device databases, instead of specifying\n" " them manually via -d\n" " -p pin PIN of device to talk to\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -w mode Set write mode when using 'device' for output. Must be\n" " specified, or will not write anything.\n" " Can be one of: erase, overwrite, addonly, addnew\n" "\n" " Options to use for 'tar' backup type:\n" " -d db Name of input database. Can be used multiple times.\n" " Not available in output mode. Note that by default,\n" " all databases in the backup are selected, when reading,\n" " unless at least one -d is specified.\n" " -D db Name of input database to skip. If no -d options are used,\n" " then all databases are automatically selected. Using -D\n" " allows a filtering selection. If -d and -D are used for\n" " the same database, -D takes precedence.\n" " -f file Tar backup file to read from or write to\n" "%s\n" " Options to use for 'ldif' type:\n" " -c dn Convert address book database to LDIF format, using the\n" " specified baseDN\n" " -C dnattr LDIF attribute name to use when building the FQDN\n" " Defaults to 'cn'\n" "\n" " Options to use for 'mime' type:\n" " -f file Filename to read from or write to. Use - to explicitly\n" " specify stdin/stdout, which is default.\n" "\n" " Options to use for 'dump' to stdout output type:\n" " -n Use hex dump parser on all databases.\n" " -T Show only the names of the databases.\n" "\n" " Options to use for 'sha1' sum stdout output type:\n" " -t Include DB Name, Type, and Unique record IDs in the checksums\n" "\n" " Options to use for 'cstore' output type:\n" " -l List filenames only\n" " -f file Filename from the above list, including path.\n" " If found, the file will be written to the current\n" " directory, using the base filename from the device.\n" "\n" " Standalone options:\n" " -h This help\n" " -I cs International charset for string conversions\n" " Valid values here are available with 'iconv --list'\n" " -S Show list of supported database parsers and builders.\n" " Use twice to show field names as well.\n" " -v Dump protocol data during operation\n" "\n" msgstr "" "bio - Entrées sorties avec Barry\n" " Copyright 2010-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Utilise : %s\n" " %s\n" "\n" " Usage: bio -i [options...] -o [options...]\n" "\n" " -i type Le type d'entrée (constructeur) utilisé pour produire\n" " les enregistrements.\n" " Possibilités : device, tar, %sldif, mime\n" " -o type Le type de sortie (analyseur lexical) pour traiter\n" " les enregistrements.\n" " Plusieurs sorties sont autorisées tant qu'il n'y a pas\n" " de conflit (tels que des sorties dupliquées).\n" " Possibilités : device, tar, %sldif, mime, dump, sha1, cstore\n" "\n" " Options du type 'device : \n" " -d bdd Nom de la base d'entrée. Peut être répété.\n" " -A Ajouter toutes les bases du périphérique, plutôt\n" " que de les spécifier manuellement avec -d\n" " -p pin PIN du périphérique auquel parler\n" " Optionnel s'il n'y a qu'un périphérique\n" " -P pass Méthode simple pour entrer le mot de passe\n" " -w mode Définit le mode d'écriture. Requis, sinon rien ne\n" " sera écrit.\n" " Possibilités : erase, overwrite, addonly, addnew\n" "\n" " Options du type 'tar' en sortie :\n" " -d bdd Nom de la base d'entrée. Peut être répété.\n" " Non disponible en sortie. Noter que par défaut, toute les\n" " bases de la sauvegarde sont sélectionnées, en lecture\n" " à moins qu'au moins une option -d ne soit spécifiée.\n" " -D bdd Nom des bases d'entrée à ignorer. Si l'option -d est absente,\n" " toutes les bases sont sélectionnées automatiquement. Utiliser -" "D\n" " permet un filtrage sur la sélection. Si -d et -D sont " "utilisés\n" " pour la même base, -D l'emporte.\n" " -f fich Ficher de sauvegarde tar à lire ou écrire.\n" "%s\n" " Options du mode 'ldif' :\n" " -c dn Convertit le carnet d'adresses au format LDIF, avec le\n" " baseDN spécifié.\n" " -C dnattr Nom d'attribut LDIF à utiliser lors de la construction du " "FQDN.\n" " 'cn' par défaut.\n" "\n" " Options du type 'mime' :\n" " -f fich Nom de fichier à lire ou écrire. Utiliser - pour spécifier les\n" " fichiers d'entrée / sortie standard, ce qui est le défaut.\n" "\n" " Options du mode 'dump' sur la sortie standard :\n" " -n Utiliser l'analyseur affichage hexadécimal pour toutes les " "bases.\n" " -T Ne montrer que les noms des basses de données.\n" "\n" " Options du mode somme 'sha1' sur la sortie standard :\n" " -t Inclut le nom de la bdd, son type et les IDs uniques\n" " d'enregistrement dans la somme de contrôle.\n" "\n" " Options du type 'cstore' en sortie :\n" " -l Ne lister que les noms de fichiers.\n" " -f fich Nom de fichier de la liste au-dessus, chemin inclus.\n" " S'il est trouvé, le fichier sera écris dans le répertoire\n" " courant, en utilisant le nom de base du fichier sur le\n" " périphérique.\n" " Options communes :\n" " -h Cette aide.\n" " -I enc Encodage pour la conversion de chaînes\n" " Les valeurs admissibles sont données par 'iconv --list'\n" " -S Afficher la liste des analyseurs et constructeurs de\n" " base de données supportés.\n" " Si passée deux fois, montre également les noms des champs.\n" " -v Afficher les échanges pendant les opérations.\n" "\n" #: tools/bio.cc:178 msgid "Filename not applicable for this mode" msgstr "Nom de fichier non applicable à ce mode" #: tools/bio.cc:183 msgid "DB not applicable for this mode" msgstr "BDD non applicable à ce mode" #: tools/bio.cc:188 msgid "DB skipping not applicable for this mode" msgstr "Ignorer une BDD non applicable à ce mode" #: tools/bio.cc:193 msgid "DBs not applicable for this mode" msgstr "BDDs non applicables à ce mode" #: tools/bio.cc:198 msgid "PIN not applicable for this mode" msgstr "PIN non applicable à ce mode" #: tools/bio.cc:203 msgid "Password not applicable for this mode" msgstr "Mot de passe non applicable à ce mode" #: tools/bio.cc:208 msgid "Device write behaviour not applicable for this mode" msgstr "Comportement d'écriture périphérique non applicable à ce mode" #: tools/bio.cc:213 msgid "DN not applicable for this mode" msgstr "DN non applicable à ce mode" #: tools/bio.cc:218 msgid "Attribute not applicable for this mode" msgstr "Attribut non applicable à ce mode" #: tools/bio.cc:223 msgid "No hex dump option in this mode" msgstr "Pas d'option d'affichage hexadécimal pour ce mode" #: tools/bio.cc:228 msgid "No name-only option in this mode" msgstr "Pas d'option d'affichage 'noms seuls' pour ce mode" #: tools/bio.cc:233 msgid "Including record IDs in the SHA1 sum is not applicable in this mode" msgstr "" "Inclure les IDs d'enregistrement dans la somme SHA1 n'est pas applicable à " "ce mode" #: tools/bio.cc:238 msgid "List option not applicable for this mode" msgstr "Option de liste non applicable à ce mode" #: tools/bio.cc:256 msgid "Invalid PIN: " msgstr "PIN invalide :" #: tools/bio.cc:310 tools/bio.cc:529 tools/btool.cc:817 tools/pppob.cc:271 msgid "PIN not found: " msgstr "PIN non trouvé : " #: tools/bio.cc:312 tools/bio.cc:531 msgid "PIN not specified, and more than one device exists." msgstr "PIN non spécifié, or il y a plus d'un périphérique." #: tools/bio.cc:316 tools/bio.cc:535 msgid "" "It seems you are trying to use the same device for multiple input or outputs." msgstr "" "Il semble que vous essayiez d'utiliser le même périphérique pour de " "multiples entrées ou sorties." #: tools/bio.cc:331 msgid "Database not found: " msgstr "Base de données non trouvée : " #: tools/bio.cc:353 msgid "Cannot use stdin as tar source file, sorry." msgstr "Impossible d'utiliser l'entrée standard comme source tar, désolé." #: tools/bio.cc:523 msgid "" "Warning: the -w switch was not specified: no data will be written to the " "device." msgstr "" "Attention : l'option -w n'a pas été activée : aucune donnée ne sera écrite " "sur le périphérique." #: tools/bio.cc:561 msgid "Cannot use stdout as tar backup file, sorry." msgstr "Impossible d'utiliser stdout comme fichier de sauvegarde tar, désolé." #: tools/bio.cc:589 msgid "Boost output requires a specific output file (-f switch)" msgstr "" "La sortie Boost requiert un type de fichier de sortie spécifique (option -f)" #: tools/bio.cc:817 msgid " (folder)" msgstr " (dossier)" #: tools/bio.cc:852 #, c-format msgid "Saving: %s as %s" msgstr "Sauvegarde : %s en tant que %s" #: tools/bio.cc:859 msgid "Error during write!" msgstr "Erreur durant l'écriture !" #: tools/bio.cc:968 msgid "" "Unknown device output mode. Must be one of: erase, overwrite, addonly, addnew" msgstr "" "Mode de sortie de périphérique inconnu. Doit être un parmi : erase, " "overwrite, addonly, addnew" #: tools/bio.cc:1157 tools/btarcmp.cc:815 msgid "Exception: " msgstr "Exception : " #: tools/bjavaloader.cc:66 #, c-format msgid "" "bjavaloader - Command line USB Blackberry Java Loader\n" " Copyright 2008-2009, Nicolas VIVIEN.\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -A Save all modules found\n" " -a Wipe applications only\n" " -i Wipe filesystem only\n" " -f Force erase, if module is in use\n" " -h This help\n" " -s List sibling in module list\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" "\n" "Commands:\n" "\n" " %s [-s]\n" " Lists modules on the handheld\n" "\n" " %s\n" " Provides information on the handheld\n" "\n" " %s <.cod file> ...\n" " Loads modules onto the handheld\n" "\n" " %s [-A] ...\n" " Retrieves modules from the handheld and writes to .cod file\n" " Note: will overwrite existing files!\n" "\n" " %s [-a | -i]\n" " Wipes the handheld\n" " Use Caution: Wiping filesystem will remove all data\n" " such as messages, contacts, etc.\n" " Wiping applications will remove all .cod files\n" " on the device, including OS .cod files.\n" "\n" " %s\n" " Reset IT policy to factory defaults\n" " Use Caution: Resetting IT policy to factory defaults will\n" " also perform a filesystem wipe which will remove\n" " all data such as messages, contacts, etc.\n" "\n" " %s [-f] ...\n" " Erase module from handheld\n" "\n" " %s\n" " Retrieves the handheld event log\n" "\n" " %s\n" " Clears the handheld event log\n" "\n" " %s\n" " Dump the stack traces for all threads to the event log\n" "\n" " %s <.bmp file>\n" " Make a screenshot of handheld\n" "\n" " %s [%s]\n" " Sets the time on the handheld to the current time\n" " Or the time specified as an argument to %s\n" " If given as argument, current system timezone is assumed\n" msgstr "" "bjavaloader - Chargeur Java USB pour Blackberry\n" " Copyright 2008-2009, Nicolas VIVIEN.\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Utilise : %s\n" "\n" " -A Sauver tous les modules trouvés\n" " -a Effacer seulement les applications\n" " -i Effacer seulement le système de fichiers\n" " -f Forcer l'effacement si un module est en cours d'utilisation\n" " -h Cette aide\n" " -s Lister les modules apparentés, dans la liste des modules.\n" " -p pin PIN du périphérique auquel parler\n" " Si un seul périphérique est branché, ce paramètre est\n" " optionnel\n" " -P pass Méthode simple pour entrer le mot de passe\n" " -v Afficher les données de protocole pendant l'opération\n" "\n" "Commandes :\n" "\n" " %s [-s]\n" " Liste tous les modules du périphérique.\n" "\n" " %s\n" " Fournit des informations sur le périphérique.\n" "\n" " %s ...\n" " Charge des modules sur le périphérique.\n" "\n" " %s [-A] ...\n" " Récupère les modules depuis le périphérique et les écrit\n" " dans un fichier .cod. Note : écrase les fichiers existants !\n" "\n" " %s [-a | -i]\n" " Efface le périphérique.\n" " Utiliser avec précautions : écraser le système de fichier\n" " effacera toutes les données, messages, contacts, etc.\n" " Écraser les applications supprimera tous les fichiers\n" " .cod du périphérique, fichiers .cod du SE inclus.\n" "\n" " %s\n" " Réinitialiser la politique IT aux paramètres par défaut\n" " Avertissement : Réinitialiser la politique IT aux paramètres par\n" " défaut va également provoquer un effacement du système\n" " de fichiers qui supprimera toutes les données,\n" " messages, contacts, etc.\n" "\n" " %s [-f] ...\n" " Supprime le module du périphérique\n" "\n" " %s\n" " Récupère le journal d'événements du périphérique\n" "\n" " %s\n" " Efface le journal d'événements du périphérique\n" "\n" " %s\n" " Écrit toutes les traces de pile pour tous les threads dans le\n" " journal d'événements\n" "\n" " %s \n" " Fait une capture d'écran du périphérique\n" "\n" " %s [%s]\n" " Définit la date et l'heure sur le périphérique à la date et\n" " l'heure courantes, ou à la date et heure spécifiées en argument\n" " à %s\n" " Si un argument est passé, la zone de temps actuelle du système est\n" " utilisée.\n" #: tools/bjavaloader.cc:173 msgid "Unable to parse time string: " msgstr "Chaîne de temps impossible à interpréter : " #: tools/bjavaloader.cc:208 msgid "Can't open: " msgstr "Impossible d'ouvrir : " #: tools/bjavaloader.cc:310 tools/bjdwp.cc:104 msgid "missing command" msgstr "commande manquante" #: tools/bjavaloader.cc:335 tools/bjdwp.cc:124 tools/bjvmdebug.cc:108 #: tools/brawchannel.cc:250 tools/brecsum.cc:123 tools/bwatch.cc:132 msgid "No device selected, or PIN not found" msgstr "Pas de périphérique sélectionné ou PIN manquant" #: tools/bjavaloader.cc:357 msgid "specify at least one .cod file to load" msgstr "indiquer au moins un fichier .cod à charger" #: tools/bjavaloader.cc:364 msgid "loading: " msgstr "chargement : " #: tools/bjavaloader.cc:366 tools/bjavaloader.cc:383 tools/bjavaloader.cc:421 #: tools/bjavaloader.cc:434 msgid "done." msgstr "fait." #: tools/bjavaloader.cc:371 msgid "specify at least one module to erase" msgstr "spécifier au moins un module à effacer" #: tools/bjavaloader.cc:378 msgid "erasing: " msgstr "en cours d'effacement : " #: tools/bjavaloader.cc:388 msgid "specify a .bmp filename" msgstr "préciser un nom de fichier .bmp" #: tools/bjavaloader.cc:419 tools/bjavaloader.cc:432 msgid "saving: " msgstr "enregistrement de : " #: tools/bjavaloader.cc:425 msgid "specify at least one module to save" msgstr "préciser au moins un module à enregistrer" #. TRANSLATORS: you may translate yes/no as long as you also #. translate "yes" to match. #: tools/bjavaloader.cc:447 #, c-format msgid "" "Use Caution: Wiping filesystem will remove all data\n" " such as messages, contacts, etc.\n" " Wiping applications will remove all .cod files\n" " on the device, including OS .cod files.\n" "\n" "You have selected to wipe the filesystem of device '%s'\n" "Continue with wipe? (yes/no) " msgstr "" "Précaution d'utilisation : L'effacement du système de\n" " fichiers va supprimer toutes les données\n" " telles que les messages, les contacts, etc.\n" " L'effacement des applications va supprimer\n" " tous les fichiers .cod du périphérique, ceux\n" " du SE inclus.\n" "\n" "Vous avez choisi d'effacer le système de fichier du périphérique '%s'\n" "Continuer l'effacement ? (oui / non)" #: tools/bjavaloader.cc:459 tools/bjavaloader.cc:475 msgid "Response of 'yes' not received, aborting." msgstr "La réponse reçue n'est pas 'oui', annulation." #: tools/bjavaloader.cc:464 #, c-format msgid "" "Use Caution: Resetting IT policy to factory defaults will\n" " also perform a filesystem wipe which will remove\n" " all data such as messages, contacts, etc.\n" "\n" "You have selected to reset device '%s' to factory defaults\n" "Continue with wipe? (yes/no) " msgstr "" "Précaution d'utilisation : Réinitialiser la politique IT aux\n" " paramètres d'usine va également effacer le\n" " système de fichiers, ce qui supprimera toutes\n" " les données telles que messages, contacts, etc.\n" "\n" "Vous avez choisi de réinitialiser le périphérique '%s' aux\n" "paramètres d'usine\n" "Continuer l'effacement ? (oui / non) " #: tools/bjavaloader.cc:479 msgid "invalid command: " msgstr "commande invalide : " #: tools/bjavaloader.cc:490 tools/bjdwp.cc:154 tools/bjvmdebug.cc:171 #: tools/brawchannel.cc:333 tools/bs11nread.cc:146 tools/btool.cc:1012 #: tools/bwatch.cc:197 tools/upldif.cc:189 msgid "Usb::Error caught: " msgstr "Exception Usb::Error attrapée : " #: tools/bjavaloader.cc:495 tools/bjdwp.cc:159 tools/bjvmdebug.cc:176 #: tools/brawchannel.cc:337 tools/bs11nread.cc:150 tools/btool.cc:1016 #: tools/bwatch.cc:202 tools/upldif.cc:192 msgid "Barry::Error caught: " msgstr "Exception Barry::Error attrapée : " #: tools/bjavaloader.cc:500 tools/bjdwp.cc:164 tools/bjvmdebug.cc:181 #: tools/bs11nread.cc:154 tools/btool.cc:1020 tools/bwatch.cc:207 #: tools/upldif.cc:195 msgid "std::exception caught: " msgstr "Exception std::exception attrapée : " #: tools/bjdwp.cc:44 #, c-format msgid "" "bjdwp - Command line USB Blackberry JDWP\n" " Copyright 2008-2009, Nicolas VIVIEN.\n" " Using: %s\n" "\n" " -h This help\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" "\n" "arguments\n" "\n" "
Interface\n" " Listen port\n" msgstr "" "bjdwp - JDWP Blackberry par USB, en ligne de commandes.\n" " Copyright 2008-2009, Nicolas VIVIEN.\n" " Utilise : %s\n" "\n" " -h Cette aide.\n" " -p pin PIN du périphérique auquel parler\n" " Si un seul périphérique est branché, ce paramètre est\n" " optionnel.\n" " -P pass Méthode simple pour entrer le mot de passe.\n" " -v Afficher les données de protocole pendant l'opération.\n" "\n" "arguments\n" "\n" " Interface\n" " Port d'écoute\n" #: tools/bjvmdebug.cc:45 #, c-format msgid "" "bjvmdebug - Command line USB Blackberry Java Debugger\n" " Copyright 2008-2009, Nicolas VIVIEN.\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -h This help\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" msgstr "" "bjvmdebug - Débogueur Java USB en ligne de commandes\n" " Copyright 2008-2009, Nicolas VIVIEN.\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Utilise : %s\n" "\n" " -h Cette aide.\n" " -p pin PIN du périphérique auquel parler\n" " Si un seul périphérique est branché, ce paramètre est\n" " optionnel.\n" " -P pass Méthode simple pour entrer le mot de passe.\n" " -v Afficher les données de protocole pendant l'opération.\n" #: tools/bjvmdebug.cc:131 msgid "Java Modules List :" msgstr "Liste des modules java : " #: tools/bjvmdebug.cc:138 msgid "Java Threads currently running :" msgstr "Threads java en cours d'exécution : " #: tools/bjvmdebug.cc:162 msgid "JVM message : " msgstr "Message de la JVM : " #: tools/boostwrap.cc:45 msgid "Archive exception in DoLoadBoostFile(): " msgstr "Exception sur une archive dans DoLoadBoostFile() : " #: tools/boostwrap.cc:64 msgid "Archive exception in DoSaveBoostFile(): " msgstr "Exception sur une archive dans DoSaveBoostFile() : " #: tools/brawchannel.cc:83 msgid "From BB: " msgstr "Lu du BB : " #: tools/brawchannel.cc:95 #, c-format msgid "Written %ld bytes over stdout" msgstr "%ld octets écrits sur la sortie standard" #: tools/brawchannel.cc:109 msgid "CallbackHandler: Received error: " msgstr "CallbackHandler : erreur reçue : " #: tools/brawchannel.cc:124 #, c-format msgid "" "brawchannel - Command line USB Blackberry raw channel interface\n" " Copyright 2010, RealVNC Ltd.\n" " Using: %s\n" "\n" "Usage:\n" "brawchannel [options] \n" "\n" " -h This help\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" " This will cause libusb output to appear on STDOUT unless\n" " the environment variable USB_DEBUG is set to 0,1 or 2.\n" msgstr "" "brawchannel - Interface en ligne de commande de canal brut USB pour " "Blackberry\n" " Copyright 2010, RealVNC Ltd.\n" " Utilise : %s\n" "\n" "Usage :\n" "brawchannel [options] \n" "\n" " -h Cette aide\n" " -p pin PIN du périphérique auquel parler\n" " Si un seul périphérique est branché, ce paramètre est\n" " optionnel\n" " -P pass Méthode simple pour entrer le mot de passe\n" " -v Afficher les données de protocole pendant l'opération\n" " Provoque l'affichage de la sortie de libusb sur la sortie\n" " standard, à moins que la variable d'environnement\n" " USB_DEBUG ne vaille 0, 1 ou 2.\n" #: tools/brawchannel.cc:209 msgid "Error: Missing raw channel name." msgstr "Erreur : nom de canal brut manquant." #: tools/brawchannel.cc:215 msgid "Error: Too many arguments." msgstr "Erreur : trop d'arguments." #: tools/brawchannel.cc:235 msgid "" "Warning: Protocol dump enabled without setting USB_DEBUG to 0, 1 or 2.\n" " libusb might log to STDOUT and ruin data stream." msgstr "" "Attention : affichage du protocole activé sans avoir défini USB_DEBUG à 0, 1 " "ou 2.\n" " la libusb risque d'afficher sur la sortie standard ce qui risque " "de corrompre le flux de données" #: tools/brawchannel.cc:257 msgid "Connected to device, starting read/write\n" msgstr "Connecté au périphérique, début de la lecture / écriture\n" #: tools/brawchannel.cc:306 msgid "Select failed with errno: " msgstr "Select a échoué avec une errno de : " #: tools/brawchannel.cc:315 #, c-format msgid "Sending %ld bytes stdin->USB\n" msgstr "Envoi de %ld octets stdin->USB\n" #: tools/brawchannel.cc:316 msgid "To BB: " msgstr "Au BB : " #: tools/brawchannel.cc:323 #, c-format msgid "Sent %ld bytes stdin->USB\n" msgstr "%ld octets envoyés stdin->USB\n" #: tools/brecsum.cc:42 #, c-format msgid "" "brecsum - Generate SHA1 sums of raw Blackberry database records.\n" " Copyright 2008-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -d db Read database 'db' and sum all its records.\n" " Can be used multiple times to fetch more than one DB\n" " -h This help\n" " -i Include DB Name, Type, and Unique record IDs in the checksums\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" msgstr "" "brecsum - Génère des sommes SHA1 des enregistrements de base de\n" " données bruts.\n" " Copyright 2008-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Utilise : %s\n" "\n" " -d bdd Lit la base de données 'bdd' et calcule la somme.pour tous\n" " ses enregistrements. Peut-être utilisé plusieurs fois pour\n" " récupérer plus d'une base de données.\n" " -h Cette aide\n" " -i Inclure le nom de BDD, le type et les IDs uniques\n" " d'enregistrement dans les sommes de contrôle.\n" " -p pin PIN du périphérique auquel parler\n" " Si un seul périphérique est branché, ce paramètre est\n" " optionnel.\n" " -P pass Méthode simple pour entrer le mot de passe.\n" " -v Afficher les données de protocole pendant l'opération.\n" #: tools/breset.cc:81 tools/breset_libusb_1_0.cc:105 #, c-format msgid "Found..." msgstr "Trouvé..." #: tools/breset.cc:82 tools/breset_libusb_1_0.cc:106 #, c-format msgid "attempting to reset.\n" msgstr "Réinitialisation en cours.\n" #: tools/breset.cc:86 tools/breset_libusb_1_0.cc:110 #, c-format msgid "Can't reset device on bus %s, devnum %u\n" msgstr "Impossible de réinitialiser le périphérique, bus %s, devnum %u\n" #: tools/breset.cc:91 tools/breset_libusb_1_0.cc:114 #, c-format msgid "%d device%s reset.\n" msgstr "%d périphérique%s réinitialisé.\n" #: tools/breset_libusb_1_0.cc:79 #, c-format msgid "Failed to start USB: %d\n" msgstr "Échec au démarrage de l'USB : %d\n" #: tools/bs11nread.cc:49 #, c-format msgid "" "bs11nread - Reads a boost serialization file (from btool)\n" " and dumps data to stdout\n" " Copyright 2008-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -f file Filename to save or load handheld data to/from\n" " -h This help\n" " -S Show list of supported database parsers\n" msgstr "" "bs11nread - Lit un fichier de sérialisation boost (de btool)\n" " et affiche le contenu su la sortie standard\n" " Copyright 2008-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Utilise : %s\n" "\n" " -f fich Nom du fichier duquel / vers lequel les données du\n" " périphérique seront lues / écrites\n" " -h Cette aide\n" " -S Affiche la liste des analyseurs de base de données\n" " supportés\n" #: tools/bs11nread.cc:76 msgid " records loaded" msgstr " enregistrement chargés" #: tools/bs11nread.cc:100 msgid "Unknown database name: " msgstr "Nom de base de données inconnu : " #: tools/bs11nread.cc:138 msgid "Filename must be specified" msgstr "Le nom de fichier doit être spécifié" #. TRANSLATORS: the Using: string is followed by the Barry library version #. string. #: tools/btarcmp.cc:56 #, c-format msgid "" "btarcmp - Compare Barry backup tarballs\n" " Copyright 2012-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " Usage: btarcmp [options...] tarball_0 tarball_1\n" "\n" " -b Use brief filename output\n" " -d db Specify a specific database to compare. Can be used\n" " multiple times. If not used at all, all databases are\n" " compared.\n" " -D db Specify a database name to skip. If both -d and -D are\n" " used for the same database name, it will be skipped.\n" " -h This help\n" " -I cs International charset for string conversions\n" " Valid values here are available with 'iconv --list'\n" " -P Only compare records that can be parsed\n" " This is the same as specifying -d for each database\n" " listed with -S.\n" " -S Show list of supported database parsers. Use twice\n" " to show field names as well.\n" " -v Show verbose diff output (twice to force hex output)\n" "\n" msgstr "" "btarcmp - Compare des tarballs de sauvegarde Barry\n" " Copyright 2012-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Utilise : %s\n" "\n" " Usage: btarcmp [options...] tarball_0 tarball_1\n" "\n" " -b Utiliser des noms de fichier courts en sortie\n" " -d bdd Préciser une base de données spécifique à comparer. Peut\n" " être utilisé plusieurs fois. Si non précisé, toutes les\n" " bases sont comparées.\n" " -D bdd Préciser une base de données à ignorer. Si -d et -D sont\n" " présents tous les deux pour un même nom de base, elle\n" " sera ignorée.\n" " -h Cette aide.\n" " -I enc Encodage pour la conversion de chaînes\n" " Les valeurs admissibles sont données par 'iconv --list'\n" " -P Ne comparer que les enregistrements des bases pouvant\n" " être interprétées. Ceci est équivalent à spécifier -d pour\n" " chaque base listée par -S.\n" " -S Affiche la liste des interpréteurs de bases de données\n" " supportés. L'utiliser deux fois pour afficher également\n" " les noms de champs.\n" " -v Afficher une sortie de comparaison verbeuse (deux fois\n" " pour forcer un affichage en hexadécimal)\n" "\n" #: tools/btarcmp.cc:186 msgid "Different database types in ParsedCompare ctor!" msgstr "Bases de données différentes dans ParsedCompare ctor !" #: tools/btarcmp.cc:461 msgid ": has no database '" msgstr ": n'a pas de base de données '" #: tools/btarcmp.cc:502 msgid "Comparing non-existant database!" msgstr "Comparaison de bases de données n'existant pas !" #: tools/btarcmp.cc:532 msgid "record has been deleted in " msgstr "enregistrement a été supprimé dans " #: tools/btarcmp.cc:533 msgid "record has been added in " msgstr "enregistrement a été ajouté dans " #: tools/btarcmp.cc:542 msgid "Tried to compare records from different databases: " msgstr "" "Tentative de comparaison d'enregistrements de bases de données différentes :" #: tools/btarcmp.cc:569 tools/btarcmp.cc:579 msgid ": differs: " msgstr ": diffère de :" #: tools/btarcmp.cc:571 tools/btarcmp.cc:581 msgid "sizes (" msgstr "tailles (" #: tools/btarcmp.cc:573 msgid "), SHA1 sums differ" msgstr "), les SHA1 diffèrent" #: tools/btarcmp.cc:589 msgid "No differences found in parsed records, but SHA1 sums differ." msgstr "" "Pas de différence à la lecture des enregistrements, mais les SHA1 diffèrent." #: tools/btarcmp.cc:596 msgid " Hex diff of record:" msgstr " diff hexa d'enregistrements :" #: tools/btarcmp.cc:687 msgid "In database: " msgstr "Dans la base de données : " #: tools/btardump.cc:42 tools/btool.cc:81 msgid " -V Dump records using MIME vformats where possible" msgstr "" " -V Affiche les enregistrements en utilisant les vformats MIME " "quand c'est possible possible" #: tools/btardump.cc:48 #, c-format msgid "" "btardump - Command line parser for Barry backup files\n" " Copyright 2010-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -d db Name of database to dump. Can be used multiple times\n" " to parse multiple databases at once. If not specified\n" " at all, all available databases from the backup are\n" " dumped.\n" " -h This help\n" " -i cs International charset for string conversions\n" " Valid values here are available with 'iconv --list'\n" "%s\n" "\n" " [files...] Backup file(s), created by btool or the backup GUI.\n" msgstr "" "btardump - Analyseur en ligne de commandes pour fichiers de sauvegarde " "Barry\n" " Copyright 2010-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Utilise : %s\n" "\n" " -d bdd Nom de la base à afficher.Peut être utilisé plusieurs fois " "pour\n" " afficher plusieurs bases. Si on spécifiées, toutes les bases " "de\n" " la sauvegarde sont affichées.\n" " -h Cette aide.\n" " -I enc Encodage pour la conversion de chaînes\n" " Les valeurs admissibles sont données par 'iconv --list'\n" "%s\n" "\n" " [fichiers...] fichier(s) de sauvegarde, créé par btool ou par " "l'interface\n" " graphique de sauvegarde.\n" #: tools/btardump.cc:132 tools/btool.cc:714 msgid "-V option not supported - no Sync library support available\n" msgstr "" "option -V option non supportée - pas de support de la synchronisation de " "bibliothèque disponible\n" #: tools/btardump.cc:175 msgid "Reading file: " msgstr "Lecture du fichier : " #: tools/btool.cc:74 msgid " -f file Filename to save or load handheld data to/from" msgstr "" " -f fich Nom de fichier à enregistrer ou à charger sur / depuis le " "péripérique" #: tools/btool.cc:87 #, c-format msgid "" "btool - Command line USB Blackberry Test Tool\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" " %s\n" "\n" " -b file Filename to save or load a Barry Backup to (tar.gz)\n" " -B bus Specify which USB bus to search on\n" " -N dev Specify which system device, using system specific string\n" "\n" " -a db Erase / clear database 'db' FROM device, deleting all\n" " its records. Can be used multiple times to clear more\n" " than one DB.\n" " -c dn Convert address book database to LDIF format, using the\n" " specified baseDN\n" " -C dnattr LDIF attribute name to use when building the FQDN\n" " Defaults to 'cn'\n" " -d db Load database 'db' FROM device and dump to screen\n" " Can be used multiple times to fetch more than one DB\n" " -e epp Override endpoint pair detection. 'epp' is a single\n" " string separated by a comma, holding the read,write\n" " endpoint pair. Example: -e 83,5\n" " Note: Endpoints are specified in hex.\n" " You should never need to use this option.\n" "%s\n" " -F sort Field name by which to sort the output. Note that the\n" " format of this field is special: 'DBName:field1,field2'\n" " with no spaces unless the spaces are part of the name.\n" " Can be used multiple times, to match your -d options.\n" " Example: -F 'Address Book:Company,LastName,FirstName'\n" " -h This help\n" " -i cs International charset for string conversions\n" " Valid values here are available with 'iconv --list'\n" " -I Sort records before output\n" " -l List devices\n" " -L List Contact field names\n" " -m Map LDIF name to Contact field / Unmap LDIF name\n" " Map: ldif,read,write - maps ldif to read/write Contact " "fields\n" " Unmap: ldif name alone\n" " -M List current LDIF mapping\n" " -n Use null parser on all databases.\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -s db Save database 'db' TO device from data loaded from -f file\n" " -S Show list of supported database parsers. Use twice to\n" " display fields names as well.\n" " -t Show database database table\n" " -T db Show record state table for given database\n" " -v Dump protocol data during operation\n" "%s\n" " -X Reset device\n" " -z Use non-threaded sockets\n" " -Z Use threaded socket router (default)\n" "\n" " -d Command modifiers: (can be used multiple times for more than 1 " "record)\n" "\n" " -r # Record index number as seen in the -T state table.\n" " This overrides the default -d behaviour, and only\n" " downloads the one specified record, sending to stdout.\n" " -R # Same as -r, but also clears the record's dirty flags.\n" " -D # Record index number as seen in the -T state table,\n" " which indicates the record to delete. Used with the -d\n" " command to specify the database.\n" msgstr "" "btool - Outil de test USB Blackberry en ligne de commandes\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Utilise : %s\n" " %s\n" "\n" " -b fich Nom de fichier de sauvegarde Barry à lire ou écrire (tar.gz)\n" " -B bus Indique le bus USB sur lequel chercher.\n" " -N périph Indique le périphérique système, chaîne dépendant du système\n" "\n" " -a bdd Efface / vide la base de données 'bdd' du périphérique, avec\n" " tous ses enregistrements. Peut être utilisé plusieurs fois\n" " pour effacer plusieurs BDD.\n" " -c dn Convertit le carnet d'adresses au format LDIF, avec le\n" " baseDN spécifié.\n" " -C dnattr Nom d'attribut LDIF à utiliser lors de la construction du\n" " FQDN. 'cn' par défaut.\n" " -d bdd Charge et affiche la base 'bdd' du périphérique. Peut-être\n" " utilisé plusieurs fois pour récupérer plus d'une base.\n" " -e pep Passer outre la détection de paire de endpoints. 'pep' est\n" " simple chaîne, contenant le paire de endpoints d'écriture\n" " / lecture, séparée pas une virgule. Exemple : -e 83,5\n" " Note : les endpoints sont spécifié en base 16.\n" " Vous ne devriez jamais utiliser cette option.\n" "%s\n" " -F nom Nom du champs par lequel la sortie doit être triée. Noter\n" " que le format de ce champs est spécial :\n" " 'DBName:field1,field2' sans espaces à moins qu'ils ne\n" " fassent partie du nom. Peut être utilisé plusieurs fois,\n" " pour correspondre aux occurrences de -d.\n" " Exemple: -F 'Address Book:Company,LastName,FirstName'\n" " -h Cette aide.\n" " -I enc Encodage pour la conversion de chaînes\n" " Les valeurs admissibles sont données par 'iconv --list'\n" " -I Trier les enregistrements avant affichage.\n" " -l Lister les périphériques.\n" " -L Lister les noms de champs de Contact.\n" " -m (ne pas) Associer les noms LDIF avec les champs de Contact\n" " Associer : ldif,read,write :\n" " associer ldif avec les champs Contact lus/écris\n" " Ne pas associer : seulement les noms ldif\n" " -M Lister la correspondance LDIF courante.\n" " -n Utiliser un analyseur null, sur toutes les bases de données.\n" " -p pin PIN du périphérique auquel parler\n" " Optionnel s'il n'y a qu'un périphérique\n" " -P pass Méthode simple pour entrer le mot de passe\n" " -s bdd Enregistrer la base 'bdd' VERS le périphérique, depuis les\n" " données chargées avec -f fich\n" " -S Afficher la liste des interpréteurs de bases de données.\n" " Utiliser deux fois pour afficher aussi les noms de champs.\n" " -t Afficher la base de données des tables de base de données.\n" " -T bdd Montrer la table d'état d'enregistrement pour la base données\n" " -v Afficher les données du protocole pendant l'opération.\n" "%s\n" " -X Réinitialiser le périphérique.\n" " -z Utiliser des sockets non threadées.\n" " -Z Utiliser un routeur de sockets threadé (par défaut).\n" "\n" " -d Modificateurs de commande : (peut être utilisé plusieurs fois\n" " pour plus d'un enregistrement)\n" "\n" " -r # Indice d'enregistrement tel que vu dans la table d'état -T.\n" " Ceci outrepasse le comportement par défaut de -d et télécharge\n" " les enregistrements spécifiés, envoyés sur la sortie standard.\n" " -R # Identique à -r, mais efface également le drapeau dirty des\n" " enregistrements\n" " -D # Indice d'enregistrement tel que vu dans la table d'état -T, " "qui\n" " indique quel enregistrement supprimer. À utiliser avec la\n" " commande -d pour spécifier la base de données.\n" #: tools/btool.cc:196 msgid "Loading: " msgstr "Chargement de :" #: tools/btool.cc:202 msgid " records loaded from '" msgstr " enregistrements chargés depuis '" #: tools/btool.cc:230 #, c-format msgid "" "Store counted %d records read from device, and %d records written to device." msgstr "" "Le store comprend %d enregistrements lus depuis le périphérique et %d " "enregistrements écris sur le périphérique." #: tools/btool.cc:234 msgid "Saving: " msgstr "Enregistrement de : " #: tools/btool.cc:239 msgid " records saved to '" msgstr " enregistrements sauvés sur '" #: tools/btool.cc:437 msgid "No Builder available for database" msgstr "Pas de constructeur disponible pour la base de données" #: tools/btool.cc:477 msgid "Unmapping: " msgstr "Ajout dans la table : " #: tools/btool.cc:481 msgid "Mapping: " msgstr "Suppression de la table : " #: tools/btool.cc:487 msgid "Read/Write name unknown: " msgstr "Nom de lecture / écriture inconnu : " #: tools/btool.cc:491 msgid "Invalid map format: " msgstr "Format de table inconnu : " #: tools/btool.cc:582 msgid "-b option not supported - no Barry Backup library support available\n" msgstr "" "Option -b non supportée - pas de support de la bibliothèque Barry Backup " "disponible\n" #: tools/btool.cc:627 msgid "-f option not supported - no Boost serialization support available\n" msgstr "" "option -f non supportée - pas de support de la sérialisation Boost " "disponible\n" #: tools/btool.cc:764 msgid "Unable to set DN Attr: " msgstr "Impossible de définir l'attribut DN :" #: tools/btool.cc:779 msgid "Blackberry device errors with errors during probe:" msgstr "Erreur du périphérique Blackberry durant la détection : " #: tools/btool.cc:790 msgid "Blackberry devices found:" msgstr "Appareils Blackberry trouvés :" #: tools/btool.cc:812 tools/pppob.cc:273 msgid "No device selected" msgstr "Pas de périphérique sélectionné" #: tools/btool.cc:825 msgid "Using device (PIN): " msgstr "Utilisation du périphérique (PIN) :" #: tools/btool.cc:841 msgid "Endpoint pair (read,write) overridden with: " msgstr "Paire de endpoints (read, write) remplacée par : " #: tools/btool.cc:922 msgid "No db names to process" msgstr "Pas de noms de bdd à analyser" #: tools/btool.cc:931 msgid "Record state table for: " msgstr "Table d'état d'enregistrements pour : " #: tools/btool.cc:940 msgid "Must have 1 db name to process" msgstr "Il faut au moins 1 nom de bdd à traiter" #: tools/btool.cc:952 msgid "Clearing record's dirty flags..." msgstr "Nettoyage des drapeaux dirty de l'enregistrement..." #: tools/btool.cc:982 msgid "No db names to erase" msgstr "Pas de nom de bdd à effacer" #: tools/btool.cc:990 msgid "Deleting all records from " msgstr "Suppression de tous les enregistrements de " #: tools/bwatch.cc:47 #, c-format msgid "" "bwatch - View video of BlackBerry screenshots\n" " Copyright 2011, Alberto Mattea\n" " Copyright 2011-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -d delay Delay interval between screenshots, in milliseconds.\n" " The lower the value, the higher the load on the device.\n" " Default is 500ms.\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" msgstr "" "bwatch - Voire des vidéos de captures d'écran de BlackBerry\n" " Copyright 2011, Alberto Mattea\n" " Copyright 2011-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Utilise : %s\n" "\n" " -d delay Durée de l'intervalle entre les captures, en millisecondes.\n" " Plus cette valeur est basse, plus la charge est importante\n" " pour le périphérique. La valeur par défaut est 500ms.\n" " -p pin PIN du périphérique auquel parler\n" " Si un seul périphérique est branché, ce paramètre est\n" " optionnel.\n" " -P pass Méthode simple pour entrer le mot de passe.\n" " -v Afficher les données de protocole pendant l'opération.\n" #: tools/bwatch.cc:87 msgid "Invalid interval value of: " msgstr "Valeur d'intervalle non valide : " #: tools/bwatch.cc:87 msgid "Defaulting to 500ms." msgstr "Utilisation de 500ms par défaut." #: tools/bwatch.cc:137 msgid "Press a key to exit..." msgstr "Appuyer une touche pour quitter..." #: tools/pppob.cc:58 #, c-format msgid "" "pppob - PPP over Barry\n" " Copyright 2007-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -l file Direct pppob log output to file (useful with -v)\n" " -p pin PIN of device to talk with\n" " If only one device plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -s Use Serial mode instead of IpModem\n" " -t Use a pseudo-tty instead of stdin/stdout\n" " -v Dump protocol data during operation (debugging only!)\n" msgstr "" "pppob - Liaison PPP au travers de Barry\n" " Copyright 2007-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Utilise : %s\n" "\n" " -l fich Rediriger les messages de pppob dans un fichier\n" " (utile avec -v)\n" " -p pin PIN du périphérique auquel parler\n" " Si un seul périphérique est branché, ce paramètre est\n" " optionnel\n" " -P pass Méthode simple pour entrer le mot de passe\n" " -s Utiliser le mode série au lieu du mode IpModem\n" " -t Utiliser un pseudo-terminal plutôt les fichiers\n" " standards\n" " -v Afficher les données de protocole pendant l'opération\n" " (pour le débogage seulement !).\n" #: tools/pppob.cc:90 msgid "Error in write()" msgstr "Erreur dans write()" #: tools/pppob.cc:135 msgid "Read error in ProcessStdin: " msgstr "Erreur de lecture dans ProcessStdin : " #: tools/pppob.cc:212 msgid "Cannot open /dev/ptmx: " msgstr "Impossible d'ouvrir /dev/ptmx : " #: tools/pppob.cc:218 msgid "Warning: grantpt() failure: " msgstr "Attention : échec de grantpt() : " #: tools/pppob.cc:222 msgid "Warning: unlockpt() failure: " msgstr "Attention : échec de unlockpt() : " #: tools/pppob.cc:280 msgid "Using IpModem mode..." msgstr "Utilisation du mode IpModem..." #: tools/pppob.cc:295 msgid "Using Serial mode per command line..." msgstr "Utilisation du mode série comme demandé dans la ligne de commande..." #: tools/pppob.cc:298 msgid "No IpModem mode available, using Serial mode..." msgstr "Mode IpModem non disponible, utilisation du mode série..." #: tools/pppob.cc:321 msgid "Exiting" msgstr "Sortie" #: tools/pppob.cc:325 msgid "exception caught in main(): " msgstr "exception attrapée dans main() :" #: tools/upldif.cc:39 msgid "" "upldif - Command line LDIF uploader\n" " Copyright 2006-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" "\n" " -p pin PIN of device to talk with\n" " If only one device plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -u Do the upload. If not specified, only dumps parsed\n" " LDIF data to stdout.\n" " -v Dump protocol data during operation\n" " -h This help output\n" msgstr "" "upldif - Envoi de fichier LDIF en ligne de commande\n" " Copyright 2006-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" "\n" " -p pin PIN du périphérique auquel parler\n" " Si un seul périphérique est branché, ce paramètre est " "optionnel\n" " -P pass Méthode simple pour entrer le mot de passe\n" " -u Faire l'envoi. Si non précisé, les données LDIF lues seront\n" " seulement affichées sur la sortie standard.\n" " -v Afficher les données de protocole pendant l'opération.\n" " -h Cette aide\n" #: tools/upldif.cc:79 #, c-format msgid "Store counted %d records." msgstr "Le Store comprend %d enregistrements." #: tools/upldif.cc:173 msgid "Device not found, or not specified" msgstr "Périphérique non trouvé, ou non spécifié" #: tools/util.cc:37 msgid "Supported Database parsers:\n" msgstr "Analyseurs de base de données supporté :\n" #: tools/util.cc:41 msgid " (* = can display in vformat MIME mode)\n" msgstr " (* = affichage possible en mode MIME vformat MIME)\n" #: tools/util.cc:82 msgid "Supported Database builders:\n" msgstr "Constructeurs de base de données supportés :\n" barry-0.18.5/po/remove-potcdate.sin0000644001161500056700000000066012242254476016505 0ustar cdfreycdfrey# Sed script that remove the POT-Creation-Date line in the header entry # from a POT file. # # The distinction between the first and the following occurrences of the # pattern is achieved by looking at the hold space. /^"POT-Creation-Date: .*"$/{ x # Test if the hold space is empty. s/P/P/ ta # Yes it was empty. First occurrence. Remove the line. g d bb :a # The hold space was nonempty. Following occurrences. Do nothing. x :b } barry-0.18.5/po/barry.pot0000644001161500056700000026731212242254476014550 0ustar cdfreycdfrey# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Net Direct, Inc. # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: barry 0.18.5\n" "Report-Msgid-Bugs-To: http://netdirect.ca/barry\n" "POT-Creation-Date: 2013-04-02 18:53-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: src/a_application.cc:59 msgid " Application " msgstr "" #: src/a_application.cc:60 src/a_library.cc:60 msgid " ID : " msgstr "" #: src/a_application.cc:61 src/a_library.cc:61 msgid " Description : " msgstr "" #: src/a_application.cc:62 src/a_library.cc:62 msgid " Vendor : " msgstr "" #: src/a_application.cc:63 src/a_library.cc:63 msgid " Copyright : " msgstr "" #: src/a_application.cc:64 src/a_library.cc:64 msgid " Required : " msgstr "" #: src/a_application.cc:64 src/a_library.cc:64 msgid "Yes" msgstr "" #: src/a_application.cc:64 src/a_library.cc:64 msgid "No" msgstr "" #: src/a_application.cc:68 src/a_library.cc:68 msgid " Files : " msgstr "" #: src/a_library.cc:59 msgid " Library " msgstr "" #: src/a_osloader.cc:74 msgid "Could not opendir: " msgstr "" #: src/a_osloader.cc:97 msgid "Cannot open ALX file: " msgstr "" #: src/a_osloader.cc:111 msgid "OS Properties :" msgstr "" #: src/a_osloader.cc:123 msgid "SFI File :" msgstr "" #: src/a_osloader.cc:127 msgid "Applications :" msgstr "" #: src/a_osloader.cc:137 msgid "Libraries :" msgstr "" #: src/backup.cc:84 msgid "Backup: No database name available" msgstr "" #: src/backup.cc:86 msgid "Backup: No unique ID available!" msgstr "" #: src/bmp.cc:80 msgid "ScreenshotToRGB: depth must be 24 or 32" msgstr "" #: src/bmp.cc:100 msgid "" "ScreenshotToRGB: Screenshot data size is too small for given width+height" msgstr "" #: src/bmp.cc:102 msgid "" "ScreenshotToRGB: Screenshot depth is not supported (Barry supports 2 byte or " "4 byte pixels in device screenshots)" msgstr "" #: src/bmp.cc:162 msgid "" "ScreenshotToRGB: bad switch value, should never happen. Double check the " "data_size check." msgstr "" #: src/bmp.cc:196 msgid "Screenshot data size is too small for given width+height" msgstr "" #: src/builder.cc:54 msgid "DBDataBuilder: offset greater than size" msgstr "" #: src/cod.cc:61 msgid "SeekNextCod: EOF while reading file signature" msgstr "" #: src/cod.cc:70 msgid "SeekNextCod: EOF while reading PKZIP header" msgstr "" #: src/cod.cc:76 msgid "SeekNextCod: EOF while skipping unused fields" msgstr "" #: src/cod.cc:89 msgid "SeekNextCod: seek to end failed" msgstr "" #: src/cod.cc:95 msgid "SeekNextCod: seek to start failed" msgstr "" #: src/cod.cc:101 msgid "SeekNextCod: unknown COD file signature" msgstr "" #: src/common.cc:79 msgid "USB library failed to initialise with libusb error: " msgstr "" #: src/common.cc:80 msgid "Failed to initialise USB" msgstr "" #: src/configfile.cc:50 msgid "DBListType dump:\n" msgstr "" #: src/configfile.cc:77 src/configfile.cc:95 msgid "Configfile: empty pin" msgstr "" #: src/configfile.cc:193 src/configfile.cc:394 msgid "Unable to open file for writing: " msgstr "" #: src/configfile.cc:219 src/configfile.cc:411 msgid "Error during write. Config may be incomplete." msgstr "" #: src/configfile.cc:329 msgid "App name must have no spaces." msgstr "" #: src/configfile.cc:420 src/configfile.cc:433 msgid "Cannot use SetKey() without specifying an appname in the constructor." msgstr "" #: src/configfile.cc:423 msgid "SetKey values may not contain newline characters." msgstr "" #: src/configfileunix.cc:91 src/configfileunix.cc:151 msgid "BuildFilename: getpwuid failed" msgstr "" #: src/configfileunix.cc:116 src/configfilewin32.cc:118 msgid "ConfigFile::CheckPath(): path is empty!" msgstr "" #: src/configfileunix.cc:130 msgid "mkdir() failed to create: " msgstr "" #: src/configfileunix.cc:139 msgid "last mkdir() failed to create: " msgstr "" #: src/configfilewin32.cc:84 src/configfilewin32.cc:163 msgid "BuildFilename: SHGetSpecialFolderPath failed" msgstr "" #: src/configfilewin32.cc:87 src/configfilewin32.cc:104 #: src/configfilewin32.cc:166 msgid "BuildFilename: conversion failed" msgstr "" #: src/configfilewin32.cc:101 msgid "BuildDefaultPath: SHGetSpecialFolderPath failed" msgstr "" #: src/configfilewin32.cc:125 msgid "Failed to convert to widechar" msgstr "" #: src/configfilewin32.cc:148 msgid "failed to create directory" msgstr "" #: src/connector.cc:185 msgid "Timeout in Connector::Reconnect()... trying again" msgstr "" #: src/controller.cc:52 msgid "Controller: Using non-threaded sockets" msgstr "" #: src/controller.cc:73 msgid "Controller: Using threaded socket router" msgstr "" #: src/controller.cc:86 msgid "Controller: GetConfiguration failed" msgstr "" #: src/controller.cc:91 msgid "Controller: SetConfiguration failed" msgstr "" #: src/controller.cc:146 msgid "Controller: explicit mode name too long" msgstr "" #: src/controller.cc:179 msgid "Controller: No channel name given with RawChannel mode" msgstr "" #: src/controller.cc:183 msgid "Controller: Invalid mode in SelectMode" msgstr "" #: src/controller.cc:200 msgid "Controller: requested mode not supported" msgstr "" #: src/controller.cc:204 msgid "Controller: mode not selected" msgstr "" #: src/controller.cc:211 msgid "Controller: error setting desktop mode" msgstr "" #: src/data.cc:293 msgid "Data::ReleaseBuffer() argument must be -1 or >= 0" msgstr "" #: src/data.cc:295 msgid "Data::ReleaseBuffer() must be called after GetBuffer()" msgstr "" #: src/data.cc:297 msgid "" "Data::ReleaseBuffer() must be called with a size smaller than the original " "buffer requested" msgstr "" #: src/data.cc:489 msgid "sizes differ: " msgstr "" #: src/dp_codinfo.cc:171 src/m_jvmdebug.cc:89 msgid " UniqueID " msgstr "" #: src/dp_codinfo.cc:172 msgid " Module Name " msgstr "" #: src/dp_codinfo.cc:173 msgid " File Name " msgstr "" #: src/error.cc:58 msgid "Bad packet size, not enough data: " msgstr "" #: src/error.cc:59 src/error.cc:68 msgid "DataSize(): " msgstr "" #: src/error.cc:60 src/error.cc:69 msgid "Required size: " msgstr "" #: src/error.cc:67 msgid "Bad packet size. Packet: " msgstr "" #: src/fifoargs.cc:105 msgid "Cannot open Barry argument fifo" msgstr "" #: src/j_jdwp.cc:94 msgid "Timeout in read" msgstr "" #: src/j_jdwp.cc:96 msgid "Error in read" msgstr "" #: src/j_jdwp.cc:117 msgid "Timeout in write (1)" msgstr "" #: src/j_jdwp.cc:119 msgid "Error in write (1)" msgstr "" #: src/j_jdwp.cc:137 msgid "Timeout in write (2)" msgstr "" #: src/j_jdwp.cc:139 msgid "Error in write (2)" msgstr "" #: src/j_server.cc:91 msgid "HOST_NOT_FOUND: The specified host is unknown" msgstr "" #: src/j_server.cc:94 msgid "NO_ADDRESS: The requested name is valid but does not have an IP address" msgstr "" #: src/j_server.cc:97 msgid "NO_RECOVERY: A non-recoverable name server error occurred" msgstr "" #: src/j_server.cc:100 msgid "" "TRY_AGAIN: A temporary error occurred on an authoritative name server. Try " "again later." msgstr "" #: src/j_server.cc:103 msgid "Unknown network error code" msgstr "" #: src/j_server.cc:142 msgid "JDWServer::Start: Cannot open socket." msgstr "" #: src/j_server.cc:154 msgid "JDWServer::Start: Cannot bind socket" msgstr "" #: src/j_server.cc:164 msgid "JDWServer::Start: Cannot listen on socket" msgstr "" #: src/j_server.cc:237 msgid "No debug information found for: " msgstr "" #: src/j_server.cc:321 src/j_server.cc:350 msgid "Packet size error !!!" msgstr "" #: src/j_server.cc:491 msgid "Commandset unknown !!!" msgstr "" #: src/ldif.cc:39 msgid "Email address" msgstr "" #: src/ldif.cc:41 src/r_calllog.cc:84 msgid "Phone number" msgstr "" #: src/ldif.cc:43 msgid "Fax number" msgstr "" #: src/ldif.cc:45 msgid "Work phone number" msgstr "" #: src/ldif.cc:47 msgid "Home phone number" msgstr "" #: src/ldif.cc:49 msgid "Mobile phone number" msgstr "" #: src/ldif.cc:51 msgid "Pager number" msgstr "" #: src/ldif.cc:53 src/r_contact.cc:118 src/r_contact.cc:503 #: src/r_hhagent.cc:69 src/r_hhagent.cc:105 src/r_hhagent.cc:290 msgid "PIN" msgstr "" #: src/ldif.cc:55 msgid "First name" msgstr "" #: src/ldif.cc:57 msgid "Last name" msgstr "" #: src/ldif.cc:59 msgid "Company name" msgstr "" #: src/ldif.cc:61 msgid "Default communications method" msgstr "" #: src/ldif.cc:63 msgid "Work Address, line 1" msgstr "" #: src/ldif.cc:65 msgid "Work Address, line 2" msgstr "" #: src/ldif.cc:67 msgid "Work Address, line 3" msgstr "" #: src/ldif.cc:69 src/r_contact.cc:128 msgid "WorkCity" msgstr "" #: src/ldif.cc:71 msgid "WorkProvince / State" msgstr "" #: src/ldif.cc:73 msgid "Work Postal / ZIP code" msgstr "" #: src/ldif.cc:75 src/r_contact.cc:131 msgid "WorkCountry" msgstr "" #: src/ldif.cc:77 src/r_contact.cc:487 msgid "Job Title" msgstr "" #: src/ldif.cc:79 msgid "Public key" msgstr "" #: src/ldif.cc:81 src/r_calendar.cc:107 src/r_calendar.cc:434 #: src/r_contact.cc:139 src/r_contact.cc:509 src/r_task.cc:108 #: src/r_task.cc:399 msgid "Notes" msgstr "" #: src/ldif.cc:83 msgid "Contact photo" msgstr "" #: src/ldif.cc:85 msgid "" "Mailing Work address (includes address lines, city, province, country, and " "postal code)" msgstr "" #: src/ldif.cc:87 msgid "" "Mailing home address (includes address lines, city, province, country, and " "postal code)" msgstr "" #: src/ldif.cc:89 msgid "First + Last names" msgstr "" #: src/ldif.cc:91 msgid "Fully qualified domain name" msgstr "" #: src/ldif.cc:213 src/ldif.cc:222 msgid "" msgstr "" #: src/ldif.cc:437 src/r_calllog.cc:338 src/r_message_base.cc:391 msgid "unknown" msgstr "" #: src/ldif.cc:782 msgid "ContactLdif Mapping:\n" msgstr "" #: src/ldif.cc:801 msgid " >>> DN attribute: " msgstr "" #: src/m_desktop.cc:89 msgid "Desktop: error getting command table" msgstr "" #: src/m_desktop.cc:139 msgid "Desktop: database name not found: " msgstr "" #: src/m_desktop.cc:162 msgid "Desktop: unknown command type" msgstr "" #: src/m_desktop.cc:167 msgid "Desktop: unable to get command code: " msgstr "" #: src/m_desktop.cc:188 src/m_desktop.cc:214 src/m_desktop.cc:251 #: src/m_desktop.cc:301 src/m_desktop.cc:336 src/m_desktop.cc:355 #: src/m_desktop.cc:406 src/m_desktop.cc:431 src/m_desktop.cc:440 #: src/m_desktop.cc:490 msgid "Database ID: " msgstr "" #: src/m_desktop.cc:226 src/m_desktop.cc:316 src/m_desktop.cc:448 msgid "Desktop: device responded with unexpected packet command code: " msgstr "" #: src/m_desktop.cc:232 src/m_desktop.cc:322 src/m_desktop.cc:454 msgid "Desktop: device responded with error code (command: " msgstr "" #: src/m_desktop.cc:233 src/m_desktop.cc:323 src/m_desktop.cc:417 #: src/m_desktop.cc:455 msgid "code: " msgstr "" #: src/m_desktop.cc:266 msgid "Desktop: invalid response packet size of: " msgstr "" #: src/m_desktop.cc:275 msgid "Desktop: unexpected command of " msgstr "" #: src/m_desktop.cc:277 msgid " instead of expected " msgstr "" #: src/m_desktop.cc:301 msgid "Index: " msgstr "" #: src/m_desktop.cc:307 msgid "Desktop: no data available in SetRecord" msgstr "" #: src/m_desktop.cc:415 msgid "Desktop: could not clear database: (command: " msgstr "" #: src/m_desktop.cc:425 msgid "Desktop: error clearing database, bad response" msgstr "" #: src/m_desktop.cc:670 msgid "This database does not exist in device: " msgstr "" #: src/m_desktop.cc:670 msgid "Dropping record." msgstr "" #: src/m_desktop.cc:700 src/m_desktop.cc:757 msgid "DeviceParser: unknown mode" msgstr "" #: src/m_ipmodem.cc:60 msgid "Exception caught in IpModem destructor, ignoring: " msgstr "" #: src/m_ipmodem.cc:68 msgid "Logic error: No password provided in SendPassword." msgstr "" #: src/m_ipmodem.cc:80 msgid "No password provided." msgstr "" #: src/m_ipmodem.cc:149 src/socket.cc:481 msgid "Password rejected by device." msgstr "" #: src/m_ipmodem.cc:198 msgid "Exception in IpModem::DataReadThread: " msgstr "" #: src/m_ipmodem.cc:220 msgid "IP Modem not supported by this device: " msgstr "" #: src/m_ipmodem.cc:260 src/socket.cc:467 #, c-format msgid "" "Fewer than %d password tries remaining in device. Refusing to proceed, to " "avoid device zapping itself. Use a Windows client, or re-cradle the device." msgstr "" #: src/m_ipmodem.cc:267 src/m_ipmodem.cc:299 src/m_ipmodem.cc:338 msgid "IpModem: Error sending password." msgstr "" #: src/m_ipmodem.cc:332 msgid "This device requested a password." msgstr "" #: src/m_ipmodem.cc:346 msgid "This device requires a password." msgstr "" #: src/m_ipmodem.cc:366 msgid "IpModem: Error creating USB read thread." msgstr "" #: src/m_javaloader.cc:242 msgid "JLEventlogEntry:Parse bad guid field" msgstr "" #: src/m_javaloader.cc:247 msgid "JLEventlogEntry:Parse bad time field" msgstr "" #: src/m_javaloader.cc:254 msgid "JLEventlogEntry:Parse bad severity field" msgstr "" #: src/m_javaloader.cc:261 msgid "JLEventlogEntry:Parse bad type field" msgstr "" #: src/m_javaloader.cc:266 msgid "JLEventlogEntry:Parse bad app field" msgstr "" #: src/m_javaloader.cc:274 msgid "JLEventlogEntry:Parse bad data field" msgstr "" #: src/m_javaloader.cc:301 msgid "Always Log" msgstr "" #: src/m_javaloader.cc:302 msgid "Severe Error" msgstr "" #: src/m_javaloader.cc:303 src/r_calllog.cc:266 msgid "Error" msgstr "" #: src/m_javaloader.cc:304 msgid "Warning" msgstr "" #: src/m_javaloader.cc:305 msgid "Information" msgstr "" #: src/m_javaloader.cc:306 msgid "Debug Info" msgstr "" #: src/m_javaloader.cc:310 msgid "Number" msgstr "" #: src/m_javaloader.cc:311 msgid "String" msgstr "" #: src/m_javaloader.cc:312 msgid "Exception" msgstr "" #: src/m_javaloader.cc:315 msgid "guid:" msgstr "" #: src/m_javaloader.cc:316 msgid " time:" msgstr "" #: src/m_javaloader.cc:317 msgid " severity:" msgstr "" #: src/m_javaloader.cc:318 msgid " type:" msgstr "" #: src/m_javaloader.cc:319 msgid " app:" msgstr "" #: src/m_javaloader.cc:320 msgid " data:" msgstr "" #: src/m_javaloader.cc:331 msgid "Hardware Id:" msgstr "" #: src/m_javaloader.cc:334 msgid "PIN:" msgstr "" #: src/m_javaloader.cc:337 msgid "OS Version:" msgstr "" #: src/m_javaloader.cc:340 msgid "VM Version:" msgstr "" #: src/m_javaloader.cc:343 msgid "Radio ID:" msgstr "" #: src/m_javaloader.cc:346 msgid "Vendor ID:" msgstr "" #: src/m_javaloader.cc:350 msgid "Active Wireless Access Families:" msgstr "" #: src/m_javaloader.cc:353 msgid "OS Metrics:" msgstr "" #: src/m_javaloader.cc:356 msgid "Bootrom Metrics:" msgstr "" #: src/m_javaloader.cc:409 msgid "JavaLoader::StartStream Hello" msgstr "" #: src/m_javaloader.cc:416 msgid "JavaLoader::StartStream Unknown1" msgstr "" #: src/m_javaloader.cc:467 msgid "JavaLoader::SendStream: set code size first" msgstr "" #: src/m_javaloader.cc:475 msgid "JavaLoader::SendStream: input stream read failed" msgstr "" #: src/m_javaloader.cc:482 msgid "JavaLoader::SendStream: not enough memory to install the application" msgstr "" #: src/m_javaloader.cc:486 msgid "JavaLoader::SendStream: send data" msgstr "" #: src/m_javaloader.cc:538 msgid "JavaLoader::StopStream error" msgstr "" #: src/m_javaloader.cc:552 msgid "JavaLoader::SetTime error" msgstr "" #: src/m_javaloader.cc:559 src/m_jvmdebug.cc:260 msgid "unexpected packet command code: " msgstr "" #: src/m_javaloader.cc:723 msgid "JavaLoader::GetScreenShot expect" msgstr "" #: src/m_javaloader.cc:746 msgid "JavaLoader::DoErase: module not found: " msgstr "" #: src/m_javaloader.cc:754 msgid "JavaLoader::DoErase: expected code ID not available" msgstr "" #: src/m_javaloader.cc:766 msgid "JavaLoader::DoErase: COD file in use." msgstr "" #: src/m_javaloader.cc:898 msgid "JavaLoader::Save: module not found: " msgstr "" #: src/m_javaloader.cc:907 msgid "JavaLoader::Save: expected module ID, but not available" msgstr "" #: src/m_jvmdebug.cc:88 msgid " ID " msgstr "" #: src/m_jvmdebug.cc:90 msgid " Module Name" msgstr "" #: src/m_jvmdebug.cc:152 msgid " Thread " msgstr "" #: src/m_jvmdebug.cc:153 msgid " Address " msgstr "" #: src/m_jvmdebug.cc:154 msgid " Byte " msgstr "" #: src/m_jvmdebug.cc:155 msgid " Unknown01 " msgstr "" #: src/m_jvmdebug.cc:156 msgid " Unknown02 " msgstr "" #: src/m_jvmdebug.cc:157 msgid " Unknown03 " msgstr "" #: src/m_jvmdebug.cc:158 msgid " Unknown04 " msgstr "" #: src/m_jvmdebug.cc:159 msgid " Unknown05 " msgstr "" #: src/m_jvmdebug.cc:160 msgid " Unknown06 " msgstr "" #: src/m_jvmdebug.cc:291 src/m_jvmdebug.cc:321 src/m_jvmdebug.cc:351 #: src/m_jvmdebug.cc:381 src/m_jvmdebug.cc:411 src/m_jvmdebug.cc:441 #: src/m_jvmdebug.cc:471 src/m_jvmdebug.cc:501 src/m_jvmdebug.cc:531 #: src/m_jvmdebug.cc:561 src/m_jvmdebug.cc:595 src/m_jvmdebug.cc:641 #: src/m_jvmdebug.cc:686 src/m_jvmdebug.cc:741 src/m_jvmdebug.cc:802 #: src/m_jvmdebug.cc:843 src/m_jvmdebug.cc:873 src/m_jvmdebug.cc:904 #: src/m_jvmdebug.cc:931 src/m_jvmdebug.cc:959 src/m_jvmdebug.cc:1001 #: src/m_jvmdebug.cc:1034 msgid "byte count mismatch" msgstr "" #: src/m_mode_base.cc:142 msgid "Socket alreay open in RetryPassword" msgstr "" #: src/m_raw_channel.cc:116 msgid "RawChannel: No routing queue set in controller" msgstr "" #: src/m_raw_channel.cc:165 msgid "RawChannel: Got packet not for socket-zero" msgstr "" #: src/m_raw_channel.cc:183 src/m_raw_channel.cc:186 msgid "RawChannel: Got unexpected socket zero packet" msgstr "" #: src/m_raw_channel.cc:205 msgid "RawChannel: Received data to handle when in non-callback mode" msgstr "" #: src/m_raw_channel.cc:212 msgid "RawChannel: Socket error received, what: " msgstr "" #: src/m_raw_channel.cc:245 msgid "RawChannel: send data size larger than MaximumPacketSize" msgstr "" #: src/m_raw_channel.cc:268 msgid "RawChannel: Receive called when channel was created with a callback" msgstr "" #: src/m_raw_channel.cc:293 msgid "RawChannel: Data size doesn't match packet size" msgstr "" #: src/m_serial.cc:45 msgid "" "A SocketRoutingQueue is required in the Controller class when using Mode::" "Serial." msgstr "" #: src/m_serial.cc:156 msgid "Must call Open() before Write() in Mode::Serial" msgstr "" #: src/packet.cc:465 msgid "Attempting to extract a return code from the wrong response packet type" msgstr "" #: src/parser.cc:62 msgid "Records for database: " msgstr "" #: src/parser.cc:66 tools/bfuse.cc:128 msgid "Raw record dump for record: " msgstr "" #: src/parser.cc:68 msgid "type: " msgstr "" #: src/parser.cc:70 msgid "offset: " msgstr "" #: src/probe.cc:95 msgid "Probe: Parse data failure: " msgstr "" #: src/probe.cc:172 #, c-format msgid "Probe logged %u exception messages:" msgstr "" #: src/probe.cc:195 msgid "Usb::Error exception caught: " msgstr "" #: src/probe.cc:224 msgid "Probe: No device descriptor for BlackBerry config (config id: " msgstr "" #: src/probe.cc:236 #, c-format msgid "Probe: Interface with BLACKBERRY_DB_CLASS (%u) not found." msgstr "" #: src/probe.cc:248 msgid "Probe: endpoint invalid." msgstr "" #: src/probe.cc:250 msgid "true" msgstr "" #: src/probe.cc:250 msgid "false" msgstr "" #: src/probe.cc:271 msgid "Probe: GetConfiguration failed" msgstr "" #: src/probe.cc:275 msgid "Probe: SetConfiguration failed" msgstr "" #: src/probe.cc:293 msgid "" "Probe: probing endpoints failed, retrying after setting alternate interface" msgstr "" #: src/probe.cc:318 msgid "Unable to discover endpoint pair for one device." msgstr "" #: src/probe.cc:366 msgid "Probe: Skipping non-bulk endpoint pair (offset: " msgstr "" #: src/probe.cc:418 msgid "Probe: Intro(0) failed, retrying after clearing halt" msgstr "" #: src/probe.cc:426 msgid "Probe: Intro(0) still failed after clearing halt" msgstr "" #: src/probe.cc:448 msgid "Probe: unable to fetch PIN" msgstr "" #: src/probe.cc:460 msgid "Probe: unable to fetch description" msgstr "" #: src/probe.cc:567 msgid "Device ID: " msgstr "" #: src/probe.cc:568 msgid "PIN: " msgstr "" #: src/probe.cc:569 msgid "Description: " msgstr "" #: src/probe.cc:571 msgid "Name: " msgstr "" #: src/r_bookmark.cc:275 msgid "Bookmark::ParseField: BookmarkType is not 'D'" msgstr "" #: src/r_bookmark.cc:325 src/r_bookmark.cc:331 src/r_bookmark.cc:337 #: src/r_bookmark.cc:418 src/r_bookmark.cc:424 msgid "Automatic" msgstr "" #: src/r_bookmark.cc:326 src/r_bookmark.cc:332 src/r_bookmark.cc:425 msgid "Enabled" msgstr "" #: src/r_bookmark.cc:327 src/r_bookmark.cc:333 src/r_bookmark.cc:426 msgid "Disabled" msgstr "" #: src/r_bookmark.cc:328 src/r_bookmark.cc:334 src/r_bookmark.cc:341 #: src/r_bookmark.cc:421 src/r_bookmark.cc:427 src/r_calllog.cc:276 #: src/r_calllog.cc:404 src/r_folder.cc:265 src/r_message_base.cc:361 #: src/r_message_base.cc:368 src/r_sms.cc:283 msgid "Unknown" msgstr "" #: src/r_bookmark.cc:338 msgid "BlackBerry" msgstr "" #: src/r_bookmark.cc:339 msgid "FireFox" msgstr "" #: src/r_bookmark.cc:340 msgid "Internet Explorer" msgstr "" #: src/r_bookmark.cc:344 msgid "Bookmark entry: " msgstr "" #: src/r_bookmark.cc:346 msgid "index " msgstr "" #: src/r_bookmark.cc:349 msgid " Name: " msgstr "" #: src/r_bookmark.cc:351 msgid " Icon: " msgstr "" #: src/r_bookmark.cc:353 msgid " Url: " msgstr "" #: src/r_bookmark.cc:354 msgid " Display mode: " msgstr "" #: src/r_bookmark.cc:356 msgid " JavaScript mode: " msgstr "" #: src/r_bookmark.cc:358 msgid " Browser Identity: " msgstr "" #: src/r_bookmark.cc:401 msgid "Record Type" msgstr "" #: src/r_bookmark.cc:402 src/r_calendar.cc:430 src/r_calllog.cc:380 #: src/r_cstore.cc:229 src/r_folder.cc:210 src/r_hhagent.cc:284 #: src/r_memo.cc:268 src/r_message_base.cc:334 src/r_servicebook.cc:447 #: src/r_sms.cc:280 src/r_task.cc:396 src/r_timezone.cc:227 msgid "Unique Record ID" msgstr "" #: src/r_bookmark.cc:404 msgid "Bookmark Field Index" msgstr "" #: src/r_bookmark.cc:406 msgid "Site Name" msgstr "" #: src/r_bookmark.cc:407 msgid "Site Icon" msgstr "" #: src/r_bookmark.cc:408 msgid "Site URL" msgstr "" #: src/r_bookmark.cc:410 msgid "Browser Identity" msgstr "" #: src/r_bookmark.cc:411 msgid "Auto detect browser" msgstr "" #: src/r_bookmark.cc:412 msgid "BlackBerry browser" msgstr "" #: src/r_bookmark.cc:413 msgid "FireFox browser" msgstr "" #: src/r_bookmark.cc:414 msgid "Internet Explorer browser" msgstr "" #: src/r_bookmark.cc:415 msgid "Unknown browser" msgstr "" #: src/r_bookmark.cc:417 msgid "Display Mode" msgstr "" #: src/r_bookmark.cc:419 msgid "Column" msgstr "" #: src/r_bookmark.cc:420 msgid "Page" msgstr "" #: src/r_bookmark.cc:423 msgid "JavaScript Mode" msgstr "" #: src/r_bookmark.cc:429 src/r_calendar.cc:458 src/r_calllog.cc:412 #: src/r_contact.cc:553 src/r_cstore.cc:236 src/r_folder.cc:231 #: src/r_hhagent.cc:298 src/r_memo.cc:274 src/r_message_base.cc:370 #: src/r_servicebook.cc:462 src/r_sms.cc:312 src/r_task.cc:425 #: src/r_timezone.cc:238 msgid "Unknown Fields" msgstr "" #: src/r_calendar.cc:106 src/r_calendar.cc:433 src/r_message_base.cc:86 #: src/r_message_base.cc:342 msgid "Subject" msgstr "" #: src/r_calendar.cc:108 src/r_calendar.cc:435 msgid "Location" msgstr "" #: src/r_calendar.cc:109 msgid "Notification Time" msgstr "" #: src/r_calendar.cc:110 src/r_calendar.cc:438 src/r_task.cc:109 #: src/r_task.cc:403 msgid "Start Time" msgstr "" #: src/r_calendar.cc:111 src/r_calendar.cc:439 msgid "End Time" msgstr "" #: src/r_calendar.cc:112 src/r_calendar.cc:440 msgid "Organizer" msgstr "" #: src/r_calendar.cc:113 src/r_calendar.cc:441 msgid "Accepted By" msgstr "" #: src/r_calendar.cc:114 src/r_calendar.cc:442 msgid "Invited" msgstr "" #: src/r_calendar.cc:115 src/r_calllog.cc:86 src/r_folder.cc:85 #: src/r_hhagent.cc:71 src/r_hhagent.cc:76 src/r_hhagent.cc:81 #: src/r_hhagent.cc:90 src/r_hhagent.cc:95 src/r_hhagent.cc:108 #: src/r_memo.cc:52 src/r_message_base.cc:89 src/r_servicebook.cc:55 #: src/r_servicebook.cc:254 src/r_servicebook.cc:261 src/r_servicebook.cc:270 #: src/r_task.cc:112 src/r_timezone.cc:60 msgid "End of List" msgstr "" #: src/r_calendar.cc:212 msgid "Calendar::ParseField: unknown appointment type" msgstr "" #: src/r_calendar.cc:227 msgid "Calendar::ParseField: not enough data in time zone code field" msgstr "" #: src/r_calendar.cc:233 msgid "Calendar::ParseField: FreeBusyFlag out of range" msgstr "" #: src/r_calendar.cc:243 msgid "Calendar::ParseField: size data unknown in calendar field" msgstr "" #: src/r_calendar.cc:249 msgid "Calendar::ParseField: ClassFlag out of range" msgstr "" #: src/r_calendar.cc:429 src/r_calllog.cc:379 src/r_contact.cc:480 #: src/r_cstore.cc:228 src/r_folder.cc:209 src/r_hhagent.cc:283 #: src/r_memo.cc:267 src/r_message_base.cc:333 src/r_servicebook.cc:446 #: src/r_sms.cc:279 src/r_task.cc:395 src/r_timezone.cc:226 msgid "Record Type Code" msgstr "" #: src/r_calendar.cc:432 msgid "All Day Event" msgstr "" #: src/r_calendar.cc:436 msgid "Notification Time (0 is off)" msgstr "" #: src/r_calendar.cc:444 msgid "Free or Busy Flag" msgstr "" #: src/r_calendar.cc:445 src/r_calendar.cc:486 msgid "Free" msgstr "" #: src/r_calendar.cc:446 src/r_calendar.cc:487 msgid "Tentative" msgstr "" #: src/r_calendar.cc:447 src/r_calendar.cc:488 src/r_calllog.cc:265 #: src/r_calllog.cc:395 src/usbwrap_libusb_1_0.cc:103 msgid "Busy" msgstr "" #: src/r_calendar.cc:448 src/r_calendar.cc:489 msgid "Out of Office" msgstr "" #: src/r_calendar.cc:450 msgid "Event Class" msgstr "" #: src/r_calendar.cc:451 src/r_calendar.cc:481 msgid "Public" msgstr "" #: src/r_calendar.cc:452 src/r_calendar.cc:482 src/r_message_base.cc:367 msgid "Confidential" msgstr "" #: src/r_calendar.cc:453 src/r_calendar.cc:483 src/r_message_base.cc:366 msgid "Private" msgstr "" #: src/r_calendar.cc:455 src/r_task.cc:406 msgid "Time Zone Code" msgstr "" #: src/r_calendar.cc:456 msgid "Time Zone Validity" msgstr "" #: src/r_calendar.cc:463 src/r_calendar.cc:598 msgid "Calendar ID" msgstr "" #: src/r_calendar.cc:492 msgid " Calendar ID: " msgstr "" #: src/r_calendar.cc:494 msgid " All Day Event: " msgstr "" #: src/r_calendar.cc:495 msgid " Class: " msgstr "" #: src/r_calendar.cc:496 msgid " Free/Busy: " msgstr "" #: src/r_calendar.cc:498 src/r_task.cc:486 msgid " Time Zone: " msgstr "" #: src/r_calendar.cc:509 msgid "Calendar entry: " msgstr "" #: src/r_calendar.cc:528 msgid "disabled" msgstr "" #: src/r_calendar.cc:601 msgid "Mail Account" msgstr "" #: src/r_calendar.cc:640 msgid "CalendarAll::ParseField: size data unknown in calendar field" msgstr "" #: src/r_calendar.cc:653 msgid "CalendarAll::ParseHeader: size data unknown in calendar field" msgstr "" #: src/r_calendar.cc:673 msgid " Mail Account: " msgstr "" #: src/r_calllog.cc:85 msgid "Contact name" msgstr "" #: src/r_calllog.cc:114 msgid "CallLog::ParseField: CallLogType is not 'p'" msgstr "" #: src/r_calllog.cc:167 msgid "CallLog::ParseField: direction field out of bounds" msgstr "" #: src/r_calllog.cc:258 src/r_sms.cc:284 msgid "Received" msgstr "" #: src/r_calllog.cc:259 src/r_folder.cc:221 src/r_folder.cc:252 #: src/r_sms.cc:285 msgid "Sent" msgstr "" #: src/r_calllog.cc:260 msgid "Call Missing (Messagerie)" msgstr "" #: src/r_calllog.cc:261 msgid "Call Missing" msgstr "" #: src/r_calllog.cc:264 src/r_calllog.cc:394 msgid "OK" msgstr "" #: src/r_calllog.cc:267 src/r_calllog.cc:280 msgid "Not supported by Barry" msgstr "" #: src/r_calllog.cc:270 src/r_calllog.cc:400 src/r_calllog.cc:407 msgid "Undefined" msgstr "" #: src/r_calllog.cc:271 msgid "Known phone number" msgstr "" #: src/r_calllog.cc:272 msgid "Unknown phone number" msgstr "" #: src/r_calllog.cc:273 msgid "Private phone number" msgstr "" #: src/r_calllog.cc:277 src/r_calllog.cc:401 msgid "Office" msgstr "" #: src/r_calllog.cc:278 src/r_calllog.cc:402 msgid "Home" msgstr "" #: src/r_calllog.cc:279 src/r_calllog.cc:403 msgid "Mobile" msgstr "" #: src/r_calllog.cc:283 msgid "CallLog entry: " msgstr "" #: src/r_calllog.cc:287 msgid " Timestamp: " msgstr "" #: src/r_calllog.cc:288 msgid " Direction: " msgstr "" #: src/r_calllog.cc:290 src/r_task.cc:481 msgid " Status: " msgstr "" #: src/r_calllog.cc:292 msgid " Phone info: " msgstr "" #: src/r_calllog.cc:294 msgid " Phone type: " msgstr "" #: src/r_calllog.cc:297 msgid " Duration: " msgstr "" #: src/r_calllog.cc:312 msgid " days " msgstr "" #: src/r_calllog.cc:314 msgid " day " msgstr "" #: src/r_calllog.cc:382 msgid "Duration of Call in Seconds" msgstr "" #: src/r_calllog.cc:383 msgid "Timestamp of Call in Milliseconds" msgstr "" #: src/r_calllog.cc:384 msgid "Contact Name" msgstr "" #: src/r_calllog.cc:385 msgid "Phone Number" msgstr "" #: src/r_calllog.cc:387 msgid "Direction of Call" msgstr "" #: src/r_calllog.cc:388 msgid "Received Call" msgstr "" #: src/r_calllog.cc:389 msgid "Placed the Call" msgstr "" #: src/r_calllog.cc:390 msgid "Failed Call" msgstr "" #: src/r_calllog.cc:391 msgid "Missed Call" msgstr "" #: src/r_calllog.cc:393 msgid "Status of Call" msgstr "" #: src/r_calllog.cc:396 msgid "Network Error" msgstr "" #: src/r_calllog.cc:397 msgid "Unsupported Status" msgstr "" #: src/r_calllog.cc:399 msgid "Phone Type" msgstr "" #: src/r_calllog.cc:406 msgid "Phone Info" msgstr "" #: src/r_calllog.cc:408 msgid "Phone Number is Set" msgstr "" #: src/r_calllog.cc:409 msgid "Phone Number Not Set" msgstr "" #: src/r_calllog.cc:410 msgid "Phone Number is Private" msgstr "" #: src/r_command.cc:99 msgid "Command table:\n" msgstr "" #: src/r_command.cc:101 msgid " Command: " msgstr "" #: src/r_contact.cc:109 src/r_contact.cc:490 msgid "Nickname" msgstr "" #: src/r_contact.cc:110 msgid "Phone" msgstr "" #: src/r_contact.cc:111 msgid "Fax" msgstr "" #: src/r_contact.cc:112 msgid "HomeFax" msgstr "" #: src/r_contact.cc:113 msgid "WorkPhone" msgstr "" #: src/r_contact.cc:114 msgid "HomePhone" msgstr "" #: src/r_contact.cc:115 msgid "MobilePhone" msgstr "" #: src/r_contact.cc:116 msgid "MobilePhone2" msgstr "" #: src/r_contact.cc:117 src/r_contact.cc:502 msgid "Pager" msgstr "" #: src/r_contact.cc:119 src/r_contact.cc:504 msgid "Radio" msgstr "" #: src/r_contact.cc:120 msgid "WorkPhone2" msgstr "" #: src/r_contact.cc:121 msgid "HomePhone2" msgstr "" #: src/r_contact.cc:122 msgid "OtherPhone" msgstr "" #: src/r_contact.cc:123 src/r_contact.cc:486 msgid "Company" msgstr "" #: src/r_contact.cc:124 msgid "DefaultCommMethod" msgstr "" #: src/r_contact.cc:125 msgid "WorkAddress1" msgstr "" #: src/r_contact.cc:126 msgid "WorkAddress2" msgstr "" #: src/r_contact.cc:127 msgid "WorkAddress3" msgstr "" #: src/r_contact.cc:129 msgid "WorkProvince" msgstr "" #: src/r_contact.cc:130 msgid "WorkPostalCode" msgstr "" #: src/r_contact.cc:132 msgid "JobTitle" msgstr "" #: src/r_contact.cc:133 msgid "PublicKey" msgstr "" #: src/r_contact.cc:134 src/r_contact.cc:508 msgid "URL" msgstr "" #: src/r_contact.cc:135 src/r_contact.cc:488 msgid "Prefix" msgstr "" #: src/r_contact.cc:136 msgid "HomeAddress1" msgstr "" #: src/r_contact.cc:137 msgid "HomeAddress2" msgstr "" #: src/r_contact.cc:138 msgid "HomeAddress3" msgstr "" #: src/r_contact.cc:140 msgid "UserDefined1" msgstr "" #: src/r_contact.cc:141 msgid "UserDefined2" msgstr "" #: src/r_contact.cc:142 msgid "UserDefined3" msgstr "" #: src/r_contact.cc:143 msgid "UserDefined4" msgstr "" #: src/r_contact.cc:144 msgid "HomeCity" msgstr "" #: src/r_contact.cc:145 msgid "HomeProvince" msgstr "" #: src/r_contact.cc:146 msgid "HomePostalCode" msgstr "" #: src/r_contact.cc:147 msgid "HomeCountry" msgstr "" #: src/r_contact.cc:148 src/r_contact.cc:514 msgid "Image" msgstr "" #: src/r_contact.cc:149 msgid "EndOfList" msgstr "" #: src/r_contact.cc:298 msgid "" "A contact record must contain either a First/Last name, or a Company name." msgstr "" #: src/r_contact.cc:319 msgid "Contact must have name or company name." msgstr "" #: src/r_contact.cc:481 src/r_servicebook.cc:454 src/r_servicebook.cc:496 msgid "Unique ID" msgstr "" #: src/r_contact.cc:482 msgid "Email Addresses" msgstr "" #: src/r_contact.cc:484 msgid "First Name" msgstr "" #: src/r_contact.cc:485 msgid "Last Name" msgstr "" #: src/r_contact.cc:491 msgid "Phone (deprecated)" msgstr "" #: src/r_contact.cc:492 msgid "Work Fax" msgstr "" #: src/r_contact.cc:493 msgid "Home Fax" msgstr "" #: src/r_contact.cc:494 msgid "Work Phone" msgstr "" #: src/r_contact.cc:496 msgid "Work Phone 2" msgstr "" #: src/r_contact.cc:497 msgid "Home Phone" msgstr "" #: src/r_contact.cc:498 msgid "Home Phone 2" msgstr "" #: src/r_contact.cc:499 msgid "Mobile Phone" msgstr "" #: src/r_contact.cc:500 msgid "Mobile Phone 2" msgstr "" #: src/r_contact.cc:501 msgid "Other Phone" msgstr "" #: src/r_contact.cc:505 msgid "Default Communications Method" msgstr "" #: src/r_contact.cc:507 msgid "Public Key" msgstr "" #: src/r_contact.cc:510 msgid "User Defined Field 1" msgstr "" #: src/r_contact.cc:511 msgid "User Defined Field 2" msgstr "" #: src/r_contact.cc:512 msgid "User Defined Field 3" msgstr "" #: src/r_contact.cc:513 msgid "User Defined Field 4" msgstr "" #: src/r_contact.cc:516 msgid "Birthday" msgstr "" #: src/r_contact.cc:517 msgid "Anniversary" msgstr "" #: src/r_contact.cc:519 msgid "Work Address" msgstr "" #: src/r_contact.cc:520 msgid "Work Address 1" msgstr "" #: src/r_contact.cc:522 msgid "Work Address 2" msgstr "" #: src/r_contact.cc:524 msgid "Work Address 3" msgstr "" #: src/r_contact.cc:526 msgid "Work City" msgstr "" #: src/r_contact.cc:528 msgid "Work Province" msgstr "" #: src/r_contact.cc:530 msgid "Work Postal Code" msgstr "" #: src/r_contact.cc:532 msgid "Work Country" msgstr "" #: src/r_contact.cc:535 msgid "Home Address" msgstr "" #: src/r_contact.cc:536 msgid "Home Address 1" msgstr "" #: src/r_contact.cc:538 msgid "Home Address 2" msgstr "" #: src/r_contact.cc:540 msgid "Home Address 3" msgstr "" #: src/r_contact.cc:542 msgid "Home City" msgstr "" #: src/r_contact.cc:544 msgid "Home Province" msgstr "" #: src/r_contact.cc:546 msgid "Home Postal Code" msgstr "" #: src/r_contact.cc:548 msgid "Home Country" msgstr "" #: src/r_contact.cc:551 src/r_memo.cc:272 src/r_task.cc:400 msgid "Categories" msgstr "" #: src/r_contact.cc:601 msgid "Contact: " msgstr "" #: src/r_contact.cc:605 msgid "FirstName" msgstr "" #: src/r_contact.cc:607 msgid "LastName" msgstr "" #: src/r_contact.cc:614 msgid " Email : " msgstr "" #: src/r_contact.cc:646 msgid " Categories : " msgstr "" #: src/r_contact.cc:651 msgid " Birthday : " msgstr "" #: src/r_contact.cc:654 msgid " Anniversary : " msgstr "" #: src/r_contact.cc:661 msgid " GroupLinks:\n" msgstr "" #: src/r_contact.cc:663 msgid " ID: " msgstr "" #: src/r_contact.cc:669 msgid " Photo image:\n" msgstr "" #: src/r_contact.cc:748 msgid "" "Error: Cannot convert complex name+address to a simple contact email " "address, skipping: " msgstr "" #: src/r_cstore.cc:150 msgid "Content Store must have a name." msgstr "" #: src/r_cstore.cc:153 msgid "Content Store item without any data." msgstr "" #: src/r_cstore.cc:231 msgid "File or Folder Name" msgstr "" #: src/r_cstore.cc:232 msgid "Folder Flag" msgstr "" #: src/r_cstore.cc:233 msgid "File Content" msgstr "" #: src/r_cstore.cc:234 msgid "File Descriptor" msgstr "" #: src/r_cstore.cc:253 msgid "ContentStore: " msgstr "" #: src/r_cstore.cc:256 msgid " Filename: " msgstr "" #: src/r_cstore.cc:257 msgid " Folder: " msgstr "" #: src/r_cstore.cc:258 msgid " BB Size: " msgstr "" #: src/r_cstore.cc:259 msgid " Actual Size: " msgstr "" #: src/r_cstore.cc:260 msgid " Descriptor:\n" msgstr "" #: src/r_cstore.cc:262 msgid " Content:\n" msgstr "" #: src/r_dbdb.cc:118 msgid "DatabaseDatabase: not enough data for parsing" msgstr "" #: src/r_dbdb.cc:123 msgid "Unknown protocol" msgstr "" #: src/r_dbdb.cc:197 msgid "Database database:\n" msgstr "" #: src/r_dbdb.cc:199 msgid " Database: " msgstr "" #: src/r_dbdb.cc:200 msgid "records: " msgstr "" #: src/r_folder.cc:84 msgid "FolderName" msgstr "" #: src/r_folder.cc:212 msgid "Folder Name" msgstr "" #: src/r_folder.cc:213 msgid "Order Number" msgstr "" #: src/r_folder.cc:214 msgid "Folder Level" msgstr "" #: src/r_folder.cc:216 msgid "Folder Type" msgstr "" #: src/r_folder.cc:217 src/r_folder.cc:248 msgid "Subtree" msgstr "" #: src/r_folder.cc:218 src/r_folder.cc:249 src/r_sms.cc:296 msgid "Deleted" msgstr "" #: src/r_folder.cc:219 src/r_folder.cc:250 msgid "Inbox" msgstr "" #: src/r_folder.cc:220 src/r_folder.cc:251 msgid "Outbox" msgstr "" #: src/r_folder.cc:222 src/r_folder.cc:253 src/usbwrap_libusb_1_0.cc:117 msgid "Other" msgstr "" #: src/r_folder.cc:223 src/r_sms.cc:286 msgid "Draft" msgstr "" #: src/r_folder.cc:257 msgid "" "Folder Records\n" "\n" msgstr "" #: src/r_folder.cc:258 msgid "Folder Name: " msgstr "" #: src/r_folder.cc:259 msgid "Folder Type: " msgstr "" #: src/r_folder.cc:263 msgid "Draft\n" msgstr "" #: src/r_folder.cc:266 msgid "Folder Number: " msgstr "" #: src/r_folder.cc:267 msgid "Folder Level: " msgstr "" #: src/r_hhagent.cc:65 src/r_hhagent.cc:86 src/r_hhagent.cc:100 #: src/r_hhagent.cc:288 msgid "Model" msgstr "" #: src/r_hhagent.cc:66 src/r_hhagent.cc:101 src/r_hhagent.cc:292 msgid "Network" msgstr "" #: src/r_hhagent.cc:67 src/r_hhagent.cc:103 src/r_hhagent.cc:289 msgid "Bands" msgstr "" #: src/r_hhagent.cc:68 src/r_hhagent.cc:104 src/r_hhagent.cc:287 msgid "MEID/ESN" msgstr "" #: src/r_hhagent.cc:70 src/r_hhagent.cc:106 src/r_hhagent.cc:291 msgid "Version" msgstr "" #: src/r_hhagent.cc:87 src/r_hhagent.cc:102 src/r_hhagent.cc:296 msgid "Manufacturer" msgstr "" #: src/r_hhagent.cc:88 msgid "Firmware" msgstr "" #: src/r_hhagent.cc:89 src/r_hhagent.cc:107 msgid "Platform" msgstr "" #: src/r_hhagent.cc:140 msgid "HandheldAgent requires SetIds() to be called before ParseField()" msgstr "" #: src/r_hhagent.cc:295 msgid "Platform Version" msgstr "" #: src/r_hhagent.cc:306 msgid "Handheld Agent: " msgstr "" #: src/r_hhagent.cc:314 msgid "HandheldAgent entry: " msgstr "" #: src/r_memo.cc:50 src/r_memo.cc:270 msgid "Title" msgstr "" #: src/r_memo.cc:51 src/r_memo.cc:271 src/r_message_base.cc:87 #: src/r_message_base.cc:343 src/r_sms.cc:310 msgid "Body" msgstr "" #: src/r_memo.cc:80 msgid "Memo::ParseField: MemoType is not 'm'" msgstr "" #: src/r_memo.cc:209 msgid "Memo entry: " msgstr "" #: src/r_memo.cc:211 msgid " Title: " msgstr "" #: src/r_memo.cc:212 msgid " Body: " msgstr "" #: src/r_memo.cc:227 msgid " Categories: " msgstr "" #: src/r_message_base.cc:80 src/r_message_base.cc:337 msgid "To" msgstr "" #: src/r_message_base.cc:81 msgid "Cc" msgstr "" #: src/r_message_base.cc:82 msgid "Bcc" msgstr "" #: src/r_message_base.cc:83 src/r_message_base.cc:340 msgid "Sender" msgstr "" #: src/r_message_base.cc:84 src/r_message_base.cc:336 msgid "From" msgstr "" #: src/r_message_base.cc:85 msgid "ReplyTo" msgstr "" #: src/r_message_base.cc:88 src/r_message_base.cc:344 msgid "Attachment" msgstr "" #: src/r_message_base.cc:278 msgid "MessageBase::BuildHeader not yet implemented" msgstr "" #: src/r_message_base.cc:283 msgid "MessageBase::BuildFields not yet implemented" msgstr "" #: src/r_message_base.cc:338 msgid "CC" msgstr "" #: src/r_message_base.cc:339 msgid "BCC" msgstr "" #: src/r_message_base.cc:341 msgid "Reply To" msgstr "" #: src/r_message_base.cc:346 msgid "Message Record ID" msgstr "" #: src/r_message_base.cc:347 msgid "Message Reply To" msgstr "" #: src/r_message_base.cc:348 msgid "Date Sent" msgstr "" #: src/r_message_base.cc:349 msgid "Date Received" msgstr "" #: src/r_message_base.cc:351 msgid "Truncated" msgstr "" #: src/r_message_base.cc:352 msgid "Read" msgstr "" #: src/r_message_base.cc:353 msgid "Reply" msgstr "" #: src/r_message_base.cc:354 src/r_sms.cc:295 msgid "Saved" msgstr "" #: src/r_message_base.cc:355 msgid "Saved Deleted" msgstr "" #: src/r_message_base.cc:357 src/r_task.cc:413 msgid "Priority" msgstr "" #: src/r_message_base.cc:358 src/r_task.cc:416 src/r_task.cc:445 msgid "Low" msgstr "" #: src/r_message_base.cc:359 src/r_message_base.cc:364 src/r_task.cc:415 #: src/r_task.cc:444 msgid "Normal" msgstr "" #: src/r_message_base.cc:360 src/r_task.cc:414 src/r_task.cc:443 msgid "High" msgstr "" #: src/r_message_base.cc:363 msgid "Sensitivity" msgstr "" #: src/r_message_base.cc:365 msgid "Personal" msgstr "" #: src/r_recordstate.cc:131 msgid " Index RecordId Dirty RecType" msgstr "" #: src/r_recordstate.cc:141 src/r_recur_base.cc:279 tools/bjavaloader.cc:455 #: tools/bjavaloader.cc:471 msgid "yes" msgstr "" #: src/r_recordstate.cc:141 src/r_recur_base.cc:279 msgid "no" msgstr "" #: src/r_recur_base.cc:91 msgid "RecurBase::ParseField: not enough data in recurrence data field" msgstr "" #: src/r_recur_base.cc:157 msgid "Unknown recurrence data type" msgstr "" #: src/r_recur_base.cc:172 msgid "" "RecurBase::BuildRecurrenceData: Attempting to build recurrence data on non-" "recurring record." msgstr "" #: src/r_recur_base.cc:226 msgid "RecurBase::BuildRecurrenceData: Unknown recurrence data type" msgstr "" #: src/r_recur_base.cc:251 src/r_recur_base.cc:323 msgid "Sun" msgstr "" #: src/r_recur_base.cc:252 src/r_recur_base.cc:324 msgid "Mon" msgstr "" #: src/r_recur_base.cc:253 src/r_recur_base.cc:325 msgid "Tue" msgstr "" #: src/r_recur_base.cc:254 src/r_recur_base.cc:326 msgid "Wed" msgstr "" #: src/r_recur_base.cc:255 src/r_recur_base.cc:327 msgid "Thu" msgstr "" #: src/r_recur_base.cc:256 src/r_recur_base.cc:328 msgid "Fri" msgstr "" #: src/r_recur_base.cc:257 src/r_recur_base.cc:329 msgid "Sat" msgstr "" #: src/r_recur_base.cc:260 src/r_timezone.cc:257 msgid "Jan" msgstr "" #: src/r_recur_base.cc:261 src/r_timezone.cc:258 msgid "Feb" msgstr "" #: src/r_recur_base.cc:262 src/r_timezone.cc:259 msgid "Mar" msgstr "" #: src/r_recur_base.cc:263 src/r_timezone.cc:260 msgid "Apr" msgstr "" #: src/r_recur_base.cc:264 src/r_timezone.cc:261 msgid "May" msgstr "" #: src/r_recur_base.cc:265 src/r_timezone.cc:262 msgid "Jun" msgstr "" #: src/r_recur_base.cc:266 src/r_timezone.cc:263 msgid "Jul" msgstr "" #: src/r_recur_base.cc:267 src/r_timezone.cc:264 msgid "Aug" msgstr "" #: src/r_recur_base.cc:268 src/r_timezone.cc:265 msgid "Sep" msgstr "" #: src/r_recur_base.cc:269 src/r_timezone.cc:266 msgid "Oct" msgstr "" #: src/r_recur_base.cc:270 src/r_timezone.cc:267 msgid "Nov" msgstr "" #: src/r_recur_base.cc:271 src/r_timezone.cc:268 msgid "Dec" msgstr "" #: src/r_recur_base.cc:279 msgid " Recurring: " msgstr "" #: src/r_recur_base.cc:284 msgid " Every day.\n" msgstr "" #. TRANSLATORS: to remove the 'th' ending on numbers, #. just replace the %s with %.0s in this string. #: src/r_recur_base.cc:290 #, c-format msgid " Every month on the %u%s" msgstr "" #: src/r_recur_base.cc:300 #, c-format msgid " Every month on the %s of week %u" msgstr "" #: src/r_recur_base.cc:307 #, c-format msgid " Every year on %s %u" msgstr "" #: src/r_recur_base.cc:314 #, c-format msgid " Every year in %s on %s of week %u" msgstr "" #: src/r_recur_base.cc:322 msgid " Every week on: " msgstr "" #: src/r_recur_base.cc:334 msgid " Unknown recurrence type\n" msgstr "" #: src/r_recur_base.cc:338 msgid " Interval: " msgstr "" #: src/r_recur_base.cc:341 msgid " Ends: never\n" msgstr "" #: src/r_recur_base.cc:343 msgid " Ends: " msgstr "" #: src/r_servicebook.cc:182 msgid "ServiceBookConfig::Build not yet implemented" msgstr "" #: src/r_servicebook.cc:195 msgid " ServiceBookConfig Format: " msgstr "" #: src/r_servicebook.cc:216 msgid " ------------------- End of Config Field\n" msgstr "" #: src/r_servicebook.cc:251 msgid "Old Name" msgstr "" #: src/r_servicebook.cc:252 msgid "Old Desc" msgstr "" #: src/r_servicebook.cc:253 msgid "Old UniqueId" msgstr "" #: src/r_servicebook.cc:258 src/r_servicebook.cc:449 src/r_servicebook.cc:492 #: src/r_timezone.cc:59 msgid "Name" msgstr "" #: src/r_servicebook.cc:259 src/r_servicebook.cc:451 src/r_servicebook.cc:494 msgid "Description" msgstr "" #: src/r_servicebook.cc:260 msgid "UniqueId" msgstr "" #: src/r_servicebook.cc:266 src/r_servicebook.cc:450 src/r_servicebook.cc:493 msgid "Hidden Name" msgstr "" #: src/r_servicebook.cc:267 src/r_servicebook.cc:452 src/r_servicebook.cc:495 msgid "DSID" msgstr "" #: src/r_servicebook.cc:268 msgid "ContentId" msgstr "" #: src/r_servicebook.cc:269 src/r_servicebook.cc:453 msgid "BES Domain" msgstr "" #: src/r_servicebook.cc:423 msgid "ServiceBook::BuildFields not yet implemented" msgstr "" #: src/r_servicebook.cc:455 src/r_servicebook.cc:497 msgid "Content ID" msgstr "" #: src/r_servicebook.cc:489 msgid "ServiceBook entry: " msgstr "" #: src/r_servicebook.cc:498 msgid "(BES) Domain" msgstr "" #: src/r_sms.cc:282 msgid "Message Status" msgstr "" #: src/r_sms.cc:288 msgid "Delivery Status" msgstr "" #: src/r_sms.cc:289 msgid "No Report" msgstr "" #: src/r_sms.cc:290 msgid "Failed" msgstr "" #: src/r_sms.cc:291 msgid "Succeeded" msgstr "" #: src/r_sms.cc:293 msgid "Is New?" msgstr "" #: src/r_sms.cc:294 msgid "New Conversation" msgstr "" #: src/r_sms.cc:297 msgid "Opened" msgstr "" #: src/r_sms.cc:299 msgid "Timestamp in Milliseconds" msgstr "" #: src/r_sms.cc:300 msgid "Service Center Timestamp" msgstr "" #: src/r_sms.cc:302 msgid "Data Coding Scheme" msgstr "" #: src/r_sms.cc:303 msgid "7bit" msgstr "" #: src/r_sms.cc:304 msgid "8bit" msgstr "" #: src/r_sms.cc:305 msgid "UCS2" msgstr "" #: src/r_sms.cc:307 msgid "Error ID" msgstr "" #: src/r_sms.cc:309 msgid "Addresses" msgstr "" #: src/r_sms.cc:322 msgid "Unknown destination" msgstr "" #: src/r_sms.cc:329 msgid "SMS record: " msgstr "" #: src/r_sms.cc:332 msgid "Timestamp: " msgstr "" #: src/r_sms.cc:336 msgid "Service Center Timestamp: " msgstr "" #: src/r_sms.cc:340 msgid "Send Error: " msgstr "" #: src/r_sms.cc:345 msgid "Received From:\n" msgstr "" #: src/r_sms.cc:348 msgid "Sent to:\n" msgstr "" #: src/r_sms.cc:351 msgid "Draft for:\n" msgstr "" #: src/r_sms.cc:354 msgid "Unknown status for:\n" msgstr "" #: src/r_sms.cc:364 msgid "New " msgstr "" #: src/r_sms.cc:366 msgid "Opened " msgstr "" #: src/r_sms.cc:368 msgid "Saved " msgstr "" #: src/r_sms.cc:370 msgid "Deleted " msgstr "" #: src/r_sms.cc:371 msgid "Message" msgstr "" #: src/r_sms.cc:371 msgid " that starts a new conversation" msgstr "" #: src/r_sms.cc:373 msgid "Content: " msgstr "" #: src/r_task.cc:107 src/r_task.cc:398 msgid "Summary" msgstr "" #: src/r_task.cc:110 src/r_task.cc:404 msgid "Due Time" msgstr "" #: src/r_task.cc:111 src/r_task.cc:405 msgid "Alarm Time" msgstr "" #: src/r_task.cc:140 msgid "Task::ParseField: Task Type is not 't'" msgstr "" #: src/r_task.cc:171 src/r_task.cc:180 msgid "Task::ParseField: priority field out of bounds" msgstr "" #: src/r_task.cc:193 msgid "Task::ParseField: not enough data in time zone code field" msgstr "" #: src/r_task.cc:213 msgid "Task::ParseField: AlarmType out of bounds" msgstr "" #: src/r_task.cc:401 msgid "UID" msgstr "" #: src/r_task.cc:407 msgid "Time Zone Code Valid" msgstr "" #: src/r_task.cc:409 msgid "Alarm Type" msgstr "" #: src/r_task.cc:410 msgid "Date" msgstr "" #: src/r_task.cc:411 src/r_task.cc:457 msgid "Relative" msgstr "" #: src/r_task.cc:418 msgid "Status" msgstr "" #: src/r_task.cc:419 src/r_task.cc:448 msgid "Not Started" msgstr "" #: src/r_task.cc:420 src/r_task.cc:449 msgid "In Progress" msgstr "" #: src/r_task.cc:421 src/r_task.cc:450 msgid "Completed" msgstr "" #: src/r_task.cc:422 src/r_task.cc:451 msgid "Waiting" msgstr "" #: src/r_task.cc:423 src/r_task.cc:452 msgid "Deferred" msgstr "" #: src/r_task.cc:455 msgid "None" msgstr "" #: src/r_task.cc:456 msgid "By Date" msgstr "" #: src/r_task.cc:460 msgid "Task entry: " msgstr "" #: src/r_task.cc:480 msgid " Priority: " msgstr "" #: src/r_task.cc:483 msgid " Alarm Type: " msgstr "" #: src/r_task.cc:494 msgid " Categories: " msgstr "" #: src/r_timezone.cc:111 msgid "TimeZone::ParseField: TimeZone Type is not valid" msgstr "" #: src/r_timezone.cc:229 msgid "TimeZone Name" msgstr "" #: src/r_timezone.cc:230 msgid "Index" msgstr "" #: src/r_timezone.cc:231 msgid "TimeZone Offset in Minutes" msgstr "" #: src/r_timezone.cc:232 msgid "Use DST?" msgstr "" #: src/r_timezone.cc:233 msgid "DST Offset" msgstr "" #: src/r_timezone.cc:234 msgid "Start Month" msgstr "" #: src/r_timezone.cc:235 msgid "End Month" msgstr "" #: src/r_timezone.cc:236 msgid "TimeZone Type" msgstr "" #: src/r_timezone.cc:271 msgid "TimeZone entry: " msgstr "" #: src/r_timezone.cc:289 msgid " Desc: " msgstr "" #: src/r_timezone.cc:290 msgid " Index: " msgstr "" #: src/r_timezone.cc:291 msgid " Type: " msgstr "" #: src/r_timezone.cc:292 msgid " Offset: " msgstr "" #: src/r_timezone.cc:292 msgid " minutes " msgstr "" #: src/r_timezone.cc:294 msgid " Split Offset: hours: " msgstr "" #: src/r_timezone.cc:295 msgid ", minutes: " msgstr "" #: src/r_timezone.cc:296 msgid " Sample TZ: " msgstr "" #: src/r_timezone.cc:297 msgid " Use DST: " msgstr "" #: src/r_timezone.cc:299 msgid " DST Offset: " msgstr "" #: src/r_timezone.cc:301 msgid "Start Month: " msgstr "" #: src/r_timezone.cc:303 msgid "Start Month: unknown (" msgstr "" #: src/r_timezone.cc:305 msgid " End Month: " msgstr "" #: src/r_timezone.cc:307 msgid " End Month: unknown (" msgstr "" #: src/record.cc:253 msgid " Unknowns:\n" msgstr "" #: src/record.cc:255 msgid " Type: " msgstr "" #: src/record.cc:257 msgid " Data:\n" msgstr "" #: src/record.cc:459 msgid "NULL time pointer passed to Date::FromTm" msgstr "" #: src/record.cc:591 msgid "Enum value not found in constant list" msgstr "" #: src/record.cc:642 msgid "Different database types in DBNamedFieldCmp" msgstr "" #: src/record.cc:647 msgid "Unknown database in DBNamedFieldCmp::operator()" msgstr "" #: src/restore.cc:184 msgid "Skipping: " msgstr "" #: src/restore.cc:298 msgid "Skipping invalid tar record: " msgstr "" #: src/restore.cc:358 msgid "Invalid state in Restore::BuildRecord()" msgstr "" #: src/restore.cc:410 msgid "Invalid state in Restore::FetchRecord()" msgstr "" #: src/router.cc:198 msgid "SimpleReadThread received uncaught exception: " msgstr "" #: src/router.cc:198 msgid " what: " msgstr "" #: src/router.cc:201 msgid "SimpleReadThread recevied uncaught exception of unknown type" msgstr "" #: src/router.cc:211 msgid "SocketRoutingQueue Leftovers: " msgstr "" #: src/router.cc:213 msgid " packet(s) for socket: " msgstr "" #: src/router.cc:343 msgid "RegisterInterest requesting a previously registered socket." msgstr "" #: src/router.cc:422 msgid "SocketRead requested data from unregistered socket." msgstr "" #: src/router.cc:616 msgid "SocketRoutingQueue: Error creating USB read thread." msgstr "" #: src/socket.cc:123 msgid "Socket: Whole packet too short to fragment" msgstr "" #: src/socket.cc:170 msgid "Socket: invalid sequence packet" msgstr "" #: src/socket.cc:183 #, c-format msgid "" "Socket 0x%x: out of sequence. (Global sequence: 0x%x. Packet sequence: 0x%x)" msgstr "" #: src/socket.cc:293 msgid "SocketZero: No device available for RawSend" msgstr "" #: src/socket.cc:324 msgid "" "SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)" msgstr "" #: src/socket.cc:338 msgid "Multiple pushbacks in SocketZero!" msgstr "" #: src/socket.cc:459 msgid "No password specified." msgstr "" #: src/socket.cc:504 msgid "" "Socket: Device closed socket when trying to open (can be caused by the wrong " "password, or if the device thinks the socket is already open... please try " "again)" msgstr "" #: src/socket.cc:512 msgid "Socket: Bad OPENED packet in Open" msgstr "" #: src/socket.cc:528 msgid "Could not find mode's starting sequence packet" msgstr "" #: src/socket.cc:617 msgid "Socket: Bad CLOSED packet in Close" msgstr "" #: src/socket.cc:628 msgid "Socket: Missing RESET_REPLY in Close" msgstr "" #: src/socket.cc:677 msgid "Socket: unknown send data in DBFragSend()" msgstr "" #: src/socket.cc:781 src/socket.cc:870 msgid "Socket: (read) unhandled packet in Packet(): " msgstr "" #: src/socket.cc:794 src/socket.cc:887 src/socket.cc:970 msgid "Socket: 10 blank packets received" msgstr "" #: src/socket.cc:840 msgid "Socket: unknown send data in PacketJVM()" msgstr "" #: src/socket.cc:908 msgid "Socket: unknown send data in PacketData()" msgstr "" #: src/socket.cc:950 msgid "file is not a valid Java code file" msgstr "" #: src/socket.cc:954 msgid "device does not support requested command" msgstr "" #: src/socket.cc:1072 msgid "Non-sequence packet in Socket::SyncSend()" msgstr "" #: src/socket.cc:1081 msgid "Socket::Receive: queue SocketRead returned false (likely a timeout)" msgstr "" #: src/socket.cc:1084 msgid "NULL queue pointer in a registered socket read." msgstr "" #: src/socket.cc:1099 msgid "" "SocketRoutingQueue required in SocketZero in order to call Socket::" "RegisterInterest()" msgstr "" #: src/socket.cc:1102 #, c-format msgid "Socket (%u) already registered in Socket::RegisterInterest()!" msgstr "" #: src/tarfile.cc:55 msgid "Unable to open tar file: " msgstr "" #: src/tarfile.cc:88 msgid "Unable to write eof" msgstr "" #: src/tarfile.cc:92 msgid "Unable to close file" msgstr "" #: src/tarfile.cc:113 msgid "Unable to write tar header" msgstr "" #: src/tarfile.cc:128 msgid "Unable to write block" msgstr "" #: src/tarfile.cc:156 src/tarfile.cc:215 src/tarfile.cc:272 msgid "Only regular files are supported inside a tarball." msgstr "" #: src/tarfile.cc:184 src/tarfile.cc:243 msgid "Unable to read block" msgstr "" #: src/tarfile.cc:281 msgid "Unable to skip tar file" msgstr "" #: src/threadwrap.cc:54 msgid "Thread: pthread_create failed." msgstr "" #: src/time.cc:154 msgid "Unknown time zone" msgstr "" #: src/usbwrap_libusb.cc:228 src/usbwrap_libusb_1_0.cc:336 msgid "invalid USB device ID" msgstr "" #: src/usbwrap_libusb.cc:231 src/usbwrap_libusb_1_0.cc:340 msgid "" "Failed to open USB device. Please check your system's USB device " "permissions." msgstr "" #: src/usbwrap_libusb.cc:275 msgid "Timeout in usb_bulk_read" msgstr "" #: src/usbwrap_libusb.cc:278 msgid "Error in usb_bulk_read(" msgstr "" #: src/usbwrap_libusb.cc:303 msgid "Timeout in usb_bulk_write (1)" msgstr "" #: src/usbwrap_libusb.cc:305 msgid "Error in usb_bulk_write (1)" msgstr "" #: src/usbwrap_libusb.cc:327 msgid "Timeout in usb_bulk_write (2)" msgstr "" #: src/usbwrap_libusb.cc:329 msgid "Error in usb_bulk_write (2)" msgstr "" #: src/usbwrap_libusb.cc:347 msgid "Timeout in usb_interrupt_read" msgstr "" #: src/usbwrap_libusb.cc:349 msgid "Error in usb_interrupt_read" msgstr "" #: src/usbwrap_libusb.cc:370 msgid "Timeout in usb_interrupt_write" msgstr "" #: src/usbwrap_libusb.cc:372 msgid "Error in usb_interrupt_write" msgstr "" #: src/usbwrap_libusb.cc:505 src/usbwrap_libusb_1_0.cc:688 msgid "claim interface failed" msgstr "" #: src/usbwrap_libusb_1_0.cc:91 msgid "Success" msgstr "" #: src/usbwrap_libusb_1_0.cc:93 msgid "IO Error" msgstr "" #: src/usbwrap_libusb_1_0.cc:95 msgid "Invalid parameter" msgstr "" #: src/usbwrap_libusb_1_0.cc:97 msgid "Access" msgstr "" #: src/usbwrap_libusb_1_0.cc:99 msgid "No device" msgstr "" #: src/usbwrap_libusb_1_0.cc:101 msgid "Not found" msgstr "" #: src/usbwrap_libusb_1_0.cc:105 msgid "Timeout" msgstr "" #: src/usbwrap_libusb_1_0.cc:107 msgid "Overflow" msgstr "" #: src/usbwrap_libusb_1_0.cc:109 msgid "Pipe" msgstr "" #: src/usbwrap_libusb_1_0.cc:111 msgid "Interrupted" msgstr "" #: src/usbwrap_libusb_1_0.cc:113 msgid "No memory" msgstr "" #: src/usbwrap_libusb_1_0.cc:115 msgid "Not supported" msgstr "" #: src/usbwrap_libusb_1_0.cc:119 msgid "Unknown LIBUSB error code" msgstr "" #: src/usbwrap_libusb_1_0.cc:272 msgid "Failed to get device list" msgstr "" #: src/usbwrap_libusb_1_0.cc:391 msgid "Timeout in BulkRead" msgstr "" #: src/usbwrap_libusb_1_0.cc:397 msgid "Error in libusb_bulk_tranfer(" msgstr "" #: src/usbwrap_libusb_1_0.cc:432 msgid "Timeout in BulkWrite" msgstr "" #: src/usbwrap_libusb_1_0.cc:434 msgid "Error in BulkWrite" msgstr "" #: src/usbwrap_libusb_1_0.cc:441 src/usbwrap_libusb_1_0.cc:477 #: src/usbwrap_libusb_1_0.cc:545 msgid "Failed to perform a complete write" msgstr "" #: src/usbwrap_libusb_1_0.cc:469 msgid "Timeout in BulkWrite (2)" msgstr "" #: src/usbwrap_libusb_1_0.cc:471 msgid "Error in BulkWrite (2)" msgstr "" #: src/usbwrap_libusb_1_0.cc:503 msgid "Timeout in InterruptRead" msgstr "" #: src/usbwrap_libusb_1_0.cc:508 msgid "Error in InterruptRead" msgstr "" #: src/usbwrap_libusb_1_0.cc:536 msgid "Timeout in InterruptWrite" msgstr "" #: src/usbwrap_libusb_1_0.cc:538 msgid "Error in InterruptWrite" msgstr "" #: src/vbase.cc:47 msgid "gmtime_r() failed on time_t of: " msgstr "" #: src/vbase.cc:51 msgid "(null pointer)" msgstr "" #: src/vbase.cc:255 msgid "Cannot construct vBase with null format" msgstr "" #: src/vbase.cc:269 msgid "Cannot set vBase with null format" msgstr "" #: src/vbase.cc:294 src/vbase.cc:315 msgid "resource error allocating vformat attribute" msgstr "" #: src/vcard.cc:141 src/vcard.cc:337 src/vevent.cc:595 src/vevent.cc:683 #: src/vjournal.cc:79 src/vtodo.cc:94 msgid "resource error allocating vformat" msgstr "" #: src/vcard.cc:512 msgid "Unable to parse BDAY field" msgstr "" #: src/vcard.cc:544 msgid "FN and ORG fields both blank in VCARD data" msgstr "" #: src/vevent.cc:72 #, c-format msgid "" "ERROR: recurrence rule contains %s, unsupported by Barry. MIME conversion " "will be incorrect." msgstr "" #: src/vevent.cc:73 src/vevent.cc:87 src/vevent.cc:110 src/vevent.cc:145 #: src/vevent.cc:150 src/vevent.cc:163 src/vevent.cc:469 src/vevent.cc:495 #: src/vevent.cc:556 msgid "Record data so far:\n" msgstr "" #: src/vevent.cc:86 #, c-format msgid "" "Warning: multiple items in BYDAY, not supported by device (%s). Using only " "the first item." msgstr "" #: src/vevent.cc:109 #, c-format msgid "" "Warning: negative week in BYDAY (%d), unsupported by device. Converting to " "positive week, based on 4 week months: %d." msgstr "" #: src/vevent.cc:140 msgid "Called GetDayOfMonthFromBYMONTHDAY() without a BYMONTHDAY" msgstr "" #: src/vevent.cc:144 msgid "Warning: BYMONTHDAY of 0, assuming 1.\n" msgstr "" #: src/vevent.cc:149 #, c-format msgid "Warning: BYMONTHDAY larger than month (%d days). Assuming 1.\n" msgstr "" #: src/vevent.cc:162 #, c-format msgid "" "Warning: negative BYMONTHDAY (%d), unsupported by device. Converting to " "positive day of month: %d." msgstr "" #: src/vevent.cc:274 msgid "Unknown RecurringType in Barry Calendar object" msgstr "" #: src/vevent.cc:414 msgid "Invalid COUNT in recurring rule: " msgstr "" #: src/vevent.cc:468 msgid "" "Warning: WEEKLY VEVENT without a day selected. Assuming day of start time." msgstr "" #: src/vevent.cc:494 msgid "" "Warning: MONTHLY VEVENT without a day type specified (no BYMONTHDAY nor " "BYDAY). Assuming BYMONTHDAY, using day of start time." msgstr "" #: src/vevent.cc:555 msgid "" "Warning: YEARLY VEVENT without a day type specified (no BYMONTHDAY nor " "BYDAY). Assuming BYMONTHDAY, using day and month of start time." msgstr "" #: src/vevent.cc:672 msgid "vCalendar data contains more than one VEVENT block, unsupported" msgstr "" #: src/vevent.cc:723 msgid "Blank DTSTART" msgstr "" #: src/vevent.cc:783 msgid "Unknown TRIGGER VALUE" msgstr "" #: src/vjournal.cc:124 msgid "vCalendar data contains more than one VJOURNAL block, unsupported" msgstr "" #: src/vjournal.cc:135 msgid "resource error allocating vjournal" msgstr "" #: src/vtodo.cc:168 msgid "vCalendar data contains more than one VTODO block, unsupported" msgstr "" #: src/vtodo.cc:179 msgid "resource error allocating vtodo" msgstr "" #: tools/balxparse.cc:65 #, c-format msgid "" "balxparse - Command line ALX parser\n" " Copyright 2009-2010, Nicolas VIVIEN.\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -h This help\n" " -i lang Internationalization language\n" " -d path OS path with all ALX files\n" " -o file OS ALX filename (Platform.alx)\n" "\n" " ...\n" " Parse one or several ALX files.\n" "\n" " Language supported :\n" "\t" msgstr "" #: tools/bcharge.cc:59 tools/bcharge_libusb_1_0.cc:60 #, c-format msgid "" "bcharge - Adjust Blackberry charging modes\n" " Copyright 2006-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" "\n" " -d Set to dual mode (0004)\n" " -o Set a Pearl to old Blackberry mode (0001)\n" " -g Set dual mode only if database interface class 255\n" " is not found\n" "\n" " -h This help message\n" " -p devpath The devpath argument from udev. If specified, will attempt\n" " to adjust USB suspend settings to keep the device charging.\n" " -s path The path where sysfs is mounted. Defaults to '/sys'\n" "\n" msgstr "" #: tools/bcharge.cc:81 #, c-format msgid "" "\n" "usb_control_msg failed: code: %d, %s\n" msgstr "" #: tools/bcharge.cc:139 tools/bcharge_libusb_1_0.cc:149 #, c-format msgid "Can't find Mass Storage interface, assuming 0.\n" msgstr "" #: tools/bcharge.cc:159 #, c-format msgid "usb_detach_kernel_driver_np() failed: %s\n" msgstr "" #: tools/bcharge.cc:162 #, c-format msgid "usb_set_configuration() failed: %s\n" msgstr "" #: tools/bcharge.cc:170 #, c-format msgid "Found device #%s..." msgstr "" #: tools/bcharge.cc:175 #, c-format msgid "unable to open device\n" msgstr "" #: tools/bcharge.cc:183 tools/bcharge_libusb_1_0.cc:196 #, c-format msgid "adjusting charge setting" msgstr "" #: tools/bcharge.cc:188 tools/bcharge_libusb_1_0.cc:201 #, c-format msgid "already at 500mA" msgstr "" #: tools/bcharge.cc:196 tools/bcharge_libusb_1_0.cc:222 #, c-format msgid "...no Pearl mode adjustment" msgstr "" #: tools/bcharge.cc:201 tools/bcharge_libusb_1_0.cc:227 #, c-format msgid "...adjusting Pearl mode to single" msgstr "" #: tools/bcharge.cc:206 tools/bcharge_libusb_1_0.cc:232 #, c-format msgid "...already in classic/single mode" msgstr "" #: tools/bcharge.cc:212 tools/bcharge_libusb_1_0.cc:238 #, c-format msgid "...adjusting Pearl mode to dual" msgstr "" #: tools/bcharge.cc:217 tools/bcharge_libusb_1_0.cc:243 #, c-format msgid "...already in dual mode" msgstr "" #: tools/bcharge.cc:223 tools/bcharge_libusb_1_0.cc:249 #, c-format msgid "...no database iface found, setting dual mode" msgstr "" #: tools/bcharge.cc:228 tools/bcharge_libusb_1_0.cc:254 #, c-format msgid "...found database iface, no change" msgstr "" #: tools/bcharge.cc:260 #, c-format msgid "" "\n" "usb_reset failed: %s\n" msgstr "" #: tools/bcharge.cc:264 tools/bcharge_libusb_1_0.cc:291 #, c-format msgid "...done" msgstr "" #: tools/bcharge.cc:267 tools/bcharge_libusb_1_0.cc:294 #, c-format msgid "...no change" msgstr "" #: tools/bcharge.cc:281 tools/bcharge_libusb_1_0.cc:308 #, c-format msgid "autosuspend adjustment failure: (file: %s): %s\n" msgstr "" #: tools/bcharge.cc:292 tools/bcharge_libusb_1_0.cc:319 #, c-format msgid "autosuspend adjustment failure (write): (file: %s): %s\n" msgstr "" #: tools/bcharge.cc:298 tools/bcharge_libusb_1_0.cc:325 #, c-format msgid "autosuspend adjustment: wrote %s to %s\n" msgstr "" #: tools/bcharge.cc:425 #, c-format msgid "" "\n" "Unable to scan devices: %s\n" msgstr "" #: tools/bcharge.cc:430 tools/bcharge_libusb_1_0.cc:460 tools/breset.cc:67 #: tools/breset_libusb_1_0.cc:82 #, c-format msgid "Scanning for Blackberry devices...\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:82 #, c-format msgid "" "\n" "usb_control_transfer failed: code: %d\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:163 #, c-format msgid "Detecting possible kernel driver conflict, trying to resolve...\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:168 #, c-format msgid "libusb_detach_kernel_driver() failed: %d\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:172 #, c-format msgid "libusb_set_configuration() failed: %d\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:179 #, c-format msgid "Found device #%d-%d..." msgstr "" #: tools/bcharge_libusb_1_0.cc:187 #, c-format msgid "unable to open device, %d\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:207 #, c-format msgid "failed to discover power level\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:214 #, c-format msgid "failed to get device descriptor: %d\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:287 #, c-format msgid "" "\n" "libusb_reset_device() failed: %d\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:453 #, c-format msgid "Failed to start up USB: %d\n" msgstr "" #: tools/bdptest.cc:60 msgid "List of debug files: " msgstr "" #: tools/bfuse.cc:71 #, c-format msgid "" "bfuse - FUSE filesystem for Blackberry databases\n" " Copyright 2008-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" msgstr "" #: tools/bfuse.cc:80 msgid "" "\n" "Barry specific options:\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" msgstr "" #: tools/bfuse.cc:434 tools/bfuse.cc:452 msgid "Constructed != name" msgstr "" #: tools/bfuse.cc:571 msgid "Hello FUSE world. This is Barry. Pleased to meet you.\n" msgstr "" #: tools/bidentify.cc:37 #, c-format msgid "" "bidentify - USB Blackberry Identifier Tool\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -B bus Specify which USB bus to search on\n" " -N dev Specify which system device, using system specific string\n" "\n" " -c If used with -m, show both hex and dec where possible\n" " -m Also show the device's ESN / MEID / IMEI\n" " -s Also show the device's USB serial number (same as shown by " "lsusb)\n" " -h This help\n" " -v Dump protocol data during operation\n" msgstr "" #: tools/bidentify.cc:162 msgid "Error on PIN: " msgstr "" #: tools/bidentify.cc:178 tools/brawchannel.cc:341 msgid "exception caught: " msgstr "" #: tools/bio.cc:68 tools/btool.cc:73 msgid "Compiled with Boost support" msgstr "" #: tools/bio.cc:70 msgid "" "\n" " Options to use for 'boost' type:\n" " -f file Boost serialization filename to read from or write to\n" " Can use - to specify stdin/stdout\n" msgstr "" #: tools/bio.cc:75 tools/btool.cc:76 msgid "Compiled without Boost support" msgstr "" #. TRANSLATORS: the i/o types, such as device, tar, mime, etc. must #. be exact. They are commands that the code tests for. Do not #. translate those particular words. Same with the -w write mode #. options. #: tools/bio.cc:85 #, c-format msgid "" "bio - Barry Input / Output\n" " Copyright 2010-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" " %s\n" "\n" " Usage: bio -i [options...] -o [options...]\n" "\n" " -i type The input type (Builder) to use for producing records\n" " Can be one of: device, tar, %sldif, mime\n" " -o type The output type (Parser) to use for processing records.\n" " Multiple outputs are allowed, as long as they don't\n" " conflict (such as two outputs writing to the same file\n" " or device).\n" " Can be one of: device, tar, %sldif, mime, dump, sha1, cstore\n" "\n" " Options to use for 'device' type:\n" " -d db Name of input database. Can be used multiple times.\n" " -A Add all available device databases, instead of specifying\n" " them manually via -d\n" " -p pin PIN of device to talk to\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -w mode Set write mode when using 'device' for output. Must be\n" " specified, or will not write anything.\n" " Can be one of: erase, overwrite, addonly, addnew\n" "\n" " Options to use for 'tar' backup type:\n" " -d db Name of input database. Can be used multiple times.\n" " Not available in output mode. Note that by default,\n" " all databases in the backup are selected, when reading,\n" " unless at least one -d is specified.\n" " -D db Name of input database to skip. If no -d options are used,\n" " then all databases are automatically selected. Using -D\n" " allows a filtering selection. If -d and -D are used for\n" " the same database, -D takes precedence.\n" " -f file Tar backup file to read from or write to\n" "%s\n" " Options to use for 'ldif' type:\n" " -c dn Convert address book database to LDIF format, using the\n" " specified baseDN\n" " -C dnattr LDIF attribute name to use when building the FQDN\n" " Defaults to 'cn'\n" "\n" " Options to use for 'mime' type:\n" " -f file Filename to read from or write to. Use - to explicitly\n" " specify stdin/stdout, which is default.\n" "\n" " Options to use for 'dump' to stdout output type:\n" " -n Use hex dump parser on all databases.\n" " -T Show only the names of the databases.\n" "\n" " Options to use for 'sha1' sum stdout output type:\n" " -t Include DB Name, Type, and Unique record IDs in the checksums\n" "\n" " Options to use for 'cstore' output type:\n" " -l List filenames only\n" " -f file Filename from the above list, including path.\n" " If found, the file will be written to the current\n" " directory, using the base filename from the device.\n" "\n" " Standalone options:\n" " -h This help\n" " -I cs International charset for string conversions\n" " Valid values here are available with 'iconv --list'\n" " -S Show list of supported database parsers and builders.\n" " Use twice to show field names as well.\n" " -v Dump protocol data during operation\n" "\n" msgstr "" #: tools/bio.cc:178 msgid "Filename not applicable for this mode" msgstr "" #: tools/bio.cc:183 msgid "DB not applicable for this mode" msgstr "" #: tools/bio.cc:188 msgid "DB skipping not applicable for this mode" msgstr "" #: tools/bio.cc:193 msgid "DBs not applicable for this mode" msgstr "" #: tools/bio.cc:198 msgid "PIN not applicable for this mode" msgstr "" #: tools/bio.cc:203 msgid "Password not applicable for this mode" msgstr "" #: tools/bio.cc:208 msgid "Device write behaviour not applicable for this mode" msgstr "" #: tools/bio.cc:213 msgid "DN not applicable for this mode" msgstr "" #: tools/bio.cc:218 msgid "Attribute not applicable for this mode" msgstr "" #: tools/bio.cc:223 msgid "No hex dump option in this mode" msgstr "" #: tools/bio.cc:228 msgid "No name-only option in this mode" msgstr "" #: tools/bio.cc:233 msgid "Including record IDs in the SHA1 sum is not applicable in this mode" msgstr "" #: tools/bio.cc:238 msgid "List option not applicable for this mode" msgstr "" #: tools/bio.cc:256 msgid "Invalid PIN: " msgstr "" #: tools/bio.cc:310 tools/bio.cc:529 tools/btool.cc:817 tools/pppob.cc:271 msgid "PIN not found: " msgstr "" #: tools/bio.cc:312 tools/bio.cc:531 msgid "PIN not specified, and more than one device exists." msgstr "" #: tools/bio.cc:316 tools/bio.cc:535 msgid "" "It seems you are trying to use the same device for multiple input or outputs." msgstr "" #: tools/bio.cc:331 msgid "Database not found: " msgstr "" #: tools/bio.cc:353 msgid "Cannot use stdin as tar source file, sorry." msgstr "" #: tools/bio.cc:523 msgid "" "Warning: the -w switch was not specified: no data will be written to the " "device." msgstr "" #: tools/bio.cc:561 msgid "Cannot use stdout as tar backup file, sorry." msgstr "" #: tools/bio.cc:589 msgid "Boost output requires a specific output file (-f switch)" msgstr "" #: tools/bio.cc:817 msgid " (folder)" msgstr "" #: tools/bio.cc:852 #, c-format msgid "Saving: %s as %s" msgstr "" #: tools/bio.cc:859 msgid "Error during write!" msgstr "" #: tools/bio.cc:968 msgid "" "Unknown device output mode. Must be one of: erase, overwrite, addonly, addnew" msgstr "" #: tools/bio.cc:1157 tools/btarcmp.cc:815 msgid "Exception: " msgstr "" #: tools/bjavaloader.cc:66 #, c-format msgid "" "bjavaloader - Command line USB Blackberry Java Loader\n" " Copyright 2008-2009, Nicolas VIVIEN.\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -A Save all modules found\n" " -a Wipe applications only\n" " -i Wipe filesystem only\n" " -f Force erase, if module is in use\n" " -h This help\n" " -s List sibling in module list\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" "\n" "Commands:\n" "\n" " %s [-s]\n" " Lists modules on the handheld\n" "\n" " %s\n" " Provides information on the handheld\n" "\n" " %s <.cod file> ...\n" " Loads modules onto the handheld\n" "\n" " %s [-A] ...\n" " Retrieves modules from the handheld and writes to .cod file\n" " Note: will overwrite existing files!\n" "\n" " %s [-a | -i]\n" " Wipes the handheld\n" " Use Caution: Wiping filesystem will remove all data\n" " such as messages, contacts, etc.\n" " Wiping applications will remove all .cod files\n" " on the device, including OS .cod files.\n" "\n" " %s\n" " Reset IT policy to factory defaults\n" " Use Caution: Resetting IT policy to factory defaults will\n" " also perform a filesystem wipe which will remove\n" " all data such as messages, contacts, etc.\n" "\n" " %s [-f] ...\n" " Erase module from handheld\n" "\n" " %s\n" " Retrieves the handheld event log\n" "\n" " %s\n" " Clears the handheld event log\n" "\n" " %s\n" " Dump the stack traces for all threads to the event log\n" "\n" " %s <.bmp file>\n" " Make a screenshot of handheld\n" "\n" " %s [%s]\n" " Sets the time on the handheld to the current time\n" " Or the time specified as an argument to %s\n" " If given as argument, current system timezone is assumed\n" msgstr "" #: tools/bjavaloader.cc:173 msgid "Unable to parse time string: " msgstr "" #: tools/bjavaloader.cc:208 msgid "Can't open: " msgstr "" #: tools/bjavaloader.cc:310 tools/bjdwp.cc:104 msgid "missing command" msgstr "" #: tools/bjavaloader.cc:335 tools/bjdwp.cc:124 tools/bjvmdebug.cc:108 #: tools/brawchannel.cc:250 tools/brecsum.cc:123 tools/bwatch.cc:132 msgid "No device selected, or PIN not found" msgstr "" #: tools/bjavaloader.cc:357 msgid "specify at least one .cod file to load" msgstr "" #: tools/bjavaloader.cc:364 msgid "loading: " msgstr "" #: tools/bjavaloader.cc:366 tools/bjavaloader.cc:383 tools/bjavaloader.cc:421 #: tools/bjavaloader.cc:434 msgid "done." msgstr "" #: tools/bjavaloader.cc:371 msgid "specify at least one module to erase" msgstr "" #: tools/bjavaloader.cc:378 msgid "erasing: " msgstr "" #: tools/bjavaloader.cc:388 msgid "specify a .bmp filename" msgstr "" #: tools/bjavaloader.cc:419 tools/bjavaloader.cc:432 msgid "saving: " msgstr "" #: tools/bjavaloader.cc:425 msgid "specify at least one module to save" msgstr "" #. TRANSLATORS: you may translate yes/no as long as you also #. translate "yes" to match. #: tools/bjavaloader.cc:447 #, c-format msgid "" "Use Caution: Wiping filesystem will remove all data\n" " such as messages, contacts, etc.\n" " Wiping applications will remove all .cod files\n" " on the device, including OS .cod files.\n" "\n" "You have selected to wipe the filesystem of device '%s'\n" "Continue with wipe? (yes/no) " msgstr "" #: tools/bjavaloader.cc:459 tools/bjavaloader.cc:475 msgid "Response of 'yes' not received, aborting." msgstr "" #: tools/bjavaloader.cc:464 #, c-format msgid "" "Use Caution: Resetting IT policy to factory defaults will\n" " also perform a filesystem wipe which will remove\n" " all data such as messages, contacts, etc.\n" "\n" "You have selected to reset device '%s' to factory defaults\n" "Continue with wipe? (yes/no) " msgstr "" #: tools/bjavaloader.cc:479 msgid "invalid command: " msgstr "" #: tools/bjavaloader.cc:490 tools/bjdwp.cc:154 tools/bjvmdebug.cc:171 #: tools/brawchannel.cc:333 tools/bs11nread.cc:146 tools/btool.cc:1012 #: tools/bwatch.cc:197 tools/upldif.cc:189 msgid "Usb::Error caught: " msgstr "" #: tools/bjavaloader.cc:495 tools/bjdwp.cc:159 tools/bjvmdebug.cc:176 #: tools/brawchannel.cc:337 tools/bs11nread.cc:150 tools/btool.cc:1016 #: tools/bwatch.cc:202 tools/upldif.cc:192 msgid "Barry::Error caught: " msgstr "" #: tools/bjavaloader.cc:500 tools/bjdwp.cc:164 tools/bjvmdebug.cc:181 #: tools/bs11nread.cc:154 tools/btool.cc:1020 tools/bwatch.cc:207 #: tools/upldif.cc:195 msgid "std::exception caught: " msgstr "" #: tools/bjdwp.cc:44 #, c-format msgid "" "bjdwp - Command line USB Blackberry JDWP\n" " Copyright 2008-2009, Nicolas VIVIEN.\n" " Using: %s\n" "\n" " -h This help\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" "\n" "arguments\n" "\n" "
Interface\n" " Listen port\n" msgstr "" #: tools/bjvmdebug.cc:45 #, c-format msgid "" "bjvmdebug - Command line USB Blackberry Java Debugger\n" " Copyright 2008-2009, Nicolas VIVIEN.\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -h This help\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" msgstr "" #: tools/bjvmdebug.cc:131 msgid "Java Modules List :" msgstr "" #: tools/bjvmdebug.cc:138 msgid "Java Threads currently running :" msgstr "" #: tools/bjvmdebug.cc:162 msgid "JVM message : " msgstr "" #: tools/boostwrap.cc:45 msgid "Archive exception in DoLoadBoostFile(): " msgstr "" #: tools/boostwrap.cc:64 msgid "Archive exception in DoSaveBoostFile(): " msgstr "" #: tools/brawchannel.cc:83 msgid "From BB: " msgstr "" #: tools/brawchannel.cc:95 #, c-format msgid "Written %ld bytes over stdout" msgstr "" #: tools/brawchannel.cc:109 msgid "CallbackHandler: Received error: " msgstr "" #: tools/brawchannel.cc:124 #, c-format msgid "" "brawchannel - Command line USB Blackberry raw channel interface\n" " Copyright 2010, RealVNC Ltd.\n" " Using: %s\n" "\n" "Usage:\n" "brawchannel [options] \n" "\n" " -h This help\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" " This will cause libusb output to appear on STDOUT unless\n" " the environment variable USB_DEBUG is set to 0,1 or 2.\n" msgstr "" #: tools/brawchannel.cc:209 msgid "Error: Missing raw channel name." msgstr "" #: tools/brawchannel.cc:215 msgid "Error: Too many arguments." msgstr "" #: tools/brawchannel.cc:235 msgid "" "Warning: Protocol dump enabled without setting USB_DEBUG to 0, 1 or 2.\n" " libusb might log to STDOUT and ruin data stream." msgstr "" #: tools/brawchannel.cc:257 msgid "Connected to device, starting read/write\n" msgstr "" #: tools/brawchannel.cc:306 msgid "Select failed with errno: " msgstr "" #: tools/brawchannel.cc:315 #, c-format msgid "Sending %ld bytes stdin->USB\n" msgstr "" #: tools/brawchannel.cc:316 msgid "To BB: " msgstr "" #: tools/brawchannel.cc:323 #, c-format msgid "Sent %ld bytes stdin->USB\n" msgstr "" #: tools/brecsum.cc:42 #, c-format msgid "" "brecsum - Generate SHA1 sums of raw Blackberry database records.\n" " Copyright 2008-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -d db Read database 'db' and sum all its records.\n" " Can be used multiple times to fetch more than one DB\n" " -h This help\n" " -i Include DB Name, Type, and Unique record IDs in the checksums\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" msgstr "" #: tools/breset.cc:81 tools/breset_libusb_1_0.cc:105 #, c-format msgid "Found..." msgstr "" #: tools/breset.cc:82 tools/breset_libusb_1_0.cc:106 #, c-format msgid "attempting to reset.\n" msgstr "" #: tools/breset.cc:86 tools/breset_libusb_1_0.cc:110 #, c-format msgid "Can't reset device on bus %s, devnum %u\n" msgstr "" #: tools/breset.cc:91 tools/breset_libusb_1_0.cc:114 #, c-format msgid "%d device%s reset.\n" msgstr "" #: tools/breset_libusb_1_0.cc:79 #, c-format msgid "Failed to start USB: %d\n" msgstr "" #: tools/bs11nread.cc:49 #, c-format msgid "" "bs11nread - Reads a boost serialization file (from btool)\n" " and dumps data to stdout\n" " Copyright 2008-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -f file Filename to save or load handheld data to/from\n" " -h This help\n" " -S Show list of supported database parsers\n" msgstr "" #: tools/bs11nread.cc:76 msgid " records loaded" msgstr "" #: tools/bs11nread.cc:100 msgid "Unknown database name: " msgstr "" #: tools/bs11nread.cc:138 msgid "Filename must be specified" msgstr "" #. TRANSLATORS: the Using: string is followed by the Barry library version #. string. #: tools/btarcmp.cc:56 #, c-format msgid "" "btarcmp - Compare Barry backup tarballs\n" " Copyright 2012-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " Usage: btarcmp [options...] tarball_0 tarball_1\n" "\n" " -b Use brief filename output\n" " -d db Specify a specific database to compare. Can be used\n" " multiple times. If not used at all, all databases are\n" " compared.\n" " -D db Specify a database name to skip. If both -d and -D are\n" " used for the same database name, it will be skipped.\n" " -h This help\n" " -I cs International charset for string conversions\n" " Valid values here are available with 'iconv --list'\n" " -P Only compare records that can be parsed\n" " This is the same as specifying -d for each database\n" " listed with -S.\n" " -S Show list of supported database parsers. Use twice\n" " to show field names as well.\n" " -v Show verbose diff output (twice to force hex output)\n" "\n" msgstr "" #: tools/btarcmp.cc:186 msgid "Different database types in ParsedCompare ctor!" msgstr "" #: tools/btarcmp.cc:461 msgid ": has no database '" msgstr "" #: tools/btarcmp.cc:502 msgid "Comparing non-existant database!" msgstr "" #: tools/btarcmp.cc:532 msgid "record has been deleted in " msgstr "" #: tools/btarcmp.cc:533 msgid "record has been added in " msgstr "" #: tools/btarcmp.cc:542 msgid "Tried to compare records from different databases: " msgstr "" #: tools/btarcmp.cc:569 tools/btarcmp.cc:579 msgid ": differs: " msgstr "" #: tools/btarcmp.cc:571 tools/btarcmp.cc:581 msgid "sizes (" msgstr "" #: tools/btarcmp.cc:573 msgid "), SHA1 sums differ" msgstr "" #: tools/btarcmp.cc:589 msgid "No differences found in parsed records, but SHA1 sums differ." msgstr "" #: tools/btarcmp.cc:596 msgid " Hex diff of record:" msgstr "" #: tools/btarcmp.cc:687 msgid "In database: " msgstr "" #: tools/btardump.cc:42 tools/btool.cc:81 msgid " -V Dump records using MIME vformats where possible" msgstr "" #: tools/btardump.cc:48 #, c-format msgid "" "btardump - Command line parser for Barry backup files\n" " Copyright 2010-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -d db Name of database to dump. Can be used multiple times\n" " to parse multiple databases at once. If not specified\n" " at all, all available databases from the backup are\n" " dumped.\n" " -h This help\n" " -i cs International charset for string conversions\n" " Valid values here are available with 'iconv --list'\n" "%s\n" "\n" " [files...] Backup file(s), created by btool or the backup GUI.\n" msgstr "" #: tools/btardump.cc:132 tools/btool.cc:714 msgid "-V option not supported - no Sync library support available\n" msgstr "" #: tools/btardump.cc:175 msgid "Reading file: " msgstr "" #: tools/btool.cc:74 msgid " -f file Filename to save or load handheld data to/from" msgstr "" #: tools/btool.cc:87 #, c-format msgid "" "btool - Command line USB Blackberry Test Tool\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" " %s\n" "\n" " -b file Filename to save or load a Barry Backup to (tar.gz)\n" " -B bus Specify which USB bus to search on\n" " -N dev Specify which system device, using system specific string\n" "\n" " -a db Erase / clear database 'db' FROM device, deleting all\n" " its records. Can be used multiple times to clear more\n" " than one DB.\n" " -c dn Convert address book database to LDIF format, using the\n" " specified baseDN\n" " -C dnattr LDIF attribute name to use when building the FQDN\n" " Defaults to 'cn'\n" " -d db Load database 'db' FROM device and dump to screen\n" " Can be used multiple times to fetch more than one DB\n" " -e epp Override endpoint pair detection. 'epp' is a single\n" " string separated by a comma, holding the read,write\n" " endpoint pair. Example: -e 83,5\n" " Note: Endpoints are specified in hex.\n" " You should never need to use this option.\n" "%s\n" " -F sort Field name by which to sort the output. Note that the\n" " format of this field is special: 'DBName:field1,field2'\n" " with no spaces unless the spaces are part of the name.\n" " Can be used multiple times, to match your -d options.\n" " Example: -F 'Address Book:Company,LastName,FirstName'\n" " -h This help\n" " -i cs International charset for string conversions\n" " Valid values here are available with 'iconv --list'\n" " -I Sort records before output\n" " -l List devices\n" " -L List Contact field names\n" " -m Map LDIF name to Contact field / Unmap LDIF name\n" " Map: ldif,read,write - maps ldif to read/write Contact " "fields\n" " Unmap: ldif name alone\n" " -M List current LDIF mapping\n" " -n Use null parser on all databases.\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -s db Save database 'db' TO device from data loaded from -f file\n" " -S Show list of supported database parsers. Use twice to\n" " display fields names as well.\n" " -t Show database database table\n" " -T db Show record state table for given database\n" " -v Dump protocol data during operation\n" "%s\n" " -X Reset device\n" " -z Use non-threaded sockets\n" " -Z Use threaded socket router (default)\n" "\n" " -d Command modifiers: (can be used multiple times for more than 1 " "record)\n" "\n" " -r # Record index number as seen in the -T state table.\n" " This overrides the default -d behaviour, and only\n" " downloads the one specified record, sending to stdout.\n" " -R # Same as -r, but also clears the record's dirty flags.\n" " -D # Record index number as seen in the -T state table,\n" " which indicates the record to delete. Used with the -d\n" " command to specify the database.\n" msgstr "" #: tools/btool.cc:196 msgid "Loading: " msgstr "" #: tools/btool.cc:202 msgid " records loaded from '" msgstr "" #: tools/btool.cc:230 #, c-format msgid "" "Store counted %d records read from device, and %d records written to device." msgstr "" #: tools/btool.cc:234 msgid "Saving: " msgstr "" #: tools/btool.cc:239 msgid " records saved to '" msgstr "" #: tools/btool.cc:437 msgid "No Builder available for database" msgstr "" #: tools/btool.cc:477 msgid "Unmapping: " msgstr "" #: tools/btool.cc:481 msgid "Mapping: " msgstr "" #: tools/btool.cc:487 msgid "Read/Write name unknown: " msgstr "" #: tools/btool.cc:491 msgid "Invalid map format: " msgstr "" #: tools/btool.cc:582 msgid "-b option not supported - no Barry Backup library support available\n" msgstr "" #: tools/btool.cc:627 msgid "-f option not supported - no Boost serialization support available\n" msgstr "" #: tools/btool.cc:764 msgid "Unable to set DN Attr: " msgstr "" #: tools/btool.cc:779 msgid "Blackberry device errors with errors during probe:" msgstr "" #: tools/btool.cc:790 msgid "Blackberry devices found:" msgstr "" #: tools/btool.cc:812 tools/pppob.cc:273 msgid "No device selected" msgstr "" #: tools/btool.cc:825 msgid "Using device (PIN): " msgstr "" #: tools/btool.cc:841 msgid "Endpoint pair (read,write) overridden with: " msgstr "" #: tools/btool.cc:922 msgid "No db names to process" msgstr "" #: tools/btool.cc:931 msgid "Record state table for: " msgstr "" #: tools/btool.cc:940 msgid "Must have 1 db name to process" msgstr "" #: tools/btool.cc:952 msgid "Clearing record's dirty flags..." msgstr "" #: tools/btool.cc:982 msgid "No db names to erase" msgstr "" #: tools/btool.cc:990 msgid "Deleting all records from " msgstr "" #: tools/bwatch.cc:47 #, c-format msgid "" "bwatch - View video of BlackBerry screenshots\n" " Copyright 2011, Alberto Mattea\n" " Copyright 2011-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -d delay Delay interval between screenshots, in milliseconds.\n" " The lower the value, the higher the load on the device.\n" " Default is 500ms.\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" msgstr "" #: tools/bwatch.cc:87 msgid "Invalid interval value of: " msgstr "" #: tools/bwatch.cc:87 msgid "Defaulting to 500ms." msgstr "" #: tools/bwatch.cc:137 msgid "Press a key to exit..." msgstr "" #: tools/pppob.cc:58 #, c-format msgid "" "pppob - PPP over Barry\n" " Copyright 2007-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -l file Direct pppob log output to file (useful with -v)\n" " -p pin PIN of device to talk with\n" " If only one device plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -s Use Serial mode instead of IpModem\n" " -t Use a pseudo-tty instead of stdin/stdout\n" " -v Dump protocol data during operation (debugging only!)\n" msgstr "" #: tools/pppob.cc:90 msgid "Error in write()" msgstr "" #: tools/pppob.cc:135 msgid "Read error in ProcessStdin: " msgstr "" #: tools/pppob.cc:212 msgid "Cannot open /dev/ptmx: " msgstr "" #: tools/pppob.cc:218 msgid "Warning: grantpt() failure: " msgstr "" #: tools/pppob.cc:222 msgid "Warning: unlockpt() failure: " msgstr "" #: tools/pppob.cc:280 msgid "Using IpModem mode..." msgstr "" #: tools/pppob.cc:295 msgid "Using Serial mode per command line..." msgstr "" #: tools/pppob.cc:298 msgid "No IpModem mode available, using Serial mode..." msgstr "" #: tools/pppob.cc:321 msgid "Exiting" msgstr "" #: tools/pppob.cc:325 msgid "exception caught in main(): " msgstr "" #: tools/upldif.cc:39 msgid "" "upldif - Command line LDIF uploader\n" " Copyright 2006-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" "\n" " -p pin PIN of device to talk with\n" " If only one device plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -u Do the upload. If not specified, only dumps parsed\n" " LDIF data to stdout.\n" " -v Dump protocol data during operation\n" " -h This help output\n" msgstr "" #: tools/upldif.cc:79 #, c-format msgid "Store counted %d records." msgstr "" #: tools/upldif.cc:173 msgid "Device not found, or not specified" msgstr "" #: tools/util.cc:37 msgid "Supported Database parsers:\n" msgstr "" #: tools/util.cc:41 msgid " (* = can display in vformat MIME mode)\n" msgstr "" #: tools/util.cc:82 msgid "Supported Database builders:\n" msgstr "" barry-0.18.5/po/POTFILES.in0000644001161500056700000000357112242254476014455 0ustar cdfreycdfrey# List of source files which contain translatable strings. src/a_alxparser.cc src/a_application.cc src/a_codsection.cc src/a_library.cc src/a_osloader.cc src/backup.cc src/base64.cc src/bmp.cc src/builder.cc src/cod.cc src/common.cc src/configfile.cc src/configfileunix.cc src/configfilewin32.cc src/connector.cc src/controller.cc src/data.cc src/dataqueue.cc src/dp_codinfo.cc src/dp_parser.cc src/error.cc src/fifoargs.cc src/getpwuidandroid.cc src/iconv.cc src/iconvwin.cc src/j_jdwp.cc src/j_manager.cc src/j_message.cc src/j_record.cc src/j_server.cc src/ldif.cc src/ldifio.cc src/log.cc src/m_desktop.cc src/m_ipmodem.cc src/m_javaloader.cc src/m_jvmdebug.cc src/m_mode_base.cc src/m_raw_channel.cc src/m_serial.cc src/mimeio.cc src/packet.cc src/parser.cc src/pin.cc src/pipe.cc src/pppfilter.cc src/probe.cc src/protocol.cc src/r_bookmark.cc src/r_calendar.cc src/r_calllog.cc src/r_command.cc src/r_contact.cc src/r_cstore.cc src/r_dbdb.cc src/r_folder.cc src/r_hhagent.cc src/r_memo.cc src/r_message_base.cc src/r_recordstate.cc src/r_recur_base.cc src/r_servicebook.cc src/r_sms.cc src/r_task.cc src/r_timezone.cc src/record.cc src/restore.cc src/router.cc src/sha1.cc src/socket.cc src/tarfile-ops-nt.cc src/tarfile.cc src/threadwrap.cc src/time.cc src/tzwrapper.cc src/usbwrap.cc src/usbwrap_libusb.cc src/usbwrap_libusb_1_0.cc src/vbase.cc src/vcard.cc src/version.cc src/vevent.cc src/vjournal.cc src/vtodo.cc src/xmlparser.cc tools/balxparse.cc tools/bcharge.cc tools/bcharge_libusb_1_0.cc tools/bdptest.cc tools/bfuse.cc tools/bidentify.cc tools/bio.cc tools/bjavaloader.cc tools/bjdwp.cc tools/bjvmdebug.cc tools/bktrans.cc tools/boostwrap.cc tools/brawchannel.cc tools/brecsum.cc tools/breset.cc tools/breset_libusb_1_0.cc tools/brimtrans.cc tools/bs11nread.cc tools/btarcmp.cc tools/btardump.cc tools/btool.cc tools/btranslate.cc tools/bwatch.cc tools/pppob.cc tools/upldif.cc tools/util.cc barry-0.18.5/po/quot.sed0000644001161500056700000000023112242254476014353 0ustar cdfreycdfreys/"\([^"]*\)"/“\1”/g s/`\([^`']*\)'/‘\1’/g s/ '\([^`']*\)' / ‘\1’ /g s/ '\([^`']*\)'$/ ‘\1’/g s/^'\([^`']*\)' /‘\1’ /g s/“”/""/g barry-0.18.5/po/Makevars0000644001161500056700000000356712242254476014401 0ustar cdfreycdfrey# Makefile variables for PO directory in any package using GNU gettext. # Usually the message domain is the same as the package name. DOMAIN = $(PACKAGE) # These two variables depend on the location of this directory. subdir = po top_builddir = .. # These options get passed to xgettext. XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ --from-code=UTF-8 --add-comments=TRANSLATORS # This is the copyright holder that gets inserted into the header of the # $(DOMAIN).pot file. Set this to the copyright holder of the surrounding # package. (Note that the msgstr strings, extracted from the package's # sources, belong to the copyright holder of the package.) Translators are # expected to transfer the copyright for their translations to this person # or entity, or to disclaim their copyright. The empty string stands for # the public domain; in this case the translators are expected to disclaim # their copyright. COPYRIGHT_HOLDER = Net Direct, Inc. # This is the email address or URL to which the translators shall report # bugs in the untranslated strings: # - Strings which are not entire sentences, see the maintainer guidelines # in the GNU gettext documentation, section 'Preparing Strings'. # - Strings which use unclear terms or require additional context to be # understood. # - Strings which make invalid assumptions about notation of date, time or # money. # - Pluralisation problems. # - Incorrect English spelling. # - Incorrect formatting. # It can be your email address, or a mailing list address where translators # can write to without being subscribed, or the URL of a web page through # which the translators can contact you. # # See the "contact" page from the URL below: MSGID_BUGS_ADDRESS = http://netdirect.ca/barry # This is the list of locale categories, beyond LC_MESSAGES, for which the # message catalogs shall be used. It is usually empty. EXTRA_LOCALE_CATEGORIES = barry-0.18.5/po/es.po0000644001161500056700000026771312242254476013661 0ustar cdfreycdfrey# Spanish translations for Barry # Copyright (C) 2013 Net Direct, Inc. # This file is distributed under the same license as the Barry package. # Cesar Ballardini , 2012, Spanish translation copyright # msgid "" msgstr "" "Project-Id-Version: barry 0.18.5\n" "Report-Msgid-Bugs-To: http://netdirect.ca/barry\n" "POT-Creation-Date: 2013-04-02 18:53-0400\n" "PO-Revision-Date: 2012-06-12 22:33-0300\n" "Last-Translator: Cesar Ballardini \n" "Language-Team: es\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/a_application.cc:59 msgid " Application " msgstr "" #: src/a_application.cc:60 src/a_library.cc:60 msgid " ID : " msgstr "" #: src/a_application.cc:61 src/a_library.cc:61 msgid " Description : " msgstr "" #: src/a_application.cc:62 src/a_library.cc:62 msgid " Vendor : " msgstr "" #: src/a_application.cc:63 src/a_library.cc:63 msgid " Copyright : " msgstr "" #: src/a_application.cc:64 src/a_library.cc:64 msgid " Required : " msgstr "" #: src/a_application.cc:64 src/a_library.cc:64 msgid "Yes" msgstr "" #: src/a_application.cc:64 src/a_library.cc:64 msgid "No" msgstr "" #: src/a_application.cc:68 src/a_library.cc:68 msgid " Files : " msgstr "" #: src/a_library.cc:59 msgid " Library " msgstr "" #: src/a_osloader.cc:74 msgid "Could not opendir: " msgstr "" #: src/a_osloader.cc:97 msgid "Cannot open ALX file: " msgstr "" #: src/a_osloader.cc:111 msgid "OS Properties :" msgstr "" #: src/a_osloader.cc:123 msgid "SFI File :" msgstr "" #: src/a_osloader.cc:127 msgid "Applications :" msgstr "" #: src/a_osloader.cc:137 msgid "Libraries :" msgstr "" #: src/backup.cc:84 msgid "Backup: No database name available" msgstr "" #: src/backup.cc:86 msgid "Backup: No unique ID available!" msgstr "" #: src/bmp.cc:80 msgid "ScreenshotToRGB: depth must be 24 or 32" msgstr "" #: src/bmp.cc:100 msgid "" "ScreenshotToRGB: Screenshot data size is too small for given width+height" msgstr "" #: src/bmp.cc:102 msgid "" "ScreenshotToRGB: Screenshot depth is not supported (Barry supports 2 byte or " "4 byte pixels in device screenshots)" msgstr "" #: src/bmp.cc:162 msgid "" "ScreenshotToRGB: bad switch value, should never happen. Double check the " "data_size check." msgstr "" #: src/bmp.cc:196 msgid "Screenshot data size is too small for given width+height" msgstr "" #: src/builder.cc:54 msgid "DBDataBuilder: offset greater than size" msgstr "" #: src/cod.cc:61 msgid "SeekNextCod: EOF while reading file signature" msgstr "" #: src/cod.cc:70 msgid "SeekNextCod: EOF while reading PKZIP header" msgstr "" #: src/cod.cc:76 msgid "SeekNextCod: EOF while skipping unused fields" msgstr "" #: src/cod.cc:89 msgid "SeekNextCod: seek to end failed" msgstr "" #: src/cod.cc:95 msgid "SeekNextCod: seek to start failed" msgstr "" #: src/cod.cc:101 msgid "SeekNextCod: unknown COD file signature" msgstr "" #: src/common.cc:79 msgid "USB library failed to initialise with libusb error: " msgstr "" #: src/common.cc:80 msgid "Failed to initialise USB" msgstr "" #: src/configfile.cc:50 msgid "DBListType dump:\n" msgstr "" #: src/configfile.cc:77 src/configfile.cc:95 msgid "Configfile: empty pin" msgstr "" #: src/configfile.cc:193 src/configfile.cc:394 msgid "Unable to open file for writing: " msgstr "" #: src/configfile.cc:219 src/configfile.cc:411 msgid "Error during write. Config may be incomplete." msgstr "" #: src/configfile.cc:329 msgid "App name must have no spaces." msgstr "" #: src/configfile.cc:420 src/configfile.cc:433 msgid "Cannot use SetKey() without specifying an appname in the constructor." msgstr "" #: src/configfile.cc:423 msgid "SetKey values may not contain newline characters." msgstr "" #: src/configfileunix.cc:91 src/configfileunix.cc:151 msgid "BuildFilename: getpwuid failed" msgstr "" #: src/configfileunix.cc:116 src/configfilewin32.cc:118 msgid "ConfigFile::CheckPath(): path is empty!" msgstr "" #: src/configfileunix.cc:130 msgid "mkdir() failed to create: " msgstr "" #: src/configfileunix.cc:139 msgid "last mkdir() failed to create: " msgstr "" #: src/configfilewin32.cc:84 src/configfilewin32.cc:163 msgid "BuildFilename: SHGetSpecialFolderPath failed" msgstr "" #: src/configfilewin32.cc:87 src/configfilewin32.cc:104 #: src/configfilewin32.cc:166 msgid "BuildFilename: conversion failed" msgstr "" #: src/configfilewin32.cc:101 msgid "BuildDefaultPath: SHGetSpecialFolderPath failed" msgstr "" #: src/configfilewin32.cc:125 msgid "Failed to convert to widechar" msgstr "" #: src/configfilewin32.cc:148 msgid "failed to create directory" msgstr "" #: src/connector.cc:185 msgid "Timeout in Connector::Reconnect()... trying again" msgstr "" #: src/controller.cc:52 msgid "Controller: Using non-threaded sockets" msgstr "" #: src/controller.cc:73 msgid "Controller: Using threaded socket router" msgstr "" #: src/controller.cc:86 msgid "Controller: GetConfiguration failed" msgstr "" #: src/controller.cc:91 msgid "Controller: SetConfiguration failed" msgstr "" #: src/controller.cc:146 msgid "Controller: explicit mode name too long" msgstr "" #: src/controller.cc:179 msgid "Controller: No channel name given with RawChannel mode" msgstr "" #: src/controller.cc:183 msgid "Controller: Invalid mode in SelectMode" msgstr "" #: src/controller.cc:200 msgid "Controller: requested mode not supported" msgstr "" #: src/controller.cc:204 msgid "Controller: mode not selected" msgstr "" #: src/controller.cc:211 msgid "Controller: error setting desktop mode" msgstr "" #: src/data.cc:293 msgid "Data::ReleaseBuffer() argument must be -1 or >= 0" msgstr "" #: src/data.cc:295 msgid "Data::ReleaseBuffer() must be called after GetBuffer()" msgstr "" #: src/data.cc:297 msgid "" "Data::ReleaseBuffer() must be called with a size smaller than the original " "buffer requested" msgstr "" #: src/data.cc:489 msgid "sizes differ: " msgstr "" #: src/dp_codinfo.cc:171 src/m_jvmdebug.cc:89 msgid " UniqueID " msgstr "" #: src/dp_codinfo.cc:172 msgid " Module Name " msgstr "" #: src/dp_codinfo.cc:173 msgid " File Name " msgstr "" #: src/error.cc:58 msgid "Bad packet size, not enough data: " msgstr "" #: src/error.cc:59 src/error.cc:68 msgid "DataSize(): " msgstr "" #: src/error.cc:60 src/error.cc:69 msgid "Required size: " msgstr "" #: src/error.cc:67 msgid "Bad packet size. Packet: " msgstr "" #: src/fifoargs.cc:105 msgid "Cannot open Barry argument fifo" msgstr "" #: src/j_jdwp.cc:94 msgid "Timeout in read" msgstr "" #: src/j_jdwp.cc:96 msgid "Error in read" msgstr "" #: src/j_jdwp.cc:117 msgid "Timeout in write (1)" msgstr "" #: src/j_jdwp.cc:119 msgid "Error in write (1)" msgstr "" #: src/j_jdwp.cc:137 msgid "Timeout in write (2)" msgstr "" #: src/j_jdwp.cc:139 msgid "Error in write (2)" msgstr "" #: src/j_server.cc:91 msgid "HOST_NOT_FOUND: The specified host is unknown" msgstr "" #: src/j_server.cc:94 msgid "NO_ADDRESS: The requested name is valid but does not have an IP address" msgstr "" #: src/j_server.cc:97 msgid "NO_RECOVERY: A non-recoverable name server error occurred" msgstr "" #: src/j_server.cc:100 msgid "" "TRY_AGAIN: A temporary error occurred on an authoritative name server. Try " "again later." msgstr "" #: src/j_server.cc:103 msgid "Unknown network error code" msgstr "" #: src/j_server.cc:142 msgid "JDWServer::Start: Cannot open socket." msgstr "" #: src/j_server.cc:154 msgid "JDWServer::Start: Cannot bind socket" msgstr "" #: src/j_server.cc:164 msgid "JDWServer::Start: Cannot listen on socket" msgstr "" #: src/j_server.cc:237 msgid "No debug information found for: " msgstr "" #: src/j_server.cc:321 src/j_server.cc:350 msgid "Packet size error !!!" msgstr "" #: src/j_server.cc:491 msgid "Commandset unknown !!!" msgstr "" #: src/ldif.cc:39 msgid "Email address" msgstr "" #: src/ldif.cc:41 src/r_calllog.cc:84 msgid "Phone number" msgstr "" #: src/ldif.cc:43 msgid "Fax number" msgstr "" #: src/ldif.cc:45 msgid "Work phone number" msgstr "" #: src/ldif.cc:47 msgid "Home phone number" msgstr "" #: src/ldif.cc:49 msgid "Mobile phone number" msgstr "" #: src/ldif.cc:51 msgid "Pager number" msgstr "" #: src/ldif.cc:53 src/r_contact.cc:118 src/r_contact.cc:503 #: src/r_hhagent.cc:69 src/r_hhagent.cc:105 src/r_hhagent.cc:290 msgid "PIN" msgstr "" #: src/ldif.cc:55 msgid "First name" msgstr "" #: src/ldif.cc:57 msgid "Last name" msgstr "" #: src/ldif.cc:59 msgid "Company name" msgstr "" #: src/ldif.cc:61 msgid "Default communications method" msgstr "" #: src/ldif.cc:63 msgid "Work Address, line 1" msgstr "" #: src/ldif.cc:65 msgid "Work Address, line 2" msgstr "" #: src/ldif.cc:67 msgid "Work Address, line 3" msgstr "" #: src/ldif.cc:69 src/r_contact.cc:128 msgid "WorkCity" msgstr "" #: src/ldif.cc:71 msgid "WorkProvince / State" msgstr "" #: src/ldif.cc:73 msgid "Work Postal / ZIP code" msgstr "" #: src/ldif.cc:75 src/r_contact.cc:131 msgid "WorkCountry" msgstr "" #: src/ldif.cc:77 src/r_contact.cc:487 msgid "Job Title" msgstr "" #: src/ldif.cc:79 msgid "Public key" msgstr "" #: src/ldif.cc:81 src/r_calendar.cc:107 src/r_calendar.cc:434 #: src/r_contact.cc:139 src/r_contact.cc:509 src/r_task.cc:108 #: src/r_task.cc:399 msgid "Notes" msgstr "" #: src/ldif.cc:83 msgid "Contact photo" msgstr "" #: src/ldif.cc:85 msgid "" "Mailing Work address (includes address lines, city, province, country, and " "postal code)" msgstr "" #: src/ldif.cc:87 msgid "" "Mailing home address (includes address lines, city, province, country, and " "postal code)" msgstr "" #: src/ldif.cc:89 msgid "First + Last names" msgstr "" #: src/ldif.cc:91 msgid "Fully qualified domain name" msgstr "" #: src/ldif.cc:213 src/ldif.cc:222 msgid "" msgstr "" #: src/ldif.cc:437 src/r_calllog.cc:338 src/r_message_base.cc:391 msgid "unknown" msgstr "" #: src/ldif.cc:782 msgid "ContactLdif Mapping:\n" msgstr "" #: src/ldif.cc:801 msgid " >>> DN attribute: " msgstr "" #: src/m_desktop.cc:89 msgid "Desktop: error getting command table" msgstr "" #: src/m_desktop.cc:139 msgid "Desktop: database name not found: " msgstr "" #: src/m_desktop.cc:162 msgid "Desktop: unknown command type" msgstr "" #: src/m_desktop.cc:167 msgid "Desktop: unable to get command code: " msgstr "" #: src/m_desktop.cc:188 src/m_desktop.cc:214 src/m_desktop.cc:251 #: src/m_desktop.cc:301 src/m_desktop.cc:336 src/m_desktop.cc:355 #: src/m_desktop.cc:406 src/m_desktop.cc:431 src/m_desktop.cc:440 #: src/m_desktop.cc:490 msgid "Database ID: " msgstr "" #: src/m_desktop.cc:226 src/m_desktop.cc:316 src/m_desktop.cc:448 msgid "Desktop: device responded with unexpected packet command code: " msgstr "" #: src/m_desktop.cc:232 src/m_desktop.cc:322 src/m_desktop.cc:454 msgid "Desktop: device responded with error code (command: " msgstr "" #: src/m_desktop.cc:233 src/m_desktop.cc:323 src/m_desktop.cc:417 #: src/m_desktop.cc:455 msgid "code: " msgstr "" #: src/m_desktop.cc:266 msgid "Desktop: invalid response packet size of: " msgstr "" #: src/m_desktop.cc:275 msgid "Desktop: unexpected command of " msgstr "" #: src/m_desktop.cc:277 msgid " instead of expected " msgstr "" #: src/m_desktop.cc:301 msgid "Index: " msgstr "" #: src/m_desktop.cc:307 msgid "Desktop: no data available in SetRecord" msgstr "" #: src/m_desktop.cc:415 msgid "Desktop: could not clear database: (command: " msgstr "" #: src/m_desktop.cc:425 msgid "Desktop: error clearing database, bad response" msgstr "" #: src/m_desktop.cc:670 msgid "This database does not exist in device: " msgstr "" #: src/m_desktop.cc:670 msgid "Dropping record." msgstr "" #: src/m_desktop.cc:700 src/m_desktop.cc:757 msgid "DeviceParser: unknown mode" msgstr "" #: src/m_ipmodem.cc:60 msgid "Exception caught in IpModem destructor, ignoring: " msgstr "" #: src/m_ipmodem.cc:68 msgid "Logic error: No password provided in SendPassword." msgstr "" #: src/m_ipmodem.cc:80 msgid "No password provided." msgstr "" #: src/m_ipmodem.cc:149 src/socket.cc:481 msgid "Password rejected by device." msgstr "" #: src/m_ipmodem.cc:198 msgid "Exception in IpModem::DataReadThread: " msgstr "" #: src/m_ipmodem.cc:220 msgid "IP Modem not supported by this device: " msgstr "" #: src/m_ipmodem.cc:260 src/socket.cc:467 #, c-format msgid "" "Fewer than %d password tries remaining in device. Refusing to proceed, to " "avoid device zapping itself. Use a Windows client, or re-cradle the device." msgstr "" #: src/m_ipmodem.cc:267 src/m_ipmodem.cc:299 src/m_ipmodem.cc:338 msgid "IpModem: Error sending password." msgstr "" #: src/m_ipmodem.cc:332 msgid "This device requested a password." msgstr "" #: src/m_ipmodem.cc:346 msgid "This device requires a password." msgstr "" #: src/m_ipmodem.cc:366 msgid "IpModem: Error creating USB read thread." msgstr "" #: src/m_javaloader.cc:242 msgid "JLEventlogEntry:Parse bad guid field" msgstr "" #: src/m_javaloader.cc:247 msgid "JLEventlogEntry:Parse bad time field" msgstr "" #: src/m_javaloader.cc:254 msgid "JLEventlogEntry:Parse bad severity field" msgstr "" #: src/m_javaloader.cc:261 msgid "JLEventlogEntry:Parse bad type field" msgstr "" #: src/m_javaloader.cc:266 msgid "JLEventlogEntry:Parse bad app field" msgstr "" #: src/m_javaloader.cc:274 msgid "JLEventlogEntry:Parse bad data field" msgstr "" #: src/m_javaloader.cc:301 msgid "Always Log" msgstr "" #: src/m_javaloader.cc:302 msgid "Severe Error" msgstr "" #: src/m_javaloader.cc:303 src/r_calllog.cc:266 msgid "Error" msgstr "" #: src/m_javaloader.cc:304 msgid "Warning" msgstr "" #: src/m_javaloader.cc:305 msgid "Information" msgstr "" #: src/m_javaloader.cc:306 msgid "Debug Info" msgstr "" #: src/m_javaloader.cc:310 msgid "Number" msgstr "" #: src/m_javaloader.cc:311 msgid "String" msgstr "" #: src/m_javaloader.cc:312 msgid "Exception" msgstr "" #: src/m_javaloader.cc:315 msgid "guid:" msgstr "" #: src/m_javaloader.cc:316 msgid " time:" msgstr "" #: src/m_javaloader.cc:317 msgid " severity:" msgstr "" #: src/m_javaloader.cc:318 msgid " type:" msgstr "" #: src/m_javaloader.cc:319 msgid " app:" msgstr "" #: src/m_javaloader.cc:320 msgid " data:" msgstr "" #: src/m_javaloader.cc:331 msgid "Hardware Id:" msgstr "" #: src/m_javaloader.cc:334 msgid "PIN:" msgstr "" #: src/m_javaloader.cc:337 msgid "OS Version:" msgstr "" #: src/m_javaloader.cc:340 msgid "VM Version:" msgstr "" #: src/m_javaloader.cc:343 msgid "Radio ID:" msgstr "" #: src/m_javaloader.cc:346 msgid "Vendor ID:" msgstr "" #: src/m_javaloader.cc:350 msgid "Active Wireless Access Families:" msgstr "" #: src/m_javaloader.cc:353 msgid "OS Metrics:" msgstr "" #: src/m_javaloader.cc:356 msgid "Bootrom Metrics:" msgstr "" #: src/m_javaloader.cc:409 msgid "JavaLoader::StartStream Hello" msgstr "" #: src/m_javaloader.cc:416 msgid "JavaLoader::StartStream Unknown1" msgstr "" #: src/m_javaloader.cc:467 msgid "JavaLoader::SendStream: set code size first" msgstr "" #: src/m_javaloader.cc:475 msgid "JavaLoader::SendStream: input stream read failed" msgstr "" #: src/m_javaloader.cc:482 msgid "JavaLoader::SendStream: not enough memory to install the application" msgstr "" #: src/m_javaloader.cc:486 msgid "JavaLoader::SendStream: send data" msgstr "" #: src/m_javaloader.cc:538 msgid "JavaLoader::StopStream error" msgstr "" #: src/m_javaloader.cc:552 msgid "JavaLoader::SetTime error" msgstr "" #: src/m_javaloader.cc:559 src/m_jvmdebug.cc:260 msgid "unexpected packet command code: " msgstr "" #: src/m_javaloader.cc:723 msgid "JavaLoader::GetScreenShot expect" msgstr "" #: src/m_javaloader.cc:746 msgid "JavaLoader::DoErase: module not found: " msgstr "" #: src/m_javaloader.cc:754 msgid "JavaLoader::DoErase: expected code ID not available" msgstr "" #: src/m_javaloader.cc:766 msgid "JavaLoader::DoErase: COD file in use." msgstr "" #: src/m_javaloader.cc:898 msgid "JavaLoader::Save: module not found: " msgstr "" #: src/m_javaloader.cc:907 msgid "JavaLoader::Save: expected module ID, but not available" msgstr "" #: src/m_jvmdebug.cc:88 msgid " ID " msgstr "" #: src/m_jvmdebug.cc:90 msgid " Module Name" msgstr "" #: src/m_jvmdebug.cc:152 msgid " Thread " msgstr "" #: src/m_jvmdebug.cc:153 msgid " Address " msgstr "" #: src/m_jvmdebug.cc:154 msgid " Byte " msgstr "" #: src/m_jvmdebug.cc:155 msgid " Unknown01 " msgstr "" #: src/m_jvmdebug.cc:156 msgid " Unknown02 " msgstr "" #: src/m_jvmdebug.cc:157 msgid " Unknown03 " msgstr "" #: src/m_jvmdebug.cc:158 msgid " Unknown04 " msgstr "" #: src/m_jvmdebug.cc:159 msgid " Unknown05 " msgstr "" #: src/m_jvmdebug.cc:160 msgid " Unknown06 " msgstr "" #: src/m_jvmdebug.cc:291 src/m_jvmdebug.cc:321 src/m_jvmdebug.cc:351 #: src/m_jvmdebug.cc:381 src/m_jvmdebug.cc:411 src/m_jvmdebug.cc:441 #: src/m_jvmdebug.cc:471 src/m_jvmdebug.cc:501 src/m_jvmdebug.cc:531 #: src/m_jvmdebug.cc:561 src/m_jvmdebug.cc:595 src/m_jvmdebug.cc:641 #: src/m_jvmdebug.cc:686 src/m_jvmdebug.cc:741 src/m_jvmdebug.cc:802 #: src/m_jvmdebug.cc:843 src/m_jvmdebug.cc:873 src/m_jvmdebug.cc:904 #: src/m_jvmdebug.cc:931 src/m_jvmdebug.cc:959 src/m_jvmdebug.cc:1001 #: src/m_jvmdebug.cc:1034 msgid "byte count mismatch" msgstr "" #: src/m_mode_base.cc:142 msgid "Socket alreay open in RetryPassword" msgstr "" #: src/m_raw_channel.cc:116 msgid "RawChannel: No routing queue set in controller" msgstr "" #: src/m_raw_channel.cc:165 msgid "RawChannel: Got packet not for socket-zero" msgstr "" #: src/m_raw_channel.cc:183 src/m_raw_channel.cc:186 msgid "RawChannel: Got unexpected socket zero packet" msgstr "" #: src/m_raw_channel.cc:205 msgid "RawChannel: Received data to handle when in non-callback mode" msgstr "" #: src/m_raw_channel.cc:212 msgid "RawChannel: Socket error received, what: " msgstr "" #: src/m_raw_channel.cc:245 msgid "RawChannel: send data size larger than MaximumPacketSize" msgstr "" #: src/m_raw_channel.cc:268 msgid "RawChannel: Receive called when channel was created with a callback" msgstr "" #: src/m_raw_channel.cc:293 msgid "RawChannel: Data size doesn't match packet size" msgstr "" #: src/m_serial.cc:45 msgid "" "A SocketRoutingQueue is required in the Controller class when using Mode::" "Serial." msgstr "" #: src/m_serial.cc:156 msgid "Must call Open() before Write() in Mode::Serial" msgstr "" #: src/packet.cc:465 msgid "Attempting to extract a return code from the wrong response packet type" msgstr "" #: src/parser.cc:62 msgid "Records for database: " msgstr "" #: src/parser.cc:66 tools/bfuse.cc:128 msgid "Raw record dump for record: " msgstr "" #: src/parser.cc:68 msgid "type: " msgstr "" #: src/parser.cc:70 msgid "offset: " msgstr "" #: src/probe.cc:95 msgid "Probe: Parse data failure: " msgstr "" #: src/probe.cc:172 #, c-format msgid "Probe logged %u exception messages:" msgstr "" #: src/probe.cc:195 msgid "Usb::Error exception caught: " msgstr "" #: src/probe.cc:224 msgid "Probe: No device descriptor for BlackBerry config (config id: " msgstr "" #: src/probe.cc:236 #, c-format msgid "Probe: Interface with BLACKBERRY_DB_CLASS (%u) not found." msgstr "" #: src/probe.cc:248 msgid "Probe: endpoint invalid." msgstr "" #: src/probe.cc:250 msgid "true" msgstr "" #: src/probe.cc:250 msgid "false" msgstr "" #: src/probe.cc:271 msgid "Probe: GetConfiguration failed" msgstr "" #: src/probe.cc:275 msgid "Probe: SetConfiguration failed" msgstr "" #: src/probe.cc:293 msgid "" "Probe: probing endpoints failed, retrying after setting alternate interface" msgstr "" #: src/probe.cc:318 msgid "Unable to discover endpoint pair for one device." msgstr "" #: src/probe.cc:366 msgid "Probe: Skipping non-bulk endpoint pair (offset: " msgstr "" #: src/probe.cc:418 msgid "Probe: Intro(0) failed, retrying after clearing halt" msgstr "" #: src/probe.cc:426 msgid "Probe: Intro(0) still failed after clearing halt" msgstr "" #: src/probe.cc:448 msgid "Probe: unable to fetch PIN" msgstr "" #: src/probe.cc:460 msgid "Probe: unable to fetch description" msgstr "" #: src/probe.cc:567 msgid "Device ID: " msgstr "" #: src/probe.cc:568 msgid "PIN: " msgstr "" #: src/probe.cc:569 msgid "Description: " msgstr "" #: src/probe.cc:571 msgid "Name: " msgstr "" #: src/r_bookmark.cc:275 msgid "Bookmark::ParseField: BookmarkType is not 'D'" msgstr "" #: src/r_bookmark.cc:325 src/r_bookmark.cc:331 src/r_bookmark.cc:337 #: src/r_bookmark.cc:418 src/r_bookmark.cc:424 msgid "Automatic" msgstr "" #: src/r_bookmark.cc:326 src/r_bookmark.cc:332 src/r_bookmark.cc:425 msgid "Enabled" msgstr "" #: src/r_bookmark.cc:327 src/r_bookmark.cc:333 src/r_bookmark.cc:426 msgid "Disabled" msgstr "" #: src/r_bookmark.cc:328 src/r_bookmark.cc:334 src/r_bookmark.cc:341 #: src/r_bookmark.cc:421 src/r_bookmark.cc:427 src/r_calllog.cc:276 #: src/r_calllog.cc:404 src/r_folder.cc:265 src/r_message_base.cc:361 #: src/r_message_base.cc:368 src/r_sms.cc:283 msgid "Unknown" msgstr "" #: src/r_bookmark.cc:338 msgid "BlackBerry" msgstr "" #: src/r_bookmark.cc:339 msgid "FireFox" msgstr "" #: src/r_bookmark.cc:340 msgid "Internet Explorer" msgstr "" #: src/r_bookmark.cc:344 msgid "Bookmark entry: " msgstr "" #: src/r_bookmark.cc:346 msgid "index " msgstr "" #: src/r_bookmark.cc:349 msgid " Name: " msgstr "" #: src/r_bookmark.cc:351 msgid " Icon: " msgstr "" #: src/r_bookmark.cc:353 msgid " Url: " msgstr "" #: src/r_bookmark.cc:354 msgid " Display mode: " msgstr "" #: src/r_bookmark.cc:356 msgid " JavaScript mode: " msgstr "" #: src/r_bookmark.cc:358 msgid " Browser Identity: " msgstr "" #: src/r_bookmark.cc:401 msgid "Record Type" msgstr "" #: src/r_bookmark.cc:402 src/r_calendar.cc:430 src/r_calllog.cc:380 #: src/r_cstore.cc:229 src/r_folder.cc:210 src/r_hhagent.cc:284 #: src/r_memo.cc:268 src/r_message_base.cc:334 src/r_servicebook.cc:447 #: src/r_sms.cc:280 src/r_task.cc:396 src/r_timezone.cc:227 msgid "Unique Record ID" msgstr "" #: src/r_bookmark.cc:404 msgid "Bookmark Field Index" msgstr "" #: src/r_bookmark.cc:406 msgid "Site Name" msgstr "" #: src/r_bookmark.cc:407 msgid "Site Icon" msgstr "" #: src/r_bookmark.cc:408 msgid "Site URL" msgstr "" #: src/r_bookmark.cc:410 msgid "Browser Identity" msgstr "" #: src/r_bookmark.cc:411 msgid "Auto detect browser" msgstr "" #: src/r_bookmark.cc:412 msgid "BlackBerry browser" msgstr "" #: src/r_bookmark.cc:413 msgid "FireFox browser" msgstr "" #: src/r_bookmark.cc:414 msgid "Internet Explorer browser" msgstr "" #: src/r_bookmark.cc:415 msgid "Unknown browser" msgstr "" #: src/r_bookmark.cc:417 msgid "Display Mode" msgstr "" #: src/r_bookmark.cc:419 msgid "Column" msgstr "" #: src/r_bookmark.cc:420 msgid "Page" msgstr "" #: src/r_bookmark.cc:423 msgid "JavaScript Mode" msgstr "" #: src/r_bookmark.cc:429 src/r_calendar.cc:458 src/r_calllog.cc:412 #: src/r_contact.cc:553 src/r_cstore.cc:236 src/r_folder.cc:231 #: src/r_hhagent.cc:298 src/r_memo.cc:274 src/r_message_base.cc:370 #: src/r_servicebook.cc:462 src/r_sms.cc:312 src/r_task.cc:425 #: src/r_timezone.cc:238 msgid "Unknown Fields" msgstr "" #: src/r_calendar.cc:106 src/r_calendar.cc:433 src/r_message_base.cc:86 #: src/r_message_base.cc:342 msgid "Subject" msgstr "" #: src/r_calendar.cc:108 src/r_calendar.cc:435 msgid "Location" msgstr "" #: src/r_calendar.cc:109 msgid "Notification Time" msgstr "" #: src/r_calendar.cc:110 src/r_calendar.cc:438 src/r_task.cc:109 #: src/r_task.cc:403 msgid "Start Time" msgstr "" #: src/r_calendar.cc:111 src/r_calendar.cc:439 msgid "End Time" msgstr "" #: src/r_calendar.cc:112 src/r_calendar.cc:440 msgid "Organizer" msgstr "" #: src/r_calendar.cc:113 src/r_calendar.cc:441 msgid "Accepted By" msgstr "" #: src/r_calendar.cc:114 src/r_calendar.cc:442 msgid "Invited" msgstr "" #: src/r_calendar.cc:115 src/r_calllog.cc:86 src/r_folder.cc:85 #: src/r_hhagent.cc:71 src/r_hhagent.cc:76 src/r_hhagent.cc:81 #: src/r_hhagent.cc:90 src/r_hhagent.cc:95 src/r_hhagent.cc:108 #: src/r_memo.cc:52 src/r_message_base.cc:89 src/r_servicebook.cc:55 #: src/r_servicebook.cc:254 src/r_servicebook.cc:261 src/r_servicebook.cc:270 #: src/r_task.cc:112 src/r_timezone.cc:60 msgid "End of List" msgstr "" #: src/r_calendar.cc:212 msgid "Calendar::ParseField: unknown appointment type" msgstr "" #: src/r_calendar.cc:227 msgid "Calendar::ParseField: not enough data in time zone code field" msgstr "" #: src/r_calendar.cc:233 msgid "Calendar::ParseField: FreeBusyFlag out of range" msgstr "" #: src/r_calendar.cc:243 msgid "Calendar::ParseField: size data unknown in calendar field" msgstr "" #: src/r_calendar.cc:249 msgid "Calendar::ParseField: ClassFlag out of range" msgstr "" #: src/r_calendar.cc:429 src/r_calllog.cc:379 src/r_contact.cc:480 #: src/r_cstore.cc:228 src/r_folder.cc:209 src/r_hhagent.cc:283 #: src/r_memo.cc:267 src/r_message_base.cc:333 src/r_servicebook.cc:446 #: src/r_sms.cc:279 src/r_task.cc:395 src/r_timezone.cc:226 msgid "Record Type Code" msgstr "" #: src/r_calendar.cc:432 msgid "All Day Event" msgstr "" #: src/r_calendar.cc:436 msgid "Notification Time (0 is off)" msgstr "" #: src/r_calendar.cc:444 msgid "Free or Busy Flag" msgstr "" #: src/r_calendar.cc:445 src/r_calendar.cc:486 msgid "Free" msgstr "" #: src/r_calendar.cc:446 src/r_calendar.cc:487 msgid "Tentative" msgstr "" #: src/r_calendar.cc:447 src/r_calendar.cc:488 src/r_calllog.cc:265 #: src/r_calllog.cc:395 src/usbwrap_libusb_1_0.cc:103 msgid "Busy" msgstr "" #: src/r_calendar.cc:448 src/r_calendar.cc:489 msgid "Out of Office" msgstr "" #: src/r_calendar.cc:450 msgid "Event Class" msgstr "" #: src/r_calendar.cc:451 src/r_calendar.cc:481 msgid "Public" msgstr "" #: src/r_calendar.cc:452 src/r_calendar.cc:482 src/r_message_base.cc:367 msgid "Confidential" msgstr "" #: src/r_calendar.cc:453 src/r_calendar.cc:483 src/r_message_base.cc:366 msgid "Private" msgstr "" #: src/r_calendar.cc:455 src/r_task.cc:406 msgid "Time Zone Code" msgstr "" #: src/r_calendar.cc:456 msgid "Time Zone Validity" msgstr "" #: src/r_calendar.cc:463 src/r_calendar.cc:598 msgid "Calendar ID" msgstr "" #: src/r_calendar.cc:492 msgid " Calendar ID: " msgstr "" #: src/r_calendar.cc:494 msgid " All Day Event: " msgstr "" #: src/r_calendar.cc:495 msgid " Class: " msgstr "" #: src/r_calendar.cc:496 msgid " Free/Busy: " msgstr "" #: src/r_calendar.cc:498 src/r_task.cc:486 msgid " Time Zone: " msgstr "" #: src/r_calendar.cc:509 msgid "Calendar entry: " msgstr "" #: src/r_calendar.cc:528 msgid "disabled" msgstr "" #: src/r_calendar.cc:601 msgid "Mail Account" msgstr "" #: src/r_calendar.cc:640 msgid "CalendarAll::ParseField: size data unknown in calendar field" msgstr "" #: src/r_calendar.cc:653 msgid "CalendarAll::ParseHeader: size data unknown in calendar field" msgstr "" #: src/r_calendar.cc:673 msgid " Mail Account: " msgstr "" #: src/r_calllog.cc:85 msgid "Contact name" msgstr "" #: src/r_calllog.cc:114 msgid "CallLog::ParseField: CallLogType is not 'p'" msgstr "" #: src/r_calllog.cc:167 msgid "CallLog::ParseField: direction field out of bounds" msgstr "" #: src/r_calllog.cc:258 src/r_sms.cc:284 msgid "Received" msgstr "" #: src/r_calllog.cc:259 src/r_folder.cc:221 src/r_folder.cc:252 #: src/r_sms.cc:285 msgid "Sent" msgstr "" #: src/r_calllog.cc:260 msgid "Call Missing (Messagerie)" msgstr "" #: src/r_calllog.cc:261 msgid "Call Missing" msgstr "" #: src/r_calllog.cc:264 src/r_calllog.cc:394 msgid "OK" msgstr "" #: src/r_calllog.cc:267 src/r_calllog.cc:280 msgid "Not supported by Barry" msgstr "" #: src/r_calllog.cc:270 src/r_calllog.cc:400 src/r_calllog.cc:407 msgid "Undefined" msgstr "" #: src/r_calllog.cc:271 msgid "Known phone number" msgstr "" #: src/r_calllog.cc:272 msgid "Unknown phone number" msgstr "" #: src/r_calllog.cc:273 msgid "Private phone number" msgstr "" #: src/r_calllog.cc:277 src/r_calllog.cc:401 msgid "Office" msgstr "" #: src/r_calllog.cc:278 src/r_calllog.cc:402 msgid "Home" msgstr "" #: src/r_calllog.cc:279 src/r_calllog.cc:403 msgid "Mobile" msgstr "" #: src/r_calllog.cc:283 msgid "CallLog entry: " msgstr "" #: src/r_calllog.cc:287 msgid " Timestamp: " msgstr "" #: src/r_calllog.cc:288 msgid " Direction: " msgstr "" #: src/r_calllog.cc:290 src/r_task.cc:481 msgid " Status: " msgstr "" #: src/r_calllog.cc:292 msgid " Phone info: " msgstr "" #: src/r_calllog.cc:294 msgid " Phone type: " msgstr "" #: src/r_calllog.cc:297 msgid " Duration: " msgstr "" #: src/r_calllog.cc:312 msgid " days " msgstr "" #: src/r_calllog.cc:314 msgid " day " msgstr "" #: src/r_calllog.cc:382 msgid "Duration of Call in Seconds" msgstr "" #: src/r_calllog.cc:383 msgid "Timestamp of Call in Milliseconds" msgstr "" #: src/r_calllog.cc:384 msgid "Contact Name" msgstr "" #: src/r_calllog.cc:385 msgid "Phone Number" msgstr "" #: src/r_calllog.cc:387 msgid "Direction of Call" msgstr "" #: src/r_calllog.cc:388 msgid "Received Call" msgstr "" #: src/r_calllog.cc:389 msgid "Placed the Call" msgstr "" #: src/r_calllog.cc:390 msgid "Failed Call" msgstr "" #: src/r_calllog.cc:391 msgid "Missed Call" msgstr "" #: src/r_calllog.cc:393 msgid "Status of Call" msgstr "" #: src/r_calllog.cc:396 msgid "Network Error" msgstr "" #: src/r_calllog.cc:397 msgid "Unsupported Status" msgstr "" #: src/r_calllog.cc:399 msgid "Phone Type" msgstr "" #: src/r_calllog.cc:406 msgid "Phone Info" msgstr "" #: src/r_calllog.cc:408 msgid "Phone Number is Set" msgstr "" #: src/r_calllog.cc:409 msgid "Phone Number Not Set" msgstr "" #: src/r_calllog.cc:410 msgid "Phone Number is Private" msgstr "" #: src/r_command.cc:99 msgid "Command table:\n" msgstr "" #: src/r_command.cc:101 msgid " Command: " msgstr "" #: src/r_contact.cc:109 src/r_contact.cc:490 msgid "Nickname" msgstr "" #: src/r_contact.cc:110 msgid "Phone" msgstr "" #: src/r_contact.cc:111 msgid "Fax" msgstr "" #: src/r_contact.cc:112 msgid "HomeFax" msgstr "" #: src/r_contact.cc:113 msgid "WorkPhone" msgstr "" #: src/r_contact.cc:114 msgid "HomePhone" msgstr "" #: src/r_contact.cc:115 msgid "MobilePhone" msgstr "" #: src/r_contact.cc:116 msgid "MobilePhone2" msgstr "" #: src/r_contact.cc:117 src/r_contact.cc:502 msgid "Pager" msgstr "" #: src/r_contact.cc:119 src/r_contact.cc:504 msgid "Radio" msgstr "" #: src/r_contact.cc:120 msgid "WorkPhone2" msgstr "" #: src/r_contact.cc:121 msgid "HomePhone2" msgstr "" #: src/r_contact.cc:122 msgid "OtherPhone" msgstr "" #: src/r_contact.cc:123 src/r_contact.cc:486 msgid "Company" msgstr "" #: src/r_contact.cc:124 msgid "DefaultCommMethod" msgstr "" #: src/r_contact.cc:125 msgid "WorkAddress1" msgstr "" #: src/r_contact.cc:126 msgid "WorkAddress2" msgstr "" #: src/r_contact.cc:127 msgid "WorkAddress3" msgstr "" #: src/r_contact.cc:129 msgid "WorkProvince" msgstr "" #: src/r_contact.cc:130 msgid "WorkPostalCode" msgstr "" #: src/r_contact.cc:132 msgid "JobTitle" msgstr "" #: src/r_contact.cc:133 msgid "PublicKey" msgstr "" #: src/r_contact.cc:134 src/r_contact.cc:508 msgid "URL" msgstr "" #: src/r_contact.cc:135 src/r_contact.cc:488 msgid "Prefix" msgstr "" #: src/r_contact.cc:136 msgid "HomeAddress1" msgstr "" #: src/r_contact.cc:137 msgid "HomeAddress2" msgstr "" #: src/r_contact.cc:138 msgid "HomeAddress3" msgstr "" #: src/r_contact.cc:140 msgid "UserDefined1" msgstr "" #: src/r_contact.cc:141 msgid "UserDefined2" msgstr "" #: src/r_contact.cc:142 msgid "UserDefined3" msgstr "" #: src/r_contact.cc:143 msgid "UserDefined4" msgstr "" #: src/r_contact.cc:144 msgid "HomeCity" msgstr "" #: src/r_contact.cc:145 msgid "HomeProvince" msgstr "" #: src/r_contact.cc:146 msgid "HomePostalCode" msgstr "" #: src/r_contact.cc:147 msgid "HomeCountry" msgstr "" #: src/r_contact.cc:148 src/r_contact.cc:514 msgid "Image" msgstr "" #: src/r_contact.cc:149 msgid "EndOfList" msgstr "" #: src/r_contact.cc:298 msgid "" "A contact record must contain either a First/Last name, or a Company name." msgstr "" #: src/r_contact.cc:319 msgid "Contact must have name or company name." msgstr "" #: src/r_contact.cc:481 src/r_servicebook.cc:454 src/r_servicebook.cc:496 msgid "Unique ID" msgstr "" #: src/r_contact.cc:482 msgid "Email Addresses" msgstr "" #: src/r_contact.cc:484 msgid "First Name" msgstr "" #: src/r_contact.cc:485 msgid "Last Name" msgstr "" #: src/r_contact.cc:491 msgid "Phone (deprecated)" msgstr "" #: src/r_contact.cc:492 msgid "Work Fax" msgstr "" #: src/r_contact.cc:493 msgid "Home Fax" msgstr "" #: src/r_contact.cc:494 msgid "Work Phone" msgstr "" #: src/r_contact.cc:496 msgid "Work Phone 2" msgstr "" #: src/r_contact.cc:497 msgid "Home Phone" msgstr "" #: src/r_contact.cc:498 msgid "Home Phone 2" msgstr "" #: src/r_contact.cc:499 msgid "Mobile Phone" msgstr "" #: src/r_contact.cc:500 msgid "Mobile Phone 2" msgstr "" #: src/r_contact.cc:501 msgid "Other Phone" msgstr "" #: src/r_contact.cc:505 msgid "Default Communications Method" msgstr "" #: src/r_contact.cc:507 msgid "Public Key" msgstr "" #: src/r_contact.cc:510 msgid "User Defined Field 1" msgstr "" #: src/r_contact.cc:511 msgid "User Defined Field 2" msgstr "" #: src/r_contact.cc:512 msgid "User Defined Field 3" msgstr "" #: src/r_contact.cc:513 msgid "User Defined Field 4" msgstr "" #: src/r_contact.cc:516 msgid "Birthday" msgstr "" #: src/r_contact.cc:517 msgid "Anniversary" msgstr "" #: src/r_contact.cc:519 msgid "Work Address" msgstr "" #: src/r_contact.cc:520 msgid "Work Address 1" msgstr "" #: src/r_contact.cc:522 msgid "Work Address 2" msgstr "" #: src/r_contact.cc:524 msgid "Work Address 3" msgstr "" #: src/r_contact.cc:526 msgid "Work City" msgstr "" #: src/r_contact.cc:528 msgid "Work Province" msgstr "" #: src/r_contact.cc:530 msgid "Work Postal Code" msgstr "" #: src/r_contact.cc:532 msgid "Work Country" msgstr "" #: src/r_contact.cc:535 msgid "Home Address" msgstr "" #: src/r_contact.cc:536 msgid "Home Address 1" msgstr "" #: src/r_contact.cc:538 msgid "Home Address 2" msgstr "" #: src/r_contact.cc:540 msgid "Home Address 3" msgstr "" #: src/r_contact.cc:542 msgid "Home City" msgstr "" #: src/r_contact.cc:544 msgid "Home Province" msgstr "" #: src/r_contact.cc:546 msgid "Home Postal Code" msgstr "" #: src/r_contact.cc:548 msgid "Home Country" msgstr "" #: src/r_contact.cc:551 src/r_memo.cc:272 src/r_task.cc:400 msgid "Categories" msgstr "" #: src/r_contact.cc:601 msgid "Contact: " msgstr "" #: src/r_contact.cc:605 msgid "FirstName" msgstr "" #: src/r_contact.cc:607 msgid "LastName" msgstr "" #: src/r_contact.cc:614 msgid " Email : " msgstr "" #: src/r_contact.cc:646 msgid " Categories : " msgstr "" #: src/r_contact.cc:651 msgid " Birthday : " msgstr "" #: src/r_contact.cc:654 msgid " Anniversary : " msgstr "" #: src/r_contact.cc:661 msgid " GroupLinks:\n" msgstr "" #: src/r_contact.cc:663 msgid " ID: " msgstr "" #: src/r_contact.cc:669 msgid " Photo image:\n" msgstr "" #: src/r_contact.cc:748 msgid "" "Error: Cannot convert complex name+address to a simple contact email " "address, skipping: " msgstr "" #: src/r_cstore.cc:150 msgid "Content Store must have a name." msgstr "" #: src/r_cstore.cc:153 msgid "Content Store item without any data." msgstr "" #: src/r_cstore.cc:231 msgid "File or Folder Name" msgstr "" #: src/r_cstore.cc:232 msgid "Folder Flag" msgstr "" #: src/r_cstore.cc:233 msgid "File Content" msgstr "" #: src/r_cstore.cc:234 msgid "File Descriptor" msgstr "" #: src/r_cstore.cc:253 msgid "ContentStore: " msgstr "" #: src/r_cstore.cc:256 msgid " Filename: " msgstr "" #: src/r_cstore.cc:257 msgid " Folder: " msgstr "" #: src/r_cstore.cc:258 msgid " BB Size: " msgstr "" #: src/r_cstore.cc:259 msgid " Actual Size: " msgstr "" #: src/r_cstore.cc:260 msgid " Descriptor:\n" msgstr "" #: src/r_cstore.cc:262 msgid " Content:\n" msgstr "" #: src/r_dbdb.cc:118 msgid "DatabaseDatabase: not enough data for parsing" msgstr "" #: src/r_dbdb.cc:123 msgid "Unknown protocol" msgstr "" #: src/r_dbdb.cc:197 msgid "Database database:\n" msgstr "" #: src/r_dbdb.cc:199 msgid " Database: " msgstr "" #: src/r_dbdb.cc:200 msgid "records: " msgstr "" #: src/r_folder.cc:84 msgid "FolderName" msgstr "" #: src/r_folder.cc:212 msgid "Folder Name" msgstr "" #: src/r_folder.cc:213 msgid "Order Number" msgstr "" #: src/r_folder.cc:214 msgid "Folder Level" msgstr "" #: src/r_folder.cc:216 msgid "Folder Type" msgstr "" #: src/r_folder.cc:217 src/r_folder.cc:248 msgid "Subtree" msgstr "" #: src/r_folder.cc:218 src/r_folder.cc:249 src/r_sms.cc:296 msgid "Deleted" msgstr "" #: src/r_folder.cc:219 src/r_folder.cc:250 msgid "Inbox" msgstr "" #: src/r_folder.cc:220 src/r_folder.cc:251 msgid "Outbox" msgstr "" #: src/r_folder.cc:222 src/r_folder.cc:253 src/usbwrap_libusb_1_0.cc:117 msgid "Other" msgstr "" #: src/r_folder.cc:223 src/r_sms.cc:286 msgid "Draft" msgstr "" #: src/r_folder.cc:257 msgid "" "Folder Records\n" "\n" msgstr "" #: src/r_folder.cc:258 msgid "Folder Name: " msgstr "" #: src/r_folder.cc:259 msgid "Folder Type: " msgstr "" #: src/r_folder.cc:263 msgid "Draft\n" msgstr "" #: src/r_folder.cc:266 msgid "Folder Number: " msgstr "" #: src/r_folder.cc:267 msgid "Folder Level: " msgstr "" #: src/r_hhagent.cc:65 src/r_hhagent.cc:86 src/r_hhagent.cc:100 #: src/r_hhagent.cc:288 msgid "Model" msgstr "" #: src/r_hhagent.cc:66 src/r_hhagent.cc:101 src/r_hhagent.cc:292 msgid "Network" msgstr "" #: src/r_hhagent.cc:67 src/r_hhagent.cc:103 src/r_hhagent.cc:289 msgid "Bands" msgstr "" #: src/r_hhagent.cc:68 src/r_hhagent.cc:104 src/r_hhagent.cc:287 msgid "MEID/ESN" msgstr "" #: src/r_hhagent.cc:70 src/r_hhagent.cc:106 src/r_hhagent.cc:291 msgid "Version" msgstr "" #: src/r_hhagent.cc:87 src/r_hhagent.cc:102 src/r_hhagent.cc:296 msgid "Manufacturer" msgstr "" #: src/r_hhagent.cc:88 msgid "Firmware" msgstr "" #: src/r_hhagent.cc:89 src/r_hhagent.cc:107 msgid "Platform" msgstr "" #: src/r_hhagent.cc:140 msgid "HandheldAgent requires SetIds() to be called before ParseField()" msgstr "" #: src/r_hhagent.cc:295 msgid "Platform Version" msgstr "" #: src/r_hhagent.cc:306 msgid "Handheld Agent: " msgstr "" #: src/r_hhagent.cc:314 msgid "HandheldAgent entry: " msgstr "" #: src/r_memo.cc:50 src/r_memo.cc:270 msgid "Title" msgstr "" #: src/r_memo.cc:51 src/r_memo.cc:271 src/r_message_base.cc:87 #: src/r_message_base.cc:343 src/r_sms.cc:310 msgid "Body" msgstr "" #: src/r_memo.cc:80 msgid "Memo::ParseField: MemoType is not 'm'" msgstr "" #: src/r_memo.cc:209 msgid "Memo entry: " msgstr "" #: src/r_memo.cc:211 msgid " Title: " msgstr "" #: src/r_memo.cc:212 msgid " Body: " msgstr "" #: src/r_memo.cc:227 msgid " Categories: " msgstr "" #: src/r_message_base.cc:80 src/r_message_base.cc:337 msgid "To" msgstr "" #: src/r_message_base.cc:81 msgid "Cc" msgstr "" #: src/r_message_base.cc:82 msgid "Bcc" msgstr "" #: src/r_message_base.cc:83 src/r_message_base.cc:340 msgid "Sender" msgstr "" #: src/r_message_base.cc:84 src/r_message_base.cc:336 msgid "From" msgstr "" #: src/r_message_base.cc:85 msgid "ReplyTo" msgstr "" #: src/r_message_base.cc:88 src/r_message_base.cc:344 msgid "Attachment" msgstr "" #: src/r_message_base.cc:278 msgid "MessageBase::BuildHeader not yet implemented" msgstr "" #: src/r_message_base.cc:283 msgid "MessageBase::BuildFields not yet implemented" msgstr "" #: src/r_message_base.cc:338 msgid "CC" msgstr "" #: src/r_message_base.cc:339 msgid "BCC" msgstr "" #: src/r_message_base.cc:341 msgid "Reply To" msgstr "" #: src/r_message_base.cc:346 msgid "Message Record ID" msgstr "" #: src/r_message_base.cc:347 msgid "Message Reply To" msgstr "" #: src/r_message_base.cc:348 msgid "Date Sent" msgstr "" #: src/r_message_base.cc:349 msgid "Date Received" msgstr "" #: src/r_message_base.cc:351 msgid "Truncated" msgstr "" #: src/r_message_base.cc:352 msgid "Read" msgstr "" #: src/r_message_base.cc:353 msgid "Reply" msgstr "" #: src/r_message_base.cc:354 src/r_sms.cc:295 msgid "Saved" msgstr "" #: src/r_message_base.cc:355 msgid "Saved Deleted" msgstr "" #: src/r_message_base.cc:357 src/r_task.cc:413 msgid "Priority" msgstr "" #: src/r_message_base.cc:358 src/r_task.cc:416 src/r_task.cc:445 msgid "Low" msgstr "" #: src/r_message_base.cc:359 src/r_message_base.cc:364 src/r_task.cc:415 #: src/r_task.cc:444 msgid "Normal" msgstr "" #: src/r_message_base.cc:360 src/r_task.cc:414 src/r_task.cc:443 msgid "High" msgstr "" #: src/r_message_base.cc:363 msgid "Sensitivity" msgstr "" #: src/r_message_base.cc:365 msgid "Personal" msgstr "" #: src/r_recordstate.cc:131 msgid " Index RecordId Dirty RecType" msgstr "" #: src/r_recordstate.cc:141 src/r_recur_base.cc:279 tools/bjavaloader.cc:455 #: tools/bjavaloader.cc:471 msgid "yes" msgstr "" #: src/r_recordstate.cc:141 src/r_recur_base.cc:279 msgid "no" msgstr "" #: src/r_recur_base.cc:91 msgid "RecurBase::ParseField: not enough data in recurrence data field" msgstr "" #: src/r_recur_base.cc:157 msgid "Unknown recurrence data type" msgstr "" #: src/r_recur_base.cc:172 msgid "" "RecurBase::BuildRecurrenceData: Attempting to build recurrence data on non-" "recurring record." msgstr "" #: src/r_recur_base.cc:226 msgid "RecurBase::BuildRecurrenceData: Unknown recurrence data type" msgstr "" #: src/r_recur_base.cc:251 src/r_recur_base.cc:323 msgid "Sun" msgstr "" #: src/r_recur_base.cc:252 src/r_recur_base.cc:324 msgid "Mon" msgstr "" #: src/r_recur_base.cc:253 src/r_recur_base.cc:325 msgid "Tue" msgstr "" #: src/r_recur_base.cc:254 src/r_recur_base.cc:326 msgid "Wed" msgstr "" #: src/r_recur_base.cc:255 src/r_recur_base.cc:327 msgid "Thu" msgstr "" #: src/r_recur_base.cc:256 src/r_recur_base.cc:328 msgid "Fri" msgstr "" #: src/r_recur_base.cc:257 src/r_recur_base.cc:329 msgid "Sat" msgstr "" #: src/r_recur_base.cc:260 src/r_timezone.cc:257 msgid "Jan" msgstr "" #: src/r_recur_base.cc:261 src/r_timezone.cc:258 msgid "Feb" msgstr "" #: src/r_recur_base.cc:262 src/r_timezone.cc:259 msgid "Mar" msgstr "" #: src/r_recur_base.cc:263 src/r_timezone.cc:260 msgid "Apr" msgstr "" #: src/r_recur_base.cc:264 src/r_timezone.cc:261 msgid "May" msgstr "" #: src/r_recur_base.cc:265 src/r_timezone.cc:262 msgid "Jun" msgstr "" #: src/r_recur_base.cc:266 src/r_timezone.cc:263 msgid "Jul" msgstr "" #: src/r_recur_base.cc:267 src/r_timezone.cc:264 msgid "Aug" msgstr "" #: src/r_recur_base.cc:268 src/r_timezone.cc:265 msgid "Sep" msgstr "" #: src/r_recur_base.cc:269 src/r_timezone.cc:266 msgid "Oct" msgstr "" #: src/r_recur_base.cc:270 src/r_timezone.cc:267 msgid "Nov" msgstr "" #: src/r_recur_base.cc:271 src/r_timezone.cc:268 msgid "Dec" msgstr "" #: src/r_recur_base.cc:279 msgid " Recurring: " msgstr "" #: src/r_recur_base.cc:284 msgid " Every day.\n" msgstr "" #. TRANSLATORS: to remove the 'th' ending on numbers, #. just replace the %s with %.0s in this string. #: src/r_recur_base.cc:290 #, c-format msgid " Every month on the %u%s" msgstr "" #: src/r_recur_base.cc:300 #, c-format msgid " Every month on the %s of week %u" msgstr "" #: src/r_recur_base.cc:307 #, c-format msgid " Every year on %s %u" msgstr "" #: src/r_recur_base.cc:314 #, c-format msgid " Every year in %s on %s of week %u" msgstr "" #: src/r_recur_base.cc:322 msgid " Every week on: " msgstr "" #: src/r_recur_base.cc:334 msgid " Unknown recurrence type\n" msgstr "" #: src/r_recur_base.cc:338 msgid " Interval: " msgstr "" #: src/r_recur_base.cc:341 msgid " Ends: never\n" msgstr "" #: src/r_recur_base.cc:343 msgid " Ends: " msgstr "" #: src/r_servicebook.cc:182 msgid "ServiceBookConfig::Build not yet implemented" msgstr "" #: src/r_servicebook.cc:195 msgid " ServiceBookConfig Format: " msgstr "" #: src/r_servicebook.cc:216 msgid " ------------------- End of Config Field\n" msgstr "" #: src/r_servicebook.cc:251 msgid "Old Name" msgstr "" #: src/r_servicebook.cc:252 msgid "Old Desc" msgstr "" #: src/r_servicebook.cc:253 msgid "Old UniqueId" msgstr "" #: src/r_servicebook.cc:258 src/r_servicebook.cc:449 src/r_servicebook.cc:492 #: src/r_timezone.cc:59 msgid "Name" msgstr "" #: src/r_servicebook.cc:259 src/r_servicebook.cc:451 src/r_servicebook.cc:494 msgid "Description" msgstr "" #: src/r_servicebook.cc:260 msgid "UniqueId" msgstr "" #: src/r_servicebook.cc:266 src/r_servicebook.cc:450 src/r_servicebook.cc:493 msgid "Hidden Name" msgstr "" #: src/r_servicebook.cc:267 src/r_servicebook.cc:452 src/r_servicebook.cc:495 msgid "DSID" msgstr "" #: src/r_servicebook.cc:268 msgid "ContentId" msgstr "" #: src/r_servicebook.cc:269 src/r_servicebook.cc:453 msgid "BES Domain" msgstr "" #: src/r_servicebook.cc:423 msgid "ServiceBook::BuildFields not yet implemented" msgstr "" #: src/r_servicebook.cc:455 src/r_servicebook.cc:497 msgid "Content ID" msgstr "" #: src/r_servicebook.cc:489 msgid "ServiceBook entry: " msgstr "" #: src/r_servicebook.cc:498 msgid "(BES) Domain" msgstr "" #: src/r_sms.cc:282 msgid "Message Status" msgstr "" #: src/r_sms.cc:288 msgid "Delivery Status" msgstr "" #: src/r_sms.cc:289 msgid "No Report" msgstr "" #: src/r_sms.cc:290 msgid "Failed" msgstr "" #: src/r_sms.cc:291 msgid "Succeeded" msgstr "" #: src/r_sms.cc:293 msgid "Is New?" msgstr "" #: src/r_sms.cc:294 msgid "New Conversation" msgstr "" #: src/r_sms.cc:297 msgid "Opened" msgstr "" #: src/r_sms.cc:299 msgid "Timestamp in Milliseconds" msgstr "" #: src/r_sms.cc:300 msgid "Service Center Timestamp" msgstr "" #: src/r_sms.cc:302 msgid "Data Coding Scheme" msgstr "" #: src/r_sms.cc:303 msgid "7bit" msgstr "" #: src/r_sms.cc:304 msgid "8bit" msgstr "" #: src/r_sms.cc:305 msgid "UCS2" msgstr "" #: src/r_sms.cc:307 msgid "Error ID" msgstr "" #: src/r_sms.cc:309 msgid "Addresses" msgstr "" #: src/r_sms.cc:322 msgid "Unknown destination" msgstr "" #: src/r_sms.cc:329 msgid "SMS record: " msgstr "" #: src/r_sms.cc:332 msgid "Timestamp: " msgstr "" #: src/r_sms.cc:336 msgid "Service Center Timestamp: " msgstr "" #: src/r_sms.cc:340 msgid "Send Error: " msgstr "" #: src/r_sms.cc:345 msgid "Received From:\n" msgstr "" #: src/r_sms.cc:348 msgid "Sent to:\n" msgstr "" #: src/r_sms.cc:351 msgid "Draft for:\n" msgstr "" #: src/r_sms.cc:354 msgid "Unknown status for:\n" msgstr "" #: src/r_sms.cc:364 msgid "New " msgstr "" #: src/r_sms.cc:366 msgid "Opened " msgstr "" #: src/r_sms.cc:368 msgid "Saved " msgstr "" #: src/r_sms.cc:370 msgid "Deleted " msgstr "" #: src/r_sms.cc:371 msgid "Message" msgstr "" #: src/r_sms.cc:371 msgid " that starts a new conversation" msgstr "" #: src/r_sms.cc:373 msgid "Content: " msgstr "" #: src/r_task.cc:107 src/r_task.cc:398 msgid "Summary" msgstr "" #: src/r_task.cc:110 src/r_task.cc:404 msgid "Due Time" msgstr "" #: src/r_task.cc:111 src/r_task.cc:405 msgid "Alarm Time" msgstr "" #: src/r_task.cc:140 msgid "Task::ParseField: Task Type is not 't'" msgstr "" #: src/r_task.cc:171 src/r_task.cc:180 msgid "Task::ParseField: priority field out of bounds" msgstr "" #: src/r_task.cc:193 msgid "Task::ParseField: not enough data in time zone code field" msgstr "" #: src/r_task.cc:213 msgid "Task::ParseField: AlarmType out of bounds" msgstr "" #: src/r_task.cc:401 msgid "UID" msgstr "" #: src/r_task.cc:407 msgid "Time Zone Code Valid" msgstr "" #: src/r_task.cc:409 msgid "Alarm Type" msgstr "" #: src/r_task.cc:410 msgid "Date" msgstr "" #: src/r_task.cc:411 src/r_task.cc:457 msgid "Relative" msgstr "" #: src/r_task.cc:418 msgid "Status" msgstr "" #: src/r_task.cc:419 src/r_task.cc:448 msgid "Not Started" msgstr "" #: src/r_task.cc:420 src/r_task.cc:449 msgid "In Progress" msgstr "" #: src/r_task.cc:421 src/r_task.cc:450 msgid "Completed" msgstr "" #: src/r_task.cc:422 src/r_task.cc:451 msgid "Waiting" msgstr "" #: src/r_task.cc:423 src/r_task.cc:452 msgid "Deferred" msgstr "" #: src/r_task.cc:455 msgid "None" msgstr "" #: src/r_task.cc:456 msgid "By Date" msgstr "" #: src/r_task.cc:460 msgid "Task entry: " msgstr "" #: src/r_task.cc:480 msgid " Priority: " msgstr "" #: src/r_task.cc:483 msgid " Alarm Type: " msgstr "" #: src/r_task.cc:494 msgid " Categories: " msgstr "" #: src/r_timezone.cc:111 msgid "TimeZone::ParseField: TimeZone Type is not valid" msgstr "" #: src/r_timezone.cc:229 msgid "TimeZone Name" msgstr "" #: src/r_timezone.cc:230 msgid "Index" msgstr "" #: src/r_timezone.cc:231 msgid "TimeZone Offset in Minutes" msgstr "" #: src/r_timezone.cc:232 msgid "Use DST?" msgstr "" #: src/r_timezone.cc:233 msgid "DST Offset" msgstr "" #: src/r_timezone.cc:234 msgid "Start Month" msgstr "" #: src/r_timezone.cc:235 msgid "End Month" msgstr "" #: src/r_timezone.cc:236 msgid "TimeZone Type" msgstr "" #: src/r_timezone.cc:271 msgid "TimeZone entry: " msgstr "" #: src/r_timezone.cc:289 msgid " Desc: " msgstr "" #: src/r_timezone.cc:290 msgid " Index: " msgstr "" #: src/r_timezone.cc:291 msgid " Type: " msgstr "" #: src/r_timezone.cc:292 msgid " Offset: " msgstr "" #: src/r_timezone.cc:292 msgid " minutes " msgstr "" #: src/r_timezone.cc:294 msgid " Split Offset: hours: " msgstr "" #: src/r_timezone.cc:295 msgid ", minutes: " msgstr "" #: src/r_timezone.cc:296 msgid " Sample TZ: " msgstr "" #: src/r_timezone.cc:297 msgid " Use DST: " msgstr "" #: src/r_timezone.cc:299 msgid " DST Offset: " msgstr "" #: src/r_timezone.cc:301 msgid "Start Month: " msgstr "" #: src/r_timezone.cc:303 msgid "Start Month: unknown (" msgstr "" #: src/r_timezone.cc:305 msgid " End Month: " msgstr "" #: src/r_timezone.cc:307 msgid " End Month: unknown (" msgstr "" #: src/record.cc:253 msgid " Unknowns:\n" msgstr "" #: src/record.cc:255 msgid " Type: " msgstr "" #: src/record.cc:257 msgid " Data:\n" msgstr "" #: src/record.cc:459 msgid "NULL time pointer passed to Date::FromTm" msgstr "" #: src/record.cc:591 msgid "Enum value not found in constant list" msgstr "" #: src/record.cc:642 msgid "Different database types in DBNamedFieldCmp" msgstr "" #: src/record.cc:647 msgid "Unknown database in DBNamedFieldCmp::operator()" msgstr "" #: src/restore.cc:184 msgid "Skipping: " msgstr "" #: src/restore.cc:298 msgid "Skipping invalid tar record: " msgstr "" #: src/restore.cc:358 msgid "Invalid state in Restore::BuildRecord()" msgstr "" #: src/restore.cc:410 msgid "Invalid state in Restore::FetchRecord()" msgstr "" #: src/router.cc:198 msgid "SimpleReadThread received uncaught exception: " msgstr "" #: src/router.cc:198 msgid " what: " msgstr "" #: src/router.cc:201 msgid "SimpleReadThread recevied uncaught exception of unknown type" msgstr "" #: src/router.cc:211 msgid "SocketRoutingQueue Leftovers: " msgstr "" #: src/router.cc:213 msgid " packet(s) for socket: " msgstr "" #: src/router.cc:343 msgid "RegisterInterest requesting a previously registered socket." msgstr "" #: src/router.cc:422 msgid "SocketRead requested data from unregistered socket." msgstr "" #: src/router.cc:616 msgid "SocketRoutingQueue: Error creating USB read thread." msgstr "" #: src/socket.cc:123 msgid "Socket: Whole packet too short to fragment" msgstr "" #: src/socket.cc:170 msgid "Socket: invalid sequence packet" msgstr "" #: src/socket.cc:183 #, c-format msgid "" "Socket 0x%x: out of sequence. (Global sequence: 0x%x. Packet sequence: 0x%x)" msgstr "" #: src/socket.cc:293 msgid "SocketZero: No device available for RawSend" msgstr "" #: src/socket.cc:324 msgid "" "SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)" msgstr "" #: src/socket.cc:338 msgid "Multiple pushbacks in SocketZero!" msgstr "" #: src/socket.cc:459 msgid "No password specified." msgstr "" #: src/socket.cc:504 msgid "" "Socket: Device closed socket when trying to open (can be caused by the wrong " "password, or if the device thinks the socket is already open... please try " "again)" msgstr "" #: src/socket.cc:512 msgid "Socket: Bad OPENED packet in Open" msgstr "" #: src/socket.cc:528 msgid "Could not find mode's starting sequence packet" msgstr "" #: src/socket.cc:617 msgid "Socket: Bad CLOSED packet in Close" msgstr "" #: src/socket.cc:628 msgid "Socket: Missing RESET_REPLY in Close" msgstr "" #: src/socket.cc:677 msgid "Socket: unknown send data in DBFragSend()" msgstr "" #: src/socket.cc:781 src/socket.cc:870 msgid "Socket: (read) unhandled packet in Packet(): " msgstr "" #: src/socket.cc:794 src/socket.cc:887 src/socket.cc:970 msgid "Socket: 10 blank packets received" msgstr "" #: src/socket.cc:840 msgid "Socket: unknown send data in PacketJVM()" msgstr "" #: src/socket.cc:908 msgid "Socket: unknown send data in PacketData()" msgstr "" #: src/socket.cc:950 msgid "file is not a valid Java code file" msgstr "" #: src/socket.cc:954 msgid "device does not support requested command" msgstr "" #: src/socket.cc:1072 msgid "Non-sequence packet in Socket::SyncSend()" msgstr "" #: src/socket.cc:1081 msgid "Socket::Receive: queue SocketRead returned false (likely a timeout)" msgstr "" #: src/socket.cc:1084 msgid "NULL queue pointer in a registered socket read." msgstr "" #: src/socket.cc:1099 msgid "" "SocketRoutingQueue required in SocketZero in order to call Socket::" "RegisterInterest()" msgstr "" #: src/socket.cc:1102 #, c-format msgid "Socket (%u) already registered in Socket::RegisterInterest()!" msgstr "" #: src/tarfile.cc:55 msgid "Unable to open tar file: " msgstr "" #: src/tarfile.cc:88 msgid "Unable to write eof" msgstr "" #: src/tarfile.cc:92 msgid "Unable to close file" msgstr "" #: src/tarfile.cc:113 msgid "Unable to write tar header" msgstr "" #: src/tarfile.cc:128 msgid "Unable to write block" msgstr "" #: src/tarfile.cc:156 src/tarfile.cc:215 src/tarfile.cc:272 msgid "Only regular files are supported inside a tarball." msgstr "" #: src/tarfile.cc:184 src/tarfile.cc:243 msgid "Unable to read block" msgstr "" #: src/tarfile.cc:281 msgid "Unable to skip tar file" msgstr "" #: src/threadwrap.cc:54 msgid "Thread: pthread_create failed." msgstr "" #: src/time.cc:154 msgid "Unknown time zone" msgstr "" #: src/usbwrap_libusb.cc:228 src/usbwrap_libusb_1_0.cc:336 msgid "invalid USB device ID" msgstr "" #: src/usbwrap_libusb.cc:231 src/usbwrap_libusb_1_0.cc:340 msgid "" "Failed to open USB device. Please check your system's USB device " "permissions." msgstr "" #: src/usbwrap_libusb.cc:275 msgid "Timeout in usb_bulk_read" msgstr "" #: src/usbwrap_libusb.cc:278 msgid "Error in usb_bulk_read(" msgstr "" #: src/usbwrap_libusb.cc:303 msgid "Timeout in usb_bulk_write (1)" msgstr "" #: src/usbwrap_libusb.cc:305 msgid "Error in usb_bulk_write (1)" msgstr "" #: src/usbwrap_libusb.cc:327 msgid "Timeout in usb_bulk_write (2)" msgstr "" #: src/usbwrap_libusb.cc:329 msgid "Error in usb_bulk_write (2)" msgstr "" #: src/usbwrap_libusb.cc:347 msgid "Timeout in usb_interrupt_read" msgstr "" #: src/usbwrap_libusb.cc:349 msgid "Error in usb_interrupt_read" msgstr "" #: src/usbwrap_libusb.cc:370 msgid "Timeout in usb_interrupt_write" msgstr "" #: src/usbwrap_libusb.cc:372 msgid "Error in usb_interrupt_write" msgstr "" #: src/usbwrap_libusb.cc:505 src/usbwrap_libusb_1_0.cc:688 msgid "claim interface failed" msgstr "" #: src/usbwrap_libusb_1_0.cc:91 msgid "Success" msgstr "" #: src/usbwrap_libusb_1_0.cc:93 msgid "IO Error" msgstr "" #: src/usbwrap_libusb_1_0.cc:95 msgid "Invalid parameter" msgstr "" #: src/usbwrap_libusb_1_0.cc:97 msgid "Access" msgstr "" #: src/usbwrap_libusb_1_0.cc:99 msgid "No device" msgstr "" #: src/usbwrap_libusb_1_0.cc:101 msgid "Not found" msgstr "" #: src/usbwrap_libusb_1_0.cc:105 msgid "Timeout" msgstr "" #: src/usbwrap_libusb_1_0.cc:107 msgid "Overflow" msgstr "" #: src/usbwrap_libusb_1_0.cc:109 msgid "Pipe" msgstr "" #: src/usbwrap_libusb_1_0.cc:111 msgid "Interrupted" msgstr "" #: src/usbwrap_libusb_1_0.cc:113 msgid "No memory" msgstr "" #: src/usbwrap_libusb_1_0.cc:115 msgid "Not supported" msgstr "" #: src/usbwrap_libusb_1_0.cc:119 msgid "Unknown LIBUSB error code" msgstr "" #: src/usbwrap_libusb_1_0.cc:272 msgid "Failed to get device list" msgstr "" #: src/usbwrap_libusb_1_0.cc:391 msgid "Timeout in BulkRead" msgstr "" #: src/usbwrap_libusb_1_0.cc:397 msgid "Error in libusb_bulk_tranfer(" msgstr "" #: src/usbwrap_libusb_1_0.cc:432 msgid "Timeout in BulkWrite" msgstr "" #: src/usbwrap_libusb_1_0.cc:434 msgid "Error in BulkWrite" msgstr "" #: src/usbwrap_libusb_1_0.cc:441 src/usbwrap_libusb_1_0.cc:477 #: src/usbwrap_libusb_1_0.cc:545 msgid "Failed to perform a complete write" msgstr "" #: src/usbwrap_libusb_1_0.cc:469 msgid "Timeout in BulkWrite (2)" msgstr "" #: src/usbwrap_libusb_1_0.cc:471 msgid "Error in BulkWrite (2)" msgstr "" #: src/usbwrap_libusb_1_0.cc:503 msgid "Timeout in InterruptRead" msgstr "" #: src/usbwrap_libusb_1_0.cc:508 msgid "Error in InterruptRead" msgstr "" #: src/usbwrap_libusb_1_0.cc:536 msgid "Timeout in InterruptWrite" msgstr "" #: src/usbwrap_libusb_1_0.cc:538 msgid "Error in InterruptWrite" msgstr "" #: src/vbase.cc:47 msgid "gmtime_r() failed on time_t of: " msgstr "" #: src/vbase.cc:51 msgid "(null pointer)" msgstr "" #: src/vbase.cc:255 msgid "Cannot construct vBase with null format" msgstr "" #: src/vbase.cc:269 msgid "Cannot set vBase with null format" msgstr "" #: src/vbase.cc:294 src/vbase.cc:315 msgid "resource error allocating vformat attribute" msgstr "" #: src/vcard.cc:141 src/vcard.cc:337 src/vevent.cc:595 src/vevent.cc:683 #: src/vjournal.cc:79 src/vtodo.cc:94 msgid "resource error allocating vformat" msgstr "" #: src/vcard.cc:512 msgid "Unable to parse BDAY field" msgstr "" #: src/vcard.cc:544 msgid "FN and ORG fields both blank in VCARD data" msgstr "" #: src/vevent.cc:72 #, c-format msgid "" "ERROR: recurrence rule contains %s, unsupported by Barry. MIME conversion " "will be incorrect." msgstr "" #: src/vevent.cc:73 src/vevent.cc:87 src/vevent.cc:110 src/vevent.cc:145 #: src/vevent.cc:150 src/vevent.cc:163 src/vevent.cc:469 src/vevent.cc:495 #: src/vevent.cc:556 msgid "Record data so far:\n" msgstr "" #: src/vevent.cc:86 #, c-format msgid "" "Warning: multiple items in BYDAY, not supported by device (%s). Using only " "the first item." msgstr "" #: src/vevent.cc:109 #, c-format msgid "" "Warning: negative week in BYDAY (%d), unsupported by device. Converting to " "positive week, based on 4 week months: %d." msgstr "" #: src/vevent.cc:140 msgid "Called GetDayOfMonthFromBYMONTHDAY() without a BYMONTHDAY" msgstr "" #: src/vevent.cc:144 msgid "Warning: BYMONTHDAY of 0, assuming 1.\n" msgstr "" #: src/vevent.cc:149 #, c-format msgid "Warning: BYMONTHDAY larger than month (%d days). Assuming 1.\n" msgstr "" #: src/vevent.cc:162 #, c-format msgid "" "Warning: negative BYMONTHDAY (%d), unsupported by device. Converting to " "positive day of month: %d." msgstr "" #: src/vevent.cc:274 msgid "Unknown RecurringType in Barry Calendar object" msgstr "" #: src/vevent.cc:414 msgid "Invalid COUNT in recurring rule: " msgstr "" #: src/vevent.cc:468 msgid "" "Warning: WEEKLY VEVENT without a day selected. Assuming day of start time." msgstr "" #: src/vevent.cc:494 msgid "" "Warning: MONTHLY VEVENT without a day type specified (no BYMONTHDAY nor " "BYDAY). Assuming BYMONTHDAY, using day of start time." msgstr "" #: src/vevent.cc:555 msgid "" "Warning: YEARLY VEVENT without a day type specified (no BYMONTHDAY nor " "BYDAY). Assuming BYMONTHDAY, using day and month of start time." msgstr "" #: src/vevent.cc:672 msgid "vCalendar data contains more than one VEVENT block, unsupported" msgstr "" #: src/vevent.cc:723 msgid "Blank DTSTART" msgstr "" #: src/vevent.cc:783 msgid "Unknown TRIGGER VALUE" msgstr "" #: src/vjournal.cc:124 msgid "vCalendar data contains more than one VJOURNAL block, unsupported" msgstr "" #: src/vjournal.cc:135 msgid "resource error allocating vjournal" msgstr "" #: src/vtodo.cc:168 msgid "vCalendar data contains more than one VTODO block, unsupported" msgstr "" #: src/vtodo.cc:179 msgid "resource error allocating vtodo" msgstr "" #: tools/balxparse.cc:65 #, c-format msgid "" "balxparse - Command line ALX parser\n" " Copyright 2009-2010, Nicolas VIVIEN.\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -h This help\n" " -i lang Internationalization language\n" " -d path OS path with all ALX files\n" " -o file OS ALX filename (Platform.alx)\n" "\n" " ...\n" " Parse one or several ALX files.\n" "\n" " Language supported :\n" "\t" msgstr "" #: tools/bcharge.cc:59 tools/bcharge_libusb_1_0.cc:60 #, c-format msgid "" "bcharge - Adjust Blackberry charging modes\n" " Copyright 2006-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" "\n" " -d Set to dual mode (0004)\n" " -o Set a Pearl to old Blackberry mode (0001)\n" " -g Set dual mode only if database interface class 255\n" " is not found\n" "\n" " -h This help message\n" " -p devpath The devpath argument from udev. If specified, will attempt\n" " to adjust USB suspend settings to keep the device charging.\n" " -s path The path where sysfs is mounted. Defaults to '/sys'\n" "\n" msgstr "" #: tools/bcharge.cc:81 #, c-format msgid "" "\n" "usb_control_msg failed: code: %d, %s\n" msgstr "" #: tools/bcharge.cc:139 tools/bcharge_libusb_1_0.cc:149 #, c-format msgid "Can't find Mass Storage interface, assuming 0.\n" msgstr "" #: tools/bcharge.cc:159 #, c-format msgid "usb_detach_kernel_driver_np() failed: %s\n" msgstr "" #: tools/bcharge.cc:162 #, c-format msgid "usb_set_configuration() failed: %s\n" msgstr "" #: tools/bcharge.cc:170 #, c-format msgid "Found device #%s..." msgstr "" #: tools/bcharge.cc:175 #, c-format msgid "unable to open device\n" msgstr "" #: tools/bcharge.cc:183 tools/bcharge_libusb_1_0.cc:196 #, c-format msgid "adjusting charge setting" msgstr "" #: tools/bcharge.cc:188 tools/bcharge_libusb_1_0.cc:201 #, c-format msgid "already at 500mA" msgstr "" #: tools/bcharge.cc:196 tools/bcharge_libusb_1_0.cc:222 #, c-format msgid "...no Pearl mode adjustment" msgstr "" #: tools/bcharge.cc:201 tools/bcharge_libusb_1_0.cc:227 #, c-format msgid "...adjusting Pearl mode to single" msgstr "" #: tools/bcharge.cc:206 tools/bcharge_libusb_1_0.cc:232 #, c-format msgid "...already in classic/single mode" msgstr "" #: tools/bcharge.cc:212 tools/bcharge_libusb_1_0.cc:238 #, c-format msgid "...adjusting Pearl mode to dual" msgstr "" #: tools/bcharge.cc:217 tools/bcharge_libusb_1_0.cc:243 #, c-format msgid "...already in dual mode" msgstr "" #: tools/bcharge.cc:223 tools/bcharge_libusb_1_0.cc:249 #, c-format msgid "...no database iface found, setting dual mode" msgstr "" #: tools/bcharge.cc:228 tools/bcharge_libusb_1_0.cc:254 #, c-format msgid "...found database iface, no change" msgstr "" #: tools/bcharge.cc:260 #, c-format msgid "" "\n" "usb_reset failed: %s\n" msgstr "" #: tools/bcharge.cc:264 tools/bcharge_libusb_1_0.cc:291 #, c-format msgid "...done" msgstr "" #: tools/bcharge.cc:267 tools/bcharge_libusb_1_0.cc:294 #, c-format msgid "...no change" msgstr "" #: tools/bcharge.cc:281 tools/bcharge_libusb_1_0.cc:308 #, c-format msgid "autosuspend adjustment failure: (file: %s): %s\n" msgstr "" #: tools/bcharge.cc:292 tools/bcharge_libusb_1_0.cc:319 #, c-format msgid "autosuspend adjustment failure (write): (file: %s): %s\n" msgstr "" #: tools/bcharge.cc:298 tools/bcharge_libusb_1_0.cc:325 #, c-format msgid "autosuspend adjustment: wrote %s to %s\n" msgstr "" #: tools/bcharge.cc:425 #, c-format msgid "" "\n" "Unable to scan devices: %s\n" msgstr "" #: tools/bcharge.cc:430 tools/bcharge_libusb_1_0.cc:460 tools/breset.cc:67 #: tools/breset_libusb_1_0.cc:82 #, c-format msgid "Scanning for Blackberry devices...\n" msgstr "En busca de dispositivos Blackberry...\n" #: tools/bcharge_libusb_1_0.cc:82 #, c-format msgid "" "\n" "usb_control_transfer failed: code: %d\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:163 #, c-format msgid "Detecting possible kernel driver conflict, trying to resolve...\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:168 #, c-format msgid "libusb_detach_kernel_driver() failed: %d\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:172 #, c-format msgid "libusb_set_configuration() failed: %d\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:179 #, c-format msgid "Found device #%d-%d..." msgstr "" #: tools/bcharge_libusb_1_0.cc:187 #, c-format msgid "unable to open device, %d\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:207 #, c-format msgid "failed to discover power level\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:214 #, c-format msgid "failed to get device descriptor: %d\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:287 #, c-format msgid "" "\n" "libusb_reset_device() failed: %d\n" msgstr "" #: tools/bcharge_libusb_1_0.cc:453 #, c-format msgid "Failed to start up USB: %d\n" msgstr "" #: tools/bdptest.cc:60 msgid "List of debug files: " msgstr "" #: tools/bfuse.cc:71 #, c-format msgid "" "bfuse - FUSE filesystem for Blackberry databases\n" " Copyright 2008-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" msgstr "" #: tools/bfuse.cc:80 msgid "" "\n" "Barry specific options:\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" msgstr "" #: tools/bfuse.cc:434 tools/bfuse.cc:452 msgid "Constructed != name" msgstr "" #: tools/bfuse.cc:571 msgid "Hello FUSE world. This is Barry. Pleased to meet you.\n" msgstr "" #: tools/bidentify.cc:37 #, c-format msgid "" "bidentify - USB Blackberry Identifier Tool\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -B bus Specify which USB bus to search on\n" " -N dev Specify which system device, using system specific string\n" "\n" " -c If used with -m, show both hex and dec where possible\n" " -m Also show the device's ESN / MEID / IMEI\n" " -s Also show the device's USB serial number (same as shown by " "lsusb)\n" " -h This help\n" " -v Dump protocol data during operation\n" msgstr "" #: tools/bidentify.cc:162 msgid "Error on PIN: " msgstr "" #: tools/bidentify.cc:178 tools/brawchannel.cc:341 msgid "exception caught: " msgstr "" #: tools/bio.cc:68 tools/btool.cc:73 msgid "Compiled with Boost support" msgstr "" #: tools/bio.cc:70 msgid "" "\n" " Options to use for 'boost' type:\n" " -f file Boost serialization filename to read from or write to\n" " Can use - to specify stdin/stdout\n" msgstr "" #: tools/bio.cc:75 tools/btool.cc:76 msgid "Compiled without Boost support" msgstr "" #. TRANSLATORS: the i/o types, such as device, tar, mime, etc. must #. be exact. They are commands that the code tests for. Do not #. translate those particular words. Same with the -w write mode #. options. #: tools/bio.cc:85 #, c-format msgid "" "bio - Barry Input / Output\n" " Copyright 2010-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" " %s\n" "\n" " Usage: bio -i [options...] -o [options...]\n" "\n" " -i type The input type (Builder) to use for producing records\n" " Can be one of: device, tar, %sldif, mime\n" " -o type The output type (Parser) to use for processing records.\n" " Multiple outputs are allowed, as long as they don't\n" " conflict (such as two outputs writing to the same file\n" " or device).\n" " Can be one of: device, tar, %sldif, mime, dump, sha1, cstore\n" "\n" " Options to use for 'device' type:\n" " -d db Name of input database. Can be used multiple times.\n" " -A Add all available device databases, instead of specifying\n" " them manually via -d\n" " -p pin PIN of device to talk to\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -w mode Set write mode when using 'device' for output. Must be\n" " specified, or will not write anything.\n" " Can be one of: erase, overwrite, addonly, addnew\n" "\n" " Options to use for 'tar' backup type:\n" " -d db Name of input database. Can be used multiple times.\n" " Not available in output mode. Note that by default,\n" " all databases in the backup are selected, when reading,\n" " unless at least one -d is specified.\n" " -D db Name of input database to skip. If no -d options are used,\n" " then all databases are automatically selected. Using -D\n" " allows a filtering selection. If -d and -D are used for\n" " the same database, -D takes precedence.\n" " -f file Tar backup file to read from or write to\n" "%s\n" " Options to use for 'ldif' type:\n" " -c dn Convert address book database to LDIF format, using the\n" " specified baseDN\n" " -C dnattr LDIF attribute name to use when building the FQDN\n" " Defaults to 'cn'\n" "\n" " Options to use for 'mime' type:\n" " -f file Filename to read from or write to. Use - to explicitly\n" " specify stdin/stdout, which is default.\n" "\n" " Options to use for 'dump' to stdout output type:\n" " -n Use hex dump parser on all databases.\n" " -T Show only the names of the databases.\n" "\n" " Options to use for 'sha1' sum stdout output type:\n" " -t Include DB Name, Type, and Unique record IDs in the checksums\n" "\n" " Options to use for 'cstore' output type:\n" " -l List filenames only\n" " -f file Filename from the above list, including path.\n" " If found, the file will be written to the current\n" " directory, using the base filename from the device.\n" "\n" " Standalone options:\n" " -h This help\n" " -I cs International charset for string conversions\n" " Valid values here are available with 'iconv --list'\n" " -S Show list of supported database parsers and builders.\n" " Use twice to show field names as well.\n" " -v Dump protocol data during operation\n" "\n" msgstr "" #: tools/bio.cc:178 msgid "Filename not applicable for this mode" msgstr "" #: tools/bio.cc:183 msgid "DB not applicable for this mode" msgstr "" #: tools/bio.cc:188 msgid "DB skipping not applicable for this mode" msgstr "" #: tools/bio.cc:193 msgid "DBs not applicable for this mode" msgstr "" #: tools/bio.cc:198 msgid "PIN not applicable for this mode" msgstr "" #: tools/bio.cc:203 msgid "Password not applicable for this mode" msgstr "" #: tools/bio.cc:208 msgid "Device write behaviour not applicable for this mode" msgstr "" #: tools/bio.cc:213 msgid "DN not applicable for this mode" msgstr "" #: tools/bio.cc:218 msgid "Attribute not applicable for this mode" msgstr "" #: tools/bio.cc:223 msgid "No hex dump option in this mode" msgstr "" #: tools/bio.cc:228 msgid "No name-only option in this mode" msgstr "" #: tools/bio.cc:233 msgid "Including record IDs in the SHA1 sum is not applicable in this mode" msgstr "" #: tools/bio.cc:238 msgid "List option not applicable for this mode" msgstr "" #: tools/bio.cc:256 msgid "Invalid PIN: " msgstr "" #: tools/bio.cc:310 tools/bio.cc:529 tools/btool.cc:817 tools/pppob.cc:271 msgid "PIN not found: " msgstr "" #: tools/bio.cc:312 tools/bio.cc:531 msgid "PIN not specified, and more than one device exists." msgstr "" #: tools/bio.cc:316 tools/bio.cc:535 msgid "" "It seems you are trying to use the same device for multiple input or outputs." msgstr "" #: tools/bio.cc:331 msgid "Database not found: " msgstr "" #: tools/bio.cc:353 msgid "Cannot use stdin as tar source file, sorry." msgstr "" #: tools/bio.cc:523 msgid "" "Warning: the -w switch was not specified: no data will be written to the " "device." msgstr "" #: tools/bio.cc:561 msgid "Cannot use stdout as tar backup file, sorry." msgstr "" #: tools/bio.cc:589 msgid "Boost output requires a specific output file (-f switch)" msgstr "" #: tools/bio.cc:817 msgid " (folder)" msgstr "" #: tools/bio.cc:852 #, c-format msgid "Saving: %s as %s" msgstr "" #: tools/bio.cc:859 msgid "Error during write!" msgstr "" #: tools/bio.cc:968 msgid "" "Unknown device output mode. Must be one of: erase, overwrite, addonly, addnew" msgstr "" #: tools/bio.cc:1157 tools/btarcmp.cc:815 msgid "Exception: " msgstr "" #: tools/bjavaloader.cc:66 #, c-format msgid "" "bjavaloader - Command line USB Blackberry Java Loader\n" " Copyright 2008-2009, Nicolas VIVIEN.\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -A Save all modules found\n" " -a Wipe applications only\n" " -i Wipe filesystem only\n" " -f Force erase, if module is in use\n" " -h This help\n" " -s List sibling in module list\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" "\n" "Commands:\n" "\n" " %s [-s]\n" " Lists modules on the handheld\n" "\n" " %s\n" " Provides information on the handheld\n" "\n" " %s <.cod file> ...\n" " Loads modules onto the handheld\n" "\n" " %s [-A] ...\n" " Retrieves modules from the handheld and writes to .cod file\n" " Note: will overwrite existing files!\n" "\n" " %s [-a | -i]\n" " Wipes the handheld\n" " Use Caution: Wiping filesystem will remove all data\n" " such as messages, contacts, etc.\n" " Wiping applications will remove all .cod files\n" " on the device, including OS .cod files.\n" "\n" " %s\n" " Reset IT policy to factory defaults\n" " Use Caution: Resetting IT policy to factory defaults will\n" " also perform a filesystem wipe which will remove\n" " all data such as messages, contacts, etc.\n" "\n" " %s [-f] ...\n" " Erase module from handheld\n" "\n" " %s\n" " Retrieves the handheld event log\n" "\n" " %s\n" " Clears the handheld event log\n" "\n" " %s\n" " Dump the stack traces for all threads to the event log\n" "\n" " %s <.bmp file>\n" " Make a screenshot of handheld\n" "\n" " %s [%s]\n" " Sets the time on the handheld to the current time\n" " Or the time specified as an argument to %s\n" " If given as argument, current system timezone is assumed\n" msgstr "" #: tools/bjavaloader.cc:173 msgid "Unable to parse time string: " msgstr "" #: tools/bjavaloader.cc:208 msgid "Can't open: " msgstr "" #: tools/bjavaloader.cc:310 tools/bjdwp.cc:104 msgid "missing command" msgstr "" #: tools/bjavaloader.cc:335 tools/bjdwp.cc:124 tools/bjvmdebug.cc:108 #: tools/brawchannel.cc:250 tools/brecsum.cc:123 tools/bwatch.cc:132 msgid "No device selected, or PIN not found" msgstr "" #: tools/bjavaloader.cc:357 msgid "specify at least one .cod file to load" msgstr "" #: tools/bjavaloader.cc:364 msgid "loading: " msgstr "" #: tools/bjavaloader.cc:366 tools/bjavaloader.cc:383 tools/bjavaloader.cc:421 #: tools/bjavaloader.cc:434 msgid "done." msgstr "" #: tools/bjavaloader.cc:371 msgid "specify at least one module to erase" msgstr "" #: tools/bjavaloader.cc:378 msgid "erasing: " msgstr "" #: tools/bjavaloader.cc:388 msgid "specify a .bmp filename" msgstr "" #: tools/bjavaloader.cc:419 tools/bjavaloader.cc:432 msgid "saving: " msgstr "" #: tools/bjavaloader.cc:425 msgid "specify at least one module to save" msgstr "" #. TRANSLATORS: you may translate yes/no as long as you also #. translate "yes" to match. #: tools/bjavaloader.cc:447 #, c-format msgid "" "Use Caution: Wiping filesystem will remove all data\n" " such as messages, contacts, etc.\n" " Wiping applications will remove all .cod files\n" " on the device, including OS .cod files.\n" "\n" "You have selected to wipe the filesystem of device '%s'\n" "Continue with wipe? (yes/no) " msgstr "" #: tools/bjavaloader.cc:459 tools/bjavaloader.cc:475 msgid "Response of 'yes' not received, aborting." msgstr "" #: tools/bjavaloader.cc:464 #, c-format msgid "" "Use Caution: Resetting IT policy to factory defaults will\n" " also perform a filesystem wipe which will remove\n" " all data such as messages, contacts, etc.\n" "\n" "You have selected to reset device '%s' to factory defaults\n" "Continue with wipe? (yes/no) " msgstr "" #: tools/bjavaloader.cc:479 msgid "invalid command: " msgstr "" #: tools/bjavaloader.cc:490 tools/bjdwp.cc:154 tools/bjvmdebug.cc:171 #: tools/brawchannel.cc:333 tools/bs11nread.cc:146 tools/btool.cc:1012 #: tools/bwatch.cc:197 tools/upldif.cc:189 msgid "Usb::Error caught: " msgstr "" #: tools/bjavaloader.cc:495 tools/bjdwp.cc:159 tools/bjvmdebug.cc:176 #: tools/brawchannel.cc:337 tools/bs11nread.cc:150 tools/btool.cc:1016 #: tools/bwatch.cc:202 tools/upldif.cc:192 msgid "Barry::Error caught: " msgstr "" #: tools/bjavaloader.cc:500 tools/bjdwp.cc:164 tools/bjvmdebug.cc:181 #: tools/bs11nread.cc:154 tools/btool.cc:1020 tools/bwatch.cc:207 #: tools/upldif.cc:195 msgid "std::exception caught: " msgstr "" #: tools/bjdwp.cc:44 #, c-format msgid "" "bjdwp - Command line USB Blackberry JDWP\n" " Copyright 2008-2009, Nicolas VIVIEN.\n" " Using: %s\n" "\n" " -h This help\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" "\n" "arguments\n" "\n" "
Interface\n" " Listen port\n" msgstr "" #: tools/bjvmdebug.cc:45 #, c-format msgid "" "bjvmdebug - Command line USB Blackberry Java Debugger\n" " Copyright 2008-2009, Nicolas VIVIEN.\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -h This help\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" msgstr "" #: tools/bjvmdebug.cc:131 msgid "Java Modules List :" msgstr "" #: tools/bjvmdebug.cc:138 msgid "Java Threads currently running :" msgstr "" #: tools/bjvmdebug.cc:162 msgid "JVM message : " msgstr "" #: tools/boostwrap.cc:45 msgid "Archive exception in DoLoadBoostFile(): " msgstr "" #: tools/boostwrap.cc:64 msgid "Archive exception in DoSaveBoostFile(): " msgstr "" #: tools/brawchannel.cc:83 msgid "From BB: " msgstr "" #: tools/brawchannel.cc:95 #, c-format msgid "Written %ld bytes over stdout" msgstr "" #: tools/brawchannel.cc:109 msgid "CallbackHandler: Received error: " msgstr "" #: tools/brawchannel.cc:124 #, c-format msgid "" "brawchannel - Command line USB Blackberry raw channel interface\n" " Copyright 2010, RealVNC Ltd.\n" " Using: %s\n" "\n" "Usage:\n" "brawchannel [options] \n" "\n" " -h This help\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" " This will cause libusb output to appear on STDOUT unless\n" " the environment variable USB_DEBUG is set to 0,1 or 2.\n" msgstr "" #: tools/brawchannel.cc:209 msgid "Error: Missing raw channel name." msgstr "" #: tools/brawchannel.cc:215 msgid "Error: Too many arguments." msgstr "" #: tools/brawchannel.cc:235 msgid "" "Warning: Protocol dump enabled without setting USB_DEBUG to 0, 1 or 2.\n" " libusb might log to STDOUT and ruin data stream." msgstr "" #: tools/brawchannel.cc:257 msgid "Connected to device, starting read/write\n" msgstr "" #: tools/brawchannel.cc:306 msgid "Select failed with errno: " msgstr "" #: tools/brawchannel.cc:315 #, c-format msgid "Sending %ld bytes stdin->USB\n" msgstr "" #: tools/brawchannel.cc:316 msgid "To BB: " msgstr "" #: tools/brawchannel.cc:323 #, c-format msgid "Sent %ld bytes stdin->USB\n" msgstr "" #: tools/brecsum.cc:42 #, c-format msgid "" "brecsum - Generate SHA1 sums of raw Blackberry database records.\n" " Copyright 2008-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -d db Read database 'db' and sum all its records.\n" " Can be used multiple times to fetch more than one DB\n" " -h This help\n" " -i Include DB Name, Type, and Unique record IDs in the checksums\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" msgstr "" #: tools/breset.cc:81 tools/breset_libusb_1_0.cc:105 #, c-format msgid "Found..." msgstr "Encontrado..." #: tools/breset.cc:82 tools/breset_libusb_1_0.cc:106 #, c-format msgid "attempting to reset.\n" msgstr "intento reiniciarlo.\n" #: tools/breset.cc:86 tools/breset_libusb_1_0.cc:110 #, c-format msgid "Can't reset device on bus %s, devnum %u\n" msgstr "No se puede reiniciar el dispositivo en canal %s, devnum %u\n" #: tools/breset.cc:91 tools/breset_libusb_1_0.cc:114 #, c-format msgid "%d device%s reset.\n" msgstr "%d dispositivo%s reiniciado(s).\n" #: tools/breset_libusb_1_0.cc:79 #, c-format msgid "Failed to start USB: %d\n" msgstr "" #: tools/bs11nread.cc:49 #, c-format msgid "" "bs11nread - Reads a boost serialization file (from btool)\n" " and dumps data to stdout\n" " Copyright 2008-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -f file Filename to save or load handheld data to/from\n" " -h This help\n" " -S Show list of supported database parsers\n" msgstr "" #: tools/bs11nread.cc:76 msgid " records loaded" msgstr "" #: tools/bs11nread.cc:100 msgid "Unknown database name: " msgstr "" #: tools/bs11nread.cc:138 msgid "Filename must be specified" msgstr "" #. TRANSLATORS: the Using: string is followed by the Barry library version #. string. #: tools/btarcmp.cc:56 #, c-format msgid "" "btarcmp - Compare Barry backup tarballs\n" " Copyright 2012-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " Usage: btarcmp [options...] tarball_0 tarball_1\n" "\n" " -b Use brief filename output\n" " -d db Specify a specific database to compare. Can be used\n" " multiple times. If not used at all, all databases are\n" " compared.\n" " -D db Specify a database name to skip. If both -d and -D are\n" " used for the same database name, it will be skipped.\n" " -h This help\n" " -I cs International charset for string conversions\n" " Valid values here are available with 'iconv --list'\n" " -P Only compare records that can be parsed\n" " This is the same as specifying -d for each database\n" " listed with -S.\n" " -S Show list of supported database parsers. Use twice\n" " to show field names as well.\n" " -v Show verbose diff output (twice to force hex output)\n" "\n" msgstr "" #: tools/btarcmp.cc:186 msgid "Different database types in ParsedCompare ctor!" msgstr "" #: tools/btarcmp.cc:461 msgid ": has no database '" msgstr "" #: tools/btarcmp.cc:502 msgid "Comparing non-existant database!" msgstr "" #: tools/btarcmp.cc:532 msgid "record has been deleted in " msgstr "" #: tools/btarcmp.cc:533 msgid "record has been added in " msgstr "" #: tools/btarcmp.cc:542 msgid "Tried to compare records from different databases: " msgstr "" #: tools/btarcmp.cc:569 tools/btarcmp.cc:579 msgid ": differs: " msgstr "" #: tools/btarcmp.cc:571 tools/btarcmp.cc:581 msgid "sizes (" msgstr "" #: tools/btarcmp.cc:573 msgid "), SHA1 sums differ" msgstr "" #: tools/btarcmp.cc:589 msgid "No differences found in parsed records, but SHA1 sums differ." msgstr "" #: tools/btarcmp.cc:596 msgid " Hex diff of record:" msgstr "" #: tools/btarcmp.cc:687 msgid "In database: " msgstr "" #: tools/btardump.cc:42 tools/btool.cc:81 msgid " -V Dump records using MIME vformats where possible" msgstr "" #: tools/btardump.cc:48 #, c-format msgid "" "btardump - Command line parser for Barry backup files\n" " Copyright 2010-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -d db Name of database to dump. Can be used multiple times\n" " to parse multiple databases at once. If not specified\n" " at all, all available databases from the backup are\n" " dumped.\n" " -h This help\n" " -i cs International charset for string conversions\n" " Valid values here are available with 'iconv --list'\n" "%s\n" "\n" " [files...] Backup file(s), created by btool or the backup GUI.\n" msgstr "" #: tools/btardump.cc:132 tools/btool.cc:714 msgid "-V option not supported - no Sync library support available\n" msgstr "" #: tools/btardump.cc:175 msgid "Reading file: " msgstr "" #: tools/btool.cc:74 msgid " -f file Filename to save or load handheld data to/from" msgstr "" #: tools/btool.cc:87 #, c-format msgid "" "btool - Command line USB Blackberry Test Tool\n" " Copyright 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" " %s\n" "\n" " -b file Filename to save or load a Barry Backup to (tar.gz)\n" " -B bus Specify which USB bus to search on\n" " -N dev Specify which system device, using system specific string\n" "\n" " -a db Erase / clear database 'db' FROM device, deleting all\n" " its records. Can be used multiple times to clear more\n" " than one DB.\n" " -c dn Convert address book database to LDIF format, using the\n" " specified baseDN\n" " -C dnattr LDIF attribute name to use when building the FQDN\n" " Defaults to 'cn'\n" " -d db Load database 'db' FROM device and dump to screen\n" " Can be used multiple times to fetch more than one DB\n" " -e epp Override endpoint pair detection. 'epp' is a single\n" " string separated by a comma, holding the read,write\n" " endpoint pair. Example: -e 83,5\n" " Note: Endpoints are specified in hex.\n" " You should never need to use this option.\n" "%s\n" " -F sort Field name by which to sort the output. Note that the\n" " format of this field is special: 'DBName:field1,field2'\n" " with no spaces unless the spaces are part of the name.\n" " Can be used multiple times, to match your -d options.\n" " Example: -F 'Address Book:Company,LastName,FirstName'\n" " -h This help\n" " -i cs International charset for string conversions\n" " Valid values here are available with 'iconv --list'\n" " -I Sort records before output\n" " -l List devices\n" " -L List Contact field names\n" " -m Map LDIF name to Contact field / Unmap LDIF name\n" " Map: ldif,read,write - maps ldif to read/write Contact " "fields\n" " Unmap: ldif name alone\n" " -M List current LDIF mapping\n" " -n Use null parser on all databases.\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -s db Save database 'db' TO device from data loaded from -f file\n" " -S Show list of supported database parsers. Use twice to\n" " display fields names as well.\n" " -t Show database database table\n" " -T db Show record state table for given database\n" " -v Dump protocol data during operation\n" "%s\n" " -X Reset device\n" " -z Use non-threaded sockets\n" " -Z Use threaded socket router (default)\n" "\n" " -d Command modifiers: (can be used multiple times for more than 1 " "record)\n" "\n" " -r # Record index number as seen in the -T state table.\n" " This overrides the default -d behaviour, and only\n" " downloads the one specified record, sending to stdout.\n" " -R # Same as -r, but also clears the record's dirty flags.\n" " -D # Record index number as seen in the -T state table,\n" " which indicates the record to delete. Used with the -d\n" " command to specify the database.\n" msgstr "" #: tools/btool.cc:196 msgid "Loading: " msgstr "" #: tools/btool.cc:202 msgid " records loaded from '" msgstr "" #: tools/btool.cc:230 #, c-format msgid "" "Store counted %d records read from device, and %d records written to device." msgstr "" #: tools/btool.cc:234 msgid "Saving: " msgstr "" #: tools/btool.cc:239 msgid " records saved to '" msgstr "" #: tools/btool.cc:437 msgid "No Builder available for database" msgstr "" #: tools/btool.cc:477 msgid "Unmapping: " msgstr "" #: tools/btool.cc:481 msgid "Mapping: " msgstr "" #: tools/btool.cc:487 msgid "Read/Write name unknown: " msgstr "" #: tools/btool.cc:491 msgid "Invalid map format: " msgstr "" #: tools/btool.cc:582 msgid "-b option not supported - no Barry Backup library support available\n" msgstr "" #: tools/btool.cc:627 msgid "-f option not supported - no Boost serialization support available\n" msgstr "" #: tools/btool.cc:764 msgid "Unable to set DN Attr: " msgstr "" #: tools/btool.cc:779 msgid "Blackberry device errors with errors during probe:" msgstr "" #: tools/btool.cc:790 #, fuzzy msgid "Blackberry devices found:" msgstr "En busca de dispositivos Blackberry...\n" #: tools/btool.cc:812 tools/pppob.cc:273 msgid "No device selected" msgstr "" #: tools/btool.cc:825 msgid "Using device (PIN): " msgstr "" #: tools/btool.cc:841 msgid "Endpoint pair (read,write) overridden with: " msgstr "" #: tools/btool.cc:922 msgid "No db names to process" msgstr "" #: tools/btool.cc:931 msgid "Record state table for: " msgstr "" #: tools/btool.cc:940 msgid "Must have 1 db name to process" msgstr "" #: tools/btool.cc:952 msgid "Clearing record's dirty flags..." msgstr "" #: tools/btool.cc:982 msgid "No db names to erase" msgstr "" #: tools/btool.cc:990 msgid "Deleting all records from " msgstr "" #: tools/bwatch.cc:47 #, c-format msgid "" "bwatch - View video of BlackBerry screenshots\n" " Copyright 2011, Alberto Mattea\n" " Copyright 2011-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -d delay Delay interval between screenshots, in milliseconds.\n" " The lower the value, the higher the load on the device.\n" " Default is 500ms.\n" " -p pin PIN of device to talk with\n" " If only one device is plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -v Dump protocol data during operation\n" msgstr "" #: tools/bwatch.cc:87 msgid "Invalid interval value of: " msgstr "" #: tools/bwatch.cc:87 msgid "Defaulting to 500ms." msgstr "" #: tools/bwatch.cc:137 msgid "Press a key to exit..." msgstr "" #: tools/pppob.cc:58 #, c-format msgid "" "pppob - PPP over Barry\n" " Copyright 2007-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" " Using: %s\n" "\n" " -l file Direct pppob log output to file (useful with -v)\n" " -p pin PIN of device to talk with\n" " If only one device plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -s Use Serial mode instead of IpModem\n" " -t Use a pseudo-tty instead of stdin/stdout\n" " -v Dump protocol data during operation (debugging only!)\n" msgstr "" #: tools/pppob.cc:90 msgid "Error in write()" msgstr "" #: tools/pppob.cc:135 msgid "Read error in ProcessStdin: " msgstr "" #: tools/pppob.cc:212 msgid "Cannot open /dev/ptmx: " msgstr "" #: tools/pppob.cc:218 msgid "Warning: grantpt() failure: " msgstr "" #: tools/pppob.cc:222 msgid "Warning: unlockpt() failure: " msgstr "" #: tools/pppob.cc:280 msgid "Using IpModem mode..." msgstr "" #: tools/pppob.cc:295 msgid "Using Serial mode per command line..." msgstr "" #: tools/pppob.cc:298 msgid "No IpModem mode available, using Serial mode..." msgstr "" #: tools/pppob.cc:321 msgid "Exiting" msgstr "" #: tools/pppob.cc:325 msgid "exception caught in main(): " msgstr "" #: tools/upldif.cc:39 msgid "" "upldif - Command line LDIF uploader\n" " Copyright 2006-2013, Net Direct Inc. (http://www.netdirect.ca/)\n" "\n" " -p pin PIN of device to talk with\n" " If only one device plugged in, this flag is optional\n" " -P pass Simplistic method to specify device password\n" " -u Do the upload. If not specified, only dumps parsed\n" " LDIF data to stdout.\n" " -v Dump protocol data during operation\n" " -h This help output\n" msgstr "" #: tools/upldif.cc:79 #, c-format msgid "Store counted %d records." msgstr "" #: tools/upldif.cc:173 msgid "Device not found, or not specified" msgstr "" #: tools/util.cc:37 msgid "Supported Database parsers:\n" msgstr "" #: tools/util.cc:41 msgid " (* = can display in vformat MIME mode)\n" msgstr "" #: tools/util.cc:82 msgid "Supported Database builders:\n" msgstr "" barry-0.18.5/po/Rules-quot0000644001161500056700000000340012242254476014672 0ustar cdfreycdfrey# Special Makefile rules for English message catalogs with quotation marks. DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot .SUFFIXES: .insert-header .po-update-en en@quot.po-create: $(MAKE) en@quot.po-update en@boldquot.po-create: $(MAKE) en@boldquot.po-update en@quot.po-update: en@quot.po-update-en en@boldquot.po-update: en@boldquot.po-update-en .insert-header.po-update-en: @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ tmpdir=`pwd`; \ echo "$$lang:"; \ ll=`echo $$lang | sed -e 's/@.*//'`; \ LC_ALL=C; export LC_ALL; \ cd $(srcdir); \ if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$lang -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ exit 1; \ fi; \ fi; \ else \ echo "creation of $$lang.po failed!" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ fi en@quot.insert-header: insert-header.sin sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header en@boldquot.insert-header: insert-header.sin sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header mostlyclean: mostlyclean-quot mostlyclean-quot: rm -f *.insert-header barry-0.18.5/po/LINGUAS0000644001161500056700000000004512242254476013716 0ustar cdfreycdfrey# Set of available languages. fr es barry-0.18.5/po/en@boldquot.header0000644001161500056700000000247112242254476016324 0ustar cdfreycdfrey# All this catalog "translates" are quotation characters. # The msgids must be ASCII and therefore cannot contain real quotation # characters, only substitutes like grave accent (0x60), apostrophe (0x27) # and double quote (0x22). These substitutes look strange; see # http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html # # This catalog translates grave accent (0x60) and apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019). # It also translates pairs of apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019) # and pairs of quotation mark (0x22) to # left double quotation mark (U+201C) and right double quotation mark (U+201D). # # When output to an UTF-8 terminal, the quotation characters appear perfectly. # When output to an ISO-8859-1 terminal, the single quotation marks are # transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to # grave/acute accent (by libiconv), and the double quotation marks are # transliterated to 0x22. # When output to an ASCII terminal, the single quotation marks are # transliterated to apostrophes, and the double quotation marks are # transliterated to 0x22. # # This catalog furthermore displays the text between the quotation marks in # bold face, assuming the VT100/XTerm escape sequences. # barry-0.18.5/po/en@quot.header0000644001161500056700000000226312242254476015462 0ustar cdfreycdfrey# All this catalog "translates" are quotation characters. # The msgids must be ASCII and therefore cannot contain real quotation # characters, only substitutes like grave accent (0x60), apostrophe (0x27) # and double quote (0x22). These substitutes look strange; see # http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html # # This catalog translates grave accent (0x60) and apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019). # It also translates pairs of apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019) # and pairs of quotation mark (0x22) to # left double quotation mark (U+201C) and right double quotation mark (U+201D). # # When output to an UTF-8 terminal, the quotation characters appear perfectly. # When output to an ISO-8859-1 terminal, the single quotation marks are # transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to # grave/acute accent (by libiconv), and the double quotation marks are # transliterated to 0x22. # When output to an ASCII terminal, the single quotation marks are # transliterated to apostrophes, and the double quotation marks are # transliterated to 0x22. # barry-0.18.5/po/ChangeLog0000644001161500056700000000071612242254476014450 0ustar cdfreycdfrey2009-11-19 gettextize * Makefile.in.in: New file, from gettext-0.17. * boldquot.sed: New file, from gettext-0.17. * en@boldquot.header: New file, from gettext-0.17. * en@quot.header: New file, from gettext-0.17. * insert-header.sin: New file, from gettext-0.17. * quot.sed: New file, from gettext-0.17. * remove-potcdate.sin: New file, from gettext-0.17. * Rules-quot: New file, from gettext-0.17. * POTFILES.in: New file. barry-0.18.5/po/README0000644001161500056700000000075212242254476013556 0ustar cdfreycdfreyHOWTO to add a new language or update translation ================================================= To add a new language --------------------- Sample to add spanish language $ cd /po $ msginit --locale=es --input=barry.pot $ echo "es" >> LINGUAS $ make update-po Then, send to barry team your work. To update translation --------------------- You have to only edit a ".po" file. $ cd /po $ vi es.po $ make update-po Then, send to barry team your work. barry-0.18.5/opensync-plugin/0000755001161500056700000000000012242254476015406 5ustar cdfreycdfreybarry-0.18.5/opensync-plugin/po/0000755001161500056700000000000012242254476016024 5ustar cdfreycdfreybarry-0.18.5/opensync-plugin/po/insert-header.sin0000644001161500056700000000124012242254476021266 0ustar cdfreycdfrey# Sed script that inserts the file called HEADER before the header entry. # # At each occurrence of a line starting with "msgid ", we execute the following # commands. At the first occurrence, insert the file. At the following # occurrences, do nothing. The distinction between the first and the following # occurrences is achieved by looking at the hold space. /^msgid /{ x # Test if the hold space is empty. s/m/m/ ta # Yes it was empty. First occurrence. Read the file. r HEADER # Output the file's contents by reading the next line. But don't lose the # current line while doing this. g N bb :a # The hold space was nonempty. Following occurrences. Do nothing. x :b } barry-0.18.5/opensync-plugin/po/boldquot.sed0000644001161500056700000000033112242254476020347 0ustar cdfreycdfreys/"\([^"]*\)"/“\1”/g s/`\([^`']*\)'/‘\1’/g s/ '\([^`']*\)' / ‘\1’ /g s/ '\([^`']*\)'$/ ‘\1’/g s/^'\([^`']*\)' /‘\1’ /g s/“”/""/g s/“/“/g s/”/”/g s/‘/‘/g s/’/’/g barry-0.18.5/opensync-plugin/po/barry-opensync-plugin.pot0000644001161500056700000000715612242254476023030 0ustar cdfreycdfrey# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Net Direct, Inc. # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: barry-opensync-plugin 0.18.5\n" "Report-Msgid-Bugs-To: http://netdirect.ca/barry\n" "POT-Creation-Date: 2012-08-07 14:46-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: src/barry_sync.cc:76 msgid "GetChanges: slow sync request detected, clearing cache and id map" msgstr "" #: src/barry_sync.cc:103 msgid "found an ADDED change" msgstr "" #: src/barry_sync.cc:111 msgid "found a MODIFIED change" msgstr "" #: src/barry_sync.cc:116 msgid "no change detected" msgstr "" #: src/barry_sync.cc:126 #, c-format msgid "change record ID: %s" msgstr "" #: src/barry_sync.cc:163 msgid "found DELETE change" msgstr "" #: src/barry_sync.cc:224 msgid "Error saving calendar cache" msgstr "" #: src/barry_sync.cc:232 msgid "Error saving calendar id map" msgstr "" #: src/barry_sync.cc:262 #, c-format msgid "Unable to get config data: %s" msgstr "" #: src/barry_sync.cc:293 #, c-format msgid "Unable to allocate memory for environment: %s" msgstr "" #: src/barry_sync.cc:319 #, c-format msgid "Unable to find PIN %lx" msgstr "" #: src/barry_sync.cc:332 #, c-format msgid "Unable to allocate memory for controller: %s" msgstr "" #: src/barry_sync.cc:385 msgid "unable to get commit function pointer" msgstr "" #: src/barry_sync.cc:393 msgid "unable to get sync object that matches change type" msgstr "" #: src/barry_sync.cc:400 msgid "This object type is disabled in the barry-sync config" msgstr "" #: src/barry_sync.cc:418 msgid "uid from change object is blank!" msgstr "" #: src/barry_sync.cc:429 #, c-format msgid "unable to get state table index for RecordId: %lu" msgstr "" #: src/barry_sync.cc:450 #, c-format msgid "CommitData() for ADDED state returned false: %s" msgstr "" #: src/barry_sync.cc:462 #, c-format msgid "CommitData() for MODIFIED state returned false: %s" msgstr "" #: src/barry_sync.cc:470 src/barry_sync.cc:471 msgid "Unknown change type" msgstr "" #: src/environment.cc:147 #, c-format msgid "found existing uid in map: %lu" msgstr "" #: src/environment.cc:158 msgid "parsed uid already exists in map, skipping" msgstr "" #: src/environment.cc:167 #, c-format msgid "made new record id: %lu" msgstr "" #: src/environment.cc:192 msgid "Tried to use empty Connector" msgstr "" #: src/environment.cc:241 #, c-format msgid "Clearing dirty flag for db %u, index %u" msgstr "" #: src/environment.cc:322 msgid "calendar syncing enabled" msgstr "" #: src/environment.cc:327 msgid "contacts syncing enabled" msgstr "" #: src/environment.cc:332 msgid "using password from config file" msgstr "" #: src/vcard.cc:75 src/vcard.cc:102 #, c-format msgid "ERROR: vcard:Barry::ConvertError exception: %s" msgstr "" #: src/vcard.cc:148 src/vevent.cc:162 msgid "Can't use recommended recordId, generating new one." msgstr "" #: src/vcard.cc:160 src/vevent.cc:174 msgid "unable to parse change data for new RecordId: " msgstr "" #: src/vcard.cc:163 src/vevent.cc:177 msgid "data: " msgstr "" #: src/vcard.cc:172 src/vevent.cc:201 msgid "adding record" msgstr "" #: src/vcard.cc:176 src/vevent.cc:205 msgid "setting record" msgstr "" #: src/vcard.cc:178 src/vevent.cc:207 msgid "clearing dirty flag" msgstr "" #: src/vevent.cc:75 src/vevent.cc:116 #, c-format msgid "ERROR: vevent:Barry::ConvertError exception: %s" msgstr "" barry-0.18.5/opensync-plugin/po/fr.po0000644001161500056700000001276112242254476017002 0ustar cdfreycdfrey# French translations for barry-opensync-plugin package. # Copyright (C) 2012-2013 Net Direct, Inc. # This file is distributed under the same license as the barry-opensync-plugin package. # Chris Frey , 2012. # msgid "" msgstr "" "Project-Id-Version: barry-opensync-plugin 0.18.5\n" "Report-Msgid-Bugs-To: http://netdirect.ca/barry\n" "POT-Creation-Date: 2012-08-07 14:46-0400\n" "PO-Revision-Date: 2012-08-05 12:47+0100\n" "Last-Translator: Nicolas CARRIER \n" "Language-Team: French\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Poedit-Basepath: ..\n" #: src/barry_sync.cc:76 msgid "GetChanges: slow sync request detected, clearing cache and id map" msgstr "" "GetChanges : requête de synchronisation lente détectée, nettoyage du cache " "et de la table des id" #: src/barry_sync.cc:103 msgid "found an ADDED change" msgstr "Un changement ADDED a été rencontré" #: src/barry_sync.cc:111 msgid "found a MODIFIED change" msgstr "Un changement MODIFIED a été rencontré" #: src/barry_sync.cc:116 msgid "no change detected" msgstr "Pas de changement détecté" #: src/barry_sync.cc:126 #, c-format msgid "change record ID: %s" msgstr "Changement de l'ID de l'enregistrement : %s" #: src/barry_sync.cc:163 msgid "found DELETE change" msgstr "Un changement DELETE a été rencontré" #: src/barry_sync.cc:224 msgid "Error saving calendar cache" msgstr "Erreur lors de la sauvegarde du cache du calendrier" #: src/barry_sync.cc:232 msgid "Error saving calendar id map" msgstr "Erreur lors de la sauvegarde de la table des id du calendrier" #: src/barry_sync.cc:262 #, c-format msgid "Unable to get config data: %s" msgstr "Impossible d'obtenir les données de configuration : %s" #: src/barry_sync.cc:293 #, c-format msgid "Unable to allocate memory for environment: %s" msgstr "Impossible d'allouer de la mémoire depuis l'environnement : %s" #: src/barry_sync.cc:319 #, c-format msgid "Unable to find PIN %lx" msgstr "Impossible de trouver le PIN %lx" #: src/barry_sync.cc:332 #, c-format msgid "Unable to allocate memory for controller: %s" msgstr "Impossible d'allouer la mémoire pour le contrôleur : %s" #: src/barry_sync.cc:385 msgid "unable to get commit function pointer" msgstr "Impossible de récupérer le pointeur de fonction de commit" #: src/barry_sync.cc:393 msgid "unable to get sync object that matches change type" msgstr "" "Impossible d'obtenir un objet de synchronisation qui corresponde au type de " "changement" #: src/barry_sync.cc:400 msgid "This object type is disabled in the barry-sync config" msgstr "Ce type d'objet est désactivé dans la configuration de barry-sync" #: src/barry_sync.cc:418 msgid "uid from change object is blank!" msgstr "L'uid dans l'objet change est vide !" #: src/barry_sync.cc:429 #, fuzzy, c-format msgid "unable to get state table index for RecordId: %lu" msgstr "" "Impossible d'obtenir l'indice de la table d'état pour le RecordId : %lu" #: src/barry_sync.cc:450 #, c-format msgid "CommitData() for ADDED state returned false: %s" msgstr "CommitData() pour l'état ADDED a retourné false : %s" #: src/barry_sync.cc:462 #, c-format msgid "CommitData() for MODIFIED state returned false: %s" msgstr "CommitData() pour l'état MODIFIED a retourné false : %s" #: src/barry_sync.cc:470 src/barry_sync.cc:471 msgid "Unknown change type" msgstr "Type de changement inconnu" #: src/environment.cc:147 #, c-format msgid "found existing uid in map: %lu" msgstr "uid existant trouvé dans la table : %lu" #: src/environment.cc:158 msgid "parsed uid already exists in map, skipping" msgstr "L'uid lu existe déjà dans la table, ignoré" #: src/environment.cc:167 #, c-format msgid "made new record id: %lu" msgstr "Création d'un nouvel id d'enregistrement : %lu" #: src/environment.cc:192 msgid "Tried to use empty Connector" msgstr "Tentative d'utiliser un Connector vide" #: src/environment.cc:241 #, c-format msgid "Clearing dirty flag for db %u, index %u" msgstr "Suppression du drapeau dirty pour la base %u, index %u" #: src/environment.cc:322 msgid "calendar syncing enabled" msgstr "Synchronisation de calendrier activée" #: src/environment.cc:327 msgid "contacts syncing enabled" msgstr "Synchronisation des contacts activée" #: src/environment.cc:332 msgid "using password from config file" msgstr "Utilisation du mot de passe du fichier de configuration" #: src/vcard.cc:75 src/vcard.cc:102 #, c-format msgid "ERROR: vcard:Barry::ConvertError exception: %s" msgstr "ERREUR : exception dans vcard:Barry::ConvertError : %s" #: src/vcard.cc:148 src/vevent.cc:162 msgid "Can't use recommended recordId, generating new one." msgstr "Impossible d'utiliser le recordId recommandé, un nouveau est généré." #: src/vcard.cc:160 src/vevent.cc:174 #, fuzzy msgid "unable to parse change data for new RecordId: " msgstr "" "Impossible de lire les données du changement pour le nouveau RecordId :" #: src/vcard.cc:163 src/vevent.cc:177 msgid "data: " msgstr "Données :" #: src/vcard.cc:172 src/vevent.cc:201 msgid "adding record" msgstr "Ajout de l'enregistrement" #: src/vcard.cc:176 src/vevent.cc:205 msgid "setting record" msgstr "Modification de l'enregistrement" #: src/vcard.cc:178 src/vevent.cc:207 msgid "clearing dirty flag" msgstr "Suppression du drapeau dirty" #: src/vevent.cc:75 src/vevent.cc:116 #, c-format msgid "ERROR: vevent:Barry::ConvertError exception: %s" msgstr "ERREUR : exception dans vevent:Barry::ConvertError : %s" barry-0.18.5/opensync-plugin/po/remove-potcdate.sin0000644001161500056700000000066012242254476021637 0ustar cdfreycdfrey# Sed script that remove the POT-Creation-Date line in the header entry # from a POT file. # # The distinction between the first and the following occurrences of the # pattern is achieved by looking at the hold space. /^"POT-Creation-Date: .*"$/{ x # Test if the hold space is empty. s/P/P/ ta # Yes it was empty. First occurrence. Remove the line. g d bb :a # The hold space was nonempty. Following occurrences. Do nothing. x :b } barry-0.18.5/opensync-plugin/po/POTFILES.in0000644001161500056700000000021112242254476017573 0ustar cdfreycdfrey# List of source files which contain translatable strings. src/barry_sync.cc src/environment.cc src/idmap.cc src/vcard.cc src/vevent.cc barry-0.18.5/opensync-plugin/po/quot.sed0000644001161500056700000000023112242254476017505 0ustar cdfreycdfreys/"\([^"]*\)"/“\1”/g s/`\([^`']*\)'/‘\1’/g s/ '\([^`']*\)' / ‘\1’ /g s/ '\([^`']*\)'$/ ‘\1’/g s/^'\([^`']*\)' /‘\1’ /g s/“”/""/g barry-0.18.5/opensync-plugin/po/Makevars0000644001161500056700000000356712242254476017533 0ustar cdfreycdfrey# Makefile variables for PO directory in any package using GNU gettext. # Usually the message domain is the same as the package name. DOMAIN = $(PACKAGE) # These two variables depend on the location of this directory. subdir = po top_builddir = .. # These options get passed to xgettext. XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ --from-code=UTF-8 --add-comments=TRANSLATORS # This is the copyright holder that gets inserted into the header of the # $(DOMAIN).pot file. Set this to the copyright holder of the surrounding # package. (Note that the msgstr strings, extracted from the package's # sources, belong to the copyright holder of the package.) Translators are # expected to transfer the copyright for their translations to this person # or entity, or to disclaim their copyright. The empty string stands for # the public domain; in this case the translators are expected to disclaim # their copyright. COPYRIGHT_HOLDER = Net Direct, Inc. # This is the email address or URL to which the translators shall report # bugs in the untranslated strings: # - Strings which are not entire sentences, see the maintainer guidelines # in the GNU gettext documentation, section 'Preparing Strings'. # - Strings which use unclear terms or require additional context to be # understood. # - Strings which make invalid assumptions about notation of date, time or # money. # - Pluralisation problems. # - Incorrect English spelling. # - Incorrect formatting. # It can be your email address, or a mailing list address where translators # can write to without being subscribed, or the URL of a web page through # which the translators can contact you. # # See the "contact" page from the URL below: MSGID_BUGS_ADDRESS = http://netdirect.ca/barry # This is the list of locale categories, beyond LC_MESSAGES, for which the # message catalogs shall be used. It is usually empty. EXTRA_LOCALE_CATEGORIES = barry-0.18.5/opensync-plugin/po/es.po0000644001161500056700000000731112242254476016775 0ustar cdfreycdfrey# Spanish translations for barry-opensync-plugin package. # Copyright (C) 2012-2013 Net Direct, Inc. # This file is distributed under the same license as the barry-opensync-plugin package. # Chris Frey , 2012. # msgid "" msgstr "" "Project-Id-Version: barry-opensync-plugin 0.18.5\n" "Report-Msgid-Bugs-To: http://netdirect.ca/barry\n" "POT-Creation-Date: 2012-08-07 14:46-0400\n" "PO-Revision-Date: 2012-07-26 23:22-0400\n" "Last-Translator: Chris Frey \n" "Language-Team: Spanish\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: src/barry_sync.cc:76 msgid "GetChanges: slow sync request detected, clearing cache and id map" msgstr "" #: src/barry_sync.cc:103 msgid "found an ADDED change" msgstr "" #: src/barry_sync.cc:111 msgid "found a MODIFIED change" msgstr "" #: src/barry_sync.cc:116 msgid "no change detected" msgstr "" #: src/barry_sync.cc:126 #, c-format msgid "change record ID: %s" msgstr "" #: src/barry_sync.cc:163 msgid "found DELETE change" msgstr "" #: src/barry_sync.cc:224 msgid "Error saving calendar cache" msgstr "" #: src/barry_sync.cc:232 msgid "Error saving calendar id map" msgstr "" #: src/barry_sync.cc:262 #, c-format msgid "Unable to get config data: %s" msgstr "" #: src/barry_sync.cc:293 #, c-format msgid "Unable to allocate memory for environment: %s" msgstr "" #: src/barry_sync.cc:319 #, c-format msgid "Unable to find PIN %lx" msgstr "" #: src/barry_sync.cc:332 #, c-format msgid "Unable to allocate memory for controller: %s" msgstr "" #: src/barry_sync.cc:385 msgid "unable to get commit function pointer" msgstr "" #: src/barry_sync.cc:393 msgid "unable to get sync object that matches change type" msgstr "" #: src/barry_sync.cc:400 msgid "This object type is disabled in the barry-sync config" msgstr "" #: src/barry_sync.cc:418 msgid "uid from change object is blank!" msgstr "" #: src/barry_sync.cc:429 #, c-format msgid "unable to get state table index for RecordId: %lu" msgstr "" #: src/barry_sync.cc:450 #, c-format msgid "CommitData() for ADDED state returned false: %s" msgstr "" #: src/barry_sync.cc:462 #, c-format msgid "CommitData() for MODIFIED state returned false: %s" msgstr "" #: src/barry_sync.cc:470 src/barry_sync.cc:471 msgid "Unknown change type" msgstr "" #: src/environment.cc:147 #, c-format msgid "found existing uid in map: %lu" msgstr "" #: src/environment.cc:158 msgid "parsed uid already exists in map, skipping" msgstr "" #: src/environment.cc:167 #, c-format msgid "made new record id: %lu" msgstr "" #: src/environment.cc:192 msgid "Tried to use empty Connector" msgstr "" #: src/environment.cc:241 #, c-format msgid "Clearing dirty flag for db %u, index %u" msgstr "" #: src/environment.cc:322 msgid "calendar syncing enabled" msgstr "" #: src/environment.cc:327 msgid "contacts syncing enabled" msgstr "" #: src/environment.cc:332 msgid "using password from config file" msgstr "" #: src/vcard.cc:75 src/vcard.cc:102 #, c-format msgid "ERROR: vcard:Barry::ConvertError exception: %s" msgstr "" #: src/vcard.cc:148 src/vevent.cc:162 msgid "Can't use recommended recordId, generating new one." msgstr "" #: src/vcard.cc:160 src/vevent.cc:174 msgid "unable to parse change data for new RecordId: " msgstr "" #: src/vcard.cc:163 src/vevent.cc:177 msgid "data: " msgstr "" #: src/vcard.cc:172 src/vevent.cc:201 msgid "adding record" msgstr "" #: src/vcard.cc:176 src/vevent.cc:205 msgid "setting record" msgstr "" #: src/vcard.cc:178 src/vevent.cc:207 msgid "clearing dirty flag" msgstr "" #: src/vevent.cc:75 src/vevent.cc:116 #, c-format msgid "ERROR: vevent:Barry::ConvertError exception: %s" msgstr "" barry-0.18.5/opensync-plugin/po/Rules-quot0000644001161500056700000000340012242254476020024 0ustar cdfreycdfrey# Special Makefile rules for English message catalogs with quotation marks. DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot .SUFFIXES: .insert-header .po-update-en en@quot.po-create: $(MAKE) en@quot.po-update en@boldquot.po-create: $(MAKE) en@boldquot.po-update en@quot.po-update: en@quot.po-update-en en@boldquot.po-update: en@boldquot.po-update-en .insert-header.po-update-en: @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ tmpdir=`pwd`; \ echo "$$lang:"; \ ll=`echo $$lang | sed -e 's/@.*//'`; \ LC_ALL=C; export LC_ALL; \ cd $(srcdir); \ if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$lang -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ exit 1; \ fi; \ fi; \ else \ echo "creation of $$lang.po failed!" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ fi en@quot.insert-header: insert-header.sin sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header en@boldquot.insert-header: insert-header.sin sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header mostlyclean: mostlyclean-quot mostlyclean-quot: rm -f *.insert-header barry-0.18.5/opensync-plugin/po/LINGUAS0000644001161500056700000000004512242254476017050 0ustar cdfreycdfrey# Set of available languages. fr es barry-0.18.5/opensync-plugin/po/en@boldquot.header0000644001161500056700000000247112242254476021456 0ustar cdfreycdfrey# All this catalog "translates" are quotation characters. # The msgids must be ASCII and therefore cannot contain real quotation # characters, only substitutes like grave accent (0x60), apostrophe (0x27) # and double quote (0x22). These substitutes look strange; see # http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html # # This catalog translates grave accent (0x60) and apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019). # It also translates pairs of apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019) # and pairs of quotation mark (0x22) to # left double quotation mark (U+201C) and right double quotation mark (U+201D). # # When output to an UTF-8 terminal, the quotation characters appear perfectly. # When output to an ISO-8859-1 terminal, the single quotation marks are # transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to # grave/acute accent (by libiconv), and the double quotation marks are # transliterated to 0x22. # When output to an ASCII terminal, the single quotation marks are # transliterated to apostrophes, and the double quotation marks are # transliterated to 0x22. # # This catalog furthermore displays the text between the quotation marks in # bold face, assuming the VT100/XTerm escape sequences. # barry-0.18.5/opensync-plugin/po/en@quot.header0000644001161500056700000000226312242254476020614 0ustar cdfreycdfrey# All this catalog "translates" are quotation characters. # The msgids must be ASCII and therefore cannot contain real quotation # characters, only substitutes like grave accent (0x60), apostrophe (0x27) # and double quote (0x22). These substitutes look strange; see # http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html # # This catalog translates grave accent (0x60) and apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019). # It also translates pairs of apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019) # and pairs of quotation mark (0x22) to # left double quotation mark (U+201C) and right double quotation mark (U+201D). # # When output to an UTF-8 terminal, the quotation characters appear perfectly. # When output to an ISO-8859-1 terminal, the single quotation marks are # transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to # grave/acute accent (by libiconv), and the double quotation marks are # transliterated to 0x22. # When output to an ASCII terminal, the single quotation marks are # transliterated to apostrophes, and the double quotation marks are # transliterated to 0x22. # barry-0.18.5/opensync-plugin/po/ChangeLog0000644001161500056700000000071612242254476017602 0ustar cdfreycdfrey2009-11-19 gettextize * Makefile.in.in: New file, from gettext-0.17. * boldquot.sed: New file, from gettext-0.17. * en@boldquot.header: New file, from gettext-0.17. * en@quot.header: New file, from gettext-0.17. * insert-header.sin: New file, from gettext-0.17. * quot.sed: New file, from gettext-0.17. * remove-potcdate.sin: New file, from gettext-0.17. * Rules-quot: New file, from gettext-0.17. * POTFILES.in: New file. barry-0.18.5/opensync-plugin/po/README0000644001161500056700000000075212242254476016710 0ustar cdfreycdfreyHOWTO to add a new language or update translation ================================================= To add a new language --------------------- Sample to add spanish language $ cd /po $ msginit --locale=es --input=barry.pot $ echo "es" >> LINGUAS $ make update-po Then, send to barry team your work. To update translation --------------------- You have to only edit a ".po" file. $ cd /po $ vi es.po $ make update-po Then, send to barry team your work. barry-0.18.5/opensync-plugin/NEWS0000644001161500056700000000000012242254476016073 0ustar cdfreycdfreybarry-0.18.5/opensync-plugin/patches/0000755001161500056700000000000012242254476017035 5ustar cdfreycdfreybarry-0.18.5/opensync-plugin/patches/libopensync-plugin-evolution2-0.22-file-path-fudge.patch0000644001161500056700000000277012242254476031327 0ustar cdfreycdfreyChris Frey This patch checks for the presense of a forward slash at the beginning of each path. If found, it forces the prefix to "file://". This is helpful when running the evolution2 plugin with the KitchenSync GUI (snapshot 2007/07/12), since the GUI seems to strip off the file:// prefix no matter what you type into the fields, and the plugin needs the prefix to operate properly. An example of a path: file:///home/cdfrey/.evolution/addressbook/local/system diff -ru libopensync-plugin-evolution2-0.22/src/evolution2_xml.c libopensync-plugin-evolution2-0.22-cdf/src/evolution2_xml.c --- libopensync-plugin-evolution2-0.22/src/evolution2_xml.c 2007-03-27 07:49:55.000000000 -0400 +++ libopensync-plugin-evolution2-0.22-cdf/src/evolution2_xml.c 2007-07-27 22:47:43.000000000 -0400 @@ -59,13 +59,13 @@ char *str = (char*)xmlNodeGetContent(cur); if (str) { if (!xmlStrcmp(cur->name, (const xmlChar *)"address_path")) { - env->addressbook_path = g_strdup(str); + env->addressbook_path = g_strdup_printf("%s%s", (str[0] == '/') ? "file://" : "", str); } if (!xmlStrcmp(cur->name, (const xmlChar *)"calendar_path")) { - env->calendar_path = g_strdup(str); + env->calendar_path = g_strdup_printf("%s%s", (str[0] == '/') ? "file://" : "", str); } if (!xmlStrcmp(cur->name, (const xmlChar *)"tasks_path")) { - env->tasks_path = g_strdup(str); + env->tasks_path = g_strdup_printf("%s%s", (str[0] == '/') ? "file://" : "", str); } xmlFree(str); } barry-0.18.5/opensync-plugin/patches/kitchensync-svn-20070712-enable.patch0000644001161500056700000000153612242254476025335 0ustar cdfreycdfreyChris Frey This patch enables objtypes, which is useful when running the file-sync plugin from the KitchenSync GUI. Without this patch, syncing against a file-sync for testing tends to end up with an empty file-sync directory. This patch applies to the 2007/07/12 snapshot of the KitchenSync SVN tree. Index: kitchensync/src/syncprocess.cpp =================================================================== --- kitchensync/src/syncprocess.cpp (revision 687137) +++ kitchensync/src/syncprocess.cpp (working copy) @@ -98,6 +98,7 @@ * * mGroup.setObjectTypeEnabled( objectTypes[ i ], true ); */ + mGroup.setObjectTypeEnabled( objectTypes[ i ], true ); } else { kdDebug() << "Disabled object type: " << objectTypes[ i ] << endl; mGroup.setObjectTypeEnabled( objectTypes[ i ], false ); barry-0.18.5/opensync-plugin/patches/README0000644001161500056700000000017012242254476017713 0ustar cdfreycdfreyThis directory contains various patches used during development to make the installation and syncing process smoother. barry-0.18.5/opensync-plugin/AUTHORS0000644001161500056700000000021212242254476016451 0ustar cdfreycdfreyWritten by Chris Frey based on the example plugin skeleton from opensync See ../AUTHORS for project-wide list. barry-0.18.5/opensync-plugin/debian/0000755001161500056700000000000012242254476016630 5ustar cdfreycdfreybarry-0.18.5/opensync-plugin/debian/copyright0000644001161500056700000000472512242254476020573 0ustar cdfreycdfreyThis package was debianized by Chris Frey on Fri, 29 Dec 2006 20:34:01 -0500. It was downloaded from http://sourceforge.net/projects/barry Upstream Authors: Chris Frey Copyright: Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2007-2013, Chris Frey Copyright (C) 2008, Brian Edginton (edge@edginton.net) Copyright (C) 1995-9 by Cryptography Research, Inc. Copyright (C) 2003 Ximian, Inc. 2005 Armin Bauer Copyright (C) 2008-2009, Nicolas VIVIEN Copyright (C) 2009, Josh Kropf For scripts in contrib/ directory: Copyright (C) 2008 Niels de Vos Copyright (C) 2008, ashley willis License: 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. 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. On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL'. For opensync-plugin/src/vformat.[c,h]: 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 St, Fifth Floor, Boston, MA 02110-1301 USA On Debian systems, the complete text of the GNU Lesser General Public License can be found in `/usr/share/common-licenses/LGPL'. barry-0.18.5/opensync-plugin/debian/changelog0000644001161500056700000000125112242254476020501 0ustar cdfreycdfreyopensync0-plugin-barry (0.18.5-1) unstable; urgency=low * New upstream version 0.18.5 -- Chris Frey Sun, 17 Nov 2013 17:31:39 -0500 opensync0-plugin-barry (0.18.4-1) unstable; urgency=low * Individual package for the 0.22 plugin * Bumped compat to level 6 (2011/06/28) * Removed .la files (2011/07/05) * Renamed package to opensync0-plugin-barry (2011/10/11) * Bumped compat to level 7 (2012/03/03) * Bumped Standards-Version to 3.9.1 (2012/03/03) * Using >0 debian version, since I'll probably be Debian maintainer now * Added barry-opensync-plugin.mo files -- Chris Frey Fri, 04 Apr 2013 01:33:39 -0400 barry-0.18.5/opensync-plugin/debian/control0000644001161500056700000000212412242254476020232 0ustar cdfreycdfreySource: opensync0-plugin-barry Section: misc Priority: optional Maintainer: Chris Frey Build-Depends: debhelper (>= 7.0.0), g++ (>= 4.1), cdbs, autoconf, automake, libtool, pkg-config, libusb-dev, zlib1g-dev, libopensync0-dev (>= 0.22), libopensync0-dev (<< 0.30), libbarry-dev (>= 0.18) Standards-Version: 3.9.3 Package: opensync0-plugin-barry Section: libs Architecture: any Depends: libopensync0 (>= 0.22), libopensync0 (<< 0.30), ${shlibs:Depends} Description: Opensync Blackberry plugin, based on the Barry project Barry is a GPL C++ library for interfacing with the RIM BlackBerry Handheld. . This package contains an opensync plugin for use with libopensync 0.22. Package: opensync0-plugin-barry-dbg Section: debug Priority: extra Architecture: any Depends: libopensync0 (>= 0.22), libopensync0 (<< 0.30), opensync0-plugin-barry (= ${binary:Version}) Description: Opensync Blackberry plugin, based on the Barry project Barry is a GPL C++ library for interfacing with the RIM BlackBerry Handheld. . This package contains the debug version of the Barry opensync plugin. barry-0.18.5/opensync-plugin/debian/compat0000644001161500056700000000000212242254476020026 0ustar cdfreycdfrey7 barry-0.18.5/opensync-plugin/debian/rules0000755001161500056700000000303712242254476017713 0ustar cdfreycdfrey#!/usr/bin/make -f # Based on the multi2 sample debian/rules file: # --- # Sample debian/rules that uses debhelper. # This file is public domain software, originally written by Joey Hess. #export DH_VERBOSE=1 include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/autotools.mk #include /usr/share/cdbs/1/rules/simple-patchsys.mk # where sources are DEB_SRCDIR = . # in which directory to build DEB_BUILDDIR = . # in which directory to install the sofware(must be full path! CURDIR does this) DEB_DESTDIR = $(CURDIR)/debian/tmp #CDBS automatically handles common flags to pass to the configure script, #but it is possible to give some extra parameters : DEB_CONFIGURE_EXTRA_FLAGS := --enable-rpathhack COMMON_CONFIGURE_FLAGS := --prefix=/usr DEB_INSTALL_DOCS_ALL = post-patches:: @rm -f $(CURDIR)/deb_srcdir @ln -s $(DEB_SRCDIR) $(CURDIR)/deb_srcdir @test -x $(DEB_SRCDIR)/configure && echo "allready autoreconf" || (cd $(DEB_SRCDIR) && autoreconf -i) makebuilddir:: # This rule is meant for the parent debian/rules to be able to call # us, and give us the location of a pre-built libbarry to # insert into our DESTDIR, to avoid needing to install # libbarry-dev to build this package. # If TREE_BUILD_DIR is empty, nothing happens. (if [ -n "$(TREE_BUILD_DIR)" ] ; then \ cd $(TREE_BUILD_DIR) && \ make DESTDIR=$(DEB_DESTDIR) install && \ rm -f `find $(DEB_DESTDIR) -name "*.la"` && \ cp $(TREE_BUILD_DIR)/debian/libbarry*/DEBIAN/shlibs \ $(CURDIR)/debian/shlibs.local ; \ fi) clean:: -@rm -f $(CURDIR)/deb_srcdir barry-0.18.5/opensync-plugin/debian/opensync0-plugin-barry-dbg.install0000644001161500056700000000000112242254476025270 0ustar cdfreycdfrey barry-0.18.5/opensync-plugin/debian/opensync0-plugin-barry.install0000644001161500056700000000025012242254476024544 0ustar cdfreycdfreydebian/tmp/usr/lib/opensync/plugins/barry_sync.so debian/tmp/usr/share/opensync/defaults/barry-sync debian/tmp/usr/share/locale/*/LC_MESSAGES/barry-opensync-plugin.mo barry-0.18.5/opensync-plugin/src/0000755001161500056700000000000012242254476016175 5ustar cdfreycdfreybarry-0.18.5/opensync-plugin/src/idmap.h0000644001161500056700000000471712242254476017451 0ustar cdfreycdfrey// // \file uidmap.h // Class that maps opensync UID strings to Blackberry // Record ID's and back. // /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_SYNC_UIDMAP_H__ #define __BARRY_SYNC_UIDMAP_H__ #include #include #include class idmap { public: typedef std::string uid_type; typedef uint32_t rid_type; // record ID typedef std::map map_type; typedef map_type::iterator iterator; typedef map_type::const_iterator const_iterator; private: // blank objects, so references work uid_type m_blank_uid; rid_type m_blank_rid; // the map data map_type m_map; public: idmap(); ~idmap(); bool Load(const char *filename); bool Save(const char *filename) const; bool UidExists(const uid_type &uid, const_iterator *it = 0) const; bool RidExists(const rid_type &rid, const_iterator *it = 0) const; const uid_type& GetUid(const rid_type &rid) const; const rid_type& GetRid(const uid_type &uid) const; const uid_type& operator[] (const rid_type &rid) const; const rid_type& operator[] (const uid_type &uid) const; // returns map::end() if either id already exists, otherwise // returns newly mapped item iterator. // // The other versions of the function are to make conversion // between different types easier, giving ability to map // with any reasonable type, and then access the real // values through the iterator if needed. const_iterator Map(const uid_type &uid, const rid_type &rid); const_iterator Map(unsigned long uid_number, const rid_type &rid); const_iterator Map(unsigned long uid_number, const std::string &rid_string); void Unmap(iterator i) { m_map.erase(i); } void UnmapUid(const uid_type &uid); void UnmapRid(const rid_type &rid); // some stl-like functions iterator begin() { return m_map.begin(); } iterator end() { return m_map.end(); } void clear() { m_map.clear(); } }; #endif barry-0.18.5/opensync-plugin/src/i18n.h0000644001161500056700000000233712242254476017132 0ustar cdfreycdfrey/// /// \file i18n.h /// Common internationalization defines, via gettext /// NOTE! This is a private header, not to be installed! /// /* Copyright (C) 2009, Nicolas VIVIEN Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_OSPLUGIN_I18N_H__ #define __BARRY_OSPLUGIN_I18N_H__ #include #include // Set the DEFAULT_TEXT_DOMAIN so that gettext.h uses dgettext() // instead of gettext(). This way we don't have to call textdomain() // and hope that nobody changes it on us later. #define DEFAULT_TEXT_DOMAIN PACKAGE #include "gettext.h" #define _(String) gettext (String) #define N_(String) String #endif barry-0.18.5/opensync-plugin/src/vcard.h0000644001161500056700000000433012242254476017445 0ustar cdfreycdfrey/// /// \file vcard.h /// Conversion routines for vcards /// /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYSYNC_VCARD_H__ #define __BARRYSYNC_VCARD_H__ #include #include #include // forward declarations class BarryEnvironment; class VCardConverter { char *m_Data; Barry::Contact m_Contact; uint32_t m_RecordId; std::string m_last_errmsg; public: VCardConverter(); explicit VCardConverter(uint32_t newRecordId); ~VCardConverter(); const std::string& GetLastError() const { return m_last_errmsg; } // Transfers ownership of m_Data to the caller char* ExtractData(); // Parses vevent data bool ParseData(const char *data); // Barry storage operator void operator()(const Barry::Contact &rec); // Barry builder operator bool operator()(Barry::Contact &rec, Barry::Builder &); // Handles calling of the Barry::Controller to fetch a specific // record, indicated by index (into the RecordStateTable). // Returns a g_malloc'd string of data containing the vevent20 // data. It is the responsibility of the caller to free it. // This is intended to be passed into the GetChanges() function. static char* GetRecordData(BarryEnvironment *env, unsigned int dbId, Barry::RecordStateTable::IndexType index); // Handles either adding or overwriting a calendar record, // given vevent20 data in data, and the proper environmebnt, // dbId, StateIndex. Set add to true if adding. static bool CommitRecordData(BarryEnvironment *env, unsigned int dbId, Barry::RecordStateTable::IndexType StateIndex, uint32_t recordId, const char *data, bool add, std::string &errmsg); }; #endif barry-0.18.5/opensync-plugin/src/vevent.cc0000644001161500056700000001262512242254476020021 0ustar cdfreycdfrey// // \file vevent.cc // Conversion routines for vevents (VCALENDAR, etc) // /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include #include "vevent.h" #include "environment.h" #include "trace.h" #include #include #include #include #include "i18n.h" using namespace Barry::Sync; ////////////////////////////////////////////////////////////////////////////// // VEventConverter::VEventConverter() : m_Data(0) { } VEventConverter::VEventConverter(uint32_t newRecordId) : m_Data(0), m_RecordId(newRecordId) { } VEventConverter::~VEventConverter() { if( m_Data ) g_free(m_Data); } // Transfers ownership of m_Data to the caller char* VEventConverter::ExtractData() { Trace trace("VEventConverter::ExtractData"); char *ret = m_Data; m_Data = 0; return ret; } bool VEventConverter::ParseData(const char *data) { Trace trace("VEventConverter::ParseData"); try { vTimeConverter vtc; vCalendar vcal(vtc); m_Cal = vcal.ToBarry(data, m_RecordId); } catch( Barry::ConvertError &ce ) { trace.logf(_("ERROR: vevent:Barry::ConvertError exception: %s"), ce.what()); m_last_errmsg = ce.what(); return false; } return true; } bool VEventConverter::MergeData(const Barry::Calendar &origin) { // Save CalendarID value // CalendarID field is used to link an entry event to an account mail if (origin.CalendarID != m_Cal.CalendarID) m_Cal.CalendarID = origin.CalendarID; return true; } // Barry storage operator void VEventConverter::operator()(const Barry::Calendar &rec) { Trace trace("VEventConverter::operator()"); // Delete data if some already exists if( m_Data ) { g_free(m_Data); m_Data = 0; } // Keep a trace of Calendar object (need to merge with the new event) m_Cal = rec; try { vTimeConverter vtc; vCalendar vcal(vtc); vcal.ToVCal(rec); m_Data = vcal.ExtractVCal(); } catch( Barry::ConvertError &ce ) { trace.logf(_("ERROR: vevent:Barry::ConvertError exception: %s"), ce.what()); m_last_errmsg = ce.what(); } } // Barry builder operator bool VEventConverter::operator()(Barry::Calendar &rec, Barry::Builder &) { Trace trace("VEventConverter::builder operator()"); rec = m_Cal; return true; } // Handles calling of the Barry::Controller to fetch a specific // record, indicated by index (into the RecordStateTable). // Returns a g_malloc'd string of data containing the vevent20 // data. It is the responsibility of the caller to free it. // This is intended to be passed into the GetChanges() function. char* VEventConverter::GetRecordData(BarryEnvironment *env, unsigned int dbId, Barry::RecordStateTable::IndexType index) { Trace trace("VEventConverter::GetRecordData()"); using namespace Barry; VEventConverter cal2event; RecordParser parser(cal2event); env->GetDesktop()->GetRecord(dbId, index, parser); return cal2event.ExtractData(); } bool VEventConverter::CommitRecordData(BarryEnvironment *env, unsigned int dbId, Barry::RecordStateTable::IndexType StateIndex, uint32_t recordId, const char *data, bool add, std::string &errmsg) { Trace trace("VEventConverter::CommitRecordData()"); uint32_t newRecordId; if( add ) { // use given id if possible if( recordId && !env->m_CalendarSync.m_Table.GetIndex(recordId) ) { // recordId is unique and non-zero newRecordId = recordId; } else { trace.log(_("Can't use recommended recordId, generating new one.")); newRecordId = env->m_CalendarSync.m_Table.MakeNewRecordId(); } } else { newRecordId = env->m_CalendarSync.m_Table.StateMap[StateIndex].RecordId; } trace.logf("newRecordId: %lu", newRecordId); VEventConverter convert(newRecordId); if( !convert.ParseData(data) ) { std::ostringstream oss; oss << _("unable to parse change data for new RecordId: ") << newRecordId << " (" << convert.GetLastError() << ") " << _("data: ") << data; errmsg = oss.str(); trace.log(errmsg.c_str()); return false; } // If we modify a data, we read at first its current value // then we merge with the parsed value from the other opensync member // Merge function is important because, we have to save some BlackBerry fields. // Fix an issue with the new OS release who supports several calendar. if( !add ) { using namespace Barry; VEventConverter cal2event; RecordParser parser(cal2event); env->GetDesktop()->GetRecord(dbId, StateIndex, parser); Calendar cal = cal2event.GetCalendar(); convert.MergeData(cal); } Barry::RecordBuilder builder(convert); if( add ) { trace.log(_("adding record")); env->GetDesktop()->AddRecord(dbId, builder); } else { trace.log(_("setting record")); env->GetDesktop()->SetRecord(dbId, StateIndex, builder); trace.log(_("clearing dirty flag")); env->GetDesktop()->ClearDirty(dbId, StateIndex); } return true; } barry-0.18.5/opensync-plugin/src/vcard.cc0000644001161500056700000001073312242254476017607 0ustar cdfreycdfrey/// /// \file vcard.cc /// Conversion routines for vcards /// /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "environment.h" #include "trace.h" #include "vcard.h" #include #include #include #include #include #include #include "i18n.h" using namespace Barry::Sync; ////////////////////////////////////////////////////////////////////////////// // VCardConverter::VCardConverter() : m_Data(0) { } VCardConverter::VCardConverter(uint32_t newRecordId) : m_Data(0), m_RecordId(newRecordId) { } VCardConverter::~VCardConverter() { if( m_Data ) g_free(m_Data); } // Transfers ownership of m_Data to the caller char* VCardConverter::ExtractData() { Trace trace("VCardConverter::ExtractData"); char *ret = m_Data; m_Data = 0; return ret; } bool VCardConverter::ParseData(const char *data) { Trace trace("VCardConverter::ParseData"); try { vCard vcard; m_Contact = vcard.ToBarry(data, m_RecordId); } catch( Barry::ConvertError &ce ) { trace.logf(_("ERROR: vcard:Barry::ConvertError exception: %s"), ce.what()); m_last_errmsg = ce.what(); return false; } return true; } // Barry storage operator void VCardConverter::operator()(const Barry::Contact &rec) { Trace trace("VCardConverter::operator()"); // Delete data if some already exists if( m_Data ) { g_free(m_Data); m_Data = 0; } try { vCard vcard; vcard.ToVCard(rec); m_Data = vcard.ExtractVCard(); } catch( Barry::ConvertError &ce ) { trace.logf(_("ERROR: vcard:Barry::ConvertError exception: %s"), ce.what()); m_last_errmsg = ce.what(); } } // Barry builder operator bool VCardConverter::operator()(Barry::Contact &rec, Barry::Builder &) { Trace trace("VCardConverter::builder operator()"); rec = m_Contact; return true; } // Handles calling of the Barry::Controller to fetch a specific // record, indicated by index (into the RecordStateTable). // Returns a g_malloc'd string of data containing the vcard30 // data. It is the responsibility of the caller to free it. // This is intended to be passed into the GetChanges() function. char* VCardConverter::GetRecordData(BarryEnvironment *env, unsigned int dbId, Barry::RecordStateTable::IndexType index) { Trace trace("VCardConverter::GetRecordData()"); using namespace Barry; VCardConverter contact2vcard; RecordParser parser(contact2vcard); env->GetDesktop()->GetRecord(dbId, index, parser); return contact2vcard.ExtractData(); } bool VCardConverter::CommitRecordData(BarryEnvironment *env, unsigned int dbId, Barry::RecordStateTable::IndexType StateIndex, uint32_t recordId, const char *data, bool add, std::string &errmsg) { Trace trace("VCardConverter::CommitRecordData()"); uint32_t newRecordId; if( add ) { // use given id if possible if( recordId && !env->m_ContactsSync.m_Table.GetIndex(recordId) ) { // recordId is unique and non-zero newRecordId = recordId; } else { trace.log(_("Can't use recommended recordId, generating new one.")); newRecordId = env->m_ContactsSync.m_Table.MakeNewRecordId(); } } else { newRecordId = env->m_ContactsSync.m_Table.StateMap[StateIndex].RecordId; } trace.logf("newRecordId: %lu", newRecordId); VCardConverter convert(newRecordId); if( !convert.ParseData(data) ) { std::ostringstream oss; oss << _("unable to parse change data for new RecordId: ") << newRecordId << " (" << convert.GetLastError() << ") " << _("data: ") << data; errmsg = oss.str(); trace.log(errmsg.c_str()); return false; } Barry::RecordBuilder builder(convert); if( add ) { trace.log(_("adding record")); env->GetDesktop()->AddRecord(dbId, builder); } else { trace.log(_("setting record")); env->GetDesktop()->SetRecord(dbId, StateIndex, builder); trace.log(_("clearing dirty flag")); env->GetDesktop()->ClearDirty(dbId, StateIndex); } return true; } barry-0.18.5/opensync-plugin/src/barry-sync0000644001161500056700000000126312242254476020213 0ustar cdfreycdfrey# # This is the default configuration file for the barry-sync opensync plugin. # Comments are preceded by a '#' mark at the beginning of a line. # The config format is a set of lines of . # # Keywords available: # # DebugMode - If present, verbose USB debug output will be enabled # # Device - If present, it is followed by the following values: # PIN number - PIN number of the device to sync with (in hex) # sync calendar - 1 to sync calendar, 0 to skip # sync contacts - 1 to sync contacts, 0 to skip # # Password secret - If present, specifies the device's password in plaintext # #DebugMode Device 3009efe3 1 1 #Password secret barry-0.18.5/opensync-plugin/src/idmap.cc0000644001161500056700000000670112242254476017602 0ustar cdfreycdfrey// // \file idmap.cc // Class that maps opensync UID strings to Blackberry // Record ID's and back. // /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "idmap.h" #include #include "trace.h" idmap::idmap() : m_blank_uid(""), m_blank_rid(0) { } idmap::~idmap() { } bool idmap::Load(const char *filename) { // start fresh m_map.clear(); std::ifstream ifs(filename); if( !ifs ) return false; std::string line; uint32_t recordId; while( ifs ) { recordId = 0; ifs >> recordId >> std::ws; std::getline(ifs, line); if( ifs && recordId && line.size() ) { Map(line, recordId); } } return ifs.eof(); } bool idmap::Save(const char *filename) const { std::ofstream ofs(filename); if( !ofs ) return false; const_iterator i = m_map.begin(); for( ; i != m_map.end(); ++i ) { ofs << i->second << " " << i->first << std::endl; } return !ofs.bad() && !ofs.fail(); } bool idmap::UidExists(const uid_type &uid, const_iterator *it) const { const_iterator i = m_map.find(uid); if( it ) *it = i; return i != m_map.end(); } bool idmap::RidExists(const rid_type &rid, const_iterator *it) const { const_iterator i = m_map.begin(); for( ; i != m_map.end(); ++i ) { if( i->second == rid ) { if( it ) *it = i; return true; } } if( it ) *it = m_map.end(); return false; } const idmap::uid_type& idmap::GetUid(const rid_type &rid) const { const_iterator i = m_map.begin(); for( ; i != m_map.end(); ++i ) { if( i->second == rid ) return i->first; } return m_blank_uid; } const idmap::rid_type& idmap::GetRid(const uid_type &uid) const { const_iterator i = m_map.find(uid); return i->second; } const idmap::uid_type& idmap::operator[] (const rid_type &rid) const { return GetUid(rid); } const idmap::rid_type& idmap::operator[] (const uid_type &uid) const { return GetRid(uid); } // returns map::end() if either id already exists, otherwise // returns newly mapped item iterator. // // The other versions of the function are to make conversion // between different types easier, giving ability to map // with any reasonable type, and then access the real // values through the iterator if needed. idmap::const_iterator idmap::Map(const uid_type &uid, const rid_type &rid) { // neither id can be blank if( uid.size() == 0 || rid == 0 ) return m_map.end(); // neither id must already exist if( UidExists(uid) || RidExists(rid) ) return m_map.end(); return m_map.insert(m_map.begin(), make_pair(uid, rid)); } /* idmap::const_iterator idmap::Map(unsigned long uid_number, const rid_type &rid) { } idmap::const_iterator idmap::Map(unsigned long uid_number, const std::string &rid_string) { } */ void idmap::UnmapUid(const uid_type &uid) { m_map.erase(uid); } void idmap::UnmapRid(const rid_type &rid) { iterator i = m_map.begin(); for( ; i != m_map.end(); ++i ) { if( i->second == rid ) { m_map.erase(i); return; } } } barry-0.18.5/opensync-plugin/src/Makefile.am0000644001161500056700000000272012242254476020232 0ustar cdfreycdfreybarry_syncdir=@OPENSYNC_PLUGINDIR@ configdir=@OPENSYNC_CONFIGDIR@ #formatsdir=@OPENSYNC_FORMATSDIR@ opensyncheaderdir=@OPENSYNC_HEADERDIR@ # To use gettext datadir = @datadir@ localedir = $(datadir)/locale DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@ INCLUDES = @TREE_BUILD_CXXFLAGS@ @GLIB2_CFLAGS@ @OPENSYNC2X_CFLAGS@ @BARRY_CFLAGS@ @BARRYSYNC_CFLAGS@ LIBS = @TREE_BUILD_LDFLAGS@ @GLIB2_LIBS@ @OPENSYNC2X_LIBS@ @BARRY_LIBS@ @BARRYSYNC_LIBS@ AM_CFLAGS = -Wall -Werror AM_CXXFLAGS = -Wall -Werror AM_LDFLAGS = if WITH_GCCVISIBILITY AM_CFLAGS += -D__BARRY_HAVE_GCCVISIBILITY__ -fvisibility=hidden #AM_CXXFLAGS += -D__BARRY_HAVE_GCCVISIBILITY__ -fvisibility=hidden -fvisibility-inlines-hidden AM_CXXFLAGS += -D__BARRY_HAVE_GCCVISIBILITY__ -fvisibility=hidden #AM_LDFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden AM_LDFLAGS += -fvisibility=hidden endif EXTRA_DIST = barry_sync.h dist_config_DATA = barry-sync noinst_HEADERS = i18n.h gettext.h opensyncheader_HEADER = barry_sync.h barry_sync_LTLIBRARIES = barry_sync.la barry_sync_la_SOURCES = \ barry_sync.cc barry_sync.h \ environment.cc environment.h \ vevent.cc vevent.h \ vcard.cc vcard.h \ idmap.cc idmap.h \ trace.h barry_sync_la_LDFLAGS = -avoid-version -export-dynamic -module barry_sync_la_LIBADD = $(LIBS) ## if you plan to install format libraries: ## #formats_LTLIBRARIES = format.la # #format_la_SOURCES = format.c #format_la_LDFLAGS = -avoid-version -export-dynamic -module #format_la_LIBADD = $(LIBS) barry-0.18.5/opensync-plugin/src/trace.h0000644001161500056700000000330212242254476017442 0ustar cdfreycdfrey// // \file trace.h // RAII class for trace logging. // /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_SYNC_TRACE_H__ #define __BARRY_SYNC_TRACE_H__ #include #include #include class Trace { const char *text, *tag; public: explicit Trace(const char *t) : text(t), tag(0) { osync_trace(TRACE_ENTRY, "barry_sync: %s", text); } Trace(const char *t, const char *tag) : text(t), tag(tag) { osync_trace(TRACE_ENTRY, "barry_sync (%s): %s", tag, text); } ~Trace() { if( tag ) osync_trace(TRACE_EXIT, "barry_sync (%s): %s", tag, text); else osync_trace(TRACE_EXIT, "barry_sync: %s", text); } void log(const char *t) { osync_trace(TRACE_INTERNAL, "barry_sync: %s", t); } void logf(const char *t, ...) { va_list vl; va_start(vl, t); char buffer[2048]; int n = vsnprintf(buffer, sizeof(buffer), t, vl); va_end(vl); if( n > -1 && n < (int)sizeof(buffer) ) osync_trace(TRACE_INTERNAL, "barry_sync: %s", buffer); else osync_trace(TRACE_INTERNAL, "barry_sync: (trace error, output too long for buffer: %s)", t); } }; #endif barry-0.18.5/opensync-plugin/src/environment.h0000644001161500056700000000514312242254476020715 0ustar cdfreycdfrey// // \file environment.h // Container / environment class for the sync module. // /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_SYNC_ENVIRONMENT_H__ #define __BARRY_SYNC_ENVIRONMENT_H__ #include #include #include #include #include "idmap.h" struct DatabaseSyncState { public: // cache is a map of record ID to bool... the bool doesn't mean // anything... the mere existence of the ID means it belongs // in the cache typedef std::map cache_type; public: // cache data std::string m_CacheFilename; cache_type m_Cache; // id map data std::string m_MapFilename; idmap m_IdMap; // device data unsigned int m_dbId; std::string m_dbName; Barry::RecordStateTable m_Table; bool m_Sync; private: std::string m_Desc; public: DatabaseSyncState(OSyncMember *pm, const char *description); ~DatabaseSyncState(); bool LoadCache(); bool SaveCache(); bool LoadMap(); bool SaveMap(); void CleanupMap(); void ClearDirtyFlags(); std::string Map2Uid(uint32_t recordId) const; unsigned long GetMappedRecordId(const std::string &uid); }; struct BarryEnvironment { private: std::string m_password; public: OSyncMember *member; // user config data std::string m_ConfigData; uint32_t m_pin; bool m_DebugMode; // device communication std::auto_ptr m_con; // sync data DatabaseSyncState m_CalendarSync, m_ContactsSync; protected: void DoConnect(); public: BarryEnvironment(OSyncMember *pm); ~BarryEnvironment(); Barry::Mode::Desktop* GetDesktop() { return &m_con->GetDesktop(); } void SetPassword(const std::string &password); void Connect(const Barry::ProbeResult &result); void Reconnect(); void Disconnect(); DatabaseSyncState* GetSyncObject(OSyncChange *change); void ParseConfig(const char *data, int size); void BuildConfig(); void ClearDirtyFlags(Barry::RecordStateTable &table, const std::string &dbname); void ClearCalendarDirtyFlags(); void ClearContactsDirtyFlags(); }; #endif barry-0.18.5/opensync-plugin/src/barry_sync.cc0000644001161500056700000004110012242254476020653 0ustar cdfreycdfrey// // \file barry_sync.cc // Opensync module for the USB Blackberry handheld // /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include #include #include #include "barry_sync.h" #include "environment.h" #include "vevent.h" #include "vcard.h" #include "trace.h" #include "config.h" #include "i18n.h" #include #include #include #include #include // All functions that are callable from outside must look like C extern "C" { static void *initialize(OSyncMember *member, OSyncError **error); static void connect(OSyncContext *ctx); static void get_changeinfo(OSyncContext *ctx); static void sync_done(OSyncContext *ctx); static void disconnect(OSyncContext *ctx); static void finalize(void *data); BXEXPORT void get_info(OSyncEnv *env); } ////////////////////////////////////////////////////////////////////////////// // // Support functions and classes // void GetChanges(OSyncContext *ctx, BarryEnvironment *env, DatabaseSyncState *pSync, const char *DBDBName, const char *ObjTypeName, const char *FormatName, GetData_t getdata) { Trace trace("GetChanges"); // shortcut references using namespace Barry; using Barry::RecordStateTable; Mode::Desktop &desktop = *env->GetDesktop(); // find the matching cache, state table, and id map for this change DatabaseSyncState::cache_type &cache = pSync->m_Cache; idmap &map = pSync->m_IdMap; // check if slow sync has been requested, and if so, empty the // cache and id map and start fresh if( osync_member_get_slow_sync(env->member, ObjTypeName) ) { trace.log(_("GetChanges: slow sync request detected, clearing cache and id map")); cache.clear(); map.clear(); } // fetch state table unsigned int dbId = desktop.GetDBID(DBDBName); RecordStateTable &table = pSync->m_Table; desktop.GetRecordStateTable(dbId, table); // cycle through the state table... // - if not in cache, it is added. // - if in cache, check Blackberry's dirty flag RecordStateTable::StateMapType::const_iterator i = table.StateMap.begin(); for( ; i != table.StateMap.end(); ++i ) { OSyncChange *change = 0; const RecordStateTable::IndexType &index = i->first; const RecordStateTable::State &state = i->second; // search the idmap for the UID std::string uid = pSync->Map2Uid(state.RecordId); // search the cache DatabaseSyncState::cache_type::const_iterator c = cache.find(state.RecordId); if( c == cache.end() ) { // not in cache, this is a new item trace.log(_("found an ADDED change")); change = osync_change_new(); osync_change_set_changetype(change, CHANGE_ADDED); } else { // in the cache... dirty? if( state.Dirty ) { // modified trace.log(_("found a MODIFIED change")); change = osync_change_new(); osync_change_set_changetype(change, CHANGE_MODIFIED); } else { trace.log(_("no change detected")); } } // finish filling out the change object if( change ) { osync_change_set_member(change, env->member); osync_change_set_objformat_string(change, FormatName); osync_change_set_uid(change, uid.c_str()); trace.logf(_("change record ID: %s"), uid.c_str()); // Now you can set the data for the object // Set the last argument to FALSE if the real data // should be queried later in a "get_data" function char *data = (*getdata)(env, dbId, index); osync_change_set_data(change, data, strlen(data), TRUE); // just report the change via osync_context_report_change(ctx, change); // map our IDs for later map.Map(uid, state.RecordId); } } // now cycle through the cache... any objects in the cache // but not found in the state table means that they have been // deleted in the device DatabaseSyncState::cache_type::const_iterator c = cache.begin(); for( ; c != cache.end(); ++c ) { uint32_t recordId = c->first; // search the idmap for the UID std::string uid = pSync->Map2Uid(recordId); // search the state table i = table.StateMap.begin(); for( ; i != table.StateMap.end(); ++i ) { if( i->second.RecordId == recordId ) break; // found } // check if not found... if( i == table.StateMap.end() ) { // register a DELETE, no data trace.log(_("found DELETE change")); OSyncChange *change = osync_change_new(); osync_change_set_changetype(change, CHANGE_DELETED); osync_change_set_member(change, env->member); osync_change_set_objformat_string(change, FormatName); osync_change_set_uid(change, uid.c_str()); trace.log(uid.c_str()); // report the change osync_context_report_change(ctx, change); } } // finally, cycle through the state map again, and overwrite the // cache with the current state table. Memory only... if successful, // it will be written back to disk later on. // start fresh cache.clear(); for( i = table.StateMap.begin(); i != table.StateMap.end(); ++i ) { const RecordStateTable::State &state = i->second; cache[state.RecordId] = false; } } CommitData_t GetCommitFunction(OSyncChange *change) { OSyncObjType *type = osync_change_get_objtype(change); const char *name = osync_objtype_get_name(type); if( strcmp(name, "event") == 0 ) { return &VEventConverter::CommitRecordData; } else if( strcmp(name, "contact") == 0 ) { return &VCardConverter::CommitRecordData; } else { return 0; } } bool FinishSync(OSyncContext *ctx, BarryEnvironment *env, DatabaseSyncState *pSync) { Trace trace("FinishSync()"); if( !pSync->m_Sync ) { // this mode is disabled in config, skip return true; } Barry::Mode::Desktop &desktop = *env->GetDesktop(); // get the state table again, so we can update // the cache properly desktop.GetRecordStateTable(pSync->m_dbId, pSync->m_Table); // update the cache if( !pSync->SaveCache() ) { osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, _("Error saving calendar cache")); return false; } // save the id map pSync->CleanupMap(); if( !pSync->SaveMap() ) { osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, _("Error saving calendar id map")); return false; } // clear all dirty flags in device env->ClearDirtyFlags(pSync->m_Table, pSync->m_dbName); return true; } ////////////////////////////////////////////////////////////////////////////// // // OpenSync API // static void *initialize(OSyncMember *member, OSyncError **error) { Trace trace("initialize"); BarryEnvironment *env = 0; // Create the environment struct, including our Barry objects try { env = new BarryEnvironment(member); // Load config file for this plugin char *configdata; int configsize; if (!osync_member_get_config(member, &configdata, &configsize, error)) { osync_error_update(error, _("Unable to get config data: %s"), osync_error_print(error)); delete env; return NULL; } // Process the configdata here and set the options on your environment env->ParseConfig(configdata, configsize); free(configdata); // FIXME - near the end of release, do a run with // this set to true, and look for USB protocol // inefficiencies. Barry::Init(env->m_DebugMode); // Load all needed cache files if( env->m_CalendarSync.m_Sync ) { env->m_CalendarSync.LoadCache(); env->m_CalendarSync.LoadMap(); } if( env->m_ContactsSync.m_Sync ) { env->m_ContactsSync.LoadCache(); env->m_ContactsSync.LoadMap(); } return env; } // Don't let C++ exceptions escape to the C code catch( std::bad_alloc &ba ) { osync_error_update(error, _("Unable to allocate memory for environment: %s"), ba.what()); delete env; return NULL; } catch( std::exception &e ) { osync_error_update(error, "%s", e.what()); delete env; return NULL; } } static void connect(OSyncContext *ctx) { Trace trace("connect"); try { // Each time you get passed a context (which is used to track // calls to your plugin) you can get the data your returned in // initialize via this call: BarryEnvironment *env = (BarryEnvironment *)osync_context_get_plugin_data(ctx); // Probe for available devices Barry::Probe probe; int nIndex = probe.FindActive(env->m_pin); if( nIndex == -1 ) { osync_context_report_error(ctx, OSYNC_ERROR_NO_CONNECTION, _("Unable to find PIN %lx"), env->m_pin); return; } env->Connect(probe.Get(nIndex)); // Success! osync_context_report_success(ctx); } // Don't let exceptions escape to the C modules catch( std::bad_alloc &ba ) { osync_context_report_error(ctx, OSYNC_ERROR_INITIALIZATION, _("Unable to allocate memory for controller: %s"), ba.what()); } catch( std::exception &e ) { osync_context_report_error(ctx, OSYNC_ERROR_INITIALIZATION, "%s", e.what()); } } static void get_changeinfo(OSyncContext *ctx) { Trace trace("get_changeinfo"); try { BarryEnvironment *env = (BarryEnvironment *)osync_context_get_plugin_data(ctx); OSyncMember *member = osync_context_get_member(ctx); if( env->m_CalendarSync.m_Sync && osync_member_objtype_enabled(member, "event") ) { GetChanges(ctx, env, &env->m_CalendarSync, "Calendar", "event", "vevent20", &VEventConverter::GetRecordData); } if( env->m_ContactsSync.m_Sync && osync_member_objtype_enabled(member, "contact") ) { GetChanges(ctx, env, &env->m_ContactsSync, "Address Book", "contact", "vcard30", &VCardConverter::GetRecordData); } // Success! osync_context_report_success(ctx); } // don't let exceptions escape to the C modules catch( std::exception &e ) { osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, "%s", e.what()); } } static osync_bool commit_change(OSyncContext *ctx, OSyncChange *change) { Trace trace("commit_change"); // We can rely on a valid record state table, since get_changeinfo() // will be called first, and will fill the table. try { BarryEnvironment *env = (BarryEnvironment *)osync_context_get_plugin_data(ctx); // find the needed commit function, based on objtype of the change CommitData_t CommitData = GetCommitFunction(change); if( !CommitData ) { osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, _("unable to get commit function pointer")); return false; } // find the matching cache, state table, and id map for this change DatabaseSyncState *pSync = env->GetSyncObject(change); if( !pSync ) { osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, _("unable to get sync object that matches change type")); return false; } // is syncing turned on for this type? if( !pSync->m_Sync ) { osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, _("This object type is disabled in the barry-sync config")); return false; } // make references instead of pointers DatabaseSyncState::cache_type &cache = pSync->m_Cache; Barry::RecordStateTable &table = pSync->m_Table; idmap &map = pSync->m_IdMap; Barry::Mode::Desktop &desktop = *env->GetDesktop(); unsigned int dbId = pSync->m_dbId; // extract RecordId from change's UID, // and update the ID map if necessary const char *uid = osync_change_get_uid(change); trace.logf("uid from change: %s", uid); if( strlen(uid) == 0 ) { osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, _("uid from change object is blank!")); } unsigned long RecordId = pSync->GetMappedRecordId(uid); // search for the RecordId in the state table, to find the // index... we only need the index if we are deleting or // modifying Barry::RecordStateTable::IndexType StateIndex; if( osync_change_get_changetype(change) != CHANGE_ADDED ) { if( !table.GetIndex(RecordId, &StateIndex) ) { osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, _("unable to get state table index for RecordId: %lu"), RecordId); return false; } } std::string errmsg; bool status; switch( osync_change_get_changetype(change) ) { case CHANGE_DELETED: desktop.DeleteRecord(dbId, StateIndex); cache.erase(RecordId); map.UnmapUid(uid); break; case CHANGE_ADDED: status = (*CommitData)(env, dbId, StateIndex, RecordId, osync_change_get_data(change), true, errmsg); if( !status ) { trace.logf(_("CommitData() for ADDED state returned false: %s"), errmsg.c_str()); osync_context_report_error(ctx, OSYNC_ERROR_PARAMETER, "%s", errmsg.c_str()); map.UnmapUid(uid); return false; } cache[RecordId] = false; break; case CHANGE_MODIFIED: status = (*CommitData)(env, dbId, StateIndex, RecordId, osync_change_get_data(change), false, errmsg); if( !status ) { trace.logf(_("CommitData() for MODIFIED state returned false: %s"), errmsg.c_str()); osync_context_report_error(ctx, OSYNC_ERROR_PARAMETER, "%s", errmsg.c_str()); map.UnmapUid(uid); return false; } break; default: trace.log(_("Unknown change type")); osync_debug("barry-sync", 0, _("Unknown change type")); break; } // Answer the call osync_context_report_success(ctx); return true; } catch( std::exception &e ) { osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, "%s", e.what()); // we don't worry about unmapping ids here, as there // is still a possibility that the record was added... // plus, the map might not get written out to disk anyway // in a plugin error state return false; } } static void sync_done(OSyncContext *ctx) { // // This function will only be called if the sync was successfull // Trace trace("sync_done"); try { BarryEnvironment *env = (BarryEnvironment *)osync_context_get_plugin_data(ctx); // we reconnect to the device here, since dirty flags // for records we've just touched do not show up until // a disconnect... as far as I can tell. env->Reconnect(); // do cleanup for each database if( FinishSync(ctx, env, &env->m_CalendarSync) && FinishSync(ctx, env, &env->m_ContactsSync) ) { // Success osync_context_report_success(ctx); } } catch( std::exception &e ) { osync_context_report_error(ctx, OSYNC_ERROR_IO_ERROR, "%s", e.what()); } } static void disconnect(OSyncContext *ctx) { Trace trace("disconnect"); // Disconnect the controller, which closes our connection BarryEnvironment *env = (BarryEnvironment *)osync_context_get_plugin_data(ctx); env->Disconnect(); // Done! osync_context_report_success(ctx); } static void finalize(void *data) { Trace trace("finalize"); BarryEnvironment *env = (BarryEnvironment *)data; delete env; } void get_info(OSyncEnv *env) { Trace trace("get_info"); static bool i18n_initialized = false; if( !i18n_initialized ) { // initialize i18n gettext directory // the rest is done in i18n.h setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); i18n_initialized = true; } // Create first plugin OSyncPluginInfo *info = osync_plugin_new_info(env); // not translation for these strings, as I think they are const, // and the info struct relies on their existence info->name = "barry-sync"; info->longname = "Barry OpenSync plugin v" PACKAGE_VERSION " for the Blackberry handheld"; info->description = "Plugin to synchronize calendar and contact entries on USB Blackberry handhelds"; info->version = 1; // API version (opensync api?) info->is_threadsafe = TRUE; info->functions.initialize = initialize; info->functions.connect = connect; info->functions.sync_done = sync_done; info->functions.disconnect = disconnect; info->functions.finalize = finalize; info->functions.get_changeinfo = get_changeinfo; // If you like, you can overwrite the default timeouts of your plugin // The default is set to 60 sec. Note that this MUST NOT be used to // wait for expected timeouts (Lets say while waiting for a webserver). // you should wait for the normal timeout and return a error. // info->timeouts.connect_timeout = 5; // There are more timeouts for the other functions // // Register each supported feature // // Calendar entries, using batch commit osync_plugin_accept_objtype(info, "event"); osync_plugin_accept_objformat(info, "event", "vevent20", NULL); osync_plugin_set_commit_objformat(info, "event", "vevent20", commit_change); // Address Book entries osync_plugin_accept_objtype(info, "contact"); osync_plugin_accept_objformat(info, "contact", "vcard30", NULL); osync_plugin_set_commit_objformat(info, "contact", "vcard30", commit_change); } barry-0.18.5/opensync-plugin/src/gettext.h0000644001161500056700000002242112242254476020033 0ustar cdfreycdfrey/* Convenience header for conditional use of GNU . Copyright (C) 1995-1998, 2000-2002, 2004-2006 Free Software Foundation, Inc. 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, 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 Library 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. */ #ifndef _LIBGETTEXT_H #define _LIBGETTEXT_H 1 /* NLS can be disabled through the configure --disable-nls option. */ #if ENABLE_NLS /* Get declarations of GNU message catalog functions. */ # include /* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by the gettext() and ngettext() macros. This is an alternative to calling textdomain(), and is useful for libraries. */ # ifdef DEFAULT_TEXT_DOMAIN # undef gettext # define gettext(Msgid) \ dgettext (DEFAULT_TEXT_DOMAIN, Msgid) # undef ngettext # define ngettext(Msgid1, Msgid2, N) \ dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) # endif #else /* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which chokes if dcgettext is defined as a macro. So include it now, to make later inclusions of a NOP. We don't include as well because people using "gettext.h" will not include , and also including would fail on SunOS 4, whereas is OK. */ #if defined(__sun) # include #endif /* Many header files from the libstdc++ coming with g++ 3.3 or newer include , which chokes if dcgettext is defined as a macro. So include it now, to make later inclusions of a NOP. */ #if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) # include # if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H # include # endif #endif /* Disabled NLS. The casts to 'const char *' serve the purpose of producing warnings for invalid uses of the value returned from these functions. On pre-ANSI systems without 'const', the config.h file is supposed to contain "#define const". */ # define gettext(Msgid) ((const char *) (Msgid)) # define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) # define dcgettext(Domainname, Msgid, Category) \ ((void) (Category), dgettext (Domainname, Msgid)) # define ngettext(Msgid1, Msgid2, N) \ ((N) == 1 \ ? ((void) (Msgid2), (const char *) (Msgid1)) \ : ((void) (Msgid1), (const char *) (Msgid2))) # define dngettext(Domainname, Msgid1, Msgid2, N) \ ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ ((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N)) # define textdomain(Domainname) ((const char *) (Domainname)) # define bindtextdomain(Domainname, Dirname) \ ((void) (Domainname), (const char *) (Dirname)) # define bind_textdomain_codeset(Domainname, Codeset) \ ((void) (Domainname), (const char *) (Codeset)) #endif /* A pseudo function call that serves as a marker for the automated extraction of messages, but does not call gettext(). The run-time translation is done at a different place in the code. The argument, String, should be a literal string. Concatenated strings and other string expressions won't work. The macro's expansion is not parenthesized, so that it is suitable as initializer for static 'char[]' or 'const char[]' variables. */ #define gettext_noop(String) String /* The separator between msgctxt and msgid in a .mo file. */ #define GETTEXT_CONTEXT_GLUE "\004" /* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be short and rarely need to change. The letter 'p' stands for 'particular' or 'special'. */ #ifdef DEFAULT_TEXT_DOMAIN # define pgettext(Msgctxt, Msgid) \ pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) #else # define pgettext(Msgctxt, Msgid) \ pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) #endif #define dpgettext(Domainname, Msgctxt, Msgid) \ pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) #define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) #ifdef DEFAULT_TEXT_DOMAIN # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) #else # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) #endif #define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) #define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category) #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * pgettext_aux (const char *domain, const char *msg_ctxt_id, const char *msgid, int category) { const char *translation = dcgettext (domain, msg_ctxt_id, category); if (translation == msg_ctxt_id) return msgid; else return translation; } #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * npgettext_aux (const char *domain, const char *msg_ctxt_id, const char *msgid, const char *msgid_plural, unsigned long int n, int category) { const char *translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); if (translation == msg_ctxt_id || translation == msgid_plural) return (n == 1 ? msgid : msgid_plural); else return translation; } /* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID can be arbitrary expressions. But for string literals these macros are less efficient than those above. */ #include #define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \ (((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \ /* || __STDC_VERSION__ >= 199901L */ ) #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS #include #endif #define pgettext_expr(Msgctxt, Msgid) \ dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) #define dpgettext_expr(Domainname, Msgctxt, Msgid) \ dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * dcpgettext_expr (const char *domain, const char *msgctxt, const char *msgid, int category) { size_t msgctxt_len = strlen (msgctxt) + 1; size_t msgid_len = strlen (msgid) + 1; const char *translation; #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS char msg_ctxt_id[msgctxt_len + msgid_len]; #else char buf[1024]; char *msg_ctxt_id = (msgctxt_len + msgid_len <= sizeof (buf) ? buf : (char *) malloc (msgctxt_len + msgid_len)); if (msg_ctxt_id != NULL) #endif { memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); msg_ctxt_id[msgctxt_len - 1] = '\004'; memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); translation = dcgettext (domain, msg_ctxt_id, category); #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS if (msg_ctxt_id != buf) free (msg_ctxt_id); #endif if (translation != msg_ctxt_id) return translation; } return msgid; } #define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) #define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * dcnpgettext_expr (const char *domain, const char *msgctxt, const char *msgid, const char *msgid_plural, unsigned long int n, int category) { size_t msgctxt_len = strlen (msgctxt) + 1; size_t msgid_len = strlen (msgid) + 1; const char *translation; #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS char msg_ctxt_id[msgctxt_len + msgid_len]; #else char buf[1024]; char *msg_ctxt_id = (msgctxt_len + msgid_len <= sizeof (buf) ? buf : (char *) malloc (msgctxt_len + msgid_len)); if (msg_ctxt_id != NULL) #endif { memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); msg_ctxt_id[msgctxt_len - 1] = '\004'; memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS if (msg_ctxt_id != buf) free (msg_ctxt_id); #endif if (!(translation == msg_ctxt_id || translation == msgid_plural)) return translation; } return (n == 1 ? msgid : msgid_plural); } #endif /* _LIBGETTEXT_H */ barry-0.18.5/opensync-plugin/src/environment.cc0000644001161500056700000002011712242254476021051 0ustar cdfreycdfrey// // \file environment.cc // Container / environment class for the sync module. // /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "environment.h" #include "trace.h" #include #include #include #include #include #include #include #include "i18n.h" using namespace Barry; ////////////////////////////////////////////////////////////////////////////// // DatabaseSyncState DatabaseSyncState::DatabaseSyncState(OSyncMember *pm, const char *description) : m_dbId(0), m_Sync(false), m_Desc(description) { m_CacheFilename = m_MapFilename = osync_member_get_configdir(pm); m_CacheFilename += "/barry_" + m_Desc + "_cache.txt"; m_MapFilename += "/barry_" + m_Desc + "_idmap.txt"; } DatabaseSyncState::~DatabaseSyncState() { } bool DatabaseSyncState::LoadCache() { Trace trace("LoadCache", m_Desc.c_str()); m_Cache.clear(); std::ifstream ifs(m_CacheFilename.c_str()); if( !ifs ) return false; while( ifs ) { uint32_t recordId = 0; ifs >> recordId; if( recordId ) { m_Cache[recordId] = false; } } if( !ifs.eof() ) { m_Cache.clear(); // assume full sync trace.log("Load failed!"); return false; } return true; } bool DatabaseSyncState::SaveCache() { Trace trace("SaveCache", m_Desc.c_str()); std::ofstream ofs(m_CacheFilename.c_str()); if( !ofs ) return false; cache_type::const_iterator i = m_Cache.begin(); for( ; i != m_Cache.end(); ++i ) { ofs << i->first << std::endl; } return !ofs.bad() && !ofs.fail(); } bool DatabaseSyncState::LoadMap() { return m_IdMap.Load(m_MapFilename.c_str()); } bool DatabaseSyncState::SaveMap() { return m_IdMap.Save(m_MapFilename.c_str()); } // cycle through the map and search the state table for each rid, // and remove any that do not exist void DatabaseSyncState::CleanupMap() { idmap::iterator i = m_IdMap.begin(); for( ; i != m_IdMap.end(); ++i ) { if( !m_Table.GetIndex(i->second) ) { // Record Id does not exist in state table, so it is // not needed anymore in the ID map m_IdMap.Unmap(i); } } } // // Map2Uid // /// Searches for the given record ID, and returns the mapped UID. If not /// found, it creates a new UID and returns it without mapping it. /// std::string DatabaseSyncState::Map2Uid(uint32_t recordId) const { // search the idmap for the UID std::string uid; idmap::const_iterator mapped_id; if( m_IdMap.RidExists(recordId, &mapped_id) ) { uid = mapped_id->first; } else { // not mapped, map it ourselves char *puid = g_strdup_printf("%s-%u", m_Desc.c_str(), recordId); uid = puid; g_free(puid); } return uid; } unsigned long DatabaseSyncState::GetMappedRecordId(const std::string &uid) { Trace trace("DatabaseSyncState::GetMappedRecordId()", m_Desc.c_str()); // if already in map, use the matching rid idmap::const_iterator it; if( m_IdMap.UidExists(uid, &it) ) { trace.logf(_("found existing uid in map: %lu"), it->second); return it->second; } // nothing in the map, so try to convert the string to a number unsigned long RecordId; if( sscanf(uid.c_str(), "%lu", &RecordId) != 0 ) { trace.logf("parsed uid as: %lu", RecordId); if( m_IdMap.Map(uid, RecordId) != m_IdMap.end() ) return RecordId; trace.logf(_("parsed uid already exists in map, skipping")); } // create one of our own, if we get here... // do this in a loop to keep going until we find an ID that's unique do { RecordId = m_Table.MakeNewRecordId(); } while( m_IdMap.Map(uid, RecordId) == m_IdMap.end() ); trace.logf(_("made new record id: %lu"), RecordId); return RecordId; } ////////////////////////////////////////////////////////////////////////////// // BarryEnvironment Public API BarryEnvironment::BarryEnvironment(OSyncMember *pm) : member(pm), m_pin(-1), m_DebugMode(false), m_CalendarSync(pm, "calendar"), m_ContactsSync(pm, "contacts") { } BarryEnvironment::~BarryEnvironment() { } void BarryEnvironment::DoConnect() { if( !m_con.get() ) throw std::logic_error(_("Tried to use empty Connector")); m_con->Connect(); // Save the DBIDs and DBNames of the databases we will work with if( m_CalendarSync.m_Sync ) { m_CalendarSync.m_dbName = Barry::Calendar::GetDBName(); m_CalendarSync.m_dbId = m_con->GetDesktop().GetDBID(Barry::Calendar::GetDBName()); } if( m_ContactsSync.m_Sync ) { m_ContactsSync.m_dbId = m_con->GetDesktop().GetDBID(Barry::Contact::GetDBName()); m_ContactsSync.m_dbName = Barry::Contact::GetDBName(); } } void BarryEnvironment::SetPassword(const std::string &password) { m_password = password; if( m_con.get() ) m_con->SetPassword(password.c_str()); } void BarryEnvironment::Connect(const Barry::ProbeResult &result) { m_con.reset(new DesktopConnector(m_password.c_str(), "UTF-8", result)); DoConnect(); } void BarryEnvironment::Reconnect() { m_con->Reconnect(2); } void BarryEnvironment::Disconnect() { m_con->Disconnect(); } void BarryEnvironment::ClearDirtyFlags(Barry::RecordStateTable &table, const std::string &dbname) { Trace trace("ClearDirtyFlags"); unsigned int dbId = m_con->GetDesktop().GetDBID(dbname); Barry::RecordStateTable::StateMapType::const_iterator i = table.StateMap.begin(); for( ; i != table.StateMap.end(); ++i ) { if( i->second.Dirty ) { trace.logf(_("Clearing dirty flag for db %u, index %u"), dbId, i->first); m_con->GetDesktop().ClearDirty(dbId, i->first); } } } void BarryEnvironment::ClearCalendarDirtyFlags() { Trace trace("ClearCalendarDirtyFlags"); ClearDirtyFlags(m_CalendarSync.m_Table, Barry::Calendar::GetDBName()); } void BarryEnvironment::ClearContactsDirtyFlags() { Trace trace("ClearContactsDirtyFlags"); ClearDirtyFlags(m_ContactsSync.m_Table, Barry::Contact::GetDBName()); } DatabaseSyncState* BarryEnvironment::GetSyncObject(OSyncChange *change) { Trace trace("BarryEnvironment::GetSyncObject()"); OSyncObjType *type = osync_change_get_objtype(change); const char *name = osync_objtype_get_name(type); if( strcmp(name, "event") == 0 ) { return &m_CalendarSync; } else if( strcmp(name, "contact") == 0 ) { return &m_ContactsSync; } else { return 0; } } void BarryEnvironment::ParseConfig(const char *data, int size) { Trace trace("ParseConfig"); m_ConfigData.assign(data, size); // The config data should contain: // - Keyword: DebugMode // - if the single word "DebugMode" is found, enable Debug // // - Keyword: Device ... // - PIN of device to sync with // - or a flag that says "autoconfig with first device found" // which will autodetect, and update the config // automatically with the found PIN... all future syncs // will then have a PIN // - checkboxes for (both can be on): // - sync calendar items // - sync contacts std::istringstream iss(m_ConfigData); std::string line; while( std::getline(iss, line) ) { if( line[0] == '#' ) continue; std::istringstream ils(line); int cal = 0, con = 0; std::string key; ils >> key; if( key == "DebugMode" ) { m_DebugMode = true; } else if( key == "Device" ) { ils >> std::hex >> m_pin >> cal >> con; std::ostringstream oss; oss << std::hex << m_pin; trace.log(oss.str().c_str()); if( cal ) { m_CalendarSync.m_Sync = true; trace.log(_("calendar syncing enabled")); } if( con ) { m_ContactsSync.m_Sync = true; trace.log(_("contacts syncing enabled")); } } else if ( key == "Password" ) { ils >> m_password; trace.log(_("using password from config file")); } } } //void BarryEnvironment::BuildConfig() //{ // FIXME - build back into one long string //} barry-0.18.5/opensync-plugin/src/vevent.h0000644001161500056700000000456112242254476017663 0ustar cdfreycdfrey// // \file vevent.h // Conversion routines for vevents (VCALENDAR, etc) // /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYSYNC_VEVENT_H__ #define __BARRYSYNC_VEVENT_H__ #include #include #include // forward declarations class BarryEnvironment; class VEventConverter { char *m_Data; Barry::Calendar m_Cal; uint32_t m_RecordId; std::string m_last_errmsg; public: VEventConverter(); explicit VEventConverter(uint32_t newRecordId); ~VEventConverter(); // Transfers ownership of m_Data to the caller char* ExtractData(); const Barry::Calendar& GetCalendar() const { return m_Cal; }; const std::string& GetLastError() const { return m_last_errmsg; } // Parses vevent data bool ParseData(const char *data); // Merge vevent data bool MergeData(const Barry::Calendar &origin); // Barry storage operator void operator()(const Barry::Calendar &rec); // Barry builder operator bool operator()(Barry::Calendar &rec, Barry::Builder &); // Handles calling of the Barry::Controller to fetch a specific // record, indicated by index (into the RecordStateTable). // Returns a g_malloc'd string of data containing the vevent20 // data. It is the responsibility of the caller to free it. // This is intended to be passed into the GetChanges() function. static char* GetRecordData(BarryEnvironment *env, unsigned int dbId, Barry::RecordStateTable::IndexType index); // Handles either adding or overwriting a calendar record, // given vevent20 data in data, and the proper environmebnt, // dbId, StateIndex. Set add to true if adding. static bool CommitRecordData(BarryEnvironment *env, unsigned int dbId, Barry::RecordStateTable::IndexType StateIndex, uint32_t recordId, const char *data, bool add, std::string &errmsg); }; #endif barry-0.18.5/opensync-plugin/src/barry_sync.h0000644001161500056700000000220312242254476020516 0ustar cdfreycdfrey// // \file barry_sync.h // Opensync module for the USB Blackberry handheld // /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_SYNC_H__ #define __BARRY_SYNC_H__ #include #include class BarryEnvironment; typedef char* (*GetData_t)(BarryEnvironment *env, unsigned int dbId, Barry::RecordStateTable::IndexType); typedef bool (*CommitData_t)(BarryEnvironment *env, unsigned int dbId, Barry::RecordStateTable::IndexType StateIndex, uint32_t recordId, const char *data, bool add, std::string &errmsg); #endif barry-0.18.5/opensync-plugin/configure.ac0000644001161500056700000000473612242254476017706 0ustar cdfreycdfreydnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) AC_INIT([Barry OpenSync Plugin], [0.18.5], [barry-devel@lists.sourceforge.net]) AC_CONFIG_SRCDIR(src/barry_sync.cc) AC_CONFIG_HEADER(config.h) AC_CONFIG_AUX_DIR([.]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE(foreign) AM_GNU_GETTEXT([external]) # this is the version of gettext, not barry AM_GNU_GETTEXT_VERSION([0.18.1]) AC_ISC_POSIX AC_PROG_CC AM_PROG_CC_STDC AC_HEADER_STDC AC_PROG_CXX AC_DISABLE_STATIC AC_PROG_LIBTOOL AX_C_CHECK_FLAG([-fvisibility=hidden], [], [], [HAVE_C_GCCVISIBILITY=1], [HAVE_C_GCCVISIBILITY=0]) AX_CXX_CHECK_FLAG([-fvisibility=hidden], [], [], [HAVE_CXX_GCCVISIBILITY=1], [HAVE_CXX_GCCVISIBILITY=0]) AM_CONDITIONAL([WITH_GCCVISIBILITY], [test "$HAVE_C_GCCVISIBILITY" = "1" -a "$HAVE_CXX_GCCVISIBILITY" = "1"]) AC_LANG([C++]) PKG_CHECK_MODULES([GLIB2], [glib-2.0]) PKG_CHECK_MODULES([OPENSYNC2X], [opensync-1.0]) PKG_CHECK_MODULES([BARRY], [libbarry-18]) PKG_CHECK_MODULES([BARRYSYNC], [libbarrysync-18]) # Carry the special tree build environment variables from parent configure, # just in case user is doing a complete tree build with --enable-opensync-plugin AC_SUBST(TREE_BUILD_CXXFLAGS) AC_SUBST(TREE_BUILD_LDFLAGS) OPENSYNC_CONFIGDIR=$(pkg-config --variable=configdir opensync-1.0) OPENSYNC_PLUGINDIR=$(pkg-config --variable=plugindir opensync-1.0) OPENSYNC_FORMATSDIR=$(pkg-config --variable=formatsdir opensync-1.0) OPENSYNC_HEADERDIR=$(pkg-config --variable=headerdir opensync-1.0) AC_SUBST(OPENSYNC_CONFIGDIR) ## This is the place where you can install the default configuration files of your plugin AC_SUBST(OPENSYNC_PLUGINDIR) ## This is the dir where you plugin will be installed AC_SUBST(OPENSYNC_FORMATSDIR) ## Here are format plugins installed (if any) AC_SUBST(OPENSYNC_HEADERDIR) ## Here are the headers that a user interface may need (if any) AC_OUTPUT([ Makefile po/Makefile.in src/Makefile ]) # # Add a special hack at the end, to let the user disable RPATH if he wants. # # http://wiki.debian.org/RpathIssue # http://lists.debian.org/debian-devel/2003/debian-devel-200306/msg00569.html # http://fedoraproject.org/wiki/Packaging:Guidelines#Removing_Rpath # AC_ARG_ENABLE([rpathhack], [AC_HELP_STRING([--enable-rpathhack], [patch libtool to remove RPATH])], [ AC_MSG_RESULT([patching libtool to fix HIDEOUS BREAKAGE]) sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool ], []) barry-0.18.5/opensync-plugin/Makefile.am0000644001161500056700000000020412242254476017436 0ustar cdfreycdfreyACLOCAL_FLAGS = -I m4 SUBDIRS = po . src EXTRA_DIST = \ buildgen.sh \ patches dist-hook: rm -rf `find $(distdir) -name CVS` barry-0.18.5/opensync-plugin/COPYING0000644001161500056700000004313312242254476016445 0ustar cdfreycdfrey GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, 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 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. Copyright (C) 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 St, 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) year 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. , 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. barry-0.18.5/opensync-plugin/buildgen.sh0000755001161500056700000000052112242254476017534 0ustar cdfreycdfrey#!/bin/sh # # Generates the build system. # if [ "$1" = "clean" ] ; then rm -rf autom4te.cache rm -f Makefile.in aclocal.m4 config.guess config.h.in config.h.in~ \ config.sub \ configure depcomp install-sh ltmain.sh missing \ src/Makefile.in INSTALL \ config.rpath \ config.h.in~ else autoreconf -if #autoreconf -ifv fi barry-0.18.5/opensync-plugin/ChangeLog0000644001161500056700000000005512242254476017160 0ustar cdfreycdfrey - see ../ChangeLog for details on progress barry-0.18.5/opensync-plugin/README0000644001161500056700000000533612242254476016275 0ustar cdfreycdfrey ***************************************************************************** * CAUTION: This is alpha software. Please make complete backups of your * * Blackberry device before experimenting. While the author has * * had good success with this software, that is no guarantee that * * you will. Please make backups. * ***************************************************************************** Development note: this plugin is in flux, not only from pure development, but also because the OpenSync libraries themselves are getting close to releasing version 0.30, which changes some internals from 0.22. This plugin is currently based on 0.22, but that may change in the future. Introduction: ------------- This directory contains a plugin for the OpenSync framework, which can be used to synchronize between handhelds and desktop management software, such as Evolution and Mozilla Sunbird. Please note that this plugin has the potential to not only change the data in your Blackberry handheld, but also, through sending sync ADD, MODIFY and DELETE changes, can change the data in your address book and calendar in your desktop software of choice. As this plugin is in development, please exercise caution, and make backups of your Blackberry (see the ../gui directory) *and* backups of your desktop software's data. You can find more information on the OpenSync framework, as well as tarballs for the version 0.22 library and plugins, at the following website: http://www.opensync.org/ Library Dependencies: --------------------- You will need the following packages installed on your system, including any dev or devel packages that come along with them. pkg-config Used by the configure scripts libopensync-0.22 OpenSync framework library sqlite Required by OpenSync glib2 Required by OpenSync libxml2 Required by OpenSync libbarry 0.x In the same tarball as this code. libusb Required by libbarry In addition to libopensync, you will need a plugin for your desktop software of choice, or for other handheld devices, such as the Palm. Please see the OpenSync website for a list of available plugins. If you've installed Barry or OpenSync in a non-standard spot, use something like the following: export PKG_CONFIG_PATH="/home/cdfrey/Barry/lib/pkgconfig:/home/cdfrey/software/lib/pkgconfig" ./configure --prefix=/home/cdfrey/Barry Installation: ------------- cd opensync-plugin ./configure (pkg-config will be used to find required libraries... make sure they are installed in standard locations, or that PKG_CONFIG_PATH is set appropriately) make su make install Please report any bugs you find to the Barry mailing list. Thanks! August 2007 barry-0.18.5/opensync-plugin/m4/0000755001161500056700000000000012242254476015726 5ustar cdfreycdfreybarry-0.18.5/opensync-plugin/m4/ax_cxx_check_flag.m40000644001161500056700000000560112242254476021612 0ustar cdfreycdfrey##### http://autoconf-archive.cryp.to/ax_cxx_check_flag.html # # SYNOPSIS # # AX_CXX_CHECK_FLAG(FLAG-TO-CHECK,[PROLOGUE],[BODY],[ACTION-IF-SUCCESS],[ACTION-IF-FAILURE]) # # DESCRIPTION # # This macro tests if the C++ compiler supports the flag # FLAG-TO-CHECK. If successfull execute ACTION-IF-SUCCESS otherwise # ACTION-IF-FAILURE. PROLOGUE and BODY are optional and should be # used as in AC_LANG_PROGRAM macro. # # This code is inspired from KDE_CHECK_COMPILER_FLAG macro. Thanks to # Bogdan Drozdowski for testing and bug fixes. # # LAST MODIFICATION # # 2007-11-26 # # COPYLEFT # # Copyright (c) 2007 Francesco Salvestrini # # 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. # # As a special exception, the respective Autoconf Macro's copyright # owner gives unlimited permission to copy, distribute and modify the # configure scripts that are the output of Autoconf when processing # the Macro. You need not follow the terms of the GNU General Public # License when using or distributing such scripts, even though # portions of the text of the Macro appear in them. The GNU General # Public License (GPL) does govern all other use of the material that # constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the # Autoconf Macro released by the Autoconf Macro Archive. When you # make and distribute a modified version of the Autoconf Macro, you # may extend this special exception to the GPL to apply to your # modified version as well. AC_DEFUN([AX_CXX_CHECK_FLAG],[ AC_PREREQ([2.61]) AC_REQUIRE([AC_PROG_CXX]) AC_REQUIRE([AC_PROG_SED]) flag=`echo "$1" | $SED 'y% .=/+-(){}<>:*,%_______________%'` AC_CACHE_CHECK([whether the C++ compiler accepts the $1 flag], [ax_cv_cxx_check_flag_$flag],[ AC_LANG_PUSH([C++]) save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $1" AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([$2],[$3]) ],[ eval "ax_cv_cxx_check_flag_$flag=yes" ],[ eval "ax_cv_cxx_check_flag_$flag=no" ]) CXXFLAGS="$save_CXXFLAGS" AC_LANG_POP ]) AS_IF([eval "test \"`echo '$ax_cv_cxx_check_flag_'$flag`\" = yes"],[ : $4 ],[ : $5 ]) ]) barry-0.18.5/opensync-plugin/m4/ax_c_check_flag.m40000644001161500056700000000554012242254476021234 0ustar cdfreycdfrey##### http://autoconf-archive.cryp.to/ax_c_check_flag.html # # SYNOPSIS # # AX_C_CHECK_FLAG(FLAG-TO-CHECK,[PROLOGUE],[BODY],[ACTION-IF-SUCCESS],[ACTION-IF-FAILURE]) # # DESCRIPTION # # This macro tests if the C compiler supports the flag FLAG-TO-CHECK. # If successfull execute ACTION-IF-SUCCESS otherwise # ACTION-IF-FAILURE. PROLOGUE and BODY are optional and should be # used as in AC_LANG_PROGRAM macro. # # This code is inspired from KDE_CHECK_COMPILER_FLAG macro. Thanks to # Bogdan Drozdowski for testing and bug fixes. # # LAST MODIFICATION # # 2007-11-26 # # COPYLEFT # # Copyright (c) 2007 Francesco Salvestrini # # 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. # # As a special exception, the respective Autoconf Macro's copyright # owner gives unlimited permission to copy, distribute and modify the # configure scripts that are the output of Autoconf when processing # the Macro. You need not follow the terms of the GNU General Public # License when using or distributing such scripts, even though # portions of the text of the Macro appear in them. The GNU General # Public License (GPL) does govern all other use of the material that # constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the # Autoconf Macro released by the Autoconf Macro Archive. When you # make and distribute a modified version of the Autoconf Macro, you # may extend this special exception to the GPL to apply to your # modified version as well. AC_DEFUN([AX_C_CHECK_FLAG],[ AC_PREREQ([2.61]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_PROG_SED]) flag=`echo "$1" | $SED 'y% .=/+-(){}<>:*,%_______________%'` AC_CACHE_CHECK([whether the C compiler accepts the $1 flag], [ax_cv_c_check_flag_$flag],[ AC_LANG_PUSH([C]) save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $1" AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([$2],[$3]) ],[ eval "ax_cv_c_check_flag_$flag=yes" ],[ eval "ax_cv_c_check_flag_$flag=no" ]) CFLAGS="$save_CFLAGS" AC_LANG_POP ]) AS_IF([eval "test \"`echo '$ax_cv_c_check_flag_'$flag`\" = yes"],[ : $4 ],[ : $5 ]) ]) barry-0.18.5/NEWS0000644001161500056700000000425112242254476012755 0ustar cdfreycdfrey2012/05 ============================================================================== Binary Package Rename --------------------- As of version 0.18, the binary package names for libbarry on Debian have been renamed to libbarry18 to reflect the major version number. The RPM may follow eventually, but testing on that side of things is slower. API Change ---------- The API of version 0.18 of the library differs substantially in numerous details from version 0.17. Mostly due to new features being added, in the library and the tools and GUI. August 2008 ============================================================================== Binary Package Rename --------------------- As of version 0.14, the binary package names for libbarry (both RPM and DEB) have been renamed to libbarry0, to match the commonly accepted procedure of most distributions. This change may cause package conflicts if you are not careful during the upgrade. Please be sure to remove old Barry packages before installing version 0.14. May 2008 ============================================================================== API Change ---------- As of version 0.13, the Barry API has changed to use a hierarchy of Mode classes instead of using the Controller class to switch modes or select them. These new Mode classes are in a new namespace called Mode. In theory, these modes can be operational at the same time, such as Desktop, Serial, and IpModem. Eventually, a JavaLoader mode may also be available. Please see the example code in the examples directory for sample code and usage. IP Modem support ---------------- Version 0.13 has preliminary IP Modem support. You will need a newer Blackberry device to make use of this. December 2006 ============================================================================== Note: as of version 0.4, Barry depends on the stable version of libusb, not the devel tarball available on the Barry sourceforge site. Install stable libusb (0.1.12 or similar) and libusb-devel from your distribution's regular package set. ------------------------------------------------------------------------------ See http://www.netdirect.ca/software/packages/barry for the latest news. barry-0.18.5/android/0000755001161500056700000000000012242254476013674 5ustar cdfreycdfreybarry-0.18.5/android/jni/0000755001161500056700000000000012242254476014454 5ustar cdfreycdfreybarry-0.18.5/android/jni/libusb/0000755001161500056700000000000012242254476015734 5ustar cdfreycdfreybarry-0.18.5/android/jni/libusb/config.h0000644001161500056700000000063612242254476017357 0ustar cdfreycdfrey#define ENABLE_LOGGING #define OS_LINUX #define API_EXPORTED #ifndef TIMESPEC_TO_TIMEVAL #define TIMESPEC_TO_TIMEVAL(tv, ts) \ do { \ (tv)->tv_sec = (ts)->tv_sec; \ (tv)->tv_usec = (ts)->tv_nsec / 1000; \ } while (0) #endif barry-0.18.5/android/jni/Android.mk0000644001161500056700000001000012242254476016354 0ustar cdfreycdfrey# Android.mk # This file is the main body of the instructions for how to build one or more native # libraries for Android using the NDK build system. LOCAL_PATH:= $(call my-dir) BARRY_ROOT:= $(LOCAL_PATH)/../../ ############### # libiconv.so # ############### include $(CLEAR_VARS) LIBICONV_NAME=libiconv-1.13.1 LOCAL_SRC_FILES := \ ../$(LIBICONV_NAME)/lib/iconv.c \ ../$(LIBICONV_NAME)/lib/relocatable.c \ ../$(LIBICONV_NAME)/libcharset/lib/localcharset.c LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/libiconv \ $(LIBICONV_NAME)/include \ $(LIBICONV_NAME)/lib \ $(LIBICONV_NAME)/libcharset/include \ $(LIBICONV_NAME)/libcharset \ $(LIBICONV_NAME)/srclib LOCAL_CFLAGS += -DBUILDING_LIBICONV -DBUILDING_LIBICONV -DIN_LIBRARY -DLIBDIR=\"\" LOCAL_EXPORT_C_INCLUDES := \ $(LOCAL_PATH)/../$(LIBICONV_NAME)/include $(info Checking if libiconv needs configuring...) COMMAND := $(shell \ export PATH=$$ANDROID_TOOLCHAIN_DIR/bin:$$PATH; \ cd $(LOCAL_PATH)/../$(LIBICONV_NAME); \ test -e config.h || CC=arm-linux-androideabi-gcc ./configure --host="arm-linux" > configure_run.log 2>&1 ) LOCAL_MODULE := libiconv include $(BUILD_SHARED_LIBRARY) ################ # libusb1.0.so # ################ include $(CLEAR_VARS) LIBUSB_NAME=libusb-1.0.8 LOCAL_SRC_FILES := \ ../$(LIBUSB_NAME)/libusb/core.c \ ../$(LIBUSB_NAME)/libusb/descriptor.c \ ../$(LIBUSB_NAME)/libusb/io.c \ ../$(LIBUSB_NAME)/libusb/sync.c \ ../$(LIBUSB_NAME)/libusb/os/linux_usbfs.c LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/libusb \ $(LIBUSB_NAME)/libusb/ \ $(LIBUSB_NAME)/libusb/os/ LOCAL_EXPORT_C_INCLUDES := \ $(LOCAL_PATH)/../$(LIBUSB_NAME)/libusb LOCAL_MODULE := libusb1.0 include $(BUILD_SHARED_LIBRARY) ######### # lsusb # ######### include $(CLEAR_VARS) LOCAL_SRC_FILES := \ ../$(LIBUSB_NAME)/examples/lsusb.c LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/../$(LIBUSB_NAME) LOCAL_SHARED_LIBRARIES += libusb1.0 LOCAL_MODULE:= lsusb include $(BUILD_EXECUTABLE) ############### # libbarry.so # ############### include $(CLEAR_VARS) BARRY_SRC_TO_INCLUDE := \ $(subst $(LOCAL_PATH)/,, \ $(wildcard $(LOCAL_PATH)/barry_root/src/*.cc) \ ) BARRY_SRC_TO_EXCLUDE := \ $(subst $(LOCAL_PATH)/,, \ $(wildcard $(LOCAL_PATH)/barry_root/src/a_*.cc) \ $(wildcard $(LOCAL_PATH)/barry_root/src/dp_*.cc) \ $(wildcard $(LOCAL_PATH)/barry_root/src/j_*.cc) \ $(wildcard $(LOCAL_PATH)/barry_root/src/v*.cc) \ ) \ barry_root/src/mimeio.cc \ barry_root/src/xmlparser.cc \ barry_root/src/tzwrapper.cc \ barry_root/src/tarfile.cc \ barry_root/src/tarfile-ops-nt.cc \ barry_root/src/backup.cc \ barry_root/src/iconvwin.cc \ barry_root/src/restore.cc \ barry_root/src/usbwrap_libusb.cc \ barry_root/src/configfilewin32.cc LOCAL_SRC_FILES:= $(filter-out $(BARRY_SRC_TO_EXCLUDE), $(BARRY_SRC_TO_INCLUDE)) barry_root/src/version.cc LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/barry \ $(LOCAL_PATH)/../$(LIBUSB_NAME)/libusb LOCAL_CFLAGS += -D__BARRY_LIBRARY_BUILD__ LOCAL_EXPORT_C_INCLUDES := \ $(LOCAL_PATH)/barry LOCAL_CPP_EXTENSION := .cc LOCAL_SHARED_LIBRARIES += libusb1.0 libiconv LOCAL_LDLIBS := -lz LOCAL_MODULE := libbarry # Have to build libbarry statically as libstdc++ is statically linked in include $(BUILD_STATIC_LIBRARY) ######### # tools # ######### TOOLS=brawchannel btool bidentify bjavaloader bjvmdebug upldif bktrans pppob brecsum $(foreach TOOL, $(TOOLS), $(eval include $(LOCAL_PATH)/BarryTool.mk)) ########### # bcharge # ########### include $(CLEAR_VARS) LOCAL_SRC_FILES := barry_root/tools/bcharge_libusb_1_0.cc LOCAL_CFLAGS += -DLOCALEDIR=\"\" LOCAL_CPP_EXTENSION := .cc LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/barry LOCAL_SHARED_LIBRARIES += libusb1.0 LOCAL_MODULE := bcharge include $(BUILD_EXECUTABLE) ########### # breset # ########### include $(CLEAR_VARS) LOCAL_SRC_FILES := barry_root/tools/breset_libusb_1_0.cc LOCAL_CFLAGS += -DLOCALEDIR=\"\" LOCAL_CPP_EXTENSION := .cc LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/barry LOCAL_SHARED_LIBRARIES += libusb1.0 LOCAL_MODULE := breset include $(BUILD_EXECUTABLE)barry-0.18.5/android/jni/Application.mk0000644001161500056700000000032412242254476017247 0ustar cdfreycdfrey#Can also set this to other values such as APP_ABI := armeabi armeabi-v7a x86 APP_ABI := armeabi APP_STL := gnustl_static # Need rtti for shared_ptr support to work on NDK r7b APP_CPPFLAGS := -fexceptions -frtti barry-0.18.5/android/jni/barry/0000755001161500056700000000000012242254476015573 5ustar cdfreycdfreybarry-0.18.5/android/jni/barry/config.h0000644001161500056700000001435012242254476017214 0ustar cdfreycdfrey /* Logical version number */ #define BARRY_LOGICAL 0 /* Major library version number */ #define BARRY_MAJOR 18 /* Minor library version number */ #define BARRY_MINOR 5 /* Full Barry version in string form */ #define BARRY_VER_STRING "0.18.5" /* Define to 1 if the `closedir' function returns void instead of `int'. */ #define CLOSEDIR_VOID 1 /* Define to 1 if translation of program messages to the user's native language is requested. */ /* #undef ENABLE_NLS */ /* Define to 1 if you have the header file. */ #define HAVE_ASSERT_H 1 /* Define to 1 if you have the `bzero' function. */ #define HAVE_BZERO 1 /* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework. */ /* #undef HAVE_CFLOCALECOPYCURRENT */ /* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework. */ /* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */ /* Define if the GNU dcgettext() function is already present or preinstalled. */ /* #undef HAVE_DCGETTEXT */ /* Define to 1 if you have the header file, and it defines `DIR'. */ #define HAVE_DIRENT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define if the GNU gettext() function is already present or preinstalled. */ /* #undef HAVE_GETTEXT */ /* Define to 1 if you have the `gettimeofday' function. */ #define HAVE_GETTIMEOFDAY 1 /* Define if you have the iconv() function and it works. */ #define HAVE_ICONV 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `memset' function. */ #define HAVE_MEMSET 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the `select' function. */ #define HAVE_SELECT 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasecmp' function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the `strchr' function. */ #define HAVE_STRCHR 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strtol' function. */ #define HAVE_STRTOL 1 /* Define to 1 if you have the `strtoul' function. */ #define HAVE_STRTOUL 1 /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_DIR_H */ /* Define to 1 if you have the header file, and it defines `DIR'. */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_SELECT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if a working strnlen exists, 0 if not. */ #define HAVE_WORKING_STRNLEN 1 /* Use crc32 when generating packed .cod files */ #define HAVE_ZLIB 1 /* Define as const if the declaration of iconv() needs const. */ #define ICONV_CONST /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Name of package */ #define PACKAGE "barry" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "barry-devel@lists.sourceforge.net" /* Define to the full name of this package. */ #define PACKAGE_NAME "barry" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "barry 0.18.5" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "barry" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "0.18.5" /* Define to the type of arg 1 for `select'. */ #define SELECT_TYPE_ARG1 int /* Define to the type of args 2, 3 and 4 for `select'. */ #define SELECT_TYPE_ARG234 (fd_set *) /* Define to the type of arg 5 for `select'. */ #define SELECT_TYPE_ARG5 (struct timeval *) /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define to 1 if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define to 1 if your declares `struct tm'. */ /* #undef TM_IN_SYS_TIME */ /* Define to use the low-level socket and USB code built into Barry. */ #define USE_BARRY_SOCKETS /**/ /* Define if libusb 0.1 interface should be used */ /* #undef USE_LIBUSB_0_1 */ /* Define if libusb 1.0 interface should be used */ #define USE_LIBUSB_1_0 /**/ /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # define _ALL_SOURCE 1 #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # define _GNU_SOURCE 1 #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # define _POSIX_PTHREAD_SEMANTICS 1 #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # define _TANDEM_SOURCE 1 #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # define __EXTENSIONS__ 1 #endif /* Version number of package */ #define VERSION "0.18.5" /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN /* # undef WORDS_BIGENDIAN */ # endif #endif /* Define to 1 if on MINIX. */ /* #undef _MINIX */ /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ /* #undef _POSIX_1_SOURCE */ /* Define to 1 if you need to in order for `stat' and other things to work. */ /* #undef _POSIX_SOURCE */ barry-0.18.5/android/jni/BarryTool.mk0000644001161500056700000000076412242254476016731 0ustar cdfreycdfrey# BarryTool.mk # This file is used to build a single Barry tool. It takes the following parameters: # TOOL - The name of the tool to make # LOCAL_PATH - Path to the JNI directory include $(CLEAR_VARS) LOCAL_SRC_FILES := barry_root/tools/$(TOOL).cc \ barry_root/tools/util.cc LOCAL_CFLAGS += -DLOCALEDIR=\"\" LOCAL_CPP_EXTENSION := .cc LOCAL_STATIC_LIBRARIES += libbarry LOCAL_SHARED_LIBRARIES += libiconv libusb1.0 LOCAL_LDLIBS := -lz LOCAL_MODULE := $(TOOL) include $(BUILD_EXECUTABLE)barry-0.18.5/android/Makefile0000644001161500056700000000477412242254476015350 0ustar cdfreycdfrey# # \file Makefile # Make rules for building Barry and dependent libraries for Android # # Copyright (C) 2011-2013 RealVNC Ltd. # # 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 in the COPYING file at the # root directory of this project for more details. LIBUSB_NAME=libusb-1.0.8 LIBICONV_NAME=libiconv-1.13.1 NDK_OUTPUT_FILES=libusb1.0.so lsusb libiconv.so \ btool brawchannel bidentify bjavaloader bjvmdebug \ upldif bktrans breset bcharge pppob brecsum include jni/Application.mk NDK_OUTPUT_ARCHES=$(APP_ABI) NDK_BINARIES=$(addprefix libs/, $(foreach ARCH,$(NDK_OUTPUT_ARCHES),$(addprefix $(ARCH)/, $(NDK_OUTPUT_FILES)))) ANDROID_TOOLCHAIN_DIR=android-ndk-tools ANDROID_NDK_PATH=$(dir $(shell which ndk-build)) WGET=wget EXTRA_DIST = \ jni/Android.mk \ jni/Application.mk \ jni/BarryTool.mk \ jni/barry/config.h \ jni/libusb/config.h \ README all: android-binaries .PHONY: android-binaries $(LIBUSB_NAME).tar.bz2: $(WGET) http://sourceforge.net/projects/libusb/files/libusb-1.0/$(LIBUSB_NAME)/$(LIBUSB_NAME).tar.bz2/download -O $(LIBUSB_NAME).tar.bz2 $(LIBICONV_NAME).tar.gz: $(WGET) http://ftp.gnu.org/pub/gnu/libiconv/$(LIBICONV_NAME).tar.gz -O $(LIBICONV_NAME).tar.gz $(LIBUSB_NAME): $(LIBUSB_NAME).tar.bz2 tar jxf $(LIBUSB_NAME).tar.bz2 touch $(LIBUSB_NAME) $(LIBICONV_NAME): $(LIBICONV_NAME).tar.gz tar zxf $(LIBICONV_NAME).tar.gz touch $(LIBICONV_NAME) $(ANDROID_TOOLCHAIN_DIR): $(ANDROID_NDK_PATH)/build/tools/make-standalone-toolchain.sh --install-dir="$(ANDROID_TOOLCHAIN_DIR)" jni/barry_root: ln -s ../../ jni/barry_root jni/barry/barry: ln -s ../../../src jni/barry/barry android-binaries: jni/barry_root jni/barry/barry $(LIBUSB_NAME) $(LIBICONV_NAME) $(ANDROID_TOOLCHAIN_DIR) +ANDROID_TOOLCHAIN_DIR="$(realpath $(ANDROID_TOOLCHAIN_DIR))" ndk-build distclean: clean -$(RM) $(LIBUSB_NAME).tar.bz2 -$(RM) $(LIBICONV_NAME).tar.gz -$(RM) -rf libs clean: -$(RM) -rf $(LIBUSB_NAME) -$(RM) -rf $(LIBICONV_NAME) -$(RM) jni/barry_root -$(RM) jni/barry/barry -$(RM) -rf obj -$(RM) -rf $(NDK_BINARIES) -$(RM) -rf $(ANDROID_TOOLCHAIN_DIR) barry-0.18.5/android/README0000644001161500056700000000354512242254476014563 0ustar cdfreycdfreyBuilding: ========= To build for android, run make with the "android-binaries" target with the "ndk-build" tool in the path. For example: make android-binaries The "ndk-build" tool is part of the Android NDK, which can be found at: http://developer.android.com/sdk/ndk/index.html Installing: =========== The easiest way to install Barry on an Android device is by using adb, which is part of the Android SDK. These instructions assume the Android device has been configured to support the root user by default. For Android Open Source Project (AOSP) devices this should be the case. Other device ROMs may have different mechanism for attaining root access, e.g. Cyanogenmod based ROMs make use of the "sudo" utility. To install Barry to the system partition on a device run: adb remount for F in libs/armeabi/*.so ; do adb push $F /system/lib; done for F in libs/armeabi/b* libs/armeabi/lsusb libs/armeabi/pppob libs/armeabi/upldif ; \ do adb push $F /system/bin; done To install Barry to a single directory on a device run: adb shell mkdir /data/Barry for F in libs/armeabi/* ; do adb push $F /data/Barry; done Running: ======== Before running Barry tools it may be necessary to grant the user running Barry access to the USB bus devices. This can be achieved by running the following: adb shell "for B in /dev/bus/usb/* ; do for D in \$B/* ; do chmod 0666 \$D ; done; done" Note: this grants access to the USB devices for all users and therefore is not secure for a system running arbitary software. Alternate security mechanisms should be employeed by such systems. If Barry was installed to the system partition then the tools can be run directly: adb shell btool However if Barry was installed to a single directory then the library path will need to be specified: adb shell "LD_LIBRARY_PATH=/data/Barry /data/Barry/btool" barry-0.18.5/libbarrybackup-18.pc.in0000644001161500056700000000050312242254476016425 0ustar cdfreycdfreyprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@/barry@BARRY_MAJOR@ Name: Barry Description: C++ library for reading and writing Barry backup files URL: http://sourceforge.net/projects/barry Version: @VERSION@ Requires: libbarry-18 Libs: -L${libdir} -lbarrybackup Cflags: -I${includedir} barry-0.18.5/menu/0000755001161500056700000000000012242254476013220 5ustar cdfreycdfreybarry-0.18.5/menu/barrydesktop.desktop0000644001161500056700000000041212242254476017321 0ustar cdfreycdfrey[Desktop Entry] Encoding=UTF-8 Name=Barry Desktop Panel Comment=Manage BlackBerry devices from a central GUI. Exec=barrydesktop Icon=barry_desktop_menu_icon Terminal=false Type=Application StartupWMClass=barrydesktop Categories=Utility; Keywords=BlackBerry;backup; barry-0.18.5/menu/barrybackup.desktop0000644001161500056700000000040712242254476017121 0ustar cdfreycdfrey[Desktop Entry] Encoding=UTF-8 Name=Barry Backup Comment=Backup and restore databases on the BlackBerry Handheld Exec=barrybackup Icon=barry_backup_menu_icon Terminal=false Type=Application StartupWMClass=barrybackup-gui Categories=Utility; Keywords=BlackBerry; barry-0.18.5/logo/0000755001161500056700000000000012242254476013214 5ustar cdfreycdfreybarry-0.18.5/logo/new_barry_icon_128.svg0000644001161500056700000021726412242254476017343 0ustar cdfreycdfrey image/svg+xml barry-0.18.5/logo/barry_logo_debian_menu_icon.xpm0000644001161500056700000002327312242254476021446 0ustar cdfreycdfrey/* XPM */ static char * barry_logo_debian_menu_icon_xpm[] = { "32 32 479 2", " c None", ". c #FFFFFF", "+ c #FCFCFC", "@ c #CCCCCB", "# c #C2C7C2", "$ c #B7BAB7", "% c #E6E5E6", "& c #E3E4E2", "* c #FEFEFE", "= c #ECECEC", "- c #2D642A", "; c #153C13", "> c #1D571A", ", c #A2A3A3", "' c #FFFEFF", ") c #FDFCFD", "! c #B8B2B8", "~ c #1D521A", "{ c #446442", "] c #F2F2F2", "^ c #336531", "/ c #123E0F", "( c #1C6319", "_ c #156712", ": c #C7CBC7", "< c #99A298", "[ c #10660C", "} c #20701C", "| c #0C3A0A", "1 c #BEC2BE", "2 c #979E9A", "3 c #002700", "4 c #185715", "5 c #0C320A", "6 c #324632", "7 c #1F681C", "8 c #0C2C0A", "9 c #1D6B19", "0 c #0F360D", "a c #1B6917", "b c #838983", "c c #FDFEFD", "d c #9A9194", "e c #601A35", "f c #5A263A", "g c #8C8687", "h c #6C012A", "i c #4D0522", "j c #14190B", "k c #164612", "l c #361018", "m c #2E1115", "n c #154A12", "o c #0F380D", "p c #124510", "q c #174010", "r c #BBBEBB", "s c #D6D4D5", "t c #E0E0E0", "u c #D3D0D2", "v c #8D3255", "w c #96083F", "x c #92083D", "y c #46041C", "z c #9A1046", "A c #950A40", "B c #8C083C", "C c #340B1C", "D c #9C1147", "E c #980A41", "F c #530523", "G c #4F202E", "H c #842D4B", "I c #850638", "J c #511F33", "K c #913458", "L c #8A224A", "M c #877A7F", "N c #C0B3B8", "O c #860034", "P c #930A3F", "Q c #8B0A3C", "R c #49051F", "S c #950B40", "T c #7C0935", "U c #580425", "V c #970A40", "W c #940A40", "X c #87093A", "Y c #45011B", "Z c #94053C", "` c #960A41", " . c #67072C", ".. c #7D0232", "+. c #96093F", "@. c #6A1233", "#. c #E2E6E5", "$. c #FDFDFD", "%. c #D9DCDB", "&. c #780A35", "*. c #8D0A3D", "=. c #860839", "-. c #380317", ";. c #41051C", ">. c #750831", ",. c #4F0521", "'. c #350416", "). c #590626", "!. c #8C093C", "~. c #4E0521", "{. c #300315", "]. c #840A39", "^. c #5A0526", "/. c #2F0213", "(. c #6C072F", "_. c #5C162F", ":. c #E7EAE9", "<. c #F3F7F6", "[. c #542838", "}. c #370116", "|. c #69062D", "1. c #500421", "2. c #76193C", "3. c #A50B47", "4. c #380418", "5. c #981446", "6. c #9B0A42", "7. c #7B0835", "8. c #2B0413", "9. c #920D40", "0. c #9C0B42", "a. c #3E041A", "b. c #540C28", "c. c #A5104A", "d. c #3E0219", "e. c #58444C", "f. c #FAFAFA", "g. c #694F59", "h. c #BE5D81", "i. c #91083D", "j. c #810937", "k. c #380318", "l. c #A3174C", "m. c #8C093B", "n. c #4E0622", "o. c #981146", "p. c #750832", "q. c #730932", "r. c #950D41", "s. c #47071F", "t. c #8F0C3E", "u. c #5C0023", "v. c #AC416A", "w. c #9A7F89", "x. c #704C5A", "y. c #99003B", "z. c #940B40", "A. c #8E0A3D", "B. c #41041C", "C. c #9D0C44", "D. c #4E0421", "E. c #960B41", "F. c #970B41", "G. c #6F082F", "H. c #780833", "I. c #89093B", "J. c #88093A", "K. c #850939", "L. c #600629", "M. c #830938", "N. c #7E0936", "O. c #600729", "P. c #94043C", "Q. c #5A2D3E", "R. c #A3A9A7", "S. c #63001F", "T. c #840939", "U. c #7F0837", "V. c #350317", "W. c #800837", "X. c #520623", "Y. c #7F0936", "Z. c #40031A", "`. c #730731", " + c #250210", ".+ c #750732", "++ c #740832", "@+ c #48051F", "#+ c #280110", "$+ c #6E072E", "%+ c #310315", "&+ c #730831", "*+ c #73032F", "=+ c #988A8F", "-+ c #F8FCFB", ";+ c #2A000C", ">+ c #45041D", ",+ c #550F2B", "'+ c #46041D", ")+ c #4C0520", "!+ c #360317", "~+ c #4D0420", "{+ c #900B3E", "]+ c #4D0521", "^+ c #6B0C31", "/+ c #9B1348", "(+ c #960A40", "_+ c #6F0730", ":+ c #5E1632", "<+ c #9B1549", "[+ c #990B41", "}+ c #27000F", "|+ c #50172D", "1+ c #927F87", "2+ c #615258", "3+ c #B63D6B", "4+ c #91093D", "5+ c #73052F", "6+ c #9A345B", "7+ c #92073D", "8+ c #910A3F", "9+ c #540422", "0+ c #A42F5C", "a+ c #93073D", "b+ c #65072B", "c+ c #870A3A", "d+ c #40041B", "e+ c #93093F", "f+ c #570424", "g+ c #78163C", "h+ c #570017", "i+ c #CAD3D0", "j+ c #685E62", "k+ c #9B023E", "l+ c #7A0834", "m+ c #7F0735", "n+ c #540523", "o+ c #6D072E", "p+ c #970A41", "q+ c #920A3F", "r+ c #830838", "s+ c #8F0A3D", "t+ c #4B0420", "u+ c #760832", "v+ c #510017", "w+ c #C2CBC8", "x+ c #EFF5F3", "y+ c #38000B", "z+ c #88073A", "A+ c #7E0836", "B+ c #320316", "C+ c #69072C", "D+ c #6B072D", "E+ c #3D041A", "F+ c #900A3D", "G+ c #940B3F", "H+ c #43041C", "I+ c #64072B", "J+ c #710730", "K+ c #3D0319", "L+ c #28000F", "M+ c #62062A", "N+ c #45051D", "O+ c #22020E", "P+ c #330010", "Q+ c #8A8285", "R+ c #D6D8D7", "S+ c #300F1C", "T+ c #330315", "U+ c #5C0727", "V+ c #60092B", "W+ c #7E0835", "X+ c #45051E", "Y+ c #64062B", "Z+ c #2E0213", "`+ c #7E103B", " @ c #A02C59", ".@ c #7A0733", "+@ c #820938", "@@ c #610327", "#@ c #B03B69", "$@ c #430018", "%@ c #D5D8D7", "&@ c #903056", "*@ c #8F073C", "=@ c #4A0721", "-@ c #98194A", ";@ c #93093E", ">@ c #63072A", ",@ c #6E0930", "'@ c #AB476E", ")@ c #94083D", "!@ c #4E0723", "~@ c #9B1247", "{@ c #830937", "]@ c #43031C", "^@ c #9D0D44", "/@ c #510014", "(@ c #C6CFCB", "_@ c #EAEEEC", ":@ c #6E1638", "<@ c #990B42", "[@ c #750833", "}@ c #870939", "|@ c #930B40", "1@ c #5F0528", "2@ c #65062B", "3@ c #750631", "4@ c #3E1224", "5@ c #BDB9BB", "6@ c #490F26", "7@ c #3A0016", "8@ c #550524", "9@ c #63072B", "0@ c #980B42", "a@ c #7B0834", "b@ c #340316", "c@ c #3E031A", "d@ c #2B0010", "e@ c #661E3A", "f@ c #570726", "g@ c #4B182A", "h@ c #DFE1E0", "i@ c #EBECEC", "j@ c #952F57", "k@ c #990940", "l@ c #370418", "m@ c #401123", "n@ c #510422", "o@ c #5B0425", "p@ c #41041B", "q@ c #79133A", "r@ c #A00A44", "s@ c #6E042D", "t@ c #802A4B", "u@ c #9B0E44", "v@ c #720931", "w@ c #D2D5D4", "x@ c #DDD7D9", "y@ c #921A48", "z@ c #9A0A42", "A@ c #580525", "B@ c #971446", "C@ c #960940", "D@ c #400C20", "E@ c #9B2453", "F@ c #880839", "G@ c #870D3D", "H@ c #940A3F", "I@ c #47031D", "J@ c #770833", "K@ c #532336", "L@ c #F3F5F4", "M@ c #EFF2F1", "N@ c #703149", "O@ c #7E0635", "P@ c #6C072E", "Q@ c #3C0419", "R@ c #6D082F", "S@ c #9C0B43", "T@ c #560424", "U@ c #68062C", "V@ c #40051C", "W@ c #530E29", "X@ c #3B0011", "Y@ c #E9EBEA", "Z@ c #A5959A", "`@ c #620024", " # c #860A3A", ".# c #42061C", "+# c #680029", "@# c #4D0421", "## c #700731", "$# c #800836", "%# c #45031D", "&# c #883856", "*# c #660329", "=# c #68082D", "-# c #9C174B", ";# c #820032", "># c #9D9F9F", ",# c #B8AEB2", "'# c #8F1A47", ")# c #57001F", "!# c #BA4E78", "~# c #67032A", "{# c #5C1E35", "]# c #42041C", "^# c #810938", "/# c #44041D", "(# c #700931", "_# c #4C2232", ":# c #F5FAF8", "<# c #FBFBFB", "[# c #EEEEEE", "}# c #DEDEDE", "|# c #C0C0C0", "1# c #4E0924", "2# c #7A0130", "3# c #2D000F", "4# c #8F073B", "5# c #4A021F", "6# c #A22354", "7# c #9D0B43", "8# c #40031B", "9# c #390318", "0# c #810736", "a# c #3E373A", "b# c #F2F4F4", "c# c #F3F3F3", "d# c #DDDDDD", "e# c #C8C8C8", "f# c #B4B4B4", "g# c #A2A2A2", "h# c #818785", "i# c #394641", "j# c #443138", "k# c #461529", "l# c #3F031A", "m# c #5C0628", "n# c #67062B", "o# c #5B0526", "p# c #A40A46", "q# c #7F0434", "r# c #473D41", "s# c #CDCDCD", "t# c #F7F7F7", "u# c #E1E1E1", "v# c #CBCBCB", "w# c #B3B3B3", "x# c #9B9B9B", "y# c #848484", "z# c #6E6E6E", "A# c #595A59", "B# c #2E2126", "C# c #A7114B", "D# c #590425", "E# c #7C0735", "F# c #880739", "G# c #361B25", "H# c #352028", "I# c #4C4045", "J# c #9A9A9A", "K# c #CACACA", "L# c #F9F9F9", "M# c #E3E3E3", "N# c #9D9D9D", "O# c #868686", "P# c #6F6F6F", "Q# c #5A5A5A", "R# c #424443", "S# c #240C15", "T# c #450C22", "U# c #151817", "V# c #191A19", "W# c #1F1D1E", "X# c #575858", "Y# c #757575", "Z# c #898989", "`# c #9C9C9C", " $ c #F6F6F6", ".$ c #CCCCCC", "+$ c #B8B8B8", "@$ c #A5A5A5", "#$ c #939393", "$$ c #838383", "%$ c #777676", "&$ c #6B6D6C", "*$ c #626564", "=$ c #686868", "-$ c #787878", ";$ c #F4F4F4", ">$ c #E4E4E4", ",$ c #D5D5D5", "'$ c #C7C7C7", ")$ c #BDBDBD", "!$ c #ADADAD", "~$ c #AAAAAA", "{$ c #F0F0F0", ". . . . . . . . . . + @ # $ . . . . % & . . . . . . . . . . . . ", ". . . . . . . . . * = - ; > , ' ) ! ~ { . * . . . . . . . . . . ", ". . . . . . . * . . ] ^ / ( _ : < [ } | 1 . * . . . . . . . . . ", ". . . . . * * . . . . 2 3 4 5 6 7 8 9 0 a b . . . * . . . . . . ", ". . . . . . c d e f g h i j k l m n o p q r s t . * . . . . . . ", ". . . . . . u v w x y z A B C D E F G H I J K L M . . . . . . . ", ". . . . * . N O P Q R E S T U V W X Y Z ` ...+.@.#.* . . . . . ", ". . . . . $.%.&.*.=.-.;.>.,.'.).!.~.{.].^./.(.A _.:.. . . . . . ", ". . . . . <.[.}.|.1.2.3.4.5.6.7.8.9.0.a.b.c.F d.e.f.* . . . . . ", ". . . . . g.h.i.j.k.l.m.n.o.W p.q.r.P A s.t.!.u.v.w.. . . . . . ", ". . . . . x.y.z.A.B.C.X D.E.F.G.H.I.J.K.L.M.N.O.P.Q.. . . . . . ", ". . . . . R.S.T.U.V.H.W.X.Y.Z.`. +.+++@+#+$+%+&+*+=+. . . . . . ", ". . . . . -+;+,.>+,+'+)+!+~+{+]+^+/+(+_+:+<+[+}+|+1+. * . . . . ", ". . . . . 2+3+4+5+6+7+8+9+0+a+b+c+z.z.(+d+A.e+f+g+h+i+. . . . . ", ". . . . . j+k+S l+m+z.A.n+a+S o+p.p+q+r+d+s+*.t+u+v+w+. . . . . ", ". . . . . x+y+z+A+B+C+D+E+F+G+J.H+I+J+K+L+M+N+O+P+Q+. * . . . . ", ". . . . * . R+S+T+]+U+V+W+X+|.Y+}.O.Z+`+ @.@+@@@#@$@. . . . . . ", ". . . . . * %@&@*@6.=@-@;@X >@,@'@)@s+!@~@A {@]@^@/@(@. . . . . ", ". . . . . * _@:@` <@>+4+z.A [@}@|@W F+B.s+J.1@2@3@4@. * . . . . ", ". . . . . . . 5@6@7@k.&+s+}@8@9@0@!.a@b@c@d@e@f@g@h@* . . . . . ", ". . . . . * * . i@j@k@>+l@m@n@l@o@L.p@q@r@s@t@u@v@w@. * . . . . ", ". . . . . . . . x@y@P z@A@B@C@D@E@F@ .G@H@.+I@J@K@L@* . . . . . ", ". . . . . . . * M@N@O@P@Q@R@T E+S@q+u+T@U@V@W@X@(@. . . . . . . ", ". . . . . . . . . Y@Z@`@ #.#+#@###$#%#&#*#=#-#;#>#. * . . . . . ", ". . . . * . * . * . ,#'#*@)#!#~#{#A@]#(+^#/#(#_#:#. . * . . . . ", ". . . . . * . <#[#}#|#1#2#3#4#5#6#7#/#8#9#0#a#b#+ . * . . . . . ", ". . . . . * c#d#e#f#g#h#i#j#k#l#m#n#).o#p#q#r#s#d#c#* . . . . . ", ". . . . . t#u#v#w#x#y#z#A#B#C#` D#E#F#G#H#I#J#w#K#u#t#. . . . . ", ". . . . . L#M#v#f#N#O#P#Q#R#S#T#U#V#W#X#Y#Z#`#f#v#M#L#. . . . . ", ". . . . * * $u#.$+$@$#$$$%$&$*$=$z#-$$$#$@$+$.$u# $* * . . . . ", ". . . . . * . $.;$>$,$'$)$w#!$~$~$!$w#)$'$,$>$;$$.. * . . . . . ", ". . . . * . . . * . + L# $c#{$[#[#{$c# $L#+ . * . . . * . . . . "}; barry-0.18.5/logo/barry_logo_icon.png0000644001161500056700000000752412242254476017101 0ustar cdfreycdfreyPNG  IHDR00WsRGBbKGD pHYs.#.#x?vtIME 5TrIDAThř{Uy{s?9 3$'Cj%`hTTT*ڋZ,*RjQаH@ `hm'̜{ǜͷg36AXxg/_6'_=i֯1ƌk>,4=|}p-~?@11!=&!8KN;vcbln%g^j/En·>`;YͨM!3dy&$FKthh?Ni0ưMntQDsl}h+]97#,Aqo _Ood'1 " uSs6%J$t}+9+gq˧oQ輻Ԋ$^OB2c]kレoiyB)41eon㎛?Ͳ#Ne~OᮈkKQinsfK!&,vN/[gU[¶~R 10wܹjABϧ`|A~Ss.daA d8= n&82늁cscb#kȾs ";kā>EI:oG+ " g,r:tl( ˬUGFiW8'I1Z;rM @:fTX !\N!9qDe˚j&0 Tb8Q`&'On2qTY6єL k&vʱj*c48۳y!LHA9s RP>԰̗i&=嚫o=$ƿ}ӭlrZeYdzB7ٰN-L׽vڬmYKu`nu\#g/|?]{bK8t.noB8\<20̕)Zd+f렍!.lnK̬Qm%'WO'c`xhJ >>‡sh!-Slr[Y.gSKфh '9rjܵ@nث(?3#,"42Қ7_nџ<8}|Xwl+]K;H#DZ Bc#Rb 8lBZd #c별hv>INHilFꤞ% A6f8'T*.UBN MB2:Fѫ+}֭[wƌ|F7~f߳k^7z9F1N]'bk.Zs=d6I.^Lk^n`.oWҀ;^[_oc_Ec;RZcϳ抷$,ąMZe`TКC67bB,))쭋GB+ː0yYR܏L?8'41Xxps2 QFE$!!%b1PX !(Hq3.Zm$n<7Y頋e~6R<*d׮]Ѣ֚K'ii[6sk|5sDsVJdE"CQ:uCj'W3l(Z4{U1ll= @ cY\葓 +{jT>BP5!cSHIT7 w,lA5y]Gq_x͠-kF:!4z."yUfDQX 9 eKNy=poc/GvP)3^opFBЭJ5Qj^s7axE?M l:Eeb#eL mKӻ.DL3u>hCɄq.}ZYr2Fo0Feh#~,!Y$gpTR!aP]+_9[ Vtb wbx*S?!rݼ^fw!KeU%"zT~]%^ŮJ%K۴dc}JBT\.>[; xJwJ,υlT,SA{"VwG}HRbg%aHTX,R,)JuZyS)t0QRQ|V[X`eT5Q.s?mN+5"ƴϽ04RH,lL&8'qE kRDq`Z* CLJmJ^ {Xg7q2!aFvxyk&NBk1l6{F'<ϫZFZRPT( ~W(p9Ze 9y image/svg+xml barry-0.18.5/logo/barry_logo.svg0000644001161500056700000023642712242254476016112 0ustar cdfreycdfrey image/svg+xml Barry Barry Open SourceMobile Access Open SourceMobile Access netdirect.ca/barry netdirect.ca/barry barry-0.18.5/logo/README0000644001161500056700000000071112242254476014073 0ustar cdfreycdfreyThese logos were originally designed by Martin Owens and made available at the following URL: http://doctormo.deviantart.com/art/Barry-Project-Branding-127863514 for the Barry project, under the Creative Commons BY-SA license. The license can be found here: http://creativecommons.org/licenses/by-sa/3.0/ The logo #1 available at the above site is not included here, since it uses the trademarked term "Blackberry" owned by RIM. barry-0.18.5/ppp/0000755001161500056700000000000012242254476013053 5ustar cdfreycdfreybarry-0.18.5/ppp/barry-emobile.chat0000644001161500056700000000111712242254476016445 0ustar cdfreycdfrey# # Some of these options found documented at: # http://wiki.colar.net/tethering_with_blackberry_pearl_on_linux # # Others are based on the peer file in XmBlackBerry # # Please send all working peer files to cdfrey@foursquare.net, so we can # build a library of peer files for different carriers. # ABORT ERROR '' AT&F OK ATZ OK ATI OK AT+CNUM OK AT+CSQ # Some Blackberries reboot on this command #OK AT+CREG? #OK AT+CGDCONT? #OK AT+CGQREQ? #OK AT+CGQMIN? #OK AT+CGATT? #OK AT+CGREG? OK AT+CGDCONT=1,"IP","data.eircom.ie" #OK AT+CGDCONT=1,"IP","broadband.eircombb.ie" OK ATDT*99# CONNECT barry-0.18.5/ppp/barry-telus.chat0000644001161500056700000000044412242254476016167 0ustar cdfreycdfrey# # This sample chat script was reported to the mailing list by Andy Herkey, # for his Sprint provider. # # Please send all working peer files to cdfrey@foursquare.net, so we can # build a library of peer files for different carriers. # ABORT ERROR '' AT&F OK ATZ OK ATI OK ATDT#777 CONNECT barry-0.18.5/ppp/barry-chinamobile.chat0000644001161500056700000000025312242254476017303 0ustar cdfreycdfreyABORT BUSY ABORT 'NO CARRIER' ABORT VOICE ABORT 'NO DIALTONE' ABORT 'NO DIAL TONE' ABORT 'NO ANSWER' ABORT DELAYED ABORT ERROR OK 'AT+CGDCONT=1,"IP","cmnet"' OK 'ATDT*99#'barry-0.18.5/ppp/barry-mts0000644001161500056700000000131412242254476014715 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation connect "/usr/sbin/chat -f /etc/chatscripts/barry-mts.chat" pty "/usr/sbin/pppob" debug # For Manitoba's MTS, you need to use a username in the form of # "##########@mip.1x.mts.net" (########## is your 10 digit phone number) # and a password of ########## (the same 10 digit number). # # Confirmed by Chris Chatelain noauth user "##########@mip.1x.mts.net" password "##########" name wapuser defaultroute usepeerdns noipdefault nodetach nodeflate nobsdcomp noaccomp nocrtscts nopcomp nomagic novj ipcp-restart 7 ipcp-accept-local ipcp-accept-remote lcp-echo-interval 0 lcp-echo-failure 999 passive mtu 1492 barry-0.18.5/ppp/barry-telus0000644001161500056700000000075712242254476015260 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation # This is a copy of barry-sprint, confirmed to work by Matt McGirr connect "/usr/sbin/chat -f /etc/chatscripts/barry-telus.chat" pty "/usr/sbin/pppob" debug noauth user wapuser password wap name wapuser defaultroute usepeerdns noipdefault nodetach nodeflate nobsdcomp noaccomp nocrtscts nopcomp nomagic novj ipcp-restart 7 ipcp-accept-local ipcp-accept-remote lcp-echo-interval 0 lcp-echo-failure 999 passive mtu 1492 barry-0.18.5/ppp/barry-vodafone-au.chat0000644001161500056700000000115212242254476017234 0ustar cdfreycdfrey# # Some of these options found documented at: # http://wiki.colar.net/tethering_with_blackberry_pearl_on_linux # # Others are based on the peer file in XmBlackBerry # # Please send all working peer files to cdfrey@foursquare.net, so we can # build a library of peer files for different carriers. # ABORT ERROR '' AT&F OK ATZ #OK ATI #OK AT+CNUM #OK AT+CSQ # Some Blackberries reboot on this command #OK AT+CREG? #OK AT+CGDCONT? #OK AT+CGQREQ? #OK AT+CGQMIN? #OK AT+CGATT? #OK AT+CGREG? #OK AT+CGDCONT=1,"IP","internet.com" OK AT+CGDCONT=1,"IP","live.vodafone.com" OK ATE0V1 OK AT OK ATS0=0 OK ATDT*99# CONNECT barry-0.18.5/ppp/barry-emobile0000644001161500056700000000042012242254476015523 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation connect "/usr/sbin/chat -f /etc/chatscripts/barry-emobile.chat" pty "/usr/sbin/pppob" user wapuser1 nodetach defaultroute noipdefault noauth usepeerdns lcp-echo-failure 0 lcp-echo-interval 0 debug barry-0.18.5/ppp/barry-kpn.chat0000644001161500056700000000033312242254476015620 0ustar cdfreycdfreyABORT BUSY ABORT 'NO CARRIER' ABORT VOICE ABORT 'NO DIALTONE' ABORT 'NO DIAL TONE' ABORT 'NO ANSWER' ABORT DELAYED ABORT ERROR SAY "Initializing\n" '' ATZ OK AT+CGDCONT=1,"IP","internet" OK-AT-OK ATDT*99# CONNECT \d\c barry-0.18.5/ppp/barry-orangeuk0000644001161500056700000000067512242254476015736 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation connect "/usr/sbin/chat -f /etc/chatscripts/barry-orangeuk.chat" pty "/usr/sbin/pppob" debug noauth user orange password orange name orange defaultroute usepeerdns noipdefault nodetach nodeflate nobsdcomp noaccomp nocrtscts nomagic nopcomp novj #nomultilink ipcp-restart 7 ipcp-accept-local ipcp-accept-remote lcp-echo-interval 0 lcp-echo-failure 999 passive mtu 1492 barry-0.18.5/ppp/barry-orange-spain.chat0000644001161500056700000000036412242254476017417 0ustar cdfreycdfreyABORT BUSY ABORT 'NO CARRIER' ABORT VOICE ABORT 'NO DIALTONE' ABORT 'NO DIAL TONE' ABORT 'NO ANSWER' ABORT DELAYED ABORT ERROR SAY "Initializing\n" '' ATZ SAY "ATE\n" OK 'AT+CGDCONT=1,"IP","internet"' OK 'AT' OK 'ATDT*99***1#' SAY "Dialing\n" barry-0.18.5/ppp/barry-chinamobile0000644001161500056700000000065312242254476016371 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation connect "/usr/sbin/chat -f /etc/chatscripts/barry-chinamobile.chat" pty "/usr/sbin/pppob" debug noauth user "" password "" defaultroute usepeerdns noipdefault nodetach nodeflate nobsdcomp noaccomp nocrtscts nopcomp nomagic novj nomultilink ipcp-restart 7 ipcp-accept-local ipcp-accept-remote lcp-echo-interval 0 lcp-echo-failure 999 passive mtu 1492 barry-0.18.5/ppp/barry-vodafone-au0000644001161500056700000000067412242254476016326 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation connect "/usr/sbin/chat -f /etc/chatscripts/barry-vodafone-au.chat" pty "/usr/sbin/pppob" debug noauth user "" password "" defaultroute usepeerdns noipdefault updetach nodeflate nobsdcomp noaccomp nocrtscts nopcomp nomagic nomultilink ipcp-restart 7 ipcp-accept-local ipcp-accept-remote ipcp-max-configure 30 lcp-echo-interval 0 lcp-echo-failure 999 passive mtu 1492 barry-0.18.5/ppp/barry-o2ireland0000644001161500056700000000060112242254476015767 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation connect "/usr/sbin/chat -f /etc/chatscripts/barry-o2ireland.chat" pty "/usr/sbin/pppob" debug debug debug user "gprs" password "gprs" defaultroute usepeerdns noipdefault nodetach nocrtscts novj nomultilink ipcp-restart 7 ipcp-accept-local ipcp-accept-remote lcp-echo-interval 0 lcp-echo-failure 999 mtu 1492 barry-0.18.5/ppp/barry-att_cingular0000644001161500056700000000100612242254476016564 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation # pppd peer file for ATT / Cingular # by Richard Esplin # Licensed under the same terms as libbarry. connect "/usr/sbin/chat -f /etc/chatscripts/barry-att_cingular.chat" pty "/usr/sbin/pppob" debug noauth user "" password "" defaultroute usepeerdns noipdefault nodetach nodeflate nobsdcomp noaccomp nocrtscts nopcomp nomagic novj ipcp-restart 7 ipcp-accept-local ipcp-accept-remote lcp-echo-interval 0 lcp-echo-failure 999 passive mtu 1492 barry-0.18.5/ppp/barry-minimal.chat0000644001161500056700000000104012242254476016452 0ustar cdfreycdfrey# # Some of these options found documented at: # http://wiki.colar.net/tethering_with_blackberry_pearl_on_linux # # Others are based on the peer file in XmBlackBerry # # Please send all working peer files to cdfrey@foursquare.net, so we can # build a library of peer files for different carriers. # ABORT ERROR '' AT&F OK ATZ OK ATI OK AT+CNUM OK AT+CSQ # Some Blackberries reboot on this command #OK AT+CREG? #OK AT+CGDCONT? #OK AT+CGQREQ? #OK AT+CGQMIN? #OK AT+CGATT? #OK AT+CGREG? OK AT+CGDCONT=1,"IP","internet.com" OK ATDT*99# CONNECT barry-0.18.5/ppp/barry-att_cingular.chat0000644001161500056700000000114712242254476017510 0ustar cdfreycdfrey# Chatscript for ATT / Cingular # by Richard Esplin # Licensed under the same terms as libbarry. # # Please send all working peer files to cdfrey@foursquare.net, so we can # build a library of peer files for different carriers. # Google says this info is important for ATT/Cingular: # Modem Initialization String: AT +CGDCONT=1,"IP","wap.cingular" # Dial-up Phone Number: *99# # Dial-up username/password: blank/blank SAY 'Setting abort string\n' ABORT ERROR SAY 'Initializing modem\n' OK AT OK ATZ SAY 'Carrier Information\n' OK AT+CGDCONT=1,"IP","wap.cingular" OK ATI OK ATDT*99# SAY 'Connecting\n' CONNECT barry-0.18.5/ppp/barry-optus-au.chat0000644001161500056700000000114112242254476016603 0ustar cdfreycdfrey# # Some of these options found documented at: # http://wiki.colar.net/tethering_with_blackberry_pearl_on_linux # # Others are based on the peer file in XmBlackBerry # # Please send all working peer files to cdfrey@foursquare.net, so we can # build a library of peer files for different carriers. # ABORT ERROR '' AT&F OK ATZ #OK ATI #OK AT+CNUM #OK AT+CSQ # Some Blackberries reboot on this command #OK AT+CREG? #OK AT+CGDCONT? #OK AT+CGQREQ? #OK AT+CGQMIN? #OK AT+CGATT? #OK AT+CGREG? #OK AT+CGDCONT=1,"IP","internet.com" OK AT+CGDCONT=1,"IP","internet" OK ATE0V1 OK AT OK ATS0=0 OK ATDT*99# CONNECT barry-0.18.5/ppp/barry-sprint0000644001161500056700000000065512242254476015440 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation connect "/usr/sbin/chat -f /etc/chatscripts/barry-sprint.chat" pty "/usr/sbin/pppob" debug noauth user wapuser password wap name wapuser defaultroute usepeerdns noipdefault nodetach nodeflate nobsdcomp noaccomp nocrtscts nopcomp nomagic novj ipcp-restart 7 ipcp-accept-local ipcp-accept-remote lcp-echo-interval 0 lcp-echo-failure 999 passive mtu 1492 barry-0.18.5/ppp/barry-minimal0000644001161500056700000000077012242254476015545 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation # This is based on connection data for a Rogers provider. # Sometimes it is better to let pppd do the handshaking for us. # In cases where barry-rogers gives the error # "Could not determine local IP address", this setup may work. connect "/usr/sbin/chat -f /etc/chatscripts/barry-minimal.chat" pty "/usr/sbin/pppob" user wapuser1 nodetach defaultroute noipdefault noauth usepeerdns lcp-echo-failure 0 lcp-echo-interval 0 debug barry-0.18.5/ppp/barry-rogers0000644001161500056700000000065512242254476015422 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation connect "/usr/sbin/chat -f /etc/chatscripts/barry-rogers.chat" pty "/usr/sbin/pppob" debug noauth user wapuser password wap name wapuser defaultroute usepeerdns noipdefault nodetach nodeflate nobsdcomp noaccomp nocrtscts nopcomp nomagic novj ipcp-restart 7 ipcp-accept-local ipcp-accept-remote lcp-echo-interval 0 lcp-echo-failure 999 passive mtu 1492 barry-0.18.5/ppp/barry-fido.chat0000644001161500056700000000034512242254476015754 0ustar cdfreycdfrey# # Contributed to Barry by Sujay D'Souza # ABORT BUSY ABORT 'NO CARRIER' ABORT VOICE ABORT 'NO DIALTONE' ABORT 'NO DIAL TONE' ABORT 'NO ANSWER' ABORT DELAYED ABO RT ERROR OK 'AT+CGDCONT=1,"IP","internet.fido.ca"' OK 'ATDT*99#' barry-0.18.5/ppp/barry-mts.chat0000644001161500056700000000006712242254476015637 0ustar cdfreycdfreyABORT ERROR '' AT&F OK ATZ OK ATI OK ATDT#777 CONNECT barry-0.18.5/ppp/barry-o2ireland.chat0000644001161500056700000000026112242254476016707 0ustar cdfreycdfreyABORT BUSY ABORT 'NO CARRIER' ABORT VOICE ABORT 'NO DIALTONE' ABORT 'NO DIAL TONE' ABORT 'NO ANSWER' ABORT DELAYED ABORT ERROR OK 'AT+CGDCONT=1,"IP","wap.dol.ie"' OK 'ATDT*99#' barry-0.18.5/ppp/barry-verizon.chat0000644001161500056700000000012312242254476016521 0ustar cdfreycdfreyABORT ERROR '' +++AT '' ATZ OK AT&F OK ATE0V1 OK AT OK ATS0=0 OK ATDT#777 CONNECT barry-0.18.5/ppp/barry-tmobileus0000644001161500056700000000075212242254476016122 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation connect "/usr/sbin/chat -f /etc/chatscripts/barry-tmobileus.chat" pty "/usr/sbin/pppob" debug user "" password "" defaultroute usepeerdns noipdefault nodetach noaccomp nocrtscts nopcomp nomagic novj nomultilink ipcp-restart 7 ipcp-accept-local ipcp-accept-remote lcp-echo-interval 0 lcp-echo-failure 999 mtu 1492 # 921600 Works For Me (TM) but won't "speed up" your connection. # 115200 also works. 921600 local barry-0.18.5/ppp/barry-orangeuk.chat0000644001161500056700000000103712242254476016645 0ustar cdfreycdfrey# # Some of these options found documented at: # http://wiki.colar.net/tethering_with_blackberry_pearl_on_linux # # Others are based on the peer file in XmBlackBerry # # Please send all working peer files to cdfrey@foursquare.net, so we can # build a library of peer files for different carriers. # ABORT ERROR '' AT&F OK ATZ OK ATI OK AT+CNUM OK AT+CSQ # Some Blackberries reboot on this command #OK AT+CREG? OK AT+CGDCONT? #OK AT+CGQREQ? #OK AT+CGQMIN? OK AT+CGATT? OK AT+CGREG? OK AT+CGDCONT=1,"IP","orangeinternet" OK ATDT*99# CONNECT barry-0.18.5/ppp/README0000644001161500056700000000534112242254476013736 0ustar cdfreycdfreyThis directory contains sample options files for pppd, as well as their associated chatscript files. They are named for the various Blackberry vendors that have different connect sequences for tethered modems. Each file is tagged with the name "barry" as well, so they can be installed in /etc/ppp/peers someday, to make all this automated and easy. It is a good idea to review these options files to make sure they suit your system. Particularly the defaultroute options, and their various security implications. You may wish to read the following URLs http://fixunix.com/ppp/62469-dial-up-route-problem-2.html http://groups.google.com/group/comp.os.linux.misc/browse_thread/thread/11fb49a3c035573/7d7e19b2e4820b0c http://linuxgazette.net/issue77/lechnyr.html Other options can be found at: http://wiki.colar.net/tethering_with_blackberry_pearl_on_linux The original peer files were based on the XmBlackBerry peer file, but many have been added over the years for various ISPs. Please send all working peer files to cdfrey@foursquare.net, so we can build a library of peer files for different carriers. Peer File Option Notes: ----------------------- # # the chat script and the USB link # connect "/usr/sbin/chat -f /etc/chatscripts/barry-rogers.chat" pty "/usr/sbin/pppob" # # decide the level of debug output you need # debug #debug debug debug # # authentication options - no need for ISP to authenticate to us, but # we may need a login here: user/password/name # # Rogers style: noauth user wapuser password wap name wapuser # or: # T-Mobile style: # You may not need to auth. If you do, use your user/pass # from www.t-mobile.com. user "" password "" # # routing options # #nodefaultroute # the safest, but least useful defaultroute usepeerdns # # options that are usually unsupported, so disable them # noipdefault nodetach # note that there's a new option on the scene: updetach #updetach nodeflate nobsdcomp noaccomp nocrtscts nopcomp nomagic #default-asyncmap # does not usually need to be specified # This is disabled by default for a Barry config, but this # has caused connection issues in the past. If you are unable # to get an ip with your provider, try commenting this out. # See: # http://www.mail-archive.com/barry-devel@lists.sourceforge.net/msg01871.html novj #nomultilink ipcp-restart 7 ipcp-accept-local ipcp-accept-remote # need lcp-echo turned off, at least for tmobile, otherwise c0onnectin # disconnects after few mn of inactivity. # thanks to loon for this info lcp-echo-interval 0 lcp-echo-failure 999 # # limit size of packets, misc. options # passive mtu 1492 # # unused options... modem and local are opposites, and determine how # far pppd goes to use the line like a modem # #modem #local barry-0.18.5/ppp/barry-tmobileus.chat0000644001161500056700000000034612242254476017037 0ustar cdfreycdfreyABORT BUSY ABORT 'NO CARRIER' ABORT VOICE ABORT 'NO DIALTONE' ABORT 'NO DIAL TONE' ABORT 'NO ANSWER' ABORT DELAYED ABORT ERROR SAY "Initializing\n" '' ATZ OK AT+CGDCONT=1,"IP","wap.voicestream.com" OK-AT-OK ATDT*99# CONNECT \d\c barry-0.18.5/ppp/barry-kpn0000644001161500056700000000065212242254476014706 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation connect "/usr/sbin/chat -f /etc/chatscripts/barry-kpn.chat" pty "/usr/sbin/pppob" debug noauth user "KPN" password "gprs" defaultroute usepeerdns noipdefault nodetach nodeflate nobsdcomp noaccomp nocrtscts nomultilink nopcomp nomagic novj ipcp-restart 7 ipcp-accept-local ipcp-accept-remote lcp-echo-interval 0 lcp-echo-failure 999 passive mtu 1492 barry-0.18.5/ppp/barry-verizon0000644001161500056700000000056212242254476015612 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation connect "/usr/sbin/chat -f /etc/chatscripts/barry-verizon.chat" pty "/usr/sbin/pppob" debug noauth user "" password "" defaultroute usepeerdns noipdefault nodetach nocrtscts novj nomultilink ipcp-restart 7 ipcp-accept-local ipcp-accept-remote lcp-echo-interval 0 lcp-echo-failure 999 mtu 1492 barry-0.18.5/ppp/barry-sprint.chat0000644001161500056700000000044412242254476016352 0ustar cdfreycdfrey# # This sample chat script was reported to the mailing list by Andy Herkey, # for his Sprint provider. # # Please send all working peer files to cdfrey@foursquare.net, so we can # build a library of peer files for different carriers. # ABORT ERROR '' AT&F OK ATZ OK ATI OK ATDT#777 CONNECT barry-0.18.5/ppp/barry-optus-au0000644001161500056700000000066712242254476015701 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation connect "/usr/sbin/chat -f /etc/chatscripts/barry-optus.chat" pty "/usr/sbin/pppob" #debug noauth user "" password "" defaultroute usepeerdns noipdefault updetach nodeflate nobsdcomp noaccomp nocrtscts nopcomp nomagic nomultilink ipcp-restart 7 ipcp-accept-local ipcp-accept-remote ipcp-max-configure 30 lcp-echo-interval 0 lcp-echo-failure 999 passive mtu 1492 barry-0.18.5/ppp/barry-rogers.chat0000644001161500056700000000104012242254476016325 0ustar cdfreycdfrey# # Some of these options found documented at: # http://wiki.colar.net/tethering_with_blackberry_pearl_on_linux # # Others are based on the peer file in XmBlackBerry # # Please send all working peer files to cdfrey@foursquare.net, so we can # build a library of peer files for different carriers. # ABORT ERROR '' AT&F OK ATZ OK ATI OK AT+CNUM OK AT+CSQ # Some Blackberries reboot on this command #OK AT+CREG? #OK AT+CGDCONT? #OK AT+CGQREQ? #OK AT+CGQMIN? #OK AT+CGATT? #OK AT+CGREG? OK AT+CGDCONT=1,"IP","internet.com" OK ATDT*99# CONNECT barry-0.18.5/ppp/barry-orange-spain0000644001161500056700000000065412242254476016503 0ustar cdfreycdfrey# See the README file in the source tree for notes and documentation connect "/usr/sbin/chat -f /etc/chatscripts/barry-orange-spain.chat" pty "/usr/sbin/pppob" debug noauth user "" password "" defaultroute usepeerdns noipdefault nodetach nodeflate nobsdcomp noaccomp nocrtscts nomagic nopcomp novj nomultilink ipcp-restart 7 ipcp-accept-local ipcp-accept-remote lcp-echo-interval 0 lcp-echo-failure 999 passive mtu 1492 barry-0.18.5/hotplug/0000755001161500056700000000000012242254476013736 5ustar cdfreycdfreybarry-0.18.5/hotplug/barry.usermap0000644001161500056700000000057312242254476016460 0ustar cdfreycdfrey# usb module match_flags idVendor idProduct bcdDevice_lo bcdDevice_hi bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass bInterfaceSubClass bInterfaceProtocol driver_info barry 0x0003 0x0fca 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 barry-0.18.5/hotplug/barry0000755001161500056700000000037712242254476015012 0ustar cdfreycdfrey#!/bin/bash # Based on the libgphoto2-2 script. GROUP=barry if [ "$ACTION" = "add" ] && [ -f "$DEVICE" ] then # check if $GROUP really exists if getent group $GROUP > /dev/null; then chmod 660 "$DEVICE" chown root.$GROUP "$DEVICE" fi fi barry-0.18.5/hotplug/README0000644001161500056700000000027312242254476014620 0ustar cdfreycdfreyDrop these files into /etc/hotplug/usb, to adjust the permissions automatically. Blackberry devices will be set to 0660 group barry. Don't forget to add the barry group to your system. barry-0.18.5/AUTHORS0000644001161500056700000001203212242254476013322 0ustar cdfreycdfreyWritten by: ----------- Chris Frey Net Direct Inc. Contributors (code and otherwise) in alphabetical order by last name: --------------------------------------------------------------------- Cesar Ballardini - Spanish translation work Michael Brown - udev rules patch - edge case testing Nicolas CARRIER - French translation work Ian Darwin - documentation fixes and additions - OpenBSD port maintainer Lee Dixon - Birthday field and opensync patch Sujay D'Souza - chat script for fido Paul Dugas - x86_64 build fix Brian Edginton - Contact and Calendar record patches, parsing unknown fields - New record parser classes: - Memos - PIN Messages - Tasks Troy Engel - usb captures on Windows XP for the BlackBerry Pearl - udev script updates - CVS testing - RPM spec files David Everly - inspiration for 'make distcheck' fixes Ron Gage - CVS testing - reverse engineering Service Book record Dr. J A Gow - recurring calendar item sync support Toby Gray - RAW channel support Andy Herkey - sample ppp chat script for Sprint - ipmodem password patches - contrib/modemtest.rb - general modem guru Jonathan Hudson - big endian testing and patches Simon Kenyon - ppp chat scripts for O2 Ireland Josh Kropf - bjavaloader command syntax changes - dump eventlog and clear eventlog support - logstacktraces support - resettofactory support - bjavaloader save module support - forced erase and load while module in use - packed module support in pkzip format Ryan Li - SMS record parsing - China mobile chat script - barrybackup GUI enhancements - threaded multi-device support in barrybackup - bash-completion scripts Duncan Mak - modern udev updates David Mansfield - opensync password patch Alberto Mattea - the bwatch tool Peter McAlpine - autoconf patches Alan Miller - usb captures on Windows XP for password authentication Andrew Nording (https://sourceforge.net/users/nording/) - ppp chatscripts for KPN Nederland Martin Owens - integration with HAL, udev, opensync, and Conduit - low level USB testing - hal FDI scripts and configuration - documentation of Content Store and SMS Messages formats - Barry logo Bill Paul - FreeBSD pppob notes and script (contrib) Mick Reed - ppp chat scripts for T-Mobile US Simon Ruggier - autoconf / build system patch - modprobe advice for bcharge/berry_charge conflict Rick Scott - password authentication code and tips - GPRS modem behaviour Peter Silva - debian packaging Andrew Sims - ppp chatscripts for Orange UK Jose Carlos Garcia Sogo - debian packaging patches Michael L. Stokes - sample ppp files for Verizon devices Adrian Taylor - preliminary work on RAW channel support Jason Thomas - autoconf / build system patch - debian package patch - ppp chatscripts for Optus and Vodafone AU Nicolas VIVIEN - bjavaloader support - screenshot support - zsh command completion scripts - Blackberry Storm fixes - opensync 0.4x plugin port - photo sync support - memo sync support - task sync support - call log parser - ldif converter patches - JVM Debug support, and bjdwp - btardump & MIME vformat using - bookmark parser - Single & multiple ALX parser - French translation work Bojan Vondra - openSUSE build and packaging contributions Niels de Vos - debian package patches - usb_storage unbind script Ashley Willis - btool null parser patch - perlbarry contrib package Robert Yaklin - VSM file format documentation Hardware Contributions (Thanks!): --------------------------------- Eric Arseneau and Jon Hylands - Blackberry 9530 - Blackberry 9550 - Blackberry Playbook Official Distro Package Maintainers: ------------------------------------ The following people and distributions include Barry as an official package in their repositories. If you use one of these distros, Barry may already be integrated into your system, and tested, thanks to these people. They have also made their presence known on the mailing list, and can be contacted there. Fedora Nathanael Noblet barry-0.18.5/doc/0000755001161500056700000000000012242254476013021 5ustar cdfreycdfreybarry-0.18.5/doc/javaloader0000644001161500056700000013326412242254476015065 0ustar cdfreycdfreyJavaLoader reverse ================== After Probe process, we have the JavaLoader command Legend : >>> : Sent <<< : Received Open Socket with BlackBerry device, then select the JavaLoader mode. URB 22 : >>> 00000000: 00 00 0c 00 05 ff 00 07 04 00 0a 00 ............ URB 23 : <<< 00000000: 00 00 10 00 06 ff 00 07 04 00 0a 00 20 f9 04 80 ............ ... URB 25 : >>> 00000000: 00 00 0c 00 05 ff 00 08 04 00 0b 00 ............ URB 24 : <<< 00000000: 00 00 10 00 06 ff 00 08 04 00 0b 00 00 00 00 00 ................ URB 27 : >>> 00000000: 00 00 18 00 07 ff 00 09 52 49 4d 5f 4a 61 76 61 ........RIM_Java 00000010: 4c 6f 61 64 65 72 00 00 Loader.. URB 26 : <<< 00000000: 00 00 30 00 08 04 00 09 52 49 4d 5f 4a 61 76 61 ..0.....RIM_Java 00000010: 4c 6f 61 64 65 72 00 00 00 00 00 00 01 00 08 00 Loader.......... 00000020: 02 00 08 00 03 01 00 00 04 01 00 00 05 10 01 00 ................ URB 29 : >>> 00000000: 00 00 0c 00 0a 04 00 0a 10 03 00 00 ............ URB 28 : <<< 00000000: 00 00 08 00 10 04 00 0a ........ URB 30 : <<< 00000000: 00 00 0c 00 13 04 01 00 00 00 00 00 ............ URB 31 : <<< 00000000: 04 00 05 00 01 ..... Specific command for JavaLoder. URB 33 : >>> 00000000: 04 00 08 00 64 00 00 00 ....d... ^^ : command ^^^^^ : packet size ^^^^^ : socket ID URB 32 : <<< 00000000: 00 00 0c 00 13 04 01 00 01 00 00 00 ............ URB 34 : <<< 00000000: 04 00 08 00 65 00 00 00 ....e... URB 36 : >>> 00000000: 04 00 08 00 70 00 01 00 ....p... ^^ : command ^^^^^ : packet size ^^^^^ : socket ID URB 35 : <<< 00000000: 00 00 0c 00 13 04 01 00 02 00 00 00 ............ URB 38 : >>> 00000000: 04 00 05 00 00 ..... ^^ : command ^^^^^ : packet size ^^^^^ : socket ID URB 37 : <<< 00000000: 00 00 0c 00 13 04 01 00 03 00 00 00 ............ URB 39 : <<< 00000000: 04 00 08 00 64 00 00 00 ....d... SendStream command. URB 41 : >>> 00000000: 04 00 08 00 67 01 04 00 ....g... ^^ : command to send the stream total size ^^^^^ : packet size ^^^^^ : socket ID URB 40 : <<< 00000000: 00 00 0c 00 13 04 01 00 04 00 00 00 ............ Start of data stream. URB 43 : >>> 00000000: 04 00 08 00 00 00 1e d0 ........ ^^^^^^^^^^^ : Application size (maybe 4 bytes) ^^^^^ : packet size ^^^^^ : socket ID URB 42 : <<< 00000000: 00 00 0c 00 13 04 01 00 05 00 00 00 ............ URB 44 : <<< 00000000: 04 00 08 00 64 00 00 00 ....d... Data header packet. URB 46 : >>> 00000000: 04 00 08 00 68 00 f8 07 ....h... ^^^^^ : data size for the next packet ^^ : always 0x00 ^^ : command ^^^^^ : packet size ^^^^^ : socket ID URB 45 : <<< 00000000: 00 00 0c 00 13 04 01 00 06 00 00 00 ............ Data packet. URB 48 : >>> 00000000: 04 00 fc 07 de c0 ff ff 00 00 00 00 00 00 00 00 ................ ^^ ..... : content of file ^^^^^ : packet size (0x07F8 = 0x07FC - 0x02) ^^^^^ : socket ID 00000010: c8 fe 59 49 00 00 00 00 00 00 00 00 08 00 ff ff ..YI............ 00000020: ff ff ff ff ff ff ff ff 4e 00 8c 01 18 1d 00 00 ........N....... 00000030: 93 19 7b 1b 58 1b 0f 00 19 00 00 02 01 02 0e b8 ..{.X........... 00000040: 00 cf 05 26 00 01 56 40 01 ff ff 01 1f 58 1b 60 ...&..V@.....X.` 00000050: 1b 16 82 48 18 17 dd 3f 06 ff ff ff 01 3f b8 03 ...H...?.....?.. 00000060: cf 05 4b 01 01 01 ff ff 02 1f 48 18 66 1b 58 1b ..K.......H.f.X. 00000070: 14 00 81 00 00 01 01 04 0e 3f 6d 01 04 00 6d 01 .........?m...m. 00000080: 05 00 6d 01 06 00 06 ff ff ff 04 1f 4a 18 58 1b ..m.........J.X. 00000090: 58 1b 6f 00 18 01 00 00 00 03 0e bb ff ff 13 01 X.o............. 000000a0: 14 b9 ff ff cf 24 09 06 ff ff ff 02 69 01 04 00 .....$......i... 000000b0: 2d 02 01 00 c8 00 69 01 08 00 2d 02 05 00 88 0c -.....i...-..... 000000c0: 69 01 09 00 2d 02 12 00 90 00 69 01 0a 00 2d 02 i...-.....i...-. 000000d0: b4 0b d0 00 69 01 06 00 2d 02 02 00 7c 00 69 01 ....i...-...|.i. 000000e0: 07 00 2d 02 01 00 74 00 69 01 0b 00 2d 02 05 00 ..-...t.i...-... 000000f0: 84 00 69 01 0c 00 2d 02 19 00 a8 00 69 01 0d 00 ..i...-.....i... 00000100: 6d 01 04 00 07 02 e2 00 20 58 1b 5d 1b 3e 18 a2 m....... X.].>.. 00000110: 19 27 dd 2d 02 b0 0b 94 0c 56 3f 28 28 1a 40 01 .'.-.....V?((.@. 00000120: ff ff 03 cd 3f 28 40 1a 40 01 ff ff 03 cd b9 ff ....?(@.@....... 00000130: ff cf 23 06 ff ff ff 02 56 3f 28 28 1a 40 01 ff ..#.....V?((.@.. 00000140: ff 03 cd 3f 28 40 1a 40 01 ff ff 03 cd 1f 58 1b ...?(@.@......X. 00000150: 63 1b 18 09 44 18 15 dd 28 e0 19 08 ff ff ff ff c...D...(....... 00000160: 23 08 ff ff ff ff 3f 06 ff ff ff 01 1f 48 18 63 #.....?......H.c 00000170: 1b 58 1b 3e 00 80 00 00 02 01 06 0e 3f 06 ff ff .X.>........?... 00000180: ff 01 b9 ff ff cf 28 f0 19 27 40 00 00 00 00 00 ......(..'@..... 00000190: 00 10 06 ff ff ff 04 56 3f 40 01 ff ff 02 3f b9 .......V?@....?. 000001a0: ff ff cf 28 08 1a 27 00 00 00 00 00 00 80 00 06 ...(..'......... 000001b0: ff ff ff 04 01 ff ff 02 1f 00 00 00 00 06 00 00 ................ 000001c0: 02 04 46 00 70 00 64 1a 64 1a 58 1b c0 1b c0 1b ..F.p.d.d.X..... 000001d0: 40 1c 9c 1c b6 1c f2 1c 46 00 0e 1d 10 1d 12 1d @.......F....... 000001e0: 14 1d 12 00 c0 1b 93 19 7b 1b 00 00 00 00 00 00 ........{....... 000001f0: 64 1a 90 1a 02 1b 2c 1b 15 1a 57 1a ce 19 d2 19 d.....,...W..... 00000200: 15 1a 4a 19 05 00 88 0c 57 19 01 00 74 00 5f 19 ..J.....W...t._. 00000210: b4 0b d0 00 67 19 12 00 90 00 6f 19 02 00 7c 00 ....g.....o...|. 00000220: 79 19 01 00 c8 00 8e 19 19 00 a8 00 01 00 04 d0 y............... 00000230: 00 00 00 00 02 00 04 d0 00 00 00 00 05 00 04 d0 ................ 00000240: 00 03 30 2e 39 00 00 00 12 00 04 d0 00 10 48 65 ..0.9.........He 00000250: 6c 6c 6f 20 57 6f 72 6c 64 20 44 65 6d 6f 00 00 llo World Demo.. 00000260: 19 00 04 d0 00 17 52 65 73 65 61 72 63 68 20 49 ......Research I 00000270: 6e 20 4d 6f 74 69 6f 6e 20 4c 74 64 2e 00 00 00 n Motion Ltd.... 00000280: 01 00 04 d0 01 00 00 00 b4 0b 04 d0 0b b2 0b b0 ................ 00000290: 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 .PNG........IHDR 000002a0: 00 00 00 30 00 00 00 24 08 06 00 00 00 cf 45 b9 ...0...$......E. 000002b0: 0a 00 00 00 09 70 48 59 73 00 00 0b 13 00 00 0b .....pHYs....... 000002c0: 13 01 00 9a 9c 18 00 00 00 04 67 41 4d 41 00 00 ..........gAMA.. 000002d0: b1 8e 7c fb 51 93 00 00 00 20 63 48 52 4d 00 00 ..|.Q.... cHRM.. 000002e0: 7a 25 00 00 80 83 00 00 f9 ff 00 00 80 e9 00 00 z%.............. 000002f0: 75 30 00 00 ea 60 00 00 3a 98 00 00 17 6f 92 5f u0...`..:....o._ 00000300: c5 46 00 00 0b 26 49 44 41 54 78 da d4 99 7b 70 .F...&IDATx...{p 00000310: 56 e5 9d c7 3f cf 39 e7 7d df e4 7d 73 83 37 17 V...?.9.}..}s.7. 00000320: de 84 04 12 88 20 01 22 b8 08 52 14 a5 0a d2 2e ..... ."..R..... 00000330: 5e a8 2c 14 44 d1 16 84 ca ba 45 f7 a6 5b 76 70 ^.,.D.....E..[vp 00000340: 57 b7 33 76 d8 11 2c d6 e2 14 58 cb 00 4a a1 5d W.3v..,...X..J.] 00000350: d8 41 83 8c 5a 5b 45 a1 24 c4 00 11 04 42 6e e4 .A..Z[E.$....Bn. 00000360: 9e 37 c9 7b 3d b7 e7 d9 3f 88 19 9d ce 8e 44 e2 .7.{=...?.....D. 00000370: 3a fd ce 3c 33 e7 f2 3b e7 f9 7d cf 73 7e d7 47 :..<3..;..}.s~.G 00000380: 28 a5 f8 4b 86 71 35 42 42 88 cf 0e d3 7c 3e df (..K.q5BB....|>. 00000390: 82 89 13 27 7e 37 14 0a e5 65 67 67 67 e8 ba ae ...'~7...eggg... 000003a0: 0d e6 23 b8 ae 2b 3b 3b 3b 7b 5b 5b 5b db 6a 6a ..#..+;;;{[[[.jj 000003b0: 6a fe db b2 ac 43 40 fc 6a 9f ff b3 b9 94 52 5f j....C@.j.....R_ 000003c0: 3a 00 bc 5e ef b2 b5 6b d7 d6 54 57 57 ab a1 42 :..^...k..TWW..B 000003d0: 75 75 b5 5a bd 7a f5 29 c3 30 16 0d 86 c0 e7 87 uu.Z.z.).0...... 000003e0: b8 9a af e7 f3 f9 16 6c df be fd c0 d2 a5 4b 01 .......l......K. 000003f0: 78 f6 d9 67 59 b2 64 09 a7 4e 9d 42 08 41 4d 4d x..gY.d..N.B.AMM 00000400: 0d 00 b9 b9 b9 dc 73 cf 3d bc f0 c2 0b ac 5e bd ......s.=.....^. 00000410: 9a 51 a3 46 b1 7b f7 6e 5c d7 e5 81 07 1e 00 e0 .Q.F.{.n\....... 00000420: d5 57 5f e5 dc b9 73 a4 a6 a6 f2 e4 93 4f 92 92 .W_...s......O.. 00000430: 92 c2 f6 ed db 9d 95 2b 57 ce 77 5d f7 c8 60 57 .......+W.w]..`W 00000440: 40 bb 1a d6 f3 e7 cf 7f e2 33 e5 01 ce 9c 39 c3 @........3....9. 00000450: b6 6d db d8 bd 7b 37 ed ed ed d4 d6 d6 22 a5 24 .m...{7......".$ 00000460: 14 0a 91 96 96 46 75 75 35 b1 58 0c 80 86 86 06 .....Fuu5.X..... 00000470: 1a 1a 1a 00 b8 78 f1 22 7b f7 ee 65 c3 86 0d 04 .....x."{..e.... 00000480: 02 01 b6 6c d9 02 c0 c3 0f 3f 6c dc 79 e7 9d 7f ...l.....?l.y... 00000490: ff b5 d9 40 71 71 71 c1 17 58 6b 1a e3 c6 8d c3 ...@qqq..Xk..... 000004a0: b6 6d 94 52 e8 ba ce e4 c9 93 99 3a 75 2a 1e 8f .m.R.......:u*.. 000004b0: 07 5d d7 f1 fb fd 03 b2 1e 8f 07 00 29 25 52 4a .]..........)%RJ 000004c0: 0c c3 20 10 08 d0 d6 d6 36 f0 ce d1 a3 47 17 01 .. .....6....G.. 000004d0: 02 18 94 57 b9 aa 15 a8 a8 a8 38 dc d7 d7 37 70 ...W......8...7p 000004e0: 9e 9b 9b 4b 79 79 39 13 27 4e 24 2d 2d 8d 9c 9c ...Kyy9.'N$--... 000004f0: 1c aa aa aa 38 78 f0 20 cd cd cd 04 83 41 76 ec ....8x. .....Av. 00000500: d8 c1 be 7d fb 08 06 83 54 56 56 b2 79 f3 66 02 ...}....TVV.y.f. 00000510: 81 00 77 dc 71 07 eb d7 af a7 b6 b6 96 15 2b 56 ..w.q.........+V 00000520: 00 10 0e 87 39 7c f8 f0 a1 c1 2a 3f 18 23 ce 5f ....9|....*?.#._ 00000530: b0 60 41 55 63 63 e3 ff 69 90 1d 1d 1d aa b5 b5 .`AUcc..i....... 00000540: 55 99 a6 a9 a4 94 2a 12 89 a8 78 3c ae 94 52 2a U.....*...x<..R* 00000550: 99 4c aa 9e 9e 9e 01 d9 68 34 3a 70 5c 57 57 a7 .L......h4:p\WW. 00000560: e6 cd 9b 77 14 c8 f9 da 8c b8 df 8d 66 14 14 14 ...w........f... 00000570: ac 5b bc 78 f1 b2 b9 73 e7 96 86 42 21 7c 3e 1f .[.x...s...B!|>. 00000580: 8e e3 90 97 97 47 76 76 f6 80 7c 32 99 a4 be be .....Gvv..|2.... 00000590: 7e 60 42 4d d3 3e 73 a1 08 21 b0 6d 9b a6 a6 26 ~`BM.>s..!.m...& 000005a0: bb a2 a2 e2 e2 eb af bf be ab a5 a5 e5 e7 40 f7 ..............@. 000005b0: 57 71 a3 83 21 f0 19 02 c0 44 21 44 c8 e7 f3 a5 Wq..!....D!D.... 000005c0: 39 8e 63 af 5a b5 ea a7 5b b6 6c 29 06 d8 b5 6b 9.c.Z...[.l)...k 000005d0: 57 df 73 cf 3d b7 eb fc f9 f3 ef 02 b6 74 a5 e3 W.s.=........t.. 000005e0: ba 6e 86 80 91 42 88 a0 10 9a df 91 4e 3b 50 05 .n...B......N;P. 000005f0: 1c 02 9c c1 fe 31 d7 4a e0 cf 30 61 c2 84 97 4e .....1.J..0a...N 00000600: 9f 3e bd e6 d4 a9 53 4c 9a 34 69 39 b0 b3 ff 56 .>....SL.4i9...V 00000610: 61 6a 66 60 61 e1 f8 d1 0b f3 c7 8d 2a 0c 04 03 ajf`a.......*... 00000620: 59 7a 8a ee b3 93 66 32 d9 95 08 db 75 89 8b 27 Yz....f2....u..' 00000630: ab 2a 7f 1b 8d 46 f6 03 6d df 18 01 60 cc c6 8d .*...F..m...`... 00000640: 1b 4f 2e 5f be 3c ad a4 a4 64 6d 34 1a dd 93 95 .O._.<...dm4.... 00000650: 17 7c e6 96 fb ee 7c a8 fc d6 69 69 c3 f2 82 a0 .|....|...ii.... 00000660: 49 4c 27 41 c2 49 10 b3 a3 cc 1b ff 5d a6 87 6e IL'A.I......]..n 00000670: a4 b6 f6 0c af ed f9 75 cb 8e 6d 5b 5f ec e9 09 .......u..m[_... 00000680: 6f 04 ac 6f 82 00 42 88 65 9b 37 6f da a4 83 ef o..o..B.e.7o.... 00000690: a7 9b 5e 6a 59 fc 4f 3f 2c 9d 34 b9 0c af d0 71 ..^jY.O?,.4....q 000006a0: 1c 9b b8 15 23 66 47 e8 88 b5 33 26 78 1d f7 4e ....#fG...3&x..N 000006b0: 5c 88 d0 c0 9f 0a 29 1e 38 76 fc 63 9e 78 e2 ef \.....).8v.c.x.. 000006c0: de 78 ff 8f ef ae 02 9a fe df 09 f4 e3 be 15 2b .x.............+ 000006d0: d7 ee cf 4c 4f 21 e9 17 dc fe ed f9 14 8c 08 11 ...LO!.......... 000006e0: b7 62 84 13 5d 74 c4 da 89 db 09 ee 9d b8 84 e1 .b..]t.......... 000006f0: fe 74 84 00 a9 1c fc 5e 83 40 00 c2 3d 71 d6 ac .t.....^.@..=q.. 00000700: 79 b4 f1 b5 3d 3b e7 00 e7 af 86 80 c1 d0 21 af y...=;........!. 00000710: ec a6 79 ff 12 9a f2 20 66 ef 39 ac cb 1f 92 22 ..y.... f.9...." 00000720: 7d 14 66 15 d1 1e 69 25 6e c7 70 95 64 6c f0 7a }.f...i%n.p.dl.z 00000730: 86 a7 a6 a3 09 78 f3 93 43 9c ed aa a5 20 23 9f .....x..C.... #. 00000740: c2 ac 91 dc 5a 3a 93 57 b6 be 52 d8 de de b6 f5 ....Z:.W..R..... 00000750: 9d b7 df fa eb ab 49 f2 86 6c 05 86 e5 8c dc f2 ......I..l...... 00000760: c8 53 ff f5 a3 8c 60 3a 26 67 29 ca 1b ce f8 50 .S....`:&g)....P 00000770: 29 39 e9 59 f4 58 61 9a 7b 9b 68 ee 6b a6 2f d9 )9.Y.Xa.{.h.k./. 00000780: 87 26 74 e2 76 94 fa 9e 3a 7c ba 81 d7 f0 32 6a .&t.v...:|....2j 00000790: 78 11 ab 66 ac 62 58 86 8f da 33 17 98 33 e7 5b x..f.bX...3..3.[ 000007a0: ff d8 de de f6 b3 21 c9 85 ae 02 b3 a6 df b1 ec ......!......... 000007b0: d1 cc cc 1c 2e 5c 7e 9b 96 ee 5a 7a a2 61 2e f7 .....\~...Zz.a.. 000007c0: 36 71 29 7c 89 b6 48 2b bd 89 3e a2 56 8c d6 48 6q)|..H+..>.V..H 000007d0: 2b c7 1b 3f e2 68 fd 51 22 c9 08 09 c7 22 6a 46 +..?.h.Q"...."jF 000007e0: 31 84 87 14 c3 47 3c 0e 65 65 63 78 ec b1 75 1b 1....G<.eecx..u. 000007f0: 80 e2 21 49 25 be 0c 59 d9 05 cb c6 ..!I%..Y.... URB 47 : <<< 00000000: 00 00 0c 00 13 04 01 00 07 00 00 00 ............ URB 49 : <<< 00000000: 04 00 08 00 64 00 00 00 ....d... ^^ : error code (0x64 == good / 0x68 == bad) ^^^^ : packet size ^^^^^ : socket ID The returned code permits you to know if the device has accepted the last data packet. 0x64 : OK 0x68 : NOK ; You have got an error. (COD file is corrupted ?) Data header packet. URB 51 : >>> 00000000: 04 00 08 00 68 00 f8 07 ....h... ^^^^^ : data size for the next packet ^^ : always 0x00 ^^ : command ^^^^^ : packet size ^^^^^ : socket ID URB 50 : <<< 00000000: 00 00 0c 00 13 04 01 00 08 00 00 00 ............ Data packet. URB 53 : >>> 00000000: 04 00 fc 07 94 cd d4 5d 2b 89 df 3b 8c 88 19 a5 .......]+..;.... ^^ ..... : content of file ^^^^^ : packet size (0x07F8 = 0x07FC - 0x02) ^^^^^ : socket ID 00000010: 3b de c1 e5 de 66 ea c3 f5 34 f7 36 d3 16 6d a5 ;....f...4.6..m. 00000020: 2b da 49 6f a2 97 b8 95 40 4a 45 cc 8c d3 d2 d7 +.Io....@JE..... 00000030: 42 c4 8c 31 21 af 0c 4d 80 52 e0 3a b0 7c d9 c3 B..1!..M.R.:.|.. 00000040: fe ec ec 9c bf 19 92 64 ee 4b 90 31 ea ba bf 9a .......d.K.1.... 00000050: ef 4b 4d 47 3a 26 79 e9 45 34 b4 1e a7 3d da 8a .KMG:&y.E4...=.. 00000060: ad 27 49 31 bd 48 5c a2 56 94 70 a2 87 ce 58 17 .'I1.H\.V.p...X. 00000070: 31 2b 8a 54 12 5b 68 2c 28 bb 9b 1b 0a ca b9 a5 1+.T.[h,(....... 00000080: 78 3a 96 03 1e 1d 3a 23 71 6a dd 06 4a 67 95 3f x:....:#qj..Jg.? 00000090: da f9 bb 23 2f 03 bd 5f 27 81 e9 23 0a c7 17 29 ...#/.._'..#...) 000000a0: 25 91 ca 26 27 90 87 c7 48 a5 a9 af 81 a4 88 e3 %..&'...H....... 000000b0: f1 19 48 25 89 3b 71 22 c9 3e a2 fd ca f7 26 7a ..H%.;q".>....&z 000000c0: 79 e4 a6 1f f0 f8 ac 47 70 24 d8 0e e8 06 f4 24 y......Gp$.....$ 000000d0: 62 6c 3f f9 1b ba dc 30 05 53 c6 16 f3 bb 23 e5 bl?....0.S....#. 000000e0: c0 7b 5f 1b 01 8f 2f 75 74 66 30 24 70 5d 04 82 .{_.../utf0$p].. 000000f0: 14 c3 c7 f5 23 a6 70 e0 dc 76 2c 61 62 78 0d 14 ....#.p..v,abx.. 00000100: 92 a4 93 a4 cf ec 43 2a 17 cb b6 b8 bd 74 0e 2b ......C*.....t.+ 00000110: a6 3d 48 dc 02 a9 40 d3 40 57 10 4e f4 d1 d0 d3 .=H...@.@W.N.... 00000120: 8c 3f d5 8f 3f 3b 03 c3 eb 29 71 2c 7b 88 08 dc .?..?;...)q,{... 00000130: bf 69 29 70 17 30 09 88 02 27 a8 dc 13 17 9a 86 .i)p.0...'...... 00000140: 42 02 0a cb 4d 32 a3 68 36 f5 b1 53 54 77 1c 27 B...M2.h6..STw.' 00000150: 20 03 28 a1 d0 35 9d b9 a5 f3 48 f3 05 08 78 02 .(..5....H...x. 00000160: 2c 2a 5f 8c 47 33 70 5c 10 fd 96 e8 2a 08 78 fc ,*_.G3p\....*.x. 00000170: 08 a1 13 31 63 48 8f 86 66 e8 59 58 f6 35 da c0 ...1cH..f.YX.5.. 00000180: fd 9b 16 03 6b 16 df 3c 76 f6 dc f2 42 26 15 05 ....k......'~7.. 00000760: e5 65 67 67 67 e8 ba ae 0d e6 23 b8 ae 2b 3b 3b .eggg.....#..+;; 00000770: 3b 7b 5b 5b 5b db 6a 6a 6a fe db b2 ac 43 40 fc ;{[[[.jjj....C@. 00000780: 6a 9f ff b3 b9 94 52 5f 3a 00 bc 5e ef b2 b5 6b j.....R_:..^...k 00000790: d7 d6 54 57 57 ab a1 42 75 75 b5 5a bd 7a f5 29 ..TWW..Buu.Z.z.) 000007a0: c3 30 16 0d 86 c0 e7 87 b8 9a af e7 f3 f9 16 6c .0.............l 000007b0: df be fd c0 d2 a5 4b 01 78 f6 d9 67 59 b2 64 09 ......K.x..gY.d. 000007c0: a7 4e 9d 42 08 41 4d 4d 0d 00 b9 b9 b9 dc 73 cf .N.B.AMM......s. 000007d0: 3d bc f0 c2 0b ac 5e bd 9a 51 a3 46 b1 7b f7 6e =.....^..Q.F.{.n 000007e0: 5c d7 e5 81 07 1e 00 e0 d5 57 5f e5 dc b9 73 a4 \........W_...s. 000007f0: a6 a6 f2 e4 93 4f 92 92 92 c2 f6 ed .....O...... URB 52 : <<< 00000000: 00 00 0c 00 13 04 01 00 09 00 00 00 ............ URB 54 : <<< 00000000: 04 00 08 00 64 00 00 00 ....d... Data header packet. URB 56 : >>> 00000000: 04 00 08 00 68 00 f8 07 ....h... ^^^^^ : data size for the next packet ^^ : always 0x00 ^^ : command ^^^^^ : packet size ^^^^^ : socket ID URB 55 : <<< 00000000: 00 00 0c 00 13 04 01 00 0a 00 00 00 ............ Data packet. URB 58 : >>> 00000000: 04 00 fc 07 db 9d 95 2b 57 ce 77 5d f7 c8 60 57 .......+W.w]..`W ^^ ..... : content of file ^^^^^ : packet size (0x07F8 = 0x07FC - 0x02) ^^^^^ : socket ID 00000010: 40 bb 1a d6 f3 e7 cf 7f e2 33 e5 01 ce 9c 39 c3 @........3....9. 00000020: b6 6d db d8 bd 7b 37 ed ed ed d4 d6 d6 22 a5 24 .m...{7......".$ 00000030: 14 0a 91 96 96 46 75 75 35 b1 58 0c 80 86 86 06 .....Fuu5.X..... 00000040: 1a 1a 1a 00 b8 78 f1 22 7b f7 ee 65 c3 86 0d 04 .....x."{..e.... 00000050: 02 01 b6 6c d9 02 c0 c3 0f 3f 6c dc 79 e7 9d 7f ...l.....?l.y... 00000060: ff b5 d9 40 71 71 71 c1 17 58 6b 1a e3 c6 8d c3 ...@qqq..Xk..... 00000070: b6 6d 94 52 e8 ba ce e4 c9 93 99 3a 75 2a 1e 8f .m.R.......:u*.. 00000080: 07 5d d7 f1 fb fd 03 b2 1e 8f 07 00 29 25 52 4a .]..........)%RJ 00000090: 0c c3 20 10 08 d0 d6 d6 36 f0 ce d1 a3 47 17 01 .. .....6....G.. 000000a0: 02 18 94 57 b9 aa 15 a8 a8 a8 38 dc d7 d7 37 70 ...W......8...7p 000000b0: 9e 9b 9b 4b 79 79 39 13 27 4e 24 2d 2d 8d 9c 9c ...Kyy9.'N$--... 000000c0: 1c aa aa aa 38 78 f0 20 cd cd cd 04 83 41 76 ec ....8x. .....Av. 000000d0: d8 c1 be 7d fb 08 06 83 54 56 56 b2 79 f3 66 02 ...}....TVV.y.f. 000000e0: 81 00 77 dc 71 07 eb d7 af a7 b6 b6 96 15 2b 56 ..w.q.........+V 000000f0: 00 10 0e 87 39 7c f8 f0 a1 c1 2a 3f 18 23 ce 5f ....9|....*?.#._ 00000100: b0 60 41 55 63 63 e3 ff 69 90 1d 1d 1d aa b5 b5 .`AUcc..i....... 00000110: 55 99 a6 a9 a4 94 2a 12 89 a8 78 3c ae 94 52 2a U.....*...x<..R* 00000120: 99 4c aa 9e 9e 9e 01 d9 68 34 3a 70 5c 57 57 a7 .L......h4:p\WW. 00000130: e6 cd 9b 77 14 c8 f9 da 8c b8 df 8d 66 14 14 14 ...w........f... 00000140: ac 5b bc 78 f1 b2 b9 73 e7 96 86 42 21 7c 3e 1f .[.x...s...B!|>. 00000150: 8e e3 90 97 97 47 76 76 f6 80 7c 32 99 a4 be be .....Gvv..|2.... 00000160: 7e 60 42 4d d3 3e 73 a1 08 21 b0 6d 9b a6 a6 26 ~`BM.>s..!.m...& 00000170: bb a2 a2 e2 e2 eb af bf be ab a5 a5 e5 e7 40 f7 ..............@. 00000180: 57 71 a3 83 21 f0 19 02 c0 44 21 44 c8 e7 f3 a5 Wq..!....D!D.... 00000190: 39 8e 63 af 5a b5 ea a7 5b b6 6c 29 06 d8 b5 6b 9.c.Z...[.l)...k 000001a0: 57 df 73 cf 3d b7 eb fc f9 f3 ef 02 b6 74 a5 e3 W.s.=........t.. 000001b0: ba 6e 86 80 91 42 88 a0 10 9a df 91 4e 3b 50 05 .n...B......N;P. 000001c0: 1c 02 9c c1 fe 31 d7 4a e0 cf 30 61 c2 84 97 4e .....1.J..0a...N 000001d0: 9f 3e bd e6 d4 a9 53 4c 9a 34 69 39 b0 b3 ff 56 .>....SL.4i9...V 000001e0: 61 6a 66 60 61 e1 f8 d1 0b f3 c7 8d 2a 0c 04 03 ajf`a.......*... 000001f0: 59 7a 8a ee b3 93 66 32 d9 95 08 db 75 89 8b 27 Yz....f2....u..' 00000200: ab 2a 7f 1b 8d 46 f6 03 6d df 18 01 60 cc c6 8d .*...F..m...`... 00000210: 1b 4f 2e 5f be 3c ad a4 a4 64 6d 34 1a dd 93 95 .O._.<...dm4.... 00000220: 17 7c e6 96 fb ee 7c a8 fc d6 69 69 c3 f2 82 a0 .|....|...ii.... 00000230: 49 4c 27 41 c2 49 10 b3 a3 cc 1b ff 5d a6 87 6e IL'A.I......]..n 00000240: a4 b6 f6 0c af ed f9 75 cb 8e 6d 5b 5f ec e9 09 .......u..m[_... 00000250: 6f 04 ac 6f 82 00 42 88 65 9b 37 6f da a4 83 ef o..o..B.e.7o.... 00000260: a7 9b 5e 6a 59 fc 4f 3f 2c 9d 34 b9 0c af d0 71 ..^jY.O?,.4....q 00000270: 1c 9b b8 15 23 66 47 e8 88 b5 33 26 78 1d f7 4e ....#fG...3&x..N 00000280: 5c 88 d0 c0 9f 0a 29 1e 38 76 fc 63 9e 78 e2 ef \.....).8v.c.x.. 00000290: de 78 ff 8f ef ae 02 9a fe df 09 f4 e3 be 15 2b .x.............+ 000002a0: d7 ee cf 4c 4f 21 e9 17 dc fe ed f9 14 8c 08 11 ...LO!.......... 000002b0: b7 62 84 13 5d 74 c4 da 89 db 09 ee 9d b8 84 e1 .b..]t.......... 000002c0: fe 74 84 00 a9 1c fc 5e 83 40 00 c2 3d 71 d6 ac .t.....^.@..=q.. 000002d0: 79 b4 f1 b5 3d 3b e7 00 e7 af 86 80 c1 d0 21 af y...=;........!. 000002e0: ec a6 79 ff 12 9a f2 20 66 ef 39 ac cb 1f 92 22 ..y.... f.9...." 000002f0: 7d 14 66 15 d1 1e 69 25 6e c7 70 95 64 6c f0 7a }.f...i%n.p.dl.z 00000300: 86 a7 a6 a3 09 78 f3 93 43 9c ed aa a5 20 23 9f .....x..C.... #. 00000310: c2 ac 91 dc 5a 3a 93 57 b6 be 52 d8 de de b6 f5 ....Z:.W..R..... 00000320: 9d b7 df fa eb ab 49 f2 86 6c 05 86 e5 8c dc f2 ......I..l...... 00000330: c8 53 ff f5 a3 8c 60 3a 26 67 29 ca 1b ce f8 50 .S....`:&g)....P 00000340: 29 39 e9 59 f4 58 61 9a 7b 9b 68 ee 6b a6 2f d9 )9.Y.Xa.{.h.k./. 00000350: 87 26 74 e2 76 94 fa 9e 3a 7c ba 81 d7 f0 32 6a .&t.v...:|....2j 00000360: 78 11 ab 66 ac 62 58 86 8f da 33 17 98 33 e7 5b x..f.bX...3..3.[ 00000370: ff d8 de de f6 b3 21 c9 85 ae 02 b3 a6 df b1 ec ......!......... 00000380: d1 cc cc 1c 2e 5c 7e 9b 96 ee 5a 7a a2 61 2e f7 .....\~...Zz.a.. 00000390: 36 71 29 7c 89 b6 48 2b bd 89 3e a2 56 8c d6 48 6q)|..H+..>.V..H 000003a0: 2b c7 1b 3f e2 68 fd 51 22 c9 08 09 c7 22 6a 46 +..?.h.Q"...."jF 000003b0: 31 84 87 14 c3 47 3c 0e 65 65 63 78 ec b1 75 1b 1....G<.eecx..u. 000003c0: 80 e2 21 49 25 be 0c 59 d9 05 cb c6 94 cd d4 5d ..!I%..Y.......] 000003d0: 2b 89 df 3b 8c 88 19 a5 3b de c1 e5 de 66 ea c3 +..;....;....f.. 000003e0: f5 34 f7 36 d3 16 6d a5 2b da 49 6f a2 97 b8 95 .4.6..m.+.Io.... 000003f0: 40 4a 45 cc 8c d3 d2 d7 42 c4 8c 31 21 af 0c 4d @JE.....B..1!..M 00000400: 80 52 e0 3a b0 7c d9 c3 fe ec ec 9c bf 19 92 64 .R.:.|.........d 00000410: ee 4b 90 31 ea ba bf 9a ef 4b 4d 47 3a 26 79 e9 .K.1.....KMG:&y. 00000420: 45 34 b4 1e a7 3d da 8a ad 27 49 31 bd 48 5c a2 E4...=...'I1.H\. 00000430: 56 94 70 a2 87 ce 58 17 31 2b 8a 54 12 5b 68 2c V.p...X.1+.T.[h, 00000440: 28 bb 9b 1b 0a ca b9 a5 78 3a 96 03 1e 1d 3a 23 (.......x:....:# 00000450: 71 6a dd 06 4a 67 95 3f da f9 bb 23 2f 03 bd 5f qj..Jg.?...#/.._ 00000460: 27 81 e9 23 0a c7 17 29 25 91 ca 26 27 90 87 c7 '..#...)%..&'... 00000470: 48 a5 a9 af 81 a4 88 e3 f1 19 48 25 89 3b 71 22 H.........H%.;q" 00000480: c9 3e a2 fd ca f7 26 7a 79 e4 a6 1f f0 f8 ac 47 .>....&zy......G 00000490: 70 24 d8 0e e8 06 f4 24 62 6c 3f f9 1b ba dc 30 p$.....$bl?....0 000004a0: 05 53 c6 16 f3 bb 23 e5 c0 7b 5f 1b 01 8f 2f 75 .S....#..{_.../u 000004b0: 74 66 30 24 70 5d 04 82 14 c3 c7 f5 23 a6 70 e0 tf0$p]......#.p. 000004c0: dc 76 2c 61 62 78 0d 14 92 a4 93 a4 cf ec 43 2a .v,abx........C* 000004d0: 17 cb b6 b8 bd 74 0e 2b a6 3d 48 dc 02 a9 40 d3 .....t.+.=H...@. 000004e0: 40 57 10 4e f4 d1 d0 d3 8c 3f d5 8f 3f 3b 03 c3 @W.N.....?..?;.. 000004f0: eb 29 71 2c 7b 88 08 dc bf 69 29 70 17 30 09 88 .)q,{....i)p.0.. 00000500: 02 27 a8 dc 13 17 9a 86 42 02 0a cb 4d 32 a3 68 .'......B...M2.h 00000510: 36 f5 b1 53 54 77 1c 27 20 03 28 a1 d0 35 9d b9 6..STw.' .(..5.. 00000520: a5 f3 48 f3 05 08 78 02 2c 2a 5f 8c 47 33 70 5c ..H...x.,*_.G3p\ 00000530: 10 fd 96 e8 2a 08 78 fc 08 a1 13 31 63 48 8f 86 ....*.x....1cH.. 00000540: 66 e8 59 58 f6 35 da c0 fd 9b 16 03 6b 16 df 3c f.YX.5......k..< 00000550: 76 f6 dc f2 42 26 15 05 89 99 0e 55 75 9d b3 b6 v...B&.....Uu... 00000560: 15 05 a9 ec e8 e2 b6 3c 9b 34 9f 8e eb d8 08 a5 .......<.4...... 00000570: f3 fd 1b 1e e1 c2 ef cf e2 48 93 a4 6b f2 83 e9 .........H..k... 00000580: 3f 64 cd cd 0f e2 c8 2b af b4 5c ae 28 df 5f c2 ?d.....+..\.(._. 00000590: 28 ae 18 b0 10 06 4a 2a a2 6e 02 33 11 43 4a 99 (.....J*.n.3.CJ. 000005a0: bc 26 23 16 8b 36 af 19 39 3c f0 d2 2b ab 66 73 .&#..6..9<..+.fs 000005b0: eb f5 f9 08 21 10 42 a0 69 1a df 1a 17 e2 47 f3 ....!.B.i.....G. 000005c0: 26 f1 fc 81 4a 9e d9 7b 8c d5 53 8a c9 72 5c 62 &...J..{..S..r\b 000005d0: 66 9c c2 ac 6c 0a 33 8b 38 d5 51 85 ae 1b d8 ae f...l.3.8.Q..... 000005e0: 8d 54 90 b0 af 94 5d 88 fe f1 39 98 2e 48 95 8a .T....]...9..H.. 000005f0: 47 4b 25 9a 68 27 da d9 8d 6b 39 2d 5f 99 80 58 GK%.h'...k9-_..X 00000600: b4 39 2d c5 a3 bf f4 fa e3 df c6 55 92 07 5e 3c .9-........U..^< 00000610: 84 10 82 19 a5 21 fe 76 fe 54 34 4d 43 13 82 a7 .....!.v.T4MC... 00000620: ee bd 11 5d d3 d8 ff 4e 2d f9 c3 d2 89 27 93 98 ...]...N-....'.. 00000630: a6 cb c2 09 4b b8 f4 fe 05 fa ec 1e de fc e4 10 ....K........... 00000640: f7 94 dd 4b f1 f0 20 49 07 2c 47 7d 16 25 11 80 ...K.. I.,G}.%.. 00000650: 2d 21 62 2a 6c 57 c3 d0 fc f4 58 bd 84 2f 5d 46 -!b*lW....X../]F 00000660: 49 79 fe 5a e2 c0 9a 95 b7 8f 63 7c 7e 26 87 aa Iy.Z......c|~&.. 00000670: ea f8 ed f1 f3 ec 3f f6 29 bf 3c f2 31 4a 29 a4 ......?.).<.1J). 00000680: 94 03 95 d1 8f bf 53 4e b7 94 b4 f7 c5 88 c7 4d ......SN.......M 00000690: 3a 7b 7b 29 ce 28 63 fd 9c ff a0 64 d8 58 ea 3a :{{).(c....d.X.: 000006a0: eb 78 f6 ad 67 f8 d5 b1 3d 9c 69 3d 07 08 a4 94 .x..g...=.i=.... 000006b0: b8 ae 4b dc 96 84 13 6e ff 80 a0 bf 14 69 7b 68 ..K....n.....i{h 000006c0: ad be 70 11 a8 bf 96 5f 68 e9 f7 a6 8d 46 29 45 ..p...._h....F)E 000006d0: a6 df cb dc c9 45 a4 78 3c 3c 36 af 9c 7d 1f 9d .....E.x<<6..}.. 000006e0: 63 e3 ff 9c 00 60 d1 cd e3 f8 87 bb 6f 62 e1 f4 c....`......ob.. 000006f0: 31 9c a8 6e 24 2f c3 8f cf 67 d0 62 74 32 32 bb 1..n$/...g.bt22. 00000700: 98 a7 67 3f c7 f3 bf df c0 db 9f 1c e1 ad da 0a ..g?............ 00000710: f2 33 0b d8 b6 78 27 05 99 f9 84 13 16 7d a6 4b .3...x'......}.K 00000720: c4 94 c4 4c 45 d4 81 92 e0 6d 8c fb 53 13 47 4f ...LE....m..S.GO 00000730: 6f fd 49 bf b3 f8 ca 04 26 8c cd 4b 47 29 45 71 o.I.....&..KG)Eq 00000740: 4e 06 8b a6 97 12 4c 4f 65 c6 d8 11 7c ff c5 37 N.....LOe...|..7 00000750: 38 79 a9 fd 4a d7 22 37 13 a5 14 d7 85 32 a9 f8 8y..J."7.....2.. 00000760: f0 02 b1 a4 89 de a7 21 10 b8 52 32 22 6b 18 2b .......!..R2"k.+ 00000770: a7 ae e3 97 d6 7f 82 50 64 a7 e7 10 8b 3b fc a1 .......Pd....;.. 00000780: e9 63 bc be 0c 30 d2 89 5b 06 31 5b 10 73 20 92 .c...0..[.1[.s . 00000790: e8 e4 dd 5d 2f 1f c2 55 bb af 35 12 5b 96 e3 7a ...]/..U..5.[..z 000007a0: bd 86 c6 43 bf 78 8b a4 7d a5 fa 7b f3 a9 fb 58 ...C.x..}..{...X 000007b0: 30 b5 84 92 dc 4c b2 02 29 3c 34 bb 0c 29 25 a6 0....L..)<4..)%. 000007c0: ed 62 68 3a 09 d3 42 00 52 29 2c db 26 91 34 c9 .bh:..B.R),.&.4. 000007d0: f4 a7 b1 66 da 4f d0 35 9d d4 94 74 0e 7f f4 0e ...f.O.5...t.... 000007e0: 3b 2a b6 91 3b 6c 04 c1 8c 11 a4 a4 66 91 91 59 ;*..;l......f..Y 000007f0: 40 30 6f 32 27 0e ed ec bc 74 e6 fd @0o2'....t.. URB 57 : <<< 00000000: 00 00 0c 00 13 04 01 00 0b 00 00 00 ............ URB 59 : <<< 00000000: 04 00 08 00 64 00 00 00 ....d... Data header packet. URB 61 : >>> 00000000: 04 00 08 00 68 00 e8 06 ....h... ^^^^^ : data size for the next packet ^^ : always 0x00 ^^ : command ^^^^^ : packet size ^^^^^ : socket ID URB 60 : <<< 00000000: 00 00 0c 00 13 04 01 00 0c 00 00 00 ............ Data packet. URB 63 : >>> 00000000: 04 00 ec 06 1f 0f 45 5f e8 64 4d 63 78 d6 8c b1 ......E_.dMcx... ^^ ..... : content of file ^^^^^ : packet size (0x06E8 = 0x06EC - 0x02) ^^^^^ : socket ID 00000010: 39 48 a5 f0 1a 3a 37 8c ca 26 94 99 4a e5 c5 36 9H...:7..&..J..6 00000020: 32 fd 5e 82 69 29 64 a4 7a 50 4a 71 aa a1 0b b7 2.^.i)d.zPJq.... 00000030: bb 1e ad 78 04 89 a4 89 e3 4a 4c cb 26 1a 37 e9 ...x.....JL.&.7. 00000040: f4 c4 31 0c 2f 68 1e 5c d5 c3 81 f7 0e e2 24 2d ..1./h.\......$- 00000050: da da 9a 69 69 6d 44 68 a0 7b bd 58 ed 3f a7 ed ...iimDh.{.X.?.. 00000060: 83 3f 3d 0d 7c 3a 14 04 7e b5 eb 83 0b b3 a6 8f .?=.|:..~....... 00000070: c9 e6 0f eb 17 22 04 8c 0c a6 73 ba a9 9b a7 5f ....."....s...._ 00000080: fb 60 40 28 7f 58 80 db ca 8a d8 7f ec 22 3d 87 .`@(.X......."=. 00000090: b7 fe 7b 8e d9 be ee fa a9 73 d3 2c 09 d1 44 12 ..{......s.,..D. 000000a0: a1 5b 08 4d 43 d3 3c 18 1e 1f 35 67 df a1 a5 a5 .[.MC.<...5g.... 000000b0: 01 8f e1 01 0d 0c c3 8b d0 04 d1 8b 4d 4e 77 cd ............MNw. 000000c0: e9 75 4a ca 57 86 aa 33 f7 eb df 1c af df 7e ff .uJ.W..3......~. 000000d0: 4d a3 b9 65 5c de 40 0c 38 dd dc 8d cf a3 a3 09 M..e\.@.8....... 000000e0: c1 e4 a2 6c a6 8d c9 e3 9f 77 7f 48 67 24 f9 33 ...l.....w.Hg$.3 000000f0: ba 1a ff f5 ed fd 2f 56 d4 9d ad 7a 7e d2 cc ef ....../V...z~... 00000100: cd cc ca 2d 01 4d 07 01 ae 8c 73 a1 ee 30 9f 5e ...-.M....s..0.^ 00000110: fa 23 86 c7 8b 94 57 42 81 15 ee 25 5a 57 57 19 .#....WB...%ZWW. 00000120: 6f 69 5d 0b 1c 1d 4c 72 f0 a5 05 8d 58 b4 f9 fe oi]...Lr....X... 00000130: 80 cf d8 bb e5 a1 19 dc 35 b9 e0 0b 81 4c 08 81 ........5....L.. 00000140: e9 48 36 ec ab 64 eb 1b 27 76 72 f0 e9 4d 40 56 .H6..d..'vr..M@V 00000150: bf 7b ce d5 3d be 05 a1 e2 29 b3 f2 4a a6 8d 48 .{..=....)..J..H 00000160: c9 c8 d6 9a db ab 08 f7 d5 63 e8 1e 94 94 b8 89 .........c...... 00000170: 04 56 77 57 57 b2 a3 e3 3d e5 ba 07 81 16 40 07 .VwWW...=.....@. 00000180: 62 40 a4 3f 0b ed ed 3f 37 af 98 d5 17 15 be ba b@.?...?7....... 00000190: 8a 6c d1 e6 bb 80 35 37 8f cd b9 7b 66 69 2e e5 .l....57...{fi.. 000001a0: 45 c3 e9 49 58 54 d5 77 f3 66 75 33 2d ed 9d 2f E..IXT.w.fu3-../ 000001b0: f3 c6 bf 6d c5 4e e4 f7 77 d8 32 00 0f e0 02 69 ...m.N..w.2....i 000001c0: fd d7 72 81 0c a1 eb 06 a0 50 2a a1 a4 ec ec 6f ..r......P*....o 000001d0: a7 44 01 5f bf f2 36 90 ec 27 d0 06 34 02 cd 40 .D._..6..'..4..@ 000001e0: 0f 60 2a a5 e4 a0 09 7c 8e c8 6c 60 36 70 63 7f .`*....|..l`6pc. 000001f0: 27 ed 18 70 40 ed 7d bc f9 9b da a1 11 7f e9 5b '..p@.}........[ 00000200: 4c ff 3b 00 0a 79 0a c5 3c 71 69 d1 00 00 00 00 L.;..y..>> 00000000: 04 00 08 00 8d 00 00 00 ........ ^^ : command ^^^^^ : packet size ^^^^^ : socket ID URB 65 : <<< 00000000: 00 00 0c 00 13 04 01 00 0e 00 00 00 ............ URB 67 : <<< 00000000: 04 00 08 00 64 00 00 00 ....d... URB 69 : >>> 00000000: 00 00 08 00 0b 04 00 0b ........ URB 68 : <<< 00000000: 00 00 08 00 0c 04 00 0b ........ barry-0.18.5/doc/bb_task_format.txt0000644001161500056700000000671112242254476016544 0ustar cdfreycdfrey BlackBerry Task Database Record format. This information is result of many btool -d Tasks dumps from a single BB 8700R. firmware v4.1.0.351 (platform 2.0.0.143) It would be interesting to receive btool -d Tasks dumps from other blackberries to see if strings which appear constant, really are. Task Header, fixed length, 0xe bytes long. 00000000: 09 00 43 00 40 03 44 02 01 00 53 32 2f 0a 01 01 ..C.@.D...S2/... _____ _____ ??????????? _____ ??????????? __ __ rec rec task type len index# u1 UniqueID? u2 00000010: 00 01 74 ???????? rec type - always 09 00 I guess this is a 'Task' Record type? rec len - length of this record in bytes, including header. u1 - always 40 03 44 02 unknown... task index - the record number within the data base. determines posting order in the device (That is, if you change sort order, the indices of tasks will be modified. Similarly, if you change the priority or due date of a task the ordinal might change as well. UniqueID - 32byte Integer, unique for each task. u2 - boolean 00 or 01 , unknown. end of header 01 00 01 74 - see type 1 field description. Fields: rest of a record is a series of fields, each with a 3 byte header: Field Header 04 00 sz - size in bytes (2 bytes), excluding header. 09 field type (1 byte) sz bytes, in the value format. field types: type value Meaning of field value format. ------ ---------- ---------------------- 11 string Categories, comma separated. 10 4tz timezone for deadlines, reminders etc... 0f min1900_t reminder by date (the minute when to remind.) 0e 4byte relative reminder flag 2 = true?, this field is absent if reminder is not relative. 0a 4byte priority (0-high,1-normal,2-low) 09 4byte status (0-not started, 1-in progress, 2-completed, 3-Waiting, 4-Defered) 08 4boolean 0-no due date, 1 there is a due date. 06 min1900_t ??? 05 min1900_t due date 03 string Note: (value of notes.) 02 string Title (the name of the task.) 01 byte always 0x74, unknown... (01 00 01 74) is always the first field of a task record. from http://off.net/cassis/protocol-description.html#h-1.3 it looks used in other DB's in the same way. no idea of it's purpose. formats: string -- null terminated string. 4tz: -- 32-bit LSB integer, values documented in doc/TimeZones.txt. ie. 0x23 is eastern time. min1900_t: -- signed 32-bit LSB integer offset in minutes. (before origin is -ve.) -- origin is 0000 hours january 1st, 1900 in the prime meridian time zone GMT/UTC -- Code to manipulate this type is present in the source code. Recurrence: -- Recurrence information does not appear to be stored in the Tasks DB. -- Recurrence is systematically mis-spelled in the protocol description document Order of fields... as observed in dump, do not know if it is significant, given fields are so self-descriptive.
<2-title> <9-status> <10-timezone> <6-??> <8-due_flag> [ <5-due_date> ] [ [ ] ] [ <11-categories> ] <3-Note> barry-0.18.5/doc/screenshot0000644001161500056700000007314612242254476015134 0ustar cdfreycdfreyScreenShot reverse ================== After Probe process, we have the JavaLoader command Legend : >>> : Sent <<< : Received Open Socket with BlackBerry device, then select the JavaLoader mode. URB : >>> 00000000: 00 00 0c 00 05 ff 00 05 04 00 07 00 ............ URB : <<< 00000000: 00 00 10 00 06 ff 00 05 04 00 07 00 00 02 00 00 ................ URB : >>> 00000000: 00 00 0c 00 05 ff 00 06 04 00 08 00 ............ URB : <<< 00000000: 00 00 10 00 06 ff 00 06 04 00 08 00 00 01 00 00 ................ URB : >>> 00000000: 00 00 0c 00 05 ff 00 07 04 00 0a 00 ............ URB : <<< 00000000: 00 00 10 00 06 ff 00 07 04 00 0a 00 20 f9 04 80 ............ ... URB : >>> 00000000: 00 00 0c 00 05 ff 00 08 04 00 0b 00 ............ URB : <<< 00000000: 00 00 10 00 06 ff 00 08 04 00 0b 00 00 00 00 00 ................ URB : >>> 00000000: 00 00 18 00 07 ff 00 09 52 49 4d 5f 4a 61 76 61 ........RIM_Java 00000010: 4c 6f 61 64 65 72 00 00 Loader.. URB : <<< 00000000: 00 00 30 00 08 04 00 09 52 49 4d 5f 4a 61 76 61 ..0.....RIM_Java 00000010: 4c 6f 61 64 65 72 00 00 00 00 00 00 01 00 08 00 Loader.......... 00000020: 02 00 08 00 03 01 00 00 04 01 00 00 05 10 01 00 ................ URB : >>> 00000000: 00 00 0c 00 0a 04 00 0a 10 03 00 00 ............ URB : <<< 00000000: 00 00 08 00 10 04 00 0a ........ URB : <<< 00000000: 00 00 0c 00 13 04 01 00 00 00 00 00 ............ URB : <<< 00000000: 04 00 05 00 01 ..... Specific command for JavaLoder. (this follow part is already described in doc/javaloader file) Open a new stream. URB : >>> 00000000: 04 00 08 00 64 00 00 00 ....d... ^^ : command ^^^^^ : packet size ^^^^^ : socket ID URB : <<< 00000000: 00 00 0c 00 13 04 01 00 01 00 00 00 ............ URB : <<< 00000000: 04 00 08 00 65 00 00 00 ....e... URB : >>> 00000000: 04 00 08 00 70 00 01 00 ....p... URB : <<< 00000000: 00 00 0c 00 13 04 01 00 02 00 00 00 ............ URB : >>> 00000000: 04 00 05 00 00 ..... URB : <<< 00000000: 00 00 0c 00 13 04 01 00 03 00 00 00 ............ URB : <<< 00000000: 04 00 08 00 64 00 00 00 ....d... ReceiveStream command. 0x87 is used to receive a screenshot from the handled. URB : >>> 00000000: 04 00 08 00 87 00 04 00 ........ ^^^^^^^^ : unknown ^^ : command to receive a stream ^^^^^ : packet size ^^^^^ : socket ID URB : <<< 00000000: 00 00 0c 00 13 04 01 00 04 00 00 00 ............ URB : >>> 00000000: 04 00 08 00 00 00 00 00 ........ URB : <<< 00000000: 00 00 0c 00 13 04 01 00 05 00 00 00 ............ URB : <<< 00000000: 04 00 08 00 64 00 10 00 ....d... ^^^^^ : size of next packet (0x0014 = 0x0010 + 4) The handled gives me the size of next packet (0x0010) FIXME : Important packet ! This packet contains info about the format screenshot. URB : <<< 00000000: 04 00 14 00 00 05 46 00 40 03 01 68 01 e0 00 10 ......F.@..h.... ^^^^^ ^^^^^ ^^^^^ : unknown ^^^^^x^^^^^ : width x height ^^^^^ : packet size ^^^^^ : socket ID 00000010: 00 00 00 00 .... Reception loop. Now I'm ready to receipt the raw data. URB : >>> 00000000: 04 00 08 00 68 00 00 00 ....h... URB : <<< 00000000: 00 00 0c 00 13 04 01 00 06 00 00 00 ............ URB : <<< 00000000: 04 00 08 00 6e 00 f8 07 ....n... ^^^^^ : size of next packet (0x7FC = 0x7F8 + 4) URB : <<< 00000000: 04 00 fc 07 00 00 00 00 00 00 00 00 00 00 00 00 ................ ^^^^^^........... raw data ^^^^^ : size ^^^^^ : socket ID 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000290: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000003a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000003b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000003c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000003d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000003e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000003f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000410: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000420: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000430: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000440: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000450: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000460: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000470: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000490: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000004a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000004b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000004c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000004d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000004e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000004f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000530: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000590: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000005a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000005b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000005c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000005d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000005e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000005f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000610: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000620: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000630: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000640: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000650: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000660: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000670: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000690: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000006a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000006b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000006c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000006d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000006e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000006f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000710: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000720: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000730: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000740: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000750: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000760: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000770: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000007a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000007b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000007c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000007d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000007e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000007f0: 00 00 00 00 00 00 00 00 00 00 00 00 ............ I have received the data, so I send an acknowledge. URB : >>> 00000000: 04 00 08 00 68 00 00 00 ....h... URB : <<< 00000000: 00 00 0c 00 13 04 01 00 07 00 00 00 ............ URB : <<< 00000000: 04 00 08 00 6e 00 f8 07 ....n... URB : <<< 00000000: 04 00 fc 07 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000290: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000003a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000003b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000003c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000003d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000003e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000003f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000410: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000420: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000430: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000440: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000450: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000460: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000470: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000490: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000004a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000004b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000004c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000004d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000004e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000004f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000530: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000590: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000005a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000005b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000005c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000005d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000005e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000005f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000610: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000620: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000630: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000640: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000650: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000660: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000670: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000690: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000006a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000006b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000006c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000006d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000006e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000006f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000710: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000720: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000730: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000740: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000750: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000760: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000770: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000007a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000007b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000007c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000007d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000007e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000007f0: 00 00 00 00 00 00 00 00 00 00 00 00 ............ URB : >>> 00000000: 04 00 08 00 68 00 00 00 ....h... [...] URB : <<< 00000000: 00 00 0c 00 13 04 01 00 af 00 00 00 ............ URB : <<< 00000000: 04 00 08 00 6e 00 48 03 ....n.H. URB : <<< 00000000: 04 00 4c 03 00 00 00 00 00 00 00 00 00 00 00 00 ..L............. 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000001f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000290: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000340: 00 00 00 00 00 00 00 00 00 00 00 00 ............ URB : >>> 00000000: 04 00 08 00 68 00 00 00 ....h... URB : <<< 00000000: 00 00 0c 00 13 04 01 00 b0 00 00 00 ............ URB : <<< 00000000: 04 00 08 00 64 00 00 00 ....d... URB : >>> 00000000: 04 00 08 00 8d 00 00 00 ........ URB : <<< 00000000: 00 00 0c 00 13 04 01 00 b1 00 00 00 ............ URB : <<< 00000000: 04 00 08 00 64 00 00 00 ....d... URB : >>> 00000000: 00 00 08 00 0b 04 00 0b ........ URB : <<< 00000000: 00 00 08 00 0c 04 00 0b ........ barry-0.18.5/doc/jdwp/0000755001161500056700000000000012242254476013765 5ustar cdfreycdfreybarry-0.18.5/doc/jdwp/usb-protocol.txt0000644001161500056700000057502512242254476017174 0ustar cdfreycdfreyJavaDebug reverse ================= With Java debug, you can communicate with the embedded JVM to debug a Java application After probe process, we have the JVM Debug command Legend : >>> : Sent <<< : Received Protocol summary : ------------------ JavaDebug protocol is quiet simple, it's always the same commande : >>> 00000000: AA AA BB BB 00 NN XX XX XX XX XX ... AA AA : socket ID BB BB : size of packet NN : Size of data (number of following bytes) XX XX XX XX ... : bytes (the data) So : BB BB = 6 + NN <<< 00000000: 00 00 AA AA 13 05 01 00 YY YY YY YY 00 00 : AA AA : size of packet 13 : sequence packet 05 01 00 : unknown field YY YY YY YY : sequence id <<< 00000000: 05 00 AA AA NN NN 05 00 : AA AA : size of packet NN NN : size of following data <<< 00000000: 05 00 AA AA XX XX XX XX ... 05 00 : AA AA : sizeof packet XX XX XX XX ... : data So, AA AA = 4 + NN NN List of commands : ------------------ *) ???? 0x53 => 00 00 00 00 00 00 00 02 00 00 00 00 *) ???? 0x01 => 00 00 00 01 00 00 00 26 00 00 00 02 *) ???? 0x6f => 00 00 *) ???? 0x8a => 06 00 14 04 *) ???? 0x90 => 00 00 *) Get list of java modules Command : 0x8d Param : [aa bb cc dd] = ID of first module Return : ID ; Address ; Module name 1 ; 0x4a174ab4 ; net_rim_app_manager 2 ; .... *) ???? Command : 0x44 Param : 00 00 00 00 Return : none *) ???? Command : 0x45 Param : 00 00 00 00 Return : none *) ???? Command : 0x54 Param : 00 00 00 00 Return : none *) ???? Command : 0x33 Param : 00 00 00 09 Return : none *) ???? Command : 0x46 Param : 00 00 00 01 Return : none *) ???? Get status ? Command : 0x06 Param : none Wait answer... Return : - 8d none, the next command to sent is 0x40 - 85 ????, the next command to sent is 0x64 - 86 ????, the next command to sent is 0x64 This command is called after an empty message (see GetConsoleMessage) We can be suspended on this command. *) GetConsoleMessage - info / comment Command : 0x40 Param : none Return : 00 00 00 09 56 4d 3a 2d 44 41 20 30 0a VM:-DA 0 00 10 61 74 74 61 63 68 3a 20 73 75 63 63 65 73 73 0a attach: success <--- : string ^^ : length of string ^^ : type = string When the JVM is running, we poll the device to get the console message (output of System.out.println). If you receive an empty message : 00 02 00 00 We have to call the GET_STATUS command. (see above) *) Go Step Into Command : 0x03 Param : none Wait answer... Return : - 8d none, the next command to sent is 0x40 - 86 ????, the next command to sent is 0x64 *) Go Command : 0x02 Param : none Wait answer... Return : - 8d none, the next command to sent is 0x40 *) ???? Command : 0x04 Param : none Wait answer... Return : - 8d none, the next command to sent is 0x40 - 86 ????, *) ???? Use to set/remove breakpoint Command : 0x1a Param : [aa bb cc dd] = address of breakpoint desired position Return : 07 00 00 00 31 <= ID of Java module 00 00 00 00 *) Set breakpoint Command : 0x21 Param : 00 00 00 31 <= ID of Java module 00 00 01 8c <= Breakpoint position Return : none *) Remove breakpoint Command : 0x22 Param : 00 00 00 31 <= ID of Java module 00 00 01 8c <= Breakpoint position Return : none *) ???? Command : 0x50 Param : 75 c5 00 00 Return : 00 00 00 00 *) ???? Command : 0x57 Param : 75 c5 00 00 Return : 00 00 00 00 *) ???? Command : 0x58 Param : 75 c5 00 00 Return : 00 00 00 00 *) ???? Command : 0x5e Param : 75 bf e0 00 Return : 0xcc *) ???? Seems to be a get status stack pointer, list of varaibles... Command : 0x64 Param : none Return : 0x64 => 77 63 40 00 00 00 00 01 00 00 00 31 00 00 00 0f 00 00 00 01 b8 00 00 00 00 02 74 bc e0 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 0x64 => 77 63 40 00 00 00 00 01 00 00 00 31 00 00 00 11 00 00 00 01 cf 00 00 00 00 02 74 bc e0 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 0x64 => 77 63 40 00 00 00 00 02 00 00 00 31 00 00 00 26 00 00 00 01 dd 00 00 00 00 31 00 00 00 15 00 00 00 01 01 00 00 00 00 01 77 5b 80 00-00 00 00 00 ^^ ^^^^^^^^^^^ 00 00 00 00 0a 0x64 => 77 63 40 00 00 00 00 03 00 00 00 31 00 00 01 6c ^^^^^^^^^^^ Id of Java module 00 00 00 01 3f 00 00 00 00 31 00 00 00 34 00 00 ^^^^^^^^^^^ ^^^^^^^^^^^ context pointer Id of Java module 00 01 01 00 00 00 00 31 00 00 00 15 00 00 00 01 ^^^^^^^^^^^ Id of Java module 01 00 00 00 00 04 75 c5 00 00 75 bf e0 00 0e dd ^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^ nbr this address title address a0 00 06 8a 20 00-00 00 00 00 00 00 00 00 0a ^^^^^ ^^^^^^^^^^^ 0x64 => 77 63 40 00 00 00 00 03 00 00 00 31 00 00 01 a3 00 00 00 01 b9 00 00 00 00 31 00 00 00 34 00 00 00 01 01 00 00 00 00 31 00 00 00 15 00 00 00 01 01 00 00 00 00 04 75 c5 00 00 75 bf e0 00 00 00 00 00 74 61 80 00 00 00 00 00 00 00 00 00 0a ^^^^^^^^^^^ str address Then, use the command 0x03 *) ???? Command : 0x65 Param : 00 00 00 00 Return : 00 00 00 00 *) Get all threads currently running in the target VM Command : 0x08 Param : none Return : 00 00 00 6f : Number of threads e6 a1 e0 00 : ID of thread 1 db f9 20 00 : ID of thread 2 ... .: USB LOGS :. ============== BarryDemo properties : --------------------------- ID = 0x31 Address : 0x4a4383be Details : --------- Open Socket with BlackBerry device, then select JVM Debug mode. >>> URB 50 00000000: 00 00 0c 00 05 ff 00 0b 02 00 0c 00 ............ <<< URB 30 00000000: 00 00 0c 00 06 ff 00 0b 00 00 00 00 ............ >>> URB 52 00000000: 00 00 18 00 07 ff 00 0c 52 49 4d 5f 4a 56 4d 44 ........RIM_JVMD 00000010: 65 62 75 67 00 00 00 00 ebug.... <<< URB 32 00000000: 00 00 30 00 08 05 00 0c 52 49 4d 5f 4a 56 4d 44 ..0.....RIM_JVMD 00000010: 65 62 75 67 00 00 00 00 00 00 00 00 01 00 07 00 ebug............ 00000020: 02 00 07 00 03 01 00 00 04 01 00 00 05 10 01 00 ................ >>> URB 54 00000000: 00 00 0c 00 0a 05 00 0d 10 03 00 00 ............ >>> URB 134 00000000: 05 00 07 00 00 01 53 ......S ^^ ^^ : size (= 0x01) <<< URB 139 00000000: 00 00 0c 00 13 05 01 00 01 00 00 00 ............ <<< URB 141 00000000: 05 00 06 00 00 0c ...... ^^^^^ size of next data <<< URB 142 00000000: 05 00 10 00 00 00 00 00 00 00 00 02 00 00 00 00 ................ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = size = 0x000c >>> URB 138 00000000: 05 00 07 00 00 01 01 ....... ^^ ^^ : size (= 0x01) <<< URB 143 00000000: 00 00 0c 00 13 05 01 00 02 00 00 00 ............ <<< URB 145 00000000: 05 00 06 00 00 0c ...... ^^^^^ size of next data <<< URB 146 00000000: 05 00 10 00 00 00 00 01 00 00 00 26 00 00 00 02 ...........&.... ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ size = 0x000c >>> URB 142 00000000: 05 00 07 00 00 01 6f ......o ^^ ^^ : size (= 0x01) <<< URB 147 00000000: 00 00 0c 00 13 05 01 00 03 00 00 00 ............ ^^^^^^^^^^^ : sequence id ^^ ^^ ^^ : unknown field ^^ : Sequence packet <<< URB 149 00000000: 05 00 06 00 00 02 ...... ^^^^^ size of next data <<< URB 150 00000000: 05 00 06 00 00 00 ...... ^^^^^ size of data = 0x0002 >>> URB 146 00000000: 05 00 07 00 00 01 8a ....... ^^ ^^ : size (= 0x01) <<< URB 151 00000000: 00 00 0c 00 13 05 01 00 04 00 00 00 ............ <<< URB 153 00000000: 05 00 06 00 00 04 ...... ^^^^^ size of next data <<< URB 154 00000000: 05 00 08 00 06 00 14 04 ........ ^^^^^^^^^^^ size of data = 0x0004 >>> URB 150 00000000: 05 00 07 00 00 01 90 ....... ^^ ^^ : size (= 0x01) <<< URB 155 00000000: 00 00 0c 00 13 05 01 00 05 00 00 00 ............ <<< URB 157 00000000: 05 00 06 00 00 00 ...... ^^^^^ size of next data Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 153 00000000: 05 00 0b 00 00 05 8d 00 00 00 00 ........... ^^^^^^^^^^^ : ID of first data desired ^^ : command ^^ : size (= 0x05) <<< URB 158 00000000: 00 00 0c 00 13 05 01 00 06 00 00 00 ............ ^^^^^^^^^^^ : sequence id ^^ ^^ ^^ : unknown field ^^ : Sequence packet <<< URB 160 00000000: 05 00 06 00 03 eb ...... ^^^^^ size of next data <<< URB 161 00000000: 05 00 ef 03 00 00 00 2b 00 00 00 01 4a 17 4a b4 .......+....J.J. ^^^^^ ^^^^^ ^^^^^^^^^^^|^^^^^^^^^^^ ^^^^^^^^^^^ socket packet nbr data | ID address ? ID size readable 00000010: 00 13 6e 65 74 5f 72 69 6d 5f 61 70 70 5f 6d 61 ..net_rim_app_ma ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ size name of module 00000020: 6e 61 67 65 72 00 00 00 02 4a 17 49 96 00 0c 6e nager....J.I...n ^^^^^^^^^^^^^^|^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^ ^^ | ID address ? size 00000030: 65 74 5f 72 69 6d 5f 63 6c 64 63 00 00 00 03 4a et_rim_cldc....J ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|^^^^^^^^^^^ name of module | ID 00000040: 17 49 96 00 0e 6e 65 74 5f 72 69 6d 5f 63 6c 64 .I...net_rim_cld 00000050: 63 2d 32 00 00 00 04 4a 17 49 96 00 0e 6e 65 74 c-2....J.I...net 00000060: 5f 72 69 6d 5f 63 6c 64 63 2d 33 00 00 00 05 4a _rim_cldc-3....J 00000070: 17 49 96 00 0f 6e 65 74 5f 72 69 6d 5f 63 6c 64 .I...net_rim_cld 00000080: 63 2d 31 33 00 00 00 06 4a 17 49 96 00 0f 6e 65 c-13....J.I...ne 00000090: 74 5f 72 69 6d 5f 63 6c 64 63 2d 31 32 00 00 00 t_rim_cldc-12... 000000a0: 07 4a 17 49 96 00 0f 6e 65 74 5f 72 69 6d 5f 63 .J.I...net_rim_c 000000b0: 6c 64 63 2d 31 31 00 00 00 08 4a 17 49 96 00 0f ldc-11....J.I... 000000c0: 6e 65 74 5f 72 69 6d 5f 63 6c 64 63 2d 31 34 00 net_rim_cldc-14. 000000d0: 00 00 09 4a 17 49 96 00 0e 6e 65 74 5f 72 69 6d ...J.I...net_rim 000000e0: 5f 63 6c 64 63 2d 36 00 00 00 0a 4a 17 49 96 00 _cldc-6....J.I.. 000000f0: 0e 6e 65 74 5f 72 69 6d 5f 63 6c 64 63 2d 38 00 .net_rim_cldc-8. 00000100: 00 00 0b 4a 17 49 96 00 0e 6e 65 74 5f 72 69 6d ...J.I...net_rim 00000110: 5f 63 6c 64 63 2d 39 00 00 00 0c 4a 17 49 96 00 _cldc-9....J.I.. 00000120: 0e 6e 65 74 5f 72 69 6d 5f 63 6c 64 63 2d 31 00 .net_rim_cldc-1. 00000130: 00 00 0d 4a 17 49 96 00 0e 6e 65 74 5f 72 69 6d ...J.I...net_rim 00000140: 5f 63 6c 64 63 2d 37 00 00 00 0e 4a 17 49 96 00 _cldc-7....J.I.. 00000150: 0f 6e 65 74 5f 72 69 6d 5f 63 6c 64 63 2d 31 38 .net_rim_cldc-18 00000160: 00 00 00 0f 4a 17 49 96 00 0f 6e 65 74 5f 72 69 ....J.I...net_ri 00000170: 6d 5f 63 6c 64 63 2d 31 39 00 00 00 10 4a 17 49 m_cldc-19....J.I 00000180: 96 00 0f 6e 65 74 5f 72 69 6d 5f 63 6c 64 63 2d ...net_rim_cldc- 00000190: 31 30 00 00 00 11 4a 17 49 96 00 0e 6e 65 74 5f 10....J.I...net_ 000001a0: 72 69 6d 5f 63 6c 64 63 2d 35 00 00 00 12 4a 17 rim_cldc-5....J. 000001b0: 49 96 00 0f 6e 65 74 5f 72 69 6d 5f 63 6c 64 63 I...net_rim_cldc 000001c0: 2d 32 33 00 00 00 13 4a 17 49 96 00 0f 6e 65 74 -23....J.I...net 000001d0: 5f 72 69 6d 5f 63 6c 64 63 2d 31 37 00 00 00 14 _rim_cldc-17.... 000001e0: 4a 17 49 96 00 0e 6e 65 74 5f 72 69 6d 5f 63 6c J.I...net_rim_cl 000001f0: 64 63 2d 34 00 00 00 15 4a 17 49 96 00 0f 6e 65 dc-4....J.I...ne 00000200: 74 5f 72 69 6d 5f 63 6c 64 63 2d 31 36 00 00 00 t_rim_cldc-16... 00000210: 16 4a 17 49 96 00 0f 6e 65 74 5f 72 69 6d 5f 63 .J.I...net_rim_c 00000220: 6c 64 63 2d 32 32 00 00 00 17 4a 17 49 96 00 0f ldc-22....J.I... 00000230: 6e 65 74 5f 72 69 6d 5f 63 6c 64 63 2d 31 35 00 net_rim_cldc-15. 00000240: 00 00 18 4a 17 49 96 00 0f 6e 65 74 5f 72 69 6d ...J.I...net_rim 00000250: 5f 63 6c 64 63 2d 32 30 00 00 00 19 4a 17 49 96 _cldc-20....J.I. 00000260: 00 0f 6e 65 74 5f 72 69 6d 5f 63 6c 64 63 2d 32 ..net_rim_cldc-2 00000270: 31 00 00 00 1a 4a 2f bb a4 00 0c 53 74 6f 72 6d 1....J/....Storm 00000280: 50 69 63 74 75 72 65 00 00 00 1b 4a 2f bb a4 00 Picture....J/... 00000290: 0e 53 74 6f 72 6d 50 69 63 74 75 72 65 2d 31 00 .StormPicture-1. 000002a0: 00 00 1c 4a 51 dc ee 00 0b 42 65 72 72 79 52 75 ...JQ....BerryRu 000002b0: 62 69 6b 73 00 00 00 1d 4a 51 dc ee 00 0d 42 65 biks....JQ....Be 000002c0: 72 72 79 52 75 62 69 6b 73 2d 31 00 00 00 1e 4a rryRubiks-1....J 000002d0: 51 dc ee 00 0d 42 65 72 72 79 52 75 62 69 6b 73 Q....BerryRubiks 000002e0: 2d 32 00 00 00 1f 4a 51 dc ee 00 0d 42 65 72 72 -2....JQ....Berr 000002f0: 79 52 75 62 69 6b 73 2d 33 00 00 00 20 4a 51 dc yRubiks-3... JQ. 00000300: ee 00 0d 42 65 72 72 79 52 75 62 69 6b 73 2d 34 ...BerryRubiks-4 00000310: 00 00 00 21 4a 51 dc ee 00 0d 42 65 72 72 79 52 ...!JQ....BerryR 00000320: 75 62 69 6b 73 2d 35 00 00 00 22 49 86 2e 58 00 ubiks-5..."I..X. 00000330: 07 73 79 73 49 6e 66 6f 00 00 00 23 49 86 2e 58 .sysInfo...#I..X 00000340: 00 09 73 79 73 49 6e 66 6f 2d 31 00 00 00 24 4a ..sysInfo-1...$J 00000350: 51 dc ee 00 0d 42 65 72 72 79 52 75 62 69 6b 73 Q....BerryRubiks 00000360: 2d 36 00 00 00 25 4a 51 dc ee 00 0d 42 65 72 72 -6...%JQ....Berr 00000370: 79 52 75 62 69 6b 73 2d 37 00 00 00 26 49 df 42 yRubiks-7...&I.B 00000380: 41 00 05 4d 65 74 72 4f 00 00 00 27 49 df 42 41 A..MetrO...'I.BA 00000390: 00 07 4d 65 74 72 4f 2d 31 00 00 00 28 4a 37 61 ..MetrO-1...(J7a 000003a0: f7 00 09 42 65 72 72 79 54 72 61 70 00 00 00 29 ...BerryTrap...) 000003b0: 4a 37 61 f7 00 0b 42 65 72 72 79 54 72 61 70 2d J7a...BerryTrap- 000003c0: 31 00 00 00 2a 4a 37 61 f7 00 0b 42 65 72 72 79 1...*J7a...Berry 000003d0: 54 72 61 70 2d 32 00 00 00 2b 4a 37 61 f7 00 0b Trap-2...+J7a... | 000003e0: 42 65 72 72 79 54 72 61 70 2d 33 00 00 00 2c BerryTrap-3..., |^^^^^^^^^^^ ID of next data (if 0x00000000 no data) Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 157 00000000: 05 00 0b 00 00 05 8d 00 00 00 2c .........., <<< URB 162 00000000: 00 00 0c 00 13 05 01 00 07 00 00 00 ............ <<< URB 164 00000000: 05 00 06 00 03 cf ...... <<< URB 165 00000000: 05 00 d3 03 00 00 00 17 00 00 00 2c 4a 37 61 f7 ...........,J7a. |^^^^^^^^^^^ ^^^^^^^^^^^                    | ID address 00000010: 00 0b 42 65 72 72 79 54 72 61 70 2d 34 00 00 00 ..BerryTrap-4... ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| size name of module | 00000020: 2d 4a 37 61 f7 00 0b 42 65 72 72 79 54 72 61 70 -J7a...BerryTrap 00000030: 2d 35 00 00 00 2e 4a 37 61 f7 00 0b 42 65 72 72 -5....J7a...Berr | 00000040: 79 54 72 61 70 2d 36 00 00 00 2f 4a 37 61 f7 00 yTrap-6.../J7a.. | 00000050: 0b 42 65 72 72 79 54 72 61 70 2d 37 00 00 00 30 .BerryTrap-7...0 | 00000060: 4a 37 61 f7 00 0b 42 65 72 72 79 54 72 61 70 2d J7a...BerryTrap- 00000070: 38 00 00 00 31 4a 43 83 be 00 09 42 61 72 72 79 8...1JC....Barry |^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^ | ID address size name of 00000080: 44 65 6d 6f 00 00 00 32 4a 31 31 a3 00 11 6e 65 Demo...2J11...ne ^^^^^^^^^^^|^^^^^^^^^^^ module | ID 00000090: 74 5f 72 69 6d 5f 62 62 5f 71 6d 5f 6d 73 6e 00 t_rim_bb_qm_msn. 000000a0: 00 00 33 4a 31 31 a3 00 13 6e 65 74 5f 72 69 6d ..3J11...net_rim 000000b0: 5f 62 62 5f 71 6d 5f 6d 73 6e 2d 36 00 00 00 34 _bb_qm_msn-6...4 000000c0: 4a 31 31 a3 00 13 6e 65 74 5f 72 69 6d 5f 62 62 J11...net_rim_bb 000000d0: 5f 71 6d 5f 6d 73 6e 2d 37 00 00 00 35 4a 31 31 _qm_msn-7...5J11 000000e0: a3 00 13 6e 65 74 5f 72 69 6d 5f 62 62 5f 71 6d ...net_rim_bb_qm 000000f0: 5f 6d 73 6e 2d 35 00 00 00 36 4a 31 31 a3 00 13 _msn-5...6J11... 00000100: 6e 65 74 5f 72 69 6d 5f 62 62 5f 71 6d 5f 6d 73 net_rim_bb_qm_ms 00000110: 6e 2d 34 00 00 00 37 4a 31 31 a3 00 13 6e 65 74 n-4...7J11...net 00000120: 5f 72 69 6d 5f 62 62 5f 71 6d 5f 6d 73 6e 2d 31 _rim_bb_qm_msn-1 00000130: 00 00 00 38 4a 31 31 a3 00 13 6e 65 74 5f 72 69 ...8J11...net_ri 00000140: 6d 5f 62 62 5f 71 6d 5f 6d 73 6e 2d 38 00 00 00 m_bb_qm_msn-8... 00000150: 39 4a 31 31 a3 00 13 6e 65 74 5f 72 69 6d 5f 62 9J11...net_rim_b 00000160: 62 5f 71 6d 5f 6d 73 6e 2d 32 00 00 00 3a 4a 31 b_qm_msn-2...:J1 00000170: 31 a3 00 13 6e 65 74 5f 72 69 6d 5f 62 62 5f 71 1...net_rim_bb_q 00000180: 6d 5f 6d 73 6e 2d 33 00 00 00 3b 4a 31 31 be 00 m_msn-3...;J11.. 00000190: 1d 6e 65 74 5f 72 69 6d 5f 62 62 5f 71 6d 5f 6d .net_rim_bb_qm_m 000001a0: 73 6e 5f 72 65 73 6f 75 72 63 65 5f 65 6e 00 00 sn_resource_en.. 000001b0: 00 3c 4a 31 31 c8 00 1d 6e 65 74 5f 72 69 6d 5f .J@....S 000001f0: 68 61 7a 61 6d 2d 33 00 00 00 3f 4a 40 a2 7f 00 hazam-3...?J@... 00000200: 08 53 68 61 7a 61 6d 2d 35 00 00 00 40 4a 40 a2 .Shazam-5...@J@. 00000210: 7f 00 08 53 68 61 7a 61 6d 2d 34 00 00 00 41 4a ...Shazam-4...AJ 00000220: 40 a2 7f 00 08 53 68 61 7a 61 6d 2d 31 00 00 00 @....Shazam-1... 00000230: 42 4a 40 a2 7f 00 08 53 68 61 7a 61 6d 2d 32 00 BJ@....Shazam-2. 00000240: 00 00 b7 4a 17 54 84 00 25 6e 65 74 5f 72 69 6d ...J.T..%net_rim 00000250: 5f 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e _theme_precision 00000260: 5f 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 00 00 _zen_360x480_t.. 00000270: 00 b8 4a 17 54 84 00 27 6e 65 74 5f 72 69 6d 5f ..J.T..'net_rim_ 00000280: 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e 5f theme_precision_ 00000290: 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 2d 31 00 zen_360x480_t-1. 000002a0: 00 00 b9 4a 17 54 84 00 27 6e 65 74 5f 72 69 6d ...J.T..'net_rim 000002b0: 5f 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e _theme_precision 000002c0: 5f 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 2d 32 _zen_360x480_t-2 000002d0: 00 00 00 ba 4a 17 54 84 00 27 6e 65 74 5f 72 69 ....J.T..'net_ri 000002e0: 6d 5f 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f m_theme_precisio 000002f0: 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 2d n_zen_360x480_t- 00000300: 33 00 00 00 bb 4a 17 54 84 00 27 6e 65 74 5f 72 3....J.T..'net_r 00000310: 69 6d 5f 74 68 65 6d 65 5f 70 72 65 63 69 73 69 im_theme_precisi 00000320: 6f 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 on_zen_360x480_t 00000330: 2d 34 00 00 00 bc 4a 17 54 84 00 27 6e 65 74 5f -4....J.T..'net_ 00000340: 72 69 6d 5f 74 68 65 6d 65 5f 70 72 65 63 69 73 rim_theme_precis 00000350: 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 30 5f ion_zen_360x480_ 00000360: 74 2d 35 00 00 00 bd 4a 17 54 84 00 27 6e 65 74 t-5....J.T..'net 00000370: 5f 72 69 6d 5f 74 68 65 6d 65 5f 70 72 65 63 69 _rim_theme_preci 00000380: 73 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 30 sion_zen_360x480 00000390: 5f 74 2d 36 00 00 00 be 4a 17 54 84 00 27 6e 65 _t-6....J.T..'ne 000003a0: 74 5f 72 69 6d 5f 74 68 65 6d 65 5f 70 72 65 63 t_rim_theme_prec 000003b0: 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 ision_zen_360x48 000003c0: 30 5f 74 2d 37 00 00 00 bf 0_t-7.... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 84 00000000: 05 00 0b 00 00 05 8d 00 00 00 bf ........... <<< URB 64 00000000: 00 00 0c 00 13 05 01 00 08 00 00 00 ............ <<< URB 66 00000000: 05 00 06 00 03 ee ...... <<< URB 67 00000000: 05 00 f2 03 00 00 00 14 00 00 00 bf 4a 17 54 84 ............J.T. 00000010: 00 27 6e 65 74 5f 72 69 6d 5f 74 68 65 6d 65 5f .'net_rim_theme_ 00000020: 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 precision_zen_36 00000030: 30 78 34 38 30 5f 74 2d 38 00 00 00 c0 4a 17 54 0x480_t-8....J.T 00000040: 84 00 27 6e 65 74 5f 72 69 6d 5f 74 68 65 6d 65 ..'net_rim_theme 00000050: 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f 33 _precision_zen_3 00000060: 36 30 78 34 38 30 5f 74 2d 39 00 00 00 c1 4a 17 60x480_t-9....J. 00000070: 54 84 00 28 6e 65 74 5f 72 69 6d 5f 74 68 65 6d T..(net_rim_them 00000080: 65 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f e_precision_zen_ 00000090: 33 36 30 78 34 38 30 5f 74 2d 31 30 00 00 00 c2 360x480_t-10.... 000000a0: 4a 17 54 84 00 28 6e 65 74 5f 72 69 6d 5f 74 68 J.T..(net_rim_th 000000b0: 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 eme_precision_ze 000000c0: 6e 5f 33 36 30 78 34 38 30 5f 74 2d 31 31 00 00 n_360x480_t-11.. 000000d0: 00 c3 4a 17 54 84 00 28 6e 65 74 5f 72 69 6d 5f ..J.T..(net_rim_ 000000e0: 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e 5f theme_precision_ 000000f0: 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 2d 31 32 zen_360x480_t-12 00000100: 00 00 00 c4 4a 17 54 84 00 28 6e 65 74 5f 72 69 ....J.T..(net_ri 00000110: 6d 5f 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f m_theme_precisio 00000120: 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 2d n_zen_360x480_t- 00000130: 31 33 00 00 00 c5 4a 17 54 84 00 28 6e 65 74 5f 13....J.T..(net_ 00000140: 72 69 6d 5f 74 68 65 6d 65 5f 70 72 65 63 69 73 rim_theme_precis 00000150: 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 30 5f ion_zen_360x480_ 00000160: 74 2d 31 34 00 00 00 c6 4a 17 54 84 00 28 6e 65 t-14....J.T..(ne 00000170: 74 5f 72 69 6d 5f 74 68 65 6d 65 5f 70 72 65 63 t_rim_theme_prec 00000180: 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 ision_zen_360x48 00000190: 30 5f 74 2d 31 35 00 00 00 c7 4a 17 54 84 00 28 0_t-15....J.T..( 000001a0: 6e 65 74 5f 72 69 6d 5f 74 68 65 6d 65 5f 70 72 net_rim_theme_pr 000001b0: 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 ecision_zen_360x 000001c0: 34 38 30 5f 74 2d 31 36 00 00 00 c8 4a 17 54 84 480_t-16....J.T. 000001d0: 00 28 6e 65 74 5f 72 69 6d 5f 74 68 65 6d 65 5f .(net_rim_theme_ 000001e0: 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 precision_zen_36 000001f0: 30 78 34 38 30 5f 74 2d 31 37 00 00 00 c9 4a 17 0x480_t-17....J. 00000200: 54 84 00 28 6e 65 74 5f 72 69 6d 5f 74 68 65 6d T..(net_rim_them 00000210: 65 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f e_precision_zen_ 00000220: 33 36 30 78 34 38 30 5f 74 2d 31 38 00 00 00 ca 360x480_t-18.... 00000230: 4a 17 54 84 00 28 6e 65 74 5f 72 69 6d 5f 74 68 J.T..(net_rim_th 00000240: 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 eme_precision_ze 00000250: 6e 5f 33 36 30 78 34 38 30 5f 74 2d 31 39 00 00 n_360x480_t-19.. 00000260: 00 cb 4a 17 54 84 00 28 6e 65 74 5f 72 69 6d 5f ..J.T..(net_rim_ 00000270: 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e 5f theme_precision_ 00000280: 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 2d 32 30 zen_360x480_t-20 00000290: 00 00 00 cc 4a 17 54 84 00 28 6e 65 74 5f 72 69 ....J.T..(net_ri 000002a0: 6d 5f 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f m_theme_precisio 000002b0: 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 2d n_zen_360x480_t- 000002c0: 32 31 00 00 00 cd 4a 17 54 84 00 28 6e 65 74 5f 21....J.T..(net_ 000002d0: 72 69 6d 5f 74 68 65 6d 65 5f 70 72 65 63 69 73 rim_theme_precis 000002e0: 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 30 5f ion_zen_360x480_ 000002f0: 74 2d 32 32 00 00 00 ce 4a 17 54 84 00 28 6e 65 t-22....J.T..(ne 00000300: 74 5f 72 69 6d 5f 74 68 65 6d 65 5f 70 72 65 63 t_rim_theme_prec 00000310: 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 ision_zen_360x48 00000320: 30 5f 74 2d 32 33 00 00 00 cf 4a 17 54 84 00 28 0_t-23....J.T..( 00000330: 6e 65 74 5f 72 69 6d 5f 74 68 65 6d 65 5f 70 72 net_rim_theme_pr 00000340: 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 ecision_zen_360x 00000350: 34 38 30 5f 74 2d 32 34 00 00 00 d0 4a 17 54 84 480_t-24....J.T. 00000360: 00 28 6e 65 74 5f 72 69 6d 5f 74 68 65 6d 65 5f .(net_rim_theme_ 00000370: 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 precision_zen_36 00000380: 30 78 34 38 30 5f 74 2d 32 35 00 00 00 d1 4a 17 0x480_t-25....J. 00000390: 54 84 00 28 6e 65 74 5f 72 69 6d 5f 74 68 65 6d T..(net_rim_them 000003a0: 65 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f e_precision_zen_ 000003b0: 33 36 30 78 34 38 30 5f 74 2d 32 36 00 00 00 d2 360x480_t-26.... 000003c0: 4a 17 54 84 00 28 6e 65 74 5f 72 69 6d 5f 74 68 J.T..(net_rim_th 000003d0: 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 eme_precision_ze 000003e0: 6e 5f 33 36 30 78 34 38 30 5f 74 2d 32 37 00 00 n_360x480_t-27.. 000003f0: 00 d3 .. Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 88 00000000: 05 00 0b 00 00 05 8d 00 00 00 d3 ........... <<< URB 68 00000000: 00 00 0c 00 13 05 01 00 09 00 00 00 ............ <<< URB 70 00000000: 05 00 06 00 03 f0 ...... <<< URB 71 00000000: 05 00 f4 03 00 00 00 14 00 00 00 d3 4a 17 54 84 ............J.T. 00000010: 00 28 6e 65 74 5f 72 69 6d 5f 74 68 65 6d 65 5f .(net_rim_theme_ 00000020: 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 precision_zen_36 00000030: 30 78 34 38 30 5f 74 2d 32 38 00 00 00 d4 4a 17 0x480_t-28....J. 00000040: 54 84 00 28 6e 65 74 5f 72 69 6d 5f 74 68 65 6d T..(net_rim_them 00000050: 65 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f e_precision_zen_ 00000060: 33 36 30 78 34 38 30 5f 74 2d 32 39 00 00 00 d5 360x480_t-29.... 00000070: 4a 17 54 84 00 28 6e 65 74 5f 72 69 6d 5f 74 68 J.T..(net_rim_th 00000080: 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 eme_precision_ze 00000090: 6e 5f 33 36 30 78 34 38 30 5f 74 2d 33 30 00 00 n_360x480_t-30.. 000000a0: 00 d6 4a 17 54 84 00 28 6e 65 74 5f 72 69 6d 5f ..J.T..(net_rim_ 000000b0: 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e 5f theme_precision_ 000000c0: 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 2d 33 31 zen_360x480_t-31 000000d0: 00 00 00 d7 4a 17 54 84 00 28 6e 65 74 5f 72 69 ....J.T..(net_ri 000000e0: 6d 5f 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f m_theme_precisio 000000f0: 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 2d n_zen_360x480_t- 00000100: 33 32 00 00 00 d8 4a 17 54 84 00 28 6e 65 74 5f 32....J.T..(net_ 00000110: 72 69 6d 5f 74 68 65 6d 65 5f 70 72 65 63 69 73 rim_theme_precis 00000120: 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 30 5f ion_zen_360x480_ 00000130: 74 2d 33 33 00 00 00 d9 4a 17 54 84 00 28 6e 65 t-33....J.T..(ne 00000140: 74 5f 72 69 6d 5f 74 68 65 6d 65 5f 70 72 65 63 t_rim_theme_prec 00000150: 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 ision_zen_360x48 00000160: 30 5f 74 2d 33 34 00 00 00 da 4a 17 54 84 00 28 0_t-34....J.T..( 00000170: 6e 65 74 5f 72 69 6d 5f 74 68 65 6d 65 5f 70 72 net_rim_theme_pr 00000180: 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 ecision_zen_360x 00000190: 34 38 30 5f 74 2d 33 35 00 00 00 db 4a 17 54 84 480_t-35....J.T. 000001a0: 00 28 6e 65 74 5f 72 69 6d 5f 74 68 65 6d 65 5f .(net_rim_theme_ 000001b0: 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 precision_zen_36 000001c0: 30 78 34 38 30 5f 74 2d 33 36 00 00 00 dc 4a 17 0x480_t-36....J. 000001d0: 54 84 00 28 6e 65 74 5f 72 69 6d 5f 74 68 65 6d T..(net_rim_them 000001e0: 65 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f e_precision_zen_ 000001f0: 33 36 30 78 34 38 30 5f 74 2d 33 37 00 00 00 dd 360x480_t-37.... 00000200: 4a 17 54 84 00 28 6e 65 74 5f 72 69 6d 5f 74 68 J.T..(net_rim_th 00000210: 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 eme_precision_ze 00000220: 6e 5f 33 36 30 78 34 38 30 5f 74 2d 33 38 00 00 n_360x480_t-38.. 00000230: 00 de 4a 17 54 84 00 28 6e 65 74 5f 72 69 6d 5f ..J.T..(net_rim_ 00000240: 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e 5f theme_precision_ 00000250: 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 2d 33 39 zen_360x480_t-39 00000260: 00 00 00 df 4a 17 54 84 00 28 6e 65 74 5f 72 69 ....J.T..(net_ri 00000270: 6d 5f 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f m_theme_precisio 00000280: 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 2d n_zen_360x480_t- 00000290: 34 30 00 00 00 e0 4a 17 54 84 00 28 6e 65 74 5f 40....J.T..(net_ 000002a0: 72 69 6d 5f 74 68 65 6d 65 5f 70 72 65 63 69 73 rim_theme_precis 000002b0: 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 30 5f ion_zen_360x480_ 000002c0: 74 2d 34 31 00 00 00 e1 4a 17 54 84 00 28 6e 65 t-41....J.T..(ne 000002d0: 74 5f 72 69 6d 5f 74 68 65 6d 65 5f 70 72 65 63 t_rim_theme_prec 000002e0: 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 ision_zen_360x48 000002f0: 30 5f 74 2d 34 32 00 00 00 e2 4a 17 54 84 00 28 0_t-42....J.T..( 00000300: 6e 65 74 5f 72 69 6d 5f 74 68 65 6d 65 5f 70 72 net_rim_theme_pr 00000310: 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 30 78 ecision_zen_360x 00000320: 34 38 30 5f 74 2d 34 33 00 00 00 e3 4a 17 54 84 480_t-43....J.T. 00000330: 00 28 6e 65 74 5f 72 69 6d 5f 74 68 65 6d 65 5f .(net_rim_theme_ 00000340: 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 precision_zen_36 00000350: 30 78 34 38 30 5f 74 2d 34 34 00 00 00 e4 4a 17 0x480_t-44....J. 00000360: 54 84 00 28 6e 65 74 5f 72 69 6d 5f 74 68 65 6d T..(net_rim_them 00000370: 65 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f e_precision_zen_ 00000380: 33 36 30 78 34 38 30 5f 74 2d 34 35 00 00 00 e5 360x480_t-45.... 00000390: 4a 17 54 84 00 28 6e 65 74 5f 72 69 6d 5f 74 68 J.T..(net_rim_th 000003a0: 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 eme_precision_ze 000003b0: 6e 5f 33 36 30 78 34 38 30 5f 74 2d 34 36 00 00 n_360x480_t-46.. 000003c0: 00 e6 4a 17 54 84 00 28 6e 65 74 5f 72 69 6d 5f ..J.T..(net_rim_ 000003d0: 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e 5f theme_precision_ 000003e0: 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 2d 34 37 zen_360x480_t-47 000003f0: 00 00 00 e7 .... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 92 00000000: 05 00 0b 00 00 05 8d 00 00 00 e7 ........... <<< URB 72 00000000: 00 00 0c 00 13 05 01 00 0a 00 00 00 ............ <<< URB 74 00000000: 05 00 06 00 03 f0 ...... <<< URB 75 00000000: 05 00 f4 03 00 00 00 1a 00 00 00 e7 4a 17 54 84 ............J.T. 00000010: 00 28 6e 65 74 5f 72 69 6d 5f 74 68 65 6d 65 5f .(net_rim_theme_ 00000020: 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f 33 36 precision_zen_36 00000030: 30 78 34 38 30 5f 74 2d 34 38 00 00 00 e8 4a 17 0x480_t-48....J. 00000040: 54 84 00 28 6e 65 74 5f 72 69 6d 5f 74 68 65 6d T..(net_rim_them 00000050: 65 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 6e 5f e_precision_zen_ 00000060: 33 36 30 78 34 38 30 5f 74 2d 34 39 00 00 00 e9 360x480_t-49.... 00000070: 4a 17 54 84 00 28 6e 65 74 5f 72 69 6d 5f 74 68 J.T..(net_rim_th 00000080: 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e 5f 7a 65 eme_precision_ze 00000090: 6e 5f 33 36 30 78 34 38 30 5f 74 2d 35 30 00 00 n_360x480_t-50.. 000000a0: 00 ea 4a 17 54 84 00 28 6e 65 74 5f 72 69 6d 5f ..J.T..(net_rim_ 000000b0: 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f 6e 5f theme_precision_ 000000c0: 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 2d 35 31 zen_360x480_t-51 000000d0: 00 00 00 eb 4a 17 54 84 00 28 6e 65 74 5f 72 69 ....J.T..(net_ri 000000e0: 6d 5f 74 68 65 6d 65 5f 70 72 65 63 69 73 69 6f m_theme_precisio 000000f0: 6e 5f 7a 65 6e 5f 33 36 30 78 34 38 30 5f 74 2d n_zen_360x480_t- 00000100: 35 32 00 00 01 11 4a 17 55 86 00 1a 6e 65 74 5f 52....J.U...net_ 00000110: 72 69 6d 5f 62 62 5f 73 65 74 75 70 77 69 7a 61 rim_bb_setupwiza 00000120: 72 64 5f 61 70 70 00 00 01 12 4a 17 55 86 00 1d rd_app....J.U... 00000130: 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 65 74 75 70 net_rim_bb_setup 00000140: 77 69 7a 61 72 64 5f 61 70 70 2d 32 33 00 00 01 wizard_app-23... 00000150: 13 4a 17 4b 2e 00 16 6e 65 74 5f 72 69 6d 5f 62 .J.K...net_rim_b 00000160: 62 5f 73 65 74 75 70 77 69 7a 61 72 64 00 00 01 b_setupwizard... 00000170: 14 4a 17 4b 2e 00 18 6e 65 74 5f 72 69 6d 5f 62 .J.K...net_rim_b 00000180: 62 5f 73 65 74 75 70 77 69 7a 61 72 64 2d 31 00 b_setupwizard-1. 00000190: 00 01 15 4a 17 49 f8 00 1b 6e 65 74 5f 72 69 6d ...J.I...net_rim 000001a0: 5f 70 6c 61 7a 6d 69 63 5f 6d 65 64 69 61 65 6e _plazmic_mediaen 000001b0: 67 69 6e 65 00 00 01 16 4a 17 4a 93 00 18 6e 65 gine....J.J...ne 000001c0: 74 5f 72 69 6d 5f 62 62 5f 66 72 61 6d 65 77 6f t_rim_bb_framewo 000001d0: 72 6b 5f 61 70 69 00 00 01 17 4a 17 4a 93 00 1a rk_api....J.J... 000001e0: 6e 65 74 5f 72 69 6d 5f 62 62 5f 66 72 61 6d 65 net_rim_bb_frame 000001f0: 77 6f 72 6b 5f 61 70 69 2d 32 00 00 01 18 4a 17 work_api-2....J. 00000200: 4a 93 00 1a 6e 65 74 5f 72 69 6d 5f 62 62 5f 66 J...net_rim_bb_f 00000210: 72 61 6d 65 77 6f 72 6b 5f 61 70 69 2d 31 00 00 ramework_api-1.. 00000220: 01 19 4a 17 4a 93 00 1a 6e 65 74 5f 72 69 6d 5f ..J.J...net_rim_ 00000230: 62 62 5f 66 72 61 6d 65 77 6f 72 6b 5f 61 70 69 bb_framework_api 00000240: 2d 33 00 00 01 1a 4a 17 4b 00 00 18 6e 65 74 5f -3....J.K...net_ 00000250: 72 69 6d 5f 62 62 5f 6c 6f 63 61 6c 65 72 65 6d rim_bb_localerem 00000260: 6f 76 61 6c 00 00 01 1b 4a 17 4b 03 00 10 6e 65 oval....J.K...ne 00000270: 74 5f 72 69 6d 5f 62 62 5f 76 6f 69 63 65 00 00 t_rim_bb_voice.. 00000280: 01 1c 4a 17 4a eb 00 12 6e 65 74 5f 72 69 6d 5f ..J.J...net_rim_ 00000290: 62 62 5f 6f 70 74 69 6f 6e 73 00 00 01 1d 4a 17 bb_options....J. 000002a0: 55 86 00 1c 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 U...net_rim_bb_s 000002b0: 65 74 75 70 77 69 7a 61 72 64 5f 61 70 70 2d 31 etupwizard_app-1 000002c0: 00 00 01 1e 4a 17 55 86 00 1c 6e 65 74 5f 72 69 ....J.U...net_ri 000002d0: 6d 5f 62 62 5f 73 65 74 75 70 77 69 7a 61 72 64 m_bb_setupwizard 000002e0: 5f 61 70 70 2d 32 00 00 01 1f 4a 17 55 86 00 1c _app-2....J.U... 000002f0: 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 65 74 75 70 net_rim_bb_setup 00000300: 77 69 7a 61 72 64 5f 61 70 70 2d 33 00 00 01 20 wizard_app-3... 00000310: 4a 17 55 86 00 1c 6e 65 74 5f 72 69 6d 5f 62 62 J.U...net_rim_bb 00000320: 5f 73 65 74 75 70 77 69 7a 61 72 64 5f 61 70 70 _setupwizard_app 00000330: 2d 34 00 00 01 21 4a 17 55 86 00 1c 6e 65 74 5f -4...!J.U...net_ 00000340: 72 69 6d 5f 62 62 5f 73 65 74 75 70 77 69 7a 61 rim_bb_setupwiza 00000350: 72 64 5f 61 70 70 2d 35 00 00 01 22 4a 17 55 86 rd_app-5..."J.U. 00000360: 00 1c 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 65 74 ..net_rim_bb_set 00000370: 75 70 77 69 7a 61 72 64 5f 61 70 70 2d 36 00 00 upwizard_app-6.. 00000380: 01 23 4a 17 55 86 00 1c 6e 65 74 5f 72 69 6d 5f .#J.U...net_rim_ 00000390: 62 62 5f 73 65 74 75 70 77 69 7a 61 72 64 5f 61 bb_setupwizard_a 000003a0: 70 70 2d 37 00 00 01 24 4a 17 55 86 00 1c 6e 65 pp-7...$J.U...ne 000003b0: 74 5f 72 69 6d 5f 62 62 5f 73 65 74 75 70 77 69 t_rim_bb_setupwi 000003c0: 7a 61 72 64 5f 61 70 70 2d 38 00 00 01 25 4a 17 zard_app-8...%J. 000003d0: 55 86 00 1c 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 U...net_rim_bb_s 000003e0: 65 74 75 70 77 69 7a 61 72 64 5f 61 70 70 2d 39 etupwizard_app-9 000003f0: 00 00 01 26 ...& Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 96 00000000: 05 00 0b 00 00 05 8d 00 00 01 26 ..........& <<< URB 76 00000000: 00 00 0c 00 13 05 01 00 0b 00 00 00 ............ <<< URB 78 00000000: 05 00 06 00 03 d7 ...... <<< URB 79 00000000: 05 00 db 03 00 00 00 19 00 00 01 26 4a 17 55 86 ...........&J.U. 00000010: 00 1d 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 65 74 ..net_rim_bb_set 00000020: 75 70 77 69 7a 61 72 64 5f 61 70 70 2d 31 30 00 upwizard_app-10. 00000030: 00 01 27 4a 17 55 86 00 1d 6e 65 74 5f 72 69 6d ..'J.U...net_rim 00000040: 5f 62 62 5f 73 65 74 75 70 77 69 7a 61 72 64 5f _bb_setupwizard_ 00000050: 61 70 70 2d 31 31 00 00 01 28 4a 17 55 86 00 1d app-11...(J.U... 00000060: 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 65 74 75 70 net_rim_bb_setup 00000070: 77 69 7a 61 72 64 5f 61 70 70 2d 31 32 00 00 01 wizard_app-12... 00000080: 29 4a 17 55 86 00 1d 6e 65 74 5f 72 69 6d 5f 62 )J.U...net_rim_b 00000090: 62 5f 73 65 74 75 70 77 69 7a 61 72 64 5f 61 70 b_setupwizard_ap 000000a0: 70 2d 31 33 00 00 01 2a 4a 17 55 86 00 1d 6e 65 p-13...*J.U...ne 000000b0: 74 5f 72 69 6d 5f 62 62 5f 73 65 74 75 70 77 69 t_rim_bb_setupwi 000000c0: 7a 61 72 64 5f 61 70 70 2d 31 34 00 00 01 2b 4a zard_app-14...+J 000000d0: 17 55 86 00 1d 6e 65 74 5f 72 69 6d 5f 62 62 5f .U...net_rim_bb_ 000000e0: 73 65 74 75 70 77 69 7a 61 72 64 5f 61 70 70 2d setupwizard_app- 000000f0: 31 35 00 00 01 2c 4a 17 55 86 00 1d 6e 65 74 5f 15...,J.U...net_ 00000100: 72 69 6d 5f 62 62 5f 73 65 74 75 70 77 69 7a 61 rim_bb_setupwiza 00000110: 72 64 5f 61 70 70 2d 31 36 00 00 01 2d 4a 17 55 rd_app-16...-J.U 00000120: 86 00 1d 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 65 ...net_rim_bb_se 00000130: 74 75 70 77 69 7a 61 72 64 5f 61 70 70 2d 31 37 tupwizard_app-17 00000140: 00 00 01 2e 4a 17 55 86 00 1d 6e 65 74 5f 72 69 ....J.U...net_ri 00000150: 6d 5f 62 62 5f 73 65 74 75 70 77 69 7a 61 72 64 m_bb_setupwizard 00000160: 5f 61 70 70 2d 31 38 00 00 01 2f 4a 17 55 86 00 _app-18.../J.U.. 00000170: 1d 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 65 74 75 .net_rim_bb_setu 00000180: 70 77 69 7a 61 72 64 5f 61 70 70 2d 31 39 00 00 pwizard_app-19.. 00000190: 01 30 4a 17 55 86 00 1d 6e 65 74 5f 72 69 6d 5f .0J.U...net_rim_ 000001a0: 62 62 5f 73 65 74 75 70 77 69 7a 61 72 64 5f 61 bb_setupwizard_a 000001b0: 70 70 2d 32 30 00 00 01 31 4a 17 55 86 00 1d 6e pp-20...1J.U...n 000001c0: 65 74 5f 72 69 6d 5f 62 62 5f 73 65 74 75 70 77 et_rim_bb_setupw 000001d0: 69 7a 61 72 64 5f 61 70 70 2d 32 31 00 00 01 32 izard_app-21...2 000001e0: 4a 17 55 86 00 1d 6e 65 74 5f 72 69 6d 5f 62 62 J.U...net_rim_bb 000001f0: 5f 73 65 74 75 70 77 69 7a 61 72 64 5f 61 70 70 _setupwizard_app 00000200: 2d 32 32 00 00 01 33 4a 17 4a 93 00 1b 6e 65 74 -22...3J.J...net 00000210: 5f 72 69 6d 5f 66 6f 6e 74 5f 6c 61 74 69 6e 5f _rim_font_latin_ 00000220: 74 72 75 65 74 79 70 65 00 00 01 34 4a 17 4a 93 truetype...4J.J. 00000230: 00 1d 6e 65 74 5f 72 69 6d 5f 66 6f 6e 74 5f 6c ..net_rim_font_l 00000240: 61 74 69 6e 5f 74 72 75 65 74 79 70 65 2d 31 00 atin_truetype-1. 00000250: 00 01 35 4a 17 4a 93 00 1d 6e 65 74 5f 72 69 6d ..5J.J...net_rim 00000260: 5f 66 6f 6e 74 5f 6c 61 74 69 6e 5f 74 72 75 65 _font_latin_true 00000270: 74 79 70 65 2d 32 00 00 01 36 4a 17 4a 93 00 1d type-2...6J.J... 00000280: 6e 65 74 5f 72 69 6d 5f 66 6f 6e 74 5f 6c 61 74 net_rim_font_lat 00000290: 69 6e 5f 74 72 75 65 74 79 70 65 2d 33 00 00 01 in_truetype-3... 000002a0: 37 4a 17 4a 93 00 1d 6e 65 74 5f 72 69 6d 5f 66 7J.J...net_rim_f 000002b0: 6f 6e 74 5f 6c 61 74 69 6e 5f 74 72 75 65 74 79 ont_latin_truety 000002c0: 70 65 2d 34 00 00 01 38 4a 17 4a 93 00 1d 6e 65 pe-4...8J.J...ne 000002d0: 74 5f 72 69 6d 5f 66 6f 6e 74 5f 6c 61 74 69 6e t_rim_font_latin 000002e0: 5f 74 72 75 65 74 79 70 65 2d 35 00 00 01 39 4a _truetype-5...9J 000002f0: 17 4a 93 00 1d 6e 65 74 5f 72 69 6d 5f 66 6f 6e .J...net_rim_fon 00000300: 74 5f 6c 61 74 69 6e 5f 74 72 75 65 74 79 70 65 t_latin_truetype 00000310: 2d 36 00 00 01 3a 4a 17 4a 93 00 1d 6e 65 74 5f -6...:J.J...net_ 00000320: 72 69 6d 5f 66 6f 6e 74 5f 6c 61 74 69 6e 5f 74 rim_font_latin_t 00000330: 72 75 65 74 79 70 65 2d 37 00 00 01 3b 4a 17 4a ruetype-7...;J.J 00000340: 93 00 1d 6e 65 74 5f 72 69 6d 5f 66 6f 6e 74 5f ...net_rim_font_ 00000350: 6c 61 74 69 6e 5f 74 72 75 65 74 79 70 65 2d 38 latin_truetype-8 00000360: 00 00 01 3c 4a 17 4a 93 00 1d 6e 65 74 5f 72 69 ...J.J...net_rim 000003c0: 5f 66 6f 6e 74 5f 6c 61 74 69 6e 5f 74 72 75 65 _font_latin_true 000003d0: 74 79 70 65 2d 31 31 00 00 01 3f type-11...? Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 100 00000000: 05 00 0b 00 00 05 8d 00 00 01 3f ..........? <<< URB 80 00000000: 00 00 0c 00 13 05 01 00 0c 00 00 00 ............ <<< URB 82 00000000: 05 00 06 00 03 e4 ...... <<< URB 83 00000000: 05 00 e8 03 00 00 00 1f 00 00 01 3f 4a 17 4a 93 ...........?J.J. 00000010: 00 1e 6e 65 74 5f 72 69 6d 5f 66 6f 6e 74 5f 6c ..net_rim_font_l 00000020: 61 74 69 6e 5f 74 72 75 65 74 79 70 65 2d 31 32 atin_truetype-12 00000030: 00 00 01 40 4a 17 4a 93 00 1e 6e 65 74 5f 72 69 ...@J.J...net_ri 00000040: 6d 5f 66 6f 6e 74 5f 6c 61 74 69 6e 5f 74 72 75 m_font_latin_tru 00000050: 65 74 79 70 65 2d 31 33 00 00 01 41 4a 17 4a 93 etype-13...AJ.J. 00000060: 00 1e 6e 65 74 5f 72 69 6d 5f 66 6f 6e 74 5f 6c ..net_rim_font_l 00000070: 61 74 69 6e 5f 74 72 75 65 74 79 70 65 2d 31 34 atin_truetype-14 00000080: 00 00 01 42 4a 17 4a 93 00 1e 6e 65 74 5f 72 69 ...BJ.J...net_ri 00000090: 6d 5f 66 6f 6e 74 5f 6c 61 74 69 6e 5f 74 72 75 m_font_latin_tru 000000a0: 65 74 79 70 65 2d 31 35 00 00 01 43 4a 17 4a 93 etype-15...CJ.J. 000000b0: 00 1e 6e 65 74 5f 72 69 6d 5f 66 6f 6e 74 5f 6c ..net_rim_font_l 000000c0: 61 74 69 6e 5f 74 72 75 65 74 79 70 65 2d 31 36 atin_truetype-16 000000d0: 00 00 01 44 4a 17 4a 93 00 1e 6e 65 74 5f 72 69 ...DJ.J...net_ri 000000e0: 6d 5f 66 6f 6e 74 5f 6c 61 74 69 6e 5f 74 72 75 m_font_latin_tru 000000f0: 65 74 79 70 65 2d 31 37 00 00 01 45 4a 17 4a 93 etype-17...EJ.J. 00000100: 00 1e 6e 65 74 5f 72 69 6d 5f 66 6f 6e 74 5f 6c ..net_rim_font_l 00000110: 61 74 69 6e 5f 74 72 75 65 74 79 70 65 2d 31 38 atin_truetype-18 00000120: 00 00 01 46 4a 17 4a 93 00 1e 6e 65 74 5f 72 69 ...FJ.J...net_ri 00000130: 6d 5f 66 6f 6e 74 5f 6c 61 74 69 6e 5f 74 72 75 m_font_latin_tru 00000140: 65 74 79 70 65 2d 31 39 00 00 01 47 4a 17 4a 93 etype-19...GJ.J. 00000150: 00 1e 6e 65 74 5f 72 69 6d 5f 66 6f 6e 74 5f 6c ..net_rim_font_l 00000160: 61 74 69 6e 5f 74 72 75 65 74 79 70 65 2d 32 30 atin_truetype-20 00000170: 00 00 01 48 4a 17 4a 93 00 1e 6e 65 74 5f 72 69 ...HJ.J...net_ri 00000180: 6d 5f 66 6f 6e 74 5f 6c 61 74 69 6e 5f 74 72 75 m_font_latin_tru 00000190: 65 74 79 70 65 2d 32 31 00 00 01 49 4a 17 4a 93 etype-21...IJ.J. 000001a0: 00 1e 6e 65 74 5f 72 69 6d 5f 66 6f 6e 74 5f 6c ..net_rim_font_l 000001b0: 61 74 69 6e 5f 74 72 75 65 74 79 70 65 2d 32 32 atin_truetype-22 000001c0: 00 00 01 4a 4a 17 4a 93 00 1e 6e 65 74 5f 72 69 ...JJ.J...net_ri 000001d0: 6d 5f 66 6f 6e 74 5f 6c 61 74 69 6e 5f 74 72 75 m_font_latin_tru 000001e0: 65 74 79 70 65 2d 32 33 00 00 01 4b 4a 17 50 bd etype-23...KJ.P. 000001f0: 00 18 6e 65 74 5f 72 69 6d 5f 62 62 5f 62 72 6f ..net_rim_bb_bro 00000200: 77 73 65 72 5f 6d 61 6e 67 6f 00 00 01 4c 4a 17 wser_mango...LJ. 00000210: 49 f2 00 0f 6e 65 74 5f 72 69 6d 5f 78 6d 6c 5f I...net_rim_xml_ 00000220: 6f 72 67 00 00 01 4d 4a 17 51 dd 00 0a 6e 65 74 org...MJ.Q...net 00000230: 5f 72 69 6d 5f 6f 73 00 00 01 4e 4a 17 51 dd 00 _rim_os...NJ.Q.. 00000240: 0c 6e 65 74 5f 72 69 6d 5f 6f 73 2d 38 00 00 01 .net_rim_os-8... 00000250: 4f 4a 17 51 dd 00 0c 6e 65 74 5f 72 69 6d 5f 6f OJ.Q...net_rim_o 00000260: 73 2d 35 00 00 01 50 4a 17 51 dd 00 0c 6e 65 74 s-5...PJ.Q...net 00000270: 5f 72 69 6d 5f 6f 73 2d 39 00 00 01 51 4a 17 51 _rim_os-9...QJ.Q 00000280: dd 00 0c 6e 65 74 5f 72 69 6d 5f 6f 73 2d 31 00 ...net_rim_os-1. 00000290: 00 01 52 4a 17 51 dd 00 0c 6e 65 74 5f 72 69 6d ..RJ.Q...net_rim 000002a0: 5f 6f 73 2d 36 00 00 01 53 4a 17 51 dd 00 0c 6e _os-6...SJ.Q...n 000002b0: 65 74 5f 72 69 6d 5f 6f 73 2d 37 00 00 01 54 4a et_rim_os-7...TJ 000002c0: 17 51 dd 00 0c 6e 65 74 5f 72 69 6d 5f 6f 73 2d .Q...net_rim_os- 000002d0: 32 00 00 01 55 4a 17 51 dd 00 0c 6e 65 74 5f 72 2...UJ.Q...net_r 000002e0: 69 6d 5f 6f 73 2d 33 00 00 01 56 4a 17 51 dd 00 im_os-3...VJ.Q.. 000002f0: 0c 6e 65 74 5f 72 69 6d 5f 6f 73 2d 34 00 00 01 .net_rim_os-4... 00000300: 57 4a 17 50 bd 00 1a 6e 65 74 5f 72 69 6d 5f 62 WJ.P...net_rim_b 00000310: 62 5f 62 72 6f 77 73 65 72 5f 6d 61 6e 67 6f 2d b_browser_mango- 00000320: 31 00 00 01 58 4a 17 50 bd 00 1a 6e 65 74 5f 72 1...XJ.P...net_r 00000330: 69 6d 5f 62 62 5f 62 72 6f 77 73 65 72 5f 6d 61 im_bb_browser_ma 00000340: 6e 67 6f 2d 37 00 00 01 59 4a 17 50 bd 00 1a 6e ngo-7...YJ.P...n 00000350: 65 74 5f 72 69 6d 5f 62 62 5f 62 72 6f 77 73 65 et_rim_bb_browse 00000360: 72 5f 6d 61 6e 67 6f 2d 38 00 00 01 5a 4a 17 4b r_mango-8...ZJ.K 00000370: 4e 00 12 6e 65 74 5f 72 69 6d 5f 65 63 6d 61 73 N..net_rim_ecmas 00000380: 63 72 69 70 74 00 00 01 5b 4a 17 4b 4e 00 14 6e cript...[J.KN..n 00000390: 65 74 5f 72 69 6d 5f 65 63 6d 61 73 63 72 69 70 et_rim_ecmascrip 000003a0: 74 2d 31 00 00 01 5c 4a 17 4b 4b 00 19 6e 65 74 t-1...\J.KK..net 000003b0: 5f 72 69 6d 5f 65 63 6d 61 73 63 72 69 70 74 5f _rim_ecmascript_ 000003c0: 72 65 67 65 78 70 00 00 01 5d 4a 17 4b 4e 00 14 regexp...]J.KN.. 000003d0: 6e 65 74 5f 72 69 6d 5f 65 63 6d 61 73 63 72 69 net_rim_ecmascri 000003e0: 70 74 2d 32 00 00 01 5e pt-2...^ Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 104 00000000: 05 00 0b 00 00 05 8d 00 00 01 5e ..........^ <<< URB 84 00000000: 00 00 0c 00 13 05 01 00 0d 00 00 00 ............ <<< URB 86 00000000: 05 00 06 00 03 e6 ...... <<< URB 87 00000000: 05 00 ea 03 00 00 00 1f 00 00 01 5e 4a 17 50 bd ...........^J.P. 00000010: 00 1a 6e 65 74 5f 72 69 6d 5f 62 62 5f 62 72 6f ..net_rim_bb_bro 00000020: 77 73 65 72 5f 6d 61 6e 67 6f 2d 32 00 00 01 5f wser_mango-2..._ 00000030: 4a 17 50 bd 00 1a 6e 65 74 5f 72 69 6d 5f 62 62 J.P...net_rim_bb 00000040: 5f 62 72 6f 77 73 65 72 5f 6d 61 6e 67 6f 2d 39 _browser_mango-9 00000050: 00 00 01 60 4a 17 50 bd 00 1a 6e 65 74 5f 72 69 ...`J.P...net_ri 00000060: 6d 5f 62 62 5f 62 72 6f 77 73 65 72 5f 6d 61 6e m_bb_browser_man 00000070: 67 6f 2d 34 00 00 01 61 4a 17 49 ff 00 0d 6e 65 go-4...aJ.I...ne 00000080: 74 5f 72 69 6d 5f 73 61 74 73 61 00 00 01 62 4a t_rim_satsa...bJ 00000090: 17 50 bd 00 1a 6e 65 74 5f 72 69 6d 5f 62 62 5f .P...net_rim_bb_ 000000a0: 62 72 6f 77 73 65 72 5f 6d 61 6e 67 6f 2d 33 00 browser_mango-3. 000000b0: 00 01 63 4a 17 50 bd 00 1a 6e 65 74 5f 72 69 6d ..cJ.P...net_rim 000000c0: 5f 62 62 5f 62 72 6f 77 73 65 72 5f 6d 61 6e 67 _bb_browser_mang 000000d0: 6f 2d 35 00 00 01 64 4a 17 50 bd 00 1a 6e 65 74 o-5...dJ.P...net 000000e0: 5f 72 69 6d 5f 62 62 5f 62 72 6f 77 73 65 72 5f _rim_bb_browser_ 000000f0: 6d 61 6e 67 6f 2d 36 00 00 01 65 4a 17 4a 01 00 mango-6...eJ.J.. 00000100: 0b 6e 65 74 5f 72 69 6d 5f 74 69 64 00 00 01 66 .net_rim_tid...f 00000110: 4a 17 4a 01 00 0d 6e 65 74 5f 72 69 6d 5f 74 69 J.J...net_rim_ti 00000120: 64 2d 31 00 00 01 67 4a 17 4a 01 00 0d 6e 65 74 d-1...gJ.J...net 00000130: 5f 72 69 6d 5f 74 69 64 2d 33 00 00 01 68 4a 17 _rim_tid-3...hJ. 00000140: 4a 01 00 0d 6e 65 74 5f 72 69 6d 5f 74 69 64 2d J...net_rim_tid- 00000150: 32 00 00 01 69 4a 17 54 93 00 19 6e 65 74 5f 72 2...iJ.T...net_r 00000160: 69 6d 5f 62 62 5f 61 70 70 73 5f 66 72 61 6d 65 im_bb_apps_frame 00000170: 77 6f 72 6b 00 00 01 6a 4a 17 54 93 00 1b 6e 65 work...jJ.T...ne 00000180: 74 5f 72 69 6d 5f 62 62 5f 61 70 70 73 5f 66 72 t_rim_bb_apps_fr 00000190: 61 6d 65 77 6f 72 6b 2d 33 00 00 01 6b 4a 17 54 amework-3...kJ.T 000001a0: 93 00 1b 6e 65 74 5f 72 69 6d 5f 62 62 5f 61 70 ...net_rim_bb_ap 000001b0: 70 73 5f 66 72 61 6d 65 77 6f 72 6b 2d 34 00 00 ps_framework-4.. 000001c0: 01 6c 4a 17 54 93 00 1b 6e 65 74 5f 72 69 6d 5f .lJ.T...net_rim_ 000001d0: 62 62 5f 61 70 70 73 5f 66 72 61 6d 65 77 6f 72 bb_apps_framewor 000001e0: 6b 2d 35 00 00 01 6d 4a 17 54 93 00 1b 6e 65 74 k-5...mJ.T...net 000001f0: 5f 72 69 6d 5f 62 62 5f 61 70 70 73 5f 66 72 61 _rim_bb_apps_fra 00000200: 6d 65 77 6f 72 6b 2d 31 00 00 01 6e 4a 17 54 93 mework-1...nJ.T. 00000210: 00 1b 6e 65 74 5f 72 69 6d 5f 62 62 5f 61 70 70 ..net_rim_bb_app 00000220: 73 5f 66 72 61 6d 65 77 6f 72 6b 2d 32 00 00 01 s_framework-2... 00000230: 6f 4a 17 4b 03 00 14 6e 65 74 5f 72 69 6d 5f 62 oJ.K...net_rim_b 00000240: 62 5f 6d 65 73 73 61 67 69 6e 67 00 00 01 70 4a b_messaging...pJ 00000250: 17 4b 03 00 16 6e 65 74 5f 72 69 6d 5f 62 62 5f .K...net_rim_bb_ 00000260: 6d 65 73 73 61 67 69 6e 67 2d 31 00 00 01 71 4a messaging-1...qJ 00000270: 17 4a e8 00 11 6e 65 74 5f 72 69 6d 5f 62 62 5f .J...net_rim_bb_ 00000280: 73 65 61 72 63 68 00 00 01 72 4a 17 4a f7 00 16 search...rJ.J... 00000290: 6e 65 74 5f 72 69 6d 5f 62 62 5f 61 64 64 72 65 net_rim_bb_addre 000002a0: 73 73 62 6f 6f 6b 00 00 01 73 4a 17 4b 09 00 11 ssbook...sJ.K... 000002b0: 6e 65 74 5f 72 69 6d 5f 62 62 5f 6d 6f 64 65 6c net_rim_bb_model 000002c0: 73 00 00 01 74 4a 17 53 9f 00 15 6e 65 74 5f 72 s...tJ.S...net_r 000002d0: 69 6d 5f 73 65 72 69 61 6c 66 6f 72 6d 61 74 73 im_serialformats 000002e0: 00 00 01 75 4a 17 52 a2 00 10 6e 65 74 5f 72 69 ...uJ.R...net_ri 000002f0: 6d 5f 63 72 79 70 74 6f 5f 31 00 00 01 76 4a 17 m_crypto_1...vJ. 00000300: 52 a2 00 12 6e 65 74 5f 72 69 6d 5f 63 72 79 70 R...net_rim_cryp 00000310: 74 6f 5f 31 2d 31 00 00 01 77 4a 17 52 a2 00 12 to_1-1...wJ.R... 00000320: 6e 65 74 5f 72 69 6d 5f 63 72 79 70 74 6f 5f 31 net_rim_crypto_1 00000330: 2d 32 00 00 01 78 4a 17 52 a2 00 12 6e 65 74 5f -2...xJ.R...net_ 00000340: 72 69 6d 5f 63 72 79 70 74 6f 5f 31 2d 33 00 00 rim_crypto_1-3.. 00000350: 01 79 4a 17 53 ae 00 21 6e 65 74 5f 72 69 6d 5f .yJ.S..!net_rim_ 00000360: 62 62 5f 62 72 6f 77 73 65 72 5f 6e 69 6e 6a 61 bb_browser_ninja 00000370: 69 6e 74 65 72 66 61 63 65 00 00 01 7a 4a 17 53 interface...zJ.S 00000380: 9f 00 1c 6e 65 74 5f 72 69 6d 5f 62 62 5f 62 72 ...net_rim_bb_br 00000390: 6f 77 73 65 72 5f 66 69 65 6c 64 5f 61 70 69 00 owser_field_api. 000003a0: 00 01 7b 4a 17 49 f4 00 13 6e 65 74 5f 72 69 6d ..{J.I...net_rim 000003b0: 5f 6c 6f 63 61 74 69 6f 6e 61 70 69 00 00 01 7c _locationapi...| 000003c0: 4a 17 54 ff 00 20 6e 65 74 5f 72 69 6d 5f 62 62 J.T.. net_rim_bb 000003d0: 5f 62 72 6f 77 73 65 72 5f 72 65 6e 64 65 72 69 _browser_renderi 000003e0: 6e 67 5f 6c 69 62 00 00 01 7d ng_lib...} Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 108 00000000: 05 00 0b 00 00 05 8d 00 00 01 7d ..........} <<< URB 88 00000000: 00 00 0c 00 13 05 01 00 0e 00 00 00 ............ <<< URB 90 00000000: 05 00 06 00 03 de ...... <<< URB 91 00000000: 05 00 e2 03 00 00 00 1d 00 00 01 7d 4a 17 54 ff ...........}J.T. 00000010: 00 22 6e 65 74 5f 72 69 6d 5f 62 62 5f 62 72 6f ."net_rim_bb_bro 00000020: 77 73 65 72 5f 72 65 6e 64 65 72 69 6e 67 5f 6c wser_rendering_l 00000030: 69 62 2d 34 00 00 01 7e 4a 17 54 ff 00 22 6e 65 ib-4...~J.T.."ne 00000040: 74 5f 72 69 6d 5f 62 62 5f 62 72 6f 77 73 65 72 t_rim_bb_browser 00000050: 5f 72 65 6e 64 65 72 69 6e 67 5f 6c 69 62 2d 36 _rendering_lib-6 00000060: 00 00 01 7f 4a 17 54 ff 00 22 6e 65 74 5f 72 69 ....J.T.."net_ri 00000070: 6d 5f 62 62 5f 62 72 6f 77 73 65 72 5f 72 65 6e m_bb_browser_ren 00000080: 64 65 72 69 6e 67 5f 6c 69 62 2d 31 00 00 01 80 dering_lib-1.... 00000090: 4a 17 54 ff 00 22 6e 65 74 5f 72 69 6d 5f 62 62 J.T.."net_rim_bb 000000a0: 5f 62 72 6f 77 73 65 72 5f 72 65 6e 64 65 72 69 _browser_renderi 000000b0: 6e 67 5f 6c 69 62 2d 33 00 00 01 81 4a 17 54 ff ng_lib-3....J.T. 000000c0: 00 22 6e 65 74 5f 72 69 6d 5f 62 62 5f 62 72 6f ."net_rim_bb_bro 000000d0: 77 73 65 72 5f 72 65 6e 64 65 72 69 6e 67 5f 6c wser_rendering_l 000000e0: 69 62 2d 32 00 00 01 82 4a 17 54 ff 00 22 6e 65 ib-2....J.T.."ne 000000f0: 74 5f 72 69 6d 5f 62 62 5f 62 72 6f 77 73 65 72 t_rim_bb_browser 00000100: 5f 72 65 6e 64 65 72 69 6e 67 5f 6c 69 62 2d 35 _rendering_lib-5 00000110: 00 00 01 83 4a 17 54 ff 00 22 6e 65 74 5f 72 69 ....J.T.."net_ri 00000120: 6d 5f 62 62 5f 62 72 6f 77 73 65 72 5f 72 65 6e m_bb_browser_ren 00000130: 64 65 72 69 6e 67 5f 6c 69 62 2d 37 00 00 01 84 dering_lib-7.... 00000140: 4a 17 4a 72 00 0b 6e 65 74 5f 72 69 6d 5f 78 6d J.Jr..net_rim_xm 00000150: 6c 00 00 01 85 4a 17 4a fd 00 12 6e 65 74 5f 72 l....J.J...net_r 00000160: 69 6d 5f 62 62 5f 62 72 6f 77 73 65 72 00 00 01 im_bb_browser... 00000170: 86 4a 17 4b 0f 00 17 6e 65 74 5f 72 69 6d 5f 62 .J.K...net_rim_b 00000180: 62 5f 70 72 6f 66 69 6c 65 73 5f 6c 69 62 00 00 b_profiles_lib.. 00000190: 01 87 4a 17 4b 0f 00 19 6e 65 74 5f 72 69 6d 5f ..J.K...net_rim_ 000001a0: 62 62 5f 70 72 6f 66 69 6c 65 73 5f 6c 69 62 2d bb_profiles_lib- 000001b0: 31 00 00 01 88 4a 17 4b 09 00 16 6e 65 74 5f 72 1....J.K...net_r 000001c0: 69 6d 5f 62 62 5f 70 68 6f 6e 65 5f 6d 6f 64 65 im_bb_phone_mode 000001d0: 6c 00 00 01 89 4a 17 4a ec 00 19 6e 65 74 5f 72 l....J.J...net_r 000001e0: 69 6d 5f 62 62 5f 70 68 6f 6e 65 5f 72 65 73 6f im_bb_phone_reso 000001f0: 75 72 63 65 00 00 01 8a 4a 17 4a ec 00 1b 6e 65 urce....J.J...ne 00000200: 74 5f 72 69 6d 5f 62 62 5f 70 68 6f 6e 65 5f 72 t_rim_bb_phone_r 00000210: 65 73 6f 75 72 63 65 2d 31 00 00 01 8b 4a 17 4a esource-1....J.J 00000220: ec 00 1b 6e 65 74 5f 72 69 6d 5f 62 62 5f 70 68 ...net_rim_bb_ph 00000230: 6f 6e 65 5f 72 65 73 6f 75 72 63 65 2d 32 00 00 one_resource-2.. 00000240: 01 8c 4a 17 4b 00 00 17 6e 65 74 5f 72 69 6d 5f ..J.K...net_rim_ 00000250: 62 62 5f 71 75 69 63 6b 63 6f 6e 74 61 63 74 00 bb_quickcontact. 00000260: 00 01 8d 4a 17 4b 15 00 14 6e 65 74 5f 72 69 6d ...J.K...net_rim 00000270: 5f 62 62 5f 70 68 6f 6e 65 5f 61 70 69 00 00 01 _bb_phone_api... 00000280: 8e 4a 17 4b 15 00 16 6e 65 74 5f 72 69 6d 5f 62 .J.K...net_rim_b 00000290: 62 5f 70 68 6f 6e 65 5f 61 70 69 2d 31 00 00 01 b_phone_api-1... 000002a0: 8f 4a 17 4b 15 00 16 6e 65 74 5f 72 69 6d 5f 62 .J.K...net_rim_b 000002b0: 62 5f 70 68 6f 6e 65 5f 61 70 69 2d 34 00 00 01 b_phone_api-4... 000002c0: 90 4a 17 4b 15 00 16 6e 65 74 5f 72 69 6d 5f 62 .J.K...net_rim_b 000002d0: 62 5f 70 68 6f 6e 65 5f 61 70 69 2d 33 00 00 01 b_phone_api-3... 000002e0: 91 4a 17 4b 15 00 16 6e 65 74 5f 72 69 6d 5f 62 .J.K...net_rim_b 000002f0: 62 5f 70 68 6f 6e 65 5f 61 70 69 2d 32 00 00 01 b_phone_api-2... 00000300: 92 4a 17 55 88 00 0e 6e 65 74 5f 72 69 6d 5f 62 .J.U...net_rim_b 00000310: 62 5f 6c 62 73 00 00 01 93 4a 17 53 a6 00 12 6e b_lbs....J.S...n 00000320: 65 74 5f 72 69 6d 5f 62 62 5f 6c 62 73 5f 61 70 et_rim_bb_lbs_ap 00000330: 69 00 00 01 94 4a 17 4b 2c 00 11 6e 65 74 5f 72 i....J.K,..net_r 00000340: 69 6d 5f 62 6c 75 65 74 6f 6f 74 68 00 00 01 95 im_bluetooth.... 00000350: 4a 17 4b 2c 00 13 6e 65 74 5f 72 69 6d 5f 62 6c J.K,..net_rim_bl 00000360: 75 65 74 6f 6f 74 68 2d 31 00 00 01 96 4a 17 55 uetooth-1....J.U 00000370: 88 00 10 6e 65 74 5f 72 69 6d 5f 62 62 5f 6c 62 ...net_rim_bb_lb 00000380: 73 2d 39 00 00 01 97 4a 17 55 88 00 10 6e 65 74 s-9....J.U...net 00000390: 5f 72 69 6d 5f 62 62 5f 6c 62 73 2d 36 00 00 01 _rim_bb_lbs-6... 000003a0: 98 4a 17 54 e4 00 1d 6e 65 74 5f 72 69 6d 5f 62 .J.T...net_rim_b 000003b0: 62 5f 61 64 64 72 65 73 73 62 6f 6f 6b 5f 6d 6f b_addressbook_mo 000003c0: 64 65 6c 73 00 00 01 99 4a 17 55 88 00 10 6e 65 dels....J.U...ne 000003d0: 74 5f 72 69 6d 5f 62 62 5f 6c 62 73 2d 38 00 00 t_rim_bb_lbs-8.. 000003e0: 01 9a .. Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 112 00000000: 05 00 0b 00 00 05 8d 00 00 01 9a ........... <<< URB 92 00000000: 00 00 0c 00 13 05 01 00 0f 00 00 00 ............ <<< URB 94 00000000: 05 00 06 00 03 b6 ...... <<< URB 95 00000000: 05 00 ba 03 00 00 00 13 00 00 01 9a 4a 17 55 88 ............J.U. 00000010: 00 10 6e 65 74 5f 72 69 6d 5f 62 62 5f 6c 62 73 ..net_rim_bb_lbs 00000020: 2d 31 00 00 01 9b 4a 17 55 88 00 10 6e 65 74 5f -1....J.U...net_ 00000030: 72 69 6d 5f 62 62 5f 6c 62 73 2d 37 00 00 01 9c rim_bb_lbs-7.... 00000040: 4a 17 55 88 00 10 6e 65 74 5f 72 69 6d 5f 62 62 J.U...net_rim_bb 00000050: 5f 6c 62 73 2d 35 00 00 01 9d 4a 17 55 88 00 10 _lbs-5....J.U... 00000060: 6e 65 74 5f 72 69 6d 5f 62 62 5f 6c 62 73 2d 32 net_rim_bb_lbs-2 00000070: 00 00 01 9e 4a 17 55 88 00 10 6e 65 74 5f 72 69 ....J.U...net_ri 00000080: 6d 5f 62 62 5f 6c 62 73 2d 33 00 00 01 9f 4a 17 m_bb_lbs-3....J. 00000090: 55 88 00 10 6e 65 74 5f 72 69 6d 5f 62 62 5f 6c U...net_rim_bb_l 000000a0: 62 73 2d 34 00 00 01 a0 4a 17 53 a6 00 14 6e 65 bs-4....J.S...ne 000000b0: 74 5f 72 69 6d 5f 62 62 5f 6c 62 73 5f 61 70 69 t_rim_bb_lbs_api 000000c0: 5f 32 00 00 01 a1 4a 17 4f de 00 33 6e 65 74 5f _2....J.O..3net_ 000000d0: 72 69 6d 5f 64 65 76 69 63 65 5f 61 70 70 73 5f rim_device_apps_ 000000e0: 67 61 6d 65 73 5f 77 6f 72 64 6d 6f 6c 65 5f 67 games_wordmole_g 000000f0: 72 61 70 68 69 63 73 5f 74 68 75 6e 64 65 72 00 raphics_thunder. 00000100: 00 01 a2 4a 17 4f de 00 36 6e 65 74 5f 72 69 6d ...J.O..6net_rim 00000110: 5f 64 65 76 69 63 65 5f 61 70 70 73 5f 67 61 6d _device_apps_gam 00000120: 65 73 5f 77 6f 72 64 6d 6f 6c 65 5f 67 72 61 70 es_wordmole_grap 00000130: 68 69 63 73 5f 74 68 75 6e 64 65 72 2d 31 32 00 hics_thunder-12. 00000140: 00 01 a3 4a 17 4f de 00 35 6e 65 74 5f 72 69 6d ...J.O..5net_rim 00000150: 5f 64 65 76 69 63 65 5f 61 70 70 73 5f 67 61 6d _device_apps_gam 00000160: 65 73 5f 77 6f 72 64 6d 6f 6c 65 5f 67 72 61 70 es_wordmole_grap 00000170: 68 69 63 73 5f 74 68 75 6e 64 65 72 2d 31 00 00 hics_thunder-1.. 00000180: 01 a4 4a 17 4f de 00 35 6e 65 74 5f 72 69 6d 5f ..J.O..5net_rim_ 00000190: 64 65 76 69 63 65 5f 61 70 70 73 5f 67 61 6d 65 device_apps_game 000001a0: 73 5f 77 6f 72 64 6d 6f 6c 65 5f 67 72 61 70 68 s_wordmole_graph 000001b0: 69 63 73 5f 74 68 75 6e 64 65 72 2d 32 00 00 01 ics_thunder-2... 000001c0: a5 4a 17 4f de 00 35 6e 65 74 5f 72 69 6d 5f 64 .J.O..5net_rim_d 000001d0: 65 76 69 63 65 5f 61 70 70 73 5f 67 61 6d 65 73 evice_apps_games 000001e0: 5f 77 6f 72 64 6d 6f 6c 65 5f 67 72 61 70 68 69 _wordmole_graphi 000001f0: 63 73 5f 74 68 75 6e 64 65 72 2d 33 00 00 01 a6 cs_thunder-3.... 00000200: 4a 17 4f de 00 35 6e 65 74 5f 72 69 6d 5f 64 65 J.O..5net_rim_de 00000210: 76 69 63 65 5f 61 70 70 73 5f 67 61 6d 65 73 5f vice_apps_games_ 00000220: 77 6f 72 64 6d 6f 6c 65 5f 67 72 61 70 68 69 63 wordmole_graphic 00000230: 73 5f 74 68 75 6e 64 65 72 2d 34 00 00 01 a7 4a s_thunder-4....J 00000240: 17 4f de 00 35 6e 65 74 5f 72 69 6d 5f 64 65 76 .O..5net_rim_dev 00000250: 69 63 65 5f 61 70 70 73 5f 67 61 6d 65 73 5f 77 ice_apps_games_w 00000260: 6f 72 64 6d 6f 6c 65 5f 67 72 61 70 68 69 63 73 ordmole_graphics 00000270: 5f 74 68 75 6e 64 65 72 2d 35 00 00 01 a8 4a 17 _thunder-5....J. 00000280: 4f de 00 35 6e 65 74 5f 72 69 6d 5f 64 65 76 69 O..5net_rim_devi 00000290: 63 65 5f 61 70 70 73 5f 67 61 6d 65 73 5f 77 6f ce_apps_games_wo 000002a0: 72 64 6d 6f 6c 65 5f 67 72 61 70 68 69 63 73 5f rdmole_graphics_ 000002b0: 74 68 75 6e 64 65 72 2d 36 00 00 01 a9 4a 17 4f thunder-6....J.O 000002c0: de 00 35 6e 65 74 5f 72 69 6d 5f 64 65 76 69 63 ..5net_rim_devic 000002d0: 65 5f 61 70 70 73 5f 67 61 6d 65 73 5f 77 6f 72 e_apps_games_wor 000002e0: 64 6d 6f 6c 65 5f 67 72 61 70 68 69 63 73 5f 74 dmole_graphics_t 000002f0: 68 75 6e 64 65 72 2d 37 00 00 01 aa 4a 17 4f de hunder-7....J.O. 00000300: 00 35 6e 65 74 5f 72 69 6d 5f 64 65 76 69 63 65 .5net_rim_device 00000310: 5f 61 70 70 73 5f 67 61 6d 65 73 5f 77 6f 72 64 _apps_games_word 00000320: 6d 6f 6c 65 5f 67 72 61 70 68 69 63 73 5f 74 68 mole_graphics_th 00000330: 75 6e 64 65 72 2d 38 00 00 01 ab 4a 17 4f de 00 under-8....J.O.. 00000340: 35 6e 65 74 5f 72 69 6d 5f 64 65 76 69 63 65 5f 5net_rim_device_ 00000350: 61 70 70 73 5f 67 61 6d 65 73 5f 77 6f 72 64 6d apps_games_wordm 00000360: 6f 6c 65 5f 67 72 61 70 68 69 63 73 5f 74 68 75 ole_graphics_thu 00000370: 6e 64 65 72 2d 39 00 00 01 ac 4a 17 4f de 00 36 nder-9....J.O..6 00000380: 6e 65 74 5f 72 69 6d 5f 64 65 76 69 63 65 5f 61 net_rim_device_a 00000390: 70 70 73 5f 67 61 6d 65 73 5f 77 6f 72 64 6d 6f pps_games_wordmo 000003a0: 6c 65 5f 67 72 61 70 68 69 63 73 5f 74 68 75 6e le_graphics_thun 000003b0: 64 65 72 2d 31 30 00 00 01 ad der-10.... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 116 00000000: 05 00 0b 00 00 05 8d 00 00 01 ad ........... <<< URB 96 00000000: 00 00 0c 00 13 05 01 00 10 00 00 00 ............ <<< URB 98 00000000: 05 00 06 00 03 da ...... <<< URB 99 00000000: 05 00 de 03 00 00 00 1a 00 00 01 ad 4a 17 4f de ............J.O. 00000010: 00 36 6e 65 74 5f 72 69 6d 5f 64 65 76 69 63 65 .6net_rim_device 00000020: 5f 61 70 70 73 5f 67 61 6d 65 73 5f 77 6f 72 64 _apps_games_word 00000030: 6d 6f 6c 65 5f 67 72 61 70 68 69 63 73 5f 74 68 mole_graphics_th 00000040: 75 6e 64 65 72 2d 31 31 00 00 01 ae 4a 17 4a f7 under-11....J.J. 00000050: 00 1b 6e 65 74 5f 72 69 6d 5f 62 62 5f 76 69 72 ..net_rim_bb_vir 00000060: 74 75 61 6c 5f 6b 65 79 62 6f 61 72 64 00 00 01 tual_keyboard... 00000070: af 4a 17 4a f7 00 1d 6e 65 74 5f 72 69 6d 5f 62 .J.J...net_rim_b 00000080: 62 5f 76 69 72 74 75 61 6c 5f 6b 65 79 62 6f 61 b_virtual_keyboa 00000090: 72 64 2d 31 00 00 01 b0 4a 17 4a b4 00 23 6e 65 rd-1....J.J..#ne 000000a0: 74 5f 72 69 6d 5f 62 62 5f 76 69 72 74 75 61 6c t_rim_bb_virtual 000000b0: 5f 6b 65 79 62 6f 61 72 64 5f 6c 69 62 72 61 72 _keyboard_librar 000000c0: 79 00 00 01 b1 4a 17 4a b4 00 25 6e 65 74 5f 72 y....J.J..%net_r 000000d0: 69 6d 5f 62 62 5f 76 69 72 74 75 61 6c 5f 6b 65 im_bb_virtual_ke 000000e0: 79 62 6f 61 72 64 5f 6c 69 62 72 61 72 79 2d 31 yboard_library-1 000000f0: 00 00 01 b2 4a 17 4a b4 00 25 6e 65 74 5f 72 69 ....J.J..%net_ri 00000100: 6d 5f 62 62 5f 76 69 72 74 75 61 6c 5f 6b 65 79 m_bb_virtual_key 00000110: 62 6f 61 72 64 5f 6c 69 62 72 61 72 79 2d 32 00 board_library-2. 00000120: 00 01 b3 4a 17 4a 7a 00 0b 6e 65 74 5f 72 69 6d ...J.Jz..net_rim 00000130: 5f 6d 32 67 00 00 01 b4 4a 17 4a f7 00 1d 6e 65 _m2g....J.J...ne 00000140: 74 5f 72 69 6d 5f 62 62 5f 76 69 72 74 75 61 6c t_rim_bb_virtual 00000150: 5f 6b 65 79 62 6f 61 72 64 2d 33 00 00 01 b5 4a _keyboard-3....J 00000160: 17 4a f7 00 1e 6e 65 74 5f 72 69 6d 5f 62 62 5f .J...net_rim_bb_ 00000170: 76 69 72 74 75 61 6c 5f 6b 65 79 62 6f 61 72 64 virtual_keyboard 00000180: 2d 31 31 00 00 01 b6 4a 17 4a f7 00 1d 6e 65 74 -11....J.J...net 00000190: 5f 72 69 6d 5f 62 62 5f 76 69 72 74 75 61 6c 5f _rim_bb_virtual_ 000001a0: 6b 65 79 62 6f 61 72 64 2d 32 00 00 01 b7 4a 17 keyboard-2....J. 000001b0: 4a f7 00 1d 6e 65 74 5f 72 69 6d 5f 62 62 5f 76 J...net_rim_bb_v 000001c0: 69 72 74 75 61 6c 5f 6b 65 79 62 6f 61 72 64 2d irtual_keyboard- 000001d0: 34 00 00 01 b8 4a 17 4a f7 00 1d 6e 65 74 5f 72 4....J.J...net_r 000001e0: 69 6d 5f 62 62 5f 76 69 72 74 75 61 6c 5f 6b 65 im_bb_virtual_ke 000001f0: 79 62 6f 61 72 64 2d 35 00 00 01 b9 4a 17 4a f7 yboard-5....J.J. 00000200: 00 1d 6e 65 74 5f 72 69 6d 5f 62 62 5f 76 69 72 ..net_rim_bb_vir 00000210: 74 75 61 6c 5f 6b 65 79 62 6f 61 72 64 2d 36 00 tual_keyboard-6. 00000220: 00 01 ba 4a 17 4a f7 00 1d 6e 65 74 5f 72 69 6d ...J.J...net_rim 00000230: 5f 62 62 5f 76 69 72 74 75 61 6c 5f 6b 65 79 62 _bb_virtual_keyb 00000240: 6f 61 72 64 2d 37 00 00 01 bb 4a 17 4a f7 00 1d oard-7....J.J... 00000250: 6e 65 74 5f 72 69 6d 5f 62 62 5f 76 69 72 74 75 net_rim_bb_virtu 00000260: 61 6c 5f 6b 65 79 62 6f 61 72 64 2d 38 00 00 01 al_keyboard-8... 00000270: bc 4a 17 4a f7 00 1d 6e 65 74 5f 72 69 6d 5f 62 .J.J...net_rim_b 00000280: 62 5f 76 69 72 74 75 61 6c 5f 6b 65 79 62 6f 61 b_virtual_keyboa 00000290: 72 64 2d 39 00 00 01 bd 4a 17 4a f7 00 1e 6e 65 rd-9....J.J...ne 000002a0: 74 5f 72 69 6d 5f 62 62 5f 76 69 72 74 75 61 6c t_rim_bb_virtual 000002b0: 5f 6b 65 79 62 6f 61 72 64 2d 31 30 00 00 01 be _keyboard-10.... 000002c0: 4a 17 4a 77 00 0e 6e 65 74 5f 72 69 6d 5f 6a 61 J.Jw..net_rim_ja 000002d0: 78 72 70 63 00 00 01 bf 4a 17 55 26 00 16 6e 65 xrpc....J.U&..ne 000002e0: 74 5f 72 69 6d 5f 62 62 5f 62 72 6f 77 73 65 72 t_rim_bb_browser 000002f0: 5f 6c 69 62 00 00 01 c0 4a 17 55 26 00 18 6e 65 _lib....J.U&..ne 00000300: 74 5f 72 69 6d 5f 62 62 5f 62 72 6f 77 73 65 72 t_rim_bb_browser 00000310: 5f 6c 69 62 2d 32 00 00 01 c1 4a 17 55 26 00 18 _lib-2....J.U&.. 00000320: 6e 65 74 5f 72 69 6d 5f 62 62 5f 62 72 6f 77 73 net_rim_bb_brows 00000330: 65 72 5f 6c 69 62 2d 34 00 00 01 c2 4a 17 55 26 er_lib-4....J.U& 00000340: 00 18 6e 65 74 5f 72 69 6d 5f 62 62 5f 62 72 6f ..net_rim_bb_bro 00000350: 77 73 65 72 5f 6c 69 62 2d 33 00 00 01 c3 4a 17 wser_lib-3....J. 00000360: 55 26 00 18 6e 65 74 5f 72 69 6d 5f 62 62 5f 62 U&..net_rim_bb_b 00000370: 72 6f 77 73 65 72 5f 6c 69 62 2d 35 00 00 01 c4 rowser_lib-5.... 00000380: 4a 17 55 26 00 18 6e 65 74 5f 72 69 6d 5f 62 62 J.U&..net_rim_bb 00000390: 5f 62 72 6f 77 73 65 72 5f 6c 69 62 2d 36 00 00 _browser_lib-6.. 000003a0: 01 c5 4a 17 55 26 00 18 6e 65 74 5f 72 69 6d 5f ..J.U&..net_rim_ 000003b0: 62 62 5f 62 72 6f 77 73 65 72 5f 6c 69 62 2d 31 bb_browser_lib-1 000003c0: 00 00 01 c6 4a 17 54 f1 00 10 6e 65 74 5f 72 69 ....J.T...net_ri 000003d0: 6d 5f 62 62 5f 65 6d 61 69 6c 00 00 01 c7 m_bb_email.... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 120 00000000: 05 00 0b 00 00 05 8d 00 00 01 c7 ........... <<< URB 100 00000000: 00 00 0c 00 13 05 01 00 11 00 00 00 ............ <<< URB 102 00000000: 05 00 06 00 03 cd ...... <<< URB 103 00000000: 05 00 d1 03 00 00 00 1d 00 00 01 c7 4a 17 54 f1 ............J.T. 00000010: 00 12 6e 65 74 5f 72 69 6d 5f 62 62 5f 65 6d 61 ..net_rim_bb_ema 00000020: 69 6c 2d 31 00 00 01 c8 4a 17 54 f1 00 12 6e 65 il-1....J.T...ne 00000030: 74 5f 72 69 6d 5f 62 62 5f 65 6d 61 69 6c 2d 33 t_rim_bb_email-3 00000040: 00 00 01 c9 4a 17 54 f1 00 12 6e 65 74 5f 72 69 ....J.T...net_ri 00000050: 6d 5f 62 62 5f 65 6d 61 69 6c 2d 35 00 00 01 ca m_bb_email-5.... 00000060: 4a 17 54 f1 00 12 6e 65 74 5f 72 69 6d 5f 62 62 J.T...net_rim_bb 00000070: 5f 65 6d 61 69 6c 2d 34 00 00 01 cb 4a 17 54 f1 _email-4....J.T. 00000080: 00 12 6e 65 74 5f 72 69 6d 5f 62 62 5f 65 6d 61 ..net_rim_bb_ema 00000090: 69 6c 2d 32 00 00 01 cc 4a 17 4a fc 00 15 6e 65 il-2....J.J...ne 000000a0: 74 5f 72 69 6d 5f 62 62 5f 73 70 65 6c 6c 63 68 t_rim_bb_spellch 000000b0: 65 63 6b 00 00 01 cd 4a 17 54 ed 00 1a 6e 65 74 eck....J.T...net 000000c0: 5f 72 69 6d 5f 62 62 5f 61 64 64 72 65 73 73 62 _rim_bb_addressb 000000d0: 6f 6f 6b 5f 67 61 6c 00 00 01 ce 4a 17 4b 22 00 ook_gal....J.K". 000000e0: 0e 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 6d 73 00 .net_rim_bb_sms. 000000f0: 00 01 cf 4a 17 53 a3 00 1c 6e 65 74 5f 72 69 6d ...J.S...net_rim 00000100: 5f 62 62 5f 65 6d 61 69 6c 5f 63 6f 6d 70 72 65 _bb_email_compre 00000110: 73 73 69 6f 6e 00 00 01 d0 4a 17 52 78 00 1a 6e ssion....J.Rx..n 00000120: 65 74 5f 72 69 6d 5f 63 6c 64 63 5f 69 6f 5f 72 et_rim_cldc_io_r 00000130: 65 6d 6f 74 65 66 69 6c 65 00 00 01 d1 4a 17 55 emotefile....J.U 00000140: 21 00 14 6e 65 74 5f 72 69 6d 5f 62 62 61 70 69 !..net_rim_bbapi 00000150: 5f 6d 61 69 6c 76 32 00 00 01 d2 4a 17 54 fe 00 _mailv2....J.T.. 00000160: 15 6e 65 74 5f 72 69 6d 5f 62 62 5f 61 74 74 61 .net_rim_bb_atta 00000170: 63 68 6d 65 6e 74 00 00 01 d3 4a 17 53 ae 00 17 chment....J.S... 00000180: 6e 65 74 5f 72 69 6d 5f 62 62 5f 62 72 6f 77 73 net_rim_bb_brows 00000190: 65 72 5f 70 75 73 68 00 00 01 d4 4a 17 53 03 00 er_push....J.S.. 000001a0: 10 6e 65 74 5f 72 69 6d 5f 63 72 79 70 74 6f 5f .net_rim_crypto_ 000001b0: 32 00 00 01 d5 4a 17 52 a2 00 11 6e 65 74 5f 72 2....J.R...net_r 000001c0: 69 6d 5f 73 6d 61 72 74 63 61 72 64 00 00 01 d6 im_smartcard.... 000001d0: 4a 17 53 03 00 12 6e 65 74 5f 72 69 6d 5f 63 72 J.S...net_rim_cr 000001e0: 79 70 74 6f 5f 32 2d 32 00 00 01 d7 4a 17 53 03 ypto_2-2....J.S. 000001f0: 00 12 6e 65 74 5f 72 69 6d 5f 63 72 79 70 74 6f ..net_rim_crypto 00000200: 5f 32 2d 31 00 00 01 d8 4a 17 49 ef 00 0f 6e 65 _2-1....J.I...ne 00000210: 74 5f 72 69 6d 5f 65 73 63 72 65 65 6e 00 00 01 t_rim_escreen... 00000220: d9 4a 17 55 6d 00 19 6e 65 74 5f 72 69 6d 5f 62 .J.Um..net_rim_b 00000230: 62 5f 73 62 69 6e 6a 65 63 74 6f 72 5f 6c 69 62 b_sbinjector_lib 00000240: 00 00 01 da 4a 17 55 6d 00 1b 6e 65 74 5f 72 69 ....J.Um..net_ri 00000250: 6d 5f 62 62 5f 73 62 69 6e 6a 65 63 74 6f 72 5f m_bb_sbinjector_ 00000260: 6c 69 62 2d 31 00 00 01 db 4a 17 55 6d 00 1b 6e lib-1....J.Um..n 00000270: 65 74 5f 72 69 6d 5f 62 62 5f 73 62 69 6e 6a 65 et_rim_bb_sbinje 00000280: 63 74 6f 72 5f 6c 69 62 2d 32 00 00 01 dc 4a 17 ctor_lib-2....J. 00000290: 55 6d 00 1b 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 Um..net_rim_bb_s 000002a0: 62 69 6e 6a 65 63 74 6f 72 5f 6c 69 62 2d 33 00 binjector_lib-3. 000002b0: 00 01 dd 4a 17 55 6d 00 1b 6e 65 74 5f 72 69 6d ...J.Um..net_rim 000002c0: 5f 62 62 5f 73 62 69 6e 6a 65 63 74 6f 72 5f 6c _bb_sbinjector_l 000002d0: 69 62 2d 34 00 00 01 de 4a 17 55 6d 00 1b 6e 65 ib-4....J.Um..ne 000002e0: 74 5f 72 69 6d 5f 62 62 5f 73 62 69 6e 6a 65 63 t_rim_bb_sbinjec 000002f0: 74 6f 72 5f 6c 69 62 2d 35 00 00 01 df 4a 17 55 tor_lib-5....J.U 00000300: 6d 00 1b 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 62 m..net_rim_bb_sb 00000310: 69 6e 6a 65 63 74 6f 72 5f 6c 69 62 2d 36 00 00 injector_lib-6.. 00000320: 01 e0 4a 17 55 6d 00 1b 6e 65 74 5f 72 69 6d 5f ..J.Um..net_rim_ 00000330: 62 62 5f 73 62 69 6e 6a 65 63 74 6f 72 5f 6c 69 bb_sbinjector_li 00000340: 62 2d 37 00 00 01 e1 4a 17 55 6d 00 1b 6e 65 74 b-7....J.Um..net 00000350: 5f 72 69 6d 5f 62 62 5f 73 62 69 6e 6a 65 63 74 _rim_bb_sbinject 00000360: 6f 72 5f 6c 69 62 2d 38 00 00 01 e2 4a 17 55 6d or_lib-8....J.Um 00000370: 00 1b 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 62 69 ..net_rim_bb_sbi 00000380: 6e 6a 65 63 74 6f 72 5f 6c 69 62 2d 39 00 00 01 njector_lib-9... 00000390: e3 4a 17 4f cd 00 36 6e 65 74 5f 72 69 6d 5f 64 .J.O..6net_rim_d 000003a0: 65 76 69 63 65 5f 61 70 70 73 5f 67 61 6d 65 73 evice_apps_games 000003b0: 5f 62 72 69 63 6b 62 72 65 61 6b 65 72 33 36 30 _brickbreaker360 000003c0: 78 34 38 30 52 65 73 6f 75 72 63 65 73 00 00 01 x480Resources... 000003d0: e4 . Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 124 00000000: 05 00 0b 00 00 05 8d 00 00 01 e4 ........... <<< URB 104 00000000: 00 00 0c 00 13 05 01 00 12 00 00 00 ............ <<< URB 106 00000000: 05 00 06 00 03 e2 ...... <<< URB 107 00000000: 05 00 e6 03 00 00 00 12 00 00 01 e4 4a 17 4f cd ............J.O. 00000010: 00 38 6e 65 74 5f 72 69 6d 5f 64 65 76 69 63 65 .8net_rim_device 00000020: 5f 61 70 70 73 5f 67 61 6d 65 73 5f 62 72 69 63 _apps_games_bric 00000030: 6b 62 72 65 61 6b 65 72 33 36 30 78 34 38 30 52 kbreaker360x480R 00000040: 65 73 6f 75 72 63 65 73 2d 38 00 00 01 e5 4a 17 esources-8....J. 00000050: 4f cd 00 38 6e 65 74 5f 72 69 6d 5f 64 65 76 69 O..8net_rim_devi 00000060: 63 65 5f 61 70 70 73 5f 67 61 6d 65 73 5f 62 72 ce_apps_games_br 00000070: 69 63 6b 62 72 65 61 6b 65 72 33 36 30 78 34 38 ickbreaker360x48 00000080: 30 52 65 73 6f 75 72 63 65 73 2d 31 00 00 01 e6 0Resources-1.... 00000090: 4a 17 4f cd 00 38 6e 65 74 5f 72 69 6d 5f 64 65 J.O..8net_rim_de 000000a0: 76 69 63 65 5f 61 70 70 73 5f 67 61 6d 65 73 5f vice_apps_games_ 000000b0: 62 72 69 63 6b 62 72 65 61 6b 65 72 33 36 30 78 brickbreaker360x 000000c0: 34 38 30 52 65 73 6f 75 72 63 65 73 2d 32 00 00 480Resources-2.. 000000d0: 01 e7 4a 17 4f cd 00 38 6e 65 74 5f 72 69 6d 5f ..J.O..8net_rim_ 000000e0: 64 65 76 69 63 65 5f 61 70 70 73 5f 67 61 6d 65 device_apps_game 000000f0: 73 5f 62 72 69 63 6b 62 72 65 61 6b 65 72 33 36 s_brickbreaker36 00000100: 30 78 34 38 30 52 65 73 6f 75 72 63 65 73 2d 33 0x480Resources-3 00000110: 00 00 01 e8 4a 17 4f cd 00 38 6e 65 74 5f 72 69 ....J.O..8net_ri 00000120: 6d 5f 64 65 76 69 63 65 5f 61 70 70 73 5f 67 61 m_device_apps_ga 00000130: 6d 65 73 5f 62 72 69 63 6b 62 72 65 61 6b 65 72 mes_brickbreaker 00000140: 33 36 30 78 34 38 30 52 65 73 6f 75 72 63 65 73 360x480Resources 00000150: 2d 34 00 00 01 e9 4a 17 4f cd 00 38 6e 65 74 5f -4....J.O..8net_ 00000160: 72 69 6d 5f 64 65 76 69 63 65 5f 61 70 70 73 5f rim_device_apps_ 00000170: 67 61 6d 65 73 5f 62 72 69 63 6b 62 72 65 61 6b games_brickbreak 00000180: 65 72 33 36 30 78 34 38 30 52 65 73 6f 75 72 63 er360x480Resourc 00000190: 65 73 2d 35 00 00 01 ea 4a 17 4f cd 00 38 6e 65 es-5....J.O..8ne 000001a0: 74 5f 72 69 6d 5f 64 65 76 69 63 65 5f 61 70 70 t_rim_device_app 000001b0: 73 5f 67 61 6d 65 73 5f 62 72 69 63 6b 62 72 65 s_games_brickbre 000001c0: 61 6b 65 72 33 36 30 78 34 38 30 52 65 73 6f 75 aker360x480Resou 000001d0: 72 63 65 73 2d 36 00 00 01 eb 4a 17 4f cd 00 38 rces-6....J.O..8 000001e0: 6e 65 74 5f 72 69 6d 5f 64 65 76 69 63 65 5f 61 net_rim_device_a 000001f0: 70 70 73 5f 67 61 6d 65 73 5f 62 72 69 63 6b 62 pps_games_brickb 00000200: 72 65 61 6b 65 72 33 36 30 78 34 38 30 52 65 73 reaker360x480Res 00000210: 6f 75 72 63 65 73 2d 37 00 00 01 ec 4a 17 54 b3 ources-7....J.T. 00000220: 00 22 6e 65 74 5f 72 69 6d 5f 76 61 64 5f 65 6e ."net_rim_vad_en 00000230: 67 69 6e 65 5f 72 65 73 6f 75 72 63 65 5f 5f 65 gine_resource__e 00000240: 6e 5f 55 53 00 00 01 ed 4a 17 54 b3 00 24 6e 65 n_US....J.T..$ne 00000250: 74 5f 72 69 6d 5f 76 61 64 5f 65 6e 67 69 6e 65 t_rim_vad_engine 00000260: 5f 72 65 73 6f 75 72 63 65 5f 5f 65 6e 5f 55 53 _resource__en_US 00000270: 2d 31 00 00 01 ee 4a 17 54 b3 00 24 6e 65 74 5f -1....J.T..$net_ 00000280: 72 69 6d 5f 76 61 64 5f 65 6e 67 69 6e 65 5f 72 rim_vad_engine_r 00000290: 65 73 6f 75 72 63 65 5f 5f 65 6e 5f 55 53 2d 32 esource__en_US-2 000002a0: 00 00 01 ef 4a 17 54 b3 00 24 6e 65 74 5f 72 69 ....J.T..$net_ri 000002b0: 6d 5f 76 61 64 5f 65 6e 67 69 6e 65 5f 72 65 73 m_vad_engine_res 000002c0: 6f 75 72 63 65 5f 5f 65 6e 5f 55 53 2d 33 00 00 ource__en_US-3.. 000002d0: 01 f0 4a 17 54 b3 00 24 6e 65 74 5f 72 69 6d 5f ..J.T..$net_rim_ 000002e0: 76 61 64 5f 65 6e 67 69 6e 65 5f 72 65 73 6f 75 vad_engine_resou 000002f0: 72 63 65 5f 5f 65 6e 5f 55 53 2d 34 00 00 01 f1 rce__en_US-4.... 00000300: 4a 17 54 b3 00 24 6e 65 74 5f 72 69 6d 5f 76 61 J.T..$net_rim_va 00000310: 64 5f 65 6e 67 69 6e 65 5f 72 65 73 6f 75 72 63 d_engine_resourc 00000320: 65 5f 5f 65 6e 5f 55 53 2d 35 00 00 01 f2 4a 17 e__en_US-5....J. 00000330: 54 b3 00 24 6e 65 74 5f 72 69 6d 5f 76 61 64 5f T..$net_rim_vad_ 00000340: 65 6e 67 69 6e 65 5f 72 65 73 6f 75 72 63 65 5f engine_resource_ 00000350: 5f 65 6e 5f 55 53 2d 36 00 00 01 f3 4a 17 54 b3 _en_US-6....J.T. 00000360: 00 24 6e 65 74 5f 72 69 6d 5f 76 61 64 5f 65 6e .$net_rim_vad_en 00000370: 67 69 6e 65 5f 72 65 73 6f 75 72 63 65 5f 5f 65 gine_resource__e 00000380: 6e 5f 55 53 2d 37 00 00 01 f4 4a 17 54 b3 00 24 n_US-7....J.T..$ 00000390: 6e 65 74 5f 72 69 6d 5f 76 61 64 5f 65 6e 67 69 net_rim_vad_engi 000003a0: 6e 65 5f 72 65 73 6f 75 72 63 65 5f 5f 65 6e 5f ne_resource__en_ 000003b0: 55 53 2d 38 00 00 01 f5 4a 17 54 b3 00 24 6e 65 US-8....J.T..$ne 000003c0: 74 5f 72 69 6d 5f 76 61 64 5f 65 6e 67 69 6e 65 t_rim_vad_engine 000003d0: 5f 72 65 73 6f 75 72 63 65 5f 5f 65 6e 5f 55 53 _resource__en_US 000003e0: 2d 39 00 00 01 f6 -9.... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 128 00000000: 05 00 0b 00 00 05 8d 00 00 01 f6 ........... <<< URB 108 00000000: 00 00 0c 00 13 05 01 00 13 00 00 00 ............ <<< URB 110 00000000: 05 00 06 00 03 e4 ...... <<< URB 111 00000000: 05 00 e8 03 00 00 00 1b 00 00 01 f6 4a 17 53 6f ............J.So 00000010: 00 2a 6e 65 74 5f 72 69 6d 5f 74 69 64 5f 64 79 .*net_rim_tid_dy 00000020: 6e 61 6d 69 63 5f 6c 69 6e 67 5f 64 61 74 61 5f namic_ling_data_ 00000030: 66 72 65 6e 63 68 5f 34 35 6b 5f 32 00 00 01 f7 french_45k_2.... 00000040: 4a 17 53 6f 00 2c 6e 65 74 5f 72 69 6d 5f 74 69 J.So.,net_rim_ti 00000050: 64 5f 64 79 6e 61 6d 69 63 5f 6c 69 6e 67 5f 64 d_dynamic_ling_d 00000060: 61 74 61 5f 66 72 65 6e 63 68 5f 34 35 6b 5f 32 ata_french_45k_2 00000070: 2d 36 00 00 01 f8 4a 17 52 cf 00 18 6e 65 74 5f -6....J.R...net_ 00000080: 72 69 6d 5f 74 69 64 5f 69 6d 5f 61 6c 70 68 5f rim_tid_im_alph_ 00000090: 63 6f 72 65 00 00 01 f9 4a 17 52 13 00 10 6e 65 core....J.R...ne 000000a0: 74 5f 72 69 6d 5f 74 69 64 5f 63 6f 72 65 00 00 t_rim_tid_core.. 000000b0: 01 fa 4a 17 53 3c 00 2a 6e 65 74 5f 72 69 6d 5f ..J.S<.*net_rim_ 000000c0: 74 69 64 5f 64 79 6e 61 6d 69 63 5f 6c 69 6e 67 tid_dynamic_ling 000000d0: 5f 64 61 74 61 5f 64 6f 6d 61 69 6e 5f 6e 61 6d _data_domain_nam 000000e0: 65 73 00 00 01 fb 4a 17 53 6f 00 2c 6e 65 74 5f es....J.So.,net_ 000000f0: 72 69 6d 5f 74 69 64 5f 64 79 6e 61 6d 69 63 5f rim_tid_dynamic_ 00000100: 6c 69 6e 67 5f 64 61 74 61 5f 66 72 65 6e 63 68 ling_data_french 00000110: 5f 34 35 6b 5f 32 2d 31 00 00 01 fc 4a 17 53 6f _45k_2-1....J.So 00000120: 00 2c 6e 65 74 5f 72 69 6d 5f 74 69 64 5f 64 79 .,net_rim_tid_dy 00000130: 6e 61 6d 69 63 5f 6c 69 6e 67 5f 64 61 74 61 5f namic_ling_data_ 00000140: 66 72 65 6e 63 68 5f 34 35 6b 5f 32 2d 32 00 00 french_45k_2-2.. 00000150: 01 fd 4a 17 53 6f 00 2c 6e 65 74 5f 72 69 6d 5f ..J.So.,net_rim_ 00000160: 74 69 64 5f 64 79 6e 61 6d 69 63 5f 6c 69 6e 67 tid_dynamic_ling 00000170: 5f 64 61 74 61 5f 66 72 65 6e 63 68 5f 34 35 6b _data_french_45k 00000180: 5f 32 2d 33 00 00 01 fe 4a 17 53 6f 00 2c 6e 65 _2-3....J.So.,ne 00000190: 74 5f 72 69 6d 5f 74 69 64 5f 64 79 6e 61 6d 69 t_rim_tid_dynami 000001a0: 63 5f 6c 69 6e 67 5f 64 61 74 61 5f 66 72 65 6e c_ling_data_fren 000001b0: 63 68 5f 34 35 6b 5f 32 2d 34 00 00 01 ff 4a 17 ch_45k_2-4....J. 000001c0: 53 6f 00 2c 6e 65 74 5f 72 69 6d 5f 74 69 64 5f So.,net_rim_tid_ 000001d0: 64 79 6e 61 6d 69 63 5f 6c 69 6e 67 5f 64 61 74 dynamic_ling_dat 000001e0: 61 5f 66 72 65 6e 63 68 5f 34 35 6b 5f 32 2d 35 a_french_45k_2-5 000001f0: 00 00 02 00 49 f2 29 ce 00 12 6e 65 74 5f 72 69 ....I.)...net_ri 00000200: 6d 5f 62 62 5f 71 6d 5f 70 65 65 72 00 00 02 01 m_bb_qm_peer.... 00000210: 49 f2 29 ce 00 14 6e 65 74 5f 72 69 6d 5f 62 62 I.)...net_rim_bb 00000220: 5f 71 6d 5f 70 65 65 72 2d 32 00 00 02 02 49 f2 _qm_peer-2....I. 00000230: 29 ce 00 14 6e 65 74 5f 72 69 6d 5f 62 62 5f 71 )...net_rim_bb_q 00000240: 6d 5f 70 65 65 72 2d 31 00 00 02 03 49 f2 29 ce m_peer-1....I.). 00000250: 00 14 6e 65 74 5f 72 69 6d 5f 62 62 5f 71 6d 5f ..net_rim_bb_qm_ 00000260: 70 65 65 72 2d 34 00 00 02 04 49 f2 29 ce 00 14 peer-4....I.)... 00000270: 6e 65 74 5f 72 69 6d 5f 62 62 5f 71 6d 5f 70 65 net_rim_bb_qm_pe 00000280: 65 72 2d 33 00 00 02 05 4a 17 55 9c 00 21 6e 65 er-3....J.U..!ne 00000290: 74 5f 72 69 6d 5f 62 62 61 70 69 5f 62 6c 61 63 t_rim_bbapi_blac 000002a0: 6b 62 65 72 72 79 6d 65 73 73 65 6e 67 65 72 00 kberrymessenger. 000002b0: 00 02 06 4a 17 55 6e 00 0c 6e 65 74 5f 72 69 6d ...J.Un..net_rim 000002c0: 5f 70 64 61 70 00 00 02 07 4a 17 55 6e 00 0e 6e _pdap....J.Un..n 000002d0: 65 74 5f 72 69 6d 5f 70 64 61 70 2d 31 00 00 02 et_rim_pdap-1... 000002e0: 08 4a 17 53 a4 00 16 6e 65 74 5f 72 69 6d 5f 70 .J.S...net_rim_p 000002f0: 64 61 70 5f 72 65 73 6f 75 72 63 65 73 00 00 02 dap_resources... 00000300: 09 49 f2 29 ce 00 14 6e 65 74 5f 72 69 6d 5f 62 .I.)...net_rim_b 00000310: 62 5f 71 6d 5f 70 65 65 72 2d 35 00 00 02 0a 4a b_qm_peer-5....J 00000320: 17 53 ac 00 12 6e 65 74 5f 72 69 6d 5f 62 62 61 .S...net_rim_bba 00000330: 70 69 5f 6d 61 70 73 00 00 02 0b 4a 17 55 a5 00 pi_maps....J.U.. 00000340: 14 6e 65 74 5f 72 69 6d 5f 62 62 61 70 69 5f 69 .net_rim_bbapi_i 00000350: 6e 76 6f 6b 65 00 00 02 0c 4a 17 55 1b 00 16 6e nvoke....J.U...n 00000360: 65 74 5f 72 69 6d 5f 62 62 5f 73 6d 73 5f 63 6f et_rim_bb_sms_co 00000370: 6d 70 6f 73 65 00 00 02 0d 4a 17 55 70 00 0e 6e mpose....J.Up..n 00000380: 65 74 5f 72 69 6d 5f 62 62 5f 6d 6d 73 00 00 02 et_rim_bb_mms... 00000390: 0e 4a 17 55 70 00 10 6e 65 74 5f 72 69 6d 5f 62 .J.Up..net_rim_b 000003a0: 62 5f 6d 6d 73 2d 31 00 00 02 0f 4a 17 55 70 00 b_mms-1....J.Up. 000003b0: 10 6e 65 74 5f 72 69 6d 5f 62 62 5f 6d 6d 73 2d .net_rim_bb_mms- 000003c0: 32 00 00 02 10 4a 17 51 8a 00 19 6e 65 74 5f 72 2....J.Q...net_r 000003d0: 69 6d 5f 62 62 5f 62 72 6f 77 73 65 72 5f 64 61 im_bb_browser_da 000003e0: 65 6d 6f 6e 00 00 02 11 emon.... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 132 00000000: 05 00 0b 00 00 05 8d 00 00 02 11 ........... <<< URB 112 00000000: 00 00 0c 00 13 05 01 00 14 00 00 00 ............ <<< URB 114 00000000: 05 00 06 00 03 ef ...... <<< URB 115 00000000: 05 00 f3 03 00 00 00 1b 00 00 02 11 4a 17 51 8a ............J.Q. 00000010: 00 1b 6e 65 74 5f 72 69 6d 5f 62 62 5f 62 72 6f ..net_rim_bb_bro 00000020: 77 73 65 72 5f 64 61 65 6d 6f 6e 2d 33 00 00 02 wser_daemon-3... 00000030: 12 4a 17 51 8a 00 1b 6e 65 74 5f 72 69 6d 5f 62 .J.Q...net_rim_b 00000040: 62 5f 62 72 6f 77 73 65 72 5f 64 61 65 6d 6f 6e b_browser_daemon 00000050: 2d 34 00 00 02 13 4a 17 51 8a 00 1b 6e 65 74 5f -4....J.Q...net_ 00000060: 72 69 6d 5f 62 62 5f 62 72 6f 77 73 65 72 5f 64 rim_bb_browser_d 00000070: 61 65 6d 6f 6e 2d 35 00 00 02 14 4a 17 4b 5f 00 aemon-5....J.K_. 00000080: 0e 6e 65 74 5f 72 69 6d 5f 6c 6f 61 64 65 72 00 .net_rim_loader. 00000090: 00 02 15 4a 17 4b 5f 00 10 6e 65 74 5f 72 69 6d ...J.K_..net_rim 000000a0: 5f 6c 6f 61 64 65 72 2d 31 00 00 02 16 4a 17 55 _loader-1....J.U 000000b0: 7b 00 14 6e 65 74 5f 72 69 6d 5f 62 62 5f 64 72 {..net_rim_bb_dr 000000c0: 6d 5f 61 67 65 6e 74 00 00 02 17 4a 17 49 ee 00 m_agent....J.I.. 000000d0: 0b 6e 65 74 5f 72 69 6d 5f 64 72 6d 00 00 02 18 .net_rim_drm.... 000000e0: 4a 17 55 15 00 17 6e 65 74 5f 72 69 6d 5f 62 62 J.U...net_rim_bb 000000f0: 5f 6d 65 64 69 61 6c 69 62 72 61 72 79 00 00 02 _medialibrary... 00000100: 19 4a 17 55 15 00 19 6e 65 74 5f 72 69 6d 5f 62 .J.U...net_rim_b 00000110: 62 5f 6d 65 64 69 61 6c 69 62 72 61 72 79 2d 31 b_medialibrary-1 00000120: 00 00 02 1a 4a 17 4a 7b 00 21 6e 65 74 5f 72 69 ....J.J{.!net_ri 00000130: 6d 5f 70 6c 61 7a 6d 69 63 5f 6d 65 64 69 61 65 m_plazmic_mediae 00000140: 6e 67 69 6e 65 5f 70 6d 65 31 32 00 00 02 1b 4a ngine_pme12....J 00000150: 17 4a 7b 00 23 6e 65 74 5f 72 69 6d 5f 70 6c 61 .J{.#net_rim_pla 00000160: 7a 6d 69 63 5f 6d 65 64 69 61 65 6e 67 69 6e 65 zmic_mediaengine 00000170: 5f 70 6d 65 31 32 2d 31 00 00 02 1c 4a 17 4a 7b _pme12-1....J.J{ 00000180: 00 23 6e 65 74 5f 72 69 6d 5f 70 6c 61 7a 6d 69 .#net_rim_plazmi 00000190: 63 5f 6d 65 64 69 61 65 6e 67 69 6e 65 5f 70 6d c_mediaengine_pm 000001a0: 65 31 32 2d 32 00 00 02 1d 4a 17 4a 72 00 22 6e e12-2....J.Jr."n 000001b0: 65 74 5f 72 69 6d 5f 70 6c 61 7a 6d 69 63 5f 6d et_rim_plazmic_m 000001c0: 65 64 69 61 65 6e 67 69 6e 65 5f 62 75 6e 64 6c ediaengine_bundl 000001d0: 65 00 00 02 1e 4a 17 49 f7 00 14 6e 65 74 5f 72 e....J.I...net_r 000001e0: 69 6d 5f 70 6c 61 7a 6d 69 63 5f 6d 61 74 68 00 im_plazmic_math. 000001f0: 00 02 1f 4a 17 51 8a 00 1b 6e 65 74 5f 72 69 6d ...J.Q...net_rim 00000200: 5f 62 62 5f 62 72 6f 77 73 65 72 5f 64 61 65 6d _bb_browser_daem 00000210: 6f 6e 2d 31 00 00 02 20 4a 17 51 8a 00 1b 6e 65 on-1... J.Q...ne 00000220: 74 5f 72 69 6d 5f 62 62 5f 62 72 6f 77 73 65 72 t_rim_bb_browser 00000230: 5f 64 61 65 6d 6f 6e 2d 32 00 00 02 21 4a 17 55 _daemon-2...!J.U 00000240: 15 00 12 6e 65 74 5f 72 69 6d 5f 62 62 5f 64 6f ...net_rim_bb_do 00000250: 63 76 69 65 77 00 00 02 22 4a 17 55 15 00 14 6e cview..."J.U...n 00000260: 65 74 5f 72 69 6d 5f 62 62 5f 64 6f 63 76 69 65 et_rim_bb_docvie 00000270: 77 2d 31 00 00 02 23 4a 17 55 15 00 14 6e 65 74 w-1...#J.U...net 00000280: 5f 72 69 6d 5f 62 62 5f 64 6f 63 76 69 65 77 2d _rim_bb_docview- 00000290: 32 00 00 02 24 4a 17 55 15 00 14 6e 65 74 5f 72 2...$J.U...net_r 000002a0: 69 6d 5f 62 62 5f 64 6f 63 76 69 65 77 2d 33 00 im_bb_docview-3. 000002b0: 00 02 25 4a 17 54 bb 00 22 6e 65 74 5f 72 69 6d ..%J.T.."net_rim 000002c0: 5f 76 61 64 5f 65 6e 67 69 6e 65 5f 72 65 73 6f _vad_engine_reso 000002d0: 75 72 63 65 5f 5f 66 72 5f 43 41 00 00 02 26 4a urce__fr_CA...&J 000002e0: 17 54 bb 00 24 6e 65 74 5f 72 69 6d 5f 76 61 64 .T..$net_rim_vad 000002f0: 5f 65 6e 67 69 6e 65 5f 72 65 73 6f 75 72 63 65 _engine_resource 00000300: 5f 5f 66 72 5f 43 41 2d 31 00 00 02 27 4a 17 54 __fr_CA-1...'J.T 00000310: bb 00 24 6e 65 74 5f 72 69 6d 5f 76 61 64 5f 65 ..$net_rim_vad_e 00000320: 6e 67 69 6e 65 5f 72 65 73 6f 75 72 63 65 5f 5f ngine_resource__ 00000330: 66 72 5f 43 41 2d 32 00 00 02 28 4a 17 54 bb 00 fr_CA-2...(J.T.. 00000340: 24 6e 65 74 5f 72 69 6d 5f 76 61 64 5f 65 6e 67 $net_rim_vad_eng 00000350: 69 6e 65 5f 72 65 73 6f 75 72 63 65 5f 5f 66 72 ine_resource__fr 00000360: 5f 43 41 2d 33 00 00 02 29 4a 17 54 bb 00 24 6e _CA-3...)J.T..$n 00000370: 65 74 5f 72 69 6d 5f 76 61 64 5f 65 6e 67 69 6e et_rim_vad_engin 00000380: 65 5f 72 65 73 6f 75 72 63 65 5f 5f 66 72 5f 43 e_resource__fr_C 00000390: 41 2d 34 00 00 02 2a 4a 17 54 bb 00 24 6e 65 74 A-4...*J.T..$net 000003a0: 5f 72 69 6d 5f 76 61 64 5f 65 6e 67 69 6e 65 5f _rim_vad_engine_ 000003b0: 72 65 73 6f 75 72 63 65 5f 5f 66 72 5f 43 41 2d resource__fr_CA- 000003c0: 35 00 00 02 2b 4a 17 54 bb 00 24 6e 65 74 5f 72 5...+J.T..$net_r 000003d0: 69 6d 5f 76 61 64 5f 65 6e 67 69 6e 65 5f 72 65 im_vad_engine_re 000003e0: 73 6f 75 72 63 65 5f 5f 66 72 5f 43 41 2d 36 00 source__fr_CA-6. 000003f0: 00 02 2c .., Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 136 00000000: 05 00 0b 00 00 05 8d 00 00 02 2c .........., <<< URB 116 00000000: 00 00 0c 00 13 05 01 00 15 00 00 00 ............ <<< URB 118 00000000: 05 00 06 00 03 f0 ...... <<< URB 119 00000000: 05 00 f4 03 00 00 00 1b 00 00 02 2c 4a 17 54 bb ...........,J.T. 00000010: 00 24 6e 65 74 5f 72 69 6d 5f 76 61 64 5f 65 6e .$net_rim_vad_en 00000020: 67 69 6e 65 5f 72 65 73 6f 75 72 63 65 5f 5f 66 gine_resource__f 00000030: 72 5f 43 41 2d 37 00 00 02 2d 4a 17 54 b9 00 1f r_CA-7...-J.T... 00000040: 6e 65 74 5f 72 69 6d 5f 76 61 64 5f 65 6e 67 69 net_rim_vad_engi 00000050: 6e 65 5f 72 65 73 6f 75 72 63 65 5f 5f 66 72 00 ne_resource__fr. 00000060: 00 02 2e 4a 17 54 b9 00 21 6e 65 74 5f 72 69 6d ...J.T..!net_rim 00000070: 5f 76 61 64 5f 65 6e 67 69 6e 65 5f 72 65 73 6f _vad_engine_reso 00000080: 75 72 63 65 5f 5f 66 72 2d 31 00 00 02 2f 4a 17 urce__fr-1.../J. 00000090: 54 b9 00 21 6e 65 74 5f 72 69 6d 5f 76 61 64 5f T..!net_rim_vad_ 000000a0: 65 6e 67 69 6e 65 5f 72 65 73 6f 75 72 63 65 5f engine_resource_ 000000b0: 5f 66 72 2d 32 00 00 02 30 4a 17 54 b9 00 21 6e _fr-2...0J.T..!n 000000c0: 65 74 5f 72 69 6d 5f 76 61 64 5f 65 6e 67 69 6e et_rim_vad_engin 000000d0: 65 5f 72 65 73 6f 75 72 63 65 5f 5f 66 72 2d 33 e_resource__fr-3 000000e0: 00 00 02 31 4a 17 54 b9 00 21 6e 65 74 5f 72 69 ...1J.T..!net_ri 000000f0: 6d 5f 76 61 64 5f 65 6e 67 69 6e 65 5f 72 65 73 m_vad_engine_res 00000100: 6f 75 72 63 65 5f 5f 66 72 2d 34 00 00 02 32 4a ource__fr-4...2J 00000110: 17 54 b9 00 21 6e 65 74 5f 72 69 6d 5f 76 61 64 .T..!net_rim_vad 00000120: 5f 65 6e 67 69 6e 65 5f 72 65 73 6f 75 72 63 65 _engine_resource 00000130: 5f 5f 66 72 2d 35 00 00 02 33 4a 17 54 b9 00 21 __fr-5...3J.T..! 00000140: 6e 65 74 5f 72 69 6d 5f 76 61 64 5f 65 6e 67 69 net_rim_vad_engi 00000150: 6e 65 5f 72 65 73 6f 75 72 63 65 5f 5f 66 72 2d ne_resource__fr- 00000160: 36 00 00 02 34 4a 17 54 b9 00 21 6e 65 74 5f 72 6...4J.T..!net_r 00000170: 69 6d 5f 76 61 64 5f 65 6e 67 69 6e 65 5f 72 65 im_vad_engine_re 00000180: 73 6f 75 72 63 65 5f 5f 66 72 2d 37 00 00 02 35 source__fr-7...5 00000190: 4a 17 51 98 00 15 6e 65 74 5f 72 69 6d 5f 62 62 J.Q...net_rim_bb 000001a0: 5f 72 69 62 62 6f 6e 5f 61 70 70 00 00 02 36 4a _ribbon_app...6J 000001b0: 17 51 98 00 17 6e 65 74 5f 72 69 6d 5f 62 62 5f .Q...net_rim_bb_ 000001c0: 72 69 62 62 6f 6e 5f 61 70 70 2d 31 00 00 02 37 ribbon_app-1...7 000001d0: 4a 17 51 98 00 17 6e 65 74 5f 72 69 6d 5f 62 62 J.Q...net_rim_bb 000001e0: 5f 72 69 62 62 6f 6e 5f 61 70 70 2d 32 00 00 02 _ribbon_app-2... 000001f0: 38 4a 17 51 98 00 17 6e 65 74 5f 72 69 6d 5f 62 8J.Q...net_rim_b 00000200: 62 5f 72 69 62 62 6f 6e 5f 61 70 70 2d 33 00 00 b_ribbon_app-3.. 00000210: 02 39 4a 17 55 c7 00 1a 6e 65 74 5f 72 69 6d 5f .9J.U...net_rim_ 00000220: 62 62 5f 72 69 62 62 6f 6e 5f 73 6b 69 6e 5f 73 bb_ribbon_skin_s 00000230: 76 67 00 00 02 3a 4a 17 55 c7 00 1c 6e 65 74 5f vg...:J.U...net_ 00000240: 72 69 6d 5f 62 62 5f 72 69 62 62 6f 6e 5f 73 6b rim_bb_ribbon_sk 00000250: 69 6e 5f 73 76 67 2d 31 00 00 02 3b 4a 17 53 aa in_svg-1...;J.S. 00000260: 00 13 6e 65 74 5f 72 69 6d 5f 62 62 61 70 69 5f ..net_rim_bbapi_ 00000270: 70 68 6f 6e 65 00 00 02 3c 4a 17 55 a3 00 18 6e phone...J.U. 000002c0: 00 18 6e 65 74 5f 72 69 6d 5f 62 62 5f 66 69 6c ..net_rim_bb_fil 000002d0: 65 5f 65 78 70 6c 6f 72 65 72 00 00 02 3f 4a 17 e_explorer...?J. 000002e0: 55 bc 00 1a 6e 65 74 5f 72 69 6d 5f 62 62 5f 66 U...net_rim_bb_f 000002f0: 69 6c 65 5f 65 78 70 6c 6f 72 65 72 2d 33 00 00 ile_explorer-3.. 00000300: 02 40 4a 17 55 bc 00 1a 6e 65 74 5f 72 69 6d 5f .@J.U...net_rim_ 00000310: 62 62 5f 66 69 6c 65 5f 65 78 70 6c 6f 72 65 72 bb_file_explorer 00000320: 2d 32 00 00 02 41 4a 17 55 bc 00 1a 6e 65 74 5f -2...AJ.U...net_ 00000330: 72 69 6d 5f 62 62 5f 66 69 6c 65 5f 65 78 70 6c rim_bb_file_expl 00000340: 6f 72 65 72 2d 31 00 00 02 42 4a 17 55 bc 00 1a orer-1...BJ.U... 00000350: 6e 65 74 5f 72 69 6d 5f 62 62 5f 66 69 6c 65 5f net_rim_bb_file_ 00000360: 65 78 70 6c 6f 72 65 72 2d 34 00 00 02 43 4a 17 explorer-4...CJ. 00000370: 4b 41 00 16 6e 65 74 5f 72 69 6d 5f 62 62 5f 6f KA..net_rim_bb_o 00000380: 70 74 69 6f 6e 73 5f 61 70 70 00 00 02 44 4a 17 ptions_app...DJ. 00000390: 4b 41 00 18 6e 65 74 5f 72 69 6d 5f 62 62 5f 6f KA..net_rim_bb_o 000003a0: 70 74 69 6f 6e 73 5f 61 70 70 2d 34 00 00 02 45 ptions_app-4...E 000003b0: 4a 17 4b 41 00 18 6e 65 74 5f 72 69 6d 5f 62 62 J.KA..net_rim_bb 000003c0: 5f 6f 70 74 69 6f 6e 73 5f 61 70 70 2d 33 00 00 _options_app-3.. 000003d0: 02 46 4a 17 4b 41 00 18 6e 65 74 5f 72 69 6d 5f .FJ.KA..net_rim_ 000003e0: 62 62 5f 6f 70 74 69 6f 6e 73 5f 61 70 70 2d 31 bb_options_app-1 000003f0: 00 00 02 47 ...G Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 140 00000000: 05 00 0b 00 00 05 8d 00 00 02 47 ..........G <<< URB 120 00000000: 00 00 0c 00 13 05 01 00 16 00 00 00 ............ <<< URB 122 00000000: 05 00 06 00 03 db ...... <<< URB 123 00000000: 05 00 df 03 00 00 00 15 00 00 02 47 4a 17 4b 41 ...........GJ.KA 00000010: 00 18 6e 65 74 5f 72 69 6d 5f 62 62 5f 6f 70 74 ..net_rim_bb_opt 00000020: 69 6f 6e 73 5f 61 70 70 2d 32 00 00 02 48 4a 17 ions_app-2...HJ. 00000030: 4b 15 00 1b 6e 65 74 5f 72 69 6d 5f 62 62 5f 70 K...net_rim_bb_p 00000040: 72 6f 66 69 6c 65 73 5f 61 70 70 5f 6e 65 77 00 rofiles_app_new. 00000050: 00 02 49 4a 17 4b 15 00 1d 6e 65 74 5f 72 69 6d ..IJ.K...net_rim 00000060: 5f 62 62 5f 70 72 6f 66 69 6c 65 73 5f 61 70 70 _bb_profiles_app 00000070: 5f 6e 65 77 2d 31 00 00 02 4a 4a 17 4f e5 00 29 _new-1...JJ.O..) 00000080: 6e 65 74 5f 72 69 6d 5f 64 65 76 69 63 65 5f 61 net_rim_device_a 00000090: 70 70 73 5f 67 61 6d 65 73 5f 77 6f 72 64 6d 6f pps_games_wordmo 000000a0: 6c 65 5f 73 6f 75 6e 64 73 00 00 02 4b 4a 17 4f le_sounds...KJ.O 000000b0: e5 00 2b 6e 65 74 5f 72 69 6d 5f 64 65 76 69 63 ..+net_rim_devic 000000c0: 65 5f 61 70 70 73 5f 67 61 6d 65 73 5f 77 6f 72 e_apps_games_wor 000000d0: 64 6d 6f 6c 65 5f 73 6f 75 6e 64 73 2d 31 00 00 dmole_sounds-1.. 000000e0: 02 4c 4a 17 4f e5 00 2b 6e 65 74 5f 72 69 6d 5f .LJ.O..+net_rim_ 000000f0: 64 65 76 69 63 65 5f 61 70 70 73 5f 67 61 6d 65 device_apps_game 00000100: 73 5f 77 6f 72 64 6d 6f 6c 65 5f 73 6f 75 6e 64 s_wordmole_sound 00000110: 73 2d 32 00 00 02 4d 4a 17 4f e5 00 2b 6e 65 74 s-2...MJ.O..+net 00000120: 5f 72 69 6d 5f 64 65 76 69 63 65 5f 61 70 70 73 _rim_device_apps 00000130: 5f 67 61 6d 65 73 5f 77 6f 72 64 6d 6f 6c 65 5f _games_wordmole_ 00000140: 73 6f 75 6e 64 73 2d 33 00 00 02 4e 4a 17 4f e5 sounds-3...NJ.O. 00000150: 00 2b 6e 65 74 5f 72 69 6d 5f 64 65 76 69 63 65 .+net_rim_device 00000160: 5f 61 70 70 73 5f 67 61 6d 65 73 5f 77 6f 72 64 _apps_games_word 00000170: 6d 6f 6c 65 5f 73 6f 75 6e 64 73 2d 34 00 00 02 mole_sounds-4... 00000180: 4f 4a 17 4f e5 00 2b 6e 65 74 5f 72 69 6d 5f 64 OJ.O..+net_rim_d 00000190: 65 76 69 63 65 5f 61 70 70 73 5f 67 61 6d 65 73 evice_apps_games 000001a0: 5f 77 6f 72 64 6d 6f 6c 65 5f 73 6f 75 6e 64 73 _wordmole_sounds 000001b0: 2d 35 00 00 02 50 4a 17 4f e5 00 2b 6e 65 74 5f -5...PJ.O..+net_ 000001c0: 72 69 6d 5f 64 65 76 69 63 65 5f 61 70 70 73 5f rim_device_apps_ 000001d0: 67 61 6d 65 73 5f 77 6f 72 64 6d 6f 6c 65 5f 73 games_wordmole_s 000001e0: 6f 75 6e 64 73 2d 36 00 00 02 51 4a 17 53 6a 00 ounds-6...QJ.Sj. 000001f0: 2e 6e 65 74 5f 72 69 6d 5f 74 69 64 5f 64 79 6e .net_rim_tid_dyn 00000200: 61 6d 69 63 5f 6c 69 6e 67 5f 64 61 74 61 5f 65 amic_ling_data_e 00000210: 6e 67 6c 69 73 68 5f 75 73 5f 34 35 6b 5f 32 00 nglish_us_45k_2. 00000220: 00 02 52 4a 17 53 6a 00 30 6e 65 74 5f 72 69 6d ..RJ.Sj.0net_rim 00000230: 5f 74 69 64 5f 64 79 6e 61 6d 69 63 5f 6c 69 6e _tid_dynamic_lin 00000240: 67 5f 64 61 74 61 5f 65 6e 67 6c 69 73 68 5f 75 g_data_english_u 00000250: 73 5f 34 35 6b 5f 32 2d 34 00 00 02 53 4a 17 53 s_45k_2-4...SJ.S 00000260: 6a 00 30 6e 65 74 5f 72 69 6d 5f 74 69 64 5f 64 j.0net_rim_tid_d 00000270: 79 6e 61 6d 69 63 5f 6c 69 6e 67 5f 64 61 74 61 ynamic_ling_data 00000280: 5f 65 6e 67 6c 69 73 68 5f 75 73 5f 34 35 6b 5f _english_us_45k_ 00000290: 32 2d 31 00 00 02 54 4a 17 53 6a 00 30 6e 65 74 2-1...TJ.Sj.0net 000002a0: 5f 72 69 6d 5f 74 69 64 5f 64 79 6e 61 6d 69 63 _rim_tid_dynamic 000002b0: 5f 6c 69 6e 67 5f 64 61 74 61 5f 65 6e 67 6c 69 _ling_data_engli 000002c0: 73 68 5f 75 73 5f 34 35 6b 5f 32 2d 32 00 00 02 sh_us_45k_2-2... 000002d0: 55 4a 17 53 6a 00 30 6e 65 74 5f 72 69 6d 5f 74 UJ.Sj.0net_rim_t 000002e0: 69 64 5f 64 79 6e 61 6d 69 63 5f 6c 69 6e 67 5f id_dynamic_ling_ 000002f0: 64 61 74 61 5f 65 6e 67 6c 69 73 68 5f 75 73 5f data_english_us_ 00000300: 34 35 6b 5f 32 2d 33 00 00 02 56 4a 17 55 f8 00 45k_2-3...VJ.U.. 00000310: 18 6e 65 74 5f 72 69 6d 5f 62 62 5f 68 65 6c 70 .net_rim_bb_help 00000320: 5f 39 35 30 30 5f 5f 65 6e 00 00 02 57 4a 17 55 _9500__en...WJ.U 00000330: f8 00 1a 6e 65 74 5f 72 69 6d 5f 62 62 5f 68 65 ...net_rim_bb_he 00000340: 6c 70 5f 39 35 30 30 5f 5f 65 6e 2d 31 00 00 02 lp_9500__en-1... 00000350: 58 4a 17 55 f8 00 1a 6e 65 74 5f 72 69 6d 5f 62 XJ.U...net_rim_b 00000360: 62 5f 68 65 6c 70 5f 39 35 30 30 5f 5f 65 6e 2d b_help_9500__en- 00000370: 32 00 00 02 59 4a 17 55 f8 00 1a 6e 65 74 5f 72 2...YJ.U...net_r 00000380: 69 6d 5f 62 62 5f 68 65 6c 70 5f 39 35 30 30 5f im_bb_help_9500_ 00000390: 5f 65 6e 2d 33 00 00 02 5a 4a 17 56 01 00 18 6e _en-3...ZJ.V...n 000003a0: 65 74 5f 72 69 6d 5f 62 62 5f 68 65 6c 70 5f 39 et_rim_bb_help_9 000003b0: 35 30 30 5f 5f 66 72 00 00 02 5b 4a 17 56 01 00 500__fr...[J.V.. 000003c0: 1a 6e 65 74 5f 72 69 6d 5f 62 62 5f 68 65 6c 70 .net_rim_bb_help 000003d0: 5f 39 35 30 30 5f 5f 66 72 2d 31 00 00 02 5c _9500__fr-1...\ Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 144 00000000: 05 00 0b 00 00 05 8d 00 00 02 5c ..........\ <<< URB 124 00000000: 00 00 0c 00 13 05 01 00 17 00 00 00 ............ <<< URB 126 00000000: 05 00 06 00 03 d6 ...... <<< URB 127 00000000: 05 00 da 03 00 00 00 16 00 00 02 5c 4a 17 56 01 ...........\J.V. 00000010: 00 1a 6e 65 74 5f 72 69 6d 5f 62 62 5f 68 65 6c ..net_rim_bb_hel 00000020: 70 5f 39 35 30 30 5f 5f 66 72 2d 32 00 00 02 5d p_9500__fr-2...] 00000030: 4a 17 56 01 00 1a 6e 65 74 5f 72 69 6d 5f 62 62 J.V...net_rim_bb 00000040: 5f 68 65 6c 70 5f 39 35 30 30 5f 5f 66 72 2d 33 _help_9500__fr-3 00000050: 00 00 02 5e 4a 17 4a 82 00 14 6e 65 74 5f 72 69 ...^J.J...net_ri 00000060: 6d 5f 6d 32 67 5f 69 6e 74 65 72 6e 61 6c 00 00 m_m2g_internal.. 00000070: 02 5f 4a 17 4a 82 00 16 6e 65 74 5f 72 69 6d 5f ._J.J...net_rim_ 00000080: 6d 32 67 5f 69 6e 74 65 72 6e 61 6c 2d 31 00 00 m2g_internal-1.. 00000090: 02 60 4a 17 4a 82 00 16 6e 65 74 5f 72 69 6d 5f .`J.J...net_rim_ 000000a0: 6d 32 67 5f 69 6e 74 65 72 6e 61 6c 2d 32 00 00 m2g_internal-2.. 000000b0: 02 61 4a 17 55 fc 00 1b 6e 65 74 5f 72 69 6d 5f .aJ.U...net_rim_ 000000c0: 62 62 5f 68 65 6c 70 5f 39 35 30 30 5f 5f 65 6e bb_help_9500__en 000000d0: 5f 47 42 00 00 02 62 4a 17 55 fc 00 1d 6e 65 74 _GB...bJ.U...net 000000e0: 5f 72 69 6d 5f 62 62 5f 68 65 6c 70 5f 39 35 30 _rim_bb_help_950 000000f0: 30 5f 5f 65 6e 5f 47 42 2d 31 00 00 02 63 4a 17 0__en_GB-1...cJ. 00000100: 55 fc 00 1d 6e 65 74 5f 72 69 6d 5f 62 62 5f 68 U...net_rim_bb_h 00000110: 65 6c 70 5f 39 35 30 30 5f 5f 65 6e 5f 47 42 2d elp_9500__en_GB- 00000120: 32 00 00 02 64 4a 17 55 fc 00 1d 6e 65 74 5f 72 2...dJ.U...net_r 00000130: 69 6d 5f 62 62 5f 68 65 6c 70 5f 39 35 30 30 5f im_bb_help_9500_ 00000140: 5f 65 6e 5f 47 42 2d 33 00 00 02 65 4a 17 53 66 _en_GB-3...eJ.Sf 00000150: 00 2e 6e 65 74 5f 72 69 6d 5f 74 69 64 5f 64 79 ..net_rim_tid_dy 00000160: 6e 61 6d 69 63 5f 6c 69 6e 67 5f 64 61 74 61 5f namic_ling_data_ 00000170: 65 6e 67 6c 69 73 68 5f 67 62 5f 34 35 6b 5f 32 english_gb_45k_2 00000180: 00 00 02 66 4a 17 53 66 00 30 6e 65 74 5f 72 69 ...fJ.Sf.0net_ri 00000190: 6d 5f 74 69 64 5f 64 79 6e 61 6d 69 63 5f 6c 69 m_tid_dynamic_li 000001a0: 6e 67 5f 64 61 74 61 5f 65 6e 67 6c 69 73 68 5f ng_data_english_ 000001b0: 67 62 5f 34 35 6b 5f 32 2d 34 00 00 02 67 4a 17 gb_45k_2-4...gJ. 000001c0: 53 66 00 30 6e 65 74 5f 72 69 6d 5f 74 69 64 5f Sf.0net_rim_tid_ 000001d0: 64 79 6e 61 6d 69 63 5f 6c 69 6e 67 5f 64 61 74 dynamic_ling_dat 000001e0: 61 5f 65 6e 67 6c 69 73 68 5f 67 62 5f 34 35 6b a_english_gb_45k 000001f0: 5f 32 2d 31 00 00 02 68 4a 17 53 66 00 30 6e 65 _2-1...hJ.Sf.0ne 00000200: 74 5f 72 69 6d 5f 74 69 64 5f 64 79 6e 61 6d 69 t_rim_tid_dynami 00000210: 63 5f 6c 69 6e 67 5f 64 61 74 61 5f 65 6e 67 6c c_ling_data_engl 00000220: 69 73 68 5f 67 62 5f 34 35 6b 5f 32 2d 32 00 00 ish_gb_45k_2-2.. 00000230: 02 69 4a 17 53 66 00 30 6e 65 74 5f 72 69 6d 5f .iJ.Sf.0net_rim_ 00000240: 74 69 64 5f 64 79 6e 61 6d 69 63 5f 6c 69 6e 67 tid_dynamic_ling 00000250: 5f 64 61 74 61 5f 65 6e 67 6c 69 73 68 5f 67 62 _data_english_gb 00000260: 5f 34 35 6b 5f 32 2d 33 00 00 02 6a 4a 17 54 b2 _45k_2-3...jJ.T. 00000270: 00 22 6e 65 74 5f 72 69 6d 5f 76 61 64 5f 65 6e ."net_rim_vad_en 00000280: 67 69 6e 65 5f 72 65 73 6f 75 72 63 65 5f 5f 65 gine_resource__e 00000290: 6e 5f 47 42 00 00 02 6b 4a 17 54 b2 00 24 6e 65 n_GB...kJ.T..$ne 000002a0: 74 5f 72 69 6d 5f 76 61 64 5f 65 6e 67 69 6e 65 t_rim_vad_engine 000002b0: 5f 72 65 73 6f 75 72 63 65 5f 5f 65 6e 5f 47 42 _resource__en_GB 000002c0: 2d 31 00 00 02 6c 4a 17 54 b2 00 24 6e 65 74 5f -1...lJ.T..$net_ 000002d0: 72 69 6d 5f 76 61 64 5f 65 6e 67 69 6e 65 5f 72 rim_vad_engine_r 000002e0: 65 73 6f 75 72 63 65 5f 5f 65 6e 5f 47 42 2d 32 esource__en_GB-2 000002f0: 00 00 02 6d 4a 17 54 b2 00 24 6e 65 74 5f 72 69 ...mJ.T..$net_ri 00000300: 6d 5f 76 61 64 5f 65 6e 67 69 6e 65 5f 72 65 73 m_vad_engine_res 00000310: 6f 75 72 63 65 5f 5f 65 6e 5f 47 42 2d 33 00 00 ource__en_GB-3.. 00000320: 02 6e 4a 17 54 b2 00 24 6e 65 74 5f 72 69 6d 5f .nJ.T..$net_rim_ 00000330: 76 61 64 5f 65 6e 67 69 6e 65 5f 72 65 73 6f 75 vad_engine_resou 00000340: 72 63 65 5f 5f 65 6e 5f 47 42 2d 34 00 00 02 6f rce__en_GB-4...o 00000350: 4a 17 54 b2 00 24 6e 65 74 5f 72 69 6d 5f 76 61 J.T..$net_rim_va 00000360: 64 5f 65 6e 67 69 6e 65 5f 72 65 73 6f 75 72 63 d_engine_resourc 00000370: 65 5f 5f 65 6e 5f 47 42 2d 35 00 00 02 70 4a 17 e__en_GB-5...pJ. 00000380: 54 b2 00 24 6e 65 74 5f 72 69 6d 5f 76 61 64 5f T..$net_rim_vad_ 00000390: 65 6e 67 69 6e 65 5f 72 65 73 6f 75 72 63 65 5f engine_resource_ 000003a0: 5f 65 6e 5f 47 42 2d 36 00 00 02 71 4a 17 54 b2 _en_GB-6...qJ.T. 000003b0: 00 24 6e 65 74 5f 72 69 6d 5f 76 61 64 5f 65 6e .$net_rim_vad_en 000003c0: 67 69 6e 65 5f 72 65 73 6f 75 72 63 65 5f 5f 65 gine_resource__e 000003d0: 6e 5f 47 42 2d 37 00 00 02 72 n_GB-7...r Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 148 00000000: 05 00 0b 00 00 05 8d 00 00 02 72 ..........r <<< URB 128 00000000: 00 00 0c 00 13 05 01 00 18 00 00 00 ............ <<< URB 130 00000000: 05 00 06 00 03 e6 ...... <<< URB 131 00000000: 05 00 ea 03 00 00 00 1f 00 00 02 72 4a 17 54 b2 ...........rJ.T. 00000010: 00 24 6e 65 74 5f 72 69 6d 5f 76 61 64 5f 65 6e .$net_rim_vad_en 00000020: 67 69 6e 65 5f 72 65 73 6f 75 72 63 65 5f 5f 65 gine_resource__e 00000030: 6e 5f 47 42 2d 38 00 00 02 73 4a 17 55 b1 00 12 n_GB-8...sJ.U... 00000040: 6e 65 74 5f 72 69 6d 5f 62 69 73 5f 63 6c 69 65 net_rim_bis_clie 00000050: 6e 74 00 00 02 74 4a 17 55 b1 00 14 6e 65 74 5f nt...tJ.U...net_ 00000060: 72 69 6d 5f 62 69 73 5f 63 6c 69 65 6e 74 2d 31 rim_bis_client-1 00000070: 00 00 02 75 4a 17 55 b1 00 14 6e 65 74 5f 72 69 ...uJ.U...net_ri 00000080: 6d 5f 62 69 73 5f 63 6c 69 65 6e 74 2d 33 00 00 m_bis_client-3.. 00000090: 02 76 4a 17 55 76 00 15 6e 65 74 5f 72 69 6d 5f .vJ.Uv..net_rim_ 000000a0: 62 62 61 70 69 5f 62 72 6f 77 73 65 72 00 00 02 bbapi_browser... 000000b0: 77 4a 17 53 d2 00 0f 6e 65 74 5f 72 69 6d 5f 62 wJ.S...net_rim_b 000000c0: 69 73 5f 6c 69 62 00 00 02 78 4a 17 55 b1 00 14 is_lib...xJ.U... 000000d0: 6e 65 74 5f 72 69 6d 5f 62 69 73 5f 63 6c 69 65 net_rim_bis_clie 000000e0: 6e 74 2d 32 00 00 02 79 4a 17 51 65 00 15 6e 65 nt-2...yJ.Qe..ne 000000f0: 74 5f 72 69 6d 5f 62 62 5f 6f 74 61 75 70 67 72 t_rim_bb_otaupgr 00000100: 61 64 65 00 00 02 7a 4a 17 51 65 00 17 6e 65 74 ade...zJ.Qe..net 00000110: 5f 72 69 6d 5f 62 62 5f 6f 74 61 75 70 67 72 61 _rim_bb_otaupgra 00000120: 64 65 2d 31 00 00 02 7b 4a 17 51 65 00 17 6e 65 de-1...{J.Qe..ne 00000130: 74 5f 72 69 6d 5f 62 62 5f 6f 74 61 75 70 67 72 t_rim_bb_otaupgr 00000140: 61 64 65 2d 32 00 00 02 7c 4a 17 50 6e 00 18 6e ade-2...|J.Pn..n 00000150: 65 74 5f 72 69 6d 5f 62 62 5f 6f 74 61 73 6c 5f et_rim_bb_otasl_ 00000160: 63 68 61 6e 6e 65 6c 00 00 02 7d 4a 17 53 28 00 channel...}J.S(. 00000170: 10 6e 65 74 5f 72 69 6d 5f 63 72 79 70 74 6f 5f .net_rim_crypto_ 00000180: 33 00 00 02 7e 4a 17 53 28 00 12 6e 65 74 5f 72 3...~J.S(..net_r 00000190: 69 6d 5f 63 72 79 70 74 6f 5f 33 2d 31 00 00 02 im_crypto_3-1... 000001a0: 7f 4a 17 53 28 00 12 6e 65 74 5f 72 69 6d 5f 63 .J.S(..net_rim_c 000001b0: 72 79 70 74 6f 5f 33 2d 32 00 00 02 80 4a 17 50 rypto_3-2....J.P 000001c0: ab 00 1a 6e 65 74 5f 72 69 6d 5f 62 62 5f 61 64 ...net_rim_bb_ad 000001d0: 64 72 65 73 73 62 6f 6f 6b 5f 61 70 70 00 00 02 dressbook_app... 000001e0: 81 4a 17 50 ab 00 1c 6e 65 74 5f 72 69 6d 5f 62 .J.P...net_rim_b 000001f0: 62 5f 61 64 64 72 65 73 73 62 6f 6f 6b 5f 61 70 b_addressbook_ap 00000200: 70 2d 32 00 00 02 82 4a 17 50 ab 00 1c 6e 65 74 p-2....J.P...net 00000210: 5f 72 69 6d 5f 62 62 5f 61 64 64 72 65 73 73 62 _rim_bb_addressb 00000220: 6f 6f 6b 5f 61 70 70 2d 31 00 00 02 83 4a 17 55 ook_app-1....J.U 00000230: 04 00 1c 6e 65 74 5f 72 69 6d 5f 62 62 5f 6d 65 ...net_rim_bb_me 00000240: 73 73 61 67 65 73 65 61 72 63 68 5f 6c 69 62 00 ssagesearch_lib. 00000250: 00 02 84 4a 17 55 04 00 1e 6e 65 74 5f 72 69 6d ...J.U...net_rim 00000260: 5f 62 62 5f 6d 65 73 73 61 67 65 73 65 61 72 63 _bb_messagesearc 00000270: 68 5f 6c 69 62 2d 31 00 00 02 85 4a 17 50 c7 00 h_lib-1....J.P.. 00000280: 14 6e 65 74 5f 72 69 6d 5f 62 62 5f 63 6c 6f 63 .net_rim_bb_cloc 00000290: 6b 5f 6c 69 62 00 00 02 86 4a 17 50 c7 00 16 6e k_lib....J.P...n 000002a0: 65 74 5f 72 69 6d 5f 62 62 5f 63 6c 6f 63 6b 5f et_rim_bb_clock_ 000002b0: 6c 69 62 2d 31 00 00 02 87 4a 17 50 c7 00 16 6e lib-1....J.P...n 000002c0: 65 74 5f 72 69 6d 5f 62 62 5f 63 6c 6f 63 6b 5f et_rim_bb_clock_ 000002d0: 6c 69 62 2d 32 00 00 02 88 4a 17 4b 34 00 14 6e lib-2....J.K4..n 000002e0: 65 74 5f 72 69 6d 5f 62 62 5f 70 68 6f 6e 65 5f et_rim_bb_phone_ 000002f0: 61 70 70 00 00 02 89 4a 17 4b 34 00 16 6e 65 74 app....J.K4..net 00000300: 5f 72 69 6d 5f 62 62 5f 70 68 6f 6e 65 5f 61 70 _rim_bb_phone_ap 00000310: 70 2d 32 00 00 02 8a 4a 17 4b 34 00 16 6e 65 74 p-2....J.K4..net 00000320: 5f 72 69 6d 5f 62 62 5f 70 68 6f 6e 65 5f 61 70 _rim_bb_phone_ap 00000330: 70 2d 31 00 00 02 8b 4a 17 55 b6 00 11 6e 65 74 p-1....J.U...net 00000340: 5f 72 69 6d 5f 62 62 5f 63 61 6d 65 72 61 00 00 _rim_bb_camera.. 00000350: 02 8c 4a 17 55 b6 00 13 6e 65 74 5f 72 69 6d 5f ..J.U...net_rim_ 00000360: 62 62 5f 63 61 6d 65 72 61 2d 31 00 00 02 8d 4a bb_camera-1....J 00000370: 17 55 b6 00 13 6e 65 74 5f 72 69 6d 5f 62 62 5f .U...net_rim_bb_ 00000380: 63 61 6d 65 72 61 2d 32 00 00 02 8e 4a 17 50 d5 camera-2....J.P. 00000390: 00 0e 6e 65 74 5f 72 69 6d 5f 62 62 5f 6d 74 70 ..net_rim_bb_mtp 000003a0: 00 00 02 8f 4a 17 50 d5 00 10 6e 65 74 5f 72 69 ....J.P...net_ri 000003b0: 6d 5f 62 62 5f 6d 74 70 2d 31 00 00 02 90 4a 17 m_bb_mtp-1....J. 000003c0: 51 88 00 22 6e 65 74 5f 72 69 6d 5f 64 65 76 69 Q.."net_rim_devi 000003d0: 63 65 5f 61 70 70 73 5f 67 61 6d 65 73 5f 77 6f ce_apps_games_wo 000003e0: 72 64 6d 6f 6c 65 00 00 02 91 rdmole.... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 152 00000000: 05 00 0b 00 00 05 8d 00 00 02 91 ........... <<< URB 132 00000000: 00 00 0c 00 13 05 01 00 19 00 00 00 ............ <<< URB 134 00000000: 05 00 06 00 03 e6 ...... <<< URB 135 00000000: 05 00 ea 03 00 00 00 1d 00 00 02 91 4a 17 51 88 ............J.Q. 00000010: 00 24 6e 65 74 5f 72 69 6d 5f 64 65 76 69 63 65 .$net_rim_device 00000020: 5f 61 70 70 73 5f 67 61 6d 65 73 5f 77 6f 72 64 _apps_games_word 00000030: 6d 6f 6c 65 2d 31 00 00 02 92 4a 17 49 fa 00 0d mole-1....J.I... 00000040: 6e 65 74 5f 72 69 6d 5f 6d 65 64 69 61 00 00 02 net_rim_media... 00000050: 93 4a 17 49 fa 00 0f 6e 65 74 5f 72 69 6d 5f 6d .J.I...net_rim_m 00000060: 65 64 69 61 2d 31 00 00 02 94 4a 17 53 37 00 12 edia-1....J.S7.. 00000070: 6e 65 74 5f 72 69 6d 5f 63 72 79 70 74 6f 5f 70 net_rim_crypto_p 00000080: 67 70 00 00 02 95 4a 17 53 37 00 14 6e 65 74 5f gp....J.S7..net_ 00000090: 72 69 6d 5f 63 72 79 70 74 6f 5f 70 67 70 2d 31 rim_crypto_pgp-1 000000a0: 00 00 02 96 4a 17 55 40 00 17 6e 65 74 5f 72 69 ....J.U@..net_ri 000000b0: 6d 5f 62 62 5f 63 61 6c 65 6e 64 61 72 5f 6c 69 m_bb_calendar_li 000000c0: 62 00 00 02 97 4a 17 55 40 00 19 6e 65 74 5f 72 b....J.U@..net_r 000000d0: 69 6d 5f 62 62 5f 63 61 6c 65 6e 64 61 72 5f 6c im_bb_calendar_l 000000e0: 69 62 2d 31 00 00 02 98 4a 17 55 26 00 18 6e 65 ib-1....J.U&..ne 000000f0: 74 5f 72 69 6d 5f 62 62 5f 66 72 65 65 5f 62 75 t_rim_bb_free_bu 00000100: 73 79 5f 6c 69 62 00 00 02 99 4a 17 52 f2 00 17 sy_lib....J.R... 00000110: 6e 65 74 5f 72 69 6d 5f 74 69 64 5f 73 70 65 6c net_rim_tid_spel 00000120: 6c 5f 63 68 65 63 6b 00 00 02 9a 4a 17 52 f2 00 l_check....J.R.. 00000130: 19 6e 65 74 5f 72 69 6d 5f 74 69 64 5f 73 70 65 .net_rim_tid_spe 00000140: 6c 6c 5f 63 68 65 63 6b 2d 31 00 00 02 9b 4a 17 ll_check-1....J. 00000150: 57 48 00 13 6e 65 74 5f 72 69 6d 5f 73 65 63 75 WH..net_rim_secu 00000160: 72 65 65 6d 61 69 6c 00 00 02 9c 4a 17 57 48 00 reemail....J.WH. 00000170: 15 6e 65 74 5f 72 69 6d 5f 73 65 63 75 72 65 65 .net_rim_securee 00000180: 6d 61 69 6c 2d 31 00 00 02 9d 4a 17 57 3e 00 17 mail-1....J.W>.. 00000190: 6e 65 74 5f 72 69 6d 5f 62 62 5f 6c 64 61 70 5f net_rim_bb_ldap_ 000001a0: 62 72 6f 77 73 65 72 00 00 02 9e 4a 17 57 2c 00 browser....J.W,. 000001b0: 1f 6e 65 74 5f 72 69 6d 5f 63 72 79 70 74 6f 5f .net_rim_crypto_ 000001c0: 6b 65 79 73 74 6f 72 65 5f 62 72 6f 77 73 65 72 keystore_browser 000001d0: 00 00 02 9f 4a 17 56 36 00 15 6e 65 74 5f 72 69 ....J.V6..net_ri 000001e0: 6d 5f 62 62 5f 63 72 79 70 74 6f 5f 61 70 69 00 m_bb_crypto_api. 000001f0: 00 02 a0 4a 17 55 a9 00 15 6e 65 74 5f 72 69 6d ...J.U...net_rim 00000200: 5f 62 62 5f 61 70 70 5f 63 65 6e 74 65 72 00 00 _bb_app_center.. 00000210: 02 a1 4a 17 55 a9 00 17 6e 65 74 5f 72 69 6d 5f ..J.U...net_rim_ 00000220: 62 62 5f 61 70 70 5f 63 65 6e 74 65 72 2d 31 00 bb_app_center-1. 00000230: 00 02 a2 4a 17 51 32 00 17 6e 65 74 5f 72 69 6d ...J.Q2..net_rim 00000240: 5f 62 62 5f 63 61 6c 65 6e 64 61 72 5f 61 70 70 _bb_calendar_app 00000250: 00 00 02 a3 4a 17 51 32 00 19 6e 65 74 5f 72 69 ....J.Q2..net_ri 00000260: 6d 5f 62 62 5f 63 61 6c 65 6e 64 61 72 5f 61 70 m_bb_calendar_ap 00000270: 70 2d 31 00 00 02 a4 4a 17 50 e2 00 10 6e 65 74 p-1....J.P...net 00000280: 5f 72 69 6d 5f 62 62 5f 63 6c 6f 63 6b 00 00 02 _rim_bb_clock... 00000290: a5 4a 17 50 e2 00 12 6e 65 74 5f 72 69 6d 5f 62 .J.P...net_rim_b 000002a0: 62 5f 63 6c 6f 63 6b 2d 31 00 00 02 a6 4a 17 55 b_clock-1....J.U 000002b0: bf 00 0e 6e 65 74 5f 72 69 6d 5f 62 62 5f 67 61 ...net_rim_bb_ga 000002c0: 73 00 00 02 a7 4a 17 55 bf 00 10 6e 65 74 5f 72 s....J.U...net_r 000002d0: 69 6d 5f 62 62 5f 67 61 73 2d 31 00 00 02 a8 4a im_bb_gas-1....J 000002e0: 17 53 11 00 28 6e 65 74 5f 72 69 6d 5f 74 69 64 .S..(net_rim_tid 000002f0: 5f 64 79 6e 61 6d 69 63 5f 6c 69 6e 67 5f 64 61 _dynamic_ling_da 00000300: 74 61 5f 66 72 65 6e 63 68 5f 6c 74 72 00 00 02 ta_french_ltr... 00000310: a9 4a 17 53 11 00 2a 6e 65 74 5f 72 69 6d 5f 74 .J.S..*net_rim_t 00000320: 69 64 5f 64 79 6e 61 6d 69 63 5f 6c 69 6e 67 5f id_dynamic_ling_ 00000330: 64 61 74 61 5f 66 72 65 6e 63 68 5f 6c 74 72 2d data_french_ltr- 00000340: 32 00 00 02 aa 4a 17 53 11 00 2a 6e 65 74 5f 72 2....J.S..*net_r 00000350: 69 6d 5f 74 69 64 5f 64 79 6e 61 6d 69 63 5f 6c im_tid_dynamic_l 00000360: 69 6e 67 5f 64 61 74 61 5f 66 72 65 6e 63 68 5f ing_data_french_ 00000370: 6c 74 72 2d 31 00 00 02 ab 4a 17 50 89 00 1d 6e ltr-1....J.P...n 00000380: 65 74 5f 72 69 6d 5f 62 62 5f 61 64 64 72 65 73 et_rim_bb_addres 00000390: 73 62 6f 6f 6b 5f 73 69 6d 61 70 70 00 00 02 ac sbook_simapp.... 000003a0: 4a 17 50 89 00 1f 6e 65 74 5f 72 69 6d 5f 62 62 J.P...net_rim_bb 000003b0: 5f 61 64 64 72 65 73 73 62 6f 6f 6b 5f 73 69 6d _addressbook_sim 000003c0: 61 70 70 2d 31 00 00 02 ad 4a 17 4f e8 00 17 6e app-1....J.O...n 000003d0: 65 74 5f 72 69 6d 5f 62 62 5f 73 69 6d 70 68 6f et_rim_bb_simpho 000003e0: 6e 65 62 6f 6f 6b 00 00 02 ae nebook.... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 156 00000000: 05 00 0b 00 00 05 8d 00 00 02 ae ........... <<< URB 136 00000000: 00 00 0c 00 13 05 01 00 1a 00 00 00 ............ <<< URB 138 00000000: 05 00 06 00 03 e1 ...... <<< URB 139 00000000: 05 00 e5 03 00 00 00 1b 00 00 02 ae 4a 17 53 d9 ............J.S. 00000010: 00 16 6e 65 74 5f 72 69 6d 5f 62 69 73 5f 63 6c ..net_rim_bis_cl 00000020: 69 65 6e 74 5f 5f 65 6e 00 00 02 af 4a 17 53 d9 ient__en....J.S. 00000030: 00 18 6e 65 74 5f 72 69 6d 5f 62 69 73 5f 63 6c ..net_rim_bis_cl 00000040: 69 65 6e 74 5f 5f 65 6e 2d 31 00 00 02 b0 4a 17 ient__en-1....J. 00000050: 51 90 00 1a 6e 65 74 5f 72 69 6d 5f 62 62 5f 64 Q...net_rim_bb_d 00000060: 65 76 69 63 65 5f 73 65 6c 66 74 65 73 74 00 00 evice_selftest.. 00000070: 02 b1 4a 17 51 90 00 1c 6e 65 74 5f 72 69 6d 5f ..J.Q...net_rim_ 00000080: 62 62 5f 64 65 76 69 63 65 5f 73 65 6c 66 74 65 bb_device_selfte 00000090: 73 74 2d 31 00 00 02 b2 4a 17 57 50 00 12 6e 65 st-1....J.WP..ne 000000a0: 74 5f 72 69 6d 5f 62 62 5f 70 67 70 5f 6c 69 62 t_rim_bb_pgp_lib 000000b0: 00 00 02 b3 4a 17 57 44 00 23 6e 65 74 5f 72 69 ....J.WD.#net_ri 000000c0: 6d 5f 63 72 79 70 74 6f 5f 6b 65 79 73 74 6f 72 m_crypto_keystor 000000d0: 65 5f 62 72 6f 77 73 65 72 5f 70 67 70 00 00 02 e_browser_pgp... 000000e0: b4 4a 17 57 50 00 14 6e 65 74 5f 72 69 6d 5f 62 .J.WP..net_rim_b 000000f0: 62 5f 70 67 70 5f 6c 69 62 2d 31 00 00 02 b5 4a b_pgp_lib-1....J 00000100: 17 49 e8 00 1c 6e 65 74 5f 72 69 6d 5f 70 6c 61 .I...net_rim_pla 00000110: 74 66 6f 72 6d 5f 69 6d 5f 72 65 73 6f 75 72 63 tform_im_resourc 00000120: 65 00 00 02 b6 4a 17 49 e8 00 1e 6e 65 74 5f 72 e....J.I...net_r 00000130: 69 6d 5f 70 6c 61 74 66 6f 72 6d 5f 69 6d 5f 72 im_platform_im_r 00000140: 65 73 6f 75 72 63 65 2d 31 00 00 02 b7 4a 17 53 esource-1....J.S 00000150: dc 00 16 6e 65 74 5f 72 69 6d 5f 62 69 73 5f 63 ...net_rim_bis_c 00000160: 6c 69 65 6e 74 5f 5f 66 72 00 00 02 b8 4a 17 53 lient__fr....J.S 00000170: dc 00 18 6e 65 74 5f 72 69 6d 5f 62 69 73 5f 63 ...net_rim_bis_c 00000180: 6c 69 65 6e 74 5f 5f 66 72 2d 31 00 00 02 b9 4a lient__fr-1....J 00000190: 17 50 59 00 1a 6e 65 74 5f 72 69 6d 5f 62 62 5f .PY..net_rim_bb_ 000001a0: 63 6c 6f 63 6b 5f 66 61 63 65 73 5f 34 38 30 00 clock_faces_480. 000001b0: 00 02 ba 4a 17 50 59 00 1c 6e 65 74 5f 72 69 6d ...J.PY..net_rim 000001c0: 5f 62 62 5f 63 6c 6f 63 6b 5f 66 61 63 65 73 5f _bb_clock_faces_ 000001d0: 34 38 30 2d 31 00 00 02 bb 4a 17 52 92 00 19 6e 480-1....J.R...n 000001e0: 65 74 5f 72 69 6d 5f 66 6f 6e 74 5f 65 75 72 6f et_rim_font_euro 000001f0: 70 65 61 6e 5f 73 66 66 00 00 02 bc 4a 17 52 92 pean_sff....J.R. 00000200: 00 1b 6e 65 74 5f 72 69 6d 5f 66 6f 6e 74 5f 65 ..net_rim_font_e 00000210: 75 72 6f 70 65 61 6e 5f 73 66 66 2d 31 00 00 02 uropean_sff-1... 00000220: bd 4a 17 55 d6 00 26 6e 65 74 5f 72 69 6d 5f 64 .J.U..&net_rim_d 00000230: 65 76 69 63 65 5f 61 70 70 73 5f 67 61 6d 65 73 evice_apps_games 00000240: 5f 62 72 69 63 6b 62 72 65 61 6b 65 72 00 00 02 _brickbreaker... 00000250: be 4a 17 55 d6 00 28 6e 65 74 5f 72 69 6d 5f 64 .J.U..(net_rim_d 00000260: 65 76 69 63 65 5f 61 70 70 73 5f 67 61 6d 65 73 evice_apps_games 00000270: 5f 62 72 69 63 6b 62 72 65 61 6b 65 72 2d 31 00 _brickbreaker-1. 00000280: 00 02 bf 4a 17 54 9d 00 18 6e 65 74 5f 72 69 6d ...J.T...net_rim 00000290: 5f 62 62 5f 6d 65 64 69 61 72 65 63 6f 72 64 65 _bb_mediarecorde 000002a0: 72 00 00 02 c0 4a 17 54 9d 00 1a 6e 65 74 5f 72 r....J.T...net_r 000002b0: 69 6d 5f 62 62 5f 6d 65 64 69 61 72 65 63 6f 72 im_bb_mediarecor 000002c0: 64 65 72 2d 31 00 00 02 c1 4a 17 54 4f 00 17 6e der-1....J.TO..n 000002d0: 65 74 5f 72 69 6d 5f 62 62 5f 72 65 73 6f 75 72 et_rim_bb_resour 000002e0: 63 65 5f 5f 65 6e 00 00 02 c2 4a 17 54 4f 00 19 ce__en....J.TO.. 000002f0: 6e 65 74 5f 72 69 6d 5f 62 62 5f 72 65 73 6f 75 net_rim_bb_resou 00000300: 72 63 65 5f 5f 65 6e 2d 31 00 00 02 c3 4a 17 54 rce__en-1....J.T 00000310: 54 00 17 6e 65 74 5f 72 69 6d 5f 62 62 5f 72 65 T..net_rim_bb_re 00000320: 73 6f 75 72 63 65 5f 5f 66 72 00 00 02 c4 4a 17 source__fr....J. 00000330: 54 54 00 19 6e 65 74 5f 72 69 6d 5f 62 62 5f 72 TT..net_rim_bb_r 00000340: 65 73 6f 75 72 63 65 5f 5f 66 72 2d 31 00 00 02 esource__fr-1... 00000350: c5 4a 17 51 76 00 1d 6e 65 74 5f 72 69 6d 5f 62 .J.Qv..net_rim_b 00000360: 62 5f 76 6f 69 63 65 6e 6f 74 65 73 72 65 63 6f b_voicenotesreco 00000370: 72 64 65 72 00 00 02 c6 4a 17 51 76 00 1f 6e 65 rder....J.Qv..ne 00000380: 74 5f 72 69 6d 5f 62 62 5f 76 6f 69 63 65 6e 6f t_rim_bb_voiceno 00000390: 74 65 73 72 65 63 6f 72 64 65 72 2d 31 00 00 02 tesrecorder-1... 000003a0: c7 4a 17 52 7a 00 18 6e 65 74 5f 72 69 6d 5f 63 .J.Rz..net_rim_c 000003b0: 6c 64 63 5f 69 6f 5f 72 69 6d 5f 69 6d 70 6c 00 ldc_io_rim_impl. 000003c0: 00 02 c8 4a 17 53 3e 00 18 6e 65 74 5f 72 69 6d ...J.S>..net_rim 000003d0: 5f 74 69 64 5f 66 61 73 74 45 75 72 6f 70 65 61 _tid_fastEuropea 000003e0: 6e 00 00 02 c9 n.... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 160 00000000: 05 00 0b 00 00 05 8d 00 00 02 c9 ........... <<< URB 140 00000000: 00 00 0c 00 13 05 01 00 1b 00 00 00 ............ <<< URB 142 00000000: 05 00 06 00 03 ea ...... <<< URB 143 00000000: 05 00 ee 03 00 00 00 1d 00 00 02 c9 4a 17 53 32 ............J.S2 00000010: 00 1d 6e 65 74 5f 72 69 6d 5f 74 69 64 5f 62 61 ..net_rim_tid_ba 00000020: 73 69 63 46 61 73 74 45 75 72 6f 70 65 61 6e 00 sicFastEuropean. 00000030: 00 02 ca 4a 17 53 07 00 23 6e 65 74 5f 72 69 6d ...J.S..#net_rim 00000040: 5f 74 69 64 5f 72 65 70 6f 73 69 74 6f 72 79 42 _tid_repositoryB 00000050: 61 73 65 64 45 75 72 6f 70 65 61 6e 00 00 02 cb asedEuropean.... 00000060: 4a 17 52 85 00 0b 6e 65 74 5f 72 69 6d 5f 77 61 J.R...net_rim_wa 00000070: 70 00 00 02 cc 4a 17 55 3a 00 11 6e 65 74 5f 72 p....J.U:..net_r 00000080: 69 6d 5f 62 62 61 70 69 5f 70 69 6d 00 00 02 cd im_bbapi_pim.... 00000090: 4a 17 51 2b 00 15 6e 65 74 5f 72 69 6d 5f 62 62 J.Q+..net_rim_bb 000000a0: 5f 61 63 74 69 76 61 74 69 6f 6e 00 00 02 ce 4a _activation....J 000000b0: 17 4a e5 00 1b 6e 65 74 5f 72 69 6d 5f 70 6c 61 .J...net_rim_pla 000000c0: 7a 6d 69 63 5f 74 68 65 6d 65 72 65 61 64 65 72 zmic_themereader 000000d0: 00 00 02 cf 4a 17 51 83 00 14 6e 65 74 5f 72 69 ....J.Q...net_ri 000000e0: 6d 5f 62 62 5f 67 61 6d 65 73 5f 61 70 70 00 00 m_bb_games_app.. 000000f0: 02 d0 4a 17 53 37 00 12 6e 65 74 5f 72 69 6d 5f ..J.S7..net_rim_ 00000100: 63 72 79 70 74 6f 5f 63 6d 73 00 00 02 d1 4a 17 crypto_cms....J. 00000110: 4a cc 00 21 6e 65 74 5f 72 69 6d 5f 70 6c 61 74 J..!net_rim_plat 00000120: 66 6f 72 6d 61 70 70 73 5f 72 65 73 6f 75 72 63 formapps_resourc 00000130: 65 5f 5f 66 72 00 00 02 d2 4a 17 4a ef 00 21 6e e__fr....J.J..!n 00000140: 65 74 5f 72 69 6d 5f 70 6c 61 74 66 6f 72 6d 61 et_rim_platforma 00000150: 70 70 73 5f 72 65 73 6f 75 72 63 65 5f 5f 65 6e pps_resource__en 00000160: 00 00 02 d3 4a 17 51 1e 00 13 6e 65 74 5f 72 69 ....J.Q...net_ri 00000170: 6d 5f 62 62 5f 74 61 73 6b 5f 61 70 70 00 00 02 m_bb_task_app... 00000180: d4 4a 17 57 54 00 14 6e 65 74 5f 72 69 6d 5f 62 .J.WT..net_rim_b 00000190: 62 5f 73 6d 69 6d 65 5f 6c 69 62 00 00 02 d5 4a b_smime_lib....J 000001a0: 17 57 40 00 2b 6e 65 74 5f 72 69 6d 5f 63 72 79 .W@.+net_rim_cry 000001b0: 70 74 6f 5f 6b 65 79 73 74 6f 72 65 5f 62 72 6f pto_keystore_bro 000001c0: 77 73 65 72 5f 63 65 72 74 69 66 69 63 61 74 65 wser_certificate 000001d0: 00 00 02 d6 4a 17 55 8e 00 13 6e 65 74 5f 72 69 ....J.U...net_ri 000001e0: 6d 5f 62 62 5f 73 75 70 6c 5f 61 70 70 00 00 02 m_bb_supl_app... 000001f0: d7 4a 17 4f 53 00 14 6e 65 74 5f 72 69 6d 5f 73 .J.OS..net_rim_s 00000200: 65 31 33 6e 65 74 74 61 62 6c 65 00 00 02 d8 4a e13nettable....J 00000210: 17 55 2c 00 15 6e 65 74 5f 72 69 6d 5f 62 62 5f .U,..net_rim_bb_ 00000220: 64 69 61 67 6e 6f 73 74 69 63 00 00 02 d9 4a 17 diagnostic....J. 00000230: 54 ac 00 0b 6e 65 74 5f 72 69 6d 5f 76 61 64 00 T...net_rim_vad. 00000240: 00 02 da 4a 17 50 bc 00 15 6e 65 74 5f 72 69 6d ...J.P...net_rim 00000250: 5f 62 62 5f 72 69 63 68 5f 65 6d 61 69 6c 00 00 _bb_rich_email.. 00000260: 02 db 4a 17 53 29 00 15 6e 65 74 5f 72 69 6d 5f ..J.S)..net_rim_ 00000270: 4d 49 44 50 52 6f 6f 74 43 65 72 74 73 00 00 02 MIDPRootCerts... 00000280: dc 4a 17 55 95 00 18 6e 65 74 5f 72 69 6d 5f 62 .J.U...net_rim_b 00000290: 62 5f 76 69 64 65 6f 72 65 63 6f 72 64 65 72 00 b_videorecorder. 000002a0: 00 02 dd 4a 17 51 19 00 17 6e 65 74 5f 72 69 6d ...J.Q...net_rim 000002b0: 5f 62 62 5f 63 61 6c 65 6e 64 61 72 5f 6f 74 61 _bb_calendar_ota 000002c0: 00 00 02 de 4a 17 4a bf 00 15 6e 65 74 5f 72 69 ....J.J...net_ri 000002d0: 6d 5f 73 65 72 76 69 63 65 73 5f 69 6d 70 6c 00 m_services_impl. 000002e0: 00 02 df 4a 17 4a 03 00 18 6e 65 74 5f 72 69 6d ...J.J...net_rim 000002f0: 5f 70 72 6f 63 65 73 73 5f 6c 61 75 6e 63 68 65 _process_launche 00000300: 72 00 00 02 e0 4a 17 56 7c 00 19 6e 65 74 5f 72 r....J.V|..net_r 00000310: 69 6d 5f 62 62 5f 70 61 73 73 77 6f 72 64 6b 65 im_bb_passwordke 00000320: 65 70 65 72 00 00 02 e1 4a 17 4b 22 00 15 6e 65 eper....J.K"..ne 00000330: 74 5f 72 69 6d 5f 62 62 5f 72 69 62 62 6f 6e 5f t_rim_bb_ribbon_ 00000340: 6c 69 62 00 00 02 e2 4a 17 51 7b 00 23 6e 65 74 lib....J.Q{.#net 00000350: 5f 72 69 6d 5f 70 6c 61 7a 6d 69 63 5f 6d 65 64 _rim_plazmic_med 00000360: 69 61 65 6e 67 69 6e 65 5f 73 6d 69 6c 5f 30 30 iaengine_smil_00 00000370: 00 00 02 e3 4a 17 55 80 00 0f 6e 65 74 5f 72 69 ....J.U...net_ri 00000380: 6d 5f 62 62 5f 69 6f 74 61 00 00 02 e4 4a 17 4f m_bb_iota....J.O 00000390: e3 00 30 6e 65 74 5f 72 69 6d 5f 64 65 76 69 63 ..0net_rim_devic 000003a0: 65 5f 61 70 70 73 5f 67 61 6d 65 73 5f 77 6f 72 e_apps_games_wor 000003b0: 64 6d 6f 6c 65 5f 72 65 73 6f 75 72 63 65 73 5f dmole_resources_ 000003c0: 5f 66 72 00 00 02 e5 4a 17 4a 40 00 1d 6e 65 74 _fr....J.J@..net 000003d0: 5f 72 69 6d 5f 70 6c 61 74 66 6f 72 6d 5f 72 65 _rim_platform_re 000003e0: 73 6f 75 72 63 65 5f 5f 66 72 00 00 02 e6 source__fr.... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 164 00000000: 05 00 0b 00 00 05 8d 00 00 02 e6 ........... <<< URB 144 00000000: 00 00 0c 00 13 05 01 00 1c 00 00 00 ............ <<< URB 146 00000000: 05 00 06 00 03 dc ...... <<< URB 147 00000000: 05 00 e0 03 00 00 00 19 00 00 02 e6 4a 17 56 2a ............J.V* 00000010: 00 22 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 65 74 ."net_rim_bb_set 00000020: 75 70 77 69 7a 61 72 64 5f 69 6d 61 67 65 73 5f upwizard_images_ 00000030: 39 35 30 30 00 00 02 e7 4a 17 55 11 00 15 6e 65 9500....J.U...ne 00000040: 74 5f 72 69 6d 5f 62 62 5f 69 6d 70 6c 75 73 5f t_rim_bb_implus_ 00000050: 61 70 70 00 00 02 e8 4a 17 51 a3 00 19 6e 65 74 app....J.Q...net 00000060: 5f 72 69 6d 5f 62 62 61 70 69 5f 6d 65 73 73 61 _rim_bbapi_messa 00000070: 67 65 6c 69 73 74 00 00 02 e9 4a 17 55 9f 00 16 gelist....J.U... 00000080: 6e 65 74 5f 72 69 6d 5f 62 62 61 70 69 5f 6d 65 net_rim_bbapi_me 00000090: 6e 75 69 74 65 6d 00 00 02 ea 4a 17 4f c1 00 23 nuitem....J.O..# 000000a0: 6e 65 74 5f 72 69 6d 5f 62 62 61 70 69 5f 6d 65 net_rim_bbapi_me 000000b0: 73 73 61 67 65 6c 69 73 74 5f 72 65 73 6f 75 72 ssagelist_resour 000000c0: 63 65 73 00 00 02 eb 4a 17 52 e9 00 2c 6e 65 74 ces....J.R..,net 000000d0: 5f 72 69 6d 5f 74 69 64 5f 64 79 6e 61 6d 69 63 _rim_tid_dynamic 000000e0: 5f 6c 69 6e 67 5f 64 61 74 61 5f 65 6e 67 6c 69 _ling_data_engli 000000f0: 73 68 5f 67 62 5f 6c 74 72 00 00 02 ec 4a 17 4f sh_gb_ltr....J.O 00000100: e1 00 30 6e 65 74 5f 72 69 6d 5f 64 65 76 69 63 ..0net_rim_devic 00000110: 65 5f 61 70 70 73 5f 67 61 6d 65 73 5f 77 6f 72 e_apps_games_wor 00000120: 64 6d 6f 6c 65 5f 72 65 73 6f 75 72 63 65 73 5f dmole_resources_ 00000130: 5f 65 6e 00 00 02 ed 4a 17 4a 6f 00 1d 6e 65 74 _en....J.Jo..net 00000140: 5f 72 69 6d 5f 70 6c 61 74 66 6f 72 6d 5f 72 65 _rim_platform_re 00000150: 73 6f 75 72 63 65 5f 5f 65 6e 00 00 02 ee 4a 17 source__en....J. 00000160: 55 7f 00 0f 6e 65 74 5f 72 69 6d 5f 62 62 5f 68 U...net_rim_bb_h 00000170: 65 6c 70 00 00 02 ef 4a 17 4a f2 00 24 6e 65 74 elp....J.J..$net 00000180: 5f 72 69 6d 5f 70 6c 61 74 66 6f 72 6d 61 70 70 _rim_platformapp 00000190: 73 5f 72 65 73 6f 75 72 63 65 5f 5f 65 6e 5f 47 s_resource__en_G 000001a0: 42 00 00 02 f0 4a 17 4a 75 00 21 6e 65 74 5f 72 B....J.Ju.!net_r 000001b0: 69 6d 5f 70 6c 61 7a 6d 69 63 5f 6d 65 64 69 61 im_plazmic_media 000001c0: 65 6e 67 69 6e 65 5f 70 6d 65 30 32 00 00 02 f1 engine_pme02.... 000001d0: 4a 17 50 7f 00 14 6e 65 74 5f 72 69 6d 5f 62 62 J.P...net_rim_bb 000001e0: 5f 6f 74 61 73 6c 5f 61 70 70 00 00 02 f2 4a 17 _otasl_app....J. 000001f0: 53 0f 00 2c 6e 65 74 5f 72 69 6d 5f 74 69 64 5f S..,net_rim_tid_ 00000200: 64 79 6e 61 6d 69 63 5f 6c 69 6e 67 5f 64 61 74 dynamic_ling_dat 00000210: 61 5f 65 6e 67 6c 69 73 68 5f 75 73 5f 6c 74 72 a_english_us_ltr 00000220: 00 00 02 f3 4a 17 54 38 00 1d 6e 65 74 5f 72 69 ....J.T8..net_ri 00000230: 6d 5f 62 62 5f 6d 61 6e 61 67 65 5f 63 6f 6e 6e m_bb_manage_conn 00000240: 65 63 74 69 6f 6e 73 00 00 02 f4 4a 17 4b 29 00 ections....J.K). 00000250: 1d 6e 65 74 5f 72 69 6d 5f 62 62 5f 70 68 6f 6e .net_rim_bb_phon 00000260: 65 5f 63 64 6d 61 5f 73 65 72 76 69 63 65 00 00 e_cdma_service.. 00000270: 02 f5 4a 17 50 5e 00 13 6e 65 74 5f 72 69 6d 5f ..J.P^..net_rim_ 00000280: 62 62 5f 6d 65 6d 6f 5f 61 70 70 00 00 02 f6 4a bb_memo_app....J 00000290: 17 4b 0f 00 18 6e 65 74 5f 72 69 6d 5f 62 62 5f .K...net_rim_bb_ 000002a0: 6d 65 73 73 61 67 69 6e 67 5f 61 70 70 00 00 02 messaging_app... 000002b0: f7 4a 17 54 1c 00 11 6e 65 74 5f 72 69 6d 5f 62 .J.T...net_rim_b 000002c0: 62 5f 67 70 73 5f 65 65 00 00 02 f8 4a 17 57 26 b_gps_ee....J.W& 000002d0: 00 15 6e 65 74 5f 72 69 6d 5f 73 6d 61 72 74 63 ..net_rim_smartc 000002e0: 61 72 64 5f 70 69 76 00 00 02 f9 4a 17 50 84 00 ard_piv....J.P.. 000002f0: 23 6e 65 74 5f 72 69 6d 5f 62 62 5f 61 64 64 72 #net_rim_bb_addr 00000300: 65 73 73 62 6f 6f 6b 5f 67 72 6f 75 70 61 64 64 essbook_groupadd 00000310: 72 65 73 73 00 00 02 fa 4a 17 54 a8 00 1a 6e 65 ress....J.T...ne 00000320: 74 5f 72 69 6d 5f 62 62 5f 72 65 6d 69 6e 64 65 t_rim_bb_reminde 00000330: 72 6d 61 6e 61 67 65 72 00 00 02 fb 4a 17 54 a1 rmanager....J.T. 00000340: 00 1f 6e 65 74 5f 72 69 6d 5f 62 62 5f 6f 70 74 ..net_rim_bb_opt 00000350: 69 6f 6e 73 5f 66 61 73 74 45 75 72 6f 70 65 61 ions_fastEuropea 00000360: 6e 00 00 02 fc 4a 17 54 3d 00 27 6e 65 74 5f 72 n....J.T=.'net_r 00000370: 69 6d 5f 62 62 5f 6f 70 74 69 6f 6e 73 5f 63 75 im_bb_options_cu 00000380: 73 74 6f 6d 77 6f 72 64 6c 69 73 74 73 63 72 65 stomwordlistscre 00000390: 65 6e 00 00 02 fd 4a 17 50 cd 00 1b 6e 65 74 5f en....J.P...net_ 000003a0: 72 69 6d 5f 62 62 5f 66 69 6c 65 69 6e 64 65 78 rim_bb_fileindex 000003b0: 73 65 72 76 69 63 65 00 00 02 fe 4a 17 52 b7 00 service....J.R.. 000003c0: 1b 6e 65 74 5f 72 69 6d 5f 63 72 79 70 74 6f 5f .net_rim_crypto_ 000003d0: 72 65 73 6f 75 72 63 65 5f 5f 66 72 00 00 02 ff resource__fr.... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 168 00000000: 05 00 0b 00 00 05 8d 00 00 02 ff ........... <<< URB 148 00000000: 00 00 0c 00 13 05 01 00 1d 00 00 00 ............ <<< URB 150 00000000: 05 00 06 00 03 e1 ...... <<< URB 151 00000000: 05 00 e5 03 00 00 00 1c 00 00 02 ff 4a 17 4a 97 ............J.J. 00000010: 00 19 6e 65 74 5f 72 69 6d 5f 62 62 5f 73 79 73 ..net_rim_bb_sys 00000020: 74 65 6d 5f 73 6d 69 6c 65 79 73 00 00 03 00 4a tem_smileys....J 00000030: 17 50 ad 00 1b 6e 65 74 5f 72 69 6d 5f 62 62 5f .P...net_rim_bb_ 00000040: 67 6c 6f 62 61 6c 73 65 61 72 63 68 5f 61 70 70 globalsearch_app 00000050: 00 00 03 01 49 f2 29 9a 00 1e 6e 65 74 5f 72 69 ....I.)...net_ri 00000060: 6d 5f 62 62 5f 71 6d 5f 70 65 65 72 5f 72 65 73 m_bb_qm_peer_res 00000070: 6f 75 72 63 65 5f 66 72 00 00 03 02 4a 17 50 da ource_fr....J.P. 00000080: 00 19 6e 65 74 5f 72 69 6d 5f 62 62 5f 70 72 6f ..net_rim_bb_pro 00000090: 66 69 6c 65 73 5f 74 75 6e 65 73 00 00 03 03 4a files_tunes....J 000000a0: 17 52 b0 00 1b 6e 65 74 5f 72 69 6d 5f 63 72 79 .R...net_rim_cry 000000b0: 70 74 6f 5f 72 65 73 6f 75 72 63 65 5f 5f 65 6e pto_resource__en 000000c0: 00 00 03 04 4a 17 50 0b 00 21 6e 65 74 5f 72 69 ....J.P..!net_ri 000000d0: 6d 5f 62 62 5f 73 74 61 6e 64 61 72 64 63 61 6c m_bb_standardcal 000000e0: 63 75 6c 61 74 6f 72 5f 61 70 70 00 00 03 05 4a culator_app....J 000000f0: 17 57 22 00 19 6e 65 74 5f 72 69 6d 5f 73 6d 61 .W"..net_rim_sma 00000100: 72 74 63 61 72 64 5f 64 61 74 61 6b 65 79 00 00 rtcard_datakey.. 00000110: 03 06 4a 17 53 f9 00 0e 6e 65 74 5f 72 69 6d 5f ..J.S...net_rim_ 00000120: 62 62 5f 65 6c 74 00 00 03 07 49 f2 29 91 00 1e bb_elt....I.)... 00000130: 6e 65 74 5f 72 69 6d 5f 62 62 5f 71 6d 5f 70 65 net_rim_bb_qm_pe 00000140: 65 72 5f 72 65 73 6f 75 72 63 65 5f 65 6e 00 00 er_resource_en.. 00000150: 03 08 4a 17 56 f5 00 20 6e 65 74 5f 72 69 6d 5f ..J.V.. net_rim_ 00000160: 73 65 63 75 72 65 65 6d 61 69 6c 5f 72 65 73 6f secureemail_reso 00000170: 75 72 63 65 5f 5f 65 6e 00 00 03 09 4a 17 51 56 urce__en....J.QV 00000180: 00 17 6e 65 74 5f 72 69 6d 5f 62 62 5f 64 6f 63 ..net_rim_bb_doc 00000190: 76 69 65 77 69 6d 61 67 65 00 00 03 0a 4a 17 51 viewimage....J.Q 000001a0: f9 00 1c 6e 65 74 5f 72 69 6d 5f 72 75 6e 74 69 ...net_rim_runti 000001b0: 6d 65 5f 72 65 73 6f 75 72 63 65 5f 5f 66 72 00 me_resource__fr. 000001c0: 00 03 0b 4a 17 54 e9 00 13 6e 65 74 5f 72 69 6d ...J.T...net_rim 000001d0: 5f 62 62 5f 70 69 6e 67 5f 61 70 70 00 00 03 0c _bb_ping_app.... 000001e0: 4a 17 50 45 00 14 6e 65 74 5f 72 69 6d 5f 62 62 J.PE..net_rim_bb 000001f0: 5f 61 6c 61 72 6d 5f 61 70 70 00 00 03 0d 4a 17 _alarm_app....J. 00000200: 4f eb 00 14 6e 65 74 5f 72 69 6d 5f 62 62 5f 61 O...net_rim_bb_a 00000210: 6c 61 72 6d 5f 6c 69 62 00 00 03 0e 4a 17 52 80 larm_lib....J.R. 00000220: 00 1c 6e 65 74 5f 72 69 6d 5f 65 76 65 6e 74 5f ..net_rim_event_ 00000230: 6c 6f 67 5f 76 69 65 77 65 72 5f 61 70 70 00 00 log_viewer_app.. 00000240: 03 0f 4a 17 52 70 00 1b 6e 65 74 5f 72 69 6d 5f ..J.Rp..net_rim_ 00000250: 63 6c 64 63 5f 69 6d 70 6c 5f 73 6f 66 74 74 6f cldc_impl_softto 00000260: 6b 65 6e 00 00 03 10 45 77 3a ac 00 15 6e 65 74 ken....Ew:...net 00000270: 5f 72 69 6d 5f 72 69 6d 73 65 63 75 72 69 64 6c _rim_rimsecuridl 00000280: 69 62 00 00 03 11 45 6c 51 07 00 0a 53 65 63 75 ib....ElQ...Secu 00000290: 72 49 44 4c 69 62 00 00 03 12 4a 17 4f 4d 00 1c rIDLib....J.OM.. 000002a0: 6e 65 74 5f 72 69 6d 5f 72 75 6e 74 69 6d 65 5f net_rim_runtime_ 000002b0: 72 65 73 6f 75 72 63 65 5f 5f 65 6e 00 00 03 13 resource__en.... 000002c0: 4a 17 53 ce 00 1c 6e 65 74 5f 72 69 6d 5f 62 62 J.S...net_rim_bb 000002d0: 5f 61 64 64 72 65 73 73 62 6f 6f 6b 5f 76 63 61 _addressbook_vca 000002e0: 72 64 00 00 03 14 4a 17 54 ec 00 1e 6e 65 74 5f rd....J.T...net_ 000002f0: 72 69 6d 5f 62 62 5f 61 70 70 6c 69 63 61 74 69 rim_bb_applicati 00000300: 6f 6e 64 65 6c 69 76 65 72 79 00 00 03 15 4a 17 ondelivery....J. 00000310: 54 25 00 1b 6e 65 74 5f 72 69 6d 5f 62 62 5f 6c T%..net_rim_bb_l 00000320: 62 73 5f 72 65 73 6f 75 72 63 65 5f 5f 66 72 00 bs_resource__fr. 00000330: 00 03 16 4a 17 4a 6c 00 19 6e 65 74 5f 72 69 6d ...J.Jl..net_rim 00000340: 5f 70 6c 61 74 66 6f 72 6d 5f 72 65 73 6f 75 72 _platform_resour 00000350: 63 65 00 00 03 17 4a 17 57 48 00 1c 6e 65 74 5f ce....J.WH..net_ 00000360: 72 69 6d 5f 62 62 5f 6c 64 61 70 5f 62 72 6f 77 rim_bb_ldap_brow 00000370: 73 65 72 5f 78 35 30 39 00 00 03 18 4a 17 56 f9 ser_x509....J.V. 00000380: 00 20 6e 65 74 5f 72 69 6d 5f 73 65 63 75 72 65 . net_rim_secure 00000390: 65 6d 61 69 6c 5f 72 65 73 6f 75 72 63 65 5f 5f email_resource__ 000003a0: 66 72 00 00 03 19 4a 17 54 45 00 16 6e 65 74 5f fr....J.TE..net_ 000003b0: 72 69 6d 5f 62 62 5f 70 72 6c 5f 75 70 67 72 61 rim_bb_prl_upgra 000003c0: 64 65 00 00 03 1a 4a 17 4b 3e 00 15 6e 65 74 5f de....J.K>..net_ 000003d0: 72 69 6d 5f 63 65 6c 6c 62 72 6f 61 64 63 61 73 rim_cellbroadcas 000003e0: 74 00 00 03 1b t.... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 172 00000000: 05 00 0b 00 00 05 8d 00 00 03 1b ........... <<< URB 152 00000000: 00 00 0c 00 13 05 01 00 1e 00 00 00 ............ <<< URB 154 00000000: 05 00 06 00 03 d4 ...... <<< URB 155 00000000: 05 00 d8 03 00 00 00 1a 00 00 03 1b 4a 17 54 23 ............J.T# 00000010: 00 1b 6e 65 74 5f 72 69 6d 5f 62 62 5f 6c 62 73 ..net_rim_bb_lbs 00000020: 5f 72 65 73 6f 75 72 63 65 5f 5f 65 6e 00 00 03 _resource__en... 00000030: 1c 4a 17 56 79 00 11 6e 65 74 5f 72 69 6d 5f 62 .J.Vy..net_rim_b 00000040: 62 5f 6d 63 5f 61 70 70 00 00 03 1d 4a 17 57 25 b_mc_app....J.W% 00000050: 00 18 6e 65 74 5f 72 69 6d 5f 73 6d 61 72 74 63 ..net_rim_smartc 00000060: 61 72 64 5f 67 73 61 63 61 63 00 00 03 1e 4a 17 ard_gsacac....J. 00000070: 51 99 00 24 6e 65 74 5f 72 69 6d 5f 70 6c 61 7a Q..$net_rim_plaz 00000080: 6d 69 63 5f 6d 65 64 69 61 65 6e 67 69 6e 65 5f mic_mediaengine_ 00000090: 73 6d 69 6c 5f 6d 6d 73 00 00 03 1f 4a 17 50 d5 smil_mms....J.P. 000000a0: 00 1d 6e 65 74 5f 72 69 6d 5f 62 62 5f 6d 65 64 ..net_rim_bb_med 000000b0: 69 61 6c 69 62 72 61 72 79 70 6c 61 79 65 72 00 ialibraryplayer. 000000c0: 00 03 20 4a 17 54 e7 00 18 6e 65 74 5f 72 69 6d .. J.T...net_rim 000000d0: 5f 62 62 5f 64 6e 73 6c 6f 6f 6b 75 70 5f 61 70 _bb_dnslookup_ap 000000e0: 70 00 00 03 21 4a 17 4a bb 00 13 6e 65 74 5f 72 p...!J.J...net_r 000000f0: 69 6d 5f 65 73 63 72 65 65 6e 5f 61 70 70 00 00 im_escreen_app.. 00000100: 03 22 4a 17 57 45 00 1b 6e 65 74 5f 72 69 6d 5f ."J.WE..net_rim_ 00000110: 62 62 5f 6c 64 61 70 5f 62 72 6f 77 73 65 72 5f bb_ldap_browser_ 00000120: 70 67 70 00 00 03 23 4a 17 54 a8 00 1a 6e 65 74 pgp...#J.T...net 00000130: 5f 72 69 6d 5f 73 6f 66 74 74 6f 6b 65 6e 73 5f _rim_softtokens_ 00000140: 6f 70 74 69 6f 6e 73 00 00 03 24 4a 17 55 6b 00 options...$J.Uk. 00000150: 16 6e 65 74 5f 72 69 6d 5f 62 62 61 70 69 5f 70 .net_rim_bbapi_p 00000160: 69 6d 5f 74 6f 64 6f 00 00 03 25 4a 17 55 99 00 im_todo...%J.U.. 00000170: 1d 6e 65 74 5f 72 69 6d 5f 74 69 64 5f 6e 65 77 .net_rim_tid_new 00000180: 57 6f 72 64 73 45 78 74 72 61 63 74 6f 72 00 00 WordsExtractor.. 00000190: 03 26 4a 17 54 48 00 13 6e 65 74 5f 72 69 6d 5f .&J.TH..net_rim_ 000001a0: 62 62 5f 72 65 73 6f 75 72 63 65 00 00 03 27 4a bb_resource...'J 000001b0: 17 50 d2 00 1e 6e 65 74 5f 72 69 6d 5f 62 62 5f .P...net_rim_bb_ 000001c0: 6d 65 64 69 61 63 6f 6e 74 65 6e 74 68 61 6e 64 mediacontenthand 000001d0: 6c 65 72 00 00 03 28 4a 17 56 d3 00 1e 6e 65 74 ler...(J.V...net 000001e0: 5f 72 69 6d 5f 62 62 5f 63 72 79 70 74 6f 5f 72 _rim_bb_crypto_r 000001f0: 65 73 6f 75 72 63 65 5f 5f 66 72 00 00 03 29 4a esource__fr...)J 00000200: 17 51 ad 00 22 6e 65 74 5f 72 69 6d 5f 61 70 70 .Q.."net_rim_app 00000210: 73 5f 69 6e 74 65 72 6e 61 6c 5f 62 72 6f 77 73 s_internal_brows 00000220: 65 72 5f 73 6d 69 6c 00 00 03 2a 4a 17 56 cd 00 er_smil...*J.V.. 00000230: 1e 6e 65 74 5f 72 69 6d 5f 62 62 5f 63 72 79 70 .net_rim_bb_cryp 00000240: 74 6f 5f 72 65 73 6f 75 72 63 65 5f 5f 65 6e 00 to_resource__en. 00000250: 00 03 2b 4a 17 54 ac 00 1a 6e 65 74 5f 72 69 6d ..+J.T...net_rim 00000260: 5f 62 62 5f 73 65 63 75 72 69 74 79 6d 6f 6e 69 _bb_securitymoni 00000270: 74 6f 72 00 00 03 2c 4a 17 4a 1a 00 20 6e 65 74 tor...,J.J.. net 00000280: 5f 72 69 6d 5f 70 6c 61 74 66 6f 72 6d 5f 69 6d _rim_platform_im 00000290: 5f 72 65 73 6f 75 72 63 65 5f 5f 66 72 00 00 03 _resource__fr... 000002a0: 2d 4a 17 51 a9 00 1b 6e 65 74 5f 72 69 6d 5f 62 -J.Q...net_rim_b 000002b0: 62 61 70 69 5f 73 74 72 69 6e 67 70 61 74 74 65 bapi_stringpatte 000002c0: 72 6e 00 00 03 2e 4a 17 53 ba 00 22 6e 65 74 5f rn....J.S.."net_ 000002d0: 72 69 6d 5f 62 62 5f 64 69 61 67 6e 6f 73 74 69 rim_bb_diagnosti 000002e0: 63 5f 72 65 73 6f 75 72 63 65 5f 5f 66 72 00 00 c_resource__fr.. 000002f0: 03 2f 4a 17 4b 1f 00 17 6e 65 74 5f 72 69 6d 5f ./J.K...net_rim_ 00000300: 62 62 5f 70 72 6f 66 69 6c 65 73 5f 61 70 70 00 bb_profiles_app. 00000310: 00 03 30 4a 17 55 21 00 21 6e 65 74 5f 72 69 6d ..0J.U!.!net_rim 00000320: 5f 62 62 5f 62 72 6f 77 73 65 72 5f 70 6c 75 67 _bb_browser_plug 00000330: 69 6e 5f 64 6f 63 76 69 65 77 00 00 03 31 4a 17 in_docview...1J. 00000340: 53 b6 00 22 6e 65 74 5f 72 69 6d 5f 62 62 5f 64 S.."net_rim_bb_d 00000350: 69 61 67 6e 6f 73 74 69 63 5f 72 65 73 6f 75 72 iagnostic_resour 00000360: 63 65 5f 5f 65 6e 00 00 03 32 4a 17 50 0e 00 13 ce__en...2J.P... 00000370: 6e 65 74 5f 72 69 6d 5f 74 63 70 5f 6f 70 74 69 net_rim_tcp_opti 00000380: 6f 6e 73 00 00 03 33 4a 17 54 3b 00 22 6e 65 74 ons...3J.T;."net 00000390: 5f 72 69 6d 5f 62 62 5f 70 72 65 6c 6f 61 64 65 _rim_bb_preloade 000003a0: 64 5f 6d 65 64 69 61 5f 63 72 61 77 6c 65 72 00 d_media_crawler. 000003b0: 00 03 34 4a 17 54 18 00 1b 6e 65 74 5f 72 69 6d ..4J.T...net_rim 000003c0: 5f 62 62 5f 65 6e 74 65 72 70 72 69 73 65 63 6f _bb_enterpriseco 000003d0: 6e 66 69 67 00 00 03 35 nfig...5 Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 176 00000000: 05 00 0b 00 00 05 8d 00 00 03 35 ..........5 <<< URB 156 00000000: 00 00 0c 00 13 05 01 00 1f 00 00 00 ............ <<< URB 158 00000000: 05 00 06 00 03 e1 ...... <<< URB 159 00000000: 05 00 e5 03 00 00 00 1a 00 00 03 35 4a 17 4a b7 ...........5J.J. 00000010: 00 1b 6e 65 74 5f 72 69 6d 5f 61 70 70 5f 6d 61 ..net_rim_app_ma 00000020: 6e 61 67 65 72 5f 63 6f 6e 73 6f 6c 65 00 00 03 nager_console... 00000030: 36 4a 17 56 62 00 1c 6e 65 74 5f 72 69 6d 5f 62 6J.Vb..net_rim_b 00000040: 62 5f 6c 64 61 70 5f 72 65 73 6f 75 72 63 65 5f b_ldap_resource_ 00000050: 5f 66 72 00 00 03 37 4a 17 4b 58 00 1f 6e 65 74 _fr...7J.KX..net 00000060: 5f 72 69 6d 5f 65 63 6d 61 73 63 72 69 70 74 5f _rim_ecmascript_ 00000070: 72 65 73 6f 75 72 63 65 5f 5f 65 6e 00 00 03 38 resource__en...8 00000080: 4a 17 57 2f 00 22 6e 65 74 5f 72 69 6d 5f 62 62 J.W/."net_rim_bb 00000090: 5f 62 72 6f 77 73 65 72 5f 70 6c 75 67 69 6e 5f _browser_plugin_ 000000a0: 73 65 63 75 72 69 74 79 00 00 03 39 4a 17 4a aa security...9J.J. 000000b0: 00 14 6e 65 74 5f 72 69 6d 5f 63 6c 64 63 5f 69 ..net_rim_cldc_i 000000c0: 6f 5f 69 6d 70 6c 00 00 03 3a 4a 17 4a b1 00 14 o_impl...:J.J... 000000d0: 6e 65 74 5f 72 69 6d 5f 62 62 5f 74 69 6d 65 7a net_rim_bb_timez 000000e0: 6f 6e 65 73 00 00 03 3b 4a 17 56 5d 00 1c 6e 65 ones...;J.V]..ne 000000f0: 74 5f 72 69 6d 5f 62 62 5f 6c 64 61 70 5f 72 65 t_rim_bb_ldap_re 00000100: 73 6f 75 72 63 65 5f 5f 65 6e 00 00 03 3c 4a 17 source__en... 00000150: 4a 17 52 6c 00 1a 6e 65 74 5f 72 69 6d 5f 74 69 J.Rl..net_rim_ti 00000160: 64 5f 77 6f 72 64 73 5f 69 6e 6a 65 63 74 6f 72 d_words_injector 00000170: 00 00 03 3f 4a 17 56 8a 00 26 6e 65 74 5f 72 69 ...?J.V..&net_ri 00000180: 6d 5f 62 62 5f 70 61 73 73 77 6f 72 64 6b 65 65 m_bb_passwordkee 00000190: 70 65 72 5f 72 65 73 6f 75 72 63 65 5f 5f 66 72 per_resource__fr 000001a0: 00 00 03 40 4a 17 49 e8 00 20 6e 65 74 5f 72 69 ...@J.I.. net_ri 000001b0: 6d 5f 70 6c 61 74 66 6f 72 6d 5f 69 6d 5f 72 65 m_platform_im_re 000001c0: 73 6f 75 72 63 65 5f 5f 65 6e 00 00 03 41 4a 17 source__en...AJ. 000001d0: 4a a7 00 28 6e 65 74 5f 72 69 6d 5f 62 62 5f 61 J..(net_rim_bb_a 000001e0: 70 70 6c 69 63 61 74 69 6f 6e 5f 70 65 72 6d 69 pplication_permi 000001f0: 73 73 69 6f 6e 73 5f 70 72 6f 78 79 00 00 03 42 ssions_proxy...B 00000200: 4a 17 56 86 00 26 6e 65 74 5f 72 69 6d 5f 62 62 J.V..&net_rim_bb 00000210: 5f 70 61 73 73 77 6f 72 64 6b 65 65 70 65 72 5f _passwordkeeper_ 00000220: 72 65 73 6f 75 72 63 65 5f 5f 65 6e 00 00 03 43 resource__en...C 00000230: 4a 17 53 d0 00 11 6e 65 74 5f 72 69 6d 5f 62 62 J.S...net_rim_bb 00000240: 5f 62 61 6e 6e 65 72 00 00 03 44 4a 17 54 51 00 _banner...DJ.TQ. 00000250: 1a 6e 65 74 5f 72 69 6d 5f 62 62 5f 72 65 73 6f .net_rim_bb_reso 00000260: 75 72 63 65 5f 5f 65 6e 5f 47 42 00 00 03 45 4a urce__en_GB...EJ 00000270: 17 54 d5 00 18 6e 65 74 5f 72 69 6d 5f 76 61 64 .T...net_rim_vad 00000280: 5f 72 65 73 6f 75 72 63 65 5f 5f 66 72 00 00 03 _resource__fr... 00000290: 46 4a 17 54 d0 00 18 6e 65 74 5f 72 69 6d 5f 76 FJ.T...net_rim_v 000002a0: 61 64 5f 72 65 73 6f 75 72 63 65 5f 5f 65 6e 00 ad_resource__en. 000002b0: 00 03 47 4a 17 4a a7 00 24 6e 65 74 5f 72 69 6d ..GJ.J..$net_rim 000002c0: 5f 62 62 5f 74 72 75 73 74 5f 61 70 70 6c 69 63 _bb_trust_applic 000002d0: 61 74 69 6f 6e 5f 6d 61 6e 61 67 65 72 00 00 03 ation_manager... 000002e0: 48 4a 17 54 41 00 28 6e 65 74 5f 72 69 6d 5f 62 HJ.TA.(net_rim_b 000002f0: 62 5f 6f 70 74 69 6f 6e 73 5f 53 70 65 6c 6c 63 b_options_Spellc 00000300: 68 65 63 6b 61 62 6c 65 4f 70 74 69 6f 6e 73 00 heckableOptions. 00000310: 00 03 49 4a 17 4b 3b 00 16 6e 65 74 5f 72 69 6d ..IJ.K;..net_rim 00000320: 5f 62 62 5f 70 68 6f 6e 65 5f 65 6e 74 72 79 00 _bb_phone_entry. 00000330: 00 03 4a 4a 17 4a ef 00 1d 6e 65 74 5f 72 69 6d ..JJ.J...net_rim 00000340: 5f 70 6c 61 74 66 6f 72 6d 61 70 70 73 5f 72 65 _platformapps_re 00000350: 73 6f 75 72 63 65 00 00 03 4b 4a 17 4f 54 00 18 source...KJ.OT.. 00000360: 6e 65 74 5f 72 69 6d 5f 72 75 6e 74 69 6d 65 5f net_rim_runtime_ 00000370: 72 65 73 6f 75 72 63 65 00 00 03 4c 4a 17 53 b1 resource...LJ.S. 00000380: 00 15 6e 65 74 5f 72 69 6d 5f 62 62 61 70 69 5f ..net_rim_bbapi_ 00000390: 6f 70 74 69 6f 6e 73 00 00 03 4d 4a 17 4b 27 00 options...MJ.K'. 000003a0: 1f 6e 65 74 5f 72 69 6d 5f 62 62 5f 70 68 6f 6e .net_rim_bb_phon 000003b0: 65 5f 63 61 6c 6c 5f 6c 6f 67 5f 65 6e 74 72 79 e_call_log_entry 000003c0: 00 00 03 4e 4a 17 52 a7 00 17 6e 65 74 5f 72 69 ...NJ.R...net_ri 000003d0: 6d 5f 63 72 79 70 74 6f 5f 72 65 73 6f 75 72 63 m_crypto_resourc 000003e0: 65 00 00 03 4f e...O Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 180 00000000: 05 00 0b 00 00 05 8d 00 00 03 4f ..........O <<< URB 160 00000000: 00 00 0c 00 13 05 01 00 20 00 00 00 ........ ... <<< URB 162 00000000: 05 00 06 00 03 e3 ...... <<< URB 163 00000000: 05 00 e7 03 00 00 00 19 00 00 03 4f 4a 17 54 93 ...........OJ.T. 00000010: 00 19 6e 65 74 5f 72 69 6d 5f 62 62 61 70 69 5f ..net_rim_bbapi_ 00000020: 70 69 6d 5f 72 65 73 5f 5f 66 72 00 00 03 50 4a pim_res__fr...PJ 00000030: 17 52 4a 00 2b 6e 65 74 5f 72 69 6d 5f 74 69 64 .RJ.+net_rim_tid 00000040: 5f 64 79 6e 61 6d 69 63 5f 74 72 61 6e 73 63 6f _dynamic_transco 00000050: 64 69 6e 67 5f 64 61 74 61 5f 43 50 31 32 35 30 ding_data_CP1250 00000060: 00 00 03 51 4a 17 50 37 00 19 6e 65 74 5f 72 69 ...QJ.P7..net_ri 00000070: 6d 5f 62 62 61 70 69 5f 70 69 6d 5f 72 65 73 5f m_bbapi_pim_res_ 00000080: 5f 65 6e 00 00 03 52 4a 17 54 70 00 12 6e 65 74 _en...RJ.Tp..net 00000090: 5f 72 69 6d 5f 62 62 5f 73 74 61 72 74 75 70 00 _rim_bb_startup. 000000a0: 00 03 53 4a 17 4a 3a 00 20 6e 65 74 5f 72 69 6d ..SJ.J:. net_rim 000000b0: 5f 70 6c 61 74 66 6f 72 6d 5f 72 65 73 6f 75 72 _platform_resour 000000c0: 63 65 5f 5f 65 6e 5f 47 42 00 00 03 54 4a 17 4b ce__en_GB...TJ.K 000000d0: 1b 00 23 6e 65 74 5f 72 69 6d 5f 62 62 5f 70 72 ..#net_rim_bb_pr 000000e0: 6f 66 69 6c 65 73 5f 61 6c 65 72 74 65 6e 67 69 ofiles_alertengi 000000f0: 6e 65 5f 61 70 70 00 00 03 55 4a 17 54 03 00 1b ne_app...UJ.T... 00000100: 6e 65 74 5f 72 69 6d 5f 62 62 5f 65 6c 74 5f 72 net_rim_bb_elt_r 00000110: 65 73 6f 75 72 63 65 5f 5f 66 72 00 00 03 56 4a esource__fr...VJ 00000120: 17 56 eb 00 1c 6e 65 74 5f 72 69 6d 5f 73 65 63 .V...net_rim_sec 00000130: 75 72 65 65 6d 61 69 6c 5f 72 65 73 6f 75 72 63 ureemail_resourc 00000140: 65 00 00 03 57 4a 17 53 ff 00 1b 6e 65 74 5f 72 e...WJ.S...net_r 00000150: 69 6d 5f 62 62 5f 65 6c 74 5f 72 65 73 6f 75 72 im_bb_elt_resour 00000160: 63 65 5f 5f 65 6e 00 00 03 58 4a 17 4a f2 00 24 ce__en...XJ.J..$ 00000170: 6e 65 74 5f 72 69 6d 5f 70 6c 61 74 66 6f 72 6d net_rim_platform 00000180: 61 70 70 73 5f 72 65 73 6f 75 72 63 65 5f 5f 65 apps_resource__e 00000190: 6e 5f 55 53 00 00 03 59 4a 17 56 c8 00 1a 6e 65 n_US...YJ.V...ne 000001a0: 74 5f 72 69 6d 5f 62 62 5f 63 72 79 70 74 6f 5f t_rim_bb_crypto_ 000001b0: 72 65 73 6f 75 72 63 65 00 00 03 5a 4a 17 51 95 resource...ZJ.Q. 000001c0: 00 2d 6e 65 74 5f 72 69 6d 5f 62 62 5f 72 69 62 .-net_rim_bb_rib 000001d0: 62 6f 6e 5f 73 6b 69 6e 5f 73 76 67 5f 44 65 6c bon_skin_svg_Del 000001e0: 61 79 65 64 49 6e 69 74 69 61 6c 69 7a 65 72 00 ayedInitializer. 000001f0: 00 03 5b 4a 17 4a bf 00 0f 6e 65 74 5f 72 69 6d ..[J.J...net_rim 00000200: 5f 75 69 5f 69 6d 70 6c 00 00 03 5c 4a 17 4a 70 _ui_impl...\J.Jp 00000210: 00 20 6e 65 74 5f 72 69 6d 5f 70 6c 61 74 66 6f . net_rim_platfo 00000220: 72 6d 5f 72 65 73 6f 75 72 63 65 5f 5f 65 6e 5f rm_resource__en_ 00000230: 55 53 00 00 03 5d 4a 17 4b 55 00 1b 6e 65 74 5f US...]J.KU..net_ 00000240: 72 69 6d 5f 65 63 6d 61 73 63 72 69 70 74 5f 72 rim_ecmascript_r 00000250: 65 73 6f 75 72 63 65 00 00 03 5e 4a 17 4f c4 00 esource...^J.O.. 00000260: 21 6e 65 74 5f 72 69 6d 5f 62 62 61 70 69 5f 6d !net_rim_bbapi_m 00000270: 65 73 73 61 67 65 6c 69 73 74 5f 72 65 73 5f 5f essagelist_res__ 00000280: 65 6e 00 00 03 5f 4a 17 57 59 00 10 6e 65 74 5f en..._J.WY..net_ 00000290: 72 69 6d 5f 62 62 5f 73 6d 69 6d 65 00 00 03 60 rim_bb_smime...` 000002a0: 4a 17 4b 2a 00 19 6e 65 74 5f 72 69 6d 5f 70 68 J.K*..net_rim_ph 000002b0: 6f 6e 65 5f 74 74 79 5f 65 6e 61 62 6c 65 72 00 one_tty_enabler. 000002c0: 00 03 61 4a 17 49 eb 00 23 6e 65 74 5f 72 69 6d ..aJ.I..#net_rim 000002d0: 5f 70 6c 61 74 66 6f 72 6d 5f 69 6d 5f 72 65 73 _platform_im_res 000002e0: 6f 75 72 63 65 5f 5f 65 6e 5f 55 53 00 00 03 62 ource__en_US...b 000002f0: 4a 17 4a 14 00 23 6e 65 74 5f 72 69 6d 5f 70 6c J.J..#net_rim_pl 00000300: 61 74 66 6f 72 6d 5f 69 6d 5f 72 65 73 6f 75 72 atform_im_resour 00000310: 63 65 5f 5f 65 6e 5f 47 42 00 00 03 63 4a 17 4f ce__en_GB...cJ.O 00000320: d3 00 2c 6e 65 74 5f 72 69 6d 5f 64 65 76 69 63 ..,net_rim_devic 00000330: 65 5f 61 70 70 73 5f 67 61 6d 65 73 5f 77 6f 72 e_apps_games_wor 00000340: 64 6d 6f 6c 65 5f 72 65 73 6f 75 72 63 65 73 00 dmole_resources. 00000350: 00 03 64 4a 17 54 cc 00 14 6e 65 74 5f 72 69 6d ..dJ.T...net_rim 00000360: 5f 76 61 64 5f 72 65 73 6f 75 72 63 65 00 00 03 _vad_resource... 00000370: 65 4a 17 4b 5a 00 1f 6e 65 74 5f 72 69 6d 5f 65 eJ.KZ..net_rim_e 00000380: 63 6d 61 73 63 72 69 70 74 5f 72 65 73 6f 75 72 cmascript_resour 00000390: 63 65 5f 5f 66 72 00 00 03 66 4a 17 52 f2 00 17 ce__fr...fJ.R... 000003a0: 6e 65 74 5f 72 69 6d 5f 74 69 64 5f 41 64 64 72 net_rim_tid_Addr 000003b0: 42 6f 6f 6b 52 65 70 00 00 03 67 4a 17 56 7e 00 BookRep...gJ.V~. 000003c0: 22 6e 65 74 5f 72 69 6d 5f 62 62 5f 70 61 73 73 "net_rim_bb_pass 000003d0: 77 6f 72 64 6b 65 65 70 65 72 5f 72 65 73 6f 75 wordkeeper_resou 000003e0: 72 63 65 00 00 03 68 rce...h Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 184 00000000: 05 00 0b 00 00 05 8d 00 00 03 68 ..........h <<< URB 164 00000000: 00 00 0c 00 13 05 01 00 21 00 00 00 ........!... <<< URB 166 00000000: 05 00 06 00 03 ee ...... <<< URB 167 00000000: 05 00 f2 03 00 00 00 1e 00 00 03 68 4a 17 4f c2 ...........hJ.O. 00000010: 00 1d 6e 65 74 5f 72 69 6d 5f 62 62 61 70 69 5f ..net_rim_bbapi_ 00000020: 6d 65 73 73 61 67 65 6c 69 73 74 5f 72 65 73 00 messagelist_res. 00000030: 00 03 69 4a 17 55 68 00 12 6e 65 74 5f 72 69 6d ..iJ.Uh..net_rim 00000040: 5f 62 62 61 70 69 5f 6d 61 69 6c 00 00 03 6a 4a _bbapi_mail...jJ 00000050: 17 4a ae 00 17 6e 65 74 5f 72 69 6d 5f 62 62 5f .J...net_rim_bb_ 00000060: 63 61 6c 6c 5f 63 6f 6e 74 72 6f 6c 00 00 03 6b call_control...k 00000070: 4a 17 56 57 00 18 6e 65 74 5f 72 69 6d 5f 62 62 J.VW..net_rim_bb 00000080: 5f 6c 64 61 70 5f 72 65 73 6f 75 72 63 65 00 00 _ldap_resource.. 00000090: 03 6c 4a 17 50 34 00 15 6e 65 74 5f 72 69 6d 5f .lJ.P4..net_rim_ 000000a0: 62 62 61 70 69 5f 70 69 6d 5f 72 65 73 00 00 03 bbapi_pim_res... 000000b0: 6d 4a 17 50 26 00 27 6e 65 74 5f 72 69 6d 5f 70 mJ.P&.'net_rim_p 000000c0: 6c 61 7a 6d 69 63 5f 6d 65 64 69 61 65 6e 67 69 lazmic_mediaengi 000000d0: 6e 65 5f 73 6d 69 6c 5f 66 6f 72 6d 61 74 00 00 ne_smil_format.. 000000e0: 03 6e 4a 17 53 f1 00 1c 6e 65 74 5f 72 69 6d 5f .nJ.S...net_rim_ 000000f0: 62 69 73 5f 63 6c 69 65 6e 74 5f 72 65 73 6f 75 bis_client_resou 00000100: 72 63 65 73 00 00 03 6f 4a 17 53 f1 00 16 6e 65 rces...oJ.S...ne 00000110: 74 5f 72 69 6d 5f 62 69 73 5f 63 6c 69 65 6e 74 t_rim_bis_client 00000120: 5f 72 65 73 00 00 03 70 49 1c 40 0b 00 14 73 66 _res...pI.@...sf 00000130: 72 66 6e 67 6f 5f 66 72 5f 77 61 70 32 5f 77 61 rfngo_fr_wap2_wa 00000140: 70 31 00 00 03 71 49 1c 40 0b 00 17 73 66 72 66 p1...qI.@...sfrf 00000150: 6e 67 6f 5f 66 72 5f 77 61 70 32 5f 77 61 70 31 ngo_fr_wap2_wap1 00000160: 2d 32 30 00 00 03 72 49 1c 40 0b 00 16 73 66 72 -20...rI.@...sfr 00000170: 66 6e 67 6f 5f 66 72 5f 77 61 70 32 5f 77 61 70 fngo_fr_wap2_wap 00000180: 31 2d 31 00 00 03 73 49 1c 40 0b 00 16 73 66 72 1-1...sI.@...sfr 00000190: 66 6e 67 6f 5f 66 72 5f 77 61 70 32 5f 77 61 70 fngo_fr_wap2_wap 000001a0: 31 2d 32 00 00 03 74 49 1c 40 0b 00 16 73 66 72 1-2...tI.@...sfr 000001b0: 66 6e 67 6f 5f 66 72 5f 77 61 70 32 5f 77 61 70 fngo_fr_wap2_wap 000001c0: 31 2d 34 00 00 03 75 49 1c 40 0b 00 17 73 66 72 1-4...uI.@...sfr 000001d0: 66 6e 67 6f 5f 66 72 5f 77 61 70 32 5f 77 61 70 fngo_fr_wap2_wap 000001e0: 31 2d 31 31 00 00 03 76 49 1c 40 0b 00 17 73 66 1-11...vI.@...sf 000001f0: 72 66 6e 67 6f 5f 66 72 5f 77 61 70 32 5f 77 61 rfngo_fr_wap2_wa 00000200: 70 31 2d 31 37 00 00 03 77 49 1c 40 0b 00 17 73 p1-17...wI.@...s 00000210: 66 72 66 6e 67 6f 5f 66 72 5f 77 61 70 32 5f 77 frfngo_fr_wap2_w 00000220: 61 70 31 2d 31 32 00 00 03 78 49 1c 40 0b 00 16 ap1-12...xI.@... 00000230: 73 66 72 66 6e 67 6f 5f 66 72 5f 77 61 70 32 5f sfrfngo_fr_wap2_ 00000240: 77 61 70 31 2d 37 00 00 03 79 49 1c 40 0b 00 17 wap1-7...yI.@... 00000250: 73 66 72 66 6e 67 6f 5f 66 72 5f 77 61 70 32 5f sfrfngo_fr_wap2_ 00000260: 77 61 70 31 2d 31 30 00 00 03 7a 49 1c 40 0b 00 wap1-10...zI.@.. 00000270: 16 73 66 72 66 6e 67 6f 5f 66 72 5f 77 61 70 32 .sfrfngo_fr_wap2 00000280: 5f 77 61 70 31 2d 33 00 00 03 7b 49 1c 40 0b 00 _wap1-3...{I.@.. 00000290: 16 73 66 72 66 6e 67 6f 5f 66 72 5f 77 61 70 32 .sfrfngo_fr_wap2 000002a0: 5f 77 61 70 31 2d 35 00 00 03 7c 49 1c 40 0b 00 _wap1-5...|I.@.. 000002b0: 16 73 66 72 66 6e 67 6f 5f 66 72 5f 77 61 70 32 .sfrfngo_fr_wap2 000002c0: 5f 77 61 70 31 2d 36 00 00 03 7d 49 1c 40 0b 00 _wap1-6...}I.@.. 000002d0: 16 73 66 72 66 6e 67 6f 5f 66 72 5f 77 61 70 32 .sfrfngo_fr_wap2 000002e0: 5f 77 61 70 31 2d 38 00 00 03 7e 49 1c 40 0b 00 _wap1-8...~I.@.. 000002f0: 16 73 66 72 66 6e 67 6f 5f 66 72 5f 77 61 70 32 .sfrfngo_fr_wap2 00000300: 5f 77 61 70 31 2d 39 00 00 03 7f 49 1c 40 0b 00 _wap1-9....I.@.. 00000310: 17 73 66 72 66 6e 67 6f 5f 66 72 5f 77 61 70 32 .sfrfngo_fr_wap2 00000320: 5f 77 61 70 31 2d 31 33 00 00 03 80 49 1c 40 0b _wap1-13....I.@. 00000330: 00 17 73 66 72 66 6e 67 6f 5f 66 72 5f 77 61 70 ..sfrfngo_fr_wap 00000340: 32 5f 77 61 70 31 2d 31 34 00 00 03 81 49 1c 40 2_wap1-14....I.@ 00000350: 0b 00 17 73 66 72 66 6e 67 6f 5f 66 72 5f 77 61 ...sfrfngo_fr_wa 00000360: 70 32 5f 77 61 70 31 2d 31 35 00 00 03 82 49 1c p2_wap1-15....I. 00000370: 40 0b 00 17 73 66 72 66 6e 67 6f 5f 66 72 5f 77 @...sfrfngo_fr_w 00000380: 61 70 32 5f 77 61 70 31 2d 31 36 00 00 03 83 49 ap2_wap1-16....I 00000390: 1c 40 0b 00 17 73 66 72 66 6e 67 6f 5f 66 72 5f .@...sfrfngo_fr_ 000003a0: 77 61 70 32 5f 77 61 70 31 2d 31 38 00 00 03 84 wap2_wap1-18.... 000003b0: 49 1c 40 0b 00 17 73 66 72 66 6e 67 6f 5f 66 72 I.@...sfrfngo_fr 000003c0: 5f 77 61 70 32 5f 77 61 70 31 2d 31 39 00 00 03 _wap2_wap1-19... 000003d0: 85 49 1c 40 0b 00 17 73 66 72 66 6e 67 6f 5f 66 .I.@...sfrfngo_f 000003e0: 72 5f 77 61 70 32 5f 77 61 70 31 2d 32 31 00 00 r_wap2_wap1-21.. 000003f0: 03 86 .. Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 188 00000000: 05 00 0b 00 00 05 8d 00 00 03 86 ........... <<< URB 168 00000000: 00 00 0c 00 13 05 01 00 22 00 00 00 ........"... <<< URB 170 00000000: 05 00 06 00 03 e4 ...... <<< URB 171 00000000: 05 00 e8 03 00 00 00 29 00 00 03 86 49 80 76 45 .......)....I.vE 00000010: 00 10 44 6f 63 73 54 6f 47 6f 43 6f 6d 6d 6f 6e ..DocsToGoCommon 00000020: 34 37 00 00 03 87 49 80 76 45 00 12 44 6f 63 73 47....I.vE..Docs 00000030: 54 6f 47 6f 43 6f 6d 6d 6f 6e 34 37 2d 32 00 00 ToGoCommon47-2.. 00000040: 03 88 49 80 76 45 00 12 44 6f 63 73 54 6f 47 6f ..I.vE..DocsToGo 00000050: 43 6f 6d 6d 6f 6e 34 37 2d 31 00 00 03 89 49 80 Common47-1....I. 00000060: 76 45 00 12 44 6f 63 73 54 6f 47 6f 43 6f 6d 6d vE..DocsToGoComm 00000070: 6f 6e 34 37 2d 33 00 00 03 8a 49 80 76 45 00 13 on47-3....I.vE.. 00000080: 44 6f 63 73 54 6f 47 6f 43 6f 6d 6d 6f 6e 34 37 DocsToGoCommon47 00000090: 2d 31 33 00 00 03 8b 49 80 76 45 00 12 44 6f 63 -13....I.vE..Doc 000000a0: 73 54 6f 47 6f 43 6f 6d 6d 6f 6e 34 37 2d 34 00 sToGoCommon47-4. 000000b0: 00 03 8c 49 80 76 45 00 12 44 6f 63 73 54 6f 47 ...I.vE..DocsToG 000000c0: 6f 43 6f 6d 6d 6f 6e 34 37 2d 36 00 00 03 8d 49 oCommon47-6....I 000000d0: 80 76 45 00 12 44 6f 63 73 54 6f 47 6f 43 6f 6d .vE..DocsToGoCom 000000e0: 6d 6f 6e 34 37 2d 37 00 00 03 8e 49 80 76 45 00 mon47-7....I.vE. 000000f0: 12 44 6f 63 73 54 6f 47 6f 43 6f 6d 6d 6f 6e 34 .DocsToGoCommon4 00000100: 37 2d 35 00 00 03 8f 49 80 76 45 00 12 44 6f 63 7-5....I.vE..Doc 00000110: 73 54 6f 47 6f 43 6f 6d 6d 6f 6e 34 37 2d 38 00 sToGoCommon47-8. 00000120: 00 03 90 49 80 76 45 00 12 44 6f 63 73 54 6f 47 ...I.vE..DocsToG 00000130: 6f 43 6f 6d 6d 6f 6e 34 37 2d 39 00 00 03 91 49 oCommon47-9....I 00000140: 80 76 45 00 13 44 6f 63 73 54 6f 47 6f 43 6f 6d .vE..DocsToGoCom 00000150: 6d 6f 6e 34 37 2d 31 30 00 00 03 92 49 80 76 45 mon47-10....I.vE 00000160: 00 13 44 6f 63 73 54 6f 47 6f 43 6f 6d 6d 6f 6e ..DocsToGoCommon 00000170: 34 37 2d 31 31 00 00 03 93 49 80 76 45 00 13 44 47-11....I.vE..D 00000180: 6f 63 73 54 6f 47 6f 43 6f 6d 6d 6f 6e 34 37 2d ocsToGoCommon47- 00000190: 31 32 00 00 03 94 49 88 24 4f 00 09 56 69 69 67 12....I.$O..Viig 000001a0: 6f 5f 41 70 69 00 00 03 95 49 88 24 4f 00 0b 56 o_Api....I.$O..V 000001b0: 69 69 67 6f 5f 41 70 69 2d 36 00 00 03 96 49 88 iigo_Api-6....I. 000001c0: 24 4f 00 0b 56 69 69 67 6f 5f 41 70 69 2d 37 00 $O..Viigo_Api-7. 000001d0: 00 03 97 49 88 24 4f 00 0b 56 69 69 67 6f 5f 41 ...I.$O..Viigo_A 000001e0: 70 69 2d 34 00 00 03 98 49 88 24 4f 00 0b 56 69 pi-4....I.$O..Vi 000001f0: 69 67 6f 5f 41 70 69 2d 33 00 00 03 99 49 88 24 igo_Api-3....I.$ 00000200: 47 00 0a 56 69 69 67 6f 5f 48 65 63 6c 00 00 03 G..Viigo_Hecl... 00000210: 9a 49 88 24 47 00 0c 56 69 69 67 6f 5f 48 65 63 .I.$G..Viigo_Hec 00000220: 6c 2d 31 00 00 03 9b 49 88 24 4f 00 0b 56 69 69 l-1....I.$O..Vii 00000230: 67 6f 5f 41 70 69 2d 31 00 00 03 9c 49 88 24 4f go_Api-1....I.$O 00000240: 00 0b 56 69 69 67 6f 5f 41 70 69 2d 32 00 00 03 ..Viigo_Api-2... 00000250: 9d 49 88 24 4f 00 0b 56 69 69 67 6f 5f 41 70 69 .I.$O..Viigo_Api 00000260: 2d 35 00 00 03 9e 49 88 24 4f 00 0b 56 69 69 67 -5....I.$O..Viig 00000270: 6f 5f 41 70 69 2d 38 00 00 03 9f 49 88 24 42 00 o_Api-8....I.$B. 00000280: 15 56 69 69 67 6f 5f 42 72 61 6e 64 5f 52 65 73 .Viigo_Brand_Res 00000290: 6f 75 72 63 65 73 00 00 03 a0 49 1c 34 ef 00 0b ources....I.4... 000002a0: 6d 69 6e 69 74 75 62 65 5f 62 62 00 00 03 a1 49 minitube_bb....I 000002b0: 1c 34 ef 00 0d 6d 69 6e 69 74 75 62 65 5f 62 62 .4...minitube_bb 000002c0: 2d 31 00 00 03 a2 49 1c 34 ef 00 0d 6d 69 6e 69 -1....I.4...mini 000002d0: 74 75 62 65 5f 62 62 2d 32 00 00 03 a3 49 1c 34 tube_bb-2....I.4 000002e0: ef 00 0d 6d 69 6e 69 74 75 62 65 5f 62 62 2d 33 ...minitube_bb-3 000002f0: 00 00 03 a4 49 1c 34 ef 00 0d 6d 69 6e 69 74 75 ....I.4...minitu 00000300: 62 65 5f 62 62 2d 34 00 00 03 a5 49 1c 34 ef 00 be_bb-4....I.4.. 00000310: 0d 6d 69 6e 69 74 75 62 65 5f 62 62 2d 35 00 00 .minitube_bb-5.. 00000320: 03 a6 49 1c 34 ef 00 0d 6d 69 6e 69 74 75 62 65 ..I.4...minitube 00000330: 5f 62 62 2d 36 00 00 03 a7 49 1c 34 ef 00 0d 6d _bb-6....I.4...m 00000340: 69 6e 69 74 75 62 65 5f 62 62 2d 37 00 00 03 a8 initube_bb-7.... 00000350: 49 80 76 a4 00 0a 57 6f 72 64 54 6f 47 6f 34 37 I.v...WordToGo47 00000360: 00 00 03 a9 49 80 76 a4 00 0c 57 6f 72 64 54 6f ....I.v...WordTo 00000370: 47 6f 34 37 2d 31 00 00 03 aa 49 80 76 a4 00 0c Go47-1....I.v... 00000380: 57 6f 72 64 54 6f 47 6f 34 37 2d 36 00 00 03 ab WordToGo47-6.... 00000390: 49 80 76 a4 00 0c 57 6f 72 64 54 6f 47 6f 34 37 I.v...WordToGo47 000003a0: 2d 33 00 00 03 ac 49 80 76 a4 00 0c 57 6f 72 64 -3....I.v...Word 000003b0: 54 6f 47 6f 34 37 2d 34 00 00 03 ad 49 80 76 a4 ToGo47-4....I.v. 000003c0: 00 0c 57 6f 72 64 54 6f 47 6f 34 37 2d 32 00 00 ..WordToGo47-2.. 000003d0: 03 ae 49 80 76 a4 00 0c 57 6f 72 64 54 6f 47 6f ..I.v...WordToGo 000003e0: 34 37 2d 35 00 00 03 af 47-5.... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 192 00000000: 05 00 0b 00 00 05 8d 00 00 03 af ........... <<< URB 172 00000000: 00 00 0c 00 13 05 01 00 23 00 00 00 ........#... <<< URB 174 00000000: 05 00 06 00 03 e6 ...... <<< URB 175 00000000: 05 00 ea 03 00 00 00 23 00 00 03 af 49 80 76 85 .......#....I.v. 00000010: 00 0b 53 68 65 65 74 54 6f 47 6f 34 37 00 00 03 ..SheetToGo47... 00000020: b0 49 80 76 85 00 0d 53 68 65 65 74 54 6f 47 6f .I.v...SheetToGo 00000030: 34 37 2d 31 00 00 03 b1 49 80 76 85 00 0d 53 68 47-1....I.v...Sh 00000040: 65 65 74 54 6f 47 6f 34 37 2d 35 00 00 03 b2 49 eetToGo47-5....I 00000050: 80 76 85 00 0d 53 68 65 65 74 54 6f 47 6f 34 37 .v...SheetToGo47 00000060: 2d 36 00 00 03 b3 49 80 76 85 00 0d 53 68 65 65 -6....I.v...Shee 00000070: 74 54 6f 47 6f 34 37 2d 33 00 00 03 b4 49 80 76 tToGo47-3....I.v 00000080: 85 00 0d 53 68 65 65 74 54 6f 47 6f 34 37 2d 32 ...SheetToGo47-2 00000090: 00 00 03 b5 49 80 76 85 00 0d 53 68 65 65 74 54 ....I.v...SheetT 000000a0: 6f 47 6f 34 37 2d 34 00 00 03 b6 49 80 76 66 00 oGo47-4....I.vf. 000000b0: 0f 53 6c 69 64 65 73 68 6f 77 54 6f 47 6f 34 37 .SlideshowToGo47 000000c0: 00 00 03 b7 49 80 76 66 00 11 53 6c 69 64 65 73 ....I.vf..Slides 000000d0: 68 6f 77 54 6f 47 6f 34 37 2d 31 00 00 03 b8 49 howToGo47-1....I 000000e0: 80 76 66 00 11 53 6c 69 64 65 73 68 6f 77 54 6f .vf..SlideshowTo 000000f0: 47 6f 34 37 2d 32 00 00 03 b9 49 80 76 66 00 11 Go47-2....I.vf.. 00000100: 53 6c 69 64 65 73 68 6f 77 54 6f 47 6f 34 37 2d SlideshowToGo47- 00000110: 33 00 00 03 ba 49 80 76 66 00 11 53 6c 69 64 65 3....I.vf..Slide 00000120: 73 68 6f 77 54 6f 47 6f 34 37 2d 34 00 00 03 bb showToGo47-4.... 00000130: 49 88 24 63 00 09 56 69 69 67 6f 5f 41 70 70 00 I.$c..Viigo_App. 00000140: 00 03 bc 49 88 24 63 00 0b 56 69 69 67 6f 5f 41 ...I.$c..Viigo_A 00000150: 70 70 2d 31 00 00 03 bd 49 88 24 63 00 0b 56 69 pp-1....I.$c..Vi 00000160: 69 67 6f 5f 41 70 70 2d 34 00 00 03 be 49 88 24 igo_App-4....I.$ 00000170: 63 00 0b 56 69 69 67 6f 5f 41 70 70 2d 35 00 00 c..Viigo_App-5.. 00000180: 03 bf 49 88 24 63 00 0b 56 69 69 67 6f 5f 41 70 ..I.$c..Viigo_Ap 00000190: 70 2d 32 00 00 03 c0 49 88 24 63 00 0b 56 69 69 p-2....I.$c..Vii 000001a0: 67 6f 5f 41 70 70 2d 33 00 00 03 c1 49 88 24 77 go_App-3....I.$w 000001b0: 00 1b 56 69 69 67 6f 5f 41 70 70 5f 52 65 73 6f ..Viigo_App_Reso 000001c0: 75 72 63 65 73 5f 34 38 30 78 33 32 30 00 00 03 urces_480x320... 000001d0: c2 49 88 24 77 00 1d 56 69 69 67 6f 5f 41 70 70 .I.$w..Viigo_App 000001e0: 5f 52 65 73 6f 75 72 63 65 73 5f 34 38 30 78 33 _Resources_480x3 000001f0: 32 30 2d 31 00 00 03 c3 49 80 76 79 00 17 53 68 20-1....I.vy..Sh 00000200: 65 65 74 54 6f 47 6f 34 37 52 65 73 6f 75 72 63 eetToGo47Resourc 00000210: 65 5f 5f 65 6e 00 00 03 c4 48 a1 2e 46 00 12 43 e__en....H..F..C 00000220: 72 61 63 6b 42 65 72 72 79 41 70 70 53 74 6f 72 rackBerryAppStor 00000230: 65 00 00 03 c5 49 80 76 3f 00 1c 44 6f 63 73 54 e....I.v?..DocsT 00000240: 6f 47 6f 43 6f 6d 6d 6f 6e 34 37 52 65 73 6f 75 oGoCommon47Resou 00000250: 72 63 65 5f 5f 66 72 00 00 03 c6 49 80 76 39 00 rce__fr....I.v9. 00000260: 1c 44 6f 63 73 54 6f 47 6f 43 6f 6d 6d 6f 6e 34 .DocsToGoCommon4 00000270: 37 52 65 73 6f 75 72 63 65 5f 5f 65 6e 00 00 03 7Resource__en... 00000280: c7 49 80 76 7f 00 17 53 68 65 65 74 54 6f 47 6f .I.v...SheetToGo 00000290: 34 37 52 65 73 6f 75 72 63 65 5f 5f 66 72 00 00 47Resource__fr.. 000002a0: 03 c8 49 88 24 82 00 16 56 69 69 67 6f 5f 53 74 ..I.$...Viigo_St 000002b0: 61 6e 64 61 72 64 5f 34 38 30 78 33 32 30 00 00 andard_480x320.. 000002c0: 03 c9 49 80 76 9e 00 16 57 6f 72 64 54 6f 47 6f ..I.v...WordToGo 000002d0: 34 37 52 65 73 6f 75 72 63 65 5f 5f 66 72 00 00 47Resource__fr.. 000002e0: 03 ca 49 80 76 99 00 16 57 6f 72 64 54 6f 47 6f ..I.v...WordToGo 000002f0: 34 37 52 65 73 6f 75 72 63 65 5f 5f 65 6e 00 00 47Resource__en.. 00000300: 03 cb 49 88 24 7c 00 12 56 69 69 67 6f 5f 50 6c ..I.$|..Viigo_Pl 00000310: 61 74 66 6f 72 6d 5f 34 32 30 00 00 03 cc 49 1c atform_420....I. 00000320: 40 22 00 12 62 62 5f 63 6f 6e 74 61 63 74 73 5f @"..bb_contacts_ 00000330: 70 6c 75 67 69 6e 00 00 03 cd 49 88 24 7f 00 12 plugin....I.$... 00000340: 56 69 69 67 6f 5f 50 6c 61 74 66 6f 72 6d 5f 34 Viigo_Platform_4 00000350: 37 30 00 00 03 ce 49 80 76 60 00 1b 53 6c 69 64 70....I.v`..Slid 00000360: 65 73 68 6f 77 54 6f 47 6f 34 37 52 65 73 6f 75 eshowToGo47Resou 00000370: 72 63 65 5f 5f 66 72 00 00 03 cf 49 80 76 5b 00 rce__fr....I.v[. 00000380: 1b 53 6c 69 64 65 73 68 6f 77 54 6f 47 6f 34 37 .SlideshowToGo47 00000390: 52 65 73 6f 75 72 63 65 5f 5f 65 6e 00 00 03 d0 Resource__en.... 000003a0: 49 88 6e 30 00 1e 56 69 69 67 6f 5f 42 72 61 6e I.n0..Viigo_Bran 000003b0: 64 5f 50 75 62 6c 69 63 42 65 74 61 5f 34 38 30 d_PublicBeta_480 000003c0: 78 33 32 30 00 00 03 d1 49 80 76 33 00 18 44 6f x320....I.v3..Do 000003d0: 63 73 54 6f 47 6f 43 6f 6d 6d 6f 6e 34 37 52 65 csToGoCommon47Re 000003e0: 73 6f 75 72 63 65 00 00 03 d2 source.... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 196 00000000: 05 00 0b 00 00 05 8d 00 00 03 d2 ........... <<< URB 176 00000000: 00 00 0c 00 13 05 01 00 24 00 00 00 ........$... <<< URB 178 00000000: 05 00 06 00 03 eb ...... <<< URB 179 00000000: 05 00 ef 03 00 00 00 2c 00 00 03 d2 49 80 76 56 .......,....I.vV 00000010: 00 17 53 6c 69 64 65 73 68 6f 77 54 6f 47 6f 34 ..SlideshowToGo4 00000020: 37 52 65 73 6f 75 72 63 65 00 00 03 d3 49 80 76 7Resource....I.v 00000030: 73 00 13 53 68 65 65 74 54 6f 47 6f 34 37 52 65 s..SheetToGo47Re 00000040: 73 6f 75 72 63 65 00 00 03 d4 49 80 76 94 00 12 source....I.v... 00000050: 57 6f 72 64 54 6f 47 6f 34 37 52 65 73 6f 75 72 WordToGo47Resour 00000060: 63 65 00 00 03 d5 49 88 24 85 00 17 63 6f 6d 5f ce....I.$...com_ 00000070: 76 69 69 67 6f 5f 76 69 69 67 6f 61 70 70 5f 61 viigo_viigoapp_a 00000080: 70 70 5f 00 00 03 d6 49 18 0e e0 00 1b 6f 70 65 pp_....I.....ope 00000090: 72 65 74 74 65 24 32 64 68 69 66 69 24 32 64 34 rette$2dhifi$2d4 000000a0: 24 32 65 32 62 65 74 61 00 00 03 d7 49 18 0e e0 $2e2beta....I... 000000b0: 00 1d 6f 70 65 72 65 74 74 65 24 32 64 68 69 66 ..operette$2dhif 000000c0: 69 24 32 64 34 24 32 65 32 62 65 74 61 2d 32 00 i$2d4$2e2beta-2. 000000d0: 00 03 d8 49 18 0e e0 00 1d 6f 70 65 72 65 74 74 ...I.....operett 000000e0: 65 24 32 64 68 69 66 69 24 32 64 34 24 32 65 32 e$2dhifi$2d4$2e2 000000f0: 62 65 74 61 2d 31 00 00 03 d9 49 95 d9 ec 00 0a beta-1....I..... 00000100: 47 6f 6f 67 6c 65 4d 61 70 73 00 00 03 da 49 95 GoogleMaps....I. 00000110: d9 ec 00 0c 47 6f 6f 67 6c 65 4d 61 70 73 2d 32 ....GoogleMaps-2 00000120: 00 00 03 db 49 95 d9 ec 00 0c 47 6f 6f 67 6c 65 ....I.....Google 00000130: 4d 61 70 73 2d 37 00 00 03 dc 49 95 d9 ec 00 0c Maps-7....I..... 00000140: 47 6f 6f 67 6c 65 4d 61 70 73 2d 33 00 00 03 dd GoogleMaps-3.... 00000150: 49 95 d9 ec 00 0c 47 6f 6f 67 6c 65 4d 61 70 73 I.....GoogleMaps 00000160: 2d 31 00 00 03 de 49 95 d9 ec 00 0c 47 6f 6f 67 -1....I.....Goog 00000170: 6c 65 4d 61 70 73 2d 36 00 00 03 df 49 95 d9 ec leMaps-6....I... 00000180: 00 0c 47 6f 6f 67 6c 65 4d 61 70 73 2d 34 00 00 ..GoogleMaps-4.. 00000190: 03 e0 49 95 d9 ec 00 0c 47 6f 6f 67 6c 65 4d 61 ..I.....GoogleMa 000001a0: 70 73 2d 35 00 00 03 e1 49 95 d9 ec 00 0c 47 6f ps-5....I.....Go 000001b0: 6f 67 6c 65 4d 61 70 73 2d 38 00 00 03 e2 49 95 ogleMaps-8....I. 000001c0: d9 ec 00 0c 47 6f 6f 67 6c 65 4d 61 70 73 2d 39 ....GoogleMaps-9 000001d0: 00 00 03 e3 4a 0d 79 9f 00 0a 42 65 72 72 79 56 ....J.y...BerryV 000001e0: 43 61 72 64 00 00 03 e4 49 5c 13 d2 00 09 51 75 Card....I\....Qu 000001f0: 69 63 6b 50 75 6c 6c 00 00 03 e5 49 ed 7c 70 00 ickPull....I.|p. 00000200: 0a 42 65 72 72 79 4c 65 76 65 6c 00 00 03 e6 49 .BerryLevel....I 00000210: ed 7c 70 00 0c 42 65 72 72 79 4c 65 76 65 6c 2d .|p..BerryLevel- 00000220: 31 00 00 03 e7 49 ed 7c 70 00 0c 42 65 72 72 79 1....I.|p..Berry 00000230: 4c 65 76 65 6c 2d 32 00 00 03 e8 49 ed 7c 70 00 Level-2....I.|p. 00000240: 0c 42 65 72 72 79 4c 65 76 65 6c 2d 33 00 00 03 .BerryLevel-3... 00000250: e9 49 95 da b8 00 04 47 49 53 54 00 00 03 ea 49 .I.....GIST....I 00000260: 95 da b8 00 06 47 49 53 54 2d 31 00 00 03 eb 49 .....GIST-1....I 00000270: 95 da b8 00 06 47 49 53 54 2d 32 00 00 03 ec 49 .....GIST-2....I 00000280: 95 da b8 00 06 47 49 53 54 2d 33 00 00 03 ed 49 .....GIST-3....I 00000290: 95 da b8 00 06 47 49 53 54 2d 34 00 00 03 ee 49 .....GIST-4....I 000002a0: 95 da b8 00 06 47 49 53 54 2d 35 00 00 03 ef 49 .....GIST-5....I 000002b0: f1 f0 99 00 0b 42 42 46 69 6c 65 53 63 6f 75 74 .....BBFileScout 000002c0: 00 00 03 f0 49 f1 f0 99 00 0d 42 42 46 69 6c 65 ....I.....BBFile 000002d0: 53 63 6f 75 74 2d 31 00 00 03 f1 49 f1 f0 99 00 Scout-1....I.... 000002e0: 0d 42 42 46 69 6c 65 53 63 6f 75 74 2d 32 00 00 .BBFileScout-2.. 000002f0: 03 f2 49 f1 f0 99 00 0d 42 42 46 69 6c 65 53 63 ..I.....BBFileSc 00000300: 6f 75 74 2d 33 00 00 03 f3 49 e4 f7 0a 00 09 6c out-3....I.....l 00000310: 61 62 79 72 69 6e 74 68 00 00 03 f4 49 e4 f7 0a abyrinth....I... 00000320: 00 0b 6c 61 62 79 72 69 6e 74 68 2d 31 00 00 03 ..labyrinth-1... 00000330: f5 49 e4 f7 0a 00 0b 6c 61 62 79 72 69 6e 74 68 .I.....labyrinth 00000340: 2d 32 00 00 03 f6 49 e4 f7 0a 00 0b 6c 61 62 79 -2....I.....laby 00000350: 72 69 6e 74 68 2d 33 00 00 03 f7 49 e4 f7 0a 00 rinth-3....I.... 00000360: 0b 6c 61 62 79 72 69 6e 74 68 2d 34 00 00 03 f8 .labyrinth-4.... 00000370: 49 e4 f7 0a 00 0b 6c 61 62 79 72 69 6e 74 68 2d I.....labyrinth- 00000380: 35 00 00 03 f9 49 e4 f7 0a 00 0b 6c 61 62 79 72 5....I.....labyr 00000390: 69 6e 74 68 2d 36 00 00 03 fa 49 e4 f7 0a 00 0b inth-6....I..... 000003a0: 6c 61 62 79 72 69 6e 74 68 2d 37 00 00 03 fb 49 labyrinth-7....I 000003b0: e4 f7 0a 00 0b 6c 61 62 79 72 69 6e 74 68 2d 38 .....labyrinth-8 000003c0: 00 00 03 fc 49 e4 f7 0a 00 0b 6c 61 62 79 72 69 ....I.....labyri 000003d0: 6e 74 68 2d 39 00 00 03 fd 49 e4 f7 0a 00 0c 6c nth-9....I.....l 000003e0: 61 62 79 72 69 6e 74 68 2d 31 30 00 00 03 fe abyrinth-10.... Command SB_COMMAND_JD_GET_MODULES_LIST -------------------------------------- >>> URB 200 00000000: 05 00 0b 00 00 05 8d 00 00 03 fe ........... <<< URB 180 00000000: 00 00 0c 00 13 05 01 00 25 00 00 00 ........%... <<< URB 182 00000000: 05 00 06 00 01 64 .....d <<< URB 183 00000000: 05 00 68 01 00 00 00 0e 00 00 03 fe 49 e4 f7 0a ..h.........I... 00000010: 00 0c 6c 61 62 79 72 69 6e 74 68 2d 31 31 00 00 ..labyrinth-11.. 00000020: 03 ff 49 a5 b6 46 00 0d 52 65 70 6c 69 47 6f 52 ..I..F..RepliGoR 00000030: 65 61 64 65 72 00 00 04 00 49 a5 b6 46 00 0f 52 eader....I..F..R 00000040: 65 70 6c 69 47 6f 52 65 61 64 65 72 2d 31 00 00 epliGoReader-1.. 00000050: 04 01 49 a5 b6 46 00 0f 52 65 70 6c 69 47 6f 52 ..I..F..RepliGoR 00000060: 65 61 64 65 72 2d 36 00 00 04 02 49 a5 b6 46 00 eader-6....I..F. 00000070: 0f 52 65 70 6c 69 47 6f 52 65 61 64 65 72 2d 37 .RepliGoReader-7 00000080: 00 00 04 03 49 a5 b6 46 00 0f 52 65 70 6c 69 47 ....I..F..RepliG 00000090: 6f 52 65 61 64 65 72 2d 34 00 00 04 04 49 a5 b6 oReader-4....I.. 000000a0: 46 00 0f 52 65 70 6c 69 47 6f 52 65 61 64 65 72 F..RepliGoReader 000000b0: 2d 35 00 00 04 05 49 a5 b6 46 00 0f 52 65 70 6c -5....I..F..Repl 000000c0: 69 47 6f 52 65 61 64 65 72 2d 33 00 00 04 06 49 iGoReader-3....I 000000d0: a5 b6 46 00 0f 52 65 70 6c 69 47 6f 52 65 61 64 ..F..RepliGoRead 000000e0: 65 72 2d 32 00 00 04 07 49 a5 b6 46 00 0f 52 65 er-2....I..F..Re 000000f0: 70 6c 69 47 6f 52 65 61 64 65 72 2d 38 00 00 04 pliGoReader-8... 00000100: 08 49 a5 b6 46 00 0f 52 65 70 6c 69 47 6f 52 65 .I..F..RepliGoRe 00000110: 61 64 65 72 2d 39 00 00 04 09 49 a5 b6 46 00 10 ader-9....I..F.. 00000120: 52 65 70 6c 69 47 6f 52 65 61 64 65 72 2d 31 30 RepliGoReader-10 00000130: 00 00 04 0a 49 a5 b6 46 00 10 52 65 70 6c 69 47 ....I..F..RepliG 00000140: 6f 52 65 61 64 65 72 2d 31 31 00 00 04 0b 49 a5 oReader-11....I. 000002e0: b6 46 00 10 52 65 70 6c 69 47 6f 52 65 61 64 65 .F..RepliGoReade 000002f0: 72 2d 31 32 00 00 00 00 r-12.... | Command SB_COMMAND_JD_GET_THREADS_LIST -------------------------------------- >>> URB 204 00000000: 05 00 07 00 00 01 08 ....... <<< URB 184 00000000: 00 00 0c 00 13 05 01 00 26 00 00 00 ........&... <<< URB 186 00000000: 05 00 06 00 01 c0 ...... <<< URB 187 00000000: 05 00 c4 01 00 00 00 6f e6 a1 e0 00 db f9 20 00 .......o...... . 00000010: 7e 38 40 00 7b 6d a0 00 4f aa 80 00 4f ab a0 00 ~8@.{m..O...O... 00000020: 4f ad 40 00 53 05 60 00 35 ee 40 00 35 ee c0 00 O.@.S.`.5.@.5... 00000030: 36 00 a0 00 41 b0 40 00 41 ca e0 00 4a 41 20 00 6...A.@.A...JA . 00000040: 4a c7 20 00 4a df 80 00 2d 47 c0 00 e2 5c 20 00 J. .J...-G...\ . 00000050: 3a 5d 60 00 3e 30 a0 00 3b 84 c0 00 38 b5 40 00 :]`.>0..;...8.@. 00000060: 38 16 c0 00 35 70 a0 00 33 26 a0 00 31 1c 00 00 8...5p..3&..1... 00000070: 34 61 00 00 34 5e e0 00 32 a6 80 00 32 92 a0 00 4a..4^..2...2... 00000080: 32 b4 60 00 32 35 c0 00 6d ef 60 00 6d ef 00 00 2.`.25..m.`.m... 00000090: 6c 9e c0 00 66 51 a0 00 60 05 20 00 5f 5f c0 00 l...fQ..`. .__.. 000000a0: 5f 5f a0 00 5f 1a c0 00 5f 2a 80 00 5d 76 a0 00 __.._..._*..]v.. 000000b0: 39 46 00 00 30 65 e0 00 2e 35 40 00 30 7a 80 00 9F..0e...5@.0z.. 000000c0: 30 27 40 00 30 29 20 00 2f c1 80 00 2f 57 20 00 0'@.0) ./.../W . 000000d0: 2f 57 00 00 2f 17 c0 00 2e 95 00 00 29 ab 40 00 /W../.......).@. 000000e0: 28 eb e0 00 28 eb 40 00 0c f6 60 00 0c f9 a0 00 (...(.@...`..... 000000f0: 0c f8 80 00 02 4d 60 00 17 10 60 00 16 04 60 00 .....M`...`...`. 00000100: 11 45 c0 00 11 46 60 00 12 46 60 00 10 09 60 00 .E...F`..F`...`. 00000110: 0e 3f a0 00 0d 11 00 00 0c b1 40 00 0d 04 20 00 .?........@... . 00000120: 0d 05 c0 00 0d 08 40 00 02 b1 a0 00 02 ab e0 00 ......@......... 00000130: 02 a9 80 00 02 a3 00 00 08 02 c0 00 08 56 a0 00 .............V.. 00000140: e0 e5 20 00 00 3b a0 00 00 9f 40 00 43 b4 c0 00 .. ..;....@.C... 00000150: 43 bd a0 00 43 ba e0 00 43 8f 40 00 0a fa e0 00 C...C...C.@..... 00000160: 18 a8 20 00 2e e2 00 00 0b aa 20 00 16 04 20 00 .. ....... ... . 00000170: 15 ce c0 00 15 a2 a0 00 15 8e 00 00 7b f4 80 00 ............{... 00000180: 7f 99 40 00 7f 9a 00 00 81 75 20 00 85 8d c0 00 ..@......u ..... 00000190: 90 3e 20 00 91 e9 80 00 e1 04 40 00 df 87 40 00 .> .......@...@. 000001a0: 73 f3 60 00 90 27 00 00 91 91 e0 00 cd ec 80 00 s.`..'.......... 000001b0: 0b 09 40 00 40 cb 40 00 40 ac 80 00 3f 5e e0 00 ..@.@.@.@...?^.. 000001c0: c9 b6 60 00 ..`. Command SB_COMMAND_JD_GET_THREAD_INFO_XXX ----------------------------------------- >>> URB 208 00000000: 05 00 0b 00 00 05 0e e6 a1 e0 00 ........... <<< URB 188 00000000: 00 00 0c 00 13 05 01 00 27 00 00 00 ........'... <<< URB 190 00000000: 05 00 06 00 00 05 ...... <<< URB 191 00000000: 05 00 09 00 92 e6 a2 20 00 ....... . >>> URB 212 00000000: 05 00 0b 00 00 05 50 e6 a2 20 00 ......P.. . <<< URB 192 00000000: 00 00 0c 00 13 05 01 00 28 00 00 00 ........(... <<< URB 194 00000000: 05 00 06 00 00 04 ...... <<< URB 195 00000000: 05 00 08 00 00 00 00 00 ........ >>> URB 216 00000000: 05 00 0b 00 00 05 0d e6 a1 e0 00 ........... <<< URB 196 00000000: 00 00 0c 00 13 05 01 00 29 00 00 00 ........)... <<< URB 198 00000000: 05 00 06 00 00 04 ...... <<< URB 199 00000000: 05 00 08 00 00 00 00 6b .......k >>> URB 220 00000000: 05 00 0b 00 00 05 85 e6 a1 e0 00 ........... <<< URB 200 00000000: 00 00 0c 00 13 05 01 00 2a 00 00 00 ........*... <<< URB 202 00000000: 05 00 06 00 00 08 ...... <<< URB 203 00000000: 05 00 0c 00 00 00 00 00 00 00 00 00 ............ >>> URB 224 00000000: 05 00 0b 00 00 05 84 e6 a1 e0 00 ........... <<< URB 204 00000000: 00 00 0c 00 13 05 01 00 2b 00 00 00 ........+... <<< URB 206 00000000: 05 00 06 00 00 08 ...... <<< URB 207 00000000: 05 00 0c 00 00 00 00 00 00 00 00 05 ............ Command SB_COMMAND_JD_GET_THREAD_INFO_XXX ----------------------------------------- >>> URB 228 00000000: 05 00 0b 00 00 05 0e db f9 20 00 ......... . <<< URB 208 00000000: 00 00 0c 00 13 05 01 00 2c 00 00 00 ........,... <<< URB 210 00000000: 05 00 06 00 00 05 ...... <<< URB 211 00000000: 05 00 09 00 92 db f9 20 00 ....... . >>> URB 232 00000000: 05 00 0b 00 00 05 50 db f9 20 00 ......P.. . <<< URB 212 00000000: 00 00 0c 00 13 05 01 00 2d 00 00 00 ........-... <<< URB 214 00000000: 05 00 06 00 00 04 ...... <<< URB 215 00000000: 05 00 08 00 00 00 00 00 ........ >>> URB 236 00000000: 05 00 0b 00 00 05 0d db f9 20 00 ......... . <<< URB 216 00000000: 00 00 0c 00 13 05 01 00 2e 00 00 00 ............ <<< URB 218 00000000: 05 00 06 00 00 04 ...... <<< URB 219 00000000: 05 00 08 00 00 00 00 3e .......> >>> URB 240 00000000: 05 00 0b 00 00 05 85 db f9 20 00 ......... . <<< URB 220 00000000: 00 00 0c 00 13 05 01 00 2f 00 00 00 ......../... <<< URB 222 00000000: 05 00 06 00 00 08 ...... <<< URB 223 00000000: 05 00 0c 00 00 00 00 00 00 00 00 00 ............ >>> URB 244 00000000: 05 00 0b 00 00 05 84 db f9 20 00 ......... . <<< URB 224 00000000: 00 00 0c 00 13 05 01 00 30 00 00 00 ........0... <<< URB 226 00000000: 05 00 06 00 00 08 ...... <<< URB 227 00000000: 05 00 0c 00 00 00 00 00 00 00 00 19 ............ Command SB_COMMAND_JD_GET_THREAD_INFO_XXX ----------------------------------------- >>> URB 248 00000000: 05 00 0b 00 00 05 0e 7e 38 40 00 .......~8@. <<< URB 228 00000000: 00 00 0c 00 13 05 01 00 31 00 00 00 ........1... <<< URB 230 00000000: 05 00 06 00 00 05 ...... <<< URB 231 00000000: 05 00 09 00 92 7e 38 40 00 .....~8@. >>> URB 252 00000000: 05 00 0b 00 00 05 50 7e 38 40 00 ......P~8@. <<< URB 232 00000000: 00 00 0c 00 13 05 01 00 32 00 00 00 ........2... <<< URB 234 00000000: 05 00 06 00 00 04 ...... <<< URB 235 00000000: 05 00 08 00 00 00 00 00 ........ >>> URB 256 00000000: 05 00 0b 00 00 05 0d 7e 38 40 00 .......~8@. <<< URB 236 00000000: 00 00 0c 00 13 05 01 00 33 00 00 00 ........3... <<< URB 238 00000000: 05 00 06 00 00 04 ...... <<< URB 239 00000000: 05 00 08 00 00 00 00 33 .......3 >>> URB 260 00000000: 05 00 0b 00 00 05 85 7e 38 40 00 .......~8@. <<< URB 240 00000000: 00 00 0c 00 13 05 01 00 34 00 00 00 ........4... <<< URB 242 00000000: 05 00 06 00 00 08 ...... <<< URB 243 00000000: 05 00 0c 00 00 00 00 00 00 00 00 00 ............ >>> URB 264 00000000: 05 00 0b 00 00 05 84 7e 38 40 00 .......~8@. <<< URB 244 00000000: 00 00 0c 00 13 05 01 00 35 00 00 00 ........5... <<< URB 246 00000000: 05 00 06 00 00 08 ...... <<< URB 247 00000000: 05 00 0c 00 00 00 00 00 00 00 00 1e ............ [...] Command SB_COMMAND_JD_UNKNOWN06 ------------------------------- >>> URB 2396 00000000: 05 00 0b 00 00 05 44 00 00 00 00 ......D.... <<< URB 2376 00000000: 00 00 0c 00 13 05 01 00 4a 02 00 00 ........J... <<< URB 2378 00000000: 05 00 06 00 00 00 ...... Command SB_COMMAND_JD_UNKNOWN07 ------------------------------- >>> URB 2399 00000000: 05 00 0b 00 00 05 45 00 00 00 00 ......E.... <<< URB 2379 00000000: 00 00 0c 00 13 05 01 00 4b 02 00 00 ........K... <<< URB 2381 00000000: 05 00 06 00 00 00 ...... Command SB_COMMAND_JD_UNKNOWN08 ------------------------------- >>> URB 2402 00000000: 05 00 0b 00 00 05 54 00 00 00 00 ......T.... <<< URB 2382 00000000: 00 00 0c 00 13 05 01 00 4c 02 00 00 ........L... <<< URB 2384 00000000: 05 00 06 00 00 00 ...... Command SB_COMMAND_JD_UNKNOWN09 ------------------------------- >>> URB 2405 00000000: 05 00 0b 00 00 05 33 00 00 00 09 ......3.... <<< URB 2385 00000000: 00 00 0c 00 13 05 01 00 4d 02 00 00 ........M... <<< URB 2387 00000000: 05 00 06 00 00 00 ...... Command SB_COMMAND_JD_UNKNOWN10 ------------------------------- >>> URB 2408 00000000: 05 00 0b 00 00 05 46 00 00 00 01 ......F.... <<< URB 2388 00000000: 00 00 0c 00 13 05 01 00 4e 02 00 00 ........N... <<< URB 2390 00000000: 05 00 06 00 00 00 ...... Command SB_COMMAND_JD_GO ------------------------ >>> URB 2411 00000000: 05 00 07 00 00 01 02 ....... <<< URB 2391 00000000: 00 00 0c 00 13 05 01 00 4f 02 00 00 ........O... <<< URB 2393 00000000: 05 00 06 00 00 00 ...... <<< URB 2394 00000000: 05 00 06 00 00 01 ...... <<< URB 2395 00000000: 05 00 05 00 8d ..... Command SB_COMMAND_JD_GET_CONSOLE_MSG ------------------------------------- >>> URB 2416 00000000: 05 00 07 00 00 01 40 ......@ <<< URB 2396 00000000: 00 00 0c 00 13 05 01 00 50 02 00 00 ........P... <<< URB 2398 00000000: 05 00 06 00 00 0b ...... <<< URB 2399 00000000: 05 00 0f 00 00 09 56 4d 3a 2d 44 41 20 30 0a ......VM:-DA 0. Command SB_COMMAND_JD_GET_CONSOLE_MSG ------------------------------------- >>> URB 2420 00000000: 05 00 07 00 00 01 40 ......@ <<< URB 2400 00000000: 00 00 0c 00 13 05 01 00 51 02 00 00 ........Q... <<< URB 2402 00000000: 05 00 06 00 00 02 ...... <<< URB 2403 00000000: 05 00 06 00 00 00 ...... Command SB_COMMAND_JD_GET_STATUS -------------------------------- >>> URB 2424 00000000: 05 00 07 00 00 01 06 ....... <<< URB 2404 00000000: 00 00 0c 00 13 05 01 00 52 02 00 00 ........R... <<< URB 2406 00000000: 05 00 06 00 00 00 ...... <<< URB 2407 00000000: 05 00 06 00 00 01 ...... <<< URB 2408 00000000: 05 00 05 00 8d ..... Command SB_COMMAND_JD_GET_CONSOLE_MSG ------------------------------------- >>> URB 2429 00000000: 05 00 07 00 00 01 40 ......@ <<< URB 2409 00000000: 00 00 0c 00 13 05 01 00 53 02 00 00 ........S... <<< URB 2411 00000000: 05 00 06 00 00 12 ...... <<< URB 2412 00000000: 05 00 16 00 00 10 61 74 74 61 63 68 3a 20 73 75 ......attach: su 00000010: 63 63 65 73 73 0a ccess. Command SB_COMMAND_JD_GET_CONSOLE_MSG ------------------------------------- >>> URB 2433 00000000: 05 00 07 00 00 01 40 ......@ <<< URB 2413 00000000: 00 00 0c 00 13 05 01 00 54 02 00 00 ........T... <<< URB 2415 00000000: 05 00 06 00 00 02 ...... <<< URB 2416 00000000: 05 00 06 00 00 00 ...... Command SB_COMMAND_JD_GET_STATUS -------------------------------- >>> URB 2437 00000000: 05 00 07 00 00 01 06 ....... <<< URB 2417 00000000: 00 00 0c 00 13 05 01 00 55 02 00 00 ........U... <<< URB 2419 00000000: 05 00 06 00 00 00 ...... <<< URB 2420 00000000: 05 00 06 00 00 01 ...... <<< URB 2421 00000000: 05 00 05 00 8d ..... Command SB_COMMAND_JD_GET_CONSOLE_MSG ------------------------------------- >>> URB 2442 00000000: 05 00 07 00 00 01 40 ......@ <<< URB 2422 00000000: 00 00 0c 00 13 05 01 00 56 02 00 00 ........V... <<< URB 2424 00000000: 05 00 06 00 00 1d ...... <<< URB 2425 00000000: 05 00 21 00 00 1b 4a 56 4d 3a 20 62 6b 6c 74 20 ..!...JVM: bklt 00000010: 40 32 36 37 34 36 31 35 34 3a 20 74 69 6d 65 72 @26746154: timer 00000020: 0a . Command SB_COMMAND_JD_GET_CONSOLE_MSG ------------------------------------- >>> URB 2703 00000000: 05 00 07 00 00 01 40 ......@ <<< URB 2708 00000000: 00 00 0c 00 13 05 01 00 5a 02 00 00 ........Z... <<< URB 2710 00000000: 05 00 06 00 00 02 ...... <<< URB 2711 00000000: 05 00 06 00 00 00 ...... Command SB_COMMAND_JD_GET_STATUS -------------------------------- >>> URB 2707 00000000: 05 00 07 00 00 01 06 ....... <<< URB 2712 00000000: 00 00 0c 00 13 05 01 00 5b 02 00 00 ........[... <<< URB 2714 00000000: 05 00 06 00 00 00 ...... Command SB_COMMAND_JD_STOP -------------------------- >>> URB 2500 00000000: 05 00 06 00 a5 02 ...... <<< URB 2518 00000000: 00 00 0c 00 13 05 01 00 69 02 00 00 ........i... <<< URB 2520 00000000: 05 00 06 00 00 01 ...... <<< URB 2521 00000000: 05 00 05 00 8a ..... Command SB_COMMAND_JD_GET_STACK ???? ------------------------------- >>> URB 2504 00000000: 05 00 07 00 00 01 64 ......d <<< URB 2522 00000000: 00 00 0c 00 13 05 01 00 6a 02 00 00 ........j... <<< URB 2524 00000000: 05 00 06 00 00 53 .....S <<< URB 2525 00000000: 05 00 57 00 c9 b6 60 00 00 00 00 03 00 00 00 09 ..W...`......... 00000010: 00 00 57 c8 00 00 00 01 cd 00 00 00 00 09 00 00 ..W............. 00000020: 67 c5 00 00 00 01 01 00 00 00 00 01 00 00 00 2e g............... 00000030: 00 00 00 01 01 00 00 00 00 05 17 8f c0 00 00 00 ................ 00000040: 00 00 00 00 00 00 d5 58 40 00 00 00 00 00 00 00 .......X@....... 00000050: 00 00 00 00 00 00 0a ....... Close and stop debugger >>> URB 2710 00000000: 00 00 08 00 0b 05 00 0e ........ <<< URB 2715 00000000: 00 00 08 00 0c 05 00 0e ........ barry-0.18.5/doc/autotext-format.txt0000644001161500056700000000432112242254476016725 0ustar cdfreycdfreyDate: Thu, 28 Sep 2006 20:40:13 -0500 From: Ron Gage User-Agent: Thunderbird 1.5.0.7 (X11/20060909) To: barry-devel-bounces@lists.sourceforge.net Subject: Partial decoding autotext database Just picking on the low hanging fruit... This is an autotext entry that translates 'eyt' with yet using AutoCase, english language... 00000000: 06 00 32 00 40 03 44 02 6d 00 c2 1a e1 72 01 04 ..2.@.D.m....r.. 00000010: 00 01 65 79 74 00 04 00 02 79 65 74 00 04 00 04 ..eyt....yet.... 00000020: 00 00 00 00 04 00 05 00 00 00 00 04 00 06 00 00 ................ 00000030: 6e 65 ne Same database with AutoCase changed to Specified Case: 00000000: 06 00 32 00 40 03 44 02 6c 00 64 02 66 18 01 04 ..2.@.D.l.d.f... 00000010: 00 01 65 79 74 00 04 00 02 79 65 74 00 04 00 04 ..eyt....yet.... 00000020: 00 00 00 00 04 00 05 01 00 00 00 04 00 06 00 00 ................ 00000030: 6e 65 ne From here, we can see field type 1 is the "from" entry, field 2 is the "to" entry, don't know about field 4 yet or field 6, but field 5 represents the AutoCase option (1 == on). Field type 4 is the language field - 0xffffffff == All Locales, 0x0 == English. Field type 6 appears to be a locale modifier in byte-reversed order. This shows the language record set to "English(US)". 00000000: 06 00 32 00 40 03 44 02 6c 00 66 02 66 18 01 04 ..2.@.D.l.f.f... 00000010: 00 01 65 79 74 00 04 00 02 79 65 74 00 04 00 04 ..eyt....yet.... 00000020: 00 00 00 00 04 00 05 01 00 00 00 04 00 06 53 55 ..............SU 00000030: 6e 65 ne The last 2 characters are part of the locale definition - giving a locale string of US-en. Note that when the language (field 4) is set to "All Locales", field 6 is entirely null: 00000000: 06 00 36 00 40 03 44 02 03 00 6f 1a e1 72 01 06 ..6.@.D...o..r.. 00000010: 00 01 68 74 74 70 73 00 06 00 02 68 74 74 70 73 ..https....https 00000020: 00 04 00 04 ff ff ff ff 04 00 05 01 00 00 00 04 ................ 00000030: 00 06 00 00 00 00 ...... That's it for tonight - got other things to do for the night. Ron Gage barry-0.18.5/doc/bb_sms_format.txt0000644001161500056700000001252312242254476016402 0ustar cdfreycdfreyBlackBerry SMS Messages Record Format This information is result of over 9000 btool -d Tasks dumps from a *single* BB 8800. RIM 8800 Series Colour GPRS Handheld App Version v4.5.0.81(108), platform 2.7.0.78 There are several cases not tested yet, which are hard to catch, i.e. `Pending', etc. information on these incidents is welcomed. Incidentally, some listings here may be inaccurate. ==Header== Length = const 0x0f bytes 00000000: 04 00 x0 x1 40 ?? 44 05 01 00 x2 x3 x4 x5 00 ....@.D........ _____ _____ ___________ _____ ___________ __ type len var0 index uniqueID type - always 04 00, perhaps SMS uses this but others also do len - length of this record in bytes, including header. var0 - 40 02 44 05/40 01 44 05(according to my 9000+ messages), change but all records keep the same. index - the record number within the data base. determines posting order in the device (That is, if you change sort order, the indices of tasks will be modified. Similarly, if you change the priority or due date of a task the ordinal might change as well. uniqueID - 32byte Integer, unique for each task, generated by time. ==Content Fields== The content is divided into 7+ parts, each with a 3byte header: id# format meaning --- ------ ------- 00 2byte size(excluding this header) 01 1byte field type The field type has 7 possible values, ordered as their appearances: ===Field Type 01=== Meaning: Metadata Size: 0x40 Repeat Count: 1 Content: id# var format worked-out meaning(variable)/value(constant) ---- --- ------- ---------- --------------------------------------- 00 yes byte yes 00=SENT/DRAFT, 01=RECV 01 yes byte yes status flags, 80=SEND ERROR, 40=DELIVERY REPORT ON(!not sure), 20=START NEW CONVERSATION, 10=SAVED, 08=DELETED, 01=OPENED 02 yes byte yes 00=OLD, 01=NEW 03 no 2byte yes 00 00 04 yes 4byte yes ff 07 00 00=RECV, ff 1f 00 00=SEND ERROR, ff ff 3f 00=DELIVERY SUCCEDDED ff ff ff 01=SENT, ff ff ff 07=WAITING, ff ff ff 7f=DRAFT 05 yes 4byte no error id, 00 00 00 00=NO ERROR, 84 34 00 00=Unidentified Subscriber 06 yes 8byte yes 8byteInt representing UNIX time(in milliseconds), first 4 bytes=uniqueID 07 yes 8byte yes representing sent time(like #06), probably not in UTC. 08 yes byte yes Data Coding Scheme: 00=7bit, 01=VCARD, 02=UCS2 09 yes 2byte no 00 00=SENT/DRAFT, 04 00=RECV, sometimes all 04 00, probably garbage information 0a yes 4byte yes 00 00 00 00=TEXT, 02 00 00 04=SEND AS FAX3, 03 00 00 04=SEND AS FAX4, 04 00 00 04=SEND AS VOICE, 05 00 00 04=SEND AS ERMES 0b yes 28byte yes 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ===Field Type 09=== Meaning: Unknown Size: Multiple of 0x8(The multiplier is probably send_times) Repeat Count: 1 Content: id# var format worked-out meaning(variable)/value(constant) ---- --- ------- ---------- --------------------------------------- 00 yes unknonwn no Unknown ===Field Type 0B=== Meaning: Unknown Size: Half of the size of field type 09 Repeat Count: 1 Content: id# var format worked-out meaning(variable)/value(constant) ---- --- ------- ---------- --------------------------------------- 00 yes unknown no Unknown ===Field Type 02=== Meaning: Phone Number Size: pn_length + 0x5 Repeat Count: recipient_num Content: id# var format worked-out meaning(variable)/value(constant) ---- --- ------- ---------- --------------------------------------- 00 yes 4byte no 00 00 00 00/01 00 00 00/03 00 00 00 01 yes string yes current recipient's number 02 no byte yes trailing NULL ===Field Type 04=== Meaning: SMS Content Size: content_length Repeat Count: 1 Content: id# var format worked-out meaning(variable)/value(constant) ---- --- ------- ---------- --------------------------------------- 00 yes string yes content ===Field Type 07=== Meaning: Unknown Size: 0xf Repeat Count: 1 Content(May be very inaccurate): id# var format worked-out meaning(variable)/value(constant) ---- --- ------- ---------- --------------------------------------- 00 yes 3byte no Unknown 01 yes byte yes `Sent As', 00=TEXT, 02=FAX3, 03=FAX4, 04=VOICE, 05=ERMES 02 no 2byte yes 00 00 03 yes byte yes 00=DEFAULT, 04=SEND AS NON-TEXT 04 yes 4byte yes 00 00 00 00=SEND AS NON-TEXT, 00 00 00 01=DEFAULT 06 no byte yes 01 07 yes byte yes 00=DELIVERY REPORT OFF, 01=DELIVERY REPORT ON 08 no 2byte yes 00 00 ===Field Type 0c=== Meaning: Possibly Footer Size: 0x8 Repeat Count: 1 Content: id# var format worked-out meaning(variable)/value(constant) ---- --- ------- ---------- --------------------------------------- 00 no 8byte yes 00 00 00 00 ff ff ff ff barry-0.18.5/doc/Exceptions0000644001161500056700000000267612242254476015100 0ustar cdfreycdfrey The Barry library has the following exception hierarchy: - std::exception - std::logic_error - std::runtime_error - Barry::Error - Usb::Error - Usb::Timeout - Barry::BadPassword - Barry::SocketCloseOnOpen - Barry::BadData - Barry::BadSize - Barry::ConfigFileError - Barry::ErrnoError - Barry::ConfigFileError - Barry::BadPackedFormat - Barry::BadPacket - Barry::ConvertError - Barry::BackupError - Barry::RestoreError - Barry::JDWP::Error - Barry::JDWP::Timeout - Barry::PinNotFound - Barry::ReturnCodeError Usb::Error All specific USB error exceptions will be derived from this class. Where possible, this class also stores the specific return code from the libusb API, to allow fine grained error handling. Barry::Error All specific Barry error exceptions will be derived from this class. This can be thrown from anywhere inside Barry. std::bad_alloc There is also the remote possibility that there will be memory exceptions from a call to 'new'. In that case, std::bad_alloc will be thrown by the standard C++ libraries. Barry does not catch these errors. std::logic_error Assert-like errors will cause std::logic_error to be thrown. Barry does sometimes throw these, but they should be be exceedingly rare. All of the above exceptions (from std, Barry, and Usb namespaces) are derived from std::exception, so they can all be caught in one statement for the efficient and lazy. :-) barry-0.18.5/doc/0001-Snoop-limit-and-endpoint-patch.patch0000644001161500056700000000475512242254476022320 0ustar cdfreycdfreyFrom 97beaf75f426ed04e4cc20dd2f65f7e2ce65ece7 Mon Sep 17 00:00:00 2001 From: Chris Frey Date: Fri, 31 Oct 2008 03:44:35 -0400 Subject: [PATCH] Snoop limit and endpoint patch Puts a limit on the amount of data pushed into the printk log, limiting it to the actual size of the USB urbs, not the whole buffer. This patch also adds some missed endpoint values to the logs. --- drivers/usb/core/devio.c | 19 +++++++++++++------ 1 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index de17738..aca73ae 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -288,7 +288,7 @@ static inline struct async *async_getpending(struct dev_state *ps, static void snoop_urb(struct urb *urb, void __user *userurb) { - int j; + int j, len; unsigned char *data = urb->transfer_buffer; if (!usbfs_snoop) @@ -301,7 +301,12 @@ static void snoop_urb(struct urb *urb, void __user *userurb) urb->transfer_buffer_length); dev_info(&urb->dev->dev, "actual_length=%d\n", urb->actual_length); dev_info(&urb->dev->dev, "data: "); - for (j = 0; j < urb->transfer_buffer_length; ++j) + + len = urb->actual_length; + if( len > urb->transfer_buffer_length ) + len = urb->transfer_buffer_length; + + for (j = 0; j < len; ++j) printk("%02x ", data[j]); printk("\n"); } @@ -759,8 +764,8 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) kfree(tbuf); return -EINVAL; } - snoop(&dev->dev, "bulk read: len=0x%02x timeout=%04d\n", - bulk.len, bulk.timeout); + snoop(&dev->dev, "bulk read: ep=0x%02x, len=0x%02x timeout=%04d\n", + bulk.ep, bulk.len, bulk.timeout); usb_unlock_device(dev); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); usb_lock_device(dev); @@ -783,8 +788,8 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) return -EFAULT; } } - snoop(&dev->dev, "bulk write: len=0x%02x timeout=%04d\n", - bulk.len, bulk.timeout); + snoop(&dev->dev, "bulk write: ep=0x%02x, len=0x%02x timeout=%04d\n", + bulk.ep, bulk.len, bulk.timeout); if (usbfs_snoop) { dev_info(&dev->dev, "bulk write: data: "); for (j = 0; j < len1; ++j) @@ -1161,6 +1166,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EFAULT; } } + snoop(&ps->dev->dev, "submit urb: bEndpoint %02x\n", + uurb->endpoint); snoop_urb(as->urb, as->userurb); async_newpending(as); if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { -- 1.6.0.3 barry-0.18.5/doc/cod-format0000644001161500056700000001344712242254476015010 0ustar cdfreycdfreyCOD file structure ================== To write the javeloader application, I need to understand the format of COD file. C structures : -------------- typedef struct { } codfile_header_t; typedef struct { int flashid; uint section_number; //always 0 uint vtable_pointer; //always 0 time_t timestamp; uint user_version; uint fieldref_pointer; ushort maxtype_list_size; short reserved; //always 0xFF int data_section; //always 0xFFFF int module_info; //always 0xFFFF ushort version; ushort code_size; ushort data_size; ushort flags; } code_header_t; sizeof(code_header_t) = 0x2C; typedef struct { ubyte flags; ubyte version; ushort num_icalls; ubyte num_modules; ubyte num_classes ; ushort exported_string_offset; ushort data_bytes_offset; ushort empty_field; ushort class_definitions; ushort array_of_unknow_fields[14]; ushort aliases; ushort array_of_unknow_fields[22]; } data_header_t; sizeof(data_header_t) = 0x34; Scheme : -------- +------------------------------------------+ | COD file header (1) | +------------------------------------------+ | Code segment header | | size = sizeof(code_header_t) = 0x2C | +------------------------------------------+ | Code segment | | size = code_header_t.code_size | +------------------------------------------+ | Data segment header | | size = sizeof(data_header_t) = 0x34 | +------------------------------------------+ | Data segment | | size = code_header_t.data_size | +------------------------------------------+ +------------------------------------------+ | COD file header (2) | +------------------------------------------+ | Code segment header | . . . . . . +------------------------------------------+ Sample (from Opera.cod) : ------------------------- 00000000 50 4B 03 04 0A 00 00 00 00 00-AB 5C 6A 39-BE 5C 58 D1 CC 0D PK.........\j9.\X... COD size ^^^^^ 00000014 01 00 CC 0D 01 00 19 00 04 00 .......... ^^^^^ ^^^^^^^^^^^^ ^^ empty byte (after the string) COD size ^^ size of string 00000014 6F 70 65 72 65 74 74 65 2D 68 operette-h [.............................. 00000028 69 66 69 2D 34 2E 32 62 65 74 61 2E 63 6F 64 FE CA 00 00 ifi-4.2beta.cod.... ................string........................] [..........] empty 00000028 DE . 0000003C C0 FF FF 00 00 00 00 00 00 00 00 E0 0E 18 49 00 00 00 00 00 ..............I..... 00000050 00 00 00 22 00 FF FF FF FF FF FF FF FF FF FF 4E 00 08 DC 98 ..."...........N.... [...] 00010DD8 A2 03 0C 0E 08 02 04 FD A2 03 4E 08 00 07 96 A3 03 1D 48 34 ..........N.......H4 00010DEC 12 08 01 03 B5 A3 03 08 04 04 E8 A3 03 25 08 05 03 A7 A4 03 .............%...... 00010E00 00 00 00 00 00 00 00 ....... 00010E00 50 4B 03 04 0A 00 00 00 00 00 AB 5C 6A PK.........\j 00010E14 39-D1 BD FC C9-1C DD 00 00-1C DD 00 00-1B 00 00 00 9................ ^^ size of string 00010E14 6F 70 65 ope 00010E28 72 65 74 74 65 2D 68 69 66 69 2D 34 2E 32 62 65 74 61 2D 31 rette-hifi-4.2beta-1 00010E3C 2E 63 6F 64 .cod 00010E3C DE C0 FF FF 00 00 00 00 00 00 00 00 E0 0E 18 49 ...............I 00010E50 00 00 00 00 00 00 00 00 1F 00 FF FF FF FF FF FF FF FF FF FF .................... 00010E64 4E 00 D8 A1 18 3B 01 00 50 29 DE 29 06 80 F8 01 15 0D FF 00 N....;..P).)........ 00010E78 00 20 0C FF FF 4D 0C 46 2F 15 0D FF FF 79 0E FF FF 82 0E FF . ...M.F/....y...... 00010E8C FF 62 07 50 29 50 29 23 11 18 00 05 13 00 08 0E 6E 02 01 0A .b.P)P)#........n... 00010EA0 00 28 CC 0C 01 FF FF 02 69 00 03 00 6D 00 03 00 A0 04 DF A1 .(......i...m....... 00010EB4 0A 6D 00 03 00 04 FF 01 00 01 55 28 1C 17 07 00 AE 11 CF 56 .m........U(.......V [...] 0001EB54 00 00 00 00 00 00 00 00 50 4B 03 04 0A 00 00 00 00 00 AB 5C ........PK.........\ 0001EB68 6A 39-24 41 BE 50 5C B0 00 00 5C B0 00-00-1B-00- 00-00 6F 70 j9$A.P\...\.......op 0001EB7C 65 72 65 74 74 65 2D 68 69 66 69 2D 34 2E 32 62 65 74 61 2D erette-hifi-4.2beta- 0001EB90 32 2E 63 6F 64 DE C0 FF FF 00 00 00 00 00 00 00 00 E0 0E 18 2.cod............... Sample (from Metro.cod) : ------------------------- 00000000 50 4B 03 04 0A 00 00 00 00 00-A0 00 51 35-BA 9F 99 5D-30 CE PK..........Q5...]0. 00000014 00 00-30 CE 00-00-15-00--04-00-4D 65 74 72 6F 56 69 65 77 65 ..0.......MetroViewe 00000028 72 2E 50 61 72 69 73 2E 63 6F 64 FE CA 00 00 DE C0 FF FF 00 r.Paris.cod......... 0000003C 00 00 00 00 00 00 00 0F 10 34 45 00 00 00 00 00 00 00 00 21 .........4E........! 0000CE54 6F 90 02 03 0F 03 A8 0F 03 04 00 02 AA 10 00 00 00 00 00 50 o..................P 0000CE68 4B 03 04 0A 00 00 00 00 00 A0 00 51 35 7A C4 FE 22-34 B3-00 K..........Q5z.."4.. 0000CE7C 00-34 B3-00--00-17-00-00--00-4D 65 74 72 6F 56 69 65 77 65 72 .4.......MetroViewer 0000CE90 2E 50 61 72 69 73 2D 31 2E 63 6F 64 DE C0 FF FF 00 00 00 00 .Paris-1.cod........ 0000CEA4 00 00 00 00 0F 10 34 45 00 00 00 00 00 00 00 00 05 00 FF FF ......4E............ barry-0.18.5/doc/BBTips0000644001161500056700000000154112242254476014070 0ustar cdfreycdfreyHow do I find out if my BlackBerry is unlocked? ----------------------------------------------- From: http://forums.crackberry.com/blackberry-unlocking-f157/how-tell-if-your-bb-unlocked-17336/ You should not need a SIM card, I never have. On your BlackBerry, go to Options > Advanced Options > Sim Card. At that screen type MEPD on your keyboard. A new menu will pop up. Look for Network in the list. If your device is "unlocked", it should say Disabled or Inactive. If it says Active, it's still locked to that carrier. List of all Databases on BlackBerry: ------------------------------------ http://btsc.webapps.blackberry.com/btsc/search.do?cmd=displayKC&docType=kc&externalId=KB03974&sliceId=1&docTypeID=DT_SUPPORTISSUE_1_1&dialogID=408910218&stateId=0 http://www.blackberryforums.com/general-blackberry-discussion/224133-databases-blackberry.html barry-0.18.5/doc/CommitPolicy.txt0000644001161500056700000000276112242254476016200 0ustar cdfreycdfrey2009/12/15 Note: now that we primarily use git for version control, and CVS is just a backup, git supports specific authors per commit. When accepting patches from others, I still use the "applied" language where appropriate, but also try to add people's names and email addresses directly into the commit, along with their exact patch. Of course, if I pull from a git repo, this happens automatically as well. - Chris Date: Fri, 25 May 2007 17:39:27 -0400 From: Chris Frey To: barry-devel@lists.sourceforge.net Subject: CVS commit policy Hi folks, For those of you sending patches, this is probably good to know: In order to track copyrights properly, so I can go back in the history and see who sent what patch, I try, whenever possible, to commit the *exact* patch I receive, even if it temporarily breaks the tree, or if there are things I don't agree with and plan to change later. For these commits, I use the words "applied patch from X" in the Changelog and the CVS commit message. And then I change whatever I think needs changing, and commit that later. In this way, history is preserved, in case it is needed down the road. Also, if you see your raw patch committed, there may be a followup commit coming after. Just to be aware of. And again, a huge thank you to everyone who has sent patches! If you have sent a patch and didn't get into the AUTHORS file, or are unhappy with what is there (perhaps an email address change, or whatever) just let me know. - Chris barry-0.18.5/doc/javaloader-reset.txt0000644001161500056700000001062612242254476017017 0ustar cdfreycdfrey>>> Send packet <<< Receive packet The following series of packets occur after SB_COMMAND_CLOSE_SOCKET when either loading or forcefully erasing a module that is in use (busy). This sequence is strikingly similar to the one used by cfp.exe utility when it resets the handheld. It also resembles the sequence used to probe for devices. The entire sequence is actually not necessary. The final packet is the only one required to cause the device to reset. However, this document helps to serve as documentation for several previously unknown packets. The meaning of several packets was discovered by analyzing the debug logs created by RIM's own USB driver on windows. Debug logging is turned on by setting two registry keys. >>> 00000000: 00 00 10 00 01 ff 00 03 bb 35 2d b9 01 00 00 00 .........5-..... ^^^^^ socket number ^^^^^ size of packet ^^ echo command this looks to be a simple echo command ^^^^^ SB_MODE_REQUEST_SOCKET in barry ^^ socket sequence ^^^^^^^^^^^^^^^^^^^^^^^ these 8 bytes seem to always increase with each execution of javaloader... if the value is interpreted as a time span in microseconds it is very close to the duration since system startup <<< 00000000: 00 00 10 00 02 ff 00 03 bb 35 2d b9 01 00 00 00 .........5-..... ^^ echo response >>> 00000000: 00 00 0c 00 05 ff 00 04 14 00 01 00 ............ ^^ fetch attribute ^^^^^ SB_MODE_REQUEST_SOCKET ^^ socket sequence ^^^^^ SB_OBJECT_INITIAL_UNKNOWN ^^^^^ SB_ATTR_INITIAL_UNKNOWN <<< 00000000: 00 00 20 00 06 ff 00 04 14 00 01 00 3c 41 30 3e .. ......... ^^ begin 20 byte device GUID <<< 00000010: 1e 47 24 0d 99 92 3f b1 38 d6 a3 6e 75 cd c9 d7 .G$...?.8..nu... >>> 00000000: 00 00 0c 00 05 ff 00 05 08 00 04 00 ............ ^^^^^ SB_OBJECT_PROFILE ^^^^^ SB_ATTR_PROFILE_PIN (Network and PPIN?) <<< 00000000: 00 00 14 00 06 ff 00 05 08 00 04 00 03 00 00 00 ................ <<< 00000010: 2e 36 61 20 .6a >>> 00000000: 00 00 0c 00 05 ff 00 06 04 00 05 00 ............ ^^^^^ SB_OBJECT_SOCKET_UNKNOWN ^^^^^ unknown (Emulator ID?) <<< 00000000: 00 00 0c 00 06 ff 00 06 00 00 00 00 ............ >>> 00000000: 00 00 0c 00 05 ff 00 07 04 00 06 00 ............ ^^^^^ SB_OBJECT_SOCKET_UNKNOWN ^^^^^ unknown (USB Serial Interface Version?) <<< 00000000: 00 00 0c 00 06 ff 00 07 00 00 00 00 ............ >>> 00000000: 00 00 0c 00 05 ff 00 08 04 00 07 00 ............ ^^^^^ SB_OBJECT_SOCKET_UNKNOWN ^^^^^ unknown (MUX Version Successful) <<< 00000000: 00 00 10 00 06 ff 00 08 04 00 07 00 00 02 00 00 ................ ^^^^^^^^^^^ MUX version = 200 >>> 00000000: 00 00 0c 00 05 ff 00 09 04 00 08 00 ............ ^^^^^ SB_OBJECT_SOCKET_UNKNOWN ^^^^^ unknown (EVDO Modem Version?) <<< 00000000: 00 00 0c 00 06 ff 00 09 00 00 00 00 ............ >>> 00000000: 00 00 0c 00 05 ff 00 0a 04 00 0a 00 ............ ^^^^^ SB_OBJECT_SOCKET_UNKNOWN ^^^^^ unknown (ESN?) <<< 00000000: 00 00 0c 00 06 ff 00 0a 00 00 00 00 ............ >>> 00000000: 00 00 08 00 03 ff 00 0b ........ ^^ reset command <<< 00000000: 00 00 08 00 04 ff 00 0b ........ ^^ reset response barry-0.18.5/doc/bookmark.txt0000644001161500056700000003150512242254476015373 0ustar cdfreycdfreyBrowser Bookmarks Documentation 1°/ 00000000: 07 00 b2 00 40 02 44 01 02 00 ff 5d ac 11 00 5c ....@.D....]...\ ^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^^^ socket size index uniqueID command 00000010: 00 11 81 8d b1 bb 7f 01 04 01 00 14 44 61 20 4c ............Da L <------------> RR RR SS ^^ <----- unknown title size 00000020: 69 6e 75 78 20 46 72 65 6e 63 68 20 50 61 67 65 inux French Page title -----> 00000030: 81 ff ff ff ff f8 d0 df cc 02 00 05 01 00 25 68 ..............%h ^^ ^^^^^^^^^^^ RR RR ^^^^^ <- size 00000040: 74 74 70 3a 2f 2f 6c 69 6e 75 78 66 72 2e 6f 72 ttp://linuxfr.or 00000050: 67 2f 69 6d 61 67 65 73 2f 66 61 76 69 63 6f 6e g/images/favicon URL favicon 00000060: 2e 69 63 6f 00 a3 fb b5 9a ff 65 00 00 00 41 00 .ico......e...A. ------> SS ^^ ^^ ^^ RR display mode browser ident. javascript mode 00000070: 12 00 17 68 74 74 70 3a 2f 2f 6c 69 6e 75 78 66 ...http://linuxf RR SS ^^ <---- size URL 00000080: 72 2e 6f 72 67 2f 70 75 62 2f 01 c2 21 00 00 00 r.org/pub/..!... ----> 00000090: 00 00 01 00 11 57 41 50 20 42 72 6f 77 73 65 72 .....WAP Browser ^^ RR ^^^^^ <--- size 000000a0: 43 6f 6e 66 69 67 00 04 00 01 00 05 57 50 54 43 Config......WPTC -------> RR RR RR RR SS ^^ <---------- size 000000b0: 50 07 P. -> ^^ 00000000: 07 00 ad 00 40 02 44 01 04 00 9d 13 85 7e 00 57 ....@.D......~.W 00000010: 00 11 87 f4 94 a7 1d 01 04 01 00 14 44 61 20 4c ............Da L 00000020: 69 6e 75 78 20 46 72 65 6e 63 68 20 50 61 67 65 inux French Page 00000030: 81 b9 fc f8 f6 c2 e3 a4 d5 08 00 05 01 00 25 68 ..............%h 00000040: 74 74 70 3a 2f 2f 6c 69 6e 75 78 66 72 2e 6f 72 ttp://linuxfr.or 00000050: 67 2f 69 6d 61 67 65 73 2f 66 61 76 69 63 6f 6e g/images/favicon 00000060: 2e 69 63 6f 00 00 00 00 00 41 00 12 00 17 68 74 .ico.....A....ht 00000070: 74 70 3a 2f 2f 6c 69 6e 75 78 66 72 2e 6f 72 67 tp://linuxfr.org 00000080: 2f 70 75 62 2f 01 c2 21 00 00 00 00 00 01 00 11 /pub/..!........ 00000090: 57 41 50 20 42 72 6f 77 73 65 72 43 6f 6e 66 69 WAP BrowserConfi 000000a0: 67 00 04 00 01 00 05 57 50 54 43 50 07 g......WPTCP. RR : reserved / unknown SS : separator brower identification : 00 - Auto 01 - BlackBerry 02 - FireFox 03 - Internet Explorer display mode : 00 - Automatique 01 - colomn 02 - page javascript mode : 00 - Automatique 01 - Enabled 02 - Disabled 2°/ Synchro : Jamais 00000000: 07 00 86 00 40 02 44 01 01 00 bc a0 a1 65 00 2f ....@.D......e./ ^^^^^ ^^^^^^^^^^^ 00000010: 00 11 86 ad 86 c1 3c 00 04 01 00 0e 50 61 67 65 ......<.....Page ^^^^^ <---- 00000020: 20 64 27 61 63 63 75 65 69 6c 81 ff ff ff ff f8 d'accueil...... -----> ^^ ^^^^^^^^^^^ 00000030: d0 df cc 02 01 05 00 00 a3 f7 db d4 d8 2f 00 00 ............./.. ^^ 00000040: 01 42 00 12 00 18 68 74 74 70 3a 2f 2f 6c 69 76 .B....http://liv ^^^^^ <---- 00000050: 65 2e 76 6f 64 61 66 6f 6e 65 2e 63 6f 6d 01 c2 e.vodafone.com.. ----> 00000060: 21 00 00 00 00 01 01 00 11 57 41 50 20 42 72 6f !........WAP Bro ^^^^^ <----------- 00000070: 77 73 65 72 43 6f 6e 66 69 67 00 04 00 01 00 05 wserConfig...... --------> ^^^^^ 00000080: 57 50 54 43 50 07 WPTCP. <------------> Synchro : 24 hours - start : 8:00 00000000: 07 00 89 00 40 02 44 01 01 00 bc a0 a1 65 00 32 ....@.D......e.2 -- 00000010: 00 11 86 ad 86 c1 3c 00 04 01 00 0e 50 61 67 65 ......<.....Page 00000020: 20 64 27 61 63 63 75 65 69 6c 81 ff ff ff ff f8 d'accueil...... 00000030: d0 df cc 02 01 05 00 01 01 8d dd e8 00 85 a3 00 ................ -------------------------- 00000040: 00 00 00 01 42 00 12 00 18 68 74 74 70 3a 2f 2f ....B....http:// -------- 00000050: 6c 69 76 65 2e 76 6f 64 61 66 6f 6e 65 2e 63 6f live.vodafone.co 00000060: 6d 01 c2 21 00 00 00 00 01 01 00 11 57 41 50 20 m..!........WAP 00000070: 42 72 6f 77 73 65 72 43 6f 6e 66 69 67 00 04 00 BrowserConfig... 00000080: 01 00 05 57 50 54 43 50 07 ...WPTCP. Synchro : 12 hours - start : 8:00 00000000: 07 00 89 00 40 02 44 01 01 00 bc a0 a1 65 00 32 ....@.D......e.2 00000010: 00 11 86 ad 86 c1 3c 00 04 01 00 0e 50 61 67 65 ......<.....Page 00000020: 20 64 27 61 63 63 75 65 69 6c 81 ff ff ff ff f8 d'accueil...... 00000030: d0 df cc 02 01 05 00 01 01 8d dd e8 00 82 d1 40 ...............@ -------- 00000040: 00 00 02 01 42 00 12 00 18 68 74 74 70 3a 2f 2f ....B....http:// 00000050: 6c 69 76 65 2e 76 6f 64 61 66 6f 6e 65 2e 63 6f live.vodafone.co 00000060: 6d 01 c2 21 00 00 00 00 01 01 00 11 57 41 50 20 m..!........WAP 00000070: 42 72 6f 77 73 65 72 43 6f 6e 66 69 67 00 04 00 BrowserConfig... 00000080: 01 00 05 57 50 54 43 50 07 ...WPTCP. Synchro : 8 hours - start : 8:00 00000000: 07 00 89 00 40 02 44 01 01 00 bc a0 a1 65 00 32 ....@.D......e.2 00000010: 00 11 86 ad 86 c1 3c 00 04 01 00 0e 50 61 67 65 ......<.....Page 00000020: 20 64 27 61 63 63 75 65 69 6c 81 ff ff ff ff f8 d'accueil...... 00000030: d0 df cc 02 01 05 00 01 01 8d dd e8 00 81 e1 00 ................ -------- 00000040: 00 00 02 01 42 00 12 00 18 68 74 74 70 3a 2f 2f ....B....http:// 00000050: 6c 69 76 65 2e 76 6f 64 61 66 6f 6e 65 2e 63 6f live.vodafone.co 00000060: 6d 01 c2 21 00 00 00 00 01 01 00 11 57 41 50 20 m..!........WAP 00000070: 42 72 6f 77 73 65 72 43 6f 6e 66 69 67 00 04 00 BrowserConfig... 00000080: 01 00 05 57 50 54 43 50 07 ...WPTCP. Synchro : 4 hours - start : 8:00 00000000: 07 00 88 00 40 02 44 01 01 00 bc a0 a1 65 00 31 ....@.D......e.1 00000010: 00 11 86 ad 86 c1 3c 00 04 01 00 0e 50 61 67 65 ......<.....Page 00000020: 20 64 27 61 63 63 75 65 69 6c 81 ff ff ff ff f8 d'accueil...... 00000030: d0 df cc 02 01 05 00 01 01 8d dd e8 00 f0 40 00 ..............@. < 8:00 > d0 df cc 02 01 05 00 01 01 a9 95 e3 20 f0 40 00 < 23:59 > 00000040: 00 00 01 42 00 12 00 18 68 74 74 70 3a 2f 2f 6c ...B....http://l 00000050: 69 76 65 2e 76 6f 64 61 66 6f 6e 65 2e 63 6f 6d ive.vodafone.com 00000060: 01 c2 21 00 00 00 00 01 01 00 11 57 41 50 20 42 ..!........WAP B 00000070: 72 6f 77 73 65 72 43 6f 6e 66 69 67 00 04 00 01 rowserConfig.... 00000080: 00 05 57 50 54 43 50 07 ..WPTCP. Synchro : Never (after 24 hours test) Indentification : BlackBerry 00000000: 07 00 81 00 40 02 44 01 01 00 bc a0 a1 65 00 2a ....@.D......e.* -- 00000010: 00 11 86 ad 86 c1 3c 00 04 01 00 0e 50 61 67 65 ......<.....Page 00000020: 20 64 27 61 63 63 75 65 69 6c 81 ff ff ff ff f8 d'accueil...... 00000030: d0 df cc 02 01 05 00 00 00 00 00 01 42 00 12 00 ............B... ----------- 00000040: 18 68 74 74 70 3a 2f 2f 6c 69 76 65 2e 76 6f 64 .http://live.vod 00000050: 61 66 6f 6e 65 2e 63 6f 6d 01 c2 21 00 00 00 00 afone.com..!.... 00000060: 01 01 00 11 57 41 50 20 42 72 6f 77 73 65 72 43 ....WAP BrowserC 00000070: 6f 6e 66 69 67 00 04 00 01 00 05 57 50 54 43 50 onfig......WPTCP 00000080: 07 . 3°/ 00000000: 07 00 82 00 40 02 44 01 04 00 bb a0 a1 65 00 2f ....@.D......e./ ^^^^^ ^^^^^^^^^^^ 00000010: 00 11 86 ad 86 c1 3b 00 04 01 00 0e 50 61 67 65 ......;.....Page ^^^^^ <---- 00000020: 20 64 27 61 63 63 75 65 69 6c 81 b9 fc f8 f6 c2 d'accueil...... -------> ^^ ^^^^^^^^^^^ 00000030: e3 a4 d5 08 01 05 00 00 a3 f9 f7 f8 e6 6e 00 00 .............n.. 00000040: 01 3e 00 12 00 1d 68 74 74 70 3a 2f 2f 6d 6f 62 .>....http://mob ^^^^^ <----------- 00000050: 69 6c 65 2e 62 6c 61 63 6b 62 65 72 72 79 2e 63 ile.blackberry.c 00000060: 6f 6d 2f 01 c2 21 00 00 00 00 01 01 00 09 47 50 om/..!........GP -----> ^^^^^ <---- 00000070: 4d 44 53 45 55 30 31 00 04 00 01 00 04 49 50 50 MDSEU01......IPP --------> ^^^^^ <------- 00000080: 50 04 P. -> ----------------------------------------------------------------------------- Further notes from Chris Frey's test devices: Section 0x11: Starts with 0x85 or 0x87 - 4 byte record ID? - 1 byte record index (00, 01, 02, 03, 04) Code: 0x04 - 1 byte "present" flag... always 1 for 0x04, I think - 2 byte big endian size - string, no null terminator Code? 0x81 always seems to follow - 81 b9 fc f8 f6 c2 e3 a4 d5 08 01 05 00 (no icon) - 81 b9 fc f8 f6 c2 e3 a4 d5 08 01 05 00 (no icon) - 81 b9 fc f8 f6 c2 e3 a4 d5 08 00 05 01 (icon url) - 81 b9 fc f8 f6 c2 e3 a4 d5 08 00 05 00 (no icon) - 81 b9 fc f8 f6 c2 e3 a4 d5 08 00 05 00 (no icon) - 81 b9 fc f8 f6 c2 e3 a4 d5 08 00 05 00 (no icon) - 81 b9 fc f8 f6 c2 e3 a4 d5 08 00 05 01 (icon url) - so: - 4 byte ID - another 4 byte ID - 1 byte unknown - 1 byte flag (seen 1 or 0) Code: 0x05 (on older devices, this is code 01 as a terminator?) - 1 byte "present" flag - if 0, then size could be 0x00a5 which adds 5 unknown bytes - if 1, then size is length of string - 2 byte big endian size - string here (may be no bytes) - 3 byte flags for display mode, javascript mode, and browser id Raw record dump for record: e2416731 00000000: 06 00 27 00 40 03 44 01 03 00 31 67 41 e2 00 15 ..'.@.D...1gA... 00000010: 00 00 82 e3 a4 d5 08 00 0e 73 75 62 66 6f 6c 64 .........subfold 00000020: 65 72 20 6e 61 6d 65 er name Type: 0x11 Data: 00000000: 85 9b ed ca 13 00 04 01 00 09 48 6f 6d 65 20 50 ..........Home P 00000010: 61 67 65 81 b9 fc f8 f6 c2 e3 a4 d5 08 01 05 00 age............. 00000020: 00 a5 b8 f0 97 e4 3a 00 00 01 ......:... Type: 0x12 Data: 00000000: 00 1c 68 74 74 70 3a 2f 2f 6d 6f 62 69 6c 65 2e ..http://mobile. 00000010: 62 6c 61 63 6b 62 65 72 72 79 2e 63 6f 6d 01 c2 blackberry.com.. 00000020: 21 00 00 00 00 01 01 00 09 53 20 54 43 50 2d 57 !........S TCP-W 00000030: 42 43 00 04 00 01 00 05 57 50 54 43 50 03 BC......WPTCP. Type: 0x11 Data: 00000000: 85 9b ed ca 13 00 04 01 00 0a 48 6f 6d 65 20 50 ..........Home P 00000010: 61 67 65 3f 81 b9 fc f8 f6 c2 e3 a4 d5 08 01 05 age?............ 00000020: 00 00 00 00 00 01 ...... Type: 0x12 Data: 00000000: 00 1c 68 74 74 70 3a 2f 2f 6d 6f 62 69 6c 65 2e ..http://mobile. 00000010: 62 6c 61 63 6b 62 65 72 72 79 2e 63 6f 6d 01 c2 blackberry.com.. 00000020: 21 00 00 00 00 01 01 00 09 53 20 54 43 50 2d 57 !........S TCP-W 00000030: 42 43 00 04 00 01 00 05 57 50 54 43 50 03 BC......WPTCP. Type: 0x11 Data: 00000000: 87 f4 f2 ce 67 04 04 01 00 08 53 70 65 63 69 61 ....g.....Specia 00000010: 6c 3f 81 b9 fc f8 f6 c2 e3 a4 d5 08 00 05 00 00 l?.............. 00000020: 00 00 00 00 .... Type: 0x12 Data: 00000000: 00 1c 68 74 74 70 3a 2f 2f 6d 6f 62 69 6c 65 2e ..http://mobile. 00000010: 62 6c 61 63 6b 62 65 72 72 79 2e 63 6f 6d 01 c2 blackberry.com.. 00000020: 21 00 00 00 00 00 01 00 09 53 20 54 43 50 2d 57 !........S TCP-W 00000030: 42 43 00 04 00 01 00 05 57 50 54 43 50 03 BC......WPTCP. barry-0.18.5/doc/vsm/0000755001161500056700000000000012242254476013626 5ustar cdfreycdfreybarry-0.18.5/doc/vsm/VSM_analysis.txt0000644001161500056700000002460312242254476016744 0ustar cdfreycdfreyAnalysis of the file format for Vendor Splash Media files ========================================================= VSM files start with the bytes 01 00 00 bc which appear to be nothing more than a magic number. Changing any of these first four bytes causes the file to not be recognized as a VSM file. Next are four bytes that give the length of the resource section in little-endian order so 46 0b 00 00 signifies that the length is 0x00000b46 or 2886 bytes long. The next four bytes are calculated by taking 0xffffffff - (the CRC-32 of the resource section). For my sample VSM file, the CRC-32 of the resource section is 0x896f263c. 0xffffffff - 0x896f263c = 0x7690d9c3 so the four bytes are c3 d9 90 76. The Vendor ID takes the next two bytes. Remember that little-endian order is used, so 36 01 is used to represent the vendor id 310 for Wind Italy. The Vendor ID MAY be changed without affecting the file signature or the checksum. The next two bytes are always zero. There is a single byte value of unknown purpose followed by two bytes of zero followed by a byte that is zero when the unknown value is zero, and one when the unknown value is non-zero. There are eight bytes of zero before the resource section begins. This may be reserved for future use. The resource section may be empty, but most often it contains resources. Each resource starts with two bytes that specify the resource type, followed by a two byte resource length value, followed by the resource data. If the last byte of the resource falls on an even-numbered address offset (assuming the first byte in the file is considered offset zero) then there is a pad null byte between the two resources. The pad byte is not figured into the length of either resource, but is included in the value for the total resource section length found in the file header. The resouces may be listed in any order, however changing any byte in the resource section including resource order will cause the file signature to be invalid. Following the resource section there may or may not be a footer and signature. The footer is the byte sequence: 1F 2D C8 D7 33 00 00 00 80 00 00 00. I am not sure of the function of the first eight bytes, but I believe the 80 00 specifies that the signature is of length 0x0080 or 128 bytes. There are two null bytes followed by a 128 byte (1024 bit) signature. The following table lists the values to use to define a field type followed by a name for each. There are also some values for flags listed after the field for which they are used. 0x0 FIELD_BITMAP_1_DATA 0x1 FIELD_BITMAP_1_TIMEOUT 0x2 FIELD_BITMAP_2_DATA 0x10 FIELD_ENGINEERING_UNIT 0x11 FIELD_SUPPRESS_SOS 0x13 FIELD_BETA_TEST 0x14 FIELD_EVALUATION_UNIT 0x15 FIELD_SUPPORT_DIRECT_DIAL_SEND 0x16 FIELD_ONS_RENDER_MODE 0x17 FIELD_DISABLE_VOLUME_BOOST 0x18 FIELD_DISABLE_BLACKBERRY_PROTECTION_MODE 0x1000 FIELD_WELCOME_MESSAGE_SUBJECT_ISO8859 0x1001 FIELD_WELCOME_MESSAGE_BODY_ISO8859 0x1002 FIELD_WELCOME_MESSAGE_FROM_ISO8859 0x1003 FIELD_WELCOME_MESSAGE_SUBJECT 0x1004 FIELD_WELCOME_MESSAGE_BODY 0x1005 FIELD_WELCOME_MESSAGE_FROM 0x1100 FIELD_DEVICE_MESSAGE_SUBJECT 0x1101 FIELD_DEVICE_MESSAGE_BODY 0x1102 FIELD_DEVICE_MESSAGE_FROM 0x1200 FIELD_TOP_TIPS_MESSAGE_SUBJECT 0x1201 FIELD_TOP_TIPS_MESSAGE_BODY 0x1202 FIELD_TOP_TIPS_MESSAGE_FROM 0x2000 FIELD_ESCREEN_HELP_MSG 0x3000 FIELD_PROVISIONING_IP 0x3001 FIELD_PROVISIONING_DEST_PORT 0x3002 FIELD_PROVISIONING_SRC_PORT 0x3003 FIELD_PROVISIONING_APN 0x3004 FIELD_PROVISIONING_DEVICE_CLASS 0x3005 FIELD_PROVISIONING_APN_USERNAME 0x3006 FIELD_PROVISIONING_APN_PASSWORD 0x3007 FIELD_PROVISIONING_FLAGS 0x1 FLAG_PROVISIONING_DONT_SEND_MSISDN 0x2 FLAG_PROVISIONING_DONT_SEND_ICCID 0x4 FLAG_PROVISIONING_SEND_SPN 0x8 FLAG_PROVISIONING_RIM 0x10 FLAG_PROVISIONING_SEND_EMPLOYEE_ROLE_FEATURE_INFO 0x20 FLAG_PROVISIONING_DONT_SEND_AIRTIME_USAGE_STATS 0x40 FLAG_PROVISIONING_INFO_LEVEL_1 0x80 FLAG_PROVISIONING_INFO_LEVEL_2 0x3100 FIELD_2ND_PROVISIONING_IP 0x3101 FIELD_2ND_PROVISIONING_DEST_PORT 0x3102 FIELD_2ND_PROVISIONING_SRC_PORT 0x3103 FIELD_2ND_PROVISIONING_APN 0x3104 FIELD_2ND_PROVISIONING_DEVICE_CLASS 0x3105 FIELD_2ND_PROVISIONING_APN_USERNAME 0x3106 FIELD_2ND_PROVISIONING_APN_PASSWORD 0x3107 FIELD_2ND_PROVISIONING_FLAGS 0x3500 TCP_APN_DEFAULT_APNNAME 0x3501 TCP_APN_DEFAULT_USERNAME 0x3502 TCP_APN_DEFAULT_PASSWORD 0x3600 FIELD_CDMA_IIF_APN 0x3601 FIELD_CDMA_IIF_APN_USERNAME 0x3602 FIELD_CDMA_IIF_APN_PASSWORD 0x3800 FIELD_PRIMARY_WIRELESS_ACCESS_FAMILY 0x1 WAF_3GPP 0x2 WAF_CDMA 0x3 WAF_WLAN 0x4 WAF_IDEN 0x4000 FIELD_BRANDING_WAP_ICON 0x4001 FIELD_BRANDING_TUNE 0x4002 FIELD_BRANDING_TUNE_NAME 0x4003 FIELD_BRANDING_KEY 0x4004 FIELD_BRANDING_TUNE_MIDI 0x4005 FIELD_BRANDING_WAP_SPLASH 0x4006 FIELD_BRANDING_TUNE_CONTENT_DATA 0x4007 FIELD_BRANDING_TUNE_CONTENT_TYPE 0x4100 FIELD_BRANDING_BROWSER_ICON_0 0x4101 FIELD_BRANDING_BROWSER_ICON_1 0x4102 FIELD_BRANDING_BROWSER_ICON_2 0x4103 FIELD_BRANDING_BROWSER_ICON_3 0x4104 FIELD_BRANDING_BROWSER_ICON_4 0x4105 FIELD_BRANDING_BROWSER_ICON_5 0x4106 FIELD_BRANDING_BROWSER_ICON_6 0x4107 FIELD_BRANDING_BROWSER_ICON_7 0x4108 FIELD_BRANDING_BROWSER_ICON_8 0x4109 FIELD_BRANDING_BROWSER_ICON_9 0x4200 FIELD_IDLESCREEN_CONTENT_TYPE 0x4201 FIELD_IDLESCREEN_CONTENT_DATA 0x4202 FIELD_BRANDING_IGNORE_INTEL_SPLASH 0x4300 FIELD_BROWSER_UAPROF_URI 0x5000 FIELD_HELP_WMLC 0x5100 FIELD_PREFERRED_PLMN_FEATURE 0x0 VALUE_PREFERRED_PLMN_DISABLED 0x1 VALUE_PREFERRED_PLMN_ENABLED 0x5200 PHONE_BOOT_URL 0x5201 PHONE_BOOT_NAIURL 0x5202 BROWSER_DOMAIN_TRUSTED 0x5203 BROWSER_PROXY_WDP 0x5300 FIELD_CELL_BROADCAST 0x5301 FIELD_CELL_BROADCAST_ALWAYS_POPUP 0x6000 FIELD_MESSAGE_LIST_OPTIONS_AUTO_ATTACHMENT_DOWNLOAD_ENABLED 0x6001 FIELD_MESSAGE_LIST_OPTIONS_AUTO_ATTACHMENT_DOWNLOAD 0x6002 FIELD_MESSAGE_LIST_OPTIONS_AUTO_ATTACHMENT_DOWNLOAD_HIGH_SPEED_NETWORK 0x7000 FIELD_OMA_CLIENT_PROVISIONING_DOCUMENT 0x7010 FIELD_GAN_SECURE_GATEWAY 0x7011 FIELD_GAN_CONTROLLER 0x7020 FIELD_GAN_ROOT_CERT_1 0x7021 FIELD_GAN_ROOT_CERT_2 0x7022 FIELD_GAN_ROOT_CERT_3 0x7023 FIELD_GAN_ROOT_CERT_4 0x7026 FIELD_GAN_WLAN_THRESHOLD 0x0 VALUE_GAN_ROVE_THRESHOLD_LOW 0x1 VALUE_GAN_ROVE_THRESHOLD_MEDIUM 0x2 VALUE_GAN_ROVE_THRESHOLD_HIGH 0x7027 FIELD_GAN_SIGNAL_STRENGTH_THRESHOLD 0x7028 FIELD_GAN_SIGNAL_QUALITY_THRESHOLD 0x7029 FIELD_GAN_PROTOCOL_VERSION 0x0 VALUE_GAN_PROTOCOL_VERSION_UMA_1_0_0 0x1 VALUE_GAN_PROTOCOL_VERSION_UMA_1_0_1 0x2 VALUE_GAN_PROTOCOL_VERSION_UMA_1_0_2 0x3 VALUE_GAN_PROTOCOL_VERSION_UMA_1_0_3 0x4 VALUE_GAN_PROTOCOL_VERSION_UMA_1_0_4 0x5 VALUE_GAN_PROTOCOL_VERSION_3GPP_rev6 0x7030 FIELD_WLAN_DISABLED 0x7031 FIELD_WLAN_ENTERPRISE_DATA_DISABLED 0x7032 FIELD_WLAN_ENTERPRISE_DATA_FLAG_OVERRIDES_IT_POLICY 0x7033 FIELD_WLAN_LAYER3_AUTH_KEY Below is a list of Vendor ID values in both hex and decimal. 0x01 1 RIM 0x64 100 T_MOBILE_US 0x65 101 CINGULAR_WIRELESS 0x66 102 AT_T_WIRELESS 0x67 103 NEXTEL 0x68 104 SPRINT_PCS 0x69 105 VERIZON_WIRELESS 0x6a 106 ALLTEL 0x6b 107 ROGERS_AT_T 0x6c 108 MICROCELL 0x6d 109 BELL_MOBILITY 0x6e 110 BT_CELLNET 0x6f 111 O2_GERMANY 0x70 112 DIGIFONE 0x71 113 TELFORT 0x72 114 T_MOBILE_GERMANY_AUSTRIA 0x73 115 TIM_ITALY 0x74 116 HUTCHISON 0x75 117 BOUYGUES_TELECOM 0x76 118 VODAFONE_SFR_FRANCE 0x77 119 ORANGE_FRANCE 0x78 120 VODAFONE_UK_NETHERLANDS 0x79 121 TELCEL_MEXICO 0x7a 122 TELSTRA 0x7b 123 T_MOBILE_UK 0x7c 124 VODAFONE_GERMANY 0x7d 125 O2_UK_IRELAND_ISLE_OF_MAN_NETHERLANDS 0x7e 126 TELUS 0x7f 127 SMART 0x80 128 STARHUB 0x81 129 TELEFONICA_SPAIN 0x82 130 VODAFONE_SWITZERLAND_SWISSCOM 0x83 131 CABLE_WIRELESS_WEST_INDIES 0x84 132 VODAFONE_ITALY 0x85 133 VODAFONE_SPAIN 0x86 134 T_MOBILE_NETHERLANDS 0x87 135 CINCINNATI_BELL 0x88 136 TELEFONICA_MEXICO 0x89 137 VODAFONE_AUSTRIA 0x8a 138 VODAFONE_AUSTRALIA_FIJI 0x8b 139 VODAFONE_IRELAND 0x8c 140 TELENOR_SWEDEN 0x8d 141 CSL 0x8e 142 ORANGE_UK 0x8f 143 VODAFONE_NEW_ZEALAND 0x90 144 SINGTEL 0x91 145 GLOBE 0x92 146 OPTUS 0x93 147 ORANGE_BE_MOBISTAR 0x94 148 VODAFONE_HUNGARY 0x95 149 BHARTI 0x96 150 KPN_NL 0x97 151 WIND_HELLAS_TIM_GREECE 0x98 152 VODAFONE_BELGIUM 0x99 153 VODAFONE_PORTUGAL 0x9a 154 TIM_BRAZIL 0x9b 155 BT_MOBILE 0x9c 156 EARTHLINK 0x9d 157 AETHER 0x9e 158 E_PLUS 0x9f 159 BASE 0xa0 160 DOBSON_COMMUNICATIONS 0xa1 161 VODAFONE_EGYPT 0xa2 162 ORANGE_SWITZERLAND 0xa3 163 RIM_WLAN 0xa4 164 T_MOBILE_SUNCOM 0xa5 165 MAXIS 0xa6 166 VODAFONE_DENMARK_TDC 0xa7 167 VODAFONE_SINGAPORE_M1 0xa8 168 VODACOM_SOUTH_AFRICA 0xa9 169 T_MOBILE_POLAND 0xaa 170 T_MOBILE_CZECH 0xab 171 T_MOBILE_HUNGARY 0xac 172 AT_T_SPRINT 0xad 173 MTN_SOUTH AFRICA 0xae 174 TIM_CHILE_ENTEL_PCS 0xaf 175 ORANGE_SPAIN 0xb0 176 VODAFONE_SMARTONE_HONG_KONG 0xb1 177 TCS_TELECOMMUNICATION_SYSTEMS 0xb2 178 AVEA 0xb3 179 FAST_100 0xb4 180 TURKCELL 0xb5 181 PARTNER_COMMUNICATIONS 0xb7 183 ORANGE_ROMANIA 0xba 186 TELKOMSEL 0xbc 188 VODAFONE_GREECE 0xbd 189 UNITED_STATES_CELLULAR_CORP 0xbe 190 MOBILINK 0xbf 191 VELOCITA_WIRELESS 0xc0 192 VODAFONE_CROATIA 0xc1 193 VODAFONE_SLOVENIA 0xc2 194 VODAFONE_LUXEMBOURG 0xc3 195 VODAFONE_ICELAND 0xc4 196 VODAFONE_FIJI 0xc5 197 VODAFONE_ROMANIA 0xc6 198 VODAFONE_CZECH 0xc7 199 VODAFONE_BAHRAIN 0xc8 200 VODAFONE_KUWAIT 0xc9 201 T_MOBILE_CROATIA 0xca 202 T_MOBILE_SLOVAKIA 0xcb 203 NORTEL 0xcc 204 CHINA_MOBILE 0xcd 205 MOVILNET 0xd1 209 SYMPAC 0xd2 210 PERSONAL_ARGENTINA 0xd4 212 ETISALAT_UAE 0xd5 213 CBEYOND 0xd6 214 AMX 0xd7 215 TELEFONICA_VENEZUELA 0xd8 216 TELEFONICA_BRAZIL 0xd9 217 ORANGE_ROMANIA 0xda 218 KTPOWERTEL_KOREA 0xdb 219 ROLLING_STONES 0xdc 220 DOCOMO 0xde 222 VODAFONE_BULGARIA 0xdf 223 NEXTEL_INTERNATIONAL 0xe0 224 PCCW_SUNDAY 0xe1 225 HAWAIIAN_TELCOM_CREDO_MOBILE 0xe2 226 VERIZON_MVNO 0xe3 227 MOBILY 0xe4 228 BWA 0xe5 229 O2_CZECH_REPUBLIC 0xe6 230 HUTCHISON_INDIA 0xe7 231 CELCOM 0xea 234 DIALOG 0xeb 235 XL 0xec 236 RELIANCE 0xed 237 VERIZON_WIRELESS_WHOLESALE 0xee 238 VODAFONE_TURKEY 0xef 239 TELEFONICA_MOROCCO_MEDITEL 0xf0 240 INDOSAT 0xf1 241 ALCATEL_SHANGHAI_BELL 0xf5 245 3_UK_ITALY_SWEDEN_DENMARK_AUSTRIA_IRELAND 0xf7 247 VODAFONE_ESSAR 0xf8 248 CENTENNIAL_WIRELESS 0xfa 250 T_MOBILE_AUSTRIA 0xfe 254 OI_BRAZIL 0xff 255 TELECOM_NEW_ZEALAND 0x102 258 HUTCHINSON_3G_AUSTRALIA 0x103 259 CABLE_&_WIRELESS_TRINIDAD_TOBAGO 0x10c 268 BMOBILE 0x10d 269 TATA_TELESERVICES_INDIA 0x10f 271 T_MOBILE_CROATIA 0x111 273 BT_ITALY 0x112 274 1&1 0x115 277 MTS_MOBILITY 0x116 278 VIRGIN_MOBILE 0x118 280 ORANGE_SLOVAKIA 0x11a 282 TAIWAN_MOBILE 0x11d 285 ORANGE_AUSTRIA 0x11e 286 VODAFONE_MALTA 0x120 288 BASE_JIM_MOBILE 0x127 295 CMCC_PEOPLES 0x12a 298 DIGITEL_WIRELESS 0x12b 299 SK_TELECOM 0x12c 300 SOLO_MOBILE 0x12d 301 CARPHONE_WAREHOUSE 0x12e 302 20:20_MOBILE_GROUP 0x134 308 XL_INDONESIA 0x135 309 FIDO_SOLUTIONS 0x136 310 WIND_ITALY barry-0.18.5/doc/vsm/MyVSM-0010000644001161500056700000000554212242254476015030 0ustar cdfreycdfreyF ِv  PNG  IHDR@O*<gAMA a IDATx^Av7 EQeg^v Nb;"zQݒ?>>>|!@SBޚ۶@3  З#` Oޯ'@#@g|z~=_: pӳ Й;_OGz>t&@Χg 3w>={ |}LOޯ'@#@g|z~=9Wf'ԕ~]| 8H`\z9arsrn{|6vg"k3x Ӭ|) |sOJUZs6$O&pJYC^<]S)ARd xMtM!@`I5L55 $E 0$O&pJYC^<]S)ARd xMtM!@`I5L55 $E 0$O&pJYC^<]S)ARd xMtM!@`I5L55 $E 0$O&pJYC^<]S)ARd xMtM!@`I5L55 $E 0$O&pJYC^߾'5%uK`yE+s+t5|0%QE 9_Y@!L`E#sӱoىB=NUtyL`x$A1ۊ& l=L`>n<~x̅ӱ l `&q*pA6?Ǽ}|#ӱ l `&q*pA6?:st(`?& |:60M1oet(`?& |:60M㷎\8<+ & lGb0L`s[72<+ & lGb0͟>y엛m GGϵ <07Dogx:V0{̟hXkW {8vX {UQގ<{CW7܃:\L8=St.L࿿5$.!@`cE/~?)$Ҫf}xݔx#&?~sP? L&jTo+Kԥ%nWRk } 07"@`{H'0 L`_yac `Z&+{jl3$f 5' 0 lׁb}~5iV(; y}EͫQV?So) ʹ}!B`j6&G-Z9<Ϻ;/ÉM*\ .)6t+ho[&> 88 K`#3u9x L`d.'p/ %0A&p02S8FfrL]N ^8 K`#3u9x L`d.'p/ %0A&p02S8FfrL]N ^8 K`#3u9x L`d.'p/ %0A&p02S8FfrL]N ^8 K`#3u9x L`d.'p/ %0A&p02S8Ffr^^컨O`We>~_LH^ 8`-# LH^jv.J%A6pt'{'0wM w"0go}>u: 0¤P=>u: 0¤P=>u: 0¤P=>u: 0¤P=>u: 0¤P=>u: 0¤P=>u: 0¤P=>u: 0¤P=>u: 0¤P=>u: 0¤P=>u: 0¤P=>u: 0¤P=>u: 0¤P=>u:sۤB 6Aέ 0¤P=1=Eg=ןG 0zCu<@q$%3 (n. X И#@`@17><[G2@cn|xel : póu,4&@ƇgXhL И#@`@17><[G2@cn|xel fY4IENDB`Welcome to BarryThanks for installing the sample branding file for the Barry project. Direct your browser to http://sourceforge.net/projects/barry and http://www.netdirect.ca/software/packages/barry/ to learn more about the Barry project.Barry Developers PThis BlackBerry has been customized with a branding file from the Barry project.barry-0.18.5/doc/vsm/MyVSM-001.txt0000644001161500056700000003211212242254476015637 0ustar cdfreycdfrey0000000: 0100 00bc 460b 0000 c3d9 9076 0903 0000 ....F......v.... ^MagicNumber ^VendorID 0x0309 (777 decimal) ^resourceSectionLength ^resourceSectionchecksum 0000010: 0000 0000 0000 0000 0000 0000 0000 dc09 ................ ^resType 0x0 (splash screen PNG) ^resLength 0x9dc 0000020: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR 0000030: 0000 0140 0000 00f0 0802 0000 00fe 4f2a ...@..........O* 0000040: 3c00 0000 0467 414d 4100 00b1 8f0b fc61 <....gAMA......a 0000050: 0500 0009 9349 4441 5478 5eed dd41 761c .....IDATx^..Av. 0000060: 370c 4551 6567 5e9a 76ae c8d1 204e 623b 7.EQeg^.v... Nb; 0000070: 8d22 0812 e4d5 f1c0 0316 c07a fcaf 51dd .".........z..Q. 0000080: 92ad 3f3e 3e3e de7c 2180 4053 029f 02fb ..?>>>.|!.@S.... 0000090: 4200 81a6 04de 9aee dbb6 1140 e0fb e333 B..........@...3 00000a0: 0a08 20d0 9700 81fb 9e9d 9d23 6002 cb00 .. ........#`... 00000b0: 029d 0998 c09d 4fcf deaf 2740 e0eb 2300 ......O...'@..#. 00000c0: 4067 0204 ee7c 7af6 7e3d 0102 5f1f 0100 @g...|z.~=.._... 00000d0: 3a13 2070 e7d3 b3f7 eb09 10f8 fa08 00d0 :. p............ 00000e0: 9900 813b 9f9e bd5f 4f80 c0d7 4700 80ce ...;..._O...G... 00000f0: 0408 dcf9 f4ec fd7a 0204 be3e 0200 7426 .......z...>..t& 0000100: 40e0 cea7 67ef d713 20f0 f511 00a0 3301 @...g... .....3. 0000110: 0277 3e3d 7bbf 9e00 81af 8f00 009d 0910 .w>={........... 0000120: b8f3 e9d9 fbf5 0408 7c7d 0400 e84c 80c0 ........|}...L.. 0000130: 9d4f cfde af27 40e0 eb23 0040 6702 04ee .O...'@..#.@g... 0000140: 7c7a f67e 3d81 3902 bf7f fbf0 e757 04ae |z.~=.9......W.. 0000150: cf1c 0089 04f2 0466 ec03 0289 27a9 d495 .......f....'... 0000160: 0492 047e 905d 977c 11f0 85c0 0081 0c81 ...~.].|........ 0000170: a938 4860 e0fc 5c7a 3981 6181 07b3 eb72 .8H`..\z9.a....r 0000180: 73f8 7205 c76e 9fc0 7b7c de36 768a aebe s.r..n..{|.6v... 0000190: 96c0 98c0 e667 2281 6b33 e8c6 0708 1078 .....g".k3.....x 00001a0: 8f09 ecd3 ac81 10df 7c29 8109 7c73 fedb ........|)..|s.. 00001b0: dffb 80c0 894f 8f4a 99c0 ed55 5a73 0304 .....O.J...UZs.. 00001c0: 3681 d724 4fd7 1402 0426 704a 9014 5943 6..$O....&pJ..YC 00001d0: 80c0 045e 933c 5d53 0810 98c0 2941 5264 ...^.<]S....)ARd 00001e0: 0d01 0213 784d f274 4d21 4060 02a7 0449 ....xM.tM!@`...I 00001f0: 9135 0408 4ce0 35c9 d335 8500 8109 9c12 .5..L.5..5...... 0000200: 2445 d610 2030 81d7 244f d714 0204 2670 $E.. 0..$O....&p 0000210: 4a90 1459 4380 c004 5e93 3c5d 5308 1098 J..YC...^.<]S... 0000220: c029 4152 640d 0102 1378 4df2 744d 2140 .)ARd....xM.tM!@ 0000230: 6002 a704 4991 3504 084c e035 c9d3 3585 `...I.5..L.5..5. 0000240: 0081 099c 1224 45d6 1020 3081 d724 4fd7 .....$E.. 0..$O. 0000250: 1402 0426 704a 9014 5943 80c0 045e 933c ...&pJ..YC...^.< 0000260: 5d53 0810 98c0 2941 5264 0d01 0213 784d ]S....)ARd....xM 0000270: f274 4d21 4060 02a7 0449 9135 0408 4ce0 .tM!@`...I.5..L. 0000280: 35c9 d335 8500 8109 9c12 2445 d610 2030 5..5......$E.. 0 0000290: 81d7 244f d714 0204 2670 4a90 1459 4380 ..$O....&pJ..YC. 00002a0: c004 5e93 3c5d 5308 1098 c029 4152 640d ..^.<]S....)ARd. 00002b0: 0102 1378 4df2 744d 2140 6002 a704 4991 ...xM.tM!@`...I. 00002c0: 3504 084c e035 c9d3 3585 0081 099c 1224 5..L.5..5......$ 00002d0: 45d6 1020 3081 d724 4fd7 1402 0426 704a E.. 0..$O....&pJ 00002e0: 9014 5943 e05e 81df bebd fb83 c027 8135 ..YC.^.......'.5 00002f0: e625 75bd 4b60 7945 e0f7 0492 b4aa 2b73 .%u.K`yE......+s 0000300: 91c0 b28b c02b 04ea e4cb e874 8bc0 af9c .....+.....t.... 0000310: 9c35 087c 11c8 30ab a8c6 1502 cb25 0251 .5.|..0......%.Q 0000320: 0245 fe0d b739 5fe0 e8c9 598f 40a3 214c .E...9_...Y.@.!L 0000330: 609f 4523 f073 02c3 d3b1 a200 81c5 1701 `.E#.s.......... 0000340: 02bf 6ff3 e310 ffd9 8907 4204 9e11 a818 ..o.......B..... 0000350: a0c3 3d0e 9fc0 cf4e ce55 0874 791b 4c60 ..=....N.U.ty.L` 0000360: 0f90 0878 84de f511 da24 41e0 3181 e1c7 ...x.....$A.1... 0000370: db8a 0226 b0f9 8380 096c 02fb a711 c711 ...&.....l...... 0000380: a818 a0c3 3d4c 60f3 0701 13d8 043e 6efe ....=L`......>n. 0000390: 3c7e eb78 cc85 c3d3 b1a2 8009 6cfe 2060 <~.x........l. ` 00003a0: 029b c026 f071 042a 06e8 700f 13d8 fc41 ...&.q.*..p....A 00003b0: c004 3681 8f9b 3fc7 bc95 7d7c 23c3 d3b1 ..6...?...}|#... 00003c0: a280 096c fe20 6002 9bc0 26f0 7104 2a06 ...l. `...&.q.*. 00003d0: e870 0f13 d8fc 41c0 0436 818f 9b3f 8fdf .p....A..6...?.. 00003e0: 3a1e 73e1 f074 ac28 6002 9b3f 0898 c026 :.s..t.(`..?...& 00003f0: b009 7c1c 818a 013a dcc3 0436 7f10 3081 ..|....:...6..0. 0000400: 4de0 e3e6 cf31 6f65 1fdf c8f0 74ac 2860 M....1oe....t.(` 0000410: 029b 3f08 98c0 26b0 097c 1c81 8a01 3adc ..?...&..|....:. 0000420: c304 367f 1030 814d e0e3 e6cf e3b7 8ec7 ..6..0.M........ 0000430: 5c38 3c1d 2b0a 98c0 e60f 0226 b009 6c02 \8<.+......&..l. 0000440: 1f47 a062 800e f730 81cd 1f04 4c60 13f8 .G.b...0....L`.. 0000450: b8f9 73cc 5bd9 c737 323c 1d2b 0a98 c0e6 ..s.[..72<.+.... 0000460: 0f02 26b0 096c 021f 47a0 6280 0ef7 3081 ..&..l..G.b...0. 0000470: cd9f 1e04 3ede de1f fc79 fcfc ec97 9b6d ....>....y.....m 0000480: f10b 4747 cecf b5cb 093c 30f6 3797 446f ..GG.....<0.7.Do 0000490: 6778 3a56 1430 817b cc9f 68f8 0e58 9f6b gx:V.0.{..h..X.k 00004a0: ef57 b510 960a ff86 7b10 3876 a8a1 0458 .W......{.8v...X 00004b0: fc98 c00c 7ba3 0e0f cb55 5180 c004 de8e ....{....UQ..... 00004c0: c03c 7b43 0e57 f837 dc83 c0db c5f7 f1d4 .<{C.W.7........ 00004d0: 3ae3 c2d9 f6be eef0 b05c 1505 084c e0bd :........\...L.. 00004e0: 0810 38e4 3d81 f78a ef19 5374 e42e 084c ..8.=.....St...L 00004f0: e0bf bf83 3592 24d7 2e21 4060 0213 b8eb ....5.$..!@`.... 0000500: 6345 8dbd 2f7e 3f29 24d2 aac5 1ea1 bb66 cE../~?)$......f 0000510: 7dc9 789c dd94 c0d1 1702 0213 7823 0204 }.x.........x#.. 0000520: 26f0 3f7e 8473 f6c4 503f 9700 8109 4ce0 &.?~.s..P?....L. 0000530: 8d26 6a54 6f02 1398 c004 feff 7fb7 f4ca .&jTo........... 0000540: 2b4b d4a5 25eb bd07 6e1c f757 52d8 6b8d +K..%...n..WR.k. 0000550: 091c 7d15 2030 8137 2240 6002 7b84 de48 ..}. 0.7"@`.{..H 0000560: c8e8 fc27 3081 094c 60ef 815f 791d d8f5 ...'0..L`.._y... 0000570: ffc1 faf8 6163 d109 60fd 5a02 26f0 2be6 ....ac..`.Z.&.+. 0000580: fdb8 c67b e0c6 f36a ad6c 33ba 1398 c01e ...{...j.l3..... 0000590: a11b bf24 1198 c0ff fecf f466 0c0a 3527 ...$.......f..5' 00005a0: 1120 3081 096c 02fb 10eb 95d7 810e 1f62 . 0..l.........b 00005b0: 7d7e a035 6956 283b 8380 09fc 8a79 177d }~.5iV(;.....y.} 00005c0: 8845 e019 9acd abb9 8fc0 5191 56ad 3ffc .E........Q.V.?. 00005d0: 53e8 af6f 29cd 0b9c cab9 0408 1c7d 21b8 S..o)........}!. 00005e0: 4260 0ee7 6a36 afda 2602 472d 5ab8 fe16 B`..j6..&.G-Z... 00005f0: 8139 3ccf bac4 ca3b 08bc d0c6 07ad 2f12 .9<....;....../. 0000600: 98c3 89a6 4d2a b55c e007 0aad bde4 2e81 ....M*.\........ 0000610: 7ffc 29cb edfe be36 089b 747f f42b 089f ..)....6..t..+.. 0000620: 68bf c9fd 0e6f 83c0 5bfc 16c5 efaf 26be h....o..[.....&. 0000630: 3e09 1038 1803 0213 3818 99a9 cb09 1cc4 >..8....8....... 0000640: 4b60 0207 2333 7539 8183 7809 4ce0 6064 K`..#3u9..x.L.`d 0000650: a62e 2770 102f 8109 1c8c ccd4 e504 0ee2 ..'p./.......... 0000660: 2530 8183 9199 ba9c c041 bc04 2670 3032 %0.......A..&p02 0000670: 5397 1338 8897 c004 0e46 66ea 7202 07f1 S..8.....Ff.r... 0000680: 1298 c0c1 c84c 5d4e e020 5e02 1338 1899 .....L]N. ^..8.. 0000690: a9cb 091c c44b 6002 0723 3375 3981 8378 .....K`..#3u9..x 00006a0: 094c e060 64a6 2e27 7010 2f81 091c 8ccc .L.`d..'p./..... 00006b0: d4e5 040e e225 3081 8391 99ba 9cc0 41bc .....%0.......A. 00006c0: 0426 7030 3253 9713 3888 97c0 040e 4666 .&p02S..8.....Ff 00006d0: ea72 0207 f112 98c0 c1c8 4c5d 4ee0 205e .r........L]N. ^ 00006e0: 0213 3818 99a9 cb09 1cc4 4b60 0207 2333 ..8.......K`..#3 00006f0: 7539 8183 7809 4ce0 6064 a62e 2770 102f u9..x.L.`d..'p./ 0000700: 8109 1c8c ccd4 e504 0ee2 2530 8183 9199 ..........%0.... 0000710: ba9c c041 bc04 2670 3032 5397 1338 8897 ...A..&p02S..8.. 0000720: c004 0e46 66ea 7202 07f1 1298 c0c1 c84c ...Ff.r........L 0000730: 5d4e e020 5e02 1338 1899 a9cb 091c c44b ]N. ^..8.......K 0000740: 6002 0723 3375 3981 8378 094c e060 64a6 `..#3u9..x.L.`d. 0000750: 2e27 7010 2f81 091c 8ccc d4e5 040e e225 .'p./..........% 0000760: 3081 8391 99ba 9cc0 41bc 0426 7030 3253 0.......A..&p02S 0000770: 9713 3888 97c0 040e 4666 ea72 0207 f112 ..8.....Ff.r.... 0000780: 98c0 c1c8 cc5e 5ee3 f0ec bba8 aa4f 6002 .....^^......O`. 0000790: 5765 edc5 3e04 7e11 d45f cb08 4ce0 485e We..>.~.._..L.H^ 00007a0: 0ad6 1238 0299 c004 8ee4 a560 2d81 2390 ...8.......`-.#. 00007b0: 094c e048 5e6a d6ce 76b8 e62e 4aba 1098 .L.H^j..v...J... 00007c0: c025 418b 3699 e770 7427 7baf 2730 8177 .%A.6..pt'{.'0.w 00007d0: 4de8 0c87 77bd d7c7 fb22 3081 1f87 67fe M...w...."0...g. 00007e0: 85b9 0ecf df6f 7d07 0213 b83e 753a a611 .....o}....>u:.. 00007f0: 2030 81d3 c2a4 503d 0102 13b8 3e75 3aa6 0....P=....>u:. 0000800: 1120 3081 d3c2 a450 3d01 0213 b83e 753a . 0....P=....>u: 0000810: a611 2030 81d3 c2a4 503d 0102 13b8 3e75 .. 0....P=....>u 0000820: 3aa6 1120 3081 d3c2 a450 3d01 0213 b83e :.. 0....P=....> 0000830: 753a a611 2030 81d3 c2a4 503d 0102 13b8 u:.. 0....P=.... 0000840: 3e75 3aa6 1120 3081 d3c2 a450 3d01 0213 >u:.. 0....P=... 0000850: b83e 753a a611 2030 81d3 c2a4 503d 0102 .>u:.. 0....P=.. 0000860: 13b8 3e75 3aa6 1120 3081 d3c2 a450 3d01 ..>u:.. 0....P=. 0000870: 0213 b83e 753a a611 2030 81d3 c2a4 503d ...>u:.. 0....P= 0000880: 0102 13b8 3e75 3aa6 1120 3081 d3c2 a450 ....>u:.. 0....P 0000890: 3d01 0213 b83e 753a a611 2030 81d3 c2a4 =....>u:.. 0.... 00008a0: 503d 0102 13b8 3e75 3aa6 1120 3081 d3c2 P=....>u:.. 0... 00008b0: a450 3d01 0213 b83e 753a a611 2030 81d3 .P=....>u:.. 0.. 00008c0: c2a4 503d 0102 13b8 3e75 3aa6 1118 10f8 ..P=....>u:..... 00008d0: 730f efdb a4ff 809d a49d a942 1711 20f0 s..........B.. . 00008e0: 36af 4117 a5ce ada6 1120 3081 d3c2 a450 6.A...... 0....P 00008f0: 3d81 3181 3d45 673d bad7 9fbc 8e47 1020 =.1.=Eg=.....G. 0000900: f01e 13f8 8830 b989 7a02 c302 1bc2 e343 .....0..z......C 0000910: b8fe d875 3c85 4086 c01c 1e71 f894 24b9 ...u<.@....q..$. 0000920: 8f25 0492 04e6 f033 8797 9cb9 a607 11c8 .%.....3........ 0000930: 13f8 2028 6e05 812e 0408 dce5 a4ec 1381 .. (n........... 0000940: 9f10 20b0 5820 d098 0081 1b1f 9ead 2340 .. .X ........#@ 0000950: 6019 40a0 3101 0237 3e3c 5b47 80c0 3280 `.@.1..7><[G..2. 0000960: 4063 0204 6e7c 78b6 8e00 8165 0081 c604 @c..n|x....e.... 0000970: 08dc f8f0 6c1d 0102 cb00 028d 0910 b8f1 ....l........... 0000980: e1d9 3a02 0496 0104 1a13 2070 e3c3 b375 ..:....... p...u 0000990: 0408 2c03 0834 2640 e0c6 8767 eb08 1058 ..,..4&@...g...X 00009a0: 0610 684c 80c0 8d0f cfd6 1120 b00c 20d0 ..hL....... .. . 00009b0: 9800 811b 1f9e ad23 4060 1940 a031 0102 .......#@`.@.1.. 00009c0: 373e 3c5b 4780 c032 8040 6302 046e 7c78 7><[G..2.@c..n|x 00009d0: b68e 0081 6500 81c6 0408 dcf8 f06c 1d01 ....e........l.. 00009e0: 02cb 0002 8d09 fc09 9066 8998 59ce 348d .........f..Y.4. 00009f0: 0000 0000 4945 4e44 ae42 6082 0100 0200 ....IEND.B`..... ^resType 0x1 (splash screen duration) ^resLength 0x2 0000a00: a00f 0310 1000 5765 6c63 6f6d 6520 746f ......Welcome to ^0xfa0 = 4000 milliseconds ^resType 0x1003 (Welcome message subject) ^resLength 0x10 ^resData "Welcome to Barry" 0000a10: 2042 6172 7279 0410 df00 5468 616e 6b73 Barry....Thanks ^resType 0x1004 (Welcome message body) ^resLength 0xdf ^resData "Thanks for..." 0000a20: 2066 6f72 2069 6e73 7461 6c6c 696e 6720 for installing 0000a30: 7468 6520 7361 6d70 6c65 2062 7261 6e64 the sample brand 0000a40: 696e 6720 6669 6c65 2066 6f72 2074 6865 ing file for the 0000a50: 2042 6172 7279 2070 726f 6a65 6374 2e20 Barry project. 0000a60: 2044 6972 6563 7420 796f 7572 2062 726f Direct your bro 0000a70: 7773 6572 2074 6f20 6874 7470 3a2f 2f73 wser to http://s 0000a80: 6f75 7263 6566 6f72 6765 2e6e 6574 2f70 ourceforge.net/p 0000a90: 726f 6a65 6374 732f 6261 7272 7920 616e rojects/barry an 0000aa0: 6420 6874 7470 3a2f 2f77 7777 2e6e 6574 d http://www.net 0000ab0: 6469 7265 6374 2e63 612f 736f 6674 7761 direct.ca/softwa 0000ac0: 7265 2f70 6163 6b61 6765 732f 6261 7272 re/packages/barr 0000ad0: 792f 2074 6f20 6c65 6172 6e20 6d6f 7265 y/ to learn more 0000ae0: 2061 626f 7574 2074 6865 2042 6172 7279 about the Barry 0000af0: 2070 726f 6a65 6374 2e00 0510 1000 4261 project......Ba ^resType 0x1005 (Welcome message from) ^resLength 0x10 ^resData "Barry Developers." 0000b00: 7272 7920 4465 7665 6c6f 7065 7273 0020 rry Developers. ^resType 0x2000 (Escreen message) 0000b10: 5000 5468 6973 2042 6c61 636b 4265 7272 P.This BlackBerr ^resLength 0x50 ^resData "This Blackberry..." 0000b20: 7920 6861 7320 6265 656e 2063 7573 746f y has been custo 0000b30: 6d69 7a65 6420 7769 7468 2061 2062 7261 mized with a bra 0000b40: 6e64 696e 6720 6669 6c65 2066 726f 6d20 nding file from 0000b50: 7468 6520 4261 7272 7920 7072 6f6a 6563 the Barry projec 0000b60: 742e t. barry-0.18.5/doc/www/0000755001161500056700000000000012242254476013645 5ustar cdfreycdfreybarry-0.18.5/doc/www/guisync.php0000644001161500056700000001100212242254476016031 0ustar cdfreycdfrey

Below is the sync mode screen of the Barry Desktop GUI:

The Sync screen displays a list of all connected devices as well as all devices that have an OpenSync configuration (whether those devices are connected or not).

Each device is setup to sync with a given application, which correspondes to the available plugins on the OpenSync side.

In addition, if multiple versions of the OpenSync engine library are installed, the specific version to use for syncing can be selected during configuration, and is shown in the list.

The last sync date is also shown. This timestamp is maintained independently of the one maintained in OpenSync and is only for information purposes.

Multiple devices can be selected in order to sync them all at once. The Sync Now button begins the sync, and each sync will be performed in sequential order.

The Run App button will, if available, launch the application that the currently selected device is configured to sync against. For example, if you are syncing your BlackBerry to Evolution, Evolution will be launched.

The Configure... button opens the following dialog:

The Configure dialog displays settings for: the OpenSync engine's library version to use, the two sync components (the BlackBerry and the Application), sync options, and conflict resolution options.

If only one version of OpenSync is installed, the engine options will not be displayed.

Configure the Barry side of the sync by entering the device password, if needed. The rest is optional.

Configure the Application side by selecting the Application to sync against, and then pressing the Configure button. Depending on the Application, the Configure button will either automatically configure everything for you, or open a new dialog to adjust parameters for that specific plugin.

The available Applications / plugins are:

  • Evolution
  • KDEPIM (0.2x engine only)

Depending on the available objects on both the Barry side of the sync and the Application side, there will be one or more sync options to choose from: Contacts, Events, Notes (Memos), and To-dos (Tasks).

By default, Barry will ask you to resolve any conflicts, but it is possible to override this using the conflict resolution choices at the bottom of the dialog. If you select Favour Device, then device data will automatically overwrite the application data's record where there is a conflict.

Back on the main Sync screen, there is one more button to discuss: 1 Way Reset.

Due to the way OpenSync is designed, it is possible to get into a "slow sync" state if one of the plugins crashes or if there is a serious problem during the sync. Unfortunately, this is normally not easy to recover from.

The best way to recover is to re-create the entire OpenSync configuration for that particular device, delete all the data on one side of the sync, and sync fresh from the beginning again.

This recovery is what the 1 Way Reset button automates. It will guide you step by step through the process, and automatically reset the OpenSync configuration, so that the next time you press Sync Now, a fresh sync will start.

Normally either your device or the Application is authoritative most of the time. For example, you mostly add data to your device, and sync with your application, moving data from device to desktop. The authoritative side of the sync the side you want to keep, deleting the data on the other side.

If the Application is authoritative, 1 Way Reset will offer to delete the data from your device for you, in preparation for the fresh sync. Alternatively, if the device authoritative, 1 Way Reset will launch the application so you can remove old records manually.

Obviously, it is good to have backups first, both of your application data and of your BlackBerry, should something go wrong. The 1 Way Reset feature is designed to help you manage OpenSync, in case you do end up in "slow sync" land. barry-0.18.5/doc/www/design.php0000644001161500056700000000470012242254476015630 0ustar cdfreycdfrey

Barry is designed to be modular in many ways.

First the core protocols will be stored in a library so that it can be used in other applications.

Second, a command-line tool will be used to present the user with a scriptable option in dealing with the BlackBerry ™ device. This will come in handy in conjunction with hotplug.

Third, a GUI tool will be used to allow users to directly manage devices and make backups of their data.

Fourth, an OpenSync Plugin will provide general synchronization support for Contacts, Calendar, Tasks, and Memos; and the OpenSync framework will provide the synchronization support for the other side of the equation. (Evolution, Sunbird, etc.)

Flexible Synchronization Targets: The main goal of barry is to synchronize data. This is complicated by the fact that the data on a user's computer could be stored in many different formats. Email, contact, calendar entries, notes, and bookmarks are the main data that we are concerned with and users may be using one of many programs to manage their data. To address this barry needs to be flexible in how it supports synchronization. It should be easy to add new synchronization targets to barry and easy to select these targets from the user interface.

Open Data Formats: Backup of the BlackBerry ™ data should be stored and read in open data formats. LDIF for example is a suitable format for contacts, mbox format is a perfect format for email data, text files are a good format for notes, and HTML is a suitable format for bookmarks. The backup GUI stores its raw backup data in gzipped tar file format.

Multi-Device: A user may need to manage more than one device on a single user profile. Barry will be able to treat each device independantly to allow it to sync differently, backup/restore to different targets, etc. This will come in handy when users are upgrading to a new device, or when one user handles backup for more than one person.

Device Support: initially we will be supporting the 7750 devices, because that's what we are using. We do have a 6750 here as well, but since it is a discontinued product we are not testing on it. The 7750 has a USB interface to the PC and we expect that there will not be significant changes between devices.

barry-0.18.5/doc/www/index.php0000644001161500056700000001733012242254476015471 0ustar cdfreycdfrey

Linux users who also use a BlackBerry ™ now have an option for managing their BlackBerry directly from Linux.

Barry is an Open Source application that provides a Desktop GUI, synchronization, backup, restore and program management for BlackBerry ™ devices.

Barry is primarily developed on Linux, but is intended as a cross platform library and application set, targeting Linux, BSD, 32/64bit, and big/little endian systems.

The Barry project began in October 2005 and has steadily added features and polish to Blackberry usage on Linux ever since. We were the first to reverse engineer the battery charging handshake via USB.

Today, it is possible to (on BlackBerry devices older than the Z10):

  • charge your Blackberry's battery from your USB port
  • parse the following database records: Address Book, Browser Bookmarks, Calendar, Content Store, Folders, Handheld Agent (partial), Memos, Messages (Email), Phone Call Logs, PIN Messages, Saved Email, Service Book, SMS messages, Tasks, Time Zones
  • create the following database records: Address Book, Calendar, Content Store, Memos, Tasks
  • export Address Book contacts in text, LDAP LDIF format, or as MIME vCards
  • import data in MIME vCard, vEvent, vJournal, and vTodo formats
  • make full data backups and restores of your device using a GUI
  • synchronize contact, calendar, memo, and task items with Evolution using the Desktop GUI
  • use the Blackberry as a modem
  • install and manage Java applications from the command line
  • take screenshots of your device
  • set the device time from the command line
  • use raw channel support to communicate with BlackBerry applications
  • ... and more

Status

  • Latest release: 0.18.5, released on 2013/11/17
  • License: GPL v2 or later
  • Download official source and binary packages from Sourceforge
  • General Sourceforge project page
  • Barry git repo
  • Note that Barry is also available in various distros. Some of these distros are listed below:
    • Debian and Ubuntu - maintianed in the Barry repo itself by Chris Frey
    • Fedora - packaged by Nathanael Noblet (RPM git repo)
    • Mandriva's RPM SVN
  • Known Issues:
    • International characters in calendar and contact records cause some devices to switch to a different low-level protocol, which Barry does not yet support.

How do I...

  • (new!)

Some helpful pages:

If you are a C++ programmer, grab the source from and take a look at the TODO file. Post a message to the mailing list when you start working on any of the listed features, so you can connect with other developers, and avoid duplicating effort.

If you are a Python programmer, contact the mailing list, since we would like to create and test a Python interface to the Barry library.

If you are not a programmer, but have a Blackberry, we can always use help in testing. Install Barry on your system, and you find.

If you prefer writing documentation, grab the source from and look under the doc/www directory. Documentation is currently in html form, as well as doxygen-generated API documentation found in the comments of the source code itself. Patches updating either set of documentation are welcome.

There are dozens of databases that need to be documented and supported in the library. If you have a BlackBerry ™ device and are interested in helping decipher data, we have a that will help you.

If you are interested in the low level USB protocol, you can download, or contribute, USB logs to the .

If you are interested in helping out or just interested in how it works, check out our .

We have put together a document that describes where we are and where we want to take Barry. Check out our to see what's happening.

Barry users and others have contributed documentation and have put these howto's on the web. Below is a list of some of these pages. These sites are not associated with NetDirect, and some of the information may be out of date, but they may still be helpful to new users.

barry-0.18.5/doc/www/roadmap.php0000644001161500056700000000033112242254476015776 0ustar cdfreycdfrey

To view the latest roadmap, please see the TODO file in the source tree.

barry-0.18.5/doc/www/codingguide.php0000644001161500056700000000723512242254476016646 0ustar cdfreycdfrey

I use plain old vim for editing files. As such, tabs are standard 8 spaces wide. When aligning the code, indents are always tabs.

	if( something ) {
		// tab to indent
	}

Sometimes I need spaces to align function call parameters:

	void ClassName::Function(int lots,
				 int of,
				 int parameters,
				 int that_need_spaces_and_tabs,
				 int to_align_perfectly)
	{
		// tab again
	}

I even use tabs to align the beginning parts of comments:

	///
	/// \file	tab_to_filename.cc
	///		Tab to the doxygen description
	///

I also use tabs to align things like simple #define numbers:

	#define ASDF_NAME	0x01	// tab between name and number
	#define ASDF_BODY	0x02	// tab between number and comment

The main place where I don't use tabs is inside tables that have to be aligned, especially where there's not enough space to fit things in one line when using tabs. For example, in the record classes, those FieldLink<> tables might use tabs for the initial indent, but everything else is spaces, to keep things lined up, and compact:

	FieldLink TaskFieldLinks[] = {
	   { TSKFC_TITLE,      "Summary",     0, 0, &Task::Summary, 0, 0 },
	   { TSKFC_NOTES,      "Notes",       0, 0, &Task::Notes, 0, 0 },
	   { TSKFC_START_TIME, "Start Time",  0, 0, 0, 0, &Task::StartTime },
	   { TSKFC_DUE_TIME,   "Due Time",    0, 0, 0, 0, &Task::DueTime },
	   { TSKFC_ALARM_TIME, "Alarm Time",  0, 0, 0, 0, &Task::AlarmTime },
	   { TSKFC_CATEGORIES, "Categories",  0, 0, &Task::Categories, 0, 0 },
	   { TSKFC_END,        "End of List", 0, 0, 0, 0, 0 },
	};

As for coding style, I keep opening braces on the statement line:

	for( ... ) {
	}

	if( something ) {
	}
	else {
	}

Except for switches, because that's just wrong. :-)

	switch( something )
	{
	case 1:
		break;
	case 2:
		break;
	default:
		break;
	}

I put spaces inside the parentheses too.

For reeeeeally long lines, I sometimes favour keeping it all on one line and things wrap. This is flexible... whichever looks best. But also remember that grep is broken by wrapped lines, so if you're writing code that could conceivably be grepped later, decide whether breaking the line is worth it. I usually try to keep error message strings on one line, even if they are long, since it makes it easier to grep for them when bug reports come in.

        // example error message....
	dout("Error 1234: too many rules");

For pointer and reference variables, the pointer and reference symbol goes next to the variable, not the the type:

	Data* data;           // wrong

	Data *data;           // right
The reason for this becomes obvious when you consider what a multi-variable declaration looks like. The first style confuses things. The second flows naturally:
	Data* block1, block2;  // wrong, declares a pointer and an object

	Data *block1, *block2; // right, declares two pointers

I think that covers it. You may see some funky for() statements sometimes, due to size:

	for(	FieldLink<Task> *b = TaskFieldLinks;
		b->type != TSKFC_END;
		b++ )
	{
	}

As long as it is clear to read, I'm generally ok. You'll notice the fixation on tabs again in this example. I'm less fussy about that, if it's clear to read.

Sometimes spaces are used to align ostream output as well:

	os << "something"
	   << "something more"
	   << std::hex << some_number;

Chris Frey

barry-0.18.5/doc/www/install.php0000644001161500056700000000113712242254476016026 0ustar cdfreycdfrey

Starting with the 0.18.x version series, Barry and OpenSync binary packages are available via apt-get or yum.

Please check out the or the for more information.

Alternately, you can find the latest available versions, sources, and individual binary packages at the Sourceforge file list page. barry-0.18.5/doc/www/rawchannel.php0000644001161500056700000001172312242254476016504 0ustar cdfreycdfrey

The Blackberry provides the ability for programs to send and receive data over the USB port via named channels. On device there are two APIs which provide access to these channels:

Barry provides APIs and tools to access the PC side of these USB channels. The Barry APIs provide similar functionality to the Blackberry Desktop Manager API.

To use USB channels with Barry you will also need the following:

  • a working Barry install, version 0.17 or later
  • a program which uses USB channels installed on your Blackberry

As part of the examples provided with the Blackberry JDEs there is a demo application called 'USB Demo' which can be found in samples/com/rim/samples/device/usbdemo in the installation folder of the JDE. You should build this and install it on your Blackberry.

The Blackberry JDEs come with an example application for the Blackberry Desktop Manager API in samples/usbclient in the installation folder. The equivalent PC side usbclient can be found in the Barry source in examples/usbclient.cc

Once the example is compiled it should be used by first running the 'USB Demo' application on the Blackberry and selecting one of the 'Connect' options from the menu. Once the 'USB Demo' application is waiting then it's possible to run the usbclient example to communicate with the Blackberry application.

The raw channel API provided by Barry exposes the channel interface as sending and receiving of packets of data. While this closely reflects the USB channel protocol, it can be unhelpful for applications which are designed with streams as their communication mechanisms. To accommodate this Barry provides a tool called brawchannel. This tool redirects the named channel over STDIN and STDOUT, allowing easy communication with pre-existing tools.

For example the following shows an example of using brawchannel to talk to the 'USB Demo' application mentioned in the previous section.

First it's necessary to run 'USB Demo' on the Blackberry and select the 'Connect (low level)' menu option. With that running it's then possible to run brawchannel by supplying the channel name on the command line. For the 'USB Demo' application this channel name is JDE_USBClient.

user@machine:~$ brawchannel JDE_USBClient

If all goes well then you should see nothing but a flashing cursor. The 'USB Demo' application expects us to say hello, so type:

Hello from Barry.<RET>

You should then see two things, firstly your terminal should now look like the following:

user@machine:~$ brawchannel JDE_USBClient
Hello from Barry.
Hello from Device

Secondly the message you typed should appear on the device (along with the demo application complaining that it's not the expected text). Next we need to say goodbye to the device, so type:

Goodbye from Barry.<RET>

The device should then say goodbye back, followed by it closing the connection.

It's also possible to use other programs, such as socat to use the brawchannel tool to communicate with the USB channel via other mechanisms such as TCP/IP sockets.

For further information please see the man page for brawchannel.

It is also possible to use USB channels directly in your application by linking to the Barry library. To make use of these USB channels you will need to create an instance of the Barry::Mode::RawChannel class. The Barry source code demonstrates creation of a RawChannel in examples/usbclient.cc and tools/brawchannel.cc.

In it's most basic form this can be done with the following code:

Barry::Init();
Barry::Probe probe;
if( probe.GetCount() <= 0 ) {
    // No blackberry found
    return 1;
}

auto_ptr router;
router.reset(new SocketRoutingQueue());
router->SpinoffSimpleReadThread();

Barry::Controller con(probe.Get(0), *router);

Barry::Mode::RawChannel rawChannel(con);

rawChannel.Open("", CHANNEL_NAME);

With data then sent and received using rawChannel.Send() and rawChannel.Receive().

barry-0.18.5/doc/www/prepend.php0000644001161500056700000000020112242254476016004 0ustar cdfreycdfrey Barry Documentation barry-0.18.5/doc/www/bugs.php0000644001161500056700000000155412242254476015323 0ustar cdfreycdfrey

When reporting a bug, it is helpful to include as much information as you can about your system, and the circumstances surrounding the bug.

Information to include, if applicable:

  • The exact error message you get, if any, when you encounter the problem
  • Version of Barry
  • How you installed Barry
  • Any sample data that may help in reproducing the problem
  • Name and version of your operating system
  • Architecture of your system (32 bit? 64 bit? Intel? iMac?)

Once you have all this information, .

If you also have a patch that solves the problem, see the page on .

barry-0.18.5/doc/www/php_conf2.php0000644001161500056700000000047512242254476016242 0ustar cdfreycdfrey barry-0.18.5/doc/www/barry.inc0000644001161500056700000000306212242254476015460 0ustar cdfreycdfrey$title"; echo "
"; echo "
"; } } function createSubHeader($title) { global $doc_mode; if( !strcmp($doc_mode, "netdirect") ) { echo "

$title

"; } else { echo '
' . $title . '
'; } } function createLink($name, $desc) { global $extension; global $barry_page_path; echo '' . $desc . "\n"; } function createHref($name) { global $extension; global $barry_page_path; echo 'href="' . $barry_page_path . $name . $extension . '"'; } function createFileLink($name, $desc) { global $files_path; echo '' . $desc . "\n"; } function createPureFileLink($name) { global $doc_mode; global $files_path; if( !strcmp($doc_mode, "netdirect") ) { createFileLink($name, basename($name)); } else { echo '' . basename($name) . "\n"; } } function createImage($filename) { global $image_path; echo ''; } function createImageEx($filename, $img_html) { global $image_path; echo ''; } ?> barry-0.18.5/doc/www/label.png0000644001161500056700000004155312242254476015442 0ustar cdfreycdfreyPNG  IHDR,t?[sRGBbKGD pHYs+tIME 8\$tEXtCommentCreated with GIMPW IDATxwE?7O (*eU5V kXuŴ1 %9 Y nz;w2kyܾUuΩSU_XOzÆ^h!6lذq fڳg+w<4}Gf[v eÆ_M> NO7HũNN &ݺw:x^}6cٰaAQI7e:Ϻ5@r4iΰgӬ~: r4ȧ|`ז4wZ3W$y~!q;:BM1 iv+8&" Ĵ`Ŋ5{G",dʇsYG!n B"+Q=XG$&RӛL N#Iq|M##p84`JI4꘦yPSUENa`x\n=avOu6×Sxy'*("H"t:PCcsyb?رc#Mwǥҗo4pQUQ@L'Dz84AJU;)[`ؘ+`U'*(J~56StCf 8A kFMSVl#Ejb@sɞƒ-ҹEC@[ ׍CSIOH24o܈NO!+d ږSHMtB# "X P-=bΛaM*BE4}50tNOf> Эe=vgk~q#4L"(A8AQU.N0ÖSr*hl`p[7gesvI.u+o}nq pP8n7((,$ 1 [+;Y(`ݰLgߙ7/7vfgηyd|?~{41M"4(FXC kҐNFj2#G-Tҗ4LL)V:r8)({:f<1`Moq~# imٱ߮`]ַ;]۷ _/ȼoWQ/٩8k6,1=HMKMƌ9Bp0oY|=&o9МlroGX~0b`/tjb 6N>2ƜSyܺ1[7f-oy M$bbH˟T q_a <Etz0 r*!AǁRtD ikX'sYKK=>_6M7sewqpνLxv8DѮ5ι|qv+~*>Bi`4ޝߞp1=8hմMy8 &FY.޽cC'}Fp3!4w :f-ڳ@nܓ4qUc?:N2O_/}N=p:DPU&&%6)@,!jMI8j` EX&bjU|e:U۟#y?pM47dy+," u! t, nD wphr$Nè~NQOUW;-4y@f=B^.<̌L5:'Ƿֱ>_GYRP\%û3e(fI Gu4!&*) 4kَN؄bɧn܃jCO$j jD nP9:D̿ MP j*RHBRT"$D#Q[:Ej ":pTstXx*#Qdlr8lٺ ^ݡQ2YY;_]LTҼVV ӹ9X..v BZʳy}#NUًѧwW H%TRiJ"$<!h ASR~yKq))ӯ%Yn"QKraHQҲ.(EBJKMr 1Ba '1B(4ڼy۹"?#5'k7qN$9"71QUAt/]v FWu3F2sĩ ,ea`ISEE LׅDQ4z5Mڮӓ$4%AFSLg秷p}3s&JwEN&U*֌QaYQ &Ĝ]NURV^F0QUUe\jҳ3ٶe#nń&V ү+W<4/7'7em֮1z;lFN<|o#+ ϣHq Nց/m3ڝgQXࢁmYz/~#o-bakd_a9drU=ٶ17ath#o/]-B4ކt_lǥ <h4om\0M .@JKJKO#[K3ַ>"4!MP<41nqYC˷L@()EvyF{ӺCwpj4qA9ص وd'# ܏Ғb RHY z5Yy4iC^^[ѽe6NMbk K8]/ceC 1S&M$rg9/tbmDaS& RĊ]:ɴH.9f5OT?Zᾩ9.AqOBDu.q3u 4~zh4EuоuseU_|<;RF͘YBӊ25KrNv BuUw{L0F8۳5'gР~ ).\S-k JȩɾBsQ^_:OGÜSI(kۜvۏh@Fz22Rp9U K ^w`8BIIr9(*=rzܓWމM/&wn>Y>:mlٯ]E1IJ߳-@ӎ:9MB ¦΁P\ˆ3{:!ɩF=b蒊HE1JιWrqV8V߀]4-*ڍشaM5K BEjb)1+ (Fl5(uݰTzEQP+&ZSս,_jXji5'-tݤa`t5#[aBQ._Ʃ8 ISZ1c$^]}@.1tMUީ9=4M(a:yv6 h߅լQ:Qڬrݠ')TEwo>9 NeЁ,(e-Nmс>F|%YK<.͖ .lH$it:  P7d˿y\p۔ -a6l`֒U(&@VnH-FkUÔFڰaoMQ,۰`!N˖ 6N*xTŞaU3 `؀*p D7L;(ކ Dž_wNXץ4 B}IN{Fچ ǁ_U4\>7n౏(( ҳE/܇d¶eÆVT\>S?_i[XExJr_tF%h)nsjÆߊ<.O?>Ģg/)/q=iۼCn476lذ1 Eb<4y1%_le?2wmS֓'V=i;$fNyj*^׃YfRRUϒnU!5%XF#!+~~7$ Xg=ǁ}6崦B0ȉ9XQ>olO)J4 <]rJr|WಲzFrrr|U]yy9֒`0]E}>!5 >-s_fg1ݚgReH{кIC.yUCKqQ1< nfϿqB19\\rh1馬c=]gZZ:;&0 8_6*n ayedfEFf'v}/c2}6+Vr { wމIHp|hq/u8]\w 8Jyfdf캸^zB.+f9x )i=Tdg[{0; RJq ˋKx4oڈQ>EZ;j"77 8I$-=-^n?[neeVG?>c.7۷q=wP\У,'FQj咄C!@wX|B"ICmHS$L0q_b)%eC :˙$% Ym  0֫'ê_('^F=! :.ՇG#q9V"jD"Li㚅4M\J*W_}\RSRkY#ô-ucF#aBt:Qzai8^mi"ud3,ǃxD"\|TLC @vl >/^wyK/$!\aGa 5n,{}qi72wuuRl2 INNKbe͚E߳vzV\כDjj:RJV\굫QUT<^7l"࣏>ş9Xa˗-a׮bG4 kt6oeKؾ};s:9%/m۶vM.v$))ꃅٸq3g)"U#IID|GR߷GP^FrmiI)eVF GB ܾmk\X5:RYpO>| :Mhp9}ڴuXiBRԴx}+W\SQs-/>Iة vƒPqRʙ_|[Vfz/%?H)\ry</g:+$VgNxT} dEyYK jλ&~}{'}G2uk@J)ד2U=h,7/>ēr#UoRٳRJyɜ=wS畗]rQB"૿G&Ȗ-Z&\ߵs4];NΞ5ƽ+-Ouk*9ϤRzxcm_=?PH8TC1Yfn½3g|n |GN)O3VXJ.(5RJ)I?[[^[!zyUd$';{<@{{y#UO/>ow~ ,2Z&aUg+^)r5FGh8$7mp}kV)C_7#G#2ைkG{^Fǟx<.qչRTP9";֪ˤR֭W/Lnk~ZY^VrgEci]OO=T<̌ ۅ WjE4Ahe? 6mZ˷)!^#٣Nqkѣa)^v[k~p(:wUB}{R?aU@IJٳWby7~R^|'*._O߲yx>VoՖ՗}Q}pa$C# yƩ*H$΍#Z0s}Zo~g a@i699\z\Џݧ 'ƛ1Gy8gg@z֠~}ܱvfϙ>At?[6%jx~F`JϫDDǗtZ'N:v" ӄÑsdu]G|fSUD#< W")l^gv>3ᅴXa?Zm͂E KJJHHHUo3yXD/k{rl`ы/@ka{zu?/^>|5}W k 8s;jXZއ}X_oP0/s4j:I)}mګIZٳGxwTSw=o<_Qit{:wUv{]*nl/ϯvNtq(y+R=o*;AV4pAt7 8t_EϳBPX\G[EZؿ?ݩ"gthz1:#:lgK^!}}4i/=Oѫ7u9 !o# &N6{&~{a=ѳ'7\}M7Dѭi(BaǶܵ'۫o 2#Q:cI.];S r, IDAT4}+כ8U.!v+juNv:9 rhܸ!:PQUn]OcA$\}2 grw?]Pk_r::d(͚7'`3:|ws/6Z׎!z}[%[v-[7oe-|4:v@Mp8 8c?]HRrw?:֠`av<=y`-7$vi]a:lLƦMf邅 v| /&0x`**lּF>ƏCAiܤ)S~j6\pAA.O̘1Mܵk1xC wTTGrpj 73mm/Pxivsr岎6iD -_Se{):Ħݥ${XFi0WFh̷G+txk< oyy@ CIyݫ=UUi .MЎZ Y)M</?f-c㶿 CiI1Ç  z G98nNFF&W^q.Z0it֍4rrЭ[wa ?M-xŗԱ:ux4o֔x>l(n;O3b(7oNrJ?0PW曬xL\MEL4FFFFry^R4hRdשǥ\dАzC0菇x<.F>-[S?]E] @V,zu?oR;:YБ;1n : mp4kނ`0pp<>"'1{q%x.#ˆ1q?c7":50MN?1D!1 8pS' p-K &F"d?i5<9y)?`y`ĨbWNCA ݈O{bqppa>b`VC( 5'=N5BfdfѸɩ:i*Ρ h_2t]?Տ-$2??:yL}OhFRJ2e膎4˗6 ,\G&;Ņ۩'$ $CH RKMHX렟ZxJ\+RbP7ŁC~F3|; wз_d~8YN4%YΐPcXr$S[e0G9שLC0LaPp(Wu+u.FJIT7ҌLS A4*_$-{w `o= j=o՘m, +ȗ k-3yOy(ӦK2,K Ѫju❄uyd8 DI0 iM0Y; !srr`! y<3SL@0$iRP$l#b6n˼gǀnpކ !8=nꌙipm) Dj7vD0 CFtˉ3sn$4뒂?zT2bvϧUv$a(a!1MɨxK@`?(Y,nJ3"QITJ!1Ĉp<.[;2 JulÒ + ߂ǮDKOta_q@%HaQ{AJB(=~|oX;9EVǷ 6l 5mQZ^&[˽vFJ{Pf̃8Xt&+A8bP¥*Vl/Ӥ&+6lBBPyxkR:΁˺PXb~~Z椒uqҤS S'i2TZͻ设PaE qLy(p944M>І$D":]5gC7uP1Q^ط<^bm:@ !!]r؏ Ըe_8A~QMp8ۖBljG؟_Y6lʐh.L\^aEX4c磙?j.saS(ŋx᯽|r72xI~qS,z5YoyO/IYD(UV z<!p|0cvE-v۰;DȀQ7ȼtjC g#D(oB AEƍhRix3ذ;|;Ò;eT˗SZ UR7.[1w?5AM8!CUQT2)2RE,iN6lV59V%iI)ږX3zavuqÚQRWFRj& 22> 8."F~?wJsՆ ;GKi-^V' ax}>.ڲb?wmfAy1V/HӴ[dž '*6IqRRJ)p9tl 4 TvSVbA6lu3 @Ш1=iÆ   6l²aÆ lذa 6l؄eÆ 6aٰa&9b%%%-l G G9.:,6l5)E,FiIIE#F[݆!0u2TÒѹܞ Ӿ)qaNn-Wo DÒ:m4bٔkܹ~7۽YS8gKr-^BW|X&e=+ %Ņ&V%EGuƒE_ 6~;$l~8 K(blذ)Y 82a h4͖ 6~Nb$!T x6lvZkUE˖mذAJI XՏBXH(%⣞hÆ E~alkW6l8)a{mp( 85ShJQa@DD IԐj*M⏨$H6a kW)1!fA %1Bn_C]D"?I\6a8qC`s6QV$䠪 .vq%C.]W;j77CHx%8NԯYGӧ8"MX6{*d|ziXycƍJCIcYgrrZ )FޱbM2^6 "Uw뷂.MHQblpR"0~E_l#AT"p4C_j\XL+(4k_/%Zf P@SIJ+")el *F5]O+HRޙ!%!D7!!L>OhJځs˥Wl.GPhmfG)t,_ ׂMX6~[v◓o -sN4QFiU'0Kط99[4:(;i%ƊvB餫|s5f#>y:@_$kx؄e1 qzܯZR(b6'PlqK.ҩE=0UUU1M3:G+[ҧ& 4W#P\^&E;p9`Ȩ̚>kK.B/v_u<Z]"QWEQ0cg,{ƯS*S|EM|ӿ)2S맓#55'`}$d~lF3g&|_| )OQ.#%F.CдY Q AGEME`nZK~-Ytńe#$DYi&sBx,2|Gu<6a8iUIΘ!^;x쭹3k%|Xȓo4tlH 5lؐ ЪU+֭_Yg{„ tޝsvfTe3s6oJH:Y%z!gmvN!Lk䛓CzhӦ 5kpݿt 4y+_r[?prj:z|*,?+"/Q ]l܍) p&uly_ 1chݺu vΝB@z-z:t{'>yG?c+0kjMjy ò+qu獉B:N@f4lVyթ InKV@SL7ˆh۴AXx嗙8q"g}6 .dѢETTT_7g u`*YP6 ̢$?A>%s(8 2I)SIC>a{BӧO!7+瞣nݺH)Yp!SL!77!:ubСߟlF~gĉYp!^x!H3h z+lZl9Nwnzޙל͒u{Hs&i#x4M8UfY&D0486(mڴe˖-Æ cӦM 3lQ /s}yy8#BD>6Ǡq;CtuE?ĊتaDݎx[!nFn&\.7~;:u3n:Oii);vop0d1(Zk1؄eUL;| ~L7 rjvd&c~Rn$'xN'73n m߾M(ZtΈ_@ZZ*ӦMEQ4***@` k3'$q~T}Gԕ}-Y$mCX^`$pˍ:q30ΎXCTA(t(  ؄eհz~2\?ysS17MO=2.՘ 'YTƗ+P65k/Ν;xgX~]}mƌ9ӧq+~(vT%=\FaQVBHZmXMG˿gϙȼ2ҟ}[*UWo*hv y?ݞ32m'@.ѫFlhvx"zäIٙ`(wLy=? $ ,] 7n<ƍQ '|߲%/#joopo~#imu,3;zVOP/s>XkvQq)<MY'@y` /K{ORrcƜOEy*pc1 0IN}7D/i^`q9ҀpPA(M%ǃ=>XHC s GiځP!1D5P!LMdKa&ą ,H`a1ڤQ W-ӹw=TK@˴mf337˹M|-Ǐ(gh R9aa<YR Cn nkҗp<#  A\|> ]twuOy(ïg2T*QR`IDAT<ͭt,.d{;A73qle\&TeNz:Ǐ=q?njܾTꞭu~b^t|cp.bdtBN羉 5Uewf 9 \Tr+XGPbE%˙s}|bb ףBm 4R;7w barry-0.18.5/doc/www/clean.sh0000755001161500056700000000013212242254476015262 0ustar cdfreycdfrey#!/bin/sh for f in `cat content_list` ; do rm -f $f.html done rm -rf www.netdirect.ca barry-0.18.5/doc/www/desktop-sync.png0000644001161500056700000036015612242254476017011 0ustar cdfreycdfreyPNG  IHDRXsRGB pHYs+tIME2I@N IDATx}wTZSNU&*  DPD5xcIbɍQcoET,Ċh@P9}f^{kAw93{vy՞g= ]$$~qz$Húo@vw#οRry& ?An ُr032?o%'BB,H%"RHg(4hwxSŨުٻQ[+5YYT3}ƅ\vV% Pyy+ NȽW{B@mmwYW2^2,8qQ bI.Br-k$#@f$wO |m ͈ڑv#"D#歡| (FVu-Dz XbȪ^jdCfCĝ>B*nQ"R,b)AȽt# 经^eḆ\E ۍ[ZG~D$5"Ĺ}r=g8 "l)NB6ޠnO4rv 9^M"f_Hs' Qc^C6jɰj]!TN-<|^:*/mq@$"A7BOM*='f0(CAQ+qfůA8x/2m ;(7G"ݘyw~i.xYrDi3VY&`N [&@AoVu^18ψ%T__@7qMl 8,߂9ߧ>bF`E " #@aKȏɂ=?_f! XU2Y}"HxLK ;fmQBF 0Mh`ƤƄO 0Xe{p/D(US)Ҫhi0a/vș5 Z\3-*dEh^q tf_L(!S";!^.€C75 a$Q@*$([@xҘdbJq~R-] ,.hV{PSх|)"@VsgY2dFzGn9#}eIܞW[ʜ߫]K)Mߔor ̌$eqd`B)(?D?!ԂPT3q=u(tmAoA5j vQ!iFʙ M+dʊވe CA3Ep fO4BaT|7H@xh:,%N38|YTYG(9vt iI܈XK Y(QIܝF`0w) Ĩxe|N#Cn>#fJ @9Q]&6shrKKŊ֋;f}]Ůx_ZlnFc{y_L8e%y9:@2HԽaȌe[Xq-VQP:h枙 ˡ< pf|N M䕿SČ7< /fllйL SaufZN\Ac^ΙHWJLx%c邆3-na*-3 M8B2NQ0U 4>_tc,ŽP4KZȤ>K:GH 9EMjo tUDs*Fzxr1B.۷\|T{!+Đ+_v+-S"rut"1hiDN,^*=#$-u3C7n!'R>PX0r:ڍ Bk+ER}OX(EufT6t5!T|3 ܀(Q yO$qSU,U$"clPK[h.Π 4죴a!Dp -"X2 [Cr0BmLj,E|Qպr$`'Pѱ-[-LUɭOEMV;n:%`B /]E/U: oA TԌ4*@E? SoA uHRZ Nd74hVH ^+ld[!c:+$HDRLVc!` ~%BWR n$.d<&x+TI˶|Ɇ#,P -;:bOFL.HwbS[!j(&NV6';~uj&_FRFuq䎏j!0/[F3Czፔ8RMYXx.Yo&/=X}nM:z49!9C P!sf$SBkH L eS`GP/gr7BQB P30P+eQf "9 M Q!%@_Å (j22Ή&,mzQixu<ҵQf``C_*IsѨs۾ɥ񸁅NqK%k˅:fXgz8lp30-hyMyyy,Jw9fa)l֫iz0hq*dMPA FL lva"lL/0+%8Tq% )=Pmz! $"hf^H>P$&"+ńb ahDC35nTdZ,qF$IuP.'_Rk&Fն]ED(j؉¹Kē@#\lLTQc[k}:L|abkD v`l%뼜 bݿL:g_}hԔED5Q`P5t"5fᗂ4uG QPz?Ś*]6}郲MϡEW;&BB&87kei*QvkޣUk12U 㑗;O4EH!l2x&yu4Uw lV PQ7:o ^ސ5(N:*-Z`<otTz/ix :,& f])kD΍G)XGԤ \I'ϸgKBOGs֍/@>OZֽD ŔDs[l(b|5du&+;㽕%ɎgC <Fd$4c=ep[ʁ:gmRO2T^g^WE0У}ԠQn~Ǣ5"FCg$G%>-_ (ٲ;@eYjP)j|X1j, h~xlE[ФYWÇX#BDBAB*L($V ٌ!,dV)P**hROJ vPs]Ҷe(7iNtrBTGpq:D5ܦ]d+zu^ټ'{֤mMNb۩}vI%RY1jy}|G͉ ShlE>q0CޔIRK0-PE/d&VԈU+"L`H5!.0;^UY! רm,~}XdЫ2T1.dPI U =8ȜxKe6K5Kk>N Ev$ ?J6bfieTŎT;H o"Ct36],/Ay3 @4>ejHPP8Dw!F߬&S{nq B ɍAǞ/9[)Y6il)8ookCe/lh)SXeTѣ,ׄdZG^Т@'eAʠ& B<1E#BJBNTUvf,!_ϚU4vd_tZ:VK?:z~ 욦ߥ-FO=\KWܔQ Sqg5:wy'ԞzS_LkzOY7rudiG7L9t_kOSo51CXwؚn;ro}Ǧ] K ;yhSd{͹wng 5m9jd4DHLQ| EOHAjyn*嚣z5K'Qv¬[Bq]&`ʹ s0DZzSE\u9kǖZ/BM.P1NӴWJ(b2iSع|/hn4cH,j lĢyۢ6Q3vdʡ,JstPVv!fcM/{1i&7)sԔ&QwԲʹ5NeL?.+wٵ,y9ݪjSF ΋3 9b@[ґt[(c(Z-viq_KGZc(/&N%%5LP0lE9QT6U8DY&\EEyuYԗIM Y4q-KR}Ӗ_cgH$zrK,Md%RQI%= {GK y ̋f'6cS`PAhWV: { %|"dzˀax@ }^@t-(Jʨ݀ahbfxO w&<}HaO]rb6?6^AHZʒjkrc>LY:o U }uw䠦qOx4._St=ZI d!}[T@GȻ_>r@U]lšhʤCmެ~'068,2Ph,  &ad2Fگ-dR}oOE$lAa{tvcu0jǁY,sRgz+e)#aXwJ>ݴHHER$yKi\1B 3!9l|bh|ۉeuM'hFr~}UqD^ZwgZBs ѦY!N9ԴVC0?͌l.k0 v!89Pu' Pa @ĴqTrj8S#$ k qCv"=+5tܾ3FჶMÄ=:%'?wkײT^ކr̽+>+:_n)q͏Vr2,|Urc]O:snӒk如飱]s|`erwm5zE4]$!`M3X<2r7ji~dQ(POe j]( -]0LFm?MgP [҂B&CG$qHd VkdH! h(Fb<ۜNy" \6Ln ."vQx怔حUNjhӴe+Vb6BJ5b$R90;`Dh74Rbcot]fS, h  ؖ7q^zPl:4Ƣ HUSZH q-PoGZLc+htNJN푍;sZRqzL|.O5ͻuAM~Rv3=f>˘6﬉gW ?)3H=ycEOH)G68 t悝5qbQhFrP$RAKҙO4%-ƚMxbPObOO(8n%ҁQjOj!ݝ&O, ){ Ip IDATaNBEY8ڊ)Im Cf' z؄ \jq(`P^5u!MpkKm]DɭԔ$ڿ7 qQjH훞k]۽S=&?i߱kόM}ȼmX:$&UDSEIXMTinXLhw aj-$e1iBr~\T ZTpvk-?;+vВ/7^M|f`ҲBA蛢]5qmiӯnWf-:~`?pWMN w+OBHDo>Ո65iVY  wqO(B7*27H}Fb eaߧ: n3bI"07!I춒rڐlD6A3Ù<e.tJ/1Ar$aV5!Yq-eNiΡ+S{$6'EWVm_Yv+ISb(*X%>L;awbhfWhؓ&+c݀NpC#pu"Dz^݉>#3VLC49Xǎ$Bd:[JtmGE*ia" Aϊ؈Y_,?wON4M@'9;*ӭ{Eos_Y \?9ZyVk/d#oiԈH08+pBfmqm6q"n7[CB0 g,)iH|rrLj'vJ)xJL1Jl{%~&^*hqTQ]~6j(gߋ"d(89U޷"UĒ{7Ú=mڢ߻sI34a{嚭 (=>-MZ cŮlثmMV`O}l'߬*^{_4iꨦv#/뻯%a{4.m Zh@vӭP%̀]ZKn?)lv9C`. E?$N1r!6ôC7T5QWr$^r;ITQEypǗo z2 7J/J[I7&~PfB>.?Զ~Ѳ2/O:eq?[ǎ.=pW}tNYcRIt@j|͎d]-Z1BH$QG>)wݼ+׌إ6t7L:)ygFĂnYeyF,<^{@U(A/9h{?IP)gk<ABjsEi6A9&}l;1Jc,9QLRG0C@,s$UXt}#QB>`4N_`E;'L؃u}cZH%)ݘ~ׂ0jEy RNA$#YȲTH5+D9KsTg9r1*ĜOQѓyFƆD5<זTu1z`EQ$FRdE{>x(η>U/|+BR&s>ڷwSE2nx\VPY((Hr |Re1tDٌe*!`dw`.0g2lk8&'(^D^_1!H6^$;LGM-o`]$n1A{b6oBzGO#@wٳnoi Ԯym|jq9"/ox#hYy[iȡţJ-rHe&@Шlf6ɎeFJAtO`4 b6SFu)3q)E߄fdFV!MVBM*hc'wϵT" wc9ݣ}X?*qah8C jѿˈx-LaR7iJ9idH^5[yr-RX\+_IcWC%Mt ҀM&,:zNQ`/Pcut|r4L^_$2OD}k[˾vK #3=juq@7Ùy]lT8~RDݧb&B/h+ "Z  ' Qvm WЛ IK'XOQ<ȰH.J.BvtCJ<+^8Ug<mw[^֩1-X^s{l[3T~Ct9,: u$-,!†Tp7Q&o f;YA cC$R_X^la^QAb0ũېV&dd~`f*tH$[LͰųwZsݏRY[U5-K-+ؼ}+"!H9bLwިf.YdCϊ(vD G/‹VHϓG"ՑPۡ9ޫN$wѨh:'" D̮##ÂHQ0 *jg2Ж`' V @ZSuHτǠzyu (Fk2 IϜB #$9_IuS}FG^_(d6XEJl`=D05 z#G)$Սz*)Ǵev?J7_(bcc=B} r_V Bmy<ĬX$h;?Q p<%bq|j]@ܒrYٍCu&yDgoú;@JRez zK.=Zs#i 6( $1p _͒j,U= vrCL[ w~o(;/kH8/xP&:hIs_O:00W>2!!ۂ@DҖ)iEDB*a|~;2:wqtx9Ԙee[EfNE@F1}!G@P69E7\iCNZwIUJA'I@v$$DijRNHb2B4);B6ژ^}X?\@Oڌ=S*C>< !ԦSd%~VDGV;g MpC8ß BʪavcA,&=8ZwCQ3 3"jJFrN7D qtŇw 2 j`$hPK-}G5D$hS.Q x ʹF!` ys*uZG"Gł|XPiAb⦻ꎮL+Dyl$E/DȮ$ԔLTPƬ/%E A o4E6ϊc[O )<]CYjdIqj! mGOLoD*ՅSH;j6!טѠ)Xɴ)[wL>BD@Tu Q}QMڊt{}y>3ZI8?EФtw` OX/L| ޅ:0d5`{N_)˸2?q*" Kgyf@l5OŠc<4`YFEw=۲g 2r[Nn*7oAJeZ\2Ugx0|aP&۽[ >|cptץ|?=тH6' pu"J)W6Anmhl &;t9٠c$T 7PBb26c)4*@^"y'Dҍ`V%ˬ#Āȑ(9n;^T2`)e:10d`^t-O4,6$I*1zm&.&#\%o?AKOI6zQ*ՀЛ@zX. WDC.)z( QA(h\2ZeIFa.VxZ֖"nIťY!MTIΙ1h( hH&D)@@J0C2z*Mުg}On=6"yDBdfvdoh쇐N.#  r̅@V [NAqlgx}Vj^ϣ@RE|Fȼ`ʹ,^q"#3 !Q2e@]n@*; TMjSPRhנB)J)o~g_zŭ=SPA0P(VaR~ >ϰ(LsHC1/M@"&%)@1Åq$Ds.E$$#e"YPUVT)Zd҃L$̲0Nŀ,~(v[[TIBcfQ b\⴦fu!;@!"jIIZꏴ& > lvODK+1}6 HO)!"lU4.`c0 5[6ϠJ ք2D&B)O1hBI(fG QfN6ۼ-XJyHGB{0JȖ]kLd{;.Xf .[ƥ'Zf89>!#ar!kRGP$%WD#l}6=TTqTkvѓ  ui&* [`('dTcz<3A0Q#ui(\rC4 Hbҍ,x tr_vԪ>L,m~t2NN?F”%R-!ɩȃ:bY)O{JY(p?#9#'c^J!*kD$JlM)Sx?`aP<3! j-LQbȂV i(QY1uT-GX~|8)?Ԟ? ϒQyXeI2jgblIi3Q۬RM"K@irAbCc$2ǝ}PinfϘ9 W (\`@Kq~(v.?S G-rp FI (ƢhtG 0^D|Md.} 4#BbgTC$ۈxK4cmjWELIb ޤecбfhEJ0@}d̦L':S^RH!h%GU2asñuTiiM%'>֞KUx50Rqc?f{!? Y}(mTVobRF/PxK2u+ȹ4i/&_CWޠ(b^Df NcT!ҵjQAp-[GZnBu3<Ӿ o}(+* s3dKK ‡rM䜢 N[ ݤtBn/f1eDQioB| A$(P O …ȾJ$(*u^fg8y3R1;!5U({E eI>wS-zB΄`E0Qh(Dpư 9]}h P]VL#6lZn_k0ʧ_)%? HdԗE 䂛Pgdh:N%Aqޜ :H.94@&-E #_z'LFv 8d6+81eP_E#6b02*]A,0f<ڣM Mo# 2Y bIk%.~,4%!2G2UU* o7zBΨ".|y\ +j \Yэ/1$Ba t!fDcjZ;-6Tsà/ǠMk9[)7*!]!~3#2!b(66eȜ4dTJf,ETHF`,b X$p{>P:`BJTUn!7$m+>GDҽ_ Ō!vKjbN@U*K`*8Q[L+#똤iHj8E'֑QEcW"k.@TJh/$@0ـE^λpM@&1igNȰPǃd0G<VT#U2D nMhr?Zbto~DR4!#@AőғDɘaL cR'K#1̔X|2/`卂oih*瀡5k@.Ц3}ȒIROU/&"xF"461>C) =2A[LnR)IMJvk@Il BH,z˦nxxJSZ(xL+V3TdMBlo~[~Pze\ϝ7PeB60iM%AX!Ii arȤ'쥤mvI^D%ic] H$2w=:"jlMlYMU)8 $(@dSXvzUEʨ Z mP)U8P#XMƎk 2w!:쾳n@4 m9Bs$pUܯ&- H S =I>ˀ؀g2:+T)U`R/s ,gs 7-CKbOVbnakVz=УWPG0$&.>I+D4#Bds!vJfH"p3N"  or&6`*@:ʘ5-vi^ˈ+,##'oO{.ikn?#HQQq>:OփלA\Z,+kI}nt2[&a) AmUn}xJ#fU_9? C06 B<. ?[u^3L򫃠w!m*  IDAT1לK\^R@HPKlX4l`^ RU1x6:\穐`p;L-+I? qn;]!mBfZ?˂"/wP @^遜iQ3r5й@E8D ϳ@֊F(+1m?)(ʶtNbBs O0|6 ʠ\x )B*+ meQ$9=}{n^v헟<)ol^k82?gAkU*lE2Vbq`NᏦ./emR"d`0",4@(=Zp0j0~OJ2to:3Ӌ$Ɵ†g0MHo$$g^]'ZZnZH+5#C3y# ` \k" , R$RmIhMRkRԞD,ll"]/FOڍll,, )jOQkZԒ$݆MM(HLc%CXfE@~TJ58DNC2nLnHr6` !Sy*D43<¬ƊP Ar €^m1'8“Fgеk޻L{$#F2֖7^|/7_~USk׫J}JِT isd%uՓ:wѫ!| A$krfvR_L}9)i.aӍ3PEeF(WG)#օeC҂v ZВ$Y(el,(*E>ZGE0K E M-<_7_~)Յ/<|禯WٶEֱC R0n(g=ɂ"5Kdxȡ dHiB@ yFԻuVeyÀ' _TDK4@d0V S s[ N? L 1v{"tۏe*[]z9Qw3`$SB)g(XjBUL0P F+EQ`D15`[aDzo?G'GR D BtedD>UN FVQL2o0`:JFCW﬑cQ4J-lFD>JFd錒]>T98Gy{:wK+ZnXtќnG ("zV-9Ag`pT~aKubn/& 6w&zfd]U^*!<,SҍNj-!!}>GC$ M JZ ](ouBD۶ssaiq!٤*:F(PviߐG%=G:7۶w_rD[!G8yyFmf}|I!#Θ>37/l+ge<}ڱ}IpՓp&}՟7_nңċv` ~w/9b g+T2׬XܸUh[;޵1bE3mW_;nknm3ŅDdYyO?m:iƝ 6oϟo'[=bĤm7^z68c"+|:/8lOTYl91|9K%e'OvqcN<#}Ãl 못u%v?2}ˏi/=a;6?9ExٱK_~ﮭ3~{x1 w~>۲P`kk.C}>6tƵXWK%[`5}]K`b9QDF>#<:>>NS VYeDbZa]nĒ[#󯼱lˏt |ǹÇ/~ωr5_zI^UR)'7wI;lVgq Q'KϺ`FQqiQqRT$ihmnh(k`CsrW} ٵ᫕#Np}EWWp;nvߝ8Nygw)DIK"i_~_{ x~N;NcNڶy"kV,wҢS^.WkK K JǞ;c튥q8U}w?sX<t6A,XPҩr3Ko,T䅇~w{hkieXwזo6Ls'O"ŽqĪmS)"wyU:;0x+rkW,;ťťc^eg6!?{?mCNt)j5Wڸ -':4[MThRJ&1F2GAP3 U8iI؎JFR$C"zq!@)1yc'_4vET{LJK^y?@CmT NXW׀`8Qy>ni^|'rutZɵmg/4< #,hj-u:}k.=zGZZRQonS}m.(naCm_nZ97.|7,|!/`rpj#FXI}cC|{1ω@SC].ݝ^ѥkS}ȑxf*@/~S/{8|̸ם{ɵe7_zf͉6EEMw _IDPשs7tk)]};y ϺÆ 'L]" ޳sŻ=sԥ =d訏?)c+H_`,'׶`M ]mofj1gM :~zƺn?:wmi^Hv/79~ܮ֏ Tz/9/UIYٳ$1QHq#*/7mD;T#94%Du)xAx ) Lԥ5\\1E߽4ʳ4b:$Ͽ_9dqYe75tٲ!iQQiſBi2**)!E3*z@Qi7qE%:uUއ/Oe7>?xy]_TZ^sמʯ% zmݜ~v3j弧ާ#lۼ>P Î8fɂo{nuS/sEE%e*tĚ=UE% &x. 47LN]WXzQ,|aVTvYiy |Tnn^w3/0Y$=G!0I'jv?s֯^9n:o-gnf%?F-W*nS=gܔ4,7/릋&HRAUWWv}U,P_]U^ k uVTZ~..,"n<力kV.w< HkW1ox*Xz+xSc}SCB}zU0?={vn-lrxӜˏGC Z0ؓ_{Ѻښ%/=ZB&x<U]`EIGS-M͍ E;/?'=Zv呣O{s{w۶wօOէٷ{ڶמjmI5sz˺/4֑m7[\㱧; =h455F4xsݾ>і֔LR_wzT*8t%/=}aGzg-M-M }F9sw?5h 0p ohCyϵ̓YU4 ڄL_*2sy Wt$GLM#3T[ਕR%AIo`.2P_˫Y_☱֮Eb{DtY~o\I| |&6rhǝ:M5]{7~s3?ݩkϳ.2>f۷Sמg:,DpXhɜ>ȉʳȑHǜ(UcN?o+<S:$Q†(R<Qvy^U!Q2 JRJ@* "6*ЛJe(#"J!=@9{}^r3}sͽNgmv줺i{դ!P幆M:6xZ~Vc@xVo7/ydEސd*5(Qڳ+ec!o^ڰɡ) VLdH,'Uo(U(@*{ƂzӣG'xb߾}*U:p)S7oFD7oްa- Y2ɇ|&Xcz'6m 3\@a(@dNi埅)'|"*#L|+ftVYeC(*N+"t`k_|ex;1mLs>xm:KJ,רD4Q645,ۉ`Pj3k_)&#aܕaM`+~QuX'\ԷmHm/L8nnCq;p$qmDIkׁmY0Z+n|[[.[K"=8+PJ;V?ٓ,D[XLQM%CUL ՟C"hAfrDRn0 _k8444===,,Lz_2dHn?\ҨQgϖ-[vܹ|ɍ7V[v IDAThѢ5j@IIɸqVZvǏ?rH 2226lyʕ+@aa믿qFڵY*We˖U?sRR҅ J1}>}kʪO A,E;C(}20@DF"pE46k㈙XX{׬Mg^vsfuİXAbx92Uf]oCbW+Fx6ua@P ƚ'ۍuu ]-!IcC٤,3ՄCTG l:ɯaɸUV#?gA֔;`ov.P ݆ , FUd+,ϻ6Z ` Hbnu'A*c C:nA-PbIHP Wd=BF%? 4:t߿7nܔ)S:eʔ#FDFF<8d 'OO8믿^vMYQQQ۷τ n޼/W^8q"jpڵ7x#??:4E O޸@>Y$<6LlȱA?4z}vR_ÄP@nmb<)xc"|`܀owluDzi.!(ݙ5uAYD$!QrB:o hHV2vhBH)o~6 `Q mȫK!\0OD#2oIp1c1mC^-ҩ,0Nغbi}l7avh t#EU&!4GR{add3 z3)UJ:5iӦ͚5{׭[7cƌYf۪UC5k6l`VZu =фF}{>BP۹b17 *pba6UԴZKޙ̘#A.!.*}q[HBGv-r8JirTeQ`ϡqo*Pٛ&74,ݱZ ? /-^r% 07@Bpj%E6S>ڇr qBTP@ޜJB)ǡbbS./ZJP0+@{@Bɶ-!1P~} e`C LFv(*$0Ѿ*$Y[E=o(QhQkC wD?o۷oN׀ի?t ?#""2K!,..nO>A˳ʔ)n;6lnnNA:u?Kz'O~O?믫Ty]~e8ON&Fl 0*%9{YP!}%!a$#hQ X NmDECEkj0*"! : ɞ63@F4:@ܑ]0!'V#3?`95Z:/wQ0-k=8UϫBP1P /H]ɹ[{y@RCQp[\ˈ(a$>-@^g;sMsgN_ _LE"lTi,}6ZbKݢJ2۝}Ť:^uG6A,$~ɪ 2812zZ~14$D$LyO>'=z|m۶.k„ }I2)_˗K󗀀 >܄:˗/+WBCC}M6%$$m۶?c!!!.ҽ~dVJA5~ EP.$PPG5DTӓVlQxFQA!бI :Yz TdԖePZֶ#!p"a RMwYD"ׂJd@Q}')Yٌ<}_2J'5#D 2@pa>-!MEի%%"#(+]an Kb71[[PZW=cHnPa8*cL#шGKnN n!f'#} AeMfD-ZPYHhPx< DjRyfy$!lvk)1cر7n]Nll-Zܽ{oٲy'z衍gϷS_xV{KD4x[{クkT^| x/ݾ}sNfLOOou&FU*L5Z9)>k-B#_@D DVR>L8 ·mL"9IզA]d~iO#AT2'׼TzDH%3AAiVzi~J36 < 3V_TQX^܅8])<U3/&n#IrK9r |H-Cu(B$p!HRq8kDO'Z2Io>n҈/P) )؈uj_vWzѹs.]a݁_DS8re:tE׊fELai *EvI$`vr?fq6f0vE@ "ezٸ}L9CE{JA]i+#"xr5߈`q˨;0*FAvIYOx+-TqP]LQ@Yv7G> &o>阍RCC5+ŗxv싼ѮM4ˠ"Yc(m\bqI aqi$q ಓdG&B %(\:зx6x\X5jƊ+~R>փEΆ(,L x%; T^ZPdGA9D1،;wF")ADTHx9HJZ {HKkd'CAQzRĊP7"+{mUȖ L+=ڡOf=gAJR EQP-\UdsU˟_Wu$ B}ӐOdi_-|(v/)@+7DB'*, 7+GAD'"x HR5OړލAv7[#A^*#,:04VTiň?6R)o#>+eJjB0&=KB ?~=7',kՄ(MJz,'$).!GM#P&nP/蔱:t>2Ŧ4n 7pt{^9Rݪѿ9Džz_~D).qLF ,S_MD=Qul>Ddzqs3dx0>*L$~l%{"ڒ$Tz@C/rS-(ϭAj31A"T͐4#Ň!UPq"*'ngTtږYTJ4!bayS_" Ml: 72 &+ wKyc_A/W)F 0RȕO>NO+2OEŻ6nǩVF0D"{wQ DZC/Maq&igU":2 !;|20cb* X$z$_B\MAV*E/r:+i*fue#$dEIbb>wcDMO؞CV YȐoj{w`O 8j#@uxֵ_}7>uХMߟm>Wa (bH@#bB%K!  興BԂkن%"ȅwu%[ŽJ #ySSU%U "Qdt>6K@=I ">`i K;* ` A S\iZJFޢ87gvVyϦc+!&H)|q.#K.9t3F{M.XqN!ȫ7`X9$6j7msESF?Crl1_Dqcܭ]W]A^>wKZ D2ex)v܏U56᝘'MU2M#zBt2}8'%/J-$8Y59.0kȻ㵌AzpG3-P_k+sg_$yV&~jκ|l 1? fiސhLwIj16"dm9  e(e-A?Ҋ0* d$Fp[JjC(^8e9+eqh]"!Qd0EƼ$t}aBV<3QNx<1ҹSl^yzxdL]k4hd:st_qQS55,E6LTIk*>TcCtZܿu6?$5M9Y<:qp"]JK6-cAAMwlXjculVbٯgK":trpwZ^NK kfn?[fǦ+uKyb 7Va"=}4}9A0qP_9 {88udMraߤ:ut_qaaڿ2I_5MyYqU <6iH"?$m:?s2}ְIsC䷟Nۼ43zxdL5jD7iRos+8p/Tra`o,ӰMr:~j"XEḹDܶc ^uW]AYSG]u[tyZSRgNuysדqd/.*{zzjx<>A!a~Qt`?g޸WFs38u/'~^`X%E?[EWulW 1cl dΐO0԰mlVAK|T4  *.IƳ*2#PJbRC>H%#&e4ߝ;^!oAvIOe'jTdnh۲YM3s+>v8{+R-2H+IU9YMbr33I[m~Jyk3W=]+炉L:uFO[0|?3`B&[p &̜` ܹM9nWˤ%Ѣ4/Hw˪1}1f9{JsI~gdAnVV{6/򭏾سy}HΟδsW?[MKKh?:ٲ޽w>[8zYΣu+.UXWPp>7< $<24".~9yyЈ:7:0<2ԤC>;sx70 Ͽb{2~>qyQ!!M!~EźۏDžN-KIhp0 (,1 hPXj,$ն lDD(fuġaZ`a=A_z=/˂bE=:~\!0n᱓?]>f3 rqP4z@D ??av4w iu"@~NS3|d%}pXhy"ω.W|Mt\|A^ .[Yj@@axPbO+ˎ-g~^t8!#h."bM8/;sƻflHk삼r?c rs1@͎$w rb*ɱ9 3_rWscb?cI1_ y9=TK)L6#ص~BBͧ\cy[ ](͎5£b#1k>0L熄%Mڏ1: IDATtٷy3uضAN@2I< IHTd.IRGAAs/YU.^QA^vTx {@ϧwF%ãbkRX?H#qDT9ԏš\}uש+~!=_}~=wj9#?Ya)c?[OXdt1G/9#s2cҁbJ&,2¢Joa9Qe#bޝt!#?7":;+=l$ɴ?FF5-,*Ľvvv\ѩ[&`ri!FDw9-,2mDZʏwow1@6\tZe^!:XṊ[Yh7+5"MY[z $IKe+(mBa2)ȣG5Nxk ޲|nco\v24!P|MzYإkm͂IgV+(h=SfF[W/H: ^P~cI om풮#5؁][I uBPe̷hb Kt=(:͛o[g)h޾u=ê93Im-Ӷr7ܱ!yЛҍ\;O3mS#ݗڨU{;-6,VfnYu޺b^ޏ;sCׁoKPHe+e5b6]7.+rM^N)Wj7i}FƖ˸q R[I%$-q ՞ogv :cm.)~=6yL޹V"cݹu Duiq#hE ڍݼu@Ev~SQž5_5%<&.ֵ{6(xJ[>\ǥ jٸUwk5Jz:e_aƶ}GG0{dgn}TA+z>X?rCA|c!:`L^QBmd|X8b@| :DY@NH)5U/[Ā YAt[.rjR>7#rh p®jںq֊ʠdйO/=|aNC_4Zwq)7nٓfEoܷu]dTl;T y.4wr2*<ܲ}7Z5ɋmfMYTX8}VǘBeA :y Z2gRwaB{6^~nV,-K~:4jlhK..*?/^hnZ={چӤ]kWPp/;3!7ns/0|Nv>XW9ݬ޵_t:A-[P?tbM&fEUߪV|lC`& U :PGƚdq `"+yJHMI Av#eF uޞ`%mnkW{6 A]0ǽJ86IQqj۰ZqkI6 TH!a>##įhΕp<OAd@_,p1K )6_;x -vma ̸umɣ}0:La<|w9- ~j=I=12n^[0w>]ۘ\l~ ¥($21P", 7/ÇS [3ouWi`\I)C=P$!JEJ6AcNI-qNHnMO!T{ G{2-$v 䱽-S-bVI4 ŏ $W' {,Ɵ Tu%! Evs-YI;$0p"qG+X#c8")DC9/=JEfnbn`!7vzA0CRpZpTBr=`纅fZ36DM"ꃝ%[&v–(I\%m»[,~t\-gu pH^^|l}&9EB3 "Y1bHH!C4d;U':yxoϚ#=:~)a o ea{ԽGM/)fHLLQ$ɺO!- P$(<'KEE:a rB dH#'ɉ'F~QlF}-J%D$լ^!eVKI>6p/P\ P\Cf!I@~Dņ}T0mJ-#uQ {]ѷ[ T(~fxߎtR\Dy,GPtlC%O׬"heI$%h>LKuIf9*h#@O)!AL q?S~޲ v5(%zAMA K)1b1h tZ8* YN YA:oP4$)*6.y??$ҖzDERd*f@HV]<r8+{NXQ/ΜW YV{!Uny8bY$5":6a% *e,$Tဌ@jUC!_q`$I>W\ _jTZI݉ʒh-"#e2JbDe@&L/|N9ٛ2~0?J 'EP]l4vCs:T$+2# mZ$mnuؤ*J "Hn pBIBHH2 8>Ԑ@vBjԹJ(6f4OqG9:$ݱ&Dx>xKI_Bb2JtJFĊ r t&](t_~p8@mǺ'K7!s%TbJ4QB i'dHsHB1hC_B$u2B%Q6"],pm0iDTz|"ygi6(M'ՉH Bo%X>vecdwPK J'q bA iX#1sBTJI6b-05fE>/z]E(Y$z!ߔ(;kSrl ϪD X҃DziN#)$1p!X8P)dLmZ0)O֨lf4@\o{ !eC~FW[ jĐXNnI R<\c=UQDMHф"fQ;0a]tj"ǟ'G{D("Q#_񙶨$u؄"N6yhU0z]e5y" .20 ,$v8u nH݀a MIʆ;^ޱ .a .HbDEKom Kpޜٜ- ụu.9'|(V>[BD j+ͤVfBW$GHVF&r&NQi8U#8)ei_a:݃vItKDs\vIwzy$M^"FG&"mZk$ 2T$$zn9}Ȟ#yF:'_=X΄'EP1B떰Eo5 y!tRFnZAFAB#0uk7IJ1H1 |Pm-O"Ő]"BN̼aA~ %DE=k_oC05Pɉh 0u9[TLPܸ}Z k|yRʹ06fFćwvDh`oĠaE6Qm̡![3jW$HY@ۃ#rm)r'u{hOvND^ I{] H{cjū[vByIXUak$e*GPi?򱯊ow,Lݔ;197[ޝ a]&iM> `uĈtILz?{G|YGYW8 WI2F!r&ALXA#e7i8B8 J)|]LefS2e*ʰ t7 4ehG(fivʍ:5r9HT1ޅnB  :Tt$%@a\BW 3VCrXȨv<{K#@iB +Ȁ&s4[GEdZaXpPHda0i@6jҔ+(*Hf3Խ`Ό5% *rS>|3b< |4dG !QiI2 ۧ+=%Cbb(5UFQx@ N0ؽ$n5{Ob 9pBm>snnb锫%|jz"Q/5*]lI' NfLȸyU„i&%e'>{{"}櫙),J_݋ohRBqyyaŨlT{bb 5:V <.LY~ zg@"0paUƵ i{{:4푰VN(,My#)( N *+U|dȲ'ma'r{vDBP3$f M+50m[Bgl6ƹ:D[ I'aw#m.&'.hZ aiIEE BM|yȀ [HR#sVJ+aT8FR;{bN9ig/*sYy/: 8ɁPEY;I,$޼џ,~`C"[JȗళK]m|psBjAbKOp`[ѵ2S prؽU_-J 8|"cbF & & (ʁCb5B/4g9}PWࠢ`*'e V 5OT 5^B a bUI$;*"t=ꑧ:_DJZڙ,n% :JQɤvVFPeL70*czy!mqm*$q*շPusgD:bhk,ʀ; Lm6: _;!)^ņxpȼ/;o1M&?ר%a|u +ר׾`1APpHÄ;֛''O{;~ رCvmɌ{R~Uxqf{\<{284K|wO*Wm>c\J6]ޛZTXX^W)v{@ IDATz<2e8BV0GtVpGFFOm_$or?:~`ҭ@q+uΟ=Zρ#"#aT{ܝiM(l}ۛdcz+zJ<W?2"((X3oڼjq{Zנ7#p܀m='z]y#:x!eʸ8q|Jԅxvo\zӼ]rV +#}څ?kxx\SC#& JOqvD(_wٳ)?'Cc\ARql_'_hI> ۴Ug+.*|z{ /':dܠ0s߿[0ʸ`xߦ.?xIR m[EOV׺竮`#[eݾBB ZNmjd>-/Ϊc[$aܬZQG0<.凃ᩗеv@/-θSUgoiaeS^mvlJ n]پhZwyMsFu9:Hr؞Sl_EqfI4FIa_mWܖ"TgnE |@wTidc{ y$;L@ 'W@W;v ~v\Cxn ٤vu梹0op=1$`O]:YfǛS]`74x7?]ڿeWf>Tx=[*<QG8._8;i^][ϳ u}25᜕.k뺥> ?9+*Tܴrʹ| r7?.{}o}< /g_j37$e5o\>i[fg gSg.+[uh40u4GoQSSWۋ򅳃٫z>ul毚;KXeWܵa1Lj@od_zQRm돋?3mUUj>mtaȾ}_N?e[$ pif|ͻ  m<"ݼe[txAXs/' 1 ~Jk*XҤȘW`f\  MRS҆tu޵xȊ>XD|rI_p'ZZ JGv _CҲưs%m`4ɺhYR*ŋk |29{}q 4 0d,c\`ڠ^rL&S`Ds'=u7^-f?autG$ |`vtyƛƔͶ%cb1\A@VS{l\و޷uA{ xf=ttl?~m^\Th%#b*6Hx 7q dg~8vx9˿n5~0ևD7_S.>?7^yC뼁01qDӺ t~e7\?αCĂr7._c!K]A|Uh 7Wax.ݴr5BB̧%/\~>xxbZ\G~9]ڍΟǫDĔs K9Y's%{l;4g L[^Vã;m 4_f4w7/;Һl0][uA!M;왺'ܼΟ<ܲLj7>|[^x09Qv{PH{϶C*#0P԰ݰGf4>aH){pQ$PrNr$enἡ LQP {%U6!LCow@Zn٩l#; )iqvmm̅+`K (xkb"޾q#ڇ1'<_}~=wj9?Y)c?%QLGr廤rǟW8{wْc8 '%ŧ}3fڂqӳϝ2eb@ظ e_[q((>DAbEDeݹU6!ʺ}+,"OaǟƻDtu>fv]Uzf܏;_ZtiL/(}3"#GN,2:zf{ZAEOþ9rǖٙ"쫑Wrrxv(謌ѶCX/'B ͏9H0),"*NzlCkH@d rZ" }IV+0(z(fVEC!,2z؏ãbJ)WrM"8<2VZw8cMڍN|uҷνW(,2ϛ¬ (UN#Хsv3zjuX}hʛ/ʆard~ttCW{Aϧ3pr]ۀ\=s?߳s?DƖpI*!{>$K꼥>ތɁŴ 3Itqw,#A5ZIAD:q]]XX$vMq""!%EFlNWL#) Jj3(z #~VO`ƹ~Z4AaZ޾_K<_ض|NmWmZ8=UǃDv \Im+ef2sƟ~&r"c~?=̴F5!qG*\}n?ש/$t/t86Uܻٙȼu1,j2Yo[.R)U4}6~f쇹e#ךEͰ%Hfq1M% yTԒR H\|Pf% Ltyu47gb$S4p}{D%7qWPU3[+ AaB}ռP u5Pf_Nθ[b#͗4jȞMg_id$_@ ij&$yn_ۤus'!! ;-Mz7>bݰ9<33' /*,^aBRO=}Fxb;ڴuI# ?[Fm:eW 56l6۞Nq+|^GbFXH[h霏"c_ltVTI3&,*,|+ yNM|'ua]޾qGfgUб4C]ؾvqN洈&G:sˆuӾ73R;7,=u"x})@#v[j޴& ?8b~& Is&..*ha^ٺ@: [%j# !}0p4}C:k/G6JH<{yJrʨ槑аeW..*|~%zOòfWl6Y-^s/fB_:in> :۳isWlԦ+Ryu>8vz҅S FmBNn^3{yW6hU'߲㜌[1?]wU{zo E31FzU@Ib#jĮt("("E^cET`30ݻ?}ιC}Q{s^k&ܤ%LHo~_{lhs.څmmhC-N0&nB'aƥuus“x ԕំI NՅpP5(be̙GCk8aYbqk`iT(ԼVC,@FGVR0f}ϕBGCҠC c Lt6U*\dc8}FvQ6h͟8tBv+)ԇх(1@!3筋!v0_U2 R(.vr|!ȍ: mI9J%yQX,ᎉCf]gn9x7juPE=x3V|6q&|2^p Eė ?.~> vj9%bI,H!G6.Ym::so2oh`qEHSgH$w"@{LIdݡ P^*{A|p2&?!h%z"dX[xEN}۝ʳ?ɴH. Ձ}HHwxU ?[TDw;Zޱ1v\E'NYJ6aaJ+B";ķ<#!V$w^˝XHMs5L?X+N+'2z^džE̚:,nń2{}hZ2и .-;sR? jaJzt H72lX{Ա[iK6 - ![E&b0˺e KEKl(bY [u9GAd0gM"qh4,>c .O(b!K stEн ܡxE9+i>E"XQFQ劣j^U},:5S1VuA`"! $ 8wJ$ KgW7RF湋H#2Jg<"r G4󴒨d  ;4z2GTHROr sxꭀXR$0& s[蛉w# %uF-õ챢[2Em-NNϕcCE堮y 1[$W$KI rIq\DdI`vG#w|^PCH&*8t &"3W&"*r"%YD6/!dҤ2,;DaiKЕ<0"˰A< Ic# nRƸ Q&Y29պ@,TK̏Q9D$ΜJ ^+ClaRl<參>5!{P]Cp buCF ,Ϳ/`)\A (\4z./&t>ƦAM>Y~#~u6]tVCi0̷1pT (*F ZiTH#bdЋ("nޠ@dwy[:X]9^Ɛ{Öc1(p]4&Dbni<>,ə_  c)Ђ89 c1,rI8EHP8- IDATOk# 8ț4(^!\oFn'V x:sE.!΄ I{Cc\;!8Iep$+ҞUvh2ΐv͋\`0#tʟ"$n$N瀬S'B48 5%V'Vv_dNm6trq.KԩH܈a4LkXL|%<%i.Ä 7>) EJm,Є/x;ɖblg\ `՟a!nNq'%DDqm̧ZLo"t; Ҁ1_MSOK+:9ʁR-}Za!U*sN ~]Gf"KB(zrƄw& {UډHܬHJk=hfgZ3Dzؑ%JH(B HMz,H: 0(uN@B$Ukd;p{x1B\#{"27;d18pQ%5O꺍{n\VP,q@EB]iN|"gΠZGEAJF善BE3gYsFF3~(z?>@CUqSJŵ4HH#Dl&nXta1"Br+{͋D΋nǸ":twm ' "m9qNq0GnE2PAVMbr3o4]'tsĻO4qa|jHx,ǙQa2@g:Hδ9 ҖO##ZE>$v±YFk-:](D)4G@Fe)3Z@! 7US yF/Bd}\ H,ZR)'8W+1S̃x]L$AkM1t,ޑBM*{3(1J'&T"04,S$"#P {'5O.:-əaEǽi)\P5BH^OFFI W)WH3&Woi~i9u dԈ&^~2*Ў = F{[Q.\d/ RCQ["m, RT+ӽc6lP W",x cұ7'=lc&X[ݖ_%Zc4Yel6=CN^6" ]sm-*sYgMPdaatR)C\;1:󢒬ƒhkd ^@b"9$p0iJ5(ՁL䜠,\\Mbi )">Xu% >m2@Bp;[`׍$j #MWM!RD DlJrYi|-gJ&LK2nC ڌ!Xn@*E:e2&F2"x|ZZBRr>Av 8N*JRRrƭb5pb3ʪ-Sj1q0AN=)_wONHB(9_HЂ&TnWb#"t(CK"e($'Q#gk񉛆M#T*"$ҡcO2B7COhr_H4Fdޒ!3\=upka8u*k"CXrt !GTj4jdM+kj c&1ejTRd&\b|/ Qo߼ E`N*5ɍnN$ZW 0LR%.?RcAlNnʂĝa?H`qdzZ$G)RdPS4U 1Sp,Y;ȦJʂytݵEz$N]=T2#+0b$pMY )ZeƆJ( 's 2>EBHwgD1<}#7 #UUU4JhAa;J @ǔH:=*?}Ƙh9}+XRtˆy*zUπ@wJT#C47$hl E $(e`0B|R5@~ ] H+XOjb<Mi켋]d6M Z+vemWM2Y}?2AU 4xEr#4AެJY!8hQ$9CL'MM(3-Z,LP*8u+K`%G}̣β O™m<< . GFCBe"C nfM(OJ D O Z"3R`irWFII)$ vH 5g1#8o@\e4X]Y,&dtP)9LpH0u-G!i.[y"A7*o^UøX|yI  -kУ8e2QK&g)9k[~;,s6|AGkklOmmU_NmPV4Px# J5y|ۜl ;>ӵ^Q(JCƼR8@:CNid>ӘҴ"E9!Mشc n: 0{ei#!h0v@dm"`j䈉i!A/K)j"FM%p̜|pٹF9I>j K"Q y%<;OQv̌$K 3E("B% "D< Pb.Oem5^dF1aKC06BQg*H“lIZT!HKU e19?엔U!Zr/e[SRGʉ s.>/?ټzA߲ չׅu˟PWצ}!OMO7O^vծKOؿ">ڵG K|FQo͙gwI;omiJIi^<|W+K>ؾ_;v}拏7,_r跜f:oB=o%{R_쬎L!5-+ HR; `"xjzhllXON=zurr8~'m}cmeyӋR_wmc'ݘ^,vvyF0χuK^]о[_P>̬B;Z[3x.5=c%lؙԴ{|VU=:o-몋댗.yQ}'vەCO5奅-Oqŵ#[>y[ٰ*f5;6k߭&%&cڪ笋5ԯ[v]{;_ٻ䙇zv}k͒wPwMnî!5-OR4n7VUW8aWN=? O|5h8S ͺkߋv]eYK3p߳4v);\U]QēNmY=|s/"t(֚_{^_PƆ7Wǻ=/59))f\?߰ ν&1)3: ^UYn4'nw3k_4z[VTpŗ?kؼ|ޥjZBC﬚w/}YZd^,~lWJjzs4{X=o5]%0SӲIGk>2uO͝~ŵ@}wK] MIDwX_wY.캔ԴpCgy[_}{5k㗾tY-J\?=g7@F@kfXaڹ?} Ni߫ЫCG"U,eAJ" -XV[nԔ=h'Dw7,ެ-('ybD>RS5tz_v˯uƯ?}7VI))W-RFVqzcMu% 7k_~/TUu_v]`'Z\8o/۲^wA;UO>% ö~jqrr W.}>~5[o}YĢZ!S6.,/B+$0dcxzz@xs?xǃO<ܒuO>R7ZRYQ~͜]Qzd32u=wTm϶7;蛞W۷瓋SR^_P}{'_Yׅe|fi˕e|a+JK\T];~e{㫧=surLqW'Tp#~GTWUnYTn?1g-媊[g̾u%, ˀÅOWt5\0o|_^||Qrr+^ᄎw?̎=-zNOWtOmƁCG+j$yk8?~[ͼ?/cwڲXYq^l{mY'XU~$p6\SYv}OsGݰTu~zO]w U_[ tW7Vt>wPjz&`ո[KNkchkK^v瓿m?o 3:tC <8?EwΏjyej*e_屫ކi?[/:NMR`䇛?|mEYOў-+;_]qlm_co(|mCtIkzǺpW[^\h+55? Ěxc`ʬUZ|,}=SSQe 5v.ʝ-[sJhG9Qi] .e(A!&x='C,Z}j\ 0)n0GH^=!4tHNN,;ZU[|7-,--wGƗGVg )1m^.77wu하<)gKIIIK0b_}155=߿^ [p^YtEӯ7_;-l2l5yiF]ǻ_KNN(/h>k-#/Nd>:k 32G|grrs\>=ׅEm}=}M}.@lkk򛥦e yWcG(lbfvT)]613;7O>dlvuO] %؈ &_? P 3>]rJJZz#է7:k܂sz.W{>?9P~UzVnFN^ yOtjۤ䔔s^POiiOKۤ3!1?~!Wgg2qg;CVέ؊&p TBDVdn3\`\s !0$U!0,e,BֆF.=+d 8@D}LHPO1=w__m􌁣'޾+ T=uⰈ1[';Irǵ5Ms˺W\4-#sڡ TpPF!MzS@ueEaVK [PUUE\ -(B(/})CEL#j* >YVՕ֭ZGg7k奏)G9y龜fk* YՕeY\SRR}Sw㷯W9`~Aa`,y upTUg E˚ u;7ty'/j*/}|SzfUJNM}Bw^{eGM:}W;ͫKw/_ݖ<)ߨFn]νvDžÒSS6-#+@/ߓjs /-a!vſP'aCEVW ܂j ,[2F>.hٺ{?/z|w?_-k˳ Zp>lC7ZL@k+r ZYKux}ކ%"}a/kRp"eZ}0< ytgt!^xi-B.}!/0A Әc4S AY&XD1>Z'L*2wN~a-[Q-Ї-MD?~څLk?'Hn^3>4SNƤO>%pNYVŘp?5 *ʾA=R9 R-NNkk>D=J7BGsjFNBGfn]$D)`[v3`§Xcc/z IDAT]9%@k?WVrÿ[,Ғ3eŧ~-vy ꓓR+ @+xQX}QII\'(o3?.-->~Yܬ+/zn֡G"@.~e3Ň|;x`߂ggnzFfeKgd-n Щ{UK^\=0 t@Ͽxg>{cz9oKTTW_6'xqn/}rҗ:vigu;vtSZwϔ}௿,y~ƓV[QL+xn/}2{QV!)9%)9ȡ*Ş^S[]qjo׮[ TUTU_Rncl>ܹeƕau;`͢gKKw}_xJT /4TT߁#wm^s%w8_*/;Zs߫&~e8oKnyunk󊹵UՕWkZ5hM-+Kx% =sLJJr^m:zgcUjY3R"-vKsqZ;.ܱfYsCE iPwo$5o':;̩,?vuE̳/ڲ#=;r7>f*N{uUGk*XcCbRrbRReYϫz75=7Dxʊ|=DHMϬ(]?wyj*T^7=TXa@-dCҊMNRb/j  0Djj~-KwY@l8u?<%5mÒ4FNY[BB'v8_wИ-+~DQ|y4f/=w"=pTs{s;ܢN҃76׵tNAi+!! m{#7{dϾwrJZz羃~CXH^mGs :7Ov`n]NNMoȾ;C}<ڪ\xZZك'cEvp{-\[#G~>۶gU#L^8gطW8]ca$Z.a.f yJE, o{I"Ĭ݉p#gQ4#Fs\^y~-+#̑plD@B9Vk֠6D> j"|S޻c:R`,-aG&'r2s3 ]ѭ$/kQg`莳gX*BM,w=*R8J Uc: G`Pi qڈqDe0p֦$Ԑ Wa0@KѶkvzSn8ꏧuP7ԡ=㺡w=ث?+_xνۜYG(=۪وu|dY5+?e$'ȕ'/)Ĕ:'%#mdNH|] dZm7nРkPE7ZTrM$Lw #v۵{Yi.ﬞWw|ۚ&}ɮ䭎ͿhqaЗ:Gv4b^䈆2v7PNJ yQ*1fCH| fZ}LE5j6حp$u!]ɕGa0Pߎ ,x^LLLxNǽH7!{>(F!-_;--C\#41*P,c| #5,tzn4xx>ӭLcąrg.R%i AP=7g% *ȓ*]#K)BkN"×r\nƚv5}m"!>M$HGnNIxahnC1#atT[b΃Nmۭ%)JhuvLUFuBj@'F\fARnOQ4H;بV:M !V- QDB ؞&m=)x>%%)TȰOq B8xUN@4#UO:h:w(,I߂]9B4.*.*Y!HG#`ͤh0/)bI4'bC$l˲DI" |Bg:/uESp8h#H`WAUVz@ %.Ŏ_ k 5C@KFNnd"'i$rnpp !2i+9IH' _s, +x-몠&<}a-A\YƹRyGB9:цυ-J; Jr5Ml%7 }WR]?B!E;&\ t292ڊ @m/nPZO"!\H2< 2vp!J^V-g:0ʀ$v褻AmdJ 4DF_ Z0b1rϡ5;2Ʌ  v$ahKr=JbA㈭.!MSҔf0y=KbnhnfL$ '`v7Ό~JC}#U1j#ϧ"%$$B"`R"$%$$'BJ"&AJ$ ؝RN,.5s@!Ne2/\VZh(ԩupD{N|d7>LQ#}{9 $ \Oe#Gl0`5N@+ L5vOԽNX#$tx.۸*EcO) TW,Gg0 Cŕru_%B@ D@{Xnh7ٕ#jECvc`P@ZXPUI"sg&*CvE' }p:i1!>].ocSc'CԢ)DИG, V".f 4'6 ctkc17G@,>hDHOdHNJ$Dʶ@)4WP /“BĤ uʔ %:)0/ \5]G.3qPMY*S(6 " v@) S(d ԛ TcU_I0 o,=ҝ񴫆r%Rgⳝ:uhJ2(M_ĭyl`ZUGp4oWĊkbu^G1<ߖ ١,1ʇ*Tľ9塆k:.7yI1vJ*KhDfKvׂKx VjDU1(hQ({r*e'{|X49AM4{]<#NS`\(CIF]2d# FRAFhlR@ltH I!'b^#_Tb2KA[@, g&= "z!|9b,+S$d[W[;Wݨ1&0Ʃ^VfFDoV@ja<C:Mo$6WF6. ܓE݉eB)bTQbkX\v.2嫤ZVLbStqU˳ŴXˀ#y bD$s_5yڅhctQqHRGCI] XP|@#nY5 QMa rK 1Jd%VE!$1ȉygʴVt`$Fm S TՃiF(Y %[>FcԶ ٶ ;ʁhf9`]kHIRQD LK5&l+ sH'ZCQ4YE c҅qj.vRtG@>5z%Ü^ %:Y2Z&=ox mӫvPj#k1YD@| J* 1HMw*=22nHDzYS .K`̓A?}0>33ŠbC IV J0o<$as("١rF[,cGX!@y7V/}m_\Db um*7%))zhWT?ZnZwM2c:D,ͮ G?JO.hS5e?|}"kyY=/!-31ˉh;=8\W)XX66Fb "+=;~,W6t>vXL2!MbۮeA&0u/E[5^yO[Xت{XSU=}̗j*^'x{ݲÿ'=RUy;J zׅyb'7?#y^qiʊgΞ6svn~uGznY=^} K*+ʦ?ݏ./-ٸemE׈t!elA@{x0tw fr>XD$$h9Dk(TR3&.6;D8""SC %֣(oZ Gl= Ic9{=?פ}"V8pÿSzq{&fffe3=ջ313'73;gИَ.8>yo˯o9hoyGN8n&f!:)+'/;7w?}:#&Lov~S\3|{'efǻ>vRvv\װoom vvntހ!`;#&?0##'޶-WPkCIYM>- o?x3s%w8/R+2sMJN=V]^*3phuJĔ䴌ύEN|,4"M1á*ÍWyO*)6$~G< !1q wA \\Q8θfdmeHQArdT'V2bwDW\E6jDd`5i5.W6NKA  g]R; I X'+q.%ېD9C*?n]vVZb`t92ۆ}C ]pOkD VILndͫ:3D+lܛ-kTo/lUSYAN^%(_~vn:BYl֢UuU:))q6b$x* C[VWUӗz60N<N:tvO?uig5k]u*ʚ7oeL]cZ}z<=+VxtӅS~uoHN:ʓt}iq?E.g}8\zg&& sB6!]7.wB/c9ƛ tK]@mS2.g3Mj5PO*gD-D$O&=l)s WԎ ':7d4.>/!)#)zt4rZJ`fB8I(~BVqfW僣ϝ dEٹo"I$B@? IDAT1L8qIϓC4'vFg0Tds6Fqmx6dYG^y_;71uae' @ّ$`鲅UƲ,"Jb>ZO/r7%iF{X'Ϡˤ51$kʐCfMN}k(xcx o]2%.N\Q]O{ԴY/yHQ.*azFkhڽ܉-#c|d)6ǟQ>/<:;P8̒CxkueMU店_أPG- oH9TM v{K^ԽJc ۴Pw[^KIM?鏧h=zb eG]}7fW&+;ˏ#NkPw]o$ghUbWGnb+WJG*'klHLJILJ./޽Fd.R ڦX/r\A ${<4V#j BnuI-j #Ys4$ )@ h wd)CƗ9uS.0JB5&Ѵ3:2J@a2 OEۅ %iD6Dk6,IF  Z'?r=}ldfI85pܟ p)Nrѫh,~vZۋ,Tʲ h8a,E*Xc0LE,"IyI m 7nzu^GhWT?3׍ uguy7ég>u um`(6?E;uĕS_[>oɳ3s?4`ž=y-uXTm9f쇧W2.YQ? 9/tɥV.z[z^rx)06w7`Ȳy\7>brsOKˏyо߰/⿎V6o2+~Yc'MWa*)lݶ[~B'mےG6?ר??gum\P$#௽}˹¹1R9L3R?1;Ev5DNڨQ3LV + >7m')'dX  1=czm$G|fl_"~DDbydHpFlY[+҈E ]䬄C"&4xL1Q!T+#E3hFZZjHO+9;8`J, Ӏ\&`Hyk))my* (;o`T^ˡ EB ɱYT5*FJBh]7^+XtW}ॵvCu B70 3em\Mg%ʧZEgg}ѐ19-3bESF+F^OPR5YFJѧqpK62M0kj rNOLN4(+7D$s#ՍQ)Ȇv0&8pJ%B 42Q #9Jh|k`\*@ZgE?GHlzBr (xdW2e@Z&U0.XI\{U3J$pS#= -30ʋX ce/EGsvɈY!; 95GM%s4<$0"5K!Mܫ[eH!GNñ 4DGf^:MFU]$&*gʭ*V#k wxqU#P>Z^بTexlk 3PD.q YIίcARvjsc$aO$և- ޛ9igL׋I[dcqEMfx9)V IhN9Ҡ"bFc OEz+L'|\fxy@]_'gMOslA)"S bC)Sd!~ch?$^9FF ^o%I/ Cx5 4uɩ\Cr|Մ@ƀOj 6ۜBe.jHuoFܡKb{!+sFZ""OEtYo6xSYϥ1@e"}6E4m1$~#dJ٣d :Dؤ̑}{$V\j I!F +o4NK ʷon@ ɜf)=:]liFtaCРL&9rP$^ 5UEQD0:Fg`n 1fH_9I4oMKєV%b;-=$qP\&w6E+GQEi3uB.qY-$wk`Z3]b R`J<2m`I롸M"Ä^N|}#}p"J;fwa~d"+͎B莢b k̯ F#( p鼀@Z`Uk5QyuS!sx'od&p_L{!Y}QD/ "EUCg_d[mVd]`)(JEpNG؁^'Zȿ>6Ls 57vr/Cb|L`,ΈX, B%ہ!ܔDHJFPrO$؈9vItNaadߙD VwB2"5u)&ǃFG2==͂M`S<ڞYYt~$"tϴEȼѬ_ Ca߷ʚ9-Ok WKB}/m*CYCQ"vA9 $uT#@26es/Zooi9UbUufHJ) P\nIg(vtY5qP\D6ݦ+L#PK`Nc~#n&Pd7>aaəK6t%k49e8 LX_0~ɨ^]A:Lvndhr:1j4=BBnf2E7(kc)7\{M\їL(V<6Ҁ ZC% MSsVh&J.sܞ"XXr+Sd 3Vv:hڛ<\/ےmXRF3&}1-[DJpp AWA1|B3F$N /XhQq(zUanWdLc=O>Xx"摍  do5Px *m}~ʁDp=)28kKb*4KMzT߰lEpj e*vr;ba 6Ӈ%(y+oxé3=DPDL$\qlm KL20;btAGbBSH2" IHv 0|kEr "Fڒ)-0g* K Q)t)n z3ͼXG;B]s\*92҆%*Y#>US)?mF)juqd*cЄJP,&PUWXU FCηRJ ڨbI渷-+5W5 . ৲GŸ*O1.Cu .`蕀\kDWV$&1ȽOh?ƕD4B4GFwGQ2 ܑi:/8DL9L ! CBmwpBQr zS߉XjJCY%M5^t tἉ! D>#C'6& c hѮK`"y<O#'(nd#V' #"˄@TX_rL&t?a7dyz(0z P%tǏ`#!)! +{~(qUBkA!^;bejJcCvr2X5+>Bw `.n,}" dF ?18F `≛ /3#RS 2zEpk~˗p抧7$R#H&a<וTv;.ڮI`3 DUSldnv#s(!H")"gh2WtsZOk0gp8fiA̬nJeC9GDJDp"ns@ͽUF_}MT \ D:|nQqp@ū0VzYdef=@N8TIO'r'S`j<V(}d)'X ~(]MQh8mv 2l3Ao0O*td$y`D90qȥD~=!t2Ɂ Z!B&v?6X(Z8Ń]%(y"ޜ\X``B^&pW!ULh/N|@2 y98ːA Hޏ>ăZ6q6/:h.VLD 2l,i>B"H) 4p`sR <' Xi NIg倀: =C;LZ% >FPCJ.iD9P-EWEw!"V$ze$:?:|,'!K\ԓ .[RgȀ$~.>Ёܫv8b \mmzq-X| *wb?icfZj_H_Rː]rN33ogfB*C5NIZ23) 'X4:Ɣ/fD3%8WtԶCA9bh@KPA!hvmET^d!~*!}a,.AG:/1L%zrM, i|GqQRCe>8rPWDDWWPpa,i4Y;uF CP^ ƨ8*8"kDB%# P) 0xlm@SAB1|]!R[lcXU9 qA?l6H"4^ȿe!_$O!uA`y9s߱ @nƑ\"a՟pUĀF=2dcN:48cAC)\9Nd0,ѕPuEHu8;X`5!c:6..(h9*D}P e@,pԲ c@ %k*-҆$PpASvBp h u}1rl o^̒, )ni ǽ#-P͂GK] W tr%`8L>U4o!gz"%eD(/t%?f&@J%OPQV5 bB]oE R?JAVEW{4=x,O (1kT  D(F6Hl H"xНD1άܓQ-tyOp9*4L>)Ѹi*.L(MdbdE2ІEbr ]'/$F`Z#g.'*p @c X2%phyGՊy~ X8Evє4uDqy,O$v`1[~wsɁ`r$"e_+@ C QEA(WrbpȀ'2HDC23j!RTTuZ*\>jH8f`T(@1QTdX@7؁VNsVĺ1Z0I@H^CÃ`9G]mˋr42QFT 4?`P1 ;&*-Hm]&`Gi@݋Rd!-)m@gr \0,!|Q=Q*cr͟hހqrQ,g[3i5'u:E%&CX@$UIQ,-LRD%# ~H|fzF3>l+0HkEX$2U&VBoG/bOs bD*Ȓ) J+"ӛYͶE.jҾVJT=͟R,q 2"`Y- j *k,@=NȦ+;ArkǢGOF@ < * 16*NcPR Ui?>cE2ZdXp P;J p T&vǙ g&zX#"vӘF`1ׂhD+y9!"HP\Ԑ}@>d aLbumo-E`m 6F,$Dm9^^b^_3fD1 !ĘјFcE%y#l`Ű8z)ѯAqAEN,8q5S+ IDATʈU_`IWc49sLsT(L(r>C Ab . oIl{@܌cS{:`c`: 1k: AKk]pdbX +^j |6< SA olzOԖ3D -',GK|UQDVaO @)g+4^(rp.k ZB*K.B E-xހ܉ +FkP伲Z1ǏA:ITG',]iYq˘57%A 69('(j6(> KۃĢ+EK)(Ge% bDhdAQByTVJkwz=2T/=tfЄe2GrZSoPVAyI[y[d&ȈРE֓L*lN/XDT)F A\REa#ai-cB.OUwv1Cc,#2zJ&-Ҵ!c:@0P*X'R myDEQvYl?s$ᔁuVp3,PA)+KkGi<`YmS܇$]e6l'XS|FA"'r Z lFCE |\Z6O@Gy"|k<.zS!׊A6BОE[gv{h{9*')0_"ڢuvpYT=2XruA&[\-9cCLNL Jh( -U%00&#D86F@CfPS~:ɵZhp(+r%%R-3bABfN];,evbc$-+wբP/X畡^FJiz-0hà!1 0uBW#P ]YyGy;x|a_^^s1H:囬NUjd +Jj4%]nȒd=.d :YYx.(J ZPshD\" +K&Ͱ`Å K)(K"U-- :䃺|+,t.KPfAdHJMF` ` HŦxb-xEx]e+ʲ7ُwl![0-;+]$0<4PzAP(JF7h!*kЮfG4 A |p)ŏڕG, d`B1_[+?H,L4ukv`rBqZ-p6f&v!vc8)ލId$C0y9~r*+;ϖ5t1N6 MB K8ϗE#21j5e3/حѺ%BrJn$4E *U ,Wd 8mrD.%ѨdTپH6p1PxkT; 2WwS\c!Z‘n3 Huncecoec51|h "֒x5ӧ\,u@Incmq3 ^ 9eAc$PHv\H@Aҙ#:0Fhװaw\Ș29,g0}(J ./90E`ó vRw6566 ؐ `(<[J<ˤZ0[4E`=;zE"t\xsZGq"'5,Ax ] dkJ4LDR)M\<[,`d*2~FwJvVS tgr(4(.tE]ta%8Zzc&'&QlyyQFTiRmTv\}dm@+ݮL -[$a),!eXPR+ɡ: F4L5DF.:[tK5kt dhk=ڙ4z AjD7֞Mn4h\wT &(<jd 4j )rl^t/94<"LOQXKM]> q]k6%2͸'h咔 IA[X DXrfY4 POLB&lCBپW"9&-XF޾[ONkeN5dFn^TAfX [בNWL?qtA B+8@Yb3fr! :D]=pb^RvwKbt( 0P 'i@:$#+Drn+8&1Ӄ3B_&6SE \p FOڤ%F2>n YL<Ù(mYV9#3-!j 14 ty !Ɨ-rF{^`-,"4[p}^UhQB0E235pdU @QH hc?B WԮb-둀qBbl}hub83UG#yǣr)]X `NA"үC YY3"OOr|EӢ#!(IHjʾcQ !G.'APRݑBAەL>]g Gh3UX"J_c4kQ!?) {X tU^} ^ DQs҉ -1lrQSTl 1D_oc)DpNDޓC;F|kѬFa-+1iDQE7(uM4y0>XfP Udu9@7a/NH -#Xw]x ,^Ɏʓ ׌A,y\ bLӊ;Ing}ӵ/be .s;@+5q@:i4Hs7'oO4 '+f0<̚}+$Pn$EuUmD+Op9q){Prdo/=ڑBDDlD&f(ko .-J%0ċ pjYmnh<Q(^NCvߢ %OX,J@zNJs"9d^F4˗O'-"PnF-%MtՍDRUsVke9!EH- z9|cÀ`~'M쮣$̂ha ]Cr|s>U\u^xI=xNus)EDQPd I1)0в41+HYQ~B@VA jt$@Mp`"mG.,X`aE_\ſn\Tl:W4Koq'FPtjsG\38 ֯N}SE%+(yEj\S4Rv.j_hbgM"&;8T-R(Y, PNh5[Rf]$yttI]7EIy<%H@h#-.]NwF1`TIE=A3e9|I/N6q˪l2;YiVAZ dI2jԋ $e01CR_yĵ'ɩiIIQ"y,Ǡ2}8Xo)G'Ǖ$<^@P**zhͯ+V'1\0F%bwBCJ"{}U ɑBTb{f,T OfؿgW_~GO(]"8wEFw^i6, UIE^jJdzQy(Ȕ0E"]|k~-y+s/Z=h$P\͕ee9XT*;7zQR!桘܃"Jn $ag)wVF$oYU>7$MuEvʰ ;=GuFіf+-230 6>^hR\DYL g"-"hc"4vb$#sb5Ed$FI' Tǚ!´ 08پ1xd7,BLD)UH5a3QE1G0(%WMUcRhbռͮ~т9>1ON}:cGÚ#w=~y{o#2o祟,nS4/[:_|c׋v,0Rwm獼oj|zF|"_[R/!wZdAKwT >Ufȋϛ]ZA!/Ƈ 1q$st\;A^@LM`Ia*9l#.x맭49yڙM}c/=1Onݴ=;_)}ݟ|4ġP#Oi7!pF@In'/ĶerA%)t-([Dc[l`KpN螚P aH5]y8$gfM~ k`mmnEz*3:TXGK Y,#十 Z rp m R!0H_=ͤ6̀ӝcS!YXDZDF3N[ %hk!gXu˜G[_ h[ MdF.dUC.URef?ݳTrE/*ֶ=juo]#RhtŒwC{5_.Ng+޾sV-JPnx5ˑ"GV(PJ)RG2˔pW;vR%q8; 1մZL b14 6@}|%T/#[‚'$Bm䞥|uEO+͎Ǡ5H$ 4ACV!dT(@)3y&r c U0@ё1>f`Ɗb43U *AР>3<zꜞx\a=)uz+1$8 P9ѝT<~$or h} 0/_1;c G9gbP(%~GpS:hJPnE#yJMKÃ_Rpb0P)֭YѸŵV/Mj*?,#3ALG8u )9l;sXTYB= uB]S\6N 4 *s"ы4hA":)4uIDa(3BiA+ 1q(n ``6ߠUj" Rzvh#!ıNtj,XO.XǏ0H}r?\ оh2$TfjZ1N)C:XԔдαTR5AƐi椒UqlhRϪėtvb꫚~م*G8Ӕb AIGJ<@3ZSGA9IC4 DKc0YT(QbRFoHyi=wbVRQO&()4(^*Ef(2(OA½A%LA!ט,Jw1>9@2{h&%YA58]PE Ar 6 C 0#H*^/ٞ$]>KRCBtѷRs\P5 >}A F c,!tHFM`js<ˎey ]}*C( Bz6+9򄢋hXE#A1cXU IoF󢎕 #fE l0S :Nsiq΂A4#(1YuA \}XʠA6-^BOC(BOF#5 #Q* B6}Mкp#0kMT*+ g#O$,,ٚX9p!-K7`* RpR-QLt, N"X| ox \%#Xq+, Hh<) ,#=!P>1ĒZ9ePFZ@ؓxփi'al $HG#|9)^O'` hx7;7ZZP $`r&ˑTr`I#&E1eq3`4:'Rb H<^ RȏkhTdLϋAH4^DƢ _B>TCQF3| uVh0Q%|iX0 rSOjhy+Y4tZE6a<;R*(`@^@̉<9*me*P9K<œ9c'd."wE@W"O!Ep>|A"*OBWr OAV0i>xe@X,HDk%H"Aqk-dX+z1, A-PZrfET NU k Cg:-4`$OѓjڄD`Is=FI_95ы,mWYŌq<73D"IYDrUAVc E* # -*RmT{fBB"m %S$>wD!!Cո{E#I )T\9(#p9 eD@/FQ<ΗEi-&}(*:9*'YG!MCȘj]t-xB m yxQu@ԩ%Y6 $}!cS0 L2J@, Mf eW4 Ude6")kD㉒1[tѪz"L 0K/uґ#<@>ԱİQ(@CUƑhnKB >J`ϩilyY T K 9C!Z, *YdUVb,W Tʌ(:=t eBۂXG麄fc @ْMQ XޏdLޘ ̳ H S$kJT}@NQyQ-ɕ/i~}1aVEJ׏dKZ<(tC(XpuKG%^`ޔlPkSd L<߈.f1ZIle/řь03](P@yȬ \;VNZhZEl6,$Ttў(9|6'/ ZH ¾ù4&6`rTH#p|&Qx0fhZhr[}$C7޽#± ,ቇgu,|!Ovo4u8ϴ^%7Pr'xdLh> /م'yt|O6IFDL pZx+ϡ]\DU;z$ᙞW YlMLUwiICf\n¾9 oexvzŋ_r=/p[ _*ґ1bM;FvͯҊWR.]ݻWo/ڷFŷ΋-[}]wURL^w}"c٤Iϕ,YjҤ~w3?)|G;_OW:_djAׯ_T))Uŋ<^.ɓ RDjJ9up7h"{8_)SzKķ,:gw~|/yӦmoj]?8zDb4/o|3yygqW̛t=ܓ߷_ԱON8WI8-㴲+apFZ 0:/˗j„|خS_z;%Y^?c;/T|222헔(9}˯hP\-Z._|Μ9 5.SUW_Xnn#~Sfvva Wcǎ0ݻ)SH"͚6lǏ}_)*<ԯ}1/n7߬uCOsq"E.]We˖]z%%JN4FZ+&'ofk_E$׷\{ر={y|ҤI扜?iEhYl/5kQ?=1zTj"Hr>D?c)vLׅ3wF)W.F~lHS#/J,sz<ɓ#s;}l޼yS{\`}O۷uxm'?mСC{{g˖s.aÆ>׻K.--O^m}ZlPWZuq}П}r„<'|O%Jp](p:#GHj JI cf,`Z*N|B=.!;)fR˷o߾Æeff}u]6|xR#ӍJ,=Ǐ_~E-7y㖲ezۓ/DLR}J˯hwj׮ȸk6}Xner3NJJ2?Yݺ~AZR6m[7nm[,SqZ^/55:;֭W>o~ڲeKM8ջK O6JT?Ho%rD9is}я?n-_XzzҥRߦ}:v k*VB;N*MzcƅFn%:^zS4IxA̓"P=j%Jh}uy9'4_۷7úٓ콾KͫqwN;+3K(9no1O+V{qӦMۋ]go+<Ȩѣo'ƌ}C vbP4O5.ԔBD:[ B@! f*`toƞ{l4s˗w%X .”)<|ysݻ޽udٽe&׮\&'W\Ϳ7cOƞaV׻ݵ .~B ۶m^oݺî! MNN޺ukt}bŊضmfM8q7\֬; 짔{ؾ}{ e9SzBju?,8QםjԨќWgoܰ |4VJ;fŊޖopO<1ft' eN?%T(GҤkYQdlh *Þ8Sܛc#Nj-Rhm۶ h{?cNNη~=CA_g8x0;;kV2t޽{_upzuC)wСCC6*UYݴaÆ۷o޽:λM4RRjF=۷oaݖ۵]kO"+G֡ð#߿aÆ'u;ճg}w2''\־C fddعsO4mTLyᅁ.BYәOzB3QSD@!"v~FF̓4iҰ#Fۚh~Chz馶ne5ޢE5k?֡C{KPBZluirrzsk׮o޼EJJ>}x /!K.ոI]>3gv_7۽@y^B - 3,IRPP;xK "E 3+wJ]cZhV@l/ R^AP~u0Ve~u!U\ZhV D" Yv9J%ZhZhh/[^LtƘuahZhpD/`Z/bS}Ob~>lي+7or~ph͡Zhg?"DBM6$`XD)i9P+h7_ژ1cƎsZ8C Fps`:>b[#"tThl(7/ԩS͚5/~۷8vzկ_"s}޵ 6iFo뮻j׮ݤI7x#wOV^ݻ{mٲsΩ;w޲ey$)))u֍_d,Sagi<9'H`2lg ׌nzdfiӦ{K.-Qă>mV\dɒŋ/_|ܹhy{nq}޵줤$ݻYfk׮]vmƍCó#G}[ڙXҥg͚uNnؽH|'>vFxHTF4 c6w6m/^|Æ [z}޼y_,Y"<{:8qobŊ5eʔ?ooK/4uKzvzVd &<ù &޽/XlΝ;z|s[̙VT;x0&x5/_p 6mv}: ӞsRGwygڵO5vҢHBel?/xذaK.]ȑ#?ĿȂ׳o05k֤ծ];%%%55jժ;6mZN^P)#q6lذa޿Zjծ];zv6dȐKꂴg7Zj!3fSSS/?P)4ks١BRŊ3-q~sM>}ҥO?4)f΍' WA4k7'L {׷oӧɽN:֭^[.^oܸ1--M3=\wZz'#>&nJ۷5k^zw}k׮ݱcƍ5bŊV}j[jUupժU)Sۗnq]83_ .׿uG˗/O?yo^\y=z3fݻwtqp5:`QFf͚~1cueo Vx|dMDb|O 1q9P~oM6f̘7|aÆh:v8a„={ٳg„ :u2ק ]wڝw9z̑#G^7q;|ԩSkժ%8qhѢEݾ};}N:v8t]veeehJy睹sN<`O<9+++++mJ?Xb͛7O:]v:tҮ]Ç۷o߾}Ço߾}<뮻ȑ#Jů~SN=~ݻ ,Yr毜gkws|E|Wlx:37`YOퟏ5ckD n}#0jԨ;wnZlC.]ZhѺu֭[jժsy*Ut54mرcƍKn&MVZ5uT'5*55cǎK=裵k׾[j%zrro=|:2eʔ+W6nܸqƫW2e~kf뺝߻w3==B W_}W_LŹ2Wa=s9~?[nO>m۶5'p5d'oGcǎ.^ B;k.0:ufK̭@2>fwW}rZhV@lK 5(p*7evӤ>Mt;ЦWJ)Ӑt;B -A"*AA0ѣ/"BDZhVp,Vq5Ցb,Vs!*B -,ʚD(ƘdXjW2RB - pL8zFZhZAc^ B}1lRHsETG7B -̐-b' itPNR!"ig -B - QzG}PR*JOdcR0" -B P4tFi"Q@= B -B+`f-uiƚ"0[lܹsjjjjjjΝlْf۩ziÇGѪUիׯ_/)]pu]Wu7 uřة?ŰO|s;z_|jժeff+55A'Nw?./ qtP \|7zP$% ޽{_~ҥ%Jʕ+,Yx˗ϝ;g{޽{7klڵk׮mܸ1%ŏir8rȻLJ޽srr͛e˖e˖v1v]=݌/T+]YΗ5y/$K|sy:zٳGꫯF_ꥧ+Vl͚5˖-۾}o?./_"CtAxP bQ0[Ѣ;w6m/^|Æ [z}޼y_,YҳgOM6O nڴ۾m۶nݺթSF]tI\5;''g̙5jTҥK.=jԨ7x#!@YӾpSvBhP/E#D ze*gӦMW^齾+;ѣG4hѢ_ /pᬬ)SwXnݺujժ5j(/z^{ɓ[o/Rɓ'[O>o.袱c&27o>x௾ĉ &޽/XlΝ;z)Nz\O?/][rg}rʽ{>]u8qhѢUVڵ~G.]ƍףG7v]=݌s/`+Y ~aS5QqٛoyΜ9z˜9sJ*uznE}._|…6lh۶mq,hsn}~wYvmS3_R6k֬O)u+!k׮Ovؑyȍ7&~x cb,zQJpcg,7c X8nƂ3y//x'N<̅O\8aB4?OV6oYJC|ЬY3/O|.]{QX13N9]ݘ>}ҥK?^uU~iS?_͞={5kLIIYgϞ|JW'lҤu]Wjղe&rl8;Ed\ˤ#W|Q ?{wtڭSκut.QvZZgzZjj*o{^ᄉkرcƍVP$ۧLҷo_bŊ_},A~7=zʕޖO۷+W *OvQ|y:TXqϟJz` _:x`ZoN|T[ѣW91cF޽<Ǐ{<ﯜt9 `QFf͚~1cMd:m~뭷V\pŊsHWlٲ3fؼyJ*]}~;kZ!Aʢ@`1!a2JӦM3f̛oٰaCcǎ&LسgϞ={&LЩS's}ҺN:'Oz5pĉE-Z(|7nܘm۶|ʹ]X͛ڵAmۖqDPJ;߻wo^^?#Fw]סcǎCݵkWVVȑ#J*;sΝ/nذ{wk׮'N|> ı|4P "[!M ~"PBvعsg֭u>gtҢE֭[nݺUV;wSLYreƍ7nz)Sx'N8jԨԎ;nz衇jժumժU_&OL=C-ZԩSZ۶mDր.\xuըQ]vǎ:uVzzz ꫯ:99 \T-Zꪫ\kѢE6mZlYLAw]G]_ߪU+1~-zyw³￟g\}=z>|8]{O?\n_s5z{>}ڶmkNmgjL7xc=RSSǎk]V&"6k֬{Wl{t3O9$+ЬYo+3g֪U۾zjI"p8݄ϜƝF&HR X3 ij\N^$p7NZhV0,%%رϭp;}/6=c/;Hu&!X1ҋw6ΙB -.t{뭷 E":qhyp ZY<)bHZhZBr)gFD}0& -B+@v睪pP'jb (JM+ C -B+p(x oP~GDBhLa"4B -B \@E<Q$cP#K 1? 'B - *+HǦ?I /Q Kdja0B -uqU{~`D| 04 nahZh,CpQ]^i DP:: MƄZh8/Xa.,"2D@LQSB+7o8M߯aq~v}+}K` 1PC5860ij̘1cǎ=Zg9SqλZ8C I;S=yM"> F^F/O>w}qرի__{fff^RSS4h0q|wÆ mڴױmܸk׮uNITXD/b:uj3gμ; "^ٳm۶---eϴo߾bʔ)SN^&tV  9b7(((<<^رc"/u=Eriiim۶mٲ/+bR:t駟:Ta^ TUUŋ%Z~D)Ri8)*X>c/^h"ZڵS۵k~Lٳ_;H l*slݺuذaaÆmݺUl֬Y%%%_~7|c=z?nsovչT ~^&qϛ7z޼y'x'N|gΞ ?}pʕ+?ʌ^z7i&?55k׮d̙XhW: 11UV>l6m/***))={рC;rK~'UViK/1^G4%يb߾}iii=黦H˗/_l2!V޺f͚c3nkjj͛x _^_IARlSo&ky?~|ĉ֎kO?4...!!yPU@EZ|ڪU_t矗L:j=p݈{޽ϟ?oiF9y}M6XƃpYMZ"GJyӧO۷o{H#F?qĉ2!&V߼y󬬬7| ]0ur\jOuuСC_|G}$F!SN_~.]ףGZ3gNzzz||#L?xYu|}VNII1cFVV֍UaJJʴi؝ejjjDDDϞ={eNY1Zk7VEzzCPQ]9y)ҳ>пnݺaCL^ܹ;v;wr~ǎr%֬,r9tS O V)}j 4 (2|3r'頄#F4i'{k%&!Dbs O.+M,_7KPA u(5b;DZ/lno /(ʄ[CщjEu.>^ 3%6DxP%B~4""B*N գ-B+N Hsj{`jR=*!!!!0rD@F[ b4*!!!!!e B !_ P /b\3%'58%$$$$$ UZa^kC6s7r\%/2u$Bу4ۨF hTl%$$$$S"d\JGAFU)T Y-«Uoz֭5r%~ӐX~ 'dX/x&uH@'z=󜟨 $X!D-" tVh,aV7n>|xӦM[n=~B3flٲUV3g* >}s)--;vl|||۶m̙s%O?=C :t裏pI&,.CHaJ<0z-1:p>k^m9q?9r9yDdɒJoyo&x>4緸4quiݻwNNN6-~g1ωł ƍw-[r웦=AZhOe Ut`8 ˗/8p`HHHzxQ9lٲԨe˖[zzia^ө l$~a߾}_x;vTUU-^\7D8,K+< A y![BQLŋ-U8Ю];]vWfddL2O?Yfdgg| `я?xNNNNNN\\\zzro)**JNN;v,]V\]|W8pPqߨQ^~唔gy_Q~zSRR=BH֭ccc{ꕕU]]]!Q7dff>3Ƣ_֭[?>k,/g tRzfҥC_~:M6+69;qg}+Vؽ{+Xѥkٳƌ 6dgg:uW_|[o;wlܹՊ⫯27^|y5jtY`2j5Te@~ .P\p!((H9 RJY*z!C-y/^Tί\2###<<<""6h{ej ߴiΝ;RSS۹,'BFǍGe2BȒ%KN}݄>})B?y{9~}9`꥗^ۇt޽GgίZN^ziժU7FRJJ;Cpq۽tRe};oӠJ\x2hK߿$&&⦯`Eפӣի/`xxxxxxFFʕ+=>(11e˖˖-"b̐o߾4aUSS3o00^P񴴴 6طsu򡡡A@@+.,X`ȑIII"VWWϞ=' p@8Ζ-[[!qxl"jҤuЌ]Vp|||->sBg}֩S'^4hR.Lo+cui.\e˖/+t-r;P:2x7>u׿OSnnnnn'NX1۶m3f̼y5kƞO.O4RhH00ZfCR` DDmǍ+6o<''G9iѢJmaaa-:|?ݳgO|DDıcǔcz@;v1cv]PPGe-[r~vu%̙3']Mu]>>>3gܵk#GEh9DAO0 ͘,XO8n(33jxGyɓ'Offf9tGCgs=wĉuֽk&MR2$--xڴi~~~~~~0ֿvVZ͟?ҥK?'DGGX?ʢzĉ͛8qy'nѣG'M4hР}By}7mڴbe <;{޻wϿAAAmڴV3?$$Ƨ\ѰޔYƓO>yۍ VtFVu#<2eʔG}֭ۃ>h:u4hP6myŋ)NZ~.]ׯG9s椧Ǐ1x ::oرŋ_~evW_}uݺu>)"**?'|ͦM1{yꩧ GmWCH\{1V锚ѳgϞ={FEEyO >KII6mK7k?~$:ƕLoSRRg̘A7VKO=T.]F7a„ҟtҷo߮]6h`ʔ)ܹsw1w\;^L"b}Sjkh4zQ2/H>U W^{W >'b̘16%$$$#F4i { TBH(2|K1)BQ.V'*$a@3 Ri֮555~/r}r?!!!;B^PͮF)xIaF%.7nܸ dc g'I)qd|,XP^^.T2N <B8'RdYu#PӒmܸqM6mݺ `giӦ#G6k֬uO?t5ϬRB~駇z(!!C}4oznnn߾}/wdϝ;/v-66UV=_}W{iiرc۶m;gΜZG<"Θ1e˖Z9si?k׮v[[ v`f͚uq7%ᇅZcu|sɬVpiAuކy5i҄-vuGϊX{2VĆ 5Ƨ饚O()SvQٳg-[|'`\ ,7n޽{lIrqҸG=zQrrr֮]K룲= ueܸqUUU˖-;r֭[JkG\7ܹs֭l%^͛7oڴo/?\V{Snlذ!===444444==ʾe˖FEEEEE.[xMNNNN=z߿~e`JyƩ)!C8M3gۇ2Nٳg۶m[ZZʞi߾}iii`/Y^׮]io߾:'r͛7 {7nطoخ]~pѣG7o޼iӦFUUlڴ~=X 6o~S* OFriUa:I8rMfS!䫯c !6l>uԫJϷn:66W^YYYՔE%''Ǐ;]twިQ#ÎsSNݵk`26YXX_oݺf͢޽{r֭[?!C<#6lXlY^^GӚa>e#cuڵS۵kGHO>Je'NPgggy6N'Oޔ0$$$33g1i#4hҥҥKZ~uf4߮^:77w}'1e??:;qg}+Vؽ{+=ɉKOO_pɒ%cƌ!1"4Ncm ͫ :L46+3fɓ=m۶3f޼y͚5'7nLت߄ٲe˷zj_xExOKK۰a{~p{۸qÇ?/;&M(M4aU"QQQ 4P?!W^)--СC޽7nf?2VىNPQQQrܳg]v)_Wٽ{wϞ==oٲk7 Fa|||->sBg}֩S'A^4j?=':==_CnH{Ǣ nٲe=z/_aΝCMHH?}nIIIfbbb5kVRRJBVϩ'_Ǟ\gRi!@T>H8Q/3aL[GD$Uƍ,f͚ &,\0))=1堠 <|~6CXo޼98srrZha]vTԤIkv_>66600Гn޽[7|||x㍩S*Jk= .RRR-ZDYhѸq}zZܱcǎ3fyyyWbٴ۶m[l5JB==Oh'TݓS+0Zz sL-&F9س@ZP͹rω'|^y}M6xڴiZ;qDyyu^{I&ُ#Fdffkk׮eiiiÇ' 6;k ǧ~:`[AڼyGyuW{>oԦM;ߪU_tg'Za3)b}]t۷o׮]4h@F瞧z*..nذaqq IDATq3fP?ѷ~{ǎ/^/feey &Mz޽{7mx"}8WjjjDDDϞ={Œ+DN ԦMwygqqq#cu~ԨQ]tӧO>}u5hР;v/ʟ})..VO:塁޹s͎{A]iPgXL6W_}uݺufp=GÓY}})))3fʲosΜ9#F*{qK,yGi0) Xќ;vUd8 geȤֽ:c(K V\O6P:d9K׫mac͈~W:tSO񔐸n;k':bĈI&)T^^/ˆ 9uD/%#%H\PԖj+uyof-( U R/*!!!!}a/'ЌR ދH>I GC&&V<=nB\CIJ5i&( 0uU`#&\| va`(!!!!!!qC@ɻMAej?5E !\CxH T(ȺK/=~µn!G@B]$E^b,Ӻ1GhfPRs"ս5X̬݋unw&g3>J22n4L{ oX*`A"RŭwlX9x;N]R~zQ6W+րFB]\xqYsGpQ-bC}*5N]ܖWUz/?NktoFYznɗ?U׺WP!ww< nwZu4Խ |he7V`eCZDoܫuDldPfs|4֪^`:Wk \QU>YʘP~gEBWtQ4^#W|<"hPyR~%9 jMw|Tyd9h\|S$$g=qYH*?GȠy]Y~%ªJUꮉ &VYz~ިҢmQA:@y؎ a;hW=KP+Sl$g?z__Rw4YHhU;68Qk{{T&QcNA']BQr#!.BCS}G7™;Djrmj9QSAx^m•֬{oטF8Rx~WtWb\ Hnɦ"OwuMn~in~+cݯZG{wuhԹy#7oUTՌ'>;xg[B|'1~մBRC1mG٠Uq^.' ~kU5_;E?}8KZ%$Ň(-;0Str\69S6]j[L8xܩ a0ۭ'Lk a9uUuUF^ӞfʟIH/Wƴ_OȐ@gد/:ąuB%!dwuhe 1̻C#: k\w6`C[nFzܲwfCj?Wiilǯ/>ƞZ((~Ⱦnk*;c" ](pRQڈ7.GV~=W7 z}E!dM$7|ǯ6snO[G+Zh$7喏 Zg:a3#XBҧ}TLÀ7V/ۭ;E`v~I_tR6_CcI/1m2W+?)%{y.zeO^M0m/g۬p 7_RP7VﯬȦ_"pw4k8VqW@׬wޕ3dVzP[:OZCDIXh4kToާ/UV&rX[E6/8uQy\APzO>Qa_{lϕc/gبIDѢ ͢9rk?]S&BH#]4٬'Uu =Թ![%vZG.~".8wܥ5 5?f[Aaڦj1!l$Я*՗*_yL}w]bG\]p^sUێ=_Y^YmbCqAYEUM0طyLNi;XU]S/($(T3 lrʿq&bd&)8}R9Sr28@\5=?w쮃rG{.so -1 }]j96P*LS=!տ${Kq@)jžrن=:pћrNVkIReTCb".*镦<[^xm{i{[/'/9_ɶ*Z77wbO*cŪWQ)7AG潍??6 n\zE7.=fק~k+55H*4e< ӗ8~r[TӗME7x W<_;mU~uW+*M=8~Qp?6{E基`\+~Yx.?_~/n0| T5%!0 Hx$DFzugPOU5:{ gsh;?_xRh_r/?rWWG,1m(:_$bm @?ڿr~׾]'5Ƨ\Wk;klY0ŮCW֣1UJ|ZGTTU;uAxٸ~chMQ'N_?vú7ֳ%[ڪ%lㄐ@%LZGJZ|1!@=c/?1r?B3wz/ ug Vͱ'Ou/?k?}F vO-⨷ m7U;6؎񚖍C*j8g?8*#Dc< j&"/KM.ڳrftf .T/}WO.:Ba6~>zwwxdIIO_y羿=%طBՆNt o%esV컧s_$\7_$Խ--_8TiySݰĔ|Y󙔻CN-G^n/xm/Ca&[l9M~NH|!lMYZU;n)FP[BO^pDY}tM畃6* n: k M}'md[B?mkktY n:Gӟ=B~zE*hlF76eՎ /`_gCj-AU VE I!G:B xE#"1|KPHHH3[y2yOv%L_ZQ 1t𑯼2եZA@̂ Uf{ңedx΃%r$$$~U^Q=C4U_FtRRmk,?!ޚЭ2C'%kTSSdb|69\.HX iJ.zH#*{!Q$*>,(( ct) ~VRI\*y YьD!l)JHHHHx`kŵU^Ӑ  Sp@2<4!!Vd\z%$$$$TdcDvIq hFJ㵣JHHHHx!+V `0Y!jf) JHHHHx@2F;%$$$$YDW"@!M: B^l9L%BJfIY' g(V0^eL幮7qA(LyB{/$!!!!!EPec|T AE"SF,eB^)JHHHHxh$3uQye$ KRBBBBBAFGꉳ5!Plҋ KP%$$$$$B"D16XpAd_8KըwI -e6_"1u13R>Ѓxvp)T`~b%$$$$M"4a`m`-MAb",JHHHHHhyH4]>u8@ WYmk!m2lNCAq9uϲhPBBBBB ١*ѡ Z-Rx kEi,i5): t:QH(!!!!Ͳ;F5\rP'ϙJ'!!!!ߐw(:ʆH|k?%$$$$$n,3I%ceTJ九-JHHHHHx,E5$AͲMYt[@ ^2^ MDE 09C @ t=CBBBBB˸ si=%Ad'6%Ie~5 /b4B6?ZСT1TbNvTBBBBƌ4T23$*.3Rȁ fE42Q&ݖ>7`m&J| %$$$$~{5 2UPOrj{-RfR @h|`.p2H%$$$$$V3-)_jAAPIN DUBBBBB siJ|M>BIHHHHV8.]>㈨%ZAMtt8Db,Q !VXBSahYR6je]IP՜ehR5S`A oLP+G$rP9!"簠UHPBBBB L]V۩"KvQh JHHHHx80)!I(#3[XI,Ck}7Cqe#y1+t2U RIHHHHH@P-8&QČձr%HPBBBBA'Q0\Gќe+! 05,`', ¥l4-"G`=I S1r3=|QHDž>](Cjϸ^ߕy / (, p"h7 8j5|gT߶j6^TjB0w>"jՎ" @4L͌Du5 e;kȵ`6t RG2d^ Qȶ'Z.׷>ZŒ*r58?:,0 @OIP!N6=3z֮ȭ@,4kkfaO:(K B~> +O"tp729@P=j)E@#&*0 :?L9P?f]zf+׆BL SB̦z"~a{ZFh~paPLf Ծt)!xMZJ<|6|j 4E+z܋2TL-D%/61YJm"!q\-Sm)̥l@u?l'Q GD`B@#g919'QSΰʐv~Pbj1-'m ^=[O~e~Gj4&Ng~hIh"@hg@_HUn0ߛ%<ˤ zug5^0١";䄨"$f|31,w9ӁW \j Ȝdp4OeK֨v\uh.EHR(ZnUzV ,jkD',z*mRA ZD-'!vM}bшEDCBY!]0u^mT$2\Ը\Z k {yHmDD]Cn{tDvUO]HXAfIl'37x4"^*bZsg`au`IąLuTA| 5 CSt E8 3NECBv.ִFx+[y~ $~.uF5z1"䶀OFy%2lNTQ)&*(#&ДZ qUmoМ!!ġkN k:pXʶ&:΍+Aݾ 1~,0(+uUizVsK8s**v%hNeܺ@4Dd+.G6F3APZ۾N; Z#hEY9u%TL TNRՎd5f2UT?±)ℐjToa=U AA3P 5>OV92jnt(`pyZ4ihEq[(P[CBCUi~/aq@Ǒ6Ȋ^kF9 3@UHnV B8Ap4ה ZPjf!NIcN,Oe5`D"aF:z& Zs`6h+9rҕB ZD [Df g"UGM(wjFF *h@3VMԴʋa5(Hm* !2k]@@bqXIDATAhPjG߳U_ IFi-ΩJ习|L 8d5HLF/%-4b]0 C l6f: o(W %'<$TԸO9]($gl ? C"@q`ԳvA i|E5G 3,O ܖSߺ^X/QKUmjR`K T프Ld"?HH*"NA'.LjhfA>bf0 QG]2d! XwbZ]`݁t[y@WCI헼·]/z`Aql6+,6޼9fB"h_I#|n u:Lf}vugPl3[ p#Q֌:fh2j@1Z\dIi:)pUZ\NM&@AC.e WCNE]Kծi:D o>۵[B} !>ǃ#l26S'ZԼ^TGMm%P=)7kbH%Rݨ?)TI4 r6p,I}]IUx q^ Q%sJz¡8'\uaa01u {OB2VUM}L9;?G`5 @[ d MƯ_KSrsr݇ E#"+3Kku30n2qvVup Gbo=_P,a"&j4%7],einTW2~ʜKŃY`) s%p:(RM u14xXpĞxhPR^, A,H#I-T $nP^ג2AI8DA2su7pU:d5/iHR^ cΫkb`v.ԭaSYurgLd]"‚_ O)B "9~EnTԭ% Lu"8(u8ũ͸QL0_.nQ&4H.27̏B1 ?gyFHi0 t?@@=,ąbH8R 'oL4;G^Jvzr 4 >e͂FL0b 4q)2x3_Yp@AqhqnH@!|D&089kp9|f٠1rXRb2(Tp,\#Z 8k #04T\i@5ذqwBeFK%&Ѐ"_Ss ǭ65j"Øٸm48 >h&XՀfi4> E 0n a֜ ~ӌTgh6PߒU,kC<3 CX/PQG4@3:+t1ԽxD݉:Opwɶ'K5x_1l ͔Q.'ilZx\D|q5#S~FtO.dnf`ӿ-6~Nq:-63WG?!`o2:t+͉}JFu'u5vn qpd_]`Sk S%wAE"'+vmf28BBjTgy'i>@w%LL 151@DE+Da ;B4K?i?_xVvdB]%{h'2bM7`P3dUsTH {?#bJͿ> >l>y,v'h}QF$r(c0߃űqf90,vo|@gH ,z>1>N~06gBKP< G6((6r$4weM7 h> XNp: bn%-; (h#'}hO"P*ȩP-vĐJ_,X@a/f ʐ8qS=VH )cR Vފl`KH=\Fհ$^J@(e@f}#!h4CBзĜ͚"GlȰԃ~@H[)9ש'UAACd0K5'8'pKUΈL|,ЕȌPYN&+.hM.?^hÐW1QX_H𹭁bh?8$nJ48-7&4DO)& !كnLR Ctq|Ѹ"/rqȧ83YCX΃.Y0OL& 1ax< @B@ eFK Z0&T"LaTk鋄x`o@AE[[P |#.EBSECvBeƏUr\.V, 8A|]Ŧ j70Y >.%P-q`slX32>sQ,o)l|YF&bLrki>9w I|f7!UDu>[Q$ZN#*R9"XrZ`.Q^ii\;Zl !>j"UPCr4HE+#Zf(pOl lœRwi\8{-F~DZ8Xs==tك>*Zw(&ȏPPZ]B XcHn$)85b {H\צ`3Z`Qlh,{=Z#9Z Y'19n!M@[1iReV$AncjdjA j@/d5#+A_{Dh!4V G \RZf=AU6f˂)i&E&地--# aT! 9Mhmt1O*0)`}\DBj.6 0qG{ etiZMH'g^.!1*"qLE󵳻 _4mSZ^Yw{Jbo)$l10g">b^s?jdM{Eh8BgɔTL`T3YY.V;n1 1kP::>FFǯFc\S% Ҭ'+OPu=4 deD5(U CP\uz9fs]|\J_ve G)4e XiC~a XBm\yj *ьj4ʺJT&i#Cr`!8|aAioTp5$dL$yi&.w /Fs jj̤,!P?GHɲ~i0`4ȂIr8>(SH5vm('`eA3 4sYB59,+ᷟfiYI+ Onp"@ԹD3ut9=&"' #[q8JsN%!W6L݁d+.M?v#?AÆHȈ#JZ9ꓣ!G:Zcctءݹs-CCCo+((t횪ʊmھG^X'hѸ>ļF[ٺ{Ϟ=oY2~I;$q W 9ׇ;[m߯u{衇*M \}r4h\b^rt"bhhZp8k4OCr$$$$$~ϐPBBBBB2B 7lrm9N9CxWQrnz hXaԩoދ%ƍ].Wvπm۶uyY3O=nl5u]?jy~~~gW1bDddd```׮]?䓺? `ԩSrKEE=3|pz\^^})/{J^ !}s͚5W)7n>zh޽y䑫fMMͿ9s,XƋ<ؿ~9s&++?[S>>>77)""[nk׮U<}ڵk?WZս{o{%{n֬Y̬YLB/>rȐ!CBCC tI׿:v?)no[tttppC=TVVf8}s%$1!!!>lnnd "_|:a„uֱ꫷rKHH_r󞿅1eʔcdžv?V~tO<6v5]q!JH&䇠+;jY(P +:[*]cmש3 -TB D ?y?^癆H"0}9'އ1O8 >/_LLLΝԍLϋ/[Ã":!5f+kjjL&ddq;<2 v ^^+2lzz;ދJڼy3Qٲƭz)̮:w7 22or9ޮ^tI0 K˙3xxat2ª38p8k<_>7222Ȁ9_+i7^(SD7=6:IK;866V_TWW_VMsr>/((8 eeehfwas쑉PWW{%%%L&/@(!dt:====%%%##N[9r$--G׿l (?z i4`Zb\GG ﯻrJVV^v}h4uvv.Q[[o!200@lԱR#<<͛6a5X,[e6T>!nnj,:!5#RSS+`&TVVzzzRmHDӋZZZ{d"_R9PVv ⹳>y2{||,;;n4/_NN+'B^bq__G&P7rJ-$B-HsY0Ovܹ!f GD17\NI199xm[~ifD;6 >Z~?Νx'WXXfmpH+Wܸq@U  A=ɢYw6`x#l{p^  M&ï>m ݗi쑉 bc|}9EWZ;vZтj vS/A;|[uu`bY1sq}NWC艊~߮FLLldddTT kL3BW^SCr:?/7gd߻WRbԘ;x0bI!`޷؉p(D099gϞk%Rgjnnnp"ĐHO.}Zk#j،pqGu_D95@ Anp^5@ '&BO\.eppl6 xj,N0OܹV}k_Ӑ gj̗Qyr/^&ޕq<k|:l۾mI5@ vz}=PtOMN/mf~bb{Xتլ[];Hw.Ƣs7hI L&-0=mnniIIMo xj@0!kQ/IENDB`barry-0.18.5/doc/www/config-backup.png0000644001161500056700000013550312242254476017072 0ustar cdfreycdfreyPNG  IHDR<6sRGBbKGD pHYs+tIME %&yKtEXtCommentCreated with GIMPW IDATxwxVE?-I ;ґf(E,,V,~k[Ŏ WY(* H^B%$H/o{x\H]]ys{3gf$ᑑ!ZbX`ŸRzZ//5c$GT+^8-G{.] E. , K`@Tv itYE\0'Sxj]K7<22anѥ_XX]T8 kNnSQu īz|I%LWѮmjVVbGaUsӏ?#+{m#"غ;YeIA$gx@I @/ OLE%8|V*2dz>?8︃F5ckFiY"ˌ9س+VMyc@G&VV3n'{@G$pa 4~_1n/EAQd$I"0t@7 !E Hu0H v׋_? YQE뺎aZQlv>JaɝYF[RfG7)9}> aXw"IF_U$<>/jpYP%8/ j%ع*ye{Hbлu,"H9] 6bo0xg9Qo@p:(<3"6 dTFNag1f#2It EM*UUEV8B+ĸtᯐvfnE4hс6MjRPݙNR)N"hVnZݻ[D,WoOH^2$ Ys<5]:5qIguȲLWSZ EknBJaa,\݅4L $+kuTf(& GRd~?^MӐ$ ݆nGUU4MA=NQeߧ!m%2!J1jnqVnC%dYywj9fEQ4 ׏d737`ü5}ݎŦ먪ªHtt*l]Hk0ɜo>6ÎnGeCtv6UEQ]k@.IButt!qX:gfә-:u!2SQ)\alzwk_hMQJ4 t@ ,=~yk38ʅdlį8tC:g3U"Ll<;;s짰Mbiݨ*vd߳6UXZWnL"ܶ͛)v(ލ0{_#|woc4\N;$ҿ{'taxzի& FͩlTW5aap$5j\$[4Qx$=Ū{+ r OZ HSYݼ3$EөmSjE~S9m,_-c_[l:\׺mOVS2Yy/9Ԭ^mHs Ow9 ^MyD:jFӎp:+p4,Ub~u/L§}w""#ܩ|"Nm]lۛ{wSF]Z7"J iyLx -,5p]fDu-UK j0t`=д&#^͓Z'0[v^i4 a\J%Q]ȡIuw" Y :d5h #T\ˆA7d2r*ӽþoeƺ4v`plfmGfupsŽ~^7?/PFbϻ5n!y;v/HոYGpcr7~;nIvN6!F.ɥ{e:$ ǝyM@Q`Uf3Rl$99<=fyUi\7a!U~Z^z9V x/}z\ۼ?eF,ЈhPm S次Ozn06 o8t$G4[ xL\_mRTKp6\hylw7 s;vfe,rqQԩ^SyeVڴlJx ͯYr^T<~Z0tJBд7 A\f` @p YFR$$$E IJRgƹ<2 fHB޹ eWP]7fTʕ"y:ͤ%xkݥ>: =iH7H1os*oxN@xo}6oً`7wm@cx~Bn֔okβ;J<0GNozZ>6q/߂8>>WOkv-H7K2Rat7FAŒqd$c@NY?cgP܌ڏ ioÁq8v6'ox5}06LL~q+Vsݵ97c9i;g)P*1YXo%tԯUo'yfp]<:j17= 'rߵٔ|Zc2C<$>*E"5}FI2s5mO RI:$C=ƖHx-UfȲ*_UA3tAaϏ[e2Fjz#p{t>"áB/{ve7WP%Tb*G9hҹ5mZ5ɳdX(6` zN 7gϗeQXLkwiT&6!npg&:bsDsu=r4Z%[&Ɩ:@N 8Uujr仹ƫYk$Um6khg%oW8z*qQw6Wv;حpd.tlY|AG`Sh۩NpncAcuɳWF-KNvlw@D|mfN 2əB..B p:WHOJz>- @3@k[%Ib"H{T(!KHSD`=!|@R$$C2ǹ{ Y:Y %nSĸF|L@!L ߿P=7;M .4 R ╛v/bbcH9ݩ2l 4\v'/U?4?۸4@|OܻcjS8}&6Okp}$6 6N!_sR-ԁ,l0 *sqHDSӫCwh @߫qcz4M{RhPlA+vnE[S-.e[Picӽ'ޮrQU1J5t JnZB&aTQ M |':<ڔ& C`#뻸<dU%@NYQ9rUdǤ%۷<ޓ6݆y@vTʥTZCMu]ב%M p:TTbb '""N'j%rs!tvCi7ڷ/^ fӭ}3B">Μ5UAc>BLl GNP㓅筘 }|SI%*2gHW(g~tf8s6Π_ƴxvo"$p*-B1n]ECFPDN:4Ζ='`zzaI9q6U)W;e[Nj2!խƬ5:v)-:/NlU(ޓ=ar6lBeg1s&d&so9Uȩ6g՚Mz]c$dʒ$! ]Ӭ1~M%ˁE'xf`,橏lٶ! D_R ]אR Bgt!+!sn)d YPy pȿ!Bb8nUZ]P'!2mx|͠7f \UhV7#4c͘g{c$^݄g2[ b=u5m5`ުdtm80[+8N07{O`fbyk>zwf10/_ᔀJ\3>#Bm~5Y~4e%Ls2^z<)g21m7ٳ9tl͓Х z>ͨ+xkyoH9ΧsSP/!nԌG|nK(:"F<ыS?> 糶ҢAu/=B}=GbY3}5)U~/ ?lj%"!Vbg@Ԋ Npw]\BP$)moмi#x94Еm8OG@+.`ͽ*`Б0@Fpbԇf؜5 P #u,Ps!mȚ_T`Pd!Xi7+]0իE nA#HV#{ӧ5mو%+7vvnЋjq^ڌoP;T;eŸعm/n˞{Y=ztiKt}G #Z9HѾucϊu;, ,&׵yHL& Ч vj.n+ӥmsZ4$gXfORZ@b*lJ>ȜEѣgڷi/"mߠ[PeXe/6_Lj֚9W]#YE|8f" $q[nef^4]q⃌DۍˮlHH躆#+ %aFux>r<;šViޓ/<ͬEs:L#^@+qc% %3=Ett8PՀ>AW ÎnO54MCtTUt E4Ԡmiҥ*w`~^׋릣5 ͯpA`O 8vl60z}Ag]TMp8PdC@~?$la'fUUQU!bÎaG6|kx^t ?O}FvYivUQ*6jo\>3tjWySR5 gĆ.O$ aXɃ>ޣDZ2dǥ4qIA Zis]~U>矟~(.]4Naaq~}xPau~.\4 *"T+Ls|eZ JyݬX8+WR)*;$ <?1QQz}!_+Y 7 ,W5EE>Mmloӓ$ ]'" 9~sPqO"ZJK.|fQڂ  HP1~0YB%HisD!#!PԳ{[ ς $ݶdҷ#eXWUUb&ȑG\\gׂ :LӧRq8U,X?WH.W`La ,gY`,X`bx,X`1< ,X ,X ς ,g Er ,\&~sdܜc8S)ɥnuEǕc g*o~iAྎ4f';+7++*:‚|#H9(-xtYyl65p"Gׯl#ʯngtt祠/5>Uf k6#)r p^@Qlf-7*f \@[|3iS`;.h^u 퓒h~YrQXG-HHRRm2Oq=w㈉TDLlsCq0.djKHD>[,! ``e.)0 \!..c%hؠ '; NhXs~]JZu]؍Zn>e^FjԨ!SqQC_cT8'ҸQ2}|>ٖqSoOqMEUe>/,]99!ʴS\!**gaA>aHbQTTDtt4u?~?8&%O^zyh<~_e(,e‹VB|3Jc+ ?/ }^^/a mKT}+F^nQQfEB<_G³:zӧNi&M8v/lkݪi<ݴqi')M72,]+pcVrs1 y"~i`smKĵן;p괩f>S|ʊo HDEGm6|nj7ƚq7jl;zݬGXXalټ:uӻ{ |T$IJDBYv5]j1yHh6?Ќ7aTTK%Ibؤ1'R$ L͇uҾCGS-(#?̮BgNztq4i{#Cɴ4b3|h8leg)He##`5u=;z޽+yB:O>nJ%R،3xŗ9v2ƍ(A 7@lL B.^D@RPe_eJa7|3?̌ ހDFAZwT*ݻd !8JNgsfaC8r(ЮK(zBB9~BvL|I,X@m(v"`3w2f7(6B M^dmګf|UU9beKrߠ߽zW@{tƔɓBf62vI{^,ԫWO&Now{m};@~}9}: !}%==nEw%smh!7ts`iܔQ#G"@G/dA?m7!Xx ~0ɈBAQa><Ǐ >* y!i'zb"ԬU}L9,ɝO8A~NY:  FBSi'EVfSX/bA"$֫+'Dsg;-D gN@|9 kNyS Hx}^3Ni m{ !2듛m'e o"v.ya]IBqwA7 IDATm[y-[Tؾ]lݼL?~X_524j >r%VضuHޱC<7r~}>]bْ"-5L#mݽsX|8|>Z51~83NĐ!CtRqi3),!غy7!>A ~`ػgqcM<|b !YЌ3e24(C2) ]tT7~IC!yQ&#Zhi ^1gsAt?X 7 ӭ^L#}tXl{Wrc o35dr.Ylnߡxg.Z(r)0xu5kւv+~kf? ;3WJ'!aSUר'Qa.};ܜlšEN>jW1 #~?P{U4h1j$gNNj;`W}<A;HnҲA^Jjj*6^}:r)IB4о'N <4UH.)&,EC-%q[xX8*aWtՌswS%_~Æ M6ZB&OāqԩDTI{}xiۋA+.* ew -}+Wz)RƶgںNJxgXz'33T }E^}wR.YmEۯz1)A]X.>>Ѓ,*UqƁQ Tm-9v8ժ%2N\q4dY-*(߷}e,YYؤQ5mƀH޹7СAc9.]qsٶ}7o_noP_x(""#X$QtJJGXl){!yG2jԸ n1380j'qٹ{kׯg?mj19*"L\! q!6u@2ʔ׶M TwF /S{FQ/4O!՝./.>N!)rBѪ -B I[?xL*BquחgWmB!<3tyI?cϘ>C!DXX֩e n0צ]3~f?(>0\5emۺ9QfXR2*mVfy=B!: |K@5B!^{uh< =2]| }; { !B!za s*+\f.0?]n{Aݾ<6`ǣ/x7B!14>ٖ/4q8xp^{Oݪron1 o)a"p{r?orS 0˫8aa%LH^<o:|>/'mNn ǼMuZ kn?Lo-t,bIVcᢅ%ȭ04vlۊ04Y{!7bp [* 2 ,g klxT@i:G:[`o$InHBPPXfFٳT8i,Xs,Ihh8{w>"''h\!a[*qq zA~93p\V/X`'v n^d=KQhSmҺ vLVOX`dYȑn%;Wt%T%Ar2Aک͛7$dC(,t{,X`Yf*bR|r8qBb+QTgy[8N]U>3l""m  O$BC9ؤaCfΞͰ_`՚>zܱ+iGxg0 &pb=bw,XbxɈwGҤQ}E;߽;Y|1aa\.BC/(d4߀˗az:otѓ4kbx,X10~Z/'MF_f*HHV8CC8KJ Noh4jЈK;8zC \)(IHEr!yiݼ .IEɩ ر-[3kwDFFPFuvO=2ɻ2\ݩ+[n +; /77G˂YҬisVI!2. &gy(.頻Qld"x>OW͘<^=zԮ]KDD8)}w{̘>~R24Y]Vi+E^n>sg%KED`NӦ-p4me&Ep~Ǻu).. DTdmvZ=C ] ]XF?8OdY&,,#GR%[ny9 {]MCG Clݾ3uȨ n:g$d$ϝChDSg|o"H=q _|an5Unٳǵ<dBXj9?w=7^'%zMK|%3aJ-We^ "-_$@ \2oNKmE8GwŶs!ص{ 6]۫ٲ}#o\Cu d$I \Nkg֜|v@Fvw%?(..(,,4/!::W(Br.aIMM%11_m+)8s&>ǘU_1؝lFtt4+q*tBy76&O¼K䒎; ܋[+TfK}Ȳ\#IRLb29e_ƥđeٿ?>.$ti}4-*z.NR5k+}Q-W^a?_-zNs 4mXwq;gD֎$i).*`Ödgai'h>?Tv'0ӪU+DA>b0<%asssywXr%s= 4B ))KӧO'**^z]4/HÆ y̺4lWI\jr/aIII$%%Oy衇kLM {f-3qDywu)b"*m~~.ںU@d]q:"~a$$T!O0p@9&s9_"2zhFj wm:w".&CY8{NZ LQ^/tޝ>}O< 3fLFS(NEXz5ݺu3jfJp%yM>#G\6hZRcǎ_zjݻ7M6eӦMbҕFEyHaeҖ=, L&c]CE\5F~~.bc)Su]ҿ%cضDZz*GJʜJOI__8kVqFX>L>7whhbyr ?ݻͬYxW裏c̘1f~fݻw;7iČzj3|Ϟ=fxd̘1 8𜱻TJ>q1k,"##YtJ=_*YG.]:t(cƌ;v_^vݻw7Ç'xܺL03hР2ZHHHz[oKrr26m⫯ى\R+-4q@kϼyy'}@jr2We9(vW.u$yKSNm:ul4ۈm7[ҖS̾}.ou֍Ν;# ??f͚gKp-PJ?k׮滦MpBVTR% O?dJu%u.h^/[nңG+.IԸ1FQF1z.99e˖ڰ!pdСCs2y2e-]'xŒyfڷocǖLՠVزeKmۖӧO^wJ[1Mm^I8bb* Y&.ǵ0y Ozb5 aaԮQ*Uع gиaר; OF&XiqI@ll,'Npq7nԭ[#Gj*̙XhqϚ5~ngvzNzgΜ ƍ|~@ #qh"/_AKIeW /%mKpݑ$sFy߯wv /J5 O<$3fL38s,*WܹIKKc޼eZl0w\fΜI~~>3f| @zz:+VG>_%}|r,XHjj*zHm¤EVn+7KDDvvlʴgrQA֮Zaƛ6iS'N$%(5ja[ljUǣ?#& [6 5b73eq]w"sGl2K=08!ԨQ+wu;=+V`dffJ?Oo–-[mrug~(^oQF&44RfΞM7Ӹ\f~ieG{~IKy<; {f{ҥKg]yL4#Gr'N0wӧO^x2r(((`޼deeѾ} yy0l4k֌jرc/;2~xƍf0n$k׮3ÓPVmZhIBB~o^yekJ*# Jth߾<0 $::  *lY^7mڴ I*%'J+!4*, sР{;w>N]vN1w<^5^53}r>|2e]{,^> y֯]hhˤI>}\s qqfڰp q:]݅8p6m wwh\$ /p䙄,IvaЩ]իAVMߍh/qBedbPPglѼ,PC;hxS7yl3=rHZ4i\S^=4M+c`޼رc;3|7i$RRNe/_30{@UmL6:"Iׯ2A|^zof=H%U#GQƆv9? Co m6{Pa*Lw.22>E֭rsqr0W~J;Pm^{ ~M3k|vB]ٝMv!_ I4%qY(vF!U(EoOMQ(Cy C# 뜼? a 4Iٳ& "[S)*"#U B:eM6 jDйrə3͞}9shg_M޽I#|⠲d%Ib㈏cUTP5fp;TP|y8I~;I_MJ n$4(*aawpvva԰aLzDaЧsIII )S*L&&=)\oQ:9Op!?M]{(],'f.鉇89لV1 >5fj3Eщχ E,H^~\\]1|ܯQ#1.߭CS4 4|YwxiT.xf'''͋ SRpvNHnŊq]PZtZ-(ZL&3N8;?BƤ#fGS~3IA+a2qqq!99P߭>mbY[TDb4(\]]ɕ+6 & VE5[Ft:UhIc-l0Q4rW"ypHLLL}DKpp0wn駃Q))zTT (7}Efᩖl6c0(p9Zy[f3f} Jbf3^?ZCjL&E"IU])B!шl fx.% F;q{Y1 h4ڗ|t:^_\]]mI$ut:T A6͖..ơhqq֒`zZ!x/1"ۓH| "׿WPxO?45CN&Htl㳴t:qlxy+T$c}-cN.6irRj&ѩIrb:Gn޸Nv))^_Բ~:ǃ8Wwqwx|:QwowC0&?FxQ^Qc %95* akW-"O<|@)Yɘ>yB\Yv-֮OB|Mbg$K-' q$''7G:F|UZu2Dafrc aS= #&).@(zyн[waFÓDQ@%EQ,筚(t:ZfZ#7;ɈNJդb6e=6Xz&XL3L4&'x|2cvfϵ;4&swgޥ5M/<9% kQUE"?9YN8O_NcgIt:K^rfUEo]8U )92֬Yݻu޽on^tN;H"ypvux#$:)F^ D"HЧINJ/)% ?0ÇvCBB^7$pM9g„FRrxKVV՝;Øh  zyf:t` 2e++WN!"u&=zUv?q:k1,>q5kg)\0b׿>lqqrv̚5<==exyyMhZ=D4}ehтÇ'N0ev1oҥKTUe˖-b\R>V͚5vr!/@>}ܹLeZOڵr rL^ʍ7pF"o޼ܻw޽{ܸq}ЦM<==QU۷o;֭c̘1/2eө8x|'` e*wf*UJϲe`ҥFݻ̙32dΝv!_~ wY#,,}vyiӦ1`7nLxׯkצe˖ԨQ~۷oOTTDDDбcG\xq\]-y=J"EXp!;vB3ެY39B )AUU=zU{qqsdT1$P;2蓓>|Æ cp¿e˖eٳ:t(nf93r.\YbޣG>Lz4i~)[l!00ڶmѣGҥK> ɓ'_۔8H7oΠADy&MP5jԠsά_:i-ޭ';w{X:uбcG3f sΥ{\^{uqҥ?q""5kȴm۶TRgJJJ̓ѣGɝ;wX|1ew\!1"#()xFA{˱`,X 9cLХK |ǎĄ DTרQ#8u...(BٲeŶv#B -իWTRU8۴i#Yre͘۷dž xb6m?>۶mjժbdoll,+W.f͚%ox6U 'E13I+xyyqI+GRRNNNh4 &T\r$"779ݻ햷jJPOEW3=,-Z4777>}nN#yw^&HSNoSi)Ro5jBGlۼSI'G'Մb%JH^&h?`471f?=L ^V]Z-t.B"|eH$Z)x?啂'H$R$ ۏDÆ =z4ϟի%sȤI/?ĉ޽;vb6 &իg$Z^jUQ(Ν[8\rŮ{HHMի-t.^8^^^+VѣG۬9s^Y7o^ΞThh(dhݺ57oޤcǎ.]]vQbE̙#ڤe˖b'N@( Ν#11Ѧ-6~MWVM;ydm''Ɇ/+VPV-Ξ=+'֮]+,CTUrcǎ+V UUIHH`С$&&NBUU"""]vm'yycx/!ׯ_h֭[?cr9ի'Y>}.\@ey0ƍGll,)))ܾ}[Ř1ch۶-M6yr )GN5uT֬Yc#&L/`ڵ6?NNNvϽo߾/^p._̣G(X`כYI:FkWEŌF*h3+CP pj48g? E3Æ cرʏ9B5b}QHEf͚bۘ Or]FbDN͛7%Kb2 Zf5NrW^L6Mt˛7o.=sL}[1Sڬ2en+&[۫bŊ$''( ϟ`?~,9q$ɬ$R& -H;i3%?<,EdʓX{.߹kw۴i%".]حgK]kjƴ-ZṬKL,WFe̬_~YuܙΝ;g(IHNyr=\Oɛ$|o}HC 5&!!kB0 v8j+!L"yɑ -Z#Iyx=}l&Ǐ߻won޼E//,X ^5jsַ~hd)R7|ST9lǠs}ɒ%\rÇcm0dF͵kx1{}Lhxyy… D K?c>rH>3ٓ… m,ŗ.] mʭ eϧtbyϞ=ʕ+y1%Kˋgϒȏ?h+ *U6l]vn#sio˖->}Ɗj}vm+oM[:dE IDATup: gǎ6ЫW/ʛ#<<oɃd!Ca???\" 6<{`ʊ+ȗ/-Z,LV3k, Dhh(%J@UUJ. ]oNժU1tڕիWĮ]&o X-[os &DݻϨZ*ݻwIIIb]&A/;#Ο?Ϯ]IJl`РA,nnϜj۶m+5vX&L@5 TRFH7PJә6mȳ6y5ז-[Xr?us綛5<<\Dc(Jn™lם`С\z7n:f͚%oZ4k֌2ePbE*U3/_FuF"El$$$ f#ҬY3`M6%66ƍuеkWʖ- X2"λm۶T\ӧ ҭ[7Ο?O"E(TwޕD ^6F[\=r}ܹ,=J>}ȟ??%K,cgV[rEmm(6lGaW^c4Q+WA{]pWWW!r۶mCѠ( _}n^k >ʕ+( qqq̜9Sޠ?|hm$&ٙv  G5=իW!wۮO8Ӿ}{Q^h ٔc̘13&]vk׮6e>>>6c͚5Yfb_ͰJ*M{^*T4H6B#22 ggF@(R4@6D"զV-Q/<ɮ%)xD"O"HI$yI"3~)#Gd˖-6o_|չՎ*l5k.\h W_}%6iw-ZTbgW^6iEe˖b]zbJFQz(B߾}quu_-V#FnnnDEEٜ˗qppuƎ my߾}yb}7NESNb{Y@L&E| ^R$cɔ-[- &*T#FG<}TD#Sf͚%ӹsgnݺʼn'Dyf8|2UUѣ6:u)R&ׯXwر?4CgϦW^b?TUe…Sn]QŅGwyGZYf 7u>{fӦMmeܿ_a moFJJ( D  Tҥ ڵkB@8%? 9$:hwbgϞŜs˖-)RE2eN8$4i[#]W{ԨQCD?ִnȑ#/^ooowΪUvCCCmxJ,Nwܱ9fΝ ۛmۊlsaС,XQF? "߶m[ܭ[7 dU@\2-[7 F>x [.(QdÃEMrrrD\]];8d1b.\ʕ+1plL <'lاO&""ggg<==ŹWTI8Agh]$JVF^okFHHǏlٲӯ_?!u!00F<]\\0 b9%%,/]pqqɱ'/СC)S\\\pww@O(Pm۶quhӦ Ǐ5JX}Sf_oe˖l79wyrɫKQ6ʖV vmNmI$Lf>>ܚ>V%J<rM͛Ǚ3gD޽{xb*T x '͛7uVٽ{7'Ovðaزe zO޼ySDHК7ްiJIa#"EQ|Hbc%‘#Gll\]]Eo׮] :TԫTw"E2GZG_@c̘1Cs``H|yHIIރ3O cǎTPEQh)x?@m*xyy䢰fJK x"(ʽxHorbŊ6<o>&[{ ÇpBƍDGG?y:#Gr!?~LYzu˗+WepԩÞ={XxX+~m\~=C<}TXKIҠjpO 8{pp0֭PsN>LÆ K]v-[{իSlY>3^{5b|ܹsE79VRZjeU}6=:˗/ӴiSq-| J"((۷oShQ֭k7?HI; &9LZs"5͞KaHriyf- 9 9y}|eI$/9R`$ r O"HH$)xD"O"HI$}*\A~wO>%<<3?yH"##m񢢢2Ե#]&Q~EkLvS/^DӉkb… v+-QQQʬYg$R$.]0e.\ȼylD`ӦMoܹsgggn߾ oI"E%W\dh4RbEϏ/b @0rMё>/_>|||:uGחڵkc6[?.]4;w@x{{Ӽysk.1࣏> *W_ ___J(A@@^^^ 8z?~oђ%K?~sF>>>>x{{Ӷm[!̹sH" gLѢEINNh42|pyJ֜ V]|qo޼iƍR4&''$ }ׯΞ[pzgzdر☓'O޹gFiץuxǡCo+Wܦk׮"O;G $h߾Uܹxwppfmlk% 3rVi~~~lٲ渋-hl%=nnnl۶ͦl6y9ҞNCd{aaab9:::Ci/ʴ&2ڽ{w:ȧb-׮]NP^BVӧO~M6xxxp}lofmԩԪU BCCh43&sI--; DFdɒL>nݺ%j"-33?3cD\=Hdꄇ'?f((_g,'/dՆ f]ENl0%G ^68;lI(r O"HH$)xD"O"HI$yĦ [vm7oҥK1b 4rlݺڵk3k,U&:u*D ޫ\^+M7a ʎ;prrۛ7r.\cǘ8q"`I}A @ LJCo߾kN,]ƍIPP1Bذ8Pdv;wVH^EZgι_1l6@BEe5/ I$9xTZ=&.D"HH$)xD"O"HI$}hӦ1vi#Çsά\5jO?h۷-[0`oe˄{ZhŨʕ+6XdIf̘ҥKW޽C-ZpBNJ:uuʕ+GܹmD`…lڴ[ҬY3/^L- `ȑ*UiӦ~R WfܹB,4ic{ŋy7[LΝaopyy3D1Ç tf4 DDDzxzz%ڴi÷~K߾}&44ŋ=Ν;sXΓ'O>eϞ=/_ɓ'_VSNLm?///z=*Ubȑ?B 4o\tݻGTTM'OҳgO:t۷E£X=zDJh߾=+Vm۶|7ҷgTT?_!)xZ\<<+9+]] ֯_{e͸s%ѽ cDFFP^==ʶmh֬ _|ahɒ%YӧOSD VZ``4o^z A>芦DGGsEhѢk֬N<֭[Q~A<%]n'O&>S9~8UT`ܹ'or!+nZj1a9Bɒ%YzhU3o}:gϞ9Çˁ8o޼6׷s F̛7)SpmQ;w.&L`߾}<44Yf1i$ .]ĉt( `00}tfΜ) ,]ӧV\)ݻǴiӘ={6111oΝ;G JI bǎܺu@Zj%5i҄e˖LϞ=G]ҥ(\0ǏghI&lٲ4iBpp0`qҥ aaa͛VZQZ5޽˵kxwҥ /_Ç9t萈` dckGݺu9x Νqܽ{sq>|H~sK%&,,M}lܸׯӨQ#d{\~[Rܳ tZbΜ9ܹsjժ +0*VիW _~%&MΝ;1%Bὤb6Nm;FxxƬ/󎏢\5۲d7$H "%@ބD$"9PQA@:TQ;)$"J{o!;;wg}23w./ׯ2,|SÊ+̴4NYh*U'ZDFF2zh&O̘1ce޼y 2D)ҥK1b|ϼߴiWuϞ=|Gʹ4K-X+ |JZڱcDzqF6jРA:tڵknGgIk.=nZmyZZWJ*V2d۶m&OE^t^p!o665kVv;Owaر+_C*exgm0LHD&Mm{=eW_}իY{5wKp`?ШQ#es)\H O)h*Ynݺk^R%/SNMGNNIII$$$xĉe˖2h4cQR%+v=Kp~HII)"uJ(23gAʲ;vȑ# e+W&11k?SPii4^, jՊdLC)Mڻqyc;wٳgk˗/+Yt:]t! +D&MT 4 <<9rNb߾}T\-[*9Zz-;,˜>}ZiuؑjՊN}9rd㫯"44d/_V~WŮҡC,Xd"%%#Gҿׯσ>H`` zPo`rm2m4ZhAXXN'`̘17<Ν;SF ZnMRR>EԫWŁX|9N x(RU_~IFFhZzI^ݹg/33ya6߿"R~Eqyy#ǎcɒ%JYzz:NG=T*֮]9y$WG ޴iӊ˿oS.]3rϦMXlϟW"nʢE7n=lذ-[D~+Vp1~iuPD ZuGbb"{'))%K`69r"vƍ7НI>|rir̹E!ă1XB˅+HIf8r/_:$ uضk`С̜9SIJ}'3\ս DV O?Ux ~(@ 'B@@ !x@w"܀ ^~e8{wfA; ___ZnJRe>}:'O,Ŝ9sزe s@Dxw+?;rqL3^z&So r+x"'OV-/IIIKryIlv*Uzv[v,=z ŵfポ;wfƌ{ѨXPƺuWΫiӦ^&%V{GϹ1B\!x Yt!s)S[l63e}Y6mؖ3ѣG+ܹC2nܸ"vӦMc|ʲ5k0uTh4r9vJlڦѫW/֭[WLL O=|+HHH`ڵ `Kr0uT ٳe?37ofԩ<쳬YF,==#G ` ~СCCj޽;Tהݻw裏iݺ~'K/.{h4ܹ-[Pzu^yb1}Yfʲy)–ȑ#ٶm111dz~|}}U5jܮ1;wT~DFF2tP呶I&ѲeKf3aaaۗ`5kd„ F Zܡ9_pa=|0ժUSKAf͚ רQm۶ѴiS,XL8"##i޼9g޼yԪUkגFiԨo&ԫWm۶xb7nytW<fq4jԈ~ j%''+WO=0`Ge׮]t6mF X~=/^TmĈL&ԩöm۔ciii^*XΝ;#I& Ѩo ݷhZ&S+WdğaƍX,, P6m GX=8V^ۥKvcΜ9޽3gfJJ +WTDGGsivڅdE>LBݹz*˗A{Aرpٳ]ӦM={!C~F#M4Q%f3̝;o:u 3}wʹoݺUS裏իׯ_B Jĸl2ŎpرM6Rx衇Jm FX̱GLk)vh~,\ qE OFjjUy.Q6ʕ+eA CF<@ 'B@@ 'B@=̵WyK2+U)4giw O?'-q# p1=<[sW҉ ݲtT ].K7ggRFS}wt]UZH۶m+."{i_nq>pSNeܸqT^p'IJJR 2gy|o=h۶-<ɺu1b˗筷ul6 D=HNN&33Sp1%֭[Yja;v I7nd\vZjπgС̙3y5}tLll,#>>Ç3vXq;K.ߟVZ)Mܳgr]tɓ'D=*{`ƌ,^,~)|< +W*'|Rb {Smߴib٧O$IbȐ!L01c(s1-Z/  8|pqO IR}*uW8QŊٰab+.:7n$11{'d2ѽ{wqaO𗴦 5i=~sYYYTPAYŋT͚5S#εkײpBXx1]tח?\oD/ǏѣGєwʕ+^eK̓{)֭4.hڹl2XG>}0\z\3ae;w$22I]0 NMq0ydE@ FϞ=2dO=^' O<p'1cpyR#R$ s8(/شiSk|X\I{7+ [5o%իWٳj4 :t?^YrtVKhh(.]"55UiFGG+Mɍ7ҭ[7~7~aEЦM^z%:vĉE3{"9p s5WN DQ$p.\ ԭ[l6u֥^^~=u+eΝ;ӿ[BCCٷo҄/ÇYjZnsU5R Bu '&''#IVI $22p'$pB&Nl&&&@TT?^jjh=ٳgth$I_'NMxx8˗W%tb0x}] Fnn.>9y$hZ:upyZ-&+B@NA<ի-[$--(Jso@ɓ'SNq ju#!x 6ns2_oy[yt1ᘘb/X#vk%E-ʃ'-%ԃg0$  5k,`4I2+aaaJK.]ceW RdA Z!x@ O  <@ 'B@˅kՌrFZ B/Dhݻa5[D݀m~Qa.w#o+/xkfr2^9v+4|!?zˎJZZqԙf#55gϖwR\9qA Af!LWпDGGӠA&<<\1\2UTJ*DEE{GMՊ Z F-˚4(//%KmHLL$!!^c*6J/V8rwVf5Z*۷oW>߳gM4!..|f͚lذNNJ+ʻ{n{=ۇntR/;{RJZh3\2ժUSoTZ&M(.1wfر1+2rHM>XڵkիWPV]?GE!xBx D۷owޡ}4oޜX.\s=Ǟ={Qlԓlŋ5k  ;vdȑ; <E4׬YÊ+EM:7xYf^$%%pBW}ywyה9rUV1o<7nXMرɓ'|rϟ8 /YD-[#< ѫ\2gΝX"n+{apRcgd0ܹ8yW$''ӪU+.^Ȱa:t}ᇬXłbjժ*6}t&Nm۶˗3f8zhC VL+A=z۷o}Q}}}?| ݻw_{V~ &Ml^r@dd$swBTWգGm^*+;dllؾ};+V`Ν^͛Yt)H 6lbQjyk׮ڵPxEΩ0YYY^zk``dNRR$Rn!xOf~ԨQ<#˴mۖ_|ݻ3j(/Ovq5dYVlْɓ'{max裏ܘR{?W^Ery%q\5lؐ{zΝ;Yl,ӱcG֮]+.,!xiR"Oٳ={VY/22^z)?Q^|E~G)e6l⣢<aػwϏ 6Zކ 2a6llۿo8q"$Qre,Yٳg9wܹsoڴɫ ^q/^|uV/TûJ]xK^WN2Μ9{jý[)+V$##lT*h˱lfL&4,l^Ç3|b#W޽ݻ7999E"6mtΝ;sL&iiir}V^~ pL4 I}"»hٺ5_̜Iɯ'-a:D.hDb00 ^S*$IRD %VwqbozNG@@W?Xak>W+{u<%I*~ԕ(NTT򷟟; ƪ5DE"!x@ O  <@ 'B@Mp !BndGvmv#,}w/;pLoԊsK}v\.ZMXXjպ۷Oy bŊTRLۮZ… !..$.^?nzƍȸemڴ)͚5ܹsHlver]hтׯONN`BBBnmnn"SN;v W~f+MڛXoٲSNqI.\ƍظq# nbIDAT+MӧOSvm4 }_|sQ~X{=z=:KL7oLxx8\RYn2믑$qfPP/;vdbccԩη~x߽uUbb"$a2PiӦqqN8S8uW/_Nr$_kwyNGƍ^ ojTT3g(ˏ9BZh4|'̞=7xCd6mSO=Ņ x矉믿V`?(N#ƍի>}Ç+7?Ά عs'bה͞={HNNf /gpٳGsNdYfڵ̚5;ÇhҤ iiil6֭[믿NjjjzyWضmײnaÆ/rYfi޼9[lQ_r%gΜaȐ!@FFL4t&MĚ5kąw JFAӡthѤ(LJ޽{ӲeKEd<iiiĐK~0`L2իWt:l?իsqm>zhb]v,[cǎ+nC=DBB\0PӦMiԨr;VzE^6lm۶K68;,)v+V0d^J@@qWPZUtz?lt:Ξ%B/e|y߅_~Z핹m-b5^bw񻸛Uq,47 n *ݎo6g ;1"^| +E ,+Yme?#Opz/8YJS[z52-vrI$j5ԬmpVq,PC(*8m)۸@Ġi2s&>EJpkA nI8")sY Y3_NuF**rG}I_UwJf_j^o\ˇ2.Ԩa|x'z-7Q ^Fv ,Ј)cu bӧ|2kܸqٳH{Gnn.ݻwAt,Ub6lK4 韝0XN58sj2'&&r9p9\V[ľ|??(\_ҼyKoﭷU^ªbŊj7iӁ {X[gn, \79NN_?f|ϖnft{},ً6~Q-6wpb!dE\% pⰻP0O?Vs{˖WKǎ4YvG++NWߚlCT9sVd9ga;:p6</azm_Z5s,*~tmϨR% xٳ$DDD~ xnj֬wgĈiӦ5OPtR!TO6Gy~±•{Jaa|z?;h'l%8.ZF&@nsHHLBJ-4V~rIeGvz':= p1qY_`**@mC9YA:23b6"P#TԩŖG9ʅ y(_<׮e0wuWX7+IN>hР;4{n?D^^6>͊nLJ5kS[ssse@zu 4-T*}ݨN &Ko:;$p.'!F-s_kC8rӉ&#iTZ4->z|t:Z *`eeg)ͫ[V,]ejdPYe·jmےpc{'}}0qXp8\.$BkXa/1,R3#q 5xOH8.,f36\^q⯓b#333#jA@v8Ш=h*%L%˨ U$r^Ō1+F<+&πAҐcrt5oBо44lh$3m?^q.1h![A 'z&`pf8Tj?Zq1ڝ)MաRh48N.._7-QD%hj5Z3iۊ۵G t  7" ZjV%df-\d)MAG̀".$GB}.R*,*hԈ Y?NZn.W3v֜ 2k$:8@j Îj}";r1OeR(щh4tyvVkӅK{?=߯'snlއl_պPB!r4j4-9f3&SN Ϡr!bZx9, des׏$It'8dLBFŊ8|G`}۠V{b,r9ӻ7F}_g;wnBp||}5!Op[p8DDFW3q:62dwHU[Nyv2y~;L?\wV/Gr4iڌ <+x*7kB5O/p\Hc@Zdbffw

The Migrate dialog provides an easy method of backing up the device's databases, and restoring them to another device.

It currently only supports the database data, and does not migrate any of the Java applications that might be on the existing device.

There are three main combo boxes: the source device, the destination device, and the write mode. If both devices are plugged in at the same time, it is possible to select them both at the beginning, but if you only have one USB cable, let it prompt you for the new device.

The available write modes are described below:

  • Erase all, then restore - (default) Erases all existing data for each database restored before uploading records.
  • Add new, and overwrite existing - Only deletes existing records if there is a conflict in the record ID, and adds all other records.
  • Add new, don't overwrite existing - Only adds records, never deletes or overwrites. Will skip uploading records where the IDs already exist. This may mean that not all the data from the old device will make it to the new one.
  • Add every record as a new entry - Deletes nothing, and adds everything new. This may cause duplicates, depending on the data in both devices.

Use the default write mode if you are unsure which option to use.

The Migrate dialog will basically perform a full backup of the source device, and will create a new backup tarball in the usual location, with the label "migrate". barry-0.18.5/doc/www/contact.php0000644001161500056700000000175112242254476016015 0ustar cdfreycdfrey

The best way to reach the Barry developers is through the barry-devel mailing list. Subscribe and then post your query or comment. This is the best place for sending patches, reporting bugs, or asking for support.

If you need to contact Chris Frey, Barry's lead developer, privately, you can send email to cdfrey @ foursquare . net. Mention the name and the version of the Barry package you are using when contacting Chris directly.

If you cannot use email for some reason, you can also post support requests and bug reports on the Sourceforge tracker page.

Barry developers and users occasionally hang out on the IRC channel #barry on irc.freenode.net.

barry-0.18.5/doc/www/desktop.php0000644001161500056700000000352212242254476016031 0ustar cdfreycdfrey

Below is the main screen of the Barry Desktop GUI. (Click the buttons in the image to get more detailed help.)

alt="Launch Backup GUI" /> alt="Sync Mode" /> alt="Modem Launcher" /> alt="Migrate Device" /> alt="Database Browse Mode" />

The screen is focused on the available modes that the Desktop supports. Each button will either launch an application, or open a new mode or dialog box to accomplish its task.

The red berry in the top left corner is the main menu. It supports the following operations:

  • Enable / disable verbose logging
  • Give a name to the currently selected device
  • Perform a USB reset on the currently selected device
  • Re-scan the USB bus for new devices
  • Display the About dialog
  • Exit

The currently selected device is chosen by the dropdown list in the lower right corner of the screen. This determines which device will be opened for Syncing, Modem, and Database Browsing. Backup and Migrate (Device Switch) have their own methods for selecting devices.

If your device is not password protected, a screenshot is taken and displayed in the lower right hand corner of the screen, as shown. barry-0.18.5/doc/www/logs.php0000644001161500056700000001154012242254476015323 0ustar cdfreycdfrey

Volunteers have contributed USB logs to help with reverse engineering the low level protocol. If you would like to contribute a log that is not already available here, please .


Please note: These logs are very dense and highly technical, and are not intended for end users, but instead intended for developers who want to help reverse engineer the low level USB protocol.


Some of the following log contributors are active on the barry-devel mailing list, in case you wish to get in touch with them.

Contributors in alphabetical order by last name:

  • Josh Kropf

      Josh notes: The following captures where retreived using SniffUsb.exe on Windows XP. For each capture I allowed the device to settle for a few seconds before executing the single javaloader command. Then after copying the log file I trimmed the initial USB IO leading up to the request for javaloader mode. This should get rid of any unrelated noise from the head of the log file.

      To create the files below I ran each log through the awk script in barry called convo.awk, and then through btranslate tool:

      awk -f convo.awk raw.log | btranslate > filtered.usb

    • - device info
    • - output from device info command
    • - erase module
    • - attempt to erase module that is in use resulting in an error
    • - forcefully erase module in use
    • - annotated portion of the javaloader USB dump relating to device reset with descriptions of the various packets
    • - load module
    • - load and replace in use module
    • - save module
    • - save large module (107748 bytes) with siblings
    • - save very large module (655796 bytes) with siblings
    • - dump eventlog
    • - dump eventlog that contains an uncaught exception
    • - clear eventlog
    • - save screenshot as bmp

      Full firmware load:

    • - (large! about 33MB) USB logs generated by VMWare Fusion as per the instructions in this tutorial.
    • - CFP info output before the OS install.
    • - CFP info output after the OS install.
  • Robert Yaklin

    • (5MB)
    • (large! about 20MB)

barry-0.18.5/doc/www/installdebian.php0000644001161500056700000001073612242254476017176 0ustar cdfreycdfrey

There are two recent non-Barry bugs popping up that are making this install process just a little bit more tricky for Debian/Ubuntu/Mint users.

One is a bug in apt-get, which causes downloads to stop with an error if one of the HTTP header lines is longer than 360 characters. Normally, this bug is not encountered, but it is encountered on sourceforge.net.

The Barry repositories on netdirect are setup to redirect all large binary file downloads to the appropriate file on sourceforge. The apt repo metadata, such as signatures and checksums are downloaded from netdirect's server itself, and the binary files are checked against them.

Sourceforge.net includes a cookie in one HTTP header line that is about 550 characters long. This has been causing trouble for a number of users.

Fortunately, the 360 character limit should be removed eventually, as this has been fixed upstream, according to this Debian bug report.

If, after following the usual steps below, you encounter the "360 char limit" error, there is a workaround. Go to the Barry file download page and navigate to your distro and platform. For example, if you are using squeeze on 64bit, navigate through: bmbuild/dists/squeeze/main/binary-amd64. Then download all the .deb files into your /var/cache/apt/archives/ directory, and install again. Apt will notice the existing files, check them, and resolve dependencies for you.

Sorry for the inconvenience. We now return to the usual documentation...

Starting with the 0.18.x version series, Barry and OpenSync binary packages are available via apt-get.

To install the latest version of Barry onto Debian Squeeze, add the following line to your /etc/apt/sources.list file:

deb http://download.barry.netdirect.ca/barry-latest/ squeeze main

If you only want to use a specific version of Barry, you can change the URL from "barry-latest" to, for example, "barry-0.18.3". Check out the latest available versions at the Sourceforge file list page.

There are multiple versions of Ubuntu available. Replace the word "squeeze" above with one of the following:

  • ubuntu1004
  • ubuntu1104
  • ubuntu1110
  • ubuntu1204

For Mint, pick the version of Debian or Ubuntu that your version of Mint is based on.

Finally, you will need to update your apt keyring with the following key:

	82DE DE11 74C1 0EA7 C55D  5679 3B52 35AE B6C2 250E

One way to fetch this key is by using gpg:

	gpg --keyserver pgp.mit.edu --recv-key B6C2250E
	gpg --armor --export B6C2250E > barry.key
	apt-key add barry.key

Barry is split up into multiple binary packages. For example, if you want the GUI backup program, you will also need the Barry library.

For most non-development systems, you will need:

  • libbarry18
  • barry-util
  • barrybackup-gui
  • barrydesktop

For syncing, you will also need one of the available versions of OpenSync (either 0.2x, or 0.39). Note that OpenSync 0.39 is sometimes called 0.4x.

The 0.2x series includes the following packages:

  • libopensync0
  • msynctool
  • opensync0-plugin-barry
  • opensync0-plugin-evolution
  • opensync0-plugin-file
  • opensync0-plugin-kdepim

The 0.4x series includes the following packages:

  • libopensync1
  • osynctool
  • opensync1-plugin-barry
  • opensync1-plugin-evolution
  • opensync1-plugin-evolution3
  • opensync1-plugin-file
  • opensync1-plugin-vformat
  • opensync1-plugin-xmlformat

There are 3 convenience packages: binarymeta2x, binarymeta4x, and binarymeta-everything. Install these if you want to install everything.

For development systems, you will need the following additional packages:

  • libbarry-dev

Everything exists in or depends on the following 4 packages: libbarry18, libopensync0, libopensync1, and barry-doc. Remove them, and the rest will follow. barry-0.18.5/doc/www/doxygen/0000755001161500056700000000000012242254476015322 5ustar cdfreycdfreybarry-0.18.5/doc/www/doxygen/README0000644001161500056700000000006612242254476016204 0ustar cdfreycdfreyPlaceholder for doxygen generated code documentation barry-0.18.5/doc/www/desktop-sync-config.png0000644001161500056700000005554112242254476020253 0ustar cdfreycdfreyPNG  IHDRrdsRGB pHYs+tIMEJ IDATxwXTGۇgY`Kߥ X@""h B(FM`X D)J .۾?9wFSs_\\sϜyfND@P&    @C@C@C@CPPP! Jy-Vi9*:zQ&v~kzH$:| @C? ‚ |}}˻XKEO`៕#Z[[mtM#+JM_nBh˗ Ͻ{GCCCV:N#Μδco)p' [YZbn#j4 CϚB?g2x&i``鸃``ZϏUnwcr[WW766&66F$={, u 鹊ȨUCqaÝMB>Ɲ8y2lj<̉'}ƍVUUav/wVqŕWY;@P'tttJJ]L9A_oNP` B(o}ţٻ!3;(\hQxxDbR"¢_>tHN3gZd}\]qU ٓ.۰1rTMM䔔.6n``@lݻ*Qj AÝK=?V nnr8<;;}C p©S↞X15k<==-he~nWO{~4|o~(H?†Xnq>GY[H ӡC"#45GâJDV0WOREʛKe0CRZZ:o`@Dcz +//Peilld0O 2}T#c:vatÃNq#! 6zz" ]     (E6^Mz?5555mkkgrszot:ݲ[!zzzCduICymm55׮L:BvΩ*+ʯ_j`hhddώmmnܘ7^SK 4>`{"xs]$ jA@[X .8P@ D$uK:]6N͡LP~dD!C :411Q744=ZS>.حO ȸsիWoݺ? s?sqCNC7oܸ~ի˖-D+WL8㧟~McǎyxxXZZN:+++-ZdooommpB߿#"""'l&8]n\.n5 C͞=;++K?++kهnދ4s;;;K m۶uId5k֬]4333//uٳg>}~zsѢE!!![n߹swa2)))H|ǎuuu7nܸ~zMMMrr2B9x??~GBF19~x7ohjjbnMM7o޴sڵvs*!D& 677߹s'hbb2hР˗b^^^d2Y[[{ƍ999:NP(ʶmN>݉Ϝ9%BRo~ 'OdСC}&'O$}CCŵO\ٺu͛ۿ$+?{NNΔ)Sƌ_0_$&,8D"HUUUe6f7oЉgΜi&b6m4k,_GG0gTc$)###222#Cvv .?~q?J[[۴4iڵk֭!!!&&&˗/?w~}ĉo޼1cƺu:ƍB3fذa_yn+@١CH7:lSKY涴zuss-,V'@c]!˿>%#+V575uB{q+7 @Qԫ^ y  ٹ?i(H? @ $RC **&&5մ^yC{6V`4T]M}ؿ;t]Hhw "q//} USWswTWSx|z :]OH${y{y2'BðN]ܣ}" ں([s.}0@C@C@C@C**PF Bh645h455jvUCjhkcY'Eҧ;ySS#(-m4:S"TUUux&P7R)|\ D4444    @C@C@C 7orbHBL.yIاt1E>RgQYYӥ,--bbf&O9w|yɤI02zi-u%DI;bYL{ŋ{eee3g˽{.hQ8OB"̧rtK+33X,}A'3><}Ozؑ&,l$uuWWף&_xMxxsL?ze(S'FfAgU4㐡{` t^HH+W ýiiC,haaܶ6-Jk`ckrFOC nnnO?]|yhIqQQS;;X<䃼WXLψesgh2\r] ZںrޭNHHݼy-{/<<yaFx" ͏=q;waLB?}Hp0Bh%G?t7?zd0K#9jvü/_3eCA蚎 %,..¢]X`bb s˗ *++{xR&5/TU|rp ?>? Yi>V+kZ/|y+KKPyyhwXUTTV~<$:;?--X'޿kmm(,9G9ikk++w,>6@B^ ,&}RzccC7FF9ͽuob}<\1\eaWK(BH__f/ɴܖL&S<А YX`nnuGMvTTml(FFJowȥb-[lt:w0 <, !#g$KCV? 4ի'Æ;&lwj*sҥ۷m4ivKK2ŝ6mZBbq۷/}qΞ=lYHCT* 37*++)J'ڋJ/^`Asa$uBd}zXٻ!3;(&_mwOfrJJ|\3tpwn9r߻'5&&FϚ|qD9s:+no<Q]F611DcEEFjij:1 ~!u_rYdDŋ>=2R 2r#F׭:bSu?hnO_9,,00 (0Zii<(3:4$n(n]OPc11 #6va$6{1N;rʇTs:p}Mܸ}CC{Ʉ+4tYh2 }Y&{     (B?TB$jkDuAEEMM {8#?hֲ2lz"hdlܶ[7nL9FF?wf갞P5@CΡf7؞H$޽};hܮ>OI$)q_G}٣ݭ  t CN"(H-騪v}³Msssh @yŀnw#^C )9sJf iii9tЅ ^ru=} ;T_Oȑ#Juuu3gΤP('Nx͛7-ZԫJtIDR@wjhJJGJKK\`!|y, 7TOOjjf5Ν?hwS'˖-NNNC oRY=0CBCuuu޵s+x<ġO?]|yhIqQQS;;;|aPNεΕ=6;(h]f xݩ?ξR\L&oݺM\re\y[xeeeUWW#󳲲?~L&Baaaw:ݻ%3Vj:5k֬]4333//Oj\ql;w믛7o;~8nk׮?ݻosur֭sttttt\~=˕oo<c<<<,--N4={vVVVVٳ:{PرI;%oݼM&uttbcbCenn|yhKKΔGމBFƎD333--͛6p.g ~lٲsqqqZZZQQQ/^D?^SS3E˯^~{^ " fܹSaK>}z۶m Jn۶M~?LǏv ,Ζ-[ cǎ7n\~&99YI;WeONn:{ӧO}}}ׯ_?~GBF1QCBQQwͽ7cniHZАB#l/{!Cl?􍍍OǍ 3EΝ;WXR"t:3eʔ1c_ d2i4ӷsppB$(!%Q9W3g۷9sYI011dРA˗//,,idɓ'1=tPEEw} ɓ'drm)͢KߋKo6iDmm햖+killESS” lddty S&'''&&>x 55鸸=zT$egg]ÇӡR/^BxBav9sÇۗFP 2sL /*t:9 7 |C8|b gʔ) rzrppXhц!I$2 _TŋGWT'OMTSꫯ=_WUU7o\zUV>lݺu|>/3k֬9p5kGytVXQRRE"~"I˖-l6bmڴIa>>>---隚ÇHmΜ9111\^VRÇ#>|r̓BW*|I_BUszJa. zy{H~ʘ2e2Bhʔ?A"z3Ͻ{Rcbbi4YMm͚0OO@ }Yht?ebYXX?#==xժUsε]r/~H$Z[[ϙ3Gj/;J?OKKW꺻O4i̘1ʔ388xӦMRpڵt%EEEObbb1+Wlܰsܗ9q[o#^|acdKK B['MB'ݿ{/nuMuBB"WXLB(1!b?zwZ|ׯ߻w/G,6;:&y ooo2ۧdF}}Ųؓ*s nB8yL">}!t֭' Nef&$S(*x*3/FCC})}UZZگڹ8΀z?k(vOhz:nqҥK.,`1e*ȑ#32%H 婩iiiyY2Yc)|ŋVVV BQԪ*,nee%BZ0###<Zm֭[j``>z_;ںl2V_UUopuu}MUUUXo.^XGG<%%?UUUSSSD"Ϗ255Oa=_$dL CBxyŋ7o0L˗#x<sl޼ٳg>y2E>[SSC&###>ݓKgp}~"rm9qD& `0'Иhmh(e1kX/lf_mdddll*>OKK377Ԍx葜;wRT*sNe)==}Ϟ= gΜ.SHWoɺ93}ӧ#0 0@l4|x}]-P(!D&ٳw!HٷwO5^Ja{y7| ^_ǩ777kk"17BHKKs|>;pw]]1655#X'bkjj !gg=t񙙙R***0wyy9Jŗ%Vn##*]YYyslD"▖װ  \Eňܵܿءu3 nݺٳ:gEFFb 6l؈;9 ߳gϛ7okjjХK^~"B7h(=k؜?.999GD zFFF#GtBCcbb455 :zѣ"h޴ .OysO\sz Gj+G:p|}}"ACAC{5u5{Gu5Χ:bbl2㓙66o߼u|ye˖?L @C{v.O B{{aÝ`Cʮ  @@%% p\=eY @C***-oZiH02 @cX>2/i` t Btrrs릻'jB E,&^]QItm"OT155a^sS?cD$u; 5Ƞtq*OPUW177"QNSF&k  T®GM^6%H'Z:/, < mk+|u"siӛAs4Dwڲ=Dپ5vtY';CUKrĉ+V{9E'C,Ed@b,&߅{rZ}|WU`hh0h g'Ą $&&}{-8$7-q:,&nJ!b* qнiiR7rnemcem/JM5P/RSUWcM۷}u$~RtrAI=2r oK.{615s9ر3><}P]]=tfYxX{ }O|p՜̽{wǏ=%[nÃݾu1̤$i&$$677?zƍwܕ&>>{wkΗ,Y"If=̻~-4ڃWXL͛7/߲#o+WlܰsGEDDĿKsgh2YHN.**0˗/@CƯ^ xFƎD333--͛6pAL) BIH?y43ON14mTf&&JMJL<ђwHr8y^Ąem.u9%9tРAV,((P5d:6eaa'5!4qMMM-++r%{YH\~7tuu@C#l8d(ƒN3 i2 hR0LKKKmiidvL$xRxcbb"__ݦ=|>_hzvU\]>>MZXy[Ox* [8jTj<|T*fee%Bf{:T$9I%% [cȑKv$iӦmw/\|N*4=ښ_P}xFƍE#+*|'O<"bbbYl6͎y6l߾oZ[[kkk~800 6vf7J-@@TT4bXQQ}x *R8AbqYIueZ#$dYqq1D;Ӓ@ DG۷6b\ϟac˗/cb@C{ C B5rpzj:)j6nfMG@@,4okH}wt1bwcFTWѮnMLL䧹jʉ&PGQzz#FxJ(}?bnu붃D"fy sYnq>GY[ Ͼu?hnKkq͇;y;, W\'nۦ{{J{ۯ}Ƃv=kéah{Jsظm ~4f,DĬ꫶MӧO࣡! gdݦZ:Ӧz"aF=<8iz뀥A52iG];5ͽnBC\}k"߉ր@!`_+ UQQ L@ ܛ!+nCZ:MM: ֈUvys_54itzf;8:*fзF,A+ ,VyF@PQQֱlO9=`}kyPUUUMMH$BF 2m!3|>ngVhPPPP4444     GsssTtQMLm/k׮A;Kw۷oH$̟?Oaׯ[go?xQng*u_]_ʺ4Wyp(#ݕP(A:)@?lFPPPBg)q\.W~DЈAk5{I$ފ?yD"siӛՄ o Dwڲ=D"IjlltHiiS]Z׷/z)S)V^mA;ojݣo޼7n\|X9׮H>>>{wkC7.lCKľSvb劍6TVV\8Wg~2}~ٳvN}qv⢧d2ymjnf!˿\U[/凱8 lür_0z@7hc&M ۷ǯZJ#PS  J&%&ׄIN6554hЪU+ Fu󆷷7LщIfffJ% 5,Ş !BC}}:G~B32hiim޴ jW=vlҎd^YD]N:KLHPQGٳgWUUmݺD"%F͖zdZZZbnKKK&) shhh`Ҟ{~3f薆nhde>'3?Ο:whw PmmG:W(DR;NTTdvv;wzqdU7Ka]į!A` ! t~g555}QAAϸqgϞzJVUUaJ ҡ"-Y4xi߅,&L$aƕ92#xIqQҎ$|o!߭\KaA>,&Civwuu W3zY RXk$B;DC ;d ֧Ï?z֖hbP@TT4bXQQ מ={p8d2D&WVUG;Ȱ}G^|#5nHȲb'~o &~ÚNNE#+*|'OCB:DR8-ڰ1U^R XbFC@]/g%%%yzz؜9yWVV7l xhmh(IZrhԘX>kL#q}~"rm롸)#!fMG@@,4o_ى~ $$z˪~練8**RWOo^cFCEgy|d|eHlQ.mm低 "Ah0 yƞ@ xmY 0m"{cO "ۆm<Zq`4H&g=ۡH$lnnp _ PPP~***B P(TQQle*`ԨU ϻQf;8: IAǷXMM TTTut#w2Dh\&+R|>h&    @C@C@C@CPP.`Hܼuy V^U0@C7oIޑ$5,S }:niT\\EۛO<ܹKɓ'&MAPX(f1? q zy.UPVV6sϸܻw**ʓw$e\R\.WMM v@5/<&<< j@ ؾ=܂҂_tkQǎWѫW}466B;ׄ-Yz4=]~jѣ.#G?(ۛOk`ckRH;o54>>{wknnnNۛ6|pݩ?ξR\L&oݺ _r *++.?w}d?㏳gBk;Z7o^eϟGsv9䢢|RjuwBP~2.aX w: B ۇ\HB.#G<񛝝Bdz)z!<%lӧeetSUU݉IDATϟ;gaa!+ qMLk_JL#Z[[mj%Zw'gNgjLYuwx/QYssBhǾ0LKKKmiidJe6)**+ׄ)(4@xgEM߹s׎mi0;::?! -,,d!>666P0Eihh(WJ}}=,REгs-mm;QW5ի'Æ;aJZZ^KRUUUJ "%<0i---cc?.J9rdFqHt尰5ӞLFCCw$w))ɸ+5 q|ƍ;{ܲe!)_;e066C;\УBu2IG 4YI9r9RGEEEEFEOSbEI4 үw}!PHȲZkmm-M0!&vÇ5550OYYa$I3?d߅{ҰJ|ϟac=))qq!]]gϞa O_vijwr.-.vH )nna9&:jDuu6$:*Ja>~!fMG@@,4ow_,-nvA3ZzJGV؜9yWVV7l t~:{|Əru0pƍowcU7e\`!|y,KHr6jRtrAJ~Hֶjj qд}p/)]쭢q7-q:,&߿}R[XjvKaOFGG;;;;;;GGG*S._ 70|ʿ26xp'o}|>k;wXESO8?1Dr#OKK:!#ݩǏ8rH]_ZRl``܂FWDnCn%ߘ>7ߌ4!jAH!񝑔ܸIY:xR?6t2*]&տ[Ujxkt_-,';tXS'NTɞJ>f[Rf,6;-8}gWW?(?T+O"@OՈTQYj_XZY %\ti XLFEy<4C}w+(=HUUs7(:0pBظ #|*<*++{JM|ŋT*U2-,';Ȫia?_C"[6*).Jڑ$pgϊ/w"JRstrMYܾ6ڃ) !I$2 _AM0;#a[X,%ѰavW_)oP``LL,fXQQѸ?RyEipH`$|):&F~RUezlvtt ʴ'"111-244444\hQLLWXXPW!dbj<ͽ sVO 4Tr P2u H@H(yo(\UDg$xJUe}U c" hBe> nCZFSSnW5>~F8(zR(P$} ,VyFQ***Z:vit:ÑQm2FUUUԉD"4.@k &ʤF+4h(h(h(h(    I!!C9}y]=}hA2M:oʏ 0PPPPP4444P&q_ @"р-@$u@(D,^s+_80FD[";4TW]XUYEEEWGq" ^r^7ᵰ_`T#(V3 ZL#/ ,mDb`T?CT%*[~܀#G &spy9K]~8ŽbEU G&Nlmm;ꫦfgHTU}ㆱ MY!_{2Q>e$sNei(S|*jx@[ J[Mx<< ]fO'22BsyPz:/)|{kT D B(RːHjʬ@{{T5W8]+~HڪNZ,zn삃wB!D"$B"у7-[4:̳ bc}sx$38qkY[ ssh+e N޾l&$B$/@x֬m AE;(=޹rP4-)JuGKMQCOzKNi^4 H+O)OX".,3IDnj!?y3g;;3&L9*j_1?ҥKJ nyP5vwb$]l2~n"EB!{D4 X[q]Ϟu`2jϠꜜLd::lL.]11wj سgO@@jժ($i͚5IIIf944tǎm߯V>8r&!sv/ԙs p,RY%Ǩ!oIfhķ׭]byFv+`LO;w%;?WP?Bil*.bbNr;6/-M?6'Nohڴi˖-jO>111Eaaa-˗/;wTܸq 4M|||G0g?\ѩuws5cL._7^-5 5U״ƂʂKJ_oF>aN'Wӎ|dQ_;5R(q2g9`Xaj)(JS^lQNNPT֭m0/j֭~z9ǏM6əIIIǎ37l0tm۶=HM:Q3Ϛ:l%嵶 1~D$ ""FıEUM2.juLڠ̟gAڤ((zkʾglZa(:8&SMNR[gggV޴(3o]SSS!"uNJ(u:]h4'|~a'jQ6XY,VD$X%cp QȆG6<#'&/ӛz9woVSQ霝W#;8t>?Ccy y)5 ggIb'N$[Y„ܸV6[pZ6h:pww/..nԉ{AU$/&Suc~(&оy_3fpOJA\+5b^(I"<8tQ:~qF]=:prÜ#G0c[Fc?Cj(.m<3>\$tܐ!lJ^AA?hȾRVo޽{ C]]yY.U* dMiICgϞrҪX9sGFF ;wJC}q-0e~,B r O=OVKƃTJ}2m%UMFӁ>H\ Äg'%?liCi,Om aIPXȇ~z5`˖;vz5&O΍~ҾJHXzځXB11q[\\o|-iIj\\[o1BHlrfTToKoX֖kf#-bo2UUٿ?(tHѣ|EXX n{$v|ߞݡS:8:T!vM+Aϱn Bu;3#[&nѹ/ꥢ~("J{-X`2޾ԨGK[>4r|L 1@ܼ+ϫبc:UUѿG[A; ,VB 4t][qR(mEQEmV=GqG^^Ϝq4Ç7n ް^4ݏU{1 (I .wH$UV1sf]]rmti+++ݫ<}UUUѵp5@%===/Oϴߟo~zuK+kv?cP{}Ȟo0zaݹCM̈́w -Bߥ|?Щ8 33A5kRKKJefdf\}\855Ү߸~n?Ξͺqɓ'T7ݼu39:::+VT.$-5M$̺q .Ӛ=f}tillLtвsZM}%K 9vk}g !D >䍜{ U:vg'''jT*_dbѣt:\ P8н477;ȯ&="&''%''d;vL>@M  J)++'_g0 )//򴮮};KxxcmmmKk{5~;u+ v404tvv1W(g(++355m=6|n}5#GhyT#bj8##so3u.A_ю8ZYY{5!5-5չ bnn#jy u󲰰(**R8u򄕕U |=z괳֭O۵kwzW#,rֶT* of]62A4HPoF?|~Lϝ;o佻̴W\[o9:9_]WG<|m!cƌ6mZPЫ[mKeKHHܺu !$>!!""J߿m̉JHLT7]4~M׬^M:eJl살ivyy?ٗ_|0adDDRR-LM;lذ/R__ӳՠ7)u?7?pD"Ahr_A?Ǐ9s֢E d2DϧlECCNѣGWՕj ?+Z9Ϩª.%.nѡÇjem328ٳg_QRb9w ?KKĄ*}ӦǏwtr }kq\7dkϱyGϊ U0!!klA-L;;**>!1fN/ CJ-m4)Qbhki㬽]˿?bgbw~N%Ή~~-7%%%ُ@+G]WroNENdbI4b㾀8 8 8 8 8 =dIT+i `-&2c\,b{D"HS@h4Wtjz!ye UOeU"z&ů4 &:hk=vLdr}wtTwtx.?{J*'*(/qa:\4aSqTP+>{ x6 K4bjJS_8p\؜/ZXXw"Rѽ%xX7bs2T_!Hn߼o;9 =N6Dϫ tg_oNhkg_U],Euƽ#[XfqvAɡ38l#]cA'v"e {{GУh2"-GF d߹,dD3SlD"ɤNz+hH_WG޺r0\52T%D*X,N2.u=/P*mO^#}Fit^5Kd%uv^ \,Jf4K8( /aHp^D"n$@WQGxS?kL9~=_?b-Qv'xn`¸. *W0XfwE8쵍fb=ǞLBڲJN檺۷J]*q ?%rm[7wQ)++#++ zU0F#W7]x:Ҍdg5k@ H$߷6RUU9IV|>6kSWZ~~1!V|+ITw~g5ll-j{=2 gwMz[6} b*2um+ɖ%'8X8ZXDo͵7/ _ucĈ#F@(}9M8Qx-_=}FL&*o3w~~W442>}OSW>c!NY0oݜ̬b'f={;oG6E B*kWʿNe1)/v]%q˓:VʩԵ힯t•3_8nޯ;.I#"X.2ご7nTWW߸qCD"{9U.޽{q7|tz^UUT! Mו~<[G\zeܜ3Ob'?u䚴tccccԵKŒ˒]Ӧ|P[[K_gd52.\$//O&#&C]C]}T֭9abG[G[m[6+gȺqc|N266o9BQ uR***]m++ +**ݜ++ ޛ0x\rBԵCCCcY|[-6'JJYv,]&#~7]S2t,111---::ZOO/:::---11G^|>>Cr8͛7;99iiiBx<Ǜ={vCCm׮]ޗ.]ڷo_~ t:ۆ lll\3D]pTsQ.Vy~ڴi\.vÆ *TG'r8ݻwP֭[-jAAAxxQU~;Dhmmmdd4yZKm}E7x~hrb||R†hg•E:S#7oz IީBHk @K$*q]s޼r,-U_}{FDŽ3ܽNW.J1a{|Eո7!r's?|-)~BԵCB杜f?m=`@jg{K'ؖtút)SУSL9zhwI///dtԑc6_\&BHJJJIIIvv{e˖~3g{o'N8}P(7nٳl.\ʺ~yy˩`zoX&Pysie˖UWWgee]tΝ;w@  Ǝ;w'Oũvk׮qFFFFqqN||ʥ鶾!WoNENS}S{ݖ0_}>.?fg3 qbꇓ VYKINX*%w1W7BWr!%Oߏ!vv'ʊ"_&}/ai皵~.G꣒5ߤR+,,k464xzGuE)ԁ;.l|<|>[uѷϱ㧝B[h[scZ&IJ<ʺS?HG[ wy,aü;펭G56z?7-Ll6799yԨQT?zuwlĉݙr~z8rīZ+<Üy* C`ҥUUUҋl !Ç/,,x~Xy)LvlU|_ug~<1r/m쨔SVjjjlll 9SץWT9z[ؘR%%O|yF<#ݾ.BJ8j F0{4*]L%7n۹_}KZZYPm EaCz];B5߄gk7 _BQ uFO?766\x>x0;KHւ'T,,-ajKBk[}}f' :PPoBvE0ħO)PB-Z~z:e>5fgϞM:&==Ngٛ6mrttp82ÇaaaeeeT߳obqBBIjjjTͳu۷(V__?k,SSSSSӨzLv]*޽{wﺹu {uuMtϔVVVfmoڪf`O Sʏb:?++Ru= (L\Tv ~Ȗ*k%_wTsC 16r8.+ U֤Ԃ-//WzKξnFJT~>|(z/K'fg lmnbmnB67My_~탢wr,^Bo+.^K+/ϝАkhȝ;˗tBTWA22-, U[&%^>g^+nuyjoTWB>b2)bPO:}[ُK+r۞ ks>Qa5HW׶n}oeeQ÷otw۱t\ϼ3`` Mځ}ѣ틌ScDDD_|:&uN(Y珹366ޱcG}#;sBǏϟO%v#FtM=Iɓ577Wy" /,, eS7J'/**=H]&iy.l6g԰H$|G UJzFE˫~XT9Ԃ~NGRzu[_T^W,;o E).Ɣ<)nh?y6]J`ԸE 9w?5JwswߺycMuUMuՖMOO ΋=J?ὤ%Ok''(W~;#|Oџ{=rP]QF\Wu1tX]m힯v{xzR :Z.^8άPv \( xOԵ ץ.+-)+-YzIK'D#GGW˗''ܹnǎ)˗/8d2.\NY~E ~ 6oذAtsssjÆ rWOQgϞ͛79rD]x㍡CXB!}ϷشiӁ8zyBNDQҮG#""/^R^^^^^G.`ɒǏҹ\n^^ (| S97o~YqqyP( .`*,,ݴibb>|Ν;SLQYQ=$v[_0H2˒}-”z*!þ~~o{͞[>T'sL h#CB;>r~ef\ٲs2GxV눰Q}J]G.\XX+W>8tTfƕHe=_ԩ hꞯTW쏣fca\鳢Rg2NٰqDGcә Qsz#hAjm'}!8&u,kWG\:Ciik׮]w!ğ.bqsSS#"455߾}{„t@ii5lee)̌Gx7bllLsS(z)sTaӧOeee66԰uYYYSScPP˗?߹gMMW\ zUmKzrr2ocee8ؿIBB<>wn̐!oq+ (N\jlݺ_~>!CII 갿Fm,-BBBto;QF[XXN>}ԨQKpWh< cKB۾uS֍_G53~894[l~1P[Ng*W9(}h!5է~jժ bWWӧO;99B>|子枖:|pCCú:++kw-!?INN;]SN:;;SܿG 9sƖ-[㏡C.Zcǎ/9~Ig4sOccb.yyǏM-mX]]+4pNT&jzRgbm銶7eJ%{yz^rf˺|)nR RT~[X~`ܸm۶B,Y2'!D+Ocn>}t;; |Ge]wwӧ/\N[sBH\\ܸqTo/]+&Lxw…gGuсqL&{?{璐8.)1114$DG- }F3=_koSa]} Z=)w.I___Wt %l߾mx @cns_}Slll`Q|Ŵi;Bݢfщ|>Ҋ>&oGFFdȈ7|l=C=|.vvvr㗢qn+ؚi`StsRY:ٽ{ݻ!yyyU%%ңf5 -$յr:Hٶm+,_H$F.iWn{g5kVԬY=cGGѽqT*IpW~ٙ-%K766%&&[čE a2HmSEgamf3̔H,fInǦLٛ&ɬ{CWwt;0FNQ-&@Sqe4F!+R6!L0y}@J_ϵffnlltw+& <3W^L&jb3tMX"! d4?=rjĉzzzXqhnn.~*++_/d2Fܾ;:r8y\&G323Riffȑ# !ôSիVعD((癙jzP%Ijj> iF9΍ٲe G7o:oܩӦ;K.=rgBHxXڵiڄƦ 9򳁁At'ti-̔'~#ҞƍÆ spbmnn.*xp9eo>|B,jưaî^9rdIIݻwNe~ٳgMP*6nt֭g-_bezz9=j5~.]5*t͚Ғk2Դ+BRDBͬ2,zΜz'? Dr7~w[og߽ؠ2ABիW,qr0zwUw֦Y[[,KI9/̉޼e !d11sr=xPj333ssii:xNOKMmL3 **+{՗lnk{~hjj󫬬jljҲrJJJyf}" 8qbVVC޽$aXX^^nooOw`8 *Hް')He2=Ã?$/umP@ru9f͚'QQ?2775\TTdffF |:hLqZ/]4ހ'N\zMPP!䵠urѩS.((,eϘ9iϛWVZ2o\𰄄DP( ""©ȈdH$ 2S\KMƍW[[ZP!WƍTs|m:\͛7700 <<~VTThHhjh7;21!JOH{{zkAt~^V$ԉ uuh)xknjl1zţmcpM4ޤ/S_^ڤuv)6- l999ǏzzzD @ܿ~뭷+++nz4 (@ HV\ejjw꣇뇆Ql6{׮]}y&ԴpBKKK33>J VVV&MQ׽ @G9sf*?;vܹs20ЧlX,KJJll<ӣ(QC&#pС㏕?RnhhXWWgeeMEavԨeAAn+x yz׳СGI;G  ӻsƍR__UXX|B 5:iҤ n߾ --mڵӧĤ榧o==-gCϧ#tcGW\R__1|۷-][YY͛7-ѥK$%%L&[d1qQqqq=m= z> >qG !nnnB\ Mg͚EWWWώekצ]&_X vX yg;9=zsE ]=}Qc =zN8 @@G;z:B _@ݏgٝ^=(@wHR4 t(Q"j _6}S.. v.@ ^YYYYYYxLf:mwJnSy_E٫;?1bDEEň#N:5`Q066 5R MLL o:mnnnKn<Y]FO:ҋ+(|٬Sٳ'88]Jq\,&ʟJK%K8W"^Ͼ~-p6o䤥E)((7111005jTyy9ɓzzz..._?IbbɓkkkWW`۫GUn...zzz uV˕p8*Rn544DEEx<7{솆v⅓QbZYY{xz̺QS]-yٯ~aX\ccO3OGWV&#####:0v͛7_jjjZbE\\޽{ !SNݾ};իWO6=Ο??>>^Yr lf'M=5xƍgϾ|r˕QFPWr#(W/%%$;;[&M6mٲe֭k,^8G`ʔ)~ -|۩ajљˤ+D(K:y`8:: C#M̋Uy]©ޟ?dž3'OB-Z4f ǏB|}}Ǟ$_ ~är3p82ꩱϞ=x-TF]~Y7T6B~waA>|xaaagѓʺر?wl$$z&+]M]PJB}}=*bbjʨ̯@WVVfmmEX[[l4]ϤPO]? F6mIfT?yRL8bbbDKKܜUSS\ܥ^ԖQuiyrR Bjܼ]h)$FFF۷ݷo_dddW\߅8 EIgZcbbON$Ib18mڴ>lnnsΔ)SWW8jhh\k5L⨺T6B"""/^R^^^^^*m G/_sκ;v$',_q^Q##Kem۶KKЀӐɓ߷JIITblGmaa9}QF)W]/_ T.aܘ!CPWazT]e:G{{x{XYY&%%k/\:|PZZ++k>|˫+(3+v77)u755n1ǽX=S~^_`uuGnݚ:uڞ=_{{{v_<#xqF_̫|Lz2Ň8 еj*ӻНaq;v5QnN8 ]F8 /1&YW5yAy&H4\#Qz<3GЫ=_H!@hfg2hxRPPqgN>q\o{fv{(t98;;g yuQ=<3^x&@@@@%&)rJL& 5ݕWЈ[Q!BkˤЈv,kV⨋ۍk҄cR$޻s۽o_ @W@+"BaUyd744H$WG !l6MzD$za_Ѧb1:@_&@@@@QQQQ z?{wFЛ{ţO[.-YuUeG[/`噙口<3seVhH( wZPPTl@;(hN̜ܼ{B͛akg?+**4$ʰe󦤤d;;c >AZ|s <yF{ -K נf:33g2ik0qݿe6CkX,S;{N폖\>Ύ΄^d%+/s,-:?/llm bѲ{%Fw|T$kiqtttGWaHߚFD`0l6f#@/#HZDt(((((    (((((    @;(b2kwbXNQLf^Y3ϬSqwР{w4661 gOzfA -Q[7++*$ zebj3ξq9D8 8 8 8  $IENDB`barry-0.18.5/doc/www/sync.php0000644001161500056700000002051312242254476015333 0ustar cdfreycdfrey

This document describes the steps needed to sync your Blackberry with Evolution, using OpenSync version 0.22 and the command line tool msynctool. The concepts are similar with other Opensync plugins, and should be relatively straightforward to sync with other data sources.

Note! - If you are using a recent version of Barry, please try the which makes syncing much easier, and supports OpenSync version 0.4x.

The first sync requires the following steps:

  • Run Evolution and make sure it has created its local databases
  • Create a sync group with msynctool, and configure each member
  • Shutdown Evolution servers
  • Run the sync

Future syncs only require the following steps:

  • Shutdown Evolution servers
  • Run the sync

First step is to always make a backup of your data. Use the GUI backup tool that comes with Barry, or the RIM Windows Desktop software, to make backups of your device data.

Remember that your device data is not the only database being operated on. Your Evolution data is also at risk, should something go wrong. You should backup your Evolution data as well. See "How To Backup Evolution" (external link) for step by step instructions on backing up your local Evolution data.

If you've never run Evolution before, start Evolution and follow its initial configuration dialogs. Once it is running, click on each of the available section buttons. These buttons include: Mail, Contacts, Calendars, Memos, and Tasks. Clicking on each of these, causes Evolution to open and create the matching databases.

Each of these sections should have a "Personal" folder. This is where data from your Blackberry will end up, and any data in these databases will be synced to your Blackberry as well.

Note: Only Contacts and Calendar items are currently supported in the Barry Opensync 0.22 plugin.

Opensync organizes its sync configurations in the form of groups. Each group contains two or more member plugins that will be synchronized.

For example, using msynctool, you can create a group called EvoBarry which will sync your Blackberry and Evolution like this:

	msynctool --delgroup EvoBarry
	msynctool --addgroup EvoBarry
	msynctool --addmember EvoBarry evo2-sync
	msynctool --addmember EvoBarry barry-sync
	msynctool --configure EvoBarry 1
	msynctool --configure EvoBarry 2
	msynctool --showgroup EvoBarry

Each configuration stage (1 and 2) will open an editor, where you can edit the member plugin's configuration file. Evolution's plugin takes its configuration in the form of XML. For example:

	<config>
	   <address_path>file:///home/cdfrey/.evolution/addressbook/local/system</address_path>
	   <calendar_path>file:///home/cdfrey/.evolution/calendar/local/system</calendar_path>
	   <tasks_path>file:///home/cdfrey/.evolution/tasks/local/system</tasks_path>
	<config>

Barry's plugin member takes a simple text file. The default configuration that comes with Barry is shown below:

	#
	# This is the default configuration file for the barry-sync opensync plugin.
	# Comments are preceded by a '#' mark at the beginning of a line.
	# The config format is a set of lines of  .
	#
	# Keywords available:
	#
	# DebugMode        - If present, verbose USB debug output will be enabled
	#
	# Device           - If present, it is followed by the following values:
	#      PIN number    - PIN number of the device to sync with (in hex)
	#      sync calendar - 1 to sync calendar, 0 to skip
	#      sync contacts - 1 to sync contacts, 0 to skip
	#
	# Password secret  - If present, specifies the device's password in plaintext
	#

	#DebugMode

	Device 3009efe3 1 1

	#Password secret

Edit the device's PIN number, and save. You're now ready to run your first sync.

It is recommended that Evolution's backend servers be shutdown before the sync is performed. Therefore, make sure you've closed Evolution, and run the following commands to sync, using the group you just configured:

	evolution --force-shutdown
	msynctool --sync EvoBarry

Status messages will appear at each stage of the sync: each plugin fetches new records, the conflict resolution is performed by the Opensync engine, and new records are written to each plugin.

There are a number of things that can go wrong during a sync:

  • One of the plugins may crash
  • Opensync may hang, or take a long time, while processing conflicts
  • Opensync may get confused and duplicate a lot of data

If one of the plugins crash...

If one of the plugins crashes due to a segmentation fault, try to get a sequence of steps that can reproduce the crash every time. At that point, enable core dumps, and run it again:

	ulimit -c unlimited
	msynctool --sync EvoBarry

This will leave a core file somewhere on your filesystem. In order to get a useful backtrace from it, you will need the debug packages for Barry and OpenSync. The debug packages for Barry are available at the Sourceforge download page. Debug packages for OpenSync should come with your distribution.

Once you have installed the matching debug packages, open the core dump file like this, which will tell you which program was running when the plugin crashed:

	gdb /bin/ls corefile
	[... lots of output ...]
	(gdb) quit

As gdb loads, it will print the name of the program that crashed. Often this is /usr/lib/opensync/osplugin or something similar. Load gdb again with the correct program, and use the backtrace (bt) command:

	gdb /usr/lib/opensync/osplugin corefile
	[... lots of output ...]
	(gdb) bt
	[... useful output ...]
	(gdb) quit

Paste the "useful ouput" above into an email and .

If OpenSync hangs...

If the hang lasts only for about 30 seconds, then it is likely the USB conversation that is timing out. Enable the DebugMode keyword in the Barry plugin configuration above, and send the last few screens of output to the .

Otherwise, Opensync supports a detailed level of logging. If you set the environment variable OSYNC_TRACE to the path of an empty directory, Opensync will write detailed logs for every thread used during the syncing process. These logs quickly get out of hand, so delete them before each test run.

Some of these logs may contain private data, so before posting them on the mailing list, or on a website, you may wish to double check. You can also to the lead developer.

If you get a load of duplicates...

If the sync has crashed, note that OpenSync will know this and attempt a slow-sync automatically the next time you run the sync. If there is a mismatch in supported fields, this can cause duplicates to be created on one or possibly both sides of the sync. For example, if your desktop software supports a Speed field, which the Blackberry does not, then with OpenSync 0.22, these records will look different, and duplicates will be created.

This bug should be fixed in the upcoming OpenSync 0.40.

In the meantime, it is much better to avoid slow-syncing, and re-create your sync configuration from scratch, as documented above.

If you know that one side is authoritative (for example, you may know that your Blackberry has the most up to date set of data), delete all the data from the opposite data source, reconfigure, and sync again.

If all else fails, restore your backups and start fresh.

barry-0.18.5/doc/www/dependencies.php0000644001161500056700000001423712242254476017013 0ustar cdfreycdfrey

Fedora systems:

  • ConsoleKit - required for accessing the Blackberry without root privileges.

Debian systems:

  • fakeroot - optional program to assist building your own Debian binary packages without root privileges
  • cdbs and debhelper - required to build binary packages
  • apt-utils - optional, if you wish to create a binary package repository

OpenBSD systems:

  • Uberry - the uberry kernel module conflicts with the ugen interface that libusb uses to talk to the device. To work around this, you will need to boot your kernel with "boot -c" and disable the uberry module. Suggestions for better ways to work around this conflict are welcome.

Mac OSX systems:

  • gettext - the default gettext autoconf scripts do not always do a very good job of detecting gettext and libintl libraries on the Mac. If it cannot find libintl, it will automatically disable NLS support. If this is important to you, add --with-libintl-prefix=/opt/local/ to the configure command line when building from source.

The following list contains all software that Barry depends on, the minimal version required, and the reason for its dependency. Some dependencies are only needed for building from source, and some are only needed for building from git.

Note: In the Barry source tree, under maintainer/depscripts/ you will find a number of distro-specific scripts which contain the appropriate apt-get or yum command lines to install all these dependencies for you. Review the script closest to your system. It may save you time.

  • git - for retrieving source from repositories
  • C and C++ compilers - 4.1.x or higher, for the tr1 includes (source build)
  • ccache - completely optional, but very useful if you plan on compiling repeatedly
  • pkg-config - source build only, so configure can autodetect library locations)
  • libusb - both versions 0.1.x and 1.x are supported and autodetected by the configure script. Found at http://www.libusb.org/
  • pthread
  • boost - optional dependency for serialization support. Use version 1.33 or higher http://www.boost.org
  • automake version 1.9 (git builds only)
  • autoconf version 2.61 (git builds only)
  • autoconf-archive
  • libtool version 1.5.22 (git builds only)
  • autopoint on some systems, this is a separate package, yet on others, it is part of gettext (git builds only)
  • doxygen suggested version 1.5.6, only for building API documentation
  • gtkmm, glademm, glibmm - version 2.4 or compatible - C++ versions of the GTK libraries, which are needed for the barrybackup GUI
  • libtar - needed for libbarrybackup, and therefore the (barrybackup GUI as well
  • zlib - needed for CRC32 checksums in library COD file support, and also used by the barrybackup GUI to compress backup files
  • libopensync version 0.2x or version 0.39 devel
  • sqlite, glib2, libxml2 - needed for syncing, required by OpenSync
  • libfuse - version 2.5 or higher (optional)
  • libiconv - needed for international charset conversions. Most Linux distros have this as part of libc. If you are using another OS such as FreeBSD, you'll have to install this separately.
  • libxml++ - version 2.6 for the Desktop
  • gettext - needed for the iconv.m4 file, on some systems, when building from git to generate configure
  • php5 - optional, needed for generating static HTML documentation (git builds only)
  • rpmdevtools and rpm-build - if building RPMs yourself
  • wxWidgets - version 2.8, required by the Desktop GUI
  • libgcal - version 0.9.6 or higher, if building the Barry Desktop
  • libSDL - optional, needed by the bwatch program
  • evolution-data-server and libebook, libedata* libraries - needed by the OpenSync evolution plugin
  • gksu or beesu or equivalent GUI sudo - needed by the Desktop for modem functionality

Well meaning people, in efforts to port the libtar examples to 64-bit systems have introduced a bug that causes libtar to mismatch standard read() and write() function call prototypes.

This bug has been seen in the Mandriva, ArchLinux, and Gentoo distros. Depending on your system, and how up to date it is, it may already have been fixed.

The curious can read more about this bug here and here.

This bug has been fixed for a long time, or never existed, on distros like Fedora or Debian, and you can probably grab sources from those distros if you really need them. If you run into this problem and require help to solve it, please email the .

The latest version of libtar can be found here.

I used to maintain lists of packages for common distros here, but it is much more useful to have a script that just works.

In the Barry source tree, under maintainer/depscripts/ you will find a number of distro-specific scripts which contain the appropriate apt-get or yum command lines to install all these dependencies for you. Review the script closest to your system. It may save you time. barry-0.18.5/doc/www/desktop-browse.png0000644001161500056700000021505612242254476017334 0ustar cdfreycdfreyPNG  IHDRXsRGB pHYs+tIME;E IDATxw]e>֩g23ɤP!! E%4"H;""WʕRC*BMiIN{gws&qW'gg]YσɶY FQ@O@;1gtLRGGRoP ߀_F(]ry& ?An ُv327*!~dRyq)d3GaZOhboUY(zwHY:vb.ظ}lxy^7J\{}d~{e'Ǿ Ϫd|(nm^)zɲP`GGA_HX&)H$ώGJ$jP`@RFrvKWDjG=OjAJFz#kدIsD% ii*j nYx}? |R K@K<ڈ!s2CL0\+~J>>XZl \$kqֻVp >1/F, @{뺏͈Ƒv#u`bоlbOMspG0cpGN@ qxd\Y<qO${c4jXS>% È"#BipW[8!ТeA v1|KV h)ADMRy< D Ip1 =r =@d8 l)Z%'! [poд{nTmE@D"2 {pCגMi/b1f %eRKKԮjxaD"F*ka?7uU{Oz+CAQkqr3 |HٶkcrB (lNI\.߭YZtWORL{$ʒc%OBf060){dOXr}#b[5zQञ3JY]U_0 MY>KQ~@+yh1d[#g| A3mMQ_F|#$fPA7hs#O~eͻGoK0sAd+G,k'٣\IkIF%$n"^]ВvۋQw2XP 9oqR,XYQT߾=ͼUUVGɓ*hehdlzUy(rkKRE(Jl}H >w@S|ɖ̓$zL aXEI C@ԓ3Maۚ`PdyXHXK57U"P=yTOz=h fHC"VipȚ|dd<%óy! sAgU,@DS*@{0kF$hK¬$u;ۋkڼDGo)YQEfmG'[a0J`/G 5ՑǓ%nD[O-- 6-9ͪJat⊖s 9<1*V!+^AooH%l Q{07_,,%"E, 2N|4Tu5*}5C%jɴpQыH)j7Ǜd`!L4VOA ((_$VKHO͖"Bg% ETd7(Wn@kQd% |G2Q7Vsˑcoh*পl=Gf]U}Z{Ax[ԜoaNR>,\l]@'deQ>Fz&.ZAF]-vX[+Fn&n\ޫ}hkЖB9}q U{"hǡ8`ʁF(:D:A\dp(> mE{a&jC? ?fkʝpV@&ZBDSDIV'Z?0" 5 *bQ$1G|}F,r -M m|KQ-wVu7mJK?9n(՘L#d) , 1tiʔ@ kZEA٫e2* $ @3{a9gVNl^8E,{bT6pRW+@9KF h9-եC^X\}`bVE6M_82~7>&C[`ms)UH(h=! -ZGG7]50KsoL$"QFemdҟuY$cvܜʢ& qYFBTvAٜ q,#^7aZ[sV0gڴisfZQgg^Zm}GUo!\k8Q}5/f|;U ,^VEwaϨ I@v!3LS|/u0'e䈩ł 3\n.Tb[$zSa X\VąFTg::J9?t`P-rUDGD܎+T\KPJhA,m8*вJtU!`"jcXDEtX [Cr4BiLjd,E|БFkp:/$SsՅ\tHm]t6m/ﳬ"7X :pF)Fsv/u&,oA 9*j@ 0m3SQ 7:&D4m,N7:RU+. c>Bx9 }FN 5 4D6B"d7ds/m3 F0<) 9X( mМF 2J&a={7)l8xZ /*ZMH@ZCK0'Qc0S4k8Q4~^$UF}ۊV:_&&,֏ g.X^&Twwa͙M"_?Y=mnr}UUUUJ]{4n3eV`Fc *FW 8kZT|Ț, ֞m Op YVAD`ԡɣswdl9b<+uBtTcźww7M_;֟cg\ IH,Nb$2X"P^",R&L`Hb"f8lT%Έ$Z$@rmDvrtQ>s4Y5;Q8wsDhS"ۓM8 s{`Ǖʻ2o~S9*QσwBz$ yge=Xxo;IY^h?mqg}SS)٧DM  Q:0X_r'hoY t "Wz"Eݣ-\7js盞]Q^_v;Į[W?J +|M8wˤK P 9۹DYCeeIڃITuϾQ@ǎcke"2=Cd lh'$X٬`Q:ot/o(ND056X-tQ7T*% 4~ (F T֖SB?NbPn- 3iPۓ88"τg(!ŧDu5B)6穷VFOO&kT>B1^5yPM/f6})rx*Yi!,V"I@^v13r{X4Snb#Vܷ{G^i⦯ IR}7yLxHϒwjué$,w39 'lZz W,kjTjirGw}F,h2C*.vVA*Hl4+voadBx۵݀oH @4OUx7% ͑A2EL.wVM랡r0_E =:@f`ϱ^MQG^4-s.DrMֳGy6?ioLsxIlVIPzw,ye|3#B{pk?y]#[h)rm@R@I,"ʘLj$qvg #<6 76$V3^:9P$QAA*ɩk@QoȖy樤hA8"b$H qDQg.PN(niX⤺֥3|oaԧsZvTap@-P~-_=#nD_AcYo*ki$|\E?/F|+@zrp񊈘X,DxnE\.2zS_~9:wk!?{F[MoDy2Br |jəQ}ASز!tp8γ1!0m$:)VV-̷8B IbW~W:a Ì"=Mh7|0;_9X`/STfF\ᬁ'R߅l[ṱq/ O*&7:::U/.P왾C+6P28q~GtDx:74ӓMwuԦ)qPjOM1&&"}=r:!=(rH,ߤt q!b'[ (TFtYQ u˼.4z#< }]s2&W;RϾQݢQC ']1nnm,A+^{u O&ޒkn;㿻WWP!qS-W~̌ޗߩ,Uї?(/ɤvWoNystG27v¬\tC1s ?ۛu?M{~bmM\7LƯk}ء/~liuU{#sjp<ؼ+nߞr綴6Nh?9wD3 HsΆ=Gս<)7sÆS.|Y}?~2qźl.]c}m#«ݘu`O'v̚>XWo؞Mw>T{FNkxe6@IVb(dwUʶ-]bnowZ1NMKh?KM3tr2&0R{P dts6-]\a˳5B.Kȁאu'%+kJ(NֶdU2Lo^jd6O v~"*&;D~ G~`csPVH% HV WH!)54,D$cA S{VsyH t63_kv(8ɶ3z^jJ"-<^vƶ oaܰ'yâ݃3{~涆jƿ$FG;6w^>6@}7ַ5{?5bC)cpUpA0qTaLK}Wӟx*h`mu˅A>1w77Np_k@jƻ蜮6qU%wF١XK.rb,,a4_H$4exg  NR+zTB))qaP%P6Эp?HF$ 2ŷK]M*0,c֚즣)Hsv[d>9 _XE#MD{/_{w~M^nF ]iȦ|~r?]Yz4fL Gtwd^YU;N XgI/`o}I@֕~uUm67i} l yٙ6xӯ8sَLM֯RUP]Ϲ}W\zo~%6O/3c/+LKT̩4qTa{Ǵ<ޕ>ȅ3\)ћ UeUYڄ!uJdMvIE*$uwFuߔhA>\MhahG9&9IԪuOϕ@ @/IUPz%(+B+ {R#+6%3{}i?c IDATJkDceV}p˄-u4w:F#$) | Ck5M moEWrv)uq!Q|@UN-+R,1-LqWE?%?w߾ y_q;ƌ(|lv~{53Ȝvt4'#41CR8|zmYQEکc[ ݽb;+9zs;nF޸3#]\]Ojѯ;qpᜮs^_WZ^^ AuhTҢ*CZ ]'_Oܰ=m]o-lL=97̽}Cso,[]}>o>F¹ vOOxZp[;_oW3=kj;.x&+}̞֖#ͫ7eo{eL>]ֵԛ1/YG%WoTڭ|jmw7Ur唓gwHAduԈw6V׽/XJ 4sfsvKo=s=(pRGX:':jsċoOq9ےQ"ywcya=sД{Fxs*6T]#fsֈɍT(  byF,5<8nu/~2ҹG1 /x6$2ߎ;|&a!*;Cm}嵐^ߟ[;q߮m;Wv.7GJYjnF_:h#!.t<O5(lʌKs\Ct-NH׍è^zkGz攁X/z\?:亂ث=n}%Եwd'We2t ZBd|"|7aOnj(@[Eܯ/t{wcĝh9uxwԈM;R"QXbVnȶwgHp@ܸ#=qT!W2G`,[]uQp}O6\vy2mgy{w>3gF̜:pe?Ǜ7mO8lMWj3-!$4HسNW}(]" U  L'UNMj*(8HHloʃ>Ag PJ7-كQt$HZH,Ah; TXУҐxd^Zǫ۵8Mo 㚦~6ﱩ cFxrjr` Z.B2{f'a5#rCl*l1`Z-<IɆ#N+~ \hzKAؘb|tc[P[c4_?}¢%MfLjs61*cYk@]I˦}˛Q3;*^wfݔ%Zj?`2]|]UW"0WHڂd$"}<՟CTf3MG%'Q:WrGFصiK dw805~z 4tLyh2ƎY"!?"'8 $9 Ucƈhgu= 8qb/>]zGߛMл૫kK7,]S30wͻ2Z=k  "xF՛{u%]QOLOĀu51HY6f\k}6ʌo_~rcԱ/^]]|9[t rʎ }m>!^[U3p~}vfƷ/?Fm,_[3#o})uK?)CϿU7QM'іU[%jyeS}%B dC/?wۤmSO;U5R²]}R۵'KWWG/55yDZOHI5gcRޣ$ ^rTKC~CH@) U =θՇqK sKN𗶭S3bGoֈo(]5LY6ޜzZj_l͘8CO6"4=,AG_=`;5ڇ!?MDς;i>4F#ʊ܀Q:Cakn?WLlL|%r}0ʺ ~9idcgl=wى%҈~{qqJc*vG %u{6=×[ߧ Cϯ;I ş_=w}įn82otWI ş_Tzs]uX_آg{o՝_Z ?h1Ǘ6?gޑc7=\T@k&ܮcg~m#rCU,2Meg#[4ľ?Sv.Twozituɇz]%+kNݳ\!_?wdޑZn[՟8q_=s{WZ^Վ `q|lZa V) .8Vf|Wۜ=<ɆK@Eqbe跓HPQΣ*L@0}|t9`DcpJһtӖJOC;ؕ35tq|ДdS/{uHS4NhgQJÚ|v$Wv|Π7,6 2nĘ#uA#U' Gj:V.wMPٺaAYעCvoygt U/4. "gawJީ/ȠQqA+:7 Tk ` c/[\⓭d7TTSJAն ,5m΄,Sɔ-Qs$nIʍd< \' 8TXH:+#QBJ89?G0s/ٚOOmwN2k]t/ʯq{R)+}vyY[﫸Tv$NJ5Q Zlٕt`.FîI|J6H %gA턷)HrL2zqa,DC\\_nKI$p%vb %NЊSŊרS%ʍ\e:[ WU:0j șRD=pHqpUAǃhX3? D {fݨ\ HzAP\IT! W:e~e!e8(!{L c"<ǟHǧ8.31xWnccnڰ|$' $e%t+Q/ Qyp R+e-o˶&Z!Al L$2BSsd8Vu "2ʨ!dѠ"R( ڤZ("0Yxxgu_bSe,k[qs$n١,9 Ѷb)K,Πc+$Gz7kJGYG؉"Lav\)iDǤ#lVBܭ]]G:Ji[Ne!*i 1p@:Mt󞯓 u6  Xjz Yk)Lԏ0qxUM .=84{?D#f>|PH [ױ8Xλ}X]@@ybuG2z(/6DkQў!˔v)+ P%$5R 9xE>UQ l#J#E>@{Z ED f5J(#<귮C A^|zu"y=8!1fwSS8' A. Q0"AEVqlf*ǶTZ$ \ nE1FA8 jCOzMȪQm !D`#U_i?OٌY"{'@҈&2Uw -ol}-;_M4lęyL :kW@(joY{ U8i*r4y@fG[D߫+hԸ ĵKjӰ&Ю#\rQ:#7 +Y*j`Z2ըL#S/Б1l}k%iT@;dJ&㺰DS)f=L/՘S4*M-PC_ʯ||`BKH*1twS5)}'RHBX{K\+ -Sr,Q~7LޔDkI4$r_^ 7!D& rE^8A#"U&Sj)(U>!R9ơ FQQLum2bphٚv`t[KJ0d-1\zQ!ACf|  N㤂v!G&i dR_'Nf V{r&-aTRW-#;2]Vu@ *XJ;^ l:o VXpNNX8Ώ"#7bpg.cpɱj '-15?,"bX޽U(~D5V yGnD8 }$>п|"vC1DRSȠ' @vWR˲D655w"E'$!$S^Fk+ hhRx+X3N7l͑9ļ"a/mxC8ß YTQB^j#R҃3cuqUGdT6AB#¬FXpM@ߛDʦ3[o1@V:LA!Gj⃉R -@nHT#AMJ}ޞT Z_h5F#2 ijoNo@,#9*JbQ! x*kaMW6d)E"5-J+DJ޹!A-GXG1h[J -1ؐMR1Pe aT bsQVhi4/eʀ3BkfBǂ%PĻd+[n?Ek$Ue80ʖ- k,sB`e`(ev eBxedh !쿄L ?ds$5/.NDI>Y23XqѿO, 4Bx|_6-PCG|օ9LlꏗWᣋbZZN3YTA[C 3|쮲I'uIvrSM ^ENjj*#7<6|$huG 1%/c",,1&ЖFEJ \s.#iDPBbC]ۙj&/]2e,M/Pi}=t~ȠQ@6e))4rF\K=SCP4V˄2D-, 5UrNP5^#3sXI' )O-EۇJfJGJjVˆx"WB["{+ork5 {Cx J60aKD4#&W*D&W-AW8n5%*q|$&DQ7#3yh@p³}"_fȑ {DDL*4]sW0v<#J'IIt=Ƣ2xTfD" ʉ)@0.H%UjD/$E{ IDATٯ"2ɇG L2 ,,E%DlP[/w؏N!a%RFDa2<Vv5r1 +B D}Y1^Xb2&ްm5,`Ccϼl[ KH,ާȟ#_2n1 F]Щ ƒs`b0BR*U&nSAPjF,h\+DZ|-Z^)S঳4MQoqk$ )֪[VtmFHc}Dl|BZ7FQ)idst\Ke)ھegJ8I3hgHWBeg1'cM-AجylCԈ,G}$V'FL1Q*FP2Cƣm<6iT mD7,m TQǢ5dB1 ,}f*Qoo=93}yB !l]N *䳢_|q2$aL:,35D]6(G%hGPQ .eBԖ=jX*Y4&.^2;m=2( a%"" ׽m&6D_r3Kk[I8WbUY@teCZĮL;Yn|VA/y:4BB/m1MVF1IӐ&pH']udc1ЕȆ ul6hAY, hNO_| Gs"09p"CSLŃd̰G<X#02DtR&vggZ:Sw&Q&1>2q1-3dRT(#Ɩ:(nc]2v=#, BЫrOC`()gh砫ePO7%;hThUYyqi"9ZHY6(Yc QL2ځ+@ M?h,6A =2B󀤵 %)ZN\*$3n"YyjG2("-D+G/zHZk EObFtʎ3J1fKXfK(&Cs0dW.C2Az'kٗq5zJ~]3!9wq ln.=RAE.ieޢ֠sHVu_Sm@ oV+ W~n)~[E߿d!h] VLMO1*@z߼BKW W?h Js=V6+thhN`2jhP!'}2pHR`0ՖJq3R=>O߃A]A HfxumliT@;˄1"D]_FF˖ U<W$`L F]# "rd71rV("t Iz&Y}XRWR)}JvŒ]>z~ 8. dTEM.F IjÒA) (geYL1|)[!73^qhP`94 -8󂆦`?um.~9j ?\Nt=}odguҼϲ?0Lܾ[/znkVmzoU&AǟqA}S^Sk9&ze OwWĽ=όlFmߟ,.%T@?â߻xnzUP{0 /ȶ1f̞ "wNU"=4 7: "-#b=Q] Ó& ?!d3%":N`Լ rr0՞l:Q-28~<D(6&4 =AQco\L:{I+0 sC9r$ Bp1ID*s9jIŰ#9\..-#kZj,W42wjVȺl}gGdF% ET 5aJAEyƸ%ű(1 SnLwLKLAG̍,?Bb!L&<A!8wJ.+zŒ "Qِ]riE32P{ bH|ZU1C^u"χ90P yG3 YArsGkeb3+Oy`@,R}|}E6C&CnjrUBSNnԝO娬<Ҝe\f3b5N/UfJE[ƹaYKZEs7y*F%A -P#ԠNIo*@ޣHWCKpn8=X(fc>H+JŔ39ǝG%?@0THEk01B:Of}_5Np11Dߗ_j$'.4X$i51"ciQ&&GNg+IR&R$JUF1 ~h3T`8vc&NݾeC@0n۷l{uh~ǖ ==[7nM3_t+|7clݰo_ܚJgh!8\ah襧skELyGoaG{ mvEw|'\ 0W^7hαu}nmm]$ָُnZ|g<[?iE?iB J#Wȝ Gz1ZOn)ؖijY !5N_1ZS$I,bMB֬BJy 0GD)nk^[P~; ~zcU5G,X#wo5v–kj׌;18¨6fa1[]W% LK458֏hEI@]~gM-.lU/\`LpcVhm gxٹ N7^zv>3DaDmͣ@*Jf ~'/kU| M  $B>d hWQ VMs"."MHJ+YډkA 7G;Hkqv +D + S:$ }& BpC$4FHB;MkdNaqж!cj-1ݧ~Hb!Ռ. *LY߮ɁY862 ]qphB; P؝AIq-.IL&*N)DD#a4Ƒ2DbbKS3O5bhNz>ox{gp3kwlX][>y׃tQ :wn/G-y=jAm/A8g~p'}5 ϙvK۸%O{mܼ?iVp {uhm7R3mơk?nv_9{رyhm^Ľ=~0q>U-mc |?ߺ(SU=wU+^2 }ˏuYCSˑ x9 |ނc$aS?nj|􉧿 *a-־}%_YHqnBmYԚuH&GcchlA3JDRIJ^6I8jyل C8Hv'@rJћHl"- G*:(oQ$tr >Ǎ}hW"K8!`@_`5Pnz9t˓BW:D4~5}Y$hf͈D<CoDf8V k ~4] Hc9IL.2%?8lB1HG$]L9.ĚZZDH'-Qq:ΤahQH<ݕ^2)$K&Q 4qWf7&u+ YHÈe? Νg3*5F'̜%\P kQRHcaXN`:RM,,%{Uw3~qǓCMr% Op 3*>@cBZ1=Dp|; dْ TkTGQVH i%#\u7c/}G<=$t}B-J`7JQAXrC.E (ET$3%TK x>[Q]%;#DѤFhgD^3H4~,l98o Ah˶`_0X.0b> }!УT H YsyZ8HtX,J㥻%bIF![0f|!Mk!U9 $Bm+h_{@# Ș/9Bg!1N\FRDvn*GDMmѧt5iE!JR,B+ld2T ŸHtb>Ľ AIKhbD"J(B ѤR8<,)9)fveE*e\O)sl'GTmJpe*HuLJ.I!E1 E\:߹ ^:(Wbdn)a7" (_)R#BE ňA7g6%:MC%SLV;H.q/{G\j>(r'-*B Pj!-&? ZW]B.墍&֢! frH9U%0.$"&b|Q{WU6gI@PDn"Ń(QG-1ͫyEm$MIGw.j:hc ^2%=(^g9=7?:뜽z!Ibj#Ra5YjYKU>PB)f|nH*qic =ĺyL$_B'E"UԪ/<ԩ !ʌDv; 0HU4?nezzJ$5J ~2U}\pk9.oI2IIl%i^btIeZ8K%ՂqT5Piv}:3Ե7ehޡI9W<Bt9ue&#'rʠ6)44Qp (Y¥"(zʺDeb :6z8X>YlmY2*.ȣÑH-ژ# VpY߀HdTiDZ) Xxim吝`8 IDATwq8/0o+OAO #T-(!D\|GQL,;RopV>UVx\TDp;gyFBYતV?ᮭ$M–Mr2~v,z$F̚fI) /G ad @*ǐZ]ܸ"[JR'̉~QɵF\OqF*eԧ$y(%ĹZx (ՃZhPWI5)I@jMl̺S_sącJ %%uKD|aȥ~TmVY[@yFfWR .Kgù[MZrt9Hoj*Ox-x%\SNŲgnj.HSYkhjVj(Nu|>ΦRK=`PRi&8Yf9a" %,QK`]E҈;"DǤFі*mʒ,|ޘj&RW̗2_:1‡?B7Ҧ[ٮ) |蹐 x,8"I [)A̖gMdB= JG)/!r?ܵ?A\Vy̏?bjwhcKe͑#V&FQ[2,Q%wJ:]g Qq/]%񬴕4،ŏTBZDq_զzJ,nj BTs~ l¨ZhDiר{D sPjK} KA샔7u@auJhHf[q j+4Uf "msgG 3JJl A4&ɖ6TqcbPMG)MΠ5.휐DA =VA蘢>DګM4{.$iJh"4k8[a>r_ؕ"$ AfRJlÁMbA)rPU͐ɣ Ɔ-#@ACWl)..wneDבn9(. H+ K0UR2*e[?7e]3,v{q{#ObʗrD[p7gwwΝ;:t[w]Y^~<ݻwvv^v[o0н3g 7ؽ9/2 ڵk_ZZZjkllLN~1 0ȯ۳_7!!]QJ,~A*%*;$r(Vy9؆r, UfɊ9 Jgmc<=sf?-Zw˗. N~q9ڛcko&|yǏKCUU՚ _|U\䓽'>\hۆ _|qKVLCOM?}%_z5kT?W&M_z|VfEX[[kw}]y⢯4TTTO~~ڛ7(׬1_~i8z C9rO!BK4Iߜ~]~~'M}Z]MMM=}{Uz޽{wow%OYv>}I< |?L׫0pO߾}jxK/Xt榼gzxxVPMHȿ?XK&=dֽo݅;5F7Xy'i ԥm}q? ?6KK}}{ B Bqҥ!C)mlDˡ*.zYx@, zژn`Uf7,*@ccr7k׮Ch>>UU{%|W^UUUoݩS'd׉\)xRZVVN*ٳ{lo E^A*%*;$~wk.+_)_R5+BP+O/j3޲m۷~(qΜiicǎڵk]]]}0F (//l[zjg3F˛7o~q;w8;;@͍ʾZ{+R鍍O5j{o,Vlެ[YY=He$BPmvUֿ?0zڐSmT^fʉRP޹s`0X{X,Ih{ѱcYY'nnn/^b_b\b4FK/|)ϟZZd2ώ< |MSSӹs͛o3r_x[ܸpd3sbWׯ_|KSbbq;w^xCTw'q^A,CZ#FDsnޟbc_\^Q͛7_zi.)S~^lD)[U]ֿ?Y7"H;$oUY\HOk8>}z0s?׻woW_}ueʪ)OoX7nxo@xDQ2t$&̞5;00(}76n]$<<  Z0n(v''-^^G<'9yО!k޽*B vGH3m[ٸ۷1clvٗ'/Kr6xQ=|{vIP+2*BF?Y(8?BVokޓ]jcm' O bNthb#mۧFMyɫo@{<HݏO!b>ε1Sc0vQLXR2 KZP ˍ<󃔊9FA|E2+^G]ѓI  J*BDS,T(Ԡ㈰|B>ᵥōw9b?OFthw S(P""dXKwS >RTMZTpA?JN1;JԌA$!3A4 "Rb%iՀf8F"kE9BѢR* @1A CARt3@`׎mxJD@)@ x'%DVZz|fa~<1! O)b'9B'BQ D[l(yP+FtRqij1O Ujqj/g܉Tk 1H8'Lqp X,#Ixz%XA4Cm<<},e@t s 77|"v_xrD+LwB: XPu[@XzJϯ0\f{Qϟp OVՠ.X^p`C^jj,sاB ,p_' \9y1+:Z(*cM6effqqq֌cݺu>|U0aw},9 0+*&SKCgkle}K- a=bB bI2mfSQe֭oւ t:]< RZ]]oϟ?O>bÆ 3g|;J|>pt=m`+ZZµ39[#d>H+WHŁ$ibVn DVgqww?x koll\tippphhMZm۲e˰az ͙ qqquuuB;6 ""bǎ6jxzz>s_А`a0[o^.^xkpTJ"/!CPrRmׇXGF ~NZnO,%{:w$x9O߳g? ջ8*G-d[ |lu__vWˮi276rMűsgݏw %<PvvKc4/NcsozPJwqrM O$utP0zb֭}[^z%~?,4a)LJmWVV5wi yײu떖6n8ksP[[;\r׮]`4a%`ͱLB4{L&č9e32twyh`/nMi҉:Ɇz8~wuy'*c!M-\y^xnno68u#uyzV7<o6pSݽE|n~R*l>8~8Sl&M^^^^W^ W.;??gϞМJiaaaBB_|annn/^zzz)//g&vؽ{G77%ۑ)--2e owQb.  :gWMC)w\hjۜLQ:<˕Zҽ0пS a=}TkKd8?Qo7 _hmGe,pvx{dc[P">KC-zڑ  d^^,Gy䣏>jјXk1cƌIJ2TZZT΢E.\`2(&F5nݺozɓSRRFp<ѶwϞ=;wdi;ށ5!DpRb.a ~5RZ{RJO]1qOwխG}eupD[L-]&acYG%2P/:κq^_h{G/R~7=U[h~{K]l<>* ڤ999/1s^{mڴiIIIIIIᮮ .>^h0aܹsz=C9BaK.o299yŊ0iҤe˖ng^󟱱=!E#{Uѣh7>}ҍ#{Lxu6u?PixXinBnMP+lwWPto@Bjȱ6fj+2NXPQj]ڃ#Gy;]Ó1Dõeh "bǡ]D-H"j,{S o9D4#,8",ó7o7*ڂ12.Kz4!턤 b:RB$A/+)ۿ" \)_deDv08Cy|'A1yѬBMs @[PjI ?bPR=&pB[|]\+()Lh*OGLz-h"(2[3cl_&/T2s_5W^ IDAT0nٲeذa{Đ>|8_cǎ رcnsssffAz}\\\]]T=* 0tзzK֭[{cǞ8qb׮]#F?~|ii𑲲Yf/((h併#wz*4JVV??qDggg??W^yE+>"qP0 m"""ٳ2իn*ٷ(Iڑ M &lʢF-B!W]]}Сڵknݺ⢢ѣ?3_z%A?>fOHHx={JJJ6 gΜqrrP]Rl |ӧO_vܹsݻw?>&&fƌߵkWiiI>f͚7o`0 z>--Ƒvz*4ʑ#G`ڎ^ʇH='2nv60ѣGΟ?$¶_V{ڸxTGUl$bjkGb'(A~qi&ret@:ڳ@eo zwy͔!l榧{zzzyy^:77Wcǎ={ǎ=z4899UUUUWWmذA;wYu{UݝrPzGerrrn:aָ~^z9;;ϛ7_f/ Ч022ɩk׮ɇv] RSSS^^^XXxIggdMF-7>iPfffϞ=tp¯gnlQ%"ikGb'’L9'SBtOԘX *DΝ;7o޼+W|||ضhIddS{W}<oٲСCƍ>|}VVV5Jj/]Rl͛cccCCCwww6e/M&})S/88ڑ+wz*4J.]V\ٽ{ݻ߿_#I9HZ#޽jO7Uǣ*JE֎OP#=_ÇR :PX06vss[xɓ'Uz\Ŵ\0\\\󝜜qTPPХK /׬Y9ާNbͶ#ՃT=*{M6,X`%%%׮]+-- .TOF߿i _ROI,j϶TJTEɶHm'ܳ!OJ*ȻV ʞ\nz7z껓'ONII1F1%%%:ڜq̘1SNzjŊl6bѢE.\0LR61cFbbbYYd*--k׉{ٹsgvvvv]__X^^n܅(ӟkkkkkkSSSx≎?$Ģ)8)֭˗mlMĚ(Iٯv$~=Q-sEQSTv@\сM 2>{7U?l2}FQ4ׯ_g&L;wnpppFF%KŋGEE[;HkGey2޽^k%JKK 6mZXXβ] ?wĈCsڵk;(2|fklgn*DɆH~#M'j)ib]&%*d`cƮ$ـX5#ºw> O岌&?R Zo9PU=S~S ;t'hl=2j<V@P1FFpHy"Iln%O tҼy8qď?6b>} 8gk=v\1Jz"-=\yj}g^GH?Eofڴi#G,..pBFFF^^n7o^p_~yС].ZH&!jD ZdY5tbVV֢EfΜ޹so޼Yxl֬Y >}rܜ9h ^WWW'm۶-""" `gϞ.]#??-[ 6wxtv9vXOOϕ+W~1vJ3IPP- MD*&T--M!;;`09s)##uѼGEE"ׯ>~}9Җ=r8|СC;5L7"1bf pEG)8D}`,O5zƍ=zPprrJNNPZ;v˗7.33Sx+33{pBV?ܽ{'9zxx={655!&D֠PRсWxmݽ[ɓ'322;wrԨQ--&Iؾ~?,leG>>>x;&ǎ߼ys>}4&IhVJXfB^VW<>1bD~~,X0{쒒k׮REooSNUz6ڲ#G-^x˖-ZQ@1TMM(Qc3ҒLHHx׷o~ӧOϟ?_xѱ̘1#11d2111F1%%#Cy5kּ<򈆬@bfA@)!DP\(gj0oPPЮ]BI(JhP$HJD!1Am$iYCDA4)b\(IQ{̜8FQ~5D-? l dQ~Xϻ !=A!D,3Z+AA&OPIQBA4$m(SEHTTľA h9r2+ b$„f!hqLkާ\^yb\ǐH](ƊM&_!t6H #v9'5 dWS]=:(MsatҼy8qď?>u֪U}р<3?N{Xʷjjj:u!QCAѬ&4K `\ K%6B$Cofڴi#G,..pBFFF^^^G .ljjڵkו+WLª# BJշ6l0sv|. QHP"T#zH-ApSqA=21"~ĘZh̙3;w..]9rȊ+;uOTc޲e˰azmؐŋ(ɓ͹ ǘ }ViŜh<^$kӉs~N1Sc_}?,$TdĀ)ĜSAMC1s:Q-jRzRyAa\+,f{PRTB'בs(-DA-@iIJxԢ鸁@-(Ry0 P1ԅ6\*IEJZ%A4'lLKy%!'b~QAkyђ$@)T%Ņ&tD)T-AhI RjΎIyMhVTRpFRP@Q!ȃ"bm^-B lAm؟E(%Ѧ, W(B6%rjъ<:LK+I{Hh^R1((WƋnO :VB6)C!==ܹs͚5˗/߻w/{+55Cvrr۰a^]mQSSS^^^XXxIggd 7!1 賸=,5(_^4¶hu~?:QFYٟ>>>l{˖-ZVVVnƍXCteʕnnn&<<\k $C-kCB̕ Y2砒Kʖ%zj`` 3K:\z{{{PJ  cW|~#B.FөEͱ3f֘cƌIJ2TZZ-pdL&OSzzzmmmmmmjjO<5AM":;U{D "'CrrWdddddϲedÇ%KŋGEE~ ΝWW[1bСCܹvZ #hdZL@Voe:35o?Qv^>')b'l,¬' Hݜ@:`cmW+`t`~Qy "D05(U*03CH4 AeHļөFss$BB| v64K EA=%l(\T-/M ږe DL,:IeZFA*O+ &Fʲ4׶d31~T\10%2"%u ZV*ZR;-M-xfD#[-թ΃pk'psHhǃA% 2!Ċ`n5zoLDmf )dNz_V׉mmlGY 8&DmDj V jNAJ;ة@c3!BA)kɃE()5+S.EkӦM6mEM[Q $$Dh]`App~_xih)N# t,H3qFNE9Z'Alݺ555u۶m--8SQQ\B{rrɓ'_"M͔E4 D QAe $I:.++5kV~OJm۶-""" `gϞ.]*3T777gff4H=3dx fXۯ>4k455;^߿?--{ݻwOKK?qǑ-45SDj LYٓvg͚5o<`0z}ZZ{ѣyyyϟJJJׯ__]]}}9r*̙3NNN<999g~w?~֭>l'N`6{gϞO [(!hdS1ּ+*Ncج퟈+'&Y9ʇݻw#"" gv]h )++C޽;00\2rH{رc^ׯ7B־Pf>䓟cCCCXXؿ/{ o622R';Gw+̟?k׮))){n7ֿ !`UN[hSmWR"#Fr=Jk)gӎ'OꫯܹI ggg9 _ ۂ*ݿrԨQ+7Um|!c֭}[^z%{ن'vz_NJJ2dH׮]~=zCjT,DsA -HLib:aBE(_ DY6`ٳg\vV ^^^W^ن O:",]/lhh?ξرcvjhhOOO_y/^̷㭷޺|ӧ}}}###!57sZ A-(B+fm NmBi3ѱM &&&55h4 0̘1#11d2ŵ ̬Fp|G>#NOOIMMm~etxʁ^x￯O^y啥K HMS&3˰246?҂M&{>K, /j<Ӳƙ3gwqq 3f̐!Cڸ_qqqQQQ5`1`E:6o{w>d.Dthb IDATPn  *B v!Xf`k~Lwҥ3f;v o%{#ms"/@* x;:HyIT4QVPPOMMJKK0aI9T0D%C!w(b_{=bĈ#F%&&dW! =X#@|HT2 aܹsǮeG-R hP)B1&.,AaBRXSCM 6 Ba%Q@(.du!h, #b4 !p{ e*]8ցeɡq0؟ A4kdxK tkc X s WeA,{Ӈļ yiF<rLiHu|8DSK(0 AA'Tu\k^!O 2$2DP$ ]{PH)CT>Yh8!X">e6 3f __R:zhL0X066O>|gF#A=HB"BTrMIY 78;;eAAA.]#ؼy… CuUYn˒BBьUh`9іa"R'JDemѢE7nd/7nVmnn4h^c֭[{cǞ8qb׮]#F?~|iiЭ!111$$$$$$))I ;vl@@@DDĎ;j;w;sʕv! 3 z MM-(tieP&,ltĉFɓpر7n CAA3g222[EEEw>|LĽ3߿k׮I&֭,...**X~p={(:t6 1G!hT HQjlIt  F믿5k|}}]]]/_w^{}:77ܹsӦMߪ5jP<44pww6e/M&m4m-[:thܸqÇ߷o^`qرٳgoڴO>HRN#$t|PMqmT>AT;PB1ۨΝ;ϙ3'>>>))s[={zj`` {xx999„//裏RSS}GyD #TmӍ S D&!T$g-s![]dIYY�cƌIJ2TZZ׮Þa„s疕l"-- FZ.\)<*h !ޖL2(;W KAC vN>:~䔕%xtt4maC%JDV(Ղ$ Μb[~HK+ɡ,\ƒ2 փ()hԁ\cp@b2^5 &E0#2 z[E 9@@8$WG-TF4GXh")˲>Ѯ,6TpYܡ!TL9٘]CPEJdX#s2b V*˯4NC`=<H*AV.u"#L{\8b \B c&:Ԭ:jGE~~| vhJs $@u&ѩt f(QĎGR5!h"|T S`J6)_WJ P3rO Jѣ,#0% JaBV HggO?,((ҥ bK-! DÖ h<[Z!%TAhѢ77n677gff4H ;vl@@@DDĎ;l4͚5_~AAAӧOgEッCCCx f^kҖ"gDrR,CDDH4*}L8h48q m@pqA4mkaۖԼ.\(z\\NǢOaΝk֬uuu]|޽{v''j?? 6h,,,trrڵkrrCUVyxxxxxmC%LAm 4Y蛚 O ~7vT,=}tnnsMƿUYY9j(!2"4496lrСq >|߾}6O<9eʔ}ׯ_ݻ6ڻGiZEMڃUK,ID(g#ss̉OJJܹ3w~~~Ϟ=e ɡ&$$|,Xjժ1cƸՅyڵvڽA&: jA,Ϡ8ؒkT .!VK,)++df̘XVVf2JKKE]pd2QJM&zGGGGG$555555k]{DzT, h[JyRn/[#K, /fq4&L;wnpppFFFvvƬiӦoNJJrqq 3f̐!Caȯ[DՄ"e!h(T]V.S?L ܥl.]4cƌcǎ%F~v^|#R%f.Ɠ b;PژY BrB T% VUUM0/3ˌ)PA4 DoiF"Fr^atDS{1bĈ#"*4A Zf1g6UeB:9"_,(C-+3wܹsE~#PB)%Dƈ^x:ƒ(ÁOPBApjb(hUt۔3RY.)`  ?nGEA2 ZCfb-dV 8ا*!'QDWf!,BH%RS##)ePDZcE(DJJzy$ 棬ѤAė/S)1XSL "ȃC:+a8D B!EmP@PB[-7^8,s8M ZA-W(5kC*Ֆ Bd)%L4 ZƂAѨ$HS @u@"6*CNM,XWy.]7o'N,"Yt۔Ҍ0 33SCZ:;pQjM SfRHѩDI*VTTTTT;::.[ofڴi#G,..pBFFF^^^p{ǏUy}}}|||ppphhoL;6 ""bǎx ʮ]}|||||wՁ)N2YBAl4LMT*s(mɣG?>**]n]eeeqqqQQQEEm6 gΜqrrP8:Z άY͛g0 ^OKKfׯ_֭>l'N`.^gϞZ…   _0r_(t!EA4dk^>1DIB^jȑ#YKfffϞ=tp¯JhMOOZzunn;w\fݫ7z ###v횜ڑZ#55wrr۰aނrmavEEٳg\yÇ^QCLx$DjB.GmI&I/#dPB"##ܹn:޽{wad2 F_}+++G%"44Tշ^SSO<9eʔ}[{-l زeˡCƍ7|}*㕢@NqW9ٮOOϫW@yy={gĈsQ`UV3յ.$$Ϡ#vZ@@\v ɡ&$$|xڦ_~!22 o~eNGA|1 йinD Q*R'XA(+P3," o޼x o;:::::yǟȣkjjjjjxE.\`2(El0mڴu?úubccٙ,--5LeeeK.xS('=;4 DjHh &$_^INN򊌌iuŒ%Kccczŋ}vu{_~+V`Z*+++---88xڴiaaam?N5kG6f̘!C88 &̝;7888###;;o>7`G=z>'Nd^SOzՀ_EN:AZTB(Y%WБHsmج퟈#b"T ˞RɥKf̘q1<7O94xrDCG 4߶J:f2rҜPF?:VUUM0O9 Xe!:Be=%XWA޽G1b77D eA4(_,rMbK ] v )ąD#[ 22K^n/sH(-%cA4-|(P&)1bNF$o[VZ裏 0g)..3f _4R:zhdgyZDsUFFF I;}EA- 5- R[ l)… vuʕ)S8sSvإ,E)VADE`5h4QXA%J؈bĂFԅ-ǽw朙.$<ܙ9{ջEEEuԩ͚5kr}/%'N|c=';(^KBQ1eA D wy+ܹs**--8pO>=snw=r-ש馛zݭ[#Flذ!|}ڴi?Ϻt~M4)Nj;zٵkSN9Eu w{oS>6}C&O|饗k׮]v^zɓcDuG>2K~5oQ`۷ѣg̘QUUeQGr?{5k;v̙3N駟~u\p%\2gΜ~>ivYg͜9s̙ݺukoO>_7z1dٽ{ݻW_}{^x?o0p())%FQwF2W7SNFc=7f̘Jng}vu]#F%u{믿C-Z_~˗Z[ooѿK/7 _ƌSZZZZZʻo7z1dƍ͛7n޼ƍAɴx_!I?#D +NgL@IIe]6mڴofҤI6m>|8СC?g}/2d6mt҃>8u{|1c;-Zlذav жmۅ v.\ы!={9sf`̙kHHD%yjM,928dN2eʊ+jkk/^|7>w{mCsꩧ5j޼y555f1bD93{욚"bUUUAAAAAG|1\wuW^z5n7z1dȐ!7|e˖-[v7:4OvP%7=B/^)Y$>^>A/$]tE=!ҵkAmڴ{m 5d~ڭ[#G*/aÆun;vlok{C ۷ѣ7o޷o;O>t{|CN9~z衇zI'[OxZ?qAp [D"xV={[}%|_@Dc ~קz{SS\D6@a1~rx#qs,ٲ=;Cɰ5\SYY|k_IMӎYbx?5RQ:uF?&Tl)HN 0`-[5ʯ&)eЋ/mӆlq>ҔS!m* 6lذa~4u;1 ~^x7VFh5O $u yi 5Kb `h}O@֟>B ~{;9(8)$^45OPwxGQ 1 . YթM"t!/yNJ4e@#CEɻ^"_NKz6r[0$&DU zK#(mY*R:s ~^Ћ/cjô%BATF$KS /^LBLTHIz)dңrЃׯ[Ndɒ͛gqƀ~.Zh;ҒK.'OXv{pE]$ԦDjժqw{WJAK(<ҥK{kD/^P,2mwy+ܹs**--8pO>U[[{M7ݻ[n#Fذarx}ݷW^jk׮O~RYYkW^}ݗnWm۶^xW_}e˖QFnѣlْu%3gg}|ATWW?ʏ̓^y!1oX}=zƌUUUƇƎ;s̩S~駅7pz룏>:uE>G}T裏j׮|'|ロNkjj SOUTTTTT}wɻ ͤ+s1Q-[|gvuWӧSO=յkW;w!Cf̘n;?~{vC9d=zoһ$4Xx#U^vmiB( {kJj))).2"oÇ?t҃>)Yݻ/ҠA^|0^ʯ|r\T.rW]uɓ`ʕꚝ;w^resp:k(/Bnv|-+B/^VPeh(; ͸hܑ0w~u׽+3fX… w6lذ0}ƻϷ_lȕ;8r?0m۶ ,?~iii੧2e=WkȑQ'|Q/,0YHD.Q4#1N2eʊ+jkk/^|7Tܩ:jԨy̚5kĈ:C6lC5o|22dȕW^dɒu]s5te%ׯ{P* 4ꫯ^rʕ+c9&СC~;v_I?\MVTTԷo|QGB xS-52aLi .;Cv:hРM6{[{n~ڭ[#GyI77lذک.=z~￿6g.Ҳ߿]vrJv|ɧzoرc9 QsjxWAcVtk!X&XSyÉ.??^s=XƋ|,CH+>ܭy#SPO2D /^)K~JT70ފt[MF4(Tg^xK6C!r=KՅ1 /^#$U$]R^؛GoËh IePnry ћ^ k?NR&/^N9 36a\>AΣ 4=jK Ћ;Bm{i?U?/;Qt#w xCuy'itA~.a.؂$0_{%_53_J#H|FT۾ܶ󊰉Iϊ,R޼E_ U5;Qؕcx[uqk^6,wo,CuÑλm?eciZ>_1awT۝xpݱ]B"BP z/^YAG(-JnzMqv~ڷtv*>oǶ%6UOtٿgXQZw}|2^M}ߋǜ׎Cmm xWpym^֌͡ϽpR)<7Ѓ:?/T(wZpJɷ|12'4>ޡwQk䵠/yUD_ >wmO}T/ ߪkQnVZ~?ޚ'+6$}K#E7\j5i<z !WFTSշcEil:j5o߻/߼WهsVϏ`OziLҭCe´oWnw Ȩ/y*(`u!E@N!l5.^9尝yoU[k Oi7Kd=޹I(ws_7p _tiJ'4i6__qǿۀM| /y/""w(ZA&F3頺vkMm:N;+3Tk6l/"8Zfsؐc_^6 ujIO,1Fr*‰o|;gg+7Vɒ>ڄovͰ_vo[Rlm#}CZ3 [x 2cq'4|Npʼn{W~-յ;axj+AZR1ˌtsWʂ(Kю,ph;j Qhx1xWsj4SD3Vz/^މ3Qzz{@#Lpc?4 `"yxKQpLv >inExijjP`" /L%=$%xi{(E@^K#T  3uP/^AwA{%ϝB#D]ªثA/Mv}̠>/^vDd-A 0i.`G-A/^hE84>I"'g/^VJL鰀]J1!/Mrnⵠ/E>KHd4/M~$Q/^>tF10KӳIz"JO/4S6qϑƧBZ$zB|%@  8oqeTT`Ũ*ƺ=2ZKsVln -"Y8 aGh܁Iqx 3O[k}1HO #CR]c\ш4Jv0sRw$ { QUEijf]D[! AE9w/H9DI֣5'n4 ۈW-Tf/ 0_z*A\=u~2d9fiLA wi.L :gZ-ZݜhhK1rbSJuj)~#MbIܝS=WDߴxBa-A] ӗ *&2&3 0HcFO10"2-gXĿ"Z8\u"rhAǸuO6>"`t7H|q-.MaL$n B$C&vҒC0?<F-TzZXL*|0Ґ;P%9?H@Yݹf~H29Mqz.xWRy"t$E1ULlƛNk$v5rDP ?xT 50\ XL%R$~|hR>"4ë%Y$t9h*K)$(LC϶TU`mP WUMX's%B}@nܪCWJ\# <$f:G ZZP+G, z*d)L#uHDkMEc 7:5e N>(R8oN<@ MXOMI( ٚZC5v̢j-R{Hi J6bJlEƷ2J5+m;~e<*<0v:T09m[qEqFBs~ѸH0}K܍V2t]҇M iO._U$<Ӻ&XSy!i "=@Po#㔍YRH>"ROm y"iÓܮa&Fy;l2n ؽ4NjFkVbG9&q}ƃv0\dBjl#J 5~lP3hFEҁ@(`Qۄ"F4Sx㓟 B(mWLD_/ЩBl,m.3ڑ$a!;^OaaO"3Dq̑\%vKˢU:9 K֠0!Y%eaxCuo !iD(HMb啲Ohmޒg#Ga9  !Tڷ#Z0kqlƣ^UqmrIMo*Fr 5`@uuu&h BrIX$q7Rh{$)T"n4橲4&Xhwȵ"Eq\"$$4o$qAPWhU6B4Fq1gcA)ć1 i̐ P, qZ_XhQOMl+K'3FSN!;]d d3Lɦ("qx (tt#eO"B(JTզkX.1-3A6YD<0H$KG湊v)"  W{rڅ-d8ݹU 0O.3EG7yE2ScίA+bE,a19,&m;vm|S֡%=  l^/ Vçq+GTt2Z)nO"Ky+-&ŧRdXk܏sƥB6b}&_1rZXxp%QXd[wn )NP&ȬǛȪɑ%M +E,: #$C*@&PޖDE044 A: 0ӓvєihM8D^ ODMrΰ"j:UQ%*ʹs.[rҨx HRtHK#"thd7V`U$~l=2PG.QZU FsDJ S3w@s@:Y-f.;YGD(E4q*pgu>ŊB֫6\Ǵ"K0E=L! .:y^)JND#&<2t3hnBk9(!}1oh]S8x0֠䢽t e 3t+[u 4ڟE0 +nȪ@pk15t62 ZG&rP _OE{kڎ]q !7b$MxԵkdPxaE!198ijRQV-@cC ::S!dyU&& ;]c<=2E <!Ga,yX4DT0  JQH_1@b!*ޚgItYvI_2 Z򘳂51Bpkj*?ײuPlZu@C9l٠|rD8HKEhiZdC;&Dv&kNxx` ; dAI%`laج >Lf]v8/{fE59Ma ]6 M;j#bЗU!zjKc,; g^X1:Nu %&32V8[@*ЀcEJGdy 7zbꇘMH4 J#hm7IU+ϸ ,RfYW:%$a5]O"Ap ΉYN$ boY "P0]AiDi,P &*B;Jc!aYE#W1 #Lp/L`XՃ SvQwl2f+vGQ킨PE 9 HfB0BF"HW1Tա\Ow<]3,9#d2IPOIgZI@*Q&,UxEBԺ)ŇT8*o*:B1`\؄hZ` BܦIEmVr ݏ /3iqN[IGP?*|dTTxI5`6' ^IMq@0Z2gHv6R\rB'-[dm RqM݀$LQi",:F.ڊK0${#ׄH ߐ䅨! h,NQ&-;f=DpXm,抂YhИ.^+- . c]H.Yr}7r0br&>(:0Ds{ רRs2R>s\PRK]M |ðdbq 2Du%"<CS[sɬDHu!,! ;-Olwy\7ɪH! zPV>cN!hrk*z:?.m#w $^)aLa)=&B'M4+nIjY(;4@rwaoo ]I ;N NB!2=cӦyՅ`)X# ]x6ǻM7 IDAT 5P~z ym:p/١"%`Jȑy QIqgt/˴. 8EXI L ZQNG֙N -9hrM#hw>"+BASV!$Ҹ?y#u ^0$JĤIK9SQZ) :W#9bf̈ . MnVj'69sn 1#p֏Vmc8rd1B&9rh-dn"<3&\$n;X|aGѻ#7HL N]hAk$R>I #Cvd҉i"TY'%zIУ|3hV ɏ F7%ōJ&67_8lmqE"$i 3\iT A=(w&/o2V[0`Au|̗s^4`` jK g5S$٧Uc8rdY,^&z:$42*HՋXntLuitE9)-pf/Q} tx2fH4Fh2YY(̬@V.) ڽ8)& #$u!u2*)iJ.JZ&oXAp I>l!4"F"iNnJQb1i[呍tq!?IetYξ{ݺH:D; (3(XBc+e@W*0vE}y[i:<)Q#jsag')N4`D̘U& H3H̿Lhkm?߼  DpɌJҀ^BiF;Žd %!X#H49v49bN"o  C6JNGs}E ؠf4$fn q66Rf>QmMiЍ#%utl!'E];Lʡ13ljs%M6"{|cP1ѦR0.r̩¤p 1 U$ZJTFqb5i ƨ@\%P_GW`Ө9#wdxAХuS4:a0G6\8ȋQnt0 D#5Al "+x܎fBEYpA&HL \i6w%@Z"7)ĝ _ݩ=:ݡ??#μP5FI]qs4T"3-\@}Uv-R4e3͜i 1@٠$ޫ%2k-TA3eeu[G6=>և1VBU[ʯ!*> tOz:pߧd0ouMm=R[(VM)dJ$}IL[bވf$_6 PuVi5VEɴ!q?RTY9׌o.)L:qL3Y(**2=4 SN 嗢l_+t($Rr B0FQcU۩em>uTCvo V%L:r4hXd/[lpA] 12[V4{"=agIޟFEW9:E2I;"ͽ78kR4ib-7c_~2}ݚUE;sm„9R q+pg@H]F:o+ON89#rm6(L`ߵOձ-[1WBAx ce2sWWov=DʼnO t^L"R<8»>.d@Mԩev8*+E"(ןSZ.tx[+oiSVμR[MX@6dRأmfɱ̞'EIA&<Y8EzA xt D.D. (/ 2.CVAudD;]|&ƈ'YGPW,9b1VD'A61WE tv}5":Ji؋g=9 5'9"YDz<2" EJ; o\%rqmd$`aJ  K3ۡ31(Er8BaYcp^ rks{LJ7 U0ۯ>"@Ⓗk{kWw|wܩ+To2>|z0aLm ?+w 3ޝO'aM7;EZ?Wح7g2.E͚V/_̤rfmMm=z[3<ZrfmMm=z2⒒y텧̖>t&t}?%|^WWۡ^=EK\8^Prq6? ;S'U{ #Eˏߏ?'3lա rl= 7| !ϓDAݥΉ{G3ׯ]}ɍ\|=kWx^?@嚕OKf;{i/@tώ|>W(|>n!DZxwzf҃p>Կcnkw]g&>fsMwk_|r"/N?:׿zWkYq 'soG>gӞZpqǥ3^{,}㉱7_?q9Q"t99IQDwBўa;idJ/C .ػIwD!΢F:UHEɀ=IL/rG9(T2dc6:U2o߉ᤤi1b%@TT*HBv/H\N@G8ӊh#XHŀ rϹR)S"-U+QsC`eQw|6N(fsȃҺ@]Y< h1nSnoF\ڪMsSnY/=>n jy :֥l_df~ѿּe>w~c>~9|2t&; !/]? {|˜O#F%lڰ.|7}ޙLCN곏Qe7sޙlCN|>KZ<>|ūnۡylQ}uٟKe 6_]q]֥N~W~g6o6SЬQ鑉nZz-K2°IB.Y~1`2>L9;l Г)ɖ!hBYHW)q$ZFQjEEU4q*WGE'ѦPY2'*j j 2M98!F j@ n"#{BT KΈl!uT6KU8v`xP dѫ9z58_Mb(EIwv!2W;F&N Zf?#;V-_?{?vrYO2قpZ6[۪]6e*P{Mt?}CN?{/ g|{oq}Ç{㥣Ԧ[yqIws2EnR+̝3k/ ^ڶ]螔[W&f/???GN6w6Ut'gsr> 0$cDl# %6Ar{#BDZF ( :-9APG$4ȬvAChXɲP!dlDʡc0X(̞k$C@ۡr@8Dp> Rb] 2CtjcT<ձ$4d5b*RZfZιhPL7G  18(,qm2`K-Ia&bD|r0sPk.=>'J8S`vϙsdž1sܼض]Nvㅿ͙%֮\VZVX֢%d ۔w2n>/>y}K֭3ޝv.j׬\6~9LVÆ(b>Ԟ{#w|o'} Tm(u'{>EE[0Du+ 7wSXl 7]xr8eqڥ@૏zo'_ t΍[zKhr#01ҍ(#=7bFM:@HZT Ux0}Y΂tf粨Ae"2ȫf% %&, e;7:"+<Ѻ4"dQVr͎IAс1dq:: FB9)٠@m~iL(,ҩL$S0EPr!9[xgr89,`7kI~Шܐz~g㺵T[WfOOة{6_q}勏=ثAa^}^<~%?ܫowޥgrUѺmN][nAeDnY8ox^q ?Yuk:I3W.*PԬ%Գ>ͬ^wf҃WnX{!Fޚf˦>~dޘ׵/~u+ծZ2ĿIYlQ]m-ձv$A&vׁFBMM!ծ8?@]cfTƔK c⅀$hz(iQ>Od}K:+bjѲ'{XOb}ɢ'=G"A>y[yEV$jH8H5u`gOVz6S/'Q$X\ H<n7r(>V(@7D+:ct`1!'-z`ܓKAQpPW9i^ um@ءG8_/0-UZl}ϟ={دG >Iv׾83WWػAлA/>1^?&{xı'k*"<#_{h[AwصO/%-Û={lwԲuGd[zؑ2-UU0Nv޳=tM-[vn{t-UU{pq fX޲uϏoZY˞^-W-kY\dg^zMV,{GW'~g'] XSTͣ(MX$P  y#D3 [NZ3!QYXq 9{ʿy)Ht}":K#rer-'|<2F\IC[O 6έӱ#N[4+/HI\FT><^QI70$NPRRVK?^Z"CLf]jyuu0Z#Z,,xV?)8Q(E,b -D¬U)p;~nI?6 k70%r4A0 p+8VGE[dDƌk!E⺹8 #K^QJV%;7}MU5~]&T) qѸÂc׋W#ۓps 2D2hj4![ k`^ .44bLሪQJ1)<ê ܤԱ:rXge6rx*G_C#7TڵH+Nh[2AgV1l un\l3m;~"4Wʓ.dr  9&8m HMoQD=3r] `Y#JI/߭S6 GL2RO "vݵW:qJR[['8Gh$ +6P\)p1fT819EvK;۲>I$|19eguaE9~v:Zn1ui) lLlbl]_!#(U5D8r$r) >t(&\hIR;B܊W B',@KcĪYEOBAJiX$eʍ$@s[bTGuBNZ5yvn&&ZMEz űO!X :!ph𔢼{ x0јvȶ2)1nEj4K:8?ȍirtd8'@$UrSWV`PD@/xTà{ J$X+Tݑ(A `IDATDB3KJ'AurH:2;"! S,L*QXl GNN#q~#eS*LP-5T f'dGg2pIAkct0Wukx;u !t1Z+C_NB]1g_L|R+li7DI% 19t(I6)W-eYaI+|/q,zn5xFݪⵂGh\TtOJGPTn:Wp;!-7( K[fhi[+ԅ:"3szZ P}:"p:9C-U% 9-9bzx˴\zs[UDh\dlM~F BijvԑT۶VOraO9|B TJ(FY*1BpB]2\a1(&4cL6JKfdtٴL0>GR-$ T$}CGvD3NR J A44ɥ -21|MY]2+­_.A ezײFШsm 9@Upe(^YPr8T-3h8F^^~j4NCb+ƀhɨJrd#XG'cG3@в?EO@2u FF3 .,}k@tEjSIaBV-$EN]%8B+C:*k3dy,5.ȈpUCZ@a:Yh[]"'n2EB(67Ѩ\Q-Hz@SiDLX Bz#+l} H ׂr1;EFtٚW%Yઔ@G%\\Xoܬ7e-R{˔yDA9f3+lDiIJds ?Ӊ0US T+6?CT A|5I ͯ.AW4V$SJ1v72H9@@-Z!$ , .|jLBEe&R`"N&K''B9(QUfftŪ$( j*x?G4 tFp\ۂ &j @+rjD\qc>! w8M?zD7rQŠqgX!t}F"ب ]gB>}Xτ9ĸGڪ$+\g!tnj/~vDȦU84d @̂[/|:"IjgkPe7 Y6ҀSkcC$ "ejD@{Ơ´ZH9MG=^m:[IXf,gpG黣nwF̨ t, 4.ZWSD2k7YG6Q=yT\~;<4a*B-5LMC'`. 6Üx0R3 r2+hQrT/@ΑBB7kOGnt36OgdM̈́RjT]Vvv4@Eb( 8(ϑu#<&i'}&[,r92`Pnh7 13f {ǜA  pp2}3"g c hQAm,\ŋ/^xŋ/^xŋ/^xŋ/^xQHtz9#N<Į;解v<ػWkdSWa^" I7߰fͪL:aEEKK `\M]üExOښ}mVZ5nEp<_uKzM|qK5=9~~~~yzףywz8r- >~4֩K?^?^?^?<=̃Wҹsaa{$'-MX.irxxxx0'JUV?$[wRQQQHc</^x W^x+B/^쐒Ju/1A"Dt;u~MpI2w9ła:ݻ7$+]_16=-y`w#Xڒ=r뭷z뭍X̚5kȐ!͚5ozꩦ>u#qG^@2L6mg/|ŊfhQQы/~}5ko-^;R#C]]}wmuuurs9k֬;vOw55T%[nQr-FR;w۪U͛}˖- _O[nEEE'|=/СCqq'nݺW68Bý۽{f͚~Gvm?3?;v,))937oM6mڴ>|͛ow9ɄfWh7^>d.s?~}衇91/jjȑmڴyWUUUgqFIIIEEE,~ǐ5뮻nԨQÇoӦM6۷Omڴ+VtI|\Nw[o}sY|5\xW/Y//,X0f>>غukuu5TWW?P׿G?'O0aވʽ;rH1b=ܣ^3fʕ+̙3cƌ7xwd6mڐ!CoxCˮz7_w^˖-wEkg{=zG,Zx_n$=3p_{/ʲ2˖-SH[t'y…ڵ}qw[]]}_niyXtUW~f /;uܱc/2/P7o^#✜zΣGy.\hƛ$g.++[~}uu̙UQQF_Q$co:޼yw &+++wֻΓÏ*omڴ){7?k*vnrCG}t̙?֭[_uՕ~:sƍТEt:USS^o,Zh=Tߒtq[_92꫋[[5~wޱc;,]4yٲeß+*:.[L}mR>u /lܸ֭[tI7tM7غu4^}+V(..p F]QQ"zhۦMŋo~+Ct>Q~W{1c\}өMZ9bC=_,XPZZZ9csD2f#F8묳9l6˃§z̙~%K۱f#-۷= և[~]7?Z*)&sw}$oӻc9ƛfΜ9a„I&{7|h͛7O8?Z>ڵkF"Ÿ^/琶izO?|+Ct>:*^}ӧO?wֻbQC=_~;pꤏ 9\rY.4^߼ysAAA6=zzE[<;oܹ՟i/ޫ^wqƍ-Zt؊0tŊ+V=C _?F|˗5w^e˖g毴hQ\>9|@lܸqذƍ{p_~_O=6m8'|r}y'J.O>EDCzGV_׏=/2~իWWUU}ᇿ)>DCocљLf|c,!UmܸO>=z#L+x'}r~<}]^zYv<*¤/?]^3w9^8#>8`~c=۴is_uU{wo+t^?蠃K_vK />|HDկ~/1^wg5x3ϼ+hժ{~0@[?d\?xwe)Szݱc_r խ[N:iu!1<⒒ˈ#ق~kvj9cI֋;{֭[) 4h=XfN]V+׮a'Ǐq/xsxH~~=o߇j5O^VW%?^?^?^?^?|"ʷ_EX[[oСCәŋ4֩K?^?^?^?<=#7~f|UjJsVVAN]av&m]7m;vбEcL4jkx嗿?^?^?^?<=)d2ٳTm ֮߰-ۧo1M]\:yΈ3N;eKJKMMӧ[P7u'Ǐ׏׏׏Q^xŋ/^xŋ/^xŋ/^xŋ/^4EgO} IENDB`barry-0.18.5/doc/www/modem.php0000644001161500056700000001620212242254476015460 0ustar cdfreycdfrey

The Blackberry has the ability to act like a Hayes compatible modem, complete with AT commands.

In order to make use of this feature you will need the Barry command line tools installed on your system. See the page for more details.

You will need three components to connect to the internet:

  • a working Barry install, version 0.13 or later
  • a working pppd and matching kernel
  • an options file and chatscript for your Blackberry provider

See the page for more information on using the GUI to manage the modem.

If you installed Barry's binary packages, specifically barry-util, then default ppp options and chat scripts are installed automatically for you. Currently there are scripts available for the following providers:

  • AT&T Cingular
  • China Mobile
  • Fido
  • KPN Nederland
  • Manitoba's MTS
  • O2 Ireland
  • Optus AU
  • Orange Spain
  • Orange UK
  • Rogers
  • Sprint
  • Telus
  • T-Mobile US
  • Verizon
  • Vodafone AU
  • and a minimalist script for debugging

For example, to run the default Rogers connection script, use the following command as root:

	pppd call barry-rogers

If none of the default scripts work, see the Troubleshooting section below.

Configuring PPPD

Sample configurations are provided in the source tarball, and if you are using a binary package, they should already be installed for you under /etc/ppp/peers and (depending on your system) /etc/chatscripts.

Copy the desired options file to /etc/ppp/peers and edit the file, making sure that the paths are referencing the correct files.

  • pty - must point to the location you installed Barry's pppob program.
  • connect - must use the correct chatscript

Establishing a Connection

If you named your options file "barry-rogers", then to connect to the internet, run:

	pppd call barry-rogers

Some systems may provide wrapper scripts for running pppd. For example, Debian uses "pon" and "poff".

If your device requires a password, you can specify this on the pppob command line. For example, if you are using the barry-rogers PPP script, edit your /etc/ppp/peers/barry-rogers file, so that the pty option says something like this:

	pty "/usr/sbin/pppob -P password"

PPP will display some messages on stdout as it connects. On success, you should see IP address negotiation and the resulting IP address for your machine. PPP will then just wait for network activity.

When testing to see if this works, use your web browser. The usual method of using ping does not work reliably, and some providers may have this blocked.

Check your routing table to make sure that the new default gateway is there.

	/sbin/route -n

Depending on your provider, you may or may not have a firewall installed when you connect to the internet through a tethered modem. Keep an eye on your open ports, and remember that connecting to the internet this way may not be the same as the network you are used to.

Also keep in mind that if your system is configured to forward packets and you have pppd setup to replace your current default route, and you are still connected to an internal network (say, via ethernet), this could allow outside connections to be routed to your internal network. The default pppd options files installed by Barry do not use the replacedefaultroute setting for this reason. Contact your network administrator for assistance on configuring your mobile network setups.

Some devices don't respond to the PPP commands at first, but after the battery is removed and reinserted, modem functionality works. This is likely due to the protocol not being completely understood, but resetting the device in this manner is enough of a workaround to get it working.

If you still run into trouble, the first task is to increase debug output and to log it. PPPD supports increased logging if you add the following lines to the options file:

	debug
	nodetach

Barry's pppob program also supports verbose protocol logging. Change your options file and edit the pppob command line. For example, if your pppob is installed in /usr/sbin, set the pty option to:

	pty "/usr/sbin/pppob -l /tmp/pppob.log -v"

Be sure to remove these options once you have your connection working, as the above causes your entire internet traffic to be logged to the output file.

If your provider is not yet supported by the sample options files, you will need to do a little digging on your own. If you are able to tether your Blackberry using a Windows system, you can duplicate the login information in your chat script.

You may also find example configurations for your provider on the various Blackberry forums available online.

If you are still having trouble, please send an email to the mailing list, including:

  • the version of Barry you are using
  • the output from pppd
  • the log output from pppob
  • the ppp options file and chatscript you used

The logs from pppob can be fairly large, so limit the size to a single run.

If your device has Bluetooth support, it is also possible to tether using Linux's own native Bluetooth serial drivers. There are probably better tutorials on this already on the net, but here are a few notes from Michael Brown to help you get started.

Bluetooth Config

Put the following in your /etc/bluetooth/rfcomm.conf file, replacing the X's with your Bluetooth BADDR.

rfcomm0 {
	bind yes;
	device XX:XX:XX:XX:XX:XX;
	channel 1;
	comment "Blackberry Dialup";
}

PPP Config

Use the same peer file that you would use for the USB tethering above, but remove the pty line that points to /usr/sbin/pppob. Since you are using the Bluetooth serial port, you don't need pppob. Replace that line with the line of your newly configured rfcomm device. You may also need to specify the baud rate.

/dev/rfcomm0
115200

Chatscript Config

No change is required. Use the same chatscript you would use for USB above.

Run as usual. For example:

	pppd call barry-rogers
barry-0.18.5/doc/www/requirements.php0000644001161500056700000000720512242254476017105 0ustar cdfreycdfrey

One of the main features of Barry is the ability to control the charging modes of the Blackberry, as well as changing configuration modes on Pearl-like devices.

In order to achieve proper charging, udev is setup to run the bcharge program every time you plug in your Blackberry.

Kernels older than 2.6.34 have a module called berry_charge, which does similar things from the kernel level. These two methods can conflict if both run at the same time.

Due to this conflict, the binary packages are setup to install a blacklist file under /etc/modprobe.d, which will disable berry_charge as long as you have the barry-util package installed.

If you are not using the binary packages, you can use the sample blacklist file that comes with the source tarball.

Recent kernels also have the ability to put the USB bus and its devices into suspend mode. Distros often have this turned on by default.

When bcharge runs, it successfully changes the Blackberry to use 500mA (its normal power level for charging), but then the kernel puts the device into suspend mode. This can have various undefined effects, such as the charge icon disappearing on the device, or having your device lose its charge in an accelerated manner.

Bcharge attempts to work around this by writing to the control files under /sys/class/usb_device/.../device/power/ to turn autosuspend off. Depending on your kernel version or kernel config, these files may not be available, but in most cases at least one of the needed files are there.

If you continue to experience trouble charging your Blackberry:

  • consider upgrading your kernel (Ubuntu 7.10 Gutsy patches their 2.6.22 kernel to fix this, for example)
  • recompile your kernel with CONFIG_USB_SUSPEND disabled

The Barry toolset performs all its actions through the /proc and/or /sysfs filesystems, using the libusb library. This requires that you have permissions to write to the USB device files setup by the kernel.

This is handled differently on various systems:

  • On Debian based systems, there is a group called plugdev, which is used to control permissions for pluggable devices. When the barry-util deb package is installed, udev is configured to set Blackberry device permissions to the plugdev group. Make sure your user is in the plugdev group.
  • On Fedora based systems, ownership is controlled by the ConsoleKit package. This changes ownership of pluggable devices to the user currently logged into the console, on the theory that anyone at the console should have control of the devices he plugs in.

The uberry kernel module conflicts with the ugen interface that libusb uses to talk to the device. To work around this, you will need to boot your kernel with "boot -c" and disable the uberry module.

Suggestions for better ways to work around this conflict are welcome.

Check out Bill Paul's notes on running pppob on FreeBSD using the userspace ppp. You can find his notes and scripts here. barry-0.18.5/doc/www/hacking.php0000644001161500056700000001353012242254476015764 0ustar cdfreycdfrey

No BlackBerry-related protocol project would be complete without referencing the fine documentation from the Cassis project, which tackled the earlier serial protocol. You can find this documentation at:

There were some major and minor differences found between the serial protocol and the USB protocol. Some of the new handheld devices use new database record access commands, and in these cases the record format changes. See the code for more detailed information.

Further documentation on the USB protocol is planned. Stay tuned.

The USB captures were performed on a Windows XP Pro system running UsbSnoop from http://benoit.papillault.free.fr/usbsnoop/index.php

You can use the convo.awk and btranslate.cc tools to turn these very verbose logs into something more manageable. Other than the normal USB control commands at the beginning of each conversation, it was found that only USB Bulk Transfers were used.

The btool utility is at the stage where it can be used instead of UsbSnoop, for database operations. You can use the -v switch to turn on data packet dumping, which will display the sent and received packets in canonical hex format as btool talks to the device. You can use this in combination with the -d switch to capture new database records to reverse engineer.

If you reverse engineer some of the unimplemented packet formats, please send patches and/or documentation to the mailing list!

See the doc/Hacking file for more information on getting started reverse engineering the protocol.

Enjoy!

barry-0.18.5/doc/www/patches.php0000644001161500056700000001241312242254476016006 0ustar cdfreycdfrey

If you are submitting code, please have a look at the .

Please keep some things in mind when preparing your patches for submission:

  • use one patch per logical change
  • test all coding changes
    • If it is a change to the build system, make sure that the test/buildtest.sh script still works.
  • include some commentary above your patch in your email
  • when mailing patches, try to keep one patch per email
  • do not cut and paste patches... either read them in directly to your mail body (preferred), or send as an attachment
  • add a [PATCH] prefix to your subject line

Submitting your changes via patch is a good thing. It may seem like an extra bit of work to create a patch and post it to the mailing list, or to make your work available in a public git repo, but there are good reasons why Open Source works that way:

  • Patches tell the maintainer that you want your change to be added to the tree. It is often too easy for busy programmers to misunderstand someone's intentions if they just send a random file. If intentions are not clear, work gets dropped on the floor.
  • Patches show that you have worked with the source code, and hopefully have tested your change.
  • Patches show that you have given some thought to where your changes should go in the tree.
  • Patches to a public mailing list encourage peer review, and show that you are ok with your code being included in a public project.
  • Patches to a public mailing list or a public repository become part of history, showing who did what, and when.
  • Patches usually get top priority from developers.
  • Patches make life easier for the developers, freeing up their time for more features and bug fixes.
  • Patches turn you into a developer. Your name can be added to the AUTHORS file.

Generating patches depends on the method you used to get the source code.

  • If you are using a tarball, expand the tarball once into a pristine directory, and again into your "working directory." When you are finished and ready to patch, do:
    	cd barry-work
    	./buildgen.sh cleanall
    	cd ..
    	diff -ruN barry-orig barry-work > patchfile
    
  • If you are using the git tree, you can make your changes in your own branch, and then create patches for each commit you've made:
    	cd barry-git
    	git format-patch origin/master
    

Submitting changes can happen in one of three methods:

  • Send a patch to the mailing list.
  • Publish your own git repository (perhaps by creating a forked tree on repo.or.cz) and notify the mailing list, indicating the branch you want people to pull from when you're ready.
  • Use the "mob" branch on Barry's git repository, and.... send a notification to the mailing list.

The git repo site repo.or.cz lets anyone create a forked tree based off the official Barry repo. This saves space on repo.or.cz, and adds your fork to a list at the bottom of the official Barry page.

This way, users and developers can look at everyone's changes and test and mix them as needed.

To create a forked tree, visit the Barry repo and click "fork" at the top.

The public git repository service at repo.or.cz provides an interesting feature, which allows anyone to push to a "mob" branch of a repository, if so configured by the admin.

It would go something like this:

        # clone with mob user
        git clone git+ssh://mob@repo.or.cz/srv/git/barry.git barry

        cd barry
        git checkout -b mob origin/mob
        git diff origin/master..mob             # make sure master == mob
        <make changes>
        git add ... && git commit
        git push origin mob
        <send email to the list, include the SHA1 sum of the commit>

This is a novel idea, as well as a security risk for anyone who blindly runs whatever is in the mob branch. Hence the recommended diff check above, to make sure you're working on an official branch.

The mob user can only push to the mob branch, so all other branches are read-only, and have been reviewed at least once by the project maintainer.

But the mob branch frees people up to use git, who may not have their own hosting, or who may not want to bother setting up their own git repo. People can use it to collaborate on a feature as well. Let your imagination run wild.

You can read more about the ideas behind the mob branch at the repo.or.cz mob page

barry-0.18.5/doc/www/default.css0000644001161500056700000001565712242254476016021 0ustar cdfreycdfrey/*----------------------------------------------------------------------*/ /* BASE ELEMENTS */ /*----------------------------------------------------------------------*/ body { font-family: Arial,Helvetica,Sans-Serif; font-size: 8pt; margin: 10px; background-color: #E0E0E0; background-image: url("/images/background.jpg"); } p { font-family: Arial,Helvetica,Sans-Serif; font-size: 10pt; } a { color: #0000CC; text-decoration: none; } a:hover { color: #0000AA; text-decoration: underline; } a:active { color: #0000AA; } a:visited { color: #0000AA; } table { font-family: Arial,Helvetica,Sans-Serif; font-size: 10pt; } form { margin: 0px; } ul { margin-top: 0px; } dl { margin-left: 25px; } /*----------------------------------------------------------------------*/ /* MAIN LOOK & FEEL */ /*----------------------------------------------------------------------*/ .pageHeader { font-family: Arial,Helvetica,Sans-Serif; font-size: 14pt; font-weight: bold; color: #313472; margin-top: 0px; margin-bottom: 3px; } .subHeader { font-family: Arial,Helvetica,Sans-Serif; font-size: 11pt; font-weight: bold; color: #313472; margin-top: 5px; margin-bottom: 5px; } .linearNav { font-family: Arial,Helvetica,Sans-Serif; font-size: 8pt; margin-left: 2px; margin-top: 2px; margin-bottom: 5px; } .itemHeader { font-family: Arial,Helvetica,Sans-Serif; font-size: 10pt; font-weight: bold; margin-top: 10px; } .note { font-family: Arial,Helvetica,Sans-Serif; font-size: 8pt; font-style: italic; text-align: center; } .copyRight { font-family: Arial,Helvetica,Sans-Serif; font-size: 8pt; font-style: italic; margin: 2px; } /*----------------------------------------------------------------------*/ /* FRAME STRUCTURES */ /*----------------------------------------------------------------------*/ .headerFrame { border: solid 1px black; border-collapse: collapse; width: 750; height: 80px; background-color: #FFFFFF; } .topMenuFrame { border-left: solid 1px black; border-right: solid 1px black; border-collapse: collapse; width: 750; height: 22px; padding: 0px; } .mainFrame { border: solid 1px #000000; border-collapse: collapse; width: 750; } .contentFrame { padding: 15px; background-color: #FFFFFF; vertical-align: top; } .leftMenuFrame { padding: 5px; background-color: #95ADDA; vertical-align: top; width: 175px; } .rightMenuFrame { background-color: #EEEEEE; vertical-align: top; width: 115px; border-left: dashed 1px #CCCCCC; padding: 10px; } /*----------------------------------------------------------------------*/ /* TOP MENU */ /*----------------------------------------------------------------------*/ .topMenuCell { font-family: Arial,Helvetica,Sans-Serif; font-size: 8pt; border-left: solid 0px black; border-right: solid 0px black; padding: 0px; background-color: #9C80A7; } .topMenuLink { color: #FFFFFF; font-weight: bold; } .topMenuLink:hover { color: #FFFFFF; text-decoration: none; } .topMenuLink:active { color: #FFFFFF; } .topMenuLink:visited { color: #FFFFFF; } /*----------------------------------------------------------------------*/ /* LEFT MENU */ /*----------------------------------------------------------------------*/ .leftMenu { width: 100%; test-align: center; } .leftMenuHeader { font-family: Arial,Helvetica,Sans-Serif; font-size: 10pt; font-weight: bold; color: #FFFFFF; text-align: center; border: 1px solid #CCCCFF; } .leftMenuHeaderLink { color: #FFFFFF; text-decoration: none; } .leftMenuHeaderLink:hover { color: #FFFFFF; text-decoration: none; } .leftMenuHeaderLink:active { color: #FFFFFF; } .leftMenuHeaderLink:visited { color: #FFFFFF; } .leftMenuLink { font-family: Arial,Helvetica,Sans-Serif; font-size: 8pt; color: #313472; text-align: left; padding: 5px; } .leftMenuLink:hover { color: #313472; text-decoration: none; } .leftMenuLink:active { color: #313472; } .leftMenuLink:visited { color: #313472; } /*----------------------------------------------------------------------*/ /* TABLE LISTINGS /*----------------------------------------------------------------------*/ .listTable { width: 95%; margin-left: auto; margin-right: auto; } .listHeader { font-family: Arial,Helvetica,Sans-Serif; font-size: 10pt; font-weight: bold; text-align: center; color: #FFFFFF; background-color: #9C80A7; padding: 2px; } .listRow { font-family: Arial,Helvetica,Sans-Serif; font-size: 8pt; } .listRow1 { background-color: #FFFFFF; } .listRow2 { background-color: #F0F0F0; } /*----------------------------------------------------------------------*/ /* PDF VERSION */ /*----------------------------------------------------------------------*/ .pdfFrame { border: solid 1px #B98A9F; border-collapse: collapse; width: 60px; margin: 3px; } .pdfCell { font-family: Arial,Helvetica,Sans-Serif; font-size: 8pt; text-align: center; padding: 5px; } /*----------------------------------------------------------------------*/ /* STYLES FOR NEWS ITEMS */ /*----------------------------------------------------------------------*/ .newsHeader { font-family: Arial,Helvetica,Sans-Serif; font-size: 10pt; font-weight: bold; margin-top: 10px; margin-bottom: 0px; } .newsDate { font-family: Arial,Helvetica,Sans-Serif; font-size: 8pt; font-style: italic; margin-top: 0px; margin-bottom: 5px; } .newsLink { font-family: Arial,Helvetica,Sans-Serif; font-size: 8pt; } .newsHeaderSide { font-family: Arial,Helvetica,Sans-Serif; font-size: 8pt; font-weight: bold; margin-top: 5px; margin-bottom: 5px; text-align: center; } .newsLinkSide { font-family: Arial,Helvetica,Sans-Serif; font-size: 8pt; text-align: right; } .newsDateSide { font-family: Arial,Helvetica,Sans-Serif; font-size: 6pt; color: #999999; margin-bottom: 10px; } /*----------------------------------------------------------------------*/ /* STYLES FOR SUMMARY PAGES */ /*----------------------------------------------------------------------*/ .summaryList { margin-top: 10px; } .summaryItem { padding-bottom: 10px; } /*----------------------------------------------------------------------*/ /* STYLES FOR CONTACT */ /*----------------------------------------------------------------------*/ .contactHeader { font-family: Arial,Helvetica,Sans-Serif; font-size: 10pt; font-weight: bold; color: #000000; margin-bottom: 10px; } .contactSub { font-family: Arial,Helvetica,Sans-Serif; font-size: 10pt; font-style: italic; } /*----------------------------------------------------------------------*/ barry-0.18.5/doc/www/static.sh0000755001161500056700000000161412242254476015475 0ustar cdfreycdfrey#!/bin/sh if [ -z "$1" ] ; then echo "Using Barry default web doc config..." for f in `cat content_list` ; do echo "Generating $f.html" cat prepend.php php_conf1.php $f.php append.php | php > $f.html done elif [ "$1" = "netdirect" ] ; then echo "Using NetDirect web doc config..." mkdir -p www.netdirect.ca/sites/www.netdirect.ca/files/barry/doxygen mkdir -p www.netdirect.ca/sites/www.netdirect.ca/files/images/barry cp *.png www.netdirect.ca/sites/www.netdirect.ca/files/images/barry mkdir -p www.netdirect.ca/pastefiles echo "For index files..." for f in `cat content_list | grep index` ; do echo "Generating $f.html" cat php_conf2.php $f.php | php > www.netdirect.ca/pastefiles/$f.html done echo "For non-index files..." for f in `cat content_list | grep -v index` ; do echo "Generating $f.html" cat php_conf3.php $f.php | php > www.netdirect.ca/pastefiles/$f.html done fi barry-0.18.5/doc/www/backup.png0000644001161500056700000012076412242254476015632 0ustar cdfreycdfreyPNG  IHDRYYsRGBbKGD pHYs+tIME ZtEXtCommentCreated with GIMPW IDATxwEڀf ,р "***SODTĜOEQl=.0``ZӲI: tWn]w2\T?oB˅(bNb&2,i5ۿiYH{)[ Y:=j1']²uN%mRX`1Fh;v5i׭1y' E^!%|ٻthߖB٤A(b7`\GG1bRR-4olN[H!м~i\xÈQ qPUQ8Li\")%ib&Z#@J%%a&isTfK~1)>7i~ Cw$oCB!&<}O|N~e6 :v c.Tl/.`ishNy@UW Odպ,-N;!K~K~:e! S"$#ռG~SϾ6mZ<5^arO躁q3'/4Lۙ&޵ϭҦeky~T%p!@\WxzD 4L :1|XŬ%(. 'ϫפm堩*iSLn92*yEi,H44{WPS0 6tyў.U]l[ϏBϋ߭ ;#\ô I<.Gڑ`6AB!4c>Ӵ E((kֱ-Y4,)Ya3lCa ^/^PD,˖ZBU-ACZЄ[g4LU a-LG* eN psLINFpkJ:'jChq1Lp$J4E47n b`Y. (eYD"Q‘izpi*% GbڜeyX6yM x{46m`沭|5;GriE!Dlvz4]7HO !?ĵ/.!z\H eٚFcH)z%\H)Q D3H/aH\DJu8)%& `ZK?fKIMxsHfv*0툸v9Ң:a ؖ㴓g{Q)7#[ȓ0LӲa5)+4 rŃNJN4 :eil۶ŋ.f>/GƝ`UYi+|(;`=p=hو[9x?oмy !Ya 0z||^ xݏD akxs3tmݘh 2gڕOf@uch% dB6oΧK\qi;"RcٺB~n2-fsL;JK˹}܅hOqq)]{3_|Ϡ~}X**Cѽ{$]H\Xo\^H1Cbmի( *5b@Qx2S/q# MEŴjF^a!8 ߙн]K^ߥw(u I0 J+؞_'Ç#Es"EQxGOO'WW1s!tЎ0g : u۹忋SyeaꨠB'5 !Jl륪:J5/鏟ˤ[r\8?piO1ҒhJܒbp\(H2uHDHŖ;RU[cܶuk%+7+EEg%-Zԓg=gӱ7o%k0=6W=9aN<) t]GFM# +ByEcN'l+i<?V"&3[#u3׏8=͂W/yLOAvF .~)/%啨fϗ(s"nCgqHkcI[xTn#ZϥQ\A7 [KJ]9ȱ,PTܚO󟛇N$ZLO2}O1sڵHB BSUKLj-r>o0L*ʫ1e=xIJ,jv A:J?~>xd~|$s8G@@Sj7*H!))<^[K9XH*MZRvgؾy~^L,႓{L [+3c:;+~ [qk ݶ g7៯"+csZ54/io{ VqûyG[#/3isVӸQ-<2Xμ1̙ y*2cKiֿ i+[8)2]Jg_pV5iĔK9o"ӞͲLE(vk"޻csҾEĖOvMP CE'e$ Zd>Xn|SMyws"0 +KX`xŴ&A]wECeU'ޚwF0t;RчRZ(,aJBR?na\Xa bOR, d6AH)&'QPǦѡSG(1>)y൹ CRR#=zd|Z5$ ӥCKۥT#3@ ڵRP\NNf:L>=;`LX̤}\V!mIY+xՌu2c.9/^-C~*~~,xe 7?_mš ӹS;?{SRoy|g~\OYйјmQ=|t y`E݈ƢR<(ۛv9*#ah{֓WH)%~~) EX`)Eړm>&(CtfiL_'zOL4E`%²0 K7N9l Bq%fSF#rMZv%q[%##@ " EQ%4n҄.Dma -RS*+*83͚ѵ}sb1!VN$  >Da8 sL6~iCʡulzwkOnO̢"Dff&PLӎߣ%bv~CӜ :㢳F1mܘ3OCIE%}xK1s0999TVߣrޞ? Z5f@+n80114Mvg= G퉢D7M @* E%!4!0b1t=1 *g<(>jW?똦ÈPzchJ'fCZбXE,FA^׻=iaZU!H0(J|8E|:@Ԥml8Rd/ CD"ujvP_0LMm֤q膁eZh*x TpSءgҡefB&r˕XV,TUEӴ4MMi +~ƃi8jR 'Ùq Wc5ULM+ӢelٰgΤױ#"H( w1gꋜq()lQ@-73vTYt?l0)s EɧEiD4%Y|NtUQ|#|M#šM[hܲ#_-@.vO[LJGTMc|/Zz:v-rPU%j-^͛ݧZ6A9CvjAk 7A= sݏcEŘ$ogLmF*+H gfD%#qg_XN4Roȸ[1˟{pX9 ˅r #@GQU\.7B["d "X:kI0`! 6nAUmOeI~[6%= =,,"%T`r єҒ f`M+`ݖm*Q5kWEZ*Gpppp$묂UҳWZ+e oX" Tf? |k>F0ۙ=۶3a<ģ\=$9#~tÍ"Į{$ѭ&n߶YϦSo;5@fmHOc>-cUVRve Es6mܜ8gG&=gv/]p>ߋC O$Y@:׹躞tܺuiM`QQ獪`{#Ҥe˖h՚qWK*މrʰj"3ymZs=/E@lvNgى6oDlߑOee%;vQiG|LNr.*TYWZ1qTTGfl߭,*.<^~P1(++s,}>v',XvBb}ܳ0rH{}齑[{ilFvao߶e9&MYa=gH[sc8888bcWb.\6z Soy%E LӤIn=NuXFbуޣ_R$v>v"۶nՖbY7׭_~;ï5@n&*P,T$f1-P<kk;88882 ĒX29_bHC"ũ-:Bh9w ("I4PG wR|:!@LӤe֨ iHMśvFUk^9_#@.HMM4(~V^W]ݧsef%4Bԩlg稚5kWBa]>:8888X4r<\uU%Թ hM܀pS @ `1,’iFT >76:T嶅iB!"H B1ըJ $r#aIdH)lT:wlq*iϦ2|J ,]|W_~q{L Tx=})a$[˓[aY ),(L|:qȐ]dу;ݻvc,O&9^/=/Nv%E4s7D1gn/y8+Wбcgrs((,`Qo1(mڶY/\)%hN+\ɔO>fG]@e&JK/e;˪xl@٭'>J^ݯUǩ?X4\Ln$\uH>}ܶcGSN>5Qޖm[YaYٍvʰfNXQngt%@)TVѻWoƌM&ț. IDATЍI^Ug2i8TGl۲osg'];'3UmwT޽XǤڶn 7Q5&j?Ήo'gУ{7:-[h"DE}hotBvV6Ï>L?)!??p %yGva\_~mۖfMmLwgS.zTg[J68hBj9(_p!;ʉ8888Or7Ӥ pbW7}kL/k׮`Г/5w.B5v OH`#Ǝ(nMoxc[l#ӊx'Nu4fϞCj(wb 1'o۶i`Zz$ӈQ^QSr%HZvfDV J 55EѐҤۃPA4%${žT^$b}k//M*+*x=K*þ;@*+@])))5dgJ˒>׍WP-wuz}FNT qppppp#@ke%-L4 'w@j*ݐ ͫ9$?"&nzREHKpwem]ǥ <9v@Z!Yt(BЧЯC܄:1 "%aO CIt~+v%y9IaJm4h9?̥Ïe#Ӳ0=8$n;$9BWr/XN;!PTgT`<Ed9GY"f o~Ofi=QӒ{#@l,i<^ !>N;,,i!.A S?N>/UN;e(ӧr '%eV@sjFt99YH [ an텙=PUX!$Te!GsƮ]wŵmFev$vV+#BUVUjE_qv%a\nzG(x}}eDc Ej|q)iYEœ0>.PO[GB-iJF\{;\L){4DƅI,~a1h xg -D K"4 Es-+#IFLڵ?'x<&K0`ӣ=G}B=Fkۑ Q!M5qw5i+I&t־֟v8餓)Q]OyVn@]G\l)3NeY >-֮e+[y'ǵwy9UM ҒbLzy7&"%M~h$N )=DcQ5m%mXͷ܂i\{uNΝ;ձZ8Yӎ˗3c ?b^}ߠ>XN8=L1%ЁSܻ:%&vg}Jue%A#sqJa5X^ KZI Degp3R /&O вe xǓKO&e9Y{cnjaԹ0Hz-}?B$۶[j Mr$ًG~0UVz]8^R}ے\m/<ϰOck WH &N]+I2|Kxeҫ 9D]տ?;5>T?a֜"mG5-kШQ&g1)%^#qlΝB(nS۴M?8K?!qI!8Cv֫۷Kc&h޼YbOO?b{ 'f$[~Q~7 .n.B)QB8li)nRS!HvQ_!Ѯ-ѠVv+RP]y7ѹ̑);=cW3yMwD-=3`;͚JD'[t wsOs~6}]ӏ[6!)ѢyҎAҴi՗ wOߣ,.*C ͷޚۇFYw sMt.r7AḿQ#tC0LfStѓ#G݄n[1/g…t!q|2s|Hw߄維QX3 cRVVFAQ1n9 g@FB N@J*~$/+-!ш-72v̝7z$;on>G_OM;*(~i۵禛k۴~׺Uڅ_?< ۶n'H%075il ܒrRξe6LV}%~h8?H4ôiұc:ґ~^C?ʬfqù+Gy~3 47Yj-=0 r 3xwvfm;^GgqLpswyDx/GÈ1裙??K󺨨0Hj1i/Bw3vmpd~k%ig ^Ⓠwy4%3zk2 8+mq<2bzkVJeU%X۩,#`D>zhwRĨh4o3YYLo"EO=$@x@\q<9//߄5r\.j&- ߶_|AR:z۶J#b:˽{Z嵢j.Ip*Ȯ  7cz 0 6nڄonvRrwr5װddN§INV@\]p&s`&%ii̚5 jRbYi|ڴs#2yʪ`듙gIkط'QR͖ܘc07xYYg= p+9f yd7^: WQUU EU؟ZڤWwZl/W?'E4BQsE7_ukyekth>RRKtq6ZO\V2aJޕJ֮^s>WR)6mE_Ԗg$ej)lyGޗ*,o >Ύy|1G?-ٰy~oB;o[IBTU﷭>'%qѲ]?ezRR O떭 ;ePw+*JuNٰavc=TUEU48IiII$4k|vؑIM^&xqqcnDն0:Atc9*evCz[ hӶUNH 5!'q|^`׿o2 7ޡ}#3ir#4m}OH?&ga'n%saqm >v0Bڷm˄{mkGCxiѲ5BV[[nw}!l;)B 5n={rqӱN+[Ux= ێszKsѣ"j>F_6!W_~E .P/] ߀"JF1!n6D$Դtڵk?AYtcƌxݛɿiv#%Hun0/i#XǤ7,uPeKLF> rSSyǫnl.T1-7m[q{<Aj0UѸIӄ(,," =Jii>ZͲrѤ<"6oڀ 3+;h p\#eʊr^.=ۍ㍻IE"$4=^/|1S8-7yIMMY0&unEݫc#j*++<| &gQ B̬D6jJK `zۓlVVEcɭ= oN~ &+).4MR:"i%@$\]Ғ" c҃Lm<|vlO=.A -7eC;qnl-*em!g= uYr7v{]wgʹi݊`3g|cJ>ƪ&و֭Zw!Z> #FIMKcH)iѢ7of2{,ZjÜP5ngXMw&ר"(;ʊ3tvavyN0sU;v-RL@ϮFB6 ht;vWTT;1ӿbY{֬};_RR M D41Mk@nڴmaKm3oo=Pe%'8-0o6u* =4z9EcOXtSVȔ'3j1PW_F<7!CO!=e{Q)g2MC-ݎ’`L,Rz_CקP: X 5=ϭg ?pK_CP\Tx5Vw@Dib~]O<Ua J*c:~ /oۊƢ77oGpd].10 4e1G5[6wQTxN|~UQYAE]E '}W|.HO7c.DTMXPƾY xMr% tpppM:'KRUUw@L/mieKg]Zeod>,aӧ~eX, buo8ձ[kv,[wmGs#P4 )_#qAс7B5ôdo.гNwpp](/KmI0:mrRX ۆf~"1Yv? zE_a4p$J}gv a&^֔^7I#WJETVW+%1<܇pPu5>.+]S'OɊ2w٫hӶ=P0wKJ,KS{sSSw9o}i%1{3Vug1^)%i85ఏ4u R]{LW#2 k#L",n<*9tB#a|fF5~}H ^R&R С}Ŏ*ڴMoI{8tLw^9ק㖗a R<=>wY^PTWʻB$#F( }~ozn ~/) ,S&>@UTCD"~{/ %׋ҒI LˋYI~>J԰HitoA'9E Y;3 &0an?V^M׮]F͛馛xy'+0 ކӉv>ρle稲,uC*lQ^F( tSbp-.,KxTpakeiYUhnJ#K4ppu)B Խ\]Zxx*¤ @&KVTP=]ɯ̒01~}rӾu{F^t1tE ̘mE5k](`0H H朦M&/))! ߿u'LWai}N8 /_5c]t*LUVeY )/z7nUJ#BV; %IL7inZl.iZ'=O^TtJ*H)PAĔdhiQT#ͧ()!1y5;CT񸰐 ϫ1R3%`f+@qSWv듸ivWKCWU21r:uЍ]rr.[`0Hѣ:t`i|J͛IIIgϞ0cƌyCM6oߞSN9%"33]ƍ9s&5Etޝnݺz}*cjՊmҮ];ڴiÜ9s|Kvc=v1M/nǏCٓ:jbJn,$ձ(ա0 K I8nA$j\V'zX6PѳsM8`S).LEKm#sb B1ʈɠٜ;.{XYвLx<\1x~$HB!p,YK-Xg+FRRu~6S| yyyL6 )%EEE\zq}Ѽ2{lN:DG\PP@$! QPPiRR^^ΦM4omҶm[f͚@֭hҤ w\3c 2x`~}ƍǓO>I8ѣG$'=z4|>$G%}7drss"6n8-Z ,Sֻ?nӧOz;vHwիFIXfM{yWYx1+WsK,I[i={D$?1bzٕϟ7|lu*Vs!;;ȑ#kW̮BQ]Q # /K%zE{/e˖vo$> ͣ/GXIH,N$$׈5bqh,IYE%hq=n$":GXXjTPL%W=pw@}v.[ 0YrСY8c5jTy3f;tR۴_|ر\wuر#=K.WĀl۶-meZ~!]qqq::Ӯ$o޽{~{k׮~R8 ,8hW0`o}[oQX ,^xеkW[(v'W^s! ftR#}:=yyy\G K"eY!$$ )eR'"Lgîۋb$&kw9mP,IL8׆q=a ^JfA~3?? Va0'fʢ|, Ĕ,^7N̔5bq M1pz(3\pAۧ: W7ͅM4w,Z(C$iӦgT <ÇrW0p@5qEKɓknZXx1.+nܹ3ǏG4nȐ!okPG1rHn6:uꔎݬ]6ݦM$뮻VZо/ <ƾ$g}vڴiS:v4x`@zߍ}iӦ۲jP1av͢Ej8O;4ƏUW]y㏜vi?I C]w7tSN=rliȲ$+$5x,j䆭[, 2'*woeھ|KǵؔMa2#w|3xu%םf?\y.ä1aHk>~~n`p` T=c$4d:SzhV+믿G}DϞ=3g'tDӹ:%b &IEx,it@QCǎyWjϷr{%M2܀'ғJ, LPU'qK"4D 7Rp2qhDVxTTY2$,HpTkG4aObnB8}N߉Kxܸ<.;2Hv=żpiY<v܎;UY$sxOo zMM'[QUBTI(++#33W_}/Hd/Wo]w83j}^$rrr+˲8p`R+qbUUٳ;e–-[2e 6l8 [!cYF2I,GAF,{zv Q Ue^=.*PoH&Iƒ(誵TIyҞ wP!7PYùNTCU[{'Ģ1CACWv*<*Ĵio…_+{'<ęg{_kڵKP%"3`ŊtޝSGQQQ}[?IvvvڵM6xqHiI׋%DpTSTTDnn.;v8me0eDoS*RI&e!{o(!KBIω۩A8}@s.|;nG2Pe|tpPC&$;B7-BQ-utsNh;^[Ey8AvI(skQJ˴1vq1~_k9 cyk#~\(OlIӠ~ fEvY C"8,T{BӒۥ~88S'ћ!g0|ԉh Nwс~,h_f$ypJo\3W2n4r3ørs|zwXɹZqL +Vp yΊX6{3os9(LKz&iOyXO{\_7A":#z6~\ی?#3'zX?م/,%I$-nZs!-ݴkc=Lx',cFBuHS( %{hnT( %qT{u2IpJBIZ~Bgxai±\we:3o}eK%(*N|[YD$n$˙rNz ]Yc T C2 dUA,nф%LK"ۣhܤ~nć<$ZA-$4J uͣ}3?^[:^A2-%$( %0o| ;+y,©[bJ."*%8|&$QGax{tg:1Lu;Cϥ"Equ*ZO[cOyɒڛGzvexhZZ^_./QJK{ݚb_go5tDMgukswcK9A'ϼkKeg%Y8 C| ۵OBimx Ev,G%:#9ϘE4Rn'_O*p8v5d 4*1t E/$|Rh;L,iiQmIUdO%3!1bٜv6#+; L2MSk J?`ˏ0iiIhrb}0U"0,J*tmA-yyM~g%=eb2A,/34{1%ZEAI*3\95~~ڃ N :ed,<.Ͳ.x] O?Lfɦ0-HTVR*1qT[zϤEw$:~DN͌? yC!;/_Lie F7Wɏ2wߍnXB3`%>nD|n×+ 1f~Uxvn7`齿w0<: 2l+ _cIV˪,=52- };ÆbmeOJ+5NBI(->Z˄eOfԷ9yAO7bEAi,ZꆬX(УM~9vP4A8p0wVʒ|gcsVb1KF7M$ J*<>g5|TD5^IټŠMHϡ&8d0,C2M2$e{fߣPK*Noe)|^Fn9g jm$C߰yبS~ I YTNi #}lqMgV^nSrpŘ}V'v䮋n{3STǩJcs;$o*Kк-짱ae8o7%Awe.3Eݛ]YI4˅Yn/HУy> 8U>rvd8i ,@J:USSFۥgyp煽he౹,\;튍z6?a_bk)7SOfܧ%ks\ڟ6s)XܠCD,LdL Ld$$$ٞ1M YVF0-*.,vsӄ|m}ufڮ alFvSQQt.Cm7=mye\srk:g0y1SC^anf PU;vл5KK ˳O?ׁ$IJ葱1LDf|N̂ YFlgkwkJxyFZdQO72yT;.%k<:[eŦ2397^ť3etG# =e1n'=f1w kL?7kwV`y!eP^qǒwK)cOyZ%'vGqqq=xCdT"XV vc) 5e{\.VogVӫݰ$jDR&ˡs:,{L!uuE(j=*IPL2&>JR%tÎl Z iq*$uʈF8A^HX~˲x}RôhTD:d ztE& |.ݲdT -5PPnc^%OR%E0AB7 E$zȲD(iB xT.W*=eA4-*2A3TD4*,D%IE2R40k`Y*ciEY;dYT:{RM}\NEC,N/m6ex ױ,p9dVakg9~v(IYe}:P01M$X,_U9~_N~W͎Pu,p*2A`w;T=u~G=%ۿU< .6Trwx"ۭʸ*y~mo}.'>(oȪ=NJu@ө~-u\2I֌ Qy6M rp]7e<,YR=ȊiMOT%J֯N+HdMbnlK۩LU4 SQaoozHgi^dYFuG 7$IGUeY{dSC,,a-Y&iLiEe؋1Jqu'2l\-=u֥$- 0 qȔEVc1|񇣳]vQ\\M6tˆ0uT&M+πӏ4n ɞ{-WU@-<(Bpx[!(OKRAR2FxdIK[iL#ʣaetDlא( I+X]{*DO$1]b4G)@$SBRܙKH{HԑKžIƩ(-˕QLPUn)JE,_pE^7߬щW piF5k~z1c^x!N;w˓O>ɓO>Ovi^+D: k5%YR V%_헫{kkEٶmF_}9| +~glڴ~<,cܸqu]1|:,Xmxe[cF׺:ѸA,*' COaIv%u;ʲuX`իWޛ͐!CK1bWo6Kkז~8Z-  _晧,VZq9G,Ӳ@xĽ-1npڳNpdо}[f~?&{ZweeZIY.h4׻7MNYY1vuKwPⰝH4.[q@@ Q$֖ux/2̈́áx\|$zҥKm|ɧ=z̯q\q5;'|X@w޹,^.7pC-s"QQ@ h2,OL@5 +F I~hI9q}b@wU>e6mH=ߐ~=?Iӧϼ[X[oOY3]p)_Y7@ hlQЪrb"(~I/bċf܏fS={vs.c].w anT}̜9Z?nH"~HHU 㰥sUTH_kY~zg_iXĦX>fAFV6$qWڌ6d({ZsXa @DhqT>P^z%>SnF> HKiD @"..όE؎N"/'iPVVZqc.' D er ە(J*NZh$B0MOmnςs( 2-i+G@'bb9K@ h<^Cvsgc6*+*9\i{,C| D\@ hVz4˖|'LHX"@ h$!p8Xf !UE?s1lsA@AAb0nhe^?AQL+ʑ_Ler\jѧ@$0[>56."eu0;rUW'I ,`ĈGt"e! ["!ۗ`ʕt zرc9ӟq/@"#nQ@X1M<>_sO,^8]ii)91X,z<>/˗`V\~R֯_'|BASss_zয়~⣏>Ԯ;pB-ZܹsJ3|8ȯ0a_}we1j(6l@!??H$BYjŴlE(+Yf#p72~x+zŪUu+Vн{w&L1cXt)ŜuY۔Ѯ];TU=z?pWs %wˉb̙3S^^~~'D 4:%9b19"bYv8tm6|TVVpW2af͚@IIir222D"~nFZlɈ#YsN8fϞC㏫1ફOf-kז{.=yժUL23v:],@иCH&á@ XMtkm3NOwgg'dgddү2|yyܹvΝ!=:ڏ?.]5֭[JHVرc +jٔ@ H4W@D D 429Q%۷ .&,A:V2a 80mqqQۂg{-dMۛ?0t,˨%X0`~XgjڵkR!2d! $tM'0SNàAoŞ={9sf]vQQQ$I; :O>ŋ/h׮ /wq'1cƢ _w8/((?Pkw2i 4M4OޟNrSRgc:f*f̘Aee[oC;sxmƫ_{+ӦA6-oj`]*X/Z7z;vtuEfF!exv@$sxңwo;Ғ">vВDQ. IvY>'\Y(x|j=A$v5tMK%I$Hio8 BiTն^FDD2E$ N54(/?h& ufx7*0 Njw D 4>,S,, G"H4}hNB@ARy K B@@ D B@@ D ! @ "! @ "! @ @ @ @@ #* F$I IH.i~*C kTPx<8.q20 Mi: GMukӦ霦6_-*+ EI7l˹袋kӣ?ƶG5Qp83Ν;3yd,XpPΩ(O@A#4=~R1Ft֍[o5?+V죏>Zz$=z_?;wn]1cF.,w]cϫKvZ xB0 Ĥ(@CIze{50wG5G1b$V*S6me`i7Lee˲;v,C I뢋.Jgɒ%t=m Yō7N;޽{3gΜ{'N`…ׇ k>'VYQ^{mZfϞNuw 8r:@p4ȇHI&cZJN0͚i8?|[ &]ĨQ#{uըĈL gѢE}r-!/b6n?ԩSK %3p~ZXd ]tM6<3\r$TN׵Ϥ!I NA vTsosѣO'&;ѣO_չ_]Ohm BvxӦ 8v7lXHhZ ˲IU[ne̘ѼD"\.mڴK ^5M;sv׷GX 9$df1R͛O&yX{s7W\1,*S.k$_~1'a/iKb(*C-뮻2m./utZlI,e׮:uꜲ8NgxɧO;g}w6eex<^$IrQ^^Ƴ>˝wNE|:vLm4bV>7|Z/@ hFUmm5Rzӧ]k/q~$Iۇo~[7өSG@~~>!yꩧ暫>}`gS!''LƎ,&ӧEAA!^/ر ghZ>xq 0[laԨEee`0yGQu;f[:$RF i"JcY@ 6PTjIAEj 0uS1솗}ygwf;޹sвe*?[M$d `4! .qTW9"$$D:_n4Iv\͛Ȏ;v$%5DAA_v覲hxڴI֭@ X-Vn}?M%/^ŋKBN]|nLɞKpaкر#PV^-l@tt \. +-a0 S fY  ĕr" N)Qc(/5yFc)t IDAT`n2J far9@ F@p:hڬ6m3ĕq۷=;a05Et"11{>?)8~J / M4G1`0j . . )mR& j 1(8J^Ñ#qeo.j#k=vT8N ;S ]*C})`&q8 ,_OExH6߈8@ F N}#A<dr ILl6{3s~ L0?8T*\E6wKlj8hyؿ/T*83a05J<) DrP* 8)Q#ߖ0Vײd `@IkUVA.3̋wg%vKP*U, `ka1۵\M%k.iyƍ#((J򖻼c4h,h4ʕ+p:HHH@LL p:p8PTGRR n߾QQQ(//hD˖-R:Y)q[c?FTT !<{GRg<͛1`dffnKرcxb ""EEERؾ}oŷuV!...]BZƉ'$BK@#\_-m FuDEEW^kr0f,ZH ӫW/p ݻ78Cdd$N>-9vNuzaڵҹ͛7KAUwo 66M6l6d2aȐ!RB΃vHLLDvv6 }XzJ^ODС8C||<58fS Q'B}@TV:Ovڅ rq׶m"5U\eǐ"œ9sl2ȑ#cG&Q\\3gΠ_~_ԩSyyyx7PTT?}*godOgg͚- AΝJѣh4Pղk4n/ t "ygΜGlٲE&>Μ9#Vaذa~ ٗ?3Ν;I&_Ue`0n tl6#gJn 6H5kJڵ#Q 0{,̘:F|a֬YޝHZZFXX(ڵ'5Uf3U*QfZ=w ~8IIKKe˖Zn"WW¸qO"-MtXZY-p @ mcT(..O?(]iĖ|ڑظq#\.' 1}4gbذo'oO?_E%tZ\.N'JJL=m4\BB _d;77۶mGǎZ_D.0g]/܏?~oܸ&`ZÞ?@VN`x ~5aŊҦV0 Pt0 jP_nPUCBQZZ-GFz.^"wށ.`A4xG\w/7n'`HKKh 8zJmz118t,MU-8^Ǻ/W^a3ގ(..+W08QETHy-_LJMjhf{Koo_x _}m۵x%I92jh]ݏɓ&Cɟ}!=#pѳ.fG|bܑr'ƍ Y|&<))@Xy hW aZU-@oXyY)Cn({C>!C}ĭ:70` VS/FߤY 'nM3EA)w,Y3q߽ʬJEbުĪb̘ ="ӢWw8DFE8 }h(Sn⤉:uqJE͊а\{weR0͸{nIW^ ̕WQoеw߫'zH<qۧ/Rh;wJcbb~ժ29zhɬdga8JDXDx:\ΖrkAO͏G&6Kt_={W "\-T;Il۲鈋//߽s?ݍ!B>s'v(UfۆBJO+*N8}{`ܸq8uXA:lqx~T)\pU]EYieC"'-۶rme.-nXCx|k<+((@XxeK5xt(t͚7EhX8bF#n\N;-6D[ϞRwޛ ")x֭]ڶŨ@D()*ļ:.]"!ѭ[nTnzQ"i[.Сc1x`EvawWoXN?q >#RߠգT 1"_x'ĄHNJ j絢ˏx\^Y6h KkNヌISV22bljK23^g5%%0lQaĉ8wN]J}x ~l})ACdcAQQ:u} GZޘ>}:Z[N Jq۱c'{R6mTr}hּ)k׮jRzH3gp]&97>el ,8ڸ+**ЩK'=cŊ7 t19 x|aY5͈(q8s{5xndԊq=>XF tXꓒ7l?yЮCgpxt#~<ޛ>Տ{ŗ(.,Z/KRCXR<@bBUY؋KK~7U:Og@xGlF~=/> =/xzޣR2 %ᅗ^đG_De6/[Ŏ3V|ݕ3:[lM|-Znݻa⤉+sxڭ;>?w`ѻO_<._ S J\Nex텋Yd+wirUFUHf^-׋ (sޑ/X!N-@DwohX88p GhX8;44:aalX˱Th{0@UoO0aSx"8yϝE\|Ke`ڔi_g4,[ 6ǠAH|}ha5W}/㝹@֭ ~ѻWosؑ x?><kV+%x\!"zjzQL|F1 {vF W|glԮU -@mO'++Y6lrQkx;;f,|JOdr.4JNʕ+Ѫy+$'+HLl9FpP00 ˳^| Nj ł翇#@yd04j3gK:98N t;#YPXPNy bOcæM&cۋ:ȭS EVR8y$3`ڴ)HHl7z.\ռ+߿8Μ9~-HXRR&_&6M1o<ԍ\ZYQ^jc欷a8 ɚu9hִ Az<2xgEDDWrvMZ^K"jRV-i+WPR$JJN۶S^ҹqԻWo|2EGHB>ק~}тӒŋIYPbD:x TBDDgNA:wqlRzQIqFp9AFh„Rg@1O]wRRrmXt_PMN:4~$r={iIҹ%PRr5Hl@3^}Ev_ +\Αϝ=(~,_Qpб}d4),4 zޝJw:uBM$ܙBDDۈh̷)!.zA9+9g.Y.e_=ӞظXjڬ9ڹS&ĄDzlc4vX:ӑ*r$r .ѳ;Ջ];G=J!W?#uR&M^zRHlSݳZhI;t'~G׉{;KDDe%4xՆhΜYR-[kf}+N]:Kb={FADD&SuW_{;t})=#?KʛWy94!T+< e_""cǎRr&Ԡa"}C)ޙoIqqrG >uR:s/Ӗ-[{|7VOҥ YT\\Dm\O~ )kd1h+/7{[/ڕ<>_p ngr:2"V{II1BBB䗩nr#8(*ª$K"PVV ِj@Rp\'sVy@Q+j1C7Eo0bɲ%߷ԍ i ȆPlV}l$MO~cZU@yY94`Î G`;n #tz=^e)[Ƥ8* zrަkajz=T*?-yQKR,ME7o&6fX.]+GnTk…&l[;]w2?11e ϟ2eJ?}r|wCXQ\$n_Hݵk K7<\EEQÌs+NE={hb"\ txzf{/W64\z@ [Çzҧ+W퇏=x GQtǎvv,E777ٵq쇷-H$ڼewKJcX;&앫V B)Cw)gWC#I&?{m SNQSSc2۷o %''/[L2sNtK-----k|e,ę!ed$sNr۷uՕ /1s&i4u9}iaAooו~5kH{:Wc 085p8gg޼y p8^B,,Z>y䶶^MMA*>p<o͊E1M6}7}m۷_G>¾_zu=U|]vvvx<Zŋ(((+f)!͛6빍vwnhh)"╧DDlvrr5ދ  [5fgplSK̘>$3=}޽vޣߍkNBQаfLMOh`hLNNL,'Z\ɉK,ٵ{OppБ#Gv G-'Β[tL]\\~oܼjU{ޟo0NcÃJ MMhȘ~$&~ X>y[ʛ N-߷8uny1&&EEcǺfxZ QT hoo61cIR# |s`b1\~6ߔm}{d8x=f%r7?v~o  5 kh݉[eXS>bf`peEEvv\IT0]]7W73s^4ڇ:gNMK3e%J1 qbqڞ={:Cկy$]lcgGPPX,D"Pwvvvttt oaatj, H <<1 ZD#GӐw R ȱiE?5 $ Ν;OmS`; w]re׬}=Y:dmmf? VVVΟ?bܹ:,رcG&2ܝ={vBBlMMK[;O@nooooon:riFյ$D#bZ&w}||<==ϝ;'J\|2WZݻk5dNOOyfzzzcc={/^877777jdjUV߿,-Z!ݮ]ܹs횚kw-IMM ?kȌ KhhhnnnJr;_[n}S\8O>~7vYYޅ2~}}钻ӧO'蚚KYY]ZZꪸ$R;z'NCdP(??_i[kk+ٓ‚~Z]UYUQ3RD%N`emmD700<]rhQݻwUTTHˁ|s8%AYnrر[nM6mܸq'iEHf K`` J%@[[{o QTWWY,Y`ny摆d2tuuD Il777ΧNzΝ;׭['3ky%/MȻ5m6.rY|>`0UUUD^ aaa #IuVbiƭ[*.fii)gĈqqq׿4і/_^TT$qv&djSGG'<<ܷoۭCBB%֎%T*"$$D^ 6yyyyyyHjHfI-[O{~}``s-Zdmm+3ky%/MȻ[\~K0-X 000(('XWn@-gN~%Kɔ0$yx ,#CG'JU^Fzw|655555PKMH/54< G@!ij@MC P45 )A`; އ@Fd pYOOO333__Ǐ|>?,,СChLLղeFJA{ yK?$SVPr ݻ222n޼IFMJJz𡲲rTTJJ1|!H&d8&]]]+**rҟGII $3 ^rrpB8}hνG*>~tBLJAՠUTT鴍+O0( Y*^rl Ad&@*LW [9 A 00022i۶mdy+++bqaaed.ϕB/ViBXnɓ]]]iBCC=<<̙ceeb sлB/RRR2o޼wa:=C9sg˔hӽa?;m6а}v???LLLƏ/|}}I;5E-Z4!ij@!i45 MéΰB`; @MC Pz AnjF溹}P[OBWnܸ1w3/B #tucpIw 7?***// _/)_5z A^^+<=:ggggPTchBhvssdR.]JLL<|0T@0bĈzFFFϟ@Hsu{{Kf``pK.8pj]}!|!@'@_ Bm/P4dsRfeḮ f1qP.84NC m|1a8_(0\2dmmaCzwhOCG >MCQC4dPQ:l:VdP@MC p$2 &83h-ӞQ0LC)HBAJ~/Qj 'HV<{~<(muЙ6{ BT2;hTJX6 %!Fb:eh-a5Lw7^ ~nJtJ~U;U5Y;L-Fk(".Ҵ79f\ ޫ̟fpr*u5:ZA7S=ksXjD3aǍKmKjB}!3_W3ktjϏ!l䓝 X~- /=?-xSWOu1x[O,Wu: .VÈ kۄ()Dfڲ4^Ϩi狻>n0'K]MKN~#.3Gt)V:DNbFM;_'fԐ%wս|is_]W3\[f"P*ӚۅnWu-]"1*qN @}B<ʗ<]rY&YEi.7uEKFG<uYN P5,Yr-UFH,؉R?7i.|!qe lIz=t4)""̟fy9iS_2>w%OJArQy;k@2PX=ehUgumbmu:EȳZ;D\.=*ʆ׊3b˙f-ǒܬ;3QY>mxެT=˯C9iWʔhӽWq#ZYŜ^o54*2ۋ ݵ=zBp[ǯM_uӐj(E$w'[e(a]:(쐏l7@W5dG uΜ}g d@=4j kVo5=xRPP`C׬Y#UYY9|[[[ s+(Xcǎ=XXrw mK[w>>>fffΝ#YّgϞ433}1ybzk:==͛鍍{!ϟx\++۷srrEUV߿ܿE444 [vmqqq|||NNbt͎$---!!ߟX薰L$ׁ QMGFF2L&ye"0%%KYYYCCcÆ n"o۶MrprwҤIjjjDS]^^wNYYX{*.FHbbb UUU.]5SSSr`emmD700<]rhQݻwUTTHc;v֭iӦ7?T\ّhkk***b*j%OcT]]d2%K,X ''_y摆=|ԩGܹ5:l۶rܯ*8*|>`0*I)AÇ鲽,_H,8.پ,FO,--j!4޷oۭCBBݻJ oѢEQQQS-[= , Y, V hΜ8|!?" cț5mjjjjjGA71>"5 @MC ў@4q Cqc28 !$NCS̞;8:ѕT2ҡ= }Ddj~Cv5 `42046}!tuWhLLղeL iޮ/ bccsss>|b~۾8Ν;#""]b~۾0aٙ4r^<  A }}l2NWK4nnn&T@Mm_R ͛^YY) -[&Ĉqqqׯ'T@Mm_R BCC=<<̙ceeb {~}``py> 29s )/H}!@{_424lj2XqNa8?x\!iȀ0 p8 @hOC`@zɏ([ZZ^4=gpJ;!))iY[BB$'voS<8i~7jԨݻw ZMP;x;v߾˃;Y7.88!^h߭/u̙cǚdff/Ǐ733-,,$ p{{{{{u 4tZSY^;́ pK.͛7͛Kaa̙3y7vs۷kjjvޭ]k BUV\Nc?Gcll\^^Nl]ppp K.;}x2K655Ilbť.--uuuU\~2rãnhhprrWbc'N!{wŤS(ΎmƆgjkjVWU~׽bIT7P}!ttt ".9ylbfKLYSO8艼)8?kxV^^7}znGU#fWVTds\EFR.nnf$q "$'6B }yc)VS5hhjLֶ9YMM1:q9\;{{T8e&k()er5 ht=@ oE"!*gDѻqX =A^[5 @M]wHߡU,_)2i.ؐ8o;'Nz k2mUUUGs?!Qݱc=tͶvv---v[ZZHC$m޲ }IDATC%o-MgYK=),,,޼y | WVVx%+;K^Oݻ6NK2]_Wu/^fFuMutt ovNvJJ2pϹ׭۷oÛ 538\[șiVVVܲy3~++<{VpLLLw@iii /*3/ HKK d2Oc.b%x_M=#33͘9Ӕm31esYh))'Mvs}=)I^{Y/=w ++{7Xnff&:!@.u":dу=dy/\#2r vs K"q͛VXfٯ&(+Ngk׮,,,L&SfhUUUv reU5kŋxH$qE Lټe˜@[aPppPD&p6FD̞-{g޼y p8`j6obj $|Sq466̞Bӛ7ms6pSD2DDlvrr5 !К7kױ U_R845݇PTE94P(F5P%2C#n6FCKJtqoH*,ȇJ ]Xɏ3ӕvJtk%|v z@؊3gXZZu<5@ lmFr$d;0PMA4B)@ͧߪ\A$VSx-rik[ۜ&8o-4˵GSZrMNyY)e ?P(u Mk6[jmWk@tuC oE"!*H rN@o[5 @MC Pk3ލc(*FQC JR_}0 sDblhT T+=%yoE"QMuG̓Q(ZZÇt8j֎76a LM/WN#15hcCCNNɓ,H$,/-*fQ_oe#Ff Cine]={GE#\>P5-F|N W:nmkO޹c``&/fsֽ9~lB(3~^#hԔ|ɮ>`8f),)z᠑:rHXgVym GaC-=NGQ _ JJ4|( AWs`ލ>aa #7o[/hg'EI |8Ybʣ 1q0fSge .EI\ܣ-[F9^66ġ.?Te[=Ż;@qD נߊ}"eMTP aڴW{WP~=↧T kLлtimx-5["Lq6qonjonmmxkWkn.'=]vg,>RVS3quu2%~Jw5SlW<10 "qPDAʹAwo\(Dx<3Z9o#ok`P9K? _wr:_ &BqÁ(b֋oi$09 ڪhmV_p~B˜e^XXyҥc:w D]-kX3WPF#((h{Džm#e;/2;e2 8<_<{kGwq}tub,7/-P;Ǐ{=n%MqqԩSLRPP?[sICS? : 0iIˏ8`+WzWf*S[kee%3ϘUXRVXR6}ƬH48xfFz,_ 룖zno_ef ᭭X]m￷\`TDFF/Yuww矉k֬IMMD&M:qℾ>Nwwﮭ1bǝ"hƍ?X,Xz5Eѭ['H2#ɐ9& \狿NzdzǠjrdKlܹZb066vذa5kDEE?abbطe'Oz*v+'0]U4v*!Pˈ qFDb.o.\d S_%C.wN}=84-^9񖭔f?ƲPt@by}U/ V[[#JIzzƖ->}9A''uu5bFbb2&Ԍ9eK"=FD h(b4 BG2Bl(@A綱 D.ΰښj###2n0]2ڞ}V.3v~i5*譾p1>?q#MMӦmبI&<4o޼%KJK 'R=ioo#~mm2yi 7λeĉάҁމVsb.FqQ (Zj*xb. .]Y2҅O@l>~ټ_#ԃƞV$ܼ[g\{ *d8ks=kSf_[Z0fJg;xV^[+S;z:(4_ϭ^s]`2`{E;>eJǕO8}ø8ŋrPV4cFSSd`iix%2rǖ-[;;;G_9~ 6>}:(,lեKȒHݰa[ƎիW`ƌ666yyÍ}2A7 P1fjyۏe5;+k/^ڱmWc~oie%xs!>pe+VN"P 矾X\(ʋSyX͑.vt9}+5Ex (:t22g|uEȮ<omH$zü:ӷQ:DHP2Ղ)W@4-*@MC P45 @MC)z3IpjIENDB`barry-0.18.5/doc/www/installfedora.php0000644001161500056700000000542212242254476017210 0ustar cdfreycdfrey

Starting with the 0.18.x version series, Barry and OpenSync binary packages are available via yum.

To install the latest version of Barry onto Fedora 16, create a new file (for example, barry.repo) in your /etc/yum.repos.d/ directory with the following contents:


[Barry]
name=Barry for Fedora $releasever - $basearch
failovermethod=priority
baseurl=http://download.barry.netdirect.ca/barry-latest/dists/fedora$releasever/i686/
enabled=1
metadata_expire=7d
gpgcheck=1
gpgkey=http://download.barry.netdirect.ca/barry-latest/dists/fedora$releasever/i686/RPM-GPG-KEY-barry

[Barry-source]
name=Barry sources for Fedora $releasever - Source
failovermethod=priority
baseurl=http://download.barry.netdirect.ca/barry-latest/dists/fedora$releasever/source-i686/
enabled=1
metadata_expire=7d
gpgcheck=1
gpgkey=http://download.barry.netdirect.ca/barry-latest/dists/fedora$releasever/source-i686/RPM-GPG-KEY-barry

If you only want to use a specific version of Barry, you can change the URLs from "barry-latest" to, for example, "barry-0.18.4". Check out the latest available versions at the Sourceforge file list page.

Currently, only Fedora 16 and 17 are supported.

Barry is split up into multiple binary packages. For example, if you want the GUI backup program, you will also need the Barry library.

For most non-development systems, you will need:

  • libbarry0
  • barry-util
  • barry-gui
  • barry-desktop

For syncing, you will also need one of the available versions of OpenSync (either 0.2x, or 0.39). Note that OpenSync 0.39 is sometimes called 0.4x.

The 0.2x series includes the following packages:

  • libopensync
  • msynctool
  • barry-opensync
  • opensync0-plugin-evolution

The 0.4x series includes the following packages:

  • libopensync1
  • osynctool
  • barry-opensync4x
  • opensync1-plugin-evolution
  • opensync1-plugin-evolution3
  • opensync1-plugin-file
  • opensync1-plugin-vformat
  • opensync1-plugin-xmlformat

There are 3 convenience packages: binarymeta2x, binarymeta4x, and binarymeta-everything. Install these if you want to install everything.

For development systems, you will need the following additional packages:

  • libbarry-devel
  • libopensync-devel or libopensync1-devel

Everything depends on the following 3 packages: libbarry0, libopensync, and/or libopensync1. Remove them, and the rest will follow. barry-0.18.5/doc/www/desktop-main.png0000644001161500056700000044175512242254476016766 0ustar cdfreycdfreyPNG  IHDR`=sRGB pHYs+ IDATxڤwdU׹URa'h4FHBA`-?>19c  I`2BaLP`$4#i4MI={Rսg}>Vu~~n{>{ڨ?O( @ R B(@$igaI"_6F);o DW{q'#st }CĻ%zí= wO~:9nBOÙGpmF {/2"|[~i`m~Qp j 3ղ੖w !}iY}w᱈V.I}߰@"Ч#+]czA]h/$c|xan/3^Y\UJO)߲~LꮓH!mjHaTKTkrhNO&f5#'Ca ~ftn4kXϼҩh|Srх+-@f;MûW퉂P`ouSS= 'V77}tȴC\KEqz."̈́~L@SgO70|DRoWB]}'IܰyK=r6e\ \YmLʇ p#R׾!!곦|mp!hKMhkvdj#,.+}u 6ߣ=SԑWnؼ~a0h>2ә)/";]B_)i[X' өtQ3@:^ZzSr`#uyC֬ Lw D`ri_2xg } 16泌GҶlcOmeH;dԴHء2dMba^:B3;o*6.%:"z2AfL=aΐХb ΕbOpGĶ11١ʑӧ{5 /E|lr'S[ٓNA$eS6|0T &v4іK]:_! ^3*fI%(φk)p .4 c*K\EV(P 4$+BZlphʃ$3["&i9~JqR\fxDxxk>8s Mv-zP'm hex˥΁:^i۩Ka~Lpsʂ mk a1:tNL}//0z .iQ ij/' Ι~y%+6$W(OunJ*5b'pv9/-Foփ6t_0}7b_=dZ k_cѩJZԼk6L\|Ct<# \@i$ؗ (q0`M/p%x́PޱFG& 3"A<`cS-'7L%m+y[C!uKy@0j63w \5!9OJ&R( $$tU9V?isjXy7x]ٍFphm}&ji9M.CdKb|M*p:(B^Y P=C}va6^-Ni3# c^)KeS˥^SP;Л!oU7yw:໋8'VaX72^*f]b}hݦ(N2c[%/g6$hcta5j! |vѯu͓?][+F#8>ompI 0JEo7v&48E>= 9;!m )}WmJ&4tËDu[f.|z2$2h#aB1|tcn4 l!Ȑ D{a}1.7۸>ރ^~=JCIbIGYKoZe_,3iAqNTE܂kMطm@6XNd YmkN.5z .?G x;IԹx@CB=3`?rcu-87&[qczQ7..|6xϬ &S ^ݏ4mt) @h<]yȌfXYQG4M&>Y.|K$Ct :rh웝.k '.UQhX4%_+? 6/v(9kg{hx- v U >YPh܃"S'WT41SɌ{e%KLHDM$`1.? .Ѡ  7QRЫ6ʸ޷}< 6 tLUJjеl 0%Ԭr/;mʎ@̵.NU9ʻ=0ig6iN盍hOsl]z<0_;9:Xwr#}pM.1)9ӥQ'emw?QtdžEd:aZ#@1-0??8GvGw6ǺD8(f4 sFE޲wh݇On{-Ćƃ X;{N#'AWxLޘ͸Zt ܈w[t=ޮ~ !;7T/ɄKU@_GxA4un}y[AD5S?Eߖ2bm41q0uC!-u5}Ǘb]xuwX;xh|!_N|շ8Z9?i:HuJ†;6"EWSF 7I.EX?;=mqط6TNHٜ'N{-TCH@RAo5co^s[sC. >߻xT`HLJrUG[Y=ϴݴ[YxɳW?8yb].ؼ!Jȫzs.Erq?߶ږ9w߽\pznݱx#GG X3or5[?ǿZYuKm)Ps}ٶXym*#@J3USCNjN_Yp 5Dd sI]f1dP.$;IĖ>4R8#w޻aCKe6mJ/Tx~R^oG_׻!1a-P(ض>o=Ii K0nÐj~kN;KŐ89|V5 ^8nXi~G~r>2ei@Z)",|}>y{;!# n,YhT3*r%u#BՅb{de}/-V()U.; RKpOŋx<j*Eoc'5pe>CUn:j"Rnv"T/sFQ N +VϭT5~8ϺZ^6G_ ݽWoݿ0ru)5:eIpdC] N6+9.LS'R728O6h:u_ծOt9Px쩹IoW7ޱn=VNcHUG?wyc_޵Tsg;rl|SnrkacJσ'\\~_صy3՝;z?yaj|W>\|S͏/^t,_|^z'O96dۂ뻶5+kսΟ0?gCO=KcW :wǶ.]\p_, k6 O<5.ta"Vō-\,1=;@N|CwŮ n^\zk5>ŋaͫEȱ}G)u t7H7t`>vUg@1o\Y0@=!"d[M$2fafF m]R"򐴧'(r>&P} KF9* lP|U ]S aSFW`aа67:z~cn Zv}3G@8kwqp`W_wOW}ϫNo?VC~W svMWxv@Dx<^hv=fyx$SFI <&;̭6"+ U5 N&H"t0aJ_. UwM%:#љtsl:8 vK7Q}mo>Ѭ<ڜ>)zck}׻i}hS>9JYS)lTmr)=Eor.# _‰S ˓hcU/7Ͻn{ޱ/9kc7i0?^I wW[q/فz7?{'Z"/gV^#K(șӣI#v27^x~'O& x?̗~-Wo>oaqH/=A?=/X|];7|O \ߪnj}/pW֫e߻oz7o|~ުjwwN-4g. Xb{{ί8}pS 7<Ͽ^o߽\_}k7_O?p4cl]]ZXnӏo⦫nW>h'|˄r_s` [5&Tex~85V%m)H*[5_zSG~|~TgW;>%^ ݷFuamJDRԇ?w,oa~v=qb5ݽGbU_rnw/׷=kZ{mk[7w~=i0?=e}WБs;ua07tfC0<{r`W҂5Gb3:'k)ZʇgTΥ~atrssRah!̢v H((/ĄǦI)F2@,|jx)AK^0yc+oX[*=WăO}mw'}䑕rA46Iώ*Y.IN1rc̩9UZc\v@؏pu5 Le_;wʼ?oM/9zU9/\{\zZ5\ф0Jv<]oAt!;z}'>5'~8v[nG|w^w`%k޷޶GEdszꎻKU9&Mw݁={" '=6};ki]tdʠ5j kojF_琞L `9q3حmTduӕ z%V]yn99zzX7piCXsC}{x\@c$f= ;[/]EVzYYmvkk'n%{#C/g78n| H?$M IDATx!9~0%qv8chuve1! yZ:Ѭxn[7>F%'[xlSv߷rC9Ӿ3mPK"XmDN͎e,='yaSi !ڊi{(lЈ zN]W ^,PD@,j᯼|_w?}u}O̟;3߼RPhE GN;;ƗܼG?`PjMs.xʎw/[lM|B26h<~Onj|Vo7#Ohi"!jU/b\,;c.lU"jb./4kUo:t:L$k:3pnϭT@?ȇ_߸*8@ $Sbm/k\`Oګ"-={˚`#HAľqw]n}7G@m_1Zֽ^vVl"6${q'-hrpҷ71d:LdKj3gQdVf#I=NI 4PF#x[⠒$]ju&q{ xفzȤq[ }mc,ēcO z:)*R%^r;Eh-}gJS􊤆>$zWLeEŹ<(C;(P,Bu,a._i4 ynrw,6_};&?'eŗ޶?<>֏p7|I碋 (J &>ⷽzޏm _q,C.o>Ƶho7(ow՟WO~|~RÛ?+egu]..7_շډ;'w={g}/0đ׿qk]O*>t|[Y۬]J5^T. ({k^zYyWUϿal%7yş#]G?sY7 !#]|kٷݮ<(~{{|+humzT1{K%8r?o񦫷vlsO}߱j lrσ3}-Ώo?4p֠l(>싖GLlMops ZGEQCvLGq,]tZJYFJ8I+q %Ͳ`9CIIII5G:杁avY&l|8Y@]p]ۚ;ûFS.]'5~]s'΍5^ ÿr5 sY\\fZ;9V;ٳ oD/:;ݓkE>yd桭KNoپ5q۶\g>stq~h񱓣Zʭzhr`em0?ⷼfw,޳c޴;?|K;m ߷xqmc;|x3_Yb,:'ɡo.U/#]J 3ÇXnG|;7">8{=;=wnw?OYؽx~Ļ\;ܵZ7O;Ïyl}`̅[X]zv7Z\02)}K.nOku2O/wFN4+Ϛ~+OLʊ~2qVA8}RCxH%aќ' &NDF<E\ouxCUSE68aE'p4zH6=uXC&p6k' OzYl@WhH8:$9ZzbUtWnW? XU@Dܐ~ qAi#^'Ѫ?wco\{[z )TR"qs~jjUIYn@O1ah;,NmCcAGAz!Fni`X|ա*|2 !·wI fӐС̣0?H\P2_^<$=QGGG3*x,X:G欤a # >kѣ'v~‘=.Kn_G!n>VA0Xt>vS2PA_ . D G#QٌkTQyhÊDE017)?*7`Z {PQŃiE8.:RYa5,'| 6>6G6+h ,<,ڋ!9\DXS殡˱;/28J R4?PN}?ܟlBƔNԼft@%υ}vL;q\hGbNsakj!.p*5S\BEZBLՒ( 3x퓋UiL_L㶽4 y"R Ek_>x{XF!.B:I{{pzSZGtO2,ʾGmb92gV 'ڛSHLI/iاvI1-GSRqӮWv^BA%N社f"ja2HQruD{&cLћ̅fTyo0T'u>CJd}wg5 lcDh m!Ѡ@aŴVAɜ>YWTs4;=#OcvG"[ ,OăI*Gȳѻ CB$lm)i]iF@C,~{kC,<DX]޹Z`ѕ\߂SYei^i3Gba2GmwlZi+B봞:s.Sh-/kin{kg#{`@/&XѪZEz*[ iC'30GԊ|;b%>d0X0ߖ a Z5ӖH ӡfȾAX/4ePؾ '$9)>QP)'xH5$L+1`gL043%\2 a^)Q'O/R4ԸgcC;U3X+1z)SRt̰,F1kX!!rҖB& NSՌ.ys#K #a)+gC2C@MĊCr/B:!Y{%ccMHL楜zhchɖҌ3=? JYU+=NBv{ Qw؊AXwB@rѶhb Sbo`#l9=-O((jbHs)@$:&( )ðaj.=ABy"Hf2~2}IWWSi1l*Yڪ~fTy@`U박]Ҕ#r ȝ ~:]VIҪ`_W8NکK Gto =gki=]^NjŝcAHn.gE+jלnJgO?Ul]+7SӴl^Hu@ Us'/ SJLmd,C-Eu-Ҭ>/Pnsƛ(o^˴YSf\'0N;S$KbўVl]6SU]?Va\(.CboJӲBB%)/Zh5/А״LSS_hx -6wXףC\g0W,O4ͼ :;_,Ǒk!}èr,&poJ9 ͆iSdB&`K8R9W\X3 ֡1)I12_?æzAp2Њ0So/eb߁bc'O65 RgXϤbV?8'~l9%\xA`D5L:-hBg5550XGyj,n-QP%4x5z.-!m1EE#R"e9(ᘩ:L(e f_NTTO^;T&Zqv;9fׂSTc02C,Eϣ1y(#taǙ>vp,TU2 1J,pLȞ ` Mw#8FwT w*tK81PPog/uX ߶S̑Ў#ʼnӹΊt:HFT鵏3H$ (ʈDDb  Ԩ[(A'*a@82b١$E5!CדO`H⪭a2_ۿ9zK4B 8"J*cK=2%S VSd"MPSJ J(_"B7T(u̘lz_u4'a݅G2;PL_i_^Xм]D Ko@a2zAv tX`KXp5a_Lwpd[ZbXdON!9#hCŒ(Slu[Bp>Vꛯ(?JݡP2o.[ywůy9"s+R97̙; x6K9T@ '#Z ۄW^ej2( ~j*u!fM8v[Om:)6g=q>'UR _;[#*̩9Pְ} ㈶A$1\vC2-3v+ܰEmx -sG P3ɦyV#I! hbP|ϞHbJ|&@(ĸ8[T Su,.7"I0f\@Obr7, ˟v<1b^qbBw,34a#vŀ**C[gRliu=BB b<o*J ķĐT0K;?3Beʶ2QRKfdo(zn@ }=)f2mNJ\|xŽ5Abhh/(jp$Oeɑbfz+NiG+p @L|Jk3CZj}V0)YsM %Du~*R[+4oǖ:2b. |T)p}8V~` AtI ol'HB *9q8[h0#[˻쟊?ZML~PYI J-n0Ͳ EJ#әLsŜB,*Ē44DlOӅi>PcE(WYOSw汤F;6!4(䀪O:LMAsjZ=K}2fFlRLXh8mu;Ėv10@aCSЦgiggѽV_wݒdl&*Afȩ㕕iQ:LL3*4ue7sJ.͘d pތ6כW/F1WɅ @mgP|u̸ݚc֝Xw-8ONC]߃o8Q[ʰ;RQfZsuK 'l-gē"[KTvshnntsnGMSX)^Q_Q*^x|sj>C8QO,-U9@gO~s2>2w?ޓO;^~%Q(mf }H9r_Rz7=z]9M#€pHj*KLxCz0}Nڒ(Je%~M 9s@ғ2NC,7:4::@;o;uZk .j2%u-i18tI}iB̰Y4+%LDtr9\ I$;Xy"jRVwW`uF9@,j0=۪:i3.7,mh0uZǯ?6g!&t4[A3mpn  k϶qmC鴔BLeǓi39PJ_Ӳ#{'MGާ\=1lL 8m,j- O;zFS8| DHT,kё3~(Ԇ_4,gַ6Gj20:gvmn8_uwGhoL<-RBINAE%DF{6nKdF,Y|{^ɲex19,-ύKYQM64]23+sl/7u3|oo*Pe7/MsssG&9– 8/ʐQsYxrv%%D" 1?䔪ۢGofFږ9qJ5V_{^\LŹ bdNUmS&ׅV3tڹOljRs]y]y^bu=f;ӌd=D?p۽ "ռ h2 =O,~=}pD4^ [6ˑӨf-VUvVrMTPO%QXP4/HV.7lu#ARdo2ZHb?Le~jvGxT >Gg-zGzZb cm3"䤑IO'I b,fȮLJ.AqAYi;CŹL.V,wvT^yuLm SB5](zhXe./JMoo'b|6B~GU A*fo!Q1(|oUL>S]PqrRٙ8S @7:bRs_.xJhR3$(,fQ @{`y~|("D蠪 ENyoUwitZ JTk 5zoLtYގ $gK! xzfN(1HSʬ[G\g[X=BAe ԹXJAҵʲQd L5>} oTDZ^L,M bfuyy%Bf4XBՈ=3̩l4z2zYg;Yc[Poqzug:=CTh~mRxt%oA i5Qe,+gZDCfI <.&!)O$tȃ=N#wR%\*ЈH\?v$!a8V !@j1c0BQ2gى!H5Dͧ{`AaMe ?3|Y9en!-&HUc ]JuXd6G]/U-O5pI}%4@MNkl 9S $ XD4Tl2z楷 }؇u y K"" 챖ǼbQlZdL?OSdP29.H.vdyP")AX4RcXaQpÂjܤ>t-h5x%3E1ҷq2(iR$|$XWh%?ńDa~sžyA 1-4Hlj[D*b;*"DX!jC$ BȬNmĘEn2PS97Y8J@'̰|"%&MTS VwAƢIK箢3dLQ5i12jKK`iӍʓc+`EhVK(:{»xS*?2r,YEnKsh5#)`9UX>o)dtNTeDʌ?#ReRQ.+jpZpPI Z)]:i\LvkN /hf)M252DfO˜t..B5|L*U1;:y\g,Ujdg_]78V:Yf5jBEc`N5!gX kP)^z"vP6B4enY 8>4ۓϨg4OvN]v'E tl@E1Bh#jݣ%;D%3@>Ƴ(mPc!UYonx {YPSd$dEA N8`6(n3D>ש${JSF2cg<=3'Oxb*q6h&r'^!0?,xA}CևljW0H$'k1xer5-F6B/Zw eբ\ |$M 1c7:Pbb077t-p IQH~|곽Fs1.@,I'/.O6AjplX TS[2yK!iOx4Ҧ*4|4a#K)P;M {r^ǩ2,;j0> 㨝2'Zױ|Dq*i #M˩0NrĂNrԀT*2`!!]I#QTOv@<. D$8ǐ ag*eV*h28]js9Z|0Kes09zK!!,fN>e6;ջs5Js8GE\`6dAٸơ`(T&qjO BU2-ڳؿ3up'X{NBD5dP`QYD̎T8r]K^`ZЦ& ,Eotn:>|-]ƹ61LiCZBQsEϐ$b/"l{H[2jj\D;x35=C@ہMiBx0|v 4 0cr; ǎ^G4t4Cr&/zWua~Cizs4"r)>98q O$Lޒmvtz= UGKñ -OP "ty^h@A[+지X #lk+%K-#:p̃\RrmNSm z10p'#n ÉLAJBQmwÕ s $tnBb:mS:g!O~(ClsBAȡPx48 ee:O.8V-vG$`"E0b8K=*'+I;*QdS 2S|,'TUg/a W\7i;3?VhڀM}Q8A%&ptŠs 4v'[°rh4HAsn'ɞ :Z_}\ c—iD3gDsT81.PUӞbm->8# nl^!aeVNK}YG2a3. rtVWa qa^fH)D>V Q " \ǐv6k.VW<[0AP2+521H7rrzO1Gi(f_HB4E.}`.>qeJ46蓫eiHA_r.> @Z9KpDSAPb!J4?OaI&j;eQ+yiH)PdLD qM\~Qn<' G< d@qJ#F|B ,v];C(eLkm2T)I&Wbe&o1Q#C5)d VbqCh"hf (X$WS_1fl^q}Fh IQ7r(J*|ĘאfK@]ZZN,.j824ܛ~$ց`ˤ%v qh}b2_Eog0 2}V>:3Iλey6px.Ntq66"(SP紿C'mUٸt1A+[]yCLNB&։c&r7O h$h}pd@M7eJhָHN\x塩OT>_'},ik3&'c/`l9В,q\+0gGV!m4]U}q BLx)%&B9h:ix*!a?m1I5K;f(}i xuӴz=J+jB)F3hE:c9J3yDcѶ # 〆 }т=]l{-Cx:@紈{¥aS{R MRLsR|HW j85Aѫ"EP!4҉oyLaw3)פ=B5/ͲC%bLV&lE  _+XHC}g᪝lU{8KkzBjN-5j~HdRV1,C.Ly@H #K3& J o4UM{4B캭;z880 0q\F2Z"孔<_ޜb<4RX%BhšlX$Zb81,J THf!=`٬S$%TcS<.k_(qh(t;")#pIh4>9==3;+P9$09 1bmـM ؀&sI HBY&u]Uzs/#t:u^J`78'^xZ|N>b%0AչrݠMJWū[:*}itG`A*J!屇X„|,JW`"Pj0S!:~@d59D(M3ޔGX3!Z3&.&؁f'$Jh 4uɇ2%̡4-=;K(ɉ5!`ʍzji"f1my4]R&4Xd/ e8PjeMG-8Bi?f m]} ن op -HXjj$kA:߅QESi0͎!Fg N,ls$0{e4 0FߊX.`lfZVX61JͮRPÂi%ՠp&S=Ϭ%.W51hRc1*IP S9Sr݂s'M3:)# iRIf>MD\ ,7 Z(C zp l4Zg1UB>5XR>5p[.j@:=!}lǬFh iɄqA{邈Lb%M2>^YJ2k9$d3+$.%ը. v ތZyD[x;Ў NNQґ#Yshuva4hրR):E5(E#LV;:T%4nF mDwnD %RRC[Ȉ#H-3\r1uL1|}]T{HTNڦ;/rIIZ_a(lؔ^,kdzŽr__,,Z&Mΐ(ݤ4MqMllD7# -y>0i gE< 15\ n(#{zlMQVA6nK[FABmY\ʃ&k(xE.[JK,d۴ c1;YKTX5#[%hLޅqfo⹬9WEa#[%)Ôqfw疠 A-ŲZ<cFM݄"bfg& Cs)]:@5 GZid 4frMbB)Yu V⍕~ĥCt#.'2X[OXl,sߐS-}Yl%2FrHtNjWBNJY*!ą(Ja('44Q/&AHcB)j3]%ή&bmBa_sZv7hhH=z̮l5 D"i66[@Mmb3].i T#G2_̾PU\hRɾ`*M1xեDIjh]&ZHlC% I&kцaxl2 €Uv2!Y, ̼ 5@VQ ͰMIBQHh+6 L F„̌`$1F2bDIN+Bn-(<,{Ǟ%ZHNB\DmzHL"!ǰ߱T#iC Lk0҉DGp 3;av6M`%#۷9veܗWO:DѥzlufL=OlN"918o'6/inW#)1Va0'#J%_زgPxE i;\5'׮ #y' 0Fy׮+{ [# LRDphoEG;بRkN4a5FcJfJ_?3 r2[W=ka!O[+I]cMHp)t,ȬLwkb- 2 "?$Hs=+8]:-Q2B$k=BVWVOi  C$=E.7DI,g.;!0j)v'?Hb0IlғeBR}4zH9` %VnDMjF!yv(`6 0T6>f 0𫑌t`!8nf/Yj O"9Ն9k* !BLj$]9hO 1ҥ |^1{ug ōԃGĂ-GRwu pwIN!-Q ,@YZ.}ſ %E9'!kLUuEF$˲JVךQnRn@0f3!Y(P9Gt"zP=P)IJJx/cy&e$uӷy#}رLn=LD|]_ !QOlx,3$eabжC{M!tw툥!b̄nd^w2:p*#Δ2' b/pL3jXyqu) BaPЍu+j?^.р{XLڀ$2'# |8#7RMy$R &Ōm".A`QWV?ʲ6ڈD7&h6E-#,Zx?O$ KMuoT&iFϤ"I$X$N kͭaOa Ơ@,Rsx.,G*+DLL³hð]tSY#;$(d{jT5!'L9{ORpI%}9-u"/j6er6{㙇>} 6s.d"+ 9}0T'*RF2@ԺK~W6UդI;W~䂧vl݆nPn3Lolwa) #+?CO0r^_%4{qƭ'JѬqA$vug9! {.'(ի徉PlZnNACF(NaK3PQ0HORQ #,?8BD{ . LNuԽVz)d<볏޼~M>+/=5kC~[Z)Ga/DTʡ Bt_~EFR8zYŏjg6˹[)1/8n\.FAX_8FFKD;sVAXl%7i_+Ô0zV;󌣠רnQxI$؟Sr?֜n= l.[0  @O]7espoR>|'uK~?|]7ėEaIхL6BT*DүV3ٌNW3,"A HQ~l ̿Kp3bGgy #@IO,"q$j1ae̅J$:W6WCXw3sG@NDP_;U(E"LHef)0pQ'Xdh=F#jwf"L83JUoc5WJ -0T/)rĊ + 14e\ X3lIU[t"rD= SxS Zb {ʅWri~'4+£‚J:'M5WJr~úV1g\E㸀fW/?w.z7m;cѮ=YCFM7x/>x w֮մR |:@HXUcPNBҵR KfpRD o޲2s~G$jIݪ?2p")tjl5RanVGbL8eD1f_x|@Vezl{05 CѶ|z@q;!S QY?d{<]׬+ u=;§mGt}y#9>R6tԸI3fy^V :asRG$" x[n\`,9!V!i؝ Y'mJ*8yoG/Ž  ۻ~yT{? qv @D,gPkTqpۖUMy,Y0up1v;W5(7ο0`X@#51&`gMR@D9"E[\ l 8cHa$ hR~rkBx٤iV<;~9T,fYΫ;lZk'h_( ^|ޗk[~%6һNu_83>|JXhho^uoߺcNgm^x/Wa~w֯|? /.{;z }YCLŀ yՑ@KͪW&1-dmJ2 ‘?)^:P-f[GbÈ]It]w/`$ ܸW|p=4d/>ϸwm]e;۪Ro22@ZŧKaf2 }wl.%>pW+Fjk/8>QhhD5IR߼}+>u7U+%DF/ XIJBpIUD3ě` t#\g QM 3ߴ+6}~T9hT~57{1rj2rrm9vt'K̞)_Xq!Ls-m23LV6՚@ TnthY.Ac""ϵz"i&dK#(k!N4rYyB〔 E [""r.Sƶ-Xh R7Ly0IDGwre#{w^ ~~\P ZyfϏθ(}=W-i~VWh;p/:yG{ԏ] sy"%Maޛ^6RF$11/h:uXZ-0QbqӦMo5}) QEW>vГA$aKhIѦ k+׫-o=?< 2bonyXD)yio8xĘY8ٗػ*xrE/pDSB0\\ !J>|颫;s|Z6o..|:۶8{ J\*64&JI%G%0h= H i!{ = 5' >W{~&:4ujbS$9N~7[z|rc$YHwx9 0O!BO"e&Ea>}2R N'Ӟ~U jnl` t"ԁ:qs/tA,YX׭h]FGu~\-AU{11i뾼,F(0hȐ^}>&|SAGa\?u 3feukV"Ly6Fx ظ+SKS!WSs/Zni <{@I;L t̩ǭY74*%ˉ+M8k(lJɓa/x. Æ _V$(f0) v Zq61_) (ܱgs:(8y߬Yվ$:Ҵ8+IA'˥ns4t5`bVxGXl2bͭSuq.9cN:Sζ^g{(. I(Ҩ hPl j9 L ԋ4crM]D" útP'9+>ODXwDt\ד2B/!bIn{9'gVמ~ۻ:ۇrJ@D)fR] qTD T^֬BzbɍdݬD[!Xi/i 8Akj\mhIYߐ/{Л rm$'i5_1l n|3VtG 9h '(#Dݧ$Gv,hG3GZCdy BIaDӢlJ{(IK1kRB@ժCx1O&@k+׃Aq#~QGuW ~Jh[U`e]bD]&Ϙ_jN.b3oБ/-qZ*v=:g{X}Ss6_vMO>p[TꥌNhoNo mۦ>~7#/Al19:tЬ<‘xaѴtaƒ&2(IzHKz6ȘC/ Xлw@( #IP  M ]ǭoqI_^Go8m9pM4d]f2Ů^z2~;vl0B]@itM8c&W @?&K!:ڶGQػ@t jF(r?:+?y]m{{X6o^(IJ"SVK #:T:d}#JpAc{ϖ-[;~[GDJ(S\VN5Tq[0MM>__4J*oZguaުj!`%o<~CF [ZjQ L&+Z-LB Q\.A|( ݌GQ丛ɘ5 xz^CRe,g|ة|׍eM\HNa$AU%@P0_vk+i?i0իqfo?1]D f6 >]*35J4K(L(ѝ'DSD5{%)QzTs[RF^}ziN>^$%0y}W.]҂cn&aTJqmH S;dE?e7'SDTnFq M+#) ABK*ZZJ*H4LB  +PU4caAW;"^6?mۚZz r׫T y_.dЏ߯ 'LᲳ%B`&-_ ?T䔝0J}Jy!IPJ9vt@|(0dǝo:ns'ADP %xepTL x@^4.괝 U0 D!McVj]s5h,e6uN߼rР.)Uzy7}>[cmž0:=[8_nD7y&~]gIn0O[D`3Њ]RFsF:iƞ?_ ̳Z- g6sg6֫C8|E~'hu+?ק?b#uE6ܛDBH>8 2ZĿǷP'jmJ^˘ 7QkEff "n݊3f1uEsYg9\#> C̙rHv-ˉb<,IWByM'&%/tOxX}-'Ls]>{qҹ9^.7`־{0Qf971_2eNq3^|T16㛬zǏ:;/Y_ DŃFdtX^ pL EJW$IIVGEQ, 5ٛXCPFQTŻoMriղ4t>FQ(wܛ/<]P+a?r; }']jn&'"߯JS_}~uݔ]f/|?|]}AȯV㗲Z)rDϾa3v8d IDATvղhM-=7j髗wk?d"ʔ/s2G͂62TJlZW2CS- A uZXޣπRoe]b5vkے)UZ4" o!ٜՑ, t "nl⽹q]ԣg־} FA?\gGg^V)r6Nyϸ)ղŕRqnsgCG: Mr+>_|YJdLЫʭ":f4ڻvG9%6O*0*DN.GKV<״8oa`W`ljBE|!Z > 2,q6nľ},#4ӄՌ=+Iأ׿(PET (;i3H(j%v8{♗4r)e\'.P~eܔ]'ﲧo{vQƦ^R }l')Kb`Q*%Z#,dTB{f?d|YA L ӝ{{Z%1~G?cAWjϟqW~mq[N9l6W2|ٿmJ4c܆۷nls]esA D/۞˥|ԨqSje ?pزi=0~,z^#Id|h0TS/&3P@;c(r˶؎RUE0r~g0t#BA\ B%AI@#ZQ4n"_"O/~{߸鳎:<wc>GܳφW~wDثϏ~~iC?~xrYq7o&Yb7 mLlkJ% `ɂidCpYDI YIdPPDY ˗0orKoGќ9$J44 e< )'@&'6M۸: roG?r_rWDaK$`Duu FaƘĂ?ۢ[%v)Ju)`  r][AEQ,_R($yeV]F.&21n,]HҕqI3v co` "uuI3fL0c Q Lh0v8`ϚQpܙsV*Y4|三#Oʙs%E ΙV2Ҫ=hH8a*Z;aZCme.4PnO( Y"B"$J@D Ü6(4OD=Ɵ_͟1{F߭ZgTwhikp">Z<[=\W?g08岟Gz3x=B롵N} 1q5?c*( fz`INVo9Rcfg(QTYc Cy^hFlh@!3`pT_&o z޽i C@ͪZaԈq6<>dPTvu@Kx$:5JM L6pySulބFdN fsa5a\<)!$"-cm!]:2L{fmY`K?S"AԶYb*I I81Sizh0L&VRB;,p]2rZ,ʋ$r7c#T$cVe aen蹢C}]WcuNr[`ǰ(%aԳ~7ȵK}9iwr=9%Ywgw7bL@|}._2ߔYs~y¾ zS+VJc>hإ5n̥ 9aS]6V|;}%SY42[uMc qKX,ؠ1p˶%!Lb޿5"z Chl;cD)Q' ]0`}sD" FK,c֘DVE5vOdy/# drcR{J0IIP.m@KfjSA_z}NWWXQMCB,`7v(&ڷolgB! i7+eERƃЯq7_qC&V;̠RFBJId4l+>[& _glCc3u\!0.O8"FajfuB.G$0YU%J&uu0A }7OTY=pEϞ"8hlL&0$kQJ L$B5Yd 2mjt81|V@ QWNr$.$AFXٖ|额$W7}$A$7q%FjϐHRߵm쨡Ohᢎ kN>Ra~;B$($29QJ aL),48$+YV;q\N"2y|>{ +uR\V0,KDHB)%~+!}” )UZ0Wk;ڈАҧ$}á[AB4gD.Yn}| X(g)9Uµc!˃&>и&JDj^I/h?y7HDqT׋[0jٴ=!\SH Wd3+!#{)}q◟} } >a3fXdf2c&|R<1CАSv;l$Iʔ`2(fihBxroo˭pGȦS (8wjqs{̛ˢYk'2&Ub[V2 z:uW+ryA_Xzr1?~3xʹWJJK$_$'-eo:ăົ*;,]!Aj_2iw4RWQ{5.A((""I x:) <(}?^}߯T*@HJT"8,;;R'EUPIf44(> V _d b_H:d|(I!E cAPab13N½%@itEF~2i 0ȗاطŭ(eRq4'~?{658LR蚸+J):SpxFcZ9i5e_5[!kR'@(m! `(wT>N0x F#X}+ȄmN7F1D\8rQo$!}Xm&A݃AX+6PӗKKKTX;($A?(= I|4.< pŋ{ON:i50ң:s\j+dGO@1he0 vIu(}zǍi1=t]'#R0gX8Ue'9S.u塗hۖM V3Y @9D& HF2 uK^e'{+hHR79yEzh'[Ű$ *@" (]/ЕrdRARvkjM2~ wliamߺzv=4*LN:f7_|zͪ'qn|,F 1 ^AmЈU( ?ls$ؚob4b\f υ YHбt$-HI#n$?~uvR>&N ]xKO?bȈ1aaS+- jﰦ bu/./IZ"yWm_O>r˞L{~ Btu?}m[6 7q>?ԑ&M5zpiv}K52'Rϡ2?9#C@) YBTTۛ{4}sw>-KRʸ*W*$eF$eDDT- 5l x)/gժ+,{Jq7@" _FQx_Q*v~5fA@EAK"q= j&A uElDOb-bhDx&;*غ$[p(NA%1ڝ-4OD ~yZxj?) @lvrCӦ{<|ȇlֹ%3ZDVk!/沔6$>X<'Rwpy [*R;;R,ΩQ;OYT]%V IIk|w駟7|ܹsR`uk`M)KDʟWK] DAT+ŒnқukKOWvmw^}f+n+-Y-U_7?]vβ% ƻzڶe~xM{`-|UxW+},蝳/ /Nرu3 +.^ɇ{{(̃J v S}^` VT)q?ft屢>?i27oea- 9O$HbggjM'&NU>ADhzd2H 7P kB/>۷lSuϽXo*r._w7?g{GΜ7]SN>?ns^~v#ݾeӷ-Z9e.D) $8ґݜwPEhd$ PT*d &pA+AQ 0_,zU<6:'ºOfTׁ D$I J,hJ… Ǐi=\sƍ?]v%tHd"37$% bX~[۶m==Iтx[sN=W-W}ݕJ9+$%tve7^3_ws% 9}A6{o~Y^7/]t2|L6*Dq/wy;Lzs>߾muvRHH&Y'yܤ @iNAn:wcf)KD5zТDАJClͷ`S`©kMuB"<)9؃/6L%݌bMБcly?c&L}͗y]f?3O-}]'D|ڑԛR5sM |$Hp>@]UdᆍǏ[__HƾuֶJs'Na`L(30:0 *{NzG,%4AjdX,Rް]y Rj VDԴb0^"Hx5dd&Jj@ĠdDA$ڻ7b52TOݹVϜ9s=s= ,XvԩSq-䨆RF$2zpSQeʎ>51NU~3;=(v:"+wYP Q,2{nEs<\*u9O=2h舖>nfN>zMLNACGT+e˰|]'A?8wyǖ͞}u,־O:?\tZrlb kdh%@~`Xuš!*Ҙ4fdE(44 G̜]U .Sb$ ĺ\>yƛlfhq-.IrER!"eW6|UJGOϿbWDآdfP"K9pȜ**_D?W:x^T.e>Ibgο]}iM IDAT|~AhIZ":ڲ\]qZz;;A־MSwO("KA/pH3 3x6ɝvRf{74Am4HZD椋,l};&4xACG4|D$BKF=[鬋"8NpׯT%-JZ'L!Ȗ^}6mfӆ{4_XƇb[`Ezk Wg/GIR^RޜOH2u.sW= dH#Q?Vr*8hA$o%;a. `A"%Bf󥮎F_zW{ڟ|F>aP {м8lR*WuZ&p钕O-%^>6ӫ;C pɒ~h}8|l., 2&h\@^1Q\0i% KE)Gp|D&{& uV<'tOIIؐPc>[/YE4Dѽ!}z3:妭]QGFIZ<*qM =zPNUX a4b:p#g̞أG>|rFs|baqwtd}+Ҋ/>{;|SFsJl1~&_0v{pϟiز?_*9h էX-g$S,QnJ}dUvm3ƍ^YX( kTώHgHiRkR$ Sgϛ/}KPhڻW;)fR)~.>G?mqC4Vy7_֯YUTFܳW}׬Z>rL0ja5D)Y%A'F)QJiEc CkD1Ph;a1$h%>pݛ q\qd7CDLaNKms OyMVl9Y.Pſ;qVu 1}fT詽8 'S$g,~דVk%!+89LsM=Z0@!`)]!$uAcaL+*plvC9%V~-O9 gWS_zB@Q$hGlߺ3I຃ )oIHbhR#uӇ)RjN//B%9)0mձj6@눂iGz;%ª7akji45lXhPu/+9,կ`AO>xc Me3T;,kB B,Hb)$2ydBuR@% e>K[Ď:aa# шlÖzyVi+O#O就S◢G\ߡGo۲kimӰbWs5[6n Sr70XW?uc'NN"~̉˗~z|]qm+/ aZiqy7]sR}>g_!ar5iᐹ5E<`z\j0ld{spDG>߭B+!xA V(j$Fx!ъ&DKcL)#"&v )iK5]m֚Ox}9}ks1u-dW?zquujOxKY/߸׸Qy7ծ{).m&A}I: ݤ +:΃$NXu-xu˳~uuy:E??omN|vup8tܜhv8\-S?HO<:Vk]-OW1G]9.?߸wGf|Ou.bP [Wc}ry٭{?囷z֤n\Eǟz2*)žk60ͨƔ83| IF mj1_ْ}NI.x|ӘN)0*ct/өyf|m7oL5xp;?OK7n׷/'z3އˤ[/Y+&ݸTfoe>ܐe.<Z\=܈oWn7M3LpѶJU3c(HB1!YqW޸yW}*/KF߸͇wz˝<(1hr"^Y1S947I]xq rZ! p 9ىM=/PlvqhTHxZ8 .J 6p,KD5s2G'^ibj 2G l;&qghhA>65(Oyѭ3}(Θn42*+wRr\iVR*La,HӖ`<GݩJpȜyhmi/~8>e:qIVVklMJ)HׅtvW(M*B!nsQˣEn׭`)*?1fd*:EWl ћirA=S>O2 L9r&BsW-G> U01":.EB$f VCMM?2qrf.o* >^Vf_&a3|,X0WӆC"|_ʨUƵnDbUhwXpIPwE1+pf7Ms= Ћi$JMΰAbuG3%5&,{1k_>,K{e2D{VV g Ū[8_cT8=JڌA:3աy[/@u1@)SPpՉ] Ȅ <+{@<uQJ-kVsB;g_|SBΚ3OHKu8^bv+jdpI0r8"8}֟?`mYR_uE&HFVO3:RGnG_q2СPUg4e5ҦE;i hain m\߶V \B彍]{vpe7e+}Q@GmAIsԎ~$>ٵz<'XgGRVfN=5'P$Shq9n36:*WBY]a؉\T1geni3 ]C[]'U5V~xG)i^^˚ba < F@FCōTd]{ nȒ=@0a<0#ݎ~vyőn'RJj>PhaК@8f ѥ1u,F"` r:]V)-RR))YԬq0K2bEm>Y;MgQtg"Տ*|U\fQyLplU#90@KRc% l0u{E%WA/[ڃ\4DH\׎Q6"ےTwR;kcWmwf$}xg AsIf,EI[h"w7Xm :hbpGRq#p:aVULn˲iVHvt|.cHBʭԪj;SVm9TKb+|C+^x<ػNI_?bf_v^Iոvv~g7w=5òǺHC(HX UCLήy7UR%ۣL~}krj߫/QL3E%S?_٘aÐƉS@g.]ƛ!Za2XsJ\ܐAZ- E59IkT@BMc)/mLvu̦Y&؟Q!}t+P&,(BfTI;1 sJEj'~0,И-:dǡ͐Jp!U 762ⷩT.8\U)hjHc}N?%nUPHf8?)POjڒ[]7dG`۝eotGr 7UCcS!F Aڃmr*V^? SPk_# .DG?ŨkKc.cLV?(2j_ ZqsI4X c˿]Oo(i(mkV=.DvNv\_j l\&6X"ʍXQw2ůV1h*4/O#Θ@$-L1>*kcH'I"x+"GDU V")5{d2a/ F[up$5uǠOG e|9##&ŚO,"’)]ֳ-I r˚uWЎjol/fRG%o/%0k(LN ;L62rY94aNŤ]9d~lpQPEMN[à(V T#5' #yPCёnC*URdX :Tg~mlE)s q,(H4'K$<%(YH,b.)ĀL?bStb)mR$MeB-JRg ֵ*c)olk i `GwqRp,5e}RP!U@ڈMR,F=`sѬpԭGyyzI?}d)Z7#pHGX&7#/J~QKFY+Pq֍.w{>tGQ+I)| C.B2X;ʿB2Š0X&#͍B+9 "ZicMZ&:lp)bi Z evQ@̝kѬ [_*IϺl7p1Pa:= 4xzv̑B2]G2oJX*ZnLCB%L!-MARVIz)&W[WdZa`wuxK~LtOAKďף݄LB@ƺz3bu@+4il֜,̕GWrIȸI)g'fTs i9)O҉\l.ou,:ç޽ݾ vsH5cߖqYMi)Bn؅@f/O8g($s ˬ'Bۡ e jؓ5~nn#Q4by1/{3ϔrt jUNHC}{:DOuU7# 14M~Z}&7T ܊o^ :Yf7#;;e5/MT0Ffzq<,r}!DO}RArg$waQp,HVYƛjԕ*JTAo6PISqfV Z$(EסBLhCGV}EtWfDIBY֛GO|rʷJ:~B]TbX:JXe6f뜛-˧޼?m" l[iLLS% Gd Ԡqn5I✺䉘:F#j,OR6ХYCP0h%g򩲦نwp'˩}=A2,9;ƅRcα0#v$FR&HV|pcLG IDATŽN`TQJ"0Lԥݼi1E/Zt;Y}X[b8XP}6Yծy+8Y+mznU1/8 ʵPek qM{pyzpٯ Q59ǡ/çP|FUpt>A'~͋ݻ^:ZߘhZJ ZŠ=ӄxep<܀Բ_HºZսb"L4 3nUk5:]fŎt4Zkc=̋[l 1J,ݬ4QѨjd&)lfF -Q|dV֕Ucm|XاvhuV(C,!6C5~Ɂ-jbFr1PjN:KʼmN$S]V"p AC䝎<+VE-pqONFFPή~@{mrcnfڻ28u^ Q)R#_GW=^yzULH׷[tĦ2HE PBU%][P%s!r巚/~[r]F#JKs:<!܊nS]M2pPTjŠǻ rkDuZb d {ޔū"!/S"HV~gtLZ%I##e^<D1CLen8FLzڂi<8)SbkrO$j9k ٚO!SSxCVt{\EHaE!#:ړ)6.Uv:XɅ_tU3F@GlaVg ԑӑ:sIOL)LW"pE6V`J B)e"qM/%rAel&,z֫%E2j"[JezaCi5c_hY6!g08.R#ug'/[:fR錛emz "N[£!) 0 /FCsLHRSZeM1MQiI$L6U`__JUg@`qGaS  :Rugs`ȪرĘYI\7d  N%"5M'{dMԥ= 28u1M磢(q(Yo~`QD$|p:9%2uF*T-˭1JX" >rDLD{~Š+QoT اQ΁h<ɦx}E\ebvVvu©gYTWg44 4~l49w@QYc=~DX'w2F RlA !oJ\wGShY)@.֪B/AZK:UM-p>e4O|aʝY "ЦLf2QF(-H75yZ{KKKSޖ.Cj>2åij<;v:m15>u9{MMCh<T1!WG#sU(ȣ(Lr!=> L^96Ń*l7dҙ`;՚CCFTdŘC/TrX+h7_҃0 H+Th];D%.hl~Ovڙ0S+U !W'r ]ε xfJPER (T  $TF#~M#3q\Ar_a'qI <<ʦpz&<+zUe^RY$3d8Ǵ^NSdR329/pT:xZO< D Õ˖'X+qK8wo^xuvw^y-1zs?({f3T7r>CTnL;/H&CVN/:RTIRi%4%bqQA'A"rnF+Hl ( !h/[!+="K.l@`q /!\J?!*ȌX#Ad!d{,z(uJ/QSÿL[S"V=e&]$ЀU($ڜ To%s7, "|f0==:eFP®u4Meds`k8T!W0X]yC)H9nީA,DWpk;>J% uJYtꂬ >TPlN jJlnp7!j]Lfv#J0{r& +lp跆17Dنq+>4~Sbx KTnf ? rJb[Afg; x>%2|DV."ۄP yk~/4u=>OXKF~PDO)6o!n?ʡoU7sk[Ϗ㺈R?{REuFTqlͻƖKk l\mUv6_M9\OcONӡgfk+}cT@x9^oH:jY'?{4{\1I~I}eϷy[.e yճ\Ǎy IC{)γE'ԛ 2η^ٗ۵V*; :g suw`=̨s 0Μ}rg7gh:)yUҞցFmwNМ\s ;ܺږ-_:ogU/v(Jˢh(N'5ֹfiz+d[N1l_uO_jջJe ު< fw_:󜑶+P/r?;[e²i54l3+پiA˭*Ҁo &lnum]{`jLg @/r  d09 Uޓ^+lwTuxxyIUVNіt6n$FRe-^sjغE %%\#o1tg<:4VD:w4~^hndm-45Y6tzΡSu{m|,j é `+ŋ)-Y =3PK{r偯=>uzF/%f8耂>|0.c$$ G/-LUc5K.967&6VEP0\ $rl JnM0ጄWBx4Ԩ/զ@E*4_{8nY5OXd1qςͩ$5:44=Vb617bfDYsk–oQ1{FU% :>T(OzM-JnX^R=Nn<ʚ}6%ŶґӒ%QMC0^ b@f9]9W[&O?`D D`Muh37v,wTЪ}/Z )Ai(3?_!~`X ʱDyl-@%s4YKƨCr",qal{&@'Cj49L{A0i;2 V6HF%,1eȧi[;-X )҆rR:(,/o^߭ZwQt-XsEdjҷqRY~NQQkƻb,[LɤWӬaFDD&:=Yn jjz3Q`(ۊUTML,Sh'G8R"iFwCn Ǟ@9J/X"RENXT|y4I.! 3xP?v~ɗܕf'kq~j)Yze+ioFtG_qCu~*uʌ-Idx =W+sB9gMpK"+#q:h)Ơ$O];X_/ܦ6}sqIXm*5]] jnCsm;BB/ $@._;tiܩNJs}E9ATCSdl7^9ub27GC׀.ye$WFGd%OX <+k-49$W`0w8:ѱ##* (HxNU Iaf\N-=Ҍ0-Y"L5Qt`'S!U#KV䝨jijdi = ]va[9C-j,Iܑ8X u=ϵih:LraX0 Y[pG[Almt$le]Ð%*KHV}vgkϩE +hK>^~h¶긣N>|wm޹ Z ! 0~kroto-od3r0F8IJN̤i>8y6mcNLud! hK6]FڒBRf֭KMy)-]Eop .~dQMd6% *B >`=w | CmZ < 2բI%U<E&{qj0mR1q˃c`by$' qfr[KcnR -"J^%q{$tcd3t6Bh`z! 8d+3P騢-14ږ{ųκ-=G < ΗakHM ߚ7㝷E㏽yzqezfIF3M(jΕ A7B'N=~OMU03Wn I=2 fV"LpC {O~7™('I$.B-|ʺ,BD7oncT Y'2TlVM&uˉ[qWKF~n%m{*B*f@#$3p|qj=tpmp,vNEުϾozЌQ~rAz,`Z2'f-Ω7Nb+3u&iJEf*F+c;O©]q|)%2]9IB46 [`(JifVќМ>- mGo,y-gT;ɤ.?;R[qaQd {i̳pז\ Sq)wUa4*khJRcLA٫v%Y|^;]SP.tR ;KBJ%i+C<*u }I=i Is:/?o^vNDceFі|(D҄uÑPF '=(.K͔ #e6yiuQ *ΔDJ?MCźMzQ68; 0ly f9\VQqb&=/@o׽oS>WL uA՞X}rH_Ezol!7}}Rkf g2S9a@,zLFEk 8d81f[(9?xGPgJ#ll1t`mGc1Ys̄\ c6mxFLi'gOY'NY2,) FDӈ8Fe=vXXAbE4]Hp`OMe\xԡ,}-_S@A+1_ڏBZ+%rInߐN 2jiz7[$v6|my&Cuͻv"D*.5Zw$*KlMZQˆ} F;2&&G8~b:d IDATlFUi15W낧j۬M7Gva>׊FʻQzdp:{W}l"Nw< /! 0]||*oxXF.10Tp %E~zP zm뱬8_<3T]; ^_;{|u& ozd~'32A<O\ӰGϫDnSA0,Z/x;Lt\ʞF]W!nrVj klyfI8>"TZPcWE3Sf7OYAsfcݠ`mZIF')y@R ֔H]YŠNC1|WR`J]@_.ۊl`ґ~ü.^yq/ʪE3bDDe}83Vl)™>{Apyuk^6}SίxrwP>ղq{Ꮯ}<s6"08̧:OϦ'?p}۴L6=YUP\LO:2k#xVaP'# sIJ=D]x!S^V'j5(ƴB$T"f!IP3,iمYU8seA;Ey.0G)>oy%b1̡+0q#}kY`E,md% k M]Ge>-5Un+g5 Gr1_6nBɢl|=;Us;p8]=Nv~3W ͎<&𩽈 \oJH)Xx΅4̫> &S6>So/>糪9*_. U~VC83̦ˡ-cչAi<`4:-0Fb:Bn NSof}fCf@MLNNGMĥ91饭SO>COlrmIPt60kߎ=cꣃآ-rц NtsЍ2'"CD73^T;Su&f iaď6Ań2 NFPM7SjlqIR]>b$3^3:Tyո6 ce#'37S)8r.rp4^ !1(ok1%b 3`wۦ3g\)a /sq ŮX1]]I0/Rէ ŭ?ipr/t@dP'dS-5skO) ѥ{w+nNg[\Nl*鯲[K(sqoKםL ᓓBZ>Ws4΃P?a#ixtu82Z7YBK. SzH.LE'Or{9-,_&Z"/C۳D1toIb#%ǹu)j9V߂.ߘҶ,{BjэgE QM-DK)򏜎XEo_N$(0=8nO!VKYr7CʼnRY!-RSX֨6ͥ@\VG8sT+k-ƉY+aw߅ѝ],狑 hԈU.6#Z%qeOzK$DC@Vb_uV)[Q2{ݍ_c P"Vs$LVxk"%%;Z~CnB-% @,q̌'%JO9jHYkGn@Z͹Wvolh3w|nCq M2Dc/tҾJiWUq`MJn)gF]VdHD5wJЉ#m,-[m_.nsE S{\Ɉ)+VT0^Oy,Nm951}6I:R `" ޫz_&\jȁ"oe|Ok;CR^Gk3.MzOB,XF@x8b~eZ9 B )"ܬLm>D_z7u~dHj=%:L Ϊ XOD-^3%l|BlY;cR[W97[Rw~9W r%Ɗ\mC TdOLm=m͜|h(cnjnySZ3WND%KZ&(E_CڿGD4nl6tu]ͭcj9Z$1: "h.[P$`-Ց8"1uho㮠kP4s[!@jl˥ f?Ӓ(-&ޑ䇅IQ# OZ&Ikj7𛨗>q_#MLjf =DQct,i[{BYbpk_%8LK5H2B ZƢkUwPqn{biBHeS\lű.6@J6|7 ƥ#C"Cscl!Ymei>hY(\ؕvM@璸k$zf0sEt>O}kVcpP_(]r !e2+=XXi0Z\C֛qZ2!/Hm:A?qҜvPi2YƖ^hisE&n_)fYVt'W]&<֋DkWO6'-#LdjםrYirӠufk5&W_N||kYsڒm)ūpLXM bBFSffMk=> 1K(. jŞiȤQX"$(̐oovPèAa߀ \LzɅ Ycno&u{8C_ u2[ 7?[nDX";r;"39O`UyPG#q pi;ۜ -d AGv.US:%) 7Wpx5\Y\ڿK}_khrZp]JobGGɚefXW,oȮ$~UJ`n|/8د)NPeO0!1磮-W,ShjXJ[=mB־蝈@Nrd'3eFpLAڴ(/3-vpIFzbo۲6)8IBĚrI %J4 D .z4;x2~I)J~%ю'6ؾ)43LYtۡ^fLq=qik7LE4U-ATS=MϡKmg%n4&bK$oZopcFB@fBW&5g(ڼﴌ-&lp 0L`]m/h/K>WOYGQC@P`["i[_ 3>|Rhp( ?~(Q? ?4}~ߐv:vJ,(~Yx;!h( ruedָbSMrሯ[,!E KaR5-ҫ$z! [܅vйavefA"VQJD,.[\ (`噋:v8Yk-&O^ --N(a9:!6Iif@6} +5ć~My.J&]KS1ZqΘ2Iw^Vav>kÄ/*SSFACYi(-U0Ո<9@j 昄\j<-PQA >N-Y[43+-!2ʺƱ;S92L ~0T=7t5%lVT]G)nIEwVr`˃F7IpyoThiCdkAe_P]- L\4khm;Ngk*>C1[x0rPeǫQV) X62Z>=Zvm ;}ulc5@7Rt̢qۮ9ZS6U:Vqz6`q F>Gʯ8@IXr;AbH:<Ȱ_Sd?>1mRL#>|$2tubo{قvbعT6Q"="&g'w(D_횿0$:Y+w =țY:0܅6Znq>zeXoxI8tuH;Ywn(MQ2|'cvL"&bq`e4cY]L>UrK QW4z ]/RJj]C*ݨ[V' `6%),u-'. H:}JJF5u@[C2dyQ 2?-WiJhb6>>]s[,DZz֑V~ ޛOz*O"<u'%JE ZϦvK3K:&( CEo裋.j麬QD"A^Z#i9'<-&=94Y[ottR~޾k9&4~_lq C0o:y$vH* _SoK:"aC !Y-Au򄫝G)|]e#Xû@L @_,="ͧ6Mhs-b0p˒wKhF<(3dVl"EPhG'߅zh(XKdπ2O&X;9&6BcAxߕrO6U%TXuiz?^eBj| W%-ӑ'@=ZhjQ.%Oza=0u(]Үs8]G  FKڵ"nhSQ%$9$N{{nP`-=ݘ-TǩҼd1 BCbnz60ɛqX4Ԋ½ho^gּ a`yrH.*(N Pq~ z Q[QWdk&DZn2h46!]EiR I 'RR 6sȏh[b2iFkXR!I#ShK˷vM2xdIҖ-I5g.xO UW(9.XqV#Tk^m2dv7W<*zSqcZͱbG/73-&!|sǦf6flWX65Q/Eѣƾ-Z`EaEl;RS10rc`pbm) 16p E߯,V=JHS+IM%W}a2di>>t1Hr (鈳aQRc$ɲs4WYn6T(#jt\ZQ\~}SU紕Swr܈L_tp@s51\16~Sq!Nz{"tf=vdʵuwNg;+\͸TT7 5?`r#:>mF 2p.JBbqT+St!&tJO|*D|1̚ 2t?T8fo C6 7TF?AZ*П* L*[RЋq {խVpwxZЬB؁>d)-['%Onfvq6hCMJnr m'*N. HWyUU0s7'~`khWþ[&|B{舏ydIOE9 >06jXS{sUk7 :6-c_*fec@# u%\A, 堏х4$;iqs`+XD8UQ{OtD p%>SN#)䓺hB F(Rm 5d0y{LJH(Cobmku틢򐄱AEa@ \n='PLz|m5èξbe {YLhc8e =U [<(+R4a+E)Pd1)|=ueʉ0K-(m$%y++LYg?/aY;w3([`%Xu"<#!ц:-!? BUr1] l{rF7K gQ,ytL we j!D$"-%ٔ (S6(B%Ug:1@pd3Z D93`8 @e ;rX˜cDá \ S[$@Mڀ1bIr1yjdDvrx9u\WDpIzel ֑6."<ƛ^'g;Z$ IDATwg~:I- 4w.h)黳ČRi^>.w0qQ4c2%}I?#ǷCOz "|,l(n2XBrwrk#~rpL?^<.e~G:R"5WgTH)Y-Yzfԝc%i @cK(DKQrrm avȨls֡P,h5[N5Aka#KӛMITIpǣ EmlB7UM-J⁠*tO/n9JOA[KtKb Uup(*v@Ir,X8'3tU3q|{1mCkhͬnݛ텛VTyj̐LLtinϞ &U[N9PJm f[-H)iK;[_Éhr1HE fЬ^4BcxB9An,V6p6F*TV*H軝]p;%Md{'d7+H}r?Y"|A:p=oʍtr1D38B )@~Xo.Q ƒq 9 `"ۊn|ڭXt'vxTq4hjIbNr<]El BӰy{.ٔ=:;h夵6q7$i|C ]ܱJ#66{'"TͺR:ql=Y/ID6B‰w[k#/eq*/XSbX+TךOkb|bOTS`.JI#9?X vwW\­j fHl-ty]xvv:TI#{\8 *Rx<\|򷠨QPLiB dxZn8p~o#W=D9J8 k%eM d#$RM-'!,@=v8\w33k奷~gy)@=㩥2imЮ̩ED꫗,3k(R3)1\"G`m c!QVzU&P ejL'ĸ)YPM,ľ,\[\`"bˠ6U`82#}z$UqJY%4:LJ;WaMSQ:RE4J[1mbAiPߑ+\uZaOg'~oS>/~W2dپ›|/;_yn vwQy.٧ܼ-؎q5ˑ dVdoy/KE#z}ǟ="ԣN0m`biYo}/y?7/_sh]]<ޟnwuج~;~KS֭t<v~㦙]^^ˋ'fߟݞ|g[8 OpzN[1\5KRDaElsqPοYN -_(X|~SY9d,2g'襳`⽔ m C6>o50Rip Rom^zt煗F{>:NWO.Noܸ5'nwm]6bmIlE(CKȌ:a.<d!Ż,&&U1dҌ];vQ%2~_nLnݾ‹/}ᥟ ?]N7o?;}ڿWru[?}|xo_GoO o+ڿzC}O_kx7_;ݗ}/9¾LĂz\k@/@ע!ǑG¥r`!T;}2(CFT 3t3m(Xptr|  ) Z|06܄UD#۽9"]"I9GgvU} q lgi>QeBԧZ5ANIG+biF)f"%3R%ca?.WE_[C_w?7~?7?-w^x$+Wo+~KO=oo7>cfO?_/|c?df7}_e .YPkLӇEuӊLѡ%)v] ' VsptD'Uv^4Jgd'$d+l鶬upԪcfiǏ/y& ?af~ם^u?g}؇'_+n޹#~_?v3G+o{ /}{7_ď~׷/O^y7n޾G=Z+hcAҸc .fs$rL Gbz5è?l{LLvXNfj54XEn_,~ykwEgm,n6M hŬ5"dQ#@յUk[5ܨjtXA 4UDz vG_<ݛ?'~<p<Yr8K0p嬚AuHp}/}퇿>?_z|O~~~o_W.Cs~nݹ{8/?G~ɗ7o}?нOȻ>3~~oOoO?K~xdJ8]0iR ez>︪V&D`ivxpß|8I[YtKiezUq>U,z].~1^s_W_/ݟ}#曾k |g};}蕷fc?wv~~Ow~%Y?-/S?Æ? _o?}ƍ^oc_w*u&->+zEX 98P4vM01\LҪ?-^EhvjΚ|)Wf9LYFgj(2fLrd,!VڂN6~/9Fj_JZ'{[iQЄv/j"Զ3M |]y{;*}ߧ<%$*{{/3諎]Qq"cG̀]BHBҟvʽ*8^\s!<^{X|y;vn}Kn: D]HFGFIFm"6 QtE9{gYk}oo΋;١aYo~>xg߿m~⑝[7te]׮۳[|ja'+84<sy{O}( >|ӽ2epJ+DIK1Ş%ӠEYyHKWv*?6>AWx1\U#ϚSJc/x>UN;n}uK.;EQU>t~It:Y;sr|-/_y W҃wr'њ;o9o~j=E7zc`/eY<|-ïn'+K6]\nUgWVΤ:iϽKJJ"v(FCQ$"3Lu7:κ L^k0"e/'D0P3gR;[*d E)EDpF1gDN/QG'vKK%Cnܹ/: &<hyǯZ1ӳʓs}CPj!5XQ?뉊|rFw&Oqm|.o|l/|\m䐛~9 [\|n'WwƜK'j۲QtVTWi{UFf-hp2\I `̷Me.)SE'"=xO>~O]Js~Ȕfvօz.PHP4ey:M0"K̈us;囄j' *˞K዁ ՕU:k oD&Z;R̳*E; UE :KQ(E#RRsMPwmE/xM;6mmf-4sWw'6x|FN׏B72eQðTʨXѺ!ڱ5nϮ8y_ᅟ6kGz-}L=j)9txQE(- W Nd1DD#IYNu}EƄ΂j煈gUNxu?8FG322k43g\pps;キE;Q7ʰ90moehTU뙭#wVL櫖8??seúۯʹsʲi3̜ZÉVo̜`9s=pW>說?3?4#Oڟ#D4w PQ0ol"OY&9c;5ZG@fOjD5_DTYjH9c*{"P$$) VXPžHYԜQoq#QdKc0*3{)fimic/ +o{6KDHbwi'y-ԺK=pʕ+<4}qIǜq-_:r87L*8P1m2h}mdjÓ~~u_U؁G:s)/pƼ{o}[4cW=r-+#O:. ?U~~vs_huxEAD>k9y ΚfΙ}tqgͭ5_Ļ\)۷l[my˲GNBĚ{>v/&OK4 ywVE+T4Ip.3- 3\\D 5EHkR0U!ռ(7NAP\WB]zqNI[.Rjͧ]¼yRMyu{ ې`> ق{rd zm,yů<~'&Gpu7_WtwخM~仇Or*|6J2tNT}-~y_U1"~j%v눓CwEYGmҲV[yY}gN{9=1Xu;/=߿pld s{6]_Psp%tڝ^f_UOvL5rI1.ؤ4E:_؇¥u$$9[)$RHMx`S;\ ?{0^!-l:|nQg1gD>HL@=جMFJW2h;zcjemx%}_9mּw_pˆǼ/ZyYZ=ߗ~'}ɛέm$ݻs:_|qў[׭{yM&nuozߟ~{fsh'\y5w9<ĮQD=w`pѰiw$yvCOooL6S5wU-msw ;z]q/֤{oڮ{W,h֋J1tĸ45&U 1ٿke͹n}z^/ʲjw:e(knmsEYCn0΢(+!@dL]J^mZ{do{lln6 SL%B]\:D_'fkIz%o1v"0 u] S9m&i|F$3jga{э[HNjD)nc #̳G |@UnG(RԌ}Ɉ̲F[BM5}iPqJ؅DUeˮW>Tpq?ݣ399y#3fZiʳLK @ [`gb ?]-I[}vڞ2|'pnthiܷ+:N;T:S}MV"L9u}nnygMtZuNx }Ra6U_C IDATh؇ny(FIA u0P|@6kŝvL+mC6CjArb߫>7)i?W֘-\B8=AiW/|;u9BvNvnjX"u!!"_ukr.K')-گuN @Q.v5-@WLW},ZtMd&(Q\4ַnXtw4\-ꬨ%VvC XIJ3xԚimA05|V"* byrQϰ'LK(Oú~z6D;2i Ƞ1jn:[G\<kAZ`ӷ=yŶG6-kQ3V]AUu=,oO0QQm/ Lk#- TB;脾t"%{HM|e8qm&L 7E^ `= ,F]Q_8P0: #B2`Te\ 䔒/' U"2?Ȓ ? $W,.ڰ u`XE4;x65)>0cҒ5gN;|zUmNsތ$ ԛZcl.+p`IMCt;e:T ye@L]l4#j4պ6bL"r6I!2V>0zasuAQt$3S9oNZF+RzesdD fuߴIKr]iXۺtt4X+}&.YugNl10@ #Eiٻ}/;'!6IU/,k#Z8"4v*܉:ftt}UNɐ4T.womʓ@(U qW1c2!5= %jjzD+54^uQyis ,31%(Z dy8Fy ֢N>0bϖ`Vү l XMW:`M Oɓ<x_O=p˖qí؂'W|YØPt\1P..-q3[ew|ML߉gs_]JfN IzG7y_=/_yg{b1<{8JcFYr{WN;'[_]|%U`GMS݌TWWU(+Ɔ<infcb<|Q'tAF) ԪQt/ >ytʩ|oY/wč z(z>#dA#J6^'UAr_)Q"7<D0XbI4c]s0DpRG8hM(WPf%G kҼbnӰRJ*:^o١xay'c# P"_EV/~^<9U޳.)o;pq2FcNPvK>w.=F_=s)ӀװB U@Pk4=>]g6 M7nEb(󾪺]YEQDTs夯^-m!c%+st/ey)gM>ģ;f͙O|dc1gW=6}x|tФ^DO*k&k)<9iJIV؅pSjd\dZ{\ô .0D&qhGRcRɁ%mWjwx0#Ň9鄐MyTĒ@Wl|g jDH@p-> RHb.6t_ x -9Fw4@5*(AuCGaA_8躧Wyu^U\\,P+MBRӚx;ן7 On>v0"E+w_puvݼEz_i >}OV#}=zm͋ߚ?|+jCw',Y~̪ O.JQ?xMiYotK_S}OK׍%]}ӆ[̈́O4vgtSD5kAcpi9u*c(4 8@M8s;mC ,>blW,9[pߟ~yw=~G{pEYlݸ~dN`񫖯|%|ߚo /^?rwٸ7~SƤ"$L(!+9QCM@1` (PB݉Y6=?=m߱iD ~iol51vҙ/o \@4u̷|3CW|+w_}Y/i}_𙿼w~|UO.]r=/#kkMLٵS_m[/k~eN>=8<|?>E~ců{͘=evM\;c>?ek嗽#_͏1g wg};7=dA{>{ļJ"НR!Qǡ UX42)1[rY ̸?Jк\P<{TV6#R^Ef ,X}T.$6Hᘀ/{#|`-t*-JY -B?'|dsyp"/:pU\`g"s.L(c>w,c4A>]=8h \}5\~qU/?9Θc صmt>S|e/xc~ W}5qDO[9W3.x?U]W`dϮ wG}o:}𠱱:-RvXAOa_M賸J*GIBi#whE¢nФpL.;tMI}_'z_]k=s^ờS``pxiDi^wF:ǯk_}+JtB'm`hw_ƿem7o{?/#D57_O9~ٻw>so~W>V^ с;Wgv5u=;?9ȓVsۈH.q({Z)!86MS Xa ?8gՊO**g{b5>68i98}rҴUtQN{<`z'Qu3_bb|/٤-7tW#ȹ ?Q+&_GL FZ^kCCS;ɥuL><ؾe# Oqغ^5wʯb|lD~ng?g?FⱑDpA@?16Xtڭw|䋿K׮?^54i;>Ï[S[cz˳ͩ51߿tݚVIS/.]qvBÁ563q(;5>cKOXMG&5a7 -<2{ҸV "ѝsj&rJM Q9 !0hFvV`%yDaq,k'AK}ߠL#t4 q{~"갚Da1Y" y_Di,vE.c٬N(JuCv(rǔ"Ks|Ωg˿+/'>f]nZh.\b=twUuCs_BUӊ;6cѽTUݪX7keՍuUh/άiI:/x&y g/xqVg硁#E10<}.]^o4~p,7_7"&q<=ǟqGOv}f{{Fy)<퇗>/|F i^yy7oX~N|i'G}| 3D}w۞􆵗}o-?VҞȴ`HX,F"$F(mPw(qĮKn`(yL9 8$LmDV/^$1'59̉#E7O}xF?$f~ RuTH)yy:Ibc^h\4LjitH-MDpˢzY7zQFQkk,]YED(h绉N.H:a'e4⌫/9Z*6kނ];BuG0{?rɡGO8Zyxf2?W .[O{pV/0mjhN$`ƚ(-tdYz0n˜s\rFLɃsC؞C#C2]puE9 67:tAS2>ۤ%R&ٸJxP7xz_܇ni3p -7N8cO?^Gb(ʲ uilphg B=:_gzfSOO6clz98tkOި_ھuEKӮvko\N{H[/ZtmD( f1I_j"fFE3&39xU!a9 fR VR5jYPڥA&O@i(1ӏ+QƑQf2 d3k:2*s{F Rc+ղl`R1FXZ\0K)&v|us+ {y<>3&[KNOJBvJ˜:.OYxÂ7;n=!GrI\}+JWԳyK t/_z_YsO?}byJT֍(ksYpύJۯ j`haǜ<11z ^ڇ2w}hY IDATWV~1'{u ː%ƆQA"2 : Y,":U>FՀA^D-H`S)4jV @}xޫ1Xﱊ_.;'INBmBWQ:MhHPsK+ (nQ@*_էmJZC3gG(0Hڶ472T&[bb|a/<v@Uw銣$nE0eڌ3Fvm_z+$:vǭZs."xͻ>WoX}]a)9odv:q#yH^)Akf&OZL*'r.-t"WD5G\nL7|Z3l$Ue9'7JҔK^yg kz3Z;-_,;p*j4޵_ޏ~UEQ;/YyKX"}sԉg ^;{vm?N}&FM:cúG׼kC v'[7otqins;?tgw ouE1{Î=^k|~o=a`pN]yܪN{=|RFd ;,YR_H9 9TL,DR{%7P *6k8v%$@'J\\DDPyWwHpS0(KDH:kb 7 6Rjh ?+QwݢgM]ljY"%S.Bkf(\8όtU"ʟCC=t}O7(5F; W~{wЬyCC?4meD]9ٳ.Y2,$׃! jƞ"6R1mH!ݠ֜kÜ1^ }K;ViPݪ7|Uu}*Z=`[eYE ݮs(]o BժPUU k^wNhTU6i,Wn W*_UιsD!+zr=G3 "O2KLgB|h?Ng>PmwNSF9ΫD8'oP(%В+6qQ)@I6}%gwWRV^pvm eNs"U#`qȼrx(KKT/]㒞(0SrVU-ډ(^"ziдbZE>Mb*LrW1 +Ƅ0ۓM}1)8يNaHDp6JZWPH̴|f!Y-{F}XGx,`tEp87 sr% %U@HJ_KD+@ɫm&UA^ʟVxpw8=Hو_| `p˄M\jc((̝A'u鐄&T]_^ 2{>QiR !up4:~vb±KisZhoX\L.ih'mI.*-= cф [0{$IQ#E5 @Mda!POy~{RJ.R+ԇҕ 9x%e8Ҹ,0; 0-πF-'ΛZ;r>IG$4ZTB27>yT4J$mh459Ā2ܧRy%mfjG)Y`rߛyNzHju~vJSq}E%GԤQ )ࢦPj&g&INjd4U3" s[@QH$}'̞Xif!;R&@@@ )#ۋi9bg+(dcPM@)B`Z4.Iu t;OYTQO(ԥ&r>#Ul2>[nGh8s.=D"<*D9餒D,´:śҔLeP:WjҥQ렺S mst늘HI%/h>;%W6{l-08v#{#SRTbCOzqcz|hm])^]j=mkΧDɫ6uD>s qg䘍2'pTgKE MMAD6Lģ}1-bhߡL6) Ѫ%IN'Tޥ/Iwɮ2/NH1K<&#)\"jʘWzױBU+0ik5\AG5NrfB?Li#r"{Oisܳ8##Q8nt<}PHqEABtwk]T>KVD|Ѱڣ8 1~(/U%9K vVַbo]9;, 3"fDT!dNTTy:%aKҔRgIB<FP p!P=#执D4h.Ҍ쪙rjCc"g @BWŅw1W#XΪ6*w\lF+Q\91})rWȋX>z붞GUqe 0xP{* #6SJ"Sxg^I̍թtPT+Շ1$u=(d)zb})CmFV[+9KУ> HkC]tIp6ZMSMͧ+RҰVBߍW9-sv|X"͸6td $-2).󗉪lCV\ /aUhbfҨjAh/mj"iqϟtOԑ^F"JKGL&7\Idnhހv>vr8K$iXkk+t(; [yS dzsQ8*ZBsT|E,ڠX;]΄B[/IoZD) ,q̗;341Z hy"N.Y'ĪgP %g!|H\DQ ʌ*c,'=,%mr&g4xj;0,T߀tGtWe%[ݐtF͖hcgꀚ@>"0 %ˬ3"B (l}YԐ/h dǬK})f0tMI l#ԋ1*>0O˓dXqCոIH2PZC7lN}P=)cEI !R"?/ 84?"uL =6)E<$4 ci}G&j4 ռ($@QJiE&/.0vg{"Iydxd atop->/Nè/V{f$20"X) r|&&JC$RŌx"7>Q&}c(0`\-85 څf;@9eB~f[e{}XJQcsKzbe#ĘA|䪜s> RRiM,kxoDBfѴR8sbH m]"Z'yBᄟ[s"8t,b7B_%ˬOb"emh|$DLIU1(\L?^l3ud`xӄCp @YjO39bBs' +>qoۥܛe~O[vix5ԨFIʧ$DUAsc7pP\H-:( R'D !G|H:[իS"B9Jvz縸ƤYW}`K˭gu2QZQ{?l"qIO v嶆(b``PEPM'ZX(#bD%ܬaIB.b 6ݘF%Pčx=0&Mw{n,Ս\Qn&U`x䜃#)t *X57n+!tP=S2m씚݈ZB3}D̮HV8c{"4>!R-{Qa&ekba\bj2YMqm=}=Y(;DTgP+o} 7$360whH1k"yD-sPǔ';{Kƹ)ȊYPMM tMhK@BY:c`ᕣK>SRrh6B]|dե%ȒfF؃3H"XK}g&Q4u5Ю/ׁCzW=T 03YtP y2=LihFʮa$cPL# UH#?2QZxu/ߒڔaS&6IF֡!ROmL j 2vG 6=' Es';T< 8LS/Pt ze#b!;[0nRpyuRU2Jxp_Ͱ3Nk|$n>Qiy[G:m0-|nmUU$&VfiM3D$ͿL@#Tk921L޴'#^vdU}}U֝*X.FRR #UrR1Be ϶&>41Ӆ<)?R% \zE(J9/ 1ߐ[Js漣4 7C1[N(HJb8:bj8Ա4R bWPq[LD&UU#K%M{/g"(9XznR˙/y78P;3+:bb!rL4ϩB3fSHnF|%HL@?0B l)!RݚJC$+aL;N-D&pUxOCJE"ɭ9CP-UqI!7A(?K%KӍGFPeD:/]xJ/( F&X|,L N/ڀlWA=?E "Q|i:tAN5UE9@Ka1KTrZ"AeH^bqVay(4AnE ?pIJhZ%Ho'p: źPga%, E12:%8*ȟU'D B:pgЩL@0H qh{ FJ{{hzܘa*0qeY<( "dDmUI'D}Ľ܉r0-D۞ `AHxlK@rPd?'%!bmHn)VD`Uwk@l?:P K,_L>$le$|H; ([P9|l,%WQ4&KL`'99JpnH9E Q72GMZC̚lH:2Qy4\bu!J7i[O E%1DDcFp%TĹKrH@a2PQEUIP0 l (rtCe~L!BFUZ٬vlQ@"k)L}PL VhY>% uMtfP/{O uP sQgɠk ƨxQhJ!(E%%JfquO QΟ:f ,֥_gHgFY!*ZJi#n:IuWs*M&q^tjG:,zrhlbpgP;#Ef!%A*iGn(_zPQN rˊ0 g]*=skaX rpfrXUCѹ̟́,1?RNn}Ta1ID :BB;-I&+_:S))q\zѻlTH3.(-EmdJI CDkH8qV`b3#0v1pB7L#Y֬OkLj6Rꓑv7URG葑$#񌎻^PT*OZ?0`'Vd:l=DZZ/IIvRUa` A0mX)hb9  TF'(c8eF5txR!e, )[7 /ТNEز[e1Smӎs 4e5+.SO@Qt(SE!J@A$j47^a ~ZzD / ٗ1ܑM"ڹkb^afz}: cжD7- )=;3ED=C}lșg B}ao/^%$Ϟ:gRh$*]=#Hp{(,_4e qw+A遚b;^i\_R(0>٤!!5 RL)[8=`+ ip=,z xEZ ̛TTAZ}2~o| s2_ T\xOEN=D¡Cz$} $n/2gU%sVb$=[F vllCn̳]I-s  e3SsXnj\(9X(jW} DXFv},%Bd?+=#v-<=Bi}0Tw ޣ:"JRZrJArb!Zk#? #i3~%di`(hA|LI#q4,ObQ)aQΑX,Z+ӰKEj; Wt5m H^#YTBBRtsPf472> sRNzЪfPdy{!mpDj1IPJv-zN5@Q^%رB0Im3IE;njzzQAWyzzovߞ5!@5DmA$UTBٮ2É+*T%vm@cb!ր$zPz|a绐 眽w=%-ؔ6qӄkX[Okm/(=ԛNN\Kd%$w)VF쥯[H: ԑs !$uvfJgZorR"`I0y 4/Zשm|j)!v€/d1+RbSyeΪlq?.64hqDLF NH "E9F' x%8ddQ0yYULͭ79 L@06@!_'wB]-RN.ݺB%x9W!ȫNGV+1Ξ1Rg6Pq=g '۸fU8IɤaVb;@57rpm(1i28:MHέhɆT,F&S =Ҟf㫆7`DUJiܥ"(:CZ"Ь4|-wCNJ(`YMjrK)@_t?o`*VVk7?I2Ԉ4SEjwiͥ#1Bx5+JfHJM$6O54蚝+ V6#2@:Y}[&y~p~2%JJaXiVodkTݱMkf.2hg1lVc}T~F\Y&\򍬨2BZɎE M:z^jF VCG-"S>MeM}j٩V^]ێ8#oK*['/Ы$=%êVc֪u!>V3bjr%%P,Y)ƌ4C9btc[w>(S56>5W4Z{`cTK2f?1[*;ECJph9֚6FȺӑO)ڛ6Ⱡkv4WP t.ϨL)`~ʮ]*[d!Z^vr?x.gmjhH|L[󘭥X$~{qiCinc.1@$'/zDjy4wY\7iGhהI/TA*@vU@. ՀcHHE4'sgdrPâ7UfbEhcd4cf-QjUL៱Rތu<^l)Ys'/jܚ=$U*W蚸=YݝRaaqPi@6I򚪭5 iz!BdCQUӚv}lٵ)35(vQmL!Ԇ# &k&1MtqSs@Z+nm3+ +tREmnt K8 rrWZQNMݲ`~g%:IR8 <æZ~4 FEbLwK-J47l0 )yƨ6ԦP*-<3D %r̽F>d&3n 2L7$qL,f5͠dMPjHU$|xiƙbД T*LX,!w4p6[ LxtF8 QsC_ZS,*R6 _t 323ؘE9)6R+&51-X">erZ쏩%=DԆR~Y%FJ!4p)4C{9BQ V+9if^)˩㣧֤uT]ɦ8hXc /ʎqIMCᢂ2&}768^l AeQVBf/79W&Km܌>aOH"tP3n1föm4&qD2$ @ aW*!jI1BxN <  cZ TϞQ{6x'a^b=TJG@dJz̪!٨w>Z12DUЭ"~F7pa 4wٕJU>1aJ 0AM-FS{J\9]nѾ\yύӴ i3ƿ1Q(Rd0jJY#TU}֖iV7\9KF+5&33"F(2_eTw\ϒ:Y`Um5dn8)&NR+"SOh>cܼ?MZLDιsE%Z`{TUM( w046i~X kQm[EɅԒ/hɼZ51[yU[ixTie\5Y"oN֩QIO\fIұȖ>F[/wb yiPvT!LZ]>[Lyt jyH`#{mY12 Iw:gS>4(GXUUv2 Dix>™z!?Šc<$J7G|Hb屟OIhic˒%Qet-C1xvMbRPa!kJ3y kdPiHcET xld@4Ms-@JA˙# h9-[wV$# g9АR(9:CEvV c]aV?36@y'3V#(І22ٸ D`hY ,AUC((X@AFوU* vРF4A]g s{9VJcԸSN#4h|)cT/ipYnyVcUQaXse103% @(A+^)[Y I0ɦ"w*!NJrRkѕQ ©HA g6qw-#g%'i<N!>(UIuu\͐ vA9NRdE.SrΗJVYӫWc*'yNHoj4Zrjmup6-V!UDYyVXFʸ%9 $E2^2x".0 ejI ]KȭxI+ u1EFYPBSdD2"=W4rd(PD98&V t '.*(RmZ jf4t%Rwxu4Vg&(4~QIW2q+QiTDVT?Z9,Lj>[t*p\4JIf-)&BSv9ҪeL܉V㚮FYu%PϺu@Ū)nU@ZCKDtnaN;bYQ }h<0B8p̅)b>psAPc(B#JϐW5 !?fƦVw[MC1Ơ:Uܝ|$Y &if"kԭ0},œDbOQBhJ# CEF_MS?խ otH!TBY$FK87಺ݨ1%n }K=|uuVZyr)ŮJCٮBWTյ):Bֿ.ZvX^JR՘|Sz&_d0eq~Q۴BK5$\ n1dv(k b 96G:MvM' r:pocjW}ވj\1q$X.kFcFnDæ_Љ뛧g^uf/Hd:Cqn`ftn8ƽrݏ{/aw04H(8 0" DB䉢bJ!&"D|ʼ' U$Р$Ay%G ++瞛T ,_ 7#PWO`r H7kxbq@h j5dڲ*ک1?21e<.<΋:'=y$3tCnM .gV ^+#0*|5[T;dˑ ] a7DtmUV5ًG>))AWy'`s6`ҠkG )~5PI0xOqA /EGTl|1$+crt,>VmړApOix,݉ Z)rCՀzj"Q^c84aP+k/t'i4gͰIʹF^`X g hKt}m+ ls{~k.\:/|ic{ZyK]>8yܤTpwĉǶd[gp n|jX~kW&&uXEzD|baU!$1hPcR9"! I|jcu7b8a ~VPVTG #GhU" sN$(D+92 !gO;@Μ] e?thǻJѲeW-68#D pwK|q&=7gPJ:`SҏSP3r'%>JM.N*:P)cz]` !6aRHs&tHMN4XigkU0 ˮc !׎S1ty=Q=7΂M"1P4VZ0଩j:Pم5Բ7KbbA@,`B  <4w _\j[zɧ?.+6>?ă_W_[n!MNyS/?_}8xyA * BLHАzEKs)bH)0ZT9$ Jv(wUyԡE`kP&Ax /5|mȟ/?W.}w۞|_ G%ˍS'8sw]7_yvoO- QU mpVgO& bOӆ L66fq!tuʝ s'ՉfGA0Γ8v$̎ى\#Vݢ' AE qDO B!av/nz5$ޛ4<s:*'V҆&-L}TfgIS90ʶ峉B>)TF_nOSiĮ8r|\[DZ M4pYvنmʼttNJ,N~iJ~ATTwyc=~ٗ- 9cZC|&s1HБCBAj& ߕFl{`4,5v6$u15"7szFH%@˟e a懇J|r1L|ų_~Oͷ=ص7~uk,t'.?uzCCX9a ʪ{bP6c-rc1u.Rl^$*(B.qAJ҃ L &7pYZ\i\Î!s2SU(cf isĝH3_q×/ܸs׿/?#Ͽ|s_}}/]<{k/Nn|kC!1~y NJB D8:/=l iOr$4}_&"`^6DjijV|XQP:.Z]r&ݦ qpW,GM/aկdYfUwS-g)&~^3Qe%j~sIgy Nxj-Q;jJ1Eʰ7aY8}SCWkתYYO9<_<ܔ &x atr` IbjGI+ȴ a {O{iH7!޹=޽Aqƒ?0 ַE#S'Nln\~KKë w~9ލRnzr)*nJBP !R`sSn$!xy 23x@Jh6pH2v 7@Y;kb=C "Lh_UWLx$(H EEHq^5P[fMPM«vJp|KrG]U^5>uoַ/{ooos n8 5nznMM&6Iowo?o7G|7_|fgr1h>-wW3J0LdNh7! dGf0k|"jHSWjC3XH V*y3:5w*P++tTkjւC}+]qQS5G}5*׶ rdWxvbCs9 }MGGZX$9*ZEو QBBX*Wz F+iH:?5c٬ef"nۦ C4(RգkE 7ܸ@s̝0KK`b1!TqH@!'ckc$"4$DJԂ0,QH'phHQQjULG*ȑA7x|qBe5ѭF|-H#f3oc HByxI5f[=UkZyL1YswN hbCݮ H1i V3F{DL9U!7jPpn-e-`H`I:=E'~ !/L>lhPqA2FOkq9{$iФKpu8qjۉDwwdv:wwgjT@ҴNzXC+^ y(DOV|?4(!V3N AWtlwNlt}hZ4Q۩TFY rAuJJf9sie5@F6VH1qt0 AShaEZYKl\yZ)'Դsr=<+*Y`Ќy5@UZ.}&R=LFU4ޖ3]\{g#[oA+ AM&C6]̑엄h:<∎S\CKC9#]Ռ֪DPJz^՞4lLpLNu4b"*Ū?+bC$N8TC=!iI;ixL4Ml6^X'zai{f{t0 p%8@q$U?gt⅟g/^ps_GM'onnܾs> .{z?_ŋ_3'W`&٘Nln̦MfkvM8iMMimLkF'Nل_x͛ןzW_I;{?pĝ~?'e=ܻwID'vN\p߸s_+'_{)40ĭf|_{>w~{O$<_w޽BA6_ٿ<=gؔ噳皰o;skI'OkLxtdNBMuO?"J!I)ERn)V4<6.f%w9RgGe\ BvqvF+M! MF<~3^{vV g5 =҄bS,)] |N=4 %+.AXJUql;;/vN%3U@dxAڿ;Sm#pc 0ģ]1Hqp?0;aFVnrnudxV,j6|ؖs7-CWUq^AH=ޝtnnohaZ~>L~w09\7=89yk'a\铓 ~+7hCR\CYf2PJOyմ/'_w;o~tpo`Ĺ+GMNn#o{ڵwoƛn}_?q1٩t}4gbwem3>;DO'w7xm[ww/^zW>s3];socrѬm~9w1l]8TZZ{ x߯>Ʃ WKv^=tJV O'k*t,YkW짎zR,zQ|Æ0FU~_ vN,m l8;LOt 5ލjrw#҅!xRMS ƝB p2&1}EeE\.`rQGv0 R-@k2c&oչhQ0Gsu,R-:YP偐jN1Z! Ep O^_ fǖR!} IDATʧ07u0(+?ԴS`QIINE?sTo޹1v{fkJO޾}c1͓mwAkݴi~zs)b6)D›{\/޽DC<0z!ڻTiM76ksy)s[a9/t눰7NPn `6SeIb9@!`&n]c%0MvaAΗf6aږJ*ő7mX,Ǭ3߸1k2=V?c5w}\s6A;Bqq c:a_ *ȢQ02/L XM1'+Ҙ.QJ)2zB`u {ͨˡטƙWƑH=}`Cc16l0Ts"Y!`#_@JB )c\qpطEUz={],jaAbaxQ,,RQsH)*JaDTt#SԱaCSV O4.җWX%vd<[XA*=tQU?^Wk{~:: l0Nߺ8x菸iƂf>|b{k{Sg/loN%ۻ 7 lN;ýoo*KGŝ%@GGkkES8B{ð\"Oh\0yJ܊8c'W*hQ ϪS⚞i ]Chg\? =kA * L=)Y98xeJphu-rHw;)wܦEאWT_VjEdlH`RQ ;S{,$jF .A+g@X[1̴c0YєglB-&ei#y6;PK" ˲<db(6P(VeϚԘQRP >iVywҮP (ۋUئMS6o!"ڮu``b@F);G.hF(Yud1cJB`)XV3]-\F+v _B>3{WC[[(* &IWr|o\4CD^Տ<0`9Za %=&{j&;_.n;{ڵӌW_믝:3Ω[Zi0?szwo/| ӝb4'rvam{?x摷~uﵯў(hx"7hHa 8(_8{n7nNm=N~,o|y)~E25/0AXɷ`q.Sq,)#tyt@`B Ғ[ }?r^CVqx8 nL{S"7>؁D&MQ"s?5k.I cQZ֕:':U5)~@TfJ^6Mn!6&0%jA%g>3{']:L& {ԇ&vv{|csvK'ߢ3v|XV|H}Som~3p^spKڗ 8'UJ̮0QHZ;36܄f"ʍ9eGQ BN5 !tԉi!894‘/M4zut`gm965ZZ-/'B>1i64=@bK4;q> `-ljTyX{i֢H<2􊓢~/jfBS=dyHIy%CcB\}d/"S1% ΙrKŪmX 68T$%@Y09Jt_ 6T|(+j"*`;Z7^M.P$J c e/w"fwv/eff`t 1qȘV+CH%Y<\✸Mg ;m-示1mm1ݽ;dy3xs`p4t6mTBpEg.>\{!s!EP "^{;/~w?6v׻û^ӻכ09ؑr2:41K!+ HҒ4`ٵ!La8 g nL54 r*FcnD;װ@&cꈎv,(~D6R_ʰq劣Cޤ8Hw%r>u!rX -Ғ0jl D%Er0~#D7ĖlO902lK0BReܢ)ڝ4P0Y>EsSW䔱z̨x .hG6Ќ(_|}mrjYՌ. ᱏ4@"_7dP1@JaULBH9$a/e?&i8@Cˣƽnr4(7O[a6ki"&>ԥ[w\+ 'QP`9qf/[{ܵX|W &ıc,0#( Bձf/Q k9VEBׄ!h\;Nvg%Xq($p5dZȴ!L΁w=Z:J;q{7JR(slXq"+'LWJ`x)ijU[V-doU(^tĺǓs{%6;.e!Ii2 Fjr \_B q)154cGOXP! "Ǯy`0[ 0l%LUxB z 2 $m%!AKl$2erD RPTs"e7HĹ 5|QZ&qoG{t:*)Sq ShOy``\ ә[[rtzg6wZY, wll}5W-94vNh=ăW_͗o^( 1 AUX#.pLLt\A :a &Ұ -Q3i@+1("Ľ'AYvڐ uf76hpA 1;,':5-r`9{ͩuUZ x(E !4h%¤[A,ҧAdmƽʉ6EjR-ȦLhКe}C1FpLC#-PRr- 2q_c5030֚K:a9N'Wc6E@V-C!8LMP>1Xܦ&5 &[(FާjWG&׸B/ h#Q R%U@ɚR"rAsǻR1a_p)\p (^~`1(GC,u.'O8XmnΨmD7qk&'IWn~ݟ/<|R>=m{>98rt8|fgcҗqt}Xkh H^THa4XO8'NupAn*,A\h&H h42 g88L뮹'Nua5נ.}KNq`m0rk37McJr7& =*QVh<7dd칐kC?FFT,؊XhG"P FFgri:$|.Xy }!O-۔‘/ Eg$'+D-9qgƍxO_{۶6}?ti6G~li 8(вi| أ/hS]nهncmܼt;7nF,ʩMȥ ]q?àAEpˠ@A3%}cDh)@FMH)C$.@D,aD6N|(3A;r,`װLa"~g֞Z?Òm4c!n j7 NzۮwDq o婱R9Zk!XUQe J2bP.6jyDDhpԫ=1aS5*b )Q&Sr&G2PFAJywJ;@o=g*PFDZ_<k_Gj֛m-a %! Gsx{i$4LI4*\E|%lQE*%4BJ^K!*m$:b+ !PʪɊ6T'qţR5cd{+vt qq*jy['P'> H(tMSRq{C`G:,oۮCӭ/>py`f;Iwk׮.' {%ɓߺs &􋣣.߻sEV}P,:9uf[s^TSX%`BIOvd0n 4쉅" píF88ځUD]i|qNY4BL! ƨJd- , w8rqawLPHpv6z焙Dnr:v#U4.fo$Lq NkB A(bYJT8Ɲ`0n2=5 a|jQr}&p,lq$.I#0af5o 堐X>e ͹QD)+5TPEXDZ-Zn+!-l6@$,hsޚV0vXQnDڦl.5Y+ք(Fv* Gc}]Vw}TsG$p;H5"ԘYD. 6/1$Ł3@UXi/s:y6ص4{{òGt2h藋u& H߼Ko};ݽkެْ܃G9wȩf HǦɌZd5ߠffMҬ@7Iɦ$Db$&\9Lw?DŖ`eU<'kq7F|~OeL~oʸZUWvO3|vr/>$BT=( ;HĀI#"B&B`{u;fL1k;n;Ԣo]oصε> 3rq$sm|D:{jT;p\;mX"3۾AL q=>>N8@EPoMZ;]\Mأ2/OᩛS'Zƪ;6G1VX2XG{?Z0YG+#&qn~/_v- -s wk@%:_y'?^Cx:ds')9Qgks]hM֥c܀rm.*ŚUcVaϴ0W%ؠ*A'Q12䚕5md&KȋwKhǰ8mJxjCRb?O 2 ɇ v穧T۷<3u$*mdF M@ 6x/Ńn $ PQ#!'f&ft"M6fF56䝺ܰk<&M}!.>מ@Anܾ1ʹUC-q2vL ӝ;UH0 :և>22zw4}3eFXLiGySOm0)U-o38jd:*M`e0(+,F,#%QJDJJp1 fZ`;QTʕx1*Ңإ"մjPFnTQ]"Cmd4նkDʾ HÊ֓GoRq6<9JJb6W]%\}5dӭq5B,d4J3JLTpamQs*%C 5TR#jqqbj\ ^.E'gH. M,7L7SbY/᜗R٘iC@f=A׿pG'$3 ܯ+@H"$ ) C<@V7'3Olþnnf^Q;9t IDAT\D(G5)J/X KJnoԷ㈷ qˎЊlƁvtQm;7Zw|Ԟ{<٬7 m v DuDW.9M0}*e 6J ',IdѱJhyBcKи?@&z6ykABqJDÁ5Mi ]_ŃO?ˏ?y8xM׬7o4mw.8Q%o~͗ƻcҸA$BCr3sDLzfP -QH܎YEXQعHs޵!9B M;w[{>Tbp.4pJahؓw5u~Z}]xp$VɰP{2F\DL*}dZns=!TێeIDWQ*,iSnV1?ks%@`c]MYujA9 ŒIC}]e\bhnj jZ ®By,3Z!Lj>B X j54d, 'Q+ 'yն(10y"-> MbNnG"gjXC"u. %REAY5E"b<9;nskp۽܇\$q]ha+QO_{W\?Ь]uU1!2Bb\J_{対8$JDDE8!C"n1'ti< 17y$rC(_tuN;qxi['ơjlVZch 2l wdj_;,4T])02-鈅lƦ<ǦêtœPy'4J U5IdfO߱aj)fM%٥V, I\N %ʎP-ƈ=9Ahi:p -w!X>^\(EMv[/$(V&|]tzhEZ7 )d:t 1sZ &=롉y 1[VW(s"΁gQaQ :o/ՠ+3w Eb!"=!&r?Ezuňkcnzi7#NO֯n6=W+/jDQZ9}ͧ_}O?:1QJ(:& 6wD62:1LB6GE14)ϑ|ݎJ,nm1T|G .Z61^sdY`yZ!#,@UHCD!3{D;c|`DQ|m>c爀s9C m ڃwx݉vL]Ӵ!tLw̝sGl=!;FVuzņk[?C":Y1, [r%k2.i܄y{dDô{w=Fl<> ŌaIo2X< \3g4F5m!hZ`K8KSQEi.`ɊZOa^G4p{*+T}7 IҲBV-qьM2SVp]<'6bҌ%E@p6RtqUK3bZ!ORkl cmJbytI?Ar6YKڔR`rH<$Bo2&u۾* Lz捛7nxH0nwvRF^g o/ݘ]NedVM7ݳ|0Ra#`NgĄL HD zus;O =##$&U1un5ƺ9o+-QGL;`j#mH㤠@|}&2,qmjєҍjFh@XvI%F6ј`;J4a9O弪~|r˂5WX\9 Te51{5Gؘ'ңTOeA8Eh%y[mH  {`84eEX,x P\fhkYJ-Fqy>b /kکլMM񗝸1Vb?o\^Mʴ*kB"GAu~Rt @~޻=6^V׵'/|<­prOnsB XQGv8Bhrs}󱏜a @D"p Gd`F"ea8xSV\!Gu8'F"l5i)!&8iy𴁳N80:ιr`$]$LxOwHw8ũ2ZRRٸk[:;Vn6X8_eNCR{d2&7YSx/)ɝٳ8N<,{#WzP_3Qi.O gN2]Ps5 }Zb,p=5I2Bi[d]KdIWajfj.|o5HEFBrf+n4 ]9fTWrwZ,ZͩP /3/N:sNr(񉱥ND9aMI#5jq~u~ξ?//vcw?~!O/0A R" 8&bxTn3xA0L|R#馒 r:Z9}1m`Um|V]zy-벬j_E4"b>|MG=K Y%)&ڞ{`U=Y~#mZ&]sĢ߆z [mnx53 p, BgK}OЕǃ0)d-&%PĄ26iPٛ~a993Cm㽇{''i{~ҬOo?x|Dá \Min}JeiB jkuHA]wDN#2"ƔRs.xy L!pBx9v:D##BP `Dg wȮHs{8qVN,S + UQHEZ-tB* #*k-E`Pl I77sJx=]sqlg*xy!.q'o.yA#ojjKxM#`8̈Ѣ+PA(9Rd1YPԃlY̳ r1`ɔcAZ`zjo~x5sߒ>U\OP-HQ\UWT4EӫK?]OlD(`xB8*VAFL!8߱hR*pb?^?>'@>ݿ۶춞0u'çWr{Ó{ Hsý /]F@B"J E`fv@9(O#Zpw@2NΟD'ε=N;ʼn@w o!# MnmWyCǰP .H VjgP&|(/3_ `j7Ҍ?Vڣћ.Ϝ2I&If[}t8TQkǯr`*a|2T5*)T&95c$]Ɗ276餃S.3XyY j4V-fX3}G,򀖂(<VA,w%HQjZ Gl3:YPcqK-:8A}UY7KMVԼϰ7#ɠ92'n]q_/?azYKpM}ƨ2E}4iL+VjRl_<|Dm*]oC xvopj7>u"䃄Uha 'r RdM o o_g;QMIxFR* DS$* $ Sd t L,:tA%(ZQITˇ9$f;*"VԗDof#jdKZn3&@z̶0cRu>v5S,G^`Lm* Y+,Swтi4FL %RxkЍVrXj-)P1v"?63m`tTSJ&N5L쁟D.S=4ܪ7;їxs^R whlMUÀhr-W.ӹyp3<| Q\xFipQ3DḰ $Es6F큡LTAJ"#$Q2!a( IR]UՒB%x7 >Qe3Kk^HTy7*$,ւKK7tX1 xeمC3B5xk%/ūhov6 Xz#q!چù if=5zĕHx=SWR=Yhշ|Rhu~/~ZOW[hѸ:. @*NDT98S7~\^_{/>?purOOo.>W_?:smQb6-.%g>@ޅ@.by@݋wO_ {bג auNk$&4knI!x=<:īmƸ<1Ep Da]h="Pp ITHtb 4$$:qTaĿu hR]9CXD)# ?w.:2kAjun'=\nmwH=9Dxo6ߌkAG$(OCا6\  (Wa.בR$ĀB䁢$UbF$zU)%)I9q?#&ҚLȑHXjjж'k1~N.HϚ IDAT^ 'G?PU ;"ZbW*~3qecx)yVIHNjn7pĤCC/͎2Bl\> +4ULm%8riXM8JOf~IVeHj2GR-YޅTH_5-=BV6BU js)@3-[3(-ۜGȦ=`0 r%7 4TȠ yND HPjnIq}>u{G[~n/~nɍˏ~o8;skOpGĵix@P61wxB[xr}W]/!w}r \ 7[ .|߽ { vp0awDHB tQ0˜ jDA1 J0~G!QE;ChBšNUT)9#/k:;j [I+,+ kzE*h3> 倖*qB(5"|IMABTXRʇ%+MhgVZKBHEra4cthn1ӊ#*Gc3+a],%1[IjL&22HΩTzDL0S0mşMҤkdV9Bu𯞜 .9 Nҧ=bRAQeTrQHJIjB,E!J&!cJcs'Yu^m~& EכwT2lî6z3lc CqfUC IkF6̹1b^cfWq#X ˵`YaTjAd.LUh>/Wl[0 |)|8lq=Ӽ=ƢjPh붖ecpq'a @ yDBH(n{Ad۬g7/eï7~}7~ٓ?^zOCڦCaZwaji"R Enk@Ȁ~ハ/< %C #vLJ5]u#njxČ!ARR&D ":J:!bJQ%IJ0! DI@n; 1O? &ă֚ 5\k1VBsΞX!HoEk_7*bnp5U^4aP( Y~k93T*k9aR+A%I/X4=;[{}n79A4߈ gy\3x̦3&Ꭶ}Kۖ.YU^8gt$,T #TW0ƫT,v_C 6 |p̈́:haNb("1:\?&p n~-&F9h&&*0":Db PBԹ6x]$p{BЍI}\9ijo~(wwqholݻq=웦avL< /jN |yuEV1Qr5"*#+#I(FRbqL}I}1ic2=lwOMvOGacn|v)ʫB/3֨(7F]c*]U9lʅ[de0W e,.Z5*(zb/uޑEj!w_Ċs4.-C hף#X=t6!6j(̇ Xղe(Y"(LqQbhѪO rk2[[K"Ѱ MN 'D\JLrUWI0RDL)+?~gMIqjp`QBu;^{;4G$E ӧnlVu"9$P yPQuO=>y}x+L;[.]/B   scJc QiHqXvWd;cGam!0f׏)޿hZ_Њ.LPѢ똀b)U:^{s5P6f--xmlh|4"$QdDP"D`!;ݸ>+: _{4Gct q-?HEqȡKCUE7QG?;#7gݻat@NF3F٧+_؊6%J  ]kJJ"c8c܎}ڏHݳx~b!>àc8>⪪&] vq נh4_ * QZv?,-Gwxu/10}UV6_PdZ˜-S֢$T'"Si%ۋ߆y\dǜVc.L7rG_co{ m.-Os]aS֝GPoz z#vC^]_#S$R* ?{r·ˍ#pTR~)&F! TUyL01%Ig9DwCqc`n(\_m>cKQ7qPL)l6ɼfQYm\f3!XG,&X:R9N5%[AeX668ldP#,R-, h䌝V즛 ׷ʘ5;4%bbb UE7xΔԖ juy8f!T3J=Aeƺ5mDg+ $4>Ĥ:EE& L;Bfvr4wqH 1Yc@yrRiw؏J'}NW>%5.MEGWQmEѫkVv۽D!QBe$t.W}aSx IiPNAA i"c)I)"qy~!`I1q4lvqOr[J=ɜ @AjBsJZGs!vq|Ev晁5l۠=ָ*Ӻ; J@b+ U":  Q Q#ff@JDzH8b:8 KzGlyR,c 'z}~۞n{8Mp}w޷M{+9" WdKW=v}bOqD87&8DMQ HdHc87ozϮ}11!]OqDZ]cώ/۴*=ٷR: qzk<R~:/Zja͹]|i&eu F5sht|2S;l*0bTGRV\L8Jzֵp xӂD*w_] ?rB\T̅jr sukdQ.G*#\葩ZܛOϠƀ"] 4; ɖX2U/z쨪Q,ntS?J3_l^夼|[UJ !:K~9i9$" IbRi0:8#{~b;;i:? |}}' 7WWU<x{01!1*! z4 wV_y姚{o!I}C)c)J%N *J{@RJ)iNʴ'xI`JMØ+01E|:gٳOr LG)6ޛYVUk}Νjzih@AQ8$*~Q#("1y>qb?!QAzx㜳VJb>Ns^{7MR-P[hd4v4 "3" @A )HBO)IHHE E8 UH*0Vl[82hx޼#}O|fXm|j<eeۑ!BY6jlAB4KmS| 0@^"DCYhe.Mt&DvavәXU4wQ^[HEl3iEݒiR-edA3M O:כ\:U]脹`1sMd5Qf/fLvƌfGMHon'˴ akޖnB8hr_r9UN]<*S" E |9^Nj@ H$2"Z)ЈZҮ@ E")b!BLu6hp4M̔ ',nL5;~ClaA.E~ | $5ұF!UD lg&&&ՐPǤiT*Hk ŢӇ!VQ a8ց"#G: %Q \Z oKyK3 V IDAT2@6o?AcL'8po@(!8}#7`E15#kArC,PQGĜ kdW##Lj^A&KV :„xi]QHшU#WuQ0LnA[p Z@쳹!"0l̛lKnt~l"q"k6SߙS.\ --(-Xs̚cW;d  jo3iZd뚏.=KIfqhORD0GԄT+4)M^+h͖VRHD(1aE[̌(u5WV'W,[fO09OTRTR?833եU3[-8ePk BxϨ,ʞKO_pd5jV51@P,t>@)IjCE]E93=ѬV^tE-E+cTTFXo0Zxikf~Sb|)ZvK65/8w$>,ߠNe"7m"cKV_l'&Ct">TSI:))OY.a7ȻE/_&К5sTeBݶa2W-Sl8BYxz :e3>d@g"Sb$٩|ڞKq]#@ ~Nl%G-΁YUA97r[1㵐;l:`/Oij( -#)e@n҄Bd9#m`~yŬ7~Z;%ػ]"Ql^ak@ѝu_2( ւy[)֑``e1 v=lB#pL )[ eiۗdкL( @؅搱u4ɹC3RQkR |#fb>ILNRNh< ϼk E_PD-AwNsHi IIsR*{f%q6rr={F痚 aOĮVe+5WʶM!hӵhJw` .?O"|=Σ'~zѽkm$ Ae`;>O?}O˕"&/<|9rj@o(<81SݱTbo040ppVǽ=4pd|zlzYYA5RHkE%]7p[7_l2?zˊ׼6jzO֋O\UgOE R+R%7߷o ")"'苊ZƠ1&i% "HLLys@[t1UGt܋r2BxfG*m'bjLz K6wVmGSTC!q0Ygr0I7xH^XCxvN?]^qv@LO^:P4Eaq Ll irLYXm4{ndsO_2YE;t:(9I]FZZa_dۜD, j)}fILo.OE AVR9uVe|\˝I [2O ɐi>ĴXmSԟ%I` P O :41:PyB_6bOjs'Ӧp)D3< d+4QdWAh8 {z5ZG#=26|k<OW[zRk] *})|[?zcwwIŴiמRO\`Uuۨնu RkuGaP*vBBk@ N{|Z5HO}&PmjN;[&4{Gvį`xT=,N+:t b:ջq1'jAcJ5g%4~͆߷m?|/?\5Qz $Vw?9o'6"ĥ=]`?2#5nR JԬB(%5 0{hjHK!\]C?،-n ]X~ef2/W| ˳sJ,t&2i.;Ce/a0(ݝ̆Izl/yT;#Nk@9m6DEʡ${!!ĬwMFn ŌP|~Oz}<8x׼5A#ص{|!䁩C۷mŒ&r=o4ZAQ}#F5A(D $-IF!Ƌ_k>~q/ۛ/J<^8'?ŋ>pxF/Y|ov%}G+?8_ֽFG{K}+FQ0U 'EC#8Q^lu`zA) Rw>EŒ{BQkI}ړɋN;xCE/~ӇG{)=H̙*w@h1 hI"t13*ǐ' ̷3r^oDްH܂/J!Niij\[ X[؉`VZ1{YY5 U/a8IC>S]wT*2d!i*gmZk'@|hKP99oѐ);LXwd``nʴ6 LL- %%f@`M@rj\'myf\?pV/rٺnx2^gF⇏SQYJ0j6[V I+{FolzhyhBϋJg(a#-5A0 =Xb)0lqgÍZcZ6gFڂŤ쩶N?|㙺+ZH $iT1O)7fH("@,Hl1`2|6nv4EAΓȬdDGlBm.M^K>(ƭq4`2]&mj3f(M#%b]AG`[2ͬAgZKvd6Nr p- ܔd|sTNq\؆\k!A0ș+2mܝֶ"9-p@2(yŢ^9[ϭt] 3jufb||jp^_p<{vz^w`|7:>}_p}_b񩉮.u"BT ǖ:JbeSpgw;&% 4PR?8 Q?XXvLϴ`;rmGguWM-Roӫ{zˤ"n}{! b J ҄0zTT*"@PG(dı!0\nh1s|g@]JmfZ 凕q*@&&D-P8UK4UióBHe=45-=݉ c&գ֦5jf `j;,GcM5q5@,r/ ،&zyi~2ef`V72;0TGzcdE:\ ά~YIM6VT72I&S`fYhG({iH`s4 bn>≒)ʐXLX-Vx:5 :788KdεnA<`X5x.镃IfH>\AkzЏP(3c"a :]}hCWf!ٙ">I,T\)*FEڷ~/-&TcLT]_ݵ_lWVOyYݳmOGh6?X9'7tyCݍêb'U!XqE #DR1ZI@P(@PT[Bw`i!/<bUj0 1=X* %&$FH;SP!5yB$Tz3rPQ.B<X J٠(!wW%K5"juʫŅal4a*}B!VzJRQ}h# IDATR@<Rxr2l]'3Sza+j=~׶=dܬ5@ Bj8#)P8 YqMHݤRy++A)*Sb篸,HLMK ׼Ep-2|q Ƶ6oKUcKlH d;&X$ /M-B9Gm%*  RLَw31@OZdu3[ʣI VDv4@on3)s?:eL+?Q LoH2 62Fp&hqR"0! -2 5dzV eu jv#oC*4tIYT(G!9CU{2lAKtr@ D2 O )%BR|bD'1Bz!bI'=D zAبtncԠb7OIeN[8ԨN+H.,-@ffgPz=!D }<< Vgo~4s j5}(jMZB2)^z6ߜN1L> O{;XY[\./yFt'#Ca&GǏuv@@5H@! @7z~2i#P>B1/QST,[ŧ|C'RP,+.kV'V"bf^+˾ bwA904X((FeB&p'4)Pb I+QD۲-ް7 y-6A tQ]|:/"cƥYkm\<eu2W8XЈCaܓdTmͤL[3CBR hF_ /CsGd݌MK Zz<35tBH1wM6d60n i[kESށ/xD_U֘Xk{9 tp٠7'I^vZxo7䣧Gy'´ΕA3&3gL2fyg4w4BOD[DH+I J4y?磌¦V, _Щi&! l4fn4[].ON׻ 0htN68S $HERAJЀQǡBR A @XhY$*K7>wqP)U^k:BHSWA)rr/[&HdhnkyVN#"3yr#gŠK|y8Db\hp`quOy\4@ B^O1EC]C]DJd>wwAiprsZƛ0B)V DYngGLg&=j D\-*ЎX2S &p*|y?(;zhJ;$"d=Ԅ;3RSZRzɥt zI BDhkr\( 8*Df+Kd QtFc|TfZa#ư teJV Hӱ D t1t  b5KFxI)=#3,N/1ӂڸ*&* Ҏ\SvҰ0~tܺd47`dnҘa,sŚa1:Mյ$4MҤ}ʫ?dk6"k&cHl9ʀicC6c꽶XgL^*𰚘!1:&fgդ,JO ǝPb2C.v@2?/t& M`Ձ i aL eS4hM F&%h`wH߱0fjBXBD@Iә4*"qZ$D>(ELԭ0*wuUK^굘PA')uդ8ŽboOTj`W=m^Ok=]rWO R1#$E_H.O*0]rpeq=6juO7hJF@<i PXY.61«]`k%] NU3޴i9[´,Z@"ڌ_F%9Gܒt6*K*:PUYe72;G"NZA2!hI{L PaF}F#2eic;q8C;J[tFɌTMⶍPhO÷\stcݎ4'5ZXݘfFRC#FzBA̦6%X4xAf#meS)Yc (?HoNs'`1 E31 jB^\0B*+ߔ0 qc5XK+=9$B%޼.!G0c59 S&1{3P oS0 Jѝ_2Sp' {Y.pf7%{#R(Df)uйl {ehΠ1GTjU+%DO$lGBg 1Ƽ3$2(kH&n!9kܽ`S~HrB$!.D?ղE>tTpx-U*~iðwoItV#-t`hi`> (6ˊS?XaTɥځ=/!y-=4^ r?G "@\,Dލܹ2։hrTCse 2NjڀVK}P Se :FL!% `=Gn<`%CcB*yby?*t`VJfKkmVd̾"Վ\ȢPn:j9$Fbm|&fqy*gG>֝ OB򑏽r-{C_I%YcCmc=Ǻ׵69;Й52D zb^)'R0E,j 'b3?g>skdrDgD4ĝl%N@_facHɔ~ĤX.wܑlK+;0&v:$N\mRs(?ߍ\(BX,ϭsLHp ^¹r8X5 eǐ8Q"pmUpĤ9b*wǬ<\j8֬ =/h\S(6dչBdl SaDLG#G#Ŝvxܜ/9q0lϙOe^_Y9e0ghK1FƑx2he8CĢ<Ȏ95݉ߋת6m_Z-utw]KŋbCĩɭ[xIWM6ut'q`l߿SO_sq1R':F oٽ_59^wAYU׬][,;g=Ok \.;9َ݉̅]~VJ288'݉N%tW,[=/I~!D'~_|D7?$9?}{sя~ús=sjOY5;wt'~e{ٳgOor1듟K_#Yr,퇶nݺ߰tYg]~:ȥ4tt'~#/| /| O>}CFDD[8 m3KR玏ٟڵkO=xܝymwy{챋.hݺu't;΍7HwunIC葾$ "ڼys ">srsz[E:-8j$N7gIH)o}[|WJ}ӟ뤔JIНK/4rljzn7866666vW'Ok~( IBGmwu]7yO_׭[ܺ/x .Bˮ:uPx衇8믿֯__ 07o߾9֭[ZO|_Z^q333_WKҜW_=66wq{]~}E011o}.x'jOlݺ8SDxIڵk?Op %c7SO=?sv+v a"=Zfx 7p 8/}Kwy'-[D}WD_+VZoTJS<#kךk֬1O;+W~%իW%ի^o߾YgEDwuוW^EOҥKƒ###裏nڴ)HRVy'tdعs VZ'P_|şncM~/򩩩$?*N8[ouǎ;vH^w}+ zj.FQ… /'/|Gz{{w<|0> oݺ59އz<x^(y~woܽ{)b^v{fff|-}s<l} w7%fC9:DN< 7ܰw^DMrPUHjnaÆ qo߾K/j֭;3F_?::5\y{.ğvi===sP(Z07_|pE~m4Bahh袋.d?}sBc9/ꪫ~x+_xx_e]v|q/^8i~_߷o"^ve7yK^^tE=== "Sԧ>FQ.O=5ktuu]poۯdIH{/{?<88ZoFzD;FIDAT;;s%s9|ٜ8NϷwIh4\.wuu%9x𠡮͟?j% Auwww2+(JfX,&0U IQj+Jn\|ҥ^ziV *P(tww !&''Lh$j׿uԥ^^>&86hZI\.W*h4o>jj5!DҦHVZ-)9a&T0_;zzzY_W|9w5[y߿7-Rz݉߯Z7\<ލzw׽>grם[ziqt1'Y7jzW~C<E֘gGZC݉N<_oÆ H?Mk݉mMډNϾn4z($Ns;oM:4uxJ+ݹ;.8ms)Dqy[o?Rsvy(Ӌ M~MaXVu~D':щNtD':щNtD':e/H] 9IENDB`barry-0.18.5/doc/www/append.php0000644001161500056700000000015112242254476015622 0ustar cdfreycdfrey

barry-0.18.5/doc/www/config.png0000644001161500056700000013470512242254476015632 0ustar cdfreycdfreyPNG  IHDR+#rsRGBbKGD pHYs+tIME xxtEXtCommentCreated with GIMPW IDATxwx?[NMo@h  7iP){Al b ^b"E IH $v{rCWU=sffgwwf3j:yfllllllV_N_˟]QYz7vuMpA ๷'.'|~_C^ٴY뢄~=pߏa*,\ ]pa!6E3u$@? DSiܢ#;&#-zuٳ/]t<{LI %'&naDL *ܙ`bdm7?A> 3Iy_֍i~66adID+=2N@OH@Aqo-dǃus/$^L0 F öytOu_ }~JKO&&H(2 'gH.@E' #av:HhjVeӅa ( id1t Q0PaTV@$IDD4Mt@7 I קibz') $!"(D:摶e}yYc"eI*7@u{v6(LQD1Lq{%ש1r%Lu1Xɻ/=HOu o/v/DEΛΔ'HH4J=h'kWt'&H|B2O,1DQDe>@C$59@RA[wlD~q.2Z{I2ݵ#n;h$!N#IP/= Sb<~YދZ rnNA~q^.ҰN `z6,5e>$&.֍iu_EdŔhXVz5 "NMbc$%qɔU^#xv?hJ&BB*'9!/6z=8Aر8(qX& k*$}PHIF:!Lۅi+$ A4&Hxѻ/޺mQCALS@LA3 j_TO EA(ϥvDX&&Ӭqcd1LEQQAˉ$IQ%0+¿h0/X>_ҪY=d Á Ӵ [j:r:0 3%Y4M4MCtL\.YF7 Epb.K0E-ث |19c'sQ8M'.QP5k:NY%)tX)(8*iI_Ё}̋ԍʐQ "G w5!=^FEAQ v54 %.#׏,!Iuo& `&$a:r:$1R&Up:82,[>tA@uv8JɱC4⧵ =ťeh4%I$ S/YB%c\T s5vsҵC+~ٸ $v/$ؠcJ~q.23Ѹ~: -O /[w^æHPm9u&NQF30@7v?J}Hơb-MWdbhY IL#crPD p/.T/߉7ӿ\kr5]$7$OKQY;r8eun=}b(AvDVܶ~Z=ٴo}СctjӌEE,ufz]9wY˒tÔYn;w%K4oҐw86vgҵ8Íc.ttVǕ. ԭPƎ̉b,_Eѓ$'yѮm(ʟq; ɷӻW&}’:uialEG:5֡9Ғ9VP̴9IQ?=ޝHjd R%D}iիIͩ]3ߎ']o3/# At( lټ7Exo& ѷ}&˷"H0⊋"5;cGa/4n܀c _koyd=Jד<'NRV =ڶ~4*o|6TcGX.׍6ƋWgY&FnEUq!#Z;⭸%Siް3nU;qǣ򴕼Tfxmnde-|c| VȧfJ-t)xnxLȨʃ.Iѷ}:|ba@s0#2 &ј“½|M8YTC%4NQVV`(J Ȣ([q 5 )g jd#$K1k xًVi O_͜%INLSRO}xjl%Sm{㖏XH:Dcouob=jS: C`ũky~402R~Л~o~}م{*)&Ŷ<*uMv/i1d5Ͷ=9m1$pH!fڜf6z_PvPpKKuٮU_V5/w,DT] d­/==޷5׽ 2(kվ1?GO YDAi YbTUo\<y5ύyлC&)׏hn!0uLðΉbxlRgY I+$Ae-3OA  \.7zrnh׀vmZ&_'_&\t4t.NVI[閰kG+g|/Wy\ 1o#ݏp} Ҟ,ҤV,3jRq/O~X5mQZiǰf7\byU$x1ݸ_nh37Sjdf2^u_-M?Ut8p4VpSiմ.7 l-p:##Q[2㇝t#Z5˴qNZe0i.'|>lO0[Y.MK-"2rOYfm$Y(qGdP%6=#/[|J|!3l9uV8k* ϯQ'%]pSWIiYRN%K)$jB_NBPEgD1J5#aEi%(UԠjwop$ɠ̯aV>1&Eesi^,_9/\=9^ܞ{[1ofͽW 7/S4|9ujx4SbMd4U^'?Am+:h&NR,B:_E3Q43l.f\޹9lL=@ٞk 9d&BΉHc7J9Gt}f.>_Q~=3b5/ƯTڟAu3>kyxvEӬ!pͥd"?` ꔕZYQI {\@4_9D 4i&k!duX< \:ci[;nMZuio)qDfGe8])nc/9QbTQCz5c?Q:iVzJsK<֏<}S?f?3~" 3[N&jψ%4i۬67ǮGȠA()H$TRi95[+H! %$LLk% Ŋ4l\DDv[VZF|"k"G p=1qE3q:5t]c`]#Sj!Xt]#PUKȉ΍{4cV 2aPP%g!%2vƬIKޕ[E ຎ~0=NBPRUcA]01 IeLI.QVy S׍!4UR^-B27Rӈ89vMAnBh.JUPp;DVy|n=Ũ.ίҎkE vEbiշx.Htr#F *WrO\׋Z(뙹6Zߪ9뀄$xm oُ{]$0&/r0A$ ddùȡlr+/MYu:ċyXy=:ۄNi-i 7k ArbYI5~7s 2Q*0t ]7qyشW Ćy齙="ㇵ&4 @s꒟7^ ~u*BT$AB3\xJ99p8ȪOf1~tǰ!M(<%%z>t>W E4UU03rm[1ɑh e?*id -}Ej]dΚ t%ԪރÊ@;]ޝfJ{ O nܵyHUS#DY^g69m 7)( qnS$da)!DuSaNX9j${;y ws@<0/iV `b TtCAb̥钅CMt 4"S:x~C4UҒh: Q07A*&}n_5 t[Na9@M Sٽ Mb wcսI?yohaJhi2X8 lyǓ\!P(j9) Ԯ…?oB; =?{LlɣO x}B5#}ǿ'/aqܮ1Mj[cDЬ^K`* Ȭ)KP?͠mbp1 ^{Y/9'wfo[zG7J?I$K6 "y):Ȳ˺0.,xԱ)K~CNM1-x󵓑i^9?Т8rQwЬ^)C~?+38ꀀ4HghҚGㆍ0 hX+4Eh4mΒ9vr>6w .}+$'uR\V׌CBHȨKHQȆ9c%.ɄKwppH)4Imٴi% ȰЭC`k&^Iy=kqdבY6W2jXmn ϴfZq.6-ҎxchZ7E:ed ӡ]K< ~_1-0cM?I[?BF!zx 5hn4=xż`31I7$^,eV.p:1^7fȏcg I2v=r4&ȀޝhQܼBߎtHthE߮Y x&ulݹCӸQ]֬5׻'4gǮCaڵss(dﯹ H.<5mZd0vz]!\;~?3~OǶ٩.H~Qi>Hصs;];ONlڶKWc &CvY|>kn7cGEE֮ƚ ;)hY] Ysj~]), 'SȬɅ{uizkizuiG:/[|Ft%ZDIB3)d>rK.mi՘߲ݢe4S܂BLǸkd,YzѱEBƊu;Yy K&u1u ؛}տlHqccisNcv¯|i4`+:~6Ą$F^xGf)8QD\8/nD4dI" b;vhT; E E݇Xd9AƍHIIe԰$8)*Sh5[vgdmmgޢLX 0D]WD A*hЈI_ˋ}ʦ{p9$Rk7eW-yǃw1kFb< 'b8]tia6g%+L! (!UӐ$ SiVX@5Mp8쐭Ei[O_ >2#uPv2(V r]a(!+,I8]Ng%j.˅ R0Bab3 N.DQDլzt8( $!;d0!PUΈTmZTro Eīp78rېBSc(Z$-Q aBU^Q,8NdYxƪ$ɑDQpD USȲeM<4% "". I-TyX!TdYr!kx͙4lOޠu~S)1+8kALrru\n;SQ)?L{=la`i`'ЯMN}s6+ ӭ`݅9\ޘxk0kGd痐bU Ab.xAMdQ!$R~sL}-EnG`*58TPʤo:quk#!֍(r؜ٔ*]y-L7tjn@qРQ@HKvڵlAdӨQ}Ik睍Yީ)͐ *-)!r-1ˡ#mlllllZ3[YLe:ƇCʵ'{4m׊Y,Kĺ$D|_^y2lj׋c튲9ۑ$xB^z-SmS<35Rc3 BBB">JV666g=nǃRֳ + t|&O_@kyK̴Ydݦ]-XHBJ<\q -.gCB iQWv%؜2`’`ԍ7hYHnA:&$VgV6666V@(|v-ALfo3%+C![qHMЍH QړSR#KKQ;__ړ _q 3>>I>}_Y)Pj|?] ,S<?u{n| V d`n >Ӆ*"EJx*O7|Nl\|TjT^SU  Sv S"ޘبo2U!>?)))[(W&66UVѺumzɪU"k֬[:m۶-[lϛ7 .c_0rH3=c38mL 9-=zQVZBLL$s3j(~avkrX2xT%颤Od؅r4<bٿo/2Q#3\/'/W_N9xx\||Oq8]' w>'p{:xgǟ|^/ϧp񈋹ù@BbޘX6_W]cƲ5xcbC*d+aԨQ9b& |h"ny(սڵk߿?v{aذaoW_Dݙ IDAT}5rvLصkII :-㉉=ą X/W]}-S|a׮ԯE Zu-mlǪ|/r)dHݺuYdI"}嗙1c5^^zdffruבΧ~e]/??-[Fқ8q"ܹ/d/_С!M/ϟO5ѣGIHHN:Q5ku\\\\J=)))y 6,r4̙嗏`ڛ0(*? qoe]'"31cD! IUA)))|g66jĜ֛oE}){}7-E,5iʒŋl)hc1c3f̈:W:ŋӯ_?&NHrr2+D;D>92ĉ3f0a-ZĘ1cXr%={$&&֭[|ۢnݺ ,y7X^HzÆ]HNޑ*9QtVm[UꭥpIjxIW$Dn:rl$W^}cy}k$꒽"V] rg @IIy̚5I&tRFmˋGX2 զfΜ)UĉoGd*j[aРA& a+u4ӤM%eUEI0z;/cL9Ņ=5?'pmGiæ*ySRuӴ=uM'Vܣ+JT}{㓏>J_,yWdccSeeeQƍcɒ%1uԊRUINNi+dffw^fΜI>}HMM妛nbԨQ ].'D1Zܹˋru],]MMM:w!ƎO?-9ߧO/_9"gv&ɓY3QRz jqQ/O(xq bc40ڝZԴ 6Qiذ!Gr} 1:ujz9wnIJ#77ܼDAhQ`2\u ᮻλ%`7۷xزe /'㏴iӆO?={Я_(e{,\u2p@6lq";v,x_z% BA5diݺ5oqQZV-ڷoONNN۲eKBm۶%55kG:t(?7x&M$?~B֭[رcy7i߾=$:7p0>xuARPF гgOjDSCH/<ϠAٲe;.̐ .{բ%=rW^&5<62o9MHII?0w|dgӤIcE93k[4Zk"0qDJ(,gƌP Fbڌ/nԯo ԇB!gd |аQc6l9(.>AVVkLFMR*gϦsθ\.ڵkGVV[fϞ=lذDwߍJg:8p k֬!;;x -tR^k)\#ذak׮4ͨ?R.RfϞ]g~C&>>Se1 χ*$ SR)+-0Mk $c# xȽt &6I*A|~?n\]npP`( r9Ai*ij*F^& ĆhMLBl\,BtBP(2b~ߖ66aSUٯfK8ڑrJ e9YG>,LM8QXטU}QQQԱ_WuVGqQn("DtaNS9u\'NlllllNUp]6666i D@0:>llll M\LŐ=;IIa:g+LPPiF RO[bWYGxßиnLH^^gccs֣h:k-}x<;pgWY)q <6PtV666g= Ӽ slolWYAII xdmiccc# `"P|Ch`x=y?}pyc̬GYn`80mllzdYF~\iڬ99T`t֮^Kޱc 0INYBh+L[=cFz{͑G[0mlllNEEN (ei/-X#ҿwr=IaA> z"쪶9 `U+HOEuBHMN4*۝Q)":$ Ʀ:#rz8Nv*Rn'GjvARr)$_yޒSRecd(qJr)RZz}x?Y?~Oٞq(8]N\.WxC )!EA+E$ڶm/W]pV E<`{?/uN62gإ GT95j`4k4$u]G*B0 LӬڀ?zi^oi+ggF%+BBE4M>S̉|Sm<<|RBПJ3Q4]K/..5kЭ[7NڻKB-`Џ J8~#6oNO,~WcT$E]WZZJ\\\EZUq8NvAAȲPwBDIGy};vZjEDLg)ssL||2=1zh^yE:v3>ppګЦu+ك`3OM*w8yZ1x<1|L:7֖66:tv][LC/ԗy'<@EvYy뭷"ߦk׮p 4m4 pUWq-D{)}OHH`ّoގ;vS^=9u%˙0a_|EDI_r%QLdərW_u=|VVz+ŘI5̬Lgi5V 7zYe1=\w\sU|L:vLΑeՋL.>^LLshߡ=cnj`ᢅqyL~w2IFfC#))55b<iӉ2Q8b-ll} ^@ /n@ M##"`ҨQ6nL_]6Ǐ7l0>b֭b߾}wѨQ#Am۶lڴ ޽{G[SAFFFK._1cD;vf͚ormolٲiiil޼f͚W_7,+2ݻorJfϚ]",[^-qDeFran 75j[o]]E+UE>1 $0{|C/8VrӸ,[,x-Z%^P%ӧϨضQlIhcԥ! U}۷o ["(v &`ô\f5'/XUVϊRRR9n׮=nЫ׹QI].'a 5$ Tr^O^|:ъ?|u%'r_0? K2 "6o̶ohެ9n%e<ˣ^L>5kWSRTTgׇ_o+Vp͕WSoZ]sQ>CߟvյגȎ;lyhcgj]PꗢZ("A`ٲ\yU4iҌ}ҳgwVXɔ)SHJJ$99'Kiִ')x)))'`劕+avq:ef͚h֬ܞ=ÖcѢÿ3D)))fذtd3z,^s i =/+)Wrzx `~È#Yd99Gٺu+ǭNI5KEf>^8zÁ{پ}bP~:tx~ Dk >ŋPPp4KJ At IO|G=7zYE |e> "Ɏ(K($ xp8]P5R#;dka`NV=J SRپc;ZtCQ<.w{WUB5\~<OgiZd*ULmll,ټa#֮;&&[w<ҒpB7 z,~]-EUC!\.Wy}E}Q슢 n7@O(p[%(wE Yn$#zGV.!I2EE'HLLya$E.(*:ģyiQn|nuJ㎊qh<4xu>:;o5@VE:;a@iV4w{`0*)[5~\P^iF1M())t Qڰxq_* I2zD CNv X$eaa#ٙYEBiD1O?VatMC1^‰ /$r#^t]Gw 0u3la~V`XM[aT4LDL$5qGLl%[>Dӄ?=Wl-8D4 [a؜ibbK[Dᵮ IIs+QYq1^Uu㜶´91tSiݶNRR-[6Rf jˌMv9o@oX/?sCfhӺ5.¶´91 P(y00{Y04 EQPuMUV6666X,S@51micccsi&=;V6666A8Mw*Y|´9شPB*G0[a-%\. d?l2 ]("  )t֍~}⍋ϭM[a_[,a $$$s ?x0jH<mlllOt2wַ󎏪znl:Hޫ %tt6@(JA *t*^n},I/{=9g|f'xyximw^ B!{}jTK ʳݙd:^9tdqι?+ܝDULK [r?ɻMCq75fՊRV@3p)ڴmEKT(_FT)X-bb>fm}~lwGW4׏5kia(zz=͟[>#t:ܻ/:utZ5 {r(,/ lyޫjVD!F?`0'K3}sDQWP3cu YqeDQdĉl۝ޙKB>ڶjEReCe(!M}>V,_F͆#66eaDqpf:W 7N5Mftl&--'NӰQ;ccsF*RHO*\$L#+lJ\D|mFFU+WѢE< Y#jMyi B… $&&)S A**-[L~NDQO4O IDAT_hߢ5'/\`A8Ǐ @m9|$F.)]ii)&%o͞ 1[d3P.ZsߡSN z12~/v{:N/~Js }>ah2J@8$֭I9} X>oETRlٰܮL|>f5Ng 7@PӇkm8 )LbPh2zgzz*!1P#%9 [LmQ#===U*TJeXbly,{{F:fN('/Bۨ @zؽ{w5Q 5m$h{Gh׮Ǻw⫯Ô.]7gY,xqRAԽ_}`XJ (@MEK>=׻/7^:u 4n[63(UYK`4zt;J+/ҠaAW'0Llݲ%K#ߙZd VgQkԡ#+~M3ҩY& Pt)._6={P5߰Ŋ#n8|5 :*_WNolp*ժWCʕ/GfƼt>LeU&tz?=QV &NN.H"} CP PJUĠ5Ⱥk(^j_W,⃏?&͚ 0ɩ'hҤ {F& Jl(SO#h}{$l%U*W$1񦬥F(B\(L6CEQdtii7nիX$T/ѷ?RI޽{7 fpB @ܮ];\"!AE0}tApЯ_? 5SN!{)rBcff4E[\*`_)?-k֭][9|t~-Zh,Y^1c*?GFN .ioL_Ͼh֬ׯ%'ӷw_j֨g?ZYdP۶HOzYmb9oVh>NVxal}#c^x~&6Yz ٲyQEY߿/IT #-& SB%N={9N^~-[Pzu67g2y5.ޞ=.C̚1?OZu$عc|c'8ux$gm+h J•K.Z\,]:Qtx=5jdꔩamm[yӣg|9dRB@P(=Üy9>)Dbvz9/f/?;yOBBB1ޕ|[, \?3Y#IRaFѥc;~Z@ 1ˆ9DBw}/p%ln=Z [rk)T`ص;&LӒcNzAe]tŋ细 cĠ. [L- tz2ksӱS{DQ[pe:{$&F2EǑ-:Uj`ZIqeo{>mN\XF(sA!H\-ϝ]?Ͽ^}0~p7SSFEjs'1&qq… G1z<=:9Nnޔ%^M%&Q5o2g4Yo͢Hs%Fz^oRysr\p#-T󝩩)Xm6U_W_~5۴=Ѷ>l6~0}'+8qqB2d?]n~Bee ÎÑɢs΄ III4=+VJNN͛I|]`mmNk*s=b}~a J%VpQtz# @%Jfϝ?oD*URĞdIػ} myL㮜 X-T\Yf rPj-5k cج C_OR9y(۶ncβ%ߔ%ZfMw{,S[Mlm>r~ÞVCLHkuz\x){foL*߷{?իJ{y>sU;%!Ǐ {_>yQ'`j%J#y~_^+OL"uj֨}:NC4z +Q3Q9~sޝ;X*5GaF.Bul୷fRL?J.eKqrBFXj !PQٲe~F9R۷Ҹ[lOŔ)9v g0ax iU^M&By[`}>TL-={%\Ut:UTF3aK,]ޝØq)[Q ѨVB5֯[ٶm˖-=E?MJU2hpXW\A3O?ClI+yntVW_|ӧO•=˗/PTXFvZx1^CN<]'{p5!{ 1h@{zg=AECTtS^e媕amuJ~TuV4okٰCoώzkKF;eS@hUɂl۴9W.^$WY> FO*VĐAOоc{ʖ)|RlM: VD_~el9׏ߟڜ9s>zn݊:ue_ZshԨ …agkќW__x7kɫ$.ۆV1MH^Yx`k b0{q[pXi5V5ЙE3m$B!%BPq)bblx< zĖJDbϰ A *RmUGJ*Hf޵3L$ݼ$66ٚC;@3W -{j+k+Fr i W@)RpQN8F HIٳ:}n&! TXDbb 3IEs*RCQj5YHe8jH]~ ϋ`&:Ɔ+Ӊ5W.QX n\(XHdHJJ"Ph1>H/z>#+*Mڒt0ܹs-'pE 铔/W-]d82| HAii/֬mk MMI@W\/p3)Z]]{[Nn;GoS k RRSPޢ( :fH'FTbYQ)%%x)W@XwIzq2 SW,JtZA zTJZ]^^ߏ(huZ>/~FD1(AŠtB@ x<Vw: ۃ둓Bu|>jTjUA:xR|~T7!yT_ZR%F믾w~sbPA0JPfR? !bPDӡR rݲx#k<>/(;BwE`v؎FJ<5BF2fgQDՆ׃A~z9r x>4A &^:(wI…xoynL':!4~4A.BhMi𨡺 !`0yՌ0慑 >\ d`֭Z O#7jܷbڛ3۷;=v& Ēs'Q4>JSl9+$3uG d:oG5k޼cfiOrU@ZpyFzɷ2듏VY(33̼͝gNDĕu =Ӳou]6-fM%7%%%_⽥Ͻy7>P"gy`[R2AHD6mh޼9ώFs#Bg!*[Srf{'DP:~];z ⛵$%%ԴTvJX÷ș'pX-ь lcيpWo^fyǏዯC yb@;CNmZӺMkj/ fAaO~aGzZ=C*Z߇ L(Bo1%KNx݃LICg~,,_h )Hr(`%9-aw:صg'j&!:kׯ像0i"e"VfEn7A@!F!f)@=c߽+S&!U3= ~3O=I钥qeS^ŊC72gXlϚ΄/}4߸A0Y3#FE(BTE@/+'BU**汞GI|l}l݆t_ 1Z%J0k<|mRHh!;#E(B){q24 X&Ο+~9ul?(V{> %1l;ܹ"E Q82OE(Bн-0B耩%|#UzK>\t!ca@`A)jY D|7)*Q3J尧e;xoXd MOO%* X~KIN ﯴ{LխdZQ>4e%þ_Q[y~*0)J;7ɓhh')Nv8t Wcd@~TU+WCBXn SI. ZKO?0݋oɯLlb#Bb):հ֮ǟ|BZ5Q*hu9%K@Ӧ0~*;whڤ)O?Lt}'b0@떭8s$ 1ciѼ/~RFc˥݇y d2HNJgL8AǎO҆hӶ Vyލt{v=k_|Ξݻ1,R"_AIf҆E%a9vXZh rl}#;uA̜!:{4͛vFǧ >I&jي'-[dԈkzkVӱãԯ߀yCbX2ɡ4lc^MrR2KJoA->)fZ' >Ei՚{v 8VF˥_ҦUkhuk1MMfG=hݪ%Rw6O`@4kڌo^V'FߧE<̝3 gw Zy{[bA&cX1-;>}{ӽc߷'OXfuwmZѩc'܏h3'e"f $ӕG0UTJŋ$--ӃhbpG<3r (VaHZgO_@"TTPj)Rri鸜ܙN^o㐑CC~rg4J)ZP<)#uL~vt& %/u֔,Yf͚1bhԠ!ȑ#orP2zMlg<ޯ/еcxy-GzEuy&mZ"ә^ /e9όx&M<>];ckP3Vmڐa4V[`Ŋ4jԈ'=@uܭ3bMټy jqy=}Ǻ?FЩ}{n7qQZ5vUk4BCѫgO._<χ~ֆ&7c]dmvoiҤ)~&/ӧ__/JU(ٴu+d SLk4kVaҥ4ߐQhIPn(3Rysٲis.4cKcyk[4hЈS֭]M-Z-[Ҹ |ǔ)[NZ[ E<zbi4hЀqqt֍۶䀸a_Ŵnۖ%K߬ #Jj;}.]rj{Fy:Pnz}j׭#ۯ0  ?әd<4>(DEG1z(^y5>.oO?xgRP՘-V*yҪu[.^8/CYu?r [&ƍ\s}Gywux=.$?ɯ82MLf.X@Ϟ}_&Myü>uAfMbCqz7c^stIKSg9r0n|_|.^@f:cMȓo>yxnDr.ukӪu$ 'Lb6xɫ} ټu3-_"lѣٱ}4grʈlrvg}߷wԕ^mAŰy/9rHe2EkL{?@TZ=zknԩOޭZ}ŋp97$ݞN#&i'MtБ@ϒϖ A.i3e ̟ "n@ zOVIN@B$&AMm۵ sXʢěp>NFBsܫh)-M4ͳm[Qx/~+ӍZ?x`pҹ_0_QÇqg{JuXɷ{Z=u;^ܮX*Kx"Ͻo9dغmns/P@C|Fx\i!{z ~ƹ"]1m2,_W_JͩsxeKvA2űX̌?~A&M;9,4L)S@9M@Az\Lٜwbw8{O_,~cb$syz\-Q пGeXz5˖ kK0[Fo0RVm>`u?zuzJ#:*>u+?'GZk2jHޙ?hhBN&YN(& gL(=r F3۷ixR֤&+ |<'qΝ@ʕZ<_}6mVM`Ҹ^zsߞ^ETp3Yq4|dmNtjQ!㏈+ WHҥTÆymT:(RbNKG5p̩w 2)SoORe+ZQPST ?I(T׮%2x`;W(GL\^)i:2e ٢E<Ԡ&U~n;נ@ P…IHrEұC{Ax\rVf۟]=zhGFEV*;UkVaX8t]uԩG\rύjJ_ 9͗ƽƍ򥋌~~D.qARSE)R0NU}{RN] ,D@I}mӎyRTΘciӖŊZ&##F>ˬfi&6iʨFx#. (ƌ_ WVƍ#=ӧkybo^KѠ۷ D1I)cCa1ZxbEj֩NrL6"rx} *ĕ+6x? Bݣ'q1&RS9v$7hJ >/QV37mx^22h d:3= V+Uʼ!Y1ÇaRDqj׮C-ϋJA?{E?~NbbbXn57mkz47̕uTP6fҥ!sqT̆kٲm;EJZ׻sn]8}Zv`寿QZ}/iE11tО]֪M A `F$&"9-|1Q9`ǎ7_ȡKr3+Vk hHkV+eʕЁ?|ZǣڱaFc˗/ǩӦ߼)/\BJz,!?O>,'bc GB|٘}{p_6gϞݒWY ժUv4իs1 %k#غu'OjеkpA Pvv'O`jA@lڼ o")%˔qÆa}jXYr7nJ5/N5i܄=wrql6Z~[h@BNiמr1!H]տr<~}M7⋗^À+7@!E7۹s'~HG Da5 ;BRvP*mӏBviGVp-NFg6k.^|iR8~4Ϗd\pg !ÙNEѣj0 L< A)J JR% MRoJbFŮ pffШ5&}~DDH:P*$\dtT*1LbG0 ;tR0L d)4 2 J5&)Lg_FQ DR|dff\NbU&R0 ag<L cf9d/oVAP " 8N4MX>|~^ǃ HQ$ߋwiZ sNG ^2331h4x^O=}1upB\ zCt~. R1>Db7T*0>z\\n4M.(9rJE49`g'V!,P(au8Nؖ huڰg~рR'. nV'M+Z6NQic ȾYp1ϗ~ߟ(O=Y߳"zy♙y5*8οc./{t]n._(}6=Ώo܁)X ==C:ݿ=Pr0aIWxKe؝*t0EQDbPQjPd`xnLޝ7f2e1tj (N*FSjn%3NEnQ+ÞY"t7Ah ! MB/D>_sըDa\n|>7.j cg~< v zN'wF0YnG&,t` f`+㒵8 ![S~~YZ"BkzG^7޻W|1JDQH/TJT*%A& T* H4 r6syEEtzGJܒsNLGSNz Z”9SL|_n]]&/2) ׯaZ'STv@0L 2w( rNIN"&6.z?QV YnՎl16avAJ dz-sJY樼.˗__f 2BA gZP: :+@ @ >Kł5*:qĆJAR绐 o] {il&QѨԪNzԯԱS\KfUv)+Ë5*Z/t3I捎:3hBxj=֨hNGfA`' RkFEM "Oa%D\!@^~e2dHp.HKEBTTysƛ̟ gϜ\Z̥ n.r9e[%|..Qύ"Ñ-&VN2m4Qk!-A@oУP8xpݙZȫ3mAfsX@n5mR5*\XG腼 q8ɍ7$ϝgQ+~Yʘc![?_}s ˺ԣGvDFMٴiIr Çg۷Cx<vs=O?裏0`@X]M&ÇgԨQC'пNz @3"0*THSLIY;w.qqq\Z2"L:ÇX͚7CRE޽,hql޴= w.P(TR.歷$O>f}K0O7;nou1MlXr<Ξ=z3٘k㬨?w&twIH(%"b_ 4PX?L$ 01DEDBZb{w-+qޯ}ԙ3gf<'Iƌ7&Df&:ϟOFĎ[o'xT{n&^} w{7ujǁÇ%3 IDATۍW@թ^ӈTqt}hߩ;w`9Lxa*UD&M\7InV|>}׷/s?DZiY ʸ5^1M:wB<<gZZ{/XKƉct؁hz:}gF^9OODbb߮\E& >W=-Z+/dcd+oNovмEK"/^DJJ*îf67]BFɢcǎ9rKؼi31HW 7бSg4Iן׫7ի7g&vڰr*4;%V\x7=t^~USXh1+^6U7KZ[zϽwo"-hɏ7JK/ce8=}aKb6p hӦ k֬!!!={zpmڴ!..C*41"ԯ_F< ұcG֯_OJJ m۶;ދĉWP1cf͢vثՄ ;HII_4vɞV=~Ru]?rqege꺮P=Bnvn@ &+3C8dg^'ϝ3p56štlu]6p꺮*V_7~~5ܯ]v뺮9>oZCَ^QCWto+WT~k]﬏7̴#8pc,ҿg/o+#s oӧNZ+(ȋoZ0 +_EwslOcՙom{^|~gǏ+_O_oIu]7xCzwuQ+/X;z bWb}ƴO|ޝ5S>Vs|ճtd뺮/Xu]4M/K,+V,[|饗4󺌌t%K5jgx#NU?^߹W=7]uG* 3b?~]wc\Z }ƾٲ9s߆7)H÷mvm8q}3J݈IZ9v)=+ cyʒLNNv-גEwEG(麷gIv|A~t37obڢI!%HQ֝eፌC5"¸ ][սh J3(槶hRj={//V + qWlT~qͪՌ;LPzqWza C 1ʞ{y㠅ea0c,Pbgvggey=x뭷7̫SW8&5E (}.MυA "UF{n/?hР2 Ŏ2? 0GUC毴rPiuX$GDwC9Vu^g| l^ӏ?ݝVI)InOX*Taݣ~2ĜSP ɘzakT(=(ߌѡ xXt O},^޴~Mþe ab:6X6XؕW^+q&atZ19\ f6clݺu\ēO۾b^xIJPN;1y٧υ̟7' C;qȤχ?Gu:߉iSc RR*T}FgL e^׸Q#F6FHD8p`u<@x2iliּ:뮧MWxqFE iܰ18'\YIJ{G߹8۶㮻ae%ǝ0mT֫Kw'+/&=_FIMhܰN߮`ꔩ̛;߯fƛo]u]V#FNZ4whөCrߧQd9QfFfSRv,YE_'5kѤI#o>ԨQڴi/Ĝ9sJ4 ;Xj>O*HLL`РK+uYJ?2o]؉pӍ7~Դ~7lL %w}:mV\yg=zb޼r\1t(^yׯ7[~t_./8MUxz3ك-[b90妛VmvZ\}11jŷ_3 R4mƎ~cٲX,v.d5kՎy/=ٴqWFSU:udZh̞Mnn.?1*;FId= 0vxڶm?aٳg'?/mr8?qN{==Fߍ`,X9iiiz- ~){С?}Qov֭ `R>NOXм'|ݍnbQ tJlXȧzSVrtskQcK!qwGS8 HiE֌tSÁv' H^OV\7*yXlIp!|_] T d` vbVEQk*hF+.6oJ^~Yʲ2-o׋$K\EB`(#FWL@ f1 qa7.\A%vǛ_gcLғ$"3&{;bCU Bl6b֝>cU$Iy$)[ ݥ>5E].{.rbc1{y}f%!\'zczRl6 v2щ wqwY%2^kzLbw8جxj%@)(ZLG53M_Kw zy'qO𧣕6M |~i*8R+)҄yVQKˊWYQ04M+6^k:IJ(1/%E wK*5SrscE#J+ B']*(ڢEДTN%Yvtp/'YD?P,dqJzgr@eFb cBVJj*)$'ߘ敯OsY'Eo܇CpɠK:-_ŋs@2\W`>OHLwb)].$&2,]ǎnڿ'c]V|oSL5pEx|RSRE;Rzu+: DHC (6.2+ãLxF`l E eGZ<-H@k~ eKx8q$Q6Ѥr~׮\ԣ'In>R08z(~XǻfqW‹̩3ߚɚkT)#S~CC5)ƶmޭ^w=`Od #˓'sܹ# 5B,,[jxny;ߤN:;23_@p[LhΥsW,r)eI> ..onԩυ滕+ޣ;u$RNV^8. 7_Cݹn \{8Nԭ @IRdOͷ+/BM49,C0ߘnJմ4^7ndG.s^35 /@@ "ƚW ըZ^`]-~=9c>^Gt>3a3w D5j|`ASRٰa=;YQ9NʕvkfMḧ$Ih6PL@hb4ܾk9{7ogACV% =(AKC5^dl(˅p!! ]{vҪСcGt"%t^$Hj ~ rN;>:{~q3Ij.WM?HFFFLD@ fNFxrX VZ @65xٱw*WƕW ҭK7V]ٹs'neUHLvV6&<ȭÇ$$cZnaaC=,_\s.O `\1 *$Wㇵ?^S~reh'[o3z\w5nozıS@ >JBYGp(+C 8JʌQVd@ ވղ`@  3EJ@  S !@ ` @ S !@ @@ g,g:H."YKAGGt#NopN0S(Npc G}/@+!F_||aX2Nj(ʛi\KJ*8wڤ%yJbiZq$'TNn"IlC`@ vѣ!ɲﶘ9]Lz9222sŕ+xw+V`Ѣ/O83%bVi aaX6?L4Mfsg^Æ26,NHSأ6Ĥ*,$,{0ৠ YZlEM<)< ZN|Nӷ@~}ek>p9뾵Ki !L̷f0Q@I8qN'J(Ğ={X4NH)bw&)95ZrQ!9%\V+$!NEAQ$Y"[zʲ RṲ,c꺎b+Ҿ}G~?JH1=¯[ p8X4]G PUYE}R!lqڍ<ƔM5pHb`ڰX,jrJ#ȲfjӲdlkƱ"yEŊf"[g r,%3R61TtM7訊ZY\.yFFU1<Zc/!d|/Yu#_+BH k—@  iܸSlv;mwsV(8[$d%`٬ W]nE *1g0^Fh߇Y.L]SHz:8.11Y=vYllvG᎘[YGBbybi pZ*θx" byf%119vgT>vG\1]#++wBN&/7Ĥdth;?l4bF)x OCT^bsED(([+֣~O: ~ijAbR2{nmnN6M 9gZR-P7ШaCttO uajH5ӈ"bعKgs_մ}2ҵyE˖\qsBJh+W4ڹGXf-G1^Hĸ1ۣΕR IY}*-ZIc/)K}s͇_ILL&?/a?pBqh׾y뮉!lfw07c}o֛'&ܹsW.W]U6jTnW/@">>_B5K|~}׼ګ Ǝm\}U}t놮;N˖bۿ/=36\:uꐔXedsW,@@ yR,+}41GvZ<| }yNy_$$& I:χ? ''=dxbzen7n-6oZ63f} _- !S,{a欙cEg~2-:\4_iU$:uS)믿fQs]z%='aWy57nwkk9Ƹu\?YY<FFЪM+0OJj2$ѻo_O B*۷7k֤)ﻏP3G((g⣅">KXv!N #֭]vvp5לR:y߻#J*8-Thvc--]S$b wW|0lKrl)uFmNv&C KLyG͎Ub'y<5'2N4yykUUI ;+ {z zi>)GaE?n`_Gz3h|rӧ͠N:<#+yIDATf֯[ˍ7Ȋ+ +}{dd-e{̘syz@66 x= >(D\\\X+?@ wW_}UuԥR+dMca|yƍgc$LjQB̳8qȸڬ_]X;z̬Lƍy)Upp 4i$Eq"Ӧ- w^=PC {wNy/ t)gmoݻ\8Mhټ^s-_HH2&c5lАzҽ$$i2UڶHNn6ytڍ_n)v`OUС#ǎC%=[8p1 c4b7jԈ`(HÆ yZj;{xщ<\ݤqS&}Q VA ۑ&=>ቤ9<+JXHg\Ĥ>?ł!w+W2͙HᵚF貇hLNNFt ];#v bV\YY c^nnL E*WH~$I2){[PtFL ܅gb]E VIIX]~7fFVfFLޢmZY1׃k1xdLBBB~=0Gy'> 8eT`}J[ZT|Qُ%9%w-ʏA?4t^/Rdyfx>HnNvLR+m<<h-z/YkU,J;*SJC/2/-Wyϒ] ͆kb6nNyi*knV]^")휥 shҸRZS`0H^n!%Dq*ORR r4&!4E0@ULcHJ!@$ʎkϢ*ԫ_31 yT\ )ӁܜlnB,#]KZ) NK,-"@ B0@ )L@ ` @ S bJv;v]G0$  P(O>2 @p.( BQTbwrE % %(K0u>/=F @p. ˲+C0%dق,[D @-@ 89bf@ 8#X--VV$- MB(*LVՊnbstU3;(%L@pVN'Gs>?a[T2꜇3.+6$$.d\GZZ׬] '` 3 Itr|15knwKҹƖp^:VP ʲj?vTZ Î Ibk9kW:tLHQN2O@ 8AapelJ osW>Pl@Xd Aիc 7V(0ȑü?s-[j<`I?3d֮]#x7.CG[DO qȑ,O'L.jժ~Gaa 3M2(((ih\Ӵ,,Ie>XAZ%rSoÏ65!EF?G۟CZdlԛōÀ®YIn?JeIugeS)q1KV ei OpHC#Q/.⑷!1>UHINB:Cd8QFݻٴiv]z/,e vPs\v 굨OڣHU- kȃErXҴzx<[rHpiE-]vn:oS+ҿS`g'h]` xlX.L7нQ"][:РA:t@Æ IKK3բE |Iq\ :̿05~@-۶5 _n'aHC.B }q~+[PT7Zɏ)ǏSfM6lH.]hڴ)6.4!L51.ܕgqMsiڠ.FD/{2yQ^zoΫ3A<5E13ϰiӦ5V#GРAz @j5j{B fp7PhHNȻf|ڿ>%;Cȡ@={ңG6lxIp:|1O?IZ*4ԫWIXdő_}g<4@ 8g-Lk+r%i+Ubסl~ےpX$Dx~y6jThw̛7!C穪7XketoM p< ScI^yׂ |jt$z]Z}پ};[}JNKKc۶mlܸnVZѨQ#VZڵky7UsaڴiÄ h۶-?0 `ʕ <5ks嗳}vjԨqDd9#_ſ`}><*$T|Ay% ٢cB$;hӨ&^UbҫZjXpDB 3i$ ر?>]tK.̚5e˾d[_ .!LYsv'Ҳ~%jUNdODe)QTC'n#)KX$Nՙ'kmh֬Y1ayƨA?pQ2q F(Dj>ޝ .7 3 efԁm(X3KUgTK_}X1kŜӵ1ہpՉG^;w/vܸ11>_AerZb S aA%$IS?qϕݙ -[On$fE h­;pӀ6 ߆O`Xqc,y}5U$^ƎC}b.ԭ[^z]v|rCaҥ\Nc?爬it\Vyk ߴ{B@p{3~$o 4,I6 ҏqӳ@ OZl1{)5k0~X&LxIwk֘]yefZ3g_ޏ_(Ve.Y@pShH5j|u\2o.{³XUME-\v(/B諯z/ߏgìR%@]]N"- !G⊅M 5j:G4e HfZ|^B_!dyFQu868vUR2Pd!6p֪;Qw`q'-]qݸ݆YV$ѥKW|>mEQp8줦V 5P?$RTHVYVL@p[i_$ nѹo=t'Jl# 9iau8pX8\.v)BkhZYW$"Kyz4^w$MF5 ۊbE8u(;i{|R#'#''䍙?fUb%E0=%S )]QեDD y}>rA2hUcW5ezBHV+NݎSQP6$Yfʄ TFlQ2Sb:9l9v ut6OFy4@R@U4vk5}ƗEp8dgf9 /N` 3 WmSulv;I6n`0i~; %6'ݎbf'>:4$ף=Ůձ[԰Zɱ:-vz~:p7O|ķnEEx6hB )gW.Y@peZBCڄՊ=Kh DQ5tue(i\G*TUժq^ ȾJx%//` "9)ՒH[QP@ gw$dY/B5Z4TiAt$sTug%=G(BQdYjhS1%)%xJ0 ?ϋ(hvZM lx.S a[p%r{RK-

The command line modem documentation can be found . The Desktop automates much of that detail, using the following dialog:

This dialog assumes that you have pppd installed and that the system permissions allow you to run it, or that you have one of the supported GUI sudo packages installed (gksu or beesu).

It lists the available ppp scripts for the known providers. It will also remember which one you chose last.

The password is optional, depending on your device setup.

Upon launching the modem connection, the pppd output will appear in a separate xterm window. You can cancel your connection at any time by pressing Ctrl-C in that window. barry-0.18.5/doc/www/content_list0000644001161500056700000000033412242254476016275 0ustar cdfreycdfreyindex design desktop hacking roadmap requirements dependencies install installdebian installfedora cvs patches codingguide backups modem guimodem contact bugs sync guisync troubleshooting logs rawchannel migrate browse barry-0.18.5/doc/www/backups.php0000644001161500056700000001167612242254476016021 0ustar cdfreycdfrey

Backups are currently performed using the Barry Backup GUI program, located in the gui/ directory of the source tarball. Instructions for building the GUI can be found on the and pages.

The Barry Backup GUI program is written using the GTK+ library. If you do not use the Gnome desktop, then the default theme for GTK+ applications often looks terrible.

Themes can be chosen for GTK+ apps without Gnome's settings or daemons interfering with your desktop of choice.

Search under the /usr/share/themes directory for 'gtkrc' files. Pick the one you like best, and then include it by reference in your .gtkrc-2.0 config file in your home directory.

For example, suppose you want to use the GTK+ Clearlooks theme. Your .gtkrc-2.0 file would contain:

	include "/usr/share/themes/Clearlooks/gtk-2.0/gtkrc"

When Backup starts, it scans the USB bus for all the Blackberry devices it can find and lists them in the main screen. The first device listed is automatically connected and highlighted.

You can connect to different devices on the fly by selecting the desired device in the list. The currently highlighted device determines what device the buttons to the right will operate on.

When connecting to a device for the first time, you are prompted to give the device a name. This will be linked to the device's PIN number for easy identification later.

The main screen presents you with a number of options.

The Backup button initiates the backup process for the currently selected device. Multiple backups and restores can be run at once.

When backing up your device, your data is saved by default in a compressed tar file in your home directory, under ~/.barry, organized by PIN number. Each tar backup file is given a timestamp in its filename. The destination directory can be changed per device, using the Config... button.

When the backup starts, you are prompted to give the backup an optional name. If you specify a name, it will be used as part of the tar filename.

Pressing the Restore button will show a File Open dialog, pointing to your ~/.barry directory, for the current device PIN.

You are not limited to the tar files in this directory, nor are you limited to backup files from the same device. You can use this tool to copy data from one device to another.

The restore is governed by your current configuration, which determines what databases are restored. Any database that is restored will be completely erased before the backup data is re-written. If the source backup file contains no data for that database, then the database will merely be erased.

There are some databases that are read-only on the BlackBerry. In addition, if your device is connected to a BES, you may not be able to restore your data. If you get errors when trying to restore a certain read-only database, disable that database in the Restore Configuration dialog, as described below.

Pressing the Config button opens the config options dialog as shown below.

You can rename your device here, set a different backup target directory, and select whether backups should have labels or not. If this checkbox is selected, you will be prompted for an optional label each time you create a new backup.

Both backup and restore operations have their own database filters which can be configured here. For the backup filter, only the enabled databases will be saved. For the restore filter, only the enabled databases will be restored, even if the backup file contains more data.

Each filter configure button provides essentially the same dialog, containing a list of databases available on your device, as well as checkboxes to enable them.

This configuration is saved per device PIN. If you backup a different device, you will need to configure its backup strategy again. You can only change the configuration for the current device with these dialogs.

The Disconnect and Disconnect All buttons let you escape the device's Desktop mode while keeping the program running. It is possible to disconnect during a backup or restore, but this may leave your device data in an unknown state.

This button refreshes the device list, which is useful when a new device has been plugged in.

barry-0.18.5/doc/www/README0000644001161500056700000000066312242254476014532 0ustar cdfreycdfreyThis website code is part of a larger system, and hence the funny looking PHP syntax. It is coded this way in order to easily plugin to that system, but the content is included in this tarball so at least the docs are available. Some simple function stubs are provided to turn this into static web pages if you have PHP installed. Just run static.sh, then point your browser at the resulting index.html. Chris Frey September 2007 barry-0.18.5/doc/www/restore.png0000644001161500056700000015321112242254476016041 0ustar cdfreycdfreyPNG  IHDR  ZsRGBbKGD pHYs+tIME (tEXtCommentCreated with GIMPW IDATxw`U?S^KiPHU:Eb)W+(6T 4PB>Ǽ@(*|wGx̽9{=\.T[\zJZͰ` ,!╓/U*}CGkQ\ۈaU ,X Qv@:wP^ZJH./]4ĤDv>J׋a ,X`῔086< vqAUG# e6Ծ R̈cێ|݊eGmq)~1axJj"?m܇]kX'NC:_X` g ljٱܵ2ҋIOCOL$QǧppZPhᶸ#XCcˮ膆$ 61 8]*wwy Z(  VQ   W/ J"B~\$p8m2Q™(Ù,=[C0u.$((feADwyS23Q$n چ1qZ|(;DI  7T02\vD d'-wCS FH#lx+4i™D w $ KuCEn>c~7/BVzW/l:%$QU!`Xn?FM[paD9dU]w8*vP!+ו*rͲǔ$ ,)HOKBTY$˨:۸5sWҲy&$imj;EQ+6G%ŕNzZ" K2GtHOKкUSP8]@@tF#&W [t9q4c#" ".ĪEs(- [™8$-y{qIzEsAImȲ9N;o/]s4w3~nC%4]#TPT0D Mfi:~Euinb@%]_k}Qh-9m2[%T0ee9P_ ҪIc&.$j6JlܒރŸtmלs۵AWAQ:Q(d|S?9N9٤'Ǚ$A5k!'؄zoe胳+e@@1Αrsuo9~ϖ]q:.D@CGbl `IdؒXÀr7rpQsIx5] "vt?l:*[sHcɪtnsZ6G'es:mŧ߬KڳCiш9u"3gM`e)>~#yor;\ºm:ZFJBd(- M7k,_,Yǁ2Z4kB:dӲv~k>FVT:ӂ;>Eak^܋YFv>[`I>|Ą8ڴjƞw8;};%^ [KiPuQ!|d5 'o{V" &\@!S> BAs4̏F(3*6GYY6QED 0lH\t4;wiP kd~޺w@ӢC{7#5 1-,&o6 k(u,YBmvmlUH]<S4o@^A3s*SF &6e;|?V>h~\}FňafZrt.ӊ}yfZӌ[ K<` z_O\'+vѤ~~,Z4N拲ԭno%+K߳5Rz y99mgD: ٰ o5 s6W>o?N0硾ųj>&:u̇-eժvtǪ-&֞mQx{-vmiX/  pf`Z6D ʠ=|l>r=}0s`C2|y(A#*LL"!?235Lj`<0tE$)d^ )#H҅LA4˺~e# 1QJZƧx۹ pv0^ ڂKZڝ%p* 9TyqG&!FNRR,o=z>UE|| {k{pyƼI9Z|'4OYKN0"L>Xrn}#)?JGK {t>#~27s" ﭢWN2j`Y%^ͅ=aɚ|CGBZ"_5ضc ^C+ҼI'Ӡ~c˟vq=idC{i?Ƨ>$IՍÇiJ["1+ BsS\FE㗃igt,.o0Mtm-fWk Kl<y~|S!:_ڼ}D?1/|OTLseУw]<z` Гٍa]00IaiTp{4TLTuPA0D\ 7x|< O(3Mѳk[Ƽq$F衝w7MYK06~qC.eP\ӷ?9:r2Lf{`Sb㍉_DSo #\/%geWz|`ESV8 `4*vKt37̪Ych0M;"ۜ\|4]`ߑ <ڷjO 0y!3挥}v} zdї hH~b<~ ;_X]) گz1 HVMTb/5ZK/GTw 6nԦm;iGjH tx*U>D7kb/ߥ%CY] S/W]y9]ĸaM ߋ?/BE6yej q\?2^u|i6cN3-wXK㴮x} OQrG({0aM dq\v?П#\x,]O ìe?XbB ,$BP*JNjYQQ6%AiD', Eդ!D 7$Y #L=$\pܺB%.҄ǜG4oͥ]f2WÕsLG`]ݐW#jcnB|A M3HwAt4QD#F54CCӵ9]"ۖA d#9!JQ,_n[Gl#dq#2)ҪQ|S=6KZZ QQV!!Y~BJ`ׯ"Ji@CAC]lxF)t R&ae7@KLw[P?1/hd6mBLr#]sѹ&!FN[ց]"˨i%`1Э*iA< ɁOG [!OI6"큮A4|vk7%$1k%nC7"6kgW1-[83 A{`d}t.Ȉ:;iliA!,b<4Mx8c'ҢYcdY&55D#>!Xbbq8L/f3r:Sk5˺~w_+h/(1U(%"dߏ~Ƽ˞~HAbͿ>7{B툭?¯duu(ޘ5.?y!$~*$!$voAUYo7jipk+<ĵ3KGH &£;6ٗoȪ=T8|||z+hg$.u*ze2slOvӺy~? fH \fH]1 ߚWr_:$.ىjIr"VH@Of4$>B70~d6OB̪܃'/cC` Rꑿj[9k R1t-2 `OF ؖ_icv[(~%XTotI$ıh% Գ#@ /7kέҝuF/UU#p\~ <{ 6#?޴7gTEATĐO F S/;mޫd4CDП# 2SzC xeip rQ_ׇ;.W_^ז0`vWc2go̞2?]ø{1^̾2W{s>:/'GlAcg2;bE}"ߌjd$$uf}?68]x복tiWMϲi!B$^`cIƜow`tC3o xދxug~ُo~@vF<تW hɵ ƽ^:ics?;&IC}k.Ui,Z$vO(FF|\9;,XNLw (Œ ۄwWӡw'SF'SUYU~ǫKع1_p}__BVVS<#*mi1A۞_nȞҬYW%\l?{ Y $[)d6Nۍ\ص7oXD)^J ff7J@JpLRMmbeA`Yta)vlϨ'?@U4Ԙ nޑ\2}{tGS4 &膀a!, {qWvM5-;PTb4j{E#0 d@M@UVkY8c2^QYfŴ9M2ٹ};{ۈM衝thׁ+v-س{sTѰ!Z&9ޅ eҒ{[r9t8λ8'v_rblEfp9l蚊6ʃZ ^}Ф~ dl5e!n@ uM0t$٬ =HH9 ]'&&''wy۩r. ɶHYdͬ]"*B0fE0߷ّe(b:bMFOW&$l+5Ȳj]ב$l[݈/d;M5<[sBegPL!U1D%$I0 4UAHUP6ԧ3EUiߪ%oTtasAt~(.`G3xSِM"a6_}\fbz:G*$uMC `vmMU N` Vu~'F@;uhgMS rbkIeUSH -H&٘DZ4rꆁ ]rRfP%D ,tZ7TFQ'jNGN LrʾeYo()` ')!DACc}E?o-OjD\Z`>}:܂?ɄHd 7yHxAM$KJ0z )I6-X,I\v!+Z ,AİХPdc~UnB[-]\#9ʼH ,X?cnu1Že$6k"䦩TLƪ` ,X`Bx !,pZb ,X *: ӌ;"Za ,X8X ,X` ,X`E,X` i` ,X ,X` ,X`66Dff3O9aNTP'Н hFhِ$WEQT`]7)OPu/ -vفd$ lU4 %DSki$ EUEh`{"d'11$%* (bPT|ʲJ8Fp\%t8PÁp8cGRQRj'#cD (Zo4`w8())ew1 ]7s7J IDAT0@%u\=z\xa * ޟKyy9f\B iJRjÆ_M\\̙3ύr׍M( ѶCԀVqϡǮ'`(ԯ߀ˆ^Nl|e7]'gdI@ST=z"66oXeK))*FQd/`1&3ade YZ߂?4boҾS'?pKYW!'(|,ΚW.g%tbz=Vo6o_|EN9XTD^^.#o^7f5?qEXd4jİaWO˾}X8>-[">>?@ִlCF0DK*l޼O? ,o^Vt:羻r5יsbBeV?sZ(K.^}A\w}v:ʴiNqq QQQX?a! > oe[o׷kl7Fxoe}xg,ѯ^i`L)ҲZ ׮|XIO)-)ASʲJ\Q5%SQQ@ye0nu ]k'.6pOkv1BvǃpHs1 "b`Md {k (lڸVǡC$6iހ-hӖȻt"VI:;?] Fu:ef!I9X3Ph z-"wlr5v$,#Fhn g%i8jnʥ3>cG.- gpNbcc$+)-`<%'W_,iO0躁n?LutkDŽ gi8V8_I36t 4D@$>>=S^^̢şq尫Ds5 PLǦv~w62 qLxv¯Χ.q 6Ow"VbhC]0Ct?0 @h@ZJPDڜ?cK'lv F^=~/ߣTV1 (,o3ꆛC"*$A} Tz-E\o.ѱ ^]3eL8a&E@ ('{זkÆ DmkIE4A8.Es%pwGH(dCvQkر#=& /+WdVR CVtQ 9rꆎ` KCxf[ @ofzb8 ǃ!~fuNA9H3bk\s)؁:hNtKMiڤ v W]9? m۶<<?Я_hz"Zt֎SavwٶmgDCuk릥5!nra`0#i,r:q\E"v\N'vMS~NG(m@ vʲ"*}> fGχ 8f6(tfcFD`0bj`95XpcC8xN ]0 ]0C:<}Ih) BN& vEu+qŖd U7(+.E!w{>W_=t @m2W tBh׮]P>@߾}# W~򬬬r\5 bND5kvr,"V;g#iéZ0IBJKKEdf5%!!2ꧥqavc:4hHQQ6Ąv}{" 2-[ ::YlڴKtl4գUv6!קӮ YY||RRpݸ 7\G  1!F^*$#;9@I)-)a||>$&:'#GRYY4X4hA@Afڵܑn]7g It(v<|c`g! iA!7oLٰa:tIl kRPPjPF0 qx^|>8YTVV0rH?~>^zK3a„ܳf"&&cҠAF͸q2e qqq?>qAONjj*[>8׿k fƍ瞫 s2q*$زe gՌ=3SL!// 0n80a={d,[{1c0i$5kƵ^Kfffd`x8qq2u]WիG^^| ˖-oUSNeͤ 0m4rss#K2Zn6msΥW^4nիWS^^ΠA;v,ƍc4i҄u}laҧHDEE{"͚eE}eҵ[w4Me+`i]-OxAٲm[wo9y Ҩ(S.gM717⊫B22sar:or:qL|n)--En~I~lݺ C7,; gi8Vh7t32,R~#/[ RgԲ)hHi߿3zh:tPdJFU7̠4M٫woUvjq2k'4KJuXt)r 7xc"s1a6nHǎk3g۷onꫯv4_|*n7]v%))}xx'^ફ=r4iwy'[nuиqcԩ,^ KII <#F@QȀ\TTy"Ʋe˘4iR4/OUur9s&,GNN4k֌TZjEZZ˖->`\|Ŭ_޽{3x` tҢEi1b3f`L4ݻw3h ^~e6l@ff&3f`|G,rn0IF%I0/iy!3X]#:A6*Kؙzk9Ǖ+q\ Aԯw}y|>]΀VQ;uȺu#*~\ĽW]y54v㦑㏓'7Iaힰ` bCe sq vƖxAv`$%'po#4]}y#H d SWUƍsM1c [M ryHIuh ֭qq\xhKn9 =!!{˗[o쭷ʶm".M6ӵkfϞ}\͝;x6oY"xk| ڶm! ϯ$R%Fꤺ%I>Ri\p ~%O=3gdǎԯ_8T~˜;wnnbbbƛ6mjךc ]#yزe iiiǵ#ŋ#uw^RRRXb;v䮻_ **h "WZiۚDhV0@fx=4lN4y,1|hKL]vǟFd1}޻#X/i|p!>_UHI"^9|(z[l`ԨMuW1sN?.ǃϯg|yy;ڵ?;{cYk*i8qpaׯΝIOV5uɩСC".lߞKZZqih&&M ?#F\g#E )& jT.WT#FDK̙3;vDZj"9bcc)))f=<5 Oll,~F=qX**ʸsUzń O/"9'B&MLd޽GCk1d4Sghj0(ZOq+%2)/9J0fu3*)1;}byy"\6={y?w&9韸}^3<,y#Ϯ^=;wGaa۶m;NWD&**8rO>3fIk`(xn<* i™o(D(BxCزe#;+; vGq® j>do2TЊ - 4B\hd8/_3L^ )#{šF:Tg@$<? қѧ膛@fMsҹ'EjQ+i+r@YrrZgOFV=ĤYL]` 2ٳf e z_h—,K!eg}R=HпZ&J U@[o#dHGmcڿ!FC]e/װ|G&Aѣ>8yE^^np 8jDffS #7l@bb© %O@Y4 ADh6j+:xdRj^gNO{ !M[IKK#.6ӬЩ۵7-#ؿ?-[ ~C}XGtG׮]P &$fFĺ8D^̐mvbxyT ]eCHvH q v9=4k߸icܹ̝3y~ʲM=Nsu$Xk['L^-g{{;F}{,z,C1HJj2~@bp)*)dŊi֬ 5*kql>|#GFft#Ϛ5M32RX,2W_MEEm۶[n瞯'x<47Q3.>:KY;nq$}/>GۧOoF+WXx8|@2Y2`PS]7ql? ?[RR?g̙3z:B8  7\ϰaW_]t!%3tn"y1e ;0nÌ0]v9]7+VQRR%/cĈk6RURÒb.Di_Kr3^yy0ޫw8G@Fo`G(^~u&Bݐ) 7^Ν?¾D$PUL6帷6>pAgpyaK=r$1-ׄ B\yG zG\{coV Xw\,!H$l6ۯV=XFMHJJBQZif.W4\ɐ@h_InF4U`4 UaV{c=JVV&Æ Q[lٲW_} _aW8| VORRRYr2uֲe9j+֭#iBZ3Ɓju*,'O& m[ L>-MGR'qql2404E p8>ʈ>& d^~ez=h X6zj<O&'MOP^^ɽJ6q8LԩSپ};FĀ%rpAn]|RwˆגP>puXyIzh\OSEj]G={KDՙ3yfsÇ2ct}r|7wywޜxtܙC0Wx|MdȤYf1uZN:#(*`l DZt#4#8Y,ӆn7biwiqNG x 8lz4k0 ***0Zgjnӊ8x~"v@>0 ~}PYF54@d8Nd)"jSO= mۖm 0qD4MEQڴiʹi/՘}ejHh_f,&NyS'G}+_~)vwj| GD', 3h% hFBB"S+rw>fm?UU40?} C'>ޜU~՗>|;Y⩻?@rOC]e ۿ11L<%r_%.[w?McyAkFp5#NXӧW]uҭȇfv!4t9UgeQV^N&TƟdN HϠp~N'=0#r\.YYqŸ(:r?ˮ]P/)YY߳93ѥS0RVt>_#CJj*M(t2eD6*OE,*+e_;{ƓP/V-9XXZ, , Aa7 s;ךҴ;HPkC3Cv&C7O0=+M0,٣׹\2d/pZ zi$cQYUUo_(pH(ƘZ5SX'0F2N*ˉO빚%&$FuE,I'js=\LH&ySLLHQ$pde]GQJJJٳG$dy䡬 IVfDȀ*^N4iM}TT9faHdHCI8U6v ]7}ٻEQx<8e4Dnj @0(8NڶifCu~?{%( ,X8 HCXa! ի@lL)3s@j]4MG ] sWe ن'պ0ьmzmX1zU%)k\'FM>/PvdDŽ>[e5$sBh;!hx|~<>)P< Նa &˪wkn2 ߏ{ٮ:Ƃ iKCWĜ>|ŊU+r80jN=ݞJ7i8B N~ݜP{a=n'^TJK~# /p$ V9v',$ ]t0ںn~Can"0 t* KCNE`MiThjXIi5fx:HDbbi[nGUU3.!䝮fcf6j$±;lCap8fV.;8ʣM6"@ BB|-RHPHq)<$h,M6?OvIp p?}>WΝ9s3g"{t:<~)u7?r@ղa5 g ״c~C ngn+TVBuwk !?ڜCh;?vc ߋ2.)pxkˌim2Yƶ--/=,Q f IDAT;0B8_^]y|n4ۑ_z{M8\%2`dٲ 0a_TH*b}:zB [XduIgR,]!CX ;ݑ7^}]'F~*;%5%?"P@eEB8rWԯX]wu@x9(^XFd UPUUB0mM|ɧD;"8F-,.fV,?Hg SG~ 82 ,Z@}}#F&ɖ)^Qťe 6r}g:;]_WBq74M#и~=eZؐ]}:U5Ѿ;z"#eY$ЧoS]iˀAsB͖L% }`&o漅9F7IOH_B[ ۚ2- #Mm]?*{-Mohmn,p.|/4M12}<џ_:0kb1w?DPV`xG~@TqxrpGƵr>͍cDZ1-kc{eK霔NtO0 IW/յR{A: 1~h[t, Yp^Kt2$Æn\SOqY俜u}YzUN`8BзOD<'0zP;~bki H%d2ildRFzyM@"-+.9ߧWޮYs@yi?XsLcŲh^p>@)~!ׯ/t2w=џw*~ϲ%K\כnI_ή*d';qv×_/s~;:jRq|ι {EQض[!Y3s_w5~͜}YvxqÙ{Yb]vFa]kJȣ|Էwqe=!/>H)U! a6t˲H&9Wh=- x5krGCkk[GN)\wM,Z˗rr pEsO>f܄]9C{/qʠxg馛i\yr5yOytu7ei/]| @?{~t]s㾀tŘwC䙓v \}OKsmz_0w?[»K/_3OO`ٲe1vXhAx<_{‚Bo5tʍάY8I'|9GNf۵.?{6*s2eks-W_u5+- cwޅf H0?Ȣ[́7fru-ԎO$kyѩ~đ| ܍=Yg 6c˗.-8fϙ /éSJ5ְzjwl>;&q‰ϝnkvf">l:k `*F( d/4$ M}%GN:ǽޙń]'`9M#UU)8KNw5j4aĽt޶ΟJ>[ؔΦ~ WbP &E!=ѿ; T!y=8;9,\2ZV< H|@J&\!'Hx*=L&)-+磏?f>c8l."Ǣ-kK(FEQH$I⎥cԓOGK2k6mb/i6~#cdt\QRX]PG4u c t!FH4bI(P?ܖcr2ӌ z7')S0r|8 )<2呜+T:[ NVlX==:^2!vED7Y}At,\BiC2Ms"6/Y `c#ixs2GࣹgiR=E=P;۱\ax\5f5zKvJ6)^~%~;Wahp-(4DuIUTFroS\+B$6w}6Y~I[ _x9w}w.-fBMLg<ʲX4E f֡"'欳bÆƍ^b},_x +2 5?,ƝO̘,[];?aw-ʋ²,7Llw}T;_)&M$86m jN&# EmY9M w5p8̃<1sgnan.ԯY͈aP55k[2iO=l*>]#Ͷyy{џ_8-Z t f[#9Ӻ7$,],kg0hVL}sw7;pW2"{oVCz7[W[zaöbSNqMє-f1-s;.e#V78& A4`;6IŌxBCW} 7ֺ 3z:hgx04gה L3BG]ը±L?@"h(.pYvO{[+x jkjY~b(B |ҕ [u'ꪒi;*PאgE8Ύv;()-cg?^؄^Uva?#>t:M8Ogل[9D::H$H.\",ïJAD"fxutS4+={hkk#`lǜ0p8hNEe% Ls;NFƦw S`f_y})C~K'dt$D qv@ Yp RX\HKkci"kkU{$]SqyHLU(_48G=r3ǟp<H)TUT $JhkmJl&UOyy9d2Z[BeU86 bZH-8hosZho $ّXړh#GކeYзOeJ:p4( ~rd[[A@QkσMxnĵ4t;@G{[eT*eY0Q^Q8D#2>|Bпo_bNt]GuN~;jjj'hn~vlR4}+G TڲEqqp"S~GGHgG.q\MNضa6sc HGBC^۫M׽^JJaa>>{-7??ח#e렩^d E`Z>~- RJȘn6TkOU_ҾFߖyr_"ezNWEkB$n0i^蝏aInxvc= ן0cnO݆ z>MSv}3mKҦPuϯ+(_v,(l;4ui6rw{o0S.Uup6)t\ ;,*cާ }YAaI Ee_E;w.d:vi'o BZ@k{~t(;% 4: 04o#aJz) kКfYc_#m+HpXܐ 5a8 SZ5Y.+XCYy*,Y WlW",ntF-"D,G t2CAPa۾uq&]!ض.҂8 C)=2(R L%i1")_!cڛX"c:ԕX",K;H*|.5 E APW- ѫď-ڦT[tF/&E,5&;\8p65F]ۚ#fёH{oG`b殈ad'۟ҖM0+ô7 |YIGڨ5nW0p.U<6F2-F+ a|FU)%єE_eX*MV6%.e¡3BHa(iKHw* Ӡ`>F@W(H<- Syob~=P^{u^>knH1}s\w=ѥLkwv7Gwy'W_}50 4/$!_ Sw{{S77wT.}J5 tl0mء!iWM1Shd(-Xߑ8H^?kǧ vߺ8 3c GD&#ehSj%b M9}B>XG2j`+$ y&I ܽ:S.7 ݇aOلl/[_XC{St$ L[2~x)o+ۻE!?f#-iܶ}FW?Q33>nf@e_@4aZV7'㸽z3&$-N޿}˃4E vC| GC02lƏ(VfC}GWr6D.-CSs$J :"y&Ro IDATT8LغK;j7c +ЭCjB[e}{r5F~PEDƭkth̶i$b)HݝPpX>M!m |Diɵ}"` ‡!Svh1*TT桷)WHf\ H{2Rabn|q5$6C97ME s6л$%e,ۍTrBBhRrq[cxy͙VFVYŀ>xW^v&79+g=`ٲetIvmky݁Ԡ(/` LY̛ɴ24@ [mXĒK°|^xe^*{;Ml;YKSd2gU'/|$es[S[%vܶō1VJƐt,ʙ.4@miU7a5vp_J4y ]Is$ϧrÈlz'IIK^o`Q / 5mrVmHr˨+ r![b` 8zB ޣC(Bχ0ݱGVpŜ~@歍q3+٪Wgԟ-Q8EtlT8Ё<^FSW>9f°r._}Fs]PCR$>U߳ H*#1-0,(+ѿ*Ob֢6*[@,p*4$SK+KUIQ~w )\u0bI5bēR~ەF~S5Rla!E(Bep)#x}X>^Njԑ!eH۹mQʒtB:H)R0M~1[QԙFw3ipI[3fYq`O sz}n[qу)/(.WAU3w6>Z崻0.ô8v><Gf60>@uAY Xa>*uDknqKk9t*!g?h.!'mHTHelE=067\pG3LS3{Y'\#(t& _%ɥ vۺacZ0nh 5xb9Wq/~S׳]Bo_^L{f>[)b02??{f|ؖDS#"D"~ دilg~aY{wNw} R2}tOuu5RJ͛9ի7j\Ess3{']tӧO'3vX,Xoҥ_NMM7CPĦ*t?H jWk]#D> ,t.|k>8sεDC ٵ6(hlOO~Ɍ=MTyiPR৶4Gb%c昭oJ)5M)[S`;4xt"/Ӑ"^50! |LYƼ;rn$ҮvZVOYGS~plUD6&id‘iӦ-I'T,8}jxka;AAʰh{ޜJuu& | M,feSB4w.-T4t$ T҆kBoJ#+ɰ3EmQXT! >]ɈD>k54EʸߗH#k)|뗐1m.\yVnMIƧ-hH!,_C>J@5,p'͠O!2Й&?k a͝N[gێ.܁m M2գMY*I~ʝ/$ M2mQS꣨@#m7G:H5U8ôO[5Ӗ#1j(sS˹Wvou(UUm:|CS].Q^a5<-y-Lڵ^E>Z"ߏ΄u,gPU8;ר v\ȍ,ǖPW1 l4Cz*#mK$G:?T$zl wX.CKZ,CoٍOEWt F/ WxyU#4ҡoea}6fXN7-c$6a3r@>#QE:8?M$4zSQR\DaA - /T@Ee%XN !ӦM`޼y81O??V\_#2dK.͕{gR^Hhmm%sM71jԨ}'x"sgz3HU@N(dXgHPT+5 DP4N`b[lX@GB:`1WbgUww PU Җ)eX텝9ΔM0I5X߽vKÍ*6鸎݆7DF2wUΔcpiW7-ި縛>)7'x#_2UUPUs߷O{qkdl&. ѷ"D]v$iLYޣ˹.K&~)*Nv3lBHM(5Meq#b0'udҶnMQQ}n]x[i \Q_@vMQHZ6.UV$Ww_pUW4Pל<"kvHB~.?>MҙtyP0 Ҏ*TTuRdhB8d|MS0)9h*vTE:|J?WqЎUUm*U SnmdHv-l$#1-uuP iM4i\r*i>Za`M{E-e]k)~]t$!{_[ I,_xfCఱwN_C20K e5} K'y $26+C3*=UM)yfYѷqKht$OV" ?LMG`pEmIw+{Cc:L K)IkZ\9q߀8&Zt'PKqU<:.xhqnlO*l]>ugbѕ\̪ﵐ9 *yG1Mi#1X/P߄Xh%{> Ķm-ZDYYmm7i$>9ZZZfzޤSK'B2t0kC)+aC EC%Q֋\*|B`zEi˘(˖D&.8uAk-Ep뒆AeLkK>Or?b+|3ճ w<1ybV#jx58fGu[ª}i5޷`MSq=; >MӞȰmb.;r(}C75Ϟ|#&ߘJY.3fk. I$cKctum N.nEpĮ5l7OVuRV@ E I[6aXL~lޫ?'Nͻ sKQU'0H*S% UŜ _t'Aاpn%6΢vlG!1ǵd B0XӒbIC*K9!-7!eZtt&2$&cj~#l'?䣩3tl~S-; -‡HhF ~a!cvsZk!0, :4ѸI0HLYX2m2M,edՙ˴r;v\Ῡ9mx:~)|zh*#! &RI|y:c\mQ}GWR~g} dn56ecE3Hi ˲12Qwo% 船ESVCwB3l/pѥWp72偩|8ww/3?G: tt)ʉ{eG\ F%35W[.hhKJ@RIYHz vYae0B?mAMSTJGԤwYܵ~U!,ˢwYAa(dR6UsulHUmvӨBJ'4E&^˱7ěK8́WQ^b B:|CwEg,C A:Vߎ5šc{&ؾ!?o&SO7P]cv#͠|)DW19)+ywIU:k6$]]crh'9 Yȸ+jNOt&ҜpxÇ4g=ұiYg$+Yג 22(¡X'2uiá$OK-i *QXdǭeX L]Mϭ%5BR_WݿEĒ4᰼1~* zM,i{ ;I8M@ӑc]sPHc@U`g7۶cZ!QGIީ0 (fu,gHM|llM[MSgraMa+QM% v3ɰ0IC?bG0LYӒ̃3{E-Qg GڼVL-edbi94%H~)k2\KmI-jrj" ݤR‘3&j}D9LNЇ$*sefh 86*Qdv+gH)<&777SZZQGŋ2d702N?"aAS{Wlm*A/\hc0Atpy8L^Pgpu>q{;xrN9` qik(nCMI=a\nxv9A%!54w~usk#$2 m)fm/"kU=ZJSSpy;j1) #ʙ8"go0@y{ MBvƽ﾿o>wqx<;Xј(]A;++) )p^uw|B׉WI\ǕVS*f8ؖᷖSUbޚ(cS{dG̈́:Ck vL2m[ئMY~db;P[s /}9XՒbusN٣jKBҥ?09K#K =HP A e~Z:3|,¥GZߖ:"x]S{,5O. [sUx|X>BE?hs~imY`Yc=(0v$/n<) P))6]ŧ7;_Yʵ˓C}s[^\mn8q$vy7OdES<[^XG]zxexFQ\К_Xœtv<^-(۹\z=! [.OTT\qdyq~+()-3Nn0 n{|)׭g穧୹[|duxi,Sλ%ի۷W>a_Wq'jC۟),# H6DER)TEe՚z-&֞^{7 =Ep0s-Lu_1S `޸\^5CI#44r4N4l0,#A:`+@6VaYXDW$MUBqA h9?A miHtq#mp@#aT 4 pn 3w̙3g|{NS&PeSETE!!Y/cuL Cő&.EFM+MĊ/rp"P0eBj;UchaMGV utĥ* YTYB7)qnL4\2*}$uä:uR3Wg(.s+D4+/D'(SQ0 e+E0vZvGiG$UQdnFi䦴"HEm7'0ca1,AV;ΤšUO$`8*Demdǁ넣&>Pj^J8l=SA2 !8JU4v c͒ Et\NE"&Mtz= NU@fWǐq?r<=T  ` 4 @$; *3e>/n~YtE_{3X41Qk!ΌYrxoÿl !~?L?hPX'IH9ޔ-`Jr4VpC$ z4t@SL\5Dc%N#06NgJ8kiZNkʓa躉aH\Ly:xUjj#$edIaZnXCBqHufAK>tKyު )+XCDn]=jIRݵMLV$FI+ֳRHrXuuI^%&LW mEtv]7$3\.9+^l ,=&\ "a]ʈ*NH FHMPQ$ b6x^ Ɋb߿mݿ ix\mIKtsyFt ՔHp[ջO;vqcUvV9&Q,M' KtǸYeȐ"Yք"d5qaVpZ#JZ.7ðfXiLw4MTJemdLDm!77v1v|b'-vPUU%۰VGh0 :HCO'-!0 gִ9N?oKxőz,B2 ȳ?ϰ l5{#I u꟣ę뒒e5]u9h>LǾeS_U345o랉4}\j/3/j/z/kOja6^J=%a+ה4%v5ᇭU&Q5ABjn6 0o ${h_sF/G{6h7bVΧAUjww)ZʣtFtCnvS EjTVA7tOqU\n^2A܁mYAA4))0? Gtn+S1my&BqS01Mǟ a!j Ӡ&`F_jB>(ٳz[\NgǿA%%%޽۷-\GD~7nltyj>\h0![!5~჏>D :J,&N_ilڴ #Z;?>[nK^z|x޽ǺuXb},$''vٴiV8At:IHHkR\\%99D ֭c͚5޽Ϸ׼@xymmmkiOUEM.)9%Hƪ{i |)moFf|Zuƒ%KBxGٲe >0 {,gfq+d*X4mۊxɤAnX[F ?@ c3v7} h4ʈ#˳wbb" a G5O>$> -[wƌ >hFRRV|>_u `\][[K$Ay}8 L$55h4ko~ٯ_?{IIIaڵ4i$P\\Lx<A^x.r)((`˖-x3fNrY*2=z0h VZe޽;_|ݺucСطv=Z^N`0ȫwoA7oϲ:u*=z[n,X޿vZNϞ=ι޽AX"Iz嬩 PS[[CMcw=-RЪxp\̜9޽{3x`VXaE'MD=8s)..y饗86l-(^}U i }g[j\Uygԩ&LꫯfŊDOA 34ɓ'c&7oMdtڕÇrJ^/III%\B)n;NMFAAm۶G`ڴi8NYpp'''( <w={w-܂4M̙CUU(G}\oiӦ|[ ,^^9))I&m{j!ukoUÇNZf&UV S1[@1יFɆ xϹ[kH` 81cc֐A8p GҥK3gs3СC߿?oF܃x<\|7 / ɓ8q"^x!` <0~xقg'/iɔ04K4޹[h۶mc[V6*)))5z駟2bƎ[oc=?nV"mAؼy3'N$еkW<\~L:wy^{k'Ƴ>ڵkE!8TTT4oryqwЬY3F;1b˗/g„ L<>穧b„ \yw}<68@=q-9sm$xG} .[nnquױyfZlɐ!CXx1˖-㤓NS_xW_v-={Z ma_3++_\ve/e˖TTT0`\n믿ޮ/{k]Æ c„ kiX3"ڶkORJZ-5`j|<\~ %%>I {=ք} 'зo_N>d"}./SN9~خq׿2sLN;4>l:t… 1b~M9<\<3N: Yi |v1--_=,P^^i<쳴kMP)SV:h%0 4MtRQQAٴiӑaHn S.Syp{$epBLqg 鰗5C0K,3G"$I(..&//A:˖-#77>EoJoغuݸ̟?|IIIP=z_t7PTTĸqgup%K!=7xb,1o/Xh-CTk\nܸ;4̇=9WVVRZZP(DnL7B +D޽mEM;۶mmڴ٬_q Xd &Mە: ^}]wΝ;QUUwP7LrUW߄=>dYt'ФIϟOnnpPDCy $(M}}UQzt2zb7Ixҭ[76ơoZ+dnikfϞ=O|F_wNAA>vl EQ޽;s=Q綳:?n_}g]~Rz<'|>o=<ѧ XCׂ;p\hۡ=}:T|D -'3h ^z%YmqqOOpt!YXw!tܙz޹s'vPE?RRRoY)M6K.4i҄38öwPkG Jrrr}u-SݺukV^uz/_Ό3yی CE~%CˆC(ʪj+Lre\y'&==Yf?ȑ#2vXGGl߾ݶ4 opw>qN?N^^ tܙ>}rw3όhZVZѱcG9眸ĉ vnO9p=ЦM x뭷uT1c]taĉ̞=O>VZv5j=s饗0k,:ZnMnݸ뮻Xngq}'t-~ا!kIoWu8>!J #3<gIiչAӦM=z4h83)**tңG|`.]J$Xjj*+WdѢEhF^^T_=>/ ʚ5kk… n[ [`?#x<rssiҤ ZbҥxϪU ++˞ѱcG~'vAϞ=Y|d'oѹ`(%%޹ cc9sp\(Kh蚉0hFñZZh~ki]*((`Քxի˨@Q7;e-նm[ѩS')--cOޥ@ @Nذak׮vӽ{w2d 0~ټy3IIItxm=:LdҤI F9h=?4uz֭=$1}tڴi Д@p4;D79!55=zd-Z;o>mo4~ D}D@lI9E4% $Ր4LUvl&:5aÆh}|eeTWU@]70 3838E5jq4;zߟ`PD=E@Ĺϭ$#*~L(%d @,Rnɵ5m+FFl\.?,_&!B!_{bK!fOi  ;`EV=K0 ?7~SR0Mh4J(j`VU|B4o#3<aAdIګh:3α*q> 233IHQ u]4 |I\mn֔@]>1* ~4̛5,0Lt;ഊ6o[[@ سvppq7UHA^V l\nDx> o #->߂D(87dӦ |$Ěw!N40&+2g=Z̧_A((V@ 8EC0D$S].O%1E ~0 JKKʊXdHa?bx<=+sm%ŸN[ySN@II5!Y=PɰMk„ $''s7rJ),,ϷWRnL(6)'0 S_[pm)c!sBt3?l&)11.#Gi&.Ϙ1z^{믿ٳ),,_P=,GȌ )GhHNN&%)$/ڵ?2jJKwY s2.Bvm(]pyӧ5Oaa!-Z8h7EӦMœ?Ds8[ٹkp_󺨍@$dRUSIMMЁ?`0oRn)V\t؆7^iZ'?0~N8hIRRU'@u8hױ'A@kxYW8\$tN3!#Fp<{bذ|Bi&>?.]]nnfd9ٽpr_=`ElժW^yQoƌt8ow}7`Ҕ$]ڿM6>O==G$Ib޼yu]GVVu0 JKcUTVԊ @ _krųŇo,.:1h&;wl*O<ɽIӌlݻbÆȲH Fx'aƍ䐝iINNyyV~1c :?%zٲeI$aԨQL<UUsRRR0u| xX@˖-oӧ \`Hᰘ#dIoF ACEQ9jOR TQ Nq p GH@ 8$`.8w(#DDӨEDH@ AprUU9kWdE"##ܖD!ag!G$`iТoUlذ/|""B  #4!?!!P!+:5Z9S׉DM|nu%|M4ss\~ f)޺d55Ԋ aBfy_3ݷьᰆitH|8BsircW\q rWyY9TTT5R hxB%Dxe8s9: ?/|7Fw uroJHttb,緛ow٪*  bU't!332@pdX4X3X0scθ^r:57/_if{9$I:KT'''O?~Ek ;4nJiqp#ҠJ3i`'KÎ݆uup7s)W<4iBAASN^ -u*q)Nj$7ƥYYY$I\qHDQQ$SOz󫫫0aB}*EQ=rR Q@&@vciQvD?%[sB/[EۜJ/g̞=o41M\~i."(ivZnw\:ڵG^4M:vi\{tЁYfa&/vNN}ͪ*nvQci -[P]]IEywKc ""T95%/HPx"{ǏW2E>c…qx㍼L6 !C0x`*JJJh֬}yǝwɍ7@8fʕ ү[zd8Ϸ{9^yQcI%4p#E4Ky -3E0dIөm?,ӵ~bŊ3)tܙлwoLOxg޽;Fbҥ?mH {[$ M~<*ݍA'RSRiK Gh@ 8DNYw5_Ͽ{fTlmnq7R9w/&oӹsg-[ 8s9f͚i߾=\r )))[N笳΢Gp:^_`ҤI0pݼ1s\r13n *"kM8@ 88sMſFia\fF__ŘaC~Z&kϾ\ve;B<{'aK/߷o_ƌyΦO>̛7$I駟ꫯY(6cCuP0 뮻D{², I@ 8ECy5î'wj2t\Mh)t4gtV#z3<=\=}YRRƩ;5nuu5Ǐ;D !J,BU*+ =â`6o̦MD `+FpŨ}?~<@pDÑJ6mD!Vک@ D@_[r0% Yzx=Q]@  8j4]e|t liM+!Iizr[!G HZ7wYo!2MdS& a&|)@HBB't't/-%@QC=GȺآb% $ahQS&#Q4Tӣ Mө crֲ2`:Mf~:6Fq8ȇ rt80 ; Lyy9EU L,Kel1} bǎ؁sގ;8=X 4sұcǸU0Er4dwt&#ɴaꚽ@ ],v$aV0@8DUe9jBZ*++؍nXݦxpaÆ1vXnvrrrb7>Ɲ$YPc֬Y̙3k7nӧOgݺư7ݻ{ 70i$$IҺuk;/=;>O?W$s[ee%7p={죲cIZ%%L{{v0 6 ,$ n7y9yx|>vW좴m;}vj+&iep{xlmۖn 4YbE\C'gy&WקOJKKyw,fԩL4 ˜9s0M~uֱ~zK&`믿-[`&ij1aLdƍi uʄB!tM##+qH (,@pdZtZχ}@mՖL2ɤY?3))LUUD&811IHOOߧu8Yh>2M,:v$I2o<^n6&OLA駟?[oEjj*]ti4'|?K2o<پ}{%#??k`HEzQUIQkTURCQU0عUU[)7b ]iυ"ӌfqG%995FӬHHLg~v"%%}Y}Yo'y6i2vX.Ӵ_|ɻMoaʔ) пѴz.+W .$++K& -)n>|]q&.MML9Oֲ5{t-* R Fy' ٹy#u***4p$L44 dYpve+WT³TTT:;v$'3oNѦMՀw>3M=n #̺ݢأ {6 nk.^sڵ q$ZhAY|<"( /qIil޼MӦM9ST^#٭$Ӷm[ <.$"(L齃L|z}uv:M1M֯_Y. r1 C׹q>n:jkC Ld̬, ;NF0o@  !1nCU111 ~Ds\la-3fHdn\.'y5+ʗ_YC @-irl# >mDuqC' k$ MAS0MUU)ٱ x<t'I^git}u|>6mo{=R$0p:B!M4ꫯ%`J&a-P$ W*I8=¡ )Ghjq*,cHV,)NIfP j$p\*ߑzB! T?$Gq覉KK#C9F# 41 -9֢ Á-4-KaiZJ ^`&i᎘&`!%IBVddYkWmaؑ2^n2I&T4Ȋ$EHr̩(r4Qh4Ee\N$ret:D"&T4H:(+`%m)_UuJ:ұc'TE%ګ=K*T,_͛7SU^iݍ$'%ӶC{N֡A  2:׮qD)䣏oEZFrے  ?]iHE0 Kye>-[{$ID K,~7dbGu? UUIHH}]#Y/d0,n1׍E[E~,n yy)#aV$KIQꅶp)I2}aȲ, aV9(S7 ]0uO I0A X`w Ŝz"+8U-[m5P:"Ȋ*+_>ٜ ixj5xc Eq;Uj*hhfpĖu$ K}ugԳ4rUQeXYbBh}~ԹUMPNR1ʊJ^A?!)! CeU9`"))h4妺h4($$$xغiY͛ @8]lJN~>`ߏvIFa:N @p$[ڻfiPU` ݻA0 Iٮ22334IҒbֵ fp:|W9 cGq1k֬]D#**w.3a: \% Lfلc ~ˬICCN_AeV$Ez,KIvv6,,16FCH2Hɲ߲vZNha:P ѰIZ:eDCtӤ_Shߊwqy5c۶$^{u Wpn YVYiǍog)ڴӉ.àACHi҄P0hݟ!| 2 @UU,diN($Қ5oŖb4MCN7?:.wnE~Kt^yEڵ⛯ӽW֭ysˮR3cUݗ,v?&$̿؞H$biJ È0֓}zu~\ )E yzNUW**O12q:rB̙1Q-9/`_?cG$קRPp Yh1  ⢋.czE63pP1Ah&bT@ 8BEQC!'( fЪU.yyX8J80BԭE6a;9*B `Ѣ[oCҒdfgQOq(t-:hr]1P/!^  j + pdߢA+2c$ :t"}[.08yp:)^B4 bօD,^,^8<j~ϝmۨaQkp|gt]& @YVјZH8颺 c[PVVFEYi[#_%7nj`ࡄBAdY!1͐ 0 k`&aA7$KSc0 $׏GG(Ws˹(Dh٢sfF3 "0**J05RTUud;Z-|g/!: 1'UY ,Ѡ}0 z`_0u;\dHhƦMDºmP$AQ$ZJ4FӬ󪅭]%t :V8U''#>hʪ <^/hS25Mb o'v&p:4Moʆukضu }R0N k яebzS]NDCBR0!n?6iYh4J~VoաZhYaՄB$x?|LCp8L( ͥ]o݂P1TT{^NS@eykWF֭kMޗi4LLn.t0kH8B8&5{wY4oe vB"Z/?Mٵk[lႋE4t=b9ꚎaDn=}1S֫'ׯ'9i׊K& ;syL( VU[VZVz@{mmEm->zVUk:_j"0@Hxs}rH4LI@'gֻzzod0/"ٴx;3N鴅V2&O坵o)+̴ipc4{QA ;~W\# ݫHzʨLZki\S>J}}-15,LtшȣDHD"̚}"hXBJt`Pviw(cJ̓Oz55DtЬm1uƬL{LG~ imoE &77xk d&FJ|mhqSOkm 璝z477u::# )|^*6Ӿ.(DlqvP# Zn~}sah4edeeepS)Ǝ~Z3'J%B XP"D"SŠ>ƸGGkһ ]wm0&OI$!#~‰r]2bR ep?^84}{mZX~@*Րn3N_Y K6KR$ ZZ2O{ttt}8B;n mD"Чe>\_؂ q֬YorlR..UHtt+Hvxeg+>z|ϣ?;R]=m۶bwYItMQ+{7mO wfg  6HP1 0 [k>$RPXܧ~ߋ;>FGm۸qʐ;scEIy#$]P瀻J B?yG5gFÛWnۜS[4.4B::mc{;4O-nLAΙ~<8/ KJ̙gňb} ] IDAT͜:,#a#v*Z#A?d!:<'; Mcv>vV^4038)C8!Vp5H'=D"rw(?JA֔2g(9neSEHm :TVWRW[KN^.w_`uӋN(*-]z*6oDnA> lfW8- v {FVvΎRA@,`Φ5NVVt50eLzό;X,GYP_OmVqmnay3ȝ-_gs>mf!\4//_ %Ѕh,y?fhz>btew(6<iXJSYYEQiZ ԅ ,d2M4e9mZ-[nXPXP³!+o1s1$IyR0EvVN&sS\[nAyy( > C2Bp>%AY\y7qݽBܫ9 =4xrFk0Pu[P3k1GtOGM%L:n*6l`2A*R Qy6Af|WNScsb u.[`6erdšmb A_ZA  hAAD  "AA  !#&A8QXm`Rv1$A'(bCC"‰:jb) cq Ž&J)RIT*֕ p؊OO`skhlm#*PD#C 9̛:& !+;oeㆍh`h!H$ByPNw '͝ ƄAD ¡CQl x/+ݾ $k{Wps>Ucu.MYYǒ{/O ͒Ѭ(N8 0{YJZ&B EDyo^"!ͨCY|g/.JA$K~"!MVV6nx{ AcwƘnP L?_=M$jCH7nxl7kl PV˲uE4 Oz`dE2mc 2gjEGK{ۚGo#8 3s)yxFs{+,tF#A 1#lb~0]9Xzyj;;߮!fQYpD JFf~z#ǍdpQ-J ƶ~6V= 9٥~ߟR|q,Bp^ǝEW"D4 (CWGVdž>GV۞"fSc% x@FݖpYZYG3t(>q u0 5kc臍,;m.6s er˙:uNp hA8nz{/>CH\~fh"M,0m Ɩv:QjqXS|nNdrqB?bP6lH Zq;W9[k +-m{X?y1=+e:\ d,j8K=rgؘ*1Lge[=yҎ`8SQJ1tP/_37mDuu5Vs[2G:'>2_qG 0,FO`>⭘g4y]6sDj73qyp c]}v&UUUWDA/RXV4-vS\~ \yƧQc;l<|6s ,`ʕ,_ٳgOr)n:>,Y a׿ĉ۶X!,Ӱ {Yqfͧc{A~%t$b7QUe#0+'?? ^yZ[[K1cg}eɾ}= aW|Ǣ3򓥯r')R)hN;&]veL2{ '2af̘1*ƍ9^z3fdZ{Zlaߗ3d{bбlE {MjC8E_|R+kv)eφNncĈk˖-/k3_|EfΜu]ǭ|kkk2dl۶ e˖qMO<& EAA(]So]+~/߿x-,;DmM,8hl4j8)hfow}7>l#L>=󾤤^{ѣGnݿ9`0٩)~X)q FV\*T_m\Oopu(Z?7G ?HQPO=[]D##Mv T*́XE4, 摌C p mVXU!'Ӣ!ĀiӦbŊs_|#Fc3755LvtqE8Nc=z4 urJ dwM`(16]UD kP;)^*r[o\sڹT5,1 O/F3үϠP#F[sfՏ%H1ưp;5wu'뛚ÕW~~)cǎ{ /hrͺoГfh {ۯmwl[t' 7]\T.PsNC-**/NJeÅ^߼&s !2~TT E)ŤIǒOf7@CCÎJOv뮦$ phjvczl8DW ;3y3Mڧ=NNn>o6/&LAϟ&.2.y\p\p޵۷"AK>qB޽"]z/bauzreUhZ4~ŖErPSOѧOaeͶm[y0a?TTTPSn ^Ew ޻cy]wt28o~|ljPWW}{y{yvl tAڀꋳU ?дvs8eX;^vC+[n- ;]R , ੧k c4N$ʅ^DKK>AݸΉ 'Ϝ/>ʦ)k&;!'uM0DT'z8(-)uݶ= pH ICWJa&LP$//-j{wk"M,'mňfe禸kkwQdxh|Б֤RIt,`_=FDQގK4C'VfȷmR "AxC:ާAxԐĶ |8kq=7舅t4,l)۠j hP{2|fCMG}a!57^[b?ߠdvvi ̐x2E_ŅǗ1iy<:пwACZ/d" =b6MXh\JR.~S,"(d^J)@c̿UGcB9 i{H$Q˪#dy;׼ {U+rZ;Q6 sX9FBTHhA81Zh*,,EVv699tUH~ECi=㹻KDS>f4ʢD C{GT2A2JiAV8~o`(+PFaTm[aġ' '%Z=1uea'BanCF8 R&aMۈ'tW1`::Ygc[~'i(eL$dxBP$A;N[a+էc kh ƐJ%q]˲ILF뉜"Ax߅c߉mv$΁[H/AAD4  AA  hAAD  "AAD4 gd;eee-AcˉuAAͫfJJJ

The Browse mode screen is shown below:

This screen provides an interface to Add, Copy, Edit, Delete, Import, and Export various database records.

By default, only the databases that Barry recognizes are shown in the list on the left, but by clicking the Show All Databases checkbox, this list will expand to include all available databases.

For the Address Book, Calendar, Memos, and Tasks databases, it is possible to edit the records directly by double clicking on them, or pressing the Edit button.

The Import button supports importing a vCard or iCalendar record, such as those attached to email by some mail clients. The Export button does the reverse.

For the rest of the databases which do not have edit dialogs available, it is only possible to use the Delete button. barry-0.18.5/doc/www/php_conf1.php0000644001161500056700000000032612242254476016234 0ustar cdfreycdfrey barry-0.18.5/doc/www/cvs.php0000644001161500056700000001531012242254476015151 0ustar cdfreycdfrey

See the page for detailed information on the software that Barry needs.

There are 2 ways to get the source code:

There are multiple source packages available on the Sourceforge download page. The main tarball is always the tar.bz2 package. This contains everything in git, as well as pre-built configure scripts and pre-generated HTML documentation.

The same development tree is also available via git, and can be browsed on the web at the Barry git page. You can clone the repository like this:

	git clone git://repo.or.cz/barry.git barry

This will place the Barry sources in the barry directory. To update your source tree periodically, do the following:

	cd barry
	./buildgen.sh cleanall      (optional)
	git checkout master
	git pull origin

If you're using a development tree, you'll need to build the usual ./configure script before you can proceed. To do this, you will need autoconf, automake, and libtool as stated on the dependencies page. The correct sequence of commands to build ./configure is already stored in the ./buildgen.sh shell script in the root level directory of the Barry tree.

	cd barry
	./buildgen.sh

At this point, or if you are using a source tarball, building Barry is a matter of the common set of commands:

	./configure
	make
	make install          (possibly as root)

The top level configure script also has a number of additional sub-package options:

  • --enable-gui - compile the Barry Backup GUI
  • --enable-desktop - compile the Barry Desktop GUI
  • --enable-opensync-plugin - compile the Barry plugin for OpenSync 0.2x
  • --enable-opensync-plugin-4x - compile the Barry plugin for OpenSync 0.39/0.4x
  • --enable-boost - include Boost support in the btool utility
  • --enable-rpathhack - if specified, uses a libtool hack to disable rpath during the build

If you want to generate doxygen documentation, run 'doxygen' from the root source directory. The resulting files will be in doc/www/doxygen/html/. Doxygen 1.7.1 has been used to do this, but presumably more recent versions will work as well.

An example that will build everything, including the Boost features in btool:

	cd barry
	./buildgen.sh cleanall         (start with a fresh tree)
	./buildgen.sh                  (this creates configure)
	./configure --enable-boost --enable-gui --enable-opensync-plugin \
		--enable-opensync-plugin-4x --enable-desktop
	make
	make install
	doxygen

This will give you a set of command line tools (bcharge, btool, breset, bidentify, bjavaloader, pppob), as well as the backup GUI (barrybackup), the Desktop GUI (barrydesktop), and will install the opensync plugins into the system directory for opensync plugins (usually /usr/lib/opensync/plugins). Available man pages are also installed.

The makefiles do not install udev rules automatically. There are sample udev rules files in the udev/ directory. For a Debian system, copy the udev/debian/10-blackberry.rules file to /etc/udev/rules.d/10-blackberry.rules, and copy the file modprobe/blacklist-berry_charge to /etc/modprobe.d/blacklist-berry_charge.

	cd barry
	(become root)
	cp udev/debian/10-blackberry.rules /etc/udev/rules.d/10-blackberry.rules
	cp modprobe/blacklist-berry_charge /etc/modprobe.d/blacklist-berry_charge

Make sure that bcharge was installed to /usr/sbin. If you used a different --prefix option on the ./configure command line, you will need to update your 10-blackberry.rules file to match.

The source tree comes with sample PPP chat scripts for using your Blackberry as a modem. These sample scripts are located under ppp/ in your source directory.

The binary packages install all the ppp options files under /etc/ppp/peers/ and all the chat scripts (with the *.chat extensions) under /etc/chatscripts/. These directories are important, since the pppd program expects to find options files under peers/ and the options files reference the chatscripts.

Copy the above samples to their appropriate directories to install modem support for your system. Make sure you have pppd installed as well.

If you install Barry in a location other than /usr, you will need to edit the options files to correct the hard coded paths in these files. The files assume that pppob is located in /usr/sbin/pppob.

See the page for more information on using your Blackberry as a modem.

Paul Dugas reports on the mailing list that he uses the following steps for building RPMs from git:

	$ cd ~/work
	$ git clone...
	$ cd barry
	$ ./buildgen.sh
	$ ./configure --enable-gui --enable-opensync-plugin
	$ make dist
	$ rpmbuild -tb barry-0.13.tar.gz

	I prefer running rpmbuild from the tarball as it's typically the way
	non-developers would build them.  I have ~/.rpmmacros setting %_topdir
	to %(echo $HOME)/.rpmbuild so the RPM building can run as me and not
	root.  The resulting RPMs end up in ~/.rpmbuild/RPMS/x86_64.

On an RPM based system, install rpm-build and rpmdevtools, then run rpmdev-setuptree to create an "rpmbuild" directory in your home directory.

Once you have ./configure generated as detailed above, you can create Debian-style binary packages for your system by running the following:

	cd barry
	fakeroot -- debian/rules binary

There are manual sub-targets in the debian/rules makefile to build binary packages for the OpenSync plugins, which you can invoke as follows:

	fakeroot -- debian/rules binary os22-binary

	or

	fakeroot -- debian/rules binary os22-binary

barry-0.18.5/doc/www/troubleshooting.php0000644001161500056700000000442112242254476017606 0ustar cdfreycdfrey

Q: When I run btool, it hangs for 30 seconds and then times out on the USB read call.

A: To verify that you are experiencing the right issue, run "btool -vl" to get a verbose USB log. At the beginning the USB configuration and endpoint information is printed. If the last set of endpoints have 0's in the values, you are experiencing the problem. The proper set of endpoints will not be displayed with "lsusb -v" in this case either.

One workaround is to run bcharge twice like this:

	bcharge
	bcharge -o

After the second bcharge, btool should work normally.


Q: I've installed Barry, and bcharge is set to run automatically, but as soon as I plug my device into the USB port, the device reboots.

A:Make sure you're running a recent version of Barry, at least 0.16 or 0.17.

Depending on the age of your kernel (older than 2.6.34?), you may have the berry_charge kernel module running, in which case you need to choose which method you wish to use. Do not run both berry_charge and bcharge.


Q: One of the Barry applications crashed, and now I keep getting a Desktop error message in hex.

A: If a Barry application crashes, that means the Desktop mode was not shutdown properly. Your device will likely appear to still be "busy" as well. Currently the only way to fix this is to reset the device, either by unplugging/replugging it, or by running the program "breset".


Q: Everytime I restore a backup with the backup GUI, the database I need does not get restored. What gives?

A: Both the backup and the restore are filtered based on your configuration. Check your Edit | Config... settings and make sure the needed database is turned on in both backup and restore.


Q: I ran the backup, but can't find my backup files! Where did they go?

A: The backup program saves all backup files as gzip'd tarballs under your home directory: ~/.barry/backup/pin_number/

Each backup session creates a new file, named with the pin number, date, and time.

barry-0.18.5/doc/Hacking0000644001161500056700000001657112242254476014322 0ustar cdfreycdfreyYou want to help? Excellent! ----------------------------- Barry currently only supports about 3 database record formats. A database dump reveals over 50 different databases types, and you can help code these. Use the following command to dump the Database Database to stdout: ./btool -t Pick a database you are interested in, and run the following command to dump the protocol to stdout: ./btool -v -d "Memos" Protocol Documentation: ----------------------- Once you have the raw protocol dump, you need to reverse engineer it. There are a number of places you can find documentation on this. The original source that I started with was the Cassis project docs. You can find them here: http://off.net/cassis/protocol-description.html While these docs are quite helpful, they only cover the serial protocol. The USB protocol is more data-block based. There are no checksums, since USB provides a reliable data transfer. The common protocol headers are struct based, until you get to the variable sized data. (This is also struct based, but requires pointer arithmetic.) See the following Barry source file for protocol structure information: src/protostructs.h Protostructs.h -------------- These structures are all low level in nature, and MUST be packed. You will notice that every struct in this header is flagged with the gcc extension "__attribute__ ((packed))", which makes it useful to apply structure to raw protocol data. You can build / deconstruct a protocol packet in this manner: Imagine you have a packet of raw data in the following buffer: char buff[4096]; You can apply the Packet struct to it directly: struct Packet *packet = (struct Packet *) buff; Looking at the structure, this gives you a lot of fixed-position data: /////////////////////////////////////////////////////////////////////////////// // Main packet struct struct Packet { uint16_t socket; // socket ID... 0 is always there uint16_t size; // total size of data packet uint8_t command; union PacketData { SocketCommand socket; SequenceCommand sequence; ModeSelectCommand mode; DBAccess db; uint8_t raw[1]; } __attribute__ ((packed)) u; } __attribute__ ((packed)); In the case of database records, you are interested in the DBAccess union member: /////////////////////////////////////////////////////////////////////////////// // Database access command structure // even fragmented packets have a tableCmd struct DBAccess { uint8_t tableCmd; union DBData { DBCommand command; DBResponse response; CommandTableField table[1]; uint8_t return_code; uint8_t fragment[1]; } __attribute__ ((packed)) u; } __attribute__ ((packed)); When downloading database records, they all arrive in a DBResponse packet. struct DBResponse { uint8_t operation; union Parameters { DBR_OldTaggedRecord tagged; DBR_OldDBDBRecord old_dbdb; DBR_DBDBRecord dbdb; } __attribute__ ((packed)) u; } __attribute__ ((packed)); Depending on the command you use, the format of the record will change. Also, newer versions of Blackberries have new "GET" commands that return a slightly different record header. Barry currenly uses the "old" command, which is supported by all USB Blackberries tested so far, so it has the greatest compatibility. Some database records are tagged with a unique ID. These databases include the Contact records, Service Book records, and Calendar records. This allows for intelligent syncing, as Barry can reference, update, and delete records individually instead of a group. struct DBR_OldTaggedRecord { uint8_t unknown; uint16_t index; uint32_t uniqueId; uint8_t unknown2; union TaggedData { CommonField field[1]; } __attribute__ ((packed)) u; } __attribute__ ((packed)); This is enough information to get you to the data you need to reverse engineer. That data will be located at: packet->u.db.u.response.u.tagged.u.field[0] So, taking an Address Book record as an example: 00000000: 06 00 37 00 40 03 44 00 08 00 80 82 b1 22 00 06 ..7.@.D......".. 00000010: 00 20 43 68 72 69 73 00 05 00 20 46 72 65 79 00 . Chris... Frey. 00000020: 14 00 01 63 64 66 72 65 79 40 6e 65 74 64 69 72 ...cdfrey@netdir 00000030: 65 63 74 2e 63 61 00 ect.ca. We now know: 06 00 - packet->socket 37 00 - packet->size 40 - packet->command 03 - packet->u.db.tableCmd 44 - packet->u.db.u.response.operation 00 - packet->u.db.u.response.u.tagged.unknown 08 00 - packet->u.db.u.response.u.tagged.index 80 82 b1 22 - packet->u.db.u.response.u.tagged.uniqueId 00 - packet->u.db.u.response.u.tagged.unknown2 06 00 - packet->u.db.u.response.u.tagged.u.field[0].size 20 - packet->u.db.u.response.u.tagged.u.field[0].type ... - continued data from sequential CommonField packets Note that CommonField packets are variable size, so you can only use field[0] the first time. You'll need to do pointer arithmetic to calculate the start of the next CommonField. This is a common theme in the database records. There is a static header (eg. DBR_OldTaggedRecord) followed by a number of fields, which each contains a common field header (eg. CommonField), followed by a variable sized block of data (CommonField's u.raw field). The next field starts size bytes later, and so on. This should give you enough information to begin hacking on additional database records. Once you have a "Record" header struct, you are ready to begin parsing into an API class. Record API Classes ------------------ Record API Classes are intended to be consistent, C++-friendly structures for storing the parsed data. You can find them in: src/record.h These classes may be broken out into multiple files someday. The requirements of these classes are as follows: - no virtual functions - must be valid STL container items - generally contain all public data - provide member functions for: - dumping to ostream - parsing downloaded data blocks from the BlackBerry - building data blocks for the BlackBerry for uploads - must have absolutely no low level protocol contamination The final point deserves some commentary. When using gcc-specific extensions like __attribute__, and when using pointer arithmetic and pointer casts across types, as is necessary in some of the low level parsing code, special compiler flags are required. Specifically, g++ requires -fno-strict-aliasing to stop it from optimizing away some of the pointer casts and data accesses. This is not desireable in an end-user application, so care must be taken to hide all low level parsing in the library, while exposing the record class structures and member function APIs to the application. Therefore src/record.h (or any new record header you add) must not include src/protostructs.h. Your .cc code may include protostructs.h, but not the header, which will be used by the application. Good luck, and happy hacking! October 2006 barry-0.18.5/doc/servicebook-notes.txt0000644001161500056700000000764012242254476017232 0ustar cdfreycdfreyThese messages come from these threads: http://sourceforge.net/mailarchive/forum.php?thread_name=20060610014753.GB27404%40foursquare.net&forum_name=barry-devel http://sourceforge.net/mailarchive/forum.php?thread_name=20060616183827.GA31426%40foursquare.net&forum_name=barry-devel From: ron@rongage.org To: barry-devel@lists.sourceforge.net Date: Thu, 15 Jun 2006 15:52:18 -0400 Subject: Re: Service Book parser Quoting Chris Frey : > On Fri, Jun 09, 2006 at 10:29:57PM -0400, Ron Gage wrote: >> Type: 0xa3 Data: >> 00000000: 4e 00 00 00 N... >> Corresponds to User ID > > Is this a string that you entered? My test blackberry doesn't show > this type. The UserID is now confirmed to be an index value into the SQL database. This value directly corresponds to the ID field in the UserConfig table on the BesMGNT database. More later - the UserConfig table appears to be the big one - where the crypt keys are kept amongst other things. Digging deeper... Ron From: ron@rongage.org To: barry-devel@lists.sourceforge.net Date: Thu, 15 Jun 2006 15:31:03 -0400 Subject: Re: Service Book parser Quoting Chris Frey : > On Fri, Jun 09, 2006 at 10:29:57PM -0400, Ron Gage wrote: >> Haven't had much chance to correlate this to all the Service Books yet - >> it IS getting late here... >> >> I have partially decoded the Desktop[CICAL] Service Book: > > Thanks! > > Btw, What is a DSID? > Not sure at this point. Possibly crypt related. Just reporting what is on the screen of my 7290. > >> Type: 0xa3 Data: >> 00000000: 4e 00 00 00 N... >> Corresponds to User ID > > Is this a string that you entered? My test blackberry doesn't show > this type. Probably related to the user id index on the BES server. UserID on the service book page is a straight forward integer. > > >> Type: 0x6 Data: >> 00000000: 53 30 30 30 30 30 30 30 S0000000 >> Corresponds to UID - aka the SRP of the BES server > > On my test device, this shows as "ff ff ff ff" in all records. > > Is your test device registered with a BES server or with BB's internet service? Ron From: ron@rongage.org To: barry-devel@lists.sourceforge.net Date: Fri, 16 Jun 2006 15:51:26 -0400 Subject: Re: more ServiceBook parsing Quoting Chris Frey : > Hi, > > I've committed some more code to CVS to parse the service book fields. I've > tested this against a 72xx device and an 8700r, and the type codes for > similar fields are different. > > I just noticed that the large "type 0x9" field has more variable length > fields inside it. I'll have to parse that out as well. > > - Chris > Even more on the 0xa field... On my BES server, with probably 2-3 exceptions, all users have this same value in bytes 4-12 of the CurrentKey field. A capabilities field perchance? From: ron@rongage.org To: barry-devel@lists.sourceforge.net Date: Fri, 16 Jun 2006 15:30:29 -0400 Subject: Re: more ServiceBook parsing Quoting Chris Frey : > Hi, > > I've committed some more code to CVS to parse the service book fields. I've > tested this against a 72xx device and an 8700r, and the type codes for > similar fields are different. > > I just noticed that the large "type 0x9" field has more variable length > fields inside it. I'll have to parse that out as well. > > - Chris > > More on the significance of the 0xc data type (it's nice to have access to a BES server, with credentials to the SQL database...) In the BesMGMT database, in the UserConfig table, there is a column (type varbinary[72]) called CurrentKey. The value in the 0xc data type corresponds directly to bytes 4 through 12 of this CurrentKey value. Data type 0xa3 is listed on the handheld as "UserID" - this value directly corresponds to the "ID" index value in the UserConfig table of the BesMGMT database on the BES server. Ron barry-0.18.5/doc/TimeZones.txt0000644001161500056700000000522012242254476015476 0ustar cdfreycdfreyThe following is a list of codes for time zones on the BlackBerry. It was reverse engineered from a BlackBerry 7750, v4.0.0.171 (Platform 1.5.0.30) Record #5 in the "Options" Database contains the device's time zone code. -------------------------------------------------------------------------------- Code(2 bytes) Name Zone Offset ------------- ------------------------------ ----------- 0x00 Eniwetok, Kwajalein -12 0x01 Midway Island, Samoa -12 0x02 Hawaii -10 0x03 Alaska -9 0x04 Pacific Time (US & Canada), Tijuana -8 0x0f Arizona -7 0x0a Mountain Time (US & Canada) -7 0x0d Chihuahua, La Paz, Mazatlan -7 0x21 Central America -6 0x19 Saskatchewan -6 0x14 Central Time (US & Canada) -6 0x1e Mexico City -6 0x2d Bogota, Lima, Quito -5 0x28 Indiana (East) -5 0x23 Eastern Time (US & Canada) -5 0x37 Caracas, La Paz -4 0x38 Santiago -4 0x32 Atlantic Time (Canada) -4 0x3c Newfoundland -3.5 0x46 Buenos Aires, Georgetown -3 0x41 Brasilia -3 0x49 Greenland -3 0x4b Mid-Atlantic -2 0x53 Cape Verde Island -1 0x50 Azores -1 0x5a Casablanca, Monrovia GMT 0x55 Dublin, Edinburgh, Lisbon, London GMT 0x71 West Central Africa +1 0x6e Amsterdam, Berlin, Bern, Rome, +1 Stockholm, Vienna 0x5f Belgrade, Bratislava, Budapest, +1 Ljubljana, Prague 0x69 Brussels, Copenhagen, Madrid, Paris +1 0x64 Sarajevo, Skopje, Sofija, Vilnius, +1 Warsaw, Zagreb 0x8c Harare, Pretoria +2 0x87 Jerusalem +2 0x73 Bucharest +2 0x78 Cairo +2 0x82 Athens, Istanbul, Minsk +2 0x7d Helsinki, Riga, Tallinn +2 0x96 Kuwait, Riyadh +3 0x9b Nairobi +3 0x9e Baghdad +3 0x91 Moscow, St. Petersburg, Volgograd +3 0xa0 Tehran +3.5 0xa5 Abu Dhabi, Muscat +4 0xaa Baku, Tbilisi, Yerevan +4 0xaf Kabul +4.5 0xb9 Islamabad, Karachi, Tashkent +5 0xb4 Ekaterinburg +5 0xbe Calcutta, Chennai, Mumbai, New Delhi +5.5 0xc1 Kathmandu +5.75 0xc3 Astana, Dhaka +6 0xc8 Sri Lanka +6 0xc9 Almaty, Novosibirsk +6 0xcb Rangoon +6.5 0xcd Bangkok, Hanoi, Jakarta +7 0xcf Krasnoyarsk +7 0xd2 Beijing, Chongqing, Hong Kong, Urumqi +8 0xd7 Kuala Lumpur, Singapore +8 0xe1 Perth +8 0xdc Taipei +8 0xe3 Irkutsk, Ulaan Bataar +8 0xeb Osaka, Sapporo, Tokyo +9 0xe6 Seoul +9 0xf0 Yakutsk +9 0xf5 Darwin +9.5 0xfa Adelaide +9.5 0x104 Brisbane +10 0x113 Guam, Port Moresby +10 0xff Canberra, Melbourne, Sydney +10 0x109 Hobart +10 0x10e Vladivostok +10 0x118 Magadan, Solomon Islands, New Caledonia +11 0x11d Fiji, Kamchatka, Marshall Islands +12 0x122 Auckland, Wellington +12 0x12c Nuku'alofa +13 barry-0.18.5/doc/VersionNotes0000644001161500056700000001051512242254476015404 0ustar cdfreycdfreyPreamble -------- Barry is primarily intended to be a library, for any application to access Blackberry devices. There will be an OpenSync module built on top of this, plus some command line utilities, and a GUI, but initially Barry is a library, and must be versioned accordingly. Additional applications built on top of Barry may be versioned separately. Since Barry is a library, applications need to know which versions they are compatible with. Unix has a version number scheme for this already. History ------- Initially, I had tried to use the old Linux kernel style of version numbering. One series of version numbers for development, and one for "stable" releases. Linux has since abandoned this versioning scheme, and after reality has bumped me about, I'm about to abandon it too. The reason is that all of Barry's releases are generally stable. They are expected to work on all systems, even in the git tree. People run Barry from the git repositories regularly, and often the code in git is more stable or feature complete than the released tarball. The goal of Barry's development style is to always be stable. Every commit should compile. Every commit should work with all devices. Every commit should be examined closely for security issues or buffer overflows. It should be possible to take a snapshot of Barry's source tree at any time and use it. Indeed, Barry's versioning over the past few years since 2005 has indicated this philosophy. Only 16 versions have been released, from 0.0.1 to 0.16. The development has been linear, and while there have been some large changes to the library and tools (such as the introduction of optional threads) this has not impacted the stability of the library. Most issues in Barry arrise from udev permissions problems or interactions with unknown parts of the Blackberry firmware. There was only one release that was specifically to fix a bug in Barry itself. (Version 0.11 which fixed a null pointer bug in 0.10, and which was released the day after.) So in the end, Barry is retaining a versioning feature it does not need (unstable and stable lines of development) and ignoring a feature it does need (library versions that indicate backward compatibility). New Direction ------------- To fix this, we're going back to 3 number versioning, but with a twist: logical.libmajor.libminor Logical now becomes something of an advertisement. When we have sufficient features, we can call it version 1. Until then, we remain version 0. Libmajor will start with the old minor, at 17. It represents a compatible library. All version 17 libraries are linkable to applications that depend on them. Libminor will represent releases that do not affect binary compatibility. So the first version using this new scheme will be version 0.17.0 and the libbarry.so will be named libbarry.so.17.0.0, libbarry.17.0.1, etc. Managing Version Numbers ------------------------ Any changes in the following areas require a bump in libmajor: - removing: - a standalone function call - a member function - a member variable from a class - a global variable - changing: - the arguments in an API call - the size or name of a member variable - the size or name or a global variable - the virtual-ness of a member function - adding: - a member variable to the middle of the class - moving: - a public element from one namespace to another Any changes in the following areas only require a bump in libminor: - adding: - a non-virtual member function to a class - a standalone function call - a global variable - an entirely brand new class - changing: - the internal implementation of a non-inline function - any class or function, in any way, that is not BXEXPORTed - any non-library code As you can see, most of the time we'll be bumping the libmajor version anyway, just like we've been bumping the minor. But at least now, distros and library users can separate Barry library versions, and safely install multiple versions of the Barry library on their system at the same time. This version scheme will in no way impact the freedom to change the API. If the API needs to be updated, we'll bump the libmajor version with impunity. If you have comments or suggestions or bug reports with regard to Barry versioning, please post to the barry-devel mailing list. Chris Frey October 2010 barry-0.18.5/doc/ReleaseChecklist.txt0000644001161500056700000001052312242254476016775 0ustar cdfreycdfreyBarry Release Checklist: ------------------------ - bump version numbers in Source locations: - configure.ac (2 places) - gui/configure.ac - opensync-plugin/configure.ac - opensync-plugin-0.4x/configure.ac - desktop/configure.ac (2 places) - libbarry*.pc.in (renamed for major version... also, requires version changes inside those .pc files, in the Requires: field) - if renamed, update following: - Makefile.am (root dir) - all configure.ac files Documentation: - doc/www/index.php - Doxyfile - update root README file as necessary Binary packaging: - rpm/barry.spec - debian/changelog - debian/control (major version only) - debian/libbarry*.* (files need to be renamed) - debian/rules (the barry18 includedir) - debian/*.lintian-overrides (major version only) - opensync-plugin/debian/changelog - opensync-plugin/debian/control (libbarry-dev) - opensync-plugin-0.4x/debian/changelog - opensync-plugin-0.4x/debian/control (libbarry-dev) Languages: - files under: po/ gui/po/ desktop/po/ desktop/po-osyncwrap/ opensync-plugin/po/ opensync-plugin-0.4x/po/ Misc: - android/jni/barry/config.h (multiple version strings) - wince/.../config.h - test/nightly.sh - tests in following order: - run 'make update-po' periodically in each po directory to update translation work - test ABI / API and bump major or minor version as appropriate - run tests under test/ - starting from a fresh sid base, test build-deps, build debian packages, and run sid lintian (only sid, since overrides in Barry are specific to sid): lintian --info --display-info --pedantic --color auto \ *.changes *.deb *.dsc - double check hardening on sid: hardening-check tmp/usr/bin/barrydesktop hardening-check tmp/usr/lib/libbarry.so.18 - between both, should show all options enabled - run binary-meta release build test (remember that chroot builds need a password, so run them first if running a batch) - write release notes, including contributors, known issues, new features and bugs fixed - include mention of distros that support Barry: (see AUTHORS file for distro list) - include description at the top of what Barry is - web docs: - update known issues list - check that all external links work, and point to proper content - upload latest web docs to netdirect project page - run: ./static.sh netdirect - upload latest doxygen docs to netdirect project page - snip this version's git shortlog history into its own file - sign-tag Barry git repo and binary-meta git repo with latest version - no need to run maintainer/tagged-release.sh since you're maintainer now - manually push git tags to repo.or.cz and sourceforge.net - create binary-meta tree under dists/, and debian source packages and tarballs, including binary-meta tarball, under sources/ ./make-apt.sh bmbuild ./make-yum.sh bmbuild ./make-slimdist.sh bmbuild - upload above tree to SourceForge ssh -x -a -2 -t USER,PROJECT@shell.sourceforge.net create then use sf-help for details MAKE SURE that the tar source files are under /files/barry/barry-{version}/barry_{version}.tar.gz, so that debian/watch remains accurate - upload binary packaging metadata to download.barry.netdirect.ca under a versioned directory (eg. barry-0.18.0/) and update the barry-latest symlink - remember to run make-redirect.sh for both the new release dir and barry-latest symlink For example: ./make-redirect.sh bmbuild /barry-0.18.3 http://sourceforge.net/projects/barry/files/barry/barry-0.18.3/bmbuild ./make-redirect.sh bmbuild /barry-latest http://sourceforge.net/projects/barry/files/barry/barry-0.18.3/bmbuild - add the new release to .htaccess, and replace barry-latest redirect links with the new ones - make backup of new htaccess in your local release directory - send announcement to devel and announce mailing list, including: - release notes - shortlog - URLs to sourceforge and OpenSUSE Build Service binary packages - URL to netdirect doc page - send email notice to intrigeri including: - name of upstream tag (i.e. barry-0.18.3-2) - example of upstream diff git log -p barry-0.18.3..barry-0.18.3-2 - release URL directly to the .dsc file - submit tracker news item at SourceForge - update Freshmeat entry - update Sourceforge screenshots / icons if applicable - update source project, bumping revision numbers in source code barry-0.18.5/doc/bjdwp/0000755001161500056700000000000012242254476014127 5ustar cdfreycdfreybarry-0.18.5/doc/bjdwp/jdwp-resume.txt0000644001161500056700000000500112242254476017126 0ustar cdfreycdfrey.: JDB command :. ================= jdb> resume .: Dump :. ========== Legend : <<< : Data received from JDB >>> : Data sent by wrapper JDWP ---- command resume ---- <<< 00 00 00 0b 00 00 00 16 00 01 04 ........ ... >>> 00 00 01 cb 00 00 00 16 80 00 00 ........ ... 00 00 00 6f e6 a1 e0 00 db f9 20 00 7e 38 40 00 ...o.... .. .~8@. 7b 6d a0 00 4f aa 80 00 4f ab a0 00 4f ad 40 00 {m..O... O...O.@. 53 05 60 00 35 ee 40 00 35 ee c0 00 36 00 a0 00 S.`.5.@. 5...6... 41 b0 40 00 41 ca e0 00 4a 41 20 00 4a c7 20 00 A.@.A... JA .J. . 4a df 80 00 2d 47 c0 00 e2 5c 20 00 3a 5d 60 00 J...-G.. .\ .:]`. 3e 30 a0 00 3b 84 c0 00 38 b5 40 00 38 16 c0 00 >0..;... 8.@.8... 35 70 a0 00 33 26 a0 00 31 1c 00 00 34 61 00 00 5p..3&.. 1...4a.. 34 5e e0 00 32 a6 80 00 32 92 a0 00 32 b4 60 00 4^..2... 2...2.`. 32 35 c0 00 6d ef 60 00 6d ef 00 00 6c 9e c0 00 25..m.`. m...l... 66 51 a0 00 60 05 20 00 5f 5f c0 00 5f 5f a0 00 fQ..`. . __..__.. 5f 1a c0 00 5f 2a 80 00 5d 76 a0 00 39 46 00 00 _..._*.. ]v..9F.. 30 65 e0 00 2e 35 40 00 30 7a 80 00 30 27 40 00 0e...5@. 0z..0'@. 30 29 20 00 2f c1 80 00 2f 57 20 00 2f 57 00 00 0) ./... /W ./W.. 2f 17 c0 00 2e 95 00 00 29 ab 40 00 28 eb e0 00 /....... ).@.(... 28 eb 40 00 0c f6 60 00 0c f9 a0 00 0c f8 80 00 (.@...`. ........ 02 4d 60 00 17 10 60 00 16 04 60 00 11 45 c0 00 .M`...`. ..`..E.. 11 46 60 00 12 46 60 00 10 09 60 00 0e 3f a0 00 .F`..F`. ..`..?.. 0d 11 00 00 0c b1 40 00 0d 04 20 00 0d 05 c0 00 ......@. .. ..... 0d 08 40 00 02 b1 a0 00 02 ab e0 00 02 a9 80 00 ..@..... ........ 02 a3 00 00 08 02 c0 00 08 56 a0 00 e0 e5 20 00 ........ .V.... . 00 3b a0 00 00 9f 40 00 43 b4 c0 00 43 bd a0 00 .;....@. C...C... 43 ba e0 00 43 8f 40 00 0a fa e0 00 18 a8 20 00 C...C.@. ...... . 2e e2 00 00 0b aa 20 00 16 04 20 00 15 ce c0 00 ...... . .. ..... 15 a2 a0 00 15 8e 00 00 7b f4 80 00 7f 99 40 00 ........ {.....@. 7f 9a 00 00 81 75 20 00 85 8d c0 00 90 3e 20 00 .....u . .....> . 91 e9 80 00 e1 04 40 00 df 87 40 00 73 f3 60 00 ......@. ..@.s.`. 90 27 00 00 91 91 e0 00 cd ec 80 00 0b 09 40 00 .'...... ......@. 40 cb 40 00 40 ac 80 00 3f 5e e0 00 c9 b6 60 00 @.@.@... ?^....`. >>> 00 00 00 0b 00 00 00 18 00 01 09 ........ ... <<< 00 00 00 0b 00 00 00 18 80 00 00 ........ ... barry-0.18.5/doc/bjdwp/jdwp-class.txt0000644001161500056700000000664112242254476016746 0ustar cdfreycdfrey.: JDB command :. ================= jdb> class com.rim.resources.net_rim_rimsecuridlibRIMResources .: Dump :. ========== Legend : <<< : Data received from JDB >>> : Data sent by wrapper JDWP ---- command class com.rim.resources.net_rim_rimsecuridlibRIMResources ---- <<< 00 00 00 0f 00 00 00 16 00 03 01 00 00 00 01 ........ ....... >>> 00 00 00 0f 00 00 00 16 80 00 00 ........ ... 00 00 00 0a .... <<< 00 00 00 0f 00 00 00 18 00 02 01 00 00 00 0a ........ ....... >>> 00 00 00 32 00 00 00 18 80 00 00 ...2.... ... 00 00 00 23 4c 6e 65 74 2f 72 69 6d 2f 64 65 76 ...#Lnet /rim/dev 69 63 65 2f 72 65 73 6f 75 72 63 65 73 2f 52 65 ice/reso urces/Re 73 6f 75 72 63 65 3b source; <<< 00 00 00 0f 00 00 00 1a 00 02 0a 00 00 00 01 ........ ....... >>> 00 00 00 0f 00 00 00 1a 80 00 00 ........ ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 1c 00 03 01 00 00 00 02 ........ ....... >>> 00 00 00 0f 00 00 00 1c 80 00 00 ........ ... 00 00 00 0b .... <<< 00 00 00 0f 00 00 00 1e 00 02 01 00 00 00 0b ........ ....... >>> 00 00 00 24 00 00 00 1e 80 00 00 ...$.... ... 00 00 00 15 4c 6a 61 76 61 2f 6c 61 6e 67 2f 45 ....Ljav a/lang/E 78 63 65 70 74 69 6f 6e 3b xception ; <<< 00 00 00 0f 00 00 00 20 00 03 01 00 00 00 03 ........ ....... >>> 00 00 00 0f 00 00 00 20 80 00 00 ........ ... 00 00 00 0b .... <<< 00 00 00 0f 00 00 00 22 00 03 01 00 00 00 04 ......." ....... >>> 00 00 00 0f 00 00 00 22 80 00 00 ......." ... 00 00 00 0b .... <<< 00 00 00 0f 00 00 00 24 00 03 01 00 00 00 05 .......$ ....... >>> 00 00 00 0f 00 00 00 24 80 00 00 .......$ ... 00 00 00 0b .... <<< 00 00 00 0f 00 00 00 26 00 03 01 00 00 00 06 .......& ....... >>> 00 00 00 0f 00 00 00 26 80 00 00 .......& ... 00 00 00 0b .... <<< 00 00 00 0f 00 00 00 28 00 03 01 00 00 00 07 .......( ....... >>> 00 00 00 0f 00 00 00 28 80 00 00 .......( ... 00 00 00 0c .... <<< 00 00 00 0f 00 00 00 2a 00 02 01 00 00 00 0c .......* ....... >>> 00 00 00 21 00 00 00 2a 80 00 00 ...!...* ... 00 00 00 12 4c 6a 61 76 61 2f 6c 61 6e 67 2f 4f ....Ljav a/lang/O 62 6a 65 63 74 3b bject; <<< 00 00 00 0f 00 00 00 2c 00 03 01 00 00 00 08 ......., ....... >>> 00 00 00 0f 00 00 00 2c 80 00 00 ........ ... 00 00 00 0b .... <<< 00 00 00 0f 00 00 00 2e 00 03 01 00 00 00 09 ........ ....... >>> 00 00 00 0f 00 00 00 2e 80 00 00 ........ ... 00 00 00 0b .... <<< 00 00 00 0f 00 00 00 30 00 03 01 00 00 00 0a .......0 ....... >>> 00 00 00 0f 00 00 00 30 80 00 00 .......0 ... 00 00 00 00 .... barry-0.18.5/doc/bjdwp/jdwp-connection.txt0000644001161500056700000001724212242254476017777 0ustar cdfreycdfrey.: Dump :. ========== Legend : <<< : Data received from JDB >>> : Data sent by wrapper JDWP ---- Connection ---- <<< 4a 44 57 50 2d 48 61 6e 64 73 68 61 6b 65 JDWP-Han dshake >>> 4a 44 57 50 2d 48 61 6e 64 73 68 61 6b 65 JDWP-Han dshake >>> 00 00 00 19 00 00 00 01 00 40 64 00 00 00 00 01 ........ .@d...... 5a 00 00 00 00 00 00 00 00 Z....... . <<< 00 00 00 0b 00 00 00 02 00 01 07 ........ ... >>> 00 00 99 1f 00 00 00 02 80 00 00 ........ ... 00 00 00 04 00 00 00 04 00 00 00 04 00 00 00 04 ........ ........ 00 00 00 04 ..... <<< 00 00 00 11 00 00 00 04 00 0f 01 08 00 00 00 00 ........ ........ 00 . >>> 00 00 00 0f 00 00 00 04 80 00 00 ........ ... 00 00 00 02 .... <<< 00 00 00 11 00 00 00 06 00 0f 01 09 00 00 00 00 ........ ........ 00 . >>> 00 00 00 0f 00 00 00 06 80 00 00 ........ ....... 00 00 00 03 .... <<< 00 00 00 2e 00 00 00 08 00 0f 01 08 02 00 00 00 ........ ........ 02 05 00 00 00 13 6a 61 76 61 2e 6c 61 6e 67 2e ......ja va.lang. 54 68 72 6f 77 61 62 6c 65 01 00 00 00 01 Throwabl e..... >>> 00 00 00 0f 00 00 00 08 80 00 00 ........ ... 00 00 00 04 .... <<< 00 00 00 0b 00 00 00 0a 00 01 01 ........ ... >>> 00 00 00 30 00 00 00 0a 80 00 00 ...0.... ... 00 00 00 07 52 49 4d 20 4a 56 4d 00 00 00 01 00 ....RIM JVM..... 00 00 04 00 00 00 03 31 2e 34 00 00 00 07 52 49 .......1 .4....RI 4d 20 4a 56 4d M JVM <<< 00 00 00 0b 00 00 00 0c 00 01 03 ........ ... (( I think that this part is gotten from BarryDemo.debug file 000000AE 00 00 00 0c 01 00 00 00 01 00 00 00 25 4c 63 6f ........ ....%Lco 000000BE 6d 2f 62 61 72 72 79 2f 74 65 73 74 73 2f 62 61 m/barry/ tests/ba 000000CE 72 72 79 64 65 6d 6f 2f 42 61 72 72 79 44 65 6d rrydemo/ BarryDem 000000DE 6f 3b 00 00 00 04 01 00 00 00 02 00 00 00 27 4c o;...... ......'L 000000EE 63 6f 6d 2f 62 61 72 72 79 2f 74 65 73 74 73 2f com/barr y/tests/ 000000FE 62 61 72 72 79 64 65 6d 6f 2f 42 61 72 72 79 53 barrydem o/BarryS 0000010E 63 72 65 65 6e 3b 00 00 00 04 01 00 00 00 03 00 creen;.. ........ 0000011E 00 00 29 4c 63 6f 6d 2f 72 69 6d 2f 72 65 73 6f ..)Lcom/ rim/reso 0000012E 75 72 63 65 73 2f 42 61 72 72 79 44 65 6d 6f 52 urces/Ba rryDemoR 0000013E 49 4d 52 65 73 6f 75 72 63 65 73 3b 00 00 00 04 IMResour ces;.... Lcom/barry/tests/barrydemo/BarryDemo; Lcom/barry/tests/barrydemo/BarryScreen; Lcom/rim/resources/BarryDemoRIMResources; )) >>> 00 00 03 a8 00 00 00 0c 80 00 00 ........ ... 00 00 00 09 01 00 00 00 01 00 00 00 35 4c 63 6f ........ ....5Lco 6d 2f 72 69 6d 2f 72 65 73 6f 75 72 63 65 73 2f m/rim/re sources/ 6e 65 74 5f 72 69 6d 5f 72 69 6d 73 65 63 75 72 net_rim_ rimsecur 69 64 6c 69 62 52 49 4d 52 65 73 6f 75 72 63 65 idlibRIM Resource 73 3b 00 00 00 04 01 00 00 00 02 00 00 00 4b 4c s;...... ......KL 6e 65 74 2f 72 69 6d 2f 64 65 76 69 63 65 2f 63 net/rim/ device/c 6c 64 63 2f 69 6d 70 6c 2f 73 6f 66 74 74 6f 6b ldc/impl /softtok 65 6e 2f 72 69 6d 73 65 63 75 72 69 64 6c 69 62 en/rimse curidlib 2f 52 69 6d 44 61 74 61 62 61 73 65 46 75 6c 6c /RimData baseFull 45 78 63 65 70 74 69 6f 6e 3b 00 00 00 04 01 00 Exceptio n;...... 00 00 03 00 00 00 4a 4c 6e 65 74 2f 72 69 6d 2f ......JL net/rim/ 64 65 76 69 63 65 2f 63 6c 64 63 2f 69 6d 70 6c device/c ldc/impl 2f 73 6f 66 74 74 6f 6b 65 6e 2f 72 69 6d 73 65 /softtok en/rimse 63 75 72 69 64 6c 69 62 2f 52 69 6d 44 65 63 72 curidlib /RimDecr 79 70 74 46 61 69 6c 45 78 63 65 70 74 69 6f 6e yptFailE xception 3b 00 00 00 04 01 00 00 00 04 00 00 00 4c 4c 6e ;....... .....LLn 65 74 2f 72 69 6d 2f 64 65 76 69 63 65 2f 63 6c et/rim/d evice/cl 64 63 2f 69 6d 70 6c 2f 73 6f 66 74 74 6f 6b 65 dc/impl/ softtoke 6e 2f 72 69 6d 73 65 63 75 72 69 64 6c 69 62 2f n/rimsec uridlib/ 52 69 6d 44 75 70 6c 69 63 61 74 65 4e 61 6d 65 RimDupli cateName 45 78 63 65 70 74 69 6f 6e 3b 00 00 00 04 01 00 Exceptio n;...... 00 00 05 00 00 00 4d 4c 6e 65 74 2f 72 69 6d 2f ......ML net/rim/ 64 65 76 69 63 65 2f 63 6c 64 63 2f 69 6d 70 6c device/c ldc/impl 2f 73 6f 66 74 74 6f 6b 65 6e 2f 72 69 6d 73 65 /softtok en/rimse 63 75 72 69 64 6c 69 62 2f 52 69 6d 44 75 70 6c curidlib /RimDupl 69 63 61 74 65 54 6f 6b 65 6e 45 78 63 65 70 74 icateTok enExcept 69 6f 6e 3b 00 00 00 04 01 00 00 00 06 00 00 00 ion;.... ........ 4b 4c 6e 65 74 2f 72 69 6d 2f 64 65 76 69 63 65 KLnet/ri m/device 2f 63 6c 64 63 2f 69 6d 70 6c 2f 73 6f 66 74 74 /cldc/im pl/softt 6f 6b 65 6e 2f 72 69 6d 73 65 63 75 72 69 64 6c oken/rim securidl 69 62 2f 52 69 6d 49 6e 76 61 6c 69 64 50 61 72 ib/RimIn validPar 61 6d 45 78 63 65 70 74 69 6f 6e 3b 00 00 00 04 amExcept ion;.... 01 00 00 00 07 00 00 00 40 4c 6e 65 74 2f 72 69 ........ @Lnet/ri 6d 2f 64 65 76 69 63 65 2f 63 6c 64 63 2f 69 6d m/device /cldc/im 70 6c 2f 73 6f 66 74 74 6f 6b 65 6e 2f 72 69 6d pl/softt oken/rim 73 65 63 75 72 69 64 6c 69 62 2f 52 69 6d 53 65 securidl ib/RimSe 63 75 72 49 44 4c 69 62 3b 00 00 00 04 01 00 00 curIDLib ;....... 00 08 00 00 00 4c 4c 6e 65 74 2f 72 69 6d 2f 64 .....LLn et/rim/d 65 76 69 63 65 2f 63 6c 64 63 2f 69 6d 70 6c 2f evice/cl dc/impl/ 73 6f 66 74 74 6f 6b 65 6e 2f 72 69 6d 73 65 63 softtoke n/rimsec 75 72 69 64 6c 69 62 2f 52 69 6d 57 72 6f 6e 67 uridlib/ RimWrong 44 65 76 69 63 65 49 44 45 78 63 65 70 74 69 6f DeviceID Exceptio 6e 3b 00 00 00 04 01 00 00 00 09 00 00 00 4e 4c n;...... ......NL 6e 65 74 2f 72 69 6d 2f 64 65 76 69 63 65 2f 63 net/rim/ device/c 6c 64 63 2f 69 6d 70 6c 2f 73 6f 66 74 74 6f 6b ldc/impl /softtok 65 6e 2f 72 69 6d 73 65 63 75 72 69 64 6c 69 62 en/rimse curidlib 2f 52 69 6d 57 72 6f 6e 67 46 6f 72 6d 46 61 63 /RimWron gFormFac 74 6f 72 45 78 63 65 70 74 69 6f 6e 3b 00 00 00 torExcep tion;... 04 . <<< 00 00 00 11 00 00 00 0e 00 0f 01 06 02 00 00 00 ........ ........ >>> 00 00 00 0f 00 00 00 0e 80 00 00 ........ ... 00 00 00 05 .... <<< 00 00 00 11 00 00 00 10 00 0f 01 07 02 00 00 00 ........ ........ >>> 00 00 00 0f 00 00 00 10 80 00 00 ........ ... 00 00 00 06 .... <<< 00 00 00 2e 00 00 00 12 00 0f 01 08 02 00 00 00 ........ ........ 02 05 00 00 00 13 6a 61 76 61 2e 6c 61 6e 67 2e ......ja va.lang. 54 68 72 6f 77 61 62 6c 65 01 00 00 00 01 Throwabl e..... >>> 00 00 00 0f 00 00 00 12 80 00 00 ........ ... 00 00 00 07 .... <<< 00 00 00 0b 00 00 00 14 00 01 0d ........ ... >>> 00 00 00 17 00 00 00 14 80 00 00 ........ ... 00 00 00 00 00 00 00 00 00 00 00 00 ........ .... ---- Disconnection (command exit) ---- <<< 00 00 00 0b 00 00 00 16 00 01 06 ........ ... barry-0.18.5/doc/bjdwp/jdwp-protocol.txt0000644001161500056700000000130612242254476017473 0ustar cdfreycdfrey.: Test to get traces :. ======================== 1°) Scheme +-------+ +--------+ +------------+ | | | | | BlackBerry | | JDB |== TCP / IP ==| JDWP |== USB ==| | | | | | | device | +-------+ +--------+ +------------+ 2°) Plug your BlackBerry device 3°) Install the BarryDemo application on your device (in using javaloader / bjavaloader) 4°) Run tcpdump on the local interface 5°) Run JDWP provided by RIM's tools (listen to port 8080) 6°) Run JDB : $ jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8080 $ jdb> resume $ jdb> exit barry-0.18.5/doc/bjdwp/jdwp-methods-and-fields.txt0000644001161500056700000002455412242254476021313 0ustar cdfreycdfreyVM Started: > classes ** classes list ** 0x1 com.barry.tests.barrydemo.BarryDemo 0x2 com.barry.tests.barrydemo.BarryScreen 0x3 com.rim.resources.BarryDemoRIMResources 0x4 com.rim.resources.net_rim_rimsecuridlibRIMResources 0x5 net.rim.device.cldc.impl.softtoken.rimsecuridlib.RimDatabaseFullException 0x6 net.rim.device.cldc.impl.softtoken.rimsecuridlib.RimDecryptFailException 0x7 net.rim.device.cldc.impl.softtoken.rimsecuridlib.RimDuplicateNameException 0x8 net.rim.device.cldc.impl.softtoken.rimsecuridlib.RimDuplicateTokenException 0x9 net.rim.device.cldc.impl.softtoken.rimsecuridlib.RimInvalidParamException 0xA net.rim.device.cldc.impl.softtoken.rimsecuridlib.RimSecurIDLib 0xB net.rim.device.cldc.impl.softtoken.rimsecuridlib.RimWrongDeviceIDException 0xC net.rim.device.cldc.impl.softtoken.rimsecuridlib.RimWrongFormFactorException > class com.barry.tests.barrydemo.BarryDemo Class: com.barry.tests.barrydemo.BarryDemo extends: net.rim.device.api.ui.UiApplication > methods com.barry.tests.barrydemo.BarryDemo ** methods list ** com.barry.tests.barrydemo.BarryDemo main(java.lang.String[]) com.barry.tests.barrydemo.BarryDemo () > fields com.barry.tests.barrydemo.BarryDemo ** fields list ** > class com.barry.tests.barrydemo.BarryScreen Class: com.barry.tests.barrydemo.BarryScreen extends: net.rim.device.api.ui.container.MainScreen > methods com.barry.tests.barrydemo.BarryScreen ** methods list ** com.barry.tests.barrydemo.BarryScreen () com.barry.tests.barrydemo.BarryScreen close() > fields com.barry.tests.barrydemo.BarryScreen ** fields list ** > exit ---- command class com.barry.tests.barrydemo.BarryDemo ---- <<< 00 00 00 0f 00 00 00 16 00 03 01 00 00 00 01 ........ ....... >>> 00 00 00 0f 00 00 00 16 80 00 00 ........ ... 00 00 00 0d .... <= 0x0000000d is a new ID since, we have to load a new class <<< 00 00 00 0f 00 00 00 18 00 02 01 00 00 00 0d ........ ....... 00 00 00 34 00 00 00 18 80 00 00 ...4.... ... 00 00 00 25 4c 6e 65 74 2f 72 69 6d 2f 64 65 76 ...%Lnet /rim/dev 69 63 65 2f 61 70 69 2f 75 69 2f 55 69 41 70 70 ice/api/ ui/UiApp 6c 69 63 61 74 69 6f 6e 3b lication ; <<< 00 00 00 0f 00 00 00 1a 00 02 0a 00 00 00 01 ........ ....... >>> 00 00 00 0f 00 00 00 1a 80 00 00 ........ ... 00 00 00 00 .... ---- command class com.barry.tests.barrydemo.BarryScreen ---- <<< 00 00 00 0f 00 00 00 1c 00 03 01 00 00 00 02 ........ ....... >>> 00 00 00 0f 00 00 00 1c 80 00 00 ........ ... 00 00 00 0e .... <= 0x0000000e is a new ID since, we have to load a new class <<< 00 00 00 0f 00 00 00 1e 00 02 01 00 00 00 0e ........ ....... >>> 00 00 00 3b 00 00 00 1e 80 00 00 ...;.... ... 00 00 00 2c 4c 6e 65 74 2f 72 69 6d 2f 64 65 76 ...,Lnet /rim/dev 69 63 65 2f 61 70 69 2f 75 69 2f 63 6f 6e 74 61 ice/api/ ui/conta 69 6e 65 72 2f 4d 61 69 6e 53 63 72 65 65 6e 3b iner/Mai nScreen; <<< 00 00 00 0f 00 00 00 20 00 03 01 00 00 00 03 ....... ....... >>> 00 00 00 0f 00 00 00 20 80 00 00 ....... ... 00 00 00 0f .... <<< 00 00 00 0f 00 00 00 22 00 02 01 00 00 00 0f ......." ....... >>> 00 00 00 32 00 00 00 22 80 00 00 ...2..." ... 00 00 00 23 4c 6e 65 74 2f 72 69 6d 2f 64 65 76 ...#Lnet /rim/dev 69 63 65 2f 72 65 73 6f 75 72 63 65 73 2f 52 65 ice/reso urces/Re 73 6f 75 72 63 65 3b source; <<< 00 00 00 0f 00 00 00 24 00 03 01 00 00 00 04 .......$ ....... >>> 00 00 00 0f 00 00 00 24 80 00 00 .......$ ... 00 00 00 10 .... <<< 00 00 00 0f 00 00 00 26 00 02 01 00 00 00 10 .......& ....... >>> 00 00 00 32 00 00 00 26 80 00 00 ...2...& ... 00 00 00 23 4c 6e 65 74 2f 72 69 6d 2f 64 65 76 ...#Lnet /rim/dev 69 63 65 2f 72 65 73 6f 75 72 63 65 73 2f 52 65 ice/reso urces/Re 73 6f 75 72 63 65 3b source; <<< 00 00 00 0f 00 00 00 28 00 03 01 00 00 00 0d .......( ....... >>> 00 00 00 0f 00 00 00 28 80 00 00 .......( ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 2a 00 03 01 00 00 00 05 .......* ....... >>> 00 00 00 0f 00 00 00 2a 80 00 00 .......* ... 00 00 00 11 .... <<< 00 00 00 0f 00 00 00 2c 00 02 01 00 00 00 11 ......., ....... >>> 00 00 00 24 00 00 00 2c 80 00 00 ...$.... ... 00 00 00 15 4c 6a 61 76 61 2f 6c 61 6e 67 2f 45 ...Ljav a/lang/E 78 63 65 70 74 69 6f 6e 3b xception ; <<< 00 00 00 0f 00 00 00 2e 00 03 01 00 00 00 06 ........ ....... >>> 00 00 00 0f 00 00 00 2e 80 00 00 ........ ... 00 00 00 11 .... <<< 00 00 00 0f 00 00 00 30 00 03 01 00 00 00 07 .......0 ....... >>> 00 00 00 0f 00 00 00 30 80 00 00 .......0 ... 00 00 00 11 .... <<< 00 00 00 0f 00 00 00 32 00 03 01 00 00 00 08 .......2 ....... >>> 00 00 00 0f 00 00 00 32 80 00 00 .......2 ... 00 00 00 11 .... <<< 00 00 00 0f 00 00 00 34 00 03 01 00 00 00 09 .......4 ....... >>> 00 00 00 0f 00 00 00 34 80 00 00 .......4 ... 00 00 00 11 .... <<< 00 00 00 0f 00 00 00 36 00 03 01 00 00 00 0a .......6 ....... >>> 00 00 00 0f 00 00 00 36 80 00 00 .......6 ... 00 00 00 12 .... <<< 00 00 00 0f 00 00 00 38 00 02 01 00 00 00 12 .......8 ....... >>> 00 00 00 21 00 00 00 38 80 00 00 ...!...8 ... 00 00 00 12 4c 6a 61 76 61 2f 6c 61 6e 67 2f 4f ....Ljav a/lang/O 62 6a 65 63 74 3b bject; <<< 00 00 00 0f 00 00 00 3a 00 03 01 00 00 00 0b .......: ....... >>> 00 00 00 0f 00 00 00 3a 80 00 00 .......: ... 00 00 00 11 .... <<< 00 00 00 0f 00 00 00 3c 00 03 01 00 00 00 0c .......< ....... >>> 00 00 00 0f 00 00 00 3c 80 00 00 .......< ... 00 00 00 11 .... <<< 00 00 00 0f 00 00 00 3e 00 02 05 00 00 00 01 .......> ....... >>> 00 00 00 52 00 00 00 3e 80 00 00 ...R...> ... 00 00 00 02 00 00 00 13 00 00 00 04 6d 61 69 6e ........ ....main 00 00 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 ....([Lj ava/lang 2f 53 74 72 69 6e 67 3b 29 56 00 00 00 19 00 00 /String; )V...... 00 14 00 00 00 06 3c 69 6e 69 74 3e 00 00 00 03 .......... 28 29 56 00 00 00 02 ()V.... <<< 00 00 00 0f 00 00 00 40 00 02 05 00 00 00 0d .......@ ....... >>> 00 00 00 0f 00 00 00 40 80 00 00 .......@ ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 42 00 02 0a 00 00 00 0d .......B ....... >>> 00 00 00 0f 00 00 00 42 80 00 00 .......B ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 44 00 02 04 00 00 00 01 .......D ....... >>> 00 00 00 0f 00 00 00 44 80 00 00 .......D ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 46 00 02 04 00 00 00 0d .......F ....... >>> 00 00 00 0f 00 00 00 46 80 00 00 .......F ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 48 00 02 0a 00 00 00 02 .......H ....... >>> 00 00 00 0f 00 00 00 48 80 00 00 .......H ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 4a 00 03 01 00 00 00 11 .......J ....... >>> 00 00 00 0f 00 00 00 4a 80 00 00 .......J ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 4c 00 03 01 00 00 00 12 .......L ....... >>> 00 00 00 0f 00 00 00 4c 80 00 00 .......L ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 4e 00 03 01 00 00 00 0e .......N ....... >>> 00 00 00 0f 00 00 00 4e 80 00 00 .......N ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 50 00 03 01 00 00 00 0f .......P ....... >>> 00 00 00 0f 00 00 00 50 80 00 00 .......P ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 52 00 03 01 00 00 00 10 .......R ....... >>> 00 00 00 0f 00 00 00 52 80 00 00 .......R ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 54 00 02 05 00 00 00 02 .......T ....... >>> 00 00 00 40 00 00 00 54 80 00 00 ...@...T ... 00 00 00 02 00 00 00 15 00 00 00 06 3c 69 6e 69 ........ ........() V....... 16 00 00 00 05 63 6c 6f 73 65 00 00 00 03 28 29 .....clo se....() 56 00 00 00 11 V.... <<< 00 00 00 0f 00 00 00 56 00 02 05 00 00 00 0e .......V ....... >>> 00 00 00 0f 00 00 00 56 80 00 00 .......V ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 58 00 02 0a 00 00 00 0e .......X ....... >>> 00 00 00 0f 00 00 00 58 80 00 00 .......X ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 5a 00 02 04 00 00 00 02 .......Z ....... >>> 00 00 00 0f 00 00 00 5a 80 00 00 .......Z ... 00 00 00 00 .... <<< 00 00 00 0f 00 00 00 5c 00 02 04 00 00 00 0e .......\ ....... >>> 00 00 00 0f 00 00 00 5c 80 00 00 .......\ ... 00 00 00 00 .... barry-0.18.5/doc/bjdwp/README0000644001161500056700000000331612242254476015012 0ustar cdfreycdfrey BJDWP Readme ============== Introduction ------------ With bjdwp you can debug with JDB your Java applications on your BlackBerry device. bjdwp is a wrapper between JDB and the JVM embedded in your device. bjdwp uses the barry library to comminucate with your device. Table of contents ----------------- 1. Note 2. Requirements 3. Compilation 4. Usage 4.1 Command line 4.2 Options 5. Status 6. Licence ========================== 1. Note ------- The JDWP application to debug Java applications for BlackBerry is currently being developed on Linux. This driver can do damages. Use this application only if you know what you are doing. 2. Requirements --------------- - Barry and libbarry 0.15 or higher (with JavaDebug mode support) - cmake 3. Compilation -------------- $ ./configure $ make To run the application, launch the binary in the "bin" directory $ cd bin $ ./bjdwp 4. Usage -------- 4.1 Command line 1°) Plug your BlackBerry device 2°) Run bjdwp wrapper $ bjdwp localhost 8000 3°) Run JDB $ jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8000 4.2 Options bjdwp accepts the same options that the tools btool, bjavaloader... bjdwp [hpPv]
-h This help\n" -p pin PIN of device to talk with\n" If only one device is plugged in, this flag is optional\n" -P pass Simplistic method to specify device password\n" -v Dump protocol data during operation\n" 5. Status --------- bjdwp isn't usable. 6. Licence ---------- bjdwp application is distributed under the licence GPL. barry-0.18.5/doc/bjdwp/sample/0000755001161500056700000000000012242254476015410 5ustar cdfreycdfreybarry-0.18.5/doc/bjdwp/sample/BarryDemo.debug0000644001161500056700000000635012242254476020310 0ustar cdfreycdfreyJw BarryDemo BarryDemo$1/home/nicolas/Project/bjdwp/sample/BarryDemo.java UiApplication Dnet.rim.device.api.ui5/opt/RIM/sdk/lib/net_rim_api.jar(net_rim_cldc-10.cod)BarryDemoRIMResourcesdcom.rim.resources /opt/RIM/sdk/lib/net_rim_api.jar Resource Dnet.rim.device.resources5/opt/RIM/sdk/lib/net_rim_api.jar(net_rim_cldc-21.cod) BarryScreen$1/home/nicolas/Project/bjdwp/sample/BarryDemo.java MainScreen Dnet.rim.device.api.ui.container5/opt/RIM/sdk/lib/net_rim_api.jar(net_rim_cldc-13.cod) voidString d java.lang2/opt/RIM/sdk/lib/net_rim_api.jar(net_rim_cldc.cod)String[] Hashtable D java.util2/opt/RIM/sdk/lib/net_rim_api.jar(net_rim_cldc.cod)bytebyte[] LabelField Dnet.rim.device.api.ui.component5/opt/RIM/sdk/lib/net_rim_api.jar(net_rim_cldc-11.cod)intmainjargstheApp <init>&&:this&:'-9  _resources B _properties B _appIcons B _appExtIcons B _appCount B_resourceExtensions B  _appNames B  _appFlags B _version B _vendor B <init>\HH\thisH\<clinit>@*jj<init>WthisWtitle Wi Jstr%E  "!#%%;'E"J*V+closelthis023   barry-0.18.5/doc/bjdwp/sample/BarryDemo.jad0000644001161500056700000000074612242254476017763 0ustar cdfreycdfreyManifest-Version: 1.0 RIM-COD-Module-Name: BarryDemo RIM-COD-Module-Dependencies: net_rim_cldc MIDlet-Jar-Size: 3202 MIDlet-1: BarryDemo,, RIM-COD-Creation-Time: 1249375422 MIDlet-Jar-URL: BarryDemo.jar RIM-COD-URL: BarryDemo.cod RIM-COD-SHA1: 05 27 b5 ff 5c cb c9 2f 23 53 83 cd de f2 69 94 83 7e ae b1 RIM-COD-Size: 1600 MicroEdition-Configuration: CLDC-1.1 MIDlet-Version: 1.0 MIDlet-Name: BarryDemo MIDlet-Vendor: Nicolas VIVIEN MicroEdition-Profile: MIDP-2.0 RIM-MIDlet-Flags-1: 0 barry-0.18.5/doc/bjdwp/sample/BarryDemo.rapc0000644001161500056700000000036312242254476020145 0ustar cdfreycdfreyMIDlet-Name: BarryDemo MIDlet-Version: 1.0 MIDlet-Vendor: Nicolas VIVIEN MIDlet-Jar-URL: BarryDemo.jar MIDlet-Jar-Size: 0 MicroEdition-Profile: MIDP-2.0 MicroEdition-Configuration: CLDC-1.1 MIDlet-1: BarryDemo,, RIM-MIDlet-Flags-1: 0 barry-0.18.5/doc/bjdwp/sample/BarryDemo.jar0000644001161500056700000000620212242254476017772 0ustar cdfreycdfreyPKxE; META-INF/PKPKxE;META-INF/MANIFEST.MF]j0 -T&.ct҄Ҳ\H ]' hq6JfirT(ǀw*1\ԦuzFUVUewL` 3PTh\s@橤viR0aӏ]f_Mln+f| m[]$'dW*5]xaכ!^f7iPK<:PKxE; BarryDemo.codUkh\Eg;nI$BC5E6Uqԍmh4`Mew>RP_EҒ6ZHbIB )BM333gΜ;sEXeϭ ŵҁnisOwV*. WQu7d9wy4M86P ƯjQW@Gtxq~\,VЦFAAh@8I`ɾFkWHX@P`K݆@Dt)znXu枳[֖s4ׯvN #rr7"4SƌèT_Jx^Kk&D]7lVUfYn#GR1Ɍߌq8olMՙx3 6F &J~Y?/@4F?wH#SYx"WJufA->-;vk9_L~Go,:xrޮA*F fin"?`vf,^f%&p] (O xBI3h6;_^ϼm|.o&Y?ekmYO~D7<,|DlUwZp"뎵.pQkn,pLct=! \'.*|֢g-*8ŭ`TTF׸-3X-FJ+֊ 8J*} ArAAr$[;\Z~Nky{_Y~~_Z]ԵGΣ;})hIIů ,3O \s)r+Kb5(O55:Ո KSb6mdDeXiӒx@lB4?PKG2@PKxE; BarryDemo.cso366 O_ǀ`G#.S# )8$&g'U*8+8xC8UtSJ2s!J,)+I-K+15¦(PKv\PKwE;BarryDemo.classmJ@Zoj`īm+ii >%&3ewF90C4sHFA 1.Cf7n;:Q%]4z}q%u2\ ' 0T0ϐ\{ھ nH"Rcː]ʨ8B۵c0"010/ͩ4_$mđ6G 7~FґH(ڃ?"i̊ hXhT3O Yz=R#Z..eۈ$(.P(W НQ"\LwmS#-HH;5G? FCNkPK+s6PKwE;BarryScreen.classSRA= L2  F  o TBQr48̤&J~׸T~kC=+%H9Uss}u+/4ĐP1@# CJC 0 &Uՠ#!ŔR F졊G*3tX%dj9CO޲FZY%wJfet-pѾy`3 µ,xcJ.6wKHͅZU7̚e4,Tkma"ZRnS'74_$GG̫NF&WOC!bFŬ9< tE\d2*u,`A"Kg ]X²+:V!bt ^^^^^^^^^^^^ ^^^^^ string 0xE types [[ 00000028 00 07 00 00 00 09 00 42 00 61 00 72 00 72 00 79 00 44 00 65 .......B.a.r.r.y.D.e ^^^^^ ^^^^^^^^^^^^ <------------------------------------------- len string 0000003C 00 6D 00 6F 00 00 08 24 00 00 00 00 00 00 00 00 00 00 00 00 .m.o...$............ ----------> ^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^  ^^^^^^^^^^^ Type ID 00000050 00 00 00 00 00 00 00 31 00 2F 00 68 00 6F 00 6D 00 65 00 2F .......1./.h.o.m.e./ ^^^^^^^^^^^ ^^^^^^^^^^^ <------------------------------------ len len string 00000064 00 6E 00 69 00 63 00 6F 00 6C 00 61 00 73 00 2F 00 50 00 72 .n.i.c.o.l.a.s./.P.r 00000078 00 6F 00 6A 00 65 00 63 00 74 00 2F 00 62 00 6A 00 64 00 77 .o.j.e.c.t./.b.j.d.w 0000008C 00 70 00 2F 00 73 00 61 00 6D 00 70 00 6C 00 65 00 2F 00 42 .p./.s.a.m.p.l.e./.B 000000A0 00 61 00 72 00 72 00 79 00 44 00 65 00 6D 00 6F 00 2E 00 6A .a.r.r.y.D.e.m.o...j 000000B4 00 61 00 76 00 61 00 00 00 00 00 00 00 00 00 00 00 02 00 00 .a.v.a.............. -----------------> ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ 000000C8 00 00 00 00 00 07 00 00 00 0D 00 55 00 69 00 41 00 70 00 70 ...........U.i.A.p.p ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ <------------------------------ len string 000000DC 00 6C 00 69 00 63 00 61 00 74 00 69 00 6F 00 6E 00 00 20 44 .l.i.c.a.t.i.o.n.. D -------------------------------------------------> ^^^^^^^^^^^ 000000F0 00 00 00 00 00 00 00 00 FF FF FF FF 00 00 00 15 00 6E 00 65 .................n.e ^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^ ^^^^^^^^^^^ <---------- len 00000104 00 74 00 2E 00 72 00 69 00 6D 00 2E 00 64 00 65 00 76 00 69 .t...r.i.m...d.e.v.i 00000118 00 63 00 65 00 2E 00 61 00 70 00 69 00 2E 00 75 00 69 00 00 .c.e...a.p.i...u.i.. --------------------------------------------------------> ^^^^^ string 0000012C 00 35 00 2F 00 6F 00 70 00 74 00 2F 00 52 00 49 00 4D 00 2F .5./.o.p.t./.R.I.M./ ^^^^^ <-------------------------------------------------------- len string 00000140 00 73 00 64 00 6B 00 2F 00 6C 00 69 00 62 00 2F 00 6E 00 65 .s.d.k./.l.i.b./.n.e 00000154 00 74 00 5F 00 72 00 69 00 6D 00 5F 00 61 00 70 00 69 00 2E .t._.r.i.m._.a.p.i.. 00000168 00 6A 00 61 00 72 00 28 00 6E 00 65 00 74 00 5F 00 72 00 69 .j.a.r.(.n.e.t._.r.i 0000017C 00 6D 00 5F 00 63 00 6C 00 64 00 63 00 2D 00 31 00 30 00 2E .m._.c.l.d.c.-.1.0.. 00000190 00 63 00 6F 00 64 00 29 00 00 00 00 00 00 00 00 00 00 00 00 .c.o.d.)............ -----------------------> 000001A4 00 00 00 00 00 00 00 07 00 00 00 15 00 42 00 61 00 72 00 72 .............B.a.r.r ^^^^^^^^^^^ ^^^^^^^^^^^ <----------------------- len string 000001B8 00 79 00 44 00 65 00 6D 00 6F 00 52 00 49 00 4D 00 52 00 65 .y.D.e.m.o.R.I.M.R.e 000001CC 00 73 00 6F 00 75 00 72 00 63 00 65 00 73 00 00 00 64 00 00 .s.o.u.r.c.e.s...d.. -------------------------------------------> ^^^^^^^^^^^^ 000001E0 00 00 00 00 00 00 00 00 00 01 00 00 00 11 00 63 00 6F 00 6D ...............c.o.m ^^^^^^^^^^^^ <----------------- len string 000001F4 00 2E 00 72 00 69 00 6D 00 2E 00 72 00 65 00 73 00 6F 00 75 ...r.i.m...r.e.s.o.u 00000208 00 72 00 63 00 65 00 73 00 00 00 20 00 2F 00 6F 00 70 00 74 .r.c.e.s... ./.o.p.t -----------------------> ^^^^^^^^^^^ <----------------------- len string 0000021C 00 2F 00 52 00 49 00 4D 00 2F 00 73 00 64 00 6B 00 2F 00 6C ./.R.I.M./.s.d.k./.l 00000230 00 69 00 62 00 2F 00 6E 00 65 00 74 00 5F 00 72 00 69 00 6D .i.b./.n.e.t._.r.i.m 00000244 00 5F 00 61 00 70 00 69 00 2E 00 6A 00 61 00 72 00 00 00 00 ._.a.p.i...j.a.r.... -------------------------------------------------> 00000258 00 00 00 0A 00 00 00 02 00 00 00 00 00 00 00 07 00 00 00 08 .................... ^^^^^^^^^^^ ^^^^^^^^^^^ 0000026C 00 52 00 65 00 73 00 6F 00 75 00 72 00 63 00 65 00 00 20 44 .R.e.s.o.u.r.c.e.. D <------------------------------------------------> ^^^^^^^^^^^ 00000280 00 00 00 00 00 00 00 00 FF FF FF FF 00 00 00 18 00 6E 00 65 .................n.e ^^^^^^^^^^^  ^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^ <---------- 00000294 00 74 00 2E 00 72 00 69 00 6D 00 2E 00 64 00 65 00 76 00 69 .t...r.i.m...d.e.v.i 000002A8 00 63 00 65 00 2E 00 72 00 65 00 73 00 6F 00 75 00 72 00 63 .c.e...r.e.s.o.u.r.c 000002BC 00 65 00 73 00 00 00 35 00 2F 00 6F 00 70 00 74 00 2F 00 52 .e.s...5./.o.p.t./.R ----------> ^^^^^^^^^^^ <------------------------------------ 000002D0 00 49 00 4D 00 2F 00 73 00 64 00 6B 00 2F 00 6C 00 69 00 62 .I.M./.s.d.k./.l.i.b 000002E4 00 2F 00 6E 00 65 00 74 00 5F 00 72 00 69 00 6D 00 5F 00 61 ./.n.e.t._.r.i.m._.a 000002F8 00 70 00 69 00 2E 00 6A 00 61 00 72 00 28 00 6E 00 65 00 74 .p.i...j.a.r.(.n.e.t 0000030C 00 5F 00 72 00 69 00 6D 00 5F 00 63 00 6C 00 64 00 63 00 2D ._.r.i.m._.c.l.d.c.- 00000320 00 32 00 31 00 2E 00 63 00 6F 00 64 00 29 00 00 00 00 00 00 .2.1...c.o.d.)...... -------------------------------------------> 00000334 00 00 00 00 00 00 00 00 00 00 00 00 00 07 00 00 00 0B 00 42 ...................B ^^^^^^^^^^^^ ^^^^^^^^^^^^ <---- ] [ len 00000348 00 61 00 72 00 72 00 79 00 53 00 63 00 72 00 65 00 65 00 6E .a.r.r.y.S.c.r.e.e.n --------------------------------------------------------------> string 0000035C 00 00 08 24 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 ...$................ 00000370 00 00 00 31 00 2F 00 68 00 6F 00 6D 00 65 00 2F 00 6E 00 69 ...1./.h.o.m.e./.n.i ^^^^^^^^^^^ <------------------------------------------------- len string 00000384 00 63 00 6F 00 6C 00 61 00 73 00 2F 00 50 00 72 00 6F 00 6A .c.o.l.a.s./.P.r.o.j 00000398 00 65 00 63 00 74 00 2F 00 62 00 6A 00 64 00 77 00 70 00 2F .e.c.t./.b.j.d.w.p./ 000003AC 00 73 00 61 00 6D 00 70 00 6C 00 65 00 2F 00 42 00 61 00 72 .s.a.m.p.l.e./.B.a.r 000003C0 00 72 00 79 00 44 00 65 00 6D 00 6F 00 2E 00 6A 00 61 00 76 .r.y.D.e.m.o...j.a.v 000003D4 00 61 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 .a.................. ----> ^^^^^ 000003E8 00 07 00 00 00 0A 00 4D 00 61 00 69 00 6E 00 53 00 63 00 72 .......M.a.i.n.S.c.r ^^^^^ ^^^^^^^^^^^^ <------------------------------------------- 000003FC 00 65 00 65 00 6E 00 00 20 44 00 00 00 00 00 00 00 00 FF FF .e.e.n.. D.......... -----------------> ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ 00000410 FF FF 00 00 00 1F 00 6E 00 65 00 74 00 2E 00 72 00 69 00 6D .......n.e.t...r.i.m ^^^^^ ^^^^^^^^^^^^ <------------------------------------------- 00000424 00 2E 00 64 00 65 00 76 00 69 00 63 00 65 00 2E 00 61 00 70 ...d.e.v.i.c.e...a.p 00000438 00 69 00 2E 00 75 00 69 00 2E 00 63 00 6F 00 6E 00 74 00 61 .i...u.i...c.o.n.t.a 0000044C 00 69 00 6E 00 65 00 72 00 00 00 35 00 2F 00 6F 00 70 00 74 .i.n.e.r...5./.o.p.t -----------------------> ^^^^^^^^^^^ <----------------------- 00000460 00 2F 00 52 00 49 00 4D 00 2F 00 73 00 64 00 6B 00 2F 00 6C ./.R.I.M./.s.d.k./.l 00000474 00 69 00 62 00 2F 00 6E 00 65 00 74 00 5F 00 72 00 69 00 6D .i.b./.n.e.t._.r.i.m 00000488 00 5F 00 61 00 70 00 69 00 2E 00 6A 00 61 00 72 00 28 00 6E ._.a.p.i...j.a.r.(.n 0000049C 00 65 00 74 00 5F 00 72 00 69 00 6D 00 5F 00 63 00 6C 00 64 .e.t._.r.i.m._.c.l.d 000004B0 00 63 00 2D 00 31 00 33 00 2E 00 63 00 6F 00 64 00 29 00 00 .c.-.1.3...c.o.d.).. --------------------------------------------------------> 000004C4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0A 00 00 .................... ^^^^^^^^^^^^ ^^^^^ ] [ 000004D8 00 04 00 76 00 6F 00 69 00 64 00 00 00 07 00 00 00 06 00 53 ...v.o.i.d.........S ^^^^^ <-----------------------> ^^^^^^^^^^^^ ^^^^^^^^^^^^ <---- ] [ 000004EC 00 74 00 72 00 69 00 6E 00 67 00 00 20 64 00 00 00 00 00 00 .t.r.i.n.g.. d...... ------------------------------> ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ 00000500 00 00 FF FF FF FF 00 00 00 09 00 6A 00 61 00 76 00 61 00 2E ...........j.a.v.a.. ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ <------------------------------ 00000514 00 6C 00 61 00 6E 00 67 00 00 00 32 00 2F 00 6F 00 70 00 74 .l.a.n.g...2./.o.p.t -----------------------> ^^^^^^^^^^^ <----------------------- 00000528 00 2F 00 52 00 49 00 4D 00 2F 00 73 00 64 00 6B 00 2F 00 6C ./.R.I.M./.s.d.k./.l 0000053C 00 69 00 62 00 2F 00 6E 00 65 00 74 00 5F 00 72 00 69 00 6D .i.b./.n.e.t._.r.i.m 00000550 00 5F 00 61 00 70 00 69 00 2E 00 6A 00 61 00 72 00 28 00 6E ._.a.p.i...j.a.r.(.n 00000564 00 65 00 74 00 5F 00 72 00 69 00 6D 00 5F 00 63 00 6C 00 64 .e.t._.r.i.m._.c.l.d 00000578 00 63 00 2E 00 63 00 6F 00 64 00 29 00 00 00 00 00 00 00 00 .c...c.o.d.)........ ------------------------------------> ^^^^^^^^^^^ ^^^^^^^^^^^ 0000058C 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 08 00 53 00 74 .................S.t ^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^ ^^^^^^^^^^^ <---------- ]  [ 000005A0 00 72 00 69 00 6E 00 67 00 5B 00 5D 00 00 00 07 00 00 00 09 .r.i.n.g.[.]........ ------------------------------------> ^^^^^^^^^^^ ^^^^^^^^^^^ ] [ 000005B4 00 48 00 61 00 73 00 68 00 74 00 61 00 62 00 6C 00 65 00 00 .H.a.s.h.t.a.b.l.e.. <-------------------------------------------------------> ^^^^^ 000005C8 20 44 00 00 00 00 00 00 00 00 FF FF FF FF 00 00 00 09 00 6A D.................j ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ <---- 000005DC 00 61 00 76 00 61 00 2E 00 75 00 74 00 69 00 6C 00 00 00 32 .a.v.a...u.t.i.l...2 -------------------------------------------------> ^^^^^^^^^^^ 000005F0 00 2F 00 6F 00 70 00 74 00 2F 00 52 00 49 00 4D 00 2F 00 73 ./.o.p.t./.R.I.M./.s <-------------------------------------------------------------- 00000604 00 64 00 6B 00 2F 00 6C 00 69 00 62 00 2F 00 6E 00 65 00 74 .d.k./.l.i.b./.n.e.t 00000618 00 5F 00 72 00 69 00 6D 00 5F 00 61 00 70 00 69 00 2E 00 6A ._.r.i.m._.a.p.i...j 0000062C 00 61 00 72 00 28 00 6E 00 65 00 74 00 5F 00 72 00 69 00 6D .a.r.(.n.e.t._.r.i.m 00000640 00 5F 00 63 00 6C 00 64 00 63 00 2E 00 63 00 6F 00 64 00 29 ._.c.l.d.c...c.o.d.) --------------------------------------------------------------> 00000654 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 .................... ^^^^^^^^^^^ ^^^^^^^^^^^  ^^^^^^^^^^^ ^^^^^^^^^^^  ^^^^^^^^^^^ 00000668 00 00 00 04 00 62 00 79 00 74 00 65 00 00 00 08 00 00 00 06 .....b.y.t.e........ ^^^^^^^^^^^  <----------------------> ^^^^^^^^^^^ ^^^^^^^^^^^ ] [ 0000067C 00 62 00 79 00 74 00 65 00 5B 00 5D 00 00 00 07 00 00 00 0A .b.y.t.e.[.]........ <-----------------------------------> ^^^^^^^^^^^ ^^^^^^^^^^^ ] [ 00000690 00 4C 00 61 00 62 00 65 00 6C 00 46 00 69 00 65 00 6C 00 64 .L.a.b.e.l.F.i.e.l.d <-------------------------------------------------------------> 000006A4 00 00 20 44 00 00 00 00 00 00 00 00 FF FF FF FF 00 00 00 1F .. D................ ^^^^^^^^^^^  ^^^^^^^^^^^ ^^^^^^^^^^^  ^^^^^^^^^^^ ^^^^^^^^^^^ len 000006B8 00 6E 00 65 00 74 00 2E 00 72 00 69 00 6D 00 2E 00 64 00 65 .n.e.t...r.i.m...d.e <-------------------------------------------------------------- 000006CC 00 76 00 69 00 63 00 65 00 2E 00 61 00 70 00 69 00 2E 00 75 .v.i.c.e...a.p.i...u 000006E0 00 69 00 2E 00 63 00 6F 00 6D 00 70 00 6F 00 6E 00 65 00 6E .i...c.o.m.p.o.n.e.n 000006F4 00 74 00 00 00 35 00 2F 00 6F 00 70 00 74 00 2F 00 52 00 49 .t...5./.o.p.t./.R.I ----> ^^^^^^^^^^^^ <------------------------------------------- len string 00000708 00 4D 00 2F 00 73 00 64 00 6B 00 2F 00 6C 00 69 00 62 00 2F .M./.s.d.k./.l.i.b./ 0000071C 00 6E 00 65 00 74 00 5F 00 72 00 69 00 6D 00 5F 00 61 00 70 .n.e.t._.r.i.m._.a.p 00000730 00 69 00 2E 00 6A 00 61 00 72 00 28 00 6E 00 65 00 74 00 5F .i...j.a.r.(.n.e.t._ 00000744 00 72 00 69 00 6D 00 5F 00 63 00 6C 00 64 00 63 00 2D 00 31 .r.i.m._.c.l.d.c.-.1 00000758 00 31 00 2E 00 63 00 6F 00 64 00 29 00 00 00 00 00 00 00 00 .1...c.o.d.)........ ------------------------------------> 0000076C 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 03 00 69 00 6E .................i.n ^^^^^^^^^^^  ^^^^^^^^^^^ <---------- ] [ type len string 00000780 00 74 00 00 00 00 00 00 00 0E .t........ ----> ^^^^^^^^^^^^ ^^^^^^^^^^^^ ]] 00000780 00 00 00 00 00 00 00 01 ^^^^^^^^^^^^ ^^^^^^^^^^^^ [[ ]] 00000780 00 00 .......... ^^^^^ [[ 00000794 00 00 00 00 00 00 00 00 00 02 00 00 00 04 00 6D 00 61 00 69 ...............m.a.i ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ <----------------- [ len string 000007A8 00 6E 00 00 00 06 00 00 00 6A 00 00 00 0E 00 00 00 0E 00 00 .n.......j.......... ----> ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ 000007BC 00 1D 00 00 00 01 00 00 00 08 00 00 00 02 00 00 00 04 00 61 ...................a ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ <---- ] [ len 000007D0 00 72 00 67 00 73 00 00 00 08 00 00 00 00 00 00 00 0E 00 00 .r.g.s.............. -----------------> ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ string 000007E4 00 1D 00 00 00 06 00 74 00 68 00 65 00 41 00 70 00 70 00 00 .......t.h.e.A.p.p.. ^^^^^ ^^^^^^^^^^^^ <------------------------------------> ^^^^^ len string 000007F8 00 00 00 00 00 01 00 00 00 17 00 00 00 1D 00 00 00 03 00 00 .................... ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ 0000080C 00 0F 00 00 00 0D 00 00 00 17 00 00 00 0F 00 00 00 1C 00 00 .................... ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ 00000820 00 10 00 00 00 06 00 3C 00 69 00 6E 00 69 00 74 00 3E 00 00 .......<.i.n.i.t.>.. ^^^^^ ^^^^^^^^^^^^ <------------------------------------> ^^^^^ 00000834 00 06 00 00 01 1C 00 00 00 26 00 00 00 26 00 00 00 3A 00 00 .........&...&...:.. ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ 00000848 00 01 00 00 00 00 00 00 00 01 00 00 00 04 00 74 00 68 00 69 ...............t.h.i ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ <----------------- 0000085C 00 73 00 00 00 00 00 00 00 00 00 00 00 26 00 00 00 3A 00 00 .s...........&...:.. ----> ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ 00000870 00 03 00 00 00 27 00 00 00 13 00 00 00 2D 00 00 00 14 00 00 .....'.......-...... ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ 00000884 00 39 00 00 00 15 00 00 00 00 00 00 00 00 00 00 00 01 00 00 .9.................. ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ 00000898 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................... ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ 000008AC 00 03 ^^^^^ ]] 000008AC 00 00 00 00 00 00 00 0A 00 00 00 01 00 00 00 0A 00 5F ..................._  ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ <---- [[ sep type [ len 000008C0 00 72 00 65 00 73 00 6F 00 75 00 72 00 63 00 65 00 73 00 00 .r.e.s.o.u.r.c.e.s.. --------------------------------------------------------> ^^^^^ string 000008D4 00 09 00 00 00 42 00 00 00 04 00 00 00 01 00 00 00 0B 00 5F .....B............._ ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ <---- variable variable ] [ len 000008E8 00 70 00 72 00 6F 00 70 00 65 00 72 00 74 00 69 00 65 00 73 .p.r.o.p.e.r.t.i.e.s --------------------------------------------------------------> string 000008FC 00 00 00 09 00 00 00 42 00 00 00 05 00 00 00 01 00 00 00 09 .......B............ ^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^ variable variable ] [ len 00000910 00 5F 00 61 00 70 00 70 00 49 00 63 00 6F 00 6E 00 73 00 00 ._.a.p.p.I.c.o.n.s.. <-------------------------------------------------------> ^^^^^ string 00000924 00 0B 00 00 00 42 00 00 00 06 00 00 00 01 00 00 00 0C 00 5F .....B............._ ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ <---- variable variable ] [ len 00000938 00 61 00 70 00 70 00 45 00 78 00 74 00 49 00 63 00 6F 00 6E .a.p.p.E.x.t.I.c.o.n 0000094C 00 73 00 00 00 0B 00 00 00 42 00 00 00 07 00 00 00 01 00 00 .s.......B.......... ----> ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ variable variable ] [ len 00000960 00 09 00 5F 00 61 00 70 00 70 00 43 00 6F 00 75 00 6E 00 74 ..._.a.p.p.C.o.u.n.t ^^^^^ <-------------------------------------------------------> string 00000974 00 00 00 0B 00 00 00 42 00 00 00 08 00 00 00 01 00 00 00 13 .......B............ ^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^ variable variable ] [ len 00000988 00 5F 00 72 00 65 00 73 00 6F 00 75 00 72 00 63 00 65 00 45 ._.r.e.s.o.u.r.c.e.E <-------------------------------------------------------------- 0000099C 00 78 00 74 00 65 00 6E 00 73 00 69 00 6F 00 6E 00 73 00 00 .x.t.e.n.s.i.o.n.s.. --------------------------------------------------------> ^^^^^ 000009B0 00 0B 00 00 00 42 00 00 00 09 00 00 00 01 00 00 00 09 00 5F .....B............._ ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ <---- variable variable ] [ len 000009C4 00 61 00 70 00 70 00 4E 00 61 00 6D 00 65 00 73 00 00 00 0B .a.p.p.N.a.m.e.s.... -------------------------------------------------> ^^^^^^^^^^^ variable 000009D8 00 00 00 42 00 00 00 0A 00 00 00 01 00 00 00 09 00 5F 00 61 ...B............._.a ^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^ <---------- variable ] [ len 000009EC 00 70 00 70 00 46 00 6C 00 61 00 67 00 73 00 00 00 0B 00 00 .p.p.F.l.a.g.s...... -------------------------------------------> ^^^^^^^^^^^^ ^^^^^ string variable 00000A00 00 42 00 00 00 0B 00 00 00 01 00 00 00 08 00 5F 00 76 00 65 .B............._.v.e ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ <----------------- variable ] [ len 00000A14 00 72 00 73 00 69 00 6F 00 6E 00 00 00 0B 00 00 00 42 00 00 .r.s.i.o.n.......B.. ------------------------------> ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^ string variable variable 00000A28 00 0C 00 00 00 01 00 00 00 07 00 5F 00 76 00 65 00 6E 00 64 ..........._.v.e.n.d ^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ <------------------------------ ] [ len string 00000A3C 00 6F 00 72 00 00 00 0B 00 00 00 42 00 00 00 0D 00 00 00 02 .o.r.......B........ ----------> ^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^ variable variable ] [ 00000A50 00 00 00 06 00 3C 00 69 00 6E 00 69 00 74 00 3E 00 00 00 06 .....<.i.n.i.t.>.... ^^^^^^^^^^^ <-----------------------------------> ^^^^^^^^^^^ len string variable 00000A64 00 00 00 5C 00 00 00 48 00 00 00 48 00 00 00 5C 00 00 00 01 ...\...H...H...\.... ^^^^^^^^^^^ ^^^^^^^^^^^  ^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^ variable variable variable 00000A78 00 00 00 02 00 00 00 01 00 00 00 04 00 74 00 68 00 69 00 73 .............t.h.i.s ^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^ <----------------------> variable ] [ len 00000A8C 00 00 00 02 00 00 00 00 00 00 00 48 00 00 00 5C 00 00 00 00 ...........H...\.... ^^^^^^^^^^^ ^^^^^^^^^^^  ^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^ variable variable variable 00000AA0 00 00 00 08 00 3C 00 63 00 6C 00 69 00 6E 00 69 00 74 00 3E .....<.c.l.i.n.i.t.> ^^^^^^^^^^^ <------------------------------------------------> len 00000AB4 00 00 00 06 00 00 40 2A 00 00 00 6A 00 00 00 6A 00 00 00 C2 ......@*...j...j.... ^^^^^^^^^^^  ^^^^^^^^^^^ ^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^ 00000AC8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................... 00000ADC 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................... 00000AF0 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 02 .................... 00000B04 00 00 00 06 00 3C 00 69 00 6E 00 69 00 74 00 3E 00 00 00 06 .....<.i.n.i.t.>.... 00000B18 00 00 00 1C 00 00 00 EB 00 00 00 EB 00 00 01 57 00 00 00 01 ...............W.... 00000B2C 00 00 00 04 00 00 00 04 00 00 00 04 00 74 00 68 00 69 00 73 .............t.h.i.s 00000B40 00 00 00 04 00 00 00 00 00 00 00 EB 00 00 01 57 00 00 00 05 ...............W.... 00000B54 00 74 00 69 00 74 00 6C 00 65 00 00 00 0C 00 00 00 01 00 00 .t.i.t.l.e.......... 00000B68 01 08 00 00 01 57 00 00 00 01 00 69 00 00 00 0D 00 00 00 02 .....W.....i........ 00000B7C 00 00 01 1C 00 00 01 4A 00 00 00 03 00 73 00 74 00 72 00 00 .......J.....s.t.r.. 00000B90 00 07 00 00 00 03 00 00 01 25 00 00 01 45 00 00 00 0B 00 00 .........%...E...... 00000BA4 00 EC 00 00 00 1C 00 00 00 F2 00 00 00 1D 00 00 01 08 00 00 .................... 00000BB8 00 1E 00 00 01 0E 00 00 00 20 00 00 01 1A 00 00 00 22 00 00 ......... .......".. 00000BCC 01 21 00 00 00 23 00 00 01 25 00 00 00 25 00 00 01 3B 00 00 .!...#...%...%...;.. 00000BE0 00 27 00 00 01 45 00 00 00 22 00 00 01 4A 00 00 00 2A 00 00 .'...E..."...J...*.. 00000BF4 01 56 00 00 00 2B 00 00 00 05 00 63 00 6C 00 6F 00 73 00 65 .V...+.....c.l.o.s.e 00000C08 00 00 00 06 00 00 00 6C 00 00 00 CB 00 00 00 CB 00 00 00 D9 .......l............ 00000C1C 00 00 00 01 00 00 00 04 00 00 00 01 00 00 00 04 00 74 00 68 .................t.h 00000C30 00 69 00 73 00 00 00 04 00 00 00 00 00 00 00 CB 00 00 00 D9 .i.s................ 00000C44 00 00 00 03 00 00 00 CC 00 00 00 30 00 00 00 D2 00 00 00 32 ...........0.......2 00000C58 00 00 00 D8 00 00 00 33 00 00 00 00 00 00 00 00 00 00 00 05 .......3............ 00000C6C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................... 00000C80 00 00 00 00 00 00 00 07 00 00 00 00 00 00 00 00 00 00 00 00 .................... 00000C94 00 00 00 00 00 00 00 04 00 00 00 07 00 00 00 01 00 00 00 00 .................... 00000CA8 00 00 00 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................... 00000CBC 00 00 00 01 00 00 00 04 00 00 00 0A 00 00 00 01 00 00 00 00 .................... 00000CD0 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................... 00000CE4 00 00 00 04 .... barry-0.18.5/doc/bjdwp/sample/BarryDemo.cod0000644001161500056700000000310012242254476017755 0ustar cdfreycdfreywJ NXK(&V@(-??6(?mmm((X-i-ti - i -i-i-xi -i -i (0 #?0(l?('@V?@n(0#O9$ *(DXB9XnBxn( Dn^^(>LDK^Qqt~x 1.0  BarryDemoNicolas VIVIEN o ... sos.........ca .........pT~AppB@-D;oB@-D;oRIMsosB@-Sc Hashtab~LabMaSc ObjPrSc UiApp[m.. sos_ sos_ sotss_pFgs_pIcs_pN,es_ptIcs_pt_p \ies_v s_vmap`hSc prln.?.. EvDp soBuff 1.04.7.0.61 $BarryDemo $End test... $Start test... $Test number net_rim_cldc&:(((,,,,,&]jH: (((,,hhhHji33HHHqH H ~H H H 'W(**,,,,,7777777 77 78Xg g G g gw 'U P/>K8FE()s(W9(l(B(?()(*(f(6P(V(+`B\Bl<-barry-0.18.5/doc/bjdwp/sample/test.txt0000644001161500056700000001745112242254476017140 0ustar cdfreycdfrey00000000 00 00 00 08 49 D7 8E 6C 00 00 00 00 00 00 00 0B 00 76 00 43 ....I..l.........v.C * * * * 00000014 00 61 00 72 00 64 00 49 00 6D 00 70 00 6F 00 72 00 74 00 00 .a.r.d.I.m.p.o.r.t.. *----- 00000028 00 19 00 00 00 07 00 00 00 06 00 4C 00 6F 00 67 00 67 00 65 ...........L.o.g.g.e -----* * * 0000003C 00 72 00 00 08 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .r...d.............. * * * * * 00000050 00 00 00 00 00 45 00 43 00 3A 00 5C 00 55 00 74 00 69 00 6C .....E.C.:.\.U.t.i.l * * 00000064 00 69 00 74 00 61 00 69 00 72 00 65 00 73 00 5C 00 42 00 6C .i.t.a.i.r.e.s.\.B.l 00000078 00 61 00 63 00 6B 00 42 00 65 00 72 00 72 00 79 00 20 00 4A .a.c.k.B.e.r.r.y. .J 0000008C 00 44 00 45 00 20 00 34 00 2E 00 37 00 2E 00 30 00 5C 00 77 .D.E. .4...7...0.\.w 000000A0 00 6F 00 72 00 6B 00 73 00 70 00 61 00 63 00 65 00 5C 00 76 .o.r.k.s.p.a.c.e.\.v 000000B4 00 43 00 61 00 72 00 64 00 49 00 6D 00 70 00 6F 00 72 00 74 .C.a.r.d.I.m.p.o.r.t 000000C8 00 5C 00 4C 00 6F 00 67 00 67 00 65 00 72 00 2E 00 6A 00 61 .\.L.o.g.g.e.r...j.a 000000DC 00 76 00 61 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 .v.a................ * * * * 000000F0 00 00 00 07 00 00 00 06 00 4F 00 62 00 6A 00 65 00 63 00 74 .........O.b.j.e.c.t * * 00000104 00 00 20 44 00 00 00 00 00 00 00 00 FF FF FF FF 00 00 00 09 .. D................ * * * * 00000118 00 6A 00 61 00 76 00 61 00 2E 00 6C 00 61 00 6E 00 67 00 00 .j.a.v.a...l.a.n.g.. 0000012C 00 28 00 2E 00 2E 00 5C 00 6C 00 69 00 62 00 5C 00 6E 00 65 .(.....\.l.i.b.\.n.e 00000140 00 74 00 5F 00 72 00 69 00 6D 00 5F 00 61 00 70 00 69 00 2E .t._.r.i.m._.a.p.i.. 00000154 00 6A 00 61 00 72 00 28 00 6E 00 65 00 74 00 5F 00 72 00 69 .j.a.r.(.n.e.t._.r.i 00000168 00 6D 00 5F 00 63 00 6C 00 64 00 63 00 2E 00 63 00 6F 00 64 .m._.c.l.d.c...c.o.d 0000017C 00 29 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .).................. * 00000190 00 07 00 00 00 10 00 53 00 6C 00 69 00 64 00 65 00 42 00 75 .......S.l.i.d.e.B.u * * 000001A4 00 74 00 74 00 6F 00 6E 00 46 00 69 00 65 00 6C 00 64 00 00 .t.t.o.n.F.i.e.l.d.. 000001B8 08 24 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 .$.................. 000001CC 00 4F 00 43 00 3A 00 5C 00 55 00 74 00 69 00 6C 00 69 00 74 .O.C.:.\.U.t.i.l.i.t 000001E0 00 61 00 69 00 72 00 65 00 73 00 5C 00 42 00 6C 00 61 00 63 .a.i.r.e.s.\.B.l.a.c 000001F4 00 6B 00 42 00 65 00 72 00 72 00 79 00 20 00 4A 00 44 00 45 .k.B.e.r.r.y. .J.D.E 00000208 00 20 00 34 00 2E 00 37 00 2E 00 30 00 5C 00 77 00 6F 00 72 . .4...7...0.\.w.o.r 0000021C 00 6B 00 73 00 70 00 61 00 63 00 65 00 5C 00 76 00 43 00 61 .k.s.p.a.c.e.\.v.C.a 00000230 00 72 00 64 00 49 00 6D 00 70 00 6F 00 72 00 74 00 5C 00 53 .r.d.I.m.p.o.r.t.\.S 00000244 00 6C 00 69 00 64 00 65 00 42 00 75 00 74 00 74 00 6F 00 6E .l.i.d.e.B.u.t.t.o.n 00000258 00 46 00 69 00 65 00 6C 00 64 00 2E 00 6A 00 61 00 76 00 61 .F.i.e.l.d...j.a.v.a 0000026C 00 00 00 07 00 00 00 00 00 00 00 0D 00 00 00 00 00 00 00 07 .................... 00000280 00 00 00 05 00 46 00 69 00 65 00 6C 00 64 00 00 20 44 00 00 .....F.i.e.l.d.. D.. 00000294 00 00 00 00 00 00 FF FF FF FF 00 00 00 15 00 6E 00 65 00 74 ...............n.e.t 000002A8 00 2E 00 72 00 69 00 6D 00 2E 00 64 00 65 00 76 00 69 00 63 ...r.i.m...d.e.v.i.c 000002BC 00 65 00 2E 00 61 00 70 00 69 00 2E 00 75 00 69 00 00 00 2A .e...a.p.i...u.i...* 000002D0 00 2E 00 2E 00 5C 00 6C 00 69 00 62 00 5C 00 6E 00 65 00 74 .....\.l.i.b.\.n.e.t 000002E4 00 5F 00 72 00 69 00 6D 00 5F 00 61 00 70 00 69 00 2E 00 6A ._.r.i.m._.a.p.i...j 000002F8 00 61 00 72 00 28 00 6E 00 65 00 74 00 5F 00 72 00 69 00 6D .a.r.(.n.e.t._.r.i.m 0000030C 00 5F 00 63 00 6C 00 64 00 63 00 2D 00 38 00 2E 00 63 00 6F ._.c.l.d.c.-.8...c.o 00000320 00 64 00 29 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .d.)................ 00000334 00 00 00 07 00 00 00 0B 00 76 00 43 00 61 00 72 00 64 00 49 .........v.C.a.r.d.I 00000348 00 6D 00 70 00 6F 00 72 00 74 00 00 08 24 00 00 00 00 00 00 .m.p.o.r.t...$...... 0000035C 00 00 00 00 00 02 00 00 00 00 00 00 00 4A 00 43 00 3A 00 5C .............J.C.:.\ 00000370 00 55 00 74 00 69 00 6C 00 69 00 74 00 61 00 69 00 72 00 65 .U.t.i.l.i.t.a.i.r.e 00000384 00 73 00 5C 00 42 00 6C 00 61 00 63 00 6B 00 42 00 65 00 72 .s.\.B.l.a.c.k.B.e.r 00000398 00 72 00 79 00 20 00 4A 00 44 00 45 00 20 00 34 00 2E 00 37 .r.y. .J.D.E. .4...7 000003AC 00 2E 00 30 00 5C 00 77 00 6F 00 72 00 6B 00 73 00 70 00 61 ...0.\.w.o.r.k.s.p.a 000003C0 00 63 00 65 00 5C 00 76 00 43 00 61 00 72 00 64 00 49 00 6D .c.e.\.v.C.a.r.d.I.m 000003D4 00 70 00 6F 00 72 00 74 00 5C 00 76 00 43 00 61 00 72 00 64 .p.o.r.t.\.v.C.a.r.d 000003E8 00 49 00 6D 00 70 00 6F 00 72 00 74 00 2E 00 6A 00 61 00 76 .I.m.p.o.r.t...j.a.v 000003FC 00 61 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 .a.................. 00000410 00 07 00 00 00 0D 00 55 00 69 00 41 00 70 00 70 00 6C 00 69 .......U.i.A.p.p.l.i 00000424 00 63 00 61 00 74 00 69 00 6F 00 6E 00 00 20 44 00 00 00 00 .c.a.t.i.o.n.. D.... 00000438 00 00 00 00 FF FF FF FF 00 00 00 15 00 6E 00 65 00 74 00 2E .............n.e.t.. 0000044C 00 72 00 69 00 6D 00 2E 00 64 00 65 00 76 00 69 00 63 00 65 .r.i.m...d.e.v.i.c.e 00000460 00 2E 00 61 00 70 00 69 00 2E 00 75 00 69 00 00 00 2B 00 2E ...a.p.i...u.i...+.. 00000474 00 2E 00 5C 00 6C 00 69 00 62 00 5C 00 6E 00 65 00 74 00 5F ...\.l.i.b.\.n.e.t._ 00000488 00 72 00 69 00 6D 00 5F 00 61 00 70 00 69 00 2E 00 6A 00 61 .r.i.m._.a.p.i...j.a 0000049C 00 72 00 28 00 6E 00 65 00 74 00 5F 00 72 00 69 00 6D 00 5F .r.(.n.e.t._.r.i.m._ 000004B0 00 63 00 6C 00 64 00 63 00 2D 00 31 00 30 00 2E 00 63 00 6F .c.l.d.c.-.1.0...c.o 000004C4 00 64 00 29 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .d.)................ 000004D8 00 00 00 07 00 00 00 17 00 76 00 43 00 61 00 72 00 64 00 49 .........v.C.a.r.d.I 000004EC 00 6D 00 70 00 6F 00 72 00 74 00 52 00 49 00 4D 00 52 00 65 .m.p.o.r.t.R.I.M.R.e 00000500 00 73 00 6F 00 75 00 72 00 63 00 65 00 73 00 00 00 64 00 00 .s.o.u.r.c.e.s...d.. 00000514 00 00 00 00 00 00 00 00 00 03 00 00 00 11 00 63 00 6F 00 6D ...............c.o.m 00000528 00 2E 00 72 00 69 00 6D 00 2E 00 72 00 65 00 73 00 6F 00 75 ...r.i.m...r.e.s.o.u 0000053C 00 72 00 63 00 65 00 73 00 00 00 16 00 2E 00 2E 00 5C 00 6C .r.c.e.s.........\.l 00000550 00 69 00 62 00 5C 00 6E 00 65 00 74 00 5F 00 72 00 69 00 6D .i.b.\.n.e.t._.r.i.m 00000564 00 5F 00 61 00 70 00 69 00 2E 00 6A 00 61 00 72 00 00 00 00 ._.a.p.i...j.a.r.... 00000578 00 00 00 09 00 00 00 02 00 00 00 00 00 00 00 07 00 00 00 08 .................... 0000058C 00 52 00 65 00 73 00 6F 00 75 00 72 00 63 00 65 00 00 20 44 .R.e.s.o.u.r.c.e.. D 000005A0 00 00 00 00 00 00 00 00 FF FF FF FF 00 00 00 18 00 6E 00 65 .................n.e 000005B4 00 74 00 2E 00 72 00 69 00 6D 00 2E 00 64 00 65 00 76 00 69 .t...r.i.m...d.e.v.i 000005C8 00 63 00 65 00 2E 00 72 00 65 00 73 00 6F 00 75 00 72 00 63 .c.e...r.e.s.o.u.r.c 000005DC 00 65 00 73 00 00 00 2B 00 2E 00 2E 00 5C 00 6C 00 69 00 62 .e.s...+.....\.l.i.b 000005F0 00 5C 00 6E 00 65 00 74 00 5F 00 72 00 69 00 6D 00 5F 00 61 .\.n.e.t._.r.i.m._.a barry-0.18.5/doc/bjdwp/jdwp-suspend.txt0000644001161500056700000000047712242254476017323 0ustar cdfreycdfrey.: JDB command :. ================= jdb> suspend .: Dump :. ========== Legend : <<< : Data received from JDB >>> : Data sent by wrapper JDWP ---- command suspend ---- <<< 00 00 00 0b 00 00 00 16 00 01 08 ........ ... <<< 00 00 00 0b 00 00 00 16 80 00 00 ........ ... barry-0.18.5/doc/USB-capture.txt0000644001161500056700000002057612242254476015666 0ustar cdfreycdfreyCapturing USB Traffic for Fun and Profit ========================================= Capturing USB traffic is critical to reverse engineering your shiny new Linux-incompatible toy. This article documents my experiences with this process in the Barry project, as well as feedback for additional methods of USB capture gleaned from the Barry community. What do these numbers mean? --------------------------- The first step is to get the USB specifications themselves. Fortunately, they are freely available on the internet at http://www.usb.org/ under the Developers section. There are two versions of USB, but the important stuff is similar in both versions. Chapters 9 and 11 document the format of the various descriptor structs involved with communicating with the device, and will be important in decoding some of the data dumps later on. Talking to the device --------------------- Programming the USB device itself does not require a kernel driver. You can do it from user space with the libusb library. This library uses the usbdevfs filesystem under /proc to pass USB messages to the kernel, and the device. As USB is a completely host-driven protocol, meaning that the device itself cannot initiate messages, a simple "make request, wait for response" style of programming is quite sufficient in the majority of cases. Some of the USB capture logs may appear reversed, in that there is a read before the write. Don't be too concerned about that. The stable version of libusb only supports synchronous communication with USB, which forces you to use a write/read cycle. Again, this is sufficient for most cases and is the path you should use when first starting out. Capturing: The Windows Way -------------------------- Your shiny new device probably has some proprietary software, and if you've played with it, you likely have it installed already on some Windows system. This is likely the fastest method to start getting captures. I used the USBsnoop package from: http://benoit.papillault.free.fr/usbsnoop/index.php I was only able to get it to work on a Windows XP Pro system, and as this was the only method I knew of at the time, I kept trying different versions of Windows until I found one that worked. If you have a Windows 2000 or 2002 system, USBsnoop may not work for you, but it is still simple to try. USBsnoop comes as a simple EXE. Whenever you wish to make a capture, you run the program, which installs the capture driver temporarily and presents you with a list of devices to listen to. Click the device, click the Install button, then plug in your device and run the software. The logs generally show up in the windows directory as usbsnoop.log. When you are finished, copy this log somewhere else for safekeeping, click the Uninstall button, and try deleting the log to start fresh for your next capture. Sometimes it requires a reboot to get rid of the log. These captures are very helpful to see the bulk of the protocol. In my experience, USBsnoop can miss some of the very early setup behaviour, but still does a smashing job capturing the heavy duty areas of the protocol. Once you have the logs, you can use the convo.awk script in the Barry src directory, and the translate.cc program to help analyze the data. Other Windows Tools: -------------------- There's a list of additional Windows USB sniffer tools at: http://wiki.wireshark.org/Tools#USB_capture Capturing: The Linux Way, Method 1 ---------------------------------- Recent versions of the Linux kernel in the 2.6 series provide their own way of getting to the low level USB behaviour. In the usbcore driver/module, there is a switch you can turn on with the following command: echo Y > /sys/module/usbcore/parameters/usbfs_snoop All USB data going through the usbdevfs interface (this includes all data transferred through libusb) will be logged from the kernel. This shows up in dmesg output, and /var/log/kern.log on most systems. The sheer amount of data that can be generated in this manner can sometimes overwhelm the dmesg kernel buffer, and some USB messages can be lost. There are two adjustments you can make to combat this. 1) I compile a custom kernel with CONFIG_LOG_BUF_SHIFT=21, the largest I can make it. I also have a custom patch that limits the size of the USB capture data. This patch for kernel 2.6.26.8 is included in the doc/ directory, and should be relatively easy to apply to other kernel versions. 2) Some distributions have syslog configured to send kernel messages to multiple logfile destinations. Change this to only one location, and disable any setting that forces a sync after each log message. This will boost logging speed, and reduce the chances of missing messages. Normally, this involves a syslog.conf line like this: kern.* -/var/log/kern.log You may only want to disable the sync temporarily, as normally, you want to guarantee that important kernel messages get saved. The data captured is very raw, in disorganized hex. Use the ktrans program in the tools/ directory to convert it to something readable. But what if you only have a Windows driver? The nice thing is that VMWare uses the usbdevfs interface to share USB devices with the virtual machines. So, install windows in a VMWare session, install your proprietary drivers and software, and watch the logging goodness appear from Linux. As of December 2006, you can still download a free version of VMWare server from: http://www.vmware.com/download/server/ Capturing: The Linux Way, Method 2 ---------------------------------- This method is independent of the usbdevfs driver, to my knowledge, and is the main method of debugging USB problems under Linux. It can also be used to capture traffic that is sent by a virtual machine such as VirtualBox or VMWare. Recent versions of the Linux kernel provide a binary interface to the usbmon logging method. You can simply cat the /sys/kernel/debug/usb/usbmon/1u file, depending on your bus number, for a text version of the capture, but the data is limited to 32 bytes. This is not sufficient for many of the bulk data transfers used by the BlackBerry. Wireshark 1.2.x plus libpcap 1.0 or higher will use the /dev/usbmon* devices to capture the full binary USB traffic. Wireshark can also export this data in plain text format, if the GUI display does not work for you. Barry includes a copy of the command line usbmon-6 tool in the source tree. If you are capturing vast amounts of data, this is the tool to use. It is not guaranteed that the binary interface will capture all data if the system is really busy. If this is a concern, renice your VM and wireshark appropriately. For more low level information on the usbmon binary interface, see the file Documentation/usb/usbmon.txt in the Linux kernel sources. Capturing: The VMWare way ------------------------- If you're running VMWare anyway, it has a built-in capability to log USB traffic. In addition, the Virtual USB Analyzer project provides a graphical way of viewing USB traffic, and can be found here: http://vusb-analyzer.sourceforge.net/ There is a tutorial there, describing how to configure VMWare to log USB traffic, and how to make use of those logs with vusb-analyzer. Capturing: The RIM way ---------------------- It was reported on the mailing list back in 2009 that it is possible to add the following entries to the Windows Registry to cause RIM's software to create verbose logs in your temp directory. Apparently this also enables sniffing the communication with the BlackBerry simulator. Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RimUsb\Parameters] "FileDump"=dword:00000001 "ServiceDebug"=dword:ffffffff This feature may have changed in more recent releases of RIM's Windows software, so your mileage may vary. Capturing: The expensive hardware way ------------------------------------- Toby Gray reports: If you've got (quite a lot of) money to spend then you could also go for a hardware USB analyzer, such as the LeCroy Advisor T3 (http://www.lecroy.com/protocolanalyzer/protocoloverview.aspx?seriesid=280). Capturing: The BeagleBoard way ------------------------------ There is also a project that makes use of the BeagleBoard (http://beagleboard.org/) to make it behave as a proxy, to sniff USB traffic. You can find more about it here: http://elinux.org/BeagleBoard/GSoC/2010_Projects/USBSniffer Happy Hacking! Chris Frey barry-0.18.5/doc/barry-research.ods0000644001161500056700000006646512242254476016462 0ustar cdfreycdfreyPK-d9l9..mimetypeapplication/vnd.oasis.opendocument.spreadsheetPK-d9Configurations2/statusbar/PK-d9'Configurations2/accelerator/current.xmlPKPK-d9Configurations2/floater/PK-d9Configurations2/popupmenu/PK-d9Configurations2/progressbar/PK-d9Configurations2/menubar/PK-d9Configurations2/toolbar/PK-d9Configurations2/images/Bitmaps/PK-d9 content.xml]FOA, %"ؙ8 lϬ,vR7){~;ΓlQ.ITE,Q۹|Թ|f}CYɫape$L8uǗz㫟_Ot&J%E/L¿NYry$7Ex.P j'y~䯣,xq,TӔO7MAi'__]=z8LW&[,(F3T_sT+%,w(ޚNu?[&݋׷{jvbÇ DDoAp|𗫿>lN;VVY^iiZ`ڃ{7@xx0OU^'z[I;&*7"?z<:s{qA3Ͷ[,eqy I4WJ7 '1!W"}})i^Y5k>.,fWx9=J)q=o>I^1?4 Sz 44S(x]樗.xz䯋lX}G{Š"]pzv,gqYm 7O#Y+;Gop{*cb,m{OXO"DX|3~oJ5MJfe:%l AV-tL4 f}eV]i -P3W,'4);ςgy+*=ޗgb /X) 5ޥhOa8$.a =ml蔦}.)6k\58Ջ,*ACpn,? VD1ëgQnE jS)t@G 'JtÁGA*t'Zq[ʺsX{ r(M/`mK8f*DA:?䪚j)2lgc=^2K`UT f~H2p9nӛAV4É=rp!C^F|3lVy{<L&|y^z6$37] `t14s`3di Àp#]Yq~OFJDfW`0֊Nj(`r$\퀸"F!P4VRԂHh+f+wn,=rѬW҆jڮ1ϻ| Pu3#U6ފfa+yD5L<+Kd3˵JW-6(lDyƑ/2T֓sa$erѕ;.:=bٕ*v9u"֟ntcGZo9"\.u;"}iѯԔw9]ݭ򰛮z^(Q3w%-JF;_5ġq QOT1Į[>_._Jp-2DB֕TVowtb}@yխ#zUe"_6uesbb4\Ğ_.^re[v3bz"A3YڔYԫ(b,GQ$ ît(^h /tk0K+VM:jX4<'eJo <9뗑P;% T^%aF/Q]?SYkN)&릆"͐Z:ʥ(Sţ6'>Lp: 6m:QќG&Bxd72MMYy[ɺ]Xė_0q*0A /kZc4?&zoCC;W8CcC/{D?K &m ^K,;6AhB 6f"C4؇;N 5耄b ],j>}o?r!"s|yTJgl"zUؾ#vlbO{-&؇ beOsD=j%0VdӞ_&FyPy~1-Af,9՛]3a.vV kb3@$ aS~Q:$$!uSpR#߷"8>4t.q=G:Dj1J<_E YP ~ܥˢZFV6><&g ۣC+=Б" \z9Fw i1 Sw{9!í -K|"ǂ3QK=GAT/h9c b(Ct3tEq*0~zjQ E<:35K^HQ F#,fD=H8qPRzD$("yֻ[2{pH/VT#ʕ0b%FPj ui;i$H+kZɋA*VR&:g]ȅ@C~q "M8-6-b8SۚxK]{n1VH5J\cP^NhTͳehyc2Dg *hMoiY*jCŹ -dLFɨ>NmP#.^!dºҮ"e֘(S@ڔ5N\4Eq&i̦0s}1%9fR./=MLAɄ;0p5L4*h~A%WԞdM]ESDS`j-s& 62M6tL@&C&/WMdBɈ@Firu\Nj-x'{oݾp5o1`{Re n\ L,Gx<ʿoe΃"{4\G7_.^>m>H"4 b== /#Ⱈy m#ƹY0 )JDx7`F1{-\:pؾ;'csF*>= O@帺0|lu|X琸q L5yݞ,2@@>?t"Ecl:xS2aI\py/(Wp&0G`* |Mq&4؍IrNI,04pn?ӑ4W3 mClB kX$B?an?:P#q &zL:VŲO' % `|"$ډ2بFjL'M'Jh\(y@O r r.:E|AE 40UL=:zt2=-l^pؘ)m!ds&$6WzTK]QB1I;; nJLoNF05$3GfcL&N^ Ym\M?[zYݦG-(`? EZ JB65TXB`GŽdzQG:b-m.L'RRB}CCai]FpǪ#lPMDu9ڇB)@:Q-R5ܙ`lMqhf.8BM bK >N*Ȭ/Э{KdlU"ڂ[ybـ[f5nY˘% w!-4޷'25mwJbbd &:+1z΀tau¤ht_gpg |X#U}s[@K ex@y?w"Υfi1 SwK,ǀ2Kz,\! GԄN:萊ߣ *Jh9c b6b e+!Dhg[l%-U|ypϨiIVS/އ 3d:&u,cC ee ]Jާ`?I0Ϣzk]GNZ6/3^QWqb(!qe,cD Qe݄K݆(S ~ByBdFض Q7H1 'ohaFhm%ߡj7bZ(C%ʾ?1IYb"eրLLlr[$1t5)mM閭r\ q ./΃b,[x͗ d(ַ,X="\#qsIi#HLZ0} efJvYV̫;?S5N7p2rΪyR"[2CbV;ʱeOd[.:-ْY;DRIqDڕeZs!& .P!Za`u,9i2*(t0ˑ4FU3dl giZTrAl-Q9{K2(=$4  XHIۗ LO }om-Ԃ-:OX&d(M` [tI 4xQJeRD #Q t@qkUc{[X+X"܍d$c' Tƨ06.&v&JZ%*a 3 *}~7LZ͇j>SV=[&^l,Yb$c'2WhkAW7 {nwJ+$c)QC(#Xߵpli1}Gm;*lvhr/N 4_y/(w` l n'lE9 T$eMfMe˜!R8]ؾr 2p13Y14c=MշN 8*ڢ8HWd,:R^Q7m¡wԴ o(&(cCcd]ھ2>]5>]5>]5>]S0>](A*sLY=6!|PJ Kjf.yulY33qYSfg0t=kg~JʗsO,ɨJzF2w)^έ^Ю.5.u#?{1?l}@yܣ*..-1XRin(af* E:8Mpo|X̞{ FۯIw*z9h VӣA~i_)]qzLqђ/A3*a43</6.49Φ&ĸ+_@/r4fn糁Mg7_Ӥ@Ia}. Y翬HWS6>F?jNّ#6RAM9*sDle *}rT#Xs-)] ]LJ6щ8$ZG.t9һTƯXkjhUB;Ş`% }ۮwf(CbCe+'DVR yU:q46Qѩ tw]0⪗z'<=4vci06qԺt݄. BeIC-I%3" #)?elJ-,ca!L.lM * [/ȚJ9?>c'\) &}q ZsӚTQDC: +̇.DOq;Yd=zUBO\<24LkKlkJZP5mIP!kzZ64B~`K 6JtP!K!ѱ;m00l5%uAl,]C8JphFK%E-sKDpu_t~;utAyPA@ۻN#?.>(72=w' 9oVH fyj=UizgEq9X_ >v?v vu17Ąn(%1R=]EI=oE(1 e0*kqKݾA!GX΃6D\y44#а-c04pg.JD' C͙594xN?*f{rV\^WkMsZ=|$j'lȯ_<_E YP ~ܥˢE@A!~6CQ¢> |X#5@`& ex@ygoR"N}Ẑ8i1b1򄂂ed/>2򺁹.0mt=ߣ *Jh9c bq3l@ !Dd֌l%-U|ypϨ)Fq#VU0ZЄw!reĖ0]G5I! YXoc-czBPalx|y>gbGV6ݞw3'RrDkؘtzwk}1'L $So`EA_L@Znv?7 {p#M^W/5M7f i^8A~^Vc,')I]z'MN wjMUۚCesD@9 n+erbaN[Pw|L*~%q.'z"-dAnl46JP`w]WӒkI%*2 *2,U%:Qt@:NJQW})k,o4J't/'y˛9xY50Ρ[dim%jL'45{ZkT@FRT>}LUP!ޭ[WM۵+ j> w< SuW#D8>*kus5W?ML:6t$u;5XnpDl2"&8V,cˤ{ހ2/C v S`Aiwm]7 ѩv?7DM!L% QO[KT}8@Pni#٩gȱUOu&G;ol~ax]jKJ_qz;tYWtUJY@Ol =Z_?uWWn kcdwn2I]>?%.zKJ81:L\iJJ5- ŜlYwqXA`/H[|m-HP X5aκ%ay: d:$jSjA]HQ~h P7%+8`Dvv+u`#duGx-#R\۽^tUɒ%ͭiP=@y-5POLTrʡLZh„ԠP:;~Zr\6e^$;*Ǚzn% :u>g!BONChrOϞ } AXC/mǛ|8i]iS$8 u/0gU33qMF { W sg&=F-8Ia֒(v{PSy`,4 $S[k2J /L3?P~4cPro~RcϒY3}.s(ܾh:4 RPq'n|_P P<>ƋdT<-wAy Ҳ}hn\?s93 xY3C?+ 1c5};\-K9镊n:u㤑c#^ E JRՂ43 ,O 6gܚ/6_%Ă7wwwa_XK4Qveki[?l3|2p@9fߐIbbБS7X!::"sza# (0ZQ" H!7 Ghuu^4An| 4MheR酧zxN6PK}yPK-d9H`meta.xml OpenOffice.org/2.4$Linux OpenOffice.org_project/680m17$Build-9310Martin Owens2008-11-03T22:59:51Martin Owens2008-11-04T00:45:525PT1H15M9SPK-d9Thumbnails/thumbnail.pngzeX\A-!ݥq' Xp&hHp4݂K.ڍ#{g{^>N:jڻ׮XpppXJrߣpp/P=g|RaD3A,8QNp5Q(Pu]]]W^=l:<あog| A$*6Ks4̾μ'%]YPn`^'F$smZGc7s*1(.qWFD4ʼ\!k_ߺ-u9) Ip]D֭h#Ͳ=}`2溥v}Z zMؕ#Fj?8^l;~3| ݁xFE92Qi`Od逵´JoV~^}#-s\Vϧ*;BM黳ō(cC-K=dd#NLm2!-Q..Ie)Kt=ݥ"k"O1檍ԵTPf_J]jCQʅQO"PHSoBEWYCT%^b]$lDh-s;( v G]_2]VP|>OY.HTT]Pa`:))A1!0e]CLa{3'AI[8ET5mäT, 5W3A+sXew_m/B`ROSֹT u$h:՗S[Gܾhe*[%Sf<l1LϪ ʪ+~Sy[3/9\_p+ όH'1uR3RMb^CyޜW1)"?:)r4-b;d~΢[Ė_1 qI1^d yE!V64!mHǃy-AwO7#ʌ$"| 쌥e(" .t.qP_f>.b/hJp,l\K yu\]tQǏՈpM # vE },+B =+6Юg/[BslVxM]9Σp5 `&Ad~r Bmľrr邕ēF!RdUC7r jJ/(nYޟbRۖuA_zFΆpQ'}ye8Sn'+빛._K#H,̵؄U[CmȻ܈-vX%*eXz=0}`qmibq>!h[/`V,\ +U/]ėfOeAJVB|o^=}K.q^Ъ_33z|YA%ˆW}8N,=,iₘ'AUx^,t{/cI}/rIDD=+_&/ߩ,~J,Jd Y1a[XX'~?˜T ^TfpTJC"=AVǏjsV8{rsK^Op/It| )*;-YȣJT_.poݶNG=_b$Yd}9"w8KBTtFb543E.wJP!9"z8Cssq9I55v+ *BߒK W+Bn7gs/KBwͣs319FTbE+h a MQrRޅ"e9ryrWngRZ86l`c)Pm%ֆI+ݾWhY6۲X\!'1cJ?w[өaQ}H>DRu  vW[-E ꠪Xśܾ׼SJ=D 9= aY_Ѳ (d\~fMx YRe6."~IK 3474x`hYOj×+ ͊kϺT'._۱ ?:Vfb:{ Q 4{}c.S΋K ۯw7-Y M= Jntۋ+@p<atk ^{cp'1^QOEI[+.E٨0<ЋTl'!?3ݨnEɒ|X:J3{Hwr[? ԔlPSj^䕛t6X,.xWx)b^.>c9W2Hi+`qZ|R)F*_i;<5đ6ҡΝ RRՑ]c%mCWˋ*͉ ,̊O]y9~)7a#\z iwla_)4q;A1ḞAŸ.]͍m3)dOHʌ߷s\Ǜ*2O'=B."hI˩GR m>²q"oJos~dm㌺AݒnaY9nb^F`oj-ݗO.M'/GX7YW:X;DvCdZJX~sSH3Sh#`3N+77"Tײz;~ݺ#ڨhtCيvNto[X:v*8Jb-@=]޿&e4Svĥ'ߑ ^]<|Q\*k،]68ʠ4ê eq[nǷ0 Z{?.7_|+x84D= Aj0,SuFE毹Bs>#7NTSͺ8&))(99gp負ԁ~S?|ʺXw0yI%@#;f6mF)!Kwz\yʺ!&-䍙I8: ϊF@|8a+-37IT#Ĩ /xt{\xn{HD xXLdyɂ&xG"{rK8Ëqkq1u°el$M{acXbK=nF 3 oBFR|CĒbZ9BzGǎA!R':vk`w}#LzuVnx_&o :g@6`p>floM,mk\2׌ 4?(R3i&i0`,)T-?bn-u `K^t֋aPI @>l{BC#3mRj|k-z*#+Zka5"tɁgWaEwL4OW уC rБ#dJF3c㸗( 9] & ZxWоwCprb\|L=u֙Ӈm.+vn[~V-]M0tS3\ؤ2`&Z'h!_5m2sxU;,1\:=q]}jKtڋ y!bioE'7hcʀcd<fc4Lia(&SY[1ce [D挭M/(ܙFYGD'~5} B2Vy>FR%)cB׋ݚx?D\ Q6AE[Vgr[a㪬(#/zWgG[܈pmdϑf pgq}ȋ$z[7 ǃ(A>oDp~xw~̳.G1XAA hۙ{ Ȏa^ѳ=E&-蘃sceMJp0WAF*8 ռ#|FbN6c̖G{̮JAGF#l`j;O+#;uc_HMLH_*r׿eII?u!EF1(̜fohݲfeo̼e]Vɳi\ Ib–qgCOnX;)nXQ22bbܼqaQIBtcC`F̣ugve,o1wJ H~NHTtz_J8zkPAŻw/,leE K1\q޺0m YؙF\B'Y6p9l\=5RZҴ@7V"bCr$FJC&Uwv{ejkDywscbR6D 'H1v9*jg`/HU[x&&q>ش;5x֋xds$AnW985'{eb>9&iZ9ڶڪǹDmAV5À"[nW,mZeAQ7~m$/W"SH$L -5sƝs %h:*z?pmǯ _;Z3x}H[bv8o07M߮Kqhw*\0+l<ڞ"v=B*Ɲ(Ke~}yUDڣ~Me)myDP}c ˻/?hF:k#x#tR 2 ?jUPne]t{/|!^ 'IJ9:5xZ+Pt>ļմ: TyV*xe+\j KUs^Yk(pJ\Sؠ]w O:玣J_EK9R6/i/F,~z9E䘫2hS>";h`hDl/ u> 9mZ0ffڠ?u-um0Rˊ(ی{,`>H%u^WWhݰ2G<`iQKKNR71+Suզ%!j Ùp|u~X}e4 0.AG50L&讜}YvI8ܕI2ūlzy<\Hpw1˃93K$U@Xk*۩Casn3H"eE5&xէ֑ˇw Gh4;PZ[]{M p G*gP!^Ԯ#9:=cR"\V4\\9[,@;ZP 4*Qz]T:@v q76V[C8\. &jRD c܊-oax,1ڤ nk54LL#rXoh9+D:98uMf0X(IVuSa~BB6:)=> -P8۶n{bN]87ؐB8 T 'U׆(ڢlX;d8x"OG/^Ъ@3I{R -}T"љ ۟Slvo-&{śGipñ,28Dn*0ӓZR $֣Ze I埒pJҩA`xY  p]OjΪswu R^Kـ J~mKQΦWXaTR:")JPq$"鑭VÿƘ3f6(cTz<,H<A<t[CىV5myTPPwov'P]q}Ô1@Mi:,tΚI8t40 p#O+<*Ӽhа96}].jt)-*dh/E,K=GFUsKJӳj-7 ,qb30Ӫi+o"m~mcn~l/%ڼ1)ڬpQt{Nx3yu*v{BwnLK;!3;+}|ԟ&G1‘Bm;` Zl?Ff7bRxɗ!@2$7P-nnFdNN6kO#*'J4ܮH&c)OYS9 k~4ftAQD9?W4r\Zf*}>/Tb2Yg9x+̟):f*@;dhK1ۿe y԰p[a Cqu濕SO ~= (:;{Z_v=)&nX芽K01iw aa o=xH8Oej_jlP7Z3xRݽ$VV=SC C@6"S8GppNQabc\ 7: ay!4舼.A$Kȑ@H(9{ \ft!9 +Gd:E *s_(>%||oNHnIR4ԌIjhh"*WnpYФxn  r5#S ʕZkZj.W͂.PB] u-ԵP6BULάQ9؜YSBVSír d! 9UUb-rH C@3 Q읚Yq *DjOqs D1bV W[`o92iCr-ň͉?) ]̊WrWbI]P}x;tMe%ӝ/:1~HJ ?vo{oҋ/w{ה?.Q}jN^%^K[F aNTGU_Sl+7C YX r"yP#g; OHO9u]QJ5ˀ  g1gP? 'u5aI^Ɗ'_}۵7 zD饐+7>:ַwT@RJOϾ CYłoY.z3j4iĘ{`쿐S9BΒ+O2O>PK\J)PK-d9META-INF/manifest.xmlKj0@=VU1q-&fW6X; HFi[S0Oͣ)k7vc^aaӠNZu`ZVzEdZ>T yb`yʝ뛣V4"BO[DȐRȻ)o zL =KbDe̡Rbw c!x!|R!|cD*wS)F$B;ߟ Jn&F] Ýr=˩Wo³̿sivE6ٍmHi7 ȜsiǷPKMfBQPK-d9l9..mimetypePK-d9TConfigurations2/statusbar/PK-d9'Configurations2/accelerator/current.xmlPK-d9Configurations2/floater/PK-d9Configurations2/popupmenu/PK-d9QConfigurations2/progressbar/PK-d9Configurations2/menubar/PK-d9Configurations2/toolbar/PK-d9Configurations2/images/Bitmaps/PK-d9{Wb' 4content.xmlPK-d9}y )styles.xmlPK-d9H`/meta.xmlPK-d9BG,/03Thumbnails/thumbnail.pngPK-d9\J) Ycsettings.xmlPK-d9MfBQgMETA-INF/manifest.xmlPK1ibarry-0.18.5/desktop/0000755001161500056700000000000012242254476013725 5ustar cdfreycdfreybarry-0.18.5/desktop/po/0000755001161500056700000000000012242254476014343 5ustar cdfreycdfreybarry-0.18.5/desktop/po/insert-header.sin0000644001161500056700000000124012242254476017605 0ustar cdfreycdfrey# Sed script that inserts the file called HEADER before the header entry. # # At each occurrence of a line starting with "msgid ", we execute the following # commands. At the first occurrence, insert the file. At the following # occurrences, do nothing. The distinction between the first and the following # occurrences is achieved by looking at the hold space. /^msgid /{ x # Test if the hold space is empty. s/m/m/ ta # Yes it was empty. First occurrence. Read the file. r HEADER # Output the file's contents by reading the next line. But don't lose the # current line while doing this. g N bb :a # The hold space was nonempty. Following occurrences. Do nothing. x :b } barry-0.18.5/desktop/po/boldquot.sed0000644001161500056700000000033112242254476016666 0ustar cdfreycdfreys/"\([^"]*\)"/“\1”/g s/`\([^`']*\)'/‘\1’/g s/ '\([^`']*\)' / ‘\1’ /g s/ '\([^`']*\)'$/ ‘\1’/g s/^'\([^`']*\)' /‘\1’ /g s/“”/""/g s/“/“/g s/”/”/g s/‘/‘/g s/’/’/g barry-0.18.5/desktop/po/fr.po0000644001161500056700000015320012242254476015313 0ustar cdfreycdfrey# Barry Desktop French Translation # Copyright (C) YEAR Net Direct, Inc. # This file is distributed under the same license as the Barry Desktop package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: barrydesktop 0.18.5\n" "Report-Msgid-Bugs-To: http://netdirect.ca/barry\n" "POT-Creation-Date: 2013-04-02 18:54-0400\n" "PO-Revision-Date: 2012-08-22 19:48+0100\n" "Last-Translator: Nicolas CARRIER \n" "Language-Team: Barry\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: ..\n" #: src/BaseFrame.cc:73 src/BaseFrame.cc:283 src/BaseFrame.cc:855 #: src/Mode_MainMenu.h:49 msgid "Barry Desktop Control Panel" msgstr "Panneau de contrôle Barry Desktop" #: src/BaseFrame.cc:109 msgid "&Verbose Logging" msgstr "Journal &Verbeux" #: src/BaseFrame.cc:110 msgid "Enable low level USB debug output" msgstr "Activer la sortie de debogage USB bas niveau " #: src/BaseFrame.cc:111 msgid "Re&name Device..." msgstr "Re&nommer le périphérique..." #: src/BaseFrame.cc:112 msgid "Re&set Device" msgstr "Réinitiali&ser le périphérique" #: src/BaseFrame.cc:113 msgid "&Rescan USB" msgstr "&Re-scanner l'USB" #: src/BaseFrame.cc:115 msgid "&About..." msgstr "&A propos..." #: src/BaseFrame.cc:117 msgid "E&xit" msgstr "&Quitter" #: src/BaseFrame.cc:157 msgid "No device selected" msgstr "Pa de périphérique sélectionné" #: src/BaseFrame.cc:174 msgid "No devices available" msgstr "Pas de périphérique disponible" #: src/BaseFrame.cc:209 msgid "Main Menu" msgstr "Menu principal" #: src/BaseFrame.cc:333 msgid "The Backup program is already running!" msgstr "Le programme de sauvegarde est déjà en cours de fonctionnement !" #: src/BaseFrame.cc:334 src/BaseFrame.cc:339 src/BaseFrame.cc:741 msgid "Backup and Restore" msgstr "Sauvegarder et restaurer" #: src/BaseFrame.cc:355 msgid "" "An error occurred that prevented the loading of Sync\n" "mode. This is most likely because a critical piece\n" "of OpenSync is missing. Check that all required\n" "plugins are installed, and that tools like 'bidentify'\n" "can find your BlackBerry(R) successfully.\n" "\n" "Error: " msgstr "" "Une erreur est survenue qui empêche de charger le\n" "mode synchronisation. Ceci, est certainement dû à\n" "l'absence d'un composant critique d'OpenSync.\n" "Vérifiez que tous les greffons requis sont installés\n" "et que les outils tels que 'bidentify' parviennent à\n" "identifier votre Blackberry®.\n" "\n" "Erreur : " #: src/BaseFrame.cc:362 msgid "Sync Mode" msgstr "Mode de synchronisation" #: src/BaseFrame.cc:376 msgid "Please select a device first." msgstr "Veuillez au préalable choisir un périphérique." #: src/BaseFrame.cc:377 msgid "No Device" msgstr "Pas de périphérique" #: src/BaseFrame.cc:670 msgid "" "An error occurred during device migration.\n" "This could be due to a low level USB issue\n" "Please make sure your device is plugged in\n" "and not in Desktop Mode. If it is, try replugging\n" "the device, and rescanning the USB bus from the menu.\n" "\n" "Error: " msgstr "" "Un erreur est survenue lors de la migration\n" "du périphérique.\n" "Ceci peut-être dû à un problème USB bas\n" "niveau. Veuillez vous assurer que votre\n" "périphérique est branché et qu'il n'est pas\n" "en mode Desktop. Si c'est bien le cas,\n" "tentez de le rebrancher et de scanner l'USB\n" "de nouveau depuis le menu.\n" "\n" "Erreur :" #: src/BaseFrame.cc:678 src/MigrateDlg.cc:101 msgid "Migrate Device" msgstr "Migrer le périphérique" #: src/BaseFrame.cc:687 msgid "" "There is no device selected in the device list. Please select a device to " "browse." msgstr "" "Aucun périphérique n'est sélectionné depuis la liste. Veuillez en " "sélectionner un à parcourir." #: src/BaseFrame.cc:688 src/BaseFrame.cc:706 msgid "Database Browser Mode" msgstr "Mode Parcours de base de données" #: src/BaseFrame.cc:698 msgid "" "An error occurred that prevented the loading of Database\n" "Browse mode. This could be due to a low level USB\n" "issue. Please make sure your device is plugged in\n" "and not in Desktop Mode. If it is, try replugging\n" "the device, and rescanning the USB bus from the menu.\n" "\n" "Error: " msgstr "" "Une erreur est survenue, empêchant d'activer le mode\n" "Parcours de base de données.\n" "Ceci peut-être dû à un problème USB bas\n" "niveau. Veuillez vous assurer que votre\n" "périphérique est branché et qu'il n'est pas\n" "en mode Desktop. Si c'est bien le cas,\n" "tentez de le rebrancher et de scanner l'USB\n" "de nouveau depuis le menu.\n" "\n" "Erreur :" #: src/BaseFrame.cc:740 msgid "" "Unable to run barrybackup, or it returned an error. Please make sure it is " "installed and in your PATH." msgstr "" "Le lancement de barrybackup a échoué, ou il a retourné une erreur. Veuillez " "vous assurer qu'il est bien installé et présent dans votre PATH." #: src/BaseFrame.cc:809 msgid "Please enter a name for the current device:" msgstr "Veuillez entrer un nom pour le périphérique courant : " #: src/BaseFrame.cc:810 msgid "Rename Device" msgstr "Renommer le périphérique" #: src/BaseFrame.cc:857 msgid "" "A Free Software graphical user interface for working with the BlackBerry® " "smartphone." msgstr "" "Logiciel libre avec interface graphique fonctionnant avec les smartphones " "BlackBerry®." #: src/BaseFrame.cc:878 msgid "Chris Frey - GUI interface" msgstr "Chris Fery - Interface graphique" #: src/BaseFrame.cc:879 msgid "Martin Owens - Barry logo" msgstr "Martin Owens - Logo de Barry" #: src/BaseFrame.cc:880 msgid "Tango Desktop Project - Public domain icons" msgstr "Projet Tango Desktop - Icônes du domaine public" #: src/CUI_Barry.cc:87 #, c-format msgid "" "Please select the databases you wish to erase\n" "on device: %s\n" "\n" "Note: all synced databases must be erased\n" "to avoid a slow-sync." msgstr "" "Veuillez sélectionner les bases de données\n" "que vous voulez effacer du périphérique : %s\n" "\n" "Note : toutes les bases de données\n" "synchronisées doivent être effacées pour\n" "éviter une synchronisation lente." #: src/CUI_Barry.cc:117 src/CUI_Google.cc:111 msgid "Select Databases to Erase" msgstr "Sélectionner les bases de données à effacer" #: src/CUI_Barry.cc:123 msgid "" "You have selected the following databases to be completely erased from " "device: " msgstr "" "Vous avez choisi les bases de données suivantes qui vont être complètement " "effacées du périphérique : " #: src/CUI_Barry.cc:128 src/CUI_Google.cc:122 msgid "Proceed with erase?" msgstr "Procéder à l'effacement ?" #: src/CUI_Barry.cc:130 src/CUI_Google.cc:124 msgid "Erase Confirmation" msgstr "Confirmation d'effacement" #: src/CUI_Barry.cc:148 msgid "No database named '" msgstr "Pas de base de données nommée '" #: src/CUI_Barry.cc:148 msgid "' in device!" msgstr "' sur le périphérique !" #: src/CUI_Barry.cc:152 msgid "Clearing db: " msgstr "Effacement de la bdd :" #: src/CUI_Barry.cc:160 msgid "Barry exception: " msgstr "Exception Barry :" #: src/CUI_Barry.cc:161 msgid "You may need to do a USB reset and rescan from the main menu." msgstr "" "Il vous est peut-être nécessaire de réinitialiser et re-scanner l'USB depuis " "le menu principal." #: src/CUI_Barry.cc:164 msgid "Barry Exception" msgstr "Exception Barry" #: src/CUI_Evolution.cc:77 msgid "Stop waiting" msgstr "Arrêter d'attendre" #: src/CUI_Evolution.cc:103 msgid "Evolution shutdown" msgstr "Fermeture d'Evolution" #: src/CUI_Evolution.cc:158 msgid "" "Unable to automatically detect Evolution's configuration.\n" "You need to run Evolution, and manually click each of the\n" "section buttons:\n" "\n" " Mail, Contacts, Calendars, Memos, and Tasks\n" "\n" "Then quit Evolution to continue configuration.\n" "\n" "Would you like to start Evolution now?\n" msgstr "" "Impossible de détecter automatiquement la configuration\n" "d'Evolution. Vous devez lancer Evolution et cliquermanuellement sur chacun " "des boutons des sections : \n" "\n" " Courrier, Contacts, Calendriers, Memos etTâches\n" "\n" "Puis quitter Evolution et continuer la configuration.\n" "\n" "Voulez-vous lancer Evolution maintenant ?\n" #: src/CUI_Evolution.cc:168 src/CUI_Evolution.cc:190 src/CUI_Evolution.cc:206 msgid "Evolution Config" msgstr "Configuration d'Evolution" #: src/CUI_Evolution.cc:178 msgid "Waiting for Evolution to exit..." msgstr "Attente de la fermeture d'Evolution" #: src/CUI_Evolution.cc:179 msgid "Evolution Running" msgstr "Evolution en cours de fonctionnement" #: src/CUI_Evolution.cc:190 src/CUI_Evolution.cc:206 msgid "" "Failed to run evolution. Please make sure it is installed and in your PATH." msgstr "" "Échec au lancement d'Evolution. Veuillez vous assurer qu'il est installé et " "présent dans votre PATH." #: src/CUI_Evolution.cc:309 msgid "Evolution already running." msgstr "Evolution est déjà en cours d'exécution." #: src/CUI_Evolution.cc:310 src/CUI_KDEPim.cc:86 msgid "Oops..." msgstr "Oups..." #: src/CUI_Evolution.cc:319 msgid "" "Starting Evolution. Delete all contacts and/or calendar entries manually, " "depending on your sync configuration." msgstr "" "Démarrage d'évolution. Supprimez toutes vos entrées de contacts et/ou de " "calendriers manuellement, en fonction de votre configuration de " "synchronisation." #: src/CUI_Evolution.cc:324 msgid "" "Starting Evolution. Delete all objects (contacts, calendar, memos, and " "tasks, depending on your sync configuration)." msgstr "" "Démarrage d'évolution. Supprimez tous les objets (contacts, calendriers, " "mémos et tâches, selon votre configuration de synchronisation)." #: src/CUI_Evolution.cc:328 msgid "Starting Evolution" msgstr "Démarrage d'évolution" #: src/CUI_Google.cc:96 msgid "" "Please select the databases you wish to erase\n" "in your Google Calendar: \n" "\n" "Note: all synced databases must be erased\n" "to avoid a slow-sync." msgstr "" "Veuillez sélectionner les bases de données\n" "que vous souhaitez supprimer de votre\n" "calendrier Google :\n" "\n" "Note : toutes les bases de données doivent\n" "être effacées pour éviter une synchronisation\n" "lente." #: src/CUI_Google.cc:106 msgid "Calendar" msgstr "Calendrier" #: src/CUI_Google.cc:107 src/GroupCfgDlg.cc:322 msgid "Contacts" msgstr "Contacts" #: src/CUI_Google.cc:117 msgid "" "You have selected the following databases to be completely erased from your " "Google Calendar:" msgstr "" "Vous avez sélectionné les bases de données suivantes, qui vont être " "supprimées de votre calendrier Google :" #: src/CUI_KDEPim.cc:59 msgid "KDEPim needs no configuration." msgstr "KDEPim ne nécessite aucune configuration." #: src/CUI_KDEPim.cc:59 msgid "KDEPim Config" msgstr "Configuration de KDEPim." #: src/CUI_KDEPim.cc:85 msgid "Kontact already running." msgstr "Kontact est déjà en cours d'exécution." #: src/CUI_KDEPim.cc:95 msgid "Starting Kontact. Delete all contacts and calendar entries manually." msgstr "" "Démarrage de Kontact. Suppression de toutes les entrées de contacts et de " "calendries manuellement." #: src/CUI_KDEPim.cc:100 msgid "" "Starting Kontact. Delete all contacts and calendar entries manually (as " "well as memos and tasks if you are syncing them too)." msgstr "" "Démarrage de Kontact. Suppression de toutes les entrées de contacts et de " "calendries manuellement (de même que les mémos et les tâches si vous les " "synchronisez également)." #: src/CUI_KDEPim.cc:105 msgid "Starting Kontact" msgstr "Démarrage de Kontact" #: src/CalendarEditDlg.cc:42 msgid "Calendar Record" msgstr "Enregistrement de calendrier" #: src/CalendarEditDlg.cc:64 msgid "Subject:" msgstr "Sujet : " #: src/CalendarEditDlg.cc:66 msgid "Location:" msgstr "Emplacement :" #: src/CalendarEditDlg.cc:69 msgid "All Day Event:" msgstr "Événement sur toute une journée : " #: src/CalendarEditDlg.cc:71 msgid "Start:" msgstr "Début : " #: src/CalendarEditDlg.cc:76 msgid "End:" msgstr "Fin : " #: src/CalendarEditDlg.cc:81 msgid "Duration:" msgstr "Durée : " #: src/CalendarEditDlg.cc:83 src/CalendarEditDlg.cc:109 msgid "hours and" msgstr "heures et" #: src/CalendarEditDlg.cc:85 src/CalendarEditDlg.cc:111 msgid "minutes." msgstr "minutes." #: src/CalendarEditDlg.cc:86 src/TaskEditDlg.cc:103 msgid "Time Zone:" msgstr "Zone de temps :" #: src/CalendarEditDlg.cc:88 msgid "System Time Zone" msgstr "Zone de temps système" #: src/CalendarEditDlg.cc:91 msgid "Show As:" msgstr "Apparaître comme :" #: src/CalendarEditDlg.cc:101 msgid "Free" msgstr "Libre" #: src/CalendarEditDlg.cc:102 msgid "Tentative" msgstr "Provisoire" #: src/CalendarEditDlg.cc:103 msgid "Busy" msgstr "Occupé" #: src/CalendarEditDlg.cc:104 msgid "Out of Office" msgstr "Sorti" #: src/CalendarEditDlg.cc:107 src/TaskEditDlg.cc:108 msgid "Reminder:" msgstr "Rappel : " #: src/CalendarEditDlg.cc:113 src/TaskEditDlg.cc:115 msgid "Recurrence:" msgstr "Fréquence : " #: src/CalendarEditDlg.cc:124 src/TaskEditDlg.cc:126 msgid "None" msgstr "Aucun" #: src/CalendarEditDlg.cc:125 src/TaskEditDlg.cc:127 msgid "Daily" msgstr "Journalier" #: src/CalendarEditDlg.cc:126 src/TaskEditDlg.cc:128 msgid "Weekly" msgstr "Hebdomadaire" #: src/CalendarEditDlg.cc:127 src/TaskEditDlg.cc:129 msgid "Monthly" msgstr "Mensuel" #: src/CalendarEditDlg.cc:128 src/TaskEditDlg.cc:130 msgid "Yearly" msgstr "Annuel" #: src/CalendarEditDlg.cc:131 src/TaskEditDlg.cc:133 msgid "Interval:" msgstr "Intervalle :" #: src/CalendarEditDlg.cc:132 src/TaskEditDlg.cc:134 msgid "Every" msgstr "Tous les" #: src/CalendarEditDlg.cc:134 src/TaskEditDlg.cc:136 msgid "days? weeks? months?" msgstr "jours ? semaines ? mois ? " #: src/CalendarEditDlg.cc:135 src/TaskEditDlg.cc:137 msgid "Days:" msgstr "Jours : " #: src/CalendarEditDlg.cc:143 src/TaskEditDlg.cc:145 msgid "Relative Date:" msgstr "Date relative :" #: src/CalendarEditDlg.cc:145 src/TaskEditDlg.cc:147 msgid "End Date:" msgstr "Date de fin : " #: src/CalendarEditDlg.cc:146 src/TaskEditDlg.cc:148 msgid "Never ends" msgstr "Ne s'achève jamais" #: src/CalendarEditDlg.cc:149 msgid "Organizer:" msgstr "Organiseur :" #: src/CalendarEditDlg.cc:151 msgid "Invited:" msgstr "Invité :" #: src/CalendarEditDlg.cc:153 msgid "Accepted By:" msgstr "Accpeté par :" #: src/CalendarEditDlg.cc:164 msgid "Public" msgstr "Public" #: src/CalendarEditDlg.cc:165 msgid "Private" msgstr "Privé" #: src/CalendarEditDlg.cc:166 msgid "Confidential" msgstr "Confidentiel" #: src/CalendarEditDlg.cc:168 msgid "Class" msgstr "Classe" #: src/CalendarEditDlg.cc:170 src/TaskEditDlg.cc:153 msgid "Notes:" msgstr "Notes : " #: src/CalendarEditDlg.cc:181 src/TaskEditDlg.cc:164 msgid "Assume Local Timezone" msgstr "Sélectionner la zone de temps locale" #: src/CalendarEditDlg.cc:302 msgid "Calendar Event" msgstr "Événement de calendrier" #: src/CalendarEditDlg.cc:326 src/CalendarEditDlg.cc:329 #: src/TaskEditDlg.cc:246 src/TaskEditDlg.cc:249 msgid "Set Reminder to 0 to disable" msgstr "Mettre le rappel à 0 pour le désactiver" #: src/CalendarEditDlg.cc:342 src/CalendarEditDlg.cc:343 #: src/TaskEditDlg.cc:262 src/TaskEditDlg.cc:263 msgid "" "Relative monthly or yearly dates take the weekday of the start date into " "account. (eg. every first Sunday of month)" msgstr "" "Les fréquences annuelle et mensuelle relatives prennent en compte le jour de " "la semaine de la date de départ. (ex : chaque premier samedi du mois)" #: src/CalendarEditDlg.cc:642 msgid "Start time must come before end time." msgstr "Le moment de début doit précéder le moment de fin." #: src/CalendarEditDlg.cc:643 msgid "Validation Error" msgstr "Erreur de validation" #: src/CalendarEditDlg.cc:827 src/TaskEditDlg.cc:705 msgid "day(s)" msgstr "jour(s)" #: src/CalendarEditDlg.cc:831 src/TaskEditDlg.cc:709 msgid "week(s)" msgstr "semaine(s)" #: src/CalendarEditDlg.cc:835 src/TaskEditDlg.cc:713 msgid "month(s)" msgstr "mois(s)" #: src/CalendarEditDlg.cc:839 src/TaskEditDlg.cc:717 msgid "year(s)" msgstr "années(s)" #: src/ConflictDlg.cc:93 msgid "Sync Conflict" msgstr "Conflit de synchronisation" #: src/ConflictDlg.cc:315 msgid "XML..." msgstr "XML..." #: src/ConflictDlg.cc:321 msgid "Select" msgstr "Choisir" #: src/ConflictDlg.cc:340 msgid "No XML map found." msgstr "Aucune table XML trouvée." #: src/ConflictDlg.cc:391 msgid "Always use this choice" msgstr "Toujours utiliser ce choix" #: src/ConflictDlg.cc:397 msgid "Duplicate" msgstr "Dupliquer" #: src/ConflictDlg.cc:403 msgid "Ignore" msgstr "Ignorer" #: src/ConflictDlg.cc:409 msgid "Keep Newer" msgstr "Garder le plus récent" #: src/ConflictDlg.cc:415 msgid "Abort" msgstr "Annuler" #: src/ConflictDlg.cc:421 src/SyncStatusDlg.cc:360 src/SyncStatusDlg.cc:371 #: src/SyncStatusDlg.cc:604 src/SyncStatusDlg.cc:608 msgid "Kill Sync" msgstr "Interrompre la synchronisation" #: src/ConflictDlg.cc:492 msgid "Raw Change Data" msgstr "Données de changement brutes" #: src/ContactEditDlg.cc:37 msgid "Contact Record" msgstr "Enregistrement de contact" #: src/ContactEditDlg.cc:50 msgid "Home" msgstr "Domicile" #: src/ContactEditDlg.cc:51 msgid "Work" msgstr "Travail" #. TRANSLATORS: this is a main screen button label #: src/ContactEditDlg.cc:52 src/util.cc:65 msgid "Misc" msgstr "Divers" #: src/ContactEditDlg.cc:53 msgid "Mobile" msgstr "Mobile" #: src/ContactEditDlg.cc:54 src/GroupCfgDlg.cc:328 msgid "Notes" msgstr "Notes" #: src/ContactEditDlg.cc:55 src/Mode_Sync.cc:182 msgid "Name" msgstr "Nom" #: src/ContactEditDlg.cc:57 msgid "Title" msgstr "Titre" #: src/ContactEditDlg.cc:59 #, fuzzy msgid "First" msgstr "Premier" #: src/ContactEditDlg.cc:61 #, fuzzy msgid "Last" msgstr "Dernier" #: src/ContactEditDlg.cc:63 msgid "Company" msgstr "Société" #: src/ContactEditDlg.cc:65 msgid "Job Title" msgstr "Titre professionnel" #: src/ContactEditDlg.cc:67 msgid "Nickname" msgstr "Surnom" #: src/ContactEditDlg.cc:69 src/ContactEditDlg.cc:89 msgid "Address" msgstr "Adresse" #: src/ContactEditDlg.cc:73 src/ContactEditDlg.cc:93 msgid "City" msgstr "Cille" #: src/ContactEditDlg.cc:75 src/ContactEditDlg.cc:95 msgid "Province" msgstr "Département" #: src/ContactEditDlg.cc:77 src/ContactEditDlg.cc:97 msgid "Postal Code" msgstr "Code postal" #: src/ContactEditDlg.cc:79 src/ContactEditDlg.cc:99 msgid "Country" msgstr "Pays" #: src/ContactEditDlg.cc:83 src/ContactEditDlg.cc:103 msgid "Phone" msgstr "Téléphone" #: src/ContactEditDlg.cc:85 src/ContactEditDlg.cc:105 msgid "Phone 2" msgstr "Téléphone 2" #: src/ContactEditDlg.cc:87 src/ContactEditDlg.cc:107 msgid "Fax" msgstr "Fax" #: src/ContactEditDlg.cc:109 msgid "Email" msgstr "Courriel" #: src/ContactEditDlg.cc:111 msgid "Other Phone" msgstr "Autre téléphone" #: src/ContactEditDlg.cc:113 msgid "Old Phone" msgstr "Ancien téléphone" #: src/ContactEditDlg.cc:115 #, fuzzy msgid "Radio" msgstr "Radio" #: src/ContactEditDlg.cc:117 src/Mode_Sync.cc:180 msgid "PIN" msgstr "PIN" #: src/ContactEditDlg.cc:119 msgid "User1" msgstr "Utilisateur1" #: src/ContactEditDlg.cc:121 msgid "User2" msgstr "Utilisateur2" #: src/ContactEditDlg.cc:123 msgid "User3" msgstr "Utilisateur3" #: src/ContactEditDlg.cc:125 msgid "User4" msgstr "Utilisateur4" #: src/ContactEditDlg.cc:127 #, fuzzy msgid "Cell" msgstr "Cellulaire" #: src/ContactEditDlg.cc:129 msgid "Cell 2" msgstr "Cellulaire 2" #: src/ContactEditDlg.cc:131 msgid "Pager" msgstr "Bipeur" #: src/ContactEditDlg.cc:134 msgid "URL" msgstr "URL" #: src/ContactEditDlg.cc:150 msgid "Contact" msgstr "Contact" #: src/ContactEditDlg.cc:183 msgid "" "Comma separated list of simple email addresses. Do not use <> characters." msgstr "" "Liste d'adresses courriel simples, séparées par des virgules. Ne pas " "utiliser de <>." #: src/ContactEditDlg.cc:346 msgid "Load new photo" msgstr "Choisir une nouvelle photo" #: src/ContactEditDlg.cc:347 msgid "Save current photo to disk" msgstr "Enregistrer la photo actuelle sur le disque" #: src/ContactEditDlg.cc:348 msgid "Delete current photo" msgstr "Supprimer la photo courante" #: src/ContactEditDlg.cc:351 msgid "A photo currently exists. Would you like to:" msgstr "Une photo existe déjà. Voulez-vous : " #: src/ContactEditDlg.cc:352 msgid "Photo Management" msgstr "Gestion de photos" #: src/ContactEditDlg.cc:398 msgid "" "A contact record must contain either a First/Last name, or a Company name." msgstr "Un contact doit contenir au moins un nom/prénom, ou un nom de société." #: src/ContactEditDlg.cc:399 src/MemoEditDlg.cc:113 msgid "Required Fields" msgstr "Champs requis" #. TRANSLATORS: this is the first part of a file selector string, #. as in: "Images files (*.bmp;*.jpg;*.png)" #. The file types are not part of the translation. #: src/ContactPhotoWidget.cc:43 msgid "Image files" msgstr "Fichiers d'images" #. TRANSLATORS: this is a file selector string. See "Image files" #. for more info. #. TRANSLATORS: this is a file selector string, #. see "Image files" for more info. #: src/ContactPhotoWidget.cc:47 src/Mode_Browse.cc:1090 msgid "All files" msgstr "Tous les fichiers" #: src/ContactPhotoWidget.cc:87 msgid "There is no photo available to save." msgstr "Il n'y a pas de photo à sauvegarder." #: src/ContactPhotoWidget.cc:88 msgid "No Photo" msgstr "Pas de photo" #. TRANSLATORS: this is a file selector string. See "Image files" #. for more info. #: src/ContactPhotoWidget.cc:95 msgid "JPEG files" msgstr "Fichiers JPEG" #: src/ContactPhotoWidget.cc:98 msgid "Save Photo as JPEG..." msgstr "Enregistrer la photo en JPEG..." #: src/ContactPhotoWidget.cc:110 msgid "Load Photo..." msgstr "Ouvrir une photo..." #: src/ContactPhotoWidget.cc:119 msgid "Unable to load selected photo." msgstr "Impossible d'ouvrir la photo choisie." #: src/ContactPhotoWidget.cc:120 msgid "Photo Load Error" msgstr "Erreur à l'ouverture de photo" #: src/ContactPhotoWidget.cc:128 msgid "Unable to convert image to JPEG." msgstr "Impossible de convertir l'image en JPEG." #: src/ContactPhotoWidget.cc:129 msgid "Photo Convert" msgstr "Conversion de photo" #: src/ContactPhotoWidget.cc:172 src/Mode_Sync.cc:262 msgid "No" msgstr "Non" #: src/ContactPhotoWidget.cc:172 msgid "Photo" msgstr "Photo" #: src/EvoCfgDlg.cc:32 msgid "Evolution Plugin Configuration" msgstr "Configuration du greffon Evolution" #: src/EvoCfgDlg.cc:51 msgid "Address Book:" msgstr "Carnet d'adresses : " #: src/EvoCfgDlg.cc:58 msgid "Calendar:" msgstr "Calendrier :" #: src/EvoCfgDlg.cc:65 msgid "Tasks:" msgstr "Tâches : " #: src/EvoCfgDlg.cc:72 msgid "Memos:" msgstr "Mémos : " #: src/EvoCfgDlg.cc:169 #, c-format msgid "File '%s' does not exist." msgstr "Le fichier '%s' n'existe pas." #: src/EvoCfgDlg.cc:181 msgid "" "No paths set! If there are no default options available in the drop down " "lists, please double check that you've initialized your Evolution account " "first." msgstr "" "Pas de chemins définis ! S'il n'y a pas de choix par défaut dans les listes " "déroulantes, veuillez vérifier que vous avez configuré votre compte " "Evolution au préalable." #: src/EvoCfgDlg.cc:194 msgid "Minimum Config Required" msgstr "Configuration minimale requise" #: src/EvoDefaultDlg.cc:36 msgid "Evolution Success" msgstr "Succès Evolution" #: src/EvoDefaultDlg.cc:52 msgid "Successfully auto-detected Evolution configuration!" msgstr "Auto-détection de la configuration Evolution réussie !" #: src/EvoDefaultDlg.cc:61 msgid "Manual Cfg..." msgstr "Configuration manuelle..." #: src/GroupCfgDlg.cc:57 msgid "Device Sync Configuration" msgstr "Configuration de la synchronisation de périphérique" #: src/GroupCfgDlg.cc:80 msgid "Must have at least one engine in GroupCfgDlg" msgstr "Au moins un moteur doit être présent dans GroupCfgDlg" #: src/GroupCfgDlg.cc:86 msgid "Configure Device - " msgstr "Configurer un périphérique - " #: src/GroupCfgDlg.cc:140 msgid "" "No supported applications found. You may need to install some opensync " "plugins." msgstr "" "Aucune d'application supportée trouvée. Il est peut-être nécessaire " "d'installer des greffons opensync." #: src/GroupCfgDlg.cc:141 msgid "No App Found" msgstr "Pas d'application trouvée" #: src/GroupCfgDlg.cc:162 msgid "OpenSync Engine" msgstr "Moteur OpenSync" #: src/GroupCfgDlg.cc:199 msgid "Barry Config" msgstr "Configuration de Barry" #: src/GroupCfgDlg.cc:205 msgid "Name:" msgstr "Nom : " #: src/GroupCfgDlg.cc:214 src/ModemDlg.cc:65 msgid "Password:" msgstr "Mot de passe : " #: src/GroupCfgDlg.cc:224 msgid "Debug output during sync" msgstr "Afficher des options de débogage lors de la synchronisation" #: src/GroupCfgDlg.cc:233 src/Mode_Sync.cc:186 msgid "Application" msgstr "Application" #: src/GroupCfgDlg.cc:261 msgid "&Configure..." msgstr "&Configuration" #: src/GroupCfgDlg.cc:277 msgid "No engine selected" msgstr "Pas de moteur sélectionné" #: src/GroupCfgDlg.cc:286 msgid "Exception caught in LoadAppNames: " msgstr "Exception attrapée dans LoadAppNames : " #: src/GroupCfgDlg.cc:311 msgid "No supported plugins available" msgstr "Aucun greffon supporté disponible" #: src/GroupCfgDlg.cc:319 msgid "Sync:" msgstr "Synchronisation : " #: src/GroupCfgDlg.cc:325 msgid "Events" msgstr "Événements" #: src/GroupCfgDlg.cc:331 msgid "To-dos" msgstr "Taches à faire" #. TRANSLATORS: these 3 strings are options for default #. conflict resolution during syncing #: src/GroupCfgDlg.cc:343 msgid "Favour device" msgstr "Périphérique préféré" #: src/GroupCfgDlg.cc:344 msgid "Favour application" msgstr "Application préférée" #: src/GroupCfgDlg.cc:345 msgid "Ask me" msgstr "Demandez-moi" #: src/GroupCfgDlg.cc:348 msgid "To Resolve Conflicts:" msgstr "Pour résoudre les conflits : " #: src/GroupCfgDlg.cc:491 msgid "Please select an application." msgstr "Veuillez choisir une application." #: src/GroupCfgDlg.cc:492 src/GroupCfgDlg.cc:500 src/GroupCfgDlg.cc:588 msgid "Application Config" msgstr "Configuration de l'application" #: src/GroupCfgDlg.cc:499 msgid "No configuration interface available for this Application." msgstr "Pas d'interface de configuration disponible pour cette application." #: src/GroupCfgDlg.cc:566 msgid "Please select an engine." msgstr "Veuillez sélectionner un moteur." #: src/GroupCfgDlg.cc:567 src/GroupCfgDlg.cc:574 msgid "Device Config" msgstr "Configuration du périphérique" #: src/GroupCfgDlg.cc:573 msgid "Barry doesn't have a PIN number. This should never happen." msgstr "Barry n'a pas de code PIN. Ceci ne devrait jamais arriver." #: src/GroupCfgDlg.cc:587 msgid "The application plugin is not fully configured." msgstr "Le greffon de l'application n'est pas complètement configuré." #: src/GroupCfgDlg.cc:615 msgid "Please select conflict resolution method." msgstr "Veuillez sélectionner une méthode de résolution de conflit." #: src/GroupCfgDlg.cc:616 msgid "Conflict Resolution" msgstr "Résolution de conflit" #: src/MemoEditDlg.cc:36 msgid "Memo Record" msgstr "Enregistrement de mémo" #: src/MemoEditDlg.cc:49 msgid "Title:" msgstr "Titre : " #: src/MemoEditDlg.cc:51 src/TaskEditDlg.cc:151 msgid "Categories:" msgstr "Catégories : " #: src/MemoEditDlg.cc:64 msgid "Memo" msgstr "Mémo" #: src/MemoEditDlg.cc:68 msgid "Comma separated" msgstr "Séparés par des virgules" #: src/MemoEditDlg.cc:70 msgid "Comma separated list of categories (can be empty)" msgstr "Liste de catégories, séparées par des virgules (peut être vide)" #: src/MemoEditDlg.cc:73 msgid "Body of memo" msgstr "Corps du mémo" #: src/MemoEditDlg.cc:112 msgid "Please enter a title for your memo." msgstr "Veuillez entrer un titre pour votre mémo" #: src/MigrateDlg.cc:144 msgid "Migrate device data from source device to target device." msgstr "" "Faire migrer les données du périphérique source vers le périphérique cible." #: src/MigrateDlg.cc:167 msgid "Ready..." msgstr "Prêt..." #: src/MigrateDlg.cc:189 msgid "Source device" msgstr "Périphérique source" #: src/MigrateDlg.cc:207 msgid "Migrate Now" msgstr "Faire migrer maintenant" #: src/MigrateDlg.cc:212 msgid "Cancel" msgstr "Annuler" #: src/MigrateDlg.cc:221 #, fuzzy msgid "Prompt to plug in later..." msgstr "Demander de brancher plus tard" #: src/MigrateDlg.cc:229 msgid "Destination device" msgstr "Périphérique cible" #. TRANSLATORS: these 4 strings are write-mode options in the #. Migrate Device dialog #: src/MigrateDlg.cc:242 msgid "Erase all, then restore" msgstr "Effacer tout puis restaurer" #: src/MigrateDlg.cc:243 msgid "Add new, and overwrite existing" msgstr "Ajouter un nouveau et écraser l'existant" #: src/MigrateDlg.cc:244 msgid "Add only, don't overwrite existing" msgstr "Ajouter seulement, ne pas écraser l'existant" #: src/MigrateDlg.cc:245 msgid "Add every record as a new entry (may cause duplicates)" msgstr "" "Ajouter chaque nouvel enregistrement comme une nouvelle entrée (peut " "provoquer des doublons)" #: src/MigrateDlg.cc:247 msgid "Write Mode:" msgstr "Mode d'écriture :" #: src/MigrateDlg.cc:275 msgid "Waiting for thread to close..." msgstr "Attente de la fin du thread..." #: src/MigrateDlg.cc:336 msgid "" "Please select a source and destination device, as well as the write mode." msgstr "" "Veuillez sélectionner des périphériques source et destination, ainsi que le " "mode d'écriture." #: src/MigrateDlg.cc:337 msgid "Migration Options Needed" msgstr "Options de migration requises" #: src/MigrateDlg.cc:343 msgid "Cannot migrate from and to the same PIN." msgstr "Impossible de migrer depuis et vers le même PIN." #: src/MigrateDlg.cc:344 msgid "Migration Options Error" msgstr "Erreur d'option de migration" #: src/MigrateDlg.cc:371 msgid "Invalid write mode. This should never happen. Contact the developers." msgstr "" "Mode d'écriture invalide. Ceci ne devrait pas se produire. Contactez les " "développeurs." #: src/MigrateDlg.cc:372 msgid "Internal Logic Error" msgstr "Erreur de logique interne" #: src/MigrateDlg.cc:412 msgid "Waiting for thread..." msgstr "En attente du thread..." #: src/MigrateDlg.cc:421 msgid "Cancelled by user..." msgstr "Annulé par l'utilisateur..." #: src/MigrateDlg.cc:439 msgid "Please plug in the target device now." msgstr "Veuillez brancher le périphérique cible maintenant." #: src/MigrateDlg.cc:440 msgid "Ready for Writing" msgstr "Prêt à écrire" #: src/MigrateDlg.cc:450 msgid "Scanning USB for devices..." msgstr "Balayage USB à la recherche de périphérique..." #: src/MigrateDlg.cc:469 msgid "User input..." msgstr "Saisie utilisateur..." #: src/MigrateDlg.cc:474 msgid "Please select the target device to write to:" msgstr "Veuillez sélectionner le périphérique cible : " #: src/MigrateDlg.cc:475 msgid "Destination PIN" msgstr "PIN de destionation" #: src/MigrateDlg.cc:487 msgid "Cannot use the same device PIN as migration destination." msgstr "Impossible d'utiliser le même PIN comme cible pour la migration." #: src/MigrateDlg.cc:488 msgid "Invalid Device Selection" msgstr "Sélection de périphérique invalide" #: src/MigrateDlg.cc:522 src/Mode_Browse.cc:258 #, c-format msgid "Please enter device password: (%d tries remaining)" msgstr "Veuillez entrer le mot de passe du périphérique : (%d essais restants)" #: src/MigrateDlg.cc:527 src/Mode_Browse.cc:263 msgid "Device Password" msgstr "Mot de passe du périphérique" #: src/MigrateDlg.cc:533 msgid "Migration Error" msgstr "Erreur de migration" #: src/MigrateDlg.cc:593 msgid "Connecting..." msgstr "Connexion en cours..." #: src/MigrateDlg.cc:645 msgid "Backing up database: " msgstr "Sauvegarde de la base de données :" #: src/MigrateDlg.cc:672 msgid "Backup aborted by user..." msgstr "Sauvegarde annulée par l'utilisateur..." #: src/MigrateDlg.cc:693 msgid "Connecting to target..." msgstr "Connexion à la cible en cours..." #: src/MigrateDlg.cc:734 msgid "Writing database: " msgstr "Écriture de la base de données :" #: src/MigrateDlg.cc:765 msgid "Restore aborted by user..." msgstr "Restauration annulée par l'utilisateur..." #: src/MigrateDlg.cc:771 msgid "Unable to clear or write to database: " msgstr "Impossible d'effacer ou d'écrire la base de données : " #: src/MigrateDlg.cc:774 msgid "Continuing to process remaining records..." msgstr "Traitement des enregistrements restants en cours..." #: src/MimeExportDlg.cc:41 #, fuzzy msgid "MIME Card Data" msgstr "Données de carte MIME" #: src/MimeExportDlg.cc:48 msgid "Save..." msgstr "Enregistrer..." #: src/MimeExportDlg.cc:78 msgid "Save Card as..." msgstr "Enregistrer la carte sous..." #: src/Mode_Browse.cc:71 msgid "" "This database is apparently read-only. If this device is connected to a " "BES, you cannot edit records via USB. (Error: " msgstr "" "Cette base de données semble être en lecture seule. Si ce périphérique est " "connecté à un serveur BES, vous ne pouvez pas modifier d'enregistrement par " "USB.(Erreur : " #: src/Mode_Browse.cc:72 msgid "Device Error" msgstr "Erreur de périphérique" #. TRANSLATORS: this is a file selector string, #. see "Image files" for more info. #: src/Mode_Browse.cc:94 msgid "VCard files" msgstr "Fichiers VCARD" #. TRANSLATORS: this is a file selector string, #. see "Image files" for more info. #: src/Mode_Browse.cc:107 msgid "ICalendar files" msgstr "Fichiers ICalendar" #: src/Mode_Browse.cc:290 msgid "raw data" msgstr "Données brutes" #: src/Mode_Browse.cc:368 msgid "DataCachePtr has no builder" msgstr "DataCachePtr n'a pas de constructeur" #: src/Mode_Browse.cc:385 msgid "Device exception: " msgstr "Exception du périphérique : " #: src/Mode_Browse.cc:554 msgid "" "Delete this record?\n" " " msgstr "" "Supprimer cet enregistrement ?\n" " " #: src/Mode_Browse.cc:555 msgid "Record Delete" msgstr "Suppression d'enregistrement" #: src/Mode_Browse.cc:599 msgid "Failed to create map mutex" msgstr "Échec à la création d'un mutex de table" #: src/Mode_Browse.cc:603 msgid "Failed to create load mutex" msgstr "Échec à la création d'un mutex de chargement" #: src/Mode_Browse.cc:738 msgid "Loading: " msgstr "Chargement : " #: src/Mode_Browse.cc:791 msgid "Show All Databases" msgstr "Montrer toutes les bases de données" #: src/Mode_Browse.cc:821 msgid "Import..." msgstr "Importer..." #: src/Mode_Browse.cc:824 msgid "Export..." msgstr "Exporter..." #: src/Mode_Browse.cc:827 msgid "Add..." msgstr "Ajouter..." #: src/Mode_Browse.cc:830 msgid "Copy..." msgstr "Copier..." #: src/Mode_Browse.cc:833 msgid "Edit..." msgstr "Éditer..." #: src/Mode_Browse.cc:836 msgid "Delete..." msgstr "Supprimer..." #: src/Mode_Browse.cc:857 msgid "Databases" msgstr "Bases de données" #: src/Mode_Browse.cc:859 msgid "Count" msgstr "Nombre" #: src/Mode_Browse.cc:867 msgid "Record Description" msgstr "Description de l'enregistrement" #: src/Mode_Browse.cc:1069 #, c-format msgid "Card file type (%s) does not match record you are trying to add (%s)." msgstr "" "Le type de carte (%s) ne correspond pas à l'enregistrement que vous essayez " "d'insérer (%s)." #: src/Mode_Browse.cc:1072 msgid "Invalid Card Type" msgstr "Type de carte invalide" #: src/Mode_Browse.cc:1095 msgid "Load Record..." msgstr "Charger un enregistrement..." #: src/Mode_Browse.cc:1106 msgid "No card data found in: " msgstr "Pas de données de carte trouvées dans : " #: src/Mode_Browse.cc:1107 msgid "Import Read Error" msgstr "Erreur de lecture à l'import" #: src/Mode_Browse.cc:1154 #, c-format msgid "Unable to import selected file: %s" msgstr "Impossible d'importer le fichier sélectionné : %s" #: src/Mode_Browse.cc:1155 msgid "Import Error" msgstr "Erreur d'importation" #: src/Mode_Browse.cc:1164 msgid "Internal pointer error: cannot find DBCachePtr for: " msgstr "" "Erreur interne de pointeur : Impossible de trouver un DBCachePtr pour : " #: src/Mode_Browse.cc:1165 src/Mode_Browse.cc:1180 msgid "Internal Error" msgstr "Erreur interne" #: src/Mode_Browse.cc:1179 msgid "Internal error: cannot add record to DBCache" msgstr "Erreur interne : Impossible d'ajouter un enregistrement au DBCache" #: src/Mode_Browse.h:99 msgid "Failed to create mutex for ThreadableDesktop" msgstr "Échec à la création d'un mutex pour ThreadableDesktop" #: src/Mode_Browse.h:469 msgid "Barry Database Browser" msgstr "Navigateur de base de données de Barry" #: src/Mode_MainMenu.cc:57 msgid "Ignorable screenshot exception: " msgstr "Exception capture d'écran pouvant être ignorée : " #: src/Mode_Sync.cc:75 msgid "" "Multiple configurations have been found with the same PIN. Please select\n" "the configuration that Barry Desktop should work with." msgstr "" "Plusieurs configuration ont été trouvées pour un même PIN. Veuillez\n" "sélectionner la configuration que Barry Desktop devrait utiliser." #: src/Mode_Sync.cc:125 msgid "Select the device(s) you want to sync and press Sync Now." msgstr "" "Sélectionnez le périphérique que vous voulez synchroniser et appuyez sur " "Synchroniser maintenant." #: src/Mode_Sync.cc:126 msgid "Use Configure to configure the currently selected device." msgstr "" "Utilisez Configure pour configurer le périphérique sélectionné actuellement." #: src/Mode_Sync.cc:127 msgid "Use Run App to start the application that the device syncs with." msgstr "" "Utiliser Lancer l'application pour lancer l'application avec laquelle le " "périphérique se synchronise." #: src/Mode_Sync.cc:128 msgid "" "Use 1-Way Reset to recover from a broken sync, copying all device data to " "application, or vice versa." msgstr "" "Utiliser la réinitialisation à sens unique pour récupérer un échec de " "synchronisation, copie de toutes les données depuis le périphérique vers " "l'application, ou vice-versa." #: src/Mode_Sync.cc:140 src/Mode_Sync.cc:507 msgid "Device List" msgstr "Liste de périphériques" #: src/Mode_Sync.cc:153 src/SyncStatusDlg.cc:349 msgid "Run App" msgstr "Lancer une application" #: src/Mode_Sync.cc:156 msgid "Configure..." msgstr "Configurer..." #: src/Mode_Sync.cc:159 msgid "1 Way Reset..." msgstr "Réinitialisation à sens unique..." #: src/Mode_Sync.cc:184 msgid "Connected" msgstr "Connecté" #: src/Mode_Sync.cc:188 msgid "Engine" msgstr "Moteur" #: src/Mode_Sync.cc:190 msgid "Last Sync" msgstr "Dernière synchronisation" #: src/Mode_Sync.cc:262 msgid "Yes" msgstr "Oui" #: src/Mode_Sync.cc:270 msgid "(No config)" msgstr "(Pas de configuration)" #: src/Mode_Sync.cc:363 src/Mode_Sync.cc:678 msgid "An application is currently running." msgstr "Une application est en cours d'exécution." #: src/Mode_Sync.cc:364 src/Mode_Sync.cc:706 msgid "Run App Error" msgstr "Erreur de lancement d'application" #: src/Mode_Sync.cc:390 msgid "Config is the same, skipping save" msgstr "Configuration inchangée, pas de sauvegarde" #: src/Mode_Sync.cc:447 msgid "" "Unable to save configuration for this device.\n" "Error: " msgstr "" "Impossible de sauver la configuration pour ce périphérique.\n" "Erreur : " #: src/Mode_Sync.cc:449 msgid "OpenSync Save Error" msgstr "Erreur de sauvegarde OpenSync" #. TRANSLATORS: first %s is the PIN number, and #. the second (in parentheses) is the device name. #: src/Mode_Sync.cc:484 #, c-format msgid "Selected device %s (%s) is not yet configured. Configure now?" msgstr "" "Le périphérique sélectionné %s (%s) n'est pas encore configuré. Le faire " "maintenant ?" #: src/Mode_Sync.cc:489 msgid "Configure Now?" msgstr "Configurer maintenant ?" #: src/Mode_Sync.cc:506 msgid "Please select one device from the list." msgstr "Veuillez sélectionner un périphérique depuis la liste." #: src/Mode_Sync.cc:536 msgid "" "Which device / application should be considered\n" "authoritative?\n" "\n" "All data in non-authoritative devices / applications\n" "will be deleted in order to setup a straight copy on\n" "the next sync." msgstr "" "Quelle est le périphérique / l'application de\n" "référence ?\n" "\n" "Tou(te)s les autres périphériques / applications\n" "seront effacé(e)s pour partir d'une copie propre à\n" "la prochaine synchronisation." #: src/Mode_Sync.cc:566 msgid "Select Authoritative Device / Application" msgstr "Sélectionner le périphérique / l'application de référence" #: src/Mode_Sync.cc:639 msgid "Unable to rewrite config! Start over manually. Error: " msgstr "" "Impossible de récrire la configuration ! Redémarrez manuellement. Erreur : " #: src/Mode_Sync.cc:643 msgid "Error Rewriting Config" msgstr "Érreur lors de la ré-écriture de la configuration" #: src/Mode_Sync.cc:659 msgid "" "The sync config you are about to save is sufficiently different from the " "existing one that a 1-Way Reset will be required. You will need to perform " "the reset at your earliest convenience, before your next sync.\n" "\n" "Continue anyway?" msgstr "" "La configuration de la synchronisation que vous vous apprêtez à sauvegarder " "est trop peu différente de l'existante pour qu'une réinitialisation à sens " "unique soit requise. Vous devrez faire une réinitialisation dès que vous le " "souhaiterez, avant votre prochaine synchronisation.\n" "\n" "Poursuivre quand même ?" #: src/Mode_Sync.cc:665 msgid "1-Way Reset Warning" msgstr "Avertissement réinitialisation à sens unique" #: src/Mode_Sync.cc:679 msgid "Sync Error" msgstr "Erreur de synchronisation" #: src/Mode_Sync.cc:705 msgid "An application is already running." msgstr "Une application est déjà en cours d'exécution." #: src/Mode_Sync.cc:751 msgid "1-Way Reset is complete, and ready to sync." msgstr "Réinitialisation à sens unique effectuée, prêt à synchroniser." #: src/Mode_Sync.cc:752 msgid "Reset Complete" msgstr "Remise à zéro effectuée" #: src/Mode_Sync.h:75 msgid "Barry Sync" msgstr "Synchronisation Barry" #: src/ModemDlg.cc:50 #, fuzzy msgid "Modem Kickstart" msgstr "Réglage du modem" #: src/ModemDlg.cc:55 msgid "Device" msgstr "Périphérique" #: src/ModemDlg.cc:56 msgid "Providers" msgstr "Fournisseurs" #: src/ModemDlg.cc:57 msgid "For device pin:" msgstr "Pour le périphérique de pin :" #: src/ModemDlg.cc:97 msgid "Modem Starter" msgstr "Démarrage du modem" #: src/ModemDlg.cc:100 msgid "Available provider scripts on your system. Must pick one." msgstr "Scripts disponibles sur votre système. Vous devez en choisir un." #: src/ModemDlg.cc:102 src/ModemDlg.cc:104 msgid "Optional device password" msgstr "Mot de passe de périphérique optionnel" #: src/ModemDlg.cc:254 msgid "" "Cannot locate the xterm program. This is used to display modem connection " "output. Please install it and try again." msgstr "" "Impossible de trouver le programme xterm. Il est nécessaire pour afficher " "les messages de connexion du modem. Veuillez l'installer et réessayer." #: src/ModemDlg.cc:254 msgid "Xterm Not Found" msgstr "Xterm non trouvé" #: src/ModemDlg.cc:263 msgid "Cannot find pppd. Please install it for modem use." msgstr "" "Impossible de trouver pppd. Veuillez l'installer pour utiliser le modem." #: src/ModemDlg.cc:263 msgid "pppd Not Found" msgstr "pppd non trouvé" #: src/ModemDlg.cc:278 #, c-format msgid "" "Your system's PPP has the suid bit set, with a group of '%s'. You should " "add your account to the '%s' group, to avoid the need to enter the root " "password every time you use the modem.\n" "\n" "Continue anyway?" msgstr "" "Le PPP de votre système a le bit suid, avec '%s' comme groupe. Vous devriez " "vous ajouter au groupe '%s' pour éviter d'entrer votre mot de passe root " "pour utiliser le modem.\n" "\n" "Continuer quand même ?" #: src/ModemDlg.cc:279 msgid "System Group" msgstr "Groupe système" #: src/ModemDlg.cc:297 msgid "Internal fork error. Should never happen." msgstr "Erreur interne de fork. Ne devrait pas arriver." #: src/ModemDlg.cc:297 msgid "Cannot Run pppd" msgstr "Impossible de lancer pppd" #: src/ModemDlg.cc:303 #, c-format msgid "Unable to run pppd correctly. Unexpected error code: %d, %s" msgstr "" "Impossible de lancer pppd correctement. Code d'erreur inattendu : %d, %s" #: src/ModemDlg.cc:304 msgid "Error Code" msgstr "Code d'erreur" #: src/ModemDlg.cc:318 msgid "" "Unable to access files in /etc/ppp/peers. Do you have the correct " "permissions?" msgstr "" "Impossible d'accéder aux fichiers de /etc/ppp/peers. Avez vous les droits " "d'accès ?" #: src/ModemDlg.cc:318 msgid "Cannot Open Peers" msgstr "Impossible d'ouvrir les peers" #: src/ModemDlg.cc:330 msgid "" "No providers found. Make sure Barry was properly installed, with peer files " "in /etc/ppp/peers." msgstr "" "Aucun fournisseur trouvé. Assurez vous que Barry est correctement installé, " "avec les fichiers peer dans /etc/ppp/peers." #: src/ModemDlg.cc:330 msgid "No Providers" msgstr "Pas de fournisseur" #: src/ModemDlg.cc:346 #, c-format msgid "" "Cannot read provider files under /etc/ppp/peers. Please check your file " "permissions. (Access failed for %s)" msgstr "" "Impossible de lire les fichiers dans /etc/ppp/peers. Vérifiez les " "permissions des fichiers. (Échec à l'accès à %s)" #: src/ModemDlg.cc:347 msgid "Permissions Error" msgstr "Erreur de permissions" #: src/ModemDlg.cc:368 #, c-format msgid "Unable to open peer file: %s" msgstr "Impossible d'ouvrir le fichier de peer : %s" #: src/ModemDlg.cc:369 msgid "Invalid Peer" msgstr "Peer invalide" #: src/ModemDlg.cc:382 msgid "Starting pppd for device PIN " msgstr "Démarrage de pppd pour le périphérique de PIN " #: src/ModemDlg.cc:393 msgid "Press enter to close window..." msgstr "Appuyez sur entrée pour fermer la fenêtre..." #: src/PNGButton.cc:57 msgid "Cannot load button bitmap." msgstr "Impossible de charger l'image du bouton." #: src/SyncStatusDlg.cc:66 msgid "Syncing entries..." msgstr "Synchronisation des entrées..." #: src/SyncStatusDlg.cc:258 msgid "Device Sync Progress" msgstr "Synchronisation du périphérique en cours" #: src/SyncStatusDlg.cc:306 msgid "Sync Progress" msgstr "Synchronisation en cours" #: src/SyncStatusDlg.cc:340 src/SyncStatusDlg.cc:629 msgid "Show Details" msgstr "Afficher les détails" #: src/SyncStatusDlg.cc:355 msgid "Sync Again" msgstr "Synchroniser de nouveau" #: src/SyncStatusDlg.cc:385 msgid "Close" msgstr "Fermer" #: src/SyncStatusDlg.cc:440 msgid "Sync Progress Dialog" msgstr "Dialogue de progression de la synchronisation" #: src/SyncStatusDlg.cc:444 msgid "Syncing: " msgstr "Synchronisation de : " #: src/SyncStatusDlg.cc:445 msgid " with " msgstr " avec " #: src/SyncStatusDlg.cc:480 msgid "No more devices to sync." msgstr "Plus de périphériques à synchroniser." #: src/SyncStatusDlg.cc:495 msgid " is not configured, skipping." msgstr " N'est pas configuré, ignoré." #: src/SyncStatusDlg.cc:496 #, fuzzy msgid "Skipping unconfigured: " msgstr "Périphérique non configuré ignoré : " #: src/SyncStatusDlg.cc:507 msgid "Starting sync for: " msgstr "Démarrage de la synchronisation pour : " #: src/SyncStatusDlg.cc:524 msgid "ERROR: App running in StartNextSync()" msgstr "ERREUR : application en cours de fonctionnement dans StartNextSync()" #: src/SyncStatusDlg.cc:545 msgid "ERROR: unable to start bsyncjail: " msgstr "ERREUR : impossible de démarrer bsyncjail : " #: src/SyncStatusDlg.cc:546 msgid "ERROR: unable to start bsyncjail" msgstr "ERREUR : impossible de démarrer bsyncjail" #: src/SyncStatusDlg.cc:557 msgid "Slow sync detected! Killing sync automatically." msgstr "" "Synchronisation lente détectée ! Annulation automatique de la " "synchronisation." #: src/SyncStatusDlg.cc:560 msgid "Slow syncs are known to be unreliable." msgstr "La synchronisation lente est réputée non-fiable." #: src/SyncStatusDlg.cc:561 msgid "Do a 1 Way Reset, and sync again." msgstr "Faites une remise à zéro à sens unique et synchronisez de nouveau." #: src/SyncStatusDlg.cc:576 msgid "The application is already running." msgstr "L'application est déjà en cours d'exécution." #: src/SyncStatusDlg.cc:577 msgid "Run Application" msgstr "Lancer l'application" #: src/SyncStatusDlg.cc:603 msgid "Already killing sync. Kill again?" msgstr "Déjà en train d'annuler la synchronisation. Annuler de nouveau ?" #: src/SyncStatusDlg.cc:607 msgid "" "This will kill the syncing child process, and will likely require a " "configuration reset.\n" "\n" "Kill sync process anyway?" msgstr "" "Ceci va tuer le processus fils de synchronisation et va certainement " "nécessiter une remise à zéro de la configuration.\n" "\n" "Poursuivre malgré tout ?" #: src/SyncStatusDlg.cc:614 msgid "Killing sync... this may take a little while..." msgstr "" "Annulation de la synchronisation... Ceci peut prendre un certain temps..." #: src/SyncStatusDlg.cc:615 msgid "Remember to re-plug your device." msgstr "Pensez à rebrancher votre périphérique." #: src/SyncStatusDlg.cc:651 msgid "Hide Details" msgstr "Masquer les détails" #: src/SyncStatusDlg.cc:675 msgid "Sync terminated: " msgstr "Synchronisation terminée : " #: src/SyncStatusDlg.cc:677 msgid "Sync finished: " msgstr "La synchronisation s'est achevée : " #: src/SyncStatusDlg.cc:680 msgid " with error code " msgstr " Avec un code d'erreur " #: src/TaskEditDlg.cc:42 msgid "Task Record" msgstr "Enregistrement de tâche" #: src/TaskEditDlg.cc:62 msgid "Task:" msgstr "Tache : " #: src/TaskEditDlg.cc:65 msgid "Status:" msgstr "État : " #: src/TaskEditDlg.cc:76 msgid "Not Started" msgstr "Pas encore démarrée" #: src/TaskEditDlg.cc:77 msgid "In Progress" msgstr "En cours" #: src/TaskEditDlg.cc:78 msgid "Completed" msgstr "Achevée" #: src/TaskEditDlg.cc:79 msgid "Waiting" msgstr "En attente" #: src/TaskEditDlg.cc:80 msgid "Deferred" msgstr "Reportée" #: src/TaskEditDlg.cc:83 msgid "Priority:" msgstr "Priorité : " #: src/TaskEditDlg.cc:92 msgid "High" msgstr "Haute" #: src/TaskEditDlg.cc:93 msgid "Normal" msgstr "Normale" #: src/TaskEditDlg.cc:94 msgid "Low" msgstr "Basse" #: src/TaskEditDlg.cc:97 msgid "Due:" msgstr "Échéance : " #: src/TaskEditDlg.cc:231 msgid "Task Event" msgstr "Événement de tâche" #: src/barrydesktop.cc:47 msgid "Scanning USB..." msgstr "Balayage USB..." #: src/barrydesktop.cc:87 msgid "" "A serious error occurred while probing the USB subsystem for BlackBerry(R) " "devices: " msgstr "" "Une erreur grave est survenue lors de la recherche de périphérique " "Blackberry® USB : " #: src/barrydesktop.cc:89 msgid "USB Error" msgstr "Erreur USB" #: src/barrydesktop.cc:150 msgid "" "No OpenSync libraries were found. Sync will be unavailable until you install " "OpenSync version 0.22 or version 0.4x on your system, along with the needed " "plugins." msgstr "" "Bibliothèque OpenSync non trouvée. La synchronisation ne sera pas disponible " "tant que vous n'aurez pas installé OpenSync 0.22 ou 0.4x, ainsi que les " "greffons nécessaires." #: src/barrydesktop.cc:150 msgid "OpenSync Not Found" msgstr "OpenSync non trouvé" #: src/bsyncjail.cc:123 msgid "Unable to connect to server." msgstr "Impossible de se connecter au serveur." #: src/bsyncjail.cc:134 msgid "Can't find matching engine for: " msgstr "Impossible de trouver de moteur correspondant à : " #: src/bsyncjail.cc:144 msgid "Unknown engine number: " msgstr "Numéro de moteur inconnu : " #: src/bsyncjail.cc:232 msgid "Invalid server response: " msgstr "Réponse du serveur invalide : " #: src/bsyncjail.cc:240 msgid "Invalid Select command from server: " msgstr "Commande Select du serveur invalide : " #: src/bsyncjail.cc:250 msgid "Abort not supported, and server sent Abort command." msgstr "" "Annulation non supportée or le serveur a envoyé une commande Annulation." #: src/bsyncjail.cc:256 msgid "Ignore not supported, and server sent Ignore command." msgstr "Ignorer non supporté or le serveur a envoyé une commande Ignorer." #: src/bsyncjail.cc:262 msgid "Keep Newer not supported, and server sent Keep Newer command." msgstr "" "Conserver le plus récent non supporté or le serveur a envoyé une commande " "Conserver le plus récent." #: src/bsyncjail.cc:267 msgid "Invalid command from server: " msgstr "Commande du serveur invalide : " #: src/bsyncjail.cc:278 msgid "Lost connection with server" msgstr "Connexion avec le server perdue" #: src/bsyncjail.cc:344 msgid "" "This is a helper program for barrydesktop, and\n" "is not intended to be called directly.\n" msgstr "" "Ceci est un programme utilitaire pour Barry Desktop\n" "et n'est pas prévu pour être invoqué directement.\n" #: src/bsyncjail.cc:355 msgid "Unable to initialize wxWidgets library, aborting." msgstr "Impossible d'initialiser la bibliothèque wxWidgets, annulation." #: src/bsyncjail.cc:361 msgid "bsyncjail exiting with code: " msgstr "bsyncjail s'est arrêté avec un code d'erreur : " #: src/exechelper.cc:69 msgid "Application Run Error" msgstr "Erreur de lancement d'application" #. TRANSLATORS: %s is the name of an application #: src/exechelper.cc:161 #, c-format msgid "%s is already running." msgstr "%s est déjà en cours d'execution." #: src/exechelper.cc:174 #, c-format msgid "Failed to run %s. Please make sure it is installed and in your PATH." msgstr "" "Impossible de lancer %s. Assurez vous qu'il est bien installé et présent " "dans votre PATH." #. TRANSLATORS: this is a main screen button label. See #. util.cc line 200 for more information on its flexibility. #: src/util.cc:51 msgid "" "Backup &\n" "Restore" msgstr "" "Sauvegarder &\n" "Restaurer" #. TRANSLATORS: this is a main screen button label #: src/util.cc:53 msgid "Sync" msgstr "Synchronisation" #. TRANSLATORS: this is a main screen button label #: src/util.cc:55 msgid "" "Modem\n" "Tethering" msgstr "" "Modem\n" "Partage de connexion" #. TRANSLATORS: this is a main screen button label #: src/util.cc:57 msgid "" "Migrate\n" "Device" msgstr "" "Migrer\n" "Périphérique" #. TRANSLATORS: this is a main screen button label #: src/util.cc:59 msgid "" "Browse\n" "Databases" msgstr "" "Parcourir\n" "Bases de\n" "données" #. TRANSLATORS: this is a main screen button label #: src/util.cc:61 msgid "" "Application\n" "Loader" msgstr "" "Application\n" "Lanceur" #. TRANSLATORS: this is a main screen button label #: src/util.cc:63 msgid "Media" msgstr "Média" #: src/util.cc:255 msgid "Unable to create button: font is invalid" msgstr "Impossible de créer le bouton : la fonte est invalide" #: src/util.cc:299 msgid "Unable to create button: text is too big to fit: " msgstr "Impossible de créer le bouton : le texte ne tient pas : " #: src/util.cc:308 msgid "Unable to create button: label is empty" msgstr "Impossible de créer le bouton : l'étiquette est vide" #: src/wxval.h:69 msgid "Invalid date!" msgstr "Date invalide !" #: src/wxval.h:69 src/wxval.h:157 msgid "Validation" msgstr "Validation" #: src/wxval.h:156 msgid "Please select one of the radio buttons." msgstr "Veuillez sélectionner l'un des boutons radio." barry-0.18.5/desktop/po/remove-potcdate.sin0000644001161500056700000000066012242254476020156 0ustar cdfreycdfrey# Sed script that remove the POT-Creation-Date line in the header entry # from a POT file. # # The distinction between the first and the following occurrences of the # pattern is achieved by looking at the hold space. /^"POT-Creation-Date: .*"$/{ x # Test if the hold space is empty. s/P/P/ ta # Yes it was empty. First occurrence. Remove the line. g d bb :a # The hold space was nonempty. Following occurrences. Do nothing. x :b } barry-0.18.5/desktop/po/POTFILES.in0000644001161500056700000000261512242254476016124 0ustar cdfreycdfrey# List of source files which contain translatable strings. # Skip all files for libosyncwrap. src/BaseButtons.cc src/BaseButtons.h src/BaseFrame.cc src/BaseFrame.h src/CUI_Barry.cc src/CUI_Barry.h src/CUI_Evolution.cc src/CUI_Evolution.h src/CUI_Google.cc src/CUI_Google.h src/CUI_KDEPim.cc src/CUI_KDEPim.h src/CalendarEditDlg.cc src/CalendarEditDlg.h src/ClickImage.cc src/ClickImage.h src/ConflictDlg.cc src/ConflictDlg.h src/ContactEditDlg.cc src/ContactEditDlg.h src/ContactPhotoWidget.cc src/ContactPhotoWidget.h src/EasyCondition.h src/EvoCfgDlg.cc src/EvoCfgDlg.h src/EvoDefaultDlg.cc src/EvoDefaultDlg.h src/EvoSources.cc src/EvoSources.h src/GroupCfgDlg.cc src/GroupCfgDlg.h src/MemoEditDlg.cc src/MemoEditDlg.h src/MigrateDlg.cc src/MigrateDlg.h src/MimeExportDlg.cc src/MimeExportDlg.h src/Mode.h src/Mode_Browse.cc src/Mode_Browse.h src/Mode_MainMenu.cc src/Mode_MainMenu.h src/Mode_Sync.cc src/Mode_Sync.h src/ModemDlg.cc src/ModemDlg.h src/PNGButton.cc src/PNGButton.h src/StringSync.cc src/StringSync.h src/SyncStatusDlg.cc src/SyncStatusDlg.h src/TaskEditDlg.cc src/TaskEditDlg.h src/barrydesktop.cc src/barrydesktop.h src/bsyncjail.cc src/configui.cc src/configui.h src/exechelper.cc src/exechelper.h src/guitimet.cc src/guitimet.h src/ipc.h src/oextract.cc src/optout.h src/ostest.cc src/util.cc src/util.h src/windowids.h src/wxval.h src/xmlcompactor.cc src/xmlcompactor.h src/xmlmap.cc src/xmlmap.h barry-0.18.5/desktop/po/barrydesktop.pot0000644001161500056700000011041512242254476017602 0ustar cdfreycdfrey# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Net Direct, Inc. # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: barrydesktop 0.18.5\n" "Report-Msgid-Bugs-To: http://netdirect.ca/barry\n" "POT-Creation-Date: 2013-04-02 18:54-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/BaseFrame.cc:73 src/BaseFrame.cc:283 src/BaseFrame.cc:855 #: src/Mode_MainMenu.h:49 msgid "Barry Desktop Control Panel" msgstr "" #: src/BaseFrame.cc:109 msgid "&Verbose Logging" msgstr "" #: src/BaseFrame.cc:110 msgid "Enable low level USB debug output" msgstr "" #: src/BaseFrame.cc:111 msgid "Re&name Device..." msgstr "" #: src/BaseFrame.cc:112 msgid "Re&set Device" msgstr "" #: src/BaseFrame.cc:113 msgid "&Rescan USB" msgstr "" #: src/BaseFrame.cc:115 msgid "&About..." msgstr "" #: src/BaseFrame.cc:117 msgid "E&xit" msgstr "" #: src/BaseFrame.cc:157 msgid "No device selected" msgstr "" #: src/BaseFrame.cc:174 msgid "No devices available" msgstr "" #: src/BaseFrame.cc:209 msgid "Main Menu" msgstr "" #: src/BaseFrame.cc:333 msgid "The Backup program is already running!" msgstr "" #: src/BaseFrame.cc:334 src/BaseFrame.cc:339 src/BaseFrame.cc:741 msgid "Backup and Restore" msgstr "" #: src/BaseFrame.cc:355 msgid "" "An error occurred that prevented the loading of Sync\n" "mode. This is most likely because a critical piece\n" "of OpenSync is missing. Check that all required\n" "plugins are installed, and that tools like 'bidentify'\n" "can find your BlackBerry(R) successfully.\n" "\n" "Error: " msgstr "" #: src/BaseFrame.cc:362 msgid "Sync Mode" msgstr "" #: src/BaseFrame.cc:376 msgid "Please select a device first." msgstr "" #: src/BaseFrame.cc:377 msgid "No Device" msgstr "" #: src/BaseFrame.cc:670 msgid "" "An error occurred during device migration.\n" "This could be due to a low level USB issue\n" "Please make sure your device is plugged in\n" "and not in Desktop Mode. If it is, try replugging\n" "the device, and rescanning the USB bus from the menu.\n" "\n" "Error: " msgstr "" #: src/BaseFrame.cc:678 src/MigrateDlg.cc:101 msgid "Migrate Device" msgstr "" #: src/BaseFrame.cc:687 msgid "" "There is no device selected in the device list. Please select a device to " "browse." msgstr "" #: src/BaseFrame.cc:688 src/BaseFrame.cc:706 msgid "Database Browser Mode" msgstr "" #: src/BaseFrame.cc:698 msgid "" "An error occurred that prevented the loading of Database\n" "Browse mode. This could be due to a low level USB\n" "issue. Please make sure your device is plugged in\n" "and not in Desktop Mode. If it is, try replugging\n" "the device, and rescanning the USB bus from the menu.\n" "\n" "Error: " msgstr "" #: src/BaseFrame.cc:740 msgid "" "Unable to run barrybackup, or it returned an error. Please make sure it is " "installed and in your PATH." msgstr "" #: src/BaseFrame.cc:809 msgid "Please enter a name for the current device:" msgstr "" #: src/BaseFrame.cc:810 msgid "Rename Device" msgstr "" #: src/BaseFrame.cc:857 msgid "" "A Free Software graphical user interface for working with the BlackBerry® " "smartphone." msgstr "" #: src/BaseFrame.cc:878 msgid "Chris Frey - GUI interface" msgstr "" #: src/BaseFrame.cc:879 msgid "Martin Owens - Barry logo" msgstr "" #: src/BaseFrame.cc:880 msgid "Tango Desktop Project - Public domain icons" msgstr "" #: src/CUI_Barry.cc:87 #, c-format msgid "" "Please select the databases you wish to erase\n" "on device: %s\n" "\n" "Note: all synced databases must be erased\n" "to avoid a slow-sync." msgstr "" #: src/CUI_Barry.cc:117 src/CUI_Google.cc:111 msgid "Select Databases to Erase" msgstr "" #: src/CUI_Barry.cc:123 msgid "" "You have selected the following databases to be completely erased from " "device: " msgstr "" #: src/CUI_Barry.cc:128 src/CUI_Google.cc:122 msgid "Proceed with erase?" msgstr "" #: src/CUI_Barry.cc:130 src/CUI_Google.cc:124 msgid "Erase Confirmation" msgstr "" #: src/CUI_Barry.cc:148 msgid "No database named '" msgstr "" #: src/CUI_Barry.cc:148 msgid "' in device!" msgstr "" #: src/CUI_Barry.cc:152 msgid "Clearing db: " msgstr "" #: src/CUI_Barry.cc:160 msgid "Barry exception: " msgstr "" #: src/CUI_Barry.cc:161 msgid "You may need to do a USB reset and rescan from the main menu." msgstr "" #: src/CUI_Barry.cc:164 msgid "Barry Exception" msgstr "" #: src/CUI_Evolution.cc:77 msgid "Stop waiting" msgstr "" #: src/CUI_Evolution.cc:103 msgid "Evolution shutdown" msgstr "" #: src/CUI_Evolution.cc:158 msgid "" "Unable to automatically detect Evolution's configuration.\n" "You need to run Evolution, and manually click each of the\n" "section buttons:\n" "\n" " Mail, Contacts, Calendars, Memos, and Tasks\n" "\n" "Then quit Evolution to continue configuration.\n" "\n" "Would you like to start Evolution now?\n" msgstr "" #: src/CUI_Evolution.cc:168 src/CUI_Evolution.cc:190 src/CUI_Evolution.cc:206 msgid "Evolution Config" msgstr "" #: src/CUI_Evolution.cc:178 msgid "Waiting for Evolution to exit..." msgstr "" #: src/CUI_Evolution.cc:179 msgid "Evolution Running" msgstr "" #: src/CUI_Evolution.cc:190 src/CUI_Evolution.cc:206 msgid "" "Failed to run evolution. Please make sure it is installed and in your PATH." msgstr "" #: src/CUI_Evolution.cc:309 msgid "Evolution already running." msgstr "" #: src/CUI_Evolution.cc:310 src/CUI_KDEPim.cc:86 msgid "Oops..." msgstr "" #: src/CUI_Evolution.cc:319 msgid "" "Starting Evolution. Delete all contacts and/or calendar entries manually, " "depending on your sync configuration." msgstr "" #: src/CUI_Evolution.cc:324 msgid "" "Starting Evolution. Delete all objects (contacts, calendar, memos, and " "tasks, depending on your sync configuration)." msgstr "" #: src/CUI_Evolution.cc:328 msgid "Starting Evolution" msgstr "" #: src/CUI_Google.cc:96 msgid "" "Please select the databases you wish to erase\n" "in your Google Calendar: \n" "\n" "Note: all synced databases must be erased\n" "to avoid a slow-sync." msgstr "" #: src/CUI_Google.cc:106 msgid "Calendar" msgstr "" #: src/CUI_Google.cc:107 src/GroupCfgDlg.cc:322 msgid "Contacts" msgstr "" #: src/CUI_Google.cc:117 msgid "" "You have selected the following databases to be completely erased from your " "Google Calendar:" msgstr "" #: src/CUI_KDEPim.cc:59 msgid "KDEPim needs no configuration." msgstr "" #: src/CUI_KDEPim.cc:59 msgid "KDEPim Config" msgstr "" #: src/CUI_KDEPim.cc:85 msgid "Kontact already running." msgstr "" #: src/CUI_KDEPim.cc:95 msgid "Starting Kontact. Delete all contacts and calendar entries manually." msgstr "" #: src/CUI_KDEPim.cc:100 msgid "" "Starting Kontact. Delete all contacts and calendar entries manually (as " "well as memos and tasks if you are syncing them too)." msgstr "" #: src/CUI_KDEPim.cc:105 msgid "Starting Kontact" msgstr "" #: src/CalendarEditDlg.cc:42 msgid "Calendar Record" msgstr "" #: src/CalendarEditDlg.cc:64 msgid "Subject:" msgstr "" #: src/CalendarEditDlg.cc:66 msgid "Location:" msgstr "" #: src/CalendarEditDlg.cc:69 msgid "All Day Event:" msgstr "" #: src/CalendarEditDlg.cc:71 msgid "Start:" msgstr "" #: src/CalendarEditDlg.cc:76 msgid "End:" msgstr "" #: src/CalendarEditDlg.cc:81 msgid "Duration:" msgstr "" #: src/CalendarEditDlg.cc:83 src/CalendarEditDlg.cc:109 msgid "hours and" msgstr "" #: src/CalendarEditDlg.cc:85 src/CalendarEditDlg.cc:111 msgid "minutes." msgstr "" #: src/CalendarEditDlg.cc:86 src/TaskEditDlg.cc:103 msgid "Time Zone:" msgstr "" #: src/CalendarEditDlg.cc:88 msgid "System Time Zone" msgstr "" #: src/CalendarEditDlg.cc:91 msgid "Show As:" msgstr "" #: src/CalendarEditDlg.cc:101 msgid "Free" msgstr "" #: src/CalendarEditDlg.cc:102 msgid "Tentative" msgstr "" #: src/CalendarEditDlg.cc:103 msgid "Busy" msgstr "" #: src/CalendarEditDlg.cc:104 msgid "Out of Office" msgstr "" #: src/CalendarEditDlg.cc:107 src/TaskEditDlg.cc:108 msgid "Reminder:" msgstr "" #: src/CalendarEditDlg.cc:113 src/TaskEditDlg.cc:115 msgid "Recurrence:" msgstr "" #: src/CalendarEditDlg.cc:124 src/TaskEditDlg.cc:126 msgid "None" msgstr "" #: src/CalendarEditDlg.cc:125 src/TaskEditDlg.cc:127 msgid "Daily" msgstr "" #: src/CalendarEditDlg.cc:126 src/TaskEditDlg.cc:128 msgid "Weekly" msgstr "" #: src/CalendarEditDlg.cc:127 src/TaskEditDlg.cc:129 msgid "Monthly" msgstr "" #: src/CalendarEditDlg.cc:128 src/TaskEditDlg.cc:130 msgid "Yearly" msgstr "" #: src/CalendarEditDlg.cc:131 src/TaskEditDlg.cc:133 msgid "Interval:" msgstr "" #: src/CalendarEditDlg.cc:132 src/TaskEditDlg.cc:134 msgid "Every" msgstr "" #: src/CalendarEditDlg.cc:134 src/TaskEditDlg.cc:136 msgid "days? weeks? months?" msgstr "" #: src/CalendarEditDlg.cc:135 src/TaskEditDlg.cc:137 msgid "Days:" msgstr "" #: src/CalendarEditDlg.cc:143 src/TaskEditDlg.cc:145 msgid "Relative Date:" msgstr "" #: src/CalendarEditDlg.cc:145 src/TaskEditDlg.cc:147 msgid "End Date:" msgstr "" #: src/CalendarEditDlg.cc:146 src/TaskEditDlg.cc:148 msgid "Never ends" msgstr "" #: src/CalendarEditDlg.cc:149 msgid "Organizer:" msgstr "" #: src/CalendarEditDlg.cc:151 msgid "Invited:" msgstr "" #: src/CalendarEditDlg.cc:153 msgid "Accepted By:" msgstr "" #: src/CalendarEditDlg.cc:164 msgid "Public" msgstr "" #: src/CalendarEditDlg.cc:165 msgid "Private" msgstr "" #: src/CalendarEditDlg.cc:166 msgid "Confidential" msgstr "" #: src/CalendarEditDlg.cc:168 msgid "Class" msgstr "" #: src/CalendarEditDlg.cc:170 src/TaskEditDlg.cc:153 msgid "Notes:" msgstr "" #: src/CalendarEditDlg.cc:181 src/TaskEditDlg.cc:164 msgid "Assume Local Timezone" msgstr "" #: src/CalendarEditDlg.cc:302 msgid "Calendar Event" msgstr "" #: src/CalendarEditDlg.cc:326 src/CalendarEditDlg.cc:329 #: src/TaskEditDlg.cc:246 src/TaskEditDlg.cc:249 msgid "Set Reminder to 0 to disable" msgstr "" #: src/CalendarEditDlg.cc:342 src/CalendarEditDlg.cc:343 #: src/TaskEditDlg.cc:262 src/TaskEditDlg.cc:263 msgid "" "Relative monthly or yearly dates take the weekday of the start date into " "account. (eg. every first Sunday of month)" msgstr "" #: src/CalendarEditDlg.cc:642 msgid "Start time must come before end time." msgstr "" #: src/CalendarEditDlg.cc:643 msgid "Validation Error" msgstr "" #: src/CalendarEditDlg.cc:827 src/TaskEditDlg.cc:705 msgid "day(s)" msgstr "" #: src/CalendarEditDlg.cc:831 src/TaskEditDlg.cc:709 msgid "week(s)" msgstr "" #: src/CalendarEditDlg.cc:835 src/TaskEditDlg.cc:713 msgid "month(s)" msgstr "" #: src/CalendarEditDlg.cc:839 src/TaskEditDlg.cc:717 msgid "year(s)" msgstr "" #: src/ConflictDlg.cc:93 msgid "Sync Conflict" msgstr "" #: src/ConflictDlg.cc:315 msgid "XML..." msgstr "" #: src/ConflictDlg.cc:321 msgid "Select" msgstr "" #: src/ConflictDlg.cc:340 msgid "No XML map found." msgstr "" #: src/ConflictDlg.cc:391 msgid "Always use this choice" msgstr "" #: src/ConflictDlg.cc:397 msgid "Duplicate" msgstr "" #: src/ConflictDlg.cc:403 msgid "Ignore" msgstr "" #: src/ConflictDlg.cc:409 msgid "Keep Newer" msgstr "" #: src/ConflictDlg.cc:415 msgid "Abort" msgstr "" #: src/ConflictDlg.cc:421 src/SyncStatusDlg.cc:360 src/SyncStatusDlg.cc:371 #: src/SyncStatusDlg.cc:604 src/SyncStatusDlg.cc:608 msgid "Kill Sync" msgstr "" #: src/ConflictDlg.cc:492 msgid "Raw Change Data" msgstr "" #: src/ContactEditDlg.cc:37 msgid "Contact Record" msgstr "" #: src/ContactEditDlg.cc:50 msgid "Home" msgstr "" #: src/ContactEditDlg.cc:51 msgid "Work" msgstr "" #. TRANSLATORS: this is a main screen button label #: src/ContactEditDlg.cc:52 src/util.cc:65 msgid "Misc" msgstr "" #: src/ContactEditDlg.cc:53 msgid "Mobile" msgstr "" #: src/ContactEditDlg.cc:54 src/GroupCfgDlg.cc:328 msgid "Notes" msgstr "" #: src/ContactEditDlg.cc:55 src/Mode_Sync.cc:182 msgid "Name" msgstr "" #: src/ContactEditDlg.cc:57 msgid "Title" msgstr "" #: src/ContactEditDlg.cc:59 msgid "First" msgstr "" #: src/ContactEditDlg.cc:61 msgid "Last" msgstr "" #: src/ContactEditDlg.cc:63 msgid "Company" msgstr "" #: src/ContactEditDlg.cc:65 msgid "Job Title" msgstr "" #: src/ContactEditDlg.cc:67 msgid "Nickname" msgstr "" #: src/ContactEditDlg.cc:69 src/ContactEditDlg.cc:89 msgid "Address" msgstr "" #: src/ContactEditDlg.cc:73 src/ContactEditDlg.cc:93 msgid "City" msgstr "" #: src/ContactEditDlg.cc:75 src/ContactEditDlg.cc:95 msgid "Province" msgstr "" #: src/ContactEditDlg.cc:77 src/ContactEditDlg.cc:97 msgid "Postal Code" msgstr "" #: src/ContactEditDlg.cc:79 src/ContactEditDlg.cc:99 msgid "Country" msgstr "" #: src/ContactEditDlg.cc:83 src/ContactEditDlg.cc:103 msgid "Phone" msgstr "" #: src/ContactEditDlg.cc:85 src/ContactEditDlg.cc:105 msgid "Phone 2" msgstr "" #: src/ContactEditDlg.cc:87 src/ContactEditDlg.cc:107 msgid "Fax" msgstr "" #: src/ContactEditDlg.cc:109 msgid "Email" msgstr "" #: src/ContactEditDlg.cc:111 msgid "Other Phone" msgstr "" #: src/ContactEditDlg.cc:113 msgid "Old Phone" msgstr "" #: src/ContactEditDlg.cc:115 msgid "Radio" msgstr "" #: src/ContactEditDlg.cc:117 src/Mode_Sync.cc:180 msgid "PIN" msgstr "" #: src/ContactEditDlg.cc:119 msgid "User1" msgstr "" #: src/ContactEditDlg.cc:121 msgid "User2" msgstr "" #: src/ContactEditDlg.cc:123 msgid "User3" msgstr "" #: src/ContactEditDlg.cc:125 msgid "User4" msgstr "" #: src/ContactEditDlg.cc:127 msgid "Cell" msgstr "" #: src/ContactEditDlg.cc:129 msgid "Cell 2" msgstr "" #: src/ContactEditDlg.cc:131 msgid "Pager" msgstr "" #: src/ContactEditDlg.cc:134 msgid "URL" msgstr "" #: src/ContactEditDlg.cc:150 msgid "Contact" msgstr "" #: src/ContactEditDlg.cc:183 msgid "" "Comma separated list of simple email addresses. Do not use <> characters." msgstr "" #: src/ContactEditDlg.cc:346 msgid "Load new photo" msgstr "" #: src/ContactEditDlg.cc:347 msgid "Save current photo to disk" msgstr "" #: src/ContactEditDlg.cc:348 msgid "Delete current photo" msgstr "" #: src/ContactEditDlg.cc:351 msgid "A photo currently exists. Would you like to:" msgstr "" #: src/ContactEditDlg.cc:352 msgid "Photo Management" msgstr "" #: src/ContactEditDlg.cc:398 msgid "" "A contact record must contain either a First/Last name, or a Company name." msgstr "" #: src/ContactEditDlg.cc:399 src/MemoEditDlg.cc:113 msgid "Required Fields" msgstr "" #. TRANSLATORS: this is the first part of a file selector string, #. as in: "Images files (*.bmp;*.jpg;*.png)" #. The file types are not part of the translation. #: src/ContactPhotoWidget.cc:43 msgid "Image files" msgstr "" #. TRANSLATORS: this is a file selector string. See "Image files" #. for more info. #. TRANSLATORS: this is a file selector string, #. see "Image files" for more info. #: src/ContactPhotoWidget.cc:47 src/Mode_Browse.cc:1090 msgid "All files" msgstr "" #: src/ContactPhotoWidget.cc:87 msgid "There is no photo available to save." msgstr "" #: src/ContactPhotoWidget.cc:88 msgid "No Photo" msgstr "" #. TRANSLATORS: this is a file selector string. See "Image files" #. for more info. #: src/ContactPhotoWidget.cc:95 msgid "JPEG files" msgstr "" #: src/ContactPhotoWidget.cc:98 msgid "Save Photo as JPEG..." msgstr "" #: src/ContactPhotoWidget.cc:110 msgid "Load Photo..." msgstr "" #: src/ContactPhotoWidget.cc:119 msgid "Unable to load selected photo." msgstr "" #: src/ContactPhotoWidget.cc:120 msgid "Photo Load Error" msgstr "" #: src/ContactPhotoWidget.cc:128 msgid "Unable to convert image to JPEG." msgstr "" #: src/ContactPhotoWidget.cc:129 msgid "Photo Convert" msgstr "" #: src/ContactPhotoWidget.cc:172 src/Mode_Sync.cc:262 msgid "No" msgstr "" #: src/ContactPhotoWidget.cc:172 msgid "Photo" msgstr "" #: src/EvoCfgDlg.cc:32 msgid "Evolution Plugin Configuration" msgstr "" #: src/EvoCfgDlg.cc:51 msgid "Address Book:" msgstr "" #: src/EvoCfgDlg.cc:58 msgid "Calendar:" msgstr "" #: src/EvoCfgDlg.cc:65 msgid "Tasks:" msgstr "" #: src/EvoCfgDlg.cc:72 msgid "Memos:" msgstr "" #: src/EvoCfgDlg.cc:169 #, c-format msgid "File '%s' does not exist." msgstr "" #: src/EvoCfgDlg.cc:181 msgid "" "No paths set! If there are no default options available in the drop down " "lists, please double check that you've initialized your Evolution account " "first." msgstr "" #: src/EvoCfgDlg.cc:194 msgid "Minimum Config Required" msgstr "" #: src/EvoDefaultDlg.cc:36 msgid "Evolution Success" msgstr "" #: src/EvoDefaultDlg.cc:52 msgid "Successfully auto-detected Evolution configuration!" msgstr "" #: src/EvoDefaultDlg.cc:61 msgid "Manual Cfg..." msgstr "" #: src/GroupCfgDlg.cc:57 msgid "Device Sync Configuration" msgstr "" #: src/GroupCfgDlg.cc:80 msgid "Must have at least one engine in GroupCfgDlg" msgstr "" #: src/GroupCfgDlg.cc:86 msgid "Configure Device - " msgstr "" #: src/GroupCfgDlg.cc:140 msgid "" "No supported applications found. You may need to install some opensync " "plugins." msgstr "" #: src/GroupCfgDlg.cc:141 msgid "No App Found" msgstr "" #: src/GroupCfgDlg.cc:162 msgid "OpenSync Engine" msgstr "" #: src/GroupCfgDlg.cc:199 msgid "Barry Config" msgstr "" #: src/GroupCfgDlg.cc:205 msgid "Name:" msgstr "" #: src/GroupCfgDlg.cc:214 src/ModemDlg.cc:65 msgid "Password:" msgstr "" #: src/GroupCfgDlg.cc:224 msgid "Debug output during sync" msgstr "" #: src/GroupCfgDlg.cc:233 src/Mode_Sync.cc:186 msgid "Application" msgstr "" #: src/GroupCfgDlg.cc:261 msgid "&Configure..." msgstr "" #: src/GroupCfgDlg.cc:277 msgid "No engine selected" msgstr "" #: src/GroupCfgDlg.cc:286 msgid "Exception caught in LoadAppNames: " msgstr "" #: src/GroupCfgDlg.cc:311 msgid "No supported plugins available" msgstr "" #: src/GroupCfgDlg.cc:319 msgid "Sync:" msgstr "" #: src/GroupCfgDlg.cc:325 msgid "Events" msgstr "" #: src/GroupCfgDlg.cc:331 msgid "To-dos" msgstr "" #. TRANSLATORS: these 3 strings are options for default #. conflict resolution during syncing #: src/GroupCfgDlg.cc:343 msgid "Favour device" msgstr "" #: src/GroupCfgDlg.cc:344 msgid "Favour application" msgstr "" #: src/GroupCfgDlg.cc:345 msgid "Ask me" msgstr "" #: src/GroupCfgDlg.cc:348 msgid "To Resolve Conflicts:" msgstr "" #: src/GroupCfgDlg.cc:491 msgid "Please select an application." msgstr "" #: src/GroupCfgDlg.cc:492 src/GroupCfgDlg.cc:500 src/GroupCfgDlg.cc:588 msgid "Application Config" msgstr "" #: src/GroupCfgDlg.cc:499 msgid "No configuration interface available for this Application." msgstr "" #: src/GroupCfgDlg.cc:566 msgid "Please select an engine." msgstr "" #: src/GroupCfgDlg.cc:567 src/GroupCfgDlg.cc:574 msgid "Device Config" msgstr "" #: src/GroupCfgDlg.cc:573 msgid "Barry doesn't have a PIN number. This should never happen." msgstr "" #: src/GroupCfgDlg.cc:587 msgid "The application plugin is not fully configured." msgstr "" #: src/GroupCfgDlg.cc:615 msgid "Please select conflict resolution method." msgstr "" #: src/GroupCfgDlg.cc:616 msgid "Conflict Resolution" msgstr "" #: src/MemoEditDlg.cc:36 msgid "Memo Record" msgstr "" #: src/MemoEditDlg.cc:49 msgid "Title:" msgstr "" #: src/MemoEditDlg.cc:51 src/TaskEditDlg.cc:151 msgid "Categories:" msgstr "" #: src/MemoEditDlg.cc:64 msgid "Memo" msgstr "" #: src/MemoEditDlg.cc:68 msgid "Comma separated" msgstr "" #: src/MemoEditDlg.cc:70 msgid "Comma separated list of categories (can be empty)" msgstr "" #: src/MemoEditDlg.cc:73 msgid "Body of memo" msgstr "" #: src/MemoEditDlg.cc:112 msgid "Please enter a title for your memo." msgstr "" #: src/MigrateDlg.cc:144 msgid "Migrate device data from source device to target device." msgstr "" #: src/MigrateDlg.cc:167 msgid "Ready..." msgstr "" #: src/MigrateDlg.cc:189 msgid "Source device" msgstr "" #: src/MigrateDlg.cc:207 msgid "Migrate Now" msgstr "" #: src/MigrateDlg.cc:212 msgid "Cancel" msgstr "" #: src/MigrateDlg.cc:221 msgid "Prompt to plug in later..." msgstr "" #: src/MigrateDlg.cc:229 msgid "Destination device" msgstr "" #. TRANSLATORS: these 4 strings are write-mode options in the #. Migrate Device dialog #: src/MigrateDlg.cc:242 msgid "Erase all, then restore" msgstr "" #: src/MigrateDlg.cc:243 msgid "Add new, and overwrite existing" msgstr "" #: src/MigrateDlg.cc:244 msgid "Add only, don't overwrite existing" msgstr "" #: src/MigrateDlg.cc:245 msgid "Add every record as a new entry (may cause duplicates)" msgstr "" #: src/MigrateDlg.cc:247 msgid "Write Mode:" msgstr "" #: src/MigrateDlg.cc:275 msgid "Waiting for thread to close..." msgstr "" #: src/MigrateDlg.cc:336 msgid "" "Please select a source and destination device, as well as the write mode." msgstr "" #: src/MigrateDlg.cc:337 msgid "Migration Options Needed" msgstr "" #: src/MigrateDlg.cc:343 msgid "Cannot migrate from and to the same PIN." msgstr "" #: src/MigrateDlg.cc:344 msgid "Migration Options Error" msgstr "" #: src/MigrateDlg.cc:371 msgid "Invalid write mode. This should never happen. Contact the developers." msgstr "" #: src/MigrateDlg.cc:372 msgid "Internal Logic Error" msgstr "" #: src/MigrateDlg.cc:412 msgid "Waiting for thread..." msgstr "" #: src/MigrateDlg.cc:421 msgid "Cancelled by user..." msgstr "" #: src/MigrateDlg.cc:439 msgid "Please plug in the target device now." msgstr "" #: src/MigrateDlg.cc:440 msgid "Ready for Writing" msgstr "" #: src/MigrateDlg.cc:450 msgid "Scanning USB for devices..." msgstr "" #: src/MigrateDlg.cc:469 msgid "User input..." msgstr "" #: src/MigrateDlg.cc:474 msgid "Please select the target device to write to:" msgstr "" #: src/MigrateDlg.cc:475 msgid "Destination PIN" msgstr "" #: src/MigrateDlg.cc:487 msgid "Cannot use the same device PIN as migration destination." msgstr "" #: src/MigrateDlg.cc:488 msgid "Invalid Device Selection" msgstr "" #: src/MigrateDlg.cc:522 src/Mode_Browse.cc:258 #, c-format msgid "Please enter device password: (%d tries remaining)" msgstr "" #: src/MigrateDlg.cc:527 src/Mode_Browse.cc:263 msgid "Device Password" msgstr "" #: src/MigrateDlg.cc:533 msgid "Migration Error" msgstr "" #: src/MigrateDlg.cc:593 msgid "Connecting..." msgstr "" #: src/MigrateDlg.cc:645 msgid "Backing up database: " msgstr "" #: src/MigrateDlg.cc:672 msgid "Backup aborted by user..." msgstr "" #: src/MigrateDlg.cc:693 msgid "Connecting to target..." msgstr "" #: src/MigrateDlg.cc:734 msgid "Writing database: " msgstr "" #: src/MigrateDlg.cc:765 msgid "Restore aborted by user..." msgstr "" #: src/MigrateDlg.cc:771 msgid "Unable to clear or write to database: " msgstr "" #: src/MigrateDlg.cc:774 msgid "Continuing to process remaining records..." msgstr "" #: src/MimeExportDlg.cc:41 msgid "MIME Card Data" msgstr "" #: src/MimeExportDlg.cc:48 msgid "Save..." msgstr "" #: src/MimeExportDlg.cc:78 msgid "Save Card as..." msgstr "" #: src/Mode_Browse.cc:71 msgid "" "This database is apparently read-only. If this device is connected to a " "BES, you cannot edit records via USB. (Error: " msgstr "" #: src/Mode_Browse.cc:72 msgid "Device Error" msgstr "" #. TRANSLATORS: this is a file selector string, #. see "Image files" for more info. #: src/Mode_Browse.cc:94 msgid "VCard files" msgstr "" #. TRANSLATORS: this is a file selector string, #. see "Image files" for more info. #: src/Mode_Browse.cc:107 msgid "ICalendar files" msgstr "" #: src/Mode_Browse.cc:290 msgid "raw data" msgstr "" #: src/Mode_Browse.cc:368 msgid "DataCachePtr has no builder" msgstr "" #: src/Mode_Browse.cc:385 msgid "Device exception: " msgstr "" #: src/Mode_Browse.cc:554 msgid "" "Delete this record?\n" " " msgstr "" #: src/Mode_Browse.cc:555 msgid "Record Delete" msgstr "" #: src/Mode_Browse.cc:599 msgid "Failed to create map mutex" msgstr "" #: src/Mode_Browse.cc:603 msgid "Failed to create load mutex" msgstr "" #: src/Mode_Browse.cc:738 msgid "Loading: " msgstr "" #: src/Mode_Browse.cc:791 msgid "Show All Databases" msgstr "" #: src/Mode_Browse.cc:821 msgid "Import..." msgstr "" #: src/Mode_Browse.cc:824 msgid "Export..." msgstr "" #: src/Mode_Browse.cc:827 msgid "Add..." msgstr "" #: src/Mode_Browse.cc:830 msgid "Copy..." msgstr "" #: src/Mode_Browse.cc:833 msgid "Edit..." msgstr "" #: src/Mode_Browse.cc:836 msgid "Delete..." msgstr "" #: src/Mode_Browse.cc:857 msgid "Databases" msgstr "" #: src/Mode_Browse.cc:859 msgid "Count" msgstr "" #: src/Mode_Browse.cc:867 msgid "Record Description" msgstr "" #: src/Mode_Browse.cc:1069 #, c-format msgid "Card file type (%s) does not match record you are trying to add (%s)." msgstr "" #: src/Mode_Browse.cc:1072 msgid "Invalid Card Type" msgstr "" #: src/Mode_Browse.cc:1095 msgid "Load Record..." msgstr "" #: src/Mode_Browse.cc:1106 msgid "No card data found in: " msgstr "" #: src/Mode_Browse.cc:1107 msgid "Import Read Error" msgstr "" #: src/Mode_Browse.cc:1154 #, c-format msgid "Unable to import selected file: %s" msgstr "" #: src/Mode_Browse.cc:1155 msgid "Import Error" msgstr "" #: src/Mode_Browse.cc:1164 msgid "Internal pointer error: cannot find DBCachePtr for: " msgstr "" #: src/Mode_Browse.cc:1165 src/Mode_Browse.cc:1180 msgid "Internal Error" msgstr "" #: src/Mode_Browse.cc:1179 msgid "Internal error: cannot add record to DBCache" msgstr "" #: src/Mode_Browse.h:99 msgid "Failed to create mutex for ThreadableDesktop" msgstr "" #: src/Mode_Browse.h:469 msgid "Barry Database Browser" msgstr "" #: src/Mode_MainMenu.cc:57 msgid "Ignorable screenshot exception: " msgstr "" #: src/Mode_Sync.cc:75 msgid "" "Multiple configurations have been found with the same PIN. Please select\n" "the configuration that Barry Desktop should work with." msgstr "" #: src/Mode_Sync.cc:125 msgid "Select the device(s) you want to sync and press Sync Now." msgstr "" #: src/Mode_Sync.cc:126 msgid "Use Configure to configure the currently selected device." msgstr "" #: src/Mode_Sync.cc:127 msgid "Use Run App to start the application that the device syncs with." msgstr "" #: src/Mode_Sync.cc:128 msgid "" "Use 1-Way Reset to recover from a broken sync, copying all device data to " "application, or vice versa." msgstr "" #: src/Mode_Sync.cc:140 src/Mode_Sync.cc:507 msgid "Device List" msgstr "" #: src/Mode_Sync.cc:153 src/SyncStatusDlg.cc:349 msgid "Run App" msgstr "" #: src/Mode_Sync.cc:156 msgid "Configure..." msgstr "" #: src/Mode_Sync.cc:159 msgid "1 Way Reset..." msgstr "" #: src/Mode_Sync.cc:184 msgid "Connected" msgstr "" #: src/Mode_Sync.cc:188 msgid "Engine" msgstr "" #: src/Mode_Sync.cc:190 msgid "Last Sync" msgstr "" #: src/Mode_Sync.cc:262 msgid "Yes" msgstr "" #: src/Mode_Sync.cc:270 msgid "(No config)" msgstr "" #: src/Mode_Sync.cc:363 src/Mode_Sync.cc:678 msgid "An application is currently running." msgstr "" #: src/Mode_Sync.cc:364 src/Mode_Sync.cc:706 msgid "Run App Error" msgstr "" #: src/Mode_Sync.cc:390 msgid "Config is the same, skipping save" msgstr "" #: src/Mode_Sync.cc:447 msgid "" "Unable to save configuration for this device.\n" "Error: " msgstr "" #: src/Mode_Sync.cc:449 msgid "OpenSync Save Error" msgstr "" #. TRANSLATORS: first %s is the PIN number, and #. the second (in parentheses) is the device name. #: src/Mode_Sync.cc:484 #, c-format msgid "Selected device %s (%s) is not yet configured. Configure now?" msgstr "" #: src/Mode_Sync.cc:489 msgid "Configure Now?" msgstr "" #: src/Mode_Sync.cc:506 msgid "Please select one device from the list." msgstr "" #: src/Mode_Sync.cc:536 msgid "" "Which device / application should be considered\n" "authoritative?\n" "\n" "All data in non-authoritative devices / applications\n" "will be deleted in order to setup a straight copy on\n" "the next sync." msgstr "" #: src/Mode_Sync.cc:566 msgid "Select Authoritative Device / Application" msgstr "" #: src/Mode_Sync.cc:639 msgid "Unable to rewrite config! Start over manually. Error: " msgstr "" #: src/Mode_Sync.cc:643 msgid "Error Rewriting Config" msgstr "" #: src/Mode_Sync.cc:659 msgid "" "The sync config you are about to save is sufficiently different from the " "existing one that a 1-Way Reset will be required. You will need to perform " "the reset at your earliest convenience, before your next sync.\n" "\n" "Continue anyway?" msgstr "" #: src/Mode_Sync.cc:665 msgid "1-Way Reset Warning" msgstr "" #: src/Mode_Sync.cc:679 msgid "Sync Error" msgstr "" #: src/Mode_Sync.cc:705 msgid "An application is already running." msgstr "" #: src/Mode_Sync.cc:751 msgid "1-Way Reset is complete, and ready to sync." msgstr "" #: src/Mode_Sync.cc:752 msgid "Reset Complete" msgstr "" #: src/Mode_Sync.h:75 msgid "Barry Sync" msgstr "" #: src/ModemDlg.cc:50 msgid "Modem Kickstart" msgstr "" #: src/ModemDlg.cc:55 msgid "Device" msgstr "" #: src/ModemDlg.cc:56 msgid "Providers" msgstr "" #: src/ModemDlg.cc:57 msgid "For device pin:" msgstr "" #: src/ModemDlg.cc:97 msgid "Modem Starter" msgstr "" #: src/ModemDlg.cc:100 msgid "Available provider scripts on your system. Must pick one." msgstr "" #: src/ModemDlg.cc:102 src/ModemDlg.cc:104 msgid "Optional device password" msgstr "" #: src/ModemDlg.cc:254 msgid "" "Cannot locate the xterm program. This is used to display modem connection " "output. Please install it and try again." msgstr "" #: src/ModemDlg.cc:254 msgid "Xterm Not Found" msgstr "" #: src/ModemDlg.cc:263 msgid "Cannot find pppd. Please install it for modem use." msgstr "" #: src/ModemDlg.cc:263 msgid "pppd Not Found" msgstr "" #: src/ModemDlg.cc:278 #, c-format msgid "" "Your system's PPP has the suid bit set, with a group of '%s'. You should " "add your account to the '%s' group, to avoid the need to enter the root " "password every time you use the modem.\n" "\n" "Continue anyway?" msgstr "" #: src/ModemDlg.cc:279 msgid "System Group" msgstr "" #: src/ModemDlg.cc:297 msgid "Internal fork error. Should never happen." msgstr "" #: src/ModemDlg.cc:297 msgid "Cannot Run pppd" msgstr "" #: src/ModemDlg.cc:303 #, c-format msgid "Unable to run pppd correctly. Unexpected error code: %d, %s" msgstr "" #: src/ModemDlg.cc:304 msgid "Error Code" msgstr "" #: src/ModemDlg.cc:318 msgid "" "Unable to access files in /etc/ppp/peers. Do you have the correct " "permissions?" msgstr "" #: src/ModemDlg.cc:318 msgid "Cannot Open Peers" msgstr "" #: src/ModemDlg.cc:330 msgid "" "No providers found. Make sure Barry was properly installed, with peer files " "in /etc/ppp/peers." msgstr "" #: src/ModemDlg.cc:330 msgid "No Providers" msgstr "" #: src/ModemDlg.cc:346 #, c-format msgid "" "Cannot read provider files under /etc/ppp/peers. Please check your file " "permissions. (Access failed for %s)" msgstr "" #: src/ModemDlg.cc:347 msgid "Permissions Error" msgstr "" #: src/ModemDlg.cc:368 #, c-format msgid "Unable to open peer file: %s" msgstr "" #: src/ModemDlg.cc:369 msgid "Invalid Peer" msgstr "" #: src/ModemDlg.cc:382 msgid "Starting pppd for device PIN " msgstr "" #: src/ModemDlg.cc:393 msgid "Press enter to close window..." msgstr "" #: src/PNGButton.cc:57 msgid "Cannot load button bitmap." msgstr "" #: src/SyncStatusDlg.cc:66 msgid "Syncing entries..." msgstr "" #: src/SyncStatusDlg.cc:258 msgid "Device Sync Progress" msgstr "" #: src/SyncStatusDlg.cc:306 msgid "Sync Progress" msgstr "" #: src/SyncStatusDlg.cc:340 src/SyncStatusDlg.cc:629 msgid "Show Details" msgstr "" #: src/SyncStatusDlg.cc:355 msgid "Sync Again" msgstr "" #: src/SyncStatusDlg.cc:385 msgid "Close" msgstr "" #: src/SyncStatusDlg.cc:440 msgid "Sync Progress Dialog" msgstr "" #: src/SyncStatusDlg.cc:444 msgid "Syncing: " msgstr "" #: src/SyncStatusDlg.cc:445 msgid " with " msgstr "" #: src/SyncStatusDlg.cc:480 msgid "No more devices to sync." msgstr "" #: src/SyncStatusDlg.cc:495 msgid " is not configured, skipping." msgstr "" #: src/SyncStatusDlg.cc:496 msgid "Skipping unconfigured: " msgstr "" #: src/SyncStatusDlg.cc:507 msgid "Starting sync for: " msgstr "" #: src/SyncStatusDlg.cc:524 msgid "ERROR: App running in StartNextSync()" msgstr "" #: src/SyncStatusDlg.cc:545 msgid "ERROR: unable to start bsyncjail: " msgstr "" #: src/SyncStatusDlg.cc:546 msgid "ERROR: unable to start bsyncjail" msgstr "" #: src/SyncStatusDlg.cc:557 msgid "Slow sync detected! Killing sync automatically." msgstr "" #: src/SyncStatusDlg.cc:560 msgid "Slow syncs are known to be unreliable." msgstr "" #: src/SyncStatusDlg.cc:561 msgid "Do a 1 Way Reset, and sync again." msgstr "" #: src/SyncStatusDlg.cc:576 msgid "The application is already running." msgstr "" #: src/SyncStatusDlg.cc:577 msgid "Run Application" msgstr "" #: src/SyncStatusDlg.cc:603 msgid "Already killing sync. Kill again?" msgstr "" #: src/SyncStatusDlg.cc:607 msgid "" "This will kill the syncing child process, and will likely require a " "configuration reset.\n" "\n" "Kill sync process anyway?" msgstr "" #: src/SyncStatusDlg.cc:614 msgid "Killing sync... this may take a little while..." msgstr "" #: src/SyncStatusDlg.cc:615 msgid "Remember to re-plug your device." msgstr "" #: src/SyncStatusDlg.cc:651 msgid "Hide Details" msgstr "" #: src/SyncStatusDlg.cc:675 msgid "Sync terminated: " msgstr "" #: src/SyncStatusDlg.cc:677 msgid "Sync finished: " msgstr "" #: src/SyncStatusDlg.cc:680 msgid " with error code " msgstr "" #: src/TaskEditDlg.cc:42 msgid "Task Record" msgstr "" #: src/TaskEditDlg.cc:62 msgid "Task:" msgstr "" #: src/TaskEditDlg.cc:65 msgid "Status:" msgstr "" #: src/TaskEditDlg.cc:76 msgid "Not Started" msgstr "" #: src/TaskEditDlg.cc:77 msgid "In Progress" msgstr "" #: src/TaskEditDlg.cc:78 msgid "Completed" msgstr "" #: src/TaskEditDlg.cc:79 msgid "Waiting" msgstr "" #: src/TaskEditDlg.cc:80 msgid "Deferred" msgstr "" #: src/TaskEditDlg.cc:83 msgid "Priority:" msgstr "" #: src/TaskEditDlg.cc:92 msgid "High" msgstr "" #: src/TaskEditDlg.cc:93 msgid "Normal" msgstr "" #: src/TaskEditDlg.cc:94 msgid "Low" msgstr "" #: src/TaskEditDlg.cc:97 msgid "Due:" msgstr "" #: src/TaskEditDlg.cc:231 msgid "Task Event" msgstr "" #: src/barrydesktop.cc:47 msgid "Scanning USB..." msgstr "" #: src/barrydesktop.cc:87 msgid "" "A serious error occurred while probing the USB subsystem for BlackBerry(R) " "devices: " msgstr "" #: src/barrydesktop.cc:89 msgid "USB Error" msgstr "" #: src/barrydesktop.cc:150 msgid "" "No OpenSync libraries were found. Sync will be unavailable until you install " "OpenSync version 0.22 or version 0.4x on your system, along with the needed " "plugins." msgstr "" #: src/barrydesktop.cc:150 msgid "OpenSync Not Found" msgstr "" #: src/bsyncjail.cc:123 msgid "Unable to connect to server." msgstr "" #: src/bsyncjail.cc:134 msgid "Can't find matching engine for: " msgstr "" #: src/bsyncjail.cc:144 msgid "Unknown engine number: " msgstr "" #: src/bsyncjail.cc:232 msgid "Invalid server response: " msgstr "" #: src/bsyncjail.cc:240 msgid "Invalid Select command from server: " msgstr "" #: src/bsyncjail.cc:250 msgid "Abort not supported, and server sent Abort command." msgstr "" #: src/bsyncjail.cc:256 msgid "Ignore not supported, and server sent Ignore command." msgstr "" #: src/bsyncjail.cc:262 msgid "Keep Newer not supported, and server sent Keep Newer command." msgstr "" #: src/bsyncjail.cc:267 msgid "Invalid command from server: " msgstr "" #: src/bsyncjail.cc:278 msgid "Lost connection with server" msgstr "" #: src/bsyncjail.cc:344 msgid "" "This is a helper program for barrydesktop, and\n" "is not intended to be called directly.\n" msgstr "" #: src/bsyncjail.cc:355 msgid "Unable to initialize wxWidgets library, aborting." msgstr "" #: src/bsyncjail.cc:361 msgid "bsyncjail exiting with code: " msgstr "" #: src/exechelper.cc:69 msgid "Application Run Error" msgstr "" #. TRANSLATORS: %s is the name of an application #: src/exechelper.cc:161 #, c-format msgid "%s is already running." msgstr "" #: src/exechelper.cc:174 #, c-format msgid "Failed to run %s. Please make sure it is installed and in your PATH." msgstr "" #. TRANSLATORS: this is a main screen button label. See #. util.cc line 200 for more information on its flexibility. #: src/util.cc:51 msgid "" "Backup &\n" "Restore" msgstr "" #. TRANSLATORS: this is a main screen button label #: src/util.cc:53 msgid "Sync" msgstr "" #. TRANSLATORS: this is a main screen button label #: src/util.cc:55 msgid "" "Modem\n" "Tethering" msgstr "" #. TRANSLATORS: this is a main screen button label #: src/util.cc:57 msgid "" "Migrate\n" "Device" msgstr "" #. TRANSLATORS: this is a main screen button label #: src/util.cc:59 msgid "" "Browse\n" "Databases" msgstr "" #. TRANSLATORS: this is a main screen button label #: src/util.cc:61 msgid "" "Application\n" "Loader" msgstr "" #. TRANSLATORS: this is a main screen button label #: src/util.cc:63 msgid "Media" msgstr "" #: src/util.cc:255 msgid "Unable to create button: font is invalid" msgstr "" #: src/util.cc:299 msgid "Unable to create button: text is too big to fit: " msgstr "" #: src/util.cc:308 msgid "Unable to create button: label is empty" msgstr "" #: src/wxval.h:69 msgid "Invalid date!" msgstr "" #: src/wxval.h:69 src/wxval.h:157 msgid "Validation" msgstr "" #: src/wxval.h:156 msgid "Please select one of the radio buttons." msgstr "" barry-0.18.5/desktop/po/quot.sed0000644001161500056700000000023112242254476016024 0ustar cdfreycdfreys/"\([^"]*\)"/“\1”/g s/`\([^`']*\)'/‘\1’/g s/ '\([^`']*\)' / ‘\1’ /g s/ '\([^`']*\)'$/ ‘\1’/g s/^'\([^`']*\)' /‘\1’ /g s/“”/""/g barry-0.18.5/desktop/po/Makevars0000644001161500056700000000357012242254476016044 0ustar cdfreycdfrey# Makefile variables for PO directory in any package using GNU gettext. # Usually the message domain is the same as the package name. DOMAIN = $(PACKAGE) # These two variables depend on the location of this directory. subdir = po top_builddir = .. # These options get passed to xgettext. XGETTEXT_OPTIONS = --keyword=_C --keyword=_W --from-code=UTF-8 --add-comments=TRANSLATORS # This is the copyright holder that gets inserted into the header of the # $(DOMAIN).pot file. Set this to the copyright holder of the surrounding # package. (Note that the msgstr strings, extracted from the package's # sources, belong to the copyright holder of the package.) Translators are # expected to transfer the copyright for their translations to this person # or entity, or to disclaim their copyright. The empty string stands for # the public domain; in this case the translators are expected to disclaim # their copyright. COPYRIGHT_HOLDER = Net Direct, Inc. # This is the email address or URL to which the translators shall report # bugs in the untranslated strings: # - Strings which are not entire sentences, see the maintainer guidelines # in the GNU gettext documentation, section 'Preparing Strings'. # - Strings which use unclear terms or require additional context to be # understood. # - Strings which make invalid assumptions about notation of date, time or # money. # - Pluralisation problems. # - Incorrect English spelling. # - Incorrect formatting. # It can be your email address, or a mailing list address where translators # can write to without being subscribed, or the URL of a web page through # which the translators can contact you. # # See the "contact" page from the URL below: MSGID_BUGS_ADDRESS = http://netdirect.ca/barry # This is the list of locale categories, beyond LC_MESSAGES, for which the # message catalogs shall be used. It is usually empty. EXTRA_LOCALE_CATEGORIES = barry-0.18.5/desktop/po/es.po0000644001161500056700000011041712242254476015316 0ustar cdfreycdfrey# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Net Direct, Inc. # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: barrydesktop 0.18.5\n" "Report-Msgid-Bugs-To: http://netdirect.ca/barry\n" "POT-Creation-Date: 2013-04-02 18:54-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/BaseFrame.cc:73 src/BaseFrame.cc:283 src/BaseFrame.cc:855 #: src/Mode_MainMenu.h:49 msgid "Barry Desktop Control Panel" msgstr "" #: src/BaseFrame.cc:109 msgid "&Verbose Logging" msgstr "" #: src/BaseFrame.cc:110 msgid "Enable low level USB debug output" msgstr "" #: src/BaseFrame.cc:111 msgid "Re&name Device..." msgstr "" #: src/BaseFrame.cc:112 msgid "Re&set Device" msgstr "" #: src/BaseFrame.cc:113 msgid "&Rescan USB" msgstr "" #: src/BaseFrame.cc:115 msgid "&About..." msgstr "" #: src/BaseFrame.cc:117 msgid "E&xit" msgstr "" #: src/BaseFrame.cc:157 msgid "No device selected" msgstr "" #: src/BaseFrame.cc:174 msgid "No devices available" msgstr "" #: src/BaseFrame.cc:209 msgid "Main Menu" msgstr "" #: src/BaseFrame.cc:333 msgid "The Backup program is already running!" msgstr "" #: src/BaseFrame.cc:334 src/BaseFrame.cc:339 src/BaseFrame.cc:741 msgid "Backup and Restore" msgstr "" #: src/BaseFrame.cc:355 msgid "" "An error occurred that prevented the loading of Sync\n" "mode. This is most likely because a critical piece\n" "of OpenSync is missing. Check that all required\n" "plugins are installed, and that tools like 'bidentify'\n" "can find your BlackBerry(R) successfully.\n" "\n" "Error: " msgstr "" #: src/BaseFrame.cc:362 msgid "Sync Mode" msgstr "" #: src/BaseFrame.cc:376 msgid "Please select a device first." msgstr "" #: src/BaseFrame.cc:377 msgid "No Device" msgstr "" #: src/BaseFrame.cc:670 msgid "" "An error occurred during device migration.\n" "This could be due to a low level USB issue\n" "Please make sure your device is plugged in\n" "and not in Desktop Mode. If it is, try replugging\n" "the device, and rescanning the USB bus from the menu.\n" "\n" "Error: " msgstr "" #: src/BaseFrame.cc:678 src/MigrateDlg.cc:101 msgid "Migrate Device" msgstr "" #: src/BaseFrame.cc:687 msgid "" "There is no device selected in the device list. Please select a device to " "browse." msgstr "" #: src/BaseFrame.cc:688 src/BaseFrame.cc:706 msgid "Database Browser Mode" msgstr "" #: src/BaseFrame.cc:698 msgid "" "An error occurred that prevented the loading of Database\n" "Browse mode. This could be due to a low level USB\n" "issue. Please make sure your device is plugged in\n" "and not in Desktop Mode. If it is, try replugging\n" "the device, and rescanning the USB bus from the menu.\n" "\n" "Error: " msgstr "" #: src/BaseFrame.cc:740 msgid "" "Unable to run barrybackup, or it returned an error. Please make sure it is " "installed and in your PATH." msgstr "" #: src/BaseFrame.cc:809 msgid "Please enter a name for the current device:" msgstr "" #: src/BaseFrame.cc:810 msgid "Rename Device" msgstr "" #: src/BaseFrame.cc:857 msgid "" "A Free Software graphical user interface for working with the BlackBerry® " "smartphone." msgstr "" #: src/BaseFrame.cc:878 msgid "Chris Frey - GUI interface" msgstr "" #: src/BaseFrame.cc:879 msgid "Martin Owens - Barry logo" msgstr "" #: src/BaseFrame.cc:880 msgid "Tango Desktop Project - Public domain icons" msgstr "" #: src/CUI_Barry.cc:87 #, c-format msgid "" "Please select the databases you wish to erase\n" "on device: %s\n" "\n" "Note: all synced databases must be erased\n" "to avoid a slow-sync." msgstr "" #: src/CUI_Barry.cc:117 src/CUI_Google.cc:111 msgid "Select Databases to Erase" msgstr "" #: src/CUI_Barry.cc:123 msgid "" "You have selected the following databases to be completely erased from " "device: " msgstr "" #: src/CUI_Barry.cc:128 src/CUI_Google.cc:122 msgid "Proceed with erase?" msgstr "" #: src/CUI_Barry.cc:130 src/CUI_Google.cc:124 msgid "Erase Confirmation" msgstr "" #: src/CUI_Barry.cc:148 msgid "No database named '" msgstr "" #: src/CUI_Barry.cc:148 msgid "' in device!" msgstr "" #: src/CUI_Barry.cc:152 msgid "Clearing db: " msgstr "" #: src/CUI_Barry.cc:160 msgid "Barry exception: " msgstr "" #: src/CUI_Barry.cc:161 msgid "You may need to do a USB reset and rescan from the main menu." msgstr "" #: src/CUI_Barry.cc:164 msgid "Barry Exception" msgstr "" #: src/CUI_Evolution.cc:77 msgid "Stop waiting" msgstr "" #: src/CUI_Evolution.cc:103 msgid "Evolution shutdown" msgstr "" #: src/CUI_Evolution.cc:158 msgid "" "Unable to automatically detect Evolution's configuration.\n" "You need to run Evolution, and manually click each of the\n" "section buttons:\n" "\n" " Mail, Contacts, Calendars, Memos, and Tasks\n" "\n" "Then quit Evolution to continue configuration.\n" "\n" "Would you like to start Evolution now?\n" msgstr "" #: src/CUI_Evolution.cc:168 src/CUI_Evolution.cc:190 src/CUI_Evolution.cc:206 msgid "Evolution Config" msgstr "" #: src/CUI_Evolution.cc:178 msgid "Waiting for Evolution to exit..." msgstr "" #: src/CUI_Evolution.cc:179 msgid "Evolution Running" msgstr "" #: src/CUI_Evolution.cc:190 src/CUI_Evolution.cc:206 msgid "" "Failed to run evolution. Please make sure it is installed and in your PATH." msgstr "" #: src/CUI_Evolution.cc:309 msgid "Evolution already running." msgstr "" #: src/CUI_Evolution.cc:310 src/CUI_KDEPim.cc:86 msgid "Oops..." msgstr "" #: src/CUI_Evolution.cc:319 msgid "" "Starting Evolution. Delete all contacts and/or calendar entries manually, " "depending on your sync configuration." msgstr "" #: src/CUI_Evolution.cc:324 msgid "" "Starting Evolution. Delete all objects (contacts, calendar, memos, and " "tasks, depending on your sync configuration)." msgstr "" #: src/CUI_Evolution.cc:328 msgid "Starting Evolution" msgstr "" #: src/CUI_Google.cc:96 msgid "" "Please select the databases you wish to erase\n" "in your Google Calendar: \n" "\n" "Note: all synced databases must be erased\n" "to avoid a slow-sync." msgstr "" #: src/CUI_Google.cc:106 msgid "Calendar" msgstr "" #: src/CUI_Google.cc:107 src/GroupCfgDlg.cc:322 msgid "Contacts" msgstr "" #: src/CUI_Google.cc:117 msgid "" "You have selected the following databases to be completely erased from your " "Google Calendar:" msgstr "" #: src/CUI_KDEPim.cc:59 msgid "KDEPim needs no configuration." msgstr "" #: src/CUI_KDEPim.cc:59 msgid "KDEPim Config" msgstr "" #: src/CUI_KDEPim.cc:85 msgid "Kontact already running." msgstr "" #: src/CUI_KDEPim.cc:95 msgid "Starting Kontact. Delete all contacts and calendar entries manually." msgstr "" #: src/CUI_KDEPim.cc:100 msgid "" "Starting Kontact. Delete all contacts and calendar entries manually (as " "well as memos and tasks if you are syncing them too)." msgstr "" #: src/CUI_KDEPim.cc:105 msgid "Starting Kontact" msgstr "" #: src/CalendarEditDlg.cc:42 msgid "Calendar Record" msgstr "" #: src/CalendarEditDlg.cc:64 msgid "Subject:" msgstr "" #: src/CalendarEditDlg.cc:66 msgid "Location:" msgstr "" #: src/CalendarEditDlg.cc:69 msgid "All Day Event:" msgstr "" #: src/CalendarEditDlg.cc:71 msgid "Start:" msgstr "" #: src/CalendarEditDlg.cc:76 msgid "End:" msgstr "" #: src/CalendarEditDlg.cc:81 msgid "Duration:" msgstr "" #: src/CalendarEditDlg.cc:83 src/CalendarEditDlg.cc:109 msgid "hours and" msgstr "" #: src/CalendarEditDlg.cc:85 src/CalendarEditDlg.cc:111 msgid "minutes." msgstr "" #: src/CalendarEditDlg.cc:86 src/TaskEditDlg.cc:103 msgid "Time Zone:" msgstr "" #: src/CalendarEditDlg.cc:88 msgid "System Time Zone" msgstr "" #: src/CalendarEditDlg.cc:91 msgid "Show As:" msgstr "" #: src/CalendarEditDlg.cc:101 msgid "Free" msgstr "" #: src/CalendarEditDlg.cc:102 msgid "Tentative" msgstr "" #: src/CalendarEditDlg.cc:103 msgid "Busy" msgstr "" #: src/CalendarEditDlg.cc:104 msgid "Out of Office" msgstr "" #: src/CalendarEditDlg.cc:107 src/TaskEditDlg.cc:108 msgid "Reminder:" msgstr "" #: src/CalendarEditDlg.cc:113 src/TaskEditDlg.cc:115 msgid "Recurrence:" msgstr "" #: src/CalendarEditDlg.cc:124 src/TaskEditDlg.cc:126 msgid "None" msgstr "" #: src/CalendarEditDlg.cc:125 src/TaskEditDlg.cc:127 msgid "Daily" msgstr "" #: src/CalendarEditDlg.cc:126 src/TaskEditDlg.cc:128 msgid "Weekly" msgstr "" #: src/CalendarEditDlg.cc:127 src/TaskEditDlg.cc:129 msgid "Monthly" msgstr "" #: src/CalendarEditDlg.cc:128 src/TaskEditDlg.cc:130 msgid "Yearly" msgstr "" #: src/CalendarEditDlg.cc:131 src/TaskEditDlg.cc:133 msgid "Interval:" msgstr "" #: src/CalendarEditDlg.cc:132 src/TaskEditDlg.cc:134 msgid "Every" msgstr "" #: src/CalendarEditDlg.cc:134 src/TaskEditDlg.cc:136 msgid "days? weeks? months?" msgstr "" #: src/CalendarEditDlg.cc:135 src/TaskEditDlg.cc:137 msgid "Days:" msgstr "" #: src/CalendarEditDlg.cc:143 src/TaskEditDlg.cc:145 msgid "Relative Date:" msgstr "" #: src/CalendarEditDlg.cc:145 src/TaskEditDlg.cc:147 msgid "End Date:" msgstr "" #: src/CalendarEditDlg.cc:146 src/TaskEditDlg.cc:148 msgid "Never ends" msgstr "" #: src/CalendarEditDlg.cc:149 msgid "Organizer:" msgstr "" #: src/CalendarEditDlg.cc:151 msgid "Invited:" msgstr "" #: src/CalendarEditDlg.cc:153 msgid "Accepted By:" msgstr "" #: src/CalendarEditDlg.cc:164 msgid "Public" msgstr "" #: src/CalendarEditDlg.cc:165 msgid "Private" msgstr "" #: src/CalendarEditDlg.cc:166 msgid "Confidential" msgstr "" #: src/CalendarEditDlg.cc:168 msgid "Class" msgstr "" #: src/CalendarEditDlg.cc:170 src/TaskEditDlg.cc:153 msgid "Notes:" msgstr "" #: src/CalendarEditDlg.cc:181 src/TaskEditDlg.cc:164 msgid "Assume Local Timezone" msgstr "" #: src/CalendarEditDlg.cc:302 msgid "Calendar Event" msgstr "" #: src/CalendarEditDlg.cc:326 src/CalendarEditDlg.cc:329 #: src/TaskEditDlg.cc:246 src/TaskEditDlg.cc:249 msgid "Set Reminder to 0 to disable" msgstr "" #: src/CalendarEditDlg.cc:342 src/CalendarEditDlg.cc:343 #: src/TaskEditDlg.cc:262 src/TaskEditDlg.cc:263 msgid "" "Relative monthly or yearly dates take the weekday of the start date into " "account. (eg. every first Sunday of month)" msgstr "" #: src/CalendarEditDlg.cc:642 msgid "Start time must come before end time." msgstr "" #: src/CalendarEditDlg.cc:643 msgid "Validation Error" msgstr "" #: src/CalendarEditDlg.cc:827 src/TaskEditDlg.cc:705 msgid "day(s)" msgstr "" #: src/CalendarEditDlg.cc:831 src/TaskEditDlg.cc:709 msgid "week(s)" msgstr "" #: src/CalendarEditDlg.cc:835 src/TaskEditDlg.cc:713 msgid "month(s)" msgstr "" #: src/CalendarEditDlg.cc:839 src/TaskEditDlg.cc:717 msgid "year(s)" msgstr "" #: src/ConflictDlg.cc:93 msgid "Sync Conflict" msgstr "" #: src/ConflictDlg.cc:315 msgid "XML..." msgstr "" #: src/ConflictDlg.cc:321 msgid "Select" msgstr "" #: src/ConflictDlg.cc:340 msgid "No XML map found." msgstr "" #: src/ConflictDlg.cc:391 msgid "Always use this choice" msgstr "" #: src/ConflictDlg.cc:397 msgid "Duplicate" msgstr "" #: src/ConflictDlg.cc:403 msgid "Ignore" msgstr "" #: src/ConflictDlg.cc:409 msgid "Keep Newer" msgstr "" #: src/ConflictDlg.cc:415 msgid "Abort" msgstr "" #: src/ConflictDlg.cc:421 src/SyncStatusDlg.cc:360 src/SyncStatusDlg.cc:371 #: src/SyncStatusDlg.cc:604 src/SyncStatusDlg.cc:608 msgid "Kill Sync" msgstr "" #: src/ConflictDlg.cc:492 msgid "Raw Change Data" msgstr "" #: src/ContactEditDlg.cc:37 msgid "Contact Record" msgstr "" #: src/ContactEditDlg.cc:50 msgid "Home" msgstr "" #: src/ContactEditDlg.cc:51 msgid "Work" msgstr "" #. TRANSLATORS: this is a main screen button label #: src/ContactEditDlg.cc:52 src/util.cc:65 msgid "Misc" msgstr "" #: src/ContactEditDlg.cc:53 msgid "Mobile" msgstr "" #: src/ContactEditDlg.cc:54 src/GroupCfgDlg.cc:328 msgid "Notes" msgstr "" #: src/ContactEditDlg.cc:55 src/Mode_Sync.cc:182 msgid "Name" msgstr "" #: src/ContactEditDlg.cc:57 msgid "Title" msgstr "" #: src/ContactEditDlg.cc:59 msgid "First" msgstr "" #: src/ContactEditDlg.cc:61 msgid "Last" msgstr "" #: src/ContactEditDlg.cc:63 msgid "Company" msgstr "" #: src/ContactEditDlg.cc:65 msgid "Job Title" msgstr "" #: src/ContactEditDlg.cc:67 msgid "Nickname" msgstr "" #: src/ContactEditDlg.cc:69 src/ContactEditDlg.cc:89 msgid "Address" msgstr "" #: src/ContactEditDlg.cc:73 src/ContactEditDlg.cc:93 msgid "City" msgstr "" #: src/ContactEditDlg.cc:75 src/ContactEditDlg.cc:95 msgid "Province" msgstr "" #: src/ContactEditDlg.cc:77 src/ContactEditDlg.cc:97 msgid "Postal Code" msgstr "" #: src/ContactEditDlg.cc:79 src/ContactEditDlg.cc:99 msgid "Country" msgstr "" #: src/ContactEditDlg.cc:83 src/ContactEditDlg.cc:103 msgid "Phone" msgstr "" #: src/ContactEditDlg.cc:85 src/ContactEditDlg.cc:105 msgid "Phone 2" msgstr "" #: src/ContactEditDlg.cc:87 src/ContactEditDlg.cc:107 msgid "Fax" msgstr "" #: src/ContactEditDlg.cc:109 msgid "Email" msgstr "" #: src/ContactEditDlg.cc:111 msgid "Other Phone" msgstr "" #: src/ContactEditDlg.cc:113 msgid "Old Phone" msgstr "" #: src/ContactEditDlg.cc:115 msgid "Radio" msgstr "" #: src/ContactEditDlg.cc:117 src/Mode_Sync.cc:180 msgid "PIN" msgstr "" #: src/ContactEditDlg.cc:119 msgid "User1" msgstr "" #: src/ContactEditDlg.cc:121 msgid "User2" msgstr "" #: src/ContactEditDlg.cc:123 msgid "User3" msgstr "" #: src/ContactEditDlg.cc:125 msgid "User4" msgstr "" #: src/ContactEditDlg.cc:127 msgid "Cell" msgstr "" #: src/ContactEditDlg.cc:129 msgid "Cell 2" msgstr "" #: src/ContactEditDlg.cc:131 msgid "Pager" msgstr "" #: src/ContactEditDlg.cc:134 msgid "URL" msgstr "" #: src/ContactEditDlg.cc:150 msgid "Contact" msgstr "" #: src/ContactEditDlg.cc:183 msgid "" "Comma separated list of simple email addresses. Do not use <> characters." msgstr "" #: src/ContactEditDlg.cc:346 msgid "Load new photo" msgstr "" #: src/ContactEditDlg.cc:347 msgid "Save current photo to disk" msgstr "" #: src/ContactEditDlg.cc:348 msgid "Delete current photo" msgstr "" #: src/ContactEditDlg.cc:351 msgid "A photo currently exists. Would you like to:" msgstr "" #: src/ContactEditDlg.cc:352 msgid "Photo Management" msgstr "" #: src/ContactEditDlg.cc:398 msgid "" "A contact record must contain either a First/Last name, or a Company name." msgstr "" #: src/ContactEditDlg.cc:399 src/MemoEditDlg.cc:113 msgid "Required Fields" msgstr "" #. TRANSLATORS: this is the first part of a file selector string, #. as in: "Images files (*.bmp;*.jpg;*.png)" #. The file types are not part of the translation. #: src/ContactPhotoWidget.cc:43 msgid "Image files" msgstr "" #. TRANSLATORS: this is a file selector string. See "Image files" #. for more info. #. TRANSLATORS: this is a file selector string, #. see "Image files" for more info. #: src/ContactPhotoWidget.cc:47 src/Mode_Browse.cc:1090 msgid "All files" msgstr "" #: src/ContactPhotoWidget.cc:87 msgid "There is no photo available to save." msgstr "" #: src/ContactPhotoWidget.cc:88 msgid "No Photo" msgstr "" #. TRANSLATORS: this is a file selector string. See "Image files" #. for more info. #: src/ContactPhotoWidget.cc:95 msgid "JPEG files" msgstr "" #: src/ContactPhotoWidget.cc:98 msgid "Save Photo as JPEG..." msgstr "" #: src/ContactPhotoWidget.cc:110 msgid "Load Photo..." msgstr "" #: src/ContactPhotoWidget.cc:119 msgid "Unable to load selected photo." msgstr "" #: src/ContactPhotoWidget.cc:120 msgid "Photo Load Error" msgstr "" #: src/ContactPhotoWidget.cc:128 msgid "Unable to convert image to JPEG." msgstr "" #: src/ContactPhotoWidget.cc:129 msgid "Photo Convert" msgstr "" #: src/ContactPhotoWidget.cc:172 src/Mode_Sync.cc:262 msgid "No" msgstr "" #: src/ContactPhotoWidget.cc:172 msgid "Photo" msgstr "" #: src/EvoCfgDlg.cc:32 msgid "Evolution Plugin Configuration" msgstr "" #: src/EvoCfgDlg.cc:51 msgid "Address Book:" msgstr "" #: src/EvoCfgDlg.cc:58 msgid "Calendar:" msgstr "" #: src/EvoCfgDlg.cc:65 msgid "Tasks:" msgstr "" #: src/EvoCfgDlg.cc:72 msgid "Memos:" msgstr "" #: src/EvoCfgDlg.cc:169 #, c-format msgid "File '%s' does not exist." msgstr "" #: src/EvoCfgDlg.cc:181 msgid "" "No paths set! If there are no default options available in the drop down " "lists, please double check that you've initialized your Evolution account " "first." msgstr "" #: src/EvoCfgDlg.cc:194 msgid "Minimum Config Required" msgstr "" #: src/EvoDefaultDlg.cc:36 msgid "Evolution Success" msgstr "" #: src/EvoDefaultDlg.cc:52 msgid "Successfully auto-detected Evolution configuration!" msgstr "" #: src/EvoDefaultDlg.cc:61 msgid "Manual Cfg..." msgstr "" #: src/GroupCfgDlg.cc:57 msgid "Device Sync Configuration" msgstr "" #: src/GroupCfgDlg.cc:80 msgid "Must have at least one engine in GroupCfgDlg" msgstr "" #: src/GroupCfgDlg.cc:86 msgid "Configure Device - " msgstr "" #: src/GroupCfgDlg.cc:140 msgid "" "No supported applications found. You may need to install some opensync " "plugins." msgstr "" #: src/GroupCfgDlg.cc:141 msgid "No App Found" msgstr "" #: src/GroupCfgDlg.cc:162 msgid "OpenSync Engine" msgstr "" #: src/GroupCfgDlg.cc:199 msgid "Barry Config" msgstr "" #: src/GroupCfgDlg.cc:205 msgid "Name:" msgstr "" #: src/GroupCfgDlg.cc:214 src/ModemDlg.cc:65 msgid "Password:" msgstr "" #: src/GroupCfgDlg.cc:224 msgid "Debug output during sync" msgstr "" #: src/GroupCfgDlg.cc:233 src/Mode_Sync.cc:186 msgid "Application" msgstr "" #: src/GroupCfgDlg.cc:261 msgid "&Configure..." msgstr "" #: src/GroupCfgDlg.cc:277 msgid "No engine selected" msgstr "" #: src/GroupCfgDlg.cc:286 msgid "Exception caught in LoadAppNames: " msgstr "" #: src/GroupCfgDlg.cc:311 msgid "No supported plugins available" msgstr "" #: src/GroupCfgDlg.cc:319 msgid "Sync:" msgstr "" #: src/GroupCfgDlg.cc:325 msgid "Events" msgstr "" #: src/GroupCfgDlg.cc:331 msgid "To-dos" msgstr "" #. TRANSLATORS: these 3 strings are options for default #. conflict resolution during syncing #: src/GroupCfgDlg.cc:343 msgid "Favour device" msgstr "" #: src/GroupCfgDlg.cc:344 msgid "Favour application" msgstr "" #: src/GroupCfgDlg.cc:345 msgid "Ask me" msgstr "" #: src/GroupCfgDlg.cc:348 msgid "To Resolve Conflicts:" msgstr "" #: src/GroupCfgDlg.cc:491 msgid "Please select an application." msgstr "" #: src/GroupCfgDlg.cc:492 src/GroupCfgDlg.cc:500 src/GroupCfgDlg.cc:588 msgid "Application Config" msgstr "" #: src/GroupCfgDlg.cc:499 msgid "No configuration interface available for this Application." msgstr "" #: src/GroupCfgDlg.cc:566 msgid "Please select an engine." msgstr "" #: src/GroupCfgDlg.cc:567 src/GroupCfgDlg.cc:574 msgid "Device Config" msgstr "" #: src/GroupCfgDlg.cc:573 msgid "Barry doesn't have a PIN number. This should never happen." msgstr "" #: src/GroupCfgDlg.cc:587 msgid "The application plugin is not fully configured." msgstr "" #: src/GroupCfgDlg.cc:615 msgid "Please select conflict resolution method." msgstr "" #: src/GroupCfgDlg.cc:616 msgid "Conflict Resolution" msgstr "" #: src/MemoEditDlg.cc:36 msgid "Memo Record" msgstr "" #: src/MemoEditDlg.cc:49 msgid "Title:" msgstr "" #: src/MemoEditDlg.cc:51 src/TaskEditDlg.cc:151 msgid "Categories:" msgstr "" #: src/MemoEditDlg.cc:64 msgid "Memo" msgstr "" #: src/MemoEditDlg.cc:68 msgid "Comma separated" msgstr "" #: src/MemoEditDlg.cc:70 msgid "Comma separated list of categories (can be empty)" msgstr "" #: src/MemoEditDlg.cc:73 msgid "Body of memo" msgstr "" #: src/MemoEditDlg.cc:112 msgid "Please enter a title for your memo." msgstr "" #: src/MigrateDlg.cc:144 msgid "Migrate device data from source device to target device." msgstr "" #: src/MigrateDlg.cc:167 msgid "Ready..." msgstr "" #: src/MigrateDlg.cc:189 msgid "Source device" msgstr "" #: src/MigrateDlg.cc:207 msgid "Migrate Now" msgstr "" #: src/MigrateDlg.cc:212 msgid "Cancel" msgstr "" #: src/MigrateDlg.cc:221 msgid "Prompt to plug in later..." msgstr "" #: src/MigrateDlg.cc:229 msgid "Destination device" msgstr "" #. TRANSLATORS: these 4 strings are write-mode options in the #. Migrate Device dialog #: src/MigrateDlg.cc:242 msgid "Erase all, then restore" msgstr "" #: src/MigrateDlg.cc:243 msgid "Add new, and overwrite existing" msgstr "" #: src/MigrateDlg.cc:244 msgid "Add only, don't overwrite existing" msgstr "" #: src/MigrateDlg.cc:245 msgid "Add every record as a new entry (may cause duplicates)" msgstr "" #: src/MigrateDlg.cc:247 msgid "Write Mode:" msgstr "" #: src/MigrateDlg.cc:275 msgid "Waiting for thread to close..." msgstr "" #: src/MigrateDlg.cc:336 msgid "" "Please select a source and destination device, as well as the write mode." msgstr "" #: src/MigrateDlg.cc:337 msgid "Migration Options Needed" msgstr "" #: src/MigrateDlg.cc:343 msgid "Cannot migrate from and to the same PIN." msgstr "" #: src/MigrateDlg.cc:344 msgid "Migration Options Error" msgstr "" #: src/MigrateDlg.cc:371 msgid "Invalid write mode. This should never happen. Contact the developers." msgstr "" #: src/MigrateDlg.cc:372 msgid "Internal Logic Error" msgstr "" #: src/MigrateDlg.cc:412 msgid "Waiting for thread..." msgstr "" #: src/MigrateDlg.cc:421 msgid "Cancelled by user..." msgstr "" #: src/MigrateDlg.cc:439 msgid "Please plug in the target device now." msgstr "" #: src/MigrateDlg.cc:440 msgid "Ready for Writing" msgstr "" #: src/MigrateDlg.cc:450 msgid "Scanning USB for devices..." msgstr "" #: src/MigrateDlg.cc:469 msgid "User input..." msgstr "" #: src/MigrateDlg.cc:474 msgid "Please select the target device to write to:" msgstr "" #: src/MigrateDlg.cc:475 msgid "Destination PIN" msgstr "" #: src/MigrateDlg.cc:487 msgid "Cannot use the same device PIN as migration destination." msgstr "" #: src/MigrateDlg.cc:488 msgid "Invalid Device Selection" msgstr "" #: src/MigrateDlg.cc:522 src/Mode_Browse.cc:258 #, c-format msgid "Please enter device password: (%d tries remaining)" msgstr "" #: src/MigrateDlg.cc:527 src/Mode_Browse.cc:263 msgid "Device Password" msgstr "" #: src/MigrateDlg.cc:533 msgid "Migration Error" msgstr "" #: src/MigrateDlg.cc:593 msgid "Connecting..." msgstr "" #: src/MigrateDlg.cc:645 msgid "Backing up database: " msgstr "" #: src/MigrateDlg.cc:672 msgid "Backup aborted by user..." msgstr "" #: src/MigrateDlg.cc:693 msgid "Connecting to target..." msgstr "" #: src/MigrateDlg.cc:734 msgid "Writing database: " msgstr "" #: src/MigrateDlg.cc:765 msgid "Restore aborted by user..." msgstr "" #: src/MigrateDlg.cc:771 msgid "Unable to clear or write to database: " msgstr "" #: src/MigrateDlg.cc:774 msgid "Continuing to process remaining records..." msgstr "" #: src/MimeExportDlg.cc:41 msgid "MIME Card Data" msgstr "" #: src/MimeExportDlg.cc:48 msgid "Save..." msgstr "" #: src/MimeExportDlg.cc:78 msgid "Save Card as..." msgstr "" #: src/Mode_Browse.cc:71 msgid "" "This database is apparently read-only. If this device is connected to a " "BES, you cannot edit records via USB. (Error: " msgstr "" #: src/Mode_Browse.cc:72 msgid "Device Error" msgstr "" #. TRANSLATORS: this is a file selector string, #. see "Image files" for more info. #: src/Mode_Browse.cc:94 msgid "VCard files" msgstr "" #. TRANSLATORS: this is a file selector string, #. see "Image files" for more info. #: src/Mode_Browse.cc:107 msgid "ICalendar files" msgstr "" #: src/Mode_Browse.cc:290 msgid "raw data" msgstr "" #: src/Mode_Browse.cc:368 msgid "DataCachePtr has no builder" msgstr "" #: src/Mode_Browse.cc:385 msgid "Device exception: " msgstr "" #: src/Mode_Browse.cc:554 msgid "" "Delete this record?\n" " " msgstr "" #: src/Mode_Browse.cc:555 msgid "Record Delete" msgstr "" #: src/Mode_Browse.cc:599 msgid "Failed to create map mutex" msgstr "" #: src/Mode_Browse.cc:603 msgid "Failed to create load mutex" msgstr "" #: src/Mode_Browse.cc:738 msgid "Loading: " msgstr "" #: src/Mode_Browse.cc:791 msgid "Show All Databases" msgstr "" #: src/Mode_Browse.cc:821 msgid "Import..." msgstr "" #: src/Mode_Browse.cc:824 msgid "Export..." msgstr "" #: src/Mode_Browse.cc:827 msgid "Add..." msgstr "" #: src/Mode_Browse.cc:830 msgid "Copy..." msgstr "" #: src/Mode_Browse.cc:833 msgid "Edit..." msgstr "" #: src/Mode_Browse.cc:836 msgid "Delete..." msgstr "" #: src/Mode_Browse.cc:857 msgid "Databases" msgstr "" #: src/Mode_Browse.cc:859 msgid "Count" msgstr "" #: src/Mode_Browse.cc:867 msgid "Record Description" msgstr "" #: src/Mode_Browse.cc:1069 #, c-format msgid "Card file type (%s) does not match record you are trying to add (%s)." msgstr "" #: src/Mode_Browse.cc:1072 msgid "Invalid Card Type" msgstr "" #: src/Mode_Browse.cc:1095 msgid "Load Record..." msgstr "" #: src/Mode_Browse.cc:1106 msgid "No card data found in: " msgstr "" #: src/Mode_Browse.cc:1107 msgid "Import Read Error" msgstr "" #: src/Mode_Browse.cc:1154 #, c-format msgid "Unable to import selected file: %s" msgstr "" #: src/Mode_Browse.cc:1155 msgid "Import Error" msgstr "" #: src/Mode_Browse.cc:1164 msgid "Internal pointer error: cannot find DBCachePtr for: " msgstr "" #: src/Mode_Browse.cc:1165 src/Mode_Browse.cc:1180 msgid "Internal Error" msgstr "" #: src/Mode_Browse.cc:1179 msgid "Internal error: cannot add record to DBCache" msgstr "" #: src/Mode_Browse.h:99 msgid "Failed to create mutex for ThreadableDesktop" msgstr "" #: src/Mode_Browse.h:469 msgid "Barry Database Browser" msgstr "" #: src/Mode_MainMenu.cc:57 msgid "Ignorable screenshot exception: " msgstr "" #: src/Mode_Sync.cc:75 msgid "" "Multiple configurations have been found with the same PIN. Please select\n" "the configuration that Barry Desktop should work with." msgstr "" #: src/Mode_Sync.cc:125 msgid "Select the device(s) you want to sync and press Sync Now." msgstr "" #: src/Mode_Sync.cc:126 msgid "Use Configure to configure the currently selected device." msgstr "" #: src/Mode_Sync.cc:127 msgid "Use Run App to start the application that the device syncs with." msgstr "" #: src/Mode_Sync.cc:128 msgid "" "Use 1-Way Reset to recover from a broken sync, copying all device data to " "application, or vice versa." msgstr "" #: src/Mode_Sync.cc:140 src/Mode_Sync.cc:507 msgid "Device List" msgstr "" #: src/Mode_Sync.cc:153 src/SyncStatusDlg.cc:349 msgid "Run App" msgstr "" #: src/Mode_Sync.cc:156 msgid "Configure..." msgstr "" #: src/Mode_Sync.cc:159 msgid "1 Way Reset..." msgstr "" #: src/Mode_Sync.cc:184 msgid "Connected" msgstr "" #: src/Mode_Sync.cc:188 msgid "Engine" msgstr "" #: src/Mode_Sync.cc:190 msgid "Last Sync" msgstr "" #: src/Mode_Sync.cc:262 msgid "Yes" msgstr "" #: src/Mode_Sync.cc:270 msgid "(No config)" msgstr "" #: src/Mode_Sync.cc:363 src/Mode_Sync.cc:678 msgid "An application is currently running." msgstr "" #: src/Mode_Sync.cc:364 src/Mode_Sync.cc:706 msgid "Run App Error" msgstr "" #: src/Mode_Sync.cc:390 msgid "Config is the same, skipping save" msgstr "" #: src/Mode_Sync.cc:447 msgid "" "Unable to save configuration for this device.\n" "Error: " msgstr "" #: src/Mode_Sync.cc:449 msgid "OpenSync Save Error" msgstr "" #. TRANSLATORS: first %s is the PIN number, and #. the second (in parentheses) is the device name. #: src/Mode_Sync.cc:484 #, c-format msgid "Selected device %s (%s) is not yet configured. Configure now?" msgstr "" #: src/Mode_Sync.cc:489 msgid "Configure Now?" msgstr "" #: src/Mode_Sync.cc:506 msgid "Please select one device from the list." msgstr "" #: src/Mode_Sync.cc:536 msgid "" "Which device / application should be considered\n" "authoritative?\n" "\n" "All data in non-authoritative devices / applications\n" "will be deleted in order to setup a straight copy on\n" "the next sync." msgstr "" #: src/Mode_Sync.cc:566 msgid "Select Authoritative Device / Application" msgstr "" #: src/Mode_Sync.cc:639 msgid "Unable to rewrite config! Start over manually. Error: " msgstr "" #: src/Mode_Sync.cc:643 msgid "Error Rewriting Config" msgstr "" #: src/Mode_Sync.cc:659 msgid "" "The sync config you are about to save is sufficiently different from the " "existing one that a 1-Way Reset will be required. You will need to perform " "the reset at your earliest convenience, before your next sync.\n" "\n" "Continue anyway?" msgstr "" #: src/Mode_Sync.cc:665 msgid "1-Way Reset Warning" msgstr "" #: src/Mode_Sync.cc:679 msgid "Sync Error" msgstr "" #: src/Mode_Sync.cc:705 msgid "An application is already running." msgstr "" #: src/Mode_Sync.cc:751 msgid "1-Way Reset is complete, and ready to sync." msgstr "" #: src/Mode_Sync.cc:752 msgid "Reset Complete" msgstr "" #: src/Mode_Sync.h:75 msgid "Barry Sync" msgstr "" #: src/ModemDlg.cc:50 msgid "Modem Kickstart" msgstr "" #: src/ModemDlg.cc:55 msgid "Device" msgstr "" #: src/ModemDlg.cc:56 msgid "Providers" msgstr "" #: src/ModemDlg.cc:57 msgid "For device pin:" msgstr "" #: src/ModemDlg.cc:97 msgid "Modem Starter" msgstr "" #: src/ModemDlg.cc:100 msgid "Available provider scripts on your system. Must pick one." msgstr "" #: src/ModemDlg.cc:102 src/ModemDlg.cc:104 msgid "Optional device password" msgstr "" #: src/ModemDlg.cc:254 msgid "" "Cannot locate the xterm program. This is used to display modem connection " "output. Please install it and try again." msgstr "" #: src/ModemDlg.cc:254 msgid "Xterm Not Found" msgstr "" #: src/ModemDlg.cc:263 msgid "Cannot find pppd. Please install it for modem use." msgstr "" #: src/ModemDlg.cc:263 msgid "pppd Not Found" msgstr "" #: src/ModemDlg.cc:278 #, c-format msgid "" "Your system's PPP has the suid bit set, with a group of '%s'. You should " "add your account to the '%s' group, to avoid the need to enter the root " "password every time you use the modem.\n" "\n" "Continue anyway?" msgstr "" #: src/ModemDlg.cc:279 msgid "System Group" msgstr "" #: src/ModemDlg.cc:297 msgid "Internal fork error. Should never happen." msgstr "" #: src/ModemDlg.cc:297 msgid "Cannot Run pppd" msgstr "" #: src/ModemDlg.cc:303 #, c-format msgid "Unable to run pppd correctly. Unexpected error code: %d, %s" msgstr "" #: src/ModemDlg.cc:304 msgid "Error Code" msgstr "" #: src/ModemDlg.cc:318 msgid "" "Unable to access files in /etc/ppp/peers. Do you have the correct " "permissions?" msgstr "" #: src/ModemDlg.cc:318 msgid "Cannot Open Peers" msgstr "" #: src/ModemDlg.cc:330 msgid "" "No providers found. Make sure Barry was properly installed, with peer files " "in /etc/ppp/peers." msgstr "" #: src/ModemDlg.cc:330 msgid "No Providers" msgstr "" #: src/ModemDlg.cc:346 #, c-format msgid "" "Cannot read provider files under /etc/ppp/peers. Please check your file " "permissions. (Access failed for %s)" msgstr "" #: src/ModemDlg.cc:347 msgid "Permissions Error" msgstr "" #: src/ModemDlg.cc:368 #, c-format msgid "Unable to open peer file: %s" msgstr "" #: src/ModemDlg.cc:369 msgid "Invalid Peer" msgstr "" #: src/ModemDlg.cc:382 msgid "Starting pppd for device PIN " msgstr "" #: src/ModemDlg.cc:393 msgid "Press enter to close window..." msgstr "" #: src/PNGButton.cc:57 msgid "Cannot load button bitmap." msgstr "" #: src/SyncStatusDlg.cc:66 msgid "Syncing entries..." msgstr "" #: src/SyncStatusDlg.cc:258 msgid "Device Sync Progress" msgstr "" #: src/SyncStatusDlg.cc:306 msgid "Sync Progress" msgstr "" #: src/SyncStatusDlg.cc:340 src/SyncStatusDlg.cc:629 msgid "Show Details" msgstr "" #: src/SyncStatusDlg.cc:355 msgid "Sync Again" msgstr "" #: src/SyncStatusDlg.cc:385 msgid "Close" msgstr "" #: src/SyncStatusDlg.cc:440 msgid "Sync Progress Dialog" msgstr "" #: src/SyncStatusDlg.cc:444 msgid "Syncing: " msgstr "" #: src/SyncStatusDlg.cc:445 msgid " with " msgstr "" #: src/SyncStatusDlg.cc:480 msgid "No more devices to sync." msgstr "" #: src/SyncStatusDlg.cc:495 msgid " is not configured, skipping." msgstr "" #: src/SyncStatusDlg.cc:496 msgid "Skipping unconfigured: " msgstr "" #: src/SyncStatusDlg.cc:507 msgid "Starting sync for: " msgstr "" #: src/SyncStatusDlg.cc:524 msgid "ERROR: App running in StartNextSync()" msgstr "" #: src/SyncStatusDlg.cc:545 msgid "ERROR: unable to start bsyncjail: " msgstr "" #: src/SyncStatusDlg.cc:546 msgid "ERROR: unable to start bsyncjail" msgstr "" #: src/SyncStatusDlg.cc:557 msgid "Slow sync detected! Killing sync automatically." msgstr "" #: src/SyncStatusDlg.cc:560 msgid "Slow syncs are known to be unreliable." msgstr "" #: src/SyncStatusDlg.cc:561 msgid "Do a 1 Way Reset, and sync again." msgstr "" #: src/SyncStatusDlg.cc:576 msgid "The application is already running." msgstr "" #: src/SyncStatusDlg.cc:577 msgid "Run Application" msgstr "" #: src/SyncStatusDlg.cc:603 msgid "Already killing sync. Kill again?" msgstr "" #: src/SyncStatusDlg.cc:607 msgid "" "This will kill the syncing child process, and will likely require a " "configuration reset.\n" "\n" "Kill sync process anyway?" msgstr "" #: src/SyncStatusDlg.cc:614 msgid "Killing sync... this may take a little while..." msgstr "" #: src/SyncStatusDlg.cc:615 msgid "Remember to re-plug your device." msgstr "" #: src/SyncStatusDlg.cc:651 msgid "Hide Details" msgstr "" #: src/SyncStatusDlg.cc:675 msgid "Sync terminated: " msgstr "" #: src/SyncStatusDlg.cc:677 msgid "Sync finished: " msgstr "" #: src/SyncStatusDlg.cc:680 msgid " with error code " msgstr "" #: src/TaskEditDlg.cc:42 msgid "Task Record" msgstr "" #: src/TaskEditDlg.cc:62 msgid "Task:" msgstr "" #: src/TaskEditDlg.cc:65 msgid "Status:" msgstr "" #: src/TaskEditDlg.cc:76 msgid "Not Started" msgstr "" #: src/TaskEditDlg.cc:77 msgid "In Progress" msgstr "" #: src/TaskEditDlg.cc:78 msgid "Completed" msgstr "" #: src/TaskEditDlg.cc:79 msgid "Waiting" msgstr "" #: src/TaskEditDlg.cc:80 msgid "Deferred" msgstr "" #: src/TaskEditDlg.cc:83 msgid "Priority:" msgstr "" #: src/TaskEditDlg.cc:92 msgid "High" msgstr "" #: src/TaskEditDlg.cc:93 msgid "Normal" msgstr "" #: src/TaskEditDlg.cc:94 msgid "Low" msgstr "" #: src/TaskEditDlg.cc:97 msgid "Due:" msgstr "" #: src/TaskEditDlg.cc:231 msgid "Task Event" msgstr "" #: src/barrydesktop.cc:47 msgid "Scanning USB..." msgstr "" #: src/barrydesktop.cc:87 msgid "" "A serious error occurred while probing the USB subsystem for BlackBerry(R) " "devices: " msgstr "" #: src/barrydesktop.cc:89 msgid "USB Error" msgstr "" #: src/barrydesktop.cc:150 msgid "" "No OpenSync libraries were found. Sync will be unavailable until you install " "OpenSync version 0.22 or version 0.4x on your system, along with the needed " "plugins." msgstr "" #: src/barrydesktop.cc:150 msgid "OpenSync Not Found" msgstr "" #: src/bsyncjail.cc:123 msgid "Unable to connect to server." msgstr "" #: src/bsyncjail.cc:134 msgid "Can't find matching engine for: " msgstr "" #: src/bsyncjail.cc:144 msgid "Unknown engine number: " msgstr "" #: src/bsyncjail.cc:232 msgid "Invalid server response: " msgstr "" #: src/bsyncjail.cc:240 msgid "Invalid Select command from server: " msgstr "" #: src/bsyncjail.cc:250 msgid "Abort not supported, and server sent Abort command." msgstr "" #: src/bsyncjail.cc:256 msgid "Ignore not supported, and server sent Ignore command." msgstr "" #: src/bsyncjail.cc:262 msgid "Keep Newer not supported, and server sent Keep Newer command." msgstr "" #: src/bsyncjail.cc:267 msgid "Invalid command from server: " msgstr "" #: src/bsyncjail.cc:278 msgid "Lost connection with server" msgstr "" #: src/bsyncjail.cc:344 msgid "" "This is a helper program for barrydesktop, and\n" "is not intended to be called directly.\n" msgstr "" #: src/bsyncjail.cc:355 msgid "Unable to initialize wxWidgets library, aborting." msgstr "" #: src/bsyncjail.cc:361 msgid "bsyncjail exiting with code: " msgstr "" #: src/exechelper.cc:69 msgid "Application Run Error" msgstr "" #. TRANSLATORS: %s is the name of an application #: src/exechelper.cc:161 #, c-format msgid "%s is already running." msgstr "" #: src/exechelper.cc:174 #, c-format msgid "Failed to run %s. Please make sure it is installed and in your PATH." msgstr "" #. TRANSLATORS: this is a main screen button label. See #. util.cc line 200 for more information on its flexibility. #: src/util.cc:51 msgid "" "Backup &\n" "Restore" msgstr "" #. TRANSLATORS: this is a main screen button label #: src/util.cc:53 msgid "Sync" msgstr "" #. TRANSLATORS: this is a main screen button label #: src/util.cc:55 msgid "" "Modem\n" "Tethering" msgstr "" #. TRANSLATORS: this is a main screen button label #: src/util.cc:57 msgid "" "Migrate\n" "Device" msgstr "" #. TRANSLATORS: this is a main screen button label #: src/util.cc:59 msgid "" "Browse\n" "Databases" msgstr "" #. TRANSLATORS: this is a main screen button label #: src/util.cc:61 msgid "" "Application\n" "Loader" msgstr "" #. TRANSLATORS: this is a main screen button label #: src/util.cc:63 msgid "Media" msgstr "" #: src/util.cc:255 msgid "Unable to create button: font is invalid" msgstr "" #: src/util.cc:299 msgid "Unable to create button: text is too big to fit: " msgstr "" #: src/util.cc:308 msgid "Unable to create button: label is empty" msgstr "" #: src/wxval.h:69 msgid "Invalid date!" msgstr "" #: src/wxval.h:69 src/wxval.h:157 msgid "Validation" msgstr "" #: src/wxval.h:156 msgid "Please select one of the radio buttons." msgstr "" barry-0.18.5/desktop/po/Rules-quot0000644001161500056700000000340012242254476016343 0ustar cdfreycdfrey# Special Makefile rules for English message catalogs with quotation marks. DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot .SUFFIXES: .insert-header .po-update-en en@quot.po-create: $(MAKE) en@quot.po-update en@boldquot.po-create: $(MAKE) en@boldquot.po-update en@quot.po-update: en@quot.po-update-en en@boldquot.po-update: en@boldquot.po-update-en .insert-header.po-update-en: @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ tmpdir=`pwd`; \ echo "$$lang:"; \ ll=`echo $$lang | sed -e 's/@.*//'`; \ LC_ALL=C; export LC_ALL; \ cd $(srcdir); \ if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$lang -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ exit 1; \ fi; \ fi; \ else \ echo "creation of $$lang.po failed!" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ fi en@quot.insert-header: insert-header.sin sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header en@boldquot.insert-header: insert-header.sin sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header mostlyclean: mostlyclean-quot mostlyclean-quot: rm -f *.insert-header barry-0.18.5/desktop/po/LINGUAS0000644001161500056700000000004512242254476015367 0ustar cdfreycdfrey# Set of available languages. fr es barry-0.18.5/desktop/po/en@boldquot.header0000644001161500056700000000247112242254476017775 0ustar cdfreycdfrey# All this catalog "translates" are quotation characters. # The msgids must be ASCII and therefore cannot contain real quotation # characters, only substitutes like grave accent (0x60), apostrophe (0x27) # and double quote (0x22). These substitutes look strange; see # http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html # # This catalog translates grave accent (0x60) and apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019). # It also translates pairs of apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019) # and pairs of quotation mark (0x22) to # left double quotation mark (U+201C) and right double quotation mark (U+201D). # # When output to an UTF-8 terminal, the quotation characters appear perfectly. # When output to an ISO-8859-1 terminal, the single quotation marks are # transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to # grave/acute accent (by libiconv), and the double quotation marks are # transliterated to 0x22. # When output to an ASCII terminal, the single quotation marks are # transliterated to apostrophes, and the double quotation marks are # transliterated to 0x22. # # This catalog furthermore displays the text between the quotation marks in # bold face, assuming the VT100/XTerm escape sequences. # barry-0.18.5/desktop/po/en@quot.header0000644001161500056700000000226312242254476017133 0ustar cdfreycdfrey# All this catalog "translates" are quotation characters. # The msgids must be ASCII and therefore cannot contain real quotation # characters, only substitutes like grave accent (0x60), apostrophe (0x27) # and double quote (0x22). These substitutes look strange; see # http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html # # This catalog translates grave accent (0x60) and apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019). # It also translates pairs of apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019) # and pairs of quotation mark (0x22) to # left double quotation mark (U+201C) and right double quotation mark (U+201D). # # When output to an UTF-8 terminal, the quotation characters appear perfectly. # When output to an ISO-8859-1 terminal, the single quotation marks are # transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to # grave/acute accent (by libiconv), and the double quotation marks are # transliterated to 0x22. # When output to an ASCII terminal, the single quotation marks are # transliterated to apostrophes, and the double quotation marks are # transliterated to 0x22. # barry-0.18.5/desktop/po/ChangeLog0000644001161500056700000000073612242254476016123 0ustar cdfreycdfrey2012-07-18 gettextize * Makefile.in.in: New file, from gettext-0.18.1. * Rules-quot: New file, from gettext-0.18.1. * boldquot.sed: New file, from gettext-0.18.1. * en@boldquot.header: New file, from gettext-0.18.1. * en@quot.header: New file, from gettext-0.18.1. * insert-header.sin: New file, from gettext-0.18.1. * quot.sed: New file, from gettext-0.18.1. * remove-potcdate.sin: New file, from gettext-0.18.1. * POTFILES.in: New file. barry-0.18.5/desktop/po/README0000644001161500056700000000077712242254476015236 0ustar cdfreycdfreyHOWTO to add a new language or update translation ================================================= To add a new language --------------------- Sample to add spanish language $ cd /po $ msginit --locale=es --input=barrydesktop.pot $ echo "es" >> LINGUAS $ make update-po Then, send to barry team your work. To update translation --------------------- You have to only edit a ".po" file. $ cd /po $ vi es.po $ make update-po Then, send to barry team your work. barry-0.18.5/desktop/NEWS0000644001161500056700000000011312242254476014417 0ustar cdfreycdfrey See http://www.netdirect.ca/software/packages/barry for the latest news. barry-0.18.5/desktop/AUTHORS0000644001161500056700000000007212242254476014774 0ustar cdfreycdfreyChris Frey See ../AUTHORS file. barry-0.18.5/desktop/doc/0000755001161500056700000000000012242254476014472 5ustar cdfreycdfreybarry-0.18.5/desktop/doc/apple-darwin9.txt0000644001161500056700000002114712242254476017714 0ustar cdfreycdfreyDownloaded from: http://devs.openttd.org/~truebrain/compile-farm/apple-darwin9.txt Cross-Compiling on Linux for Mac OS X 10.3 - 10.5 (PPC and Intel) ==================================== Last Updated: 2009-03-29 It often is wroten down as impossible, but it can be done (and our nightlies are the living proof of that). You can make OSX binaries on a Linux based system. But, the process is not easy. Even worse, in the years we are supplying this, we had to change this documentation more often than any other target. This is mostly because you can't use a mainstream GCC, but you need the one from Apple. When you figured this out, and where to get the binutils tools, it in fact is very straight forward. Requirements: - Mac OS X SDK Framework 10.4u. - 7zip 4.61+ to extract DMG files. - A fast computer, or a lots of time. - A working 32bit linux compiler (on 64bit, use -m32 ;)). - Bison installed (else it configures, but compile fails). You get: - A i686-apple-darwin9 compiler (gcc and g++) For Mac OS X 10.4 - 10.5 Intel - A powerpc-apple-darwin9 compiler (gcc and g++) For Mac OS X 10.3 - 10.5 PPC - A x86_64-apple-darwin9 compiler (gcc and g++) For Mac OS X 10.5 Intel (64bit) Notes: - Even on 64bit systems, compile 32bit binaries. It avoids a lot of errors. Warning: - I can't guarantee you this will work, nor that it won't break your system. - Please, don't complain to me or ask me about this documentation. It is more meant as internal reference for when ever I want to reinstall the system. If it doesn't work for you, too bad, nothing to see here, find some other source. Ps: - Yes, this also works with Mac OS X 10.5 Intel. - Yes, you can also make a x86_64 compiler. The Start --------- Pick which compiler you want to compile. Either one should do: - i686-apple-darwin9 - powerpc-apple-darwin9 - x86_64-apple-darwin9 Now put that in a variable: export TARGET=i686-apple-darwin9 We will use this a lot later on, to simplify this documentation, and show you it works for any target you pick. CCTools ------- To start, you need tools like 'ld', 'ar', ... this you can find in the package named 'odcctools'. I used various of sources over the years, the last one which seems to produce valid linux binaries, is located here: http://iphone-dev.googlecode.com/svn/ A bit good comes of the iPhone development after all ;) To install it, you need some minor modifications. Also, I used the 'branches' version, which has 9.2 ld version (well, I thought the name was just more cool!) The current odcctools (r280) seems to contain a bug in the 'as'. It registers 'word' twice, which gives an error. Sadly enough, both definitions are different. But, this patch fixes the problem by commenting one out, hoping the value of the other (older) one is correct. The odcctools also contain a few other bugs and problems. So load all the patches. After that, it seems to compile just fine. # svn checkout http://iphone-dev.googlecode.com/svn/branches/odcctools-9.2-ld/ # cd odcctools-9.2-ld # wget http://devs.openttd.org/~truebrain/compile-farm/odcctools_as.patch # patch -p0 < odcctools_as.patch # wget http://devs.openttd.org/~truebrain/compile-farm/odcctools_qsort.patch # patch -p0 < odcctools_qsort.patch # wget http://devs.openttd.org/~truebrain/compile-farm/odcctools_lipo.patch # patch -p0 < odcctools_lipo.patch # wget http://devs.openttd.org/~truebrain/compile-farm/odcctools_ld64.patch # patch -p0 < odcctools_ld64.patch # ./configure --prefix=/usr/$TARGET --target=$TARGET --with-sysroot=/usr/$TARGET --enable-ld64 In case you run x86_64-pc-linux-gnu, you might want to consider running this instead: # LDFLAGS="-m32" CFLAGS="-m32" ./configure --prefix=/usr/$TARGET --target=$TARGET --with-sysroot=/usr/$TARGET --enable-ld64 Next: # vi Makefile On the line 'COMPONENTS = ', remove 'otool'. If you want this tool, make sure you have a objc++ compiler .. I don't, and I don't care about this tool. # make # make install Now you should have a few useful tools in /usr/$TARGET/bin directory. If not, take a step back, and try again. Mac OS X SDK ------------ Nowedays 7zip support .dmg files too (4.61+ I believe; I used 4.65). So now you can extract the files without access to a Mac. First, download xcode 3.1.2 from the Apple website (you need an account!). Feel free to use any other version. The newer the better I guess. For most targets, you want to extract the 10.4u SDK. This allows your binary to run from 10.3 to 10.5. But if you want to go for the x86_64 compiler, you need to go for the 10.5 SDK. As 10.4 can't run 64bit code anyway, it shouldn't be a real problem. After downloading, you can extract it with (a long tree of compressed objects in other compressed objects): # mkdir xcode # cd xcode # 7z x ../xcode312_2621_developerdvd.dmg # 7z x 5.hfs # 7z x Xcode\ Tools/Packages/MacOSX10.4.Universal.pkg # 7z x Payload # cpio -i < Payload~ # cp -R SDKs/MacOSX10.4u.sdk/* /usr/$TARGET/ # ln -sf /usr/$TARGET/System/Library/Frameworks /usr/$TARGET/Library/Frameworks This should give you enough files to continue the compile. You need to use 'cpio' on the last step, as 7z eats symlinks. GCC --- Now the most important part: GCC, your compiler. Download the latest GCC From the Apple website. I used: http://www.opensource.apple.com/darwinsource/tarballs/other/gcc-5490.tar.gz Feel free to use any newer. Extract the file somewhere. # cd /var/tmp # tar zxvf gcc-5490.tar.gz gcc works nicely out-of-the-box, but Apple introduced one stupid thing: they use 'lipo' to check if the host is 32bit or 64bit. Of course it should be checking against the target. So we need a patch to force either 32bit (which also happens when you don't patch) or 64bit (which you need if you want to use x86_64-apple-darwin9). So apply either of those patches: # cd gcc-5490 # wget http://devs.openttd.org/~truebrain/compile-farm/gcc-32bit.patch # wget http://devs.openttd.org/~truebrain/compile-farm/gcc-64bit.patch # patch -p0 < gcc-??bit.patch Also apply this patch, to avoid some weirdness with CFLAGS: # wget http://devs.openttd.org/~truebrain/compile-farm/gcc-cflags.patch # patch -p0 < gcc-cflags.patch Apply this patch if you don't want /usr/$TARGET/$TARGET dir (it annoys me .. it is nothing really ground-breaking or code-changing): # wget http://devs.openttd.org/~truebrain/compile-farm/gcc-tooldir.patch # patch -p0 < gcc-tooldir.patch # cd .. Now you can compile, like: # mkdir gcc-build # cd gcc-build # export PATH=$PATH:/usr/$TARGET/bin # ../gcc-5490/configure --prefix=/usr/$TARGET --disable-checking --enable-languages=c,objc,c++,obj-c++ --with-as=/usr/$TARGET/bin/$TARGET-as --with-ld=/usr/$TARGET/bin/$TARGET-ld --target=$TARGET --with-sysroot=/usr/$TARGET --enable-static --enable-shared --disable-nls --disable-multilib If you are on a 64bit system, you can run the following (avoids -lm errors): # CFLAGS="-m32" LDFLAGS="-m32" ../gcc-5490/configure --prefix=/usr/$TARGET --disable-checking --enable-languages=c,objc,c++,obj-c++ --with-as=/usr/$TARGET/bin/${TARGET}-as --with-ld=/usr/$TARGET/bin/${TARGET}-ld --target=$TARGET --with-sysroot=/usr/$TARGET --enable-static --enable-shared --disable-nls --disable-multilib If you are compiling x86_64-apple-darwin9, make sure to replace 'ld' with 'ld64' in the above configure. It isn't doing this on its own. Also, it looks like if you want to use 10.5 SDK for any other target, you need to use 'ld64' too. It seems 'ld' is slightly too old to understand a certain section in a library of the 10.5 SDK. Now just compile: # make # make install On a 32bit system, you most likely run into a problem with libstdc++v3. It tries to compile something while it is not allowed, or so it tells. I have yet no idea why this happens, I just know on a 64bit system this problem does not exist. If you solve it, please email me, and I will add your addition here. Now you should have a working gcc and g++ binary in your /usr/$TARGET/bin directory. As I said, it is very simple if you know which tools to use and what to use for configure flags. Other libs ---------- If you need libraries like libpng or libz, please start up your Mac OS X, and just copy them from there. Make sure that you use the right versions, and if possible universal build versions (those with multiple versions in them). It is almost impossible to compile such libraries yourself on your cross-compiler, and I would advise against it. Copying from a real Mac OS X is much easier, and shows much better results. But that is just my advise ;) Conclusion ---------- There is not really much more to it. If this worked for you, and you want to thank me, please donate some money to OpenTTD. It is always very welcome. barry-0.18.5/desktop/doc/DesktopPlan.txt0000644001161500056700000001556612242254476017474 0ustar cdfreycdfreyRequirements: ============= Main overriding design goal: make it easy to use... sacrifice functionality if you can't make it easy... add it later, but do the user-friendly stuff now. - one front panel screen to manage your blackberries, with all available main options as buttons on that front panel including: - easily readable header: "Barry Desktop Control Panel" - backup and restore - device switcher utility (basically an automated backup/restore?) - javaloader (manage programs, as well as the extra javaloader commands) - sync, with pre-defined list of applications: - Evolution - Sunbird - Kontact - for each supported application, automate the configuration process as much as possible... make the user pick the bare minimum! for example, Evolution has a file:///... path in its configuration in opensync 0.22 that can be auto-detected and configured automatically - media management (grab photos, etc) (will take longer than the rest, since low level USB is needed) - FUSE file browser via GUI - button to launch browser to jump to netdirect.ca/barry ? - system tray status icon, with access to desktop app - show Barry logo - cross platform - Linux, multi-distro - BSD? - Mac OS X - look into how OpenOffice/NeoOffice works and how Firefox manages cross-platform support - support both opensync versions: 0.22 and 0.4x Mainscreen Buttons: =================== Backup & Restore Sync Modem (configuration and going online/offline) Javaloader (loading and saving applications) Device Switch (a clone of a full backup and restore from one device to another) Browse Databases (browse database data like a filesystem hierarchy) Media Management (access photos, music, etc. via three methods: - MTP (Storm only) - Mass Storage: the SD card filesystem - proprietary USB protocol to access on-device memory storing pictures, sounds, etc (this is not yet implemented or reverse engineered) Miscellaneous - view device's event log - clear device's event log - take device screenshot - set the device's time API for supporting both opensync versions: ========================================== Wait, can we load libopensync libraries themselves with dlopen? Create a plugin system, loaded with dlopen(), with a similar API in each plugin. Common Functions: - list available opensync plugins (this is a function at the highest app level... since we are in charge of these API plugin wrappers) - list groups - list plugins - list objects - add group / del group - add member / del member (is del member available in 0.22?) - configure member - sync group - logging output to a common directory (and zapping that log directory before every sync) Possible Errors: - conflicts during sync - can't autodetect applications to sync with - need for slow-sync? - complete mess up - this usually initiates a desire to redo an entire sync from scratch, blowing one side away and syncing completely from one direction FIXME - finish adding to these above lists after analyzing osynctool's source For 0.22, base functionality off msynctool code: Sync screen mock up: ==================== +------------------------------------------------------------------------+ | Barry Sync | | | | [ Sync Now ] | | Available Devices: | | | | +==================================================================+ | | |Sync | PIN | Name |Connected| Sync With | Engine | | | +-----+----------+----------------+---------+-----------+----------+ | | | [X] | 3009efe3 | Old Faithful | Yes | Evolution | 0.40 | | | | [ ] | 20634523 | Borrowed 8120 | No | Sunbird | 0.22 | | | | [ ] | 10235478 | | Yes | ... | ... | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +------------------------------------------------------------------------+ - syncable devices can be skipped by unchecking in Sync column - unconnected or unconfigured devices have Sync checkbox greyed out - double click to configure a device - should be possible in theory to add as many Apps to the Sync With field as needed... it is all the same opensync group anyway Sync Now button: - for each device: - halt the App (can evolution --force-shutdown be used safetly at any time?) - run the engine's sync - may be able to thread non-conflicting devices - don't sync devices at the same time with the same apps in their Sync With list Sync Recovery Options: - start fresh: this keeps App's data and blanks the device - be sure to warn the user his device will be blanked! - when starting fresh, the desktop should remember the configs on both sides and reconfigure automatically after the zap Sync Config Constraints: - a device can only be used in one opensync config - an App can be used in multiple opensync configs - each specific engine plugin will have an App config class for it i.e. 0.22 barry-sync config class 0.40 evo-sync config class 0.22 evo-sync config class Sync Lists: - List of devices, includes: - all configured devices, from both engines, whether plugged in or not - all plugged devices - get names for each device from barrybackup config data - List of Apps - depends on what is supported by barry desktop + and depends on what plugins are installed for each engine + and depends on what Apps are actually installed (does the list of available plugins provide this info?) - List of engines - desktop should remember what engines it knows about so that if an engine disappears for some reason, it can warn the user (but don't ever abort) - if a known engine appears and then disappears, but no devices were actually configured to use it, don't warn so heavily Sync Config Storage: - sync config (groups, members, plugins) only stored in opensync - known engines stored in desktop cfg - known plugins for each engine too - but only remember the plugins and engines we actually use, so the user isn't bothered needlessly - desktop should remember which configs were unchecked, in the Sync column above, so a user can easily stop syncing a given device without having to delete the config barry-0.18.5/desktop/src/0000755001161500056700000000000012242254476014514 5ustar cdfreycdfreybarry-0.18.5/desktop/src/CUI_Barry.cc0000644001161500056700000001131012242254476016576 0ustar cdfreycdfrey/// /// \file CUI_Barry.cc /// ConfigUI derived class to configure the Barry "App" /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "CUI_Barry.h" #include "barrydesktop.h" #include #include #include "wxi18n.h" using namespace std; namespace AppConfig { Barry::Barry() { } std::string Barry::AppName() const { return OpenSync::Config::Barry::AppName(); } bool Barry::Configure(wxWindow *parent, plugin_ptr old_plugin) { return false; } ConfigUI::plugin_ptr Barry::GetPlugin() { return m_container; } bool Barry::RunApp(wxWindow *parent) { return false; } void Barry::PreSyncAppInit() { // nothing to do } bool Barry::ZapData(wxWindow *parent, plugin_ptr plugin, OpenSync::API *engine) { try { m_parent = parent; // extract OpenSync::Config::Barry from plugin // this *can* throw an exception if the wrong plugin is // passed in, but we want this... such an exception would // represent a bug in the app, not a runtime error OpenSync::Config::Barry &barry = dynamic_cast(*plugin); // build device name string device_name; const ::Barry::Probe::Results &results = wxGetApp().GetResults(); int index = ::Barry::Probe::Find(results, barry.GetPin()); if( index != -1 ) device_name = results[index].GetDisplayName(); else device_name = barry.GetPin().Str(); // default to PIN if not in list // build intro message wxString msg = wxString::Format( _W("Please select the databases you wish to erase\n" "on device: %s\n" "\n" "Note: all synced databases must be erased\n" "to avoid a slow-sync."), wxString(device_name.c_str(), wxConvUTF8).c_str()); // build list of databases (base on information from engine, if // the pointer is valid) wxArrayString dbs; wxArrayInt selections; if( !engine || (barry.GetSupportedSyncTypes(*engine) & PST_CONTACTS) ) { dbs.Add( wxString(::Barry::Contact::GetDBName(), wxConvUTF8) ); selections.Add(dbs.GetCount() - 1); } if( !engine || (barry.GetSupportedSyncTypes(*engine) & PST_EVENTS) ) { dbs.Add( wxString(::Barry::Calendar::GetDBName(), wxConvUTF8) ); selections.Add(dbs.GetCount() - 1); } if( !engine || (barry.GetSupportedSyncTypes(*engine) & PST_NOTES) ) { dbs.Add( wxString(::Barry::Memo::GetDBName(), wxConvUTF8) ); selections.Add(dbs.GetCount() - 1); } if( !engine || (barry.GetSupportedSyncTypes(*engine) & PST_TODOS) ) { dbs.Add( wxString(::Barry::Task::GetDBName(), wxConvUTF8) ); selections.Add(dbs.GetCount() - 1); } // present the list to the user int count = wxGetMultipleChoices(selections, msg, _W("Select Databases to Erase"), dbs, m_parent); if( count <= 0 ) return false; // nothing to do // display selections to the user for one final confirmation ostringstream oss; oss << _C("You have selected the following databases to be completely " "erased from device: ") << device_name << "\n\n"; for( size_t i = 0; i < selections.GetCount(); i++ ) { oss << string(dbs[selections[i]].utf8_str()) << "\n"; } oss << "\n" << _C("Proceed with erase?"); wxString confirm(oss.str().c_str(), wxConvUTF8); int choice = wxMessageBox(confirm, _W("Erase Confirmation"), wxYES_NO | wxICON_QUESTION, m_parent); if( choice != wxYES ) return false; // nothing to do // connect to the device and delete all selected databases wxBusyCursor wait; ::Barry::Controller con(results[index]); ::Barry::Mode::Desktop desktop(con); desktop.Open(); const ::Barry::DatabaseDatabase &dbdb = desktop.GetDBDB(); for( size_t i = 0; i < selections.GetCount(); i++ ) { string dbname(dbs[selections[i]].utf8_str()); unsigned int dbid; if( !dbdb.GetDBNumber(dbname, dbid) ) { barryverbose(_C("No database named '") << dbname << _C("' in device!")); continue; } barryverbose(_C("Clearing db: ") << dbname); desktop.ClearDatabase(dbid); } return true; } catch( ::Barry::Error &e ) { ostringstream oss; oss << _C("Barry exception: ") << e.what() << "\n\n" << _C("You may need to do a USB reset and rescan from the " "main menu."); wxString msg(oss.str().c_str(), wxConvUTF8); wxMessageBox(msg, _W("Barry Exception"), wxOK | wxICON_ERROR, m_parent); return false; } } } barry-0.18.5/desktop/src/Mode_MainMenu.h0000644001161500056700000000263512242254476017350 0ustar cdfreycdfrey/// /// \file Mode_MainMenu.h /// Mode derived class for the main menu buttons /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_MODE_MAINMENU_H__ #define __BARRYDESKTOP_MODE_MAINMENU_H__ #include #include #include "Mode.h" #include "wxi18n.h" class BaseButtons; namespace Barry { class Pin; } class MainMenuMode : public Mode { std::auto_ptr m_basebuttons; wxBitmap m_screenshot; public: MainMenuMode(wxWindow *parent); ~MainMenuMode(); void UpdateScreenshot(const Barry::Pin &pin); // events (called from BaseFrame) wxString GetTitleText() const { return _W("Barry Desktop Control Panel"); } void OnPaint(wxDC &dc); void OnMouseMotion(wxDC &dc, int x, int y); void OnLeftDown(wxDC &dc, int x, int y); void OnLeftUp(wxDC &dc, int x, int y); }; #endif barry-0.18.5/desktop/src/configui.cc0000644001161500056700000000324712242254476016634 0ustar cdfreycdfrey/// /// \file configui.cc /// Base class for plugin config user interfaces /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "configui.h" #include "osconfig.h" #include "CUI_Evolution.h" #include "CUI_Barry.h" #include "CUI_Google.h" #include "CUI_KDEPim.h" // Static factory function ConfigUI::configui_ptr ConfigUI::CreateConfigUI(const std::string &appname) { ConfigUI::configui_ptr ui; if( appname == OpenSync::Config::Barry::AppName() ) { ui.reset( new AppConfig::Barry ); } else if( appname == OpenSync::Config::Evolution::AppName() ) { ui.reset( new AppConfig::Evolution ); } else if( appname == OpenSync::Config::Evolution3::AppName() ) { ui.reset( new AppConfig::Evolution3 ); } else if( appname == OpenSync::Config::Google::AppName() ) { ui.reset( new AppConfig::Google ); } else if( appname == OpenSync::Config::KDEPim::AppName() ) { ui.reset( new AppConfig::KDEPim ); } return ui; } ////////////////////////////////////////////////////////////////////////////// // ConfigUI class ConfigUI::ConfigUI() : ExecHelper(0) { } ConfigUI::~ConfigUI() { } barry-0.18.5/desktop/src/ConflictDlg.cc0000644001161500056700000003711512242254476017222 0ustar cdfreycdfrey/// /// \file ConflictDlg.cc /// The dialog used during a sync, to display conflicting /// changes, and let the user decide what to do. /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "ConflictDlg.h" #include "windowids.h" #include "util.h" #include #include #include #include #include "wxi18n.h" using namespace std; ////////////////////////////////////////////////////////////////////////////// // ConflictDlg class BEGIN_EVENT_TABLE(ConflictDlg, wxDialog) EVT_BUTTON (Dialog_Conflict_ShowButton1, ConflictDlg::OnShowButton) EVT_BUTTON (Dialog_Conflict_ShowButton2, ConflictDlg::OnShowButton) EVT_BUTTON (Dialog_Conflict_ShowButton3, ConflictDlg::OnShowButton) EVT_BUTTON (Dialog_Conflict_ShowButton4, ConflictDlg::OnShowButton) EVT_BUTTON (Dialog_Conflict_ShowButton5, ConflictDlg::OnShowButton) EVT_BUTTON (Dialog_Conflict_ShowButton6, ConflictDlg::OnShowButton) EVT_BUTTON (Dialog_Conflict_ShowButton7, ConflictDlg::OnShowButton) EVT_BUTTON (Dialog_Conflict_ShowButton8, ConflictDlg::OnShowButton) EVT_BUTTON (Dialog_Conflict_ShowButton9, ConflictDlg::OnShowButton) EVT_BUTTON (Dialog_Conflict_SelectButton1, ConflictDlg::OnSelectButton) EVT_BUTTON (Dialog_Conflict_SelectButton2, ConflictDlg::OnSelectButton) EVT_BUTTON (Dialog_Conflict_SelectButton3, ConflictDlg::OnSelectButton) EVT_BUTTON (Dialog_Conflict_SelectButton4, ConflictDlg::OnSelectButton) EVT_BUTTON (Dialog_Conflict_SelectButton5, ConflictDlg::OnSelectButton) EVT_BUTTON (Dialog_Conflict_SelectButton6, ConflictDlg::OnSelectButton) EVT_BUTTON (Dialog_Conflict_SelectButton7, ConflictDlg::OnSelectButton) EVT_BUTTON (Dialog_Conflict_SelectButton8, ConflictDlg::OnSelectButton) EVT_BUTTON (Dialog_Conflict_SelectButton9, ConflictDlg::OnSelectButton) EVT_BUTTON (Dialog_Conflict_DuplicateButton, ConflictDlg::OnDuplicateButton) EVT_BUTTON (Dialog_Conflict_AbortButton, ConflictDlg::OnAbortButton) EVT_BUTTON (Dialog_Conflict_IgnoreButton, ConflictDlg::OnIgnoreButton) EVT_BUTTON (Dialog_Conflict_KeepNewerButton, ConflictDlg::OnKeepNewerButton) EVT_BUTTON (Dialog_Conflict_KillSyncButton, ConflictDlg::OnKillSyncButton) EVT_CHECKBOX (Dialog_Conflict_AlwaysCheckbox, ConflictDlg::OnAlwaysCheckbox) END_EVENT_TABLE() ConflictDlg::ConflictDlg(wxWindow *parent, const OpenSync::API &engine, const std::string &supported_commands, const std::vector &changes, ConflictDlg::AlwaysMemoryBlock &always) : wxDialog(parent, Dialog_Conflict, _W("Sync Conflict")) , m_engine(engine) , m_changes(changes) , m_supported_commands(supported_commands) , m_always(always) , m_kill_sync(false) , m_topsizer(0) { // the max text width is the maximum width that any line of text // in a conflict summary can use... it is calculated with // (screen_width - window_border_width*2) / change_count m_max_text_width = (wxSystemSettings::GetMetric(wxSYS_SCREEN_X) - wxSystemSettings::GetMetric(wxSYS_BORDER_X) * 2 - 10 * 2 - 5 * 2 * m_changes.size()) / m_changes.size(); // first, parse all change data ParseChanges(); // create a global set of key names that contain differing data // between changes CreateDifferingKeyNameSet(); // setup the raw GUI CreateLayout(); } ConflictDlg::~ConflictDlg() { } void ConflictDlg::ParseChanges() { m_maps.clear(); // create an xmlmap to start with, so we only parse the // map file once ostringstream oss; oss << m_engine.GetEngineName() << "/xmlmap"; tr1::shared_ptr basemap; try { basemap.reset(new XmlNodeMap(GetBaseFilename(oss.str())) ); } catch( std::runtime_error &e ) { basemap.reset(); } for( size_t i = 0; i < m_changes.size(); i++ ) { XmlPair xp; xp.dom.reset( new xmlpp::DomParser ); xp.dom->parse_memory_raw( (const unsigned char*) m_changes[i].printable_data.data(), m_changes[i].printable_data.size()); if( basemap.get() ) { xp.map.reset( new XmlNodeMap(*basemap) ); xp.map->ImportNodes(xp.dom->get_document()->get_root_node()); xp.map->PurgeEmpties(); xp.map->SortBySummary(); } m_maps.push_back(xp); } } void ConflictDlg::CreateDifferingKeyNameSet() { // start fresh m_differing_keys.clear(); if( !m_maps.size() || !m_maps[0].map.get() ) return; // nothing to do // find a list of all available key names key_set all_keys; // set of all keys names from all xmlmaps for( size_t i = 0; i < m_maps.size(); i++ ) { XmlNodeMap::iterator mi = m_maps[i].map->begin(), me = m_maps[i].map->end(); for( ; mi != me; ++mi ) { all_keys.insert(mi->KeyName()); } } // cycle through all keys and find ones that have changes for( key_set::iterator i = all_keys.begin(); i!=all_keys.end(); ++i ) { // find the mapping from the first nodemap XmlNodeMapping *first = m_maps[0].map->Find(*i); if( !first ) { // if a key does not exist in this map, then // it does in another, and therefore is "differing" m_differing_keys.insert(*i); continue; } // cycle through all remaining nodemaps, find the mapping that // matches the keyname, and compare... if any do not // exist, or do not match, add to the differing keys set for( size_t j = 1; j < m_maps.size(); j++ ) { XmlNodeMapping *next = m_maps[j].map->Find(*i); // compare! if( !next || *first != *next ) { m_differing_keys.insert(*i); break; } } } } // // +-barry-sync---------+ +-evo2-sync----------+ +-google-sync------+ // | | | | | | // | Adam Brandee | | Adam Brandee | | Adam Brandee | // | IBM Canada | | | | IBM Canada | < red // | 1-519-555-1212 | | 1-519-555-1212 | | 1-519-555-1111 | < red // | abramble@ibm.com | | abramble@ibm.com | | abramble@ibm.com | // | ---- | | ---- | | ---- | // | 123 Big Street | | 123 Big Street | | 123 Long St. | < red // | | | | | Canada | < red // +--------------------+ +--------------------+ +------------------+ // // [See XML] [Select] [See XML] [Select] [See XML] [Select] // // // At the bottom of the dialog, display the rest of the optional buttons, // like Duplicate, Abort, etc. Also include a checkbox for "always"... // figure out the best way to handle "always" selections... always // change #1? // // If converting an XML change's data to a hash map throws an exception // somewhere in the xmlpp::DomParser, then that change will have to // be handled in a raw manner. I don't think any changes can be // displayed in a table like above, but each should get a scrolling // edit control with the raw data included. // // If possible, take the default table font and reduce it by 20% or // something, because this table will likely hold a lot of data. // void ConflictDlg::CreateLayout() { m_topsizer = new wxBoxSizer(wxVERTICAL); CreateSummaries(m_topsizer); CreateAlternateButtons(m_topsizer); SetSizer(m_topsizer); m_topsizer->SetSizeHints(this); m_topsizer->Layout(); } void ConflictDlg::CreateSummaries(wxSizer *sizer) { // this sizer is the horizontal box containing one // "map summary" each wxBoxSizer *box = new wxBoxSizer(wxHORIZONTAL); for( size_t i = 0; i < m_maps.size(); i++ ) { CreateSummary(box, i); } sizer->Add(box, 0, wxEXPAND | wxALL, 5); } void ConflictDlg::CreateSummary(wxSizer *sizer, size_t change_index) { // this sizer contains the summary box in the top and the // buttons in the bottom wxBoxSizer *box = new wxBoxSizer(wxVERTICAL); CreateSummaryGroup(box, change_index); sizer->Add(box, 1, wxEXPAND | wxLEFT | wxRIGHT, 5); } void ConflictDlg::CreateSummaryGroup(wxSizer *sizer, size_t change_index) { wxString name(m_changes[change_index].plugin_name.c_str(), wxConvUTF8); wxStaticBoxSizer *box = new wxStaticBoxSizer(wxVERTICAL, this, name); XmlNodeMap *xml = m_maps[change_index].map.get(); if( xml ) { // add all priority 0 mappings XmlNodeMap::iterator nmi = xml->begin(), nme = xml->priority_end(); for( ; nmi != nme; ++nmi ) { AddMapping(box, *nmi, IsDifferent(*nmi)); } // add small separator (line?) box->Add( new wxStaticLine(this), 0, wxEXPAND | wxALL, 5); // add all differing mappings, in the map order, to preserve // the map file's user-friendly display order nmi = nme; // start at priority_end() to skip priority 0 nme = xml->end(); for( ; nmi != nme; ++nmi ) { if( !IsDifferent(*nmi) ) continue; AddMapping(box, *nmi, true); } } else { AddEmptyNotice(box); } box->Add(0, 10, 0); box->Add(0, 0, 1); CreateSummaryButtons(box, change_index); sizer->Add(box, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 0); } void ConflictDlg::CreateSummaryButtons(wxSizer *sizer, size_t change_index) { wxBoxSizer *box = new wxBoxSizer(wxHORIZONTAL); box->Add(0, 0, 1); box->Add( new wxButton(this, Dialog_Conflict_ShowButton1 + change_index, _W("XML..."), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT), 0, wxTOP | wxLEFT | wxRIGHT, 3); box->Add( new wxButton(this, Dialog_Conflict_SelectButton1 + change_index, _W("Select"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT), 0, wxTOP | wxLEFT | wxRIGHT, 3); sizer->Add(box, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 0); } bool ConflictDlg::IsDifferent(const XmlNodeMapping &mapping) const { return m_differing_keys.find(mapping.KeyName()) != m_differing_keys.end(); } void ConflictDlg::AddEmptyNotice(wxSizer *sizer) { wxFont font = GetFont(); font.SetStyle( wxFONTSTYLE_ITALIC ); wxStaticText *text = new wxStaticText(this, wxID_ANY, _W("No XML map found."), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE | wxST_NO_AUTORESIZE); text->SetFont(font); sizer->Add( text, 0, wxEXPAND, 0); } void ConflictDlg::AddMapping(wxSizer *sizer, XmlNodeMapping &mapping, bool differing) { // display differing text in red? Not sure how to do that... using italic // use a big bold font for the high priority items wxFont priority_font = GetFont(); priority_font.SetWeight( wxFONTWEIGHT_BOLD ); // italic for changed items wxFont priority_changed = priority_font; priority_changed.SetStyle( wxFONTSTYLE_ITALIC ); wxFont changed = GetFont(); changed.SetStyle( wxFONTSTYLE_ITALIC ); for( size_t i = 0; i < mapping.size(); i++ ) { wxString data(mapping[i].Summary().raw().c_str(), wxConvUTF8); wxStaticText *text = new wxStaticText(this, wxID_ANY, data, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE | wxST_NO_AUTORESIZE); if( mapping.Priority() == 0 ) { if( differing ) text->SetFont(priority_changed); else text->SetFont(priority_font); } else { if( differing ) text->SetFont(changed); } text->Wrap(m_max_text_width); sizer->Add( text, 0, wxEXPAND, 0); } } void ConflictDlg::CreateAlternateButtons(wxSizer *sizer) { wxBoxSizer *box = new wxBoxSizer(wxHORIZONTAL); box->Add( new wxCheckBox(this, Dialog_Conflict_AlwaysCheckbox, _W("Always use this choice")), 0, wxALIGN_CENTRE, 0); box->Add( -1, -1, 1 ); if( m_supported_commands.find('D') != string::npos ) { box->Add( new wxButton(this, Dialog_Conflict_DuplicateButton, _W("Duplicate")), 0, wxLEFT , 5); } if( m_supported_commands.find('I') != string::npos ) { box->Add( new wxButton(this, Dialog_Conflict_IgnoreButton, _W("Ignore")), 0, wxLEFT, 5); } if( m_supported_commands.find('N') != string::npos ) { box->Add( new wxButton(this, Dialog_Conflict_KeepNewerButton, _W("Keep Newer")), 0, wxLEFT, 5); } if( m_supported_commands.find('A') != string::npos ) { box->Add( new wxButton(this, Dialog_Conflict_AbortButton, _W("Abort")), 0, wxLEFT, 5); } else { // no abort available, so add a Kill Sync button box->Add( new wxButton(this, Dialog_Conflict_KillSyncButton, _W("Kill Sync")), 0, wxLEFT, 5); } sizer->Add(box, 0, wxEXPAND | wxALL, 10); } ////////////////////////////////////////////////////////////////////////////// // public members void ConflictDlg::clear() { m_command_string.clear(); m_kill_sync = false; } int ConflictDlg::ShowModal() { int ret = 0; // start fresh clear(); // is there a favoured plugin name? if( m_always.m_favour_plugin_name.size() ) { // find the matching plugin name for( size_t i = 0; i < m_changes.size(); i++ ) { if( m_changes[i].plugin_name == m_always.m_favour_plugin_name ) { ostringstream oss; oss << "S " << m_changes[i].id; m_command_string = oss.str(); return ret; } } } // is there an "always" answer we can use? if( m_always.m_always ) { if( m_always.m_last_command == "S" ) { // find the change that has a matching member_id // and plugin_name for( size_t i = 0; i < m_changes.size(); i++ ) { if( m_changes[i].member_id == m_always.m_member_id && m_changes[i].plugin_name == m_always.m_plugin_name ) { ostringstream oss; oss << "S " << m_changes[i].id; m_command_string = oss.str(); return ret; } } } else { m_command_string = m_always.m_last_command; return ret; // done } } // ok, no "always" data that works, so ask the user do { ret = wxDialog::ShowModal(); } while( m_command_string.size() == 0 && !m_kill_sync ); return ret; } void ConflictDlg::OnShowButton(wxCommandEvent &event) { int index = event.GetId() - Dialog_Conflict_ShowButton1; wxString xmldata(m_changes[index].printable_data.c_str(), wxConvUTF8); // let's try this the quick manual way... wxDialog dlg(this, wxID_ANY, _W("Raw Change Data")); wxBoxSizer *box = new wxBoxSizer(wxVERTICAL); box->Add( new wxTextCtrl(&dlg, wxID_ANY, xmldata, wxDefaultPosition, wxSize(400, 400), wxTE_MULTILINE | wxTE_READONLY), 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 10); box->Add( dlg.CreateButtonSizer(wxOK), 0, wxEXPAND | wxALL, 10 ); dlg.SetSizer(box); box->SetSizeHints(&dlg); box->Layout(); dlg.ShowModal(); } void ConflictDlg::OnSelectButton(wxCommandEvent &event) { int index = event.GetId() - Dialog_Conflict_SelectButton1; // store command in m_always m_always.m_member_id = m_changes[index].member_id; m_always.m_plugin_name = m_changes[index].plugin_name; m_always.m_last_command = "S"; // build actual command ostringstream oss; oss << "S " << m_changes[index].id; m_command_string = oss.str(); EndModal(event.GetId()); } void ConflictDlg::OnDuplicateButton(wxCommandEvent &event) { m_command_string = m_always.m_last_command = "D"; EndModal(event.GetId()); } void ConflictDlg::OnAbortButton(wxCommandEvent &event) { m_command_string = m_always.m_last_command = "A"; EndModal(event.GetId()); } void ConflictDlg::OnIgnoreButton(wxCommandEvent &event) { m_command_string = m_always.m_last_command = "I"; EndModal(event.GetId()); } void ConflictDlg::OnKeepNewerButton(wxCommandEvent &event) { m_command_string = m_always.m_last_command = "N"; EndModal(event.GetId()); } void ConflictDlg::OnKillSyncButton(wxCommandEvent &event) { m_command_string.clear(); m_always.m_last_command.clear(); m_kill_sync = true; EndModal(event.GetId()); } void ConflictDlg::OnAlwaysCheckbox(wxCommandEvent &event) { m_always.m_always = event.IsChecked(); } barry-0.18.5/desktop/src/ClickImage.cc0000644001161500056700000000457012242254476017021 0ustar cdfreycdfrey/// /// \file ClickImage.cc /// Clickable image class /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "ClickImage.h" ////////////////////////////////////////////////////////////////////////////// // ClickableImage ClickableImage::ClickableImage(wxWindow *parent, const wxBitmap &image, int ID, int x, int y, bool event_on_up, const wxCursor &hover) : m_parent(parent) , m_id(ID) , m_image(image) , m_x(x) , m_y(y) , m_focus(false) , m_event_on_up(event_on_up) , m_hover_cursor(hover) { } bool ClickableImage::CalculateHit(int x, int y) { return ( x >= m_x && x < (m_x + m_image.GetWidth()) ) && ( y >= m_y && y < (m_y + m_image.GetHeight()) ); } void ClickableImage::Draw(wxDC &dc) { dc.DrawBitmap(m_image, m_x, m_y, true); } void ClickableImage::HandleMotion(wxDC &dc, int x, int y) { bool focus = CalculateHit(x, y); if( focus && !m_focus ) { // newly in focus m_parent->SetCursor(m_hover_cursor); } else if( m_focus && !focus ) { // not in focus anymore m_parent->SetCursor(wxNullCursor); } // remember state m_focus = focus; } void ClickableImage::HandleDown(wxDC &dc, int x, int y) { if( !m_event_on_up ) { m_focus = CalculateHit(x, y); if( m_focus ) { // replace the cursor m_parent->SetCursor(wxNullCursor); m_focus = false; // send the event wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED,m_id); m_parent->GetEventHandler()->ProcessEvent(event); } } } void ClickableImage::HandleUp(wxDC &dc, int x, int y) { if( m_event_on_up ) { m_focus = CalculateHit(x, y); if( m_focus ) { // replace the cursor m_parent->SetCursor(wxNullCursor); m_focus = false; // send the event wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED,m_id); m_parent->GetEventHandler()->ProcessEvent(event); } } } barry-0.18.5/desktop/src/bsynccl.cc0000644001161500056700000000627212242254476016467 0ustar cdfreycdfrey/// /// \file bsyncjail.cc /// Helper program to isolate the actual syncing into its /// own process. Communicates with the main barrydesktop /// via wxWidgets IPC communication. This belongs in its /// own process since the sync can hang, and may need to /// be killed from the GUI. /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include #include #include #include "os22.h" #include "os40.h" #include "tempdir.h" #include "ostypes.h" #include "i18n.h" using namespace std; // command line arguments string g_argv_version, g_argv_group_name; OpenSync::Config::pst_type g_sync_types = PST_DO_NOT_SET; class BarrySyncJail : public OpenSync::SyncStatus { private: TempDir m_temp; std::auto_ptr m_engine; // communication variables int m_sequenceID; public: BarrySyncJail(); ~BarrySyncJail(); // // overrides // virtual bool OnInit(); virtual int OnExit(); // // OpenSync::SyncStatus virtual overrides // // virtual void CheckSummary(OpenSync::SyncSummary &summary); }; ////////////////////////////////////////////////////////////////////////////// // BarrySyncJail BarrySyncJail::BarrySyncJail() : m_temp("bsyncjail") { OnInit(); } BarrySyncJail::~BarrySyncJail() { } bool BarrySyncJail::OnInit() { cerr << "OnInit()" << endl; // load opensync engine try { if( g_argv_version == "0.22" ) m_engine.reset( new OpenSync::OpenSync22 ); else { m_engine.reset( new OpenSync::OpenSync40 ); } } catch( std::exception &e ) { cerr << e.what() << endl; return false; } if( !m_engine.get() ) { cerr << "Unknown engine number: " << g_argv_version << endl; return false; } // start the sync try { m_engine->Discover(g_argv_group_name); m_engine->Sync(g_argv_group_name, *this, g_sync_types); } catch( std::exception &e ) { cerr << e.what() << endl; return true; } return true; } int BarrySyncJail::OnExit() { cerr << "OnExit()" << endl; return 0; } // // OpenSync::SyncStatus virtual overrides // /* void BarrySyncJail::CheckSummary(OpenSync::SyncSummary &summary) { cerr << "CheckSummary" << endl; // FIXME: not currently supported... abort every time // cerr << "FIXME: CheckSummary() not implemented, aborting" << endl; // summary.Abort(); summary.Continue(); } */ int main(int argc, char *argv[]) { cerr << "bsyncjail startup" << endl; if( argc != 4 ) { cerr << _C("This is a helper program for barrydesktop, and\n" "is not intended to be called directly.\n") << endl; return 1; } g_argv_version = argv[1]; g_argv_group_name = argv[2]; g_sync_types = atoi(argv[3]); BarrySyncJail app; return app.OnExit(); } barry-0.18.5/desktop/src/osconfig.cc0000644001161500056700000002634712242254476016646 0ustar cdfreycdfrey/// /// \file osconfig.cc /// Class which detects a set of available or known devices /// in an opensync-able system. /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "osconfig.h" #include "os40.h" #include #include #include #include #include #include "i18n.h" using namespace std; using namespace Barry; namespace OpenSync { namespace Config { ////////////////////////////////////////////////////////////////////////////// // Unsupported config class std::string Unsupported::AppName() { return _C("Unsupported"); } ////////////////////////////////////////////////////////////////////////////// // Barry config class Barry::Barry(const ::Barry::Pin &pin) : m_debug_mode(false) , m_pin(pin) { if( !m_pin.Valid() ) throw std::logic_error(_C("Barry config must have valid pin number.")); } Barry::Barry(Converter *load_converter, const Member &member) : m_debug_mode(false) { load_converter->Load(*this, member); // // check that the loaded pin is valid... if not, it is // likely safe to assume that something is horribly wrong. // in the case where the Application wishes to add a new // barry plugin, it should use the Pin constructor. // if you *really* need to try to salvage an old // corrupt config, you can always do the // converter->Load(barry_obj) manually, and pick out // the left overs. // if( !m_pin.Valid() ) { std::ostringstream oss; oss << _C("Unable to load pin number from Barry plugin config. Consider this group corrupt, or not fully configured: ") << member; throw LoadError(oss.str()); } } ////////////////////////////////////////////////////////////////////////////// // Group class Group::Group(const std::string &group_name, OpenSync::API &api, unsigned throw_mask) : m_group_name(group_name) { Load(api, throw_mask); } Group::Group(const std::string &group_name) : m_group_name(group_name) { } // Checks for OSCG_THROW_ON_NO_BARRY and OSCG_THROW_ON_MULTIPLE_BARRIES void Group::BarryCheck(OpenSync::API &api, const std::string &group_name, const member_list_type &members, unsigned throw_mask) { if( ! (throw_mask & (OSCG_THROW_ON_NO_BARRY | OSCG_THROW_ON_MULTIPLE_BARRIES) ) ) return; // nothing to do int found = 0; std::string barry_name = Config::Barry::PluginName(api); member_list_type::const_iterator b = members.begin(), e = members.end(); for( ; b != e; ++b ) { if( b->plugin_name == barry_name ) found++; } if( found == 0 && (throw_mask & OSCG_THROW_ON_NO_BARRY) ) { throw LoadError( string_vprintf(_C("No Barry plugins found in group '%s' and OSCG_THROW_ON_NO_BARRY is set."), group_name.c_str())); } if( found > 1 && (throw_mask & OSCG_THROW_ON_MULTIPLE_BARRIES) ) { throw LoadError( string_vprintf(_C("Found %d Barry plugins in group '%s' and OSCG_THROW_ON_MULTIPLE_BARRIES is set."), found, group_name.c_str())); } } bool Group::GroupMatchesExistingConfig(OpenSync::API &api) { member_list_type members; api.GetMembers(m_group_name, members); // what needs to match: // // - number of connected Config::Plugin objects in our // list must match number of members in config // - each member ID must match along with the plugin_name // of each member // // check totals match if( (unsigned) GetConnectedCount() != members.size() ) { barryverbose("Connected count of " << GetConnectedCount() << " does not match member count of " << members.size()); return false; } // cycle through our own vector, matching against each member_id // in the members list const_iterator ci = begin(), ce = end(); for( ; ci != ce; ++ci ) { if( (*ci)->GetMemberId() == -1 ) continue; Member *m = members.Find( (*ci)->GetMemberId() ); if( !m ) { barryverbose("Can't match member ID: " << (*ci)->GetMemberId() ); return false; } if( m->plugin_name != (*ci)->GetPluginName(api) ) { barryverbose("Plugin names don't match: " << m->plugin_name << ", " << (*ci)->GetPluginName(api)); return false; } } return true; } bool Group::HasUnsupportedPlugins() const { const_iterator b = begin(), e = end(); for( ; b != e; ++b ) { if( (*b)->IsUnsupported() ) return true; } return false; } bool Group::HasBarryPlugins() const { const_iterator b = begin(), e = end(); for( ; b != e; ++b ) { if( (*b)->GetAppName() == Config::Barry::AppName() ) return true; } return false; } bool Group::GroupExists(OpenSync::API &api) const { // does m_group_name exist in the API list? string_list_type groups; api.GetGroupNames(groups); return std::find(groups.begin(), groups.end(), m_group_name) != groups.end(); } bool Group::AllConfigured(OpenSync::API &api) const { const_iterator b = begin(), e = end(); for( ; b != e; ++b ) { if( !(*b)->IsConfigured(api) ) return false; } return true; } int Group::GetConnectedCount() const { int count = 0; const_iterator b = begin(), e = end(); for( ; b != e; ++b ) { if( (*b)->GetMemberId() != -1 ) count++; } return count; } pst_type Group::GetSupportedSyncTypes(OpenSync::API &api) const { pst_type types = PST_ALL; const_iterator b = begin(), e = end(); for( ; b != e; ++b ) { types &= (*b)->GetSupportedSyncTypes(api); } return types; } std::string Group::GetAppNames() const { std::string names; const_iterator b = begin(), e = end(); for( ; b != e; ++b ) { std::string name = (*b)->GetAppName(); if( name != Config::Barry::AppName() ) { if( names.size() ) names += ", "; names += name; } } return names; } OpenSync::Config::Barry& Group::GetBarryPlugin() { return const_cast ( const_cast (this)->GetBarryPlugin() ); } const OpenSync::Config::Barry& Group::GetBarryPlugin() const { const_iterator b = begin(), e = end(); for( ; b != e; ++b ) { if( (*b)->GetAppName() == Config::Barry::AppName() ) return dynamic_cast (*(*b)); } // not found throw std::logic_error("No Barry Plugins in Group"); } OpenSync::Config::Plugin* Group::GetNonBarryPlugin() { return const_cast ( const_cast (this)->GetNonBarryPlugin() ); } const OpenSync::Config::Plugin* Group::GetNonBarryPlugin() const { const_iterator b = begin(), e = end(); for( ; b != e; ++b ) { if( (*b)->GetAppName() != Config::Barry::AppName() ) return (*b).get(); } return 0; } void Group::DisconnectMembers() { iterator b = begin(), e = end(); for( ; b != e; ++b ) { (*b)->SetMemberId(-1); } } void Group::Load(OpenSync::API &api, unsigned throw_mask) { Load(m_group_name, api, throw_mask); } void Group::Load(const std::string &src_group_name, OpenSync::API &api, unsigned throw_mask) { member_list_type members; api.GetMembers(src_group_name, members); BarryCheck(api, src_group_name, members, throw_mask); member_list_type::const_iterator b = members.begin(), e = members.end(); for( ; b != e; ++b ) { Converter &converter = api.GetConverter(); Converter::plugin_ptr p = converter.CreateAndLoadPlugin(*b); p->SetMemberId(b->id); if( p->IsUnsupported() && (throw_mask & OSCG_THROW_ON_UNSUPPORTED) ) { throw LoadError( string_vprintf(_C("Unsupported plugin '%s' in group '%s' and OSCG_THROW_ON_UNSUPPORTED is set."), b->plugin_name.c_str(), src_group_name.c_str())); } // everything looks ok, add the plugin to our list push_back(p); } } void Group::ResetGroupName(const std::string &new_group_name) { m_group_name = new_group_name; } void Group::AddPlugin(OpenSync::Config::Plugin *plugin) { plugin_ptr pp(plugin); push_back(pp); } void Group::DeletePlugin(iterator i, OpenSync::API &api) { // is this plugin connected to a previously saved group config? if( (*i)->GetMemberId() != -1 ) { // this plugin has a member ID... only OpenSync 0.40 can // delete members like that... do we have 40 support? OpenSync::OpenSync40 *api40 = dynamic_cast (&api); if( !api40 ) { // not version 0.40... can't do it capt'n! throw DeleteError(_C("Cannot delete individual members from an OpenSync group with versions < 0.40.")); } // so... we have the capability... check that the plugin // name of the ID in the group matches what we think it // should be member_list_type members; api40->GetMembers(m_group_name, members); Member *m = members.Find( (*i)->GetMemberId() ); if( !m ) { throw DeleteError(string_vprintf(_C("Tried to delete non-existent member ID %ld (%s) from group '%s'"), (*i)->GetMemberId(), (*i)->GetPluginName(api).c_str(), m_group_name.c_str())); } if( m->plugin_name != (*i)->GetPluginName(api) ) { throw DeleteError(string_vprintf(_C("Tried to delete member ID %ld using plugin '%s' from group '%s', but the existing member uses plugin '%s'"), (*i)->GetMemberId(), (*i)->GetPluginName(api).c_str(), m_group_name.c_str(), m->plugin_name.c_str())); } // so far so good... try deleting it api40->DeleteMember(m_group_name, (*i)->GetMemberId()); } // remove from our own array erase(i); } void Group::Save(OpenSync::API &api) { if( GroupExists(api) ) { // groups already exists, so need to confirm that our // connected plugins match the existing member_ids and // plugin names in the group's member list if( !GroupMatchesExistingConfig(api) ) { throw SaveError(string_vprintf(_C("Tried to overwrite group '%s' with a Group set that did not match in ID's and plugin names."), m_group_name.c_str())); } } else { // group does not exist, so create it if needed if( size() ) api.AddGroup(m_group_name); } // cycle through all plugins and save them all iterator b = begin(), e = end(); for( ; b != e; ++b ) { Config::Plugin &p = *(*b); if( p.GetMemberId() == -1 ) { // this plugin has never been saved yet, so // add it fresh long newid = api.AddMember(m_group_name, p.GetPluginName(api), ""); p.SetMemberId(newid); } // save config p.Save(api, m_group_name); } } bool Group::Compare(const Group &other) const { // size of group equal? if( size() != other.size() ) return false; // name of group? if( m_group_name != other.m_group_name ) return false; // cycle through all plugins, searching for a match in other const_iterator i = begin(); for( ; i != end(); ++i ) { bool sametype, equal; bool match = false; // search other for a match const_iterator oi = other.begin(); for( ; oi != other.end(); ++oi ) { if( (match = (*i)->Compare(*(*oi), sametype, equal)) ) break; } if( !match ) return false; } return true; } Group::group_ptr Group::Clone() const { group_ptr g( new Group(m_group_name) ); // clone all plugins const_iterator b = begin(), e = end(); for( ; b != e; ++b ) { plugin_ptr p( (*b)->Clone() ); g->push_back(p); } return g; } }} // namespace OpenSync::Config barry-0.18.5/desktop/src/osconv22.h0000644001161500056700000000646212242254476016350 0ustar cdfreycdfrey/// /// \file osconv22.h /// Converter class for opensync 0.22 plugins /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_OSCONV22_H__ #define __BARRY_OSCONV22_H__ #include "osbase.h" namespace OpenSync { class Converter22 : public Converter { OpenSync::API &m_api; protected: std::string GrabField(const std::string &cfg, const std::string &name); public: Converter22(OpenSync::API &api); virtual bool IsPluginSupported(const std::string &plugin_name, std::string *appname = 0) const; virtual plugin_ptr CreateAndLoadPlugin(const Member &member); virtual std::string GetPluginName(const Config::Barry &) const; virtual std::string GetPluginName(const Config::Evolution &) const; virtual std::string GetPluginName(const Config::Evolution3 &) const; virtual std::string GetPluginName(const Config::Google &) const; virtual std::string GetPluginName(const Config::KDEPim &) const; virtual std::string GetPluginName(const Config::Unsupported &) const; virtual bool IsConfigured(const Config::Barry &) const; virtual bool IsConfigured(const Config::Evolution &) const; virtual bool IsConfigured(const Config::Evolution3 &) const; virtual bool IsConfigured(const Config::Google &) const; virtual bool IsConfigured(const Config::KDEPim &) const; virtual bool IsConfigured(const Config::Unsupported &) const; virtual Config::pst_type GetSupportedSyncTypes(const Config::Barry &) const; virtual Config::pst_type GetSupportedSyncTypes(const Config::Evolution &) const; virtual Config::pst_type GetSupportedSyncTypes(const Config::Evolution3 &) const; virtual Config::pst_type GetSupportedSyncTypes(const Config::Google &) const; virtual Config::pst_type GetSupportedSyncTypes(const Config::KDEPim &) const; virtual Config::pst_type GetSupportedSyncTypes(const Config::Unsupported &) const; virtual void Load(Config::Barry &config, const Member &member); virtual void Load(Config::Evolution &config, const Member &member); virtual void Load(Config::Evolution3 &config, const Member &member); virtual void Load(Config::Google &config, const Member &member); virtual void Load(Config::KDEPim &config, const Member &member); virtual void Load(Config::Unsupported &config, const Member &member); virtual void Save(const Config::Barry &config, const std::string &group_name); virtual void Save(const Config::Evolution &config, const std::string &group_name); virtual void Save(const Config::Evolution3 &config, const std::string &group_name); virtual void Save(const Config::Google &config, const std::string &group_name); virtual void Save(const Config::KDEPim &config, const std::string &group_name); virtual void Save(const Config::Unsupported &config, const std::string &group_name); }; } // namespace OpenSync #endif barry-0.18.5/desktop/src/optout.h0000644001161500056700000000664012242254476016225 0ustar cdfreycdfrey/// /// \file OptOut.h /// A set of container classes and element base class that support /// smart elements that can remove themselves from the container /// upon deletion. /// /// To use it, derive your element from OptOut::Element, and /// then add new-ly allocated pointers to the Vector. The /// Vector will delete any remaining elements, and each /// element can be deleted early, either with a delete this /// by themselves, or deleted manually outside of the Vector. /// /* Copyright (C) 2010-2013, Chris Frey 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __UTIL_OPTOUT_H__ #define __UTIL_OPTOUT_H__ #include namespace OptOut { class ContainerBase; class Element { friend class ContainerBase; ContainerBase *m_container; protected: virtual void OptIn(ContainerBase *container) { OptOut(); m_container = container; } virtual void OptOut(); public: Element() : m_container(0) {} virtual ~Element() { OptOut(); } }; class ContainerBase { friend class Element; protected: virtual void NotifyElement(Element *element) { element->OptIn(this); } virtual void OptOut(Element *element) = 0; public: virtual ~ContainerBase() { } }; inline void Element::OptOut() { if( m_container ) { m_container->OptOut(this); m_container = 0; } } template class Vector : public ContainerBase { public: typedef std::vector container_type; typedef container_type::iterator iterator; typedef container_type::const_iterator const_iterator; typedef container_type::size_type size_type; private: container_type m_con; protected: virtual void OptOut(Element *element) { for( iterator i = m_con.begin(); i != m_con.end(); ++i ) { if( (*i) == element ) { m_con.erase(i); return; } } } public: ~Vector() { iterator i; while( (i = m_con.begin()) != m_con.end() ) { // this will remove the element from the array, // hence the while, starting over each time delete (*i); } } // std::vector<> compatible functions size_type size() { return m_con.size(); } void push_back(Element *element) { NotifyElement(element); m_con.push_back(element); } TypeT* operator[] (size_type n) { return dynamic_cast (m_con[n]); } iterator begin() { return m_con.begin(); } const_iterator begin() const { return m_con.begin(); } iterator end() { return m_con.end(); } const_iterator end() const { return m_con.end(); } iterator rbegin() { return m_con.rbegin(); } const_iterator rbegin() const { return m_con.rbegin(); } iterator rend() { return m_con.rend(); } const_iterator rend() const { return m_con.rend(); } // since iterators hold Element* pointers, these functions // are just a helpful dynamic cast aid TypeT* GetType(iterator i) { return dynamic_cast (*i); } const TypeT* GetType(const_iterator i) { return dynamic_cast (*i); } }; } // namespace OptOut #endif barry-0.18.5/desktop/src/EasyCondition.h0000644001161500056700000000253312242254476017440 0ustar cdfreycdfrey/// /// \file EasyCondition.h /// Wrapper thread around wxMutex and wxCondition, to make /// simple waits easy and safe. Also an RAII scope signaler. /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_EASYCONDITION_H__ #define __BARRYDESKTOP_EASYCONDITION_H__ #include class EasyCondition { wxMutex m_mutex; wxCondition m_condition; public: EasyCondition() : m_condition(m_mutex) { m_mutex.Lock(); } void Wait() { m_condition.Wait(); } void Signal() { wxMutexLocker lock(m_mutex); m_condition.Broadcast(); } }; class ScopeSignaler { EasyCondition &m_condition; public: explicit ScopeSignaler(EasyCondition &cond) : m_condition(cond) { } ~ScopeSignaler() { m_condition.Signal(); } }; #endif barry-0.18.5/desktop/src/CalendarEditDlg.cc0000644001161500056700000007372512242254476020007 0ustar cdfreycdfrey/// /// \file CalendarEditDlg.cc /// Dialog class to handle the editing of the Calendar record /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "CalendarEditDlg.h" #include "windowids.h" #include #include "wxval.h" #include "util.h" using namespace std; using namespace Barry; // begin wxGlade: ::extracode // end wxGlade ////////////////////////////////////////////////////////////////////////////// // CalendarEditDlg class CalendarEditDlg::CalendarEditDlg(wxWindow* parent, Barry::Calendar &rec, bool editable, const Barry::TimeZones *device_zones) : wxDialog(parent, Dialog_CalendarEdit, _W("Calendar Record")) , m_zones(device_zones ? device_zones : &m_static_zones) , m_rec(rec) , m_duration_hours(0) , m_duration_minutes(0) , m_reminder_hours(0) , m_reminder_minutes(0) , m_interval(0) , m_relative_date(false) { // set all weekday 'bits' to false for( int i = 0; i < 7; i++ ) m_weekdays[i] = false; if( editable ) { bottom_buttons = CreateButtonSizer(wxOK | wxCANCEL); } else { bottom_buttons = CreateButtonSizer(wxCANCEL); } // begin wxGlade: CalendarEditDlg::CalendarEditDlg label_1 = new wxStaticText(this, wxID_ANY, _W("Subject:")); m_Subject = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_2 = new wxStaticText(this, wxID_ANY, _W("Location:")); m_Location = new wxTextCtrl(this, wxID_ANY, wxEmptyString); static_line_1 = new wxStaticLine(this, wxID_ANY); label_4 = new wxStaticText(this, wxID_ANY, _W("All Day Event:")); m_AllDayCheck = new wxCheckBox(this, Dialog_CalendarEdit_AllDayCheck, wxEmptyString); label_5 = new wxStaticText(this, wxID_ANY, _W("Start:")); m_StartDateCtrl = new wxDatePickerCtrl(this, Dialog_CalendarEdit_StartDateCtrl, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxDP_DROPDOWN|wxDP_SHOWCENTURY); m_StartHoursSpinner = new wxSpinCtrl(this, Dialog_CalendarEdit_StartHoursSpinner, wxT(""), wxDefaultPosition, wxDefaultSize, wxSP_WRAP|wxTE_NOHIDESEL, 0, 23); label_11 = new wxStaticText(this, wxID_ANY, wxT(":")); m_StartMinutesSpinner = new wxSpinCtrl(this, Dialog_CalendarEdit_StartMinutesSpinner, wxT(""), wxDefaultPosition, wxDefaultSize, wxSP_WRAP|wxTE_NOHIDESEL, 0, 59); label_6 = new wxStaticText(this, wxID_ANY, _W("End:")); m_EndDateCtrl = new wxDatePickerCtrl(this, Dialog_CalendarEdit_EndDateCtrl, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxDP_DROPDOWN|wxDP_SHOWCENTURY); m_EndHoursSpinner = new wxSpinCtrl(this, Dialog_CalendarEdit_EndHoursSpinner, wxT(""), wxDefaultPosition, wxDefaultSize, wxSP_WRAP|wxTE_NOHIDESEL, 0, 23); label_12 = new wxStaticText(this, wxID_ANY, wxT(":")); m_EndMinutesSpinner = new wxSpinCtrl(this, Dialog_CalendarEdit_EndMinutesSpinner, wxT(""), wxDefaultPosition, wxDefaultSize, wxSP_WRAP|wxTE_NOHIDESEL, 0, 59); label_7 = new wxStaticText(this, wxID_ANY, _W("Duration:")); m_DurationHoursSpinner = new wxSpinCtrl(this, Dialog_CalendarEdit_DurationHoursSpinner, wxT(""), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 999); label_13 = new wxStaticText(this, wxID_ANY, _W("hours and")); m_DurationMinutesSpinner = new wxSpinCtrl(this, Dialog_CalendarEdit_DurationMinutesSpinner, wxT(""), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 59); label_17 = new wxStaticText(this, wxID_ANY, _W("minutes.")); label_8 = new wxStaticText(this, wxID_ANY, _W("Time Zone:")); const wxString m_TimezoneChoice_choices[] = { _W("System Time Zone") }; m_TimezoneChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 1, m_TimezoneChoice_choices, 0); label_9 = new wxStaticText(this, wxID_ANY, _W("Show As:")); /* const wxString m_ShowAsChoice_choices[] = { wxT("Free"), wxT("Tentative"), wxT("Busy"), wxT("Out of Office") }; */ wxArrayString m_ShowAsChoice_choices; m_ShowAsChoice_choices.Add( _W("Free") ); m_ShowAsChoice_choices.Add( _W("Tentative") ); m_ShowAsChoice_choices.Add( _W("Busy") ); m_ShowAsChoice_choices.Add( _W("Out of Office") ); m_ShowAsChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ShowAsChoice_choices, 0); label_10 = new wxStaticText(this, wxID_ANY, _W("Reminder:")); m_ReminderHoursSpinner = new wxSpinCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 999); label_13_copy = new wxStaticText(this, wxID_ANY, _W("hours and")); m_ReminderMinutesSpinner = new wxSpinCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 59); label_17_copy = new wxStaticText(this, wxID_ANY, _W("minutes.")); static_line_2 = new wxStaticLine(this, wxID_ANY); label_18 = new wxStaticText(this, wxID_ANY, _W("Recurrence:")); /* const wxString m_RecurrenceChoice_choices[] = { wxT("None"), wxT("Daily"), wxT("Weekly"), wxT("Monthly"), wxT("Yearly") }; */ wxArrayString m_RecurrenceChoice_choices; m_RecurrenceChoice_choices.Add( _W("None") ); m_RecurrenceChoice_choices.Add( _W("Daily") ); m_RecurrenceChoice_choices.Add( _W("Weekly") ); m_RecurrenceChoice_choices.Add( _W("Monthly") ); m_RecurrenceChoice_choices.Add( _W("Yearly") ); m_RecurrenceChoice = new wxChoice(this, Dialog_CalendarEdit_RecurrenceChoice, wxDefaultPosition, wxDefaultSize, m_RecurrenceChoice_choices, 0); RecurIntervalLabel = new wxStaticText(this, wxID_ANY, _W("Interval:")); RecurIntervalLabelB = new wxStaticText(this, wxID_ANY, _W("Every")); m_IntervalSpinner = new wxSpinCtrl(this, wxID_ANY, wxT("1"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 999); m_IntervalUnitLabel = new wxStaticText(this, wxID_ANY, _W("days? weeks? months?"), wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE); RecurDaysLabel = new wxStaticText(this, wxID_ANY, _W("Days:")); m_SunCheck = new wxCheckBox(this, wxID_ANY, wxT("S")); m_MonCheck = new wxCheckBox(this, wxID_ANY, wxT("M")); m_TueCheck = new wxCheckBox(this, wxID_ANY, wxT("T")); m_WedCheck = new wxCheckBox(this, wxID_ANY, wxT("W")); m_ThuCheck = new wxCheckBox(this, wxID_ANY, wxT("T")); m_FriCheck = new wxCheckBox(this, wxID_ANY, wxT("F")); m_SatCheck = new wxCheckBox(this, wxID_ANY, wxT("S")); RecurRelativeDateLabel = new wxStaticText(this, wxID_ANY, _W("Relative Date:")); m_RelativeDateCheck = new wxCheckBox(this, wxID_ANY, wxEmptyString); RecurEndDateLabel = new wxStaticText(this, wxID_ANY, _W("End Date:")); m_NeverEndsCheck = new wxCheckBox(this, Dialog_CalendarEdit_NeverEndsCheck, _W("Never ends")); m_RecurEndDateCtrl = new wxDatePickerCtrl(this, wxID_ANY, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxDP_DROPDOWN|wxDP_SHOWCENTURY); static_line_3 = new wxStaticLine(this, wxID_ANY); label_14 = new wxStaticText(this, wxID_ANY, _W("Organizer:")); m_OrganizerText = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_15 = new wxStaticText(this, wxID_ANY, _W("Invited:")); m_InvitedText = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_16 = new wxStaticText(this, wxID_ANY, _W("Accepted By:")); m_AcceptedByText = new wxTextCtrl(this, wxID_ANY, wxEmptyString); static_line_4 = new wxStaticLine(this, wxID_ANY); /* const wxString m_ClassRadioBox_choices[] = { wxT("Public"), wxT("Private"), wxT("Confidential") }; */ wxArrayString m_ClassRadioBox_choices; m_ClassRadioBox_choices.Add( _W("Public") ); m_ClassRadioBox_choices.Add( _W("Private") ); m_ClassRadioBox_choices.Add( _W("Confidential") ); m_ClassRadioBox = new wxRadioBox(this, wxID_ANY, _W("Class"), wxDefaultPosition, wxDefaultSize, m_ClassRadioBox_choices, 3, wxRA_SPECIFY_COLS); static_line_5 = new wxStaticLine(this, wxID_ANY); label_3 = new wxStaticText(this, wxID_ANY, _W("Notes:")); m_NotesText = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); set_properties(); do_layout(); // end wxGlade m_top_sizer->Add(bottom_buttons, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 5); // fill the time zone control with real time zones m_TimezoneChoice->Clear(); m_TimezoneChoice->Append(_W("Assume Local Timezone"), (void*)0); Barry::TimeZones::const_iterator b, e; for( b = m_zones->begin(), e = m_zones->end(); b != e; ++b ) { m_TimezoneChoice->Append( wxString(b->GetDescription().c_str(), wxConvUTF8), (void*) &b->Index); } m_TimezoneChoice->SetSelection(0); // layout again, in case sizes are different RedoLayout(); } void CalendarEditDlg::RedoLayout() { m_top_sizer->Fit(this); Layout(); } BEGIN_EVENT_TABLE(CalendarEditDlg, wxDialog) // begin wxGlade: CalendarEditDlg::event_table EVT_CHECKBOX(Dialog_CalendarEdit_AllDayCheck, CalendarEditDlg::OnAllDayEvent) EVT_DATE_CHANGED(Dialog_CalendarEdit_StartDateCtrl, CalendarEditDlg::OnStartDateChanged) EVT_SPINCTRL(Dialog_CalendarEdit_StartHoursSpinner, CalendarEditDlg::OnStartHoursSpin) EVT_SPINCTRL(Dialog_CalendarEdit_StartMinutesSpinner, CalendarEditDlg::OnStartMinutesSpin) EVT_DATE_CHANGED(Dialog_CalendarEdit_EndDateCtrl, CalendarEditDlg::OnEndDateChanged) EVT_SPINCTRL(Dialog_CalendarEdit_EndHoursSpinner, CalendarEditDlg::OnEndHoursSpin) EVT_SPINCTRL(Dialog_CalendarEdit_EndMinutesSpinner, CalendarEditDlg::OnEndMinutesSpin) EVT_SPINCTRL(Dialog_CalendarEdit_DurationHoursSpinner, CalendarEditDlg::OnDurationHoursSpin) EVT_SPINCTRL(Dialog_CalendarEdit_DurationMinutesSpinner, CalendarEditDlg::OnDurationMinutesSpin) EVT_CHOICE(Dialog_CalendarEdit_RecurrenceChoice, CalendarEditDlg::OnRecurrenceChoice) EVT_CHECKBOX(Dialog_CalendarEdit_NeverEndsCheck, CalendarEditDlg::OnEndDateCheckbox) // end wxGlade END_EVENT_TABLE(); void CalendarEditDlg::OnAllDayEvent(wxCommandEvent &event) { bool checked = m_AllDayCheck->IsChecked(); if( checked ) { // set start time to date at 00:00 and end time at // day + 1 at 00:00 // time m_StartHoursSpinner->SetValue(0); m_StartMinutesSpinner->SetValue(0); m_EndHoursSpinner->SetValue(0); m_EndMinutesSpinner->SetValue(0); // date m_StartDateCtrl->SetValue(m_StartDateCtrl->GetValue().GetDateOnly()); m_EndDateCtrl->SetValue(m_StartDateCtrl->GetValue().GetDateOnly() + wxDateSpan::Day()); // duration m_DurationHoursSpinner->SetValue(24); m_DurationMinutesSpinner->SetValue(0); } EnableAllDayMode(checked); } void CalendarEditDlg::OnStartDateChanged(wxDateEvent &event) { UpdateDuration(); } void CalendarEditDlg::OnStartHoursSpin(wxSpinEvent &event) { UpdateDuration(); } void CalendarEditDlg::OnStartMinutesSpin(wxSpinEvent &event) { UpdateDuration(); } void CalendarEditDlg::OnEndDateChanged(wxDateEvent &event) { UpdateDuration(); } void CalendarEditDlg::OnEndHoursSpin(wxSpinEvent &event) { UpdateDuration(); } void CalendarEditDlg::OnEndMinutesSpin(wxSpinEvent &event) { UpdateDuration(); } void CalendarEditDlg::OnDurationHoursSpin(wxSpinEvent &event) { UpdateEndDate(); } void CalendarEditDlg::OnDurationMinutesSpin(wxSpinEvent &event) { UpdateEndDate(); } void CalendarEditDlg::OnRecurrenceChoice(wxCommandEvent &event) { TransferDataFromWindow(); EnableRecurMode(m_rec.Recurring); } void CalendarEditDlg::OnEndDateCheckbox(wxCommandEvent &event) { m_RecurEndDateCtrl->Enable( !m_NeverEndsCheck->IsChecked() ); } // wxGlade: add CalendarEditDlg event handlers void CalendarEditDlg::set_properties() { // begin wxGlade: CalendarEditDlg::set_properties SetTitle(_W("Calendar Event")); m_Subject->SetFocus(); m_Subject->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Subject))); m_Location->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Location))); m_AllDayCheck->SetValidator(wxGenericValidator(&m_rec.AllDayEvent)); m_StartDateCtrl->SetMinSize(wxSize(110, -1)); m_StartDateCtrl->SetValidator(DateTimeValidator(&m_StartDateObj.m_date)); m_StartHoursSpinner->SetMinSize(wxSize(45, -1)); m_StartHoursSpinner->SetValidator(wxGenericValidator(&m_StartDateObj.m_hour)); m_StartMinutesSpinner->SetMinSize(wxSize(45, -1)); m_StartMinutesSpinner->SetValidator(wxGenericValidator(&m_StartDateObj.m_min)); m_EndDateCtrl->SetMinSize(wxSize(110, -1)); m_EndDateCtrl->SetValidator(DateTimeValidator(&m_EndDateObj.m_date)); m_EndHoursSpinner->SetMinSize(wxSize(45, -1)); m_EndHoursSpinner->SetValidator(wxGenericValidator(&m_EndDateObj.m_hour)); m_EndMinutesSpinner->SetMinSize(wxSize(45, -1)); m_EndMinutesSpinner->SetValidator(wxGenericValidator(&m_EndDateObj.m_min)); m_DurationHoursSpinner->SetMinSize(wxSize(45, -1)); m_DurationHoursSpinner->SetValidator(wxGenericValidator(&m_duration_hours)); m_DurationMinutesSpinner->SetMinSize(wxSize(45, -1)); m_DurationMinutesSpinner->SetValidator(wxGenericValidator(&m_duration_minutes)); m_TimezoneChoice->SetSelection(0); m_ShowAsChoice->SetSelection(2); m_ReminderHoursSpinner->SetMinSize(wxSize(45, -1)); m_ReminderHoursSpinner->SetToolTip(_W("Set Reminder to 0 to disable")); m_ReminderHoursSpinner->SetValidator(wxGenericValidator(&m_reminder_hours)); m_ReminderMinutesSpinner->SetMinSize(wxSize(45, -1)); m_ReminderMinutesSpinner->SetToolTip(_W("Set Reminder to 0 to disable")); m_ReminderMinutesSpinner->SetValidator(wxGenericValidator(&m_reminder_minutes)); m_RecurrenceChoice->SetValidator(wxGenericValidator(&m_recur_choice)); m_RecurrenceChoice->SetSelection(0); m_IntervalSpinner->SetMinSize(wxSize(45, -1)); m_IntervalSpinner->SetValidator(wxGenericValidator(&m_interval)); m_SunCheck->SetValidator(wxGenericValidator(&m_weekdays[0])); m_MonCheck->SetValidator(wxGenericValidator(&m_weekdays[1])); m_TueCheck->SetValidator(wxGenericValidator(&m_weekdays[2])); m_WedCheck->SetValidator(wxGenericValidator(&m_weekdays[3])); m_ThuCheck->SetValidator(wxGenericValidator(&m_weekdays[4])); m_FriCheck->SetValidator(wxGenericValidator(&m_weekdays[5])); m_SatCheck->SetValidator(wxGenericValidator(&m_weekdays[6])); RecurRelativeDateLabel->SetToolTip(_W("Relative monthly or yearly dates take the weekday of the start date into account. (eg. every first Sunday of month)")); m_RelativeDateCheck->SetToolTip(_W("Relative monthly or yearly dates take the weekday of the start date into account. (eg. every first Sunday of month)")); m_RelativeDateCheck->SetValidator(wxGenericValidator(&m_relative_date)); m_NeverEndsCheck->SetValidator(wxGenericValidator(&m_rec.Perpetual)); m_NeverEndsCheck->SetValue(1); m_RecurEndDateCtrl->SetMinSize(wxSize(110, -1)); m_RecurEndDateCtrl->Enable(false); m_RecurEndDateCtrl->SetValidator(DateTimeValidator(&m_RecurEndDateObj.m_date)); m_OrganizerText->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_organizer))); m_InvitedText->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_invited))); m_AcceptedByText->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_accepted_by))); m_ClassRadioBox->SetValidator(MakeRadioBoxValidator(&m_rec.ClassFlag).Add(Barry::Calendar::Public).Add(Barry::Calendar::Private).Add(Barry::Calendar::Confidential)); m_ClassRadioBox->SetSelection(0); m_NotesText->SetMinSize(wxSize(-1, 61)); m_NotesText->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Notes))); // end wxGlade } void CalendarEditDlg::do_layout() { // begin wxGlade: CalendarEditDlg::do_layout wxBoxSizer* sizer_surround = new wxBoxSizer(wxVERTICAL); wxBoxSizer* sizer_1 = new wxBoxSizer(wxVERTICAL); wxBoxSizer* sizer_2 = new wxBoxSizer(wxHORIZONTAL); wxFlexGridSizer* grid_sizer_3 = new wxFlexGridSizer(3, 2, 5, 5); wxFlexGridSizer* grid_sizer_4 = new wxFlexGridSizer(5, 2, 5, 5); wxBoxSizer* sizer_8 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* m_DaysCtrlsSizer = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* m_IntervalCtrlsSizer = new wxBoxSizer(wxHORIZONTAL); wxFlexGridSizer* grid_sizer_2 = new wxFlexGridSizer(7, 2, 5, 5); wxBoxSizer* sizer_5_copy = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* sizer_5 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* sizer_4 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* sizer_3 = new wxBoxSizer(wxHORIZONTAL); wxFlexGridSizer* grid_sizer_1 = new wxFlexGridSizer(2, 2, 5, 5); grid_sizer_1->Add(label_1, 0, 0, 0); grid_sizer_1->Add(m_Subject, 0, wxEXPAND, 0); grid_sizer_1->Add(label_2, 0, 0, 0); grid_sizer_1->Add(m_Location, 0, wxEXPAND, 0); grid_sizer_1->AddGrowableCol(1); sizer_1->Add(grid_sizer_1, 0, wxEXPAND, 0); sizer_1->Add(static_line_1, 0, wxALL|wxEXPAND, 5); grid_sizer_2->Add(label_4, 0, 0, 0); grid_sizer_2->Add(m_AllDayCheck, 0, 0, 0); grid_sizer_2->Add(label_5, 0, wxALIGN_CENTER_VERTICAL, 0); sizer_3->Add(m_StartDateCtrl, 0, 0, 0); sizer_3->Add(20, 20, 0, 0, 0); sizer_3->Add(m_StartHoursSpinner, 0, 0, 0); sizer_3->Add(label_11, 0, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 1); sizer_3->Add(m_StartMinutesSpinner, 0, 0, 0); grid_sizer_2->Add(sizer_3, 1, wxEXPAND, 0); grid_sizer_2->Add(label_6, 0, wxALIGN_CENTER_VERTICAL, 0); sizer_4->Add(m_EndDateCtrl, 0, 0, 0); sizer_4->Add(20, 20, 0, 0, 0); sizer_4->Add(m_EndHoursSpinner, 0, 0, 0); sizer_4->Add(label_12, 0, wxALL|wxALIGN_CENTER_VERTICAL, 1); sizer_4->Add(m_EndMinutesSpinner, 0, 0, 0); grid_sizer_2->Add(sizer_4, 1, wxEXPAND, 0); grid_sizer_2->Add(label_7, 0, wxALIGN_CENTER_VERTICAL, 0); sizer_5->Add(m_DurationHoursSpinner, 0, wxRIGHT, 5); sizer_5->Add(label_13, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); sizer_5->Add(m_DurationMinutesSpinner, 0, wxRIGHT, 5); sizer_5->Add(label_17, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_2->Add(sizer_5, 1, wxEXPAND, 0); grid_sizer_2->Add(label_8, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_2->Add(m_TimezoneChoice, 0, 0, 0); grid_sizer_2->Add(label_9, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_2->Add(m_ShowAsChoice, 0, 0, 0); grid_sizer_2->Add(label_10, 0, wxALIGN_CENTER_VERTICAL, 0); sizer_5_copy->Add(m_ReminderHoursSpinner, 0, wxRIGHT, 5); sizer_5_copy->Add(label_13_copy, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); sizer_5_copy->Add(m_ReminderMinutesSpinner, 0, wxRIGHT, 5); sizer_5_copy->Add(label_17_copy, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_2->Add(sizer_5_copy, 1, wxEXPAND, 0); grid_sizer_2->AddGrowableCol(1); sizer_1->Add(grid_sizer_2, 0, wxEXPAND, 0); sizer_1->Add(static_line_2, 0, wxALL|wxEXPAND, 5); grid_sizer_4->Add(label_18, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_4->Add(m_RecurrenceChoice, 0, 0, 0); grid_sizer_4->Add(RecurIntervalLabel, 0, wxALIGN_CENTER_VERTICAL, 0); m_IntervalCtrlsSizer->Add(RecurIntervalLabelB, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); m_IntervalCtrlsSizer->Add(m_IntervalSpinner, 0, wxRIGHT, 5); m_IntervalCtrlsSizer->Add(m_IntervalUnitLabel, 1, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_4->Add(m_IntervalCtrlsSizer, 1, wxEXPAND, 0); grid_sizer_4->Add(RecurDaysLabel, 0, wxALIGN_CENTER_VERTICAL, 0); m_DaysCtrlsSizer->Add(m_SunCheck, 0, wxRIGHT, 5); m_DaysCtrlsSizer->Add(m_MonCheck, 0, wxRIGHT, 5); m_DaysCtrlsSizer->Add(m_TueCheck, 0, wxRIGHT, 5); m_DaysCtrlsSizer->Add(m_WedCheck, 0, wxRIGHT, 5); m_DaysCtrlsSizer->Add(m_ThuCheck, 0, wxRIGHT, 5); m_DaysCtrlsSizer->Add(m_FriCheck, 0, wxRIGHT, 5); m_DaysCtrlsSizer->Add(m_SatCheck, 0, wxRIGHT, 5); grid_sizer_4->Add(m_DaysCtrlsSizer, 1, wxEXPAND, 0); grid_sizer_4->Add(RecurRelativeDateLabel, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_4->Add(m_RelativeDateCheck, 0, 0, 0); grid_sizer_4->Add(RecurEndDateLabel, 0, wxALIGN_CENTER_VERTICAL, 0); sizer_8->Add(m_NeverEndsCheck, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 10); sizer_8->Add(m_RecurEndDateCtrl, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_4->Add(sizer_8, 1, wxEXPAND, 0); grid_sizer_4->AddGrowableCol(1); sizer_1->Add(grid_sizer_4, 0, wxEXPAND, 0); sizer_1->Add(static_line_3, 0, wxALL|wxEXPAND, 5); grid_sizer_3->Add(label_14, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_3->Add(m_OrganizerText, 0, wxEXPAND, 0); grid_sizer_3->Add(label_15, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_3->Add(m_InvitedText, 0, wxEXPAND, 0); grid_sizer_3->Add(label_16, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_3->Add(m_AcceptedByText, 0, wxEXPAND, 0); grid_sizer_3->AddGrowableCol(1); sizer_1->Add(grid_sizer_3, 0, wxEXPAND, 0); sizer_1->Add(static_line_4, 0, wxALL|wxEXPAND, 5); sizer_1->Add(m_ClassRadioBox, 0, wxEXPAND, 0); sizer_1->Add(static_line_5, 0, wxALL|wxEXPAND, 5); sizer_2->Add(label_3, 0, wxRIGHT, 5); sizer_2->Add(m_NotesText, 1, wxEXPAND, 0); sizer_1->Add(sizer_2, 1, wxEXPAND, 0); sizer_surround->Add(sizer_1, 1, wxALL|wxEXPAND, 10); SetSizer(sizer_surround); sizer_surround->Fit(this); Layout(); // end wxGlade m_top_sizer = sizer_surround; } bool CalendarEditDlg::TransferDataToWindow() { // prepare temporary variables, from record m_organizer = m_rec.Organizer.ToCommaSeparated(); m_invited = m_rec.Invited.ToCommaSeparated(); m_accepted_by = m_rec.AcceptedBy.ToCommaSeparated(); m_StartDateObj.Set(m_rec.StartTime.Time); m_EndDateObj.Set(m_rec.EndTime.Time); int duration = m_rec.EndTime.Time - m_rec.StartTime.Time; duration /= 60; // convert to minutes if( m_rec.EndTime.Time >= m_rec.StartTime.Time ) { m_duration_hours = duration / 60; m_duration_minutes = duration % 60; } if( m_rec.NotificationTime.Time ) { int span = m_rec.StartTime.Time - m_rec.NotificationTime.Time; span /= 60; // convert to minutes if( m_rec.StartTime.Time > m_rec.NotificationTime.Time ) { m_reminder_hours = span / 60; m_reminder_minutes = span % 60; } else { m_reminder_hours = 0; m_reminder_minutes = 15; } } EnableAllDayMode(m_rec.AllDayEvent); // set the timezone choice only if the record's data is valid m_TimezoneChoice->SetSelection(0); // default to none if( m_rec.TimeZoneValid ) { TimeZones::const_iterator i = m_zones->Find(m_rec.TimeZoneCode); if( i != m_zones->end() ) { int array_index = i - m_zones->begin(); // select item, skipping 0's "none" option m_TimezoneChoice->SetSelection(array_index + 1); } } #define SA_FREE 0 #define SA_TENTATIVE 1 #define SA_BUSY 2 #define SA_OUT_OF_OFFICE 3 switch( m_rec.FreeBusyFlag ) { case Barry::Calendar::Free: m_ShowAsChoice->SetSelection(SA_FREE); break; case Barry::Calendar::Tentative: m_ShowAsChoice->SetSelection(SA_TENTATIVE); break; case Barry::Calendar::Busy: default: m_ShowAsChoice->SetSelection(SA_BUSY); break; case Barry::Calendar::OutOfOffice: m_ShowAsChoice->SetSelection(SA_OUT_OF_OFFICE); break; } // Note that recur_choice values are (zero-based) in the following // order: // None, Daily, Weekly, Monthly, Yearly #define RC_NONE 0 #define RC_DAILY 1 #define RC_WEEKLY 2 #define RC_MONTHLY 3 #define RC_YEARLY 4 if( m_rec.Recurring ) { switch( m_rec.RecurringType ) { case Barry::RecurBase::Day: m_recur_choice = RC_DAILY; m_relative_date = false; break; case Barry::RecurBase::MonthByDate: m_recur_choice = RC_MONTHLY; m_relative_date = false; break; case Barry::RecurBase::MonthByDay: m_recur_choice = RC_MONTHLY; m_relative_date = true; break; case Barry::RecurBase::YearByDate: m_recur_choice = RC_YEARLY; m_relative_date = false; break; case Barry::RecurBase::YearByDay: m_recur_choice = RC_YEARLY; m_relative_date = true; break; case Barry::RecurBase::Week: m_recur_choice = RC_WEEKLY; m_relative_date = false; m_weekdays[0] = m_rec.WeekDays & CAL_WD_SUN; m_weekdays[1] = m_rec.WeekDays & CAL_WD_MON; m_weekdays[2] = m_rec.WeekDays & CAL_WD_TUE; m_weekdays[3] = m_rec.WeekDays & CAL_WD_WED; m_weekdays[4] = m_rec.WeekDays & CAL_WD_THU; m_weekdays[5] = m_rec.WeekDays & CAL_WD_FRI; m_weekdays[6] = m_rec.WeekDays & CAL_WD_SAT; break; default: cerr << "Bad RecurringType in CalendarEditDlg" << endl; m_recur_choice = RC_NONE; m_relative_date = false; } } else { m_recur_choice = RC_NONE; m_relative_date = false; } m_interval = m_rec.Interval; m_RecurEndDateObj.Set(m_rec.RecurringEndTime.Time); if( m_rec.Perpetual ) { m_RecurEndDateCtrl->Enable(false); } else { m_RecurEndDateCtrl->Enable(); } EnableRecurMode(m_rec.Recurring); m_strings.RefreshWx(); // let the base class call the validaors to do the rest if( wxDialog::TransferDataToWindow() ) { // on success, do just a little bit of fine tuning MakeDateRecent(true, m_StartDateCtrl); MakeDateRecent(true, m_EndDateCtrl); MakeDateRecent(true, m_RecurEndDateCtrl); return true; } else { return false; } } bool CalendarEditDlg::TransferDataFromWindow() { if( !wxDialog::TransferDataFromWindow() ) return false; m_strings.Sync(); m_rec.Organizer.clear(); m_rec.Organizer.AddCommaSeparated(m_organizer); m_rec.Invited.clear(); m_rec.Invited.AddCommaSeparated(m_invited); m_rec.AcceptedBy.clear(); m_rec.AcceptedBy.AddCommaSeparated(m_accepted_by); m_rec.StartTime.Time = m_StartDateObj.Get(); m_rec.EndTime.Time = m_EndDateObj.Get(); if( m_rec.EndTime.Time < m_rec.StartTime.Time ) { wxMessageBox(_W("Start time must come before end time."), _W("Validation Error"), wxOK | wxICON_INFORMATION, this); return false; } int span = ((m_reminder_hours * 60) + m_reminder_minutes) * 60; m_rec.NotificationTime.Time = m_rec.StartTime.Time - span; switch( m_ShowAsChoice->GetSelection() ) { case SA_FREE: m_rec.FreeBusyFlag = Barry::Calendar::Free; break; case SA_TENTATIVE: m_rec.FreeBusyFlag = Barry::Calendar::Tentative; break; case SA_BUSY: default: m_rec.FreeBusyFlag = Barry::Calendar::Busy; break; case SA_OUT_OF_OFFICE: m_rec.FreeBusyFlag = Barry::Calendar::OutOfOffice; break; } // set the timezone choice only if the record's data is valid int sel = m_TimezoneChoice->GetSelection(); if( sel > 0 ) { m_rec.TimeZoneCode = (*m_zones)[sel-1].Index; m_rec.TimeZoneValid = true; } else { // default was selected m_rec.TimeZoneValid = false; } // Note that recur_choice values are (zero-based) in the following // order: // None, Daily, Weekly, Monthly, Yearly switch( m_recur_choice ) { case RC_NONE: default: m_rec.Recurring = false; break; case RC_DAILY: m_rec.Recurring = true; m_rec.RecurringType = Barry::RecurBase::Day; break; case RC_WEEKLY: m_rec.Recurring = true; m_rec.RecurringType = Barry::RecurBase::Week; m_rec.WeekDays = 0; if( m_weekdays[0] ) m_rec.WeekDays |= CAL_WD_SUN; if( m_weekdays[1] ) m_rec.WeekDays |= CAL_WD_MON; if( m_weekdays[2] ) m_rec.WeekDays |= CAL_WD_TUE; if( m_weekdays[3] ) m_rec.WeekDays |= CAL_WD_WED; if( m_weekdays[4] ) m_rec.WeekDays |= CAL_WD_THU; if( m_weekdays[5] ) m_rec.WeekDays |= CAL_WD_FRI; if( m_weekdays[6] ) m_rec.WeekDays |= CAL_WD_SAT; break; case RC_MONTHLY: m_rec.Recurring = true; if( m_relative_date ) m_rec.RecurringType = Barry::RecurBase::MonthByDay; else m_rec.RecurringType = Barry::RecurBase::MonthByDate; break; case RC_YEARLY: m_rec.Recurring = true; if( m_relative_date ) m_rec.RecurringType = Barry::RecurBase::YearByDay; else m_rec.RecurringType = Barry::RecurBase::YearByDate; break; } m_rec.Interval = m_interval; if( !m_rec.Perpetual ) { m_rec.RecurringEndTime.Time = m_RecurEndDateObj.Get(); } return true; } void CalendarEditDlg::UpdateDuration() { TransferDataFromWindow(); if( m_EndDateObj.Get() < m_StartDateObj.Get() ) { // error... end date cannot be before start date // set end date to start date m_EndDateCtrl->SetValue(m_StartDateCtrl->GetValue()); m_EndHoursSpinner->SetValue(m_StartHoursSpinner->GetValue()); m_EndMinutesSpinner->SetValue(m_StartMinutesSpinner->GetValue()); // duration is 0 m_DurationHoursSpinner->SetValue(0); m_DurationMinutesSpinner->SetValue(0); return; } else { // set duration to time span of End - Start time_t diff = m_EndDateObj.Get() - m_StartDateObj.Get(); diff /= 60; // convert to minutes m_DurationHoursSpinner->SetValue(diff / 60); m_DurationMinutesSpinner->SetValue(diff % 60); } } void CalendarEditDlg::UpdateEndDate() { TransferDataFromWindow(); m_EndDateObj.Set( m_StartDateObj.Get() + m_duration_hours * 60 * 60 + m_duration_minutes * 60 ); m_EndDateCtrl->SetValue(wxDateTime(m_EndDateObj.m_date)); m_EndHoursSpinner->SetValue(m_EndDateObj.m_hour); m_EndMinutesSpinner->SetValue(m_EndDateObj.m_min); } void CalendarEditDlg::EnableAllDayMode(bool all_day) { // if in all day mode, disable start time, end time, duration spinners m_StartHoursSpinner->Enable(!all_day); m_StartMinutesSpinner->Enable(!all_day); m_EndHoursSpinner->Enable(!all_day); m_EndMinutesSpinner->Enable(!all_day); m_DurationHoursSpinner->Enable(!all_day); m_DurationMinutesSpinner->Enable(!all_day); } void CalendarEditDlg::EnableRecurMode(bool recur) { // show all controls RecurIntervalLabel->Show(recur); RecurIntervalLabelB->Show(recur); m_IntervalSpinner->Show(recur); m_IntervalUnitLabel->Show(recur); RecurDaysLabel->Show(recur); m_SunCheck->Show(recur); m_MonCheck->Show(recur); m_TueCheck->Show(recur); m_WedCheck->Show(recur); m_ThuCheck->Show(recur); m_FriCheck->Show(recur); m_SatCheck->Show(recur); RecurRelativeDateLabel->Show(recur); m_RelativeDateCheck->Show(recur); RecurEndDateLabel->Show(recur); m_NeverEndsCheck->Show(recur); m_RecurEndDateCtrl->Show(recur); // enable based on choice int choice = m_RecurrenceChoice->GetSelection(); m_SunCheck->Enable(choice == RC_WEEKLY); m_MonCheck->Enable(choice == RC_WEEKLY); m_TueCheck->Enable(choice == RC_WEEKLY); m_WedCheck->Enable(choice == RC_WEEKLY); m_ThuCheck->Enable(choice == RC_WEEKLY); m_FriCheck->Enable(choice == RC_WEEKLY); m_SatCheck->Enable(choice == RC_WEEKLY); // update labels if( recur ) { switch( m_RecurrenceChoice->GetSelection() ) { case RC_NONE: default: m_IntervalUnitLabel->SetLabel(_T("")); break; case RC_DAILY: m_IntervalUnitLabel->SetLabel(_W("day(s)")); break; case RC_WEEKLY: m_IntervalUnitLabel->SetLabel(_W("week(s)")); break; case RC_MONTHLY: m_IntervalUnitLabel->SetLabel(_W("month(s)")); break; case RC_YEARLY: m_IntervalUnitLabel->SetLabel(_W("year(s)")); break; } } RedoLayout(); } // // Note: this file is very similar to TaskEditDlg.cc, and should be kept // in lock step as much as possible. They are in separate files, since // the GUI code is generated with wxglade // barry-0.18.5/desktop/src/CalendarEditDlg.h0000644001161500056700000001204612242254476017636 0ustar cdfreycdfrey/// /// \file CalendarEditDlg.h /// Dialog class to handle the editing of the Calendar record /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_CALENDAR_EDIT_DLG_H__ #define __BARRYDESKTOP_CALENDAR_EDIT_DLG_H__ //#define wxUSE_DATEPICKCTRL 1 #include "StringSync.h" #include "guitimet.h" #include #include #include // begin wxGlade: ::dependencies #include #include #include // end wxGlade #include // begin wxGlade: ::extracode // end wxGlade class CalendarEditDlg: public wxDialog { public: // begin wxGlade: CalendarEditDlg::ids // end wxGlade private: // begin wxGlade: CalendarEditDlg::methods void set_properties(); void do_layout(); // end wxGlade protected: Barry::TimeZones m_static_zones; const Barry::TimeZones *m_zones; Barry::Calendar &m_rec; StringSync m_strings; GUITimeT m_StartDateObj; GUITimeT m_EndDateObj; GUITimeT m_RecurEndDateObj; int m_duration_hours, m_duration_minutes; int m_reminder_hours, m_reminder_minutes; int m_interval; int m_recur_choice; bool m_weekdays[7]; bool m_relative_date; std::string m_organizer, m_invited, m_accepted_by; // begin wxGlade: CalendarEditDlg::attributes wxStaticText* label_1; wxTextCtrl* m_Subject; wxStaticText* label_2; wxTextCtrl* m_Location; wxStaticLine* static_line_1; wxStaticText* label_4; wxCheckBox* m_AllDayCheck; wxStaticText* label_5; wxDatePickerCtrl* m_StartDateCtrl; wxSpinCtrl* m_StartHoursSpinner; wxStaticText* label_11; wxSpinCtrl* m_StartMinutesSpinner; wxStaticText* label_6; wxDatePickerCtrl* m_EndDateCtrl; wxSpinCtrl* m_EndHoursSpinner; wxStaticText* label_12; wxSpinCtrl* m_EndMinutesSpinner; wxStaticText* label_7; wxSpinCtrl* m_DurationHoursSpinner; wxStaticText* label_13; wxSpinCtrl* m_DurationMinutesSpinner; wxStaticText* label_17; wxStaticText* label_8; wxChoice* m_TimezoneChoice; wxStaticText* label_9; wxChoice* m_ShowAsChoice; wxStaticText* label_10; wxSpinCtrl* m_ReminderHoursSpinner; wxStaticText* label_13_copy; wxSpinCtrl* m_ReminderMinutesSpinner; wxStaticText* label_17_copy; wxStaticLine* static_line_2; wxStaticText* label_18; wxChoice* m_RecurrenceChoice; wxStaticText* RecurIntervalLabel; wxStaticText* RecurIntervalLabelB; wxSpinCtrl* m_IntervalSpinner; wxStaticText* m_IntervalUnitLabel; wxStaticText* RecurDaysLabel; wxCheckBox* m_SunCheck; wxCheckBox* m_MonCheck; wxCheckBox* m_TueCheck; wxCheckBox* m_WedCheck; wxCheckBox* m_ThuCheck; wxCheckBox* m_FriCheck; wxCheckBox* m_SatCheck; wxStaticText* RecurRelativeDateLabel; wxCheckBox* m_RelativeDateCheck; wxStaticText* RecurEndDateLabel; wxCheckBox* m_NeverEndsCheck; wxDatePickerCtrl* m_RecurEndDateCtrl; wxStaticLine* static_line_3; wxStaticText* label_14; wxTextCtrl* m_OrganizerText; wxStaticText* label_15; wxTextCtrl* m_InvitedText; wxStaticText* label_16; wxTextCtrl* m_AcceptedByText; wxStaticLine* static_line_4; wxRadioBox* m_ClassRadioBox; wxStaticLine* static_line_5; wxStaticText* label_3; wxTextCtrl* m_NotesText; // end wxGlade wxSizer *bottom_buttons; wxSizer *m_top_sizer; DECLARE_EVENT_TABLE(); // sets to protected: protected: // helper functions void UpdateDuration(); void UpdateEndDate(); void RedoLayout(); void EnableAllDayMode(bool all_day = true); void EnableRecurMode(bool recur = true); public: CalendarEditDlg(wxWindow* parent, Barry::Calendar &rec, bool editable, const Barry::TimeZones *device_zones); virtual bool TransferDataToWindow(); virtual bool TransferDataFromWindow(); public: virtual void OnAllDayEvent(wxCommandEvent &event); // wxGlade: virtual void OnStartDateChanged(wxDateEvent &event); // wxGlade: virtual void OnStartHoursSpin(wxSpinEvent &event); // wxGlade: virtual void OnStartMinutesSpin(wxSpinEvent &event); // wxGlade: virtual void OnEndDateChanged(wxDateEvent &event); // wxGlade: virtual void OnEndHoursSpin(wxSpinEvent &event); // wxGlade: virtual void OnEndMinutesSpin(wxSpinEvent &event); // wxGlade: virtual void OnDurationHoursSpin(wxSpinEvent &event); // wxGlade: virtual void OnDurationMinutesSpin(wxSpinEvent &event); // wxGlade: virtual void OnRecurrenceChoice(wxCommandEvent &event); // wxGlade: virtual void OnEndDateCheckbox(wxCommandEvent &event); // wxGlade: }; // wxGlade: end class #endif barry-0.18.5/desktop/src/osconfig.h0000644001161500056700000005315312242254476016503 0ustar cdfreycdfrey/// /// \file osconfig.h /// Class which detects a set of available or known devices /// in an opensync-able system. /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_OSCONFIG_H__ #define __BARRY_OSCONFIG_H__ #include #include #include #include #include "osbase.h" #include "ostypes.h" #include namespace OpenSync { namespace Config { // Exception class for configuration load errors class LoadError : public std::exception { std::string m_msg; public: LoadError(const std::string &msg) : m_msg(msg) {} virtual ~LoadError() throw() {} virtual const char* what() const throw() { return m_msg.c_str(); } }; class SaveError : public std::exception { std::string m_msg; public: SaveError(const std::string &msg) : m_msg(msg) {} virtual ~SaveError() throw() {} virtual const char* what() const throw() { return m_msg.c_str(); } }; /// Thrown when a member cannot be deleted from the group class DeleteError : public std::logic_error { public: DeleteError(const std::string &msg) : std::logic_error(msg) {} }; // Base class for all opensync plugin configurations class Plugin { long m_member_id; // -1 if not saved to the group yet public: Plugin() : m_member_id(-1) { } virtual ~Plugin() { } virtual long GetMemberId() const { return m_member_id; } virtual void SetMemberId(long id) { m_member_id = id; } // // operations // virtual Plugin* Clone() const = 0; /// IsUnsupported() returns true if the config format for this /// plugin has no OpenSync::Config::* class to parse / handle it. virtual bool IsUnsupported() const { return true; } virtual std::string GetAppName() const = 0; // returns a GUI-friendly // name for the application that this plugin // is for... i.e. plugin name might // be "evo2-sync" but the app name // would be "Evolution" /// Throws SaveError if member_id is -1 virtual void Save(OpenSync::API &api, const std::string &group_name) const = 0; // sample implementation: //{ // api.GetConverter().Save(*this, group_name); //} virtual std::string GetPluginName(OpenSync::API &api) const = 0; // sample implementation: //{ // return api.GetConverter().GetPluginName(*this); //} virtual bool IsConfigured(OpenSync::API &api) const = 0; // sample implementation: //{ // return api.GetConverter().IsConfigured(*this); //} virtual pst_type GetConfiguredSyncTypes() const { return PST_NONE; } virtual pst_type GetSupportedSyncTypes(OpenSync::API &api) const = 0; // sample implementation: //{ // return api.GetConverter().GetSupportedSyncTypes(*this) // && GetConfiguredSyncTypes(); //} /// Support function for Group::Compare(). If plugin is the /// same type as this, sametype is set to true. If sametype /// is true, and the data is functionally equivalent, /// equal is set to true. Returns (sametype && equal). virtual bool Compare(const Plugin &plugin, bool &sametype, bool &equal) const { sametype = equal = false; return sametype && equal; } }; class Unsupported : public Plugin { private: // configuration settings std::string m_raw_config; public: Unsupported() { } explicit Unsupported(Converter *load_converter, const Member &member) { load_converter->Load(*this, member); } const std::string& GetRawConfig() const { return m_raw_config; } void SetRawConfig(const std::string &c) { m_raw_config = c; } // virtual overrides virtual Unsupported* Clone() const { return new Unsupported(*this); } virtual bool IsUnsupported() const { return true; } virtual std::string GetAppName() const { return AppName(); } virtual void Save(OpenSync::API &api, const std::string &group_name) const { api.GetConverter().Save(*this, group_name); } virtual std::string GetPluginName(OpenSync::API &api) const { return api.GetConverter().GetPluginName(*this); } virtual bool IsConfigured(OpenSync::API &api) const { return api.GetConverter().IsConfigured(*this); } virtual pst_type GetSupportedSyncTypes(OpenSync::API &api) const { return api.GetConverter().GetSupportedSyncTypes(*this) & GetConfiguredSyncTypes();; } // statics static std::string AppName(); }; class Barry : public Plugin { private: // configuration settings bool m_debug_mode; ::Barry::Pin m_pin; std::string m_password; protected: // This constructor is protected, so that only derived // classes can create a configuration without a pin number. Barry() : m_debug_mode(false) { } public: explicit Barry(const ::Barry::Pin &pin); explicit Barry(Converter *load_converter, const Member &member); bool IsDebugMode() const { return m_debug_mode; } ::Barry::Pin GetPin() const { return m_pin; } std::string GetPassword() const { return m_password; } void DebugMode(bool mode = true) { m_debug_mode = mode; } void SetPin(const ::Barry::Pin &pin) { m_pin = pin; } void SetPassword(const std::string &pass) { m_password = pass; } // virtual overrides virtual Barry* Clone() const { return new Barry(*this); } virtual bool IsUnsupported() const { return false; } virtual std::string GetAppName() const { return AppName(); } virtual void Save(OpenSync::API &api, const std::string &group_name) const { api.GetConverter().Save(*this, group_name); } virtual std::string GetPluginName(OpenSync::API &api) const { return api.GetConverter().GetPluginName(*this); } virtual bool IsConfigured(OpenSync::API &api) const { return api.GetConverter().IsConfigured(*this); } virtual pst_type GetConfiguredSyncTypes() const { return m_pin.Valid() ? PST_ALL : PST_NONE; } virtual pst_type GetSupportedSyncTypes(OpenSync::API &api) const { return api.GetConverter().GetSupportedSyncTypes(*this) & GetConfiguredSyncTypes(); } virtual bool Compare(const Plugin &plugin, bool &sametype, bool &equal) const { sametype = equal = false; const Barry *other = dynamic_cast (&plugin); if( other ) { sametype = true; if( m_debug_mode == other->m_debug_mode && m_pin == other->m_pin && m_password == other->m_password ) equal = true; } return sametype && equal; } // statics static std::string AppName() { return "Barry"; } static std::string PluginName(OpenSync::API &api) { return api.GetConverter().GetPluginName(Barry()); } static pst_type SupportedSyncTypes(OpenSync::API &api) { return api.GetConverter().GetSupportedSyncTypes(Barry()); } }; class Evolution : public Plugin { private: // configuration settings std::string m_address_path; std::string m_calendar_path; std::string m_tasks_path; std::string m_memos_path; protected: static void SetIfExists(std::string &var, const std::string &dir); public: Evolution() { } explicit Evolution(Converter *load_converter, const Member &member) { load_converter->Load(*this, member); } const std::string& GetAddressPath() const { return m_address_path; } const std::string& GetCalendarPath() const { return m_calendar_path; } const std::string& GetTasksPath() const { return m_tasks_path; } const std::string& GetMemosPath() const { return m_memos_path; } void SetAddressPath(const std::string &p) { m_address_path = p; } void SetCalendarPath(const std::string &p) { m_calendar_path = p; } void SetTasksPath(const std::string &p) { m_tasks_path = p; } void SetMemosPath(const std::string &p) { m_memos_path = p; } // specific operations bool AutoDetect(); // throw if unable to detect?? // virtual overrides virtual Evolution* Clone() const { return new Evolution(*this); } virtual bool IsUnsupported() const { return false; } virtual std::string GetAppName() const { return AppName(); } virtual void Save(OpenSync::API &api, const std::string &group_name) const { api.GetConverter().Save(*this, group_name); } virtual std::string GetPluginName(OpenSync::API &api) const { return api.GetConverter().GetPluginName(*this); } virtual bool IsConfigured(OpenSync::API &api) const { return api.GetConverter().IsConfigured(*this); } virtual pst_type GetConfiguredSyncTypes() const { pst_type pst = PST_NONE; if( m_address_path.size() ) pst |= PST_CONTACTS; if( m_calendar_path.size() ) pst |= PST_EVENTS; if( m_tasks_path.size() ) pst |= PST_TODOS; if( m_memos_path.size() ) pst |= PST_NOTES; return pst; } virtual pst_type GetSupportedSyncTypes(OpenSync::API &api) const { // supported types include what the plugin is capable of, // ANDed against what has been configured return api.GetConverter().GetSupportedSyncTypes(*this) & GetConfiguredSyncTypes(); } virtual bool Compare(const Plugin &plugin, bool &sametype, bool &equal) const { sametype = equal = false; const Evolution *other = dynamic_cast (&plugin); if( other ) { sametype = true; if( m_address_path == other->m_address_path && m_calendar_path == other->m_calendar_path && m_tasks_path == other->m_tasks_path && m_memos_path == other->m_memos_path ) equal = true; } return sametype && equal; } // statics static std::string AppName() { return "Evolution"; } static std::string PluginName(OpenSync::API &api) { return api.GetConverter().GetPluginName(Evolution()); } static pst_type SupportedSyncTypes(OpenSync::API &api) { return api.GetConverter().GetSupportedSyncTypes(Evolution()); } }; class Evolution3 : public Evolution { public: Evolution3() { } explicit Evolution3(Converter *load_converter, const Member &member) { load_converter->Load(*this, member); } // virtual overrides virtual Evolution3* Clone() const { return new Evolution3(*this); } virtual std::string GetAppName() const { return AppName(); } virtual void Save(OpenSync::API &api, const std::string &group_name) const { api.GetConverter().Save(*this, group_name); } virtual std::string GetPluginName(OpenSync::API &api) const { return api.GetConverter().GetPluginName(*this); } virtual bool IsConfigured(OpenSync::API &api) const { return api.GetConverter().IsConfigured(*this); } virtual pst_type GetSupportedSyncTypes(OpenSync::API &api) const { return api.GetConverter().GetSupportedSyncTypes(*this) & GetConfiguredSyncTypes(); } virtual bool Compare(const Plugin &plugin, bool &sametype, bool &equal) const { sametype = equal = false; const Evolution3 *other = dynamic_cast (&plugin); if( other ) { // we've established that Evolution3 == Evolution3, // but the actual compare can be done by the base // class... return Evolution::Compare(plugin, sametype, equal); } else return false; } // statics static std::string AppName() { return "Evolution 3"; } static std::string PluginName(OpenSync::API &api) { return api.GetConverter().GetPluginName(Evolution3()); } static pst_type SupportedSyncTypes(OpenSync::API &api) { return api.GetConverter().GetSupportedSyncTypes(Evolution3()); } }; class Google : public Plugin { private: // configuration settings std::string m_username; std::string m_password; bool m_contacts_enabled; bool m_calendar_enabled; public: Google() : m_contacts_enabled(true) , m_calendar_enabled(true) { } explicit Google(Converter *load_converter, const Member &member) { load_converter->Load(*this, member); } const std::string& GetUsername() const { return m_username; } const std::string& GetPassword() const { return m_password; } bool IsContactsEnabled() const { return m_contacts_enabled; } bool IsCalendarEnabled() const { return m_calendar_enabled; } void SetUsername(const std::string &u) { m_username = u; } void SetPassword(const std::string &p) { m_password = p; } bool EnableContacts(bool setting = true) { bool old = m_contacts_enabled; m_contacts_enabled = setting; return old; } bool EnableCalendar(bool setting = true) { bool old = m_calendar_enabled; m_calendar_enabled = setting; return old; } // virtual overrides virtual Google* Clone() const { return new Google(*this); } virtual bool IsUnsupported() const { return false; } virtual std::string GetAppName() const { return AppName(); } virtual void Save(OpenSync::API &api, const std::string &group_name) const { api.GetConverter().Save(*this, group_name); } virtual std::string GetPluginName(OpenSync::API &api) const { return api.GetConverter().GetPluginName(*this); } virtual bool IsConfigured(OpenSync::API &api) const { return api.GetConverter().IsConfigured(*this); } virtual pst_type GetConfiguredSyncTypes() const { pst_type pst = PST_NONE; if( m_contacts_enabled ) pst |= PST_CONTACTS; if( m_calendar_enabled ) pst |= PST_EVENTS; return pst; } virtual pst_type GetSupportedSyncTypes(OpenSync::API &api) const { return api.GetConverter().GetSupportedSyncTypes(*this) & GetConfiguredSyncTypes(); } virtual bool Compare(const Plugin &plugin, bool &sametype, bool &equal) const { sametype = equal = false; const Google *other = dynamic_cast (&plugin); if( other ) { sametype = true; if( m_username == other->m_username && m_password == other->m_password && m_contacts_enabled == other->m_contacts_enabled && m_calendar_enabled == other->m_calendar_enabled ) equal = true; } return sametype && equal; } // statics static std::string AppName() { return "Google Calendar"; } static std::string PluginName(OpenSync::API &api) { return api.GetConverter().GetPluginName(Google()); } static pst_type SupportedSyncTypes(OpenSync::API &api) { return api.GetConverter().GetSupportedSyncTypes(Google()); } }; class KDEPim : public Plugin { private: // version 0.22 has no config public: KDEPim() { } explicit KDEPim(Converter *load_converter, const Member &member) { load_converter->Load(*this, member); } // virtual overrides virtual KDEPim* Clone() const { return new KDEPim(*this); } virtual bool IsUnsupported() const { return false; } virtual std::string GetAppName() const { return AppName(); } virtual void Save(OpenSync::API &api, const std::string &group_name) const { api.GetConverter().Save(*this, group_name); } virtual std::string GetPluginName(OpenSync::API &api) const { return api.GetConverter().GetPluginName(*this); } virtual bool IsConfigured(OpenSync::API &api) const { return api.GetConverter().IsConfigured(*this); } virtual pst_type GetConfiguredSyncTypes() const { return PST_ALL; } virtual pst_type GetSupportedSyncTypes(OpenSync::API &api) const { return api.GetConverter().GetSupportedSyncTypes(*this) & GetConfiguredSyncTypes(); } virtual bool Compare(const Plugin &plugin, bool &sametype, bool &equal) const { sametype = equal = false; const KDEPim *other = dynamic_cast (&plugin); if( other ) { sametype = true; // no data for this config, so always equal equal = true; } return sametype && equal; } // statics static std::string AppName() { return "KDEPim / Kontact"; } static std::string PluginName(OpenSync::API &api) { return api.GetConverter().GetPluginName(KDEPim()); } static pst_type SupportedSyncTypes(OpenSync::API &api) { return api.GetConverter().GetSupportedSyncTypes(KDEPim()); } }; // // Group // /// This class handles the loading of all the config plugins in a /// given group. /// class Group : private std::vector > { public: typedef std::tr1::shared_ptr value_type; typedef std::tr1::shared_ptr group_ptr; typedef value_type plugin_ptr; typedef std::vector base_type; typedef base_type::iterator iterator; typedef base_type::const_iterator const_iterator; private: std::string m_group_name; protected: static void BarryCheck(OpenSync::API &api, const std::string &group_name, const member_list_type &members, unsigned throw_mask); // not copyable... use Clone() Group(const Group &other); Group& operator=(const Group &other); public: // OpenSync Config Group Throw Masks #define OSCG_THROW_ON_UNSUPPORTED 0x01 #define OSCG_THROW_ON_NO_BARRY 0x02 #define OSCG_THROW_ON_MULTIPLE_BARRIES 0x04 /// This constructor loads an existing Group from the /// given OpenSync api resource, filling the vector /// array with the required plugin config classes. /// /// If desired, specify a mask, which will cause the /// constructor to throw exceptions on the given conditions. /// /// OSCG_THROW_ON_UNSUPPORTED - if set, the constructor will /// throw LoadError if there is a plugin in the group /// for which there is no corresponding Plugin- /// derived class to handle it /// OSCG_THROW_ON_NO_BARRY - if set, the constructor will /// throw LoadError if there are no Barry plugins /// in the group /// OSCG_THROW_ON_MULTIPLE_BARRIES - if set, the constructor will /// throw LoadError if there is more than one Barry /// plugin in the group /// Group(const std::string &group_name, OpenSync::API &api, unsigned throw_mask = 0); /// This constructor creates an empty, but named, Group. explicit Group(const std::string &group_name); bool HasUnsupportedPlugins() const; bool HasBarryPlugins() const; bool GroupExists(OpenSync::API &api) const; bool AllConfigured(OpenSync::API &api) const; int GetConnectedCount() const; const std::string& GetGroupName() const { return m_group_name; } /// Cycles through all plugins and ANDs the supported types /// for each together, and returns it. The returned value is /// the minimum set of supportable sync types for this group for /// the given API engine. pst_type GetSupportedSyncTypes(OpenSync::API &api) const; /// Returns comma separated string of application/plugin names, /// excluding Barry std::string GetAppNames() const; /// Returns a reference to the (first) Barry plugin in the group. /// Will throw std::logic_error if not found. OpenSync::Config::Barry& GetBarryPlugin(); const OpenSync::Config::Barry& GetBarryPlugin() const; /// Returns a pointer to the first non-Barry plugin in the group. /// Returns 0 if not found. OpenSync::Config::Plugin* GetNonBarryPlugin(); const OpenSync::Config::Plugin* GetNonBarryPlugin() const; /// Sets the member_id of all plugins to -1, thereby making them /// appear like they have never been saved to an API before. /// A call to Save() after a call to DisconnectMembers() will /// create a completely new group. Note that if the group name /// already exists in the API, saving to it again may cause /// a low level exception to be thrown. void DisconnectMembers(); /// Loads all available plugins from the named group, using /// the api given. If this Group isn't empty (size() != 0), /// then DisconnectMembers() will be called first. void Load(OpenSync::API &api, unsigned throw_mask = 0); /// Same as Load() above, but loads from src_group_name instead /// of m_group_name. m_group_name will not be changed. void Load(const std::string &src_group_name, OpenSync::API &api, unsigned throw_mask = 0); /// Overwrites m_group_name with a new one. void ResetGroupName(const std::string &new_group_name); /// Adds plugin to group, and takes ownership of the pointer void AddPlugin(OpenSync::Config::Plugin *plugin); /// Remove the plugin from the group. Only can guarantee removal /// of non-saved (i.e. disconnected) plugins. If a plugin has /// already been saved to the underlying OpenSync API, it /// may not be possible to delete just one member from the /// group (0.22), and a DeleteError will be thrown. /// /// If you don't want to actually delete any members from any /// existing configs, then DisconnectMembers() first. void DeletePlugin(iterator i, OpenSync::API &api); /// Returns true if it is possible to resave this /// Group to the existing opensync config. If this returns /// false, and there are connected members, Save() will /// throw. Save() will automatically call this function /// during saving. /// /// Note: only call this if GroupExists() is true, otherwise, /// this function is irrelevant. bool GroupMatchesExistingConfig(OpenSync::API &api); /// Save all plugins as members of the group. If the group doesn't /// exist, it will be created. If the group does exist, and its /// existing plugin list and member_id's don't match this Group's /// list, SaveError will be thrown. If a plugin doesn't have a /// member_id, it will be added as a new member to the group and /// given an id. Note that an exception thrown from this function /// means that the group is left in an undefined state. Best to /// delete it and start over. Or load it, delete it (through the API), /// disconnect it, and save it again. void Save(OpenSync::API &api); /// Compares against another group, including all the plugins, /// and each plugin data. Order of plugins in group does not /// matter, nor do file-specific data, like member IDs. /// If saving both groups would result in functionally equivalent /// sync groups, then they are equal. This is used to avoid /// re-saving when not necessary. /// Returns true if equal. bool Compare(const Group &group) const; /// Clones this Group object and returns a group_ptr of the new one group_ptr Clone() const; /// Forget all plugins and delete them all using base_type::clear; // bring underlying implementation forward using base_type::size; using base_type::begin; using base_type::end; using base_type::operator[]; }; }} // namespace OpenSync::Config #endif barry-0.18.5/desktop/src/ipc.h0000644001161500056700000000501512242254476015441 0ustar cdfreycdfrey/// /// \file ipc.h /// Common things needed for both client and server /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_IPC_H__ #define __BARRYDESKTOP_IPC_H__ #include #define SERVER_SERVICE_NAME _T("/tmp/bsyncjail.socket") // Connection Topics #define TOPIC_STATUS _T("Status") #define TOPIC_CONFLICT _T("Conflict") // Status items #define STATUS_ITEM_ERROR _T("Error") #define STATUS_ITEM_ENGINE _T("Engine") #define STATUS_ITEM_MAPPING _T("Mapping") #define STATUS_ITEM_ENTRY _T("Entry") #define STATUS_ITEM_MEMBER _T("Member") // Special engine messages #define ENGINE_STATUS_SLOW_SYNC _T("SLOW_SYNC: on") // Conflict items #define CONFLICT_ITEM_START _T("Start") #define CONFLICT_ITEM_CHANGE _T("Change") #define CONFLICT_ITEM_ANSWER _T("Answer") // Used to convert const char* strings into temporary writable // buffers, since wxConnection is not very const correct. class SillyBuffer { wxChar *m_buf; int m_size; int m_data_size; public: SillyBuffer() : m_buf( new wxChar[100] ) , m_size(100) , m_data_size(0) { } ~SillyBuffer() { delete [] m_buf; } int size() const { return m_data_size; } wxChar* buf() { return m_buf; } void resize(int len) { if( len+1 > m_size ) { delete [] m_buf; m_buf = 0; m_buf = new wxChar[len+1]; m_size = len+1; m_data_size = 0; } } SillyBuffer& sbuf(const wxString &str) { buf(str); return *this; } SillyBuffer& sbuf(const char *str) { buf(str); return *this; } SillyBuffer& sbuf(const std::string &str) { buf(str); return *this; } wxChar* buf(const wxString &str) { resize(str.Len()); memcpy(m_buf, str.GetData(), str.Len() * sizeof(wxChar)); m_buf[str.Len()] = 0; m_data_size = str.Len(); return m_buf; } wxChar* buf(const char *str) { return buf(wxString(str, wxConvUTF8)); } wxChar* buf(const std::string &str) { return buf(wxString(str.c_str(), wxConvUTF8, str.size())); } }; extern SillyBuffer sb; #endif barry-0.18.5/desktop/src/ContactEditDlg.wxg0000644001161500056700000016472612242254476020113 0ustar cdfreycdfrey Contact wxVERTICAL wxALL|wxEXPAND 5 wxHORIZONTAL wxRIGHT|wxEXPAND|wxALIGN_CENTER_VERTICAL 3 $parent $id m_rec Dialog_ContactEdit_PhotoButton wxBOTTOM|wxEXPAND 3 3 2 1,3,5 6 2 wxRIGHT|wxALIGN_CENTER_VERTICAL 1 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Prefix)) wxLEFT|wxALIGN_CENTER_VERTICAL 10 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.FirstName)) 100, -1 wxLEFT|wxALIGN_CENTER_VERTICAL 10 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.LastName)) 100, -1 wxRIGHT|wxALIGN_CENTER_VERTICAL 1 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Company)) wxLEFT|wxALIGN_CENTER_VERTICAL 10 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.JobTitle)) wxLEFT|wxALIGN_CENTER_VERTICAL 10 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Nickname)) 100, -1 wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND 5 wxHORIZONTAL wxLEFT|wxRIGHT|wxEXPAND 2 wxHORIZONTAL wxEXPAND 0 3 11 2 1 wxALIGN_CENTER_VERTICAL 0 1 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeAddress.Address1)) 170, -1 0 20 20 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeAddress.Address2)) 0 20 20 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeAddress.Address3)) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeAddress.City)) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeAddress.Province)) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeAddress.PostalCode)) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeAddress.Country)) wxEXPAND 0 1 wxEXPAND 0 1 wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomePhone)) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomePhone2)) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeFax)) wxLEFT|wxRIGHT|wxEXPAND 2 wxHORIZONTAL wxEXPAND 0 3 11 2 1 wxALIGN_CENTER_VERTICAL 0 1 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkAddress.Address1)) 170, -1 0 20 20 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkAddress.Address2)) 0 20 20 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkAddress.Address3)) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkAddress.City)) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkAddress.Province)) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkAddress.PostalCode)) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkAddress.Country)) wxEXPAND 0 1 wxEXPAND 0 1 wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkPhone)) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkPhone2)) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Fax)) wxEXPAND 0 wxHORIZONTAL wxEXPAND 0 3 10 2 1 wxALIGN_CENTER_VERTICAL 0 1 0 Comma separated list of simple email addresses. Do not use <> characters. wxTextValidator(wxFILTER_NONE, m_strings.Add(m_email_list)) 170, -1 wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.OtherPhone)) 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Phone)) 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Radio)) 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.PIN)) 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.UserDefined1)) 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.UserDefined2)) 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.UserDefined3)) 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.UserDefined4)) wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND 5 wxHORIZONTAL wxRIGHT|wxALIGN_CENTER_VERTICAL 1 1 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.MobilePhone)) 100, -1 0 20 20 wxRIGHT|wxALIGN_CENTER_VERTICAL 1 1 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.MobilePhone2)) 100, -1 0 20 20 wxRIGHT|wxALIGN_CENTER_VERTICAL 1 1 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Pager)) 100, -1 wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND 5 wxVERTICAL wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Notes)) wxEXPAND 0 wxHORIZONTAL wxRIGHT|wxALIGN_CENTER_VERTICAL 1 1 wxALL 2 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.URL)) barry-0.18.5/desktop/src/ClickImage.h0000644001161500056700000000246212242254476016661 0ustar cdfreycdfrey/// /// \file ClickImage.h /// Clickable image class /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_CLICKIMAGE_H__ #define __BARRYDESKTOP_CLICKIMAGE_H__ #include class ClickableImage { wxWindow *m_parent; int m_id; wxBitmap m_image; int m_x, m_y; bool m_focus; bool m_event_on_up; wxCursor m_hover_cursor; protected: bool CalculateHit(int x, int y); public: ClickableImage(wxWindow *parent, const wxBitmap &image, int ID, int x, int y, bool event_on_up = true, const wxCursor &hover = wxCursor(wxCURSOR_HAND)); void Draw(wxDC &dc); void HandleMotion(wxDC &dc, int x, int y); void HandleDown(wxDC &dc, int x, int y); void HandleUp(wxDC &dc, int x, int y); }; #endif barry-0.18.5/desktop/src/EvoSources.cc0000644001161500056700000002520512242254476017124 0ustar cdfreycdfrey/// /// \file EvoSources.cc /// A class that creates a list of Evolution data sources. /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) Based on evolution2_sync.h and list_sources.c from evolution opensync plugin by Ian Martin Copyright (C) 2009, Ian Martin, licensed under LGPL 2.1 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 in the COPYING file at the root directory of this project for more details. */ #include "../config.h" #if HAVE_EVOLUTION // // Some versions of libical use a ring buffer for the following // functions, for which the library manages memory. Somewhere along // the line, this was fixed so that the application was responsible // for freeing the strings returned by these functions. A warning // was added to the header that would display if HANDLE_LIBICAL_MEMORY // was not defined. // // Even newer versions of evolution-data-server, which this plugin // depends on, get rid of some of these functions, while newer // versions of libical add _r variants that implement the // application-free functinality. // // Since this plugin does not use these functions, we disable the // warning by defining HANDLE_LIBICAL_MEMORY, then include the // headers. // #define HANDLE_LIBICAL_MEMORY 1 #include #include // For some reason, the evolution-data-server libraries use a floating // point number in the version numbers, which causes trouble during // compiles when compared in preprocessor statements. Define our own // here, only comparing major and minor, since that's all we should need // to care about. #define NON_FLOAT_EDS_CHECK_VERSION(major,minor,micro) \ (EDS_MAJOR_VERSION > (major) || \ (EDS_MAJOR_VERSION == (major) && EDS_MINOR_VERSION > (minor)) || \ (EDS_MAJOR_VERSION == (major) && EDS_MINOR_VERSION == (minor))) #if NON_FLOAT_EDS_CHECK_VERSION(3,6,0) #include #include #include #include "EvoSources.h" struct EvoFunctions { void (*g_type_init)(void); }; // helper functions void FetchSources(EvoFunctions &funcs, EvoSources::List &list, ESourceRegistry *reg, const gchar *extension_type) { GList *sources = e_source_registry_list_sources(reg, extension_type); ESource *source = NULL; GList *s = NULL; for( s = sources; s; s = s->next ) { source = E_SOURCE(s->data); EvoSource sitem; sitem.m_SourceName = e_source_get_display_name(source); sitem.m_SourcePath = e_source_get_uid(source); list.push_back(sitem); } g_list_free_full(sources, g_object_unref); } void EvoSources::LoadBaseSyms() { m_funcs->g_type_init = &g_type_init; } bool EvoSources::LoadEbookLib() { m_funcs.reset( new EvoFunctions ); LoadBaseSyms(); m_funcs->g_type_init(); GError *gerror = NULL; ESourceRegistry *reg = e_source_registry_new_sync(NULL, &gerror); FetchSources(*m_funcs, m_addressbook, reg, E_SOURCE_EXTENSION_ADDRESS_BOOK); g_object_unref(reg); return true; } bool EvoSources::LoadEcalLib() { m_funcs.reset( new EvoFunctions ); LoadBaseSyms(); m_funcs->g_type_init(); GError *gerror = NULL; ESourceRegistry *reg = e_source_registry_new_sync(NULL, &gerror); if( !reg ) { m_error_msg = gerror->message; return false; } FetchSources(*m_funcs, m_events, reg, E_SOURCE_EXTENSION_CALENDAR); FetchSources(*m_funcs, m_tasks, reg, E_SOURCE_EXTENSION_TASK_LIST); FetchSources(*m_funcs, m_memos, reg, E_SOURCE_EXTENSION_MEMO_LIST); g_object_unref(reg); return true; } /////////////////////////////////////////////////////////////////////////////// #else // EDS_CHECK_VERSION(3,6,0) /////////////////////////////////////////////////////////////////////////////// #include #include #include #include "EvoSources.h" struct EvoFunctions { void (*g_type_init)(void); gboolean (*e_book_get_addressbooks)(ESourceList**, GError **); gboolean (*e_cal_get_sources)(ESourceList **, ECalSourceType, GError **); GSList* (*e_source_list_peek_groups)(ESourceList *); GSList* (*e_source_group_peek_sources)(ESourceGroup *); const gchar* (*e_source_group_peek_name)(ESourceGroup *); const gchar* (*e_source_peek_name)(ESource *); gchar* (*e_source_get_uri)(ESource *); }; // helper functions void FetchSources(EvoFunctions &funcs, EvoSources::List &list, ESourceList *sources) { GSList *g = NULL; for( g = funcs.e_source_list_peek_groups(sources); g; g = g->next ) { ESourceGroup *group = (ESourceGroup*) g->data; GSList *s = NULL; for( s = funcs.e_source_group_peek_sources(group); s; s = s->next ) { EvoSource sitem; ESource *source = (ESource*) s->data; sitem.m_GroupName = funcs.e_source_group_peek_name(group); sitem.m_SourceName = funcs.e_source_peek_name(source); sitem.m_SourcePath = funcs.e_source_get_uri(source); list.push_back(sitem); } } } void FetchAddressBooks(EvoFunctions &funcs, EvoSources::List &list) { ESourceList *sources = NULL; if( funcs.e_book_get_addressbooks(&sources, NULL) ) { FetchSources(funcs, list, sources); } } void FetchCalendars(EvoFunctions &funcs, EvoSources::List &list, ECalSourceType source_type) { ESourceList *sources = NULL; if( funcs.e_cal_get_sources(&sources, source_type, NULL) ) { FetchSources(funcs, list, sources); } } void EvoSources::LoadBaseSyms() { // Ideally, these functions would be loaded dynamically, // but there are two problems with that, which need to be // cracked first: // // - the glib major version numbers, according to the .so // files, are not consistent between distros // - when used dynamically, in a program that is not otherwise // linked to glib, it can segfault... and it seems to get // funky somewhere inside glib itself... so I'm guessing that // the library is not being initialized properly :-( // // All this means that general compilations of barrydesktop will // need evolution-data-server and friends linked in. It is possible // to compile without, but then you risk getting a weak auto-detection // of data sources in newer versions of evolution. If your data // sources are located in paths like this: // // file:///home/cdfrey/.evolution/addressbook/local/system // // then it is safe to disable evolution for the barrydesktop compile. // Otherwise, if your version of evolution uses funkier names, or // uses local:system, or puts its files under ~/.config, then // build with evolution and link against it. // // Note that if you do not have any OpenSync libraries installed, // then you don't need this evolution source detection at all, and // you can safely disable evolution for the barrydesktop compile too, // since the desktop GUI will not allow the user to even enter the // sync screen without OpenSync. // m_funcs->g_type_init = &g_type_init; m_funcs->e_source_list_peek_groups = &e_source_list_peek_groups; m_funcs->e_source_group_peek_sources = &e_source_group_peek_sources; m_funcs->e_source_group_peek_name = &e_source_group_peek_name; m_funcs->e_source_peek_name = &e_source_peek_name; m_funcs->e_source_get_uri = &e_source_get_uri; m_funcs->e_book_get_addressbooks = &e_book_get_addressbooks; m_funcs->e_cal_get_sources = &e_cal_get_sources; } bool EvoSources::LoadEbookLib() { m_funcs.reset( new EvoFunctions ); LoadBaseSyms(); m_funcs->g_type_init(); FetchAddressBooks(*m_funcs, m_addressbook); return true; } bool EvoSources::LoadEcalLib() { m_funcs.reset( new EvoFunctions ); LoadBaseSyms(); m_funcs->g_type_init(); FetchCalendars(*m_funcs, m_events, E_CAL_SOURCE_TYPE_EVENT); FetchCalendars(*m_funcs, m_tasks, E_CAL_SOURCE_TYPE_TODO); FetchCalendars(*m_funcs, m_memos, E_CAL_SOURCE_TYPE_JOURNAL); return true; } #endif // EDS_CHECK_VERSION void EvoSources::Detect() { Clear(); if( LoadEbookLib() && LoadEcalLib() ) { // done! m_supported = true; } else { Clear(); GuessPaths(); m_supported = false; } } bool EvoSources::IsSupported() const { return m_supported; } ///////////////////////////////////////////////////////////////////////////// #else // HAVE_EVOLUTION ///////////////////////////////////////////////////////////////////////////// // No Evolution data libraries available #include "EvoSources.h" #include // helper functions void EvoSources::Detect() { GuessPaths(); } bool EvoSources::IsSupported() const { return false; } ///////////////////////////////////////////////////////////////////////////// #endif // HAVE_EVOLUTION ///////////////////////////////////////////////////////////////////////////// #include #include #include #include using namespace std; bool EvoSources::PathExists(const std::string &path) { struct stat s; if( stat(path.c_str(), &s) == 0 ) { if( S_ISDIR(s.st_mode) ) { return true; } } return false; } void SetIfExists(EvoSources::List &list, const std::string &group, const std::string &name, const std::string &dir) { if( EvoSources::PathExists(dir) ) { EvoSource sitem; sitem.m_GroupName = group; sitem.m_SourceName = name; sitem.m_SourcePath = "file://" + dir; list.push_back(sitem); } } EvoSources::EvoSources() { Detect(); } void EvoSources::GuessPaths() { struct passwd *pw = getpwuid(getuid()); if( !pw ) return; string base = pw->pw_dir; base += "/.evolution/"; string tail = "/local/system"; SetIfExists(m_addressbook, "Autodetect", "Addressbook", base + "addressbook" + tail); SetIfExists(m_events, "Autodetect", "Events", base + "calendar" + tail); SetIfExists(m_tasks, "Autodetect", "Tasks", base + "tasks" + tail); SetIfExists(m_memos, "Autodetect", "Memos", base + "memos" + tail); } void EvoSources::Clear() { m_addressbook.clear(); m_events.clear(); m_tasks.clear(); m_memos.clear(); } bool EvoSources::IsEmpty() const { return m_addressbook.empty() && m_events.empty() && m_tasks.empty() && m_memos.empty(); } bool EvoSources::IsDefaultable() const { return // first three are required m_addressbook.size() && m_addressbook[0].m_SourcePath.size() && m_events.size() && m_events[0].m_SourcePath.size() && m_tasks.size() && m_tasks[0].m_SourcePath.size() && // and all lists must not have more than 1 item m_addressbook.size() <= 1 && m_events.size() <= 1 && m_tasks.size() <= 1 && m_memos.size() <= 1; } barry-0.18.5/desktop/src/Mode_MainMenu.cc0000644001161500056700000000426512242254476017507 0ustar cdfreycdfrey/// /// \file Mode_MainMenu.cc /// Mode derived class for the main menu buttons /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "Mode_MainMenu.h" #include "BaseButtons.h" #include "barrydesktop.h" #include ////////////////////////////////////////////////////////////////////////////// // MainMenuMode MainMenuMode::MainMenuMode(wxWindow *parent) : m_basebuttons( new BaseButtons(parent) ) { } MainMenuMode::~MainMenuMode() { } void MainMenuMode::UpdateScreenshot(const Barry::Pin &pin) { // clear existing screenshot m_screenshot = wxBitmap(); // fetch the new device's screenshot try { if( pin.Valid() ) { int index = Barry::Probe::FindActive(wxGetApp().GetResults(), pin); if( index != -1 ) { wxBusyCursor wait; m_screenshot = wxGetApp().GetScreenshot(wxGetApp().GetResults()[index]); } } } catch( Barry::Error &be ) { // don't worry if we can't get a screenshot... not all // devices support it barryverbose(_C("Ignorable screenshot exception: ") << be.what()); } } void MainMenuMode::OnPaint(wxDC &dc) { static bool init = false; // paint the buttons if( !init ) { m_basebuttons->InitAll(dc); init = true; } m_basebuttons->DrawAll(dc); // paint the screenshot if available if( m_screenshot.IsOk() ) { dc.DrawBitmap(m_screenshot, 410, 290); } } void MainMenuMode::OnMouseMotion(wxDC &dc, int x, int y) { m_basebuttons->HandleMotion(dc, x, y); } void MainMenuMode::OnLeftDown(wxDC &dc, int x, int y) { m_basebuttons->HandleDown(dc, x, y); } void MainMenuMode::OnLeftUp(wxDC &dc, int x, int y) { m_basebuttons->HandleUp(dc, x, y); } barry-0.18.5/desktop/src/util.h0000644001161500056700000000521512242254476015645 0ustar cdfreycdfrey/// /// \file util.h /// Utility functions specific to Barry Desktop /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_UTIL_H__ #define __BARRYDESKTOP_UTIL_H__ #include #include #define BUTTON_STATE_NORMAL 0 #define BUTTON_STATE_FOCUS 1 #define BUTTON_STATE_PUSHED 2 // exception class for DrawButtonLabel() function below class DrawButtonLabelError : public std::runtime_error { public: DrawButtonLabelError(const std::string &msg) : std::runtime_error(msg) { } }; template int GetMaxWidth(wxWindow *win, IteratorT begin, IteratorT end, StrFn sfn) { int max_width = 0; for( ; begin != end(); ++begin ) { int this_width = 0; int this_height = 0; win->GetTextExtent(wxString(sfn(*begin).c_str(), wxConvUTF8), &this_width, &this_height); max_width = std::max(max_width, this_width); } return max_width; } const wxArrayString& GetButtonLabels(); std::string GetBaseFilename(const std::string &filename); wxString GetImageFilename(const wxString &filename); wxString GetButtonFilename(int id, int state); wxString GetButtonLabel(int id); bool IsButtonEnabled(int id); class wxDatePickerCtrl; void MakeDateRecent(bool checked, wxDatePickerCtrl *picker); bool IsParsable(const std::string &dbname); bool IsBuildable(const std::string &dbname); void DrawButtonLabelDC(wxDC &dc, const wxBitmap &bmp, const wxString &label, wxFont &font, const wxColour &textfg, int left, int top, int right, int bottom); // Determine parsable classes via template specialization template inline bool IsParsable() { return false; } #undef HANDLE_PARSER #define HANDLE_PARSER(dbname) \ template <> \ inline bool IsParsable() \ { \ return true; \ } ALL_KNOWN_PARSER_TYPES // Determine buildable classes via template specialization template inline bool IsBuildable() { return false; } #undef HANDLE_BUILDER #define HANDLE_BUILDER(dbname) \ template <> \ inline bool IsBuildable() \ { \ return true; \ } ALL_KNOWN_BUILDER_TYPES #endif barry-0.18.5/desktop/src/GroupCfgDlg.cc0000644001161500056700000004276612242254476017205 0ustar cdfreycdfrey/// /// \file GroupCfgDlg.cc /// The configuration dialog used when a user double clicks /// on a device in the device list. It lets the user choose /// the app to sync with Barry, as well as the engine to use. /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "GroupCfgDlg.h" #include "windowids.h" #include "configui.h" #include "barrydesktop.h" #include #include "wxi18n.h" using namespace std; using namespace OpenSync; BEGIN_EVENT_TABLE(GroupCfgDlg, wxDialog) EVT_BUTTON (Dialog_GroupCfg_AppConfigButton, GroupCfgDlg::OnConfigureApp) EVT_CHECKBOX (Dialog_GroupCfg_ContactsCheck, GroupCfgDlg::OnSyncTypeCheck) EVT_CHECKBOX (Dialog_GroupCfg_EventsCheck, GroupCfgDlg::OnSyncTypeCheck) EVT_CHECKBOX (Dialog_GroupCfg_NotesCheck, GroupCfgDlg::OnSyncTypeCheck) EVT_CHECKBOX (Dialog_GroupCfg_TodosCheck, GroupCfgDlg::OnSyncTypeCheck) EVT_TEXT (Dialog_GroupCfg_EngineCombo, GroupCfgDlg::OnEngineComboChange) EVT_TEXT (Dialog_GroupCfg_AppCombo, GroupCfgDlg::OnAppComboChange) END_EVENT_TABLE() ////////////////////////////////////////////////////////////////////////////// // GroupCfgDlg class GroupCfgDlg::GroupCfgDlg(wxWindow *parent, const DeviceEntry &device, OpenSync::APISet &apiset) : wxDialog(parent, Dialog_GroupCfg, _W("Device Sync Configuration")) , m_device(device) , m_apiset(apiset) , m_app_count(0) , m_engine(0) , m_barry_plugin(m_device.GetPin()) , m_topsizer(0) , m_appsizer(0) , m_engine_combo(0) , m_app_combo(0) , m_password_edit(0) , m_name_edit(0) , m_debug_check(0) , m_sync_contacts_check(0) , m_sync_events_check(0) , m_sync_notes_check(0) , m_sync_todos_check(0) , m_favour_radios(0) { std::string appname; // make sure there is at least one engine if( !apiset.os22() && !apiset.os40() ) throw std::logic_error(_C("Must have at least one engine in GroupCfgDlg")); // setup the raw GUI CreateLayout(); // set window title to device PIN and name string label = _C("Configure Device - "); label += m_device.GetPin().Str(); if( m_device.GetDeviceName().size() ) label += " (" + m_device.GetDeviceName() + ")"; SetTitle(wxString(label.c_str(), wxConvUTF8)); // copy over the extras // and initialize the engine / sync type map with config data // if available if( m_device.GetExtras() ) { const DeviceExtras *extras = m_device.GetExtras(); m_favour_plugin_name = extras->m_favour_plugin_name; m_sync_types[apiset.os22()] = extras->m_sync_types; m_sync_types[apiset.os40()] = extras->m_sync_types; } else { // default to all on, in worst case scenario m_sync_types[apiset.os22()] = PST_ALL; m_sync_types[apiset.os40()] = PST_ALL; } // initialize current engine pointer if( m_device.GetEngine() ) { m_engine = const_cast (m_device.GetEngine()); } // initialize local group and plugin data if( m_engine && m_device.GetConfigGroup() ) { const Config::Group *group = m_device.GetConfigGroup(); // use existing group name, if available m_group_name = group->GetGroupName(); // copy Barry plugin config, if available if( group->HasBarryPlugins() ) m_barry_plugin = group->GetBarryPlugin(); // copy non-Barry plugin config, if available const Config::Plugin *plugin = group->GetNonBarryPlugin(); if( plugin ) { appname = plugin->GetAppName(); m_plugins[m_engine][appname].reset( plugin->Clone() ); } } else { m_group_name = "barrydesktop_" + m_device.GetPin().Str(); } SelectCurrentEngine(); LoadBarryConfig(); SelectApplication(appname); SelectFavour(); if( m_app_count == 0 ) { wxMessageBox(_W("No supported applications found. You may need to install some opensync plugins."), _W("No App Found"), wxOK | wxICON_ERROR, this); } } void GroupCfgDlg::CreateLayout() { m_topsizer = new wxBoxSizer(wxVERTICAL); AddEngineSizer(m_topsizer); AddConfigSizer(m_topsizer); AddSyncTypeSizer(m_topsizer); AddFavourSizer(m_topsizer); AddButtonSizer(m_topsizer); SetSizer(m_topsizer); m_topsizer->SetSizeHints(this); m_topsizer->Layout(); } void GroupCfgDlg::AddEngineSizer(wxSizer *sizer) { wxSizer *engine = new wxStaticBoxSizer( new wxStaticBox(this, wxID_ANY, _W("OpenSync Engine")), wxHORIZONTAL ); wxArrayString engines; if( m_apiset.os22() ) engines.Add(wxString(m_apiset.os22()->GetVersion(),wxConvUTF8)); if( m_apiset.os40() ) engines.Add(wxString(m_apiset.os40()->GetVersion(),wxConvUTF8)); engine->Add( m_engine_combo = new wxComboBox(this, Dialog_GroupCfg_EngineCombo, _T(""), wxDefaultPosition, wxSize(100, -1), engines, wxCB_READONLY), 1, wxALL, 5); sizer->Add(engine, 0, wxTOP | wxLEFT | wxRIGHT | wxEXPAND, 10); // if only one engine is available, don't bother showing the combo if( !m_apiset.os22() || !m_apiset.os40() ) { sizer->Hide(engine, true); } } void GroupCfgDlg::AddConfigSizer(wxSizer *sizer) { wxSizer *config = new wxBoxSizer(wxHORIZONTAL); AddBarrySizer(config); AddAppSizer(config); sizer->Add(config, 1, wxTOP | wxLEFT | wxRIGHT | wxEXPAND, 10); } void GroupCfgDlg::AddBarrySizer(wxSizer *sizer) { wxSizer *barry = new wxStaticBoxSizer( new wxStaticBox(this, wxID_ANY, _W("Barry Config")), wxVERTICAL ); wxSizer *dname = new wxBoxSizer(wxHORIZONTAL); dname->Add( new wxStaticText(this, wxID_ANY, _W("Name:")), 0, wxALIGN_RIGHT | wxALIGN_CENTRE_VERTICAL, 2); dname->Add( m_name_edit = new wxTextCtrl(this, wxID_ANY, _T("")), 1, wxALIGN_LEFT, 0); barry->Add(dname, 0, wxALL | wxEXPAND, 5); wxSizer *password = new wxBoxSizer(wxHORIZONTAL); password->Add( new wxStaticText(this, wxID_ANY, _W("Password:")), 0, wxALIGN_RIGHT | wxALIGN_CENTRE_VERTICAL, 2); password->Add( m_password_edit = new wxTextCtrl(this, wxID_ANY, _T(""), wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD), 1, wxALIGN_LEFT, 0); barry->Add(password, 0, wxALL | wxEXPAND, 5); barry->Add( m_debug_check = new wxCheckBox(this, wxID_ANY, _W("Debug output during sync")), 0, wxALIGN_LEFT, 5); sizer->Add(barry, 0, wxRIGHT | wxEXPAND, 5); } void GroupCfgDlg::AddAppSizer(wxSizer *sizer) { m_appsizer = new wxStaticBoxSizer( new wxStaticBox(this, wxID_ANY, _W("Application")), wxVERTICAL ); UpdateAppSizer(false); sizer->Add(m_appsizer, 0, wxLEFT | wxEXPAND, 5); } void GroupCfgDlg::UpdateAppSizer(bool relayout) { // start fresh m_appsizer->Clear(true); wxArrayString appnames; LoadAppNames(appnames); appnames.Sort(); // FIXME - make size of combobox the size of the longest // string in apps? using textextent calcs m_appsizer->Add( m_app_combo = new wxComboBox(this, Dialog_GroupCfg_AppCombo, _T(""), wxDefaultPosition, wxSize(200, -1), appnames, wxCB_READONLY), 0, wxALL | wxALIGN_CENTRE, 5); m_appsizer->Add( new wxButton(this, Dialog_GroupCfg_AppConfigButton, _W("&Configure...")), 0, wxALL | wxALIGN_CENTRE, 5); // in case this is called after the dialog is already displayed, // we need to readjust everything if( relayout ) m_topsizer->Layout(); } void GroupCfgDlg::LoadAppNames(wxArrayString &appnames) { // need to load app names based on engine plugin availability // NOTE - do not load the Barry plugin, since that's already assumed if( !m_engine ) { // no engine available appnames.Add(_W("No engine selected")); return; } string_list_type plugins; try { m_engine->GetPluginNames(plugins); } catch( std::exception &e ) { barrylog(_C("Exception caught in LoadAppNames: ") << e.what()); return; } // cycle through all available plugins, and add the ones // that we support int added = 0; string_list_type::const_iterator i = plugins.begin(); for( ; i != plugins.end(); ++i ) { string appname; if( m_engine->GetConverter().IsPluginSupported(*i, &appname) ) { // found a supported plugin... // skip Barry if( appname == Config::Barry::AppName() ) continue; appnames.Add( wxString(appname.c_str(), wxConvUTF8) ); added++; } } m_app_count = added; if( m_app_count == 0 ) { appnames.Add(_W("No supported plugins available")); return; } } void GroupCfgDlg::AddSyncTypeSizer(wxSizer *sizer) { wxStaticBoxSizer *checks = new wxStaticBoxSizer(wxHORIZONTAL, this, _W("Sync:")); checks->Add( m_sync_contacts_check = new wxCheckBox(this, Dialog_GroupCfg_ContactsCheck, _W("Contacts")), 0, wxRIGHT | wxEXPAND, 10); checks->Add( m_sync_events_check = new wxCheckBox(this, Dialog_GroupCfg_EventsCheck, _W("Events")), 0, wxRIGHT | wxEXPAND, 10); checks->Add( m_sync_notes_check = new wxCheckBox(this, Dialog_GroupCfg_NotesCheck, _W("Notes")), 0, wxRIGHT | wxEXPAND, 10); checks->Add( m_sync_todos_check = new wxCheckBox(this, Dialog_GroupCfg_TodosCheck, _W("To-dos")), 0, wxRIGHT | wxEXPAND, 10); sizer->Add( checks, 0, wxTOP | wxLEFT | wxRIGHT | wxEXPAND, 10); } void GroupCfgDlg::AddFavourSizer(wxSizer *sizer) { wxArrayString labels; // TRANSLATORS: these 3 strings are options for default // conflict resolution during syncing labels.Add( _W("Favour device") ); labels.Add( _W("Favour application") ); labels.Add( _W("Ask me") ); sizer->Add( m_favour_radios = new wxRadioBox(this, wxID_ANY, _W("To Resolve Conflicts:"), wxDefaultPosition, wxDefaultSize, labels, 1, wxRA_SPECIFY_ROWS), 0, wxTOP | wxLEFT | wxRIGHT | wxEXPAND, 10); } void GroupCfgDlg::AddButtonSizer(wxSizer *sizer) { wxSizer *button = CreateSeparatedButtonSizer(wxOK | wxCANCEL); sizer->Add(button, 0, wxALL | wxEXPAND | wxALIGN_RIGHT, 10); } void GroupCfgDlg::SelectCurrentEngine() { if( m_engine_combo ) { if( !m_engine ) { m_engine = m_apiset.os22() ? m_apiset.os22() : m_apiset.os40(); } if( m_engine ) m_engine_combo->SetValue( wxString(m_engine->GetVersion(), wxConvUTF8)); UpdateAppSizer(); } } void GroupCfgDlg::LoadBarryConfig() { Config::Barry &bp = m_barry_plugin; // use m_device here, since BarryDesktopApp::GetDeviceName() // may return an empty string if the device is not currently // plugged in wxString dname(m_device.GetDeviceName().c_str(), wxConvUTF8); m_name_edit->SetValue(dname); m_password_edit->SetValue(wxString(bp.GetPassword().c_str(), wxConvUTF8)); m_debug_check->SetValue( bp.IsDebugMode() ); } void GroupCfgDlg::SelectApplication(const std::string appname) { m_app_combo->SetValue(wxString(appname.c_str(), wxConvUTF8)); SelectSyncTypes(); } void GroupCfgDlg::SelectSyncTypes() { if( !m_engine ) { SetSyncTypeChecks(PST_NONE); EnableSyncTypeChecks(PST_NONE); return; } string app = GetCurrentAppName(); plugin_ptr ap = GetCurrentPlugin(); // calculate the supported sync types // Note: we could also take the Barry plugin config into // consideration here, but so far, we just use the // opensync group config pst_type supported = PST_NONE; if( ap.get() ) { supported = m_barry_plugin.GetSupportedSyncTypes(*m_engine) & ap->GetSupportedSyncTypes(*m_engine); } // make sure our current selection is limited by our new // set of supported plugins m_sync_types[m_engine] &= supported; // enable the checkboxes according to our ability EnableSyncTypeChecks(supported); // set the checkboxes according to our choices SetSyncTypeChecks(m_sync_types[m_engine]); } void GroupCfgDlg::SelectFavour() { if( m_engine && m_favour_plugin_name == Config::Barry::PluginName(*m_engine) ) { m_favour_radios->SetSelection(0); } else if( m_engine && m_favour_plugin_name.size() ) { m_favour_radios->SetSelection(1); } else { // ask the user m_favour_radios->SetSelection(2); } } void GroupCfgDlg::EnableSyncTypeChecks(pst_type types) { m_sync_contacts_check->Enable( types & PST_CONTACTS ); m_sync_events_check ->Enable( types & PST_EVENTS ); m_sync_notes_check ->Enable( types & PST_NOTES ); m_sync_todos_check ->Enable( types & PST_TODOS ); } void GroupCfgDlg::SetSyncTypeChecks(pst_type types) { m_sync_contacts_check->SetValue( types & PST_CONTACTS ); m_sync_events_check ->SetValue( types & PST_EVENTS ); m_sync_notes_check ->SetValue( types & PST_NOTES ); m_sync_todos_check ->SetValue( types & PST_TODOS ); } GroupCfgDlg::pst_type GroupCfgDlg::GetSyncTypeChecks() { pst_type types = PST_NONE; if( m_sync_contacts_check->GetValue() ) types |= PST_CONTACTS; if( m_sync_events_check ->GetValue() ) types |= PST_EVENTS; if( m_sync_notes_check ->GetValue() ) types |= PST_NOTES; if( m_sync_todos_check ->GetValue() ) types |= PST_TODOS; return types; } std::string GroupCfgDlg::GetCurrentAppName() const { wxString app = m_app_combo->GetValue(); return std::string(app.utf8_str()); } GroupCfgDlg::plugin_ptr GroupCfgDlg::GetCurrentPlugin() { string appname = GetCurrentAppName(); appcfg_map &cfgs = m_plugins[m_engine]; appcfg_map::iterator pi = cfgs.find(appname); if( pi != cfgs.end() ) return pi->second; else return plugin_ptr(); // not found, return empty ptr } void GroupCfgDlg::OnConfigureApp(wxCommandEvent &event) { string app = GetCurrentAppName(); if( app.size() == 0 ) { wxMessageBox(_W("Please select an application."), _W("Application Config"), wxOK | wxICON_ERROR, this); return; } ConfigUI::ptr ui = ConfigUI::CreateConfigUI(app); if( !ui.get() ) { wxMessageBox(_W("No configuration interface available for this Application."), _W("Application Config"), wxOK | wxICON_ERROR, this); return; } if( ui->Configure(this, GetCurrentPlugin()) ) { ConfigUI::plugin_ptr plugin = ui->GetPlugin(); if( plugin.get() ) { m_plugins[m_engine][app] = plugin; // if this is the first time, default to all if( m_sync_types[m_engine] == PST_NONE ) m_sync_types[m_engine] = PST_ALL; // update the types checkboxes SelectSyncTypes(); } } } void GroupCfgDlg::OnEngineComboChange(wxCommandEvent &event) { // remember what plugin we're using plugin_ptr old_app = GetCurrentPlugin(); // update engine pointer wxString newEngine = m_engine_combo->GetValue(); if( m_apiset.os22() && newEngine == wxString(m_apiset.os22()->GetVersion(), wxConvUTF8) ) { m_engine = m_apiset.os22(); } else if( m_apiset.os40() && newEngine == wxString(m_apiset.os40()->GetVersion(), wxConvUTF8) ) { m_engine = m_apiset.os40(); } // update the application list UpdateAppSizer(); // if plugin can be configured in new engine, keep our current // config, otherwise, reset if( old_app.get() && m_engine->GetConverter().IsPluginSupported(old_app->GetPluginName(*m_engine)) ) { // update the app list SelectApplication(old_app->GetAppName()); } else { // leave GUI as is, and zap our plugin data SelectApplication(""); } } void GroupCfgDlg::OnAppComboChange(wxCommandEvent &event) { SelectSyncTypes(); } void GroupCfgDlg::OnSyncTypeCheck(wxCommandEvent &event) { if( !m_engine ) return; m_sync_types[m_engine] = GetSyncTypeChecks(); } bool GroupCfgDlg::TransferDataFromWindow() { // engine must be set! if( !m_engine ) { wxMessageBox(_W("Please select an engine."), _W("Device Config"), wxOK | wxICON_ERROR, this); return false; } // make sure the Barry plugin is configured if( !m_barry_plugin.IsConfigured(*m_engine) ) { wxMessageBox(_W("Barry doesn't have a PIN number. This should never happen."), _W("Device Config"), wxOK | wxICON_ERROR, this); return false; } // make sure the application plugin is configured plugin_ptr app = GetCurrentPlugin(); if( !app.get() || !app->IsConfigured(*m_engine) ) { // the app hasn't been configured yet, do it automatically wxCommandEvent event; OnConfigureApp(event); app = GetCurrentPlugin(); if( !app.get() || !app->IsConfigured(*m_engine) ) { wxMessageBox(_W("The application plugin is not fully configured."), _W("Application Config"), wxOK | wxICON_ERROR, this); return false; } } // copy over barry specific settings m_device_name = string(m_name_edit->GetValue().utf8_str()); m_barry_plugin.SetPassword(string(m_password_edit->GetValue().utf8_str())); m_barry_plugin.DebugMode(m_debug_check->GetValue()); // make sure conflict resolution is known int findex = m_favour_radios->GetSelection(); switch( findex ) { case 0: // Favour device m_favour_plugin_name = Config::Barry::PluginName(*m_engine); break; case 1: // Favour application m_favour_plugin_name = app->GetPluginName(*m_engine); break; case 2: // Ask me m_favour_plugin_name.clear(); break; default: // borked wxMessageBox(_W("Please select conflict resolution method."), _W("Conflict Resolution"), wxOK | wxICON_ERROR, this); return false; } // save the new device name wxGetApp().SetDeviceName(m_barry_plugin.GetPin(), m_device_name); // save the sync type checkboxes m_sync_types[m_engine] = GetSyncTypeChecks(); return true; } int GroupCfgDlg::ShowModal() { int status = wxDialog::ShowModal(); plugin_ptr app = GetCurrentPlugin(); if( status == wxID_OK && app.get() ) { // construct a new group from user's results m_group.reset( new Config::Group(m_group_name) ); m_group->AddPlugin( m_barry_plugin.Clone() ); m_group->AddPlugin( app->Clone() ); // don't forget the extras m_extras.reset( new DeviceExtras(m_barry_plugin.GetPin()) ); m_extras->m_favour_plugin_name = m_favour_plugin_name; m_extras->m_sync_types = m_sync_types[m_engine]; } else { m_group.reset(); m_extras.reset(); } return status; } barry-0.18.5/desktop/src/StringSync.h0000644001161500056700000000621012242254476016767 0ustar cdfreycdfrey/// /// \file StringSync.h /// Class to easily manage the wxString / std::string boundary /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_STRING_SYNC_H__ #define __BARRYDESKTOP_STRING_SYNC_H__ #include #include // // StringSync // /// Provides a wxString or std::string while maintaining a link to /// a corresponding external string of the opposite kind. When /// Sync() is called, the external linked string is updated with the /// current contents of the returned string. /// /// This class contains two lists of strings: one that maps external /// std::strings to internal wxStrings, and another that maps external /// wxStrings to internal std::strings. These lists never mix. /// Add or Refresh transfers data from external to internal, and Sync /// transfers data from internal to external. /// /// Normally, you would use Add and Refresh when setting up a dialog, /// and once setup, never use them again. Use Sync when extracting /// data from the dialog, back into the original variables again. /// /// Note that you must call Sync explicitly, as it is not called /// in the destructor, since it is impossible to know when the /// external strings are freed, and they may have been freed already /// by the time ~StringSync() is called. /// class StringSync { public: typedef std::pair WxIsCopyType; typedef std::pair StdIsCopyType; typedef std::list WxIsCopyList; typedef std::list StdIsCopyList; private: WxIsCopyList m_wx; StdIsCopyList m_std; public: /// On destruction, calls Sync() ~StringSync(); /// Creates an internal wxString, copies the contents of source /// into it, and returns its reference. wxString* Add(std::string &source); /// Does the opposite std::string* Add(wxString &source); /// Copies all internal wxString contents into the corresponding /// external std::strings. void SyncToStd(); /// Copies all internal std::string contents into the corresponding /// external wxStrings. void SyncToWx(); /// Calls both SyncToStd() and SyncToWx() void Sync(); /// Copies the contents of all the external std::strings into /// their internal wxStrings, basically doing an Add() for each one /// without re-creating the wxStrings. void RefreshWx(); /// Copies the contents of all the external wxStrings into their /// internal std::strings, basically doing an Add() for each one /// without re-creating the std::strings. void RefreshStd(); /// Calls both RefreshStd() and RefreshWx() void Refresh(); }; #endif barry-0.18.5/desktop/src/barrydesktop.cc0000644001161500056700000001237012242254476017537 0ustar cdfreycdfrey/// /// \file barrydesktop.cc /// Program entry point for the desktop GUI /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "barrydesktop.h" #include "util.h" #include "osbase.h" #include "BaseFrame.h" #include #include #include #include "wxi18n.h" using namespace std; UsbScanSplash::UsbScanSplash() { wxImage scanpng(GetImageFilename(_T("scanning.png"))); wxBitmap scanning(scanpng); // draw i18n text on the splash screen { wxMemoryDC dc; dc.SelectObject(scanning); int pointsize = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) .GetPointSize(); wxFont font(pointsize + 2, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); DrawButtonLabelDC(dc, scanning, _W("Scanning USB..."), font, *wxBLACK, 70, -1, -1, -1); } std::auto_ptr splash( new wxSplashScreen( scanning, wxSPLASH_CENTRE_ON_SCREEN, 0, NULL, -1, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER) ); splash->Show(true); for( int i = 0; i < 4; i++ ) { wxGetApp().Yield(); wxMilliSleep(250); wxGetApp().Yield(); } } UsbScanSplash::~UsbScanSplash() { } ////////////////////////////////////////////////////////////////////////////// // BarryDesktopApp BarryDesktopApp::BarryDesktopApp() : m_global_config("BarryDesktop") , m_set( new OpenSync::APISet ) { } void BarryDesktopApp::Probe() { // start fresh m_results.clear(); try { // This can throw Usb::Error exceptions Barry::Probe probe; m_results = probe.GetResults(); } catch( Usb::Error &e ) { wxString msg = _W("A serious error occurred while probing the USB subsystem for BlackBerry(R) devices: "); msg += wxString(e.what(), wxConvUTF8); wxMessageBox(msg, _W("USB Error"), wxOK | wxICON_ERROR); } } wxBitmap BarryDesktopApp::GetScreenshot(const Barry::ProbeResult &device) const { // FIXME - will need to eventually move the controller object // into the main app, I think, and maybe the modes too, so // that multiple menu commands can work simultaneously Barry::Controller con(device); Barry::Mode::JavaLoader javaloader(con); javaloader.Open(); javaloader.StartStream(); Barry::JLScreenInfo info; Barry::Data image; javaloader.GetScreenshot(info, image); // Convert to BMP format Barry::Data bitmap(-1, GetTotalBitmapSize(info)); Barry::ScreenshotToBitmap(info, image, bitmap); // Load as wxImage wxMemoryInputStream stream(bitmap.GetData(), bitmap.GetSize()); wxImage bmp(stream, wxBITMAP_TYPE_BMP); bmp.Rescale(180, 100, wxIMAGE_QUALITY_HIGH); return wxBitmap(bmp); } void BarryDesktopApp::SetDeviceName(Barry::Pin pin, const std::string &name) { if( !pin.Valid() ) return; // load device config Barry::ConfigFile cfg(pin); // re-save device config cfg.SetDeviceName(name); cfg.Save(); // update our results if this device exists in our list int index = Barry::Probe::Find(m_results, pin); if( index != -1 ) { m_results[index].m_cfgDeviceName = name; } } std::string BarryDesktopApp::GetDeviceName(Barry::Pin pin) const { string name; int index = Barry::Probe::Find(m_results, pin); if( index != -1 ) name = m_results[index].m_cfgDeviceName; return name; } void BarryDesktopApp::ShowMissingOpenSyncMessage() { wxMessageBox(_W("No OpenSync libraries were found. Sync will be unavailable until you install OpenSync version 0.22 or version 0.4x on your system, along with the needed plugins."), _W("OpenSync Not Found"), wxOK | wxICON_INFORMATION); } bool BarryDesktopApp::OnInit() { // initialize i18n INIT_I18N(PACKAGE); // Add a PNG handler for loading buttons and backgrounds wxImage::AddHandler( new wxPNGHandler ); // Add handlers for loading Contact Photos wxImage::AddHandler( new wxJPEGHandler ); wxImage::AddHandler( new wxTIFFHandler ); wxImage::AddHandler( new wxXPMHandler ); std::auto_ptr splash( new UsbScanSplash ); // Initialize Barry and USB Barry::Init(m_global_config.VerboseLogging()); // Scan bus at the beginning so we know what devices we've got Probe(); // Search for available OpenSync libraries if( m_set->OpenAvailable() == 0 ) { ShowMissingOpenSyncMessage(); } // Create the main frame window where all the action happens wxImage back(GetImageFilename(_T("background.png"))); if( !back.IsOk() ) { Yield(); return false; } BaseFrame *frame = new BaseFrame(back); // Clean up the splash screen, and init the main frame splash.reset(); SetTopWindow(frame); frame->Show(true); return true; } int BarryDesktopApp::OnExit() { try { m_global_config.Save(); } catch( std::exception &e ) { cerr << "Exception caught while saving config: " << e.what() << endl; } return 0; } // This takes care of main() and wxGetApp() for us. IMPLEMENT_APP(BarryDesktopApp) barry-0.18.5/desktop/src/BaseButtons.h0000644001161500056700000000240212242254476017114 0ustar cdfreycdfrey/// /// \file BaseButtons.h /// Support class for BaseFrame /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_BASEBUTTONS_H__ #define __BARRYDESKTOP_BASEBUTTONS_H__ #include class PNGButton; class wxDC; class wxWindow; class BaseButtons { private: std::vector m_buttons; PNGButton *m_current; int m_buttonWidth, m_buttonHeight; protected: PNGButton* CalculateHit(int x, int y); public: BaseButtons(wxWindow *parent); ~BaseButtons(); void InitAll(wxDC &dc); void DrawAll(wxDC &dc); void HandleMotion(wxDC &dc, int x, int y); void HandleDown(wxDC &dc, int x, int y); void HandleUp(wxDC &dc, int x, int y); }; #endif barry-0.18.5/desktop/src/BaseFrame.h0000644001161500056700000000574212242254476016522 0ustar cdfreycdfrey/// /// \file BaseFrame.h /// Class for the fixed-size frame that holds the main app /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_BASEFRAME_H__ #define __BARRYDESKTOP_BASEFRAME_H__ #include #include #include #include #include "exechelper.h" #define MAIN_HEADER_OFFSET 40 class MainMenuMode; class SyncMode; class BrowseMode; class ClickableImage; class Mode; class BaseFrame : public wxFrame, public TermCatcher { private: DECLARE_EVENT_TABLE() // sets to protected: private: std::auto_ptr m_background; std::auto_ptr m_main_menu_mode;// only this mode is // never reset() std::auto_ptr m_sync_mode; std::auto_ptr m_browse_mode; std::auto_ptr m_barry_logo, m_netdirect_logo; std::auto_ptr m_sysmenu; std::auto_ptr m_device_combo; std::auto_ptr m_back_button; int m_width, m_height; Mode *m_current_mode; ExecHelper m_backup_process; bool m_rescan_pending; public: BaseFrame(const wxImage &background); // utility functions void UpdateMenuState(); void CreateDeviceCombo(Barry::Pin pin = Barry::Pin()); Barry::Pin GetCurrentComboPin(); void EnableBackButton(Mode *new_mode); void DisableBackButton(); // also returns to the main menu // events void OnSize(wxSizeEvent &event); void OnPaint(wxPaintEvent &event); void OnMouseMotion(wxMouseEvent &event); void OnLeftDown(wxMouseEvent &event); void OnLeftUp(wxMouseEvent &event); void OnBackupRestore(wxCommandEvent &event); void OnSync(wxCommandEvent &event); void OnModem(wxCommandEvent &event); void OnAppLoader(wxCommandEvent &event); void OnMigrateDevice(wxCommandEvent &event); void OnBrowseDatabases(wxCommandEvent &event); void OnMediaManagement(wxCommandEvent &event); void OnMisc(wxCommandEvent &event); void OnBackButton(wxCommandEvent &event); void OnTermBackupAndRestore(wxProcessEvent &event); void OnBarryLogoClicked(wxCommandEvent &event); void OnNetDirectLogoClicked(wxCommandEvent &event); void OnDeviceComboChange(wxCommandEvent &event); // sys menu (triggered by the Barry logo) void OnVerboseLogging(wxCommandEvent &event); void OnRenameDevice(wxCommandEvent &event); void OnResetDevice(wxCommandEvent &event); void OnRescanUsb(wxCommandEvent &event); void OnAbout(wxCommandEvent &event); void OnExit(wxCommandEvent &event); }; #endif barry-0.18.5/desktop/src/EvoSources.h0000644001161500056700000000535012242254476016765 0ustar cdfreycdfrey/// /// \file EvoSources.h /// A class that creates a list of Evolution data sources. /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) Based on evolution2_sync.h and list_sources.c from evolution opensync plugin by Ian Martin Copyright (C) 2009, Ian Martin, licensed under LGPL 2.1 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_EVO_SOURCES_H__ #define __BARRY_EVO_SOURCES_H__ #include #include #include //#include "dlopen.h" struct EvoSource { std::string m_GroupName; std::string m_SourceName; std::string m_SourcePath; }; struct EvoFunctions; // // EvoSources // /// Instatiating this class does the work of filling the list. Just /// probe the data with the member functions as needed. /// class EvoSources //: public DlOpen { public: typedef std::vector List; private: std::auto_ptr m_funcs; bool m_supported; List m_addressbook; List m_events; List m_tasks; List m_memos; std::string m_error_msg; protected: void LoadBaseSyms(); bool LoadEbookLib(); bool LoadEcalLib(); void GuessPaths(); void Clear(); public: /// Generally always succeeds, in some manner, but if you were /// expecting a different result than you got, check GetErrorMsg(); EvoSources(); const std::string& GetErrorMsg() const { return m_error_msg; } /// This is automatically run from inside the constructor. /// It can be called again to retry detection with the same instance, /// but note that any previous results will be Clear()'d. void Detect(); /// Returns true if this class has built-in support for talking /// to the Evolution data server. False if a dummy wrapper was /// built at compile time due to lack of proper libraries. bool IsSupported() const; /// Returns true if all list are empty bool IsEmpty() const; /// Returns true if minimum 3 paths are available, and if there is /// only 1 path in each list. bool IsDefaultable() const; const List& GetAddressBook() const { return m_addressbook; } const List& GetEvents() const { return m_events; } const List& GetTasks() const { return m_tasks; } const List& GetMemos() const { return m_memos; } static bool PathExists(const std::string &path); }; #endif barry-0.18.5/desktop/src/error.cc0000644001161500056700000000222212242254476016152 0ustar cdfreycdfrey/// /// \file error.cc /// Exception class implementations /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "error.h" #include ///////////////////////////////////////////////////////////////////////////// // class DlError std::string DlError::GetMsg(const std::string &msg) { std::string ret = msg; char *derr = dlerror(); if( derr == NULL ) { ret += ": (dlerror returned NULL)"; } else { ret += ": "; ret += derr; } return ret; } DlError::DlError(const std::string &msg) : std::runtime_error(DlError::GetMsg(msg.c_str())) { } barry-0.18.5/desktop/src/os40.h0000644001161500056700000001334012242254476015453 0ustar cdfreycdfrey/// /// \file os40.h /// Wrapper class for opensync 0.4x syncing behaviour /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_OS40_H__ #define __BARRYDESKTOP_OS40_H__ #include "dlopen.h" #include "osbase.h" #include namespace OpenSync { class OpenSync40Private; class OS40PluginConfigPrivate; class OS40ConfigResourcePrivate; class OS40PluginConfig; class OpenSync40; class OS40ConfigResource { friend class OS40PluginConfig; private: OS40ConfigResourcePrivate *m_priv; bool m_exists; // true if this resources exists // in the plugin config. // AddResource() sets this to true private: OS40ConfigResource(const OS40PluginConfig &parent, void *resource, bool existing_resource); OS40ConfigResource(const OS40ConfigResource &other);//disabled copy OS40ConfigResource& operator=(const OS40ConfigResource &other); public: ~OS40ConfigResource(); /// Returns true if this instance represents an existing /// resource in the config. If this is false, then /// AddResource() must be called, otherwise any changes /// will not be saved to the config object. bool IsExistingResource() const; void AddResource(); // safe to call multiple times bool IsEnabled() const; OS40ConfigResource& Enable(bool enabled = true); // searches for the objformat, and fills in config with its config // value if it exists and returns true... otherwise returns false bool FindObjFormat(const std::string &objformat, std::string &config); OS40ConfigResource& SetObjFormat(const std::string &objformat, const std::string &config = ""); std::string GetName() const; OS40ConfigResource& SetName(const std::string &name); std::string GetPreferredFormat() const; OS40ConfigResource& SetPreferredFormat(const std::string &format); std::string GetMime() const; OS40ConfigResource& SetMime(const std::string &mime); std::string GetObjType() const; private:OS40ConfigResource& SetObjType(const std::string &objtype); // objtype is set // automatically when this object is created with GetResource() public: std::string GetPath() const; OS40ConfigResource& SetPath(const std::string &path); std::string GetUrl() const; OS40ConfigResource& SetUrl(const std::string &url); }; class OS40PluginConfig { friend class OS40ConfigResource; friend class OpenSync40; public: typedef std::auto_ptr OS40ConfigResourcePtr; enum { NONE_TYPE, BOOL_TYPE, CHAR_TYPE, DOUBLE_TYPE, INT_TYPE, LONG_TYPE, LONGLONG_TYPE, UINT_TYPE, ULONG_TYPE, ULONGLONG_TYPE, STRING_TYPE }; private: OpenSync40Private *m_privapi; // external pointer to OpenSync40 std::tr1::shared_ptr m_priv; private: OS40PluginConfig(OpenSync40Private *privapi, void *member, void *config); public: std::string GetAdvanced(const std::string &name); void SetAdvanced(const std::string &name, const std::string &display_name, const std::string &val); void SetAdvanced(const std::string &name, const std::string &display_name, int val_type, const std::string &val); OS40ConfigResourcePtr GetResource(const std::string &objtype); std::string GetUsername() const; void SetUsername(const std::string &username); std::string GetPassword() const; void SetPassword(const std::string &password); void Save(); }; class OpenSync40 : public DlOpen, public OpenSync::API { public: private: // private opensync 0.40 function pointers and data OpenSync40Private *m_priv; protected: void SetupEnvironment(OpenSync40Private *p); public: OpenSync40(); ~OpenSync40(); // // Virtual API overrides // // Functional abilities information... this does not come from // the engine itself, but is information the osbase library // determines useful for applications to know bool IsSlowSyncSupported() const { return true; } // FIXME - is this right? // General engine information const char* GetVersion() const; const char* GetEngineName() const; void GetPluginNames(string_list_type &plugins); void GetFormats(format_list_type &formats); // Information about configured groups void GetGroupNames(string_list_type &groups); void GetMembers(const std::string &group_name, member_list_type &members); // Group configuration void AddGroup(const std::string &group_name); void DeleteGroup(const std::string &group_name); // Plugin configuration helper Converter& GetConverter(); // Member configuration long AddMember(const std::string &group_name, const std::string &plugin_name, const std::string &member_name); void DeleteMember(const std::string &group_name, long member_id); void DeleteMember(const std::string &group_name, const std::string &plugin_name); bool IsConfigurable(const std::string &group_name, long member_id); std::string GetConfiguration(const std::string &group_name, long member_id); OS40PluginConfig GetConfigurationObj(const std::string &group_name, long member_id); void SetConfiguration(const std::string &group_name, long member_id, const std::string &config_data); void Discover(const std::string &group_name); // Syncing void Sync(const std::string &group_name, SyncStatus &status_callback, Config::pst_type sync_types/* = PST_DO_NOT_SET*/); }; } // namespace OpenSync #endif barry-0.18.5/desktop/src/CUI_Google.cc0000644001161500056700000000714412242254476016745 0ustar cdfreycdfrey/// /// \file CUI_Google.cc /// ConfigUI derived class to configure the Google App /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "CUI_Google.h" #include #include #include #include #include "wxi18n.h" using namespace std; namespace AppConfig { ////////////////////////////////////////////////////////////////////////////// // Google config UI class Google::Google() : m_google(0) , m_parent(0) { // gcal_t google_calendar = gcal_new(GCALENDAR); // gcal_get_authentication(google_calendar, "username", "password"); } std::string Google::AppName() const { return OpenSync::Config::Google::AppName(); } bool Google::Configure(wxWindow *parent, plugin_ptr old_plugin) { m_parent = parent; // create our plugin config m_google = dynamic_cast (old_plugin.get()); if( m_google ) { m_google = m_google->Clone(); } else { m_google = new OpenSync::Config::Google; } m_container.reset( m_google ); // display dialog and let user fill in the details return false; // FIXME - not finished } ConfigUI::plugin_ptr Google::GetPlugin() { m_google = 0; return m_container; } bool Google::RunApp(wxWindow *parent) { return false; } void Google::PreSyncAppInit() { } bool Google::ZapData(wxWindow *parent, plugin_ptr plugin, OpenSync::API *engine) { m_parent = parent; // extract OpenSync::Config::Google from plugin // this *can* throw an exception if the wrong plugin is // passed in, but we want this... such an exception would // represent a bug in the app, not a runtime error OpenSync::Config::Google &google = dynamic_cast(*plugin); // build intro message wxString msg = _W("Please select the databases you wish to erase\n" "in your Google Calendar: \n" "\n" "Note: all synced databases must be erased\n" "to avoid a slow-sync."); // build list of databases (base on information from engine, if // the pointer is valid) wxArrayString dbs; wxArrayInt selections; dbs.Add( _W("Calendar") ); selections.Add(0); dbs.Add( _W("Contacts") ); selections.Add(1); // present the list to the user int count = wxGetMultipleChoices(selections, msg, _W("Select Databases to Erase"), dbs, m_parent); if( count <= 0 ) return false; // nothing to do // display selections to the user for one final confirmation ostringstream oss; oss << _C("You have selected the following databases to be completely " "erased from your Google Calendar:") << "\n\n"; for( size_t i = 0; i < selections.GetCount(); i++ ) { oss << string(dbs[selections[i]].utf8_str()) << "\n"; } oss << "\n" << _C("Proceed with erase?"); wxString confirm(oss.str().c_str(), wxConvUTF8); int choice = wxMessageBox(confirm, _W("Erase Confirmation"), wxYES_NO | wxICON_QUESTION, m_parent); if( choice != wxYES ) return false; // nothing to do // might be busy for a bit wxBusyCursor wait; // connect to Google Calendar and delete all selected databases (void)google; return false; // FIXME - not finished } } // namespace AppConfig barry-0.18.5/desktop/src/MigrateDlg.h0000644001161500056700000000653612242254476016716 0ustar cdfreycdfrey/// /// \file MigrateDlg.h /// Dialog for the "Migrate Device" main menu mode button... /// going with a dialog instead of a mode class this time. /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_MIGRATEDLG_H__ #define __BARRYDESKTOP_MIGRATEDLG_H__ #include #include "deviceset.h" #include "EasyCondition.h" // Event types for the MigrateDlg DECLARE_EVENT_TYPE(MET_THREAD_FINISHED, -1) DECLARE_EVENT_TYPE(MET_CHECK_DEST_PIN, -1) DECLARE_EVENT_TYPE(MET_SET_STATUS_MSG, -1) DECLARE_EVENT_TYPE(MET_PROMPT_PASSWORD, -1) DECLARE_EVENT_TYPE(MET_ERROR_MSG, -1) class MigrateDlg : public wxDialog { DECLARE_EVENT_TABLE() // sets to protected: private: // external data sources const Barry::Probe::Results &m_results; int m_current_device_index; // in case we need to rescan the USB for a newly plugged device Barry::Probe::Results m_new_results; // migration settings, for the thread bool m_migrate_thread_created; // true until joined pthread_t m_migrate_thread; volatile bool m_abort_flag; volatile bool m_thread_running; const Barry::ProbeResult *m_source_device, *m_dest_device; Barry::DeviceParser::WriteMode m_write_mode; EasyCondition m_waiter; wxString m_password; // backup data, used by the thread in BackupSource() std::string m_backup_tarfile; Barry::DatabaseDatabase m_source_dbdb; // dialog controls wxSizer *m_topsizer; wxChoice *m_source_combo, *m_dest_combo, *m_write_mode_combo; wxButton *m_migrate_button; wxCheckBox *m_wipe_check; wxStaticText *m_status; wxGauge *m_progress; protected: void CreateLayout(); void AddDescriptionSizer(wxSizer *sizer); void AddMainSizer(wxSizer *sizer); void AddStatusSizer(wxSizer *sizer); void Main_AddSourceSizer(wxSizer *sizer); void Main_AddButtonSizer(wxSizer *sizer); void Main_AddDestSizer(wxSizer *sizer); void EnableControls(bool enable = true); void DoSafeClose(); void SendEvent(int event_type); void SendStatusEvent(const wxString &msg, int pos = -1, int max = -1); void SendErrorMsgEvent(const wxString &msg); // thread helper functions, called from the thread void BackupSource(); void CheckDestPin(); void RestoreToDest(); public: MigrateDlg(wxWindow *parent, const Barry::Probe::Results &results, int current_device_index = -1); void WaitForEvent(); const wxString& GetPassword() const { return m_password; } // event handlers void OnMigrateNow(wxCommandEvent &event); void OnCancel(wxCommandEvent &event); void OnCloseWindow(wxCloseEvent &event); void OnThreadFinished(wxCommandEvent &event); void OnCheckDestPin(wxCommandEvent &event); void OnSetStatusMsg(wxCommandEvent &event); void OnPromptPassword(wxCommandEvent &event); void OnErrorMsg(wxCommandEvent &event); // migration thread function static void* MigrateThread(void *arg); }; #endif barry-0.18.5/desktop/src/oextract.cc0000644001161500056700000000775312242254476016670 0ustar cdfreycdfrey// // This is just experimentation code to figure out the config API in 0.4x // // Compile with: // g++ -Wall -o oextract oextract.cc $(pkg-config --cflags --libs libopensync1) // #include #include #include #include #include using namespace std; #define NP(x) (x ? x : "(null)") OSyncGroupEnv *genv; OSyncPluginEnv *penv; void get_advanced(OSyncPluginConfig *config, const char *name) { cout << "Advanced: " << name << ": " << NP(osync_plugin_config_get_advancedoption_value_by_name(config, name)) << endl; } void add_advanced(OSyncPluginConfig *config, const char *name, const char *display, const char *value) { OSyncError *ose = NULL; OSyncPluginAdvancedOption *option = osync_plugin_advancedoption_new(&ose); if( !option ) throw "bad option"; osync_plugin_advancedoption_set_displayname(option, "Test Display Name"); osync_plugin_advancedoption_set_name(option, "TestName"); osync_plugin_advancedoption_set_type(option, OSYNC_PLUGIN_ADVANCEDOPTION_TYPE_STRING); osync_plugin_advancedoption_set_value(option, "Whippoorwill"); osync_plugin_config_add_advancedoption(config, option); osync_plugin_advancedoption_unref(option); } void dump_resource(OSyncPluginResource *res) { cout << "Resource: " << NP(osync_plugin_resource_get_name(res)) << ": " << (osync_plugin_resource_is_enabled(res) ? "enabled" : "disabled"); if( osync_plugin_resource_get_preferred_format(res) ) cout << "\n pref format: " << osync_plugin_resource_get_preferred_format(res); if( osync_plugin_resource_get_mime(res) ) cout << "\n mime: " << NP(osync_plugin_resource_get_mime(res)); if( osync_plugin_resource_get_objtype(res) ) cout << "\n objtype: " << NP(osync_plugin_resource_get_objtype(res)); if( osync_plugin_resource_get_path(res) ) cout << "\n path: " << NP(osync_plugin_resource_get_path(res)); if( osync_plugin_resource_get_url(res) ) cout << "\n url: " << NP(osync_plugin_resource_get_url(res)); osync_plugin_resource_set_url(res, "http://whoopiecushion/"); cout << endl; } void dump_resources(OSyncPluginConfig *config) { OSyncList *resources = osync_plugin_config_get_resources(config); for( OSyncList *o = resources; o; o = o->next ) { OSyncPluginResource *res = (OSyncPluginResource*) o->data; dump_resource(res); } } void test_member(OSyncGroup *group, int member_id) { OSyncError *ose = NULL; cout << "Testing member: " << member_id << endl; OSyncMember *member = osync_group_find_member(group, member_id); if( !member ) throw "bad member id"; OSyncPlugin *plugin = osync_plugin_env_find_plugin(penv, osync_member_get_pluginname(member)); if( !plugin ) throw "bad plugin"; OSyncPluginConfig *config = osync_member_get_config_or_default(member, &ose); if( !config ) throw "bad config"; // extract advanced fields get_advanced(config, "PinCode"); get_advanced(config, "Debug"); // test add add_advanced(config, "TestName", "Test Display Name", "Whippoorwill"); get_advanced(config, "TestName"); // extract resources dump_resources(config); // save new config if( !osync_member_save(member, &ose) ) throw "bad member save"; // due to leak in library, I don't think this is safe to call? //osync_plugin_config_unref(config); } void test() { OSyncError *ose = NULL; // create genv = osync_group_env_new(&ose); if( !genv ) throw "bad genv"; penv = osync_plugin_env_new(&ose); if( !penv ) throw "bad penv"; // load if( !osync_group_env_load_groups(genv, NULL, &ose) ) throw "bad group load"; if( !osync_plugin_env_load(penv, NULL, &ose) ) throw "bad plugin load"; // find config OSyncGroup *group = osync_group_env_find_group(genv, "test"); if( !group ) throw "bad group"; test_member(group, 1); test_member(group, 2); // clean up osync_plugin_env_unref(penv); osync_group_env_unref(genv); } int main() { try { test(); } catch( const char *msg ) { cout << "Exception: " << msg << endl; return 1; } } barry-0.18.5/desktop/src/xmlcompactor.h0000644001161500056700000000401212242254476017372 0ustar cdfreycdfrey/// /// \file xmlcompactor.h /// Compact an XML file into a map of pretty xpaths and content /// /* Copyright (C) 2010-2013, Chris Frey 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __XMLCOMPACTOR_H__ #define __XMLCOMPACTOR_H__ #include #include #include class XmlCompactor : public std::map , public xmlpp::DomParser { public: typedef Glib::ustring string_type; typedef std::map base_map_type; typedef xmlpp::DomParser base_xml_type; typedef base_map_type::iterator iterator; typedef base_map_type::const_iterator const_iterator; typedef bool (XmlCompactor::*content_handler)(xmlpp::ContentNode*); typedef std::vector content_set; private: Glib::ustring m_skip_prefix; Glib::ustring m_common_prefix; protected: Glib::ustring HackPath(const Glib::ustring &path); bool WalkNodes(xmlpp::Node *node, content_handler handler); bool DoMap(xmlpp::ContentNode *content); bool ComparePrefix(xmlpp::ContentNode *content); public: XmlCompactor(); /// returns the common prefix of all entries, suitable for /// use as an argument to Map() Glib::ustring FindCommonPrefix(); void Map(const Glib::ustring &skip); Glib::ustring Value(const Glib::ustring &key); // // XML-based helpers // content_set Find(const Glib::ustring &xpath) const; void Dump(std::ostream &os) const; }; std::ostream& operator<<(std::ostream &os, XmlCompactor &parser); #endif barry-0.18.5/desktop/src/ContactPhotoWidget.cc0000644001161500056700000001362412242254476020602 0ustar cdfreycdfrey/// /// \file ContactPhotoWidget.cc /// Bitmap button that shows a Contact::Image photo /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "ContactPhotoWidget.h" #include "windowids.h" #include #include #include #include #include "wxi18n.h" using namespace std; #define MAX_IMAGE_HEIGHT 60 #define DEFAULT_IMAGE_WIDTH 50 ContactPhotoWidget::ContactPhotoWidget(wxWindow *parent, wxWindowID id, Barry::Contact &rec) : m_rec(rec) { // TRANSLATORS: this is the first part of a file selector string, // as in: "Images files (*.bmp;*.jpg;*.png)" // The file types are not part of the translation. m_file_filter = _W("Image files"); m_file_filter += _T(" (*.bmp;*.jpg;*.png;*.xmp;*.tif)|*.bmp;*.jpg;*.png;*.xmp;*.tif;*.tiff|"); // TRANSLATORS: this is a file selector string. See "Image files" // for more info. m_file_filter += _W("All files"); m_file_filter += _T(" (*.*)|*.*"); // limit size of image to 60 px height int max_height = MAX_IMAGE_HEIGHT, width = 0; if( m_rec.Image.size() ) { width = LoadRecImage(max_height); } // anything loaded? if not, load "empty" bitmap if( !m_bitmap.get() ) { width = DEFAULT_IMAGE_WIDTH; max_height = MAX_IMAGE_HEIGHT; m_bitmap.reset( new wxBitmap(width, max_height) ); DrawNoPhoto(*m_bitmap, width, max_height); } // have bitmap, create our bitmap button Create(parent, id, *m_bitmap, wxDefaultPosition, wxSize(width, max_height)); } int ContactPhotoWidget::LoadRecImage(int max_height) { // load m_rec.Image into a wxBitmap wxMemoryInputStream stream(m_rec.Image.data(), m_rec.Image.size()); wxImage jpeg(stream, wxBITMAP_TYPE_JPEG); float ratio = (float)max_height / jpeg.GetHeight(); int width = jpeg.GetWidth() * ratio; jpeg.Rescale(width, max_height, wxIMAGE_QUALITY_HIGH); m_bitmap.reset( new wxBitmap(jpeg) ); return width; } void ContactPhotoWidget::PromptAndSave(wxWindow *parent) { if( !m_rec.Image.size() ) { wxMessageBox(_W("There is no photo available to save."), _W("No Photo"), wxICON_INFORMATION | wxOK, this); return; } // TRANSLATORS: this is a file selector string. See "Image files" // for more info. wxString filter = _W("JPEG files"); filter += _T(" (*.jpg)|*.jpg"); wxFileDialog dlg(parent, _W("Save Photo as JPEG..."), _T(""), _T(""), filter, wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxFD_PREVIEW); if( dlg.ShowModal() == wxID_OK ) { ofstream ofs(dlg.GetPath().utf8_str(), ios::binary); ofs.write(m_rec.Image.data(), m_rec.Image.size()); } } /// Returns true if a new image has been loaded (may want to resize) bool ContactPhotoWidget::PromptAndLoad(wxWindow *parent) { wxFileDialog dlg(parent, _W("Load Photo..."), _T(""), _T(""), m_file_filter, wxFD_OPEN | wxFD_PREVIEW); if( dlg.ShowModal() != wxID_OK ) return false; // Load image in whatever format it's in wxImage image; if( !image.LoadFile(dlg.GetPath()) ) { wxMessageBox(_W("Unable to load selected photo."), _W("Photo Load Error"), wxICON_ERROR | wxOK, this); return false; } // Save image to memory as a JPEG wxMemoryOutputStream stream; if( !image.SaveFile(stream, wxBITMAP_TYPE_JPEG) ) { wxMessageBox(_W("Unable to convert image to JPEG."), _W("Photo Convert"), wxICON_ERROR | wxOK); return false; } // Store into Contact record const char *begin = (char*)stream.GetOutputStreamBuffer()->GetBufferStart(), *end = (char*)stream.GetOutputStreamBuffer()->GetBufferEnd(); int size = end - begin; m_rec.Image.assign(begin, size); // Update our button LoadRecImage(MAX_IMAGE_HEIGHT); SetBitmapLabel(*m_bitmap); SetSize(m_bitmap->GetWidth(), m_bitmap->GetHeight()); return true; } void ContactPhotoWidget::DeletePhoto() { // zap the record m_rec.Image.clear(); // replace with message wxSize client = GetClientSize(); int width = client.GetWidth(); int height = client.GetHeight(); m_bitmap.reset( new wxBitmap(width, height) ); DrawNoPhoto(*m_bitmap, width, height); SetBitmapLabel(*m_bitmap); } void ContactPhotoWidget::DrawNoPhoto(wxBitmap &bm, int width, int height) { wxMemoryDC dc; dc.SelectObject(bm); // resources wxColour textcolour(0xa9, 0xa5, 0xa2); wxColour background(0xed, 0xec, 0xeb); wxPen pen(background); wxBrush brush(background); wxString line1(_W("No")), line2(_W("Photo")); int pointsize =wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) .GetPointSize(); wxFont font(pointsize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); // trim fontsize so it fits wxSize line1_extent, line2_extent; do { font.SetPointSize(pointsize--); dc.SetFont(font); line1_extent = dc.GetTextExtent(line1); line2_extent = dc.GetTextExtent(line2); } while( line1_extent.GetWidth() > width || line2_extent.GetWidth() > width); // setup DC dc.SetPen(pen); dc.SetBrush(brush); dc.SetTextForeground(textcolour); dc.SetTextBackground(background); // calculate position int total_height = line1_extent.GetHeight() + line2_extent.GetHeight(); int y1_start = (height - total_height) / 2; int y2_start = y1_start + line1_extent.GetHeight(); int x1_start = (width - line1_extent.GetWidth()) / 2; int x2_start = (width - line2_extent.GetWidth()) / 2; // draw dc.DrawRectangle(0, 0, width, height); dc.DrawText(line1, x1_start, y1_start); dc.DrawText(line2, x2_start, y2_start); // cleanup dc.SetPen(wxNullPen); dc.SetBrush(wxNullBrush); } barry-0.18.5/desktop/src/os22.h0000644001161500056700000000510612242254476015454 0ustar cdfreycdfrey/// /// \file os22.h /// Wrapper class for opensync 0.22 syncing behaviour /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_OS22_H__ #define __BARRYDESKTOP_OS22_H__ #include "dlopen.h" #include "osbase.h" namespace OpenSync { class OpenSync22Private; class OpenSync22 : public DlOpen, public OpenSync::API { static bool symbols_loaded; OpenSync22Private *m_priv; protected: void SetupEnvironment(OpenSync22Private *p); public: OpenSync22(); ~OpenSync22(); static bool SymbolsLoaded() { return symbols_loaded; } // // Virtual API overrides // // Functional abilities information... this does not come from // the engine itself, but is information the osbase library // determines useful for applications to know bool IsSlowSyncSupported() const { return false; } // General engine information const char* GetVersion() const; const char* GetEngineName() const; void GetPluginNames(string_list_type &plugins); void GetFormats(format_list_type &formats); // Information about configured groups void GetGroupNames(string_list_type &groups); void GetMembers(const std::string &group_name, member_list_type &members); // Group configuration void AddGroup(const std::string &group_name); void DeleteGroup(const std::string &group_name); // Plugin configuration helper Converter& GetConverter(); // Member configuration long AddMember(const std::string &group_name, const std::string &plugin_name, const std::string &member_name); // DeleteMember() not possible to implement in 0.22 bool IsConfigurable(const std::string &group_name, long member_id); std::string GetConfiguration(const std::string &group_name, long member_id); void SetConfiguration(const std::string &group_name, long member_id, const std::string &config_data); void Discover(const std::string &group_name); // Syncing void Sync(const std::string &group_name, SyncStatus &status_callback, Config::pst_type sync_types/* = PST_DO_NOT_SET*/); }; } // namespace OpenSync #endif barry-0.18.5/desktop/src/MemoEditDlg.cc0000644001161500056700000000731712242254476017165 0ustar cdfreycdfrey/// /// \file MemoEditDlg.cc /// Dialog class to handle the editing of the Memo record /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "MemoEditDlg.h" #include "windowids.h" #include "wxi18n.h" // begin wxGlade: ::extracode // end wxGlade ////////////////////////////////////////////////////////////////////////////// // MemoEditDlg class MemoEditDlg::MemoEditDlg(wxWindow* parent, Barry::Memo &rec, bool editable) : wxDialog(parent, Dialog_MemoEdit, _W("Memo Record")) , m_rec(rec) { m_rec.Categories.CategoryList2Str(m_category_list); if( editable ) { bottom_buttons = CreateButtonSizer(wxOK | wxCANCEL); } else { bottom_buttons = CreateButtonSizer(wxCANCEL); } // begin wxGlade: MemoEditDlg::MemoEditDlg label_1 = new wxStaticText(this, wxID_ANY, _W("Title:")); text_ctrl_2 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_2 = new wxStaticText(this, wxID_ANY, _W("Categories:")); text_ctrl_3 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); text_ctrl_1 = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); set_properties(); do_layout(); // end wxGlade } void MemoEditDlg::set_properties() { // begin wxGlade: MemoEditDlg::set_properties SetTitle(_W("Memo")); text_ctrl_2->SetMinSize(wxSize(300, -1)); text_ctrl_2->SetFocus(); text_ctrl_2->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Title))); label_2->SetToolTip(_W("Comma separated")); text_ctrl_3->SetMinSize(wxSize(300, -1)); text_ctrl_3->SetToolTip(_W("Comma separated list of categories (can be empty)")); text_ctrl_3->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_category_list))); text_ctrl_1->SetMinSize(wxSize(-1, 240)); text_ctrl_1->SetToolTip(_W("Body of memo")); text_ctrl_1->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Body))); // end wxGlade } void MemoEditDlg::do_layout() { // begin wxGlade: MemoEditDlg::do_layout wxBoxSizer* sizer_1 = new wxBoxSizer(wxVERTICAL); wxFlexGridSizer* grid_sizer_1 = new wxFlexGridSizer(2, 2, 10, 5); grid_sizer_1->Add(label_1, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1->Add(text_ctrl_2, 1, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1->Add(label_2, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1->Add(text_ctrl_3, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0); sizer_1->Add(grid_sizer_1, 0, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 10); sizer_1->Add(text_ctrl_1, 2, wxALL|wxEXPAND, 10); // end wxGlade sizer_1->Add(bottom_buttons, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 10); // NOTE: watch that wxGlade doesn't add these again above, if // you regenerate the code... we need this here, so that we // can add the button spacer. SetSizer(sizer_1); sizer_1->Fit(this); Layout(); } bool MemoEditDlg::TransferDataFromWindow() { if( !wxDialog::TransferDataFromWindow() ) return false; m_strings.Sync(); m_rec.Categories.CategoryStr2List(m_category_list); // make sure that the title contains something if( !m_rec.Title.size() ) { wxMessageBox(_W("Please enter a title for your memo."), _W("Required Fields"), wxOK | wxICON_INFORMATION, this); return false; } return true; } barry-0.18.5/desktop/src/EvoCfgDlg.cc0000644001161500056700000001411312242254476016623 0ustar cdfreycdfrey/// /// \file EvoCfgDlg.cc /// The configuration dialog used to configure Evolution sources /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "EvoCfgDlg.h" #include "osconfig.h" #include "windowids.h" #include "wxi18n.h" using namespace std; EvoCfgDlg::EvoCfgDlg(wxWindow *parent, const OpenSync::Config::Evolution &ec, const EvoSources &es) : wxDialog(parent, Dialog_EvoCfg, _W("Evolution Plugin Configuration")) , m_address_path(ec.GetAddressPath()) , m_calendar_path(ec.GetCalendarPath()) , m_tasks_path(ec.GetTasksPath()) , m_memos_path(ec.GetMemosPath()) , m_empty_config(ec.GetAddressPath().empty() && ec.GetCalendarPath().empty() && ec.GetTasksPath().empty() && ec.GetMemosPath().empty()) , m_sources(es) { CreateLayout(); } void EvoCfgDlg::CreateLayout() { m_topsizer = new wxBoxSizer(wxVERTICAL); m_topsizer->Add( new wxStaticText(this, wxID_ANY, _W("Address Book:")), 0, wxALIGN_LEFT | wxTOP | wxLEFT | wxRIGHT, 10); AddCombo(&m_address_combo, wxID_ANY, m_address_path, m_sources.GetAddressBook()); m_topsizer->Add(m_address_combo, 0, wxEXPAND | wxLEFT | wxRIGHT, 10); m_topsizer->Add( new wxStaticText(this, wxID_ANY, _W("Calendar:")), 0, wxALIGN_LEFT | wxTOP | wxLEFT | wxRIGHT, 10); AddCombo(&m_calendar_combo, wxID_ANY, m_calendar_path, m_sources.GetEvents()); m_topsizer->Add(m_calendar_combo, 0, wxEXPAND | wxLEFT | wxRIGHT, 10); m_topsizer->Add( new wxStaticText(this, wxID_ANY, _W("Tasks:")), 0, wxALIGN_LEFT | wxTOP | wxLEFT | wxRIGHT, 10); AddCombo(&m_tasks_combo, wxID_ANY, m_tasks_path, m_sources.GetTasks()); m_topsizer->Add(m_tasks_combo, 0, wxEXPAND | wxLEFT | wxRIGHT, 10); m_topsizer->Add( new wxStaticText(this, wxID_ANY, _W("Memos:")), 0, wxALIGN_LEFT | wxTOP | wxLEFT | wxRIGHT, 10); AddCombo(&m_memos_combo, wxID_ANY, m_memos_path, m_sources.GetMemos()); m_topsizer->Add(m_memos_combo, 0, wxEXPAND | wxLEFT | wxRIGHT, 10); wxSizer *button = CreateSeparatedButtonSizer(wxOK | wxCANCEL); m_topsizer->Add(button, 0, wxALL | wxEXPAND | wxALIGN_RIGHT, 10); SetSizer(m_topsizer); m_topsizer->SetSizeHints(this); m_topsizer->Layout(); } void EvoCfgDlg::AddCombo(wxComboBox **combo, int id, const std::string ¤t_path, const EvoSources::List &list) { // // Note: the evolution opensync plugins allow "default" as a // configuration string, to chose to connect to the default // Evolution address book or calendar. This is not detected // by the EvoSources detection, since this is a special property // of the opensync plugin. // // So we handle the "default" strings specially below. // // is the current path in the list? bool in_list = false; for( EvoSources::List::const_iterator i = list.begin(); current_path.size() && i != list.end(); ++i ) { if( i->m_SourcePath == current_path ) { in_list = true; break; } } // // create an array of choices // wxArrayString choices; // add current_path as first in list if it is not already there if( current_path.size() && !in_list && current_path != "default" ) { choices.Add(wxString(current_path.c_str(), wxConvUTF8)); } // add the evolution special "default" option before the sources // list, since it's probably what the user wants choices.Add(_T("default")); // add the sources list for( EvoSources::List::const_iterator i = list.begin(); i!=list.end(); ++i ) { if( i->m_SourcePath.size() ) { choices.Add(wxString(i->m_SourcePath.c_str(), wxConvUTF8)); } } // default choice... if we have an empty config, this is the first // time the user is running this dialog, so use the first option // in the combo box as the default. // // if not an empty config, then show what the user currently // has in the config, even if it is empty wxString default_value; if( m_empty_config && choices.GetCount() ) { // first run, use first item default_value = choices[0]; } else { // show user's current config default_value = wxString(current_path.c_str(), wxConvUTF8); } // create the combo box *combo = new wxComboBox(this, id, default_value, wxDefaultPosition, wxDefaultSize, // wxSize(250, -1), //wxDefaultSize, choices, wxCB_DROPDOWN); } void EvoCfgDlg::SetPaths(OpenSync::Config::Evolution &ec) const { ec.SetAddressPath(m_address_path); ec.SetCalendarPath(m_calendar_path); ec.SetTasksPath(m_tasks_path); ec.SetMemosPath(m_memos_path); } wxString EvoCfgDlg::CheckPath(const wxString &name, const std::string &path) const { if( path.size() > 7 && path.substr(0, 7) == "file://" ) { std::string p = path.substr(7); if( !EvoSources::PathExists(p) ) { wxString msg = wxString::Format(_W("File '%s' does not exist."), name.c_str()); return msg; } } return _T(""); } wxString EvoCfgDlg::ValidatePaths() const { if( m_address_path.empty() && m_calendar_path.empty() && m_tasks_path.empty() && m_memos_path.empty() ) return _W("No paths set! If there are no default options available in the drop down lists, please double check that you've initialized your Evolution account first."); return _T(""); } bool EvoCfgDlg::TransferDataFromWindow() { m_address_path = string(m_address_combo->GetValue().utf8_str()); m_calendar_path = string(m_calendar_combo->GetValue().utf8_str()); m_tasks_path = string(m_tasks_combo->GetValue().utf8_str()); m_memos_path = string(m_memos_combo->GetValue().utf8_str()); wxString msg = ValidatePaths(); if( msg.size() ) { wxMessageBox(msg, _W("Minimum Config Required"), wxOK | wxICON_ERROR, this); return false; } return true; } int EvoCfgDlg::ShowModal() { return wxDialog::ShowModal(); } barry-0.18.5/desktop/src/xmlcompactor.cc0000644001161500056700000001206312242254476017535 0ustar cdfreycdfrey/// /// \file xmlcompactor.cc /// Compact an XML file into a map of pretty xpaths and content /// /* Copyright (C) 2010-2013, Chris Frey 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 in the COPYING file at the root directory of this project for more details. */ #include "xmlcompactor.h" #include #include #include using namespace std; std::ostream& operator<<(std::ostream &os, XmlCompactor &parser) { parser.Dump(os); return os; } XmlCompactor::XmlCompactor() { } // ugly hack to pretty up the output Glib::ustring XmlCompactor::HackPath(const Glib::ustring &path) { const char *bad[] = { "[0]", "[1]", "[2]", "[3]", "[4]", "[5]", "[6]", "[7]", "[8]", "[9]" }; const char *good[] = { "[00]", "[01]", "[02]", "[03]", "[04]", "[05]", "[06]", "[07]", "[08]", "[09]" }; Glib::ustring p = path; // strip off the ending "text()" size_t pos = p.rfind("/text()"); if( pos != Glib::ustring::npos && (pos + 7) == p.size() ) p.resize(pos); // remove leading name if possible if( m_skip_prefix.size() && p.find(m_skip_prefix) == 0 ) p.replace(0, m_skip_prefix.size(), ""); // remove leading slash if( p[0] == '/' ) p.replace(0, 1, ""); // convert single digit offsets to two for( int i = 0; i < 10; i++ ) { size_t pos; while( (pos = p.find(bad[i])) != Glib::ustring::npos ) { p.replace(pos, 3, good[i]); } } return p; } bool XmlCompactor::WalkNodes(xmlpp::Node *node, content_handler handler) { xmlpp::ContentNode *content = dynamic_cast(node); if( content ) { if( content->is_white_space() ) return true; // skip whitespace between content if( !(this->*handler)(content) ) return false; // handler had a problem,stop processing } xmlpp::Node::NodeList list = node->get_children(); xmlpp::Node::NodeList::iterator i = list.begin(); for( ; i != list.end(); ++i ) { if( !WalkNodes(*i, handler) ) return false; // pass the "stop processing" msg down } return true; } bool XmlCompactor::DoMap(xmlpp::ContentNode *content) { (*this)[HackPath(content->get_path())] = content->get_content(); return true; } bool XmlCompactor::ComparePrefix(xmlpp::ContentNode *content) { Glib::ustring path = content->get_path(); if( m_common_prefix.size() == 0 ) { m_common_prefix = path; } else { // find max length of matching strings size_t len = min(m_common_prefix.size(), path.size()); size_t max = 0; while( len-- ) { if( m_common_prefix[max] != path[max] ) break; max++; } if( max == 0 ) { // there's no prefix available m_common_prefix.clear(); return false; } else { // snag the largest prefix! m_common_prefix = m_common_prefix.substr(0, max); } } return true; } Glib::ustring XmlCompactor::FindCommonPrefix() { m_common_prefix.clear(); xmlpp::Node *root = get_document()->get_root_node(); WalkNodes(root, &XmlCompactor::ComparePrefix); return m_common_prefix; } void XmlCompactor::Map(const Glib::ustring &skip) { m_skip_prefix = skip; xmlpp::Node *root = get_document()->get_root_node(); WalkNodes(root, &XmlCompactor::DoMap); } Glib::ustring XmlCompactor::Value(const Glib::ustring &key) { iterator i = find(key); if( i == end() ) return ""; return i->second; } XmlCompactor::content_set XmlCompactor::Find(const Glib::ustring &xpath) const { using namespace xmlpp; content_set content; Node *root = get_document()->get_root_node(); NodeSet nodes = root->find(xpath); NodeSet::iterator ni = nodes.begin(); for( ; ni != nodes.end(); ++ni ) { ContentNode *cn = dynamic_cast (*ni); if( cn && !cn->is_white_space() ) { content.push_back(cn->get_content()); } } return content; } void XmlCompactor::Dump(std::ostream &os) const { for( const_iterator i = begin(); i != end(); ++i ) { os << i->first.raw() << ": " << i->second.raw() << "\n"; } } #ifdef XMLCOMPACTOR int main(int argc, char *argv[]) { try { locale loc(""); cin.imbue( loc ); cout.imbue( loc ); XmlCompactor parser; parser.parse_stream(cin); cerr << "Common prefix: " << parser.FindCommonPrefix() << endl; parser.Map(argc >= 2 ? argv[1] : ""); cout << parser << endl; cout << endl; for( int i = 2; i < argc; i++ ) { XmlCompactor::content_set content = parser.Find(argv[i]); cout << "XPath: " << argv[i] << endl; cout << "Found " << content.size() << " values" << endl; XmlCompactor::content_set::iterator ci = content.begin(); for( ; ci != content.end(); ++ci ) { cout << " " << (*ci) << endl; } } } catch( Glib::ConvertError &e ) { cerr << e.what() << endl; return 1; } catch( std::exception &e ) { cerr << e.what() << endl; return 1; } } #endif barry-0.18.5/desktop/src/dlopen.cc0000644001161500056700000000272412242254476016311 0ustar cdfreycdfrey/// /// \file dlopen.cc /// Base class wrapper for dlopen() behaviour /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "dlopen.h" #include #include #include #include #include using namespace std; ///////////////////////////////////////////////////////////////////////////// // DlOpen class -- protected members bool DlOpen::Open(const char *libname) { Shutdown(); m_handle = dlopen(libname, RTLD_NOW | RTLD_LOCAL); return m_handle != NULL; } void DlOpen::Shutdown() { if( m_handle ) { if( dlclose(m_handle) != 0 ) { cout << "ERROR: dlclose() return non-zero" << endl; cout << dlerror() << endl; } m_handle = 0; } } ///////////////////////////////////////////////////////////////////////////// // DlOpen class -- public members DlOpen::DlOpen() : m_handle(0) { } DlOpen::~DlOpen() { Shutdown(); } barry-0.18.5/desktop/src/MimeExportDlg.cc0000644001161500056700000000470612242254476017552 0ustar cdfreycdfrey/// /// \file MimeExportDlg.cc /// Dialog class to handle viewing/exporting of MIME card data /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "MimeExportDlg.h" #include "windowids.h" #include #include #include "wxi18n.h" using namespace std; ////////////////////////////////////////////////////////////////////////////// // MimeExportDlg class BEGIN_EVENT_TABLE(MimeExportDlg, wxDialog) EVT_BUTTON (Dialog_MimeExport_SaveButton, MimeExportDlg::OnSaveButton) END_EVENT_TABLE() MimeExportDlg::MimeExportDlg(wxWindow* parent, const std::string &vdata, const std::string &file_types) : wxDialog(parent, Dialog_MimeExport, _W("MIME Card Data")) , m_vdata(vdata) , m_file_types(file_types) { bottom_buttons = CreateButtonSizer(wxOK); text_ctrl_1 = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); save_button = new wxButton(this, Dialog_MimeExport_SaveButton, _W("Save...")); set_properties(); do_layout(); } void MimeExportDlg::set_properties() { text_ctrl_1->SetMinSize(wxSize(400, 240)); text_ctrl_1->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_vdata))); } void MimeExportDlg::do_layout() { wxBoxSizer* sizer_1 = new wxBoxSizer(wxVERTICAL); sizer_1->Add(text_ctrl_1, 2, wxALL|wxEXPAND, 10); bottom_buttons->Insert(0, save_button, 0, wxRIGHT, 5); sizer_1->Add(bottom_buttons, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 10); SetSizer(sizer_1); sizer_1->Fit(this); Layout(); } void MimeExportDlg::OnSaveButton(wxCommandEvent &event) { wxString ftypes(m_file_types.c_str(), wxConvUTF8); wxFileDialog dlg(this, _W("Save Card as..."), _T(""), _T(""), ftypes, wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxFD_PREVIEW); if( dlg.ShowModal() == wxID_OK ) { ofstream ofs(dlg.GetPath().utf8_str(), ios::binary); ofs.write(m_vdata.data(), m_vdata.size()); ofs.close(); } } barry-0.18.5/desktop/src/Mode_Browse.h0000644001161500056700000003117612242254476017102 0ustar cdfreycdfrey/// /// \file Mode_Browse.h /// Mode derived class for database browsing /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_MODE_BROWSE_H__ #define __BARRYDESKTOP_MODE_BROWSE_H__ #include "Mode.h" #include "util.h" #include #include #include #include #include #include "wxi18n.h" class GUIDesktopConnector : public Barry::DesktopConnector { wxWindow *m_parent; public: GUIDesktopConnector(wxWindow *parent, const char *password, const std::string &locale, const Barry::ProbeResult &result) : Barry::DesktopConnector(password, locale, result) , m_parent(parent) { } virtual bool PasswordPrompt(const Barry::BadPassword &bp, std::string &password_result); }; // Holds the "right" to use the desktop, and this right expires with the // scope of this class, and no other code can use it while this object exists. // // Is copied around by the below auto_ptr<> typedef. class DesktopInstance { private: Barry::scoped_lock m_lock; // external interfaces... owned by caller GUIDesktopConnector &m_gdc; public: explicit DesktopInstance(pthread_mutex_t &mutex, GUIDesktopConnector &gdc) : m_lock(mutex) , m_gdc(gdc) { } GUIDesktopConnector& Connector() { return m_gdc; } Barry::Mode::Desktop& Desktop() { return m_gdc.GetDesktop(); } Barry::IConverter& IC() { return m_gdc.GetIConverter(); } }; typedef std::auto_ptr DesktopInstancePtr; // // ThreadableDesktop // /// Protection class that holds the GUIDesktopConnector (i.e. the main /// desktop instance) and a mutex. To access the desktop object, call /// Get(), which locks access for the caller and returns the /// DesktopInstancePtr smart pointer. The lock is released when /// the DesktopInstancePtr goes out of scope. /// class ThreadableDesktop { private: pthread_mutex_t m_mutex; // external interfaces... owned by caller GUIDesktopConnector &m_gdc; public: explicit ThreadableDesktop(GUIDesktopConnector &gdc) : m_gdc(gdc) { if( pthread_mutex_init(&m_mutex, NULL) ) { throw Barry::Error(_C("Failed to create mutex for ThreadableDesktop")); } } DesktopInstancePtr Get() { return DesktopInstancePtr( new DesktopInstance(m_mutex, m_gdc)); } }; // // DataCache // /// Abstract base class representing a single cached record in a database. /// Does not actually contain the record data (base classes hold that), but /// defines what can be done with such a record cache object. (eg. such as /// editing the record) /// class DataCache { public: typedef Barry::RecordStateTable::IndexType IndexType; private: IndexType m_state_index; uint32_t m_record_id; public: DataCache(IndexType state_index, uint32_t record_id) : m_state_index(state_index) , m_record_id(record_id) { } virtual ~DataCache() {} virtual IndexType GetStateIndex() const { return m_state_index; } virtual uint32_t GetRecordId() const { return m_record_id; } virtual void SetIds(IndexType state_index, uint32_t record_id) { std::cout << "DataCache::SetIds(" << state_index << ", " << record_id << ");" << std::endl; m_state_index = state_index; m_record_id = record_id; } // set editable to false if you just want to view record // non-buildable records will always be non-editable regardless virtual bool Edit(wxWindow *parent, bool editable, const Barry::TimeZones &zones) = 0; virtual bool Card(wxWindow *parent, std::string &vdata) {return false;} virtual std::string GetDescription() const = 0; virtual bool IsBuildable() const { return false; } bool operator< (const DataCache &other) { return GetDescription() < other.GetDescription(); } }; // // DataCachePtr // /// Basically a shared_ptr, but with the added operator<() /// overload so that it calls DataCache's operator<(), for sorting /// of objects via this pointer. /// class DataCachePtr : public std::tr1::shared_ptr { public: DataCachePtr() { } explicit DataCachePtr(DataCache *obj) : std::tr1::shared_ptr(obj) { } bool operator< (const DataCachePtr &other) { return (*this)->operator<( *other ); } }; // // DBDataCache // /// Derived class from DataCache that holds the raw data of a record that /// does not yet have a parser. Unable to do much with such records in /// terms of editing, but still able to be cached in the DBMap. /// class DBDataCache : public DataCache { Barry::DBData m_raw; public: DBDataCache(DataCache::IndexType index, const Barry::DBData &raw); virtual bool Edit(wxWindow *parent, bool editable, const Barry::TimeZones &zones); virtual std::string GetDescription() const; }; // returns true if GUI indicates change (i.e. if dialogreturns wxID_OK) #undef HANDLE_PARSER #define HANDLE_PARSER(dbname) \ bool EditRecord(wxWindow *parent, bool editable, \ const Barry::TimeZones &zones, Barry::dbname &rec); ALL_KNOWN_PARSER_TYPES // // RecordCache<> // /// Template class derived from DataCache which holds the parsed record data /// for the templated record type. Allows actions such as editing. /// template class RecordCache : public DataCache , public Barry::Builder { private: RecordT m_rec; public: RecordCache(DataCache::IndexType index, const RecordT &rec) : DataCache(index, rec.GetUniqueId()) , m_rec(rec) { // if copying from another record, don't copy what // we don't understand m_rec.Unknowns.clear(); } const RecordT& GetRecord() const { return m_rec; } // hook SetIds() to grab any new record_ids / UniqueIDs virtual void SetIds(IndexType state_index, uint32_t record_id) { std::cout << "RecordCache::SetIds(" << state_index << ", " << record_id << ");" << std::endl; DataCache::SetIds(state_index, record_id); m_rec.SetIds(RecordT::GetDefaultRecType(), record_id); } virtual bool Edit(wxWindow *parent, bool editable, const Barry::TimeZones &zones) { RecordT copy = m_rec; bool changed = EditRecord(parent, editable, zones, copy); // FIXME - we could, at this point, add a (copy != m_rec) // check here, to prevent writing a record that has not // changed, but that would require using the FieldHandle<> // system (a lot of code), and it's not a critical feature // right now if( changed && editable ) { m_rec = copy; return true; } return false; } virtual bool Card(wxWindow *parent, std::string &vdata) { if( !Barry::MimeDump::Supported() ) return false; std::ostringstream oss; Barry::MimeDump::Dump(oss, m_rec); vdata = oss.str(); return true; } virtual std::string GetDescription() const { return m_rec.GetDescription(); } virtual bool IsBuildable() const { return ::IsBuildable(); } // // Barry::Builder overrides // virtual bool BuildRecord(Barry::DBData &data, size_t &offset, const Barry::IConverter *ic) { Barry::SetDBData(m_rec, data, offset, ic); return true; } virtual bool FetchRecord(Barry::DBData &data, const Barry::IConverter *ic) { size_t offset = 0; Barry::SetDBData(m_rec, data, offset, ic); return true; } virtual bool EndOfFile() const { return true; } }; // // DBCache // /// This is a container class that holds a std::list of DataCache-derived /// objects for all the records of a single database. /// class DBCache : public Barry::AllRecordStore, public Barry::Parser { public: typedef Barry::RecordStateTable::IndexType IndexType; typedef std::list DataList; typedef DataList::iterator iterator; typedef DataList::const_iterator const_iterator; private: ThreadableDesktop &m_tdesktop; std::string m_dbname; unsigned int m_dbid; Barry::RecordStateTable m_state; DataList m_records; // per-record load state IndexType m_index; protected: // helper functions, to work around Tasks bug in device bool OverwriteRecord(wxWindow *parent, iterator record); bool DeleteAndAddRecord(wxWindow *parent, iterator record); public: // loads records in constructor DBCache(ThreadableDesktop &tdesktop, const std::string &dbname); virtual ~DBCache(); const std::string& GetDBName() { return m_dbname; } iterator Get(int list_offset); const_iterator Get(int list_offset) const; // returns the numeric index of the record, to keep with GUI int GetIndex(iterator record) const; int GetIndex(const_iterator record) const; iterator Add(wxWindow *parent, DataCachePtr p); // adds to device too, // just like Add() below iterator Add(wxWindow *parent, const Barry::TimeZones &zones, iterator copy_record); bool Edit(wxWindow *parent, const Barry::TimeZones &zones, iterator record); bool Delete(wxWindow *parent, iterator record); iterator begin() { return m_records.begin(); } iterator end() { return m_records.end(); } const_iterator begin() const { return m_records.begin(); } const_iterator end() const { return m_records.end(); } // For Barry::AllRecordStore #undef HANDLE_PARSER #define HANDLE_PARSER(tname) \ virtual void operator() (const Barry::tname &); ALL_KNOWN_PARSER_TYPES // For Barry::Parser virtual void ParseRecord(const Barry::DBData &data, const Barry::IConverter *ic); }; // // DBMap // /// A std::map based container that maps database names with their /// corresponding DBCaches. /// class DBMap { public: typedef std::tr1::shared_ptr DBCachePtr; typedef std::map MapType; private: ThreadableDesktop &m_tdesktop; MapType m_map; pthread_mutex_t m_map_mutex; pthread_mutex_t m_load_mutex; public: DBMap(ThreadableDesktop &tdesktop); DBCachePtr LoadDBCache(const std::string &dbname); DBCachePtr GetDBCache(const std::string &dbname); }; // // BrowseMode // /// The Desktop GUI mode class for browsing databases and manipulating records. /// class BrowseMode : public wxEvtHandler, public Mode { private: DECLARE_EVENT_TABLE() // sets to protected: private: wxWindow *m_parent; // device interface std::auto_ptr m_con; std::auto_ptr m_tdesktop; std::auto_ptr m_dbmap; Barry::DatabaseDatabase m_dbdb; std::auto_ptr m_zones; // window controls std::auto_ptr m_top_sizer; std::auto_ptr m_dbdb_list; std::auto_ptr m_record_list; std::auto_ptr m_show_all_checkbox; std::auto_ptr m_import_record_button; std::auto_ptr m_export_record_button; std::auto_ptr m_add_record_button; std::auto_ptr m_copy_record_button; std::auto_ptr m_edit_record_button; std::auto_ptr m_delete_record_button; std::auto_ptr m_load_status_text; // misc supporting data wxString m_device_id_str; // GUI state bool m_buildable; // true if currently displayed db has // a Builder available for it bool m_editable; // true if currently displayed db has // an edit dialog available for it bool m_cardable; // true if currently displayed db is // capable of MIME style import/exports bool m_show_all; // if true, show all databases in list // instead of just the parsable ones std::string m_current_dbname; long m_current_record_item; // thread state pthread_t m_cache_thread; volatile bool m_abort_flag; protected: void CreateControls(); int GUItoDBDBIndex(int gui_index); void FillDBDBList(); void FillRecordList(const std::string &dbname); void UpdateButtons(); void FillCache(); // background thread function static void* FillCacheThread(void *bobj); public: BrowseMode(wxWindow *parent, const Barry::ProbeResult &device); ~BrowseMode(); void SendStatusEvent(const std::string &dbname); // virtual override events (derived from Mode) wxString GetTitleText() const { return _W("Barry Database Browser"); } // window events void OnDBDBListSelChange(wxListEvent &event); void OnRecordListSelChange(wxListEvent &event); void OnRecordListActivated(wxListEvent &event); void OnShowAll(wxCommandEvent &event); void OnImportRecord(wxCommandEvent &event); void OnExportRecord(wxCommandEvent &event); void OnAddRecord(wxCommandEvent &event); void OnCopyRecord(wxCommandEvent &event); void OnEditRecord(wxCommandEvent &event); void OnDeleteRecord(wxCommandEvent &event); void OnStatusEvent(wxCommandEvent &event); }; #endif barry-0.18.5/desktop/src/StringSync.cc0000644001161500056700000000440312242254476017127 0ustar cdfreycdfrey/// /// \file StringSync.h /// Class to easily manage the wxString / std::string boundary /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "StringSync.h" using namespace std; ////////////////////////////////////////////////////////////////////////////// // StringSync StringSync::~StringSync() { // do not Sync() here, since, if this object is part of another // class, then external strings may have already been // freed, depending on the order of objects defined in that class } wxString* StringSync::Add(std::string &source) { m_wx.push_front(WxIsCopyType(wxString(source.c_str(), wxConvUTF8), &source)); return &m_wx.begin()->first; } std::string* StringSync::Add(wxString &source) { m_std.push_front(StdIsCopyType(std::string(source.utf8_str()), &source)); return &m_std.begin()->first; } void StringSync::SyncToStd() { WxIsCopyList::iterator b = m_wx.begin(); for( ; b != m_wx.end(); ++b ) { b->second->assign(b->first.utf8_str()); } } void StringSync::SyncToWx() { StdIsCopyList::iterator b = m_std.begin(); for( ; b != m_std.end(); ++b ) { *b->second = wxString(b->first.c_str(), wxConvUTF8); } } void StringSync::Sync() { // call order doesn't matter, since lists are independent SyncToStd(); SyncToWx(); } void StringSync::RefreshWx() { WxIsCopyList::iterator b = m_wx.begin(); for( ; b != m_wx.end(); ++b ) { b->first = wxString(b->second->c_str(), wxConvUTF8); } } void StringSync::RefreshStd() { StdIsCopyList::iterator b = m_std.begin(); for( ; b != m_std.end(); ++b ) { b->first.assign(b->second->utf8_str()); } } void StringSync::Refresh() { // call order doesn't matter, since lists are independent RefreshWx(); RefreshStd(); } barry-0.18.5/desktop/src/dlopen.h0000644001161500056700000000330612242254476016150 0ustar cdfreycdfrey/// /// \file dlopen.h /// Base class wrapper for dlopen() behaviour /// Drawback: only one dlopen'd library per class. /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_DLOPEN_H__ #define __BARRYDESKTOP_DLOPEN_H__ #include "error.h" #include #include #include // // DlOpen // /// Base class wrapper for dlopen() libraries. Only handles one /// library handle at a time. /// class DlOpen { void *m_handle; protected: bool Open(const char *libname); void Shutdown(); template void LoadSym(FuncPtrT &funcptr, const char *symbol) { // work around the warning: ISO C++ forbids casting // between pointer-to-function and pointer-to-object //funcptr = (FuncPtrT) dlsym(this->m_handle, symbol); void *fptr = dlsym(this->m_handle, symbol); if( fptr == NULL ) throw DlError(std::string("Can't load ") + symbol); if( sizeof(fptr) != sizeof(FuncPtrT) ) throw std::logic_error("Platform not supported: sizeof(void*) != sizeof(void (*)())"); memcpy(&funcptr, &fptr, sizeof(void*)); } public: DlOpen(); virtual ~DlOpen(); }; #endif barry-0.18.5/desktop/src/guitimet.h0000644001161500056700000000205412242254476016515 0ustar cdfreycdfrey/// /// \file guitimet.h /// Object to hold the date/time data of a set of GUI controls /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_GUITIMET_H__ #define __BARRYDESKTOP_GUITIMET_H__ class GUITimeT { public: wxDateTime m_date; int m_hour; int m_min; public: GUITimeT() : m_hour(0) , m_min(0) { } explicit GUITimeT(time_t t) : m_hour(0) , m_min(0) { Set(t); } void Set(time_t t); time_t Get() const; }; #endif barry-0.18.5/desktop/src/xmlmap.h0000644001161500056700000001167412242254476016174 0ustar cdfreycdfrey/// /// \file xmlmap.h /// Map an XML node tree according to an XML map file. /// The map is not fully nested, and provides mostly a /// flat view, based on the map. /// /* Copyright (C) 2010-2013, Chris Frey 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __XMLMAP_H__ #define __XMLMAP_H__ #include #include #include #include #include class XmlNodeMapping; class XmlNodeSummary { xmlpp::Node *m_node; XmlNodeMapping *m_mapping; Glib::ustring m_name; Glib::ustring m_summary; protected: void CreateSummary(); void ProcessListKey(std::ostream &os, const Glib::ustring &name); void ProcessKey(std::ostream &os, const Glib::ustring &key); public: XmlNodeSummary(xmlpp::Node *node, XmlNodeMapping *mapping); Glib::ustring Path() const { return m_node ? m_node->get_path(): Glib::ustring(); } const Glib::ustring& Name() const { return m_name; } const Glib::ustring& Summary() const { return m_summary; } Glib::ustring GetContent(const Glib::ustring &child_name) const; Glib::ustring GetContent(xmlpp::Node *node) const; static bool SummaryCompare(const XmlNodeSummary &a, const XmlNodeSummary &b); static bool PathCompare(const XmlNodeSummary &a, const XmlNodeSummary &b); }; class XmlNodeMapping { public: typedef std::vector compare_list; typedef std::vector summary_list; private: Glib::ustring m_node_key_name; // "/contact/Address" excluding any // [1] and [2] offsets // This is is from the friendly map // definition file. int m_priority; Glib::ustring m_format; compare_list m_compare_node_names; summary_list m_summaries; protected: static void SplitCompareName(const Glib::ustring &compare_name, Glib::ustring &name, Glib::ustring &type); public: XmlNodeMapping(const Glib::ustring &node_name, int priority, const Glib::ustring &format); // data access const Glib::ustring& KeyName() const { return m_node_key_name; } Glib::ustring ShortName() const { return size() ? m_summaries[0].Name() : Glib::ustring(); } int Priority() const { return m_priority; } const Glib::ustring& Format() const { return m_format; } bool IsEmpty() const { return size() == 0; } // operations void AddCompareName(const Glib::ustring &node_name); void AddNode(xmlpp::Node *node); void SortBySummary(); void SortByPath(); const XmlNodeSummary& operator[] (int index) const; size_t size() const { return m_summaries.size(); } void clear() { m_summaries.clear(); } bool operator== (const XmlNodeMapping &other) const; bool operator!= (const XmlNodeMapping &other) const { return !operator==(other); } void Dump(std::ostream &os) const; void DumpSummaries(std::ostream &os) const; }; class XmlNodeMap : public std::vector > { // we use a vector of shared_ptr's here because the Summary // objects store pointers to the Mappings, and must remain stable public: typedef std::tr1::shared_ptr ptr_type; typedef std::vector base_type; // helps to hide the shared_ptr complexity when the // user iterates through the vector template class deref_iterator : public BaseT { public: explicit deref_iterator(BaseT it) : BaseT(it) {} TargetT& operator*() const { return *BaseT::operator*(); } TargetT* operator->() const { return &(*BaseT::operator*()); } }; typedef deref_iterator iterator; typedef deref_iterator const_iterator; private: void LoadMap(const std::string &type_name, const std::string &map_filename); public: XmlNodeMap(const std::string &type_name, const std::string &map_filename); XmlNodeMap(const std::string &map_filename); XmlNodeMap(const XmlNodeMap &other); void ImportNodes(xmlpp::Node *node, bool purge = false); void PurgeEmpties(); XmlNodeMapping* Find(const Glib::ustring &node_name); void SortBySummary(); void SortByPath(); void Dump(std::ostream &os, int stop_priority = 1) const; iterator begin() { return iterator(base_type::begin()); } iterator end() { return iterator(base_type::end()); } const_iterator begin() const { return const_iterator(base_type::begin()); } const_iterator end() const { return const_iterator(base_type::end()); } iterator priority_end(int stop_priority = 1); void clear(); XmlNodeMap& operator=(const XmlNodeMap &other); }; #endif barry-0.18.5/desktop/src/MemoEditDlg.h0000644001161500056700000000323612242254476017023 0ustar cdfreycdfrey/// /// \file MemoEditDlg.h /// Dialog class to handle the editing of the Memo record /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_MEMO_EDIT_DLG_H__ #define __BARRYDESKTOP_MEMO_EDIT_DLG_H__ #include "StringSync.h" #include #include // begin wxGlade: ::dependencies // end wxGlade // begin wxGlade: ::extracode // end wxGlade class MemoEditDlg : public wxDialog { private: Barry::Memo &m_rec; std::string m_category_list; StringSync m_strings; // begin wxGlade: MemoEditDlg::methods void set_properties(); void do_layout(); // end wxGlade protected: // begin wxGlade: MemoEditDlg::attributes wxStaticText* label_1; wxTextCtrl* text_ctrl_2; wxStaticText* label_2; wxTextCtrl* text_ctrl_3; wxTextCtrl* text_ctrl_1; // end wxGlade wxSizer *bottom_buttons; public: // begin wxGlade: MemoEditDlg::ids // end wxGlade MemoEditDlg(wxWindow* parent, Barry::Memo &rec, bool editable); // in case any validation is required: virtual bool TransferDataFromWindow(); }; // wxGlade: end class #endif // MEMOEDITDLG_H barry-0.18.5/desktop/src/wxi18n.h0000644001161500056700000000536412242254476016033 0ustar cdfreycdfrey/// /// \file wxi18n.h /// Internationalization header for wxWidgets code /// /// Note: the i18n headers are intentionally split between non-wxWidgets code /// and wxWidgets code, via i18n.h and wxi18n.h. This is so that, /// wxWidgets's version of _() is guaranteed to be removed in favour /// of our own _W(), and so prevent confusion. Also, the osyncwrap /// library code does not strictly depend on wxWidgets, and so should /// not use any of its headers nor defines nor its wxString. Keeping /// libosyncwrap separate should make it easier to turn it into a /// standalone library someday. /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_DESKTOP_WXI18N_H__ #define __BARRY_DESKTOP_WXI18N_H__ // Make sure that i18n.h is not included in this module #ifdef __BARRY_DESKTOP_I18N_H__ #error Cannot include both i18n.h and wxi18n.h in same module. #endif #include #include // For the osyncwrap library, it uses gettext, not wxWidgets, so we need // to make sure we initialize gettext if it is available. // // The bindtextdomain define was taken from gettext.h. #if ENABLE_NLS #include #else # define bindtextdomain(Domainname, Dirname) \ ((void) (Domainname), (const char *) (Dirname)) #endif // Make sure wxWidgets' version of _() does not affect us #include #undef _ // Define our own _W() macro, used wherever we'd normally use _T() style // strings, which creates a wxString on the fly. // For wxString(_W("blah blah")) #define _W(x) wxString(wxGetTranslation(_T(x))) // For plain old const char* strings... // Note! this returns a temporary const string! // Do not rely on its existence beyond the statement it lives in. #define _C(x) wxString(wxGetTranslation(_T(x))).utf8_str().data() // Convenience macro to initialize i18n, using wxWidgets #define INIT_I18N(package) { \ /* Do gettext first, if possible, for libosyncwrap */ \ setlocale(LC_ALL, ""); \ bindtextdomain("barryosyncwrap", LOCALEDIR); \ /* Init wxWidgets */ \ static wxLocale locale; \ locale.Init(); \ locale.AddCatalogLookupPathPrefix(_T(LOCALEDIR)); \ locale.AddCatalog(_T(package)); \ } #endif barry-0.18.5/desktop/src/deviceset.h0000644001161500056700000001541212242254476016643 0ustar cdfreycdfrey/// /// \file deviceset.h /// Class which detects a set of available or known devices /// in an opensync-able system. /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_DEVICE_SET_H__ #define __BARRY_DEVICE_SET_H__ #include "osconfig.h" #include "ostypes.h" #include namespace Barry { class GlobalConfigFile; } // // DeviceExtras // /// Config class to hold, load, and save device-related extras that are /// not saved in either the Barry::ConfigFile or the OpenSync group /// config. /// /// These items are not stored in Barry::ConfigFile since they pertain /// to a particular OpenSync sync group. The user may have groups /// configured outside of BarryDesktop. class DeviceExtras { Barry::Pin m_pin; public: // config data... The Extras std::string m_favour_plugin_name; // if empty, ask user time_t m_last_sync_time; OpenSync::Config::pst_type m_sync_types; protected: std::string MakeBaseKey(const std::string &group_name); public: explicit DeviceExtras(const Barry::Pin &pin); DeviceExtras(const Barry::Pin& pin, const Barry::GlobalConfigFile &config, const std::string &group_name); // // operations // void Load(const Barry::GlobalConfigFile &config, const std::string &group_name); void Save(Barry::GlobalConfigFile &config, const std::string &group_name); }; // // DeviceEntry // /// Entry in the DeviceSet class. This class must be STL container safe. /// class DeviceEntry { public: typedef std::tr1::shared_ptr group_ptr; typedef std::tr1::shared_ptr extras_ptr; private: // pointers to external data // pointers may be 0 if data is not available (such as when // a device is not connected, it would not have a ProbeResult) const Barry::ProbeResult *m_result; // pointer to external data group_ptr m_group; // may contain 0 OpenSync::API *m_engine; // may be 0 extras_ptr m_extras; // may contain 0 std::string m_device_name; protected: OpenSync::Config::Barry* FindBarry(); // returns pointer to the Barry // plugin object in m_group // or 0 if not available public: DeviceEntry(const Barry::GlobalConfigFile &config, const Barry::ProbeResult *result, group_ptr group, OpenSync::API *engine, const std::string &secondary_device_name = ""); Barry::Pin GetPin() const; std::string GetDeviceName() const; bool IsConnected() const { return m_result; } bool IsConfigured() const { return m_group.get() && m_engine && m_group->AllConfigured(*m_engine); } std::string GetAppNames() const { return m_group.get() && m_engine ? m_group->GetAppNames() : ""; } /// Returns a string uniquely identifying this DeviceEntry std::string GetIdentifyingString() const; const Barry::ProbeResult* GetProbeResult() { return m_result; } OpenSync::Config::Group* GetConfigGroup() { return m_group.get(); } const OpenSync::Config::Group* GetConfigGroup() const { return m_group.get(); } OpenSync::API* GetEngine() { return m_engine; } const OpenSync::API* GetEngine() const { return m_engine; } DeviceExtras* GetExtras() { return m_extras.get(); } const DeviceExtras* GetExtras() const { return m_extras.get(); } void SetConfigGroup(group_ptr group, OpenSync::API *engine, extras_ptr extras); void SetDeviceName(const std::string &name) { m_device_name = name; } }; std::ostream& operator<< (std::ostream &os, const DeviceEntry &de); // // DeviceSet // /// This class detects known devices on an opensync-able system. /// It will search for connected (USB) devices and devices that have been /// configured in OpenSync (both 0.22 and 0.4x) but are not currently /// connected. /// /// For each device entry, it will know the following: /// - pin /// - device name (from barrybackup configs) /// - whether connected or not /// - whether configured for opensync or not... if so, it will also /// keep track of: /// - the app(s) it will sync with (in one sync group only) /// - the version of the engine it is configured with /// /// If a device is configured in both 0.4x and 0.22, or even in two /// groups in one engine, then all are loaded. Use FindDuplicates() /// and KillDuplicates() to sort that out with the user's help. /// /// Since this class needs to open and parse a lot of information during /// construction anyway, it will store as much as possible, to allow for /// editing in a GUI and saving it later. The domain specific data /// may be encapsulated in further classes. /// class DeviceSet : public std::vector { public: typedef std::vector base_type; typedef base_type::iterator iterator; typedef base_type::const_iterator const_iterator; typedef std::vector subset_type; private: const Barry::GlobalConfigFile &m_config; OpenSync::APISet &m_apiset; Barry::Probe::Results m_results; protected: void LoadSet(); void LoadConfigured(OpenSync::API &api); void LoadUnconfigured(); void Sort(); public: /// Does a USB probe automatically DeviceSet(const Barry::GlobalConfigFile &config, OpenSync::APISet &apiset); /// Skips the USB probe and uses the results set given DeviceSet(const Barry::GlobalConfigFile &config, OpenSync::APISet &apiset, const Barry::Probe::Results &results); iterator FindPin(const Barry::Pin &pin); const_iterator FindPin(const Barry::Pin &pin) const; static subset_type::const_iterator FindPin(const subset_type &subset, const Barry::Pin &pin); static std::string Subset2String(const subset_type &set); subset_type String2Subset(const std::string &list); /// Searches for DeviceEntry's in the set that have the same /// pin number. This is most likely due to OpenSync having /// multiple configurations with the same device. This /// function returns a vector of iterators into the DeviceSet, /// or an empty vector if no duplicates are found. /// /// You can solve the duplicate by erase()ing the chosen /// iterator. Call this function multiple times to find /// all the duplicates. subset_type FindDuplicates(); /// Safely removes all entries that are referenced by /// the iterators in dups. Note that a call to erase() /// invalidates the other iterators, so this function /// does it safely. void KillDuplicates(const subset_type &dups); }; std::ostream& operator<< (std::ostream &os, const DeviceSet &ds); #endif barry-0.18.5/desktop/src/ContactEditDlg.h0000644001161500056700000000756512242254476017532 0ustar cdfreycdfrey/// /// \file ContactEditDlg.h /// Dialog class to handle the editing of the Contact record /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_CONTACT_EDIT_DLG_H__ #define __BARRYDESKTOP_CONTACT_EDIT_DLG_H__ #include "StringSync.h" #include #include // begin wxGlade: ::dependencies #include // end wxGlade // begin wxGlade: ::extracode // end wxGlade class ContactPhotoWidget; class ContactEditDlg : public wxDialog { public: // begin wxGlade: ContactEditDlg::ids // end wxGlade private: Barry::Contact &m_rec; std::string m_email_list; StringSync m_strings; // begin wxGlade: ContactEditDlg::methods void set_properties(); void do_layout(); // end wxGlade protected: // begin wxGlade: ContactEditDlg::attributes wxStaticBox* sizer_8_staticbox; wxStaticBox* sizer_7_staticbox; wxStaticBox* sizer_2_staticbox; wxStaticBox* sizer_6_staticbox; wxStaticBox* sizer_5_staticbox; wxStaticBox* sizer_9_staticbox; ContactPhotoWidget* m_photo; wxStaticText* label_13; wxTextCtrl* Prefix; wxStaticText* FirstNameStatic; wxTextCtrl* FirstName; wxStaticText* LastNameStatic; wxTextCtrl* LastName; wxStaticText* label_14; wxTextCtrl* Company; wxStaticText* label_15; wxTextCtrl* JobTitle; wxStaticText* label_9; wxTextCtrl* Nickname; wxStaticText* label_1; wxTextCtrl* HomeAddress1; wxTextCtrl* HomeAddress2; wxTextCtrl* HomeAddress3; wxStaticText* label_2; wxTextCtrl* HomeCity; wxStaticText* label_3; wxTextCtrl* HomeProvince; wxStaticText* label_4; wxTextCtrl* HomePostalCode; wxStaticText* label_5; wxTextCtrl* HomeCountry; wxStaticLine* static_line_1; wxStaticLine* static_line_2; wxStaticText* label_6; wxTextCtrl* HomePhone; wxStaticText* label_7; wxTextCtrl* HomePhone2; wxStaticText* label_8; wxTextCtrl* HomeFax; wxStaticText* label_1_copy; wxTextCtrl* WorkAddress1; wxTextCtrl* WorkAddress2; wxTextCtrl* WorkAddress3; wxStaticText* label_2_copy; wxTextCtrl* WorkCity; wxStaticText* label_3_copy; wxTextCtrl* WorkProvince; wxStaticText* label_4_copy; wxTextCtrl* WorkPostalCode; wxStaticText* label_5_copy; wxTextCtrl* WorkCountry; wxStaticLine* static_line_1_copy; wxStaticLine* static_line_2_copy; wxStaticText* label_6_copy; wxTextCtrl* WorkPhone; wxStaticText* label_7_copy; wxTextCtrl* WorkPhone2; wxStaticText* label_8_copy; wxTextCtrl* WorkFax; wxStaticText* label_17; wxTextCtrl* text_ctrl_9; wxStaticText* label_18; wxTextCtrl* text_ctrl_1; wxStaticText* label_19; wxTextCtrl* text_ctrl_2; wxStaticText* label_20; wxTextCtrl* text_ctrl_3; wxStaticText* label_21; wxTextCtrl* text_ctrl_4; wxStaticText* label_22; wxTextCtrl* text_ctrl_5; wxStaticText* label_23; wxTextCtrl* text_ctrl_6; wxStaticText* label_24; wxTextCtrl* text_ctrl_7; wxStaticText* label_25; wxTextCtrl* text_ctrl_8; wxStaticText* label_10; wxTextCtrl* MobilePhone; wxStaticText* label_11; wxTextCtrl* MobilePhone2; wxStaticText* label_12; wxTextCtrl* Pager; wxTextCtrl* Notes; wxStaticText* label_16; wxTextCtrl* Url; // end wxGlade wxSizer *bottom_buttons; DECLARE_EVENT_TABLE(); // sets to protected: public: ContactEditDlg(wxWindow *parent, Barry::Contact &rec, bool editable); int ShowModal(); public: void OnPhotoButton(wxCommandEvent &event); virtual bool TransferDataFromWindow(); }; #endif barry-0.18.5/desktop/src/ostypes.cc0000644001161500056700000000347012242254476016535 0ustar cdfreycdfrey/// /// \file ostypes.cc /// Low level type helper functions for os wrapper library /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "ostypes.h" #include using namespace std; namespace OpenSync { namespace Config { pst_type PSTString2Type(const std::string &pst_string) { pst_type types = PST_NONE; if( pst_string.find("contact") != string::npos ) types |= PST_CONTACTS; if( pst_string.find("event") != string::npos ) types |= PST_EVENTS; if( pst_string.find("note") != string::npos ) types |= PST_NOTES; if( pst_string.find("todo") != string::npos ) types |= PST_TODOS; if( pst_string.find("default_only") != string::npos ) types |= PST_DO_NOT_SET; cout << "pst_string '" << pst_string << "' to " << types << endl; return types; } std::string PSTType2String(pst_type types) { string pst_string; if( types & PST_CONTACTS ) pst_string += "contact "; if( types & PST_EVENTS ) pst_string += "event "; if( types & PST_NOTES ) pst_string += "note "; if( types & PST_TODOS ) pst_string += "todo "; if( types & PST_DO_NOT_SET ) pst_string += "default_only "; cout << "type " << types << " to '" << pst_string << "'" << endl; return pst_string; } }} // namespace OpenSync::Config barry-0.18.5/desktop/src/i18n.h0000644001161500056700000000403412242254476015445 0ustar cdfreycdfrey/// /// \file i18n.h /// Internationalization header /// /// Note: the i18n headers are intentionally split between non-wxWidgets code /// and wxWidgets code, via i18n.h and wxi18n.h. This is so that, /// wxWidgets's version of _() is guaranteed to be removed in favour /// of our own _W(), and so prevent confusion. Also, the osyncwrap /// library code does not strictly depend on wxWidgets, and so should /// not use any of its headers nor defines nor its wxString. Keeping /// libosyncwrap separate should make it easier to turn it into a /// standalone library someday. /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_DESKTOP_I18N_H__ #define __BARRY_DESKTOP_I18N_H__ // Make sure that wxi18n.h is not included in this module #ifdef __BARRY_DESKTOP_WXI18N_H__ #error Cannot include both i18n.h and wxi18n.h in same module. #endif #include #include // Set the DEFAULT_TEXT_DOMAIN so that gettext.h uses dgettext() // instead of gettext(). This way we don't have to call textdomain() // and hope that nobody changes it on us later. #define DEFAULT_TEXT_DOMAIN "barryosyncwrap" #include "gettext.h" // Define our own macro for plain const char* strings, so that // there is no conflict with wxWidgets. For std::string(_C("blah blah")). #define _C(x) gettext(x) // Convenience macro for main(). #define INIT_I18N() { \ bindtextdomain("barryosyncwrap", LOCALEDIR); \ } #endif barry-0.18.5/desktop/src/0.22/0000755001161500056700000000000012242254476015075 5ustar cdfreycdfreybarry-0.18.5/desktop/src/0.22/Makefile.am0000644001161500056700000000007512242254476017133 0ustar cdfreycdfreydist_xmlmap22_DATA = \ xmlmap EXTRA_DIST = \ Makefile.am barry-0.18.5/desktop/src/0.22/xmlmap0000644001161500056700000000642112242254476016321 0ustar cdfreycdfrey# The order listed in this file is the order that the fields will be # stored when parsed into friendly lists. # # # Note: Type may be included in any of these: # # $ = use first value found # % = generate comma separated list of all values of that name # , = add comma after value if non-zero length # ( = enclose next variable or list in parentheses # Contact /contact/Name 0 $Prefix $FirstName $Additional $LastName $Suffix FirstName LastName Additional Prefix Suffix #Contact /contact/FormattedName 0 $Content # Content Contact /contact/Organization 0 $Name Name Department Unit # Type not included in compare list, since it varies... Contact /contact/Telephone 0 $Content (%Type Content Contact /contact/EMail 0 $Content (%Type Content Type Contact /contact/Categories 1 %Category Category Contact /contact/Address 1 (%Type $PostalBox $Street, $City, $Region, $Country, $PostalCode PostalBox Street City Region Country PostalCode ExtendedAddress Type #Contact /contact/AddressLabel 1 $Content # Content # Type Contact /contact/Title 1 $Content Content Contact /contact/Nickname 1 $Content Content Contact /contact/Birthday 1 $Content Content Contact /contact/Note 1 $Content Content Contact /contact/Photo 1 Image Data Content Contact /contact/Url 1 $Content Content Contact /contact/Agent 1 $Content Content Contact /contact/Mailer 1 $Content Content Contact /contact/Timezone 1 $Content Content Contact /contact/Location 1 $Latitude / $Longitude Latitude Longitude Contact /contact/Role 1 $Content Content Contact /contact/Logo 1 Logo Data Content Contact /contact/Class 1 $Content Content # key event data: summary, dates, location, description Calendar /vcal/Event/Summary 0 $Content Content Calendar /vcal/Event/Description 0 $Content Content Calendar /vcal/Event/Location 0 $Content Content Calendar /vcal/Event/DateCreated 1 Created: $Content Content[timestamp] Calendar /vcal/Event/DateStarted 1 Started: $Content Content[timestamp] Calendar /vcal/Event/DateDue 1 Due: $Content Content[timestamp] Calendar /vcal/Event/Duration 1 Duration: $Content Content Calendar /vcal/Event/DateEnd 1 End: $Content Content[timestamp] Calendar /vcal/Event/Organizer 1 Organizer: $Content Content Calendar /vcal/Event/Attendee 1 Attendee: $Content Content Calendar /vcal/Event/Contact 1 Contact: $Content Content Calendar /vcal/Event/Completed 1 $Content Content Calendar /vcal/Event/Categories 1 %Category Category Calendar /vcal/Event/Method 1 $Content Content #Calendar /vcal/Event/DateCalendarCreated 1 CalCreated: $Content # Content #Calendar /vcal/Event/PercentComplete 1 $Content # Content #Calendar /vcal/RecurrenceRule 1 %Rule # Rule #Calendar /vcal/Event/Transparency 1 $Content # Content # FIXME - Alarm needs testing: Calendar /vcal/Event/Alarm 1 $AlarmDescription AlarmAction AlarmDescription AlarmTrigger Calendar /vcal/Event/Class 1 $Content Content Calendar /vcal/Event/Url 1 $Content Content Calendar /vcal/Event/Priority 1 $Content Content #Calendar /vcal/Event/Sequence 1 $Content # Content #Calendar /vcal/RecurrenceDate 1 $Content # Content Calendar /vcal/Event/Geo 1 $Latitude / $Longitude Latitude Longitude Calendar /vcal/Event/Status 1 $Content Content Calendar /vcal/Event/Attach 1 Attach Data Content #Calendar /vcal/ExclusionDate 1 $Content # Content # Value barry-0.18.5/desktop/src/SyncStatusDlg.cc0000644001161500056700000004214312242254476017576 0ustar cdfreycdfrey/// /// \file SyncStatusDlg.cc /// The dialog used during a sync, to display status messages /// and error messages, and handle sync conflicts via callback. /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "SyncStatusDlg.h" #include "ConflictDlg.h" #include "windowids.h" #include "configui.h" #include "barrydesktop.h" #include #include #include #include #include #include "wxi18n.h" using namespace std; SillyBuffer sb; ////////////////////////////////////////////////////////////////////////////// // StatusConnection class StatusConnection::StatusConnection(SyncStatusDlg &dlg, wxTextCtrl &window) : m_dlg(dlg) , m_status(window) { } bool StatusConnection::OnPoke(const wxString &topic, const wxString &item, wxChar *data, int size, wxIPCFormat format) { if( topic != TOPIC_STATUS ) return false; wxString msg(data, size); if( item == STATUS_ITEM_ERROR ) { m_dlg.Print(msg, *wxRED); m_dlg.ShortPrint(msg); } else if( item == STATUS_ITEM_ENTRY ) { m_dlg.Print(msg, *wxBLUE); m_dlg.ShortPrint(_W("Syncing entries...")); } else if( item == STATUS_ITEM_MAPPING ) { m_dlg.Print(msg, *wxBLUE); } else if( item == STATUS_ITEM_ENGINE ) { wxString key = ENGINE_STATUS_SLOW_SYNC; if( msg.substr(0, key.size()) == key ) { m_dlg.OnSlowSync(); } else { m_dlg.Print(msg, *wxGREEN); m_dlg.ShortPrint(msg); } } else if( item == STATUS_ITEM_MEMBER ) { m_dlg.Print(msg, *wxCYAN); } else { // unknown item m_dlg.Print(msg, *wxBLACK); } return true; } ////////////////////////////////////////////////////////////////////////////// // ConflictConnection class ConflictConnection::ConflictConnection(SyncStatusDlg &dlg) : m_dlg(dlg) , m_asking_user(false) , m_current_sequenceID(-1) , m_current_offset(-1) , m_expected_total_changes(0) { // check if there's a favoured plugin name from the DeviceEntry config if( m_dlg.GetCurrentDevice() && m_dlg.GetCurrentDevice()->GetExtras() ) { m_always.m_favour_plugin_name = m_dlg.GetCurrentDevice()-> GetExtras()->m_favour_plugin_name; } } bool ConflictConnection::OnPoke(const wxString &topic, const wxString &item, wxChar *data, int size, wxIPCFormat format) { barryverbose("Conflict::OnPoke: " << string(topic.utf8_str()) << ", " << string(item.utf8_str())); if( topic != TOPIC_CONFLICT ) return false; // if currently handling a user request, don't change // the state machine... the client shouldn't be poking // if he just Request'd anyway if( m_asking_user ) return false; wxString msg(data, size); istringstream iss(string(msg.utf8_str())); if( item == CONFLICT_ITEM_START ) { // overwrite any existing sequence m_changes.clear(); iss >> m_current_sequenceID >> m_current_offset >> m_expected_total_changes >> m_supported_commands; if( !iss || m_current_offset != 0 || m_expected_total_changes < 2) { // invalid start command, throw it away m_current_sequenceID = -1; m_current_offset = -1; m_expected_total_changes = 0; return false; } barryverbose("New conflict item: " << m_current_sequenceID << ", " << m_current_offset << ", " << "expected changes: " << m_expected_total_changes << ", supported commands: " << m_supported_commands); } else if( item == CONFLICT_ITEM_CHANGE ) { int sequenceID = 0, offset = 0; OpenSync::SyncChange change; iss >> sequenceID >> offset >> change.id >> ws; getline(iss, change.plugin_name); getline(iss, change.uid); change.member_id = 0; if( !iss || sequenceID != m_current_sequenceID || offset != (m_current_offset + 1) ) { return false; } m_current_offset = offset; // grab remaining "printable data" copy((istreambuf_iterator(iss)), (istreambuf_iterator()), back_inserter(change.printable_data)); m_changes.push_back(change); barryverbose("New conflict change: " << m_current_sequenceID << ", " << m_current_offset << ", data: " << change.printable_data); } return true; } wxChar* ConflictConnection::OnRequest(const wxString &topic, const wxString &item, int *size, wxIPCFormat format) { // make sure we are in a valid sequence if( m_current_sequenceID == -1 || m_current_offset == -1 || m_expected_total_changes < 2) { barryverbose("Conflict: not in a valid sequence: " << m_current_sequenceID << ", " << m_current_offset << ", " << m_expected_total_changes); return NULL; } // make sure we have a valid set of changes if( m_current_offset != m_expected_total_changes || (size_t)m_expected_total_changes != m_changes.size() ) { barryverbose("Conflict: not a valid set of changes: " << m_current_offset << ", " << m_expected_total_changes << ", " << m_changes.size()); return NULL; } m_asking_user = true; // ask the user what to do if( !m_dlg.GetCurrentDevice() ) { barryverbose("Conflict: current device is null"); return NULL; } OpenSync::API *engine = m_dlg.GetCurrentDevice()->GetEngine(); ConflictDlg dlg(&m_dlg, *engine, m_supported_commands, m_changes, m_always); m_dlg.StopTimer(); dlg.ShowModal(); m_dlg.StartTimer(); // done m_asking_user = false; // did the user ask to kill the sync? if( dlg.IsKillSync() ) { // die! m_dlg.KillSync(); return NULL; } // prepare response for client ostringstream oss; oss << m_current_sequenceID << " " << dlg.GetCommand(); m_buf.buf(oss.str()); // oddly, this is the size in bytes, not in wxChars *size = (m_buf.size() + 1) * sizeof(wxChar); return m_buf.buf(); } ////////////////////////////////////////////////////////////////////////////// // SyncStatus class BEGIN_EVENT_TABLE(SyncStatusDlg, wxDialog) EVT_INIT_DIALOG (SyncStatusDlg::OnInitDialog) EVT_BUTTON (Dialog_SyncStatus_RunAppButton, SyncStatusDlg::OnRunApp) EVT_BUTTON (Dialog_SyncStatus_SyncAgainButton, SyncStatusDlg::OnSyncAgain) EVT_BUTTON (Dialog_SyncStatus_KillCloseButton, SyncStatusDlg::OnKillClose) EVT_BUTTON (Dialog_SyncStatus_ShowDetailsButton, SyncStatusDlg::OnShowDetails) EVT_END_PROCESS (Dialog_SyncStatus_SyncTerminated, SyncStatusDlg::OnExecTerminated) EVT_TIMER (Dialog_SyncStatus_Timer, SyncStatusDlg::OnTimer) END_EVENT_TABLE() SyncStatusDlg::SyncStatusDlg(wxWindow *parent, const DeviceSet::subset_type &subset) : wxDialog(parent, Dialog_SyncStatus, _W("Device Sync Progress"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) , TermCatcher(this, Dialog_SyncStatus_SyncTerminated) , m_subset(subset) , m_next_device(m_subset.begin()) , m_jailexec(this) , m_killingjail(false) , m_timer(this, Dialog_SyncStatus_Timer) , m_topsizer(0) , m_short_status(0) , m_throbber(0) , m_status_edit(0) , m_runapp_button(0) , m_syncagain_button(0) , m_killclose_button(0) , m_details_button(0) , m_repositioned(false) { wxBusyCursor wait; // setup the raw GUI CreateLayout(); // create the IPC server wxServer::Create(SERVER_SERVICE_NAME); } SyncStatusDlg::~SyncStatusDlg() { // make sure bsyncjail dies if we do m_jailexec.KillApp(); } void SyncStatusDlg::CreateLayout() { m_topsizer = new wxBoxSizer(wxVERTICAL); AddStatusSizer(m_topsizer); AddButtonSizer(m_topsizer); SetSizer(m_topsizer); m_topsizer->SetSizeHints(this); m_topsizer->Layout(); } void SyncStatusDlg::AddStatusSizer(wxSizer *sizer) { wxSizer *ss = new wxStaticBoxSizer( new wxStaticBox(this, wxID_ANY, _W("Sync Progress")), wxVERTICAL ); // add a set of short status and progress throbber wxSizer *shorts = new wxBoxSizer(wxHORIZONTAL); shorts->Add( m_short_status = new wxStaticText(this, wxID_ANY, _T(""), wxDefaultPosition, wxSize(350, -1), wxALIGN_LEFT), 1, wxALIGN_CENTRE_VERTICAL | wxALL, 2); shorts->Add( m_throbber = new wxGauge(this, wxID_ANY, 0), 0, wxALL | wxEXPAND, 2); ss->Add( shorts, 0, wxEXPAND, 0); ss->Add( m_status_edit = new wxTextCtrl(this, wxID_ANY, _T(""), wxDefaultPosition, wxSize(475, 450), wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH), 0, wxALL | wxEXPAND, 2); // start with the details hidden m_status_edit->Hide(); sizer->Add(ss, 1, wxTOP | wxLEFT | wxRIGHT | wxEXPAND, 5); } void SyncStatusDlg::AddButtonSizer(wxSizer *sizer) { wxSizer *button = new wxBoxSizer(wxHORIZONTAL); button->Add( m_details_button = new wxButton(this, Dialog_SyncStatus_ShowDetailsButton, _W("Show Details")), 0, wxALL, 3); button->Add( -1, -1, 1 ); if( m_subset.size() == 1 ) { button->Add( m_runapp_button = new wxButton(this, Dialog_SyncStatus_RunAppButton, _W("Run App")), 0, wxALL, 3); } button->Add( m_syncagain_button = new wxButton(this, Dialog_SyncStatus_SyncAgainButton, _W("Sync Again")), 0, wxALL, 3); button->Add( m_killclose_button = new wxButton(this, Dialog_SyncStatus_KillCloseButton, _W("Kill Sync")), 0, wxALL, 3); sizer->Add(button, 0, wxALL | wxEXPAND, 5); } void SyncStatusDlg::SetRunning() { if( m_runapp_button ) m_runapp_button->Enable(false); m_syncagain_button->Enable(false); m_killclose_button->SetLabel(_W("Kill Sync")); m_killclose_button->Enable(true); UpdateTitle(); m_throbber->SetRange(10); m_throbber->SetValue(0); StartTimer(); } void SyncStatusDlg::SetClose() { if( m_runapp_button ) m_runapp_button->Enable(true); m_syncagain_button->Enable(true); m_killclose_button->SetLabel(_W("Close")); m_killclose_button->Enable(true); UpdateTitle(); m_throbber->SetRange(10); m_throbber->SetValue(10); StopTimer(); } void SyncStatusDlg::PrintStd(const std::string &msg, const wxColour &colour) { Print(wxString(msg.c_str(), wxConvUTF8), colour); } void SyncStatusDlg::Print(const wxString &msg, const wxColour &colour) { m_status_edit->SetDefaultStyle(wxTextAttr(colour)); m_status_edit->AppendText(_T("\n") + msg); } void SyncStatusDlg::ShortPrintStd(const std::string &msg) { ShortPrint(wxString(msg.c_str(), wxConvUTF8)); } void SyncStatusDlg::ShortPrint(const wxString &msg) { m_short_status->SetLabel(msg); } void SyncStatusDlg::Throb() { m_throbber->Pulse(); } void SyncStatusDlg::StartTimer() { m_timer.Start(250); } void SyncStatusDlg::StopTimer() { m_timer.Stop(); } DeviceEntry* SyncStatusDlg::GetCurrentDevice() { if( m_current_device == m_subset.end() ) return 0; return &(*(*m_current_device)); } void SyncStatusDlg::UpdateTitle() { if( m_next_device == m_subset.end() ) { SetTitle(_W("Sync Progress Dialog")); } else { ostringstream oss; oss << _C("Syncing: ") << (*m_next_device)->GetPin().Str() << _C(" with ") << (*m_next_device)->GetAppNames(); wxString label(oss.str().c_str(), wxConvUTF8); SetTitle(label); } } void SyncStatusDlg::UpdateLastSyncTime() { if( m_current_device != m_subset.end() && (*m_current_device)->GetConfigGroup() && (*m_current_device)->GetExtras() ) { (*m_current_device)->GetExtras()->m_last_sync_time = time(NULL); (*m_current_device)->GetExtras()->Save( wxGetApp().GetGlobalConfig(), (*m_current_device)->GetConfigGroup()->GetGroupName()); } } void SyncStatusDlg::KillSync() { m_jailexec.KillApp(m_killingjail); m_killingjail = true; // jump to the end of the sync roster, so we don't start the // next device m_current_device = m_next_device = m_subset.end(); } void SyncStatusDlg::StartNextSync() { m_killingjail = false; // anything to do? if( m_next_device == m_subset.end() ) { Print(_W("No more devices to sync."), *wxBLACK); SetClose(); return; } else { SetRunning(); } // grab all required information we need to sync m_current_device = m_next_device; DeviceEntry &device = *(*m_next_device); const DeviceExtras *extras = device.GetExtras(); m_device_id = device.GetPin().Str() + " (" + device.GetDeviceName() + ")"; if( !device.IsConfigured() ) { PrintStd(m_device_id + _C(" is not configured, skipping."), *wxRED); ShortPrintStd(_C("Skipping unconfigured: ") + m_device_id); ++m_next_device; m_current_device = m_subset.end(); StartNextSync(); return; } OpenSync::API *engine = device.GetEngine(); OpenSync::Config::Group *group = device.GetConfigGroup(); string group_name = group->GetGroupName(); string statusmsg = _C("Starting sync for: ") + m_device_id; PrintStd(statusmsg, *wxBLACK); ShortPrintStd(statusmsg); // for each plugin / app, perform the pre-sync steps for( OpenSync::Config::Group::iterator i = group->begin(); i != group->end(); ++i ) { ConfigUI::ptr ui = ConfigUI::CreateConfigUI((*i)->GetAppName()); if( ui.get() ) { ui->PreSyncAppInit(); } } // initialize sync jail process if( m_jailexec.IsAppRunning() ) { wxString msg(_W("ERROR: App running in StartNextSync()")); Print(msg, *wxRED); ShortPrint(msg); SetClose(); return; } // bsyncjail is in pkglibexecdir wxFileName path(wxTheApp->argv[0]); wxString command(BARRYDESKTOP_PKGLIBEXECDIR, wxConvUTF8); command += path.GetPathSeparator(); command += _T("bsyncjail "); command += wxString(engine->GetVersion(), wxConvUTF8); command += _T(" "); command += wxString(group_name.c_str(), wxConvUTF8); command += _T(" "); ostringstream sync_code; sync_code << dec << extras->m_sync_types; command += wxString(sync_code.str().c_str(), wxConvUTF8); if( !m_jailexec.Run(NULL, "bsyncjail", command) ) { Print(_W("ERROR: unable to start bsyncjail: ") + command, *wxRED); ShortPrint(_W("ERROR: unable to start bsyncjail")); SetClose(); return; } // sync is underway... advance to the next device ++m_next_device; } void SyncStatusDlg::OnSlowSync() { Print(_W("Slow sync detected! Killing sync automatically."), *wxRED); KillSync(); Print(_W("Slow syncs are known to be unreliable."), *wxBLACK); Print(_W("Do a 1 Way Reset, and sync again."), *wxBLACK); } void SyncStatusDlg::OnInitDialog(wxInitDialogEvent &event) { barryverbose("OnInitDialog"); StartNextSync(); } void SyncStatusDlg::OnRunApp(wxCommandEvent &event) { if( m_subset.size() != 1 ) return; if( m_ui.get() && m_ui->IsAppRunning() ) { wxMessageBox(_W("The application is already running."), _W("Run Application"), wxOK | wxICON_ERROR, this); return; } OpenSync::Config::Group *group = m_subset[0]->GetConfigGroup(); if( !group ) return; m_ui = ConfigUI::CreateConfigUI(group->GetAppNames()); if( !m_ui.get() ) return; m_ui->RunApp(this); } void SyncStatusDlg::OnSyncAgain(wxCommandEvent &event) { m_next_device = m_subset.begin(); StartNextSync(); } void SyncStatusDlg::OnKillClose(wxCommandEvent &event) { if( m_jailexec.IsAppRunning() ) { int choice; if( m_killingjail ) { choice = wxMessageBox(_W("Already killing sync. Kill again?"), _W("Kill Sync"), wxYES_NO | wxICON_QUESTION, this); } else { choice = wxMessageBox(_W("This will kill the syncing child process, and will likely require a configuration reset.\n\nKill sync process anyway?"), _W("Kill Sync"), wxYES_NO | wxICON_QUESTION, this); } if( choice == wxYES ) { KillSync(); Print(_W("Killing sync... this may take a little while..."), *wxRED); Print(_W("Remember to re-plug your device."), *wxRED); // let the terminate call clean up the buttons return; } } else { EndModal(0); } } void SyncStatusDlg::OnShowDetails(wxCommandEvent &event) { if( m_status_edit->IsShown() ) { m_status_edit->Hide(); m_details_button->SetLabel(_W("Show Details")); } else { if( !m_repositioned ) { // try to position the window in a readable spot... // do this first, so that the resize wxSize size = GetSize(); wxPoint pos = GetScreenPosition(); int screen_height = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y); int new_height = size.GetHeight() + 470; if( (pos.y + new_height) > screen_height && new_height < screen_height ) { int wiggle_room = screen_height - new_height; int y = wiggle_room / 2; Move(pos.x, y); } m_repositioned = true; } m_status_edit->Show(); m_details_button->SetLabel(_W("Hide Details")); } m_topsizer->Fit(this); } wxConnectionBase* SyncStatusDlg::OnAcceptConnection(const wxString &topic) { wxConnectionBase *con = 0; if( topic == TOPIC_STATUS && m_status_edit ) con = new StatusConnection(*this, *m_status_edit); else if( topic == TOPIC_CONFLICT ) con = new ConflictConnection(*this); if( con ) m_connections.push_back( dynamic_cast (con) ); return con; } void SyncStatusDlg::OnExecTerminated(wxProcessEvent &event) { ostringstream oss; if( m_killingjail ) oss << _C("Sync terminated: "); else oss << _C("Sync finished: "); oss << m_device_id; if( m_jailexec.GetChildExitCode() ) oss << _C(" with error code ") << m_jailexec.GetChildExitCode(); PrintStd(oss.str(), *wxBLACK); ShortPrintStd(oss.str()); UpdateLastSyncTime(); m_current_device = m_subset.end(); StartNextSync(); } void SyncStatusDlg::OnTimer(wxTimerEvent &event) { Throb(); } barry-0.18.5/desktop/src/configui.h0000644001161500056700000000514412242254476016474 0ustar cdfreycdfrey/// /// \file configui.h /// Base class for plugin config user interfaces /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_CONFIGUI_H__ #define __BARRY_CONFIGUI_H__ #include #include #include #include #include #include "osconfig.h" #include "exechelper.h" // // ConfigUI // /// Base class for plugin config user interfaces /// /// To use, call the static factory function to create the config UI /// object for a given App. Then call Configure(), which will block /// and may do a number of configuration steps to let the user /// configure the App. If Configure() returns true, then call /// GetPlugin() to retrieve the fully configured plugin. /// class ConfigUI : public ExecHelper { public: typedef OpenSync::Config::Group::plugin_ptr plugin_ptr; typedef std::auto_ptr configui_ptr; typedef configui_ptr ptr; public: ConfigUI(); virtual ~ConfigUI(); /// Returns OpenSync::Config::*::AppName() for the specific app virtual std::string AppName() const = 0; /// Handles all the GUI work of configuring the App /// old_plugin may contain null if this is a first-time config virtual bool Configure(wxWindow *parent, plugin_ptr old_plugin) = 0; /// Returns a configured plugin object (after a successful Configure()) virtual plugin_ptr GetPlugin() = 0; /// Runs the Application, if not already running.. parent may /// be NULL if you don't want this class to pop up error messages /// if unable to run the app virtual bool RunApp(wxWindow *parent) = 0; /// Performs any initialization steps that the App requires before /// running the sync (for example, Evolution needs a --force-shutdown) virtual void PreSyncAppInit() = 0; /// Presents the user with the warning / instructions for zapping /// the data on this plugin. Returns false if user aborted along /// the way. virtual bool ZapData(wxWindow *parent, plugin_ptr plugin, OpenSync::API *engine) = 0; static configui_ptr CreateConfigUI(const std::string &appname); }; #endif barry-0.18.5/desktop/src/blistevo.cc0000644001161500056700000000332012242254476016650 0ustar cdfreycdfrey/// /// \file blistevo.cc /// Command line test tool for EvoSources /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "EvoSources.h" #include #include "i18n.h" using namespace std; void DumpItems(const EvoSources::List &list) { EvoSources::List::const_iterator i; for( i = list.begin(); i != list.end(); ++i ) { cout << " " << i->m_GroupName << ", " << i->m_SourceName << ", " << i->m_SourcePath << endl; } } int main() { setlocale(LC_ALL, ""); INIT_I18N(); const char *separator = "\n-----------------------------------------\n"; EvoSources es; cout << _C("Defaultable: ") << (es.IsDefaultable() ? _C("Yes") : _C("No")) << endl; cout << _C("Error during detect: ") << (es.GetErrorMsg().size() ? es.GetErrorMsg().c_str() : _C("(none)")) << endl; cout << _C("Results:") << "\n"; cout << "\n" << _C("Addressbook:") << separator; DumpItems(es.GetAddressBook()); cout << "\n" << _C("Events:") << separator; DumpItems(es.GetEvents()); cout << "\n" << _C("Tasks:") << separator; DumpItems(es.GetTasks()); cout << "\n" << _C("Memos:") << separator; DumpItems(es.GetMemos()); } barry-0.18.5/desktop/src/TaskEditDlg.wxg0000644001161500056700000011421112242254476017402 0ustar cdfreycdfrey Task Event wxVERTICAL wxALL|wxEXPAND 10 wxVERTICAL wxEXPAND 0 5 2 1 2 5 wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 1 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Summary)) wxALL|wxEXPAND 5 1 wxEXPAND 0 5 10 1 2 5 wxALIGN_CENTER_VERTICAL 0 1 0 0 Not Started In Progress Completed Waiting Deferred wxALIGN_CENTER_VERTICAL 0 1 0 1 High Normal Low wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxHORIZONTAL 0 Dialog_TaskEdit_DueCheck OnDueCheck 0 Dialog_TaskEdit_DueDateCtrl DateTimeValidator(&m_DueDateObj.m_date) 110, -1 0 20 20 0 Dialog_TaskEdit_DueHoursSpinner 0, 23 wxGenericValidator(&m_DueDateObj.m_hour) 45, -1 wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL 1 1 0 Dialog_TaskEdit_DueMinutesSpinner 0, 59 wxGenericValidator(&m_DueDateObj.m_min) 45, -1 wxALIGN_CENTER_VERTICAL 0 1 0 0 System Time Zone wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxHORIZONTAL 0 Dialog_TaskEdit_ReminderCheck OnReminderCheck 0 Dialog_TaskEdit_ReminderDateCtrl DateTimeValidator(&m_ReminderDateObj.m_date) 110, -1 0 20 20 5 Set Reminder to 0 to disable Dialog_TaskEdit_ReminderHoursSpinner 0, 999 wxGenericValidator(&m_ReminderDateObj.m_hour) 45, -1 wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL 1 1 wxRIGHT 5 Set Reminder to 0 to disable Dialog_TaskEdit_ReminderMinutesSpinner 0, 59 wxGenericValidator(&m_ReminderDateObj.m_min) 45, -1 wxALL|wxEXPAND 5 1 wxEXPAND 0 5 5 1 2 5 wxALIGN_CENTER_VERTICAL 0 1 0 0 Dialog_TaskEdit_RecurrenceChoice None Daily Weekly Monthly Yearly OnRecurrenceChoice wxGenericValidator(&m_recur_choice) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxHORIZONTAL wxRIGHT|wxALIGN_CENTER_VERTICAL 5 1 wxRIGHT 5 1, 999 1 wxGenericValidator(&m_interval) 45, -1 wxALIGN_CENTER_VERTICAL 0 1 wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxHORIZONTAL wxRIGHT 5 wxGenericValidator(&m_weekdays[0]) wxRIGHT 5 wxGenericValidator(&m_weekdays[1]) wxRIGHT 5 wxGenericValidator(&m_weekdays[2]) wxRIGHT 5 wxGenericValidator(&m_weekdays[3]) wxRIGHT 5 wxGenericValidator(&m_weekdays[4]) wxRIGHT 5 wxGenericValidator(&m_weekdays[5]) wxRIGHT 5 wxGenericValidator(&m_weekdays[6]) wxALIGN_CENTER_VERTICAL 0 1 Relative monthly or yearly dates take the weekday of the start date into account. (eg. every first Sunday of month) 0 Relative monthly or yearly dates take the weekday of the start date into account. (eg. every first Sunday of month) wxGenericValidator(&m_relative_date) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxHORIZONTAL wxRIGHT|wxALIGN_CENTER_VERTICAL 10 1 Dialog_TaskEdit_NeverEndsCheck OnEndDateCheckbox wxGenericValidator(&m_rec.Perpetual) wxALIGN_CENTER_VERTICAL 0 1 DateTimeValidator(&m_RecurEndDateObj.m_date) 110, -1 wxALL|wxEXPAND 5 1 wxEXPAND 0 5 2 1 2 5 wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_categories)) wxRIGHT 5 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Notes)) -1, 71 barry-0.18.5/desktop/src/PNGButton.cc0000644001161500056700000001014712242254476016646 0ustar cdfreycdfrey/// /// \file PNGButton.cc /// Class for turning a set of PNG images into buttons /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "PNGButton.h" #include "barrydesktop.h" #include "wxi18n.h" ////////////////////////////////////////////////////////////////////////////// // PNGButton PNGButton::PNGButton(wxWindow *parent, int ID, int x, int y, bool enabled) : m_parent(parent) , m_id(ID) , m_x(x) , m_y(y) , m_state(0) , m_enabled(enabled) { // normal[0] m_bitmaps[BUTTON_STATE_NORMAL] = LoadButtonBitmap(BUTTON_STATE_NORMAL); // focus[1] m_bitmaps[BUTTON_STATE_FOCUS] = LoadButtonBitmap(BUTTON_STATE_FOCUS); // pushed[2] m_bitmaps[BUTTON_STATE_PUSHED] = LoadButtonBitmap(BUTTON_STATE_PUSHED); // and the label text, translated m_label = GetButtonLabel(m_id); } wxBitmap PNGButton::LoadButtonBitmap(int state) { wxString file = GetButtonFilename(m_id, state); wxImage image(file); wxBitmap bmp(image); if( !image.IsOk() || !bmp.IsOk() ) { wxGetApp().Yield(); throw std::runtime_error(_C("Cannot load button bitmap.")); } return bmp; } // // Due to limitations in DC transparency support, and for speed reasons, // we use this Init() opportunity to create a brand new bitmap for each // button, which includes the background and the transparency bitmap drawing, // and the button text. // void PNGButton::Init(wxDC &dc) { // grab the existing background first int width = m_bitmaps[BUTTON_STATE_NORMAL].GetWidth(); int height = m_bitmaps[BUTTON_STATE_NORMAL].GetHeight(); m_background = wxBitmap(width, height); // copy it over, no transparency { wxMemoryDC grab_dc; grab_dc.SelectObject(m_background); grab_dc.Blit(0, 0, width, height, &dc, m_x, m_y, wxCOPY, false); } // this font may be modified by DrawButtonLabelDC... keep it // outside the loop so the same size font will be used for all // buttons int pointsize = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) .GetPointSize(); wxFont font(pointsize + 2, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD); // for each button, draw it with background + transparency + label for( int i = 0; i < 3; i++ ) { wxBitmap final = wxBitmap(width, height); { wxMemoryDC dc; dc.SelectObject(final); // draw the background, no transparency dc.DrawBitmap(m_background, 0, 0, false); // draw the button, with transparency dc.DrawBitmap(m_bitmaps[i], 0, 0); // draw the text DrawButtonLabelDC(dc, m_bitmaps[i], m_label, font, *wxBLACK, 80, 12, -15, -15); } // copy final button bitmap into m_bitmaps array for use m_bitmaps[i] = final; } } void PNGButton::Draw(wxDC &dc) { // just splat the final button onto the screen at the exepcted // coordinates dc.DrawBitmap(m_bitmaps[m_state], m_x, m_y, false); } /// This is only used if the button is moved, and the background needs to /// be restored. Currently only theoretical. void PNGButton::Erase(wxDC &dc) { dc.DrawBitmap(m_background, m_x, m_y, false); } void PNGButton::Normal(wxDC &dc) { if( !m_enabled ) return; m_state = BUTTON_STATE_NORMAL; Draw(dc); } void PNGButton::Focus(wxDC &dc) { if( !m_enabled ) return; m_state = BUTTON_STATE_FOCUS; Draw(dc); } void PNGButton::Push(wxDC &dc) { if( !m_enabled ) return; m_state = BUTTON_STATE_PUSHED; Draw(dc); } void PNGButton::Click(wxDC &dc) { if( !m_enabled ) return; if( IsPushed() ) { // return to normal m_state = BUTTON_STATE_NORMAL; Draw(dc); // send the event wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, m_id); m_parent->GetEventHandler()->ProcessEvent(event); } } barry-0.18.5/desktop/src/ContactPhotoWidget.h0000644001161500056700000000266612242254476020450 0ustar cdfreycdfrey/// /// \file ContactPhotoWidget.h /// Bitmap button that shows a Contact::Image photo /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_CONTACT_PHOTO_WIDGET_H__ #define __BARRYDESKTOP_CONTACT_PHOTO_WIDGET_H__ #include #include namespace Barry { class Contact; } class ContactPhotoWidget : public wxBitmapButton { Barry::Contact &m_rec; std::auto_ptr m_bitmap; wxString m_file_filter; protected: int LoadRecImage(int max_height); public: ContactPhotoWidget(wxWindow *parent, wxWindowID id, Barry::Contact &rec); /// Lets user save current Photo to a JPG file void PromptAndSave(wxWindow *parent); /// Lets user replace current Photo with an image file bool PromptAndLoad(wxWindow *parent); void DeletePhoto(); static void DrawNoPhoto(wxBitmap &bm, int width, int height); }; #endif barry-0.18.5/desktop/src/0.40/0000755001161500056700000000000012242254476015075 5ustar cdfreycdfreybarry-0.18.5/desktop/src/0.40/Makefile.am0000644001161500056700000000007512242254476017133 0ustar cdfreycdfreydist_xmlmap40_DATA = \ xmlmap EXTRA_DIST = \ Makefile.am barry-0.18.5/desktop/src/0.40/xmlmap0000644001161500056700000000002712242254476016315 0ustar cdfreycdfrey# Not yet implemented barry-0.18.5/desktop/src/MigrateDlg.cc0000644001161500056700000005012612242254476017046 0ustar cdfreycdfrey/// /// \file MigrateDlg.cc /// Dialog for the "Migrate Device" main menu mode button... /// going with a dialog instead of a mode class this time. /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "MigrateDlg.h" #include "windowids.h" #include "configui.h" #include "barrydesktop.h" #include #include #include #include #include "wxi18n.h" using namespace std; using namespace OpenSync; DEFINE_EVENT_TYPE(MET_THREAD_FINISHED) DEFINE_EVENT_TYPE(MET_CHECK_DEST_PIN) DEFINE_EVENT_TYPE(MET_SET_STATUS_MSG) DEFINE_EVENT_TYPE(MET_PROMPT_PASSWORD) DEFINE_EVENT_TYPE(MET_ERROR_MSG) BEGIN_EVENT_TABLE(MigrateDlg, wxDialog) EVT_BUTTON (Dialog_Migrate_MigrateNowButton, MigrateDlg::OnMigrateNow) EVT_BUTTON (Dialog_Migrate_CancelButton, MigrateDlg::OnCancel) EVT_CLOSE (MigrateDlg::OnCloseWindow) EVT_COMMAND (wxID_ANY, MET_THREAD_FINISHED, MigrateDlg::OnThreadFinished) EVT_COMMAND (wxID_ANY, MET_CHECK_DEST_PIN, MigrateDlg::OnCheckDestPin) EVT_COMMAND (wxID_ANY, MET_SET_STATUS_MSG, MigrateDlg::OnSetStatusMsg) EVT_COMMAND (wxID_ANY, MET_PROMPT_PASSWORD, MigrateDlg::OnPromptPassword) EVT_COMMAND (wxID_ANY, MET_ERROR_MSG, MigrateDlg::OnErrorMsg) END_EVENT_TABLE() class EventDesktopConnector : public Barry::DesktopConnector { MigrateDlg *m_dlg; public: EventDesktopConnector(MigrateDlg *dlg, const char *password, const std::string &locale, const Barry::ProbeResult &result) : Barry::DesktopConnector(password, locale, result) , m_dlg(dlg) { } virtual bool PasswordPrompt(const Barry::BadPassword &bp, std::string &password_result); }; bool EventDesktopConnector::PasswordPrompt(const Barry::BadPassword &bp, std::string &password_result) { // ping the parent and wait for finish wxCommandEvent event(MET_PROMPT_PASSWORD, wxID_ANY); event.SetEventObject(m_dlg); event.SetInt(bp.remaining_tries()); m_dlg->AddPendingEvent(event); m_dlg->WaitForEvent(); password_result = m_dlg->GetPassword().utf8_str(); // assume that a blank password means the user wishes to quit... // wxWidgets doesn't seem to handle this very well? return password_result.size() > 0; } ////////////////////////////////////////////////////////////////////////////// // MigrateDlg class MigrateDlg::MigrateDlg(wxWindow *parent, const Barry::Probe::Results &results, int current_device_index) : wxDialog(parent, Dialog_GroupCfg, _W("Migrate Device")) , m_results(results) , m_current_device_index(current_device_index) , m_migrate_thread_created(false) , m_abort_flag(false) , m_thread_running(false) , m_source_device(0) , m_dest_device(0) , m_topsizer(0) , m_source_combo(0) , m_dest_combo(0) , m_write_mode_combo(0) , m_migrate_button(0) , m_wipe_check(0) , m_status(0) , m_progress(0) { // setup the raw GUI CreateLayout(); } void MigrateDlg::WaitForEvent() { m_waiter.Wait(); } void MigrateDlg::CreateLayout() { m_topsizer = new wxBoxSizer(wxVERTICAL); // AddDescriptionSizer(m_topsizer); AddMainSizer(m_topsizer); AddStatusSizer(m_topsizer); SetSizer(m_topsizer); m_topsizer->SetSizeHints(this); m_topsizer->Layout(); } void MigrateDlg::AddDescriptionSizer(wxSizer *sizer) { sizer->Add( new wxStaticText(this, wxID_ANY, _W("Migrate device data from source device to target device.")), 0, wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL | wxTOP | wxLEFT | wxRIGHT, 10); } void MigrateDlg::AddMainSizer(wxSizer *sizer) { // add 3 main sections together into one sizer wxSizer *main = new wxBoxSizer(wxHORIZONTAL); Main_AddSourceSizer(main); Main_AddButtonSizer(main); Main_AddDestSizer(main); // add main sizer to top level sizer sizer->Add(main, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 10); } void MigrateDlg::AddStatusSizer(wxSizer *sizer) { sizer->Add( new wxStaticLine(this), 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 10); sizer->Add( m_status = new wxStaticText(this, wxID_ANY, _W("Ready...")), 0, wxEXPAND | wxLEFT | wxRIGHT, 10); // Reduce font size for status text wxFont font = m_status->GetFont(); font.SetPointSize(font.GetPointSize() - 1); m_status->SetFont( font ); sizer->Add( m_progress = new wxGauge(this, wxID_ANY, 100), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 10); } void MigrateDlg::Main_AddSourceSizer(wxSizer *sizer) { wxArrayString devices; for( Barry::Probe::Results::const_iterator i = m_results.begin(); i != m_results.end(); ++i ) { devices.Add(wxString(i->GetDisplayName().c_str(), wxConvUTF8)); } wxSizer *source = new wxStaticBoxSizer( new wxStaticBox(this, wxID_ANY, _W("Source device")), wxVERTICAL ); source->Add( m_source_combo = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxSize(225, -1), devices), 0, wxALL, 5); if( m_current_device_index >= 0 ) m_source_combo->SetSelection(m_current_device_index); sizer->Add(source, 0, wxEXPAND, 0); } void MigrateDlg::Main_AddButtonSizer(wxSizer *sizer) { wxSizer *buttons = new wxBoxSizer(wxVERTICAL); buttons->Add( m_migrate_button = new wxButton(this, Dialog_Migrate_MigrateNowButton, _W("Migrate Now")), 0, wxALIGN_CENTRE, 0); m_migrate_button->SetDefault(); buttons->AddSpacer(10); buttons->Add( new wxButton(this, Dialog_Migrate_CancelButton, _W("Cancel")), 0, wxALIGN_CENTRE, 0); sizer->Add(buttons, 1, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 10); } void MigrateDlg::Main_AddDestSizer(wxSizer *sizer) { wxArrayString devices; devices.Add(_W("Prompt to plug in later...")); for( Barry::Probe::Results::const_iterator i = m_results.begin(); i != m_results.end(); ++i ) { devices.Add(wxString(i->GetDisplayName().c_str(), wxConvUTF8)); } wxSizer *dest = new wxStaticBoxSizer( new wxStaticBox(this, wxID_ANY, _W("Destination device")), wxVERTICAL ); dest->Add( m_dest_combo = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxSize(225, -1), devices), 0, wxALL, 5); m_dest_combo->SetSelection(0); wxArrayString write_modes; // TRANSLATORS: these 4 strings are write-mode options in the // Migrate Device dialog write_modes.Add(_W("Erase all, then restore")); write_modes.Add(_W("Add new, and overwrite existing")); write_modes.Add(_W("Add only, don't overwrite existing")); write_modes.Add(_W("Add every record as a new entry (may cause duplicates)")); dest->Add( new wxStaticText(this, wxID_ANY, _W("Write Mode:")), 0, wxTOP | wxLEFT | wxRIGHT, 5); dest->Add( m_write_mode_combo = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxSize(225, -1), write_modes), 0, wxALL, 5); m_write_mode_combo->SetSelection(0); // dest->Add( m_wipe_check = wxCheckBox(maybe a checkbox for "wipe device before restore")); sizer->Add(dest, 0, wxEXPAND, 0); } void MigrateDlg::EnableControls(bool enable) { m_source_combo->Enable(enable); m_dest_combo->Enable(enable); m_write_mode_combo->Enable(enable); m_migrate_button->Enable(enable); //m_wipe_check->Enable(enable); } void MigrateDlg::DoSafeClose() { // if migrate thread is running, try to close it down first... // do not exit the dialog until the thread is properly stopped! if( m_thread_running ) { m_abort_flag = true; m_status->SetLabel(_W("Waiting for thread to close...")); if( m_migrate_thread_created ) { void *junk; pthread_join(m_migrate_thread, &junk); m_migrate_thread_created = false; } } // all activity is stopped, so close dialog EndModal(wxID_CANCEL); } void MigrateDlg::SendEvent(int event_type) { wxCommandEvent event(event_type, wxID_ANY); event.SetEventObject(this); AddPendingEvent(event); } void MigrateDlg::SendStatusEvent(const wxString &msg, int pos, int max) { wxCommandEvent event(MET_SET_STATUS_MSG, wxID_ANY); event.SetEventObject(this); event.SetString(msg); int value = 0; if( pos == -1 ) value |= 0xff00; else value |= (pos << 8); if( max == -1 ) value |= 0xff; else value |= max & 0xff; event.SetInt(value); AddPendingEvent(event); } void MigrateDlg::SendErrorMsgEvent(const wxString &msg) { wxCommandEvent event(MET_ERROR_MSG, wxID_ANY); event.SetEventObject(this); event.SetString(msg); AddPendingEvent(event); } void MigrateDlg::OnMigrateNow(wxCommandEvent &event) { // gather info from dialog int source_index = m_source_combo->GetSelection(); int dest_index = m_dest_combo->GetSelection(); int write_mode_index = m_write_mode_combo->GetSelection(); // validate options if( source_index == wxNOT_FOUND || dest_index == wxNOT_FOUND || write_mode_index == wxNOT_FOUND ) { wxMessageBox(_W("Please select a source and destination device, as well as the write mode."), _W("Migration Options Needed"), wxOK | wxICON_ERROR, this); return; } // do not migrate from one PIN to the same PIN if( source_index == (dest_index - 1) ) { wxMessageBox(_W("Cannot migrate from and to the same PIN."), _W("Migration Options Error"), wxOK | wxICON_ERROR, this); return; } // set the migration arguments m_source_device = &m_results[source_index]; if( dest_index > 0 ) { m_dest_device = &m_results[dest_index-1]; } else { m_dest_device = 0; // an invalid dest causes a prompt } switch( write_mode_index ) { case 0: m_write_mode = Barry::DeviceParser::ERASE_ALL_WRITE_ALL; break; case 1: m_write_mode = Barry::DeviceParser::INDIVIDUAL_OVERWRITE; break; case 2: m_write_mode = Barry::DeviceParser::ADD_BUT_NO_OVERWRITE; break; case 3: m_write_mode = Barry::DeviceParser::ADD_WITH_NEW_ID; break; default: wxMessageBox(_W("Invalid write mode. This should never happen. Contact the developers."), _W("Internal Logic Error"), wxOK | wxICON_ERROR, this); return; } // disable all buttons and controls except cancel EnableControls(false); // turn off the stop flag m_abort_flag = false; m_thread_running = false; // fire up migrate thread, and let the thread close the dialog when // done (can we EndModal() from a thread?) int ret = pthread_create(&m_migrate_thread, NULL, &MigrateDlg::MigrateThread, this); if( ret != 0 ) { // go back to normal EnableControls(true); return; } else { m_migrate_thread_created = true; } // thread started... let it finish } void MigrateDlg::OnCancel(wxCommandEvent &event) { DoSafeClose(); } void MigrateDlg::OnCloseWindow(wxCloseEvent &event) { DoSafeClose(); } void MigrateDlg::OnThreadFinished(wxCommandEvent &event) { if( m_migrate_thread_created ) { m_status->SetLabel(_W("Waiting for thread...")); void *junk; pthread_join(m_migrate_thread, &junk); m_migrate_thread_created = false; } if( m_abort_flag ) { // user cancelled in some way, restore GUI EnableControls(true); m_status->SetLabel(_W("Cancelled by user...")); } else { // if we were not aborted, then this is success, and we // can close the original dialog EndModal(wxID_CANCEL); } } void MigrateDlg::OnCheckDestPin(wxCommandEvent &event) { ScopeSignaler done(m_waiter); if( m_dest_device && m_dest_device->m_pin.Valid() ) return; // nothing to do // no destination pin was available, so user may need to plugin // the new device right now, before continuing int response = wxMessageBox(_W("Please plug in the target device now."), _W("Ready for Writing"), wxOK | wxCANCEL | wxICON_INFORMATION, this); if( response != wxOK ) { // user cancelled m_abort_flag = true; return; } { wxBusyCursor wait; m_status->SetLabel(_W("Scanning USB for devices...")); // pause for 2 seconds to let any new devices settle down wxGetApp().Yield(); wxSleep(2); // rescan the USB and try to find the new device Barry::Probe probe; m_new_results = probe.GetResults(); } // now prompt the user... create a list of PIN display names wxArrayString devices; for( Barry::Probe::Results::const_iterator i = m_new_results.begin(); i != m_new_results.end(); ++i ) { devices.Add(wxString(i->GetDisplayName().c_str(), wxConvUTF8)); } m_status->SetLabel(_W("User input...")); do { // prompt the user with this list int choice = wxGetSingleChoiceIndex(_W("Please select the target device to write to:"), _W("Destination PIN"), devices, this); if( choice == -1 ) { // user cancelled m_abort_flag = true; return; } // found the new PIN to use! m_dest_device = &m_new_results[choice]; // check if user needs to choose again if( m_dest_device->m_pin == m_source_device->m_pin ) { wxMessageBox(_W("Cannot use the same device PIN as migration destination."), _W("Invalid Device Selection"), wxOK | wxICON_ERROR, this); } } while( m_dest_device->m_pin == m_source_device->m_pin ); } void MigrateDlg::OnSetStatusMsg(wxCommandEvent &event) { if( event.GetString().size() ) { m_status->SetLabel(event.GetString()); } if( (unsigned int)event.GetInt() != 0xffff ) { unsigned int value = (unsigned int) event.GetInt(); unsigned int pos = (value & 0xff00) >> 8; unsigned int max = (value & 0xff); if( pos != 0xff ) { m_progress->SetValue(pos); } if( max != 0xff ) { m_progress->SetRange(max); } } } void MigrateDlg::OnPromptPassword(wxCommandEvent &event) { ScopeSignaler done(m_waiter); // create prompt based on exception data wxString prompt = wxString::Format( _W("Please enter device password: (%d tries remaining)"), event.GetInt()); // ask user for device password m_password = wxGetPasswordFromUser(prompt, _W("Device Password"), _T(""), this); } void MigrateDlg::OnErrorMsg(wxCommandEvent &event) { ScopeSignaler done(m_waiter); wxMessageBox(event.GetString(), _W("Migration Error"), wxOK | wxICON_ERROR, this); } void* MigrateDlg::MigrateThread(void *arg) { MigrateDlg *us = (MigrateDlg*) arg; // we are running! us->m_thread_running = true; try { // backup source PIN us->BackupSource(); // make sure we have a destination PIN if( !us->m_abort_flag ) us->CheckDestPin(); // restore to dest PIN if( !us->m_abort_flag ) us->RestoreToDest(); } catch( std::exception &e ) { us->SendErrorMsgEvent(wxString(e.what(), wxConvUTF8)); us->m_waiter.Wait(); } // invalidate the device selection pointers, since // m_new_results may not always exist us->m_source_device = us->m_dest_device = 0; // we are done! us->m_thread_running = false; // send event to let main GUI thread we're finished us->SendEvent(MET_THREAD_FINISHED); return 0; } class PeekParser : public Barry::Parser { std::string m_dbname; public: virtual void ParseRecord(const Barry::DBData &data, const Barry::IConverter *ic) { m_dbname = data.GetDBName(); } const std::string& GetDBName() const { return m_dbname; } }; // This is called from the thread void MigrateDlg::BackupSource() { // connect to the source device SendStatusEvent(_W("Connecting...")); EventDesktopConnector connect(this, "", "utf-8", *m_source_device); if( !connect.Reconnect(2) ) { // user cancelled m_abort_flag = true; return; } // fetch DBDB, for list of databases to backup... back them all up // remember to save this DBDB into the class, so it is available // for the restore stage m_source_dbdb = connect.GetDesktop().GetDBDB(); unsigned int total = m_source_dbdb.GetTotalRecordCount(); // create DeviceBuilder for fetching all Barry::DeviceBuilder builder(connect.GetDesktop()); builder.Add(m_source_dbdb); // calculate the default backup path location, based on user name // (see backup GUI for code?) Barry::ConfigFile cfg(m_source_device->m_pin); Barry::ConfigFile::CheckPath(cfg.GetPath()); m_backup_tarfile = cfg.GetPath() + "/" + Barry::MakeBackupFilename(m_source_device->m_pin, "migrate"); // and create tarball output parser Barry::Backup parser(m_backup_tarfile); // create the pipe Barry::Pipe pipe(builder); PeekParser peeker; // create tee parser, so we can see what's being written Barry::TeeParser tee; tee.Add(peeker); tee.Add(parser); // setup status bar unsigned int count = 0; SendStatusEvent(_T(""), 0, 100); // cycle through all databases while( !builder.EndOfFile() ) { if( !pipe.PumpEntry(tee) ) continue; count++; // ok, first entry has been pumped, so we can use // peeker to create the status message, and only once ostringstream oss; oss << _C("Backing up database: ") << peeker.GetDBName() << "..."; // calculate 1 to 100 percentage, based on number of // databases being backed up, and update status bar too int percent = count / (float)total * 100.0; // send status event once SendStatusEvent(wxString(oss.str().c_str(),wxConvUTF8), percent); // backup the rest of the database, but don't update status // for each record int block = 0; while( pipe.PumpEntry(tee) ) { count++; block++; if( block >= 25 ) { int percent = count / (float)total * 100.0; SendStatusEvent(_T(""), percent); block = 0; } // on each record (pump cycle?), as often as possible, // check the m_abort_flag, and abort if necessary, // updating the status message if( m_abort_flag ) { SendStatusEvent(_W("Backup aborted by user...")); return; } } } // close all files, etc. parser.Close(); } // This is called from the thread void MigrateDlg::CheckDestPin() { SendEvent(MET_CHECK_DEST_PIN); m_waiter.Wait(); } // This is called from the thread void MigrateDlg::RestoreToDest() { // connect to the dest device SendStatusEvent(_W("Connecting to target...")); EventDesktopConnector connect(this, "", "utf-8", *m_dest_device); if( !connect.Reconnect(2) ) { // user cancelled m_abort_flag = true; return; } // fetch DBDB of dest device, for list of databases we can restore // to... compare with the backup DBDB to create a list of similarly // named databases which we can restore.... Barry::DatabaseDatabase dest_dbdb = connect.GetDesktop().GetDBDB(); // create the restore builder object, to read from tarball Barry::Restore builder(m_backup_tarfile); // add all database names from the _dest_ DBDB to the Restore // filter... this way, only databases that exist on the new // device will get restored builder.Add(dest_dbdb); unsigned int total = builder.GetRecordTotal();// counts filtered records // create device parser, to write to device Barry::DeviceParser parser(connect.GetDesktop(), m_write_mode); // create the pipe Barry::Pipe pipe(builder); // setup status bar unsigned int count = 0; SendStatusEvent(_T(""), 0, 100); // cycle through all databases Barry::DBData meta; // record meta data of next tar record while( !builder.EndOfFile() ) try { if( !builder.GetNextMeta(meta) ) continue; // ok, first entry has been pumped, so we can use // peeker to create the status message, and only once ostringstream oss; oss << _C("Writing database: ") << meta.GetDBName() << "..."; // for debugging purposes in the field, display the names // of the databases we restore cerr << oss.str() << endl; // calculate 1 to 100 percentage, based on number of // databases being backed up, and update status bar too int percent = count / (float)total * 100.0; // send status event once SendStatusEvent(wxString(oss.str().c_str(),wxConvUTF8), percent); // restore the rest of the database, but don't update status // for each record int block = 0; while( pipe.PumpEntry(parser) ) { count++; block++; if( block >= 25 ) { int percent = count / (float)total * 100.0; SendStatusEvent(_T(""), percent); block = 0; } // on each record (pump cycle?), as often as possible, // check the m_abort_flag, and abort if necessary, // updating the status message if( m_abort_flag ) { SendStatusEvent(_W("Restore aborted by user...")); return; } } } catch( Barry::ReturnCodeError &e ) { cerr << _C("Unable to clear or write to database: ") << meta.GetDBName() << ": " << e.what() << endl; cerr << _C("Continuing to process remaining records...") << endl; // skip the problematic database, and keep on trying builder.SkipCurrentDB(); } } barry-0.18.5/desktop/src/tempdir.cc0000644001161500056700000000323512242254476016472 0ustar cdfreycdfrey/// /// \file tempdir.cc /// Temp directory & file wrapper class /// /* Copyright (C) 2009-2013, Chris Frey The idea to use glib's g_get_tmp_dir() came from opensync's osynctool. 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 in the COPYING file at the root directory of this project for more details. */ #include "tempdir.h" #include #include #include #include #include #include #include #include "i18n.h" TempDir::TempDir(const char *basename) : m_template(0) , m_files(0) { m_template = g_strdup_printf("%s/%s-XXXXXX", g_get_tmp_dir(), basename); if( mkdtemp(m_template) == NULL ) { g_free(m_template); throw std::runtime_error(std::string(_C("Cannot create temp directory: ")) + strerror(errno)); } } TempDir::~TempDir() { // delete all files for( int i = 0; i < m_files; i++ ) { unlink(MakeFilename(i).c_str()); } // delete directory rmdir(m_template); // cleanup memory g_free(m_template); } std::string TempDir::MakeFilename(int file_id) const { std::ostringstream oss; oss << m_template << "/" << file_id; return oss.str(); } std::string TempDir::GetNewFilename() { return MakeFilename(m_files++); } barry-0.18.5/desktop/src/bsyncjail.cc0000644001161500056700000002145312242254476017006 0ustar cdfreycdfrey/// /// \file bsyncjail.cc /// Helper program to isolate the actual syncing into its /// own process. Communicates with the main barrydesktop /// via wxWidgets IPC communication. This belongs in its /// own process since the sync can hang, and may need to /// be killed from the GUI. /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include #include #include #include "ipc.h" #include "os22.h" #include "os40.h" #include "tempdir.h" #include "ostypes.h" #include "wxi18n.h" using namespace std; // command line arguments string g_argv_version, g_argv_group_name; OpenSync::Config::pst_type g_sync_types = PST_DO_NOT_SET; SillyBuffer sb; class ClientConnection : public wxConnection { public: ClientConnection() {} }; class Client : public wxClient { public: Client() {} ClientConnection* OnMakeConnection() { return new ClientConnection; } }; class BarrySyncJail : public OpenSync::SyncStatus { private: TempDir m_temp; std::auto_ptr m_engine; std::auto_ptr m_client; wxConnectionBase *m_status_con, *m_conflict_con; // communication variables int m_sequenceID; public: BarrySyncJail(); ~BarrySyncJail(); // // overrides // virtual bool OnInit(); virtual int OnExit(); // // OpenSync::SyncStatus virtual overrides // virtual void HandleConflict(OpenSync::SyncConflict &conflict); virtual void EntryStatus(const std::string &msg, bool error); virtual void MappingStatus(const std::string &msg, bool error); virtual void EngineStatus(const std::string &msg, bool error, bool slowsync); virtual void MemberStatus(long member_id, const std::string &plugin_name, const std::string &msg, bool error); virtual void CheckSummary(OpenSync::SyncSummary &summary); virtual void ReportError(const std::string &msg); }; DECLARE_APP(BarrySyncJail) ////////////////////////////////////////////////////////////////////////////// // BarrySyncJail BarrySyncJail::BarrySyncJail() : m_temp("bsyncjail") , m_status_con(0) , m_conflict_con(0) , m_sequenceID(0) { OnInit(); } BarrySyncJail::~BarrySyncJail() { } bool BarrySyncJail::OnInit() { cerr << "OnInit()" << endl; // connect to parent app m_client.reset( new Client ); m_status_con = m_client->MakeConnection(_T("localhost"), SERVER_SERVICE_NAME, TOPIC_STATUS); m_conflict_con = m_client->MakeConnection(_T("localhost"), SERVER_SERVICE_NAME, TOPIC_CONFLICT); if( !m_status_con || !m_conflict_con ) { cerr << _C("Unable to connect to server.") << endl; return false; } // load opensync engine try { if( g_argv_version.substr(0, 3) == "0.2" ) m_engine.reset( new OpenSync::OpenSync22 ); else { m_engine.reset( new OpenSync::OpenSync40 ); if( g_argv_version != m_engine->GetVersion() ) throw std::runtime_error(_C("Can't find matching engine for: ") + g_argv_version); } } catch( std::exception &e ) { m_status_con->Poke(STATUS_ITEM_ERROR, sb.buf(e.what())); cerr << e.what() << endl; return false; } if( !m_engine.get() ) { m_status_con->Poke(STATUS_ITEM_ERROR, sb.buf(string(_C("Unknown engine number: ")) + g_argv_version)); return false; } // start the sync try { m_engine->Discover(g_argv_group_name); m_engine->Sync(g_argv_group_name, *this, g_sync_types); } catch( std::exception &e ) { m_status_con->Poke(STATUS_ITEM_ERROR, sb.buf(e.what())); cerr << e.what() << endl; return true; } return true; } int BarrySyncJail::OnExit() { cerr << "OnExit()" << endl; // clean up the client connection... do this early, so that // TempDir can clean up the files if necessary m_client.reset(); return 0; } // // OpenSync::SyncStatus virtual overrides // void BarrySyncJail::HandleConflict(OpenSync::SyncConflict &conflict) { OpenSync::SyncConflict::iterator i; int size = 0; wxChar *buf = 0; // start with a new sequence ID m_sequenceID++; int offset = 0; // msg 1: sequence ID, offset 0 // send available menu / functions possible, and number of // changes that conflict ostringstream oss; oss << m_sequenceID << " " << offset << " " << conflict.size() << " " << "SD"; if( conflict.IsAbortSupported() ) oss << "A"; if( conflict.IsIgnoreSupported() ) oss << "I"; if( conflict.IsKeepNewerSupported() ) oss << "N"; if( !m_conflict_con->Poke(CONFLICT_ITEM_START, sb.buf(oss.str())) ) goto connection_lost; // all following messages contain the sequence ID, // the change ID, and the change data i = conflict.begin(); for( ; i != conflict.end(); ++i ) { oss.str(""); offset++; oss << m_sequenceID << " " << offset << " " << i->id << " \n"; oss << i->plugin_name << "\n"; oss << i->uid << "\n"; oss << i->printable_data; if( !m_conflict_con->Poke(CONFLICT_ITEM_CHANGE, sb.buf(oss.str())) ) goto connection_lost; } // then wait on the server to tell us what choice was made buf = m_conflict_con->Request(CONFLICT_ITEM_ANSWER, &size); if( buf ) { wxString msg(buf); istringstream iss(string(msg.utf8_str())); int sequenceID = 0; string command; int id; iss >> sequenceID >> command; if( !iss || sequenceID != m_sequenceID ) { // invalid command from server, something is wrong throw std::runtime_error(_C("Invalid server response: ") + string(msg.utf8_str())); } switch( command[0] ) { case 'S': // Select iss >> id; if( !iss ) throw std::runtime_error(_C("Invalid Select command from server: ") + string(msg.utf8_str())); conflict.Select(id); break; case 'D': // Duplicate conflict.Duplicate(); break; case 'A': // Abort if( !conflict.IsAbortSupported() ) throw std::runtime_error(_C("Abort not supported, and server sent Abort command.")); conflict.Abort(); break; case 'I': // Ignore if( !conflict.IsIgnoreSupported() ) throw std::runtime_error(_C("Ignore not supported, and server sent Ignore command.")); conflict.Ignore(); break; case 'N': // Keep Newer if( !conflict.IsKeepNewerSupported() ) throw std::runtime_error(_C("Keep Newer not supported, and server sent Keep Newer command.")); conflict.KeepNewer(); break; default: throw std::runtime_error(_C("Invalid command from server: ") + string(msg.utf8_str())); } // all done! return; } connection_lost: if( conflict.IsAbortSupported() ) conflict.Abort(); else throw std::runtime_error(_C("Lost connection with server")); } void BarrySyncJail::EntryStatus(const std::string &msg, bool error) { if( error ) ReportError(msg); else m_status_con->Poke(STATUS_ITEM_ENTRY, sb.buf(msg)); } void BarrySyncJail::MappingStatus(const std::string &msg, bool error) { if( error ) ReportError(msg); else m_status_con->Poke(STATUS_ITEM_MAPPING, sb.buf(msg)); } void BarrySyncJail::EngineStatus(const std::string &msg, bool error, bool slowsync) { if( error ) ReportError(msg); else m_status_con->Poke(STATUS_ITEM_ENGINE, sb.buf(msg)); // slow sync on 0.22 is unreliable... send a special notice // to the GUI if( slowsync && !m_engine->IsSlowSyncSupported() ) m_status_con->Poke(STATUS_ITEM_ENGINE, sb.buf(ENGINE_STATUS_SLOW_SYNC)); } void BarrySyncJail::MemberStatus(long member_id, const std::string &plugin_name, const std::string &msg, bool error) { if( error ) ReportError(msg); else m_status_con->Poke(STATUS_ITEM_MEMBER, sb.buf(msg)); } void BarrySyncJail::CheckSummary(OpenSync::SyncSummary &summary) { // FIXME: not currently supported... abort every time // cerr << "FIXME: CheckSummary() not implemented, aborting" << endl; // summary.Abort(); summary.Continue(); } void BarrySyncJail::ReportError(const std::string &msg) { m_status_con->Poke(STATUS_ITEM_ERROR, sb.buf(msg)); cerr << "ReportError(): " << msg << endl; } int main(int argc, char *argv[]) { INIT_I18N(PACKAGE); wxApp::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, "bsyncjail"); cerr << "bsyncjail startup" << endl; if( argc != 4 ) { cerr << _C("This is a helper program for barrydesktop, and\n" "is not intended to be called directly.\n") << endl; return 1; } g_argv_version = argv[1]; g_argv_group_name = argv[2]; g_sync_types = atoi(argv[3]); wxInitializer initializer; if( !initializer ) { cerr << _C("Unable to initialize wxWidgets library, aborting.") << endl; return 1; } BarrySyncJail app; int ret = app.OnExit(); cerr << _C("bsyncjail exiting with code: ") << ret << endl; return ret; } barry-0.18.5/desktop/src/CUI_Evolution.h0000644001161500056700000000417712242254476017362 0ustar cdfreycdfrey/// /// \file CUI_Evolution.h /// ConfigUI derived class to configure the Evolution App /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_CUI_EVOLUTION_H__ #define __BARRY_CUI_EVOLUTION_H__ #include "configui.h" #include "osconfig.h" #include class wxWindow; namespace AppConfig { class EvolutionPtrBase : public ConfigUI { private: OpenSync::Config::Evolution *m_evolution; protected: plugin_ptr m_container; // merely holds m_evolution protected: EvolutionPtrBase(); // by default, creates Evolution object... override for others virtual void AcquirePlugin(plugin_ptr old_plugin); virtual OpenSync::Config::Evolution* GetEvolutionPtr(); virtual void Clear(); public: virtual plugin_ptr GetPlugin(); }; class Evolution : public EvolutionPtrBase { private: // convenience pointers wxWindow *m_parent; protected: bool InitialRun(); public: Evolution(); // virtual overrides (ConfigUI) virtual std::string AppName() const; virtual bool Configure(wxWindow *parent, plugin_ptr old_plugin); virtual bool RunApp(wxWindow *parent); virtual void PreSyncAppInit(); virtual bool ZapData(wxWindow *parent, plugin_ptr plugin, OpenSync::API *engine); // static utility functions static long ForceShutdown(); }; class Evolution3 : public Evolution { private: OpenSync::Config::Evolution3 *m_evolution3; protected: virtual void AcquirePlugin(plugin_ptr old_plugin); virtual OpenSync::Config::Evolution* GetEvolutionPtr(); virtual void Clear(); public: Evolution3(); virtual plugin_ptr GetPlugin(); }; } #endif barry-0.18.5/desktop/src/CUI_KDEPim.cc0000644001161500056700000000525512242254476016603 0ustar cdfreycdfrey/// /// \file CUI_KDEPim.cc /// ConfigUI derived class to configure the KDEPim App /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "CUI_KDEPim.h" #include "os22.h" // only for the dynamic_cast #include #include #include "wxi18n.h" namespace AppConfig { ////////////////////////////////////////////////////////////////////////////// // KDEPim config UI class KDEPim::KDEPim() : m_kdepim(0) , m_parent(0) { } std::string KDEPim::AppName() const { return OpenSync::Config::KDEPim::AppName(); } bool KDEPim::Configure(wxWindow *parent, plugin_ptr old_plugin) { m_parent = parent; // create our plugin config m_kdepim = dynamic_cast (old_plugin.get()); if( m_kdepim ) { m_kdepim = m_kdepim->Clone(); } else { m_kdepim = new OpenSync::Config::KDEPim; } m_container.reset( m_kdepim ); // tell the user all went well wxMessageBox(_W("KDEPim needs no configuration."), _W("KDEPim Config"), wxOK | wxICON_INFORMATION, m_parent); return true; } ConfigUI::plugin_ptr KDEPim::GetPlugin() { m_kdepim = 0; return m_container; } bool KDEPim::RunApp(wxWindow *parent) { return Run(parent, AppName(), _T("kontact")); } void KDEPim::PreSyncAppInit() { } bool KDEPim::ZapData(wxWindow *parent, plugin_ptr plugin, OpenSync::API *engine) { m_parent = parent; if( IsAppRunning() ) { wxMessageBox(_W("Kontact already running."), _W("Oops..."), wxOK | wxICON_INFORMATION, m_parent); return false; } // tell the user what to do wxString msg; if( dynamic_cast(engine) ) { msg = _W( "Starting Kontact. Delete all contacts and calendar " "entries manually."); } else { msg = _W( "Starting Kontact. Delete all contacts and calendar " "entries manually (as well as memos and tasks if you are " "syncing them too)." ); } int choice = wxMessageBox(msg, _W("Starting Kontact"), wxOK | wxCANCEL | wxICON_QUESTION, m_parent); if( choice != wxOK ) return false; RunApp(parent); // Kontact forks, so we just have to trust that the user did it :-( return true; } } // namespace AppConfig barry-0.18.5/desktop/src/ostypes.h0000644001161500056700000000265612242254476016404 0ustar cdfreycdfrey/// /// \file ostypes.h /// Low level types for os wrapper library /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_OSTYPES_H__ #define __BARRYDESKTOP_OSTYPES_H__ #include // Bitmap field, determining what sync types are supported // PST = Plugin Sync Type #define PST_NONE 0x00 #define PST_CONTACTS 0x01 #define PST_EVENTS 0x02 #define PST_NOTES 0x04 #define PST_TODOS 0x08 #define PST_ALL 0x0f #define PST_DO_NOT_SET 0x10000000 // used by the engine to signal // an attempt to run without // specifying supported types... // i.e. just run with default // efforts namespace OpenSync { namespace Config { typedef unsigned int pst_type; // Handy conversion functions pst_type PSTString2Type(const std::string &pst_string); std::string PSTType2String(pst_type types); }} #endif barry-0.18.5/desktop/src/TaskEditDlg.cc0000644001161500056700000005735012242254476017174 0ustar cdfreycdfrey/// /// \file TaskEditDlg.cc /// Dialog class to handle the editing of the Task record /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "TaskEditDlg.h" #include "windowids.h" #include #include "wxval.h" #include "util.h" using namespace std; using namespace Barry; // begin wxGlade: ::extracode // end wxGlade ////////////////////////////////////////////////////////////////////////////// // TaskEditDlg class TaskEditDlg::TaskEditDlg(wxWindow* parent, Barry::Task &rec, bool editable, const Barry::TimeZones *device_zones) : wxDialog(parent, Dialog_TaskEdit, _W("Task Record")) , m_zones(device_zones ? device_zones : &m_static_zones) , m_rec(rec) , m_reminder_hours(0) , m_reminder_minutes(0) , m_interval(0) , m_relative_date(false) { // set all weekday 'bits' to false for( int i = 0; i < 7; i++ ) m_weekdays[i] = false; if( editable ) { bottom_buttons = CreateButtonSizer(wxOK | wxCANCEL); } else { bottom_buttons = CreateButtonSizer(wxCANCEL); } // begin wxGlade: TaskEditDlg::TaskEditDlg label_1 = new wxStaticText(this, wxID_ANY, _W("Task:")); m_TaskSummary = new wxTextCtrl(this, wxID_ANY, wxEmptyString); static_line_1 = new wxStaticLine(this, wxID_ANY); label_2 = new wxStaticText(this, wxID_ANY, _W("Status:")); /* const wxString m_StatusChoice_choices[] = { wxT("Not Started"), wxT("In Progress"), wxT("Completed"), wxT("Waiting"), wxT("Deferred") }; */ wxArrayString m_StatusChoice_choices; m_StatusChoice_choices.Add( _W("Not Started") ); m_StatusChoice_choices.Add( _W("In Progress") ); m_StatusChoice_choices.Add( _W("Completed") ); m_StatusChoice_choices.Add( _W("Waiting") ); m_StatusChoice_choices.Add( _W("Deferred") ); m_StatusChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_StatusChoice_choices, 0); label_9 = new wxStaticText(this, wxID_ANY, _W("Priority:")); /* const wxString m_PriorityChoice_choices[] = { wxT("High"), wxT("Normal"), wxT("Low") }; */ wxArrayString m_PriorityChoice_choices; m_PriorityChoice_choices.Add( _W("High") ); m_PriorityChoice_choices.Add( _W("Normal") ); m_PriorityChoice_choices.Add( _W("Low") ); m_PriorityChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_PriorityChoice_choices, 0); label_5 = new wxStaticText(this, wxID_ANY, _W("Due:")); m_DueCheck = new wxCheckBox(this, Dialog_TaskEdit_DueCheck, wxEmptyString); m_DueDateCtrl = new wxDatePickerCtrl(this, Dialog_TaskEdit_DueDateCtrl, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxDP_DROPDOWN|wxDP_SHOWCENTURY); m_DueHoursSpinner = new wxSpinCtrl(this, Dialog_TaskEdit_DueHoursSpinner, wxT(""), wxDefaultPosition, wxDefaultSize, wxSP_WRAP|wxTE_NOHIDESEL, 0, 23); label_11 = new wxStaticText(this, wxID_ANY, wxT(":")); m_DueMinutesSpinner = new wxSpinCtrl(this, Dialog_TaskEdit_DueMinutesSpinner, wxT(""), wxDefaultPosition, wxDefaultSize, wxSP_WRAP|wxTE_NOHIDESEL, 0, 59); label_8 = new wxStaticText(this, wxID_ANY, _W("Time Zone:")); const wxString m_TimezoneChoice_choices[] = { wxT("System Time Zone") }; m_TimezoneChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 1, m_TimezoneChoice_choices, 0); label_10 = new wxStaticText(this, wxID_ANY, _W("Reminder:")); m_ReminderCheck = new wxCheckBox(this, Dialog_TaskEdit_ReminderCheck, wxEmptyString); m_ReminderDateCtrl = new wxDatePickerCtrl(this, Dialog_TaskEdit_ReminderDateCtrl); m_ReminderHoursSpinner = new wxSpinCtrl(this, Dialog_TaskEdit_ReminderHoursSpinner, wxT(""), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 999); label_6 = new wxStaticText(this, wxID_ANY, wxT(":")); m_ReminderMinutesSpinner = new wxSpinCtrl(this, Dialog_TaskEdit_ReminderMinutesSpinner, wxT(""), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 59); static_line_2 = new wxStaticLine(this, wxID_ANY); label_18 = new wxStaticText(this, wxID_ANY, _W("Recurrence:")); /* const wxString m_RecurrenceChoice_choices[] = { wxT("None"), wxT("Daily"), wxT("Weekly"), wxT("Monthly"), wxT("Yearly") }; */ wxArrayString m_RecurrenceChoice_choices; m_RecurrenceChoice_choices.Add( _W("None") ); m_RecurrenceChoice_choices.Add( _W("Daily") ); m_RecurrenceChoice_choices.Add( _W("Weekly") ); m_RecurrenceChoice_choices.Add( _W("Monthly") ); m_RecurrenceChoice_choices.Add( _W("Yearly") ); m_RecurrenceChoice = new wxChoice(this, Dialog_TaskEdit_RecurrenceChoice, wxDefaultPosition, wxDefaultSize, m_RecurrenceChoice_choices, 0); RecurIntervalLabel = new wxStaticText(this, wxID_ANY, _W("Interval:")); RecurIntervalLabelB = new wxStaticText(this, wxID_ANY, _W("Every")); m_IntervalSpinner = new wxSpinCtrl(this, wxID_ANY, wxT("1"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 999); m_IntervalUnitLabel = new wxStaticText(this, wxID_ANY, _W("days? weeks? months?"), wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE); RecurDaysLabel = new wxStaticText(this, wxID_ANY, _W("Days:")); m_SunCheck = new wxCheckBox(this, wxID_ANY, wxT("S")); m_MonCheck = new wxCheckBox(this, wxID_ANY, wxT("M")); m_TueCheck = new wxCheckBox(this, wxID_ANY, wxT("T")); m_WedCheck = new wxCheckBox(this, wxID_ANY, wxT("W")); m_ThuCheck = new wxCheckBox(this, wxID_ANY, wxT("T")); m_FriCheck = new wxCheckBox(this, wxID_ANY, wxT("F")); m_SatCheck = new wxCheckBox(this, wxID_ANY, wxT("S")); RecurRelativeDateLabel = new wxStaticText(this, wxID_ANY, _W("Relative Date:")); m_RelativeDateCheck = new wxCheckBox(this, wxID_ANY, wxEmptyString); RecurEndDateLabel = new wxStaticText(this, wxID_ANY, _W("End Date:")); m_NeverEndsCheck = new wxCheckBox(this, Dialog_TaskEdit_NeverEndsCheck, _W("Never ends")); m_RecurEndDateCtrl = new wxDatePickerCtrl(this, wxID_ANY, wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxDP_DROPDOWN|wxDP_SHOWCENTURY); static_line_3 = new wxStaticLine(this, wxID_ANY); label_4 = new wxStaticText(this, wxID_ANY, _W("Categories:")); m_CategoriesText = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_3 = new wxStaticText(this, wxID_ANY, _W("Notes:")); m_NotesText = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); set_properties(); do_layout(); // end wxGlade m_top_sizer->Add(bottom_buttons, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 5); // fill the time zone control with real time zones m_TimezoneChoice->Clear(); m_TimezoneChoice->Append(_W("Assume Local Timezone"), (void*)0); Barry::TimeZones::const_iterator b, e; for( b = m_zones->begin(), e = m_zones->end(); b != e; ++b ) { m_TimezoneChoice->Append( wxString(b->GetDescription().c_str(), wxConvUTF8), (void*) &b->Index); } m_TimezoneChoice->SetSelection(0); // layout again, in case sizes are different RedoLayout(); } void TaskEditDlg::RedoLayout() { m_top_sizer->Fit(this); Layout(); } BEGIN_EVENT_TABLE(TaskEditDlg, wxDialog) // begin wxGlade: TaskEditDlg::event_table EVT_CHECKBOX(Dialog_TaskEdit_DueCheck, TaskEditDlg::OnDueCheck) EVT_CHECKBOX(Dialog_TaskEdit_ReminderCheck, TaskEditDlg::OnReminderCheck) EVT_CHOICE(Dialog_TaskEdit_RecurrenceChoice, TaskEditDlg::OnRecurrenceChoice) EVT_CHECKBOX(Dialog_TaskEdit_NeverEndsCheck, TaskEditDlg::OnEndDateCheckbox) // end wxGlade END_EVENT_TABLE(); // wxGlade: add TaskEditDlg event handlers void TaskEditDlg::OnDueCheck(wxCommandEvent &event) { EnableDueDate(m_DueCheck->IsChecked()); // make sure the first date is in a recent range, if not previously // valid... MakeDateRecent(m_DueCheck->IsChecked(), m_DueDateCtrl); } void TaskEditDlg::OnRecurrenceChoice(wxCommandEvent &event) { TransferDataFromWindow(); EnableRecurMode(m_rec.Recurring); } void TaskEditDlg::OnEndDateCheckbox(wxCommandEvent &event) { m_RecurEndDateCtrl->Enable( !m_NeverEndsCheck->IsChecked() ); // make sure there is a recent date in the ctrl MakeDateRecent(!m_NeverEndsCheck->IsChecked(), m_RecurEndDateCtrl); } void TaskEditDlg::OnReminderCheck(wxCommandEvent &event) { EnableReminderDate(m_ReminderCheck->IsChecked()); // make sure the first date is in a recent range, if not previously // valid... MakeDateRecent(m_ReminderCheck->IsChecked(), m_ReminderDateCtrl); } void TaskEditDlg::set_properties() { // begin wxGlade: TaskEditDlg::set_properties SetTitle(_W("Task Event")); m_TaskSummary->SetFocus(); m_TaskSummary->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Summary))); m_StatusChoice->SetSelection(0); m_PriorityChoice->SetSelection(1); m_DueDateCtrl->SetMinSize(wxSize(110, -1)); m_DueDateCtrl->SetValidator(DateTimeValidator(&m_DueDateObj.m_date)); m_DueHoursSpinner->SetMinSize(wxSize(45, -1)); m_DueHoursSpinner->SetValidator(wxGenericValidator(&m_DueDateObj.m_hour)); m_DueMinutesSpinner->SetMinSize(wxSize(45, -1)); m_DueMinutesSpinner->SetValidator(wxGenericValidator(&m_DueDateObj.m_min)); m_TimezoneChoice->SetSelection(0); m_ReminderDateCtrl->SetMinSize(wxSize(110, -1)); m_ReminderDateCtrl->SetValidator(DateTimeValidator(&m_ReminderDateObj.m_date)); m_ReminderHoursSpinner->SetMinSize(wxSize(45, -1)); m_ReminderHoursSpinner->SetToolTip(_W("Set Reminder to 0 to disable")); m_ReminderHoursSpinner->SetValidator(wxGenericValidator(&m_ReminderDateObj.m_hour)); m_ReminderMinutesSpinner->SetMinSize(wxSize(45, -1)); m_ReminderMinutesSpinner->SetToolTip(_W("Set Reminder to 0 to disable")); m_ReminderMinutesSpinner->SetValidator(wxGenericValidator(&m_ReminderDateObj.m_min)); m_RecurrenceChoice->SetValidator(wxGenericValidator(&m_recur_choice)); m_RecurrenceChoice->SetSelection(0); m_IntervalSpinner->SetMinSize(wxSize(45, -1)); m_IntervalSpinner->SetValidator(wxGenericValidator(&m_interval)); m_SunCheck->SetValidator(wxGenericValidator(&m_weekdays[0])); m_MonCheck->SetValidator(wxGenericValidator(&m_weekdays[1])); m_TueCheck->SetValidator(wxGenericValidator(&m_weekdays[2])); m_WedCheck->SetValidator(wxGenericValidator(&m_weekdays[3])); m_ThuCheck->SetValidator(wxGenericValidator(&m_weekdays[4])); m_FriCheck->SetValidator(wxGenericValidator(&m_weekdays[5])); m_SatCheck->SetValidator(wxGenericValidator(&m_weekdays[6])); RecurRelativeDateLabel->SetToolTip(_W("Relative monthly or yearly dates take the weekday of the start date into account. (eg. every first Sunday of month)")); m_RelativeDateCheck->SetToolTip(_W("Relative monthly or yearly dates take the weekday of the start date into account. (eg. every first Sunday of month)")); m_RelativeDateCheck->SetValidator(wxGenericValidator(&m_relative_date)); m_NeverEndsCheck->SetValidator(wxGenericValidator(&m_rec.Perpetual)); m_NeverEndsCheck->SetValue(1); m_RecurEndDateCtrl->SetMinSize(wxSize(110, -1)); m_RecurEndDateCtrl->Enable(false); m_RecurEndDateCtrl->SetValidator(DateTimeValidator(&m_RecurEndDateObj.m_date)); m_CategoriesText->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_categories))); m_NotesText->SetMinSize(wxSize(-1, 71)); m_NotesText->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Notes))); // end wxGlade } void TaskEditDlg::do_layout() { // begin wxGlade: TaskEditDlg::do_layout wxBoxSizer* sizer_surround = new wxBoxSizer(wxVERTICAL); wxBoxSizer* sizer_1 = new wxBoxSizer(wxVERTICAL); wxFlexGridSizer* grid_sizer_3 = new wxFlexGridSizer(2, 2, 5, 5); wxFlexGridSizer* grid_sizer_4 = new wxFlexGridSizer(5, 2, 5, 5); wxBoxSizer* sizer_8 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* m_DaysCtrlsSizer = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* m_IntervalCtrlsSizer = new wxBoxSizer(wxHORIZONTAL); wxFlexGridSizer* grid_sizer_2 = new wxFlexGridSizer(10, 2, 5, 5); wxBoxSizer* sizer_5_copy = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* sizer_3 = new wxBoxSizer(wxHORIZONTAL); wxFlexGridSizer* grid_sizer_1 = new wxFlexGridSizer(2, 2, 5, 5); grid_sizer_1->Add(label_1, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1->Add(m_TaskSummary, 0, wxEXPAND, 0); grid_sizer_1->AddGrowableCol(1); sizer_1->Add(grid_sizer_1, 0, wxEXPAND, 0); sizer_1->Add(static_line_1, 0, wxALL|wxEXPAND, 5); grid_sizer_2->Add(label_2, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_2->Add(m_StatusChoice, 0, 0, 0); grid_sizer_2->Add(label_9, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_2->Add(m_PriorityChoice, 0, 0, 0); grid_sizer_2->Add(label_5, 0, wxALIGN_CENTER_VERTICAL, 0); sizer_3->Add(m_DueCheck, 0, 0, 0); sizer_3->Add(m_DueDateCtrl, 0, 0, 0); sizer_3->Add(20, 20, 0, 0, 0); sizer_3->Add(m_DueHoursSpinner, 0, 0, 0); sizer_3->Add(label_11, 0, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 1); sizer_3->Add(m_DueMinutesSpinner, 0, 0, 0); grid_sizer_2->Add(sizer_3, 1, wxEXPAND, 0); grid_sizer_2->Add(label_8, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_2->Add(m_TimezoneChoice, 0, 0, 0); grid_sizer_2->Add(label_10, 0, wxALIGN_CENTER_VERTICAL, 0); sizer_5_copy->Add(m_ReminderCheck, 0, 0, 0); sizer_5_copy->Add(m_ReminderDateCtrl, 0, 0, 0); sizer_5_copy->Add(20, 20, 0, 0, 0); sizer_5_copy->Add(m_ReminderHoursSpinner, 0, 0, 5); sizer_5_copy->Add(label_6, 0, wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL, 1); sizer_5_copy->Add(m_ReminderMinutesSpinner, 0, wxRIGHT, 5); grid_sizer_2->Add(sizer_5_copy, 1, wxEXPAND, 0); grid_sizer_2->AddGrowableCol(1); sizer_1->Add(grid_sizer_2, 0, wxEXPAND, 0); sizer_1->Add(static_line_2, 0, wxALL|wxEXPAND, 5); grid_sizer_4->Add(label_18, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_4->Add(m_RecurrenceChoice, 0, 0, 0); grid_sizer_4->Add(RecurIntervalLabel, 0, wxALIGN_CENTER_VERTICAL, 0); m_IntervalCtrlsSizer->Add(RecurIntervalLabelB, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5); m_IntervalCtrlsSizer->Add(m_IntervalSpinner, 0, wxRIGHT, 5); m_IntervalCtrlsSizer->Add(m_IntervalUnitLabel, 1, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_4->Add(m_IntervalCtrlsSizer, 1, wxEXPAND, 0); grid_sizer_4->Add(RecurDaysLabel, 0, wxALIGN_CENTER_VERTICAL, 0); m_DaysCtrlsSizer->Add(m_SunCheck, 0, wxRIGHT, 5); m_DaysCtrlsSizer->Add(m_MonCheck, 0, wxRIGHT, 5); m_DaysCtrlsSizer->Add(m_TueCheck, 0, wxRIGHT, 5); m_DaysCtrlsSizer->Add(m_WedCheck, 0, wxRIGHT, 5); m_DaysCtrlsSizer->Add(m_ThuCheck, 0, wxRIGHT, 5); m_DaysCtrlsSizer->Add(m_FriCheck, 0, wxRIGHT, 5); m_DaysCtrlsSizer->Add(m_SatCheck, 0, wxRIGHT, 5); grid_sizer_4->Add(m_DaysCtrlsSizer, 1, wxEXPAND, 0); grid_sizer_4->Add(RecurRelativeDateLabel, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_4->Add(m_RelativeDateCheck, 0, 0, 0); grid_sizer_4->Add(RecurEndDateLabel, 0, wxALIGN_CENTER_VERTICAL, 0); sizer_8->Add(m_NeverEndsCheck, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 10); sizer_8->Add(m_RecurEndDateCtrl, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_4->Add(sizer_8, 1, wxEXPAND, 0); grid_sizer_4->AddGrowableCol(1); sizer_1->Add(grid_sizer_4, 0, wxEXPAND, 0); sizer_1->Add(static_line_3, 0, wxALL|wxEXPAND, 5); grid_sizer_3->Add(label_4, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_3->Add(m_CategoriesText, 0, wxEXPAND, 0); grid_sizer_3->Add(label_3, 0, wxRIGHT, 5); grid_sizer_3->Add(m_NotesText, 1, wxEXPAND, 0); grid_sizer_3->AddGrowableCol(1); sizer_1->Add(grid_sizer_3, 1, wxEXPAND, 0); sizer_surround->Add(sizer_1, 1, wxALL|wxEXPAND, 10); SetSizer(sizer_surround); sizer_surround->Fit(this); Layout(); // end wxGlade m_top_sizer = sizer_surround; } bool TaskEditDlg::TransferDataToWindow() { // prepare temporary variables, from record m_rec.Categories.CategoryList2Str(m_categories); // due time m_DueCheck->SetValue(m_rec.DueTime.IsValid()); EnableDueDate(m_rec.DueTime.IsValid()); m_DueDateObj.Set(m_rec.DueTime.Time); // alarm / reminder time m_ReminderCheck->SetValue(m_rec.AlarmTime.IsValid()); EnableReminderDate(m_rec.AlarmTime.IsValid()); m_ReminderDateObj.Set(m_rec.AlarmTime.Time); // status #define S_NOT_STARTED 0 #define S_IN_PROGRESS 1 #define S_COMPLETED 2 #define S_WAITING 3 #define S_DEFERRED 4 switch( m_rec.StatusFlag ) { case Barry::Task::NotStarted: default: m_StatusChoice->SetSelection(S_NOT_STARTED); break; case Barry::Task::InProgress: m_StatusChoice->SetSelection(S_IN_PROGRESS); break; case Barry::Task::Completed: m_StatusChoice->SetSelection(S_COMPLETED); break; case Barry::Task::Waiting: m_StatusChoice->SetSelection(S_WAITING); break; case Barry::Task::Deferred: m_StatusChoice->SetSelection(S_DEFERRED); break; } // priority #define P_HIGH 0 #define P_NORMAL 1 #define P_LOW 2 switch( m_rec.PriorityFlag ) { case Barry::Task::High: m_PriorityChoice->SetSelection(P_HIGH); break; case Barry::Task::Normal: default: m_PriorityChoice->SetSelection(P_NORMAL); break; case Barry::Task::Low: m_PriorityChoice->SetSelection(P_LOW); break; } // set the timezone choice only if the record's data is valid m_TimezoneChoice->SetSelection(0); // default to none if( m_rec.TimeZoneValid ) { TimeZones::const_iterator i = m_zones->Find(m_rec.TimeZoneCode); if( i != m_zones->end() ) { int array_index = i - m_zones->begin(); // select item, skipping 0's "none" option m_TimezoneChoice->SetSelection(array_index + 1); } } // Note that recur_choice values are (zero-based) in the following // order: // None, Daily, Weekly, Monthly, Yearly #define RC_NONE 0 #define RC_DAILY 1 #define RC_WEEKLY 2 #define RC_MONTHLY 3 #define RC_YEARLY 4 if( m_rec.Recurring ) { switch( m_rec.RecurringType ) { case Barry::RecurBase::Day: m_recur_choice = RC_DAILY; m_relative_date = false; break; case Barry::RecurBase::MonthByDate: m_recur_choice = RC_MONTHLY; m_relative_date = false; break; case Barry::RecurBase::MonthByDay: m_recur_choice = RC_MONTHLY; m_relative_date = true; break; case Barry::RecurBase::YearByDate: m_recur_choice = RC_YEARLY; m_relative_date = false; break; case Barry::RecurBase::YearByDay: m_recur_choice = RC_YEARLY; m_relative_date = true; break; case Barry::RecurBase::Week: m_recur_choice = RC_WEEKLY; m_relative_date = false; m_weekdays[0] = m_rec.WeekDays & CAL_WD_SUN; m_weekdays[1] = m_rec.WeekDays & CAL_WD_MON; m_weekdays[2] = m_rec.WeekDays & CAL_WD_TUE; m_weekdays[3] = m_rec.WeekDays & CAL_WD_WED; m_weekdays[4] = m_rec.WeekDays & CAL_WD_THU; m_weekdays[5] = m_rec.WeekDays & CAL_WD_FRI; m_weekdays[6] = m_rec.WeekDays & CAL_WD_SAT; break; default: cerr << "Bad RecurringType in CalendarEditDlg" << endl; m_recur_choice = RC_NONE; m_relative_date = false; } } else { m_recur_choice = RC_NONE; m_relative_date = false; } m_interval = m_rec.Interval; m_RecurEndDateObj.Set(m_rec.RecurringEndTime.Time); if( m_rec.Perpetual ) { m_RecurEndDateCtrl->Enable(false); } else { m_RecurEndDateCtrl->Enable(); } EnableRecurMode(m_rec.Recurring); m_strings.Refresh(); return wxDialog::TransferDataToWindow(); } bool TaskEditDlg::TransferDataFromWindow() { if( !wxDialog::TransferDataFromWindow() ) return false; m_strings.Sync(); m_rec.Categories.CategoryStr2List(m_categories); // due time if( m_DueCheck->IsChecked() ) m_rec.DueTime.Time = m_DueDateObj.Get(); else m_rec.DueTime.clear(); // alarm / reminder time if( m_ReminderCheck->IsChecked() ) m_rec.AlarmTime.Time = m_ReminderDateObj.Get(); else m_rec.AlarmTime.clear(); // status switch( m_StatusChoice->GetSelection() ) { case S_NOT_STARTED: default: m_rec.StatusFlag = Barry::Task::NotStarted; break; case S_IN_PROGRESS: m_rec.StatusFlag = Barry::Task::InProgress; break; case S_COMPLETED: m_rec.StatusFlag = Barry::Task::Completed; break; case S_WAITING: m_rec.StatusFlag = Barry::Task::Waiting; break; case S_DEFERRED: m_rec.StatusFlag = Barry::Task::Deferred; break; } // priority switch( m_PriorityChoice->GetSelection() ) { case P_HIGH: m_rec.PriorityFlag = Barry::Task::High; break; case P_NORMAL: default: m_rec.PriorityFlag = Barry::Task::Normal; break; case P_LOW: m_rec.PriorityFlag = Barry::Task::Low; break; } // set the timezone choice only if the record's data is valid int sel = m_TimezoneChoice->GetSelection(); if( sel > 0 ) { m_rec.TimeZoneCode = (*m_zones)[sel-1].Index; m_rec.TimeZoneValid = true; } else { // default was selected m_rec.TimeZoneValid = false; } // Note that recur_choice values are (zero-based) in the following // order: // None, Daily, Weekly, Monthly, Yearly switch( m_recur_choice ) { case RC_NONE: default: m_rec.Recurring = false; break; case RC_DAILY: m_rec.Recurring = true; m_rec.RecurringType = Barry::RecurBase::Day; break; case RC_WEEKLY: m_rec.Recurring = true; m_rec.RecurringType = Barry::RecurBase::Week; m_rec.WeekDays = 0; if( m_weekdays[0] ) m_rec.WeekDays |= CAL_WD_SUN; if( m_weekdays[1] ) m_rec.WeekDays |= CAL_WD_MON; if( m_weekdays[2] ) m_rec.WeekDays |= CAL_WD_TUE; if( m_weekdays[3] ) m_rec.WeekDays |= CAL_WD_WED; if( m_weekdays[4] ) m_rec.WeekDays |= CAL_WD_THU; if( m_weekdays[5] ) m_rec.WeekDays |= CAL_WD_FRI; if( m_weekdays[6] ) m_rec.WeekDays |= CAL_WD_SAT; break; case RC_MONTHLY: m_rec.Recurring = true; if( m_relative_date ) m_rec.RecurringType = Barry::RecurBase::MonthByDay; else m_rec.RecurringType = Barry::RecurBase::MonthByDate; break; case RC_YEARLY: m_rec.Recurring = true; if( m_relative_date ) m_rec.RecurringType = Barry::RecurBase::YearByDay; else m_rec.RecurringType = Barry::RecurBase::YearByDate; break; } m_rec.Interval = m_interval; if( !m_rec.Perpetual ) { m_rec.RecurringEndTime.Time = m_RecurEndDateObj.Get(); } cout << "TaskEditDlg::TransferDataFromWindow():\n" << m_rec << endl; return true; } void TaskEditDlg::EnableDueDate(bool enable) { m_DueDateCtrl->Enable(enable); m_DueHoursSpinner->Enable(enable); m_DueMinutesSpinner->Enable(enable); m_RecurrenceChoice->Enable(enable); if( !enable ) { m_RecurrenceChoice->SetSelection(0); EnableRecurMode(false); } } void TaskEditDlg::EnableReminderDate(bool enable) { m_ReminderDateCtrl->Enable(enable); m_ReminderHoursSpinner->Enable(enable); m_ReminderMinutesSpinner->Enable(enable); } void TaskEditDlg::EnableRecurMode(bool recur) { // show all controls RecurIntervalLabel->Show(recur); RecurIntervalLabelB->Show(recur); m_IntervalSpinner->Show(recur); m_IntervalUnitLabel->Show(recur); RecurDaysLabel->Show(recur); m_SunCheck->Show(recur); m_MonCheck->Show(recur); m_TueCheck->Show(recur); m_WedCheck->Show(recur); m_ThuCheck->Show(recur); m_FriCheck->Show(recur); m_SatCheck->Show(recur); RecurRelativeDateLabel->Show(recur); m_RelativeDateCheck->Show(recur); RecurEndDateLabel->Show(recur); m_NeverEndsCheck->Show(recur); m_RecurEndDateCtrl->Show(recur); // enable based on choice int choice = m_RecurrenceChoice->GetSelection(); m_SunCheck->Enable(choice == RC_WEEKLY); m_MonCheck->Enable(choice == RC_WEEKLY); m_TueCheck->Enable(choice == RC_WEEKLY); m_WedCheck->Enable(choice == RC_WEEKLY); m_ThuCheck->Enable(choice == RC_WEEKLY); m_FriCheck->Enable(choice == RC_WEEKLY); m_SatCheck->Enable(choice == RC_WEEKLY); // update labels if( recur ) { switch( m_RecurrenceChoice->GetSelection() ) { case RC_NONE: default: m_IntervalUnitLabel->SetLabel(_T("")); break; case RC_DAILY: m_IntervalUnitLabel->SetLabel(_W("day(s)")); break; case RC_WEEKLY: m_IntervalUnitLabel->SetLabel(_W("week(s)")); break; case RC_MONTHLY: m_IntervalUnitLabel->SetLabel(_W("month(s)")); break; case RC_YEARLY: m_IntervalUnitLabel->SetLabel(_W("year(s)")); break; } } RedoLayout(); } // // Note: this file is very similar to CalendarEditDlg.cc, and should be kept // in lock step as much as possible. They are in separate files, since // the GUI code is generated with wxglade // barry-0.18.5/desktop/src/CUI_Barry.h0000644001161500056700000000252712242254476016452 0ustar cdfreycdfrey/// /// \file CUI_Barry.h /// ConfigUI derived class to configure the Barry "App" /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_CUI_BARRY_H__ #define __BARRY_CUI_BARRY_H__ #include "configui.h" #include "osconfig.h" #include class wxWindow; namespace AppConfig { class Barry : public ConfigUI { plugin_ptr m_container; // convenience pointers wxWindow *m_parent; public: Barry(); // virtual overrides (ConfigUI) virtual std::string AppName() const; virtual bool Configure(wxWindow *parent, plugin_ptr old_plugin); virtual plugin_ptr GetPlugin(); virtual bool RunApp(wxWindow *parent); virtual void PreSyncAppInit(); virtual bool ZapData(wxWindow *parent, plugin_ptr plugin, OpenSync::API *engine); }; } #endif barry-0.18.5/desktop/src/Mode_Sync.h0000644001161500056700000000503612242254476016551 0ustar cdfreycdfrey/// /// \file Mode_Sync.h /// Mode derived class for syncing /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_MODE_SYNC_H__ #define __BARRYDESKTOP_MODE_SYNC_H__ #include "Mode.h" #include "deviceset.h" #include "configui.h" #include "wxi18n.h" class SyncMode : public wxEvtHandler, public Mode { private: DECLARE_EVENT_TABLE() // sets to protected: private: wxWindow *m_parent; std::auto_ptr m_device_set; ConfigUI::ptr m_cui; // window controls std::auto_ptr m_topsizer; std::auto_ptr m_sync_now_button; std::auto_ptr m_configure_button; std::auto_ptr m_run_app_button; std::auto_ptr m_1way_reset_button; std::auto_ptr m_device_list; std::auto_ptr m_label[4]; protected: static std::string Timestamp(time_t last_sync); int GetMaxTimestampWidth(wxWindow *win); void FillDeviceList(); void UpdateButtons(); DeviceSet::subset_type GetSelectedDevices(); void ReselectDevices(const DeviceSet::subset_type &set); void ConfigureDevice(int device_index); void ConfigureDevice(DeviceEntry &entry); void CheckConfigured(DeviceSet::subset_type &subset); void RefillList(); int GetSelectedDevice(); // returns index, or -1 if none or // more than one selected... also // handles the message box int GetAuthoritativeSide(int device_index); bool ZapConflicts(int device_index, int authoritative_side); void RewriteConfig(int device_index); bool WarnAbout1WayReset(); public: SyncMode(wxWindow *parent); ~SyncMode(); // virtual override events (derived from Mode) wxString GetTitleText() const { return _W("Barry Sync"); } // window events void OnSyncNow(wxCommandEvent &event); void OnConfigure(wxCommandEvent &event); void OnRunApp(wxCommandEvent &event); void On1WayReset(wxCommandEvent &event); void OnListSelChange(wxListEvent &event);//to keep track of button state void OnConfigureDevice(wxListEvent &event); }; #endif barry-0.18.5/desktop/src/ContactEditDlg.cc0000644001161500056700000004601712242254476017663 0ustar cdfreycdfrey/// /// \file ContactEditDlg.cc /// Dialog class to handle the editing of the Contact record /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "ContactEditDlg.h" #include "ContactPhotoWidget.h" #include "windowids.h" #include "wxi18n.h" // begin wxGlade: ::extracode // end wxGlade ////////////////////////////////////////////////////////////////////////////// // ContactEditDlg class ContactEditDlg::ContactEditDlg(wxWindow *parent, Barry::Contact &rec, bool editable) : wxDialog(parent, Dialog_ContactEdit, _W("Contact Record")) , m_rec(rec) { m_email_list = Barry::Contact::Email2CommaString(m_rec.EmailAddresses); if( editable ) { bottom_buttons = CreateButtonSizer(wxOK | wxCANCEL); } else { bottom_buttons = CreateButtonSizer(wxCANCEL); } // begin wxGlade: ContactEditDlg::ContactEditDlg sizer_5_staticbox = new wxStaticBox(this, -1, _W("Home")); sizer_6_staticbox = new wxStaticBox(this, -1, _W("Work")); sizer_2_staticbox = new wxStaticBox(this, -1, _W("Misc")); sizer_7_staticbox = new wxStaticBox(this, -1, _W("Mobile")); sizer_8_staticbox = new wxStaticBox(this, -1, _W("Notes")); sizer_9_staticbox = new wxStaticBox(this, -1, _W("Name")); m_photo = new ContactPhotoWidget(this, Dialog_ContactEdit_PhotoButton, m_rec); label_13 = new wxStaticText(this, wxID_ANY, _W("Title")); Prefix = new wxTextCtrl(this, wxID_ANY, wxEmptyString); FirstNameStatic = new wxStaticText(this, wxID_ANY, _W("First")); FirstName = new wxTextCtrl(this, wxID_ANY, wxEmptyString); LastNameStatic = new wxStaticText(this, wxID_ANY, _W("Last")); LastName = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_14 = new wxStaticText(this, wxID_ANY, _W("Company")); Company = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_15 = new wxStaticText(this, wxID_ANY, _W("Job Title")); JobTitle = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_9 = new wxStaticText(this, wxID_ANY, _W("Nickname")); Nickname = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_1 = new wxStaticText(this, wxID_ANY, _W("Address")); HomeAddress1 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); HomeAddress2 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); HomeAddress3 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_2 = new wxStaticText(this, wxID_ANY, _W("City")); HomeCity = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_3 = new wxStaticText(this, wxID_ANY, _W("Province")); HomeProvince = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_4 = new wxStaticText(this, wxID_ANY, _W("Postal Code")); HomePostalCode = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_5 = new wxStaticText(this, wxID_ANY, _W("Country")); HomeCountry = new wxTextCtrl(this, wxID_ANY, wxEmptyString); static_line_1 = new wxStaticLine(this, wxID_ANY); static_line_2 = new wxStaticLine(this, wxID_ANY); label_6 = new wxStaticText(this, wxID_ANY, _W("Phone")); HomePhone = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_7 = new wxStaticText(this, wxID_ANY, _W("Phone 2")); HomePhone2 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_8 = new wxStaticText(this, wxID_ANY, _W("Fax")); HomeFax = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_1_copy = new wxStaticText(this, wxID_ANY, _W("Address")); WorkAddress1 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); WorkAddress2 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); WorkAddress3 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_2_copy = new wxStaticText(this, wxID_ANY, _W("City")); WorkCity = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_3_copy = new wxStaticText(this, wxID_ANY, _W("Province")); WorkProvince = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_4_copy = new wxStaticText(this, wxID_ANY, _W("Postal Code")); WorkPostalCode = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_5_copy = new wxStaticText(this, wxID_ANY, _W("Country")); WorkCountry = new wxTextCtrl(this, wxID_ANY, wxEmptyString); static_line_1_copy = new wxStaticLine(this, wxID_ANY); static_line_2_copy = new wxStaticLine(this, wxID_ANY); label_6_copy = new wxStaticText(this, wxID_ANY, _W("Phone")); WorkPhone = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_7_copy = new wxStaticText(this, wxID_ANY, _W("Phone 2")); WorkPhone2 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_8_copy = new wxStaticText(this, wxID_ANY, _W("Fax")); WorkFax = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_17 = new wxStaticText(this, wxID_ANY, _W("Email")); text_ctrl_9 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_18 = new wxStaticText(this, wxID_ANY, _W("Other Phone")); text_ctrl_1 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_19 = new wxStaticText(this, wxID_ANY, _W("Old Phone")); text_ctrl_2 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_20 = new wxStaticText(this, wxID_ANY, _W("Radio")); text_ctrl_3 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_21 = new wxStaticText(this, wxID_ANY, _W("PIN")); text_ctrl_4 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_22 = new wxStaticText(this, wxID_ANY, _W("User1")); text_ctrl_5 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_23 = new wxStaticText(this, wxID_ANY, _W("User2")); text_ctrl_6 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_24 = new wxStaticText(this, wxID_ANY, _W("User3")); text_ctrl_7 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_25 = new wxStaticText(this, wxID_ANY, _W("User4")); text_ctrl_8 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_10 = new wxStaticText(this, wxID_ANY, _W("Cell")); MobilePhone = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_11 = new wxStaticText(this, wxID_ANY, _W("Cell 2")); MobilePhone2 = new wxTextCtrl(this, wxID_ANY, wxEmptyString); label_12 = new wxStaticText(this, wxID_ANY, _W("Pager")); Pager = new wxTextCtrl(this, wxID_ANY, wxEmptyString); Notes = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER|wxTE_MULTILINE); label_16 = new wxStaticText(this, wxID_ANY, _W("URL")); Url = new wxTextCtrl(this, wxID_ANY, wxEmptyString); set_properties(); do_layout(); // end wxGlade } BEGIN_EVENT_TABLE(ContactEditDlg, wxDialog) EVT_BUTTON (Dialog_ContactEdit_PhotoButton, ContactEditDlg::OnPhotoButton) END_EVENT_TABLE(); void ContactEditDlg::set_properties() { // begin wxGlade: ContactEditDlg::set_properties SetTitle(_W("Contact")); Prefix->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Prefix))); FirstName->SetMinSize(wxSize(100, -1)); FirstName->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.FirstName))); LastName->SetMinSize(wxSize(100, -1)); LastName->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.LastName))); Company->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Company))); JobTitle->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.JobTitle))); Nickname->SetMinSize(wxSize(100, -1)); Nickname->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Nickname))); HomeAddress1->SetMinSize(wxSize(170, -1)); HomeAddress1->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeAddress.Address1))); HomeAddress2->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeAddress.Address2))); HomeAddress3->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeAddress.Address3))); HomeCity->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeAddress.City))); HomeProvince->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeAddress.Province))); HomePostalCode->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeAddress.PostalCode))); HomeCountry->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeAddress.Country))); HomePhone->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomePhone))); HomePhone2->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomePhone2))); HomeFax->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.HomeFax))); WorkAddress1->SetMinSize(wxSize(170, -1)); WorkAddress1->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkAddress.Address1))); WorkAddress2->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkAddress.Address2))); WorkAddress3->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkAddress.Address3))); WorkCity->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkAddress.City))); WorkProvince->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkAddress.Province))); WorkPostalCode->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkAddress.PostalCode))); WorkCountry->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkAddress.Country))); WorkPhone->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkPhone))); WorkPhone2->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.WorkPhone2))); WorkFax->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Fax))); text_ctrl_9->SetMinSize(wxSize(170, -1)); text_ctrl_9->SetToolTip(_W("Comma separated list of simple email addresses. Do not use <> characters.")); text_ctrl_9->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_email_list))); text_ctrl_1->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.OtherPhone))); text_ctrl_2->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Phone))); text_ctrl_3->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Radio))); text_ctrl_4->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.PIN))); text_ctrl_5->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.UserDefined1))); text_ctrl_6->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.UserDefined2))); text_ctrl_7->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.UserDefined3))); text_ctrl_8->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.UserDefined4))); MobilePhone->SetMinSize(wxSize(100, -1)); MobilePhone->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.MobilePhone))); MobilePhone2->SetMinSize(wxSize(100, -1)); MobilePhone2->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.MobilePhone2))); Pager->SetMinSize(wxSize(100, -1)); Pager->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Pager))); Notes->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Notes))); Url->SetValidator(wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.URL))); // end wxGlade } void ContactEditDlg::do_layout() { // begin wxGlade: ContactEditDlg::do_layout wxBoxSizer* sizer_1 = new wxBoxSizer(wxVERTICAL); wxStaticBoxSizer* sizer_8 = new wxStaticBoxSizer(sizer_8_staticbox, wxVERTICAL); wxBoxSizer* sizer_10 = new wxBoxSizer(wxHORIZONTAL); wxStaticBoxSizer* sizer_7 = new wxStaticBoxSizer(sizer_7_staticbox, wxHORIZONTAL); wxBoxSizer* sizer_4 = new wxBoxSizer(wxHORIZONTAL); wxStaticBoxSizer* sizer_2 = new wxStaticBoxSizer(sizer_2_staticbox, wxHORIZONTAL); wxFlexGridSizer* grid_sizer_3 = new wxFlexGridSizer(10, 2, 1, 3); wxStaticBoxSizer* sizer_6 = new wxStaticBoxSizer(sizer_6_staticbox, wxHORIZONTAL); wxFlexGridSizer* grid_sizer_1_copy = new wxFlexGridSizer(11, 2, 1, 3); wxStaticBoxSizer* sizer_5 = new wxStaticBoxSizer(sizer_5_staticbox, wxHORIZONTAL); wxFlexGridSizer* grid_sizer_1 = new wxFlexGridSizer(11, 2, 1, 3); wxStaticBoxSizer* sizer_9 = new wxStaticBoxSizer(sizer_9_staticbox, wxHORIZONTAL); wxFlexGridSizer* grid_sizer_2 = new wxFlexGridSizer(2, 6, 2, 3); sizer_9->Add(m_photo, 0, wxRIGHT|wxEXPAND|wxALIGN_CENTER_VERTICAL, 3); grid_sizer_2->Add(label_13, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 1); grid_sizer_2->Add(Prefix, 0, wxEXPAND, 0); grid_sizer_2->Add(FirstNameStatic, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 10); grid_sizer_2->Add(FirstName, 1, wxEXPAND, 0); grid_sizer_2->Add(LastNameStatic, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 10); grid_sizer_2->Add(LastName, 1, wxEXPAND, 0); grid_sizer_2->Add(label_14, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 1); grid_sizer_2->Add(Company, 0, wxEXPAND, 0); grid_sizer_2->Add(label_15, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 10); grid_sizer_2->Add(JobTitle, 0, wxEXPAND, 0); grid_sizer_2->Add(label_9, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 10); grid_sizer_2->Add(Nickname, 1, wxEXPAND, 0); grid_sizer_2->AddGrowableCol(1); grid_sizer_2->AddGrowableCol(3); grid_sizer_2->AddGrowableCol(5); sizer_9->Add(grid_sizer_2, 1, wxBOTTOM|wxEXPAND, 3); sizer_1->Add(sizer_9, 0, wxALL|wxEXPAND, 5); grid_sizer_1->Add(label_1, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1->Add(HomeAddress1, 0, 0, 0); grid_sizer_1->Add(20, 20, 0, 0, 0); grid_sizer_1->Add(HomeAddress2, 0, wxEXPAND, 0); grid_sizer_1->Add(20, 20, 0, 0, 0); grid_sizer_1->Add(HomeAddress3, 0, wxEXPAND, 0); grid_sizer_1->Add(label_2, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1->Add(HomeCity, 0, wxEXPAND, 0); grid_sizer_1->Add(label_3, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1->Add(HomeProvince, 0, wxEXPAND, 0); grid_sizer_1->Add(label_4, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1->Add(HomePostalCode, 0, wxEXPAND, 0); grid_sizer_1->Add(label_5, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1->Add(HomeCountry, 0, wxEXPAND, 0); grid_sizer_1->Add(static_line_1, 0, wxEXPAND, 0); grid_sizer_1->Add(static_line_2, 0, wxEXPAND, 0); grid_sizer_1->Add(label_6, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1->Add(HomePhone, 0, wxEXPAND, 0); grid_sizer_1->Add(label_7, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1->Add(HomePhone2, 0, wxEXPAND, 0); grid_sizer_1->Add(label_8, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1->Add(HomeFax, 0, wxEXPAND, 0); sizer_5->Add(grid_sizer_1, 1, wxEXPAND, 0); sizer_4->Add(sizer_5, 1, wxLEFT|wxRIGHT|wxEXPAND, 2); grid_sizer_1_copy->Add(label_1_copy, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1_copy->Add(WorkAddress1, 0, 0, 0); grid_sizer_1_copy->Add(20, 20, 0, 0, 0); grid_sizer_1_copy->Add(WorkAddress2, 0, wxEXPAND, 0); grid_sizer_1_copy->Add(20, 20, 0, 0, 0); grid_sizer_1_copy->Add(WorkAddress3, 0, wxEXPAND, 0); grid_sizer_1_copy->Add(label_2_copy, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1_copy->Add(WorkCity, 0, wxEXPAND, 0); grid_sizer_1_copy->Add(label_3_copy, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1_copy->Add(WorkProvince, 0, wxEXPAND, 0); grid_sizer_1_copy->Add(label_4_copy, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1_copy->Add(WorkPostalCode, 0, wxEXPAND, 0); grid_sizer_1_copy->Add(label_5_copy, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1_copy->Add(WorkCountry, 0, wxEXPAND, 0); grid_sizer_1_copy->Add(static_line_1_copy, 0, wxEXPAND, 0); grid_sizer_1_copy->Add(static_line_2_copy, 0, wxEXPAND, 0); grid_sizer_1_copy->Add(label_6_copy, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1_copy->Add(WorkPhone, 0, wxEXPAND, 0); grid_sizer_1_copy->Add(label_7_copy, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1_copy->Add(WorkPhone2, 0, wxEXPAND, 0); grid_sizer_1_copy->Add(label_8_copy, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_1_copy->Add(WorkFax, 0, wxEXPAND, 0); sizer_6->Add(grid_sizer_1_copy, 1, wxEXPAND, 0); sizer_4->Add(sizer_6, 1, wxLEFT|wxRIGHT|wxEXPAND, 2); grid_sizer_3->Add(label_17, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_3->Add(text_ctrl_9, 0, 0, 0); grid_sizer_3->Add(label_18, 0, wxALIGN_CENTER_VERTICAL, 0); grid_sizer_3->Add(text_ctrl_1, 0, wxEXPAND, 0); grid_sizer_3->Add(label_19, 0, 0, 0); grid_sizer_3->Add(text_ctrl_2, 0, wxEXPAND, 0); grid_sizer_3->Add(label_20, 0, 0, 0); grid_sizer_3->Add(text_ctrl_3, 0, wxEXPAND, 0); grid_sizer_3->Add(label_21, 0, 0, 0); grid_sizer_3->Add(text_ctrl_4, 0, wxEXPAND, 0); grid_sizer_3->Add(label_22, 0, 0, 0); grid_sizer_3->Add(text_ctrl_5, 0, wxEXPAND, 0); grid_sizer_3->Add(label_23, 0, 0, 0); grid_sizer_3->Add(text_ctrl_6, 0, wxEXPAND, 0); grid_sizer_3->Add(label_24, 0, 0, 0); grid_sizer_3->Add(text_ctrl_7, 0, wxEXPAND, 0); grid_sizer_3->Add(label_25, 0, 0, 0); grid_sizer_3->Add(text_ctrl_8, 0, wxEXPAND, 0); sizer_2->Add(grid_sizer_3, 1, wxEXPAND, 0); sizer_4->Add(sizer_2, 1, wxEXPAND, 0); sizer_1->Add(sizer_4, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 5); sizer_7->Add(label_10, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 1); sizer_7->Add(MobilePhone, 1, 0, 0); sizer_7->Add(20, 20, 0, 0, 0); sizer_7->Add(label_11, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 1); sizer_7->Add(MobilePhone2, 1, 0, 0); sizer_7->Add(20, 20, 0, 0, 0); sizer_7->Add(label_12, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 1); sizer_7->Add(Pager, 1, 0, 0); sizer_1->Add(sizer_7, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 5); sizer_8->Add(Notes, 0, wxEXPAND, 0); sizer_10->Add(label_16, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 1); sizer_10->Add(Url, 1, wxALL, 2); sizer_8->Add(sizer_10, 0, wxEXPAND, 0); sizer_1->Add(sizer_8, 1, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 5); // end wxGlade sizer_1->Add(bottom_buttons, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 5); // NOTE: the code generator will generate these 3 calls above. // They may be removed above, since it will probably slow // down the GUI display. SetSizer(sizer_1); sizer_1->Fit(this); Layout(); } int ContactEditDlg::ShowModal() { int ret = wxDialog::ShowModal(); return ret; } void ContactEditDlg::OnPhotoButton(wxCommandEvent &event) { if( m_rec.Image.size() ) { // an image exists, prompt user what to do wxArrayString choices; choices.Add( _W("Load new photo") ); choices.Add( _W("Save current photo to disk") ); choices.Add( _W("Delete current photo") ); int choice = wxGetSingleChoiceIndex( _W("A photo currently exists. Would you like to:"), _W("Photo Management"), choices, this); switch( choice ) { case 0: // load new photo if( m_photo->PromptAndLoad(this) ) { Layout(); } break; case 1: // save photo m_photo->PromptAndSave(this); break; case 2: // delete photo m_photo->DeletePhoto(); Layout(); break; default: // do nothing! break; } } else { // no image exists, assume he wants to load a new one if( m_photo->PromptAndLoad(this) ) { // FIXME - if the photo is wider than old button, // this doesn't seem to work. Why? Layout(); } } } bool ContactEditDlg::TransferDataFromWindow() { if( !wxDialog::TransferDataFromWindow() ) return false; m_strings.Sync(); Barry::Contact::CommaString2Email(m_email_list, m_rec.EmailAddresses); // one final validation: make sure either the name field or the // company field has data if( !m_rec.GetFullName().size() && !m_rec.Company.size() ) { wxMessageBox(_W("A contact record must contain either a First/Last name, or a Company name."), _W("Required Fields"), wxOK | wxICON_INFORMATION, this); return false; } return true; } barry-0.18.5/desktop/src/exechelper.h0000644001161500056700000001170212242254476017012 0ustar cdfreycdfrey/// /// \file exechelper.h /// Helper class to wrap wxProcess and wxExecute operations /// /* Copyright (C) 2010-2013, Chris Frey 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_EXECHELPER_H__ #define __BARRYDESKTOP_EXECHELPER_H__ #include #include #include class ExecHelper; class TermCatcher { friend class ExecHelper; wxEvtHandler *m_handler; int m_id; ExecHelper *m_eh; public: TermCatcher(wxEvtHandler *handler = 0, int id = 0) : m_handler(handler) , m_id(id) , m_eh(0) { } virtual ~TermCatcher(); // WARNING: this can be called from another thread when not // using wxWidgets' exec code... it may not be possible to // safely call GUI functions from this callback on all platforms. // // By default it just posts a wxProcessEvent(windowid, pid, status) // which is thread-safe. Add a EVT_END_PROCESS(windowid, func) // handler to your event table to handle this. virtual void ExecTerminated(int pid, int status) { if( m_handler ) { wxProcessEvent pe(m_id, pid, status); m_handler->AddPendingEvent(pe); } } }; // // ExecHelper // /// Wrapper around the wxProcess class, that does much of the same /// stuff, but also stores the child process's status code without /// requiring a virtual override. /// /// If ExecHelper is destroyed before the app exits, the callback /// will be "lost", but the AppCallback class will cleanup after itself. /// /// If you specify a TermCatcher pointer, then as long as TermCatcher /// and ExecHelper exist, you will get an event via the virtual /// ExecTerminated() call. If either ExecHelper or TermCatcher /// go out of scope before that happens, the callback will be "lost" /// but everything will be cleaned up automatically. /// /// The idea: Create a class where your real work happens, and derive /// that class from TermCatcher. Then create an instance /// of ExecHelper inside that class, and pass 'this' to its /// constructor. If this is a dialog class that disappears /// before the app exits, the destructors will handle things automatically. /// class ExecHelper { friend class TermCatcher; protected: // This funky class is required because wxProcess deletes itself, // so that if ExecHelper is deleted before AppCallback, a segfault // is not caused by the OnTerminate() call. class AppCallback : public wxProcess { ExecHelper *m_container; public: AppCallback(ExecHelper *container) : m_container(container) { } void Detach() { m_container = 0; } // virtual overrides (wxProcess) virtual void OnTerminate(int pid, int status) { if( m_container && this == m_container->m_app_callback ) { m_container->m_app_pid = -1; m_container->m_app_status = status; m_container->m_app_callback = 0; // signal if legal if( m_container->m_catcher ) { try { m_container->m_catcher->ExecTerminated(pid, status); } catch( ... ) { // we are fully responsible // for cleaning ourselves up, // so do that, and then re- // throw, and hope for the // best... delete this; throw; } } } // cleanup delete this; } }; TermCatcher *m_catcher; AppCallback *m_app_callback; int m_app_pid; int m_app_status; time_t m_started; protected: // helper functions void RunError(wxWindow *parent, const wxString &msg); int Execute(bool use_wx, const wxString &command, AppCallback *cb); public: /// It is safe to pass a NULL catcher here. No default is /// specified so that the compiler helps prevent forgetfulness. ExecHelper(TermCatcher *catcher); virtual ~ExecHelper(); time_t GetStartTime() const { return m_started; } /// Runs the Application, if not already running.. parent may /// be NULL if you don't want this class to pop up error messages /// if unable to run the app. The 'appname' argument is a /// user-friendly name for the application you are running. virtual bool Run(wxWindow *parent, const std::string &appname, const wxString &command); /// Returns true if App is currently running virtual bool IsAppRunning(); /// Blocks until child exits virtual void WaitForChild(); /// Returns raw status code: see waitpid() for info on how to use it virtual int GetRawAppStatus() const { return m_app_status; } /// Returns child's exit code virtual int GetChildExitCode() const; /// Sends a termination signal to the App, if running virtual void KillApp(bool hardkill = false); }; #endif barry-0.18.5/desktop/src/EvoCfgDlg.h0000644001161500056700000000407612242254476016474 0ustar cdfreycdfrey/// /// \file EvoCfgDlg.h /// The configuration dialog used to configure Evolution sources /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_EVOCFGDLG_H__ #define __BARRYDESKTOP_EVOCFGDLG_H__ #include #include "EvoSources.h" #include "ostypes.h" // forward declarations namespace OpenSync { namespace Config { class Evolution; } } class EvoCfgDlg : public wxDialog { // configuration settings std::string m_address_path; std::string m_calendar_path; std::string m_tasks_path; std::string m_memos_path; bool m_empty_config; // true if all paths are empty, and // therefore the first time this // is running, and defaults my be // attempted // external data const EvoSources &m_sources; // dialog controls wxSizer *m_topsizer; wxComboBox *m_address_combo; wxComboBox *m_calendar_combo; wxComboBox *m_tasks_combo; wxComboBox *m_memos_combo; protected: void CreateLayout(); void AddCombo(wxComboBox **combo, int id, const std::string ¤t_path, const EvoSources::List &list); wxString CheckPath(const wxString &name, const std::string &path) const; /// returns error message string on error, otherwise empty string wxString ValidatePaths() const; public: EvoCfgDlg(wxWindow *parent, const OpenSync::Config::Evolution &ec, const EvoSources &es); // results void SetPaths(OpenSync::Config::Evolution &ec) const; // event handlers // overrides virtual bool TransferDataFromWindow(); int ShowModal(); }; #endif barry-0.18.5/desktop/src/ConflictDlg.h0000644001161500056700000000720212242254476017056 0ustar cdfreycdfrey/// /// \file ConflictDlg.h /// The dialog used during a sync, to display conflicting /// changes, and let the user decide what to do. /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_CONFLICTDLG_H__ #define __BARRYDESKTOP_CONFLICTDLG_H__ #include #include #include #include "osbase.h" #include "xmlmap.h" class ConflictDlg : public wxDialog { DECLARE_EVENT_TABLE() // sets to protected: public: typedef std::tr1::shared_ptr map_ptr; typedef std::tr1::shared_ptr dom_ptr; struct XmlPair { ConflictDlg::dom_ptr dom; // never null ConflictDlg::map_ptr map; // can contain null! }; typedef std::vector mapped_list; typedef std::set key_set; // Stored by the caller to remember the "always" selection // Pass it back into the dialog to have it automatically // select for you. struct AlwaysMemoryBlock { bool m_always; long m_member_id; std::string m_plugin_name; std::string m_last_command; std::string m_favour_plugin_name; void clear() { m_always = false; m_member_id = -1; m_plugin_name.clear(); m_last_command.clear(); m_favour_plugin_name.clear(); } AlwaysMemoryBlock() : m_always(false) , m_member_id(-1) { } }; private: // external data sources const OpenSync::API &m_engine; const std::vector &m_changes; std::string m_supported_commands; // a char string: "SDAIN" AlwaysMemoryBlock &m_always; // mapped data mapped_list m_maps; key_set m_differing_keys; // results bool m_kill_sync; std::string m_command_string; // eg. "S 1" // dialog sizing int m_max_text_width; // dialog controls wxSizer *m_topsizer; protected: void CreateLayout(); void CreateSummaries(wxSizer *sizer); void CreateSummary(wxSizer *sizer, size_t change_index); void CreateSummaryGroup(wxSizer *sizer, size_t change_index); void CreateSummaryButtons(wxSizer *sizer, size_t change_index); bool IsDifferent(const XmlNodeMapping &mapping) const; void AddEmptyNotice(wxSizer *sizer); void AddMapping(wxSizer *sizer, XmlNodeMapping &mapping, bool differing); void CreateAlternateButtons(wxSizer *sizer); void ParseChanges(); void CreateDifferingKeyNameSet(); public: ConflictDlg(wxWindow *parent, const OpenSync::API &engine, const std::string &supported_commands, const std::vector &changes, AlwaysMemoryBlock &always); ~ConflictDlg(); // data access const std::string& GetCommand() const { return m_command_string; } bool IsKillSync() const { return m_kill_sync; } void Clear() { clear(); } void clear(); // override, in order to force an answer int ShowModal(); // event handlers void OnShowButton(wxCommandEvent &event); void OnSelectButton(wxCommandEvent &event); void OnDuplicateButton(wxCommandEvent &event); void OnAbortButton(wxCommandEvent &event); void OnIgnoreButton(wxCommandEvent &event); void OnKeepNewerButton(wxCommandEvent &event); void OnKillSyncButton(wxCommandEvent &event); void OnAlwaysCheckbox(wxCommandEvent &event); }; #endif barry-0.18.5/desktop/src/CUI_Evolution.cc0000644001161500056700000002206412242254476017513 0ustar cdfreycdfrey/// /// \file CUI_Evolution.cc /// ConfigUI derived class to configure the Evolution App /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "CUI_Evolution.h" #include "EvoSources.h" #include "EvoCfgDlg.h" #include "EvoDefaultDlg.h" #include "os22.h" // only for the dynamic_cast #include "windowids.h" #include #include #include "wxi18n.h" namespace AppConfig { namespace { class ExecCallback : public wxProcess { public: wxDialog *m_waitdlg; int m_pid; int m_status; ExecCallback(wxDialog *dlg) : m_waitdlg(dlg) , m_pid(0) , m_status(0) { } virtual void OnTerminate(int pid, int status) { m_pid = pid; m_status = status; if( m_waitdlg ) { // close the dialog and let it delete us m_waitdlg->EndModal(wxID_OK); } else { // our parent doesn't exist, delete ourselves delete this; } } }; class WaitDialog : public wxDialog { DECLARE_EVENT_TABLE() public: WaitDialog(wxWindow *parent, const wxString &msg, const wxString &title) : wxDialog(parent, wxID_ANY, title) { wxBoxSizer *top = new wxBoxSizer(wxVERTICAL); top->Add( new wxStaticText(this, wxID_ANY, msg), 0, wxALL | wxALIGN_LEFT, 10); top->Add( new wxButton(this, wxID_CANCEL, _W("Stop waiting")), 0, wxALL | wxALIGN_RIGHT, 5); SetSizer(top); top->SetSizeHints(this); top->Layout(); SetEscapeId(wxID_CANCEL); } void OnButton(wxCommandEvent &event) { EndModal(wxID_CANCEL); } }; BEGIN_EVENT_TABLE(WaitDialog, wxDialog) EVT_BUTTON (wxID_CANCEL, WaitDialog::OnButton) END_EVENT_TABLE() } // namespace ////////////////////////////////////////////////////////////////////////////// // Static utility functions long Evolution::ForceShutdown() { ExecHelper shutdown(NULL); shutdown.Run(NULL, _C("Evolution shutdown"), _T("evolution --force-shutdown")); shutdown.WaitForChild(); return shutdown.GetChildExitCode(); } ////////////////////////////////////////////////////////////////////////////// // EvolutionPtrBase class EvolutionPtrBase::EvolutionPtrBase() : m_evolution(0) { } void EvolutionPtrBase::AcquirePlugin(plugin_ptr old_plugin) { // create our plugin config m_evolution = dynamic_cast (old_plugin.get()); if( m_evolution ) { m_evolution = m_evolution->Clone(); } else { m_evolution = new OpenSync::Config::Evolution; } m_container.reset( m_evolution ); } OpenSync::Config::Evolution* EvolutionPtrBase::GetEvolutionPtr() { return m_evolution; } void EvolutionPtrBase::Clear() { m_container.reset(); m_evolution = 0; } ConfigUI::plugin_ptr EvolutionPtrBase::GetPlugin() { m_evolution = 0; return m_container; } ////////////////////////////////////////////////////////////////////////////// // Evolution config UI class Evolution::Evolution() : m_parent(0) { } bool Evolution::InitialRun() { wxString msg = _W( "Unable to automatically detect Evolution's configuration.\n" "You need to run Evolution, and manually click each of the\n" "section buttons:\n" "\n" " Mail, Contacts, Calendars, Memos, and Tasks\n" "\n" "Then quit Evolution to continue configuration.\n" "\n" "Would you like to start Evolution now?\n"); int choice = wxMessageBox(msg, _W("Evolution Config"), wxYES_NO | wxICON_QUESTION, m_parent); if( choice == wxNO ) return false; ForceShutdown(); // start Evolution, and wait for it to exit, showing a waiting // message to the user WaitDialog waitdlg(m_parent, _W("Waiting for Evolution to exit..."), _W("Evolution Running")); ExecCallback *callback = new ExecCallback(&waitdlg); const wxChar *start_argv[] = { _T("evolution"), NULL }; long ret = wxExecute((wxChar**)start_argv, wxEXEC_ASYNC, callback); if( ret == 0 ) { delete callback; wxMessageBox(_W("Failed to run evolution. Please make sure it is installed and in your PATH."), _W("Evolution Config"), wxOK | wxICON_ERROR, m_parent); return false; } if( waitdlg.ShowModal() == wxID_CANCEL ) { // user aborted, so ExecCallback will be left // waiting, and waitdlg will go out of scope, so // reset the callback's pointer callback->m_waitdlg = 0; return false; // user aborted } else { // if we don't get wxID_CANCEL, then the callback // closed us, and we can delete it if( callback->m_status ) { // error status code wxMessageBox(_W("Failed to run evolution. Please make sure it is installed and in your PATH."), _W("Evolution Config"), wxOK | wxICON_ERROR, m_parent); delete callback; return false; } else { delete callback; } } // so far so good... return true; } std::string Evolution::AppName() const { return OpenSync::Config::Evolution::AppName(); } bool Evolution::Configure(wxWindow *parent, plugin_ptr old_plugin) { m_parent = parent; AcquirePlugin(old_plugin); // auto detect first EvoSources srcs; // if no sources are found at all, and if Evolution is in the path // do InitialRun and then auto detect again if( srcs.IsEmpty() ) { if( !InitialRun() ) { // impossible to do initial run, so fail here Clear(); return false; } srcs.Detect(); } // we now have an auto detect (EvoSources) to work with // if minimum three paths are available, and if no list has // more than 1 item, then just default to those settings // and notify the user... in the notification, allow // the user to "Manual Cfg..." button bool manual = false; if( srcs.IsDefaultable() ) { EvoDefaultDlg dlg(m_parent); if( dlg.ShowModal() == Dialog_EvoDefault_ManualConfigButton ) { manual = true; } } // otherwise, if default settings are not possible, then // load the path config dialog without notification if( !srcs.IsDefaultable() || manual ) { EvoCfgDlg cfgdlg(m_parent, *GetEvolutionPtr(), srcs); if( cfgdlg.ShowModal() == wxID_OK ) { cfgdlg.SetPaths(*GetEvolutionPtr()); } else { Clear(); return false; } } else { // it's defaultable! use default paths GetEvolutionPtr()->SetAddressPath(srcs.GetAddressBook().size() ? srcs.GetAddressBook()[0].m_SourcePath : ""); GetEvolutionPtr()->SetCalendarPath(srcs.GetEvents().size() ? srcs.GetEvents()[0].m_SourcePath : ""); GetEvolutionPtr()->SetTasksPath(srcs.GetTasks().size() ? srcs.GetTasks()[0].m_SourcePath : ""); GetEvolutionPtr()->SetMemosPath(srcs.GetMemos().size() ? srcs.GetMemos()[0].m_SourcePath : ""); } // success! return true; } bool Evolution::RunApp(wxWindow *parent) { return Run(parent, AppName(), _T("evolution")); } void Evolution::PreSyncAppInit() { ForceShutdown(); } bool Evolution::ZapData(wxWindow *parent, plugin_ptr plugin, OpenSync::API *engine) { m_parent = parent; // extract OpenSync::Config::Evolution from plugin // this *can* throw an exception if the wrong plugin is // passed in, but we want this... such an exception would // represent a bug in the app, not a runtime error // OpenSync::Config::Evolution &evo = // dynamic_cast(*plugin); if( IsAppRunning() ) { wxMessageBox(_W("Evolution already running."), _W("Oops..."), wxOK | wxICON_INFORMATION, m_parent); return false; } // tell the user what to do wxString msg; if( dynamic_cast(engine) ) { msg = _W( "Starting Evolution. Delete all contacts and/or calendar " "entries manually, depending on your sync configuration."); } else { msg = _W( "Starting Evolution. Delete all objects (contacts, calendar, " "memos, and tasks, depending on your sync configuration)." ); } int choice = wxMessageBox(msg, _W("Starting Evolution"), wxOK | wxCANCEL | wxICON_QUESTION, m_parent); if( choice != wxOK ) return false; RunApp(parent); // wait for app to finish... this is kinda lame, but // we don't want other Zaps to happen before this is finished while( IsAppRunning() ) wxMilliSleep(500); return true; } ////////////////////////////////////////////////////////////////////////////// // Evolution3 class Evolution3::Evolution3() : m_evolution3(0) { } void Evolution3::AcquirePlugin(plugin_ptr old_plugin) { // create our plugin config m_evolution3 = dynamic_cast (old_plugin.get()); if( m_evolution3 ) { m_evolution3 = m_evolution3->Clone(); } else { m_evolution3 = new OpenSync::Config::Evolution3; } m_container.reset( m_evolution3 ); } OpenSync::Config::Evolution* Evolution3::GetEvolutionPtr() { return m_evolution3; } void Evolution3::Clear() { m_container.reset(); m_evolution3 = 0; } ConfigUI::plugin_ptr Evolution3::GetPlugin() { m_evolution3 = 0; return m_container; } } // namespace AppConfig barry-0.18.5/desktop/src/util.cc0000644001161500056700000002062112242254476016001 0ustar cdfreycdfrey/// /// \file util.cc /// Utility functions specific to Barry Desktop /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "util.h" #include "barrydesktop.h" #include "windowids.h" #include #include #include #include "wxi18n.h" using namespace std; const wxChar *ButtonNames[] = { _T("backuprestore"), _T("sync"), _T("modem"), _T("migratedevice"), _T("browsedatabases"), _T("apploader"), _T("media"), _T("misc"), 0 }; const wxArrayString& GetButtonLabels() { static wxArrayString m_labels; if( m_labels.GetCount() == 0 ) { // TRANSLATORS: this is a main screen button label. See // util.cc line 200 for more information on its flexibility. m_labels.Add( _W("Backup &\nRestore") ); // TRANSLATORS: this is a main screen button label m_labels.Add( _W("Sync") ); // TRANSLATORS: this is a main screen button label m_labels.Add( _W("Modem\nTethering") ); // TRANSLATORS: this is a main screen button label m_labels.Add( _W("Migrate\nDevice") ); // TRANSLATORS: this is a main screen button label m_labels.Add( _W("Browse\nDatabases") ); // TRANSLATORS: this is a main screen button label m_labels.Add( _W("Application\nLoader") ); // TRANSLATORS: this is a main screen button label m_labels.Add( _W("Media") ); // TRANSLATORS: this is a main screen button label m_labels.Add( _W("Misc") ); } return m_labels; } bool ButtonEnabled[] = { true, // backuprestore true, // sync true, // modem true, // migratedevice true, // browsedatabases false, // apploader false, // media false, // misc false }; const wxChar *StateNames[] = { _T("-normal.png"), _T("-focus.png"), _T("-pushed.png"), 0 }; ////////////////////////////////////////////////////////////////////////////// // Utility functions std::string GetBaseFilename(const std::string &filename) { std::string file = BARRYDESKTOP_BASEDATADIR; file += filename; if( wxFileExists(wxString(file.c_str(), wxConvUTF8)) ) return file; // fall back to the devel tree return filename; } /// Returns full path and filename for given filename. /// 'filename' should have no directory component, as the /// directory will be prepended and returned. wxString GetImageFilename(const wxString &filename) { // try the official install directory first wxString file = _T(BARRYDESKTOP_IMAGEDIR); file += filename; if( wxFileExists(file) ) return file; // oops, assume we're running from the build directory, // and use the images dir file = wxPathOnly(wxGetApp().argv[0]); file += _T("/../images/"); file += filename; if( wxFileExists(file) ) return file; // hmmm.... maybe we're running from inside the libtool // build subdirectories file = wxPathOnly(wxGetApp().argv[0]); file += _T("/../../images/"); file += filename; return file; } wxString GetButtonFilename(int id, int state) { return GetImageFilename( wxString(ButtonNames[id - MainMenu_FirstButton]) + StateNames[state] ); } wxString GetButtonLabel(int id) { return GetButtonLabels()[id - MainMenu_FirstButton]; } bool IsButtonEnabled(int id) { return ButtonEnabled[id - MainMenu_FirstButton]; } void MakeDateRecent(bool checked, wxDatePickerCtrl *picker) { wxDateTime when = picker->GetValue(); if( checked && (!when.IsValid() || when < wxDateTime(1, wxDateTime::Jan, 1975, 0, 0, 0)) ) { when = wxDateTime::Now(); picker->SetValue(when); } } bool IsParsable(const std::string &dbname) { #undef HANDLE_PARSER #define HANDLE_PARSER(dbn) \ if( dbname == Barry::dbn::GetDBName() ) return true; ALL_KNOWN_PARSER_TYPES return false; } bool IsBuildable(const std::string &dbname) { #undef HANDLE_BUILDER #define HANDLE_BUILDER(dbn) \ if( dbname == Barry::dbn::GetDBName() ) return true; ALL_KNOWN_BUILDER_TYPES return false; } namespace { struct LabelLine { wxString m_line; int m_width; int m_height; LabelLine(const wxString &line, const wxDC &dc) : m_line(line) , m_width(0) , m_height(0) { dc.GetTextExtent(line, &m_width, &m_height); } }; } // // DrawButtonLabel // /// Draws the given label text in the specified area of the bitmap, /// modifying the DC in the process (the bitmap is only used for /// sizing). This is intended for use in creating the main Desktop /// buttons, but can be used on any image. /// /// The left/top/right/bottom coordinates are relative to the 0,0 of /// the bitmap itself, and limit the area where the label text will be /// drawn. If -1 is used for any of the values, the bitmap edge will /// be used. If other negative numbers are used, (edge - value) will /// be used. /// /// The label text can contain \n characters to split into multiple /// lines. Each line will be centered (left/right) in the coordinate /// area, and all lines will be centered (top/bottom) in the coordinate /// area. A trailing \n character is not required, and not recommended. /// /// If the coordinate area is too small for the given text and font, /// the font will be reduced iteratively for a few points and tried again. /// If still too big, a DrawButtonLabelError exception will be thrown. /// Note that the font passed in will be modified in this case, in case /// the new point size needs to be used elsewhere. /// /// If the label contains an empty string, a DrawButtonLabelError exception will /// be thrown. This is to prevent any unlabeled buttons in the system. /// /// If Font is invalid, DrawButtonLabelError will be thrown. /// void DrawButtonLabelDC(wxDC &dc, const wxBitmap &bmp, const wxString &label, wxFont &font, const wxColour &textfg, int left, int top, int right, int bottom) { // calculate the coordinates, and various sanity checks if( left == -1 ) left = 0; if( top == -1 ) top = 0; if( right == -1 ) right = bmp.GetWidth(); if( bottom == -1 ) bottom = bmp.GetHeight(); if( right < -1 ) right = bmp.GetWidth() + right; if( bottom < -1 ) bottom = bmp.GetHeight() + bottom; int width = right - left; if( width < 0 ) { swap(left, right); width = right - left; } int height = bottom - top; if( height < 0 ) { swap(top, bottom); height = bottom - top; } if( !font.IsOk() ) throw DrawButtonLabelError(_C("Unable to create button: font is invalid")); // create DC to work with, writing into the bitmap given to us dc.SetFont(font); dc.SetTextForeground(textfg); dc.SetMapMode(wxMM_TEXT); // build vector of lines, and calculate totals int total_text_height = 0; int widest_line = 0; std::vector lines; // ... and keep trying if too big for( int tries = 0; ; tries++ ) { // start fresh total_text_height = 0; widest_line = 0; lines.clear(); wxStringTokenizer tokens(label, _T("\n")); while( tokens.HasMoreTokens() ) { wxString token = tokens.GetNextToken(); token.Trim(true); token.Trim(false); if( !tokens.HasMoreTokens() && token.size() == 0 ) { // we're done here... last line is empty break; } LabelLine line(token, dc); lines.push_back( line ); total_text_height += line.m_height; widest_line = max(widest_line, line.m_width); } // do we have enough room? if( total_text_height <= height && widest_line <= width ) { // good to go! break; } // only reduce font so much... if( tries >= 4 ) throw DrawButtonLabelError(_C("Unable to create button: text is too big to fit: ") + string(label.utf8_str())); // too big, reduce font and try again font.SetPointSize( font.GetPointSize() - 1 ); dc.SetFont(font); } // empty? if( lines.size() == 0 ) throw DrawButtonLabelError(_C("Unable to create button: label is empty")); // calculate starting height int y = (height - total_text_height) / 2 + top; // draw each line, centering each one horizontally, and // incrementing y by the line's height on each pass std::vector::iterator b = lines.begin(), e = lines.end(); for( ; b != e; ++b ) { int x = (width - b->m_width) / 2 + left; dc.DrawText(b->m_line, x, y); y += b->m_height; } } barry-0.18.5/desktop/src/osprivatebase.h0000644001161500056700000000265212242254476017541 0ustar cdfreycdfrey/// /// \file osprivatebase.h /// Base API class for OpenSync sync conflicts /// This API will operate both 0.22 and 0.4x /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_OSPRIVATEBASE_H__ #define __BARRYDESKTOP_OSPRIVATEBASE_H__ #include #include namespace OpenSync { class SyncConflictPrivateBase { public: virtual ~SyncConflictPrivateBase() {} virtual bool IsAbortSupported() const = 0; virtual bool IsIgnoreSupported() const = 0; virtual bool IsKeepNewerSupported() const = 0; virtual void Select(int change_id) = 0; virtual void Abort() = 0; virtual void Duplicate() = 0; virtual void Ignore() = 0; virtual void KeepNewer() = 0; }; class SyncSummaryPrivateBase { public: virtual ~SyncSummaryPrivateBase() {} virtual void Abort() = 0; virtual void Continue() = 0; }; } #endif barry-0.18.5/desktop/src/CUI_KDEPim.h0000644001161500056700000000263312242254476016442 0ustar cdfreycdfrey/// /// \file CUI_KDEPim.h /// ConfigUI derived class to configure the KDEPim App /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_CUI_KDEPIM_H__ #define __BARRY_CUI_KDEPIM_H__ #include "configui.h" #include "osconfig.h" #include class wxWindow; namespace AppConfig { class KDEPim : public ConfigUI { OpenSync::Config::KDEPim *m_kdepim; plugin_ptr m_container; // merely holds m_kdepim // convenience pointers wxWindow *m_parent; public: KDEPim(); // virtual overrides (ConfigUI) virtual std::string AppName() const; virtual bool Configure(wxWindow *parent, plugin_ptr old_plugin); virtual plugin_ptr GetPlugin(); virtual bool RunApp(wxWindow *parent); virtual void PreSyncAppInit(); virtual bool ZapData(wxWindow *parent, plugin_ptr plugin, OpenSync::API *engine); }; } #endif barry-0.18.5/desktop/src/osconv40.cc0000644001161500056700000002370312242254476016503 0ustar cdfreycdfrey/// /// \file osconv40.cc /// Converter class for opensync 0.40 plugins /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "osconv40.h" #include "osconfig.h" #include #include "i18n.h" using namespace std; // Supported plugin names #define PLUGIN_BARRY "barry-sync" #define PLUGIN_EVOLUTION "evo2-sync" #define PLUGIN_EVOLUTION3 "evo3-sync" #define PLUGIN_GOOGLE "google-data" #define PLUGIN_KDEPIM "kdepim-sync" #define PLUGIN_FILE "file-sync" #define PLUGIN_SUNBIRD "sunbird-sync" #define PLUGIN_LDAP "ldap-sync" namespace OpenSync { ////////////////////////////////////////////////////////////////////////////// // Converter40 Converter40::Converter40(OpenSync::OpenSync40 &api) : m_api(api) { } bool Converter40::IsPluginSupported(const std::string &plugin_name, std::string *appname) const { if( plugin_name == PLUGIN_BARRY ) { if( appname ) *appname = Config::Barry::AppName(); return true; } else if( plugin_name == PLUGIN_EVOLUTION ) { if( appname ) *appname = Config::Evolution::AppName(); return true; } else if( plugin_name == PLUGIN_EVOLUTION3 ) { if( appname ) *appname = Config::Evolution3::AppName(); return true; } else if( plugin_name == PLUGIN_GOOGLE ) { if( appname ) *appname = Config::Google::AppName(); return true; } return false; } Converter::plugin_ptr Converter40::CreateAndLoadPlugin(const Member &member) { Converter::plugin_ptr ptr; // compare plugin name in member with all known plugins that // we support... and default to Unsupported if not if( member.plugin_name == PLUGIN_BARRY ) { ptr.reset( new Config::Barry(this, member) ); } else if( member.plugin_name == PLUGIN_EVOLUTION ) { ptr.reset( new Config::Evolution(this, member) ); } else if( member.plugin_name == PLUGIN_EVOLUTION3 ) { ptr.reset( new Config::Evolution3(this, member) ); } else if( member.plugin_name == PLUGIN_GOOGLE ) { ptr.reset( new Config::Google(this, member) ); } // default: Unsupported else { ptr.reset( new Config::Unsupported(this, member) ); } return ptr; } std::string Converter40::GetPluginName(const Config::Barry &) const { return PLUGIN_BARRY; } std::string Converter40::GetPluginName(const Config::Evolution &) const { return PLUGIN_EVOLUTION; } std::string Converter40::GetPluginName(const Config::Evolution3 &) const { return PLUGIN_EVOLUTION3; } std::string Converter40::GetPluginName(const Config::Google &) const { return PLUGIN_GOOGLE; } std::string Converter40::GetPluginName(const Config::KDEPim &) const { return PLUGIN_KDEPIM; } std::string Converter40::GetPluginName(const Config::Unsupported &) const { return "unsupported-sync"; } bool Converter40::IsConfigured(const Config::Barry &config) const { return config.GetPin().Valid(); } bool Converter40::IsConfigured(const Config::Evolution &config) const { // as long as one is configured, we're good return config.GetAddressPath().size() || config.GetCalendarPath().size() || config.GetTasksPath().size() || config.GetMemosPath().size(); } bool Converter40::IsConfigured(const Config::Evolution3 &config) const { return IsConfigured(static_cast (config)); } bool Converter40::IsConfigured(const Config::Google &config) const { // password might (maaayybe) be empty, so skip it return config.GetUsername().size(); } bool Converter40::IsConfigured(const Config::KDEPim &config) const { // FIXME - not sure about this plugin yet return false; } bool Converter40::IsConfigured(const Config::Unsupported &) const { return false; } // FIXME - these should/could? access the capabilities feature of // opensync 0.4x, but I think that requires a discovery, and // this information is required at the configuration stage // for the GUI Config::pst_type Converter40::GetSupportedSyncTypes(const Config::Barry &) const { return PST_CONTACTS | PST_EVENTS | PST_NOTES | PST_TODOS; } Config::pst_type Converter40::GetSupportedSyncTypes(const Config::Evolution &) const { return PST_CONTACTS | PST_EVENTS | PST_NOTES | PST_TODOS; } Config::pst_type Converter40::GetSupportedSyncTypes(const Config::Evolution3 &) const { return PST_CONTACTS | PST_EVENTS | PST_NOTES | PST_TODOS; } Config::pst_type Converter40::GetSupportedSyncTypes(const Config::Google &) const { return PST_CONTACTS | PST_EVENTS; } Config::pst_type Converter40::GetSupportedSyncTypes(const Config::KDEPim &) const { return PST_CONTACTS | PST_EVENTS | PST_NOTES | PST_TODOS; } Config::pst_type Converter40::GetSupportedSyncTypes(const Config::Unsupported &) const { return PST_NONE; } void Converter40::Load(Config::Barry &config, const Member &member) { // start with a default setting config.DebugMode(false); config.SetPassword(""); config.SetPin(Barry::Pin()); // read in config for barry-sync OS40PluginConfig cfg = m_api.GetConfigurationObj(member.group_name, member.id); string value = cfg.GetAdvanced("Debug"); if( value == "1" ) config.DebugMode(true); value = cfg.GetAdvanced("PinCode"); { istringstream iss(value); uint32_t pin = 0; iss >> hex >> pin; config.SetPin(Barry::Pin(pin)); } value = cfg.GetPassword(); config.SetPassword(value); } void Converter40::Load(Config::Evolution &config, const Member &member) { OS40PluginConfig cfg = m_api.GetConfigurationObj(member.group_name, member.id); config.SetAddressPath(cfg.GetResource("contact")->GetUrl()); config.SetCalendarPath(cfg.GetResource("event")->GetUrl()); config.SetTasksPath(cfg.GetResource("todo")->GetUrl()); config.SetMemosPath(cfg.GetResource("note")->GetUrl()); } void Converter40::Load(Config::Evolution3 &config, const Member &member) { Load(static_cast (config), member); } void Converter40::Load(Config::Google &config, const Member &member) { OS40PluginConfig cfg = m_api.GetConfigurationObj(member.group_name, member.id); config.SetUsername(cfg.GetUsername()); config.SetPassword(cfg.GetPassword()); config.EnableContacts(cfg.GetResource("contact")->IsEnabled()); config.EnableCalendar(cfg.GetResource("event")->IsEnabled()); } void Converter40::Load(Config::KDEPim &config, const Member &member) { // FIXME } void Converter40::Load(Config::Unsupported &config, const Member &member) { string cfg = m_api.GetConfiguration(member.group_name, member.id); config.SetRawConfig(cfg); } void Converter40::Save(const Config::Barry &config, const std::string &group_name) { if( config.GetMemberId() == -1 ) throw Config::SaveError(_C("Cannot save a plugin with a member_id of -1")); OS40PluginConfig cfg = m_api.GetConfigurationObj(group_name, config.GetMemberId()); cfg.SetAdvanced("Debug", "Debug mode", OS40PluginConfig::BOOL_TYPE, config.IsDebugMode() ? "1" : "0"); cfg.SetAdvanced("PinCode", "PIN number", OS40PluginConfig::STRING_TYPE, config.GetPin().Str()); cfg.SetPassword(config.GetPassword()); cfg.GetResource("contact")-> SetName("Contacts"). Enable(true). SetObjFormat("vcard30"). AddResource(); cfg.GetResource("event")-> SetName("Event"). Enable(true). SetObjFormat("vevent20"). AddResource(); cfg.GetResource("todo")-> SetName("Todo"). Enable(true). SetObjFormat("vtodo20"). AddResource(); cfg.GetResource("note")-> SetName("Memo"). Enable(true). SetObjFormat("vjournal"). AddResource(); cfg.Save(); } void Converter40::Save(const Config::Evolution &config, const std::string &group_name) { if( config.GetMemberId() == -1 ) throw Config::SaveError(_C("Cannot save a plugin with a member_id of -1")); OS40PluginConfig cfg = m_api.GetConfigurationObj(group_name, config.GetMemberId()); cfg.GetResource("contact")-> Enable(config.GetAddressPath().size()). SetObjFormat("vcard21", "VCARD_EXTENSION=Evolution"). SetObjFormat("vcard30", "VCARD_EXTENSION=Evolution"). SetUrl(config.GetAddressPath()). AddResource(); cfg.GetResource("event")-> Enable(config.GetCalendarPath().size()). SetObjFormat("vevent20"). SetUrl(config.GetCalendarPath()). AddResource(); cfg.GetResource("todo")-> Enable(config.GetTasksPath().size()). SetObjFormat("vtodo20"). SetUrl(config.GetTasksPath()). AddResource(); cfg.GetResource("note")-> Enable(config.GetMemosPath().size()). SetObjFormat("vjournal"). SetUrl(config.GetMemosPath()). AddResource(); cfg.Save(); } void Converter40::Save(const Config::Evolution3 &config, const std::string &group_name) { Save(static_cast (config), group_name); } void Converter40::Save(const Config::Google &config, const std::string &group_name) { if( config.GetMemberId() == -1 ) throw Config::SaveError(_C("Cannot save a plugin with a member_id of -1")); OS40PluginConfig cfg = m_api.GetConfigurationObj(group_name, config.GetMemberId()); cfg.SetUsername(config.GetUsername()); cfg.SetPassword(config.GetPassword()); cfg.GetResource("contact")-> Enable(config.IsContactsEnabled()). SetObjFormat("xmlformat-contact-doc"). AddResource(); cfg.GetResource("event")-> Enable(config.IsCalendarEnabled()). SetObjFormat("xmlformat-event-doc"). AddResource(); cfg.Save(); } void Converter40::Save(const Config::KDEPim &config, const std::string &group_name) { // FIXME } void Converter40::Save(const Config::Unsupported &config, const std::string &group_name) { if( config.GetMemberId() == -1 ) throw Config::SaveError(_C("Cannot save a plugin with a member_id of -1")); m_api.SetConfiguration(group_name, config.GetMemberId(), config.GetRawConfig()); } } // namespace OpenSync barry-0.18.5/desktop/src/os40.cc0000644001161500056700000022425012242254476015615 0ustar cdfreycdfrey/// /// \file os40.cc /// Wrapper class for opensync 0.22 syncing behaviour /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) Used code from osynctool (GPL v2+) as a guide to the API, and copied some of the status messages, as well as one funcion directly: static const char *OSyncChangeType2String(OSyncChangeType type) Copyright (C) 2004-2005 Armin Bauer Copyright (C) 2006-2007 Daniel Friedrich Copyright (C) 2008-2009 Daniel Gollub 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 in the COPYING file at the root directory of this project for more details. */ #include "os40.h" #include "os22.h" #include "osprivatebase.h" #include "tempdir.h" #include "osconv40.h" #include #include #include #include #include #include #include #include "i18n.h" // use relative paths to backtrack enough to specify only 0.4x includes #include <../libopensync1/opensync/opensync.h> #include <../libopensync1/opensync/opensync-group.h> #include <../libopensync1/opensync/opensync-format.h> #include <../libopensync1/opensync/opensync-plugin.h> #include <../libopensync1/opensync/opensync-engine.h> #include <../libopensync1/opensync/opensync-data.h> #include <../libopensync1/opensync/opensync-capabilities.h> using namespace std; using namespace Barry; namespace OpenSync { typedef Barry::vLateSmartPtr EngineHandle; typedef Barry::vLateSmartPtr SyncListHandle; // // Private class declarations // class TossError { OSyncError *m_error; OpenSync40Private *m_priv; public: // simple wrapper... unref's the error on destruction TossError(OpenSync40Private *priv) : m_error(0) , m_priv(priv) { } ~TossError() { Clear(); } /// Returns NULL if no error std::string GetErrorMsg(); bool IsSet(); void Clear(); operator OSyncError**() { return &m_error; } }; class OpenSync40Private { public: // function pointers const char* (*osync_get_version)(); const char* (*osync_error_print)(OSyncError **error); char* (*osync_error_print_stack)(OSyncError **error); osync_bool (*osync_error_is_set)(OSyncError **error); void (*osync_error_unref)(OSyncError **error); OSyncGroupEnv* (*osync_group_env_new)(OSyncError **error); OSyncFormatEnv* (*osync_format_env_new)(OSyncError **error); OSyncPluginEnv* (*osync_plugin_env_new)(OSyncError **error); void (*osync_group_env_unref)(OSyncGroupEnv *env); void (*osync_format_env_unref)(OSyncFormatEnv *env); void (*osync_plugin_env_unref)(OSyncPluginEnv *env); osync_bool (*osync_plugin_env_load)(OSyncPluginEnv *env, const char *path, OSyncError **error); OSyncList* (*osync_plugin_env_get_plugins)( OSyncPluginEnv *env); const char* (*osync_plugin_get_name)(OSyncPlugin *plugin); void (*osync_list_free)(OSyncList *list); osync_bool (*osync_group_env_load_groups)( OSyncGroupEnv *env, const char *path, OSyncError **error); osync_bool (*osync_format_env_load_plugins)( OSyncFormatEnv *env, const char *path, OSyncError **error); OSyncList* (*osync_group_env_get_groups)( OSyncGroupEnv *env); const char* (*osync_group_get_name)(OSyncGroup *group); OSyncGroup* (*osync_group_env_find_group)( OSyncGroupEnv *env, const char *name); OSyncList* (*osync_group_get_members)(OSyncGroup *group); const char* (*osync_member_get_name)(OSyncMember *member); osync_memberid (*osync_member_get_id)(OSyncMember *member); const char* (*osync_member_get_pluginname)( OSyncMember *member); OSyncList* (*osync_format_env_get_objformats)( OSyncFormatEnv *env); const char* (*osync_objformat_get_name)( OSyncObjFormat *format); const char* (*osync_objformat_get_objtype)( OSyncObjFormat *format); OSyncGroup* (*osync_group_new)(OSyncError **error); void (*osync_group_unref)(OSyncGroup *group); void (*osync_group_set_name)(OSyncGroup *group, const char *name); osync_bool (*osync_group_env_add_group)(OSyncGroupEnv *env, OSyncGroup *group, OSyncError **error); osync_bool (*osync_group_save)(OSyncGroup *group, OSyncError **error); osync_bool (*osync_group_delete)(OSyncGroup *group, OSyncError **error); void (*osync_group_env_remove_group)( OSyncGroupEnv *env, OSyncGroup *group); OSyncPlugin* (*osync_plugin_env_find_plugin)( OSyncPluginEnv *env, const char *name); void (*osync_member_unref)(OSyncMember *member); OSyncMember* (*osync_member_new)(OSyncError **error); void (*osync_group_add_member)(OSyncGroup *group, OSyncMember *member); void (*osync_member_set_pluginname)( OSyncMember *member, const char *pluginname); void (*osync_member_set_name)(OSyncMember *member, const char *name); osync_bool (*osync_member_save)(OSyncMember *member, OSyncError **error); OSyncMember* (*osync_group_find_member)(OSyncGroup *group, osync_memberid id); osync_bool (*osync_member_delete)(OSyncMember *member, OSyncError **error); void (*osync_group_remove_member)(OSyncGroup *group, OSyncMember *member); OSyncPluginConfig* (*osync_plugin_config_new)(OSyncError **error); osync_bool (*osync_plugin_config_file_load)( OSyncPluginConfig *config, const char *path, OSyncError **error); void (*osync_member_set_config)(OSyncMember *member, OSyncPluginConfig *config); OSyncPluginConfig* (*osync_member_get_config_or_default)( OSyncMember *member, OSyncError **error); osync_bool (*osync_plugin_config_file_save)( OSyncPluginConfig *config, const char *path, OSyncError **error); OSyncPluginConfigurationType (*osync_plugin_get_config_type)( OSyncPlugin *plugin); OSyncEngine* (*osync_engine_new)(OSyncGroup *group, OSyncError **error); void (*osync_engine_unref)(OSyncEngine *engine); osync_bool (*osync_engine_discover_and_block)( OSyncEngine *engine, OSyncMember *member, OSyncError **error); OSyncList* (*osync_member_get_objtypes)( OSyncMember *member); unsigned int (*osync_list_length)(const OSyncList *list); void (*osync_error_set)(OSyncError **error, OSyncErrorType type, const char *format, ...); osync_bool (*osync_engine_finalize)(OSyncEngine *engine, OSyncError **error); OSyncList* (*osync_mapping_engine_get_changes)( OSyncMappingEngine *engine); osync_bool (*osync_mapping_engine_supports_ignore)( OSyncMappingEngine *engine); osync_bool (*osync_mapping_engine_supports_use_latest)( OSyncMappingEngine *engine); OSyncList* (*osync_list_nth)(OSyncList *list, unsigned int n); osync_bool (*osync_engine_mapping_solve)( OSyncEngine *engine, OSyncMappingEngine *mapping_engine, OSyncChange *change, OSyncError **error); osync_bool (*osync_engine_abort)(OSyncEngine *engine, OSyncError **error); osync_bool (*osync_engine_mapping_duplicate)( OSyncEngine *engine, OSyncMappingEngine *mapping_engine, OSyncError **error); osync_bool (*osync_engine_mapping_ignore_conflict)( OSyncEngine *engine, OSyncMappingEngine *mapping_engine, OSyncError **error); osync_bool (*osync_engine_mapping_use_latest)( OSyncEngine *engine, OSyncMappingEngine *mapping_engine, OSyncError **error); OSyncChangeType (*osync_change_get_changetype)( OSyncChange *change); OSyncMember* (*osync_mapping_engine_change_find_member)( OSyncMappingEngine *engine, OSyncChange *change); OSyncData* (*osync_change_get_data)(OSyncChange *change); char* (*osync_data_get_printable)(OSyncData *data, OSyncError **error); void (*osync_free)(void *ptr); const char* (*osync_change_get_uid)(OSyncChange *change); osync_bool (*osync_engine_continue)(OSyncEngine *engine, OSyncError **error); OSyncList* (*osync_engine_get_objengines)( OSyncEngine *engine); OSyncList* (*osync_obj_engine_get_members)( OSyncObjEngine* engine); const char* (*osync_obj_engine_get_objtype)( OSyncObjEngine *engine); const OSyncList* (*osync_obj_engine_get_mapping_entry_engines_of_member)( OSyncObjEngine *engine, OSyncMember *member); osync_bool (*osync_entry_engine_is_dirty)( OSyncMappingEntryEngine *engine); OSyncChangeType (*osync_entry_engine_get_changetype)( OSyncMappingEntryEngine *engine); OSyncChange* (*osync_engine_change_update_get_change)( OSyncEngineChangeUpdate *update); OSyncMember* (*osync_engine_change_update_get_member)( OSyncEngineChangeUpdate *update); OSyncError* (*osync_engine_change_update_get_error)( OSyncEngineChangeUpdate *update); OSyncEngineChangeEvent (*osync_engine_change_update_get_event)( OSyncEngineChangeUpdate *update); OSyncObjFormat* (*osync_change_get_objformat)( OSyncChange *change); OSyncError* (*osync_engine_mapping_update_get_error)( OSyncEngineMappingUpdate *update); OSyncError* (*osync_engine_update_get_error)( OSyncEngineUpdate *update); OSyncEngineEvent (*osync_engine_update_get_event)( OSyncEngineUpdate *update); const char* (*osync_engine_member_update_get_objtype)( OSyncEngineMemberUpdate *update); OSyncMember* (*osync_engine_member_update_get_member)( OSyncEngineMemberUpdate *update); OSyncError* (*osync_engine_member_update_get_error)( OSyncEngineMemberUpdate *update); OSyncEngineMemberEvent (*osync_engine_member_update_get_event)( OSyncEngineMemberUpdate *update); void (*osync_engine_set_conflict_callback)( OSyncEngine *engine, osync_conflict_cb callback, void *user_data); void (*osync_engine_set_changestatus_callback)( OSyncEngine *engine, osync_status_change_cb callback, void *user_data); void (*osync_engine_set_mappingstatus_callback)( OSyncEngine *engine, osync_status_mapping_cb callback, void *user_data); void (*osync_engine_set_enginestatus_callback)( OSyncEngine *engine, osync_status_engine_cb callback, void *user_data); void (*osync_engine_set_memberstatus_callback)( OSyncEngine *engine, osync_status_member_cb callback, void *user_data); void (*osync_engine_set_multiply_callback)( OSyncEngine *engine, osync_multiply_cb callback, void *user_data); osync_bool (*osync_engine_initialize)(OSyncEngine *engine, OSyncError **error); osync_bool (*osync_engine_synchronize_and_block)( OSyncEngine *engine,OSyncError **error); OSyncEngineMappingEvent (*osync_engine_mapping_update_get_event)( OSyncEngineMappingUpdate *update); void (*osync_plugin_resource_unref)( OSyncPluginResource *resource); void (*osync_plugin_config_add_resource)( OSyncPluginConfig *config, OSyncPluginResource *resource); osync_bool (*osync_plugin_resource_is_enabled)( OSyncPluginResource *resource); void (*osync_plugin_resource_enable)( OSyncPluginResource *resource, osync_bool enable); OSyncList* (*osync_plugin_resource_get_objformat_sinks)( OSyncPluginResource *resource); const char* (*osync_objformat_sink_get_objformat)( OSyncObjFormatSink *sink); const char* (*osync_objformat_sink_get_config)( OSyncObjFormatSink *sink); void (*osync_objformat_sink_set_config)( OSyncObjFormatSink *sink, const char *config); OSyncObjFormatSink* (*osync_objformat_sink_new)( const char *objformat, OSyncError **error); void (*osync_plugin_resource_add_objformat_sink)( OSyncPluginResource *resource, OSyncObjFormatSink *formatsink); void (*osync_objformat_sink_unref)( OSyncObjFormatSink *sink); const char* (*osync_plugin_resource_get_preferred_format)( OSyncPluginResource *resource); void (*osync_plugin_resource_set_preferred_format)( OSyncPluginResource *resource, const char *preferred_format); const char* (*osync_plugin_resource_get_mime)( OSyncPluginResource *resource); void (*osync_plugin_resource_set_mime)( OSyncPluginResource *resource, const char *mime); const char* (*osync_plugin_resource_get_objtype)( OSyncPluginResource *resource); void (*osync_plugin_resource_set_objtype)( OSyncPluginResource *resource, const char *objtype); const char* (*osync_plugin_resource_get_path)( OSyncPluginResource *resource); void (*osync_plugin_resource_set_path)( OSyncPluginResource *resource, const char *path); const char* (*osync_plugin_resource_get_url)( OSyncPluginResource *resource); void (*osync_plugin_resource_set_url)( OSyncPluginResource *resource, const char *url); const char* (*osync_plugin_config_get_advancedoption_value_by_name)( OSyncPluginConfig *config, const char *name); OSyncList* (*osync_plugin_config_get_advancedoptions)( OSyncPluginConfig *config); void (*osync_plugin_config_add_advancedoption)( OSyncPluginConfig *config, OSyncPluginAdvancedOption *option); OSyncPluginAdvancedOption* (*osync_plugin_advancedoption_new)( OSyncError **error); void (*osync_plugin_advancedoption_unref)( OSyncPluginAdvancedOption *option); const char* (*osync_plugin_advancedoption_get_name)( OSyncPluginAdvancedOption *option); void (*osync_plugin_advancedoption_set_name)( OSyncPluginAdvancedOption *option, const char *name); void (*osync_plugin_advancedoption_set_displayname)( OSyncPluginAdvancedOption *option, const char *displayname); void (*osync_plugin_advancedoption_set_type)( OSyncPluginAdvancedOption *option, OSyncPluginAdvancedOptionType type); void (*osync_plugin_advancedoption_set_value)( OSyncPluginAdvancedOption *option, const char *value); OSyncList* (*osync_plugin_config_get_resources)( OSyncPluginConfig *config); OSyncPluginResource* (*osync_plugin_resource_ref)( OSyncPluginResource *resource); OSyncPluginResource* (*osync_plugin_resource_new)( OSyncError **error); const char* (*osync_plugin_resource_get_name)( OSyncPluginResource *resource); void (*osync_plugin_resource_set_name)( OSyncPluginResource *resource, const char *name); OSyncPluginAuthentication* (*osync_plugin_config_get_authentication)( OSyncPluginConfig *config); const char* (*osync_plugin_authentication_get_password)( OSyncPluginAuthentication *auth); OSyncPluginAuthentication* (*osync_plugin_authentication_new)( OSyncError **error); osync_bool (*osync_plugin_authentication_option_is_supported)( OSyncPluginAuthentication *auth, OSyncPluginAuthenticationOptionSupportedFlag flag); void (*osync_plugin_authentication_unref)( OSyncPluginAuthentication *auth); void (*osync_plugin_config_set_authentication)( OSyncPluginConfig *config, OSyncPluginAuthentication *auth); void (*osync_plugin_authentication_set_password)( OSyncPluginAuthentication *auth, const char *password); const char* (*osync_plugin_authentication_get_username)( OSyncPluginAuthentication *auth); void (*osync_plugin_authentication_set_username)( OSyncPluginAuthentication *auth, const char *password); void (*osync_group_set_objtype_enabled)( OSyncGroup *group, const char *objtype, osync_bool enabled); // data pointers vLateSmartPtr group_env; vLateSmartPtr format_env; vLateSmartPtr plugin_env; TossError error; Converter40 converter; OpenSync40Private(OpenSync40 &api) : error(this) , converter(api) { } // helper functions std::string osync_error_print_stack_wrapper(OSyncError **error) { std::string rmsg; char *msg = osync_error_print_stack(error); if( msg ) { rmsg = msg; osync_free(msg); } else { rmsg = _C("(NULL error msg)"); } return rmsg; } }; class SyncConflict40Private : public SyncConflictPrivateBase { OpenSync40Private *m_priv; OSyncEngine *m_engine; OSyncMappingEngine *m_mapping; OSyncList *m_changes; public: SyncConflict40Private(OpenSync40Private *priv, OSyncEngine *engine, OSyncMappingEngine *mapping); ~SyncConflict40Private(); virtual bool IsAbortSupported() const; virtual bool IsIgnoreSupported() const; virtual bool IsKeepNewerSupported() const; virtual void Select(int change_id); // takes the id of SyncChange virtual void Abort(); virtual void Duplicate(); virtual void Ignore(); virtual void KeepNewer(); void AppendChanges(std::vector &list); }; class SyncSummary40Private : public SyncSummaryPrivateBase { OpenSync40Private *m_priv; OSyncEngine *m_engine; public: SyncSummary40Private(OpenSync40Private *priv, OSyncEngine *engine); ~SyncSummary40Private(); virtual void Abort(); virtual void Continue(); // returns true if any member is dirty bool AppendMembers(std::vector &list); }; class OS40PluginConfigPrivate { public: OSyncMember *m_member; OSyncPluginConfig *m_config; OS40PluginConfigPrivate() : m_member(0) , m_config(0) { } }; class OS40ConfigResourcePrivate { public: OpenSync40Private *m_privapi; OS40PluginConfigPrivate *m_parentpriv; OSyncPluginResource *m_resource; OS40ConfigResourcePrivate() : m_privapi(0) , m_parentpriv(0) , m_resource(0) { } }; struct CallbackBundle { OpenSync40Private *m_priv; SyncStatus *m_status; CallbackBundle(OpenSync40Private *priv, SyncStatus &status) : m_priv(priv) , m_status(&status) { } }; void conflict_handler(OSyncEngine *, OSyncMappingEngine *, void *); void entry_status(OSyncEngineChangeUpdate *, void *); void mapping_status(OSyncEngineMappingUpdate *, void *); void engine_status(OSyncEngineUpdate *, void *); void member_status(OSyncEngineMemberUpdate *, void *); void multiply_summary(OSyncEngine *, void *); ///////////////////////////////////////////////////////////////////////////// // Static helper functions static const char *OSyncChangeType2String(OSyncChangeType type) { switch (type) { case OSYNC_CHANGE_TYPE_ADDED: return _C("ADDED"); case OSYNC_CHANGE_TYPE_UNMODIFIED: return _C("UNMODIFIED"); case OSYNC_CHANGE_TYPE_DELETED: return _C("DELETED"); case OSYNC_CHANGE_TYPE_MODIFIED: return _C("MODIFIED"); default: case OSYNC_CHANGE_TYPE_UNKNOWN: return "?"; } } ///////////////////////////////////////////////////////////////////////////// // SyncConflict40Private member functions SyncConflict40Private::SyncConflict40Private(OpenSync40Private *priv, OSyncEngine *engine, OSyncMappingEngine *mapping) : m_priv(priv) , m_engine(engine) , m_mapping(mapping) , m_changes(0) { m_changes = m_priv->osync_mapping_engine_get_changes(m_mapping); } SyncConflict40Private::~SyncConflict40Private() { m_priv->osync_list_free(m_changes); } bool SyncConflict40Private::IsAbortSupported() const { return true; } bool SyncConflict40Private::IsIgnoreSupported() const { return m_priv->osync_mapping_engine_supports_ignore(m_mapping); } bool SyncConflict40Private::IsKeepNewerSupported() const { return m_priv->osync_mapping_engine_supports_use_latest(m_mapping); } void SyncConflict40Private::Select(int change_id) { OSyncList *c = m_priv->osync_list_nth(m_changes, change_id); if( !c ) throw std::logic_error("Bad change_id"); OSyncChange *change = (OSyncChange *) c->data; if( !m_priv->osync_engine_mapping_solve(m_engine, m_mapping, change, m_priv->error) ) { throw std::runtime_error(m_priv->error.GetErrorMsg()); } } void SyncConflict40Private::Abort() { if( !m_priv->osync_engine_abort(m_engine, m_priv->error) ) { ostringstream oss; oss << _C("Problems while aborting: ") << m_priv->error.GetErrorMsg(); throw std::runtime_error(oss.str()); } } void SyncConflict40Private::Duplicate() { if( !m_priv->osync_engine_mapping_duplicate(m_engine, m_mapping, m_priv->error) ) throw std::runtime_error(m_priv->error.GetErrorMsg()); } void SyncConflict40Private::Ignore() { if( !IsIgnoreSupported() ) throw std::logic_error("Ignore not supported, yet Ignore() called."); if( !m_priv->osync_engine_mapping_ignore_conflict(m_engine, m_mapping, m_priv->error) ) { throw std::runtime_error(m_priv->error.GetErrorMsg()); } } void SyncConflict40Private::KeepNewer() { if( !IsKeepNewerSupported() ) throw std::logic_error("Keep Newer not supported, yet KeepNewer() called."); if( !m_priv->osync_engine_mapping_use_latest(m_engine, m_mapping, m_priv->error) ) throw std::runtime_error(m_priv->error.GetErrorMsg()); } void SyncConflict40Private::AppendChanges(std::vector &list) { int i = 0; for( OSyncList *c = m_changes; c; c = c->next, i++ ) { OSyncChange *change = (OSyncChange *) c->data; if( m_priv->osync_change_get_changetype(change) != OSYNC_CHANGE_TYPE_UNKNOWN ) { OSyncMember *member = m_priv->osync_mapping_engine_change_find_member(m_mapping, change); OSyncData *data = m_priv->osync_change_get_data(change); SyncChange entry; char *printable = m_priv->osync_data_get_printable(data, m_priv->error); if( printable ) entry.printable_data = printable; m_priv->osync_free(printable); if( m_priv->error.IsSet() ) throw std::runtime_error(m_priv->error.GetErrorMsg()); entry.id = i; entry.member_id = m_priv->osync_member_get_id(member); entry.plugin_name = m_priv->osync_member_get_pluginname(member); entry.uid = m_priv->osync_change_get_uid(change); // add to list list.push_back(entry); } } } ///////////////////////////////////////////////////////////////////////////// // SyncSummary40Private member functions SyncSummary40Private::SyncSummary40Private(OpenSync40Private *priv, OSyncEngine *engine) : m_priv(priv) , m_engine(engine) { } SyncSummary40Private::~SyncSummary40Private() { } void SyncSummary40Private::Abort() { if( !m_priv->osync_engine_abort(m_engine, m_priv->error) ) throw std::runtime_error(m_priv->error.GetErrorMsg()); } void SyncSummary40Private::Continue() { if( !m_priv->osync_engine_continue(m_engine, m_priv->error) ) throw std::runtime_error(m_priv->error.GetErrorMsg()); } bool SyncSummary40Private::AppendMembers(std::vector &list) { SyncListHandle objengines(m_priv->osync_list_free); objengines = m_priv->osync_engine_get_objengines(m_engine); int i = 0; bool dirty = false; for( OSyncList *o = objengines.get(); o; o = o->next ) { OSyncObjEngine *objengine = (OSyncObjEngine *) o->data; SyncListHandle members(m_priv->osync_list_free); members = m_priv->osync_obj_engine_get_members(objengine); for( OSyncList *m = members.get(); m; m = m->next ) { OSyncMember *member = (OSyncMember *) m->data; // Fill in common summary data SyncMemberSummary entry; entry.id = i; entry.objtype_name = m_priv->osync_obj_engine_get_objtype(objengine); entry.member_id = m_priv->osync_member_get_id(member); entry.plugin_name = m_priv->osync_member_get_pluginname(member); const OSyncList *mapping_entry_engines = m_priv->osync_obj_engine_get_mapping_entry_engines_of_member(objengine, member); // Calculate summary counts for( const OSyncList *e = mapping_entry_engines; e; e = e->next ) { OSyncMappingEntryEngine *entry_engine = (OSyncMappingEntryEngine*) e->data; if( !m_priv->osync_entry_engine_is_dirty(entry_engine) ) continue; dirty = true; OSyncChangeType type = m_priv->osync_entry_engine_get_changetype(entry_engine); switch (type) { case OSYNC_CHANGE_TYPE_ADDED: entry.added++; break; case OSYNC_CHANGE_TYPE_MODIFIED: entry.modified++; break; case OSYNC_CHANGE_TYPE_DELETED: entry.deleted++; break; default: break; } } // Add entry to list list.push_back(entry); } } return dirty; } ///////////////////////////////////////////////////////////////////////////// // Callback functions void conflict_handler(OSyncEngine *engine, OSyncMappingEngine *mapping, void *cbdata) { CallbackBundle *cb = (CallbackBundle*) cbdata; try { // build the SyncConflict object SyncConflict40Private scp(cb->m_priv, engine, mapping); SyncConflict conflict(scp); // append all conflicting changes as vector objects in the same // order as the opensync library mapping scp.AppendChanges(conflict); // call the status handler cb->m_status->HandleConflict(conflict); } catch( std::exception &e ) { cb->m_status->ReportError( string(_C("Conflict not resolved. ")) + e.what()); } catch( ... ) { cb->m_status->ReportError( _C("Unknown exception caught in conflict_handler()")); } } void entry_status(OSyncEngineChangeUpdate *status, void *cbdata) { CallbackBundle *cb = (CallbackBundle*) cbdata; try { OSyncChange *change = cb->m_priv->osync_engine_change_update_get_change(status); OSyncMember *member = cb->m_priv->osync_engine_change_update_get_member(status); OSyncError *error = cb->m_priv->osync_engine_change_update_get_error(status); string fmt, msg; bool error_event = false; switch( cb->m_priv->osync_engine_change_update_get_event(status) ) { case OSYNC_ENGINE_CHANGE_EVENT_READ: fmt = _C("Received an entry %s (%s) from member %d (%s): %s"); msg = OSyncChangeType2String(cb->m_priv->osync_change_get_changetype(change)); break; case OSYNC_ENGINE_CHANGE_EVENT_WRITTEN: fmt = _C("Sent an entry %s (%s) to member %d (%s): %s"); msg = OSyncChangeType2String(cb->m_priv->osync_change_get_changetype(change)); break; case OSYNC_ENGINE_CHANGE_EVENT_ERROR: error_event = true; fmt = _C("Error for entry %s (%s) and member %d (%s): %s"); msg = cb->m_priv->osync_error_print_stack_wrapper(&(error)); break; } if( fmt.size() ) { string status_msg = string_vprintf(fmt.c_str(), cb->m_priv->osync_change_get_uid(change), cb->m_priv->osync_objformat_get_name( cb->m_priv->osync_change_get_objformat(change)), cb->m_priv->osync_member_get_id(member), cb->m_priv->osync_member_get_pluginname(member), msg.c_str()); // call the status handler cb->m_status->EntryStatus(status_msg, error_event); } } catch( std::exception &e ) { cb->m_status->ReportError( string(_C("entry_status error: ")) + e.what()); } catch( ... ) { cb->m_status->ReportError( _C("Unknown exception caught in entry_status()")); } } void mapping_status(OSyncEngineMappingUpdate *status, void *cbdata) { CallbackBundle *cb = (CallbackBundle*) cbdata; try { OSyncError *error = cb->m_priv->osync_engine_mapping_update_get_error(status); ostringstream oss; bool error_event = false; switch( cb->m_priv->osync_engine_mapping_update_get_event(status) ) { case OSYNC_ENGINE_MAPPING_EVENT_SOLVED: oss << _C("Mapping solved"); break; case OSYNC_ENGINE_MAPPING_EVENT_ERROR: error_event = true; oss << _C("Mapping error: ") << cb->m_priv->osync_error_print_stack_wrapper(&(error)); break; } // call the status handler if( oss.str().size() ) cb->m_status->MappingStatus(oss.str(), error_event); } catch( std::exception &e ) { cb->m_status->ReportError( string(_C("mapping_status error: ")) + e.what()); } catch( ... ) { cb->m_status->ReportError( _C("Unknown exception caught in mapping_status()")); } } void engine_status(OSyncEngineUpdate *status, void *cbdata) { CallbackBundle *cb = (CallbackBundle*) cbdata; try { OSyncError *error = cb->m_priv->osync_engine_update_get_error(status); ostringstream oss; bool error_event = false; bool slow_sync = false; switch( cb->m_priv->osync_engine_update_get_event(status) ) { case OSYNC_ENGINE_EVENT_CONNECTED: oss << _C("All clients connected or error"); break; case OSYNC_ENGINE_EVENT_CONNECT_DONE: /* Not of interest for regular user. */ break; case OSYNC_ENGINE_EVENT_READ: oss << _C("All clients sent changes or error"); break; case OSYNC_ENGINE_EVENT_MAPPED: oss << _C("All changes got mapped"); break; case OSYNC_ENGINE_EVENT_MULTIPLIED: oss << _C("All changes got multiplied"); break; case OSYNC_ENGINE_EVENT_PREPARED_WRITE: oss << _C("All changes got prepared for write"); break; case OSYNC_ENGINE_EVENT_PREPARED_MAP: /* Not of interest for regular user. */ break; case OSYNC_ENGINE_EVENT_WRITTEN: oss << _C("All clients have written"); break; case OSYNC_ENGINE_EVENT_DISCONNECTED: oss << _C("All clients have disconnected"); break; case OSYNC_ENGINE_EVENT_ERROR: error_event = true; oss << _C("The sync failed: ") << cb->m_priv->osync_error_print_stack_wrapper(&(error)); break; case OSYNC_ENGINE_EVENT_SUCCESSFUL: oss << _C("The sync was successful"); break; case OSYNC_ENGINE_EVENT_PREV_UNCLEAN: oss << _C("The previous synchronization was unclean. Slow-syncing"); slow_sync = true; break; case OSYNC_ENGINE_EVENT_END_CONFLICTS: oss << _C("All conflicts have been reported"); break; case OSYNC_ENGINE_EVENT_SYNC_DONE: oss << _C("All clients reported sync done"); break; } // call the status handler if( oss.str().size() ) cb->m_status->EngineStatus(oss.str(), error_event, slow_sync); } catch( std::exception &e ) { cb->m_status->ReportError( string(_C("engine_status error: ")) + e.what()); } catch( ... ) { cb->m_status->ReportError( _C("Unknown exception caught in engine_status()")); } } void member_status(OSyncEngineMemberUpdate *status, void *cbdata) { CallbackBundle *cb = (CallbackBundle*) cbdata; try { bool error_event = false; bool valid = true; string fmt, sinkmsg, errmsg; const char *objtype = cb->m_priv->osync_engine_member_update_get_objtype(status); if( objtype == NULL ) sinkmsg = _C("Main sink"); else sinkmsg = string_vprintf(_C("%s sink"), objtype); OSyncMember *member = cb->m_priv->osync_engine_member_update_get_member(status); OSyncError *error = cb->m_priv->osync_engine_member_update_get_error(status); switch( cb->m_priv->osync_engine_member_update_get_event(status) ) { case OSYNC_ENGINE_MEMBER_EVENT_CONNECTED: // TRANSLATORS: resulting message may look like this: // "Main sink of member 5 (barry-sync) just connected" // The "Main sink" part is based on the "Main sink" // string or the "%s sink" string. fmt = _C("%s of member %d (%s) just connected"); break; case OSYNC_ENGINE_MEMBER_EVENT_CONNECT_DONE: // Special event - but not interesting for // the normal user. break; case OSYNC_ENGINE_MEMBER_EVENT_DISCONNECTED: fmt = _C("%s of member %d (%s) just disconnected"); break; case OSYNC_ENGINE_MEMBER_EVENT_READ: fmt = _C("%s of member %d (%s) just sent all changes"); break; case OSYNC_ENGINE_MEMBER_EVENT_WRITTEN: fmt = _C("%s of member %d (%s) committed all changes"); break; case OSYNC_ENGINE_MEMBER_EVENT_SYNC_DONE: fmt = _C("%s of member %d (%s) reported sync done"); break; case OSYNC_ENGINE_MEMBER_EVENT_DISCOVERED: fmt = _C("%s of member %d (%s) discovered its objtypes"); break; case OSYNC_ENGINE_MEMBER_EVENT_ERROR: fmt = _C("%s of member %d (%s) had an error: %s"); errmsg = cb->m_priv->osync_error_print_stack_wrapper(&error); error_event = true; break; default: valid = false; break; } // construct the msg string msg = string_vprintf(fmt.c_str(), sinkmsg.c_str(), cb->m_priv->osync_member_get_id(member), cb->m_priv->osync_member_get_pluginname(member), errmsg.c_str()); // call the status handler if( msg.size() && valid ) { cb->m_status->MemberStatus( cb->m_priv->osync_member_get_id(member), cb->m_priv->osync_member_get_pluginname(member), msg, error_event); } } catch( std::exception &e ) { cb->m_status->ReportError( string(_C("member_status error: ")) + e.what()); } catch( ... ) { cb->m_status->ReportError( _C("Unknown exception caught in member_status()")); } } void multiply_summary(OSyncEngine *engine, void *cbdata) { CallbackBundle *cb = (CallbackBundle*) cbdata; try { // build the SyncSummary object SyncSummary40Private ssp(cb->m_priv, engine); SyncSummary summary(ssp); // append a summary for each objtype member if( ssp.AppendMembers(summary) ) { // call the status handler only if dirty cb->m_status->CheckSummary(summary); } else { // nothing dirty, just continue summary.Continue(); } } catch( std::exception &e ) { cb->m_status->ReportError( string(_C("Error handling summary item. ")) + e.what()); } catch( ... ) { cb->m_status->ReportError( _C("Unknown exception caught in multiply_summary()")); } } ///////////////////////////////////////////////////////////////////////////// // OS40ConfigResource - public members OS40ConfigResource::OS40ConfigResource(const OS40PluginConfig &parent, void *resource, bool existing_resource) : m_priv( new OS40ConfigResourcePrivate ) , m_exists(existing_resource) { m_priv->m_privapi = parent.m_privapi; m_priv->m_parentpriv = parent.m_priv.get(); m_priv->m_resource = (OSyncPluginResource*) resource; } OS40ConfigResource::~OS40ConfigResource() { // unref the resource, since we hold a copy m_priv->m_privapi-> osync_plugin_resource_unref(m_priv->m_resource); delete m_priv; } bool OS40ConfigResource::IsExistingResource() const { return m_exists; } // safe to call multiple times void OS40ConfigResource::AddResource() { if( !IsExistingResource() ) { m_priv->m_privapi-> osync_plugin_config_add_resource( m_priv->m_parentpriv->m_config, m_priv->m_resource); } } bool OS40ConfigResource::IsEnabled() const { return m_priv->m_privapi-> osync_plugin_resource_is_enabled(m_priv->m_resource); } OS40ConfigResource& OS40ConfigResource::Enable(bool enabled) { m_priv->m_privapi->osync_plugin_resource_enable(m_priv->m_resource, enabled); return *this; } bool OS40ConfigResource::FindObjFormat(const std::string &objformat, std::string &config) { SyncListHandle sinks(m_priv->m_privapi->osync_list_free); sinks = m_priv->m_privapi-> osync_plugin_resource_get_objformat_sinks(m_priv->m_resource); for( OSyncList *o = sinks.get(); o; o = o->next ) { OSyncObjFormatSink *sink = (OSyncObjFormatSink*) o->data; if( objformat == m_priv->m_privapi->osync_objformat_sink_get_objformat(sink) ) { const char *cfg = m_priv->m_privapi->osync_objformat_sink_get_config(sink); if( cfg ) config = cfg; else config.clear(); return true; } } return false; } OS40ConfigResource& OS40ConfigResource::SetObjFormat(const std::string &objformat, const std::string &config) { // if it already exists, just set the config value SyncListHandle sinks(m_priv->m_privapi->osync_list_free); sinks = m_priv->m_privapi-> osync_plugin_resource_get_objformat_sinks(m_priv->m_resource); for( OSyncList *o = sinks.get(); o; o = o->next ) { OSyncObjFormatSink *sink = (OSyncObjFormatSink*) o->data; if( objformat == m_priv->m_privapi->osync_objformat_sink_get_objformat(sink) ) { m_priv->m_privapi->osync_objformat_sink_set_config(sink, config.c_str()); return *this; } } // if we get here, it doesn't exist, and we need to add it OSyncObjFormatSink *sink = m_priv->m_privapi-> osync_objformat_sink_new(objformat.c_str(), m_priv->m_privapi->error); if( !sink ) throw std::runtime_error(m_priv->m_privapi->error.GetErrorMsg()); if( config.size() ) m_priv->m_privapi->osync_objformat_sink_set_config(sink, config.c_str()); m_priv->m_privapi->osync_plugin_resource_add_objformat_sink( m_priv->m_resource, sink); m_priv->m_privapi->osync_objformat_sink_unref(sink); return *this; } std::string OS40ConfigResource::GetName() const { string value; const char *pv = m_priv->m_privapi-> osync_plugin_resource_get_name(m_priv->m_resource); if( pv ) value = pv; return value; } OS40ConfigResource& OS40ConfigResource::SetName(const std::string &name) { m_priv->m_privapi-> osync_plugin_resource_set_name(m_priv->m_resource, name.c_str()); return *this; } std::string OS40ConfigResource::GetPreferredFormat() const { string value; const char *pv = m_priv->m_privapi-> osync_plugin_resource_get_preferred_format(m_priv->m_resource); if( pv ) value = pv; return value; } OS40ConfigResource& OS40ConfigResource::SetPreferredFormat(const std::string &format) { m_priv->m_privapi-> osync_plugin_resource_set_preferred_format(m_priv->m_resource, format.c_str()); return *this; } std::string OS40ConfigResource::GetMime() const { string value; const char *pv = m_priv->m_privapi->osync_plugin_resource_get_mime( m_priv->m_resource); if( pv ) value = pv; return value; } OS40ConfigResource& OS40ConfigResource::SetMime(const std::string &mime) { m_priv->m_privapi->osync_plugin_resource_set_mime(m_priv->m_resource, mime.c_str()); return *this; } std::string OS40ConfigResource::GetObjType() const { string value; const char *pv = m_priv->m_privapi->osync_plugin_resource_get_objtype( m_priv->m_resource); if( pv ) value = pv; return value; } OS40ConfigResource& OS40ConfigResource::SetObjType(const std::string &objtype) { m_priv->m_privapi->osync_plugin_resource_set_objtype(m_priv->m_resource, objtype.c_str()); return *this; } std::string OS40ConfigResource::GetPath() const { string value; const char *pv = m_priv->m_privapi->osync_plugin_resource_get_path( m_priv->m_resource); if( pv ) value = pv; return value; } OS40ConfigResource& OS40ConfigResource::SetPath(const std::string &path) { m_priv->m_privapi->osync_plugin_resource_set_path(m_priv->m_resource, path.c_str()); return *this; } std::string OS40ConfigResource::GetUrl() const { string value; const char *pv = m_priv->m_privapi->osync_plugin_resource_get_url( m_priv->m_resource); if( pv ) value = pv; return value; } OS40ConfigResource& OS40ConfigResource::SetUrl(const std::string &url) { m_priv->m_privapi->osync_plugin_resource_set_url(m_priv->m_resource, url.c_str()); return *this; } ///////////////////////////////////////////////////////////////////////////// // OS40PluginConfig - public members OS40PluginConfig::OS40PluginConfig(OpenSync40Private *privapi, void *member, void *config) : m_privapi(privapi) { m_priv.reset( new OS40PluginConfigPrivate ); m_priv->m_member = (OSyncMember*) member; m_priv->m_config = (OSyncPluginConfig*) config; } std::string OS40PluginConfig::GetAdvanced(const std::string &name) { const char *value = m_privapi->osync_plugin_config_get_advancedoption_value_by_name(m_priv->m_config, name.c_str()); string val; if( value ) val = value; return val; } void OS40PluginConfig::SetAdvanced(const std::string &name, const std::string &display_name, const std::string &val) { SetAdvanced(name, display_name, STRING_TYPE, val); } void OS40PluginConfig::SetAdvanced(const std::string &name, const std::string &display_name, int val_type, const std::string &val) { // find the first advanced option with this name SyncListHandle aos(m_privapi->osync_list_free); aos = m_privapi->osync_plugin_config_get_advancedoptions(m_priv->m_config); OSyncPluginAdvancedOption *option = 0; for( OSyncList *o = aos.get(); o; o = o->next ) { option = (OSyncPluginAdvancedOption*) o->data; if( name == m_privapi->osync_plugin_advancedoption_get_name(option) ) break; } if( option ) { // found existing option, set it with val m_privapi->osync_plugin_advancedoption_set_value(option, val.c_str()); } else { // option with that name does not exist, so create it option = m_privapi->osync_plugin_advancedoption_new(m_privapi->error); if( !option ) throw std::runtime_error(m_privapi->error.GetErrorMsg()); m_privapi->osync_plugin_advancedoption_set_name(option, name.c_str()); m_privapi->osync_plugin_advancedoption_set_displayname(option, display_name.c_str()); OSyncPluginAdvancedOptionType type; switch( val_type ) { case NONE_TYPE: type = OSYNC_PLUGIN_ADVANCEDOPTION_TYPE_NONE; break; case BOOL_TYPE: type = OSYNC_PLUGIN_ADVANCEDOPTION_TYPE_BOOL; break; case CHAR_TYPE: type = OSYNC_PLUGIN_ADVANCEDOPTION_TYPE_CHAR; break; case DOUBLE_TYPE: type = OSYNC_PLUGIN_ADVANCEDOPTION_TYPE_DOUBLE; break; case INT_TYPE: type = OSYNC_PLUGIN_ADVANCEDOPTION_TYPE_INT; break; case LONG_TYPE: type = OSYNC_PLUGIN_ADVANCEDOPTION_TYPE_LONG; break; case LONGLONG_TYPE: type = OSYNC_PLUGIN_ADVANCEDOPTION_TYPE_LONGLONG; break; case UINT_TYPE: type = OSYNC_PLUGIN_ADVANCEDOPTION_TYPE_UINT; break; case ULONG_TYPE: type = OSYNC_PLUGIN_ADVANCEDOPTION_TYPE_ULONG; break; case ULONGLONG_TYPE: type = OSYNC_PLUGIN_ADVANCEDOPTION_TYPE_ULONGLONG; break; case STRING_TYPE: type = OSYNC_PLUGIN_ADVANCEDOPTION_TYPE_STRING; break; default: throw std::logic_error("Bad type in SetAdvanced()"); } m_privapi->osync_plugin_advancedoption_set_type(option, type); m_privapi->osync_plugin_advancedoption_set_value(option, val.c_str()); m_privapi->osync_plugin_config_add_advancedoption(m_priv->m_config, option); m_privapi->osync_plugin_advancedoption_unref(option); } } OS40PluginConfig::OS40ConfigResourcePtr OS40PluginConfig::GetResource(const std::string &objtype) { OS40ConfigResourcePtr ptr; // FIXME - get_resources() does not give us a copy, so don't use // the SyncListHandle here OSyncList *rs = m_privapi->osync_plugin_config_get_resources(m_priv->m_config); for( OSyncList *o = rs; o; o = o->next ) { OSyncPluginResource *res = (OSyncPluginResource*) o->data; if( objtype == m_privapi->osync_plugin_resource_get_objtype(res) ) { // bump the resource count, since OS40ConfigResource // will unref it in the destructor m_privapi->osync_plugin_resource_ref(res); ptr.reset( new OS40ConfigResource(*this, res, true) ); return ptr; } } // this res has a ref bump already, no ref() needed like it is above OSyncPluginResource *res = m_privapi->osync_plugin_resource_new(m_privapi->error); if( !res ) throw std::runtime_error(m_privapi->error.GetErrorMsg()); ptr.reset( new OS40ConfigResource(*this, res, false) ); // we search by objtype name, so make sure this is set in // the new object ptr->SetObjType(objtype); return ptr; } std::string OS40PluginConfig::GetUsername() const { string username; OSyncPluginAuthentication *auth = m_privapi->osync_plugin_config_get_authentication(m_priv->m_config); if( !auth ) return username; const char *un = m_privapi->osync_plugin_authentication_get_username(auth); if( !un ) return username; username = un; return username; } void OS40PluginConfig::SetUsername(const std::string &username) { OSyncPluginAuthentication *auth = m_privapi->osync_plugin_config_get_authentication(m_priv->m_config); if( !auth ) { auth = m_privapi->osync_plugin_authentication_new(m_privapi->error); if( !auth ) throw std::runtime_error(m_privapi->error.GetErrorMsg()); if( !m_privapi->osync_plugin_authentication_option_is_supported(auth, OSYNC_PLUGIN_AUTHENTICATION_USERNAME) ) { m_privapi->osync_plugin_authentication_unref(auth); throw std::runtime_error(_C("Username (authentication parameter) is not supported in plugin!")); } // all looks ok, add it to the config m_privapi->osync_plugin_config_set_authentication(m_priv->m_config, auth); // unref our copy, since the config now has it... // our auth pointer will still be valid since config holds it m_privapi->osync_plugin_authentication_unref(auth); } m_privapi->osync_plugin_authentication_set_username(auth, username.c_str()); } std::string OS40PluginConfig::GetPassword() const { string password; OSyncPluginAuthentication *auth = m_privapi->osync_plugin_config_get_authentication(m_priv->m_config); if( !auth ) return password; const char *pass = m_privapi->osync_plugin_authentication_get_password(auth); if( !pass ) return password; password = pass; return password; } void OS40PluginConfig::SetPassword(const std::string &password) { OSyncPluginAuthentication *auth = m_privapi->osync_plugin_config_get_authentication(m_priv->m_config); if( !auth ) { auth = m_privapi->osync_plugin_authentication_new(m_privapi->error); if( !auth ) throw std::runtime_error(m_privapi->error.GetErrorMsg()); if( !m_privapi->osync_plugin_authentication_option_is_supported(auth, OSYNC_PLUGIN_AUTHENTICATION_PASSWORD) ) { m_privapi->osync_plugin_authentication_unref(auth); throw std::runtime_error(_C("Password authentication is not supported in plugin!")); } // all looks ok, add it to the config m_privapi->osync_plugin_config_set_authentication(m_priv->m_config, auth); // unref our copy, since the config now has it... // our auth pointer will still be valid since config holds it m_privapi->osync_plugin_authentication_unref(auth); } m_privapi->osync_plugin_authentication_set_password(auth, password.c_str()); } void OS40PluginConfig::Save() { if( !m_privapi->osync_member_save(m_priv->m_member, m_privapi->error) ) throw std::runtime_error(m_privapi->error.GetErrorMsg()); } ///////////////////////////////////////////////////////////////////////////// // OpenSync40 (API override class) - public members OpenSync40::OpenSync40() { // due to bugs in the way opensync 0.22 loads its modules, // (i.e. it doesn't load the plugins using RTLD_LOCAL, and // so libopensync.so.0 is loaded and pollutes the symbol table, // causing symbol clashes) we need to make sure that // OpenSync40 is only loaded first... if OpenSync22 was // loaded first, we will fail, so error out if( OpenSync22::SymbolsLoaded() ) throw std::logic_error("Always load OpenSync40 before OpenSync22, to avoid symbol table conflicts."); if( !Open("libopensync.so.1") ) throw DlError("Can't dlopen libopensync.so.1"); // store locally in case of constructor exception in LoadSym std::auto_ptr p(new OpenSync40Private(*this)); // load all required symbols... // we don't need to use try/catch here, since the base // class destructor will clean up for us if LoadSym() throws LoadSym(p->osync_get_version, "osync_get_version"); LoadSym(p->osync_error_print, "osync_error_print"); LoadSym(p->osync_error_print_stack, "osync_error_print_stack"); LoadSym(p->osync_error_is_set, "osync_error_is_set"); LoadSym(p->osync_error_unref, "osync_error_unref"); LoadSym(p->osync_group_env_new, "osync_group_env_new"); LoadSym(p->osync_format_env_new, "osync_format_env_new"); LoadSym(p->osync_plugin_env_new, "osync_plugin_env_new"); LoadSym(p->osync_group_env_unref, "osync_group_env_unref"); LoadSym(p->osync_format_env_unref, "osync_format_env_unref"); LoadSym(p->osync_plugin_env_unref, "osync_plugin_env_unref"); LoadSym(p->osync_plugin_env_load, "osync_plugin_env_load"); LoadSym(p->osync_plugin_env_get_plugins,"osync_plugin_env_get_plugins"); LoadSym(p->osync_plugin_get_name, "osync_plugin_get_name"); LoadSym(p->osync_list_free, "osync_list_free"); LoadSym(p->osync_group_env_load_groups, "osync_group_env_load_groups"); LoadSym(p->osync_format_env_load_plugins, "osync_format_env_load_plugins"); LoadSym(p->osync_group_env_get_groups, "osync_group_env_get_groups"); LoadSym(p->osync_group_get_name, "osync_group_get_name"); LoadSym(p->osync_group_env_find_group, "osync_group_env_find_group"); LoadSym(p->osync_group_get_members, "osync_group_get_members"); LoadSym(p->osync_member_get_name, "osync_member_get_name"); LoadSym(p->osync_member_get_id, "osync_member_get_id"); LoadSym(p->osync_member_get_pluginname, "osync_member_get_pluginname"); LoadSym(p->osync_format_env_get_objformats, "osync_format_env_get_objformats"); LoadSym(p->osync_objformat_get_name, "osync_objformat_get_name"); LoadSym(p->osync_objformat_get_objtype, "osync_objformat_get_objtype"); LoadSym(p->osync_group_new, "osync_group_new"); LoadSym(p->osync_group_unref, "osync_group_unref"); LoadSym(p->osync_group_set_name, "osync_group_set_name"); LoadSym(p->osync_group_env_add_group, "osync_group_env_add_group"); LoadSym(p->osync_group_save, "osync_group_save"); LoadSym(p->osync_group_delete, "osync_group_delete"); LoadSym(p->osync_group_env_remove_group,"osync_group_env_remove_group"); LoadSym(p->osync_plugin_env_find_plugin,"osync_plugin_env_find_plugin"); LoadSym(p->osync_member_unref, "osync_member_unref"); LoadSym(p->osync_member_new, "osync_member_new"); LoadSym(p->osync_group_add_member, "osync_group_add_member"); LoadSym(p->osync_member_set_pluginname, "osync_member_set_pluginname"); LoadSym(p->osync_member_set_name, "osync_member_set_name"); LoadSym(p->osync_member_save, "osync_member_save"); LoadSym(p->osync_group_find_member, "osync_group_find_member"); LoadSym(p->osync_member_delete, "osync_member_delete"); LoadSym(p->osync_group_remove_member, "osync_group_remove_member"); LoadSym(p->osync_plugin_config_new, "osync_plugin_config_new"); LoadSym(p->osync_plugin_config_file_load, "osync_plugin_config_file_load"); LoadSym(p->osync_member_set_config, "osync_member_set_config"); LoadSym(p->osync_member_get_config_or_default, "osync_member_get_config_or_default"); LoadSym(p->osync_plugin_config_file_save, "osync_plugin_config_file_save"); LoadSym(p->osync_plugin_get_config_type,"osync_plugin_get_config_type"); LoadSym(p->osync_engine_new, "osync_engine_new"); LoadSym(p->osync_engine_unref, "osync_engine_unref"); LoadSym(p->osync_engine_discover_and_block, "osync_engine_discover_and_block"); LoadSym(p->osync_member_get_objtypes, "osync_member_get_objtypes"); LoadSym(p->osync_list_length, "osync_list_length"); LoadSym(p->osync_error_set, "osync_error_set"); LoadSym(p->osync_engine_finalize, "osync_engine_finalize"); LoadSym(p->osync_mapping_engine_get_changes, "osync_mapping_engine_get_changes"); LoadSym(p->osync_mapping_engine_supports_ignore, "osync_mapping_engine_supports_ignore"); LoadSym(p->osync_mapping_engine_supports_use_latest, "osync_mapping_engine_supports_use_latest"); LoadSym(p->osync_list_nth, "osync_list_nth"); LoadSym(p->osync_engine_mapping_solve, "osync_engine_mapping_solve"); LoadSym(p->osync_engine_abort, "osync_engine_abort"); LoadSym(p->osync_engine_mapping_duplicate, "osync_engine_mapping_duplicate"); LoadSym(p->osync_engine_mapping_ignore_conflict, "osync_engine_mapping_ignore_conflict"); LoadSym(p->osync_engine_mapping_use_latest, "osync_engine_mapping_use_latest"); LoadSym(p->osync_change_get_changetype, "osync_change_get_changetype"); LoadSym(p->osync_mapping_engine_change_find_member, "osync_mapping_engine_change_find_member"); LoadSym(p->osync_change_get_data, "osync_change_get_data"); LoadSym(p->osync_data_get_printable, "osync_data_get_printable"); LoadSym(p->osync_free, "osync_free"); LoadSym(p->osync_change_get_uid, "osync_change_get_uid"); LoadSym(p->osync_engine_continue, "osync_engine_continue"); LoadSym(p->osync_engine_get_objengines, "osync_engine_get_objengines"); LoadSym(p->osync_obj_engine_get_members, "osync_obj_engine_get_members"); LoadSym(p->osync_obj_engine_get_objtype, "osync_obj_engine_get_objtype"); LoadSym(p->osync_obj_engine_get_mapping_entry_engines_of_member, "osync_obj_engine_get_mapping_entry_engines_of_member"); LoadSym(p->osync_entry_engine_is_dirty,"osync_entry_engine_is_dirty"); LoadSym(p->osync_entry_engine_get_changetype, "osync_entry_engine_get_changetype"); LoadSym(p->osync_engine_change_update_get_change, "osync_engine_change_update_get_change"); LoadSym(p->osync_engine_change_update_get_member, "osync_engine_change_update_get_member"); LoadSym(p->osync_engine_change_update_get_error, "osync_engine_change_update_get_error"); LoadSym(p->osync_engine_change_update_get_event, "osync_engine_change_update_get_event"); LoadSym(p->osync_change_get_objformat, "osync_change_get_objformat"); LoadSym(p->osync_engine_mapping_update_get_error, "osync_engine_mapping_update_get_error"); LoadSym(p->osync_engine_update_get_error, "osync_engine_update_get_error"); LoadSym(p->osync_engine_update_get_event, "osync_engine_update_get_event"); LoadSym(p->osync_engine_member_update_get_objtype, "osync_engine_member_update_get_objtype"); LoadSym(p->osync_engine_member_update_get_member, "osync_engine_member_update_get_member"); LoadSym(p->osync_engine_member_update_get_error, "osync_engine_member_update_get_error"); LoadSym(p->osync_engine_member_update_get_event, "osync_engine_member_update_get_event"); LoadSym(p->osync_engine_set_conflict_callback, "osync_engine_set_conflict_callback"); LoadSym(p->osync_engine_set_changestatus_callback, "osync_engine_set_changestatus_callback"); LoadSym(p->osync_engine_set_mappingstatus_callback, "osync_engine_set_mappingstatus_callback"); LoadSym(p->osync_engine_set_enginestatus_callback, "osync_engine_set_enginestatus_callback"); LoadSym(p->osync_engine_set_memberstatus_callback, "osync_engine_set_memberstatus_callback"); LoadSym(p->osync_engine_set_multiply_callback, "osync_engine_set_multiply_callback"); LoadSym(p->osync_engine_initialize, "osync_engine_initialize"); LoadSym(p->osync_engine_synchronize_and_block, "osync_engine_synchronize_and_block"); LoadSym(p->osync_engine_mapping_update_get_event, "osync_engine_mapping_update_get_event"); LoadSym(p->osync_plugin_resource_unref, "osync_plugin_resource_unref"); LoadSym(p->osync_plugin_config_add_resource, "osync_plugin_config_add_resource"); LoadSym(p->osync_plugin_resource_is_enabled, "osync_plugin_resource_is_enabled"); LoadSym(p->osync_plugin_resource_enable, "osync_plugin_resource_enable"); LoadSym(p->osync_plugin_resource_get_objformat_sinks, "osync_plugin_resource_get_objformat_sinks"); LoadSym(p->osync_objformat_sink_get_objformat, "osync_objformat_sink_get_objformat"); LoadSym(p->osync_objformat_sink_get_config, "osync_objformat_sink_get_config"); LoadSym(p->osync_objformat_sink_set_config, "osync_objformat_sink_set_config"); LoadSym(p->osync_objformat_sink_new, "osync_objformat_sink_new"); LoadSym(p->osync_plugin_resource_add_objformat_sink, "osync_plugin_resource_add_objformat_sink"); LoadSym(p->osync_objformat_sink_unref, "osync_objformat_sink_unref"); LoadSym(p->osync_plugin_resource_get_preferred_format, "osync_plugin_resource_get_preferred_format"); LoadSym(p->osync_plugin_resource_set_preferred_format, "osync_plugin_resource_set_preferred_format"); LoadSym(p->osync_plugin_resource_get_mime, "osync_plugin_resource_get_mime"); LoadSym(p->osync_plugin_resource_set_mime, "osync_plugin_resource_set_mime"); LoadSym(p->osync_plugin_resource_get_objtype, "osync_plugin_resource_get_objtype"); LoadSym(p->osync_plugin_resource_set_objtype, "osync_plugin_resource_set_objtype"); LoadSym(p->osync_plugin_resource_get_path, "osync_plugin_resource_get_path"); LoadSym(p->osync_plugin_resource_set_path, "osync_plugin_resource_set_path"); LoadSym(p->osync_plugin_resource_get_url, "osync_plugin_resource_get_url"); LoadSym(p->osync_plugin_resource_set_url, "osync_plugin_resource_set_url"); LoadSym(p->osync_plugin_config_get_advancedoption_value_by_name, "osync_plugin_config_get_advancedoption_value_by_name"); LoadSym(p->osync_plugin_config_get_advancedoptions, "osync_plugin_config_get_advancedoptions"); LoadSym(p->osync_plugin_config_add_advancedoption, "osync_plugin_config_add_advancedoption"); LoadSym(p->osync_plugin_advancedoption_new, "osync_plugin_advancedoption_new"); LoadSym(p->osync_plugin_advancedoption_unref, "osync_plugin_advancedoption_unref"); LoadSym(p->osync_plugin_advancedoption_get_name, "osync_plugin_advancedoption_get_name"); LoadSym(p->osync_plugin_advancedoption_set_name, "osync_plugin_advancedoption_set_name"); LoadSym(p->osync_plugin_advancedoption_set_displayname, "osync_plugin_advancedoption_set_displayname"); LoadSym(p->osync_plugin_advancedoption_set_type, "osync_plugin_advancedoption_set_type"); LoadSym(p->osync_plugin_advancedoption_set_value, "osync_plugin_advancedoption_set_value"); LoadSym(p->osync_plugin_config_get_resources, "osync_plugin_config_get_resources"); LoadSym(p->osync_plugin_resource_ref, "osync_plugin_resource_ref"); LoadSym(p->osync_plugin_resource_new, "osync_plugin_resource_new"); LoadSym(p->osync_plugin_resource_get_name, "osync_plugin_resource_get_name"); LoadSym(p->osync_plugin_resource_set_name, "osync_plugin_resource_set_name"); LoadSym(p->osync_plugin_config_get_authentication, "osync_plugin_config_get_authentication"); LoadSym(p->osync_plugin_authentication_get_password, "osync_plugin_authentication_get_password"); LoadSym(p->osync_plugin_authentication_new, "osync_plugin_authentication_new"); LoadSym(p->osync_plugin_authentication_option_is_supported, "osync_plugin_authentication_option_is_supported"); LoadSym(p->osync_plugin_authentication_unref, "osync_plugin_authentication_unref"); LoadSym(p->osync_plugin_config_set_authentication, "osync_plugin_config_set_authentication"); LoadSym(p->osync_plugin_authentication_set_password, "osync_plugin_authentication_set_password"); LoadSym(p->osync_plugin_authentication_get_username, "osync_plugin_authentication_get_username"); LoadSym(p->osync_plugin_authentication_set_username, "osync_plugin_authentication_set_username"); LoadSym(p->osync_group_set_objtype_enabled, "osync_group_set_objtype_enabled"); // fixup free pointers p->group_env.SetFreeFunc(p->osync_group_env_unref); p->format_env.SetFreeFunc(p->osync_format_env_unref); p->plugin_env.SetFreeFunc(p->osync_plugin_env_unref); // setup opensync support environment SetupEnvironment(p.get()); // this pointer is ours now m_priv = p.release(); } OpenSync40::~OpenSync40() { delete m_priv; m_priv = 0; } void OpenSync40::SetupEnvironment(OpenSync40Private *p) { // allocate group, format, and env p->group_env = p->osync_group_env_new(p->error); if( !p->group_env.get() ) throw std::runtime_error(p->error.GetErrorMsg()); p->format_env = p->osync_format_env_new(p->error); if( !p->format_env.get() ) throw std::runtime_error(p->error.GetErrorMsg()); p->plugin_env = p->osync_plugin_env_new(p->error); if( !p->plugin_env.get() ) throw std::runtime_error(p->error.GetErrorMsg()); // load group, format, and env if( !p->osync_group_env_load_groups(p->group_env.get(), NULL, p->error) || !p->osync_format_env_load_plugins(p->format_env.get(), NULL, p->error) || !p->osync_plugin_env_load(p->plugin_env.get(), NULL, p->error) ) throw std::runtime_error(p->error.GetErrorMsg()); } const char* OpenSync40::GetVersion() const { return m_priv->osync_get_version(); } const char* OpenSync40::GetEngineName() const { return "0.40"; } void OpenSync40::GetPluginNames(string_list_type &plugins) { // start fresh plugins.clear(); OSyncPlugin *plugin; OSyncList *plugin_list, *p; plugin_list = m_priv->osync_plugin_env_get_plugins(m_priv->plugin_env.get()); for( p = plugin_list; p; p = p->next ) { plugin = (OSyncPlugin *) p->data; plugins.push_back(m_priv->osync_plugin_get_name(plugin)); } m_priv->osync_list_free(plugin_list); } void OpenSync40::GetFormats(format_list_type &formats) { // start fresh formats.clear(); OSyncList *o, *list = m_priv->osync_format_env_get_objformats(m_priv->format_env.get()); for( o = list; o; o = o->next ) { OSyncObjFormat *format = (OSyncObjFormat *) o->data; Format new_format; new_format.name = m_priv->osync_objformat_get_name(format); new_format.object_type = m_priv->osync_objformat_get_objtype(format); formats.push_back(new_format); } m_priv->osync_list_free(list); } void OpenSync40::GetGroupNames(string_list_type &groups) { // start fresh groups.clear(); OSyncGroup *group; OSyncList *g, *group_list = m_priv->osync_group_env_get_groups(m_priv->group_env.get()); for( g = group_list; g; g = g->next ) { group = (OSyncGroup *) g->data; groups.push_back(m_priv->osync_group_get_name(group)); } m_priv->osync_list_free(group_list); } void OpenSync40::GetMembers(const std::string &group_name, member_list_type &members) { // start fresh members.clear(); OSyncGroup *group = m_priv->osync_group_env_find_group(m_priv->group_env.get(), group_name.c_str()); if( !group ) { ostringstream oss; oss << "GetMembers(): " << _C("Unable to find group with name: ") << group_name; throw std::runtime_error(oss.str()); } OSyncList *member_list = m_priv->osync_group_get_members(group); for( OSyncList *m = member_list; m; m = m->next ) { Member new_member; OSyncMember *member = (OSyncMember *) m->data; const char *membername = m_priv->osync_member_get_name(member); if (membername) { new_member.friendly_name = membername; } new_member.group_name = group_name; new_member.id = m_priv->osync_member_get_id(member); new_member.plugin_name = m_priv->osync_member_get_pluginname(member); // add to member list members.push_back(new_member); } // cleanup m_priv->osync_list_free(member_list); } void OpenSync40::AddGroup(const std::string &group_name) { OSyncGroup *group = m_priv->osync_group_new(m_priv->error); if( !group ) throw std::runtime_error("AddGroup(): " + m_priv->error.GetErrorMsg()); m_priv->osync_group_set_name(group, group_name.c_str()); if( !m_priv->osync_group_env_add_group(m_priv->group_env.get(), group, m_priv->error) ) { m_priv->osync_group_unref(group); throw std::runtime_error("AddGroup(): " + m_priv->error.GetErrorMsg()); } if( !m_priv->osync_group_save(group, m_priv->error) ) { m_priv->osync_group_unref(group); throw std::runtime_error("AddGroup(): " + m_priv->error.GetErrorMsg()); } m_priv->osync_group_unref(group); } void OpenSync40::DeleteGroup(const std::string &group_name) { OSyncGroup *group = m_priv->osync_group_env_find_group(m_priv->group_env.get(), group_name.c_str()); if( !group ) throw std::runtime_error(string("DeleteGroup(): ") + _C("Group not found: ") + group_name); if( !m_priv->osync_group_delete(group, m_priv->error) ) throw std::runtime_error("DeleteGroup(): " + m_priv->error.GetErrorMsg()); m_priv->osync_group_env_remove_group(m_priv->group_env.get(), group); } Converter& OpenSync40::GetConverter() { return m_priv->converter; } long OpenSync40::AddMember(const std::string &group_name, const std::string &plugin_name, const std::string &member_name) { OSyncGroup *group = m_priv->osync_group_env_find_group(m_priv->group_env.get(), group_name.c_str()); if( !group ) throw std::runtime_error(string("AddMember(): ") + _C("Group not found: ") + group_name); OSyncPlugin *plugin = m_priv->osync_plugin_env_find_plugin(m_priv->plugin_env.get(), plugin_name.c_str()); if( !plugin ) throw std::runtime_error(string("AddMember(): ") + _C("Plugin not found: ") + plugin_name); vLateSmartPtr mptr(m_priv->osync_member_unref); mptr = m_priv->osync_member_new(m_priv->error); if( !mptr.get() ) throw std::runtime_error("AddMember(): " + m_priv->error.GetErrorMsg()); m_priv->osync_group_add_member(group, mptr.get()); m_priv->osync_member_set_pluginname(mptr.get(), plugin_name.c_str()); if( member_name.size() ) m_priv->osync_member_set_name(mptr.get(), member_name.c_str()); if( !m_priv->osync_member_save(mptr.get(), m_priv->error) ) throw std::runtime_error("AddMember(): " + m_priv->error.GetErrorMsg()); return m_priv->osync_member_get_id(mptr.get()); } void OpenSync40::DeleteMember(const std::string &group_name, long member_id) { OSyncGroup *group = m_priv->osync_group_env_find_group(m_priv->group_env.get(), group_name.c_str()); if( !group ) throw std::runtime_error(string("DeleteMember(): ") + _C("Group not found: ") + group_name); OSyncMember *member = m_priv->osync_group_find_member(group, member_id); if( !member ) { ostringstream oss; oss << "DeleteMember(): " << _C("Member not found: ") << member_id; throw std::runtime_error(oss.str()); } if( !m_priv->osync_member_delete(member, m_priv->error) ) throw std::runtime_error("DeleteMember(): " + m_priv->error.GetErrorMsg()); m_priv->osync_group_remove_member(group, member); } void OpenSync40::DeleteMember(const std::string &group_name, const std::string &plugin_name) { member_list_type mlist; GetMembers(group_name, mlist); Member *member = mlist.Find(plugin_name.c_str()); if( !member ) throw std::runtime_error(string("DeleteMember(): ") + _C("Member not found: ") + plugin_name); DeleteMember(group_name, member->id); } bool OpenSync40::IsConfigurable(const std::string &group_name, long member_id) { OSyncGroup *group = m_priv->osync_group_env_find_group(m_priv->group_env.get(), group_name.c_str()); if( !group ) throw std::runtime_error(string("IsConfigurable(): ") + _C("Group not found: ") + group_name); OSyncMember *member = m_priv->osync_group_find_member(group, member_id); if( !member ) { ostringstream oss; oss << "IsConfigurable(): " << _C("Member not found: ") << member_id; throw std::runtime_error(oss.str()); } OSyncPlugin *plugin = m_priv->osync_plugin_env_find_plugin(m_priv->plugin_env.get(), m_priv->osync_member_get_pluginname(member)); if( !plugin ) throw std::runtime_error(string("IsConfigurable(): ") + _C("Unable to find plugin with name: ") + m_priv->osync_member_get_pluginname(member)); OSyncPluginConfigurationType type = m_priv->osync_plugin_get_config_type(plugin); return type != OSYNC_PLUGIN_NO_CONFIGURATION; } std::string OpenSync40::GetConfiguration(const std::string &group_name, long member_id) { if( !IsConfigurable(group_name, member_id) ) { throw std::runtime_error(string("GetConfiguration(): ") + string_vprintf(_C("Member %ld of group '%s' does not accept configuration."), member_id, group_name.c_str())); } OSyncGroup *group = m_priv->osync_group_env_find_group(m_priv->group_env.get(), group_name.c_str()); if( !group ) throw std::runtime_error(string("GetConfiguration(): ") + _C("Group not found: ") + group_name); OSyncMember *member = m_priv->osync_group_find_member(group, member_id); if( !member ) { ostringstream oss; oss << "GetConfiguration(): " << _C("Member not found: ") << member_id; throw std::runtime_error(oss.str()); } OSyncPlugin *plugin = m_priv->osync_plugin_env_find_plugin(m_priv->plugin_env.get(), m_priv->osync_member_get_pluginname(member)); if( !plugin ) throw std::runtime_error(string("GetConfiguration(): ") + _C("Unable to find plugin with name: ") + m_priv->osync_member_get_pluginname(member)); OSyncPluginConfig *config = m_priv->osync_member_get_config_or_default(member, m_priv->error); if( !config ) throw std::runtime_error("GetConfiguration(): " + m_priv->error.GetErrorMsg()); // To emulate 0.22 behaviour, we need to use 0.4x save-to-file // functions, and then load that from the file again, and // return that string as the configuratin. TempDir tempdir("opensyncapi"); string filename = tempdir.GetNewFilename(); if( !m_priv->osync_plugin_config_file_save(config, filename.c_str(), m_priv->error) ) throw std::runtime_error("GetConfiguration(): " + m_priv->error.GetErrorMsg()); ifstream in(filename.c_str()); string config_data; char buf[4096]; while( in ) { in.read(buf, sizeof(buf)); config_data.append(buf, in.gcount()); } return config_data; } OS40PluginConfig OpenSync40::GetConfigurationObj(const std::string &group_name, long member_id) { if( !IsConfigurable(group_name, member_id) ) { throw std::runtime_error(string("GetConfigurationObj(): ") + string_vprintf(_C("Member %ld of group '%s' does not accept configuration."), member_id, group_name.c_str())); } OSyncGroup *group = m_priv->osync_group_env_find_group(m_priv->group_env.get(), group_name.c_str()); if( !group ) throw std::runtime_error(string("GetConfigurationObj(): ") + _C("Group not found: ") + group_name); OSyncMember *member = m_priv->osync_group_find_member(group, member_id); if( !member ) { ostringstream oss; oss << "GetConfigurationObj(): " << _C("Member not found: ") << member_id; throw std::runtime_error(oss.str()); } OSyncPlugin *plugin = m_priv->osync_plugin_env_find_plugin(m_priv->plugin_env.get(), m_priv->osync_member_get_pluginname(member)); if( !plugin ) throw std::runtime_error(string("GetConfigurationObj(): ") + _C("Unable to find plugin with name: ") + m_priv->osync_member_get_pluginname(member)); OSyncPluginConfig *config = m_priv->osync_member_get_config_or_default(member, m_priv->error); if( !config ) throw std::runtime_error("GetConfigurationObj(): " + m_priv->error.GetErrorMsg()); return OS40PluginConfig(m_priv, member, config); } void OpenSync40::SetConfiguration(const std::string &group_name, long member_id, const std::string &config_data) { if( !IsConfigurable(group_name, member_id) ) { throw std::runtime_error(string("SetConfiguration(): ") + string_vprintf(_C("Member %ld of group '%s' does not accept configuration."), member_id, group_name.c_str())); } OSyncGroup *group = m_priv->osync_group_env_find_group(m_priv->group_env.get(), group_name.c_str()); if( !group ) throw std::runtime_error(string("SetConfiguration(): ") + _C("Group not found: ") + group_name); OSyncMember *member = m_priv->osync_group_find_member(group, member_id); if( !member ) { ostringstream oss; oss << "SetConfiguration(): " << _C("Member not found: ") << member_id; throw std::runtime_error(oss.str()); } OSyncPlugin *plugin = m_priv->osync_plugin_env_find_plugin(m_priv->plugin_env.get(), m_priv->osync_member_get_pluginname(member)); if( !plugin ) throw std::runtime_error(string("SetConfiguration(): ") + _C("Unable to find plugin with name: ") + m_priv->osync_member_get_pluginname(member)); // To emulate 0.22 behaviour, we need to use 0.4x save-to-file // functions, and then load that from the file again, and // return that string as the configuratin. TempDir tempdir("opensyncapi"); string filename = tempdir.GetNewFilename(); // write config data to file { ofstream out(filename.c_str()); out << config_data; } // load brand new config from file // if a new config object isn't created here, the loaded config // will be added to the existing config OSyncPluginConfig *new_config = m_priv->osync_plugin_config_new(m_priv->error); if( !m_priv->osync_plugin_config_file_load(new_config, filename.c_str(), m_priv->error) ) throw std::runtime_error("SetConfiguration(): " + m_priv->error.GetErrorMsg()); m_priv->osync_member_set_config(member, new_config); if( !m_priv->osync_member_save(member, m_priv->error)) throw std::runtime_error("SetConfiguration(): " + m_priv->error.GetErrorMsg()); } void OpenSync40::Discover(const std::string &group_name) { OSyncGroup *group = m_priv->osync_group_env_find_group(m_priv->group_env.get(), group_name.c_str()); if( !group ) throw std::runtime_error(string("Discover(): ") + _C("Group not found: ") + group_name); EngineHandle engine(m_priv->osync_engine_unref); engine = m_priv->osync_engine_new(group, m_priv->error); if( !engine.get() ) throw std::runtime_error("Discover(): " + m_priv->error.GetErrorMsg()); SyncListHandle members(m_priv->osync_list_free); members = m_priv->osync_group_get_members(group); OSyncList *m = NULL; for( m = members.get(); m; m = m->next ) { OSyncMember *member = (OSyncMember *) m->data; /* Discover the objtypes for the members */ if( !m_priv->osync_engine_discover_and_block(engine.get(), member, m_priv->error)) break; SyncListHandle objtypes(m_priv->osync_list_free); objtypes = m_priv->osync_member_get_objtypes(member); if( m_priv->osync_list_length(objtypes.get()) == 0 ) { m_priv->osync_error_set(m_priv->error, OSYNC_ERROR_GENERIC, _C("discover failed: no objtypes returned")); break; } if( !m_priv->osync_member_save(member, m_priv->error) ) break; } // check for error if( m ) { m_priv->osync_engine_finalize(engine.get(), m_priv->error); throw std::runtime_error("Discover(): " + m_priv->error.GetErrorMsg()); } } void OpenSync40::Sync(const std::string &group_name, SyncStatus &status_callback, Config::pst_type sync_types) { OSyncGroup *group = m_priv->osync_group_env_find_group(m_priv->group_env.get(), group_name.c_str()); if( !group ) throw std::runtime_error(string("Sync(): ") + _C("Group not found: ") + group_name); // enable/disable each objtype, as per sync_types if( !(sync_types & PST_DO_NOT_SET) ) { cerr << "enabling objtypes: " << sync_types << endl; m_priv->osync_group_set_objtype_enabled(group, "contact", (sync_types & PST_CONTACTS) ? TRUE : FALSE); m_priv->osync_group_set_objtype_enabled(group, "event", (sync_types & PST_EVENTS) ? TRUE : FALSE); m_priv->osync_group_set_objtype_enabled(group, "note", (sync_types & PST_NOTES) ? TRUE : FALSE); m_priv->osync_group_set_objtype_enabled(group, "todo", (sync_types & PST_TODOS) ? TRUE : FALSE); } EngineHandle engine(m_priv->osync_engine_unref); engine = m_priv->osync_engine_new(group, m_priv->error); if( !engine.get() ) throw std::runtime_error("Sync(): " + m_priv->error.GetErrorMsg()); CallbackBundle cbdata(m_priv, status_callback); m_priv->osync_engine_set_conflict_callback(engine.get(), conflict_handler, &cbdata); m_priv->osync_engine_set_changestatus_callback(engine.get(), entry_status, &cbdata); m_priv->osync_engine_set_mappingstatus_callback(engine.get(), mapping_status, &cbdata); m_priv->osync_engine_set_enginestatus_callback(engine.get(), engine_status, &cbdata); m_priv->osync_engine_set_memberstatus_callback(engine.get(), member_status, &cbdata); m_priv->osync_engine_set_multiply_callback(engine.get(), multiply_summary, &cbdata); SyncListHandle members(m_priv->osync_list_free); members = m_priv->osync_group_get_members(group); OSyncList *m = NULL; for( m = members.get(); m; m = m->next ) { OSyncMember *member = (OSyncMember *) m->data; SyncListHandle objtypes(m_priv->osync_list_free); objtypes = m_priv->osync_member_get_objtypes(member); if( m_priv->osync_list_length(objtypes.get()) == 0 ) { cout << "Sync(): " << "Member " << m_priv->osync_member_get_id(member) << " has no objtypes. Has it already been discovered?" << endl; } } if( !m_priv->osync_engine_initialize(engine.get(), m_priv->error) ) throw std::runtime_error("Sync(): " + m_priv->error.GetErrorMsg()); if( !m_priv->osync_engine_synchronize_and_block(engine.get(), m_priv->error) ) { m_priv->osync_engine_finalize(engine.get(), NULL); throw std::runtime_error("Sync(): " + m_priv->error.GetErrorMsg()); } if( !m_priv->osync_engine_finalize(engine.get(), m_priv->error) ) throw std::runtime_error("Sync(): " + m_priv->error.GetErrorMsg()); } ///////////////////////////////////////////////////////////////////////////// // TossError public members /// Returns NULL if no error std::string TossError::GetErrorMsg() { return std::string(m_priv->osync_error_print_stack_wrapper(&m_error)); } bool TossError::IsSet() { return m_priv->osync_error_is_set(&m_error); } void TossError::Clear() { if( m_error ) { m_priv->osync_error_unref(&m_error); m_error = 0; } } } // namespace OpenSync barry-0.18.5/desktop/src/ModemDlg.wxg0000644001161500056700000001273412242254476016742 0ustar cdfreycdfrey Modem Starter wxHORIZONTAL wxALL|wxEXPAND 7 wxVERTICAL wxBOTTOM|wxEXPAND 5 wxHORIZONTAL wxRIGHT|wxALIGN_CENTER_VERTICAL 2 1 wxLEFT|wxALIGN_CENTER_VERTICAL 10 1 100, -1 wxEXPAND 0 wxVERTICAL wxEXPAND 0 0 Available provider scripts on your system. Must pick one. barry-minimal barry-rogers barry-testing -1, 150 wxEXPAND 0 wxHORIZONTAL wxRIGHT|wxALIGN_CENTER_VERTICAL 2 1 Optional device password 0 Optional device password 150, -1 barry-0.18.5/desktop/src/osbase.cc0000644001161500056700000002125412242254476016303 0ustar cdfreycdfrey/// /// \file osbase.cc /// Base API class helpers /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "osbase.h" #include "os22.h" #include "os40.h" #include "osprivatebase.h" #include #include #include #include "i18n.h" using namespace std; namespace OpenSync { std::ostream& operator<< (std::ostream &os, const string_list_type &list) { string_list_type::const_iterator b = list.begin(), e = list.end(); for( ; b != e; ++b ) { os << *b << endl; } return os; } std::ostream& operator<< (std::ostream &os, const Member &member) { os << "Member ID: 0x" << hex << member.id << "\n Plugin Name: " << member.plugin_name; os << "\n Friendly Name: "; if( member.friendly_name.size() ) os << member.friendly_name; else os << ""; return os; } std::ostream& operator<< (std::ostream &os, const member_list_type &list) { member_list_type::const_iterator b = list.begin(), e = list.end(); for( ; b != e; ++b ) { os << *b << endl; } return os; } std::ostream& operator<< (std::ostream &os, const Format &format) { os << "Format: " << format.name << " (Object Type: " << format.object_type << ")"; return os; } std::ostream& operator<< (std::ostream &os, const format_list_type &list) { format_list_type::const_iterator b = list.begin(), e = list.end(); for( ; b != e; ++b ) { os << *b << endl; } return os; } ///////////////////////////////////////////////////////////////////////////// // MemberSet public members Member* MemberSet::Find(long id) { iterator b = begin(), e = end(); for( ; b != e; ++b ) { if( b->id == id ) return &(*b); } return 0; } Member* MemberSet::Find(const char *plugin_name) { iterator b = begin(), e = end(); for( ; b != e; ++b ) { if( b->plugin_name == plugin_name ) return &(*b); } return 0; } long MemberSet::FindId(const char *plugin_name) { iterator b = begin(), e = end(); for( ; b != e; ++b ) { if( b->plugin_name == plugin_name ) return b->id; } return -1; } ///////////////////////////////////////////////////////////////////////////// // FormatSet public members Format* FormatSet::Find(const char *name) { iterator b = begin(), e = end(); for( ; b != e; ++b ) { if( b->name == name ) return &(*b); } return 0; } ///////////////////////////////////////////////////////////////////////////// // SyncConflict public members SyncConflict::SyncConflict(SyncConflictPrivateBase &conflict) : m_conflict(conflict) { } SyncConflict::~SyncConflict() { } bool SyncConflict::IsAbortSupported() const { return m_conflict.IsAbortSupported(); } bool SyncConflict::IsIgnoreSupported() const { return m_conflict.IsIgnoreSupported(); } bool SyncConflict::IsKeepNewerSupported() const { return m_conflict.IsKeepNewerSupported(); } std::string SyncConflict::GetMenu() const { ostringstream oss; oss << _C("Which entry do you want to use?\n[1-9] To select a side"); // Translator note: the menu letters must remain the same! if( IsAbortSupported() ) oss << _C(", [A]bort"); oss << _C(", [D]uplicate"); if( IsIgnoreSupported() ) oss << _C(", [I]gnore"); if( IsKeepNewerSupported() ) oss << _C(", Keep [N]ewer"); return oss.str(); } void SyncConflict::Select(int change_index) { m_conflict.Select(change_index); } void SyncConflict::Abort() { m_conflict.Abort(); } void SyncConflict::Duplicate() { m_conflict.Duplicate(); } void SyncConflict::Ignore() { m_conflict.Ignore(); } void SyncConflict::KeepNewer() { m_conflict.KeepNewer(); } std::ostream& SyncConflict::Dump(std::ostream &os) const { const_iterator b = begin(), e = end(); for( ; b != e; ++b ) { os << "Entry " << (b->id+1) << ":\n" << "Member: " << b->member_id << "(" << b->plugin_name << ")\n" << "UID: " << b->uid << "\n" << "Data: " << b->printable_data << "\n"; } return os; } ///////////////////////////////////////////////////////////////////////////// // SyncSummary public members SyncSummary::SyncSummary(SyncSummaryPrivateBase &summary) : m_summary(summary) { } SyncSummary::~SyncSummary() { } void SyncSummary::Abort() { m_summary.Abort(); } void SyncSummary::Continue() { m_summary.Continue(); } std::ostream& SyncSummary::Dump(std::ostream &os) const { string objtype_name; const_iterator b = begin(), e = end(); for( ; b != e; ++b ) { if( b->objtype_name != objtype_name ) { objtype_name = b->objtype_name; os << "Objtype: " << b->objtype_name << "\n"; } os << "\tMember " << b->id << "(" << b->member_id << ") " << b->plugin_name << ": Adding(" << b->added << ") " << "Modifying(" << b->modified << ") " << "Deleting(" << b->deleted << ")\n"; } return os; } ///////////////////////////////////////////////////////////////////////////// // SyncStatus public members - default, CLI imeplementations SyncStatus::~SyncStatus() { } void SyncStatus::HandleConflict(SyncConflict &conflict) { bool again = true; while( again ) { again = false; cout << _C("Conflicting items:") << "\n" << conflict << endl; cout << conflict.GetMenu() << ": "; string line; getline(cin, line); switch( line[0] ) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': conflict.Select(atoi(line.c_str()) - 1); break; case 'A': case 'a': if( conflict.IsAbortSupported() ) conflict.Abort(); else cout << _C("Abort not supported!") << endl; break; case 'D': case 'd': conflict.Duplicate(); break; case 'I': case 'i': if( conflict.IsIgnoreSupported() ) conflict.Ignore(); else cout << _C("Ignore not supported!") << endl; break; case 'N': case 'n': if( conflict.IsKeepNewerSupported() ) conflict.KeepNewer(); else cout << _C("Keep Newer not supported!") << endl; break; default: again = true; break; } } } void SyncStatus::EntryStatus(const std::string &msg, bool error) { if( error ) cout << _C("ERROR: "); cout << msg << endl; } void SyncStatus::MappingStatus(const std::string &msg, bool error) { if( error ) cout << _C("ERROR: "); cout << msg << endl; } void SyncStatus::EngineStatus(const std::string &msg, bool error, bool slowsync) { if( error ) cout << _C("ERROR: "); cout << msg << endl; } void SyncStatus::MemberStatus(long member_id, const std::string &plugin_name, const std::string &msg, bool error) { if( error ) cout << _C("ERROR: "); cout << msg << endl; } void SyncStatus::CheckSummary(SyncSummary &summary) { cout << "\n" << _C("Synchronization Forecast Summary:") << "\n"; cout << summary << endl; cout << _C("Do you want to continue the synchronization? (N/y): "); string line; getline(cin, line); // Abort if not got accepted with 'y' if( line[0] != 'y') { cout << "\n" << _C("Aborting! Synchronization got aborted by user!") << endl; summary.Abort(); } else { cout << "\n" << _C("OK! Completing synchronization!") << endl; summary.Continue(); } } void SyncStatus::ReportError(const std::string &msg) { cout << _C("CALLBACK ERROR: ") << msg << endl; } ///////////////////////////////////////////////////////////////////////////// // OpenSyncAPISet public members APISet::APISet() { // initialize gettext, only once, for libosyncwrap static bool i18n_initialized = false; if( !i18n_initialized ) { INIT_I18N(); i18n_initialized = true; } } APISet::~APISet() { iterator b = begin(), e = end(); for( ; b != e; ++b ) { delete *b; } base_type::clear(); } // throws if not all can be opened void APISet::OpenAll() { push_back( new OpenSync40 ); push_back( new OpenSync22 ); } // does not throw int APISet::OpenAvailable() { int loaded = 0; try { API *p = new OpenSync40; push_back(p); loaded++; } catch( std::exception &e ) { cerr << _C("Unable to load opensync 0.40: ") << e.what(); push_back(0); } try { API *p = new OpenSync22; push_back(p); loaded++; } catch( std::exception &e ) { cerr << _C("Unable to load opensync 0.22: ") << e.what(); push_back(0); } return loaded; } int APISet::GetAvailable() const { return ((*this)[0] ? 1 : 0) + ((*this)[1] ? 1 : 0); } API* APISet::os40() { return (*this)[0]; } API* APISet::os22() { return (*this)[1]; } } // namespace OpenSync barry-0.18.5/desktop/src/GroupCfgDlg.h0000644001161500056700000001053412242254476017033 0ustar cdfreycdfrey/// /// \file GroupCfgDlg.h /// The configuration dialog used when a user double clicks /// on a device in the device list. It lets the user choose /// the app to sync with Barry, as well as the engine to use. /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_GROUPCFGDLG_H__ #define __BARRYDESKTOP_GROUPCFGDLG_H__ #include #include "deviceset.h" class GroupCfgDlg : public wxDialog { DECLARE_EVENT_TABLE() // sets to protected: private: typedef OpenSync::Config::Group::plugin_ptr plugin_ptr; typedef OpenSync::Config::pst_type pst_type; typedef std::map appcfg_map; typedef std::map engapp_map; typedef std::map engtypes_map; // external data sources const DeviceEntry &m_device; OpenSync::APISet &m_apiset; // misc flags int m_app_count; // results of the configuration std::string m_device_name; std::string m_group_name; DeviceEntry::group_ptr m_group; DeviceEntry::extras_ptr m_extras; // in-process config results... i.e. the plugin config // is stored here, and can be overwritten as the user // keeps fiddling with the controls... a map of engines // and apps is kept, so that if the user changes engine // or app, and then changes back, his settings are not lost... // this also means that pre-existing configs from outside // the dialog are kept if possible, to help with re-saving // of opensync configs engapp_map m_plugins; // map of engines/apps/plugins engtypes_map m_sync_types; // map of engines/sync types // this is a map only to preserve user selections between // engines, similar to the plugin behaviour above OpenSync::API *m_engine; // current engine OpenSync::Config::Barry m_barry_plugin; std::string m_favour_plugin_name; // an extra // dialog controls wxSizer *m_topsizer, *m_appsizer; wxComboBox *m_engine_combo, *m_app_combo; wxTextCtrl *m_password_edit, *m_name_edit; wxCheckBox *m_debug_check; wxCheckBox *m_sync_contacts_check; wxCheckBox *m_sync_events_check; wxCheckBox *m_sync_notes_check; wxCheckBox *m_sync_todos_check; wxRadioBox *m_favour_radios; protected: void CreateLayout(); void AddEngineSizer(wxSizer *sizer); void AddConfigSizer(wxSizer *sizer); void AddBarrySizer(wxSizer *sizer); void AddAppSizer(wxSizer *sizer); void UpdateAppSizer(bool relayout = true); // called if engine changes, // to update the app combo, etc, with available // apps void LoadAppNames(wxArrayString &appnames); void AddSyncTypeSizer(wxSizer *sizer); void AddFavourSizer(wxSizer *sizer); void AddButtonSizer(wxSizer *sizer); void SelectCurrentEngine(); void LoadBarryConfig(); void SelectApplication(const std::string appname); void SelectSyncTypes(); void SelectFavour(); // utility functions for interacting with the sync type checkboxes void EnableSyncTypeChecks(pst_type types); void SetSyncTypeChecks(pst_type types); pst_type GetSyncTypeChecks(); std::string GetCurrentAppName() const; // returns name of currently // selected app, for the currently // selected engine... if none selected, // returns empty string (size() == 0) plugin_ptr GetCurrentPlugin(); public: GroupCfgDlg(wxWindow *parent, const DeviceEntry &device, OpenSync::APISet &apiset); // results std::string GetDeviceName() const { return m_device_name; } DeviceEntry::group_ptr GetGroup() { return m_group; } OpenSync::API* GetEngine() const { return m_engine; } DeviceEntry::extras_ptr GetExtras() { return m_extras; } // event handlers void OnConfigureApp(wxCommandEvent &event); void OnEngineComboChange(wxCommandEvent &event); void OnAppComboChange(wxCommandEvent &event); void OnSyncTypeCheck(wxCommandEvent &event); // overrides virtual bool TransferDataFromWindow(); int ShowModal(); }; #endif barry-0.18.5/desktop/src/Mode_Browse.cc0000644001161500056700000010227112242254476017233 0ustar cdfreycdfrey/// /// \file Mode_Browse.cc /// Mode derived class for database browsing /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "Mode_Browse.h" #include "BaseFrame.h" #include "ContactEditDlg.h" #include "CalendarEditDlg.h" #include "MemoEditDlg.h" #include "TaskEditDlg.h" #include "MimeExportDlg.h" #include "windowids.h" #include #include #include using namespace std; using namespace Barry; DEFINE_EVENT_TYPE(BMET_LOAD_STATUS) BEGIN_EVENT_TABLE(BrowseMode, wxEvtHandler) EVT_LIST_ITEM_SELECTED(BrowseMode_DBDBList, BrowseMode::OnDBDBListSelChange) EVT_LIST_ITEM_SELECTED(BrowseMode_RecordList, BrowseMode::OnRecordListSelChange) EVT_LIST_ITEM_ACTIVATED(BrowseMode_RecordList, BrowseMode::OnRecordListActivated) EVT_CHECKBOX (BrowseMode_ShowAllCheckbox, BrowseMode::OnShowAll) EVT_BUTTON (BrowseMode_ImportRecordButton, BrowseMode::OnImportRecord) EVT_BUTTON (BrowseMode_ExportRecordButton, BrowseMode::OnExportRecord) EVT_BUTTON (BrowseMode_AddRecordButton, BrowseMode::OnAddRecord) EVT_BUTTON (BrowseMode_CopyRecordButton, BrowseMode::OnCopyRecord) EVT_BUTTON (BrowseMode_EditRecordButton, BrowseMode::OnEditRecord) EVT_BUTTON (BrowseMode_DeleteRecordButton, BrowseMode::OnDeleteRecord) EVT_COMMAND (wxID_ANY, BMET_LOAD_STATUS, BrowseMode::OnStatusEvent) END_EVENT_TABLE() ////////////////////////////////////////////////////////////////////////////// // Standalone functions void ShowReadOnlyMsg(wxWindow *parent, const Barry::ReturnCodeError &rce) { wxString what(rce.what(), wxConvUTF8); wxMessageBox(_W("This database is apparently read-only. If this device is connected to a BES, you cannot edit records via USB. (Error: ") + what + _T(")"), _W("Device Error"), wxOK | wxICON_ERROR, parent); } bool IsEditable(const std::string &dbname) { // add entry here for each edit dialog available return dbname == Contact::GetDBName() || dbname == Calendar::GetDBName() || dbname == Memo::GetDBName() || dbname == Task::GetDBName(); } bool IsCardable(const std::string &dbname, std::string *file_types = 0); bool IsCardable(const std::string &dbname, std::string *file_types) { // add entry here for each record that can handle MIME style // import / exports if( dbname == Contact::GetDBName() ) { if( file_types ) { // TRANSLATORS: this is a file selector string, // see "Image files" for more info. *file_types = _C("VCard files"); *file_types += " (*.vcf;*.vcard)|*.vcf;*.vcard"; } return true; } else if( dbname == Calendar::GetDBName() || dbname == Memo::GetDBName() || dbname == Task::GetDBName() ) { if( file_types ) { // TRANSLATORS: this is a file selector string, // see "Image files" for more info. *file_types = _C("ICalendar files"); *file_types += " (*.ical;*.ics;*.ifb;*.icalendar)|*.ical;*.ics;*.ifb;*.icalendar"; } return true; } return false; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::Contact &rec) { ContactEditDlg edit(parent, rec, editable); return edit.ShowModal() == wxID_OK; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::Bookmark &rec) { return false; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::Calendar &rec) { CalendarEditDlg edit(parent, rec, editable, &zones); return edit.ShowModal() == wxID_OK; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::CalendarAll &rec) { return false; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::ContentStore &rec) { return false; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::Folder &rec) { return false; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::Memo &rec) { MemoEditDlg edit(parent, rec, editable); return edit.ShowModal() == wxID_OK; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::Message &rec) { return false; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::CallLog &rec) { return false; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::PINMessage &rec) { return false; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::SavedMessage &rec) { return false; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::ServiceBook &rec) { return false; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::Sms &rec) { return false; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::Task &rec) { TaskEditDlg edit(parent, rec, editable, &zones); return edit.ShowModal() == wxID_OK; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::TimeZone &rec) { return false; } bool EditRecord(wxWindow *parent, bool editable, const Barry::TimeZones &zones, Barry::HandheldAgent &rec) { return false; } ////////////////////////////////////////////////////////////////////////////// // GUIDesktopConnector bool GUIDesktopConnector::PasswordPrompt(const Barry::BadPassword &bp, std::string &password_result) { // create prompt based on exception data wxString prompt = wxString::Format( _W("Please enter device password: (%d tries remaining)"), bp.remaining_tries()); // ask user for device password wxString pass = wxGetPasswordFromUser(prompt, _W("Device Password"), _T(""), m_parent); password_result = pass.utf8_str(); // assume that a blank password means the user wishes to quit... // wxWidgets doesn't seem to handle this very well? return password_result.size() > 0; } ////////////////////////////////////////////////////////////////////////////// // DBDataCache DBDataCache::DBDataCache(DataCache::IndexType index, const Barry::DBData &raw) : DataCache(index, raw.GetUniqueId()) , m_raw(raw) { } bool DBDataCache::Edit(wxWindow *parent, bool editable, const Barry::TimeZones &zones) { return false; } std::string DBDataCache::GetDescription() const { return _C("raw data"); } ////////////////////////////////////////////////////////////////////////////// // DBCache DBCache::DBCache(ThreadableDesktop &tdesktop, const std::string &dbname) : m_tdesktop(tdesktop) , m_dbname(dbname) { // lock the desktop DesktopInstancePtr dip = m_tdesktop.Get(); // grab the DBID m_dbid = dip->Desktop().GetDBID(m_dbname); // load the record state table dip->Desktop().GetRecordStateTable(m_dbid, m_state); // load all records AllRecordParser ap(*this, *this); RecordStateTable::StateMapType::iterator i = m_state.StateMap.begin(); for( ; i != m_state.StateMap.end(); ++i ) { m_index = i->second.Index; // save for the callback dip->Desktop().GetRecord(m_dbid, m_index, ap); } // sort the list of records by description m_records.sort(); } DBCache::~DBCache() { } DBCache::iterator DBCache::Get(int list_offset) { iterator i = begin(); for( ; i != end() && list_offset; ++i, list_offset-- ) ; return i; } DBCache::const_iterator DBCache::Get(int list_offset) const { const_iterator i = begin(); for( ; i != end() && list_offset; ++i, list_offset-- ) ; return i; } int DBCache::GetIndex(iterator record) const { iterator i = const_cast (this)->begin(); iterator e = const_cast (this)->end(); for( int index = 0; i != e; ++i, index++ ) { if( i == record ) return index; } return -1; } int DBCache::GetIndex(const_iterator record) const { const_iterator i = begin(); for( int index = 0; i != end(); ++i, index++ ) { if( i == record ) return index; } return -1; } DBCache::iterator DBCache::Add(wxWindow *parent, DataCachePtr p) { // see if this record has a builder Barry::Builder *bp = dynamic_cast (p.get()); if( !bp ) { cerr << _C("DataCachePtr has no builder") << endl; return end(); } // give record a new UniqueID uint32_t record_id = m_state.MakeNewRecordId(); cout << "New recordID generated: 0x" << hex << record_id << endl; p->SetIds(p->GetStateIndex(), record_id); // add record to device DesktopInstancePtr dip = m_tdesktop.Get(); Barry::Mode::Desktop &desktop = dip->Desktop(); bool iv = Barry::IsVerbose(); Barry::Verbose(true); try { desktop.AddRecord(m_dbid, *bp); } catch( Barry::ReturnCodeError &rce ) { cerr << _C("Device exception: ") << rce.what() << endl; if( rce.IsReadOnly() ) { ShowReadOnlyMsg(parent, rce); return end(); } throw; } Barry::Verbose(iv); // update our copy of the record state table from device desktop.GetRecordStateTable(m_dbid, m_state); cout << m_state << endl; // find our new record_id in list, to find the state index IndexType new_index; if( !m_state.GetIndex(record_id, &new_index) ) { throw std::logic_error("Need to reconnect for adding a record?"); } // update new state_index in the data cache record p->SetIds(new_index, record_id); // add DataCachePtr to our own cache list m_records.push_front(p); // return iterator pointing to new record return begin(); } DBCache::iterator DBCache::Add(wxWindow *parent, const Barry::TimeZones &zones, iterator copy_record) { DataCachePtr p; #undef HANDLE_BUILDER #define HANDLE_BUILDER(tname) \ if( m_dbname == Barry::tname::GetDBName() ) { \ Barry::tname rec; \ if( copy_record != end() ) { \ RecordCache *rc = dynamic_cast* > (copy_record->get()); \ if( rc ) { \ rec = rc->GetRecord(); \ } \ } \ p.reset( new RecordCache(0, rec) ); \ } ALL_KNOWN_BUILDER_TYPES // anything else is not addable or buildable if( !p.get() ) { return end(); } if( p->Edit(parent, true, zones) ) { return Add(parent, p); } else { return end(); } } bool DBCache::OverwriteRecord(wxWindow *parent, iterator record) { // see if this record has a builder Barry::Builder *bp = dynamic_cast ((*record).get()); if( !bp ) return false; cout << "Changing device record with index: 0x" << hex << (*record)->GetStateIndex() << endl; cout << m_state << endl; // update the device with new record data DesktopInstancePtr dip = m_tdesktop.Get(); Barry::Mode::Desktop &desktop = dip->Desktop(); bool iv = Barry::IsVerbose(); Barry::Verbose(true); try { desktop.SetRecord(m_dbid, (*record)->GetStateIndex(), *bp); } catch( Barry::ReturnCodeError &rce ) { if( rce.IsReadOnly() ) { ShowReadOnlyMsg(parent, rce); return false; } throw; } Barry::Verbose(iv); return true; } bool DBCache::DeleteAndAddRecord(wxWindow *parent, iterator record) { // see if this record has a builder Barry::Builder *bp = dynamic_cast ((*record).get()); if( !bp ) return false; cout << "Changing device record with index: 0x" << hex << (*record)->GetStateIndex() << endl; cout << m_state << endl; // update the device with new record data DesktopInstancePtr dip = m_tdesktop.Get(); Barry::Mode::Desktop &desktop = dip->Desktop(); bool iv = Barry::IsVerbose(); Barry::Verbose(true); try { desktop.DeleteRecord(m_dbid, (*record)->GetStateIndex()); desktop.AddRecord(m_dbid, *bp); } catch( Barry::ReturnCodeError &rce ) { if( rce.IsReadOnly() ) { ShowReadOnlyMsg(parent, rce); return false; } throw; } Barry::Verbose(iv); // update our copy of the record state table from device desktop.GetRecordStateTable(m_dbid, m_state); cout << m_state << endl; // find our record_id in list, to find the state index IndexType new_index; if( !m_state.GetIndex((*record)->GetRecordId(), &new_index) ) { throw std::logic_error("DAA: Need to reconnect for adding a record?"); } // update new state_index in the data cache record (*record)->SetIds(new_index, (*record)->GetRecordId()); return true; } bool DBCache::Edit(wxWindow *parent, const Barry::TimeZones &zones, iterator record) { if( record == end() ) return false; if( (*record)->Edit(parent, true, zones) && (*record)->IsBuildable() ) { // see if this record is part of the Tasks database RecordCache *tp = dynamic_cast< RecordCache*> ((*record).get()); if( tp ) { // yes, it is... the Tasks database has a bug // so we need to "edit" by deleting and adding // the record again return DeleteAndAddRecord(parent, record); } else { // use the normal code for all other records return OverwriteRecord(parent, record); } } else { return false; } } bool DBCache::Delete(wxWindow *parent, iterator record) { if( record == end() ) return false; // prompt user with Yes / No message wxString desc((*record)->GetDescription().c_str(), wxConvUTF8); int choice = wxMessageBox(_W("Delete this record?\n ") + desc, _W("Record Delete"), wxYES_NO | wxICON_QUESTION, parent); // if no, return false if( choice != wxYES ) return false; cout << "Deleting device record with index: 0x" << hex << (*record)->GetStateIndex() << endl; cout << m_state << endl; // delete record from device DesktopInstancePtr dip = m_tdesktop.Get(); Barry::Mode::Desktop &desktop = dip->Desktop(); desktop.DeleteRecord(m_dbid, (*record)->GetStateIndex()); // remove record from cache list m_records.erase(record); return true; } // For Barry::AllRecordStore #undef HANDLE_PARSER #define HANDLE_PARSER(tname) \ void DBCache::operator() (const Barry::tname &rec) \ { \ DataCachePtr p( new RecordCache(m_index, rec) ); \ m_records.push_front(p); \ } ALL_KNOWN_PARSER_TYPES // For Barry::Parser void DBCache::ParseRecord(const Barry::DBData &data, const Barry::IConverter *ic) { DataCachePtr p( new DBDataCache(m_index, data) ); m_records.push_front(p); } ////////////////////////////////////////////////////////////////////////////// // DBMap DBMap::DBMap(ThreadableDesktop &tdesktop) : m_tdesktop(tdesktop) { if( pthread_mutex_init(&m_map_mutex, NULL) ) { throw Barry::Error(_C("Failed to create map mutex")); } if( pthread_mutex_init(&m_load_mutex, NULL) ) { throw Barry::Error(_C("Failed to create load mutex")); } } DBMap::DBCachePtr DBMap::LoadDBCache(const std::string &dbname) { // first, check for pre-loaded data, before the load lock, // to make sure we return pre-loaded data with utmost haste { scoped_lock map_lock(m_map_mutex); MapType::iterator i = m_map.find(dbname); if( i != m_map.end() ) return i->second; } // if not found, lock and load, but be careful, since we // don't want to open a window here for loading a db twice scoped_lock load_lock(m_load_mutex); // check again for pre-loaded data, since between // map.unlock and load.lock there could have been // another successful load { scoped_lock map_lock(m_map_mutex); MapType::iterator i = m_map.find(dbname); if( i != m_map.end() ) return i->second; } // do the load, without map.lock, since this can take a // significant amount of time DBCachePtr p( new DBCache(m_tdesktop, dbname) ); // lock once more to update the map, and then done scoped_lock map_lock(m_map_mutex); m_map[dbname] = p; return p; } DBMap::DBCachePtr DBMap::GetDBCache(const std::string &dbname) { scoped_lock lock(m_map_mutex); MapType::iterator i = m_map.find(dbname); if( i != m_map.end() ) return i->second; return DBCachePtr(); } ////////////////////////////////////////////////////////////////////////////// // BrowseMode BrowseMode::BrowseMode(wxWindow *parent, const ProbeResult &device) : m_parent(parent) , m_buildable(false) , m_editable(false) , m_cardable(false) , m_show_all(false) { // create device identifying string m_device_id_str = wxString(device.GetDisplayName().c_str(), wxConvUTF8); // // connect to the device // m_con.reset( new GUIDesktopConnector(m_parent, "", "utf-8", device) ); m_con->Reconnect(2); m_tdesktop.reset( new ThreadableDesktop(*m_con) ); // keep our own copy, and sort by name for later m_dbdb = m_con->GetDesktop().GetDBDB(); m_dbdb.SortByName(); // store a copy of the time zone set for record editing if( TimeZones::IsLoadable(m_con->GetDesktop()) ) { // load time zones from device itself m_zones.reset( new TimeZones(m_con->GetDesktop()) ); } else { // use static time zone table from Barry library m_zones.reset( new TimeZones ); } CreateControls(); // create our DBMap and give it the threadable desktop, // now that we're finished doing any desktop USB work m_dbmap.reset( new DBMap(*m_tdesktop) ); // // From here down, we assume that our constructor succeeds, with // no exceptions! // // fire off a background thread to cache database records // in advance... if it fails, don't worry about it m_abort_flag = false; int ret = pthread_create(&m_cache_thread, NULL, &BrowseMode::FillCacheThread, this); if( ret != 0 ) m_abort_flag = true; // no need to join later // connect ourselves to the parent's event handling chain // do this last, so that we are guaranteed our destructor // will run, in case of exceptions m_parent->PushEventHandler(this); } BrowseMode::~BrowseMode() { // unhook that event handler! m_parent->PopEventHandler(); // make sure the cache thread is finished before we destroy it :-) if( !m_abort_flag ) { m_abort_flag = true; void *junk; pthread_join(m_cache_thread, &junk); } } std::string& GetDBName(Barry::DatabaseDatabase::Database &db) { return db.Name; } void BrowseMode::SendStatusEvent(const std::string &dbname) { wxCommandEvent event(BMET_LOAD_STATUS, wxID_ANY); event.SetEventObject(this); if( dbname.size() ) { wxString msg(_W("Loading: ")); msg += wxString(dbname.c_str(), wxConvUTF8); event.SetString(msg); } else { event.SetString(_T("")); } AddPendingEvent(event); } void BrowseMode::CreateControls() { m_top_sizer.reset( new wxBoxSizer(wxVERTICAL) ); // make space for the main header, which is not part of our // work area m_top_sizer->AddSpacer(MAIN_HEADER_OFFSET); // // add list boxes to main area, the list_sizer // wxStaticBoxSizer *list_sizer = new wxStaticBoxSizer(wxHORIZONTAL, m_parent, m_device_id_str); // add database listctrl m_dbdb_list.reset (new wxListCtrl(m_parent, BrowseMode_DBDBList, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL) ); //| wxLC_VRULES // int max_db_width = GetMaxWidth(m_dbdb_list.get(), // m_dbdb.Databases.begin(), m_dbdb.Databases.end(), // &GetDBName); list_sizer->Add( m_dbdb_list.get(), 4, wxEXPAND | wxALL, 4 ); // add the record listctrl m_record_list.reset(new wxListCtrl(m_parent, BrowseMode_RecordList, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL) ); //| wxLC_VRULES list_sizer->Add( m_record_list.get(), 5, wxEXPAND | wxALL, 4 ); // add list sizer to top sizer m_top_sizer->Add( list_sizer, 1, wxEXPAND | wxALL, 4 ); // // add "show all" checkbox and load status static textbox, inside sizer // wxBoxSizer *status_sizer = new wxBoxSizer(wxHORIZONTAL); m_show_all_checkbox.reset( new wxCheckBox(m_parent, BrowseMode_ShowAllCheckbox, _W("Show All Databases"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE) ); status_sizer->Add( m_show_all_checkbox.get(), 0, wxEXPAND, 0 ); m_show_all_checkbox->SetValue(m_show_all); status_sizer->AddStretchSpacer(); m_load_status_text.reset( new wxStaticText(m_parent, BrowseMode_LoadStatusText, _T(""), wxDefaultPosition, wxSize(200, -1), wxST_NO_AUTORESIZE) ); status_sizer->Add( m_load_status_text.get(), 0, wxEXPAND | wxALIGN_CENTRE_VERTICAL, 0 ); m_top_sizer->Add( status_sizer, 0, wxEXPAND | wxALL, 4 ); // // bottom buttons // // add bottom buttons - these go in the bottom FOOTER area // so their heights must be fixed to MAIN_HEADER_OFFSET // minus a border of 5px top and bottom wxSize footer(75, MAIN_HEADER_OFFSET - 5 - 5); wxBoxSizer *buttons = new wxBoxSizer(wxHORIZONTAL); m_import_record_button.reset( new wxButton(m_parent, BrowseMode_ImportRecordButton, _W("Import..."), wxDefaultPosition, footer) ); m_export_record_button.reset( new wxButton(m_parent, BrowseMode_ExportRecordButton, _W("Export..."), wxDefaultPosition, footer) ); m_add_record_button.reset( new wxButton(m_parent, BrowseMode_AddRecordButton, _W("Add..."), wxDefaultPosition, footer) ); m_copy_record_button.reset( new wxButton(m_parent, BrowseMode_CopyRecordButton, _W("Copy..."), wxDefaultPosition, footer) ); m_edit_record_button.reset( new wxButton(m_parent, BrowseMode_EditRecordButton, _W("Edit..."), wxDefaultPosition, footer)); m_delete_record_button.reset( new wxButton(m_parent, BrowseMode_DeleteRecordButton, _W("Delete..."), wxDefaultPosition, footer) ); buttons->Add(m_import_record_button.get(), 0, wxRIGHT, 5); buttons->Add(m_export_record_button.get(), 0, wxRIGHT, 5); buttons->Add(m_add_record_button.get(), 0, wxRIGHT, 5); buttons->Add(m_copy_record_button.get(), 0, wxRIGHT, 5); buttons->Add(m_edit_record_button.get(), 0, wxRIGHT, 5); buttons->Add(m_delete_record_button.get(), 0, wxRIGHT, 5); m_top_sizer->Add(buttons, 0, wxALL | wxALIGN_RIGHT, 5); // // recalc size of children and add columns // wxSize client_size = m_parent->GetClientSize(); m_top_sizer->SetDimension(0, 0, client_size.GetWidth(), client_size.GetHeight()); // m_dbdb_list wxSize dbdb_size = m_dbdb_list->GetClientSize(); int scroll_width = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); int size = dbdb_size.GetWidth() - scroll_width; m_dbdb_list->InsertColumn(0, _W("Databases"), wxLIST_FORMAT_LEFT, size * 0.80); m_dbdb_list->InsertColumn(1, _W("Count"), wxLIST_FORMAT_LEFT, size * 0.20 + scroll_width); // add back the scroll width // so it doesn't look half-baked when // there is no scroll bar // m_record_list wxSize record_size = m_record_list->GetClientSize(); m_record_list->InsertColumn(0, _W("Record Description"), wxLIST_FORMAT_LEFT, record_size.GetWidth()); // // add data // FillDBDBList(); /* // attempt to re-select the devices as we last saw them ReselectDevices(m_device_set->String2Subset(wxGetApp().GetGlobalConfig().GetKey("SelectedDevices"))); UpdateButtons(); */ } int BrowseMode::GUItoDBDBIndex(int gui_index) { if( m_show_all ) return gui_index; DatabaseDatabase::DatabaseArrayType::const_iterator i = m_dbdb.Databases.begin(), e = m_dbdb.Databases.end(); for( int index = 0; i != e; ++i, index++ ) { // only bump index on the parsable databases if( !m_show_all && !IsParsable(i->Name) ) continue; if( !gui_index ) return index; gui_index--; } // error return -1; } void BrowseMode::FillDBDBList() { // start fresh m_dbdb_list->DeleteAllItems(); DatabaseDatabase::DatabaseArrayType::const_iterator i = m_dbdb.Databases.begin(), e = m_dbdb.Databases.end(); for( int index = 0; i != e; ++i, index++ ) { // Only show parsable databases, depending on GUI if( !m_show_all && !IsParsable(i->Name) ) continue; // Database Name wxString text(i->Name.c_str(), wxConvUTF8); long item = m_dbdb_list->InsertItem(index, text); // Record Count ostringstream oss; oss << dec << i->RecordCount; text = wxString(oss.str().c_str(), wxConvUTF8); m_dbdb_list->SetItem(item, 1, text); } UpdateButtons(); } void BrowseMode::FillRecordList(const std::string &dbname) { try { // start fresh m_record_list->DeleteAllItems(); // grab our DB DBMap::DBCachePtr db = m_dbmap->LoadDBCache(dbname); // cycle through the cache, and insert the descriptions // given for each record DBCache::const_iterator b = db->begin(), e = db->end(); for( int index = 0; b != e; ++b, index++ ) { wxString text((*b)->GetDescription().c_str(), wxConvUTF8); //long item = m_record_list->InsertItem(index, text); } } catch( Barry::Error &be ) { cerr << be.what() << endl; } } void BrowseMode::UpdateButtons() { int selected_count = m_record_list->GetSelectedItemCount(); // can only import if this is a cardable DB m_import_record_button->Enable(m_cardable); // can only export if this is a cardable DB and only 1 selected m_export_record_button->Enable(m_cardable && selected_count == 1); // can only add if we have a builder and dialog for this record type m_add_record_button->Enable(m_buildable && m_editable); // can only copy or edit if we have a builder, a dialog, and // only 1 is selected m_copy_record_button->Enable( m_buildable && m_editable && selected_count == 1); m_edit_record_button->Enable( m_buildable && m_editable && selected_count == 1); // can only delete if something is selected m_delete_record_button->Enable(selected_count > 0); } void BrowseMode::FillCache() { // create a copy of the dbdb, and sort in ascending order of // record count, so the last db loaded is the longest... // hopefully this makes the UI more user-friendly and responsive DatabaseDatabase dbdb = m_dbdb; dbdb.SortByRecordCount(); // cycle through the dbdb and load all Parsable databases DatabaseDatabase::DatabaseArrayType::const_iterator i = dbdb.Databases.begin(), e = dbdb.Databases.end(); for( ; i != e; ++i ) { if( IsParsable(i->Name) ) try { SendStatusEvent(i->Name); m_dbmap->LoadDBCache(i->Name); } catch( Barry::Error &be ) { cerr << be.what() << endl; } if( m_abort_flag ) break; } SendStatusEvent(""); // finished m_abort_flag = true; } void* BrowseMode::FillCacheThread(void *bobj) { BrowseMode *bm = (BrowseMode*) bobj; bm->FillCache(); return NULL; } void BrowseMode::OnDBDBListSelChange(wxListEvent &event) { wxBusyCursor wait; int index = GUItoDBDBIndex(event.GetIndex()); m_current_dbname = m_dbdb.Databases.at(index).Name; m_buildable = ::IsBuildable(m_current_dbname); m_editable = ::IsEditable(m_current_dbname); m_cardable = ::IsCardable(m_current_dbname); m_current_record_item = -1; FillRecordList(m_current_dbname); UpdateButtons(); } void BrowseMode::OnRecordListSelChange(wxListEvent &event) { // grab the cache for the current database... Get is ok here, // since the cache is already loaded by the main db list DBMap::DBCachePtr p = m_dbmap->GetDBCache(m_current_dbname); if( !p.get() ) return; // grab the record list index m_current_record_item = event.GetIndex(); // m_current_record_item = m_record_list->GetNextItem( // m_current_record_item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); UpdateButtons(); } void BrowseMode::OnRecordListActivated(wxListEvent &event) { wxCommandEvent ce; OnEditRecord(ce); } void BrowseMode::OnShowAll(wxCommandEvent &event) { m_show_all = !m_show_all; FillDBDBList(); } template bool CheckTypes(wxWindow *parent, const string &dbname, const vector &types) { if( !MimeBuilder::IsMember(SyncT::GetVName(), types) ) { CategoryList tlist; tlist = types; string tslist; tlist.CategoryList2Str(tslist); wxString msg = wxString::Format(_W("Card file type (%s) does not match record you are trying to add (%s)."), wxString(tslist.c_str(), wxConvUTF8).c_str(), wxString(dbname.c_str(), wxConvUTF8).c_str()); wxMessageBox(msg, _W("Invalid Card Type"), wxOK | wxICON_INFORMATION, parent); return false; } return true; } void BrowseMode::OnImportRecord(wxCommandEvent &event) { string file_types; if( !IsCardable(m_current_dbname, &file_types) ) return; // we are loading files here, so also allow *.* file_types += "|"; // TRANSLATORS: this is a file selector string, // see "Image files" for more info. file_types += _C("All files"); file_types += " (*.*)|*.*"; wxString file_filter(file_types.c_str(), wxConvUTF8); wxFileDialog dlg(m_parent, _W("Load Record..."), _T(""), _T(""), file_filter, wxFD_OPEN | wxFD_PREVIEW); if( dlg.ShowModal() != wxID_OK ) return; // open file ifstream ifs(dlg.GetPath().utf8_str()); string vrec; vector types; if( !MimeBuilder::ReadMimeRecord(ifs, vrec, types) ) { wxMessageBox(_W("No card data found in: ") + dlg.GetPath(), _W("Import Read Error"), wxOK | wxICON_ERROR, m_parent); return; } DataCachePtr rp; string convert_error; try { const string &dn = m_current_dbname; // and read per record type: if( m_current_dbname == Contact::GetDBName() ) { if( !CheckTypes(m_parent, dn, types) ) return; Sync::vCard vcard; Contact rec = vcard.ToBarry(vrec.c_str(), 0); rp.reset( new RecordCache(0, rec) ); } else if( m_current_dbname == Calendar::GetDBName() ) { if( !CheckTypes(m_parent, dn, types) ) return; Sync::vTimeConverter vtc; Sync::vCalendar vcal(vtc); Calendar rec = vcal.ToBarry(vrec.c_str(), 0); rp.reset( new RecordCache(0, rec) ); } else if( m_current_dbname == Memo::GetDBName() ) { if( !CheckTypes(m_parent, dn, types) ) return; Sync::vTimeConverter vtc; Sync::vJournal vjournal(vtc); Memo rec = vjournal.ToBarry(vrec.c_str(), 0); rp.reset( new RecordCache(0, rec) ); } else if( m_current_dbname == Task::GetDBName() ) { if( !CheckTypes(m_parent, dn, types) ) return; Sync::vTimeConverter vtc; Sync::vTodo vtodo(vtc); Task rec = vtodo.ToBarry(vrec.c_str(), 0); rp.reset( new RecordCache(0, rec) ); } } catch( Barry::ConvertError &ce ) { convert_error = ce.what(); } if( convert_error.size() ) { wxString msg = wxString::Format(_W("Unable to import selected file: %s"), wxString(convert_error.c_str(), wxConvUTF8).c_str()); wxMessageBox(msg, _W("Import Error"), wxOK | wxICON_ERROR, m_parent); return; } // grab the cache for the current database... Get is ok here, // since the cache is already loaded by the main db list DBMap::DBCachePtr dbp = m_dbmap->GetDBCache(m_current_dbname); if( !dbp.get() ) { wxMessageBox(_W("Internal pointer error: cannot find DBCachePtr for: ") + wxString(m_current_dbname.c_str(), wxConvUTF8), _W("Internal Error"), wxOK | wxICON_ERROR, m_parent); return; } DBCache::iterator i = dbp->Add(m_parent, rp); if( i != dbp->end() ) { wxString text((*i)->GetDescription().c_str(), wxConvUTF8); // insert new record in same spot as DBCache has it m_current_record_item = dbp->GetIndex(i); m_record_list->InsertItem(m_current_record_item, text); } else { wxMessageBox(_W("Internal error: cannot add record to DBCache"), _W("Internal Error"), wxOK | wxICON_ERROR, m_parent); return; } } void BrowseMode::OnExportRecord(wxCommandEvent &event) { string file_types; if( !IsCardable(m_current_dbname, &file_types) ) return; // grab the cache for the current database... Get is ok here, // since the cache is already loaded by the main db list DBMap::DBCachePtr p = m_dbmap->GetDBCache(m_current_dbname); if( !p.get() ) return; DBCache::iterator i = p->Get(m_current_record_item); string vdata; if( (*i)->Card(m_parent, vdata) ) { MimeExportDlg dlg(m_parent, vdata, file_types); dlg.ShowModal(); } } void BrowseMode::OnAddRecord(wxCommandEvent &event) { // grab the cache for the current database... Get is ok here, // since the cache is already loaded by the main db list DBMap::DBCachePtr p = m_dbmap->GetDBCache(m_current_dbname); if( !p.get() ) return; DBCache::iterator i = p->Add(m_parent, *m_zones, p->end()); if( i != p->end() ) { wxString text((*i)->GetDescription().c_str(), wxConvUTF8); // insert new record in same spot as DBCache has it m_current_record_item = p->GetIndex(i); m_record_list->InsertItem(m_current_record_item, text); } } void BrowseMode::OnCopyRecord(wxCommandEvent &event) { // grab the cache for the current database... Get is ok here, // since the cache is already loaded by the main db list DBMap::DBCachePtr p = m_dbmap->GetDBCache(m_current_dbname); if( !p.get() ) return; DBCache::iterator source = p->Get(m_current_record_item); DBCache::iterator i = p->Add(m_parent, *m_zones, source); if( i != p->end() ) { wxString text((*i)->GetDescription().c_str(), wxConvUTF8); // insert new record in same spot as DBCache has it m_current_record_item = p->GetIndex(i); m_record_list->InsertItem(m_current_record_item, text); } } void BrowseMode::OnEditRecord(wxCommandEvent &event) { // grab the cache for the current database... Get is ok here, // since the cache is already loaded by the main db list DBMap::DBCachePtr p = m_dbmap->GetDBCache(m_current_dbname); if( !p.get() ) return; DBCache::iterator i = p->Get(m_current_record_item); if( p->Edit(m_parent, *m_zones, i) ) { wxString text((*i)->GetDescription().c_str(), wxConvUTF8); m_record_list->SetItem(m_current_record_item, 0, text); } } void BrowseMode::OnDeleteRecord(wxCommandEvent &event) { // grab the cache for the current database... Get is ok here, // since the cache is already loaded by the main db list DBMap::DBCachePtr p = m_dbmap->GetDBCache(m_current_dbname); if( !p.get() ) return; DBCache::iterator i = p->Get(m_current_record_item); if( p->Delete(m_parent, i) ) { m_record_list->DeleteItem(m_current_record_item); } } void BrowseMode::OnStatusEvent(wxCommandEvent &event) { m_load_status_text->SetLabel(event.GetString()); } barry-0.18.5/desktop/src/Makefile.am0000644001161500056700000001035412242254476016553 0ustar cdfreycdfreyLIB_OSYNCWRAP_VERSION = @BARRY_DESKTOP_MAJOR@:@BARRY_DESKTOP_MINOR@:0 SUBDIRS = . 0.22 0.40 EXTRA_DIST = \ ContactEditDlg.wxg \ CalendarEditDlg.wxg \ MemoEditDlg.wxg \ TaskEditDlg.wxg \ ModemDlg.wxg \ oextract.cc # To use gettext datadir = @datadir@ localedir = $(datadir)/locale DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@ INCLUDES = $(TREE_BUILD_CXXFLAGS) $(BARRY_CFLAGS) $(OPENSYNC22_CFLAGS) $(OPENSYNC40_CFLAGS) $(GLIB2_CFLAGS) $(EVOLUTION_CFLAGS) # opensync libraries are not included here... they are loaded with dlopen() LIBS = $(TREE_BUILD_LDFLAGS) $(BARRY_LIBS) $(GLIB2_LIBS) AM_CXXFLAGS = -ansi -Wall -g AM_CPPFLAGS = -DBARRYDESKTOP_BASEDATADIR='"$(basedatadir)"' -DBARRYDESKTOP_IMAGEDIR='"$(imagedir)"' -DBARRYDESKTOP_PKGLIBEXECDIR='"$(pkglibexecdir)"' -DBARRYDESKTOP_SYSTEM_GUI_SU='"$(GUISU)"' AM_LDFLAGS = # This should really use @BARRY_MAJOR@ but that's from the root configure.ac # not ours. Desktop's major version should never really change from # Barry's though, so we should be safe. include_osyncwrapdir = ${includedir}/barry@BARRY_DESKTOP_MAJOR@/osyncwrap noinst_PROGRAMS = ostest xmlcompactor xmlmap bsynccl bin_PROGRAMS = barrydesktop pkglibexec_PROGRAMS = bsyncjail blistevo lib_LTLIBRARIES = libosyncwrap.la include_osyncwrap_HEADERS = \ error.h \ dlopen.h \ tempdir.h \ ostypes.h \ osbase.h osprivatebase.h \ osconfig.h \ osconv22.h \ osconv40.h \ os22.h \ os40.h noinst_HEADERS = libosyncwrap_la_SOURCES = \ i18n.h gettext.h \ error.cc error.h \ dlopen.cc dlopen.h \ tempdir.cc tempdir.h \ deviceset.cc deviceset.h \ ostypes.cc ostypes.h \ osbase.cc osbase.h osprivatebase.h \ osconfig.cc osconfig.h \ osconv22.h \ osconv40.h \ os22.h \ os40.h if WITH_OPENSYNC22 libosyncwrap_la_SOURCES += os22.cc osconv22.cc else libosyncwrap_la_SOURCES += null-os22.cc endif if WITH_OPENSYNC40 libosyncwrap_la_SOURCES += os40.cc osconv40.cc else libosyncwrap_la_SOURCES += null-os40.cc endif libosyncwrap_la_LDFLAGS = -ldl -version-info ${LIB_OSYNCWRAP_VERSION} barrydesktop_SOURCES = \ wxi18n.h \ barrydesktop.cc barrydesktop.h \ ipc.h optout.h \ EasyCondition.h \ windowids.h \ util.cc util.h \ StringSync.cc StringSync.h \ xmlcompactor.cc xmlcompactor.h \ xmlmap.cc xmlmap.h \ guitimet.cc guitimet.h \ ClickImage.cc ClickImage.h \ PNGButton.cc PNGButton.h \ BaseButtons.cc BaseButtons.h \ BaseFrame.cc BaseFrame.h \ ContactPhotoWidget.cc ContactPhotoWidget.h \ Mode.h \ Mode_MainMenu.cc Mode_MainMenu.h \ Mode_Sync.cc Mode_Sync.h \ Mode_Browse.cc Mode_Browse.h \ ModemDlg.cc ModemDlg.h \ MigrateDlg.cc MigrateDlg.h \ ContactEditDlg.cc ContactEditDlg.h \ CalendarEditDlg.cc CalendarEditDlg.h \ wxval.h \ MemoEditDlg.cc MemoEditDlg.h \ TaskEditDlg.cc TaskEditDlg.h \ GroupCfgDlg.cc GroupCfgDlg.h \ MimeExportDlg.cc MimeExportDlg.h \ SyncStatusDlg.cc SyncStatusDlg.h \ ConflictDlg.cc ConflictDlg.h \ configui.cc configui.h \ exechelper.cc exechelper.h \ CUI_Barry.cc CUI_Barry.h \ CUI_Evolution.cc CUI_Evolution.h \ CUI_Google.cc CUI_Google.h \ CUI_KDEPim.cc CUI_KDEPim.h \ EvoSources.cc EvoSources.h \ EvoCfgDlg.cc EvoCfgDlg.h \ EvoDefaultDlg.cc EvoDefaultDlg.h barrydesktop_LDADD = libosyncwrap.la -ldl @WX_LIBS@ $(LIBXMLPP_LIBS) $(LIBGCAL_LIBS) $(EVOLUTION_LIBS) barrydesktop_CXXFLAGS = $(AM_CXXFLAGS) @WX_CXXFLAGS@ $(LIBXMLPP_CFLAGS) \ $(LIBGCAL_CFLAGS) bsyncjail_SOURCES = bsyncjail.cc ipc.h bsyncjail_LDADD = libosyncwrap.la -ldl @WX_LIBS@ bsyncjail_CXXFLAGS = $(AM_CXXFLAGS) @WX_CXXFLAGS@ bsynccl_SOURCES = bsynccl.cc bsynccl_LDADD = libosyncwrap.la -ldl bsynccl_CXXFLAGS = $(AM_CXXFLAGS) ostest_SOURCES = \ ostest.cc ostest_CXXFLAGS = if WITH_OPENSYNC22 ostest_CXXFLAGS += -DWITH_OPENSYNC22 endif if WITH_OPENSYNC40 ostest_CXXFLAGS += -DWITH_OPENSYNC40 endif #ostest_LDFLAGS = -avoid-version ostest_LDADD = libosyncwrap.la -ldl xmlcompactor_SOURCES = xmlcompactor.cc xmlcompactor.h xmlcompactor_CXXFLAGS = -DXMLCOMPACTOR $(AM_CXXFLAGS) $(LIBXMLPP_CFLAGS) xmlcompactor_LDADD = $(LIBXMLPP_LIBS) xmlmap_SOURCES = xmlmap.cc xmlmap.h xmlmap_CXXFLAGS = -DXMLMAP $(AM_CXXFLAGS) $(LIBXMLPP_CFLAGS) xmlmap_LDADD = $(LIBXMLPP_LIBS) blistevo_SOURCES = blistevo.cc \ i18n.h gettext.h \ EvoSources.cc EvoSources.h \ dlopen.cc dlopen.h \ error.cc error.h blistevo_CXXFLAGS = $(AM_CXXFLAGS) blistevo_LDADD = -ldl $(EVOLUTION_LIBS) barry-0.18.5/desktop/src/EvoDefaultDlg.cc0000644001161500056700000000451212242254476017512 0ustar cdfreycdfrey/// /// \file EvoDefaultDlg.cc /// Successful defaults detected dialog /// The configuration dialog used to configure Evolution sources /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "EvoDefaultDlg.h" #include "windowids.h" #include #include "wxi18n.h" using namespace std; BEGIN_EVENT_TABLE(EvoDefaultDlg, wxDialog) EVT_BUTTON (Dialog_EvoDefault_ManualConfigButton, EvoDefaultDlg::OnManualButton) END_EVENT_TABLE() EvoDefaultDlg::EvoDefaultDlg(wxWindow *parent) : wxDialog(parent, Dialog_EvoDefault, _W("Evolution Success")) { CreateLayout(); } void EvoDefaultDlg::CreateLayout() { wxSizer *topsizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer *msgsizer = new wxBoxSizer(wxHORIZONTAL); // I'd love to add a portable, system ICON_INFORMATION here, // but I don't know how in wxWidgets :-( Please send me a patch. //msgsizer->Add( someicon ); msgsizer->Add( new wxStaticText(this, wxID_ANY, _W("Successfully auto-detected Evolution configuration!")), 0, wxALIGN_LEFT | wxTOP | wxLEFT | wxRIGHT, 10); topsizer->Add(msgsizer, 0, 0, 0); topsizer->Add( new wxStaticLine(this), 0, wxTOP | wxLEFT | wxRIGHT | wxEXPAND, 10); wxBoxSizer *buttons = new wxBoxSizer(wxHORIZONTAL); buttons->Add( new wxButton(this, Dialog_EvoDefault_ManualConfigButton, _W("Manual Cfg...")), 0, wxALIGN_LEFT | wxEXPAND, 0); buttons->AddStretchSpacer(1); wxButton *ok = new wxButton(this, wxID_OK, _T("Ok")); ok->SetDefault(); buttons->Add( ok, 0, wxALIGN_RIGHT | wxEXPAND, 0); topsizer->Add(buttons, 0, wxALL | wxEXPAND | wxALIGN_RIGHT, 10); SetSizer(topsizer); topsizer->SetSizeHints(this); topsizer->Layout(); } void EvoDefaultDlg::OnManualButton(wxCommandEvent &event) { EndModal(Dialog_EvoDefault_ManualConfigButton); } barry-0.18.5/desktop/src/Mode.h0000644001161500056700000000224712242254476015556 0ustar cdfreycdfrey/// /// \file Mode.h /// Mode base class... each main button gets a mode /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_MODE_H__ #define __BARRYDESKTOP_MODE_H__ #include class Mode { public: Mode() {} virtual ~Mode() {} // events (called from BaseFrame) virtual wxString GetTitleText() const { return _T("FIXME - Incorrect Mode Title"); } virtual void OnPaint(wxDC &dc) {} virtual void OnMouseMotion(wxDC &dc, int x, int y) {} virtual void OnLeftDown(wxDC &dc, int x, int y) {} virtual void OnLeftUp(wxDC &dc, int x, int y) {} }; #endif barry-0.18.5/desktop/src/MimeExportDlg.h0000644001161500056700000000253612242254476017413 0ustar cdfreycdfrey/// /// \file MimeExportDlg.h /// Dialog class to handle viewing/exporting of MIME card data /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_MIME_EXPORT_DLG_H__ #define __BARRYDESKTOP_MIME_EXPORT_DLG_H__ #include "StringSync.h" #include #include class MimeExportDlg : public wxDialog { private: std::string m_vdata; std::string m_file_types; StringSync m_strings; void set_properties(); void do_layout(); protected: wxTextCtrl *text_ctrl_1; wxButton *save_button; wxSizer *bottom_buttons; protected: DECLARE_EVENT_TABLE() // sets to protected public: MimeExportDlg(wxWindow* parent, const std::string &vdata, const std::string &file_types); void OnSaveButton(wxCommandEvent &event); }; #endif barry-0.18.5/desktop/src/deviceset.cc0000644001161500056700000002661212242254476017005 0ustar cdfreycdfrey/// /// \file deviceset.cc /// Class which detects a set of available or known devices /// in an opensync-able system. /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "deviceset.h" #include #include #include #include #include #include "i18n.h" using namespace std; ////////////////////////////////////////////////////////////////////////////// // DeviceExtras class DeviceExtras::DeviceExtras(const Barry::Pin &pin) : m_pin(pin) , m_last_sync_time(0) , m_sync_types(PST_NONE) { } DeviceExtras::DeviceExtras(const Barry::Pin & pin, const Barry::GlobalConfigFile &config, const std::string &group_name) : m_pin(pin) , m_last_sync_time(0) { Load(config, group_name); } std::string DeviceExtras::MakeBaseKey(const std::string &group_name) { ostringstream oss; oss << m_pin.Str() << "-" << group_name << "-"; return oss.str(); } void DeviceExtras::Load(const Barry::GlobalConfigFile &config, const std::string &group_name) { string key = MakeBaseKey(group_name); m_favour_plugin_name = config.GetKey(key + "FavourPlugin"); string num = config.GetKey(key + "LastSyncTime"); m_last_sync_time = atol(num.c_str()); using OpenSync::Config::PSTString2Type; using OpenSync::Config::PSTType2String; string stypes = config.GetKey(key + "SyncTypes", PSTType2String(PST_ALL)); m_sync_types = PSTString2Type(stypes); } void DeviceExtras::Save(Barry::GlobalConfigFile &config, const std::string &group_name) { string key = MakeBaseKey(group_name); config.SetKey(key + "FavourPlugin", m_favour_plugin_name); ostringstream oss; oss << m_last_sync_time; config.SetKey(key + "LastSyncTime", oss.str()); config.SetKey(key + "SyncTypes", OpenSync::Config::PSTType2String(m_sync_types)); } ////////////////////////////////////////////////////////////////////////////// // DeviceEntry class DeviceEntry::DeviceEntry(const Barry::GlobalConfigFile &config, const Barry::ProbeResult *result, group_ptr group, OpenSync::API *engine, const std::string &secondary_device_name) : m_result(result) , m_group(group) , m_engine(engine) , m_device_name(secondary_device_name) { // just make sure that our device name has something in it if( !m_device_name.size() && m_result ) m_device_name = m_result->m_cfgDeviceName; // load the extras if available Barry::Pin pin = GetPin(); if( pin.Valid() && IsConfigured() ) { m_extras.reset( new DeviceExtras(pin, config, m_group->GetGroupName()) ); } } // returns pointer to the Barry plugin object in m_group // or 0 if not available OpenSync::Config::Barry* DeviceEntry::FindBarry() { if( m_group.get() && m_group->HasBarryPlugins() ) return &m_group->GetBarryPlugin(); return 0; } Barry::Pin DeviceEntry::GetPin() const { Barry::Pin pin; // load convenience values if( m_result ) { pin = m_result->m_pin; } if( m_group.get() && m_group->HasBarryPlugins() ) { const OpenSync::Config::Barry &bp = m_group->GetBarryPlugin(); if( bp.GetPin().Valid() ) { // double check for possible conflicting pin numbers if( pin.Valid() ) { if( pin != bp.GetPin() ) { throw std::logic_error("Probe pin != group pin in DeviceEntry"); } } // got a valid pin, save it pin = bp.GetPin(); } } return pin; } std::string DeviceEntry::GetDeviceName() const { if( m_device_name.size() ) return m_device_name; else if( m_result ) return m_result->m_cfgDeviceName; else return std::string(); } std::string DeviceEntry::GetIdentifyingString() const { ostringstream oss; oss << GetPin().Str(); string name = GetDeviceName(); if( name.size() ) oss << " (" << name << ")"; if( IsConfigured() ) oss << ", Group: " << GetConfigGroup()->GetGroupName(); else oss << ", Not configured"; if( GetEngine() ) oss << ", Engine: " << GetEngine()->GetVersion(); return oss.str(); } void DeviceEntry::SetConfigGroup(group_ptr group, OpenSync::API *engine, extras_ptr extras) { m_group = group; m_engine = engine; m_extras = extras; } std::ostream& operator<< (std::ostream &os, const DeviceEntry &de) { os << setfill(' ') << setw(8) << de.GetPin().Str(); os << "|" << setfill(' ') << setw(35) << de.GetDeviceName(); os << "|" << setfill(' ') << setw(4) << (de.IsConnected() ? _C("yes") : _C("no")); os << "|" << setfill(' ') << setw(4) << (de.IsConfigured() ? _C("yes") : _C("no")); os << "|" << setfill(' ') << setw(7) << (de.GetEngine() ? de.GetEngine()->GetVersion() : ""); return os; } ////////////////////////////////////////////////////////////////////////////// // DeviceSet class /// Does a USB probe automatically DeviceSet::DeviceSet(const Barry::GlobalConfigFile &config, OpenSync::APISet &apiset) : m_config(config) , m_apiset(apiset) { Barry::Probe probe; m_results = probe.GetResults(); LoadSet(); } /// Skips the USB probe and uses the results set given DeviceSet::DeviceSet(const Barry::GlobalConfigFile &config, OpenSync::APISet &apiset, const Barry::Probe::Results &results) : m_config(config) , m_apiset(apiset) , m_results(results) { LoadSet(); } void DeviceSet::LoadSet() { if( m_apiset.os40() ) LoadConfigured(*m_apiset.os40()); if( m_apiset.os22() ) LoadConfigured(*m_apiset.os22()); LoadUnconfigured(); Sort(); } /// Constructor helper function. Adds configured DeviceEntry's to the set. /// Does no sorting. void DeviceSet::LoadConfigured(OpenSync::API &api) { using namespace OpenSync; // // we already have the connected devices in m_results, so // load every Barry-related group that exists in the given API // // get group list string_list_type groups; api.GetGroupNames(groups); // for each group for( string_list_type::iterator b = groups.begin(); b != groups.end(); ++b ) { try { // load the group via Config::Group DeviceEntry::group_ptr g( new Config::Group(*b, api, OSCG_THROW_ON_UNSUPPORTED | OSCG_THROW_ON_NO_BARRY | OSCG_THROW_ON_MULTIPLE_BARRIES) ); // now that we have a config group, check to see // if the pin in the group's Barry plugin is // available in the probe results... if so, it is // also connected OpenSync::Config::Barry &plugin = g->GetBarryPlugin(); Barry::Probe::Results::iterator result = std::find(m_results.begin(), m_results.end(), plugin.GetPin()); const Barry::ProbeResult *connected = 0; string dev_name; if( result != m_results.end() ) { connected = &(*result); dev_name = connected->m_cfgDeviceName; } else { // the device is not connected, so do a // special load of a possible device config // to load the device name Barry::ConfigFile cf(plugin.GetPin()); dev_name = cf.GetDeviceName(); } // if no LoadError exceptions, add to configured list push_back( DeviceEntry(m_config, connected, g, &api, dev_name) ); } catch( Config::LoadError &le ) { // if we catch LoadError, it just means that this // isn't a config that Barry Desktop can handle // so just log and skip it barryverbose("DeviceSet::LoadConfigured: " << le.what()); } } } void DeviceSet::LoadUnconfigured() { // cycle through the probe results, and add any devices for // which their pins do not yet exist in the list for( Barry::Probe::Results::const_iterator i = m_results.begin(); i != m_results.end(); ++i ) { iterator p = FindPin(i->m_pin); if( p == end() ) { // this pin isn't in the list yet, so add it // as an unconfigured item // create the DeviceEntry with a null group_ptr DeviceEntry item( m_config, &(*i), DeviceEntry::group_ptr(), 0 ); push_back( item ); } } } /// Constructor helper function. Loads the device list. Sort by /// pin number, but in the following groups: /// /// - configured first (both connected and unconnected) /// - unconfigured but connected second /// /// This should preserve the sort order across multiple loads, to keep /// a relatively consistent listing for the user. /// namespace { bool DeviceEntryCompare(const DeviceEntry &a, const DeviceEntry &b) { if( a.IsConfigured() == b.IsConfigured() ) return strcmp(a.GetPin().Str().c_str(), b.GetPin().Str().c_str()) < 0; else return a.IsConfigured(); } } void DeviceSet::Sort() { std::sort(begin(), end(), &DeviceEntryCompare); } DeviceSet::iterator DeviceSet::FindPin(const Barry::Pin &pin) { for( iterator i = begin(); i != end(); ++i ) { if( i->GetPin() == pin ) return i; } return end(); } DeviceSet::const_iterator DeviceSet::FindPin(const Barry::Pin &pin) const { for( const_iterator i = begin(); i != end(); ++i ) { if( i->GetPin() == pin ) return i; } return end(); } DeviceSet::subset_type::const_iterator DeviceSet::FindPin( const DeviceSet::subset_type &subset, const Barry::Pin &pin) { for( subset_type::const_iterator i = subset.begin(); i != subset.end(); ++i ) { if( (*i)->GetPin() == pin ) return i; } return subset.end(); } std::string DeviceSet::Subset2String(const DeviceSet::subset_type &set) { std::string list; subset_type::const_iterator i = set.begin(); for( ; i != set.end(); ++i ) { if( list.size() ) list += " "; list += (*i)->GetPin().Str(); } return list; } DeviceSet::subset_type DeviceSet::String2Subset(const std::string &list) { subset_type set; istringstream iss(list); Barry::Pin pin; while( iss >> pin ) { if( !pin.Valid() ) continue; // search for pin in device set iterator i = FindPin(pin); if( i != end() ) set.push_back(i); } return set; } DeviceSet::subset_type DeviceSet::FindDuplicates() { subset_type dups; for( iterator i = begin(); i != end(); ++i ) { // start with this PIN dups.push_back(i); // search for a duplicate, and add all dups found for( iterator j = begin(); j != end(); ++j ) { // skip ourselves if( j == i ) continue; if( i->GetPin() == j->GetPin() ) { // found a duplicate dups.push_back(j); } } // if we have multiple iterators in dups, we're done if( dups.size() > 1 ) return dups; // else, start over dups.clear(); } return dups; } void DeviceSet::KillDuplicates(const subset_type &dups) { // anything to do? if( dups.size() == 0 ) return; // nope // only one? if( dups.size() == 1 ) { erase(dups[0]); return; } // ok, we have multiple dups to erase, so we need to make // a copy of ourselves and skip all matching iterators, // then copy the result back to this base_type copy; for( iterator i = begin(); i != end(); ++i ) { if( find(dups.begin(), dups.end(), i) == dups.end() ) { // not in the dups list, copy it copy.push_back(*i); } } // copy back clear(); base_type::operator=(copy); } std::ostream& operator<< (std::ostream &os, const DeviceSet &ds) { os << " PIN | Device Name |Con |Cfg |Engine\n"; os << "--------+-----------------------------------+----+----+-------\n"; for( DeviceSet::const_iterator i = ds.begin(); i != ds.end(); ++i ) os << *i << "\n" << i->GetIdentifyingString() << endl; return os; } barry-0.18.5/desktop/src/xmlmap.cc0000644001161500056700000003110112242254476016315 0ustar cdfreycdfrey/// /// \file xmlmap.cc /// Map an XML node tree according to an XML map file. /// The map is not fully nested, and provides mostly a /// flat view, based on the map. /// /* Copyright (C) 2010-2013, Chris Frey 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 in the COPYING file at the root directory of this project for more details. */ #include "xmlmap.h" #include #include #include #include #include #include #include using namespace std; ////////////////////////////////////////////////////////////////////////////// // XmlNodeSummary XmlNodeSummary::XmlNodeSummary(xmlpp::Node *node, XmlNodeMapping *mapping) : m_node(node) , m_mapping(mapping) , m_name(node->get_name()) { CreateSummary(); } void XmlNodeSummary::ProcessListKey(ostream &os, const Glib::ustring &name) { xmlpp::Node::NodeList list = m_node->get_children(name); xmlpp::Node::NodeList::iterator i = list.begin(); for( int count = 0; i != list.end(); ++i ) { Glib::ustring content = GetContent(*i); if( !content.size() ) continue; if( count ) os << ", "; os << content; count++; } } void XmlNodeSummary::ProcessKey(ostream &os, const Glib::ustring &key) { if( key.size() == 0 ) return; switch( key[0] ) { case '(': os << "("; ProcessKey(os, key.substr(1)); os << ") "; break; case '$': { bool comma = false; Glib::ustring wkey = key; if( key[key.size()-1] == ',' ) { comma = true; wkey = key.substr(0, key.size()-1); } Glib::ustring content = GetContent(wkey.substr(1)); os << content; if( comma && content.size() ) os << ","; os << " "; } break; case '%': ProcessListKey(os, key.substr(1)); break; default: os << key << " "; break; } } void XmlNodeSummary::CreateSummary() { ostringstream oss; istringstream iss(m_mapping->Format()); Glib::ustring key; while( iss >> key ) { ProcessKey(oss, key); } m_summary = oss.str(); } Glib::ustring XmlNodeSummary::GetContent(const Glib::ustring &child_name) const { xmlpp::Node::NodeList list = m_node->get_children(child_name); if( list.size() ) { return GetContent(*list.begin()); } else { return Glib::ustring(); } } Glib::ustring XmlNodeSummary::GetContent(xmlpp::Node *node) const { Glib::ustring content_value; xmlpp::ContentNode *content = dynamic_cast(node); while( !content ) { xmlpp::Node::NodeList list = node->get_children(); if( !list.size() ) break; node = *list.begin(); content = dynamic_cast(node); } if( content ) { content_value = content->get_content(); } return content_value; } bool XmlNodeSummary::SummaryCompare(const XmlNodeSummary &a, const XmlNodeSummary &b) { return a.Summary() < b.Summary(); } bool XmlNodeSummary::PathCompare(const XmlNodeSummary &a, const XmlNodeSummary &b) { return a.Path() < b.Path(); } ////////////////////////////////////////////////////////////////////////////// // XmlNodeMapping XmlNodeMapping::XmlNodeMapping(const Glib::ustring &node_name, int priority, const Glib::ustring &format) : m_node_key_name(node_name) , m_priority(priority) , m_format(format) { } void XmlNodeMapping::AddCompareName(const Glib::ustring &node_name) { m_compare_node_names.push_back(node_name); } void XmlNodeMapping::AddNode(xmlpp::Node *node) { XmlNodeSummary summary(node, this); m_summaries.push_back(summary); } void XmlNodeMapping::SortBySummary() { sort(m_summaries.begin(), m_summaries.end(), &XmlNodeSummary::SummaryCompare); } void XmlNodeMapping::SortByPath() { sort(m_summaries.begin(), m_summaries.end(), &XmlNodeSummary::PathCompare); } const XmlNodeSummary& XmlNodeMapping::operator[] (int index) const { return m_summaries[index]; } // Parse a compare_name in the format of "name[type]" into // its component parts, without the brackets. void XmlNodeMapping::SplitCompareName(const Glib::ustring &compare_name, Glib::ustring &name, Glib::ustring &type) { size_t pos = compare_name.find('['); if( pos == Glib::ustring::npos ) { name = compare_name; type.clear(); } else { name = compare_name.substr(0, pos); pos++; while( compare_name[pos] && compare_name[pos] != ']' ) { type += compare_name[pos]; pos++; } } } bool Timestamp2Unix(const Glib::ustring &stamp, time_t &result) { struct tm split; bool utc; if( !Barry::Sync::iso_to_tm(stamp.c_str(), &split, utc) ) return false; split.tm_isdst = -1; if( utc ) result = Barry::Sync::utc_mktime(&split); else result = mktime(&split); return result != (time_t)-1; } bool TimestampsEqual(const Glib::ustring &content1, const Glib::ustring &content2) { time_t t1, t2; if( !Timestamp2Unix(content1, t1) || !Timestamp2Unix(content2, t2) ) { // could throw there, but this is just used to // pretty up the display, so defaulting to false // is fine return false; } return t1 == t2; } bool XmlNodeMapping::operator== (const XmlNodeMapping &other) const { // make sure mapfile data are the same if( KeyName() != other.KeyName() || Priority() != other.Priority() || Format() != other.Format() || m_compare_node_names != other.m_compare_node_names ) return false; // if the node counts are different, not equal if( m_summaries.size() != other.m_summaries.size() ) return false; // cycle through all compare names, and compare the // values for those names from each node summary for( compare_list::const_iterator namei = m_compare_node_names.begin(); namei != m_compare_node_names.end(); ++namei ) { for( summary_list::const_iterator sumi = m_summaries.begin(), other_sumi = other.m_summaries.begin(); sumi != m_summaries.end() && other_sumi != other.m_summaries.end(); ++sumi, ++other_sumi ) { Glib::ustring name, type; SplitCompareName(*namei, name, type); Glib::ustring content1 = sumi->GetContent(name), content2 = other_sumi->GetContent(name); if( type == "timestamp" ) { // compare content as timestamps if( !TimestampsEqual(content1, content2) ) return false; } else { // compare as raw strings if( content1 != content2 ) return false; } } } // all good! return true; } void XmlNodeMapping::Dump(std::ostream &os) const { os << m_node_key_name << ": Priority " << m_priority << ", Nodes: " << m_summaries.size() << "\n"; os << " Format: " << m_format << "\n"; os << " Compare Names (" << m_compare_node_names.size() << "):\n"; os << " "; for( compare_list::const_iterator i = m_compare_node_names.begin(); i != m_compare_node_names.end(); ++i ) { if( i != m_compare_node_names.begin() ) os << ", "; os << (*i); } os << "\n"; if( m_summaries.size() ) { os << " Summaries (" << m_summaries.size() << " nodes):\n"; for( summary_list::const_iterator i = m_summaries.begin(); i != m_summaries.end(); ++i ) { os << " " << i->Name() << " > " << i->Summary() << "\n"; } } os << "\n"; } void XmlNodeMapping::DumpSummaries(std::ostream &os) const { for( size_t n = 0; n < size(); n++ ) { os << m_summaries[n].Summary() << endl; } } ////////////////////////////////////////////////////////////////////////////// // XmlNodeMap XmlNodeMap::XmlNodeMap(const std::string &type_name, const std::string &map_filename) { LoadMap(type_name, map_filename); } XmlNodeMap::XmlNodeMap(const std::string &map_filename) { LoadMap(string(), map_filename); } // copy constructor - only copies the map data, not the node. // you must Import as usual XmlNodeMap::XmlNodeMap(const XmlNodeMap &other) { operator=(other); } void XmlNodeMap::LoadMap(const std::string &type_name, const std::string &map_filename) { ifstream is(map_filename.c_str()); if( !is ) throw std::runtime_error("Unable to open: " + map_filename); std::string line; while( getline(is, line) ) { if( line[0] == '#' || line[0] == '\t' ) continue; if( line.size() == 0 ) continue; string type, key, format; int priority = -1; istringstream iss(line); iss >> type >> key >> priority >> std::ws; getline(iss, format); if( !iss ) { // skip if error continue; } if( type_name.size() && type != type_name ) { // skip types not for us continue; } ptr_type mapping( new XmlNodeMapping(key, priority, format) ); while( is.peek() == '\t' ) { getline(is, line); mapping->AddCompareName(line.substr(1)); } push_back(mapping); } } void XmlNodeMap::ImportNodes(xmlpp::Node *node, bool purge) { if( XmlNodeMapping *mapping = Find(node->get_path()) ) { mapping->AddNode(node); return; } xmlpp::Node::NodeList list = node->get_children(); xmlpp::Node::NodeList::iterator i = list.begin(); for( ; i != list.end(); ++i ) { ImportNodes(*i, false); } if( purge ) { PurgeEmpties(); } } /// Removes all XmlNodeMappings that contain no node summaries. /// This lets the caller remove mappings that do not match the /// XML data that was imported. For example, a map may contain /// mappings for Contacts and Calendar items, but only one /// is parsed and imported at once. This function will remove /// the unused mappings. void XmlNodeMap::PurgeEmpties() { // iterator new_end = remove_if(begin(), end(), // mem_fun_ref(&XmlNodeMapping::IsEmpty)); // ------------------------------------------------------- // not all compilers compile remove_if() for us, so do it // manually: find the first empty iterator new_end = begin(); for( ; new_end != end(); ++new_end ) { if( new_end->IsEmpty() ) break; } if( new_end == end() ) return; // nothing is empty, nothing to purge // copy the remainder, skipping the empties iterator good = new_end; ++good; for( ; good != end(); ++good ) { if( !good->IsEmpty() ) { *new_end = *good; ++new_end; } } // done re-implementation of remove_if() // ------------------------------------------------------- // erase the junk at the end (need to call this whether // you use remove_if() or not erase(new_end, end()); } XmlNodeMapping* XmlNodeMap::Find(const Glib::ustring &node_name) { iterator i = begin(); for( ; i != end(); ++i ) { const Glib::ustring &xpath = node_name; XmlNodeMapping *mapping = &(*i); const Glib::ustring &key = mapping->KeyName(); if( xpath.size() == key.size() && xpath == key ) { return mapping; } else if( xpath.size() > key.size() && xpath.substr(0, key.size()) == key && xpath[key.size()] == '[' ) { return mapping; } } return 0; } void XmlNodeMap::SortBySummary() { for_each(begin(), end(), mem_fun_ref(&XmlNodeMapping::SortBySummary)); } void XmlNodeMap::SortByPath() { for_each(begin(), end(), mem_fun_ref(&XmlNodeMapping::SortByPath)); } void XmlNodeMap::Dump(std::ostream &os, int stop_priority) const { const_iterator i = begin(); for( ; i != end(); ++i ) { if( i->Priority() >= stop_priority ) return; i->Dump(os); } } XmlNodeMap::iterator XmlNodeMap::priority_end(int stop_priority) { iterator i = begin(); for( ; i != end(); ++i ) { if( i->Priority() >= stop_priority ) return i; } return i; } void XmlNodeMap::clear() { for_each(begin(), end(), mem_fun_ref(&XmlNodeMapping::clear)); } XmlNodeMap& XmlNodeMap::operator=(const XmlNodeMap &other) { const_iterator i = other.begin(); for( ; i != other.end(); ++i ) { ptr_type p( new XmlNodeMapping(*i) ); p->clear(); push_back(p); } return *this; } #ifdef XMLMAP #include #include #include using namespace std::tr1; using namespace std::tr1::placeholders; int main(int argc, char *argv[]) { try { locale loc(""); cin.imbue( loc ); cout.imbue( loc ); xmlpp::DomParser parser; parser.parse_stream(cin); XmlNodeMap np("Contact", "0.22/xmlmap"); np.ImportNodes(parser.get_document()->get_root_node()); np.Dump(cout, 99); np.SortBySummary(); cout << "\n\nCute summary:\n"; for_each(np.begin(), np.priority_end(), bind( mem_fn(&XmlNodeMapping::DumpSummaries), _1, ref(cout))); np.SortByPath(); cout << "\n\nCute summary:\n"; for_each(np.begin(), np.priority_end(), bind( mem_fn(&XmlNodeMapping::DumpSummaries), _1, ref(cout))); } catch( Glib::ConvertError &e ) { cerr << e.what() << endl; return 1; } catch( std::exception &e ) { cerr << e.what() << endl; return 1; } } #endif barry-0.18.5/desktop/src/EvoDefaultDlg.h0000644001161500056700000000211512242254476017351 0ustar cdfreycdfrey/// /// \file EvoDefaultDlg.h /// Successful defaults detected dialog /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_EVODEFAULTDLG_H__ #define __BARRYDESKTOP_EVODEFAULTDLG_H__ #include // forward declarations class EvoDefaultDlg : public wxDialog { DECLARE_EVENT_TABLE() // sets to protected: protected: void CreateLayout(); public: explicit EvoDefaultDlg(wxWindow *parent); // event handlers void OnManualButton(wxCommandEvent &event); }; #endif barry-0.18.5/desktop/src/gettext.h0000644001161500056700000002242112242254476016352 0ustar cdfreycdfrey/* Convenience header for conditional use of GNU . Copyright (C) 1995-1998, 2000-2002, 2004-2006 Free Software Foundation, Inc. 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, 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 Library 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. */ #ifndef _LIBGETTEXT_H #define _LIBGETTEXT_H 1 /* NLS can be disabled through the configure --disable-nls option. */ #if ENABLE_NLS /* Get declarations of GNU message catalog functions. */ # include /* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by the gettext() and ngettext() macros. This is an alternative to calling textdomain(), and is useful for libraries. */ # ifdef DEFAULT_TEXT_DOMAIN # undef gettext # define gettext(Msgid) \ dgettext (DEFAULT_TEXT_DOMAIN, Msgid) # undef ngettext # define ngettext(Msgid1, Msgid2, N) \ dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) # endif #else /* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which chokes if dcgettext is defined as a macro. So include it now, to make later inclusions of a NOP. We don't include as well because people using "gettext.h" will not include , and also including would fail on SunOS 4, whereas is OK. */ #if defined(__sun) # include #endif /* Many header files from the libstdc++ coming with g++ 3.3 or newer include , which chokes if dcgettext is defined as a macro. So include it now, to make later inclusions of a NOP. */ #if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) # include # if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H # include # endif #endif /* Disabled NLS. The casts to 'const char *' serve the purpose of producing warnings for invalid uses of the value returned from these functions. On pre-ANSI systems without 'const', the config.h file is supposed to contain "#define const". */ # define gettext(Msgid) ((const char *) (Msgid)) # define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) # define dcgettext(Domainname, Msgid, Category) \ ((void) (Category), dgettext (Domainname, Msgid)) # define ngettext(Msgid1, Msgid2, N) \ ((N) == 1 \ ? ((void) (Msgid2), (const char *) (Msgid1)) \ : ((void) (Msgid1), (const char *) (Msgid2))) # define dngettext(Domainname, Msgid1, Msgid2, N) \ ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ ((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N)) # define textdomain(Domainname) ((const char *) (Domainname)) # define bindtextdomain(Domainname, Dirname) \ ((void) (Domainname), (const char *) (Dirname)) # define bind_textdomain_codeset(Domainname, Codeset) \ ((void) (Domainname), (const char *) (Codeset)) #endif /* A pseudo function call that serves as a marker for the automated extraction of messages, but does not call gettext(). The run-time translation is done at a different place in the code. The argument, String, should be a literal string. Concatenated strings and other string expressions won't work. The macro's expansion is not parenthesized, so that it is suitable as initializer for static 'char[]' or 'const char[]' variables. */ #define gettext_noop(String) String /* The separator between msgctxt and msgid in a .mo file. */ #define GETTEXT_CONTEXT_GLUE "\004" /* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be short and rarely need to change. The letter 'p' stands for 'particular' or 'special'. */ #ifdef DEFAULT_TEXT_DOMAIN # define pgettext(Msgctxt, Msgid) \ pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) #else # define pgettext(Msgctxt, Msgid) \ pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) #endif #define dpgettext(Domainname, Msgctxt, Msgid) \ pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) #define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) #ifdef DEFAULT_TEXT_DOMAIN # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) #else # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) #endif #define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) #define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category) #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * pgettext_aux (const char *domain, const char *msg_ctxt_id, const char *msgid, int category) { const char *translation = dcgettext (domain, msg_ctxt_id, category); if (translation == msg_ctxt_id) return msgid; else return translation; } #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * npgettext_aux (const char *domain, const char *msg_ctxt_id, const char *msgid, const char *msgid_plural, unsigned long int n, int category) { const char *translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); if (translation == msg_ctxt_id || translation == msgid_plural) return (n == 1 ? msgid : msgid_plural); else return translation; } /* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID can be arbitrary expressions. But for string literals these macros are less efficient than those above. */ #include #define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \ (((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \ /* || __STDC_VERSION__ >= 199901L */ ) #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS #include #endif #define pgettext_expr(Msgctxt, Msgid) \ dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) #define dpgettext_expr(Domainname, Msgctxt, Msgid) \ dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * dcpgettext_expr (const char *domain, const char *msgctxt, const char *msgid, int category) { size_t msgctxt_len = strlen (msgctxt) + 1; size_t msgid_len = strlen (msgid) + 1; const char *translation; #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS char msg_ctxt_id[msgctxt_len + msgid_len]; #else char buf[1024]; char *msg_ctxt_id = (msgctxt_len + msgid_len <= sizeof (buf) ? buf : (char *) malloc (msgctxt_len + msgid_len)); if (msg_ctxt_id != NULL) #endif { memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); msg_ctxt_id[msgctxt_len - 1] = '\004'; memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); translation = dcgettext (domain, msg_ctxt_id, category); #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS if (msg_ctxt_id != buf) free (msg_ctxt_id); #endif if (translation != msg_ctxt_id) return translation; } return msgid; } #define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) #define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * dcnpgettext_expr (const char *domain, const char *msgctxt, const char *msgid, const char *msgid_plural, unsigned long int n, int category) { size_t msgctxt_len = strlen (msgctxt) + 1; size_t msgid_len = strlen (msgid) + 1; const char *translation; #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS char msg_ctxt_id[msgctxt_len + msgid_len]; #else char buf[1024]; char *msg_ctxt_id = (msgctxt_len + msgid_len <= sizeof (buf) ? buf : (char *) malloc (msgctxt_len + msgid_len)); if (msg_ctxt_id != NULL) #endif { memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); msg_ctxt_id[msgctxt_len - 1] = '\004'; memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS if (msg_ctxt_id != buf) free (msg_ctxt_id); #endif if (!(translation == msg_ctxt_id || translation == msgid_plural)) return translation; } return (n == 1 ? msgid : msgid_plural); } #endif /* _LIBGETTEXT_H */ barry-0.18.5/desktop/src/barrydesktop.h0000644001161500056700000000462512242254476017405 0ustar cdfreycdfrey/// /// \file barrydesktop.h /// Program entry point for the desktop GUI /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_BARRYDESKTOP_H__ #define __BARRYDESKTOP_BARRYDESKTOP_H__ #include #include #include class wxSplashScreen; namespace OpenSync { class APISet; } class UsbScanSplash { std::auto_ptr m_splash; public: UsbScanSplash(); ~UsbScanSplash(); }; class BarryDesktopApp : public wxApp { private: Barry::GlobalConfigFile m_global_config; Barry::Probe::Results m_results; std::auto_ptr m_set; public: BarryDesktopApp(); // // data access // Barry::GlobalConfigFile& GetGlobalConfig() { return m_global_config; } const Barry::Probe::Results& GetResults() const { return m_results; } OpenSync::APISet& GetOpenSync() { return *m_set; } // // operations // void ShowMissingOpenSyncMessage(); /// Fills m_results with new data after a brand new scan. /// Does not catch exceptions. void Probe(); /// Grabs a screenshot of the given device. /// Can throw exceptions on error. wxBitmap GetScreenshot(const Barry::ProbeResult &device) const; /// Sets the device name for the given device PIN. /// If the PIN exists in m_results, the associated /// m_results entry will be updated with the new device name, /// so the next GetResults() will contain the new name. void SetDeviceName(Barry::Pin pin, const std::string &name); /// Returns device name for the given PIN, but ONLY if the /// device is connected. If you want to read the device /// name of an unconnected device, use DeviceSet or just /// load the config manually with Barry::ConfigFile. std::string GetDeviceName(Barry::Pin pin) const; // // overrides // virtual bool OnInit(); virtual int OnExit(); }; DECLARE_APP(BarryDesktopApp) #endif barry-0.18.5/desktop/src/ModemDlg.cc0000644001161500056700000002760612242254476016526 0ustar cdfreycdfrey/// /// \file ModemDlg.cc /// Dialog class to handle modem functionality /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "ModemDlg.h" #include "windowids.h" #include "exechelper.h" #include "barrydesktop.h" #include "tempdir.h" #include #include #include #include #include #include #include #include #include #include #include #include "wxi18n.h" using namespace std; // begin wxGlade: ::extracode // end wxGlade ModemDlg::ModemDlg(wxWindow* parent, const std::vector &peers, const std::string &default_peer, const Barry::Pin &pin) : wxDialog(parent, Dialog_Modem, _W("Modem Kickstart")) { bottom_buttons = CreateButtonSizer(wxOK | wxCANCEL); // begin wxGlade: ModemDlg::ModemDlg sizer_5_staticbox = new wxStaticBox(this, -1, _W("Device")); sizer_1_staticbox = new wxStaticBox(this, -1, _W("Providers")); label_2 = new wxStaticText(this, wxID_ANY, _W("For device pin:")); device_label = new wxStaticText(this, wxID_ANY, wxT("3009efe3")); const wxString list_box_1_choices[] = { wxT("barry-minimal"), wxT("barry-rogers"), wxT("barry-testing") }; list_box_1 = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 3, list_box_1_choices, wxLB_SINGLE); label_1 = new wxStaticText(this, wxID_ANY, _W("Password:")); text_ctrl_1 = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD); set_properties(); do_layout(); // end wxGlade // add all peers to the listbox list_box_1->Clear(); int default_index = -1, index = 0; for( std::vector::const_iterator i = peers.begin(); i != peers.end(); ++i, ++index ) { if( default_peer == *i ) default_index = index; list_box_1->Append(wxString(i->c_str(), wxConvUTF8)); } if( default_index >= 0 ) { list_box_1->SetSelection(default_index); } else { list_box_1->SetSelection(0); } // set the PIN value device_label->SetLabel(wxString(pin.Str().c_str(), wxConvUTF8)); } void ModemDlg::set_properties() { // begin wxGlade: ModemDlg::set_properties SetTitle(_W("Modem Starter")); device_label->SetMinSize(wxSize(100, -1)); list_box_1->SetMinSize(wxSize(-1, 150)); list_box_1->SetToolTip(_W("Available provider scripts on your system. Must pick one.")); list_box_1->SetSelection(0); label_1->SetToolTip(_W("Optional device password")); text_ctrl_1->SetMinSize(wxSize(150, -1)); text_ctrl_1->SetToolTip(_W("Optional device password")); // end wxGlade } void ModemDlg::do_layout() { // begin wxGlade: ModemDlg::do_layout wxBoxSizer* sizer_2 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* sizer_3 = new wxBoxSizer(wxVERTICAL); wxStaticBoxSizer* sizer_5 = new wxStaticBoxSizer(sizer_5_staticbox, wxHORIZONTAL); wxStaticBoxSizer* sizer_1 = new wxStaticBoxSizer(sizer_1_staticbox, wxVERTICAL); wxBoxSizer* sizer_4 = new wxBoxSizer(wxHORIZONTAL); sizer_4->Add(label_2, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 2); sizer_4->Add(device_label, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 10); sizer_3->Add(sizer_4, 0, wxBOTTOM|wxEXPAND, 5); sizer_1->Add(list_box_1, 0, wxEXPAND, 0); sizer_3->Add(sizer_1, 0, wxEXPAND, 0); sizer_5->Add(label_1, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 2); sizer_5->Add(text_ctrl_1, 0, 0, 0); sizer_3->Add(sizer_5, 1, wxEXPAND, 0); sizer_2->Add(sizer_3, 0, wxALL|wxEXPAND, 7); // end wxGlade sizer_3->Add(bottom_buttons, 0, wxTOP|wxEXPAND, 5); SetSizer(sizer_2); sizer_2->Fit(this); Layout(); } // // ProgramDetect // /// Searches for the given program name, in various directories, and /// stores the following info: /// Exists() - file exists, and if true, then: /// GetPath() - returns full path of file, and: /// IsExecutable() - returns true if file is a runnable program /// IsSuid() - returns true if file is suid /// GetGroup() - returns the group name of the file /// /// For pppd, for example, this may return on Debian: /// exists? true /// path? /usr/sbin/pppd /// executable? true if user in group, false if not /// suid? true, suid root on Debian /// group? uses the 'dip' group on Debian /// /// On Fedora: /// exists? true /// path? /usr/sbin/pppd /// exec? true /// suid? false /// group? root /// class ProgramDetect { std::string m_path; std::string m_group; bool m_executable; bool m_suid; public: void Dump(std::ostream &os) { os << "Path: " << m_path << "\n"; os << "Group: " << m_group << "\n"; os << "Exec: " << (m_executable ? "true" : "false") << "\n"; os << "Suid: " << (m_suid ? "true" : "false") << "\n"; } const std::string& GetPath() const { return m_path; } const std::string& GetGroup() const { return m_group; } bool Exists() const { return m_path.size() > 0; } bool IsExecutable() const { return m_executable; } bool IsSuid() const { return m_suid; } bool CheckPath(const std::string &path) { if( access(path.c_str(), F_OK) == 0 ) { m_path = path; return true; } return false; } void CheckAll(const char *prog, const std::string &path) { istringstream iss(path); string p; while( getline(iss, p, ':') ) { string f = p + "/" + prog; if( CheckPath(f) ) return; } } ProgramDetect(const char *prog, const std::string &path) : m_executable(false) , m_suid(false) { // find the program first CheckAll(prog, path); // does it exist? if( !m_path.size() ) return; // nope // executable? if( access(m_path.c_str(), X_OK) == 0 ) { m_executable = true; } // suid? struct stat s; if( stat(m_path.c_str(), &s) == 0 ) { if( s.st_mode & S_ISUID ) { m_suid = true; } struct group *g = getgrgid(s.st_gid); if( g ) { m_group = g->gr_name; } } } }; std::string ModemDlg::GetPeerName() const { return string(list_box_1->GetStringSelection().utf8_str()); } std::string ModemDlg::GetPassword() const { return string(text_ctrl_1->GetValue().utf8_str()); } void ModemDlg::DoModem(wxWindow *parent, const Barry::Pin &pin) { // // Search for dependency programs: xterm, pppd, gksu, etc. // // test whether xterm is in the path ProgramDetect xterm("xterm", getenv("PATH")); if( !xterm.Exists() || !xterm.IsExecutable() ) { wxMessageBox(_W("Cannot locate the xterm program. This is used to display modem connection output. Please install it and try again."), _W("Xterm Not Found"), wxOK | wxICON_ERROR, parent); return; } // test whether we can run pppd, probably need to use full // /usr/sbin/pppd path to reach it... check for return code // of 0 or 2 ProgramDetect pppd("pppd", "/usr/sbin:/usr/bin"); if( !pppd.Exists() ) { wxMessageBox(_W("Cannot find pppd. Please install it for modem use."), _W("pppd Not Found"), wxOK | wxICON_ERROR, parent); return; } // // Check if we need root access to run pppd // string need_sudo; if( pppd.IsExecutable() && pppd.IsSuid() ) { // all good! } else if( !pppd.IsExecutable() && pppd.IsSuid() && pppd.GetGroup() != "root" ) { wxString gname(pppd.GetGroup().c_str(), wxConvUTF8); wxString msg = wxString::Format(_W("Your system's PPP has the suid bit set, with a group of '%s'. You should add your account to the '%s' group, to avoid the need to enter the root password every time you use the modem.\n\nContinue anyway?"), gname.c_str(), gname.c_str()); int choice = wxMessageBox(msg, _W("System Group"), wxYES_NO, parent); if( choice != wxYES ) return; need_sudo = BARRYDESKTOP_SYSTEM_GUI_SU + string(" "); } else if( pppd.IsExecutable() && !pppd.IsSuid() ) { need_sudo = BARRYDESKTOP_SYSTEM_GUI_SU + string(" "); } // // Check if we can run pppd, in the non-root case // if( need_sudo.size() == 0 ) { ExecHelper eh(0); wxString cmd((pppd.GetPath() + " permission_test").c_str(), wxConvUTF8); if( !eh.Run(0, "", cmd) ) { wxMessageBox(_W("Internal fork error. Should never happen."), _W("Cannot Run pppd"), wxOK | wxICON_ERROR, parent); return; } eh.WaitForChild(); if( !(eh.GetChildExitCode() == 0 || eh.GetChildExitCode() == 2) ) { wxString msg = wxString::Format(_W("Unable to run pppd correctly. Unexpected error code: %d, %s"), eh.GetChildExitCode(), cmd.c_str()); wxMessageBox(msg, _W("Error Code"), wxOK | wxICON_ERROR, parent); return; } } // // Load all peer files. // // do a search in /etc/ppp/peers for all barry-* files and // store in a vector // std::vector peers; wxDir dir(wxString("/etc/ppp/peers", wxConvUTF8)); if( !dir.IsOpened() ) { wxMessageBox(_W("Unable to access files in /etc/ppp/peers. Do you have the correct permissions?"), _W("Cannot Open Peers"), wxOK | wxICON_ERROR, parent); return; } wxString filename; bool cont = dir.GetFirst(&filename, _T("barry-*"), wxDIR_FILES); while( cont ) { peers.push_back( string(filename.utf8_str()) ); cont = dir.GetNext(&filename); } // anything available? if( !peers.size() ) { wxMessageBox(_W("No providers found. Make sure Barry was properly installed, with peer files in /etc/ppp/peers."), _W("No Providers"), wxOK | wxICON_ERROR, parent); return; } // sort the vector sort(peers.begin(), peers.end()); // // Double check that we can read the peer files // // do an access or file open test on the first barry-* file // to make sure that we have access to peers/ string testfile = "/etc/ppp/peers/" + peers[0]; if( access(testfile.c_str(), R_OK) != 0 ) { wxString msg = wxString::Format(_W("Cannot read provider files under /etc/ppp/peers. Please check your file permissions. (Access failed for %s)"), wxString(testfile.c_str(), wxConvUTF8).c_str()); wxMessageBox(msg, _W("Permissions Error"), wxOK | wxICON_ERROR, parent); return; } // // Fetch default peer choice // Barry::GlobalConfigFile &config = wxGetApp().GetGlobalConfig(); string key = pin.Str() + "-DefaultPeer"; string default_peer = config.GetKey(key); // // Show the dialog // ModemDlg dlg(parent, peers, default_peer, pin); if( dlg.ShowModal() == wxID_OK ) { string peer = dlg.GetPeerName(); string peerfile = "/etc/ppp/peers/" + peer; if( !peer.size() || access(peerfile.c_str(), R_OK) != 0 ) { wxString msg = wxString::Format(_W("Unable to open peer file: %s"), wxString(peerfile.c_str(), wxConvUTF8).c_str()); wxMessageBox(msg, _W("Invalid Peer"), wxOK | wxICON_ERROR, parent); return; } // save peer selection as default for this device config.SetKey(key, peer); // create shell script which calls pppd TempDir tempdir("BarryDesktopModem"); string tmp_path = tempdir.GetNewFilename(); ofstream otmp(tmp_path.c_str()); otmp << "#!/bin/sh" << endl; otmp << "echo " << _C("Starting pppd for device PIN ") << pin.Str() << "... " << endl; ostringstream cmdoss; cmdoss << need_sudo << pppd.GetPath() << " call " << peer; // show command with echo too otmp << "echo" << endl; otmp << "echo '" << cmdoss.str() << "'" << endl; otmp << cmdoss.str() << endl; otmp << "echo " << _C("Press enter to close window...") << endl; otmp << "read" << endl; otmp.close(); chmod(tmp_path.c_str(), S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH); // create command line using xterm as display wxString xterm_cmd((xterm.GetPath() + " " + tmp_path).c_str(), wxConvUTF8); // setup argument fifo Barry::FifoArgs args; args.m_password = dlg.GetPassword(); args.m_pin = pin; Barry::FifoServer fifo(args); // run! and go back to main screen ExecHelper run(0); run.Run(parent, "modem", xterm_cmd); fifo.Serve(5); } } barry-0.18.5/desktop/src/error.h0000644001161500056700000000215312242254476016017 0ustar cdfreycdfrey/// /// \file error.h /// Exception classes specific to the desktop /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_ERROR_H__ #define __BARRYDESKTOP_ERROR_H__ #include #include /// \addtogroup exceptions /// @{ // // DlError // /// Represents and stores the error message from the last /// dlopen() related error. /// class DlError : public std::runtime_error { static std::string GetMsg(const std::string &msg); public: DlError(const std::string &msg); }; /// @} #endif barry-0.18.5/desktop/src/PNGButton.h0000644001161500056700000000264212242254476016511 0ustar cdfreycdfrey/// /// \file PNGButton.h /// Class for turning a set of PNG images into buttons /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_PNGBUTTON_H__ #define __BARRYDESKTOP_PNGBUTTON_H__ #include #include "util.h" class PNGButton { wxBitmap m_bitmaps[3]; // normal[0], focus[1], pushed[2] wxString m_label; wxBitmap m_background; wxWindow *m_parent; int m_id; int m_x, m_y; int m_state; // index into m_bitmaps bool m_enabled; protected: wxBitmap LoadButtonBitmap(int state); public: PNGButton(wxWindow *parent, int ID, int x, int y, bool enabled = true); bool IsPushed() const { return m_state == BUTTON_STATE_PUSHED; } void Init(wxDC &dc); void Draw(wxDC &dc); void Erase(wxDC &dc); void Normal(wxDC &dc); void Focus(wxDC &dc); void Push(wxDC &dc); void Click(wxDC &dc); }; #endif barry-0.18.5/desktop/src/CalendarEditDlg.wxg0000644001161500056700000015013012242254476020211 0ustar cdfreycdfrey Calendar Event wxVERTICAL wxALL|wxEXPAND 10 wxVERTICAL wxEXPAND 0 5 2 1 2 5 0 1 wxEXPAND 0 1 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Subject)) 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Location)) wxALL|wxEXPAND 5 1 wxEXPAND 0 5 7 1 2 5 0 1 0 Dialog_CalendarEdit_AllDayCheck OnAllDayEvent wxGenericValidator(&m_rec.AllDayEvent) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxHORIZONTAL 0 Dialog_CalendarEdit_StartDateCtrl OnStartDateChanged DateTimeValidator(&m_StartDateObj.m_date) 110, -1 0 20 20 0 Dialog_CalendarEdit_StartHoursSpinner 0, 23 OnStartHoursSpin wxGenericValidator(&m_StartDateObj.m_hour) 45, -1 wxLEFT|wxRIGHT|wxALIGN_CENTER_VERTICAL 1 1 0 Dialog_CalendarEdit_StartMinutesSpinner 0, 59 OnStartMinutesSpin wxGenericValidator(&m_StartDateObj.m_min) 45, -1 wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxHORIZONTAL 0 Dialog_CalendarEdit_EndDateCtrl OnEndDateChanged DateTimeValidator(&m_EndDateObj.m_date) 110, -1 0 20 20 0 Dialog_CalendarEdit_EndHoursSpinner 0, 23 OnEndHoursSpin wxGenericValidator(&m_EndDateObj.m_hour) 45, -1 wxALL|wxALIGN_CENTER_VERTICAL 1 1 0 Dialog_CalendarEdit_EndMinutesSpinner 0, 59 OnEndMinutesSpin wxGenericValidator(&m_EndDateObj.m_min) 45, -1 wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxHORIZONTAL wxRIGHT 5 Dialog_CalendarEdit_DurationHoursSpinner 0, 999 OnDurationHoursSpin wxGenericValidator(&m_duration_hours) 45, -1 wxRIGHT|wxALIGN_CENTER_VERTICAL 5 1 wxRIGHT 5 Dialog_CalendarEdit_DurationMinutesSpinner 0, 59 OnDurationMinutesSpin wxGenericValidator(&m_duration_minutes) 45, -1 wxALIGN_CENTER_VERTICAL 0 1 wxALIGN_CENTER_VERTICAL 0 1 0 0 System Time Zone wxALIGN_CENTER_VERTICAL 0 1 0 2 Free Tentative Busy Out of Office wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxHORIZONTAL wxRIGHT 5 Set Reminder to 0 to disable 0, 999 wxGenericValidator(&m_reminder_hours) 45, -1 wxRIGHT|wxALIGN_CENTER_VERTICAL 5 1 wxRIGHT 5 Set Reminder to 0 to disable 0, 59 wxGenericValidator(&m_reminder_minutes) 45, -1 wxALIGN_CENTER_VERTICAL 0 1 wxALL|wxEXPAND 5 1 wxEXPAND 0 5 5 1 2 5 wxALIGN_CENTER_VERTICAL 0 1 0 0 Dialog_CalendarEdit_RecurrenceChoice None Daily Weekly Monthly Yearly OnRecurrenceChoice wxGenericValidator(&m_recur_choice) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxHORIZONTAL wxRIGHT|wxALIGN_CENTER_VERTICAL 5 1 wxRIGHT 5 1, 999 1 wxGenericValidator(&m_interval) 45, -1 wxALIGN_CENTER_VERTICAL 0 1 wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxHORIZONTAL wxRIGHT 5 wxGenericValidator(&m_weekdays[0]) wxRIGHT 5 wxGenericValidator(&m_weekdays[1]) wxRIGHT 5 wxGenericValidator(&m_weekdays[2]) wxRIGHT 5 wxGenericValidator(&m_weekdays[3]) wxRIGHT 5 wxGenericValidator(&m_weekdays[4]) wxRIGHT 5 wxGenericValidator(&m_weekdays[5]) wxRIGHT 5 wxGenericValidator(&m_weekdays[6]) wxALIGN_CENTER_VERTICAL 0 1 Relative monthly or yearly dates take the weekday of the start date into account. (eg. every first Sunday of month) 0 Relative monthly or yearly dates take the weekday of the start date into account. (eg. every first Sunday of month) wxGenericValidator(&m_relative_date) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxHORIZONTAL wxRIGHT|wxALIGN_CENTER_VERTICAL 10 1 Dialog_CalendarEdit_NeverEndsCheck OnEndDateCheckbox wxGenericValidator(&m_rec.Perpetual) wxALIGN_CENTER_VERTICAL 0 1 DateTimeValidator(&m_RecurEndDateObj.m_date) 110, -1 wxALL|wxEXPAND 5 1 wxEXPAND 0 5 3 1 2 5 wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_organizer)) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_invited)) wxALIGN_CENTER_VERTICAL 0 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_accepted_by)) wxALL|wxEXPAND 5 1 wxEXPAND 0 0 3 Public Private Confidential MakeRadioBoxValidator(&m_rec.ClassFlag).Add(Barry::Calendar::Public).Add(Barry::Calendar::Private).Add(Barry::Calendar::Confidential) wxALL|wxEXPAND 5 1 wxEXPAND 0 wxHORIZONTAL wxRIGHT 5 1 wxEXPAND 0 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Notes)) -1, 61 barry-0.18.5/desktop/src/BaseFrame.cc0000644001161500056700000006207512242254476016662 0ustar cdfreycdfrey/// /// \file BaseFrame.cc /// Class for the fixed-size frame that holds the main app /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "BaseFrame.h" #include "Mode_MainMenu.h" #include "Mode_Sync.h" #include "Mode_Browse.h" #include "MigrateDlg.h" #include "ModemDlg.h" #include "ClickImage.h" #include "barrydesktop.h" #include "windowids.h" #include "config.h" #include #include #include // include icons and logos #include "../images/barry_logo_icon.xpm" #include "../images/logo_NetDirect.xpm" using namespace std; BEGIN_EVENT_TABLE(BaseFrame, wxFrame) EVT_SIZE (BaseFrame::OnSize) EVT_PAINT (BaseFrame::OnPaint) EVT_MOTION (BaseFrame::OnMouseMotion) EVT_LEFT_DOWN (BaseFrame::OnLeftDown) EVT_LEFT_UP (BaseFrame::OnLeftUp) EVT_BUTTON (MainMenu_BackupAndRestore, BaseFrame::OnBackupRestore) EVT_BUTTON (MainMenu_Sync, BaseFrame::OnSync) EVT_BUTTON (MainMenu_Modem, BaseFrame::OnModem) EVT_BUTTON (MainMenu_AppLoader, BaseFrame::OnAppLoader) EVT_BUTTON (MainMenu_MigrateDevice, BaseFrame::OnMigrateDevice) EVT_BUTTON (MainMenu_BrowseDatabases, BaseFrame::OnBrowseDatabases) EVT_BUTTON (MainMenu_MediaManagement, BaseFrame::OnMediaManagement) EVT_BUTTON (MainMenu_Misc, BaseFrame::OnMisc) EVT_BUTTON (MainMenu_BackButton, BaseFrame::OnBackButton) EVT_BUTTON (HotImage_BarryLogo, BaseFrame::OnBarryLogoClicked) EVT_BUTTON (HotImage_NetDirectLogo, BaseFrame::OnNetDirectLogoClicked) EVT_TEXT (Ctrl_DeviceCombo, BaseFrame::OnDeviceComboChange) EVT_MENU (SysMenu_VerboseLogging, BaseFrame::OnVerboseLogging) EVT_MENU (SysMenu_RenameDevice, BaseFrame::OnRenameDevice) EVT_MENU (SysMenu_ResetDevice, BaseFrame::OnResetDevice) EVT_MENU (SysMenu_RescanUsb, BaseFrame::OnRescanUsb) EVT_MENU (SysMenu_About, BaseFrame::OnAbout) EVT_MENU (SysMenu_Exit, BaseFrame::OnExit) EVT_END_PROCESS (Process_BackupAndRestore, BaseFrame::OnTermBackupAndRestore) END_EVENT_TABLE() ////////////////////////////////////////////////////////////////////////////// // BaseFrame BaseFrame::BaseFrame(const wxImage &background) : wxFrame(NULL, wxID_ANY, _W("Barry Desktop Control Panel"), wxPoint(50, 50), wxSize(background.GetWidth(), background.GetHeight()), wxMINIMIZE_BOX | wxCAPTION | wxCLOSE_BOX | wxSYSTEM_MENU | wxCLIP_CHILDREN) , TermCatcher(this, Process_BackupAndRestore) , m_width(background.GetWidth()) , m_height(background.GetHeight()) , m_current_mode(0) , m_backup_process(this) , m_rescan_pending(false) { // This is a workaround for different size behaviour // in the GTK version of wxWidgets 2.9 SetClientSize(wxSize(background.GetWidth(), background.GetHeight())); // load base bitmaps m_background.reset( new wxBitmap(background) ); // the main menu mode always exists, but may not always be current m_main_menu_mode.reset( new MainMenuMode(this) ); m_current_mode = m_main_menu_mode.get(); m_barry_logo.reset( new ClickableImage(this, wxBitmap(barry_logo_icon_xpm), HotImage_BarryLogo, 4, 4, false) ); wxBitmap nd_logo(logo_NetDirect_xpm); m_netdirect_logo.reset( new ClickableImage(this, nd_logo, HotImage_NetDirectLogo, m_width - 3 - nd_logo.GetWidth(), (MAIN_HEADER_OFFSET - nd_logo.GetHeight()) / 2, true, wxNullCursor)); // Create the Barry Logo popup system menu m_sysmenu.reset( new wxMenu ); m_sysmenu->Append( new wxMenuItem(m_sysmenu.get(), SysMenu_VerboseLogging, _W("&Verbose Logging"), _W("Enable low level USB debug output"), wxITEM_CHECK, NULL) ); m_sysmenu->Append(SysMenu_RenameDevice, _W("Re&name Device...")); m_sysmenu->Append(SysMenu_ResetDevice, _W("Re&set Device")); m_sysmenu->Append(SysMenu_RescanUsb, _W("&Rescan USB")); m_sysmenu->AppendSeparator(); m_sysmenu->Append(SysMenu_About, _W("&About...")); m_sysmenu->AppendSeparator(); m_sysmenu->Append(wxID_EXIT, _W("E&xit")); UpdateMenuState(); CreateDeviceCombo(wxGetApp().GetGlobalConfig().GetLastDevice()); } void BaseFrame::UpdateMenuState() { if( !m_sysmenu.get() ) return; wxMenuItemList &list = m_sysmenu->GetMenuItems(); wxMenuItemList::iterator b = list.begin(); for( ; b != list.end(); ++b ) { wxMenuItem *item = *b; switch( item->GetId() ) { case SysMenu_VerboseLogging: item->Check(Barry::IsVerbose()); break; } } } void BaseFrame::CreateDeviceCombo(Barry::Pin pin) { const Barry::Probe::Results &results = wxGetApp().GetResults(); // default to: // no device selected, if multiple available and no default given // no devices available, if nothing there // the first device, if only one exists int selected = 0; // create a list of selections wxArrayString devices; // if there's more than one device, let the user pick "none" if( results.size() > 1 ) { devices.Add(_W("No device selected")); } // add one entry for each device for( Barry::Probe::Results::const_iterator i = results.begin(); i != results.end(); ++i ) { // if this is the desired item, remember this selection if( pin.Valid() && i->m_pin == pin ) { selected = devices.GetCount(); } devices.Add(wxString(i->GetDisplayName().c_str(), wxConvUTF8)); } // if nothing is there, be descriptive if( devices.GetCount() == 0 ) { devices.Add(_W("No devices available")); } // create the combobox int x = m_width - 300; int y = m_height - (MAIN_HEADER_OFFSET - 5); m_device_combo.reset( new wxComboBox(this, Ctrl_DeviceCombo, _T(""), wxPoint(x, y), wxSize(290, -1), devices, wxCB_READONLY) ); // select the desired entry m_device_combo->SetValue(devices[selected]); // update the screenshot m_main_menu_mode->UpdateScreenshot(GetCurrentComboPin()); } Barry::Pin BaseFrame::GetCurrentComboPin() { // fetch newly selected device wxString value = m_device_combo->GetValue(); istringstream iss(string(value.utf8_str()).substr(0,8)); Barry::Pin pin; iss >> pin; return pin; } void BaseFrame::EnableBackButton(Mode *new_mode) { // create the button - this goes in the bottom FOOTER area // so the height must be fixed to MAIN_HEADER_OFFSET // minus a border of 5px top and bottom wxPoint pos(10, m_height - (MAIN_HEADER_OFFSET - 5)); wxSize size(-1, MAIN_HEADER_OFFSET - 5 - 5); m_back_button.reset( new wxButton(this, MainMenu_BackButton, _W("Main Menu"), pos, size) ); // set the new mode m_current_mode = new_mode; // destroy the device switcher combo box m_device_combo.reset(); // without the device combo, there is no concept of a // "current device" so temporarily disable the USB options m_sysmenu->Enable(SysMenu_RenameDevice, false); m_sysmenu->Enable(SysMenu_ResetDevice, false); m_sysmenu->Enable(SysMenu_RescanUsb, false); // repaint! Refresh(false); } void BaseFrame::DisableBackButton() { // destroy the back button m_back_button.reset(); // delete all modes m_sync_mode.reset(); m_browse_mode.reset(); // create the device switcher combo again CreateDeviceCombo(wxGetApp().GetGlobalConfig().GetLastDevice()); // enable the USB menu options Barry::Pin pin = GetCurrentComboPin(); m_sysmenu->Enable(SysMenu_RenameDevice, pin.Valid()); m_sysmenu->Enable(SysMenu_ResetDevice, true); m_sysmenu->Enable(SysMenu_RescanUsb, true); // reset the current mode to main menu and repaint m_current_mode = m_main_menu_mode.get(); Refresh(false); // if a USB rescan is pending, do it now if( m_rescan_pending ) { wxCommandEvent event; OnRescanUsb(event); } } void BaseFrame::OnSize(wxSizeEvent &event) { } void BaseFrame::OnPaint(wxPaintEvent &event) { wxPaintDC dc(this); dc.SetMapMode(wxMM_TEXT); // paint the background image dc.DrawBitmap(*m_background, 0, 0); // paint the header: Barry logo m_barry_logo->Draw(dc); // paint the header: NetDirect logo // m_netdirect_logo->Draw(dc); // paint the header: text auto_ptr font( wxFont::New(14, wxFONTFAMILY_SWISS, wxFONTFLAG_ANTIALIASED, _T("Luxi Sans")) ); dc.SetFont( *font ); dc.SetTextForeground( wxColour(0xd2, 0xaf, 0x0b) ); dc.SetTextBackground( wxColour(0, 0, 0, wxALPHA_TRANSPARENT) ); long width, height, descent; wxString header = _W("Barry Desktop Control Panel"); if( m_current_mode ) header = m_current_mode->GetTitleText(); dc.GetTextExtent(header, &width, &height, &descent); int x = (m_width - width) / 2; int y = (MAIN_HEADER_OFFSET - height) / 2; dc.DrawText(header, x, y); // let the mode do its thing if( m_current_mode ) m_current_mode->OnPaint(dc); } void BaseFrame::OnMouseMotion(wxMouseEvent &event) { wxClientDC dc(this); m_barry_logo->HandleMotion(dc, event.m_x, event.m_y); // m_netdirect_logo->HandleMotion(dc, event.m_x, event.m_y); // the mode if( m_current_mode ) m_current_mode->OnMouseMotion(dc, event.m_x, event.m_y); } void BaseFrame::OnLeftDown(wxMouseEvent &event) { wxClientDC dc(this); m_barry_logo->HandleDown(dc, event.m_x, event.m_y); // m_netdirect_logo->HandleDown(dc, event.m_x, event.m_y); event.Skip(); // the mode if( m_current_mode ) m_current_mode->OnLeftDown(dc, event.m_x, event.m_y); } void BaseFrame::OnLeftUp(wxMouseEvent &event) { wxClientDC dc(this); m_barry_logo->HandleUp(dc, event.m_x, event.m_y); // m_netdirect_logo->HandleUp(dc, event.m_x, event.m_y); // the mode if( m_current_mode ) m_current_mode->OnLeftUp(dc, event.m_x, event.m_y); } void BaseFrame::OnBackupRestore(wxCommandEvent &event) { if( m_backup_process.IsAppRunning() ) { wxMessageBox(_W("The Backup program is already running!"), _W("Backup and Restore"), wxOK | wxICON_INFORMATION, this); return; } if( !m_backup_process.Run(this, _C("Backup and Restore"), _T("barrybackup")) ) return; } void BaseFrame::OnSync(wxCommandEvent &event) { if( wxGetApp().GetOpenSync().GetAvailable() == 0 ) { wxGetApp().ShowMissingOpenSyncMessage(); return; } try { m_sync_mode.reset( new SyncMode(this) ); } catch( std::exception &e ) { wxString msg(_W( "An error occurred that prevented the loading of Sync\n" "mode. This is most likely because a critical piece\n" "of OpenSync is missing. Check that all required\n" "plugins are installed, and that tools like 'bidentify'\n" "can find your BlackBerry(R) successfully.\n\n" "Error: ")); msg += wxString(e.what(), wxConvUTF8); wxMessageBox(msg, _W("Sync Mode"), wxOK | wxICON_ERROR, this); return; } EnableBackButton(m_sync_mode.get()); } void BaseFrame::OnModem(wxCommandEvent &event) { Barry::Pin pin = GetCurrentComboPin(); if( pin.Valid() ) { ModemDlg::DoModem(this, pin); } else { wxMessageBox(_W("Please select a device first."), _W("No Device"), wxOK | wxICON_ERROR, this); } /* OpenSync::SyncChange change; change.id = 1; change.member_id = 1; change.plugin_name = "barry-sync"; change.uid = "12341524235234"; change.printable_data = "\n" " \n" " PRODID\n" " -//OpenSync//NONSGML Barry Contact Record//EN\n" " \n" " \n" " Adame Brandee\n" " \n" " \n" " Brandee\n" " Adame\n" " \n" " \n" " 71 Long St.\n" "Toronto ON Canada\n" "N0N 0N0\n" " home\n" " \n" "
\n" " 71 Long St.\n" " Toronto\n" " ON\n" " N0N 0N0\n" " Canada\n" " home\n" "
\n" " \n" " +1 (416) 555-7711\n" " voice\n" " home\n" " \n" " \n" " +1 (416) 955-7117\n" " msg\n" " cell\n" " \n" " \n" " abrandee@sympatico.ca\n" " internet\n" " pref\n" " \n" " \n" " Personal\n" " \n" " \n" " Interweb salesman... 24/7\n" " \n" "
"; std::vector changes; changes.push_back(change); change.id = 2; change.member_id = 2; change.plugin_name = "evo2-sync"; change.uid = "asdfioausdf_1235234as_asdf12341524235234"; change.printable_data = "\n" " \n" " +1 (416) 955-7117\n" " CELL\n" " 2\n" " \n" " \n" " +1 (416) 555-7711\n" " HOME\n" " VOICE\n" " 1\n" " \n" " \n" " abrandee@sympatico.ca\n" " OTHER\n" " 1\n" " \n" " \n" " FALSE\n" " \n" " \n" " 20100322T225303Z\n" " \n" " \n" " PRODID\n" " -//OpenSync//NONSGML Barry Contact Record//EN\n" " \n" " \n" " Adam Brandeee\n" " \n" " \n" " Brandeee\n" " Adam\n" " \n" " \n" " 71 Long St.\n" "Toronto, ON\n" "N0N 0N1\n" "Canada\n" " home\n" " \n" "
\n" " 71 Long St.\n" " Toronto\n" " ON\n" " N0N 0N1\n" " Canada\n" " home\n" "
\n" " \n" " Personal\n" " \n" " \n" " Brandeee, Adam\n" " \n" "
"; changes.push_back(change); { ConflictDlg::AlwaysMemoryBlock always; ConflictDlg dlg(this, *wxGetApp().GetOpenSync().os22(), "SDAIN", changes, always); dlg.ShowModal(); wxString msg(dlg.GetCommand().c_str(), wxConvUTF8); msg += _T(" "); msg += always.m_always ? _T("always") : _T("not always"); wxMessageBox(msg); } */ } void BaseFrame::OnAppLoader(wxCommandEvent &event) { /* OpenSync::SyncChange change; change.id = 1; change.member_id = 1; change.plugin_name = "barry-sync"; change.uid = "12341524235234"; change.printable_data = "\n" " \n" " \n" " 0\n" " \n" " \n" " Subject\n" " \n" " \n" " Bring burnt offering\n" " \n" " \n" " Tent\n" " \n" " \n" " 20100506T040000Z\n" " \n" " \n" " 20100507T040000Z\n" " \n" " \n" " AUDIO\n" " \n" " 20100506T034500Z\n" " DATE-TIME\n" " \n" " \n" " \n" "\n"; std::vector changes; changes.push_back(change); change.id = 2; change.member_id = 2; change.plugin_name = "evo2-sync"; change.uid = "asdfioausdf_1235234as_asdf12341524235234"; change.printable_data = "\n" " \n" " PUBLISH\n" " \n" " \n" " /softwarestudio.org/Tzfile/America/Thunder_Bay\n" " America/Thunder_Bay\n" " \n" " EST\n" " 19701107T010000\n" " \n" " FREQ=YEARLY\n" " INTERVAL=1\n" " BYDAY=2SU\n" " BYMONTH=11\n" " \n" " -0400\n" " -0500\n" " \n" " \n" " EDT\n" " 19700313T030000\n" " \n" " FREQ=YEARLY\n" " INTERVAL=1\n" " BYDAY=2SU\n" " BYMONTH=3\n" " \n" " -0500\n" " -0400\n" " \n" " \n" " \n" " \n" " 1\n" " \n" " \n" " Celebration day\n" " \n" " \n" " Tent of\n" " \n" " \n" " 20100506T000000\n" " /softwarestudio.org/Tzfile/America/Thunder_Bay\n" " \n" " \n" " 20100507T000000\n" " /softwarestudio.org/Tzfile/America/Thunder_Bay\n" " \n" " \n" " 20100430T214736Z\n" " \n" " \n" " 20100430T214736\n" " \n" " \n" " 20100430T214927\n" " \n" " \n" " Bring burnt offering\n" " \n" " \n" " PUBLIC\n" " \n" " \n" " OPAQUE\n" " \n" " \n" " AUDIO\n" " \n" " 20100506T034500Z\n" " DATE-TIME\n" " \n" " \n" " \n" "\n"; changes.push_back(change); { ConflictDlg::AlwaysMemoryBlock always; ConflictDlg dlg(this, *wxGetApp().GetOpenSync().os22(), "SDAIN", changes, always); dlg.ShowModal(); wxString msg(dlg.GetCommand().c_str(), wxConvUTF8); msg += _T(" "); msg += always.m_always ? _T("always") : _T("not always"); wxMessageBox(msg); } */ } void BaseFrame::OnMigrateDevice(wxCommandEvent &event) { try { int i = Barry::Probe::Find(wxGetApp().GetResults(), GetCurrentComboPin()); MigrateDlg dlg(this, wxGetApp().GetResults(), i); dlg.ShowModal(); } catch( std::exception &e ) { wxString msg(_W( "An error occurred during device migration.\n" "This could be due to a low level USB issue\n" "Please make sure your device is plugged in\n" "and not in Desktop Mode. If it is, try replugging\n" "the device, and rescanning the USB bus from the menu.\n" "\n" "Error: ")); msg += wxString(e.what(), wxConvUTF8); wxMessageBox(msg, _W("Migrate Device"), wxOK | wxICON_ERROR, this); return; } } void BaseFrame::OnBrowseDatabases(wxCommandEvent &event) { int i = Barry::Probe::Find(wxGetApp().GetResults(), GetCurrentComboPin()); if( i == -1 ) { wxMessageBox(_W("There is no device selected in the device list. Please select a device to browse."), _W("Database Browser Mode"), wxOK | wxICON_ERROR, this); return; } try { m_browse_mode.reset( new BrowseMode(this, wxGetApp().GetResults()[i]) ); } catch( std::exception &e ) { wxString msg(_W( "An error occurred that prevented the loading of Database\n" "Browse mode. This could be due to a low level USB\n" "issue. Please make sure your device is plugged in\n" "and not in Desktop Mode. If it is, try replugging\n" "the device, and rescanning the USB bus from the menu.\n" "\n" "Error: ")); msg += wxString(e.what(), wxConvUTF8); wxMessageBox(msg, _W("Database Browser Mode"), wxOK | wxICON_ERROR, this); return; } EnableBackButton(m_browse_mode.get()); } void BaseFrame::OnMediaManagement(wxCommandEvent &event) { } void BaseFrame::OnMisc(wxCommandEvent &event) { } void BaseFrame::OnBackButton(wxCommandEvent &event) { DisableBackButton(); } void BaseFrame::OnTermBackupAndRestore(wxProcessEvent &event) { barryverbose("OnTermBackupAndRestore(): done = " << (!m_backup_process.IsAppRunning() ? "true" : "false") << ", status = " << m_backup_process.GetRawAppStatus() << ", exit code = " << m_backup_process.GetChildExitCode()); // only give a warning if the application could not be run... // if there's an error code, and it's been running for longer // than a second or two, then it's a real error code, or a // segfault or something similar. if( !m_backup_process.IsAppRunning() && m_backup_process.GetChildExitCode() && (time(NULL) - m_backup_process.GetStartTime()) < 2 ) { wxMessageBox(_W("Unable to run barrybackup, or it returned an error. Please make sure it is installed and in your PATH."), _W("Backup and Restore"), wxOK | wxICON_ERROR, this); } else { // looks like a successful run... the device name may // have been changed by the BarryBackup GUI, so reprobe // to refresh the names and device list wxCommandEvent event; OnRescanUsb(event); } } void BaseFrame::OnBarryLogoClicked(wxCommandEvent &event) { PopupMenu(m_sysmenu.get(), 20, 20); } void BaseFrame::OnNetDirectLogoClicked(wxCommandEvent &event) { // fire up a browser to point to the Barry documentation wxBusyCursor wait; ::wxLaunchDefaultBrowser(_T("http://netdirect.ca/barry")); } void BaseFrame::OnDeviceComboChange(wxCommandEvent &event) { Barry::Pin pin = GetCurrentComboPin(); // any change? if( pin == wxGetApp().GetGlobalConfig().GetLastDevice() ) return; // nope // save wxGetApp().GetGlobalConfig().SetLastDevice(pin); // update sys menu m_sysmenu->Enable(SysMenu_RenameDevice, pin.Valid()); // update the main mode's screenshot m_main_menu_mode->UpdateScreenshot(pin); if( m_current_mode == m_main_menu_mode.get() ) Refresh(false); // FIXME - if inside a sub menu mode, we need to destroy the mode // class and start fresh } void BaseFrame::OnVerboseLogging(wxCommandEvent &event) { Barry::Verbose( !Barry::IsVerbose() ); wxGetApp().GetGlobalConfig().SetVerboseLogging( Barry::IsVerbose() ); UpdateMenuState(); } void BaseFrame::OnRenameDevice(wxCommandEvent &event) { Barry::Pin pin = GetCurrentComboPin(); if( !pin.Valid() ) return; // grab the current known name of the device const Barry::Probe::Results &results = wxGetApp().GetResults(); int index = Barry::Probe::Find(results, pin); if( index == -1 ) return; wxString current_name(results[index].m_cfgDeviceName.c_str(), wxConvUTF8); wxTextEntryDialog dlg(this, _W("Please enter a name for the current device:"), _W("Rename Device"), current_name, wxTextEntryDialogStyle); if( dlg.ShowModal() != wxID_OK ) return; // nothing to do wxString name = dlg.GetValue(); if( name == current_name ) return; // nothing to do wxGetApp().SetDeviceName(pin, string(name.utf8_str())); // refill combo box CreateDeviceCombo(wxGetApp().GetGlobalConfig().GetLastDevice()); } void BaseFrame::OnResetDevice(wxCommandEvent &event) { int i = Barry::Probe::Find(wxGetApp().GetResults(), GetCurrentComboPin()); if( i != -1 ) { Usb::Device dev(wxGetApp().GetResults()[i].m_dev); dev.Reset(); wxBusyCursor wait; wxSleep(4); OnRescanUsb(event); } } void BaseFrame::OnRescanUsb(wxCommandEvent &event) { if( m_current_mode == m_main_menu_mode.get() ) { std::auto_ptr splash( new UsbScanSplash ); wxGetApp().Probe(); CreateDeviceCombo(wxGetApp().GetGlobalConfig().GetLastDevice()); m_rescan_pending = false; } else { // flag that we need to rescan the next time we return // to the main screen m_rescan_pending = true; } } void BaseFrame::OnAbout(wxCommandEvent &event) { wxAboutDialogInfo info; info.SetName(_W("Barry Desktop Control Panel")); info.SetVersion(_T(BARRY_DESKTOP_VER_STRING)); info.SetDescription(_W("A Free Software graphical user interface for working with the BlackBerry® smartphone.")); info.SetCopyright(_T("Copyright © 2009-2013, Net Direct Inc.")); info.SetWebSite(_T("http://netdirect.ca/barry")); info.SetLicense(_T( " This program is free software; you can redistribute it and/or modify\n" " it under the terms of the GNU General Public License as published by\n" " the Free Software Foundation; either version 2 of the License, or\n" " (at your option) any later version.\n" "\n" " This program is distributed in the hope that it will be useful,\n" " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" "\n" " See the GNU General Public License in the COPYING file at the\n" " root directory of this project for more details.\n")); info.AddDeveloper(_T("Net Direct Inc.")); // info.AddDeveloper(_T("Chris Frey ")); // info.AddDeveloper(_T("See AUTHORS file for detailed")); // info.AddDeveloper(_T("contribution information.")); info.AddArtist(_W("Chris Frey - GUI interface")); info.AddArtist(_W("Martin Owens - Barry logo")); info.AddArtist(_W("Tango Desktop Project - Public domain icons")); wxAboutBox(info); } void BaseFrame::OnExit(wxCommandEvent &event) { Close(true); } barry-0.18.5/desktop/src/osconv22.cc0000644001161500056700000002310412242254476016476 0ustar cdfreycdfrey/// /// \file osconv22.cc /// Converter class for opensync 0.22 plugins /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "osconv22.h" #include "osconfig.h" #include #include "i18n.h" using namespace std; // Supported plugin names #define PLUGIN_BARRY "barry-sync" #define PLUGIN_EVOLUTION "evo2-sync" #define PLUGIN_EVOLUTION3 "evo3-sync" // not supported on 0.2x #define PLUGIN_GOOGLE "google-calendar" // "google-data" ??? #define PLUGIN_KDEPIM "kdepim-sync" #define PLUGIN_FILE "file-sync" #define PLUGIN_SUNBIRD "sunbird-sync" #define PLUGIN_LDAP "ldap-sync" namespace OpenSync { ////////////////////////////////////////////////////////////////////////////// // Converter22 Converter22::Converter22(OpenSync::API &api) : m_api(api) { } bool Converter22::IsPluginSupported(const std::string &plugin_name, std::string *appname) const { if( plugin_name == PLUGIN_BARRY ) { if( appname ) *appname = Config::Barry::AppName(); return true; } else if( plugin_name == PLUGIN_EVOLUTION ) { // only Evolution, not Evolution3, which is not available on // version 0.2x if( appname ) *appname = Config::Evolution::AppName(); return true; } else if( plugin_name == PLUGIN_KDEPIM ) { if( appname ) *appname = Config::KDEPim::AppName(); return true; } return false; } Converter::plugin_ptr Converter22::CreateAndLoadPlugin(const Member &member) { Converter::plugin_ptr ptr; // compare plugin name in member with all known plugins that // we support... and default to Unsupported if not if( member.plugin_name == PLUGIN_BARRY ) { ptr.reset( new Config::Barry(this, member) ); } else if( member.plugin_name == PLUGIN_EVOLUTION ) { ptr.reset( new Config::Evolution(this, member) ); } else if( member.plugin_name == PLUGIN_KDEPIM ) { ptr.reset( new Config::KDEPim(this, member) ); } // default: Unsupported else { ptr.reset( new Config::Unsupported(this, member) ); } return ptr; } std::string Converter22::GetPluginName(const Config::Barry &) const { return PLUGIN_BARRY; } std::string Converter22::GetPluginName(const Config::Evolution &) const { return PLUGIN_EVOLUTION; } std::string Converter22::GetPluginName(const Config::Evolution3 &) const { return "unsupported-evo3-sync"; } std::string Converter22::GetPluginName(const Config::Google &) const { return PLUGIN_GOOGLE; } std::string Converter22::GetPluginName(const Config::KDEPim &) const { return PLUGIN_KDEPIM; } std::string Converter22::GetPluginName(const Config::Unsupported &) const { return "unsupported-sync"; } bool Converter22::IsConfigured(const Config::Barry &config) const { return config.GetPin().Valid(); } bool Converter22::IsConfigured(const Config::Evolution &config) const { // the 22 barry plugin only supports address and calendar, // and as long as either one is configured, we're good return config.GetAddressPath().size() || config.GetCalendarPath().size(); } bool Converter22::IsConfigured(const Config::Evolution3 &config) const { return false; } bool Converter22::IsConfigured(const Config::Google &config) const { return false; } bool Converter22::IsConfigured(const Config::KDEPim &config) const { // KDEPim on 0.22 needs no configuration, so it is always configured return true; } bool Converter22::IsConfigured(const Config::Unsupported &) const { return false; } Config::pst_type Converter22::GetSupportedSyncTypes(const Config::Barry &) const { return PST_CONTACTS | PST_EVENTS; } Config::pst_type Converter22::GetSupportedSyncTypes(const Config::Evolution &) const { return PST_CONTACTS | PST_EVENTS | PST_TODOS; } Config::pst_type Converter22::GetSupportedSyncTypes(const Config::Evolution3 &) const { return PST_NONE; } Config::pst_type Converter22::GetSupportedSyncTypes(const Config::Google &) const { return PST_CONTACTS | PST_EVENTS; } Config::pst_type Converter22::GetSupportedSyncTypes(const Config::KDEPim &) const { return PST_CONTACTS | PST_EVENTS | PST_NOTES | PST_TODOS; } Config::pst_type Converter22::GetSupportedSyncTypes(const Config::Unsupported &) const { return PST_NONE; } void Converter22::Load(Config::Barry &config, const Member &member) { // start with a default setting config.DebugMode(false); config.SetPassword(""); config.SetPin(Barry::Pin()); // grab the config string cfg = m_api.GetConfiguration(member.group_name, member.id); // The config data should contain: // - Keyword: DebugMode // - if the single word "DebugMode" is found, enable Debug // // - Keyword: Device ... // - PIN of device to sync with // - or a flag that says "autoconfig with first device found" // which will autodetect, and update the config // automatically with the found PIN... all future syncs // will then have a PIN // - checkboxes for (both can be on): // - sync calendar items // - sync contacts istringstream iss(cfg); string line; while( getline(iss, line) ) { if( line[0] == '#' ) continue; istringstream ils(line); string key; ils >> key; if( key == "DebugMode" ) { config.DebugMode(true); } else if( key == "Device" ) { Barry::Pin pin; int cal = 0, con = 0; ils >> pin >> cal >> con; config.SetPin(pin); // ignore cal and con, since syncs are // not reliable if they are set... assume 1 for both } else if ( key == "Password" ) { string password; ils >> password; config.SetPassword(password); } } } // yes, I know that I should use an XML library here, but... but... but :-) // this is such a simple format, I should be able to do this manually.... // (famous last words, eh?) std::string Converter22::GrabField(const std::string &cfg, const std::string &name) { string start = "<" + name + ">"; string end = ""; size_t spos = cfg.find(start); size_t epos = cfg.find(end); if( spos == string::npos || epos == string::npos ) return ""; spos += start.size(); int count = epos - spos; if( spos > epos ) return ""; return cfg.substr(spos, count); } void Converter22::Load(Config::Evolution &config, const Member &member) { string cfg = m_api.GetConfiguration(member.group_name, member.id); config.SetAddressPath(GrabField(cfg, "address_path")); config.SetCalendarPath(GrabField(cfg, "calendar_path")); config.SetTasksPath(GrabField(cfg, "tasks_path")); } void Converter22::Load(Config::Evolution3 &config, const Member &member) { throw std::logic_error("Loading config for Evolution3 plugin is not supported for 0.22. Use the Unsupported class."); } void Converter22::Load(Config::Google &config, const Member &member) { throw std::logic_error("Loading config for Google calendar plugin is not supported for 0.22. Use the Unsupported class."); } void Converter22::Load(Config::KDEPim &config, const Member &member) { // KDEPim on 0.22 needs no config, so nothing to do here } void Converter22::Load(Config::Unsupported &config, const Member &member) { string cfg = m_api.GetConfiguration(member.group_name, member.id); config.SetRawConfig(cfg); } void Converter22::Save(const Config::Barry &config, const std::string &group_name) { if( config.GetMemberId() == -1 ) throw Config::SaveError(_C("Cannot save a plugin with a member_id of -1")); ostringstream oss; oss << "Device " << config.GetPin().Str() << " 1 1" << endl; if( config.IsDebugMode() ) oss << "DebugMode" << endl; if( config.GetPassword().size() ) oss << "Password " << config.GetPassword() << endl; m_api.SetConfiguration(group_name, config.GetMemberId(), oss.str()); } void Converter22::Save(const Config::Evolution &config, const std::string &group_name) { if( config.GetMemberId() == -1 ) throw Config::SaveError(_C("Cannot save a plugin with a member_id of -1")); ostringstream oss; oss << "\n"; if( config.GetAddressPath().size() ) oss << " " << config.GetAddressPath() << "\n"; if( config.GetCalendarPath().size() ) oss << " " << config.GetCalendarPath() << "\n"; if( config.GetTasksPath().size() ) oss << " " << config.GetTasksPath() << "\n"; oss << "" << endl; m_api.SetConfiguration(group_name, config.GetMemberId(), oss.str()); } void Converter22::Save(const Config::Evolution3 &config, const std::string &group_name) { throw std::logic_error("Saving config for Evolution3 plugin is not supported for 0.22. Use the Unsupported class."); } void Converter22::Save(const Config::Google &config, const std::string &group_name) { throw std::logic_error("Saving config for Google calendar plugin is not supported for 0.22. Use the Unsupported class."); } void Converter22::Save(const Config::KDEPim &config, const std::string &group_name) { // KDEPim 0.22 needs no config, so nothing to do here } void Converter22::Save(const Config::Unsupported &config, const std::string &group_name) { if( config.GetMemberId() == -1 ) throw Config::SaveError(_C("Cannot save a plugin with a member_id of -1")); m_api.SetConfiguration(group_name, config.GetMemberId(), config.GetRawConfig()); } } // namespace OpenSync barry-0.18.5/desktop/src/MemoEditDlg.wxg0000644001161500056700000001010712242254476017374 0ustar cdfreycdfrey Memo wxVERTICAL wxLEFT|wxRIGHT|wxTOP|wxEXPAND 10 5 2 2 10 wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL 0 1 wxALIGN_CENTER_VERTICAL 0 1 wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Title)) 300, -1 wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL 0 1 Comma separated wxEXPAND|wxALIGN_CENTER_VERTICAL 0 Comma separated list of categories (can be empty) wxTextValidator(wxFILTER_NONE, m_strings.Add(m_category_list)) 300, -1 wxALL|wxEXPAND 10 Body of memo wxTextValidator(wxFILTER_NONE, m_strings.Add(m_rec.Body)) -1, 240 barry-0.18.5/desktop/src/CUI_Google.h0000644001161500056700000000261112242254476016601 0ustar cdfreycdfrey/// /// \file CUI_Google.h /// ConfigUI derived class to configure the Google App /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_CUI_GOOGLE_H__ #define __BARRY_CUI_GOOGLE_H__ #include "configui.h" #include "osconfig.h" class wxWindow; namespace AppConfig { class Google : public ConfigUI { OpenSync::Config::Google *m_google; plugin_ptr m_container; // merely holds m_google // convenience pointers wxWindow *m_parent; public: Google(); // virtual overrides (ConfigUI) virtual std::string AppName() const; virtual bool Configure(wxWindow *parent, plugin_ptr old_plugin); virtual plugin_ptr GetPlugin(); virtual bool RunApp(wxWindow *parent); virtual void PreSyncAppInit(); virtual bool ZapData(wxWindow *parent, plugin_ptr plugin, OpenSync::API *engine); }; } #endif barry-0.18.5/desktop/src/osconv40.h0000644001161500056700000000637512242254476016353 0ustar cdfreycdfrey/// /// \file osconv40.h /// Converter class for opensync 0.40 plugins /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_OSCONV40_H__ #define __BARRY_OSCONV40_H__ #include "osbase.h" #include "os40.h" namespace OpenSync { class Converter40 : public Converter { OpenSync::OpenSync40 &m_api; public: Converter40(OpenSync::OpenSync40 &api); virtual bool IsPluginSupported(const std::string &plugin_name, std::string *appname = 0) const; virtual plugin_ptr CreateAndLoadPlugin(const Member &member); virtual std::string GetPluginName(const Config::Barry &) const; virtual std::string GetPluginName(const Config::Evolution &) const; virtual std::string GetPluginName(const Config::Evolution3 &) const; virtual std::string GetPluginName(const Config::Google &) const; virtual std::string GetPluginName(const Config::KDEPim &) const; virtual std::string GetPluginName(const Config::Unsupported &) const; virtual bool IsConfigured(const Config::Barry &) const; virtual bool IsConfigured(const Config::Evolution &) const; virtual bool IsConfigured(const Config::Evolution3 &) const; virtual bool IsConfigured(const Config::Google &) const; virtual bool IsConfigured(const Config::KDEPim &) const; virtual bool IsConfigured(const Config::Unsupported &) const; virtual Config::pst_type GetSupportedSyncTypes(const Config::Barry &) const; virtual Config::pst_type GetSupportedSyncTypes(const Config::Evolution &) const; virtual Config::pst_type GetSupportedSyncTypes(const Config::Evolution3 &) const; virtual Config::pst_type GetSupportedSyncTypes(const Config::Google &) const; virtual Config::pst_type GetSupportedSyncTypes(const Config::KDEPim &) const; virtual Config::pst_type GetSupportedSyncTypes(const Config::Unsupported &) const; virtual void Load(Config::Barry &config, const Member &member); virtual void Load(Config::Evolution &config, const Member &member); virtual void Load(Config::Evolution3 &config, const Member &member); virtual void Load(Config::Google &config, const Member &member); virtual void Load(Config::KDEPim &config, const Member &member); virtual void Load(Config::Unsupported &config, const Member &member); virtual void Save(const Config::Barry &config, const std::string &group_name); virtual void Save(const Config::Evolution &config, const std::string &group_name); virtual void Save(const Config::Evolution3 &config, const std::string &group_name); virtual void Save(const Config::Google &config, const std::string &group_name); virtual void Save(const Config::KDEPim &config, const std::string &group_name); virtual void Save(const Config::Unsupported &config, const std::string &group_name); }; } // namespace OpenSync #endif barry-0.18.5/desktop/src/null-os40.cc0000644001161500056700000001437612242254476016573 0ustar cdfreycdfrey/// /// \file null-os40.cc /// Null wrapper class for with opensync 0.4x is not available /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "os40.h" #include "osconv40.h" #include "i18n.h" namespace OpenSync { static void ThrowNotSupported() { throw std::logic_error("Not supported on this system."); } ///////////////////////////////////////////////////////////////////////////// // OpenSync40 - public members OpenSync40::OpenSync40() { throw std::runtime_error(_C("OpenSync 0.4x support was not compiled in.")); } OpenSync40::~OpenSync40() { } ///////////////////////////////////////////////////////////////////////////// // Null implementations const char* OpenSync40::GetVersion() const { return 0; } const char* OpenSync40::GetEngineName() const { return "0.40"; } void OpenSync40::GetPluginNames(string_list_type &plugins) { } void OpenSync40::GetFormats(format_list_type &formats) { } void OpenSync40::GetGroupNames(string_list_type &groups) { } void OpenSync40::GetMembers(const std::string &group_name, member_list_type &members) { } void OpenSync40::AddGroup(const std::string &group_name) { } void OpenSync40::DeleteGroup(const std::string &group_name) { } Converter& OpenSync40::GetConverter() { throw std::logic_error(_C("Not supported on this system.")); } long OpenSync40::AddMember(const std::string &group_name, const std::string &plugin_name, const std::string &member_name) { return 0; } void OpenSync40::DeleteMember(const std::string &group_name, long member_id) { } void OpenSync40::DeleteMember(const std::string &group_name, const std::string &plugin_name) { } bool OpenSync40::IsConfigurable(const std::string &group_name, long member_id) { return false; } std::string OpenSync40::GetConfiguration(const std::string &group_name, long member_id) { return ""; } void OpenSync40::SetConfiguration(const std::string &group_name, long member_id, const std::string &config_data) { } void OpenSync40::Discover(const std::string &group_name) { } void OpenSync40::Sync(const std::string &group_name, SyncStatus &status_callback, Config::pst_type sync_types) { } ////////////////////////////////////////////////////////////////////////////// // Null Converter40 Converter40::Converter40(OpenSync::OpenSync40 &api) : m_api(api) { } bool Converter40::IsPluginSupported(const std::string &plugin_name, std::string *appname) const { return false; } Converter::plugin_ptr Converter40::CreateAndLoadPlugin(const Member &member) { return Converter::plugin_ptr(); } std::string Converter40::GetPluginName(const Config::Barry &) const { throw std::logic_error(_C("Not supported on this system.")); } std::string Converter40::GetPluginName(const Config::Evolution &) const { throw std::logic_error(_C("Not supported on this system.")); } std::string Converter40::GetPluginName(const Config::Evolution3 &) const { throw std::logic_error(_C("Not supported on this system.")); } std::string Converter40::GetPluginName(const Config::Google &) const { throw std::logic_error(_C("Not supported on this system.")); } std::string Converter40::GetPluginName(const Config::KDEPim &) const { throw std::logic_error(_C("Not supported on this system.")); } std::string Converter40::GetPluginName(const Config::Unsupported &) const { throw std::logic_error(_C("Not supported on this system.")); } bool Converter40::IsConfigured(const Config::Barry &) const { return false; } bool Converter40::IsConfigured(const Config::Evolution &) const { return false; } bool Converter40::IsConfigured(const Config::Evolution3 &) const { return false; } bool Converter40::IsConfigured(const Config::Google &) const { return false; } bool Converter40::IsConfigured(const Config::KDEPim &) const { return false; } bool Converter40::IsConfigured(const Config::Unsupported &) const { return false; } Config::pst_type Converter40::GetSupportedSyncTypes(const Config::Barry &) const { return PST_NONE; } Config::pst_type Converter40::GetSupportedSyncTypes(const Config::Evolution &) const { return PST_NONE; } Config::pst_type Converter40::GetSupportedSyncTypes(const Config::Evolution3 &) const { return PST_NONE; } Config::pst_type Converter40::GetSupportedSyncTypes(const Config::Google &) const { return PST_NONE; } Config::pst_type Converter40::GetSupportedSyncTypes(const Config::KDEPim &) const { return PST_NONE; } Config::pst_type Converter40::GetSupportedSyncTypes(const Config::Unsupported &) const { return PST_NONE; } void Converter40::Load(Config::Barry &config, const Member &member) { ThrowNotSupported(); } void Converter40::Load(Config::Evolution &config, const Member &member) { ThrowNotSupported(); } void Converter40::Load(Config::Evolution3 &config, const Member &member) { ThrowNotSupported(); } void Converter40::Load(Config::Google &config, const Member &member) { ThrowNotSupported(); } void Converter40::Load(Config::KDEPim &config, const Member &member) { ThrowNotSupported(); } void Converter40::Load(Config::Unsupported &config, const Member &member) { ThrowNotSupported(); } void Converter40::Save(const Config::Barry &config, const std::string &group_name) { ThrowNotSupported(); } void Converter40::Save(const Config::Evolution &config, const std::string &group_name) { ThrowNotSupported(); } void Converter40::Save(const Config::Evolution3 &config, const std::string &group_name) { ThrowNotSupported(); } void Converter40::Save(const Config::Google &config, const std::string &group_name) { ThrowNotSupported(); } void Converter40::Save(const Config::KDEPim &config, const std::string &group_name) { ThrowNotSupported(); } void Converter40::Save(const Config::Unsupported &config, const std::string &group_name) { ThrowNotSupported(); } } barry-0.18.5/desktop/src/BaseButtons.cc0000644001161500056700000000603212242254476017255 0ustar cdfreycdfrey/// /// \file BaseButtons.cc /// Support class for BaseFrame /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "BaseButtons.h" #include "BaseFrame.h" #include "PNGButton.h" #include "windowids.h" #include "util.h" #include #include using namespace std; ////////////////////////////////////////////////////////////////////////////// // BaseButtons BaseButtons::BaseButtons(wxWindow *parent) : m_current(0) { // first, discover the size of the average button wxString file = GetButtonFilename(MainMenu_BackupAndRestore, BUTTON_STATE_NORMAL); wxImage sizer(file); m_buttonWidth = sizer.GetWidth(); m_buttonHeight = sizer.GetHeight(); for( int i = MainMenu_FirstButton; i <= MainMenu_LastButton; i++ ) { int row = (i - MainMenu_FirstButton) / 3; int col = (i - MainMenu_FirstButton) % 3; int y_offset = MAIN_HEADER_OFFSET; // skip the header PNGButton *button = new PNGButton(parent, i, col * m_buttonWidth, row * m_buttonHeight + y_offset, IsButtonEnabled(i)); m_buttons.push_back(button); } } BaseButtons::~BaseButtons() { vector::iterator b = m_buttons.begin(); for( ; b != m_buttons.end(); ++b ) { delete *b; } m_buttons.clear(); } PNGButton* BaseButtons::CalculateHit(int x, int y) { int col = x / m_buttonWidth; if( x < 0 || col < 0 || col > 2 ) return 0; int y_offset = MAIN_HEADER_OFFSET; // graphic header size int row = (y - y_offset) / m_buttonHeight; if( y < y_offset || row < 0 || row > 2 ) return 0; unsigned int index = col + row * 3; if( index >= m_buttons.size() ) return 0; return m_buttons[index]; } void BaseButtons::InitAll(wxDC &dc) { vector::iterator b = m_buttons.begin(); for( ; b != m_buttons.end(); ++b ) { (*b)->Init(dc); } } void BaseButtons::DrawAll(wxDC &dc) { vector::iterator b = m_buttons.begin(); for( ; b != m_buttons.end(); ++b ) { (*b)->Draw(dc); } } void BaseButtons::HandleMotion(wxDC &dc, int x, int y) { PNGButton *hit = CalculateHit(x, y); if( hit != m_current ) { // clean up old hit if( m_current ) { m_current->Normal(dc); } m_current = hit; // draw the new state if( m_current ) m_current->Focus(dc); } } void BaseButtons::HandleDown(wxDC &dc, int x, int y) { HandleMotion(dc, x, y); if( m_current ) { m_current->Push(dc); } } void BaseButtons::HandleUp(wxDC &dc, int x, int y) { HandleMotion(dc, x, y); if( m_current && m_current->IsPushed() ) { m_current->Click(dc); } } barry-0.18.5/desktop/src/osbase.h0000644001161500056700000002554412242254476016153 0ustar cdfreycdfrey/// /// \file osbase.h /// Base API class for OpenSync interaction. /// This API will operate both 0.22 and 0.4x /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_OSBASE_H__ #define __BARRYDESKTOP_OSBASE_H__ #include #include #include #include #include "ostypes.h" namespace OpenSync { struct Member { std::string group_name; long id; std::string friendly_name; // may not always have a name std::string plugin_name; }; struct MemberSet : public std::vector { Member* Find(long id); Member* Find(const char *plugin_name); long FindId(const char *plugin_name); // returns -1 if not found }; struct Format { std::string name; std::string object_type; }; struct FormatSet : public std::vector { Format* Find(const char *name); }; typedef std::vector string_list_type; typedef MemberSet member_list_type; typedef FormatSet format_list_type; std::ostream& operator<< (std::ostream &os, const string_list_type &list); std::ostream& operator<< (std::ostream &os, const Member &member); std::ostream& operator<< (std::ostream &os, const member_list_type &list); std::ostream& operator<< (std::ostream &os, const Format &format); std::ostream& operator<< (std::ostream &os, const format_list_type &list); class SyncConflictPrivateBase; struct SyncChange { int id; long member_id; std::string plugin_name; std::string uid; std::string printable_data; }; class SyncConflict : public std::vector { SyncConflictPrivateBase &m_conflict; public: SyncConflict(SyncConflictPrivateBase &conflict); ~SyncConflict(); bool IsAbortSupported() const; bool IsIgnoreSupported() const; bool IsKeepNewerSupported() const; std::string GetMenu() const; void Select(int change_id); // takes the id field of SyncChange void Abort(); void Duplicate(); void Ignore(); void KeepNewer(); std::ostream& Dump(std::ostream &os) const; }; inline std::ostream& operator<< (std::ostream &os, const SyncConflict &conflict) { return conflict.Dump(os); } class SyncSummaryPrivateBase; struct SyncMemberSummary { int id; std::string objtype_name; long member_id; std::string plugin_name; unsigned long added; unsigned long modified; unsigned long deleted; SyncMemberSummary() : added(0), modified(0), deleted(0) {} }; class SyncSummary : public std::vector { SyncSummaryPrivateBase &m_summary; public: SyncSummary(SyncSummaryPrivateBase &summary); ~SyncSummary(); void Abort(); void Continue(); std::ostream& Dump(std::ostream &os) const; }; inline std::ostream& operator<< (std::ostream &os, const SyncSummary &summary) { return summary.Dump(os); } // notes: OpenSync::SyncStatus is a base class with all the opensync // callbacks as virtual functions, with reasonable defaults. The // programmer can override any callbacks he so chooses as below. // // If a callback has state or information or requires a decision, it // passes in a reference to a base class (example below: SyncConflict). // This base class is really a reference to a derived class specific // to the 0.22 or 0.4x library API, and contains pointers to the // OpenSync40 or OpenSync22 classes and private structs, and handles // all cleanup of the state it holds. Also, these classes hold // information in C++ style variables... for example SyncConflict // will hold a vector of objects that contain the osync change // information of each conflicting change, as well as a means to // access a pretty printed version. No OpenSync constants will // be used in these objects. // // If abstracted enough, the override code should be dead simple, // like below, and also be generic enough to run on both 0.22 and // 0.4x libraries, dynamically. :-D // class SyncStatus { public: virtual ~SyncStatus(); // virtual overrides virtual void HandleConflict(OpenSync::SyncConflict &conflict); virtual void EntryStatus(const std::string &msg, bool error); virtual void MappingStatus(const std::string &msg, bool error); virtual void EngineStatus(const std::string &msg, bool error, bool slowsync); virtual void MemberStatus(long member_id, const std::string &plugin_name, const std::string &msg, bool error); virtual void CheckSummary(OpenSync::SyncSummary &summary); virtual void ReportError(const std::string &msg); }; // forward declarations for the Converter class namespace Config { class Plugin; class Barry; class Evolution; class Evolution3; class Google; class KDEPim; class Unsupported; } // // Converter // /// Base class for the converter api, which converts from/to a data-holding /// plugin configuration class to/from the API. /// /// For 0.22, it will manually write the config fields into a std::string /// suitable for a call to API::SetConfiguration(), and then call /// SetConfiguration() itself. /// /// For 0.4x, it may do the same thing, or might use the new 0.4x calls /// to set the individual fields through the low level opensync API. /// /// The API class creates an instance of a matching derived class /// (for 0.22 or 0.4x, per the API itself), and returns a pointer /// whenever asked. /// class Converter { public: typedef std::tr1::shared_ptr plugin_ptr; public: virtual ~Converter() {} virtual bool IsPluginSupported(const std::string &plugin_name, std::string *appname = 0) const = 0; virtual plugin_ptr CreateAndLoadPlugin(const Member &member) = 0; virtual std::string GetPluginName(const Config::Barry &) const = 0; virtual std::string GetPluginName(const Config::Evolution &) const = 0; virtual std::string GetPluginName(const Config::Evolution3 &) const = 0; virtual std::string GetPluginName(const Config::Google &) const = 0; virtual std::string GetPluginName(const Config::KDEPim &) const = 0; virtual std::string GetPluginName(const Config::Unsupported &) const = 0; virtual bool IsConfigured(const Config::Barry &) const = 0; virtual bool IsConfigured(const Config::Evolution &) const = 0; virtual bool IsConfigured(const Config::Evolution3 &) const = 0; virtual bool IsConfigured(const Config::Google &) const = 0; virtual bool IsConfigured(const Config::KDEPim &) const = 0; virtual bool IsConfigured(const Config::Unsupported &) const = 0; virtual Config::pst_type GetSupportedSyncTypes(const Config::Barry &) const = 0; virtual Config::pst_type GetSupportedSyncTypes(const Config::Evolution &) const = 0; virtual Config::pst_type GetSupportedSyncTypes(const Config::Evolution3 &) const = 0; virtual Config::pst_type GetSupportedSyncTypes(const Config::Google &) const = 0; virtual Config::pst_type GetSupportedSyncTypes(const Config::KDEPim &) const = 0; virtual Config::pst_type GetSupportedSyncTypes(const Config::Unsupported &) const = 0; virtual void Load(Config::Barry &config, const Member &member) = 0; virtual void Load(Config::Evolution &config, const Member &member) = 0; virtual void Load(Config::Evolution3 &config, const Member &member) = 0; virtual void Load(Config::Google &config, const Member &member) = 0; virtual void Load(Config::KDEPim &config, const Member &member) = 0; virtual void Load(Config::Unsupported &config, const Member &member) = 0; virtual void Save(const Config::Barry &config, const std::string &group_name) = 0; virtual void Save(const Config::Evolution &config, const std::string &group_name) = 0; virtual void Save(const Config::Evolution3 &config, const std::string &group_name) = 0; virtual void Save(const Config::Google &config, const std::string &group_name) = 0; virtual void Save(const Config::KDEPim &config, const std::string &group_name) = 0; virtual void Save(const Config::Unsupported &config, const std::string &group_name) = 0; }; class API { public: API() { } virtual ~API() { } // Functional abilities information... this does not come from // the engine itself, but is information the osbase library // determines useful for applications to know virtual bool IsSlowSyncSupported() const = 0; // General engine information virtual const char* GetVersion() const = 0; virtual const char* GetEngineName() const = 0; // "0.22" or "0.40", etc virtual void GetPluginNames(string_list_type &plugins) = 0; virtual void GetFormats(format_list_type &formats) = 0; // Information about configured groups virtual void GetGroupNames(string_list_type &groups) = 0; virtual void GetMembers(const std::string &group_name, member_list_type &members) = 0; // Group configuration virtual void AddGroup(const std::string &group_name) = 0; virtual void DeleteGroup(const std::string &group_name) = 0; // Plugin configuration helper virtual Converter& GetConverter() = 0; // Member configuration // AddMember() returns new member_id? virtual long AddMember(const std::string &group_name, const std::string &plugin_name, const std::string &member_name) = 0; virtual bool IsConfigurable(const std::string &group_name, long member_id) = 0; virtual std::string GetConfiguration(const std::string &group_name, long member_id) = 0; virtual void SetConfiguration(const std::string &group_name, long member_id, const std::string &config_data) = 0; virtual void Discover(const std::string &group_name) = 0; // Syncing // // API Note: we put the sync_types here, and not in a special // API of its own, since 0.22 does not save this state, and // while 0.4x does, it is not easy to determine whether every // member in the group is configured the same... so we do it on // the fly during the sync process, and we don't save the state. // // Therefore it is possible that you can disable an objtype in // a 0.4x config, and sync here with it enabled, and the config // files will remain the same! This could be confusing for debugging, // make sure you compare the barry config with the opensync config // when debugging sync issues. // virtual void Sync(const std::string &group_name, SyncStatus &status_callback, Config::pst_type sync_types/* = PST_DO_NOT_SET*/) = 0; }; class APISet : private std::vector { typedef std::vector base_type; public: APISet(); ~APISet(); void OpenAll(); // throws if not all can be opened int OpenAvailable(); // opens only what is available and // returns # of APIs successfully loaded. // throws if some already loaded int GetAvailable() const;// returns # of APIs successfully loaded API* os40(); API* os22(); }; } // namespace OpenSync #endif barry-0.18.5/desktop/src/null-os22.cc0000644001161500056700000001441412242254476016564 0ustar cdfreycdfrey/// /// \file null-os22.cc /// Null wrapper class for when opensync 0.22 is not available /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "os22.h" #include "osconv22.h" #include "i18n.h" namespace OpenSync { static void ThrowNotSupported() { throw std::logic_error(_C("Not supported on this system.")); } ///////////////////////////////////////////////////////////////////////////// // OpenSync22 - public members bool OpenSync22::symbols_loaded = false; OpenSync22::OpenSync22() { throw std::runtime_error(_C("OpenSync 0.22 support was not compiled in.")); } OpenSync22::~OpenSync22() { } ///////////////////////////////////////////////////////////////////////////// // Null implementations const char* OpenSync22::GetVersion() const { return 0; } const char* OpenSync22::GetEngineName() const { return "0.22"; } void OpenSync22::GetPluginNames(string_list_type &plugins) { } void OpenSync22::GetFormats(format_list_type &formats) { } void OpenSync22::GetGroupNames(string_list_type &groups) { } void OpenSync22::GetMembers(const std::string &group_name, member_list_type &members) { } void OpenSync22::AddGroup(const std::string &group_name) { } void OpenSync22::DeleteGroup(const std::string &group_name) { } Converter& OpenSync22::GetConverter() { throw std::logic_error(_C("Not supported on this system.")); } long OpenSync22::AddMember(const std::string &group_name, const std::string &plugin_name, const std::string &member_name) { return 0; } bool OpenSync22::IsConfigurable(const std::string &group_name, long member_id) { return false; } std::string OpenSync22::GetConfiguration(const std::string &group_name, long member_id) { return ""; } void OpenSync22::SetConfiguration(const std::string &group_name, long member_id, const std::string &config_data) { } void OpenSync22::Discover(const std::string &group_name) { } void OpenSync22::Sync(const std::string &group_name, SyncStatus &status_callback, Config::pst_type sync_types) { } ////////////////////////////////////////////////////////////////////////////// // Null Converter class Converter22::Converter22(OpenSync::API &api) : m_api(api) { } bool Converter22::IsPluginSupported(const std::string &plugin_name, std::string *appname) const { return false; } Converter::plugin_ptr Converter22::CreateAndLoadPlugin(const Member &member) { return Converter::plugin_ptr(); } std::string Converter22::GetPluginName(const Config::Barry &) const { throw std::logic_error(_C("Not supported on this system.")); } std::string Converter22::GetPluginName(const Config::Evolution &) const { throw std::logic_error(_C("Not supported on this system.")); } std::string Converter22::GetPluginName(const Config::Evolution3 &) const { throw std::logic_error(_C("Not supported on this system.")); } std::string Converter22::GetPluginName(const Config::Google &) const { throw std::logic_error(_C("Not supported on this system.")); } std::string Converter22::GetPluginName(const Config::KDEPim &) const { throw std::logic_error(_C("Not supported on this system.")); } std::string Converter22::GetPluginName(const Config::Unsupported &) const { throw std::logic_error(_C("Not supported on this system.")); } bool Converter22::IsConfigured(const Config::Barry &) const { return false; } bool Converter22::IsConfigured(const Config::Evolution &) const { return false; } bool Converter22::IsConfigured(const Config::Evolution3 &) const { return false; } bool Converter22::IsConfigured(const Config::Google &) const { return false; } bool Converter22::IsConfigured(const Config::KDEPim &) const { return false; } bool Converter22::IsConfigured(const Config::Unsupported &) const { return false; } Config::pst_type Converter22::GetSupportedSyncTypes(const Config::Barry &) const { return PST_NONE; } Config::pst_type Converter22::GetSupportedSyncTypes(const Config::Evolution &) const { return PST_NONE; } Config::pst_type Converter22::GetSupportedSyncTypes(const Config::Evolution3 &) const { return PST_NONE; } Config::pst_type Converter22::GetSupportedSyncTypes(const Config::Google &) const { return PST_NONE; } Config::pst_type Converter22::GetSupportedSyncTypes(const Config::KDEPim &) const { return PST_NONE; } Config::pst_type Converter22::GetSupportedSyncTypes(const Config::Unsupported &) const { return PST_NONE; } void Converter22::Load(Config::Barry &config, const Member &member) { ThrowNotSupported(); } std::string Converter22::GrabField(const std::string &cfg, const std::string &name) { throw std::logic_error(_C("Not supported on this system.")); } void Converter22::Load(Config::Evolution &config, const Member &member) { ThrowNotSupported(); } void Converter22::Load(Config::Evolution3 &config, const Member &member) { ThrowNotSupported(); } void Converter22::Load(Config::Google &config, const Member &member) { ThrowNotSupported(); } void Converter22::Load(Config::KDEPim &config, const Member &member) { ThrowNotSupported(); } void Converter22::Load(Config::Unsupported &config, const Member &member) { ThrowNotSupported(); } void Converter22::Save(const Config::Barry &config, const std::string &group_name) { ThrowNotSupported(); } void Converter22::Save(const Config::Evolution &config, const std::string &group_name) { ThrowNotSupported(); } void Converter22::Save(const Config::Evolution3 &config, const std::string &group_name) { ThrowNotSupported(); } void Converter22::Save(const Config::Google &config, const std::string &group_name) { ThrowNotSupported(); } void Converter22::Save(const Config::KDEPim &config, const std::string &group_name) { ThrowNotSupported(); } void Converter22::Save(const Config::Unsupported &config, const std::string &group_name) { ThrowNotSupported(); } } barry-0.18.5/desktop/src/SyncStatusDlg.h0000644001161500056700000001117012242254476017434 0ustar cdfreycdfrey/// /// \file SyncStatusDlg.h /// The dialog used during a sync, to display status messages /// and error messages, and handle sync conflicts via callback. /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_SYNCSTATUSDLG_H__ #define __BARRYDESKTOP_SYNCSTATUSDLG_H__ #include #include "ipc.h" #include "osbase.h" #include "deviceset.h" #include "exechelper.h" #include "optout.h" #include "configui.h" #include "ConflictDlg.h" class SyncStatusDlg; class StatusConnection : public wxConnection, public OptOut::Element { SyncStatusDlg &m_dlg; wxTextCtrl &m_status; public: StatusConnection(SyncStatusDlg &dlg, wxTextCtrl &window); bool OnPoke(const wxString &topic, const wxString &item, wxChar *data, int size, wxIPCFormat format); // wxWidgets bug override - stop the 'delete this' behaviour, // since sometimes events seem to come through after // the delete... not sure why, and hard to debug. // This is with wxWidgets 2.8.7. // // With this override, the container in SyncStatusDlg // will handle all the deleting. virtual bool OnDisconnect() { return true; } }; class ConflictConnection : public wxConnection, public OptOut::Element { SyncStatusDlg &m_dlg; SillyBuffer m_buf; // conflict state machine bool m_asking_user; int m_current_sequenceID; int m_current_offset; int m_expected_total_changes; std::string m_supported_commands; std::vector m_changes; // "always" memory ConflictDlg::AlwaysMemoryBlock m_always; public: ConflictConnection(SyncStatusDlg &dlg); bool OnPoke(const wxString &topic, const wxString &item, wxChar *data, int size, wxIPCFormat format); wxChar* OnRequest(const wxString &topic, const wxString &item, int *size, wxIPCFormat format); // wxWidgets bug override - stop the 'delete this' behaviour, // since sometimes events seem to come through after // the delete... not sure why, and hard to debug. // This is with wxWidgets 2.8.7. // // With this override, the container in SyncStatusDlg // will handle all the deleting. virtual bool OnDisconnect() { return true; } }; class SyncStatusDlg : public wxDialog , public wxServer , public TermCatcher { DECLARE_EVENT_TABLE() // sets to protected: private: // external data sources DeviceSet::subset_type m_subset; DeviceSet::subset_type::iterator m_next_device, m_current_device; // for handling bsyncjail ExecHelper m_jailexec; std::string m_device_id; bool m_killingjail; // for handling run app ConfigUI::ptr m_ui; // connection holder, to make sure they get deleted if we // go out of scope OptOut::Vector m_connections; wxTimer m_timer; // dialog controls wxSizer *m_topsizer; wxStaticText *m_short_status; wxGauge *m_throbber; wxTextCtrl *m_status_edit; wxButton *m_runapp_button, *m_syncagain_button, *m_killclose_button; wxButton *m_details_button; // state bool m_repositioned; protected: void CreateLayout(); void AddStatusSizer(wxSizer *sizer); void AddButtonSizer(wxSizer *sizer); // set buttons to "running" state void SetRunning(); // set buttons to "close" state void SetClose(); void UpdateTitle(); void UpdateLastSyncTime(); public: SyncStatusDlg(wxWindow *parent, const DeviceSet::subset_type &subset); ~SyncStatusDlg(); // operations void KillSync(); void StartNextSync(); void PrintStd(const std::string &msg, const wxColour &colour); void Print(const wxString &msg, const wxColour &colour); void ShortPrintStd(const std::string &msg); void ShortPrint(const wxString &msg); void Throb(); void StartTimer(); void StopTimer(); DeviceEntry* GetCurrentDevice(); // event handlers void OnSlowSync(); // called from StatusConnection void OnInitDialog(wxInitDialogEvent &event); void OnRunApp(wxCommandEvent &event); void OnSyncAgain(wxCommandEvent &event); void OnKillClose(wxCommandEvent &event); void OnShowDetails(wxCommandEvent &event); void OnExecTerminated(wxProcessEvent &event); void OnTimer(wxTimerEvent &event); // virtual overrides from wxServer wxConnectionBase* OnAcceptConnection(const wxString &topic); }; #endif barry-0.18.5/desktop/src/Mode_Sync.cc0000644001161500056700000005345112242254476016713 0ustar cdfreycdfrey/// /// \file Mode_Sync.cc /// Mode derived class for syncing /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "Mode_Sync.h" #include "BaseFrame.h" #include "GroupCfgDlg.h" #include "SyncStatusDlg.h" #include "barrydesktop.h" #include "windowids.h" #include using namespace std; BEGIN_EVENT_TABLE(SyncMode, wxEvtHandler) EVT_BUTTON (SyncMode_SyncNowButton, SyncMode::OnSyncNow) EVT_BUTTON (SyncMode_ConfigureButton, SyncMode::OnConfigure) EVT_BUTTON (SyncMode_RunAppButton, SyncMode::OnRunApp) EVT_BUTTON (SyncMode_1WayResetButton, SyncMode::On1WayReset) EVT_LIST_ITEM_SELECTED(SyncMode_DeviceList, SyncMode::OnListSelChange) EVT_LIST_ITEM_DESELECTED(SyncMode_DeviceList, SyncMode::OnListSelChange) EVT_LIST_ITEM_ACTIVATED(SyncMode_DeviceList, SyncMode::OnConfigureDevice) END_EVENT_TABLE() ////////////////////////////////////////////////////////////////////////////// // SyncMode SyncMode::SyncMode(wxWindow *parent) : m_parent(parent) { wxBusyCursor wait; wxSize client_size = parent->GetClientSize(); // create our list of devices m_device_set.reset( new DeviceSet(wxGetApp().GetGlobalConfig(), wxGetApp().GetOpenSync(), wxGetApp().GetResults()) ); barryverbose(*m_device_set); // eliminate all duplicate device entries DeviceSet::subset_type subset; do { subset = m_device_set->FindDuplicates(); if( subset.size() ) { // build list of choices wxArrayString choices; DeviceSet::subset_type::iterator i = subset.begin(); for( ; i != subset.end(); ++i ) { string desc = (*i)->GetIdentifyingString(); choices.Add( wxString(desc.c_str(), wxConvUTF8) ); } // let the user choose // FIXME - the width of the choice dialog is // determined by the length of the string... // which is less than ideal int choice = wxGetSingleChoiceIndex(_W("Multiple configurations have been found with the same PIN. Please select\nthe configuration that Barry Desktop should work with."), _T("Duplicate PIN"), choices, parent); // remove everything except keep if( choice != -1 ) { subset.erase(subset.begin() + choice); } m_device_set->KillDuplicates(subset); barryverbose(*m_device_set); } } while( subset.size() ); // // create the window controls we need // m_topsizer.reset( new wxBoxSizer(wxVERTICAL) ); // make space for the main header, which is not part of our // work area m_topsizer->AddSpacer(MAIN_HEADER_OFFSET); // add status area // // Select the device(s) you want to sync and press Sync Now // Press Configure... to configure the currently selected device // Press Run App to start the application that the device syncs with // Press 1-Way Reset to recover from a broken sync, copying all // device data to application, or vice versa. // m_topsizer->AddSpacer(5); m_sync_now_button.reset( new wxButton(parent, SyncMode_SyncNowButton, _T("Sync Now"))); wxSize sync_button_size = m_sync_now_button->GetClientSize(); int wrapwidth = client_size.GetWidth() - 20 - sync_button_size.GetWidth(); wxBoxSizer *infosizer = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *linesizer = new wxBoxSizer(wxVERTICAL); // info lines #define MAKE_INFO_LABEL(a, b) \ m_label[a].reset( new wxStaticText(parent, -1, b, \ wxPoint(15, 100)) ); \ m_label[a]->Wrap(wrapwidth); \ linesizer->Add(m_label[a].get(), 0, wxEXPAND, 0); \ linesizer->AddSpacer(4); MAKE_INFO_LABEL(0, _W("Select the device(s) you want to sync and press Sync Now.")); MAKE_INFO_LABEL(1, _W("Use Configure to configure the currently selected device.")); MAKE_INFO_LABEL(2, _W("Use Run App to start the application that the device syncs with.")); MAKE_INFO_LABEL(3, _W("Use 1-Way Reset to recover from a broken sync, copying all device data to application, or vice versa.")); infosizer->Add( linesizer, 1, wxALIGN_LEFT, 0 ); infosizer->Add( m_sync_now_button.get(), 0, wxALIGN_RIGHT, 0 ); m_topsizer->Add( infosizer, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxRIGHT, 10 ); // status, final spacing m_topsizer->AddSpacer(10); // add device list wxStaticBoxSizer *box = new wxStaticBoxSizer(wxHORIZONTAL, parent, _W("Device List")); m_device_list.reset (new wxListCtrl(parent, SyncMode_DeviceList, wxDefaultPosition, wxDefaultSize, wxLC_REPORT /*| wxLC_VRULES*/) ); box->Add( m_device_list.get(), 1, wxEXPAND | wxALL, 4 ); m_topsizer->Add(box, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 10 ); // add bottom buttons - these go in the bottom FOOTER area // so their heights must be fixed to MAIN_HEADER_OFFSET // minus a border of 5px top and bottom wxSize footer(-1, MAIN_HEADER_OFFSET - 5 - 5); wxBoxSizer *buttons = new wxBoxSizer(wxHORIZONTAL); m_run_app_button.reset( new wxButton(parent, SyncMode_RunAppButton, _W("Run App"), wxDefaultPosition, footer)); m_configure_button.reset( new wxButton(parent, SyncMode_ConfigureButton, _W("Configure..."), wxDefaultPosition, footer) ); m_1way_reset_button.reset( new wxButton(parent, SyncMode_1WayResetButton, _W("1 Way Reset..."), wxDefaultPosition, footer) ); buttons->Add(m_run_app_button.get(), 0, wxRIGHT, 5 ); buttons->Add(m_configure_button.get(), 0, wxRIGHT, 5 ); buttons->Add(m_1way_reset_button.get(), 0, wxRIGHT, 5 ); m_topsizer->Add(buttons, 0, wxALL | wxALIGN_RIGHT, 5 ); // recalc size of children m_topsizer->SetDimension(0, 0, client_size.GetWidth(), client_size.GetHeight()); // insert list columns based on the new list size wxSize list_size = m_device_list->GetSize(); int timestamp_width = GetMaxTimestampWidth(m_device_list.get()); // FIXME - for some reason, even with the width calculated, // when displayed in the listctrl, there's not enough space... // possibly because there's space between columns... I don't // know how to calculate the column inter-space size, so add // a constant here :-( timestamp_width += 8; int usable_width = list_size.GetWidth() - timestamp_width; m_device_list->InsertColumn(0, _W("PIN"), wxLIST_FORMAT_LEFT, usable_width * 0.16); m_device_list->InsertColumn(1, _W("Name"), wxLIST_FORMAT_LEFT, usable_width * 0.33); m_device_list->InsertColumn(2, _W("Connected"), wxLIST_FORMAT_CENTRE, usable_width * 0.16); m_device_list->InsertColumn(3, _W("Application"), wxLIST_FORMAT_CENTRE, usable_width * 0.18); m_device_list->InsertColumn(4, _W("Engine"), wxLIST_FORMAT_CENTRE, usable_width * 0.17); m_device_list->InsertColumn(5, _W("Last Sync"), wxLIST_FORMAT_CENTRE, timestamp_width); FillDeviceList(); // attempt to re-select the devices as we last saw them ReselectDevices(m_device_set->String2Subset(wxGetApp().GetGlobalConfig().GetKey("SelectedDevices"))); UpdateButtons(); // connect ourselves to the parent's event handling chain // do this last, so that we are guaranteed our destructor // will run, in case of exceptions m_parent->PushEventHandler(this); } SyncMode::~SyncMode() { m_parent->PopEventHandler(); // save selected devices for later wxGetApp().GetGlobalConfig().SetKey("SelectedDevices", DeviceSet::Subset2String(GetSelectedDevices())); } std::string SyncMode::Timestamp(time_t last_sync) { string ret; struct tm local; if( localtime_r(&last_sync, &local) != NULL ) { char timestamp[20]; strftime(timestamp, sizeof(timestamp), "%b %d, %H:%M", &local); ret = timestamp; } return ret; } int SyncMode::GetMaxTimestampWidth(wxWindow *win) { int max_width = 0; DeviceSet::const_iterator i = m_device_set->begin(); for( ; i != m_device_set->end(); ++i ) { int this_width = 0; int this_height = 0; if( i->GetExtras() ) { time_t last_sync = i->GetExtras()->m_last_sync_time; if( last_sync ) { win->GetTextExtent(wxString(Timestamp(last_sync).c_str(), wxConvUTF8), &this_width, &this_height); } } max_width = max(max_width, this_width); } return max_width; } void SyncMode::FillDeviceList() { // start fresh m_device_list->DeleteAllItems(); DeviceSet::const_iterator i = m_device_set->begin(); for( int index = 0; i != m_device_set->end(); ++i, index++ ) { // PIN number wxString text(i->GetPin().Str().c_str(), wxConvUTF8); long item = m_device_list->InsertItem(index, text); // Device name text = wxString(i->GetDeviceName().c_str(), wxConvUTF8); m_device_list->SetItem(item, 1, text); // Connected? text = i->IsConnected() ? _W("Yes") : _W("No"); m_device_list->SetItem(item, 2, text); // Configured? if( i->IsConfigured() ) { text = wxString(i->GetAppNames().c_str(), wxConvUTF8); } else { text = _W("(No config)"); } m_device_list->SetItem(item, 3, text); // Engine if( i->GetEngine() ) text = wxString(i->GetEngine()->GetVersion(), wxConvUTF8); else text = _T(""); m_device_list->SetItem(item, 4, text); // Last Sync if( i->GetExtras() ) { time_t last_sync = i->GetExtras()->m_last_sync_time; if( last_sync ) { wxString ts(Timestamp(last_sync).c_str(), wxConvUTF8); m_device_list->SetItem(item, 5, ts); } } } UpdateButtons(); } void SyncMode::UpdateButtons() { int selected_count = m_device_list->GetSelectedItemCount(); // update the SyncNow button (only on if anything is selected) m_sync_now_button->Enable(selected_count > 0); m_configure_button->Enable(selected_count == 1); m_run_app_button->Enable(selected_count == 1); m_1way_reset_button->Enable(selected_count == 1); // if only one item is selected, enable RunApp button bool enable_run_app = false; if( selected_count == 1 ) { // good, only one is selected, find out which one long item = -1; item = m_device_list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if( item != -1 ) { DeviceEntry &entry = (*m_device_set)[item]; if( entry.GetAppNames().size() ) { // has application configured! enable_run_app = true; } } } m_run_app_button->Enable(enable_run_app); } DeviceSet::subset_type SyncMode::GetSelectedDevices() { DeviceSet::subset_type subset; long item = -1; do { item = m_device_list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if( item != -1 ) { subset.push_back(m_device_set->begin() + item); } } while( item != -1 ); return subset; } void SyncMode::ReselectDevices(const DeviceSet::subset_type &set) { for( long item = m_device_list->GetNextItem(-1); item != -1; item = m_device_list->GetNextItem(item) ) { bool selected = DeviceSet::FindPin(set, (*m_device_set)[item].GetPin()) != set.end(); m_device_list->SetItemState(item, selected ? wxLIST_STATE_SELECTED : 0, wxLIST_STATE_SELECTED); } } void SyncMode::ConfigureDevice(int device_index) { DeviceEntry &entry = (*m_device_set)[device_index]; ConfigureDevice(entry); } void SyncMode::ConfigureDevice(DeviceEntry &entry) { // make sure it's not already running if( m_cui.get() && m_cui->IsAppRunning() ) { wxMessageBox(_W("An application is currently running."), _W("Run App Error"), wxOK | wxICON_ERROR, m_parent); return; } GroupCfgDlg dlg(m_parent, entry, wxGetApp().GetOpenSync()); if( dlg.ShowModal() == wxID_OK && dlg.GetEngine() && dlg.GetGroup().get() && dlg.GetExtras().get() ) { bool skip_rewrite = false; bool delete_old = false; // does old group exist? if( entry.GetEngine() && entry.GetConfigGroup() && entry.GetConfigGroup()->GroupExists(*entry.GetEngine()) ) { // yes, is the new group equal? string v1 = entry.GetEngine()->GetVersion(); string v2 = dlg.GetEngine()->GetVersion(); skip_rewrite = (v1 == v2 && dlg.GetGroup()->Compare(*entry.GetConfigGroup())); if( skip_rewrite ) { // config is the same, don't bother saving again barryverbose(_C("Config is the same, skipping save")); } else { // clean up after ourselves... if the new // config uses a different engine, delete // the config on the old engine if( entry.GetEngine() != dlg.GetEngine() ) { delete_old = true; } } } if( !skip_rewrite ) try { OpenSync::API *eng = dlg.GetEngine(); DeviceEntry::group_ptr grp = dlg.GetGroup(); // make sure that the save will be successful if( grp->GroupExists(*eng) ) { if( !grp->GroupMatchesExistingConfig(*eng) ) { if( WarnAbout1WayReset() ) { eng->DeleteGroup(grp->GetGroupName()); grp->DisconnectMembers(); } else { // skip save return; } } else { // group we want to save has the // same set of plugins and member IDs // as the one already there... // so do not disconnect members } } else { // we are saving a brand new group, so make // sure that all members are new grp->DisconnectMembers(); } // save the new one grp->Save(*dlg.GetEngine()); // clean up the old engine's group, so we don't leave // garbage behind... do this after a successful // save, so that we don't delete existing knowledge // before we've crossed over if( delete_old ) { barryverbose("Engine change detected in config: deleting old config '" << entry.GetConfigGroup()->GetGroupName() << "' from engine " << entry.GetEngine()->GetVersion() << " in order to save it to engine " << dlg.GetEngine()->GetVersion()); entry.GetEngine()->DeleteGroup(entry.GetConfigGroup()->GetGroupName()); } } catch( OpenSync::Config::SaveError &se ) { barryverbose("Exception during save: " << se.what()); wxString msg = _W("Unable to save configuration for this device.\nError: "); msg += wxString(se.what(), wxConvUTF8); wxMessageBox(msg, _W("OpenSync Save Error"), wxOK | wxICON_ERROR, m_parent); return; } // save the extras... this is cheap, so no need to check // skip_rewrite dlg.GetExtras()->Save(wxGetApp().GetGlobalConfig(), dlg.GetGroup()->GetGroupName()); // update the device set entry.SetConfigGroup(dlg.GetGroup(), dlg.GetEngine(), dlg.GetExtras()); entry.SetDeviceName(dlg.GetDeviceName()); // update! RefillList(); } } void SyncMode::CheckConfigured(DeviceSet::subset_type &subset) { for( DeviceSet::subset_type::iterator i = subset.begin(); i != subset.end(); ++i ) { DeviceEntry &device = *(*i); if( !device.IsConnected() ) continue; if( device.IsConfigured() ) continue; wxString msg = wxString::Format( // TRANSLATORS: first %s is the PIN number, and // the second (in parentheses) is the device name. _W("Selected device %s (%s) is not yet configured. Configure now?"), wxString(device.GetPin().Str().c_str(), wxConvUTF8).c_str(), wxString(device.GetDeviceName().c_str(), wxConvUTF8).c_str()); int response = wxMessageBox(msg, _W("Configure Now?"), wxYES_NO, m_parent); if( response == wxYES ) { ConfigureDevice(device); } } } void SyncMode::RefillList() { DeviceSet::subset_type subset = GetSelectedDevices(); FillDeviceList(); ReselectDevices(subset); } int SyncMode::GetSelectedDevice() { if( m_device_list->GetSelectedItemCount() != 1 ) { wxMessageBox(_W("Please select one device from the list."), _W("Device List"), wxOK | wxICON_ERROR, m_parent); return -1; } // find selected device long item = -1; item = m_device_list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); return item; } // // Returns an index into the config group for the given device index // that represents the authoritative side of the sync. This means // that during the 1-Way Reset, the plugin at this index must NOT // be zapped! All the others must be zapped. // // Returns -1 if the user cancels, or if not enough data to decide. // int SyncMode::GetAuthoritativeSide(int device_index) { // grab the device entry and group config DeviceEntry &entry = (*m_device_set)[device_index]; OpenSync::Config::Group *group = entry.GetConfigGroup(); if( !group ) return -1; // build message wxString intro(_W( "Which device / application should be considered\n" "authoritative?\n" "\n" "All data in non-authoritative devices / applications\n" "will be deleted in order to setup a straight copy on\n" "the next sync.")); // build list of devices / applications wxArrayString list; OpenSync::Config::Group::iterator gi = group->begin(); for( ; gi != group->end(); ++gi ) { // the Barry plugin is special if( dynamic_cast( (*gi).get() ) ) { // this is a Barry plugin, so display the // device name, not the plugin name string device_name = entry.GetPin().Str(); if( entry.GetDeviceName().size() ) device_name += " (" + entry.GetDeviceName() + ")"; list.Add( wxString(device_name.c_str(), wxConvUTF8) ); } else { // add the application name list.Add( wxString((*gi)->GetAppName().c_str(), wxConvUTF8) ); } } // ask the user int choice = wxGetSingleChoiceIndex(intro, _W("Select Authoritative Device / Application"), list, m_parent); return choice; } bool SyncMode::ZapConflicts(int device_index, int authoritative_side) { // grab the device entry and group config DeviceEntry &entry = (*m_device_set)[device_index]; OpenSync::Config::Group *group = entry.GetConfigGroup(); if( !group ) return false; // cycle through list of sync plugins, zapping each // non-authoritative one OpenSync::Config::Group::iterator gi = group->begin(); for( int i = 0; gi != group->end(); ++gi, ++i ) { // skip the authoritative plugin! if( i == authoritative_side ) continue; OpenSync::Config::Plugin &plugin = *(*gi); // create a configUI object, for zapping ConfigUI::ptr ui = ConfigUI::CreateConfigUI(plugin.GetAppName()); if( !ui.get() ) { // no possibility for zapping here... so just // assume that it doesn't need it for now... // worst that can happen, should be it slow-syncs // all the time continue; } bool success = ui->ZapData(m_parent, *gi, entry.GetEngine()); if( !success ) { // if the user cancels one, cancel all the rest return false; } } // if we reach this, we succeeded return true; } void SyncMode::RewriteConfig(int device_index) { // grab the device entry and group config DeviceEntry &entry = (*m_device_set)[device_index]; OpenSync::Config::Group *group = entry.GetConfigGroup(); OpenSync::API *engine = entry.GetEngine(); if( !group || !engine ) return; string group_name = group->GetGroupName(); try { // delete the existing group name engine->DeleteGroup(group_name); // disconnect the plugins from the group, to // make them "new" again group->DisconnectMembers(); // save group->Save(*engine); // success! barryverbose(group_name << " group config rewritten"); return; } catch( std::runtime_error &re ) { ostringstream oss; oss << _C("Unable to rewrite config! Start over manually. " "Error: ") << re.what(); wxString msg(oss.str().c_str(), wxConvUTF8); wxMessageBox(msg, _W("Error Rewriting Config"), wxOK | wxICON_ERROR, m_parent); } // if we get here, the group is in an undefined state, // so delete it to make sure nothing odd is left behind try { engine->DeleteGroup(group_name); } catch( std::runtime_error &re ) { barryverbose("Error while deleting undefined group '" << group_name << "': " << re.what()); } } bool SyncMode::WarnAbout1WayReset() { int answer = wxMessageBox( _W("The sync config you are about to save " "is sufficiently different from the existing one that " "a 1-Way Reset will be required. You will need to " "perform the reset at your earliest convenience, before " "your next sync.\n\n" "Continue anyway?"), _W("1-Way Reset Warning"), wxYES_NO | wxICON_QUESTION, m_parent); return answer == wxYES; } void SyncMode::OnSyncNow(wxCommandEvent &event) { DeviceSet::subset_type subset = GetSelectedDevices(); if( subset.size() == 0 ) return; // nothing to do // make sure an app is not running if( m_cui.get() && m_cui->IsAppRunning() ) { wxMessageBox(_W("An application is currently running."), _W("Sync Error"), wxOK | wxICON_ERROR, m_parent); return; } // check that all selections are configured CheckConfigured(subset); // do the sync SyncStatusDlg dlg(m_parent, subset); dlg.ShowModal(); // update the timestamps RefillList(); } void SyncMode::OnConfigure(wxCommandEvent &event) { int item = GetSelectedDevice(); if( item != -1 ) ConfigureDevice(item); } void SyncMode::OnRunApp(wxCommandEvent &event) { // make sure it's not already running if( m_cui.get() && m_cui->IsAppRunning() ) { wxMessageBox(_W("An application is already running."), _W("Run App Error"), wxOK | wxICON_ERROR, m_parent); return; } // find selected device int item = GetSelectedDevice(); if( item == -1 ) return; // retrieve device's group config DeviceEntry &entry = (*m_device_set)[item]; OpenSync::Config::Plugin *plugin = 0; if( entry.GetConfigGroup() ) plugin = entry.GetConfigGroup()->GetNonBarryPlugin(); if( !plugin ) return; // run the app m_cui = ConfigUI::CreateConfigUI(plugin->GetAppName()); if( m_cui.get() ) m_cui->RunApp(m_parent); } void SyncMode::On1WayReset(wxCommandEvent &event) { int item = GetSelectedDevice(); if( item == -1 ) return; // let user pick the authoritative side of the sync int side = GetAuthoritativeSide(item); if( side == -1 ) return; // zap the data of all remaining sync elements if( !ZapConflicts(item, side) ) return; // rewrite the config RewriteConfig(item); // reload the deviceset RefillList(); // tell the user all's well wxMessageBox(_W("1-Way Reset is complete, and ready to sync."), _W("Reset Complete"), wxOK | wxICON_INFORMATION, m_parent); } void SyncMode::OnListSelChange(wxListEvent &event) { UpdateButtons(); } void SyncMode::OnConfigureDevice(wxListEvent &event) { ConfigureDevice(event.GetIndex()); } barry-0.18.5/desktop/src/wxval.h0000644001161500056700000001012712242254476016027 0ustar cdfreycdfrey/// /// \file wxval.h /// Homemade validators derived from wxValidator /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_WXVAL_H__ #define __BARRYDESKTOP_WXVAL_H__ #include #include "wxi18n.h" class DateTimeValidator : public wxValidator { wxDateTime *m_pDateTime; mutable wxDatePickerCtrl *m_pCtrl; public: explicit DateTimeValidator(wxDateTime *pval) : m_pDateTime(pval) { } DateTimeValidator(const DateTimeValidator &other) : m_pDateTime(other.m_pDateTime) { } virtual wxValidator* Clone() const { return new DateTimeValidator(*this); } bool CheckState() const { if( !m_pDateTime ) return false; if( !m_validatorWindow ) return false; if( !m_validatorWindow->IsKindOf(CLASSINFO(wxDatePickerCtrl)) ) return false; m_pCtrl = dynamic_cast(m_validatorWindow); return m_pCtrl; } virtual bool Validate(wxWindow *parent) { // Validate() checks the *control's* value, not the // in-memory value, according to the wxWidgets documentation, // so do TransferFromWindow() first if( !(TransferFromWindow() && m_pDateTime->IsValid()) ) { wxMessageBox(_W("Invalid date!"), _W("Validation"), wxOK | wxICON_INFORMATION, parent); return false; } return true; } virtual bool TransferToWindow() { if( !CheckState() ) return false; if( !m_pDateTime->IsValid() ) return false; m_pCtrl->SetValue(*m_pDateTime); return true; } virtual bool TransferFromWindow() { if( !CheckState() ) return false; *m_pDateTime = m_pCtrl->GetValue(); return true; } }; template class RadioBoxValidator : public wxValidator { mutable std::vector m_codes; EnumT *m_pEnum; mutable wxRadioBox *m_pCtrl; public: explicit RadioBoxValidator(EnumT *pval) : m_pEnum(pval) { } RadioBoxValidator(const RadioBoxValidator &other) : m_codes(other.m_codes) , m_pEnum(other.m_pEnum) { } virtual wxValidator* Clone() const { return new RadioBoxValidator(*this); } // return const reference to self to allow .Add().Add() series // on constructor const RadioBoxValidator& Add(EnumT code) const { m_codes.push_back(code); return *this; } bool CheckState() const { if( !m_pEnum ) return false; if( !m_validatorWindow ) return false; if( !m_validatorWindow->IsKindOf(CLASSINFO(wxRadioBox)) ) return false; m_pCtrl = dynamic_cast(m_validatorWindow); return m_pCtrl; } bool IsSelectionValid() const { return std::find(m_codes.begin(), m_codes.end(), *m_pEnum) != m_codes.end(); } virtual bool Validate(wxWindow *parent) { // Validate() checks the *control's* value, not the // in-memory value, according to the wxWidgets documentation, // so do TransferFromWindow() first if( !(TransferFromWindow() && IsSelectionValid()) ) { wxMessageBox( _W("Please select one of the radio buttons."), _W("Validation"), wxOK | wxICON_INFORMATION, parent); return false; } return true; } virtual bool TransferToWindow() { if( !CheckState() ) return false; typename std::vector::iterator i = std::find( m_codes.begin(), m_codes.end(), *m_pEnum); if( i == m_codes.end() ) return false; m_pCtrl->SetSelection(i - m_codes.begin()); return true; } virtual bool TransferFromWindow() { if( !CheckState() ) return false; *m_pEnum = m_codes.at(m_pCtrl->GetSelection()); return true; } }; template RadioBoxValidator MakeRadioBoxValidator(EnumT *pval) { return RadioBoxValidator(pval); } #endif barry-0.18.5/desktop/src/ostest.cc0000644001161500056700000001616012242254476016350 0ustar cdfreycdfrey/// /// \file ostest.cc /// Test application for the OpenSync API /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include #include #include #include #include "os22.h" #include "os40.h" #include "deviceset.h" using namespace std; using namespace OpenSync; void DeviceSetTest(Barry::GlobalConfigFile &config, APISet &set) { DeviceSet dset(config, set); cout << "========================================================\n"; cout << " Device Set results:\n"; cout << "========================================================\n"; cout << dset << endl; } void Test(API &os) { cout << "=======================================================\n"; cout << " Begin test run: " << os.GetVersion() << "\n"; cout << "=======================================================\n"; format_list_type flist; os.GetFormats(flist); cout << "Formats:\n" << flist << endl; string_list_type slist; os.GetPluginNames(slist); cout << "Plugins:\n" << slist << endl; os.GetGroupNames(slist); cout << "Groups:\n" << slist << endl; for( string_list_type::iterator b = slist.begin(); b != slist.end(); ++ b) { member_list_type mlist; os.GetMembers(*b, mlist); cout << "Members for group: " << *b << endl; cout << "---------------------------------------\n"; cout << mlist << endl; } // // Test Group / Members // const std::string group_name = "ostest_trial_group"; cout << "Testing with group_name: " << group_name << endl; // start fresh try { os.DeleteGroup(group_name); } catch( std::runtime_error &re ) { cout << "DeleteGroup: " << re.what() << endl; } // add group twice, to confirm behaviour os.AddGroup(group_name); cout << "Added: " << group_name << endl; try { os.AddGroup(group_name); throw std::logic_error("AddGroup() succeeded incorrectly!"); } catch( std::runtime_error &re ) { cout << "AddGroup: " << re.what() << endl; } if( OpenSync40 *os40 = dynamic_cast(&os) ) { try { os40->DeleteMember(group_name, 1); } catch( std::runtime_error &re ) { cout << "DeleteMember: " << re.what() << endl; } } os.AddMember(group_name, "barry-sync", "Barry sync member"); os.AddMember(group_name, "evo2-sync", "Evolution sync member"); // test deleting the member twice, to confirm behaviour // only os40 has DeleteMember() if( OpenSync40 *os40 = dynamic_cast(&os) ) { os.AddMember(group_name, "file-sync", "File sync member"); os40->DeleteMember(group_name, "file-sync"); try { os40->DeleteMember(group_name, "file-sync"); } catch( std::runtime_error &re ) { cout << "DeleteMember: " << re.what() << endl; } } // display our test group member_list_type mlist; os.GetMembers(group_name, mlist); cout << "Members for group: " << group_name << endl; cout << "---------------------------------------\n"; cout << mlist << endl; // dump configurations cout << group_name << "(1): " << (os.IsConfigurable(group_name, 1) ? "configurable" : "not configurable") << endl; cout << group_name << "(2): " << (os.IsConfigurable(group_name, 2) ? "configurable" : "not configurable") << endl; cout << "Member 1's configuration:\n"; cout << os.GetConfiguration(group_name, 1) << endl; cout << "Member 2's configuration:\n"; cout << os.GetConfiguration(group_name, 2) << endl; // add comment to bottom of barry-sync config long id = mlist.FindId("barry-sync"); string barry_config = os.GetConfiguration(group_name, id); if( dynamic_cast(&os) ) barry_config += "\n# This is a test\n"; else barry_config += "\n"; os.SetConfiguration(group_name, id, barry_config); cout << "New config for member " << id << ":\n"; cout << os.GetConfiguration(group_name, id); // discover os.Discover(group_name); // try a sync SyncStatus status_callbacks; os.Sync(group_name, status_callbacks, PST_DO_NOT_SET); os.Sync(group_name, status_callbacks, PST_DO_NOT_SET); // loop string command; while( (cout << "Enter 'q' to quit: "), getline(cin, command), command[0] != 'q' ) { os.Sync(group_name, status_callbacks, PST_DO_NOT_SET); } // delete group twice, to confirm behaviour os.DeleteGroup(group_name); cout << "Deleted: " << group_name << endl; try { os.DeleteGroup(group_name); throw std::logic_error("DeleteGroup() succeeded incorrectly!"); } catch( std::runtime_error &re ) { cout << "DeleteGroup failed as expected" << endl; } cout << "=======================================================\n"; cout << " End test run: " << os.GetVersion() << "\n"; cout << "=======================================================\n"; } #ifdef WITH_OPENSYNC40 void ShowAdvanced(OS40PluginConfig &cfg, const char *name) { cout << name << ": " << cfg.GetAdvanced(name) << endl; } #endif void TestConfig(OpenSync40 &os, const char *name, long member_id) { #ifndef WITH_OPENSYNC40 cout << "OpenSync40 support not compiled in." << endl; #else OS40PluginConfig cfg = os.GetConfigurationObj(name, member_id); ShowAdvanced(cfg, "PinCode"); ShowAdvanced(cfg, "Debug"); cfg.SetAdvanced("TestName", "Test Display Name", "Whippoorwill"); OS40PluginConfig::OS40ConfigResourcePtr res = cfg.GetResource("contact"); if( res->IsExistingResource() ) { cout << "Resource: " << res->GetName() << ": " << (res->IsEnabled() ? "enabled" : "disabled") << endl; cout << " pref format: " << res->GetPreferredFormat() << endl; cout << " mime: " << res->GetMime() << endl; cout << " objtype: " << res->GetObjType() << endl; cout << " path: " << res->GetPath() << endl; cout << " url: " << res->GetUrl() << endl; string config; if( res->FindObjFormat("vcard30", config) ) { cout << " objformat: vcard30: " << config << endl; } else { cout << " no vcard30 found" << endl; } } else { cout << "No contact resource found" << endl; } // add one / set one res = cfg.GetResource("testresource"); if( res->IsExistingResource() ) cout << "testresource exists" << endl; res->SetObjFormat("vcard30"). SetUrl("http://netdirect.ca/"). SetName("ResourceName"). Enable(). AddResource(); cfg.Save(); #endif } void TestConfig(API &os) { OpenSync40 *os40 = dynamic_cast (&os); TestConfig(*os40, "test", 1); TestConfig(*os40, "test", 2); } int main() { Barry::Init(true); try { Barry::GlobalConfigFile config("ostest"); APISet set; set.OpenAvailable(); DeviceSetTest(config, set); if( set.os40() ) { TestConfig(*set.os40()); Test(*set.os40()); } if( set.os22() ) { Test(*set.os22()); } } catch( std::exception &e ) { cout << "TEST FAILED: " << e.what() << endl; } return 0; } barry-0.18.5/desktop/src/exechelper.cc0000644001161500056700000001025512242254476017152 0ustar cdfreycdfrey/// /// \file exechelper.cc /// Helper class to wrap wxProcess and wxExecute operations /// /* Copyright (C) 2010-2013, Chris Frey 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 in the COPYING file at the root directory of this project for more details. */ #include "exechelper.h" #include #include #include #include #include #include #include #include "wxi18n.h" using namespace std; TermCatcher::~TermCatcher() { if( m_eh ) m_eh->m_catcher = 0; } ExecHelper::ExecHelper(TermCatcher *catcher) : m_catcher(catcher) , m_app_callback(0) , m_app_pid(-1) , m_app_status(-1) , m_started(0) { // link ourselves to the catcher... the catcher will unlink if necessary if( m_catcher ) m_catcher->m_eh = this; } ExecHelper::~ExecHelper() { if( m_app_callback ) { m_app_callback->Detach(); m_app_callback = 0; } if( m_catcher ) m_catcher->m_eh = 0; } void ExecHelper::RunError(wxWindow *parent, const wxString &msg) { if( !parent ) return; wxMessageBox(msg, _W("Application Run Error"), wxOK | wxICON_ERROR, parent); } int ExecHelper::Execute(bool use_wx, const wxString &command, AppCallback *cb) { if( use_wx ) { return wxExecute(command, wxEXEC_ASYNC, m_app_callback); } // // use our own forking mechanism, due to bugs in wxWidgets :-( // class WaitThread : public wxThread { int m_pid; AppCallback *m_callback; public: WaitThread(int pid, AppCallback *cb) : m_pid(pid) , m_callback(cb) { } virtual void* Entry() { int status; int pid = waitpid(m_pid, &status, 0); if( pid == m_pid ) { // our child finished m_callback->OnTerminate(pid, status); } return 0; } }; // about to fork, log the start time m_started = time(NULL); // create child int pid = fork(); if( pid == -1 ) { // no child created return -1; } else if( pid == 0 ) { // we are the child // parse the command line into an array char *argv[100]; int argc = 0; wxStringTokenizer t(command, _T(" ")); while( t.HasMoreTokens() && argc < 99 ) { wxString token = t.GetNextToken(); std::string ctoken(token.utf8_str()); argv[argc] = new char[ctoken.size() + 1]; strcpy(argv[argc], ctoken.c_str()); argc++; } argv[argc] = 0; execvp(argv[0], argv); cerr << "execvp() failed: " << strerror(errno) << endl; for( int i = 0; argv[i]; i++ ) { cerr << argv[i] << " "; } cerr << endl; exit(255); } else { // we are the parent... start the wait thread WaitThread *wt = new WaitThread(pid, cb); wt->Create(); wt->Run(); return pid; } } bool ExecHelper::Run(wxWindow *parent, const std::string &appname, const wxString &command) { if( IsAppRunning() ) { RunError(parent, // TRANSLATORS: %s is the name of an application wxString::Format(_W("%s is already running."), appname.c_str())); return false; } m_app_callback = new AppCallback(this); m_app_pid = Execute(false, command, m_app_callback); if( m_app_pid <= 0 ) { delete m_app_callback; m_app_callback = 0; m_app_pid = -1; RunError(parent, wxString::Format( _W("Failed to run %s. Please make sure it is " "installed and in your PATH."), appname.c_str())); return false; } return true; } bool ExecHelper::IsAppRunning() { return m_app_callback && m_app_pid > 0; } void ExecHelper::WaitForChild() { while( IsAppRunning() ) usleep(50000); } int ExecHelper::GetChildExitCode() const { int status = GetRawAppStatus(); return WEXITSTATUS(status); } void ExecHelper::KillApp(bool hardkill) { if( IsAppRunning() ) { // m_app_callback->Kill(m_app_pid, hardkill ? wxSIGKILL : wxSIGTERM); kill(m_app_pid, hardkill ? SIGKILL : SIGTERM); // let the callback handle the cleanup } } barry-0.18.5/desktop/src/tempdir.h0000644001161500056700000000275112242254476016336 0ustar cdfreycdfrey/// /// \file tempdir.h /// Temp directory & file wrapper class /// /* Copyright (C) 2009-2013, Chris Frey 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_TEMPDIR_H__ #define __BARRYDESKTOP_TEMPDIR_H__ #include // // class TempDir // /// This class creates a new temp directory on instantiation, /// and provides access members to retrieve the directory name /// and incrementing filenames. On destruction, all the returned /// filenames are deleted, and the directory is removed. /// class TempDir { char *m_template; int m_files; std::string MakeFilename(int file_id) const; public: /// basename is a simple identifier, such as "barry" /// The /tmp dir will be prepended automatically. TempDir(const char *basename); ~TempDir(); std::string GetDir() const { return m_template; } /// Returns unique filename in the form of /// /tmp/opensyncapi-XXXXX/0, 1, 2, etc. std::string GetNewFilename(); }; #endif barry-0.18.5/desktop/src/TaskEditDlg.h0000644001161500056700000000761612242254476017036 0ustar cdfreycdfrey/// /// \file TaskEditDlg.h /// Dialog class to handle the editing of the Task record /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_TASK_EDIT_DLG_H__ #define __BARRYDESKTOP_TASK_EDIT_DLG_H__ //#define wxUSE_DATEPICKCTRL 1 #include "StringSync.h" #include "guitimet.h" #include #include #include // begin wxGlade: ::dependencies #include #include #include // end wxGlade #include // begin wxGlade: ::extracode // end wxGlade class TaskEditDlg : public wxDialog { public: // begin wxGlade: TaskEditDlg::ids // end wxGlade private: // begin wxGlade: TaskEditDlg::methods void set_properties(); void do_layout(); // end wxGlade protected: Barry::TimeZones m_static_zones; const Barry::TimeZones *m_zones; Barry::Task &m_rec; StringSync m_strings; GUITimeT m_DueDateObj; GUITimeT m_ReminderDateObj; GUITimeT m_RecurEndDateObj; int m_reminder_hours, m_reminder_minutes; int m_interval; int m_recur_choice; bool m_weekdays[7]; bool m_relative_date; std::string m_categories; // begin wxGlade: TaskEditDlg::attributes wxStaticText* label_1; wxTextCtrl* m_TaskSummary; wxStaticLine* static_line_1; wxStaticText* label_2; wxChoice* m_StatusChoice; wxStaticText* label_9; wxChoice* m_PriorityChoice; wxStaticText* label_5; wxCheckBox* m_DueCheck; wxDatePickerCtrl* m_DueDateCtrl; wxSpinCtrl* m_DueHoursSpinner; wxStaticText* label_11; wxSpinCtrl* m_DueMinutesSpinner; wxStaticText* label_8; wxChoice* m_TimezoneChoice; wxStaticText* label_10; wxCheckBox* m_ReminderCheck; wxDatePickerCtrl* m_ReminderDateCtrl; wxSpinCtrl* m_ReminderHoursSpinner; wxStaticText* label_6; wxSpinCtrl* m_ReminderMinutesSpinner; wxStaticLine* static_line_2; wxStaticText* label_18; wxChoice* m_RecurrenceChoice; wxStaticText* RecurIntervalLabel; wxStaticText* RecurIntervalLabelB; wxSpinCtrl* m_IntervalSpinner; wxStaticText* m_IntervalUnitLabel; wxStaticText* RecurDaysLabel; wxCheckBox* m_SunCheck; wxCheckBox* m_MonCheck; wxCheckBox* m_TueCheck; wxCheckBox* m_WedCheck; wxCheckBox* m_ThuCheck; wxCheckBox* m_FriCheck; wxCheckBox* m_SatCheck; wxStaticText* RecurRelativeDateLabel; wxCheckBox* m_RelativeDateCheck; wxStaticText* RecurEndDateLabel; wxCheckBox* m_NeverEndsCheck; wxDatePickerCtrl* m_RecurEndDateCtrl; wxStaticLine* static_line_3; wxStaticText* label_4; wxTextCtrl* m_CategoriesText; wxStaticText* label_3; wxTextCtrl* m_NotesText; // end wxGlade wxSizer *bottom_buttons; wxSizer *m_top_sizer; DECLARE_EVENT_TABLE(); // sets to protected: protected: // helper functions void RedoLayout(); void EnableDueDate(bool enable = true); void EnableReminderDate(bool enable = true); void EnableRecurMode(bool recur = true); public: TaskEditDlg(wxWindow* parent, Barry::Task &rec, bool editable, const Barry::TimeZones *device_zones); virtual bool TransferDataToWindow(); virtual bool TransferDataFromWindow(); public: virtual void OnDueCheck(wxCommandEvent &event); // wxGlade: virtual void OnRecurrenceChoice(wxCommandEvent &event); // wxGlade: virtual void OnEndDateCheckbox(wxCommandEvent &event); // wxGlade: virtual void OnReminderCheck(wxCommandEvent &event); // wxGlade: }; // wxGlade: end class #endif barry-0.18.5/desktop/src/windowids.h0000644001161500056700000001122312242254476016673 0ustar cdfreycdfrey/// /// \file windowids.h /// Window IDs for the Barry Desktop GUI /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_WINDOWIDS_H__ #define __BARRYDESKTOP_WINDOWIDS_H__ #include ////////////////////////////////////////////////////////////////////////////// // IDs for controls and menu items (no menus in this app yet) enum { SysMenu_Exit = wxID_EXIT, SysMenu_About = wxID_ABOUT, MainMenu_FirstButton = wxID_HIGHEST, MainMenu_BackupAndRestore = MainMenu_FirstButton, MainMenu_Sync, MainMenu_Modem, MainMenu_MigrateDevice, MainMenu_BrowseDatabases, MainMenu_LastButton = MainMenu_BrowseDatabases, // FIXME - just until // apploader, media, and misc are implemented. // see real last button below... // Note, this has to be here, since enum // number relies on this position. MainMenu_AppLoader, MainMenu_MediaManagement, MainMenu_Misc, // MainMenu_LastButton = MainMenu_Misc, // Main menu buttons that don't always exist MainMenu_BackButton, // Clickable, "hot" images that do something HotImage_BarryLogo, HotImage_NetDirectLogo, // Misc IDs Ctrl_DeviceCombo, Process_BackupAndRestore, // SyncMode IDs SyncMode_SyncNowButton, SyncMode_ConfigureButton, SyncMode_RunAppButton, SyncMode_1WayResetButton, SyncMode_DeviceList, // BrowseMode IDs BrowseMode_DBDBList, BrowseMode_RecordList, BrowseMode_ShowAllCheckbox, BrowseMode_ImportRecordButton, BrowseMode_ExportRecordButton, BrowseMode_AddRecordButton, BrowseMode_CopyRecordButton, BrowseMode_EditRecordButton, BrowseMode_DeleteRecordButton, BrowseMode_LoadStatusText, // Dialog IDs Dialog_GroupCfg, Dialog_GroupCfg_EngineCombo, Dialog_GroupCfg_AppCombo, Dialog_GroupCfg_AppConfigButton, Dialog_GroupCfg_ContactsCheck, Dialog_GroupCfg_EventsCheck, Dialog_GroupCfg_NotesCheck, Dialog_GroupCfg_TodosCheck, Dialog_EvoCfg, Dialog_EvoDefault, Dialog_EvoDefault_ManualConfigButton, Dialog_SyncStatus, Dialog_SyncStatus_RunAppButton, Dialog_SyncStatus_SyncAgainButton, Dialog_SyncStatus_KillCloseButton, Dialog_SyncStatus_SyncTerminated, Dialog_SyncStatus_ShowDetailsButton, Dialog_SyncStatus_Timer, Dialog_Conflict, Dialog_Conflict_DataList, Dialog_Conflict_SelectButton1, Dialog_Conflict_SelectButton2, Dialog_Conflict_SelectButton3, Dialog_Conflict_SelectButton4, Dialog_Conflict_SelectButton5, Dialog_Conflict_SelectButton6, Dialog_Conflict_SelectButton7, Dialog_Conflict_SelectButton8, Dialog_Conflict_SelectButton9, Dialog_Conflict_ShowButton1, Dialog_Conflict_ShowButton2, Dialog_Conflict_ShowButton3, Dialog_Conflict_ShowButton4, Dialog_Conflict_ShowButton5, Dialog_Conflict_ShowButton6, Dialog_Conflict_ShowButton7, Dialog_Conflict_ShowButton8, Dialog_Conflict_ShowButton9, Dialog_Conflict_DuplicateButton, Dialog_Conflict_AbortButton, Dialog_Conflict_IgnoreButton, Dialog_Conflict_KeepNewerButton, Dialog_Conflict_KillSyncButton, Dialog_Conflict_AlwaysCheckbox, Dialog_ContactEdit, Dialog_ContactEdit_PhotoButton, Dialog_CalendarEdit, Dialog_CalendarEdit_AllDayCheck, Dialog_CalendarEdit_StartDateCtrl, Dialog_CalendarEdit_StartHoursSpinner, Dialog_CalendarEdit_StartMinutesSpinner, Dialog_CalendarEdit_EndDateCtrl, Dialog_CalendarEdit_EndHoursSpinner, Dialog_CalendarEdit_EndMinutesSpinner, Dialog_CalendarEdit_DurationHoursSpinner, Dialog_CalendarEdit_DurationMinutesSpinner, Dialog_CalendarEdit_RecurrenceChoice, Dialog_CalendarEdit_NeverEndsCheck, Dialog_TaskEdit, Dialog_TaskEdit_DueCheck, Dialog_TaskEdit_DueDateCtrl, Dialog_TaskEdit_DueHoursSpinner, Dialog_TaskEdit_DueMinutesSpinner, Dialog_TaskEdit_ReminderCheck, Dialog_TaskEdit_ReminderDateCtrl, Dialog_TaskEdit_ReminderHoursSpinner, Dialog_TaskEdit_ReminderMinutesSpinner, Dialog_TaskEdit_RecurrenceChoice, Dialog_TaskEdit_NeverEndsCheck, Dialog_MemoEdit, Dialog_Migrate_MigrateNowButton, Dialog_Migrate_CancelButton, Dialog_Modem, Dialog_MimeExport, Dialog_MimeExport_SaveButton, SysMenu_FirstItem, SysMenu_VerboseLogging = SysMenu_FirstItem, SysMenu_RenameDevice, SysMenu_ResetDevice, SysMenu_RescanUsb, SysMenu_LastItem = SysMenu_RescanUsb }; #endif barry-0.18.5/desktop/src/os22.cc0000644001161500056700000010525012242254476015613 0ustar cdfreycdfrey/// /// \file os22.cc /// Wrapper class for opensync 0.22 syncing behaviour /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) Used code from msynctool (GPL v2+) as a guide to the API, and copied some of its status messages and one function directly: static const char *OSyncChangeType2String(OSyncChangeType c); Copyright (C) 2004-2005 Armin Bauer 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 in the COPYING file at the root directory of this project for more details. */ #include "os22.h" #include "osprivatebase.h" #include "osconv22.h" #include #include #include #include #include #include #include "i18n.h" // use relative paths to backtrack enough to specify only 0.22 includes #include <../opensync-1.0/opensync/opensync.h> #include <../opensync-1.0/osengine/engine.h> using namespace std; using namespace Barry; namespace OpenSync { typedef Barry::vLateSmartPtr EngineHandle; class OpenSync22Private { public: // function pointers const char* (*osync_get_version)(); OSyncEnv* (*osync_env_new)(); void (*osync_env_free)(OSyncEnv *env); void (*osync_env_set_option)(OSyncEnv *env, const char *name, const char *value); osync_bool (*osync_env_finalize)(OSyncEnv *env, OSyncError **error); int (*osync_env_num_plugins)(OSyncEnv *env); OSyncPlugin* (*osync_env_nth_plugin)(OSyncEnv *env, int nth); const char* (*osync_plugin_get_name)(OSyncPlugin *plugin); void (*osync_error_free)(OSyncError **error); const char* (*osync_error_print)(OSyncError **error); osync_bool (*osync_env_initialize)(OSyncEnv *env, OSyncError **error); int (*osync_env_num_groups)(OSyncEnv *env); OSyncGroup* (*osync_env_nth_group)(OSyncEnv *env, int nth); const char* (*osync_group_get_name)(OSyncGroup *group); OSyncGroup* (*osync_env_find_group)(OSyncEnv *env, const char *name); int (*osync_group_num_members)(OSyncGroup *group); OSyncMember* (*osync_group_nth_member)(OSyncGroup *group, int nth); long long int (*osync_member_get_id)(OSyncMember *member); const char* (*osync_member_get_pluginname)( OSyncMember *member); OSyncFormatEnv* (*osync_conv_env_new)(OSyncEnv *env); void (*osync_conv_env_free)(OSyncFormatEnv *env); int (*osync_conv_num_objtypes)(OSyncFormatEnv *env); OSyncObjType* (*osync_conv_nth_objtype)(OSyncFormatEnv *env, int nth); int (*osync_conv_num_objformats)( OSyncObjType *type); OSyncObjFormat* (*osync_conv_nth_objformat)(OSyncObjType *type, int nth); const char* (*osync_objformat_get_name)( OSyncObjFormat *format); const char* (*osync_objtype_get_name)(OSyncObjType *type); OSyncGroup* (*osync_group_new)(OSyncEnv *env); void (*osync_group_set_name)(OSyncGroup *group, const char *name); osync_bool (*osync_group_save)(OSyncGroup *group, OSyncError **error); osync_bool (*osync_group_delete)(OSyncGroup *group, OSyncError **error); OSyncMember* (*osync_member_new)(OSyncGroup *group); osync_bool (*osync_member_instance_plugin)( OSyncMember *member, const char *pluginname, OSyncError **error); osync_bool (*osync_member_save)(OSyncMember *member, OSyncError **error); OSyncMember* (*osync_member_from_id)(OSyncGroup *group, int id); osync_bool (*osync_member_need_config)(OSyncMember *member, OSyncConfigurationTypes *type, OSyncError **error); osync_bool (*osync_member_get_config_or_default)( OSyncMember *member, char **data, int *size, OSyncError **error); void (*osync_member_set_config)(OSyncMember *member, const char *data, int size); osync_bool (*osengine_mapping_ignore_supported)( OSyncEngine *engine, OSyncMapping *mapping); osync_bool (*osengine_mapping_check_timestamps)( OSyncEngine *engine, OSyncMapping *mapping, OSyncError **error); OSyncChange* (*osengine_mapping_nth_change)( OSyncMapping *mapping, int nth); void (*osengine_mapping_solve)(OSyncEngine *engine, OSyncMapping *mapping, OSyncChange *change); void (*osengine_mapping_duplicate)( OSyncEngine *engine, OSyncMapping *dupe_mapping); osync_bool (*osengine_mapping_ignore_conflict)( OSyncEngine *engine, OSyncMapping *mapping, OSyncError **error); osync_bool (*osengine_mapping_solve_latest)( OSyncEngine *engine, OSyncMapping *mapping, OSyncError **error); const char* (*osync_change_get_uid)(OSyncChange *change); osync_bool (*osengine_init)(OSyncEngine *engine, OSyncError **error); OSyncMember* (*osync_change_get_member)(OSyncChange *change); int (*osync_change_get_datasize)( OSyncChange *change); OSyncEngine* (*osengine_new)(OSyncGroup *group, OSyncError **error); void (*osengine_free)(OSyncEngine *engine); void (*osengine_finalize)(OSyncEngine *engine); osync_bool (*osengine_sync_and_block)(OSyncEngine *engine, OSyncError **error); void (*osengine_set_memberstatus_callback)( OSyncEngine *engine, void (* function) (OSyncMemberUpdate *, void *), void *user_data); void (*osengine_set_changestatus_callback)( OSyncEngine *engine, void (* function) (OSyncEngine *, OSyncChangeUpdate *, void *), void *user_data); void (*osengine_set_enginestatus_callback)( OSyncEngine *engine, void (* function) (OSyncEngine *, OSyncEngineUpdate *, void *), void *user_data); void (*osengine_set_mappingstatus_callback)( OSyncEngine *engine, void (* function) (OSyncMappingUpdate *, void *), void *user_data); void (*osengine_set_conflict_callback)( OSyncEngine *engine, void (* function) (OSyncEngine *, OSyncMapping *, void *), void *user_data); int (*osengine_mapping_num_changes)( OSyncMapping *mapping); OSyncChangeType (*osync_change_get_changetype)( OSyncChange *change); char* (*osync_change_get_printable)( OSyncChange *change); void (*osync_group_set_objtype_enabled)( OSyncGroup *group, const char *objtypestr, osync_bool enabled); // data pointers OSyncEnv *env; Converter22 converter; OpenSync22Private(OpenSync22 &api) : env(0) , converter(api) { } }; class SyncConflict22Private : public SyncConflictPrivateBase { OpenSync22Private *m_priv; OSyncEngine *m_engine; OSyncMapping *m_mapping; public: SyncConflict22Private(OpenSync22Private *priv, OSyncEngine *engine, OSyncMapping *mapping); ~SyncConflict22Private(); virtual bool IsAbortSupported() const; virtual bool IsIgnoreSupported() const; virtual bool IsKeepNewerSupported() const; virtual void Select(int change_id); // takes id of SyncChange object virtual void Abort(); // not supported in 0.22 virtual void Duplicate(); virtual void Ignore(); virtual void KeepNewer(); void AppendChanges(std::vector &list); }; struct CallbackBundle22 { OpenSync22Private *m_priv; SyncStatus *m_status; CallbackBundle22(OpenSync22Private *priv, SyncStatus &status) : m_priv(priv) , m_status(&status) { } }; void member_status(OSyncMemberUpdate *, void *); void entry_status(OSyncEngine *, OSyncChangeUpdate *, void *); void engine_status(OSyncEngine *, OSyncEngineUpdate *,void *); void mapping_status(OSyncMappingUpdate *, void *); void conflict_handler(OSyncEngine *, OSyncMapping *, void *); ///////////////////////////////////////////////////////////////////////////// // Static helper functions static const char *OSyncChangeType2String(OSyncChangeType c) { switch (c) { case CHANGE_ADDED: return _C("ADDED"); case CHANGE_UNMODIFIED: return _C("UNMODIFIED"); case CHANGE_DELETED: return _C("DELETED"); case CHANGE_MODIFIED: return _C("MODIFIED"); default: case CHANGE_UNKNOWN: return "?"; } } ///////////////////////////////////////////////////////////////////////////// // SyncConflict22Private member functions SyncConflict22Private::SyncConflict22Private(OpenSync22Private *priv, OSyncEngine *engine, OSyncMapping *mapping) : m_priv(priv) , m_engine(engine) , m_mapping(mapping) { } SyncConflict22Private::~SyncConflict22Private() { } bool SyncConflict22Private::IsAbortSupported() const { return false; // Abort not explicitly supported in 0.22 } bool SyncConflict22Private::IsIgnoreSupported() const { return m_priv->osengine_mapping_ignore_supported(m_engine, m_mapping); } bool SyncConflict22Private::IsKeepNewerSupported() const { return m_priv->osengine_mapping_check_timestamps(m_engine, m_mapping, NULL); } void SyncConflict22Private::Select(int change_id) { OSyncChange *change = m_priv->osengine_mapping_nth_change(m_mapping, change_id); if( !change ) { throw std::runtime_error(_C("Bad change_id, or error getting nth change object.")); } m_priv->osengine_mapping_solve(m_engine, m_mapping, change); } void SyncConflict22Private::Abort() { throw std::logic_error("Conflict::Abort() not supported in 0.22"); } void SyncConflict22Private::Duplicate() { m_priv->osengine_mapping_duplicate(m_engine, m_mapping); } void SyncConflict22Private::Ignore() { if( !IsIgnoreSupported() ) throw std::logic_error("Ignore not supported, yet Ignore() called."); OSyncError *error = NULL; if( !m_priv->osengine_mapping_ignore_conflict(m_engine, m_mapping, &error)) { ostringstream oss; oss << _C("Conflict not ignored: ") << m_priv->osync_error_print(&error); m_priv->osync_error_free(&error); throw std::runtime_error(oss.str()); } } void SyncConflict22Private::KeepNewer() { if( !IsKeepNewerSupported() ) throw std::logic_error("Keep Newer not supported, yet KeepNewer() called."); OSyncError *error = NULL; if( !m_priv->osengine_mapping_solve_latest(m_engine, m_mapping, &error)) { ostringstream oss; oss << _C("Conflict not resolved: ") << m_priv->osync_error_print(&error); m_priv->osync_error_free(&error); throw std::runtime_error(oss.str()); } } void SyncConflict22Private::AppendChanges(std::vector &list) { for( int i = 0; i < m_priv->osengine_mapping_num_changes(m_mapping); i++ ) { OSyncChange *change = m_priv->osengine_mapping_nth_change(m_mapping, i); if( m_priv->osync_change_get_changetype(change) != CHANGE_UNKNOWN ) { SyncChange entry; char *printable = m_priv->osync_change_get_printable(change); if( printable ) { entry.printable_data = printable; g_free(printable); } OSyncMember *member = m_priv->osync_change_get_member(change); entry.id = i; entry.member_id = m_priv->osync_member_get_id(member); entry.plugin_name = m_priv->osync_member_get_pluginname(member); entry.uid = m_priv->osync_change_get_uid(change); // add to list list.push_back(entry); } } } ///////////////////////////////////////////////////////////////////////////// // Callback functions void member_status(OSyncMemberUpdate *status, void *cbdata) { CallbackBundle22 *cb = (CallbackBundle22*) cbdata; try { bool error_event = false; bool valid = true; string fmt, trailer; switch( status->type ) { case MEMBER_CONNECTED: fmt = _C("Member %lld (%s) just connected"); break; case MEMBER_DISCONNECTED: fmt = _C("Member %lld (%s) just disconnected"); break; case MEMBER_SENT_CHANGES: fmt = _C("Member %lld (%s) just sent all changes"); break; case MEMBER_COMMITTED_ALL: fmt = _C("Member %lld (%s) committed all changes"); break; case MEMBER_CONNECT_ERROR: fmt = _C("Member %lld (%s) had an error while connecting: %s"); trailer = cb->m_priv->osync_error_print(&status->error); break; case MEMBER_GET_CHANGES_ERROR: fmt = _C("Member %lld (%s) had an error while getting changes: %s"); trailer = cb->m_priv->osync_error_print(&status->error); error_event = true; break; case MEMBER_SYNC_DONE_ERROR: fmt = _C("Member %lld (%s) had an error while calling sync done: %s"); trailer = cb->m_priv->osync_error_print(&status->error); error_event = true; break; case MEMBER_DISCONNECT_ERROR: fmt = _C("Member %lld (%s) had an error while disconnecting: %s"); trailer = cb->m_priv->osync_error_print(&status->error); error_event = true; break; case MEMBER_COMMITTED_ALL_ERROR: fmt = _C("Member %lld (%s) had an error while commiting changes: %s"); trailer = cb->m_priv->osync_error_print(&status->error); error_event = true; break; default: valid = false; break; } // combine the message string msg = string_vprintf(fmt.c_str(), cb->m_priv->osync_member_get_id(status->member), cb->m_priv->osync_member_get_pluginname(status->member), trailer.c_str()); // call the status handler if( msg.size() && valid ) { cb->m_status->MemberStatus( cb->m_priv->osync_member_get_id(status->member), cb->m_priv->osync_member_get_pluginname(status->member), msg, error_event); } } catch( std::exception &e ) { cb->m_status->ReportError( string(_C("member_status error: ")) + e.what()); } catch( ... ) { cb->m_status->ReportError( _C("Unknown exception caught in member_status()")); } } void entry_status(OSyncEngine *engine, OSyncChangeUpdate *status, void *cbdata) { CallbackBundle22 *cb = (CallbackBundle22*) cbdata; try { OSyncMember *member = cb->m_priv->osync_change_get_member(status->change); bool error_event = false; string msg; switch( status->type ) { case CHANGE_RECEIVED_INFO: msg = string_vprintf(_C("Received an entry %s without data from member %d (%s). Change type: %s"), cb->m_priv->osync_change_get_uid(status->change), status->member_id, cb->m_priv->osync_member_get_pluginname(member), OSyncChangeType2String(cb->m_priv->osync_change_get_changetype(status->change))); break; case CHANGE_RECEIVED: msg = string_vprintf(_C("Received an entry %s with data of size %d from member %d (%s). Change type: %s"), cb->m_priv->osync_change_get_uid(status->change), cb->m_priv->osync_change_get_datasize(status->change), status->member_id, cb->m_priv->osync_member_get_pluginname(member), OSyncChangeType2String(cb->m_priv->osync_change_get_changetype(status->change))); break; case CHANGE_SENT: msg = string_vprintf(_C("Sent an entry %s of size %d to member %d (%s). Change type: %s"), cb->m_priv->osync_change_get_uid(status->change), cb->m_priv->osync_change_get_datasize(status->change), status->member_id, cb->m_priv->osync_member_get_pluginname(member), OSyncChangeType2String(cb->m_priv->osync_change_get_changetype(status->change))); break; case CHANGE_WRITE_ERROR: error_event = true; msg = string_vprintf(_C("Error writing entry %s to member %d (%s): %s"), cb->m_priv->osync_change_get_uid(status->change), status->member_id, cb->m_priv->osync_member_get_pluginname(member), cb->m_priv->osync_error_print(&status->error)); break; case CHANGE_RECV_ERROR: error_event = true; msg = string_vprintf(_C("Error reading entry %s from member %d (%s): %s"), cb->m_priv->osync_change_get_uid(status->change), status->member_id, cb->m_priv->osync_member_get_pluginname(member), cb->m_priv->osync_error_print(&(status->error))); break; } // call the status handler if( msg.size() ) { cb->m_status->EntryStatus(msg, error_event); } } catch( std::exception &e ) { cb->m_status->ReportError( string(_C("entry_status error:")) + e.what()); } catch( ... ) { cb->m_status->ReportError( _C("Unknown exception caught in entry_status()")); } } void engine_status(OSyncEngine *engine, OSyncEngineUpdate *status, void *cbdata) { CallbackBundle22 *cb = (CallbackBundle22*) cbdata; try { ostringstream oss; bool error_event = false; switch( status->type ) { case ENG_PREV_UNCLEAN: oss << _C("The previous synchronization was unclean. Slow-syncing."); break; case ENG_ENDPHASE_CON: oss << _C("All clients connected or error"); break; case ENG_END_CONFLICTS: oss << _C("All conflicts have been reported"); break; case ENG_ENDPHASE_READ: oss << _C("All clients sent changes or error"); break; case ENG_ENDPHASE_WRITE: oss << _C("All clients have written"); break; case ENG_ENDPHASE_DISCON: oss << _C("All clients have disconnected"); break; case ENG_SYNC_SUCCESSFULL: oss << _C("The sync was successful"); break; case ENG_ERROR: oss << _C("The sync failed: ") << cb->m_priv->osync_error_print(&status->error); error_event = true; break; } // call the status handler if( oss.str().size() ) cb->m_status->EngineStatus(oss.str(), error_event, status->type == ENG_PREV_UNCLEAN); } catch( std::exception &e ) { cb->m_status->ReportError( string(_C("engine_status error: ")) + e.what()); } catch( ... ) { cb->m_status->ReportError( _C("Unknown exception caught in engine_status()")); } } void mapping_status(OSyncMappingUpdate *status, void *cbdata) { CallbackBundle22 *cb = (CallbackBundle22*) cbdata; try { ostringstream oss; bool error_event = false; switch( status->type ) { case MAPPING_SOLVED: oss << _C("Mapping solved"); break; case MAPPING_SYNCED: oss << _C("Mapping Synced"); break; case MAPPING_WRITE_ERROR: error_event = true; oss << _C("Mapping Write Error: ") << cb->m_priv->osync_error_print(&status->error); break; } // call the status handler if( oss.str().size() ) cb->m_status->MappingStatus(oss.str(), error_event); } catch( std::exception &e ) { cb->m_status->ReportError( string(_C("mapping_status error: ")) + e.what()); } catch( ... ) { cb->m_status->ReportError( _C("Unknown exception caught in mapping_status()")); } } void conflict_handler(OSyncEngine *engine, OSyncMapping *mapping, void *cbdata) { CallbackBundle22 *cb = (CallbackBundle22*) cbdata; try { // build the SyncConflict object SyncConflict22Private scp(cb->m_priv, engine, mapping); SyncConflict conflict(scp); // append all conflicting changes as vector objects in the same // order as the opensync library mapping scp.AppendChanges(conflict); // call the status handler cb->m_status->HandleConflict(conflict); } catch( std::exception &e ) { cb->m_status->ReportError( string(_C("Conflict not resolved. ")) + e.what()); } catch( ... ) { cb->m_status->ReportError( _C("Unknown exception caught in conflict_handler()")); } } ///////////////////////////////////////////////////////////////////////////// // OpenSync22 - public members bool OpenSync22::symbols_loaded = false; OpenSync22::OpenSync22() { if( !Open("libosengine.so.0") ) throw DlError("Can't dlopen libosengine.so.0"); // the symbol table is now thoroughly polluted... symbols_loaded = true; // store locally in case of constructor exception in LoadSym std::auto_ptr p(new OpenSync22Private(*this)); // load all required symbols... // we don't need to use try/catch here, since the base // class destructor will clean up for us if LoadSym() throws LoadSym(p->osync_get_version, "osync_get_version"); LoadSym(p->osync_env_new, "osync_env_new"); LoadSym(p->osync_env_free, "osync_env_free"); LoadSym(p->osync_env_set_option, "osync_env_set_option"); LoadSym(p->osync_env_finalize, "osync_env_finalize"); LoadSym(p->osync_env_num_plugins, "osync_env_num_plugins"); LoadSym(p->osync_env_nth_plugin, "osync_env_nth_plugin"); LoadSym(p->osync_plugin_get_name, "osync_plugin_get_name"); LoadSym(p->osync_error_free, "osync_error_free"); LoadSym(p->osync_error_print, "osync_error_print"); LoadSym(p->osync_env_initialize, "osync_env_initialize"); LoadSym(p->osync_env_num_groups, "osync_env_num_groups"); LoadSym(p->osync_env_nth_group, "osync_env_nth_group"); LoadSym(p->osync_group_get_name, "osync_group_get_name"); LoadSym(p->osync_env_find_group, "osync_env_find_group"); LoadSym(p->osync_group_num_members, "osync_group_num_members"); LoadSym(p->osync_group_nth_member, "osync_group_nth_member"); LoadSym(p->osync_member_get_id, "osync_member_get_id"); LoadSym(p->osync_member_get_pluginname, "osync_member_get_pluginname"); LoadSym(p->osync_conv_env_new, "osync_conv_env_new"); LoadSym(p->osync_conv_env_free, "osync_conv_env_free"); LoadSym(p->osync_conv_num_objtypes, "osync_conv_num_objtypes"); LoadSym(p->osync_conv_nth_objtype, "osync_conv_nth_objtype"); LoadSym(p->osync_conv_num_objformats, "osync_conv_num_objformats"); LoadSym(p->osync_conv_nth_objformat, "osync_conv_nth_objformat"); LoadSym(p->osync_objformat_get_name, "osync_objformat_get_name"); LoadSym(p->osync_objtype_get_name, "osync_objtype_get_name"); LoadSym(p->osync_group_new, "osync_group_new"); LoadSym(p->osync_group_set_name, "osync_group_set_name"); LoadSym(p->osync_group_save, "osync_group_save"); LoadSym(p->osync_group_delete, "osync_group_delete"); LoadSym(p->osync_member_new, "osync_member_new"); LoadSym(p->osync_member_instance_plugin,"osync_member_instance_plugin"); LoadSym(p->osync_member_save, "osync_member_save"); LoadSym(p->osync_member_from_id, "osync_member_from_id"); LoadSym(p->osync_member_need_config, "osync_member_need_config"); LoadSym(p->osync_member_get_config_or_default, "osync_member_get_config_or_default"); LoadSym(p->osync_member_set_config, "osync_member_set_config"); LoadSym(p->osengine_mapping_ignore_supported, "osengine_mapping_ignore_supported"); LoadSym(p->osengine_mapping_check_timestamps, "osengine_mapping_check_timestamps"); LoadSym(p->osengine_mapping_nth_change, "osengine_mapping_nth_change"); LoadSym(p->osengine_mapping_solve, "osengine_mapping_solve"); LoadSym(p->osengine_mapping_duplicate, "osengine_mapping_duplicate"); LoadSym(p->osengine_mapping_ignore_conflict, "osengine_mapping_ignore_conflict"); LoadSym(p->osengine_mapping_solve_latest, "osengine_mapping_solve_latest"); LoadSym(p->osync_change_get_uid, "osync_change_get_uid"); LoadSym(p->osengine_init, "osengine_init"); LoadSym(p->osync_change_get_member, "osync_change_get_member"); LoadSym(p->osync_change_get_datasize, "osync_change_get_datasize"); LoadSym(p->osengine_new, "osengine_new"); LoadSym(p->osengine_free, "osengine_free"); LoadSym(p->osengine_finalize, "osengine_finalize"); LoadSym(p->osengine_sync_and_block, "osengine_sync_and_block"); LoadSym(p->osengine_set_memberstatus_callback, "osengine_set_memberstatus_callback"); LoadSym(p->osengine_set_changestatus_callback, "osengine_set_changestatus_callback"); LoadSym(p->osengine_set_enginestatus_callback, "osengine_set_enginestatus_callback"); LoadSym(p->osengine_set_mappingstatus_callback, "osengine_set_mappingstatus_callback"); LoadSym(p->osengine_set_conflict_callback, "osengine_set_conflict_callback"); LoadSym(p->osengine_mapping_num_changes, "osengine_mapping_num_changes"); LoadSym(p->osync_change_get_changetype, "osync_change_get_changetype"); LoadSym(p->osync_change_get_printable, "osync_change_get_printable"); LoadSym(p->osync_group_set_objtype_enabled, "osync_group_set_objtype_enabled"); // do common initialization of opensync environment SetupEnvironment(p.get()); // this pointer is ours now m_priv = p.release(); } OpenSync22::~OpenSync22() { // clean up opensync environment, closing plugins, etc. if( m_priv->env ) { m_priv->osync_env_finalize(m_priv->env, NULL); m_priv->osync_env_free(m_priv->env); } // free private class data delete m_priv; m_priv = 0; } void OpenSync22::SetupEnvironment(OpenSync22Private *p) { // we are fully responsible for this pointer, since // we run inside the constructor... only on success // will responsibility be transferred to the destructor p->env = p->osync_env_new(); if( !p->env ) throw std::runtime_error(_C("Error allocating opensync 0.22 environment")); p->osync_env_set_option(p->env, "GROUPS_DIRECTORY", NULL); p->osync_env_set_option(p->env, "LOAD_GROUPS", "TRUE"); p->osync_env_set_option(p->env, "LOAD_PLUGINS", "TRUE"); p->osync_env_set_option(p->env, "LOAD_FORMATS", "TRUE"); OSyncError *error = NULL; if( !p->osync_env_initialize(p->env, &error) ) { // grab error message std::runtime_error err(m_priv->osync_error_print(&error)); // cleanup p->osync_error_free(&error); p->osync_env_free(m_priv->env); // throw throw err; } } const char* OpenSync22::GetVersion() const { return m_priv->osync_get_version(); } const char* OpenSync22::GetEngineName() const { return "0.22"; } void OpenSync22::GetPluginNames(string_list_type &plugins) { // start fresh plugins.clear(); OSyncPlugin *p; for( int i = 0; i < m_priv->osync_env_num_plugins(m_priv->env); i++) { p = m_priv->osync_env_nth_plugin(m_priv->env, i); plugins.push_back(m_priv->osync_plugin_get_name(p)); } } void OpenSync22::GetFormats(format_list_type &formats) { // start fresh formats.clear(); // cycle through all object types and simulate a 0.4x-like // list based on the attached formats OSyncFormatEnv *fenv = m_priv->osync_conv_env_new(m_priv->env); if( !fenv ) { throw std::runtime_error(string("GetFormats(): ") + _C("Unable to load format environment in GetFormats (22)")); } for( int i = 0; i < m_priv->osync_conv_num_objtypes(fenv); i++ ) { OSyncObjType *type = m_priv->osync_conv_nth_objtype(fenv, i); for( int i = 0; i < m_priv->osync_conv_num_objformats(type); i++ ) { OSyncObjFormat *format = m_priv->osync_conv_nth_objformat(type, i); const char *objformat_name = m_priv->osync_objformat_get_name(format); if( !formats.Find(objformat_name) ) { Format new_format; new_format.name = objformat_name; new_format.object_type = m_priv->osync_objtype_get_name(type); formats.push_back(new_format); } } } m_priv->osync_conv_env_free(fenv); } void OpenSync22::GetGroupNames(string_list_type &groups) { // start fresh groups.clear(); OSyncGroup *g; for( int i = 0; i < m_priv->osync_env_num_groups(m_priv->env); i++ ) { g = m_priv->osync_env_nth_group(m_priv->env, i); groups.push_back(m_priv->osync_group_get_name(g)); } } void OpenSync22::GetMembers(const std::string &group_name, member_list_type &members) { // start fresh members.clear(); OSyncGroup *group = m_priv->osync_env_find_group(m_priv->env, group_name.c_str()); if( !group ) { throw std::runtime_error(string("GetMembers(): ") + _C("Unable to find group with name: ") + group_name); } for( int i = 0; i < m_priv->osync_group_num_members(group); i++ ) { OSyncMember *member = m_priv->osync_group_nth_member(group, i); Member new_member; new_member.group_name = group_name; new_member.id = m_priv->osync_member_get_id(member); new_member.plugin_name = m_priv->osync_member_get_pluginname(member); // we are switching opensync's long long int ID to // our long... to double check they are equal after // the conversion if( new_member.id != m_priv->osync_member_get_id(member) ) { throw std::logic_error("GetMembers(): OpenSync's member ID is too large to fit in OpenSyncAPI (22)"); } // add to member list members.push_back(new_member); } } void OpenSync22::AddGroup(const std::string &group_name) { if( m_priv->osync_env_find_group(m_priv->env, group_name.c_str()) ) throw std::runtime_error(string("AddGroup(): ") + _C("Group already exists: ") + group_name); OSyncGroup *group = m_priv->osync_group_new(m_priv->env); m_priv->osync_group_set_name(group, group_name.c_str()); OSyncError *error = NULL; if( !m_priv->osync_group_save(group, &error) ) { // grab error message std::runtime_error err(string("AddGroup(): ") + _C("Unable to save group: ") + m_priv->osync_error_print(&error)); // cleanup m_priv->osync_error_free(&error); throw err; } } void OpenSync22::DeleteGroup(const std::string &group_name) { OSyncGroup *group = m_priv->osync_env_find_group(m_priv->env, group_name.c_str()); if( !group ) throw std::runtime_error(string("DeleteGroup(): ") + _C("Group not found: ") + group_name); OSyncError *error = NULL; if( !m_priv->osync_group_delete(group, &error) ) { std::runtime_error err(string("DeleteGroup(): ") + _C("Unable to delete group: ") + m_priv->osync_error_print(&error)); m_priv->osync_error_free(&error); throw err; } } Converter& OpenSync22::GetConverter() { return m_priv->converter; } long OpenSync22::AddMember(const std::string &group_name, const std::string &plugin_name, const std::string &member_name) { OSyncGroup *group = m_priv->osync_env_find_group(m_priv->env, group_name.c_str()); if( !group ) throw std::runtime_error(string("AddMember(): ") + _C("Group not found: ") + group_name); OSyncMember *member = m_priv->osync_member_new(group); OSyncError *error = NULL; if( !m_priv->osync_member_instance_plugin(member, plugin_name.c_str(), &error) ) { std::runtime_error err(string("AddMember(): ") + _C("Unable to connect plugin with member: ") + member_name + "/" + plugin_name + ": " + m_priv->osync_error_print(&error)); m_priv->osync_error_free(&error); throw err; } if( !m_priv->osync_member_save(member, &error) ) { std::runtime_error err(string("AddMember(): ") + _C("Unable to save member: ") + member_name + "/" + plugin_name + ": " + m_priv->osync_error_print(&error)); m_priv->osync_error_free(&error); throw err; } return m_priv->osync_member_get_id(member); } bool OpenSync22::IsConfigurable(const std::string &group_name, long member_id) { OSyncGroup *group = m_priv->osync_env_find_group(m_priv->env, group_name.c_str()); if( !group ) throw std::runtime_error(_C("Group not found: ") + group_name); OSyncMember *member = m_priv->osync_member_from_id(group, member_id); if( !member ) { ostringstream oss; oss << "IsConfigurable(): " << _C("Member not found: ") << member_id; throw std::runtime_error(oss.str()); } OSyncConfigurationTypes type = NO_CONFIGURATION; OSyncError *error = NULL; if( !m_priv->osync_member_need_config(member, &type, &error) ) { std::runtime_error err(string(_C("Unable to determine needed config: ")) + m_priv->osync_error_print(&error)); m_priv->osync_error_free(&error); throw err; } return type != NO_CONFIGURATION; } std::string OpenSync22::GetConfiguration(const std::string &group_name, long member_id) { if( !IsConfigurable(group_name, member_id) ) { throw std::runtime_error(string("GetConfiguration(): ") + string_vprintf(_C("Member %ld of group '%s' does not accept configuration."), member_id, group_name.c_str())); } OSyncGroup *group = m_priv->osync_env_find_group(m_priv->env, group_name.c_str()); if( !group ) throw std::runtime_error(string("GetConfiguration(): ") + _C("Group not found: ") + group_name); OSyncMember *member = m_priv->osync_member_from_id(group, member_id); if( !member ) { throw std::runtime_error(string("GetConfiguration(): ") + string_vprintf(_C("Member %ld not found."), member_id)); } OSyncError *error = NULL; char *data = NULL; int size = 0; if( !m_priv->osync_member_get_config_or_default(member, &data, &size, &error)) { std::runtime_error err(string("GetConfiguration(): ") + _C("Unable to retrieve config: ") + m_priv->osync_error_print(&error)); m_priv->osync_error_free(&error); throw err; } std::string config(data, size); g_free(data); return config; } void OpenSync22::SetConfiguration(const std::string &group_name, long member_id, const std::string &config_data) { if( !IsConfigurable(group_name, member_id) ) { throw std::runtime_error(string("SetConfiguration(): ") + string_vprintf(_C("Member %ld of group '%s' does not accept configuration."), member_id, group_name.c_str())); } OSyncGroup *group = m_priv->osync_env_find_group(m_priv->env, group_name.c_str()); if( !group ) throw std::runtime_error(string("SetConfiguration(): ") + _C("Group not found: ") + group_name); OSyncMember *member = m_priv->osync_member_from_id(group, member_id); if( !member ) { throw std::runtime_error(string("SetConfiguration(): ") + string_vprintf(_C("Member %ld not found."), member_id)); } m_priv->osync_member_set_config(member, config_data.c_str(), config_data.size()); OSyncError *error = NULL; if( !m_priv->osync_member_save(member, &error) ) { std::runtime_error err(string("SetConfiguration(): ") + _C("Unable to save member's config: ") + m_priv->osync_error_print(&error)); m_priv->osync_error_free(&error); throw err; } } void OpenSync22::Discover(const std::string &group_name) { // Discover is a successful noop on 0.22 } void OpenSync22::Sync(const std::string &group_name, SyncStatus &status_callback, Config::pst_type sync_types) { OSyncGroup *group = m_priv->osync_env_find_group(m_priv->env, group_name.c_str()); if( !group ) throw std::runtime_error(string("Sync(): ") + _C("Group not found: ") + group_name); // enable/disable each objtype, as per sync_types if( !(sync_types & PST_DO_NOT_SET) ) { cerr << "enabling objtypes: " << sync_types << endl; m_priv->osync_group_set_objtype_enabled(group, "contact", (sync_types & PST_CONTACTS) ? TRUE : FALSE); m_priv->osync_group_set_objtype_enabled(group, "event", (sync_types & PST_EVENTS) ? TRUE : FALSE); m_priv->osync_group_set_objtype_enabled(group, "note", (sync_types & PST_NOTES) ? TRUE : FALSE); m_priv->osync_group_set_objtype_enabled(group, "todo", (sync_types & PST_TODOS) ? TRUE : FALSE); } OSyncError *error = NULL; EngineHandle engine(m_priv->osengine_free); engine = m_priv->osengine_new(group, &error); if( !engine.get() ) { std::ostringstream oss; oss << _C("Error while synchronizing: ") << m_priv->osync_error_print(&error); m_priv->osync_error_free(&error); throw std::runtime_error(oss.str()); } CallbackBundle22 cbdata(m_priv, status_callback); m_priv->osengine_set_memberstatus_callback(engine.get(), &member_status, &cbdata); m_priv->osengine_set_changestatus_callback(engine.get(), &entry_status, &cbdata); m_priv->osengine_set_enginestatus_callback(engine.get(), &engine_status, &cbdata); m_priv->osengine_set_mappingstatus_callback(engine.get(), &mapping_status, &cbdata); m_priv->osengine_set_conflict_callback(engine.get(), &conflict_handler, &cbdata); if( !m_priv->osengine_init(engine.get(), &error) ) { ostringstream oss; oss << _C("Error initializing osengine: ") << m_priv->osync_error_print(&error); m_priv->osync_error_free(&error); throw std::runtime_error(oss.str()); } // successfully initialized, so finalize must be called EngineHandle initialized_engine(m_priv->osengine_finalize); initialized_engine = engine.get(); if( !m_priv->osengine_sync_and_block(engine.get(), &error) ) { ostringstream oss; oss << _C("Error during sync: ") << m_priv->osync_error_print(&error); m_priv->osync_error_free(&error); throw std::runtime_error(oss.str()); } } } // namespace OpenSync barry-0.18.5/desktop/src/ModemDlg.h0000644001161500056700000000345312242254476016362 0ustar cdfreycdfrey/// /// \file ModemDlg.h /// Dialog class to handle modem functionality /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYDESKTOP_MODEM_DLG_H__ #define __BARRYDESKTOP_MODEM_DLG_H__ #include #include #include #include // begin wxGlade: ::dependencies // end wxGlade // begin wxGlade: ::extracode // end wxGlade namespace Barry { class Pin; } class ModemDlg : public wxDialog { public: // begin wxGlade: ModemDlg::ids // end wxGlade private: // begin wxGlade: ModemDlg::methods void set_properties(); void do_layout(); // end wxGlade protected: // begin wxGlade: ModemDlg::attributes wxStaticBox* sizer_5_staticbox; wxStaticBox* sizer_1_staticbox; wxStaticText* label_2; wxStaticText* device_label; wxListBox* list_box_1; wxStaticText* label_1; wxTextCtrl* text_ctrl_1; // end wxGlade wxSizer *bottom_buttons; wxSizer *m_top_sizer; public: ModemDlg(wxWindow* parent, const std::vector &peers, const std::string &default_peer, const Barry::Pin &pin); std::string GetPeerName() const; std::string GetPassword() const; static void DoModem(wxWindow *parent, const Barry::Pin &pin); }; // wxGlade: end class #endif // MODEMDLG_H barry-0.18.5/desktop/src/guitimet.cc0000644001161500056700000000201412242254476016647 0ustar cdfreycdfrey/// /// \file guitimet.cc /// Object to hold the date/time data of a set of GUI controls /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include #include "guitimet.h" void GUITimeT::Set(time_t t) { m_date.Set(t); m_hour = m_date.GetHour(); m_min = m_date.GetMinute(); } time_t GUITimeT::Get() const { wxDateTime tmp = m_date.GetDateOnly(); tmp.SetHour(m_hour); tmp.SetMinute(m_min); return tmp.GetTicks(); } barry-0.18.5/desktop/configure.ac0000644001161500056700000001763712242254476016231 0ustar cdfreycdfrey# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. # # Parts taken from the pkg.m4 file from pkg-config # Copyright 2004 Scott James Remnant # AC_PREREQ(2.61) AC_INIT([barrydesktop], [0.18.5], [barry-devel@lists.sourceforge.net]) #AM_CONFIG_HEADER(config.h) AC_CONFIG_SRCDIR([src/barrydesktop.cc]) AC_CONFIG_HEADERS([config.h:config.h.in]) AC_CONFIG_AUX_DIR([.]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE AM_GNU_GETTEXT([external]) # this is the version of gettext, not barry AM_GNU_GETTEXT_VERSION([0.18.1]) # # Barry Desktop Version Numbers # # Be sure to keep BARRY_DESKTOP_MAJOR == BARRY_MAJOR from ../configure.ac! # (see desktop/src/Makefile.am for the reason) # BARRY_DESKTOP_LOGICAL=0 BARRY_DESKTOP_MAJOR=18 BARRY_DESKTOP_MINOR=5 AC_DEFINE_UNQUOTED([BARRY_DESKTOP_LOGICAL], [$BARRY_DESKTOP_LOGICAL], [Logical version number]) AC_DEFINE_UNQUOTED([BARRY_DESKTOP_MAJOR], [$BARRY_DESKTOP_MAJOR], [Major library version number]) AC_DEFINE_UNQUOTED([BARRY_DESKTOP_MINOR], [$BARRY_DESKTOP_MINOR], [Minor library version number]) AC_DEFINE_UNQUOTED([BARRY_DESKTOP_VER_STRING], ["${BARRY_DESKTOP_LOGICAL}.${BARRY_DESKTOP_MAJOR}.${BARRY_DESKTOP_MINOR}"], [Full Barry Desktop version in string form]) AC_SUBST([BARRY_DESKTOP_LOGICAL]) AC_SUBST([BARRY_DESKTOP_MAJOR]) AC_SUBST([BARRY_DESKTOP_MINOR]) # # Checks for programs. # AC_PROG_CC AC_PROG_CXX AC_PROG_MAKE_SET AC_PROG_LIBTOOL AC_LANG([C]) PKG_CHECK_MODULES([LIBGCAL], [libgcal >= 0.9.6], [], [ LGTEMP_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -lgcal" AC_RUN_IFELSE( [AC_LANG_PROGRAM( [[ #include #include #include int get_the_url(char *data, int length, char **url); void xmlCleanupParser(void) { // if this gets called, the libgcal we are using is broken exit(1); } ]], [[ const char *xml = ""; char *dest; get_the_url(xml, strlen(xml), &dest); ]] ) ], [LG_TRY_AGAIN=yes], [AC_MSG_ERROR( [ Your copy of libgcal is older than 0.9.6, and it contains this bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=597153 You will need to upgrade to avoid segfaults when syncing with Google calendar. ] )], [AC_MSG_ERROR( [ Your copy of libgcal is older than 0.9.6. Since you are cross-compiling it is not possible to easily check whether the following bug exists in your copy or not: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=597153 Please upgrade and try again. ] )] ) LDFLAGS="$LGTEMP_LDFLAGS" if test "$LG_TRY_AGAIN" = "yes" ; then AC_MSG_RESULT([found patched libgcal...]) PKG_CHECK_MODULES([LIBGCAL], [libgcal >= 0.9.4]) fi ] ) AC_LANG([C++]) # # Search for a GUI-style version of su. If not specified, we search for # gksu (for Debian), beesu (for Fedora), and kdesu (for openSUSE), # searched in the above order. # # User can override with the option. # AC_ARG_WITH([guisu], [AS_HELP_STRING([--with-guisu=CMD], [specify GUI oriented su wrapper program @<:@default: searches for gksu, beesu, or kdesu in that order@:>@])], [ GUISU="$with_guisu" AC_MSG_NOTICE([Using user-specified GUI su wrapper: $GUISU]) ], [ if test -x /usr/bin/gksu ; then GUISU="gksu" AC_MSG_NOTICE([Found GUI su wrapper: gksu]) elif test -x /usr/bin/beesu ; then GUISU="beesu" AC_MSG_NOTICE([Found GUI su wrapper: beesu]) elif test -x /usr/bin/kdesu ; then GUISU="kdesu" AC_MSG_NOTICE([Found GUI su wrapper: kdesu]) else AC_MSG_ERROR([Unable to find a GUI oriented su wrapper. This is required for modem operation, in case permissions are not set on pppd properly. Please specify the GUI su wrapper you wish to use with the --with-guisu configure option. Note that it MUST be a GUI. You cannot use the command line su. ]) fi ]) AC_SUBST([GUISU]) # # Check for Evolution data server libraries, and allow user to disable # if needed. # AC_ARG_WITH([evolution], [AS_HELP_STRING([--with-evolution], [use evolution libs to help configure sync (yes,no,check) @<:@default=check@:>@])], [], [with_evolution=check]) if test "x$with_evolution" != xno ; then PKG_CHECK_MODULES([EVOLUTION], [libebook-1.2 libecal-1.2 libedataserver-1.2], [ AC_DEFINE([HAVE_EVOLUTION], [1], [Define to 1 if Evolution data server libraries are available.]) ], [ if test "x$with_evolution" != xcheck; then AC_MSG_FAILURE([--with-evolution was given, but test for evolution failed]) fi ]) fi PKG_CHECK_MODULES([BARRY], [libbarry-18 libbarrysync-18 libbarrybackup-18]) PKG_CHECK_MODULES([GLIB2], [glib-2.0]) PKG_CHECK_MODULES([LIBXMLPP], [libxml++-2.6]) PKG_CHECK_MODULES([OPENSYNC22], [opensync-1.0], [], [OS22NOTFOUND=yes]) PKG_CHECK_MODULES([OPENSYNC40], [libopensync1], [], [OS40NOTFOUND=yes]) if test "$OS22NOTFOUND" = "yes" -a "$OS40NOTFOUND" = "yes" ; then AC_MSG_WARN(dnl [ ************************************************************************* WARNING: Unable to find development libraries for either opensync 0.22 or 0.4x. Barry Desktop will be built without any sync support. ************************************************************************* If this is not desired, consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables: OPENSYNC22_CFLAGS and OPENSYNC22_LIBS or OPENSYNC40_CFLAGS and OPENSYNC40_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. ]) fi AM_CONDITIONAL([WITH_OPENSYNC22], [test "$OS22NOTFOUND" != "yes"]) AM_CONDITIONAL([WITH_OPENSYNC40], [test "$OS40NOTFOUND" != "yes"]) # Carry the special tree build environment variables from parent configure, # just in case user is doing a complete tree build with --enable-desktop AC_SUBST(TREE_BUILD_CXXFLAGS) AC_SUBST(TREE_BUILD_LDFLAGS) # Check for wxWidgets libraries AM_OPTIONS_WXCONFIG AM_PATH_WXCONFIG([2.8.0], [], [ AC_MSG_ERROR([ wxWidgets is required to build the Barry desktop, but the wx-config script could not be found. Please check that wx-config is in your path, that the directory where wxWidgets libraries are installed (returned by the 'wx-config --libs' command) is in LD_LIBRARY_PATH, and that wxWidgets is version 2.3.4 or above. ]) ]) # Setup system directories, so src/Makefile.am can use them for the compile # and for the image/data file installations. (image_DATA) basedatadir="$datadir/barry/desktop/" imagedir="$datadir/barry/desktop/images/" xmlmap22dir="$datadir/barry/desktop/0.22/" xmlmap40dir="$datadir/barry/desktop/0.40/" AC_SUBST(basedatadir) AC_SUBST(imagedir) AC_SUBST(xmlmap22dir) AC_SUBST(xmlmap40dir) # Checks for libraries. AC_CHECK_LIB([pthread], [main]) # Checks for header files. AC_HEADER_DIRENT AC_HEADER_STDC AC_CHECK_HEADERS([assert.h stdint.h time.h]) # Checks for typedefs, structures, and compiler characteristics. #AC_TYPE_SIZE_T AC_HEADER_TIME AC_STRUCT_TM # Checks for library functions. AC_FUNC_CLOSEDIR_VOID AC_PROG_GCC_TRADITIONAL AC_FUNC_MALLOC AC_FUNC_MKTIME AC_FUNC_REALLOC AC_FUNC_SELECT_ARGTYPES AC_FUNC_STAT AC_CHECK_FUNCS([bzero gettimeofday memset select strcasecmp strchr strerror strtol strtoul]) AC_CONFIG_FILES([Makefile po/Makefile.in po-osyncwrap/Makefile.in images/Makefile src/Makefile src/0.22/Makefile src/0.40/Makefile man/Makefile]) AC_OUTPUT # # Add a special hack at the end, to let the user disable RPATH if he wants. # # http://wiki.debian.org/RpathIssue # http://lists.debian.org/debian-devel/2003/debian-devel-200306/msg00569.html # http://fedoraproject.org/wiki/Packaging:Guidelines#Removing_Rpath # AC_ARG_ENABLE([rpathhack], [AC_HELP_STRING([--enable-rpathhack], [patch libtool to remove RPATH])], [ AC_MSG_RESULT([patching libtool to fix HIDEOUS BREAKAGE]) sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool ], []) barry-0.18.5/desktop/TODO0000644001161500056700000000331312242254476014415 0ustar cdfreycdfreyRelease TODO List: ================== - package barrydesktop so that all .o files are included, to comply with the LGPL (wxWidgets) Feature TODO List: ================== - menu item: reset current device, wait, and rescan Sync: ----- - test 0.4x, and see if it is possible to do a clean one-way sync without deleting all 4 databases... on 0.22 this seems to cause opensync to go into a stupendously long busy loop... maybe 0.4x is better - 0.4x has a CheckSummary state, that shows what changes are going to happen just before the sync happens... in the command line version, this is shown in a text table... should create a dialog for the user to approve first... perhaps make this a config option, so that the user doesn't have to confirm on each sync if he doesn't want to Wishlist TODO List: =================== - menu item: direct logging to a file - or, log to a stringstream... this can always be added later if grabbing the verbose data from stderr is not enough - hook into HAL or inotify or udev somehow, to automatically detect when a new device has been unplugged or plugged in, and do a usb scan immediately, and update the lists, in the main screen, and in sync - add timer to screenshot, so it updates every second Dieter Rams' ten principles to "good design" ============================================ * Good design is innovative * Good design makes a product useful * Good design is aesthetic * Good design makes a product understandable * Good design is unobtrusive * Good design is honest * Good design is long-lasting * Good design is thorough down to the last detail * Good design is environmentally friendly * Good design is as little design as possible http://en.wikipedia.org/wiki/Dieter_Rams barry-0.18.5/desktop/Makefile.am0000644001161500056700000000022512242254476015760 0ustar cdfreycdfreyACLOCAL_FLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = COPYING ChangeLog README buildgen.sh \ doc SUBDIRS = po po-osyncwrap . images src man barry-0.18.5/desktop/po-osyncwrap/0000755001161500056700000000000012242254476016366 5ustar cdfreycdfreybarry-0.18.5/desktop/po-osyncwrap/insert-header.sin0000644001161500056700000000124012242254476021630 0ustar cdfreycdfrey# Sed script that inserts the file called HEADER before the header entry. # # At each occurrence of a line starting with "msgid ", we execute the following # commands. At the first occurrence, insert the file. At the following # occurrences, do nothing. The distinction between the first and the following # occurrences is achieved by looking at the hold space. /^msgid /{ x # Test if the hold space is empty. s/m/m/ ta # Yes it was empty. First occurrence. Read the file. r HEADER # Output the file's contents by reading the next line. But don't lose the # current line while doing this. g N bb :a # The hold space was nonempty. Following occurrences. Do nothing. x :b } barry-0.18.5/desktop/po-osyncwrap/barryosyncwrap.pot0000644001161500056700000003020312242254476022175 0ustar cdfreycdfrey# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Net Direct, Inc. # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: barrydesktop 0.18.5\n" "Report-Msgid-Bugs-To: http://netdirect.ca/barry\n" "POT-Creation-Date: 2013-04-02 18:54-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: src/blistevo.cc:47 msgid "Defaultable: " msgstr "" #: src/blistevo.cc:48 msgid "Yes" msgstr "" #: src/blistevo.cc:48 msgid "No" msgstr "" #: src/blistevo.cc:49 msgid "Error during detect: " msgstr "" #: src/blistevo.cc:51 msgid "(none)" msgstr "" #: src/blistevo.cc:53 msgid "Results:" msgstr "" #: src/blistevo.cc:55 msgid "Addressbook:" msgstr "" #: src/blistevo.cc:57 msgid "Events:" msgstr "" #: src/blistevo.cc:59 msgid "Tasks:" msgstr "" #: src/blistevo.cc:61 msgid "Memos:" msgstr "" #: src/bsynccl.cc:140 msgid "" "This is a helper program for barrydesktop, and\n" "is not intended to be called directly.\n" msgstr "" #: src/null-os22.cc:30 src/null-os22.cc:87 src/null-os22.cc:145 #: src/null-os22.cc:150 src/null-os22.cc:155 src/null-os22.cc:160 #: src/null-os22.cc:165 src/null-os22.cc:170 src/null-os22.cc:241 #: src/null-os40.cc:85 src/null-os40.cc:152 src/null-os40.cc:157 #: src/null-os40.cc:162 src/null-os40.cc:167 src/null-os40.cc:172 #: src/null-os40.cc:177 msgid "Not supported on this system." msgstr "" #: src/null-os22.cc:40 msgid "OpenSync 0.22 support was not compiled in." msgstr "" #: src/null-os40.cc:38 msgid "OpenSync 0.4x support was not compiled in." msgstr "" #: src/deviceset.cc:195 src/deviceset.cc:196 msgid "yes" msgstr "" #: src/deviceset.cc:195 src/deviceset.cc:196 msgid "no" msgstr "" #: src/os22.cc:250 src/os40.cc:548 msgid "ADDED" msgstr "" #: src/os22.cc:251 src/os40.cc:549 msgid "UNMODIFIED" msgstr "" #: src/os22.cc:252 src/os40.cc:550 msgid "DELETED" msgstr "" #: src/os22.cc:253 src/os40.cc:551 msgid "MODIFIED" msgstr "" #: src/os22.cc:293 msgid "Bad change_id, or error getting nth change object." msgstr "" #: src/os22.cc:317 msgid "Conflict not ignored: " msgstr "" #: src/os22.cc:332 msgid "Conflict not resolved: " msgstr "" #: src/os22.cc:383 #, c-format msgid "Member %lld (%s) just connected" msgstr "" #: src/os22.cc:386 #, c-format msgid "Member %lld (%s) just disconnected" msgstr "" #: src/os22.cc:389 #, c-format msgid "Member %lld (%s) just sent all changes" msgstr "" #: src/os22.cc:392 #, c-format msgid "Member %lld (%s) committed all changes" msgstr "" #: src/os22.cc:395 #, c-format msgid "Member %lld (%s) had an error while connecting: %s" msgstr "" #: src/os22.cc:399 #, c-format msgid "Member %lld (%s) had an error while getting changes: %s" msgstr "" #: src/os22.cc:404 #, c-format msgid "Member %lld (%s) had an error while calling sync done: %s" msgstr "" #: src/os22.cc:409 #, c-format msgid "Member %lld (%s) had an error while disconnecting: %s" msgstr "" #: src/os22.cc:414 #, c-format msgid "Member %lld (%s) had an error while commiting changes: %s" msgstr "" #: src/os22.cc:439 src/os40.cc:1038 msgid "member_status error: " msgstr "" #: src/os22.cc:443 src/os40.cc:1042 msgid "Unknown exception caught in member_status()" msgstr "" #: src/os22.cc:461 #, c-format msgid "Received an entry %s without data from member %d (%s). Change type: %s" msgstr "" #: src/os22.cc:468 #, c-format msgid "" "Received an entry %s with data of size %d from member %d (%s). Change type: " "%s" msgstr "" #: src/os22.cc:476 #, c-format msgid "Sent an entry %s of size %d to member %d (%s). Change type: %s" msgstr "" #: src/os22.cc:485 #, c-format msgid "Error writing entry %s to member %d (%s): %s" msgstr "" #: src/os22.cc:493 #, c-format msgid "Error reading entry %s from member %d (%s): %s" msgstr "" #: src/os22.cc:508 msgid "entry_status error:" msgstr "" #: src/os22.cc:512 src/os40.cc:846 msgid "Unknown exception caught in entry_status()" msgstr "" #: src/os22.cc:527 msgid "The previous synchronization was unclean. Slow-syncing." msgstr "" #: src/os22.cc:530 src/os40.cc:901 msgid "All clients connected or error" msgstr "" #: src/os22.cc:533 src/os40.cc:939 msgid "All conflicts have been reported" msgstr "" #: src/os22.cc:536 src/os40.cc:907 msgid "All clients sent changes or error" msgstr "" #: src/os22.cc:539 src/os40.cc:922 msgid "All clients have written" msgstr "" #: src/os22.cc:542 src/os40.cc:925 msgid "All clients have disconnected" msgstr "" #: src/os22.cc:545 src/os40.cc:932 msgid "The sync was successful" msgstr "" #: src/os22.cc:548 src/os40.cc:929 msgid "The sync failed: " msgstr "" #: src/os22.cc:562 src/os40.cc:954 msgid "engine_status error: " msgstr "" #: src/os22.cc:566 src/os40.cc:958 msgid "Unknown exception caught in engine_status()" msgstr "" #: src/os22.cc:581 src/os40.cc:863 msgid "Mapping solved" msgstr "" #: src/os22.cc:584 msgid "Mapping Synced" msgstr "" #: src/os22.cc:588 msgid "Mapping Write Error: " msgstr "" #: src/os22.cc:599 src/os40.cc:879 msgid "mapping_status error: " msgstr "" #: src/os22.cc:603 src/os40.cc:883 msgid "Unknown exception caught in mapping_status()" msgstr "" #: src/os22.cc:625 src/os40.cc:789 msgid "Conflict not resolved. " msgstr "" #: src/os22.cc:629 src/os40.cc:793 msgid "Unknown exception caught in conflict_handler()" msgstr "" #: src/os22.cc:755 msgid "Error allocating opensync 0.22 environment" msgstr "" #: src/os22.cc:808 msgid "Unable to load format environment in GetFormats (22)" msgstr "" #: src/os22.cc:850 src/os40.cc:1862 msgid "Unable to find group with name: " msgstr "" #: src/os22.cc:877 msgid "Group already exists: " msgstr "" #: src/os22.cc:885 msgid "Unable to save group: " msgstr "" #: src/os22.cc:898 src/os22.cc:919 src/os22.cc:944 src/os22.cc:975 #: src/os22.cc:1009 src/os22.cc:1037 src/os40.cc:1911 src/os40.cc:1930 #: src/os40.cc:1957 src/os40.cc:1989 src/os40.cc:2018 src/os40.cc:2069 #: src/os40.cc:2102 src/os40.cc:2147 src/os40.cc:2188 msgid "Group not found: " msgstr "" #: src/os22.cc:902 msgid "Unable to delete group: " msgstr "" #: src/os22.cc:925 msgid "Unable to connect plugin with member: " msgstr "" #: src/os22.cc:931 msgid "Unable to save member: " msgstr "" #: src/os22.cc:949 src/os40.cc:1962 src/os40.cc:1979 src/os40.cc:1994 #: src/os40.cc:2023 src/os40.cc:2074 src/os40.cc:2107 msgid "Member not found: " msgstr "" #: src/os22.cc:956 msgid "Unable to determine needed config: " msgstr "" #: src/os22.cc:968 src/os22.cc:1002 src/os40.cc:2011 src/os40.cc:2062 #: src/os40.cc:2095 #, c-format msgid "Member %ld of group '%s' does not accept configuration." msgstr "" #: src/os22.cc:979 src/os22.cc:1013 #, c-format msgid "Member %ld not found." msgstr "" #: src/os22.cc:986 msgid "Unable to retrieve config: " msgstr "" #: src/os22.cc:1020 msgid "Unable to save member's config: " msgstr "" #: src/os22.cc:1057 msgid "Error while synchronizing: " msgstr "" #: src/os22.cc:1078 msgid "Error initializing osengine: " msgstr "" #: src/os22.cc:1090 msgid "Error during sync: " msgstr "" #: src/os40.cc:447 msgid "(NULL error msg)" msgstr "" #: src/os40.cc:610 msgid "Problems while aborting: " msgstr "" #: src/os40.cc:812 #, c-format msgid "Received an entry %s (%s) from member %d (%s): %s" msgstr "" #: src/os40.cc:817 #, c-format msgid "Sent an entry %s (%s) to member %d (%s): %s" msgstr "" #: src/os40.cc:823 #, c-format msgid "Error for entry %s (%s) and member %d (%s): %s" msgstr "" #: src/os40.cc:842 msgid "entry_status error: " msgstr "" #: src/os40.cc:868 msgid "Mapping error: " msgstr "" #: src/os40.cc:910 msgid "All changes got mapped" msgstr "" #: src/os40.cc:913 msgid "All changes got multiplied" msgstr "" #: src/os40.cc:916 msgid "All changes got prepared for write" msgstr "" #: src/os40.cc:935 msgid "The previous synchronization was unclean. Slow-syncing" msgstr "" #: src/os40.cc:942 msgid "All clients reported sync done" msgstr "" #: src/os40.cc:974 msgid "Main sink" msgstr "" #: src/os40.cc:976 #, c-format msgid "%s sink" msgstr "" #. TRANSLATORS: resulting message may look like this: #. "Main sink of member 5 (barry-sync) just connected" #. The "Main sink" part is based on the "Main sink" #. string or the "%s sink" string. #: src/os40.cc:990 #, c-format msgid "%s of member %d (%s) just connected" msgstr "" #: src/os40.cc:997 #, c-format msgid "%s of member %d (%s) just disconnected" msgstr "" #: src/os40.cc:1000 #, c-format msgid "%s of member %d (%s) just sent all changes" msgstr "" #: src/os40.cc:1003 #, c-format msgid "%s of member %d (%s) committed all changes" msgstr "" #: src/os40.cc:1006 #, c-format msgid "%s of member %d (%s) reported sync done" msgstr "" #: src/os40.cc:1009 #, c-format msgid "%s of member %d (%s) discovered its objtypes" msgstr "" #: src/os40.cc:1012 #, c-format msgid "%s of member %d (%s) had an error: %s" msgstr "" #: src/os40.cc:1067 msgid "Error handling summary item. " msgstr "" #: src/os40.cc:1071 msgid "Unknown exception caught in multiply_summary()" msgstr "" #: src/os40.cc:1440 msgid "Username (authentication parameter) is not supported in plugin!" msgstr "" #: src/os40.cc:1478 msgid "Password authentication is not supported in plugin!" msgstr "" #: src/os40.cc:1934 msgid "Plugin not found: " msgstr "" #: src/os40.cc:2000 src/os40.cc:2029 src/os40.cc:2080 src/os40.cc:2113 msgid "Unable to find plugin with name: " msgstr "" #: src/os40.cc:2167 msgid "discover failed: no objtypes returned" msgstr "" #: src/osbase.cc:158 msgid "" "Which entry do you want to use?\n" "[1-9] To select a side" msgstr "" #: src/osbase.cc:162 msgid ", [A]bort" msgstr "" #: src/osbase.cc:164 msgid ", [D]uplicate" msgstr "" #: src/osbase.cc:167 msgid ", [I]gnore" msgstr "" #: src/osbase.cc:170 msgid ", Keep [N]ewer" msgstr "" #: src/osbase.cc:267 msgid "Conflicting items:" msgstr "" #: src/osbase.cc:289 msgid "Abort not supported!" msgstr "" #: src/osbase.cc:300 msgid "Ignore not supported!" msgstr "" #: src/osbase.cc:307 msgid "Keep Newer not supported!" msgstr "" #: src/osbase.cc:319 src/osbase.cc:326 src/osbase.cc:333 src/osbase.cc:343 msgid "ERROR: " msgstr "" #: src/osbase.cc:349 msgid "Synchronization Forecast Summary:" msgstr "" #: src/osbase.cc:352 msgid "Do you want to continue the synchronization? (N/y): " msgstr "" #: src/osbase.cc:358 msgid "Aborting! Synchronization got aborted by user!" msgstr "" #: src/osbase.cc:361 msgid "OK! Completing synchronization!" msgstr "" #: src/osbase.cc:368 msgid "CALLBACK ERROR: " msgstr "" #: src/osbase.cc:413 msgid "Unable to load opensync 0.40: " msgstr "" #: src/osbase.cc:423 msgid "Unable to load opensync 0.22: " msgstr "" #: src/osconfig.cc:42 msgid "Unsupported" msgstr "" #: src/osconfig.cc:54 msgid "Barry config must have valid pin number." msgstr "" #: src/osconfig.cc:73 msgid "" "Unable to load pin number from Barry plugin config. Consider this group " "corrupt, or not fully configured: " msgstr "" #: src/osconfig.cc:114 #, c-format msgid "No Barry plugins found in group '%s' and OSCG_THROW_ON_NO_BARRY is set." msgstr "" #: src/osconfig.cc:119 #, c-format msgid "" "Found %d Barry plugins in group '%s' and OSCG_THROW_ON_MULTIPLE_BARRIES is " "set." msgstr "" #: src/osconfig.cc:307 #, c-format msgid "" "Unsupported plugin '%s' in group '%s' and OSCG_THROW_ON_UNSUPPORTED is set." msgstr "" #: src/osconfig.cc:337 msgid "" "Cannot delete individual members from an OpenSync group with versions < 0.40." msgstr "" #: src/osconfig.cc:349 #, c-format msgid "Tried to delete non-existent member ID %ld (%s) from group '%s'" msgstr "" #: src/osconfig.cc:356 #, c-format msgid "" "Tried to delete member ID %ld using plugin '%s' from group '%s', but the " "existing member uses plugin '%s'" msgstr "" #: src/osconfig.cc:378 #, c-format msgid "" "Tried to overwrite group '%s' with a Group set that did not match in ID's " "and plugin names." msgstr "" #: src/osconv22.cc:304 src/osconv22.cc:321 src/osconv22.cc:358 #: src/osconv40.cc:269 src/osconv40.cc:307 src/osconv40.cc:344 #: src/osconv40.cc:370 msgid "Cannot save a plugin with a member_id of -1" msgstr "" #: src/tempdir.cc:40 msgid "Cannot create temp directory: " msgstr "" barry-0.18.5/desktop/po-osyncwrap/boldquot.sed0000644001161500056700000000033112242254476020711 0ustar cdfreycdfreys/"\([^"]*\)"/“\1”/g s/`\([^`']*\)'/‘\1’/g s/ '\([^`']*\)' / ‘\1’ /g s/ '\([^`']*\)'$/ ‘\1’/g s/^'\([^`']*\)' /‘\1’ /g s/“”/""/g s/“/“/g s/”/”/g s/‘/‘/g s/’/’/g barry-0.18.5/desktop/po-osyncwrap/fr.po0000644001161500056700000004440212242254476017341 0ustar cdfreycdfrey# Barry Desktop French Translation # Copyright (C) 2012-2013 Net Direct, Inc. # This file is distributed under the same license as the Barry Desktop package. # Copyright Nicolas CARRIER , 2012 # msgid "" msgstr "" "Project-Id-Version: barrydesktop 0.18.5\n" "Report-Msgid-Bugs-To: http://netdirect.ca/barry\n" "POT-Creation-Date: 2013-04-02 18:54-0400\n" "PO-Revision-Date: 2012-08-05 18:16+0100\n" "Last-Translator: Nicolas CARRIER \n" "Language-Team: Barry\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: ..\n" #: src/blistevo.cc:47 msgid "Defaultable: " msgstr "" #: src/blistevo.cc:48 #, fuzzy msgid "Yes" msgstr "oui" #: src/blistevo.cc:48 msgid "No" msgstr "" #: src/blistevo.cc:49 #, fuzzy msgid "Error during detect: " msgstr "Erreur lors de la synchronisation : " #: src/blistevo.cc:51 msgid "(none)" msgstr "" #: src/blistevo.cc:53 msgid "Results:" msgstr "" #: src/blistevo.cc:55 msgid "Addressbook:" msgstr "French Addressbook:" #: src/blistevo.cc:57 msgid "Events:" msgstr "Évenements" #: src/blistevo.cc:59 msgid "Tasks:" msgstr "Tâches :" #: src/blistevo.cc:61 msgid "Memos:" msgstr "Mémos :" #: src/bsynccl.cc:140 msgid "" "This is a helper program for barrydesktop, and\n" "is not intended to be called directly.\n" msgstr "" "Ceci est un programme utilitaire pour barrydesktop et\n" "n'est pas prévu pour être appelé directement.\n" #: src/null-os22.cc:30 src/null-os22.cc:87 src/null-os22.cc:145 #: src/null-os22.cc:150 src/null-os22.cc:155 src/null-os22.cc:160 #: src/null-os22.cc:165 src/null-os22.cc:170 src/null-os22.cc:241 #: src/null-os40.cc:85 src/null-os40.cc:152 src/null-os40.cc:157 #: src/null-os40.cc:162 src/null-os40.cc:167 src/null-os40.cc:172 #: src/null-os40.cc:177 msgid "Not supported on this system." msgstr "Non supporté sur ce système" #: src/null-os22.cc:40 msgid "OpenSync 0.22 support was not compiled in." msgstr "French OpenSync 0.22 support was not compiled in." #: src/null-os40.cc:38 msgid "OpenSync 0.4x support was not compiled in." msgstr "French OpenSync 0.4x support was not compiled in." #: src/deviceset.cc:195 src/deviceset.cc:196 msgid "yes" msgstr "oui" #: src/deviceset.cc:195 src/deviceset.cc:196 msgid "no" msgstr "non" #: src/os22.cc:250 src/os40.cc:548 msgid "ADDED" msgstr "AJOUTÉ" #: src/os22.cc:251 src/os40.cc:549 msgid "UNMODIFIED" msgstr "NON MODIFIÉ" #: src/os22.cc:252 src/os40.cc:550 msgid "DELETED" msgstr "SUPPRIMÉ" #: src/os22.cc:253 src/os40.cc:551 msgid "MODIFIED" msgstr "MODIFIÉ" #: src/os22.cc:293 msgid "Bad change_id, or error getting nth change object." msgstr "" "change_id invalide ou erreur lors de la récupération du nième objet change." #: src/os22.cc:317 msgid "Conflict not ignored: " msgstr "Conflit non ignoré : " #: src/os22.cc:332 msgid "Conflict not resolved: " msgstr "Conflit non résolu : " #: src/os22.cc:383 #, c-format msgid "Member %lld (%s) just connected" msgstr "Le membre %lld (%s) vient de se connecter" #: src/os22.cc:386 #, c-format msgid "Member %lld (%s) just disconnected" msgstr "Le membre %lld (%s) vient de se déconnecter" #: src/os22.cc:389 #, c-format msgid "Member %lld (%s) just sent all changes" msgstr "Le membre %lld (%s) vient d'envoyer tous les changements" #: src/os22.cc:392 #, c-format msgid "Member %lld (%s) committed all changes" msgstr "Le membre %lld (%s) vient de valider tous les changements" #: src/os22.cc:395 #, c-format msgid "Member %lld (%s) had an error while connecting: %s" msgstr "Le membre %lld (%s) a rencontré un erreur lors de la connectino : %s" #: src/os22.cc:399 #, c-format msgid "Member %lld (%s) had an error while getting changes: %s" msgstr "" "Le membre %lld (%s) a rencontré une erreur lors de la récupération des " "modifications : %s" #: src/os22.cc:404 #, c-format msgid "Member %lld (%s) had an error while calling sync done: %s" msgstr "" "Le membre %lld (%s) a rencontré une erreur quand l'appel à sync a été " "effectué : %s" #: src/os22.cc:409 #, c-format msgid "Member %lld (%s) had an error while disconnecting: %s" msgstr "Le membre %lld (%s) a rencontré une erreur à la déconnexion : %s" #: src/os22.cc:414 #, c-format msgid "Member %lld (%s) had an error while commiting changes: %s" msgstr "" "Le membre %lld (%s) a rencontré une erreur à la validation des changements : " "%s" #: src/os22.cc:439 src/os40.cc:1038 msgid "member_status error: " msgstr "Erreur dans member_status :" #: src/os22.cc:443 src/os40.cc:1042 msgid "Unknown exception caught in member_status()" msgstr "Exception inconnue attrapée dans member_status()" #: src/os22.cc:461 #, c-format msgid "Received an entry %s without data from member %d (%s). Change type: %s" msgstr "" "Une entrée %s a été reçue sans donnée, du membre %d (%s). Type de " "changement : %s" #: src/os22.cc:468 #, c-format msgid "" "Received an entry %s with data of size %d from member %d (%s). Change type: " "%s" msgstr "" "Une entrée %s a été reçue avec %d octets de données, du membre %d (%s). Type " "de changement : %s" #: src/os22.cc:476 #, c-format msgid "Sent an entry %s of size %d to member %d (%s). Change type: %s" msgstr "" "Une entrée %s a été envoyée avec %d octets de données, au membre %d (%s). " "Type de changement : %s" #: src/os22.cc:485 #, c-format msgid "Error writing entry %s to member %d (%s): %s" msgstr "Erreur lors de l'écriture de l'entrée %s au membre %d (%s) : %s" #: src/os22.cc:493 #, c-format msgid "Error reading entry %s from member %d (%s): %s" msgstr "Erreur lors de la lecture de l'entrée %s au membre %d (%s) : %s" #: src/os22.cc:508 msgid "entry_status error:" msgstr "Erreur dans entry_status :" #: src/os22.cc:512 src/os40.cc:846 msgid "Unknown exception caught in entry_status()" msgstr "Exception inconnue attrapée dans entry_status()" #: src/os22.cc:527 msgid "The previous synchronization was unclean. Slow-syncing." msgstr "" "La précédente synchronisation n'était pas propre. Synchronisation lente." #: src/os22.cc:530 src/os40.cc:901 msgid "All clients connected or error" msgstr "Tous les clients sont connectés ou une erreur est survenue" #: src/os22.cc:533 src/os40.cc:939 msgid "All conflicts have been reported" msgstr "Tous les conflits ont été signalés" #: src/os22.cc:536 src/os40.cc:907 msgid "All clients sent changes or error" msgstr "" "Tous les clients ont envoyé leurs changements ou une erreur est survenue" #: src/os22.cc:539 src/os40.cc:922 msgid "All clients have written" msgstr "Tous les clients on écrit" #: src/os22.cc:542 src/os40.cc:925 msgid "All clients have disconnected" msgstr "Tous les clients se sont déconnectés" #: src/os22.cc:545 src/os40.cc:932 msgid "The sync was successful" msgstr "La synchronisation a réussi" #: src/os22.cc:548 src/os40.cc:929 msgid "The sync failed: " msgstr "La synchronisation a échoué : " #: src/os22.cc:562 src/os40.cc:954 msgid "engine_status error: " msgstr "Erreur dans engine_status : " #: src/os22.cc:566 src/os40.cc:958 msgid "Unknown exception caught in engine_status()" msgstr "Exception inconnue attrapée dans engine_status()" #: src/os22.cc:581 src/os40.cc:863 msgid "Mapping solved" msgstr "Correspondance résolue" #: src/os22.cc:584 msgid "Mapping Synced" msgstr "Correspondance synchronisée" #: src/os22.cc:588 msgid "Mapping Write Error: " msgstr "Erreur lors de l'écriture de la correspondance : " #: src/os22.cc:599 src/os40.cc:879 msgid "mapping_status error: " msgstr "Erreur dans mapping_status : " #: src/os22.cc:603 src/os40.cc:883 msgid "Unknown exception caught in mapping_status()" msgstr "Exception inconnue attrapée dans mapping_status() : " #: src/os22.cc:625 src/os40.cc:789 msgid "Conflict not resolved. " msgstr "Conflit non résolu." #: src/os22.cc:629 src/os40.cc:793 msgid "Unknown exception caught in conflict_handler()" msgstr "Exception inconnue attrapée dans conflict_handler()" #: src/os22.cc:755 msgid "Error allocating opensync 0.22 environment" msgstr "Erreur lors de l'allocation de l'environnement opensync 0.22." #: src/os22.cc:808 msgid "Unable to load format environment in GetFormats (22)" msgstr "Impossible de charger l'environnement de format dans GetFormats (22)" #: src/os22.cc:850 src/os40.cc:1862 msgid "Unable to find group with name: " msgstr "Impossible de trouver le groupe de nom : " #: src/os22.cc:877 msgid "Group already exists: " msgstr "Le groupe existe déjà : " #: src/os22.cc:885 msgid "Unable to save group: " msgstr "Impossible d'enregistrer le groupe : " #: src/os22.cc:898 src/os22.cc:919 src/os22.cc:944 src/os22.cc:975 #: src/os22.cc:1009 src/os22.cc:1037 src/os40.cc:1911 src/os40.cc:1930 #: src/os40.cc:1957 src/os40.cc:1989 src/os40.cc:2018 src/os40.cc:2069 #: src/os40.cc:2102 src/os40.cc:2147 src/os40.cc:2188 msgid "Group not found: " msgstr "Groupe non trouvé : " #: src/os22.cc:902 msgid "Unable to delete group: " msgstr "Impossible de supprimer le groupe : " #: src/os22.cc:925 msgid "Unable to connect plugin with member: " msgstr "Impossible de connecter le greffon au membre : " #: src/os22.cc:931 msgid "Unable to save member: " msgstr "Impossible d'enregistrer le membre : " #: src/os22.cc:949 src/os40.cc:1962 src/os40.cc:1979 src/os40.cc:1994 #: src/os40.cc:2023 src/os40.cc:2074 src/os40.cc:2107 msgid "Member not found: " msgstr "Membre non trouvé : " #: src/os22.cc:956 msgid "Unable to determine needed config: " msgstr "Impossible de déterminer la configuration requise : " #: src/os22.cc:968 src/os22.cc:1002 src/os40.cc:2011 src/os40.cc:2062 #: src/os40.cc:2095 #, c-format msgid "Member %ld of group '%s' does not accept configuration." msgstr "Le membre %ld du groupe '%s' n'accepte pas de configuration." #: src/os22.cc:979 src/os22.cc:1013 #, c-format msgid "Member %ld not found." msgstr "Le membre %ld n'a pas été trouvé." #: src/os22.cc:986 msgid "Unable to retrieve config: " msgstr "Impossible de récupérer la configuration : " #: src/os22.cc:1020 msgid "Unable to save member's config: " msgstr "Impossible d'enregistrer la configuration du membre : " #: src/os22.cc:1057 msgid "Error while synchronizing: " msgstr "Erreur lors de la synchronisation : " #: src/os22.cc:1078 msgid "Error initializing osengine: " msgstr "Erreur lors de l'initialisation d'osengine : " #: src/os22.cc:1090 msgid "Error during sync: " msgstr "Erreur lors de la synchronisation : " #: src/os40.cc:447 msgid "(NULL error msg)" msgstr "(message d'erreur NULL)" #: src/os40.cc:610 msgid "Problems while aborting: " msgstr "Problèmes lors de l'annulation : " #: src/os40.cc:812 #, c-format msgid "Received an entry %s (%s) from member %d (%s): %s" msgstr "L'entrée %s (%s) a été reçue, de la part du membre %d (%s) : %s" #: src/os40.cc:817 #, c-format msgid "Sent an entry %s (%s) to member %d (%s): %s" msgstr "L'entrée %s (%s) a été envoyée au membre %d (%s) : %s" #: src/os40.cc:823 #, c-format msgid "Error for entry %s (%s) and member %d (%s): %s" msgstr "Erreur concernant l'entrée %s (%s) et le membre %d (%s) : %s" #: src/os40.cc:842 msgid "entry_status error: " msgstr "Erreur dans entry_status : " #: src/os40.cc:868 msgid "Mapping error: " msgstr "Erreur de correspondance : " #: src/os40.cc:910 msgid "All changes got mapped" msgstr "Tous les changements ont trouvé une correspondance" #: src/os40.cc:913 #, fuzzy msgid "All changes got multiplied" msgstr "Tous les changements ont été multipliés" #: src/os40.cc:916 msgid "All changes got prepared for write" msgstr "Tous les changements ont été préparés pour l'écriture" #: src/os40.cc:935 msgid "The previous synchronization was unclean. Slow-syncing" msgstr "" "La précédente synchronisation n'était pas propre. Synchronisation lente." #: src/os40.cc:942 msgid "All clients reported sync done" msgstr "Tous les clients ont indiqué que la synchronisation a été effectuée" #: src/os40.cc:974 msgid "Main sink" msgstr "Sortie principale" #: src/os40.cc:976 #, c-format msgid "%s sink" msgstr "Sortie %s" #. TRANSLATORS: resulting message may look like this: #. "Main sink of member 5 (barry-sync) just connected" #. The "Main sink" part is based on the "Main sink" #. string or the "%s sink" string. #: src/os40.cc:990 #, c-format msgid "%s of member %d (%s) just connected" msgstr "%s du membre %d (%s) vient de se connecter" #: src/os40.cc:997 #, c-format msgid "%s of member %d (%s) just disconnected" msgstr "%s du membre %d (%s) vient de se déconnecter" #: src/os40.cc:1000 #, c-format msgid "%s of member %d (%s) just sent all changes" msgstr "%s du membre %d (%s) vient d'envoyer tous les changements" #: src/os40.cc:1003 #, c-format msgid "%s of member %d (%s) committed all changes" msgstr "%s du membre %d (%s) vient d'envoyer tous les changements" #: src/os40.cc:1006 #, c-format msgid "%s of member %d (%s) reported sync done" msgstr "%s du membre %d (%s) a indiqué que la synchronisation a été effectuée" #: src/os40.cc:1009 #, c-format msgid "%s of member %d (%s) discovered its objtypes" msgstr "%s du membre %d (%s) a découvert ses objtypes" #: src/os40.cc:1012 #, c-format msgid "%s of member %d (%s) had an error: %s" msgstr "%s du membre %d (%s) a rencontré une erreur : %s" #: src/os40.cc:1067 msgid "Error handling summary item. " msgstr "Élément de résumé de gestion d'erreur." #: src/os40.cc:1071 msgid "Unknown exception caught in multiply_summary()" msgstr "Exception inconnue attrapée dans multiply_summary()" #: src/os40.cc:1440 msgid "Username (authentication parameter) is not supported in plugin!" msgstr "" "Le nom d'utilisateur (comme paramètre d'authentification) n'est pas supporté " "dans ce greffon !" #: src/os40.cc:1478 msgid "Password authentication is not supported in plugin!" msgstr "" "L'authentification par mot de passe n'est pas supportée dans ce greffon !" #: src/os40.cc:1934 msgid "Plugin not found: " msgstr "Greffon non trouvé" #: src/os40.cc:2000 src/os40.cc:2029 src/os40.cc:2080 src/os40.cc:2113 msgid "Unable to find plugin with name: " msgstr "Impossible de trouver le greffon nommé : " #: src/os40.cc:2167 msgid "discover failed: no objtypes returned" msgstr "La recherche a échoué : aucun objtype renvoyé" #: src/osbase.cc:158 msgid "" "Which entry do you want to use?\n" "[1-9] To select a side" msgstr "" "Quelle entrée voulez-vous utiliser ?\n" "[1-9] Pour choisir un côté" #: src/osbase.cc:162 msgid ", [A]bort" msgstr ", [A]nnuler" #: src/osbase.cc:164 msgid ", [D]uplicate" msgstr ", [D]upliquer" #: src/osbase.cc:167 msgid ", [I]gnore" msgstr ", [I]gnorer" #: src/osbase.cc:170 msgid ", Keep [N]ewer" msgstr ", Co[N]server le plus récent" #: src/osbase.cc:267 msgid "Conflicting items:" msgstr "Éléments en conflit : " #: src/osbase.cc:289 msgid "Abort not supported!" msgstr "L'annulation n'est pas supportée !" #: src/osbase.cc:300 msgid "Ignore not supported!" msgstr "Ignorer n'est pas supporté !" #: src/osbase.cc:307 msgid "Keep Newer not supported!" msgstr "Conserver le plus récent n'est pas supporté !" #: src/osbase.cc:319 src/osbase.cc:326 src/osbase.cc:333 src/osbase.cc:343 msgid "ERROR: " msgstr "ERREUR : " #: src/osbase.cc:349 msgid "Synchronization Forecast Summary:" msgstr "Résumé de prévision de synchronisation : " #: src/osbase.cc:352 msgid "Do you want to continue the synchronization? (N/y): " msgstr "Voulez-vous continuer la synchronisation ? (N/y) :" #: src/osbase.cc:358 msgid "Aborting! Synchronization got aborted by user!" msgstr "Annulation ! La synchronisation a été annulée par l'utilisateur !" #: src/osbase.cc:361 msgid "OK! Completing synchronization!" msgstr "OK ! Synchronisation effectuée !" #: src/osbase.cc:368 msgid "CALLBACK ERROR: " msgstr "ERREUR DE FONCTION DE RAPPEL : " #: src/osbase.cc:413 msgid "Unable to load opensync 0.40: " msgstr "Impossible de charger opensync 0.40 : " #: src/osbase.cc:423 msgid "Unable to load opensync 0.22: " msgstr "Impossible de charger opensync 0.22 : " #: src/osconfig.cc:42 msgid "Unsupported" msgstr "Non supporté" #: src/osconfig.cc:54 msgid "Barry config must have valid pin number." msgstr "La configuration de Barry doit comporter un code pin valide." #: src/osconfig.cc:73 msgid "" "Unable to load pin number from Barry plugin config. Consider this group " "corrupt, or not fully configured: " msgstr "" "Impossible de charger le code pin depuis la configuration du greffon Barry. " "Ce groupe est considéré comme corrompu, ou incomplètement configuré : " #: src/osconfig.cc:114 #, c-format msgid "No Barry plugins found in group '%s' and OSCG_THROW_ON_NO_BARRY is set." msgstr "" "Aucun greffon Barry trouvé dans le groupe '%s' et OSCG_THROW_ON_NO_BARRY est " "activé." #: src/osconfig.cc:119 #, c-format msgid "" "Found %d Barry plugins in group '%s' and OSCG_THROW_ON_MULTIPLE_BARRIES is " "set." msgstr "" "%d greffons Barry trouvés dans le groupe '%s' et OSCG_THROW_ON_NO_BARRY est " "activé." #: src/osconfig.cc:307 #, c-format msgid "" "Unsupported plugin '%s' in group '%s' and OSCG_THROW_ON_UNSUPPORTED is set." msgstr "" "Greffon '%s' non-supporté dans le groupe '%s' et OSCG_THROW_ON_NO_BARRY est " "activé." #: src/osconfig.cc:337 msgid "" "Cannot delete individual members from an OpenSync group with versions < 0.40." msgstr "" "Impossible de supprimer séparément les membres d'un groupe OpenSync avec les " "versions < 0.40." #: src/osconfig.cc:349 #, c-format msgid "Tried to delete non-existent member ID %ld (%s) from group '%s'" msgstr "" "Tentative de supprimer l'élément inexistant d'ID %ld (%s) du groupe '%s'" #: src/osconfig.cc:356 #, c-format msgid "" "Tried to delete member ID %ld using plugin '%s' from group '%s', but the " "existing member uses plugin '%s'" msgstr "" "Tentative de supprimer le membre d'ID %ld en utilisant le greffon '%s' du " "groupe '%s', mais le membre existant utilise le greffon '%s'" #: src/osconfig.cc:378 #, c-format msgid "" "Tried to overwrite group '%s' with a Group set that did not match in ID's " "and plugin names." msgstr "" "Tentative d'écraser le groupe '%s' avec un ensemble de groupes qui ne " "correspond pas au niveau des IDs et des noms de greffon." #: src/osconv22.cc:304 src/osconv22.cc:321 src/osconv22.cc:358 #: src/osconv40.cc:269 src/osconv40.cc:307 src/osconv40.cc:344 #: src/osconv40.cc:370 msgid "Cannot save a plugin with a member_id of -1" msgstr "Impossible de sauvegarder un greffon avec un member_id valant -1" #: src/tempdir.cc:40 msgid "Cannot create temp directory: " msgstr "Impossible de créer le répertoire temporaire : " barry-0.18.5/desktop/po-osyncwrap/remove-potcdate.sin0000644001161500056700000000066012242254476022201 0ustar cdfreycdfrey# Sed script that remove the POT-Creation-Date line in the header entry # from a POT file. # # The distinction between the first and the following occurrences of the # pattern is achieved by looking at the hold space. /^"POT-Creation-Date: .*"$/{ x # Test if the hold space is empty. s/P/P/ ta # Yes it was empty. First occurrence. Remove the line. g d bb :a # The hold space was nonempty. Following occurrences. Do nothing. x :b } barry-0.18.5/desktop/po-osyncwrap/POTFILES.in0000644001161500056700000000107512242254476020146 0ustar cdfreycdfrey# List of source files (for libosyncwrap only!) which contain # translatable strings. # Standalone programs src/blistevo.cc src/bsynccl.cc # This list should match Makefile.am's libosyncwrap fairly closely. src/dlopen.cc src/dlopen.h src/error.cc src/error.h src/null-os22.cc src/null-os40.cc src/deviceset.cc src/deviceset.h src/os22.cc src/os22.h src/os40.cc src/os40.h src/osbase.cc src/osbase.h src/osconfig.cc src/osconfig.h src/osconv22.cc src/osconv22.h src/osconv40.cc src/osconv40.h src/osprivatebase.h src/ostypes.cc src/ostypes.h src/tempdir.cc src/tempdir.h barry-0.18.5/desktop/po-osyncwrap/quot.sed0000644001161500056700000000023112242254476020047 0ustar cdfreycdfreys/"\([^"]*\)"/“\1”/g s/`\([^`']*\)'/‘\1’/g s/ '\([^`']*\)' / ‘\1’ /g s/ '\([^`']*\)'$/ ‘\1’/g s/^'\([^`']*\)' /‘\1’ /g s/“”/""/g barry-0.18.5/desktop/po-osyncwrap/Makevars0000644001161500056700000000360612242254476020067 0ustar cdfreycdfrey# Makefile variables for PO directory in any package using GNU gettext. # Usually the message domain is the same as the package name. DOMAIN = barryosyncwrap # These two variables depend on the location of this directory. subdir = po-osyncwrap top_builddir = .. # These options get passed to xgettext. XGETTEXT_OPTIONS = --keyword=_C --keyword=_W --from-code=UTF-8 --add-comments=TRANSLATORS # This is the copyright holder that gets inserted into the header of the # $(DOMAIN).pot file. Set this to the copyright holder of the surrounding # package. (Note that the msgstr strings, extracted from the package's # sources, belong to the copyright holder of the package.) Translators are # expected to transfer the copyright for their translations to this person # or entity, or to disclaim their copyright. The empty string stands for # the public domain; in this case the translators are expected to disclaim # their copyright. COPYRIGHT_HOLDER = Net Direct, Inc. # This is the email address or URL to which the translators shall report # bugs in the untranslated strings: # - Strings which are not entire sentences, see the maintainer guidelines # in the GNU gettext documentation, section 'Preparing Strings'. # - Strings which use unclear terms or require additional context to be # understood. # - Strings which make invalid assumptions about notation of date, time or # money. # - Pluralisation problems. # - Incorrect English spelling. # - Incorrect formatting. # It can be your email address, or a mailing list address where translators # can write to without being subscribed, or the URL of a web page through # which the translators can contact you. # # See the "contact" page from the URL below: MSGID_BUGS_ADDRESS = http://netdirect.ca/barry # This is the list of locale categories, beyond LC_MESSAGES, for which the # message catalogs shall be used. It is usually empty. EXTRA_LOCALE_CATEGORIES = barry-0.18.5/desktop/po-osyncwrap/es.po0000644001161500056700000003022512242254476017337 0ustar cdfreycdfrey# Barry Spanish Translation File # Copyright (C) 2012-2013 Net Direct, Inc. # This file is distributed under the same license as the Barry Desktop package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: barrydesktop 0.18.5\n" "Report-Msgid-Bugs-To: http://netdirect.ca/barry\n" "POT-Creation-Date: 2013-04-02 18:54-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/blistevo.cc:47 msgid "Defaultable: " msgstr "" #: src/blistevo.cc:48 msgid "Yes" msgstr "" #: src/blistevo.cc:48 msgid "No" msgstr "" #: src/blistevo.cc:49 msgid "Error during detect: " msgstr "" #: src/blistevo.cc:51 msgid "(none)" msgstr "" #: src/blistevo.cc:53 msgid "Results:" msgstr "" #: src/blistevo.cc:55 msgid "Addressbook:" msgstr "" #: src/blistevo.cc:57 msgid "Events:" msgstr "" #: src/blistevo.cc:59 msgid "Tasks:" msgstr "" #: src/blistevo.cc:61 msgid "Memos:" msgstr "" #: src/bsynccl.cc:140 msgid "" "This is a helper program for barrydesktop, and\n" "is not intended to be called directly.\n" msgstr "" #: src/null-os22.cc:30 src/null-os22.cc:87 src/null-os22.cc:145 #: src/null-os22.cc:150 src/null-os22.cc:155 src/null-os22.cc:160 #: src/null-os22.cc:165 src/null-os22.cc:170 src/null-os22.cc:241 #: src/null-os40.cc:85 src/null-os40.cc:152 src/null-os40.cc:157 #: src/null-os40.cc:162 src/null-os40.cc:167 src/null-os40.cc:172 #: src/null-os40.cc:177 msgid "Not supported on this system." msgstr "" #: src/null-os22.cc:40 msgid "OpenSync 0.22 support was not compiled in." msgstr "" #: src/null-os40.cc:38 msgid "OpenSync 0.4x support was not compiled in." msgstr "" #: src/deviceset.cc:195 src/deviceset.cc:196 msgid "yes" msgstr "" #: src/deviceset.cc:195 src/deviceset.cc:196 msgid "no" msgstr "" #: src/os22.cc:250 src/os40.cc:548 msgid "ADDED" msgstr "" #: src/os22.cc:251 src/os40.cc:549 msgid "UNMODIFIED" msgstr "" #: src/os22.cc:252 src/os40.cc:550 msgid "DELETED" msgstr "" #: src/os22.cc:253 src/os40.cc:551 msgid "MODIFIED" msgstr "" #: src/os22.cc:293 msgid "Bad change_id, or error getting nth change object." msgstr "" #: src/os22.cc:317 msgid "Conflict not ignored: " msgstr "" #: src/os22.cc:332 msgid "Conflict not resolved: " msgstr "" #: src/os22.cc:383 #, c-format msgid "Member %lld (%s) just connected" msgstr "" #: src/os22.cc:386 #, c-format msgid "Member %lld (%s) just disconnected" msgstr "" #: src/os22.cc:389 #, c-format msgid "Member %lld (%s) just sent all changes" msgstr "" #: src/os22.cc:392 #, c-format msgid "Member %lld (%s) committed all changes" msgstr "" #: src/os22.cc:395 #, c-format msgid "Member %lld (%s) had an error while connecting: %s" msgstr "" #: src/os22.cc:399 #, c-format msgid "Member %lld (%s) had an error while getting changes: %s" msgstr "" #: src/os22.cc:404 #, c-format msgid "Member %lld (%s) had an error while calling sync done: %s" msgstr "" #: src/os22.cc:409 #, c-format msgid "Member %lld (%s) had an error while disconnecting: %s" msgstr "" #: src/os22.cc:414 #, c-format msgid "Member %lld (%s) had an error while commiting changes: %s" msgstr "" #: src/os22.cc:439 src/os40.cc:1038 msgid "member_status error: " msgstr "" #: src/os22.cc:443 src/os40.cc:1042 msgid "Unknown exception caught in member_status()" msgstr "" #: src/os22.cc:461 #, c-format msgid "Received an entry %s without data from member %d (%s). Change type: %s" msgstr "" #: src/os22.cc:468 #, c-format msgid "" "Received an entry %s with data of size %d from member %d (%s). Change type: " "%s" msgstr "" #: src/os22.cc:476 #, c-format msgid "Sent an entry %s of size %d to member %d (%s). Change type: %s" msgstr "" #: src/os22.cc:485 #, c-format msgid "Error writing entry %s to member %d (%s): %s" msgstr "" #: src/os22.cc:493 #, c-format msgid "Error reading entry %s from member %d (%s): %s" msgstr "" #: src/os22.cc:508 msgid "entry_status error:" msgstr "" #: src/os22.cc:512 src/os40.cc:846 msgid "Unknown exception caught in entry_status()" msgstr "" #: src/os22.cc:527 msgid "The previous synchronization was unclean. Slow-syncing." msgstr "" #: src/os22.cc:530 src/os40.cc:901 msgid "All clients connected or error" msgstr "" #: src/os22.cc:533 src/os40.cc:939 msgid "All conflicts have been reported" msgstr "" #: src/os22.cc:536 src/os40.cc:907 msgid "All clients sent changes or error" msgstr "" #: src/os22.cc:539 src/os40.cc:922 msgid "All clients have written" msgstr "" #: src/os22.cc:542 src/os40.cc:925 msgid "All clients have disconnected" msgstr "" #: src/os22.cc:545 src/os40.cc:932 msgid "The sync was successful" msgstr "" #: src/os22.cc:548 src/os40.cc:929 msgid "The sync failed: " msgstr "" #: src/os22.cc:562 src/os40.cc:954 msgid "engine_status error: " msgstr "" #: src/os22.cc:566 src/os40.cc:958 msgid "Unknown exception caught in engine_status()" msgstr "" #: src/os22.cc:581 src/os40.cc:863 msgid "Mapping solved" msgstr "" #: src/os22.cc:584 msgid "Mapping Synced" msgstr "" #: src/os22.cc:588 msgid "Mapping Write Error: " msgstr "" #: src/os22.cc:599 src/os40.cc:879 msgid "mapping_status error: " msgstr "" #: src/os22.cc:603 src/os40.cc:883 msgid "Unknown exception caught in mapping_status()" msgstr "" #: src/os22.cc:625 src/os40.cc:789 msgid "Conflict not resolved. " msgstr "" #: src/os22.cc:629 src/os40.cc:793 msgid "Unknown exception caught in conflict_handler()" msgstr "" #: src/os22.cc:755 msgid "Error allocating opensync 0.22 environment" msgstr "" #: src/os22.cc:808 msgid "Unable to load format environment in GetFormats (22)" msgstr "" #: src/os22.cc:850 src/os40.cc:1862 msgid "Unable to find group with name: " msgstr "" #: src/os22.cc:877 msgid "Group already exists: " msgstr "" #: src/os22.cc:885 msgid "Unable to save group: " msgstr "" #: src/os22.cc:898 src/os22.cc:919 src/os22.cc:944 src/os22.cc:975 #: src/os22.cc:1009 src/os22.cc:1037 src/os40.cc:1911 src/os40.cc:1930 #: src/os40.cc:1957 src/os40.cc:1989 src/os40.cc:2018 src/os40.cc:2069 #: src/os40.cc:2102 src/os40.cc:2147 src/os40.cc:2188 msgid "Group not found: " msgstr "" #: src/os22.cc:902 msgid "Unable to delete group: " msgstr "" #: src/os22.cc:925 msgid "Unable to connect plugin with member: " msgstr "" #: src/os22.cc:931 msgid "Unable to save member: " msgstr "" #: src/os22.cc:949 src/os40.cc:1962 src/os40.cc:1979 src/os40.cc:1994 #: src/os40.cc:2023 src/os40.cc:2074 src/os40.cc:2107 msgid "Member not found: " msgstr "" #: src/os22.cc:956 msgid "Unable to determine needed config: " msgstr "" #: src/os22.cc:968 src/os22.cc:1002 src/os40.cc:2011 src/os40.cc:2062 #: src/os40.cc:2095 #, c-format msgid "Member %ld of group '%s' does not accept configuration." msgstr "" #: src/os22.cc:979 src/os22.cc:1013 #, c-format msgid "Member %ld not found." msgstr "" #: src/os22.cc:986 msgid "Unable to retrieve config: " msgstr "" #: src/os22.cc:1020 msgid "Unable to save member's config: " msgstr "" #: src/os22.cc:1057 msgid "Error while synchronizing: " msgstr "" #: src/os22.cc:1078 msgid "Error initializing osengine: " msgstr "" #: src/os22.cc:1090 msgid "Error during sync: " msgstr "" #: src/os40.cc:447 msgid "(NULL error msg)" msgstr "" #: src/os40.cc:610 msgid "Problems while aborting: " msgstr "" #: src/os40.cc:812 #, c-format msgid "Received an entry %s (%s) from member %d (%s): %s" msgstr "" #: src/os40.cc:817 #, c-format msgid "Sent an entry %s (%s) to member %d (%s): %s" msgstr "" #: src/os40.cc:823 #, c-format msgid "Error for entry %s (%s) and member %d (%s): %s" msgstr "" #: src/os40.cc:842 msgid "entry_status error: " msgstr "" #: src/os40.cc:868 msgid "Mapping error: " msgstr "" #: src/os40.cc:910 msgid "All changes got mapped" msgstr "" #: src/os40.cc:913 msgid "All changes got multiplied" msgstr "" #: src/os40.cc:916 msgid "All changes got prepared for write" msgstr "" #: src/os40.cc:935 msgid "The previous synchronization was unclean. Slow-syncing" msgstr "" #: src/os40.cc:942 msgid "All clients reported sync done" msgstr "" #: src/os40.cc:974 msgid "Main sink" msgstr "" #: src/os40.cc:976 #, c-format msgid "%s sink" msgstr "" #. TRANSLATORS: resulting message may look like this: #. "Main sink of member 5 (barry-sync) just connected" #. The "Main sink" part is based on the "Main sink" #. string or the "%s sink" string. #: src/os40.cc:990 #, c-format msgid "%s of member %d (%s) just connected" msgstr "" #: src/os40.cc:997 #, c-format msgid "%s of member %d (%s) just disconnected" msgstr "" #: src/os40.cc:1000 #, c-format msgid "%s of member %d (%s) just sent all changes" msgstr "" #: src/os40.cc:1003 #, c-format msgid "%s of member %d (%s) committed all changes" msgstr "" #: src/os40.cc:1006 #, c-format msgid "%s of member %d (%s) reported sync done" msgstr "" #: src/os40.cc:1009 #, c-format msgid "%s of member %d (%s) discovered its objtypes" msgstr "" #: src/os40.cc:1012 #, c-format msgid "%s of member %d (%s) had an error: %s" msgstr "" #: src/os40.cc:1067 msgid "Error handling summary item. " msgstr "" #: src/os40.cc:1071 msgid "Unknown exception caught in multiply_summary()" msgstr "" #: src/os40.cc:1440 msgid "Username (authentication parameter) is not supported in plugin!" msgstr "" #: src/os40.cc:1478 msgid "Password authentication is not supported in plugin!" msgstr "" #: src/os40.cc:1934 msgid "Plugin not found: " msgstr "" #: src/os40.cc:2000 src/os40.cc:2029 src/os40.cc:2080 src/os40.cc:2113 msgid "Unable to find plugin with name: " msgstr "" #: src/os40.cc:2167 msgid "discover failed: no objtypes returned" msgstr "" #: src/osbase.cc:158 msgid "" "Which entry do you want to use?\n" "[1-9] To select a side" msgstr "" #: src/osbase.cc:162 msgid ", [A]bort" msgstr "" #: src/osbase.cc:164 msgid ", [D]uplicate" msgstr "" #: src/osbase.cc:167 msgid ", [I]gnore" msgstr "" #: src/osbase.cc:170 msgid ", Keep [N]ewer" msgstr "" #: src/osbase.cc:267 msgid "Conflicting items:" msgstr "" #: src/osbase.cc:289 msgid "Abort not supported!" msgstr "" #: src/osbase.cc:300 msgid "Ignore not supported!" msgstr "" #: src/osbase.cc:307 msgid "Keep Newer not supported!" msgstr "" #: src/osbase.cc:319 src/osbase.cc:326 src/osbase.cc:333 src/osbase.cc:343 msgid "ERROR: " msgstr "" #: src/osbase.cc:349 msgid "Synchronization Forecast Summary:" msgstr "" #: src/osbase.cc:352 msgid "Do you want to continue the synchronization? (N/y): " msgstr "" #: src/osbase.cc:358 msgid "Aborting! Synchronization got aborted by user!" msgstr "" #: src/osbase.cc:361 msgid "OK! Completing synchronization!" msgstr "" #: src/osbase.cc:368 msgid "CALLBACK ERROR: " msgstr "" #: src/osbase.cc:413 msgid "Unable to load opensync 0.40: " msgstr "" #: src/osbase.cc:423 msgid "Unable to load opensync 0.22: " msgstr "" #: src/osconfig.cc:42 msgid "Unsupported" msgstr "" #: src/osconfig.cc:54 msgid "Barry config must have valid pin number." msgstr "" #: src/osconfig.cc:73 msgid "" "Unable to load pin number from Barry plugin config. Consider this group " "corrupt, or not fully configured: " msgstr "" #: src/osconfig.cc:114 #, c-format msgid "No Barry plugins found in group '%s' and OSCG_THROW_ON_NO_BARRY is set." msgstr "" #: src/osconfig.cc:119 #, c-format msgid "" "Found %d Barry plugins in group '%s' and OSCG_THROW_ON_MULTIPLE_BARRIES is " "set." msgstr "" #: src/osconfig.cc:307 #, c-format msgid "" "Unsupported plugin '%s' in group '%s' and OSCG_THROW_ON_UNSUPPORTED is set." msgstr "" #: src/osconfig.cc:337 msgid "" "Cannot delete individual members from an OpenSync group with versions < 0.40." msgstr "" #: src/osconfig.cc:349 #, c-format msgid "Tried to delete non-existent member ID %ld (%s) from group '%s'" msgstr "" #: src/osconfig.cc:356 #, c-format msgid "" "Tried to delete member ID %ld using plugin '%s' from group '%s', but the " "existing member uses plugin '%s'" msgstr "" #: src/osconfig.cc:378 #, c-format msgid "" "Tried to overwrite group '%s' with a Group set that did not match in ID's " "and plugin names." msgstr "" #: src/osconv22.cc:304 src/osconv22.cc:321 src/osconv22.cc:358 #: src/osconv40.cc:269 src/osconv40.cc:307 src/osconv40.cc:344 #: src/osconv40.cc:370 msgid "Cannot save a plugin with a member_id of -1" msgstr "" #: src/tempdir.cc:40 msgid "Cannot create temp directory: " msgstr "" barry-0.18.5/desktop/po-osyncwrap/Rules-quot0000644001161500056700000000340012242254476020366 0ustar cdfreycdfrey# Special Makefile rules for English message catalogs with quotation marks. DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot .SUFFIXES: .insert-header .po-update-en en@quot.po-create: $(MAKE) en@quot.po-update en@boldquot.po-create: $(MAKE) en@boldquot.po-update en@quot.po-update: en@quot.po-update-en en@boldquot.po-update: en@boldquot.po-update-en .insert-header.po-update-en: @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ tmpdir=`pwd`; \ echo "$$lang:"; \ ll=`echo $$lang | sed -e 's/@.*//'`; \ LC_ALL=C; export LC_ALL; \ cd $(srcdir); \ if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$lang -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ exit 1; \ fi; \ fi; \ else \ echo "creation of $$lang.po failed!" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ fi en@quot.insert-header: insert-header.sin sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header en@boldquot.insert-header: insert-header.sin sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header mostlyclean: mostlyclean-quot mostlyclean-quot: rm -f *.insert-header barry-0.18.5/desktop/po-osyncwrap/LINGUAS0000644001161500056700000000004512242254476017412 0ustar cdfreycdfrey# Set of available languages. fr es barry-0.18.5/desktop/po-osyncwrap/en@boldquot.header0000644001161500056700000000247112242254476022020 0ustar cdfreycdfrey# All this catalog "translates" are quotation characters. # The msgids must be ASCII and therefore cannot contain real quotation # characters, only substitutes like grave accent (0x60), apostrophe (0x27) # and double quote (0x22). These substitutes look strange; see # http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html # # This catalog translates grave accent (0x60) and apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019). # It also translates pairs of apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019) # and pairs of quotation mark (0x22) to # left double quotation mark (U+201C) and right double quotation mark (U+201D). # # When output to an UTF-8 terminal, the quotation characters appear perfectly. # When output to an ISO-8859-1 terminal, the single quotation marks are # transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to # grave/acute accent (by libiconv), and the double quotation marks are # transliterated to 0x22. # When output to an ASCII terminal, the single quotation marks are # transliterated to apostrophes, and the double quotation marks are # transliterated to 0x22. # # This catalog furthermore displays the text between the quotation marks in # bold face, assuming the VT100/XTerm escape sequences. # barry-0.18.5/desktop/po-osyncwrap/en@quot.header0000644001161500056700000000226312242254476021156 0ustar cdfreycdfrey# All this catalog "translates" are quotation characters. # The msgids must be ASCII and therefore cannot contain real quotation # characters, only substitutes like grave accent (0x60), apostrophe (0x27) # and double quote (0x22). These substitutes look strange; see # http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html # # This catalog translates grave accent (0x60) and apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019). # It also translates pairs of apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019) # and pairs of quotation mark (0x22) to # left double quotation mark (U+201C) and right double quotation mark (U+201D). # # When output to an UTF-8 terminal, the quotation characters appear perfectly. # When output to an ISO-8859-1 terminal, the single quotation marks are # transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to # grave/acute accent (by libiconv), and the double quotation marks are # transliterated to 0x22. # When output to an ASCII terminal, the single quotation marks are # transliterated to apostrophes, and the double quotation marks are # transliterated to 0x22. # barry-0.18.5/desktop/po-osyncwrap/ChangeLog0000644001161500056700000000073612242254476020146 0ustar cdfreycdfrey2012-07-18 gettextize * Makefile.in.in: New file, from gettext-0.18.1. * Rules-quot: New file, from gettext-0.18.1. * boldquot.sed: New file, from gettext-0.18.1. * en@boldquot.header: New file, from gettext-0.18.1. * en@quot.header: New file, from gettext-0.18.1. * insert-header.sin: New file, from gettext-0.18.1. * quot.sed: New file, from gettext-0.18.1. * remove-potcdate.sin: New file, from gettext-0.18.1. * POTFILES.in: New file. barry-0.18.5/desktop/po-osyncwrap/README0000644001161500056700000000102312242254476017242 0ustar cdfreycdfreyHOWTO to add a new language or update translation ================================================= To add a new language --------------------- Sample to add spanish language $ cd /po-osyncwrap $ msginit --locale=es --input=barrydesktop.pot $ echo "es" >> LINGUAS $ make update-po Then, send to barry team your work. To update translation --------------------- You have to only edit a ".po" file. $ cd /po-osyncwrap $ vi es.po $ make update-po Then, send to barry team your work. barry-0.18.5/desktop/COPYING0000644001161500056700000004313312242254476014764 0ustar cdfreycdfrey GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, 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 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. Copyright (C) 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 St, 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) year 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. , 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. barry-0.18.5/desktop/buildgen.sh0000755001161500056700000000065312242254476016061 0ustar cdfreycdfrey#!/bin/sh # # Generates the build system. # if [ "$1" = "clean" ] ; then rm -rf autom4te.cache rm -f Makefile.in aclocal.m4 config.guess config.h.in config.sub \ configure depcomp install-sh ltmain.sh missing \ images/Makefile.in \ man/Makefile.in \ src/Makefile.in src/*.bak \ src/0.22/Makefile.in \ src/0.40/Makefile.in \ config.rpath \ INSTALL \ config.h.in~ else autoreconf -if #autoreconf -ifv fi barry-0.18.5/desktop/man/0000755001161500056700000000000012242254476014500 5ustar cdfreycdfreybarry-0.18.5/desktop/man/Makefile.am0000644001161500056700000000004012242254476016526 0ustar cdfreycdfreydist_man_MANS = barrydesktop.1 barry-0.18.5/desktop/man/barrydesktop.10000644001161500056700000000222312242254476017272 0ustar cdfreycdfrey.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH BARRYDESKTOP 1 "September 24, 2009" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME .B barrydesktop \- Barry Project's control panel for the BlackBerry(R) handheld .SH SYNOPSIS .B barrydesktop [\-?][\-d] .SH DESCRIPTION .PP .B barrydesktop is a GUI application which provides general control of your Blackberry(R) handheld devices. This application is still in development. .SH AUTHOR .nh .B barrydesktop is part of the Barry project. This manual page was written by Chris Frey. .SH SEE ALSO .PP http://www.netdirect.ca/software/packages/barry barry-0.18.5/desktop/ChangeLog0000644001161500056700000000004012242254476015471 0ustar cdfreycdfrey - See git history for details barry-0.18.5/desktop/README0000644001161500056700000000052612242254476014610 0ustar cdfreycdfrey This is the Desktop sub-project of the Barry project. You will need the Barry library compiled and installed to use this. This directory contains a fully standalone build tree, but can optionally be built automatically when you build Barry if you use the --enable-desktop configure option. See doc/www/index.html for more documentation. barry-0.18.5/desktop/images/0000755001161500056700000000000012242254476015172 5ustar cdfreycdfreybarry-0.18.5/desktop/images/backuprestore-focus.png0000644001161500056700000003745712242254476021706 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME)|ftEXtCommentCreated with The GIMPd%n IDATx}]vus?' 9I6L *Azaik?7enQPA/,(}R)/ )($9߻b֘sy#φ<^{5s1_~ݯuz$p~ݯu_~ݯ) -}if}[E3۟ ȷ|.3f}M[zff_H~_E8[zio{8y}[z5_(n_ ?U9JF3&? h?1k _G YKy2xcKw}kWs\m,@Cx(sMabmiIqaRڐs@6~t}S<'7sXZ0jLs8 \׍,u|zP92DH ȵelZ 榍M$fzpjU驃˿ *bpC1~#.b@r@g"W+Vtc߳֡S0LzMIt絑/9\i9!F>ya=\!EsSG pzesljaeW v ޾is]>>1{ ):-,7FkPO2Q"$գq? )m"/`Q8 JT$9_%?JX "B|bs®,0%/.:g=0n0?̌k_Wz'g^i#t1xG[3v¹̆'2`ٵVܿJt B<웉b׃^rHNYp>tHVHgžv8>4(AKKpϼ. (&ҫ/*j|6_A>\ yB0P99$n|Y|13w,c<𑆆ïE77%%䔁.ndӓg?RaA+$} R3XgXRhDlɦ& 8n=9`p 7O9/Pȴlfּ4'[I#ãV`;1(GfHl=3) 7Q]%~>D[QdO+xG͆[;" pQ ņi&TS%逄Nb X.i!9]7>X!KOeW}cifvf4;줱5Fx`Psgn̊L帚rε cLG/go=1<3r#*&ERX7ޘy-9!{ܐ+ CBEDKcwtQRFNBGb0\`p|R nn9 )%{@^4"t:iH;iF.rkQwxT@Fl!n`MAZE}4v0=`a$pLSi!2aC@l4lNNkL MVV± c9Ѧ`$!x%H OaP#WG\¬B}H5DLn!c>&}P _jtIz͟6«BdZ@><QQF:S;*6$k4H=Hswk5pft{X`H%4xz\PhjmB¢ݗ(@85 [yI1b<-T+91ᖇ(#X$H&HwSL>V ~$ĠJ_:ܻa1>e x +$5oZ}8B4j5#kY`ͺO[an447;hgsL"2<=h]`v,Fݩ6mbYEy]r5IED2|S^Y*H=UU*}yx"KO L-+b7%Pn:7{ `~ ʱ<;:6joJٹJ;je%?NâaҀDC@ vZ8NhG?c8j]+a^qj+yQy?$*7 {S[F*j$7HJXвIڙrX1g$^z~xE*awnvn0n~rwp[Q:; D,DJFrp0RwPV!zG_zBgsGfg<F:`lϽ^O*A{D}WR2ή]e5@7K^}C0+xʘKQIS( Ɲz=/\\w[9ptAL^VCzL5<E6:S-7XiBYE'`F'|I=h 8jOr]U(! 뜫Rr'za P`^(4&^ىD,ރUGJ}ބ'4h@=7DQP:;˱j31}&AIpTՈ!ѫ#P 827zLo&AHt?AY"p'fvSɇG춷VcVT镸wJqW9P nRm h`:ZB,mA@Frn@Iq~L#ÁwO \I7y!N|23!O@-@p8Zq ֌v6tEF#qvOz¬BGh 4;}o޻gcU$FWIEڦ-#T;Pn l}} =C҃x5\vԬ*^w[G!}Z\TaA ЍޣF|$Q ;FU@*FހN.Ez^y"rrdRш$rI;)ܥUR I]6x+NV-Ke(=+),|_ /on0 jx}X9H0 C«d ;0 e^vHL5~5½m('Nj cz.|NT{^勼>o{Oڬu`@!Х1fltgtWP:Q1֍_J7Ae$w#L#g|`h+,?MB g" BedEpHK_ޥ[}zEb25Pѿo`Ύa@9 c/$_o7k}g~\vn|-?̷5Z/iLaNh#7cLwxqUhck~sk:J6T z~$<{W[k@StkS*d\ Mk'ːE1y $_<-ST8Lk7K4/(9?ro#|YNp$ uIٿ[/V)O1#i? G q.ҿ\aɑo Er՛E{ƈFEmhfUu9|1gthcQjсKEUqrТ\ t1X 6N[)e|gzφ\(\t7K{壶1WO ?َԞ-6HC>h }4 B}8Aɹ6\h3QǣKX:YػQiK!}Ȝ^T?fmW )l =Xp (XWLtzbA`  Go30>C(Ng=*6T1i"4z/mp3o'یkZ!`XsL(%sJbf"^[W=D<?n3Z]R, Q'5wpSGdƢOBh/jOE5I{`Y \E±M# u0=W;[*~ #H A=ȩՅ{a,fx9Agypsv%! 35<6b w˴+ mb/jgNM\xFJp#WѵT[^U)N=/dla!4"QVXv" }s=1GB!ot:>^uw j;kdg|Zu_ P+1>EAfF*n^ o_lյrOZҠ70V-ăjcmF~ALqd^rG`O6^)DQGAko_͞[\gJ~& ŷӸyaa@"#i}EIb6A=~:(SRWm9?"v!CK}*,:ՑI#kݩN 惧P ><úQWlp%dk0:~Zot@.;q$"] nShn.YjtC;;z8;x/(Ic=Ʀ"@4 >>jY?-WcTRm*QxJg+8 0RF Ҭ.2Q)Xa ٷCb[S0F0$~zyyQRt1~T-khtMKܟ2 yk+sBHmqS2Ҫho2Kwi5 RL^CX**'d$ܜm?}\FG2Bq`ӑ%rw,R'RU@iPRer*.[iy޽oIh)}5ycb@gbuzIDATKXm^v(\4m0tvrTrI(ay/-~Z+mS5 clzWt¦pliHe+*P["; ;A+ZnKK/~٣l2xlr휙MPV¾|ZW4DiMrg{?gl"a7ûa-v$L 5uG4iw*`># 52B,$LDWJms9p%J ^qU(g()#JR"Md:9^:U?i{RbtyVd(9ܠH#_ăx?o]i|;8nvyڳg~~!kɃ<dfa2Ptfw/^@YSk+&teffЕ럯Ma;`أ} }8qIVR .Tp): *v+h a ;N<Ϲ5ܒ<ʴ UJPvBê6C-%r?*$2n$8Ԅ(T!> ڔW 6X~)X:lqr\ELLJ`3ёMFObaU:h0kC~n߶%&Kx;ϳO#?O|i9lj[p}x4iC7`D6(6 4-MlEVѯmH z+QsO i/1Әlr=UTt6Qb|=pB:=0\q !Ljʫ٫O~??7L>a}}sP#<W|?ea>'X H%_ WLdzԒqGЛBTXXFmG`{mRz`4#@m%o?st"CТo*Qh?q wʷOo}uL˃?M7NCx̃r̼6 W?ɷ_?c׎Vf jT_f "7XmzҰ>5|4 @Des q! ;M隒8^hvќd*@cOFiS~se1qa&TI:MI#iEOkiKww=~W_}F6 "3,54)k$o{γW}}+{^Zqؽ 'YS*s]:7 Pݤ6䰶4q} zJ[z X׃H,5hBDiOCJo*WC c Om Wu0Sez5?<\"D<lV?2Y9F-- ë}k^}CJmnQo J`3rn$ӽi_߄q 殜"i$h2d9,BGSxWgZ8{=;JXdɍp58lGOY2r'QΝXw!V/MM,oяŻS.AZJ9Qy Fu<4Wy! CV㪲{s3jΫ`қ\jC)@ i]>Tb"YL%ksE`)ydRCFQ'e](vcش՛ 7&s, :ip\Kg(F3q*7C6?'d7Dz#ܣG7iHlflȾaBZ*Hk0O"g []'n$iN˰T{2=UEW ` J-SGmhyF{gKkRC}0W%=S}Op3in*w b \{ !Jmw$"ZHz)=]4y -H]^jrj85b;k l ȘKRKIY3R50s% ",u1S\Гen9^"I$,קY[h'1RH k`Pzn5 Ȅ:J\za0+&t}ѶzW]obʣI 7*M-_9cn<욼KxRs.>/cI֤QPƢXPFF?0Dj۪-ɐ0Jf rƤ# Vռ 9a3 8{`ChƆ>%7Yf檻,e7VM&;,a.!1x1ՙ5a>#(vEWYlt3}5Ȋd\5M^.kC' `{q$}2b l.Y!4#¡~q5jt0 ججYTR2)~EG*M"إ#IH4"h3듡lNg%hŻ O3`( W<=P1ؚGn J jGBhcuHt&qVY4ۑsJDQ?A1 } uymϩa[.Q]4ui2*3>zJt:@'$+VR$I׺I|-@cPa@[FdMPľ oAi0j9l8tOX:se͊Pi'DYq7]~{`<*#ljgi$X<7ᖽZƙ{/X ڑPHӥx=4w&x, b'`&!&ͨBt H+ĚH>+G?e1Ѧ] U7Qh_f4K#|zQ=Fc>7,YjEleeD c2DGyMc^++lQ%I%ƋŠDh:ӐWj^()&JFbW~v^RAS߄)CGIiN%biJ5BecPϝCt]RƤmNbL/WDBC< ;&FCQYkdB/z޹KpIQ~.^>.#ٔ~wQ=Vs%2 5f_wOLވP&;cg3#eOQI:N_YH~;;|&:_]b{^ZWfEΞr AQ C=tNdg^@Z(nexf朆\ʀi w.L/+KvM]6_G9ӧ6/(Z0 ')d>)%bʉV! 5M j4K ݿ6(Ϯ{%;cpvQ]@ qŒB9qS(O]⸈sHi, ^zU][)h{_˕;3by]ArnYfT'ydS0sdFT8'rjȅyB:lUNQhDdU%EUƟX$sURٕ&zb=isْgYf99 /B4׍jHHLuGy,Rcd:e)WTQ,)R}Aw^me`+hdd=w(PckV ,\,T$E+6&yM1 dS w%B.DXzҦZT0ɾ'+“G m$*6׊y:ShIـP37'!;&V+O׵.T7@V9D\?IZQ߆an".E%zZx,wE"@A b~iYM Um)`#H. |QNMEb-TWId %B?>2Z ׼R)-I!y+3LbYb̪W0BS:Ėh:3{۰1`Y&QdkRlE0rɝ*4wI,}dC]X>i`espb HOVPpѫ@ȝ+M3@JA^*3nYj(^Ϫ71D2魲aEh=)W~>^xgK*/H C4Rk13%6:/+:beyԢF<͐}~2 ʷc3xf.Q ]Igc[R@BS#X<$Xt2nXkE4Լ a}]vLsPjI5oyCa-c5hCkӻND5coau@id=n".ؽ엛hxGI,.j2Ǣ"-K $=кE=_Cg@O\EWY~KJ%P͒zK4p@~ nX'Yk@,-k@LnjW{X((*WT~:7x3[wrֵ!q^NY1"M :_ৄmN5L0 ʑgK ~=`jiܲt~7ABXqB`4%MjY(W4`v&#EqmH")06RA"UYD&,C.̤Y#v:jF!5y Ce.)IRh(IJr1yUW)-KdSO?f~~=|D-|}E _ٳ:ޯl7O?efcf?_~̾gu_~=~1ɍ~ݯf_~ݯu_~!?tɻIENDB`barry-0.18.5/desktop/images/apploader-focus.png0000644001161500056700000004050512242254476020770 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME+9ktEXtCommentCreated with The GIMPd%n IDATx}[iV_j-F7A^$$چ h&_4I||B#Q bK &б.眽 ۜs6YRuk79c \q9.r\d$^,q9.r\q9.ޘooܮr? [.r|7>?D:%F_O}۾'%2rxͽHP1!zƚI7~~l~󢻖>R: %M0?zi&v|k<17W1 lMxs=v~3CpB;X،;Ϻ=̇k Cd0xŐ ѓH>l; a亰P1,nk$|\ؚF D# y` 3]AḤGy<^$aui8,Q6 #{ rIݲcH8<La%a) 3_Ùy7F]k z]LC-:6͂s$mz>FReb{V~^l@ -p;5d}U2LeFkѬ5"xƦ~ 5PڡsVJ܆\[ٳ!#|Cv5ñEoEwuK%"5f,ı˷4LCJndFvtg_t&A@|8=D*̹!ܓr# /h }t$4V޾@C&"@q7 ~B͋ ]8W7[}L\bY *]DuXF&=!@`myLA*,:ׯ[uտ Ty!x ܆t(փpH4^K|%%!zj Sh6A#)H:dZ5-e+F4@Q5bE;L*E ukͻiqY X`$& 连# (RY /uKx5-[_}aǃb( gR o S z]nZohf>da!牅2ëK5T6Ji/^TJn?rf#7efLŸZn?i^[7oL뎙–_zGBX>XykvfKҭ&*U0B u8ZJ K]vE E?~#l3h4'όff RңPCQW]E#n2 I^P&BJAun"Q_t{cGlktLo(Ugh:6%j|3:CչPfO08s5[)C fA[ }QyP@f0QVГCO{Wya">>m7c-2jkQv/b.0ܡv"XC+bT6+b`TDE,T󎢐@aj% .^`Ni{%L)y%)@*àTgו@E9Xnf=ǼMzW/PK76%$I7rf2p{)vhl۪aH`j$lBC3 7J5:%J @iUJ@F$bՀr.(lU&e.Qح瘪PڂvmDJȖO{չ͌fq!9d|3?mYHפb8"@\(Fe|q|]lzq>cz<_hKqZ`y N4Rh՜H f5`&ryT㑏Z L"H5 Q2JNvPb1]d)e{)>w\|\ sXzOX3|YU ûV0\5, Óxts]!۸jWAlvYeA&_`MnS,I7.RݺWbqOy2imfFDHn hlyd`+,`"=="ǀJ>H(B)2lR$B""c9f^a/*{wcww)@G#ɸ~#wwLHd:C-ts9g56&0x.zs+-AO'Q]w嚕RaOd-7sl$yI:S(9'jmƊXmz0ьfFf 5N8+PQDa'YfNU~VRB#Q(RByzR?.Чs]K|4CK>Iȝ[JG3h8#,&?@^(4琷RFxqҋBv`6 cllApx :N:37u:*A8]W8X8]6]d0h'V ;5BV#hmF 6."-f\gZSLP)D&zN6KEjΥ`Wwvjr._[< 4n}s4)2m%2(3i8n\-:,JW`R=P @ƣkXo@ވq:v'N[ _ hH3mεZ1BJ8qE28ͧ" RٽRjMƊP$eȂBžI8mޑTz[b%zXag`f ꊏғaL|\}ƒnΊ')Ff/׽Fb iV}4ManOhu)x)Oy99z 0f sl 2RU[6S|<'|TfB RRTTR:`/f(&54X|zPj m҅E/Pk2λ$C|ꝣ_x7=L_г7i/r()tč ևfP[NV f!^:jhe5N[5\a*[ 깍fO\=.Jm8R bѪDF͌,@! SMP6{" {>cdt_pO|]pt,SnBA2"ţN)W=AiZ + E*i Ԫ*sy2'5ub7+B(c3ͬRv2n?H iUuE:;].Yf5P%UGQ+"Xѫ%XW {Agzߗ#8Xa-oaJAfI9Y\ Q) W䄖B**dbN[$N ;hbC%Ư:wGE­6A3ܴ[$c͔E(@YHQ+wR,EzKb$%5zDX(IF.7^;tzoAkDTOYՎCl F=t`˙v:y<Ϙơ(KC({Ù*%5h f6mcUHrm^ Z ӮXz6bai]eE^ΩBP475:mZ :rrN_{A|Ụ{i%ȽEC׸ha2w]V;1,d,(0PI*O0\.gɢGCrLDCE@aUg^eu:u]yV|Gz7UUG*Ěmmf1jfb$l?/}˯eo;}W> '}_ $S *^1WI*WVvYI[Eb[IMkXFLE`qQZG-Fꬃ=`혔Z(O\ueSѻ'mf=Pc*u +ӣtUQ?G>x+70h?6>O__mmC5XdłwV;BjIl]˪c7*}qP:5v3ӦBz9=~pn Wش#p B+v# &5: 4IoU͇ͤS5%0fEҚazb/O۾{Jp{](dHw@x츹~盗~?˿x}Ll`iP)<5jdS"![ L1# #-"ʕB[ȃߋtAwiai< DܩE6s35&=~BH6tOw1'ңUk c җ <(xK(;8q 7׏^^x0 HUP,YCKҬ6#rQkѨ"UTD4rPA Q*9h˜ŵx;ʠxnLV)F E| cOGv QN;tN29RU^*gtd5GθYܜ ׏C;{~Çx!{kCmu#AA̺DYӌ@MJZc),F%_y1:zя=1>EZAEF2+n o,յoBA%n^Bk7\X(A6Oaog\:!~~7׆G?O@z{y>y'ly?Cqu6=Vj2dV!l]rFmM4:&IIkо7ĎfͭS,Y3?ӫŷڴxfac㰢ѵF:asrq4g" Na=fr솜'c@hn_p>7ןCѻWW£G<| <ӆդ^A{W5nk8UjRtԪjA,{Cn!(f"ҿZpҬtQ5;0MICF;c~$!CS}`ꨠ5ѝ԰a>w+Az#W5:m0*|U.#$bs!׏L}o+G(xsخދ_VW ֒5H{D; WgP.6E#j60 BE6#4l`4X(4.ZWJ%v_G̿HzNfLUDbdlQC_F |/홷>cfFŅj 7x މ77>?sw/敏g?"NWWxTpu苣!IWl-0,aciR96Kgu"neexWt*8SY\эjkhB煨gU*&!FErVJ`;12n3ܯ liDM qto[m|t|B3a8(#sկCa/nG Wp _mܗbe^6K+pą8ΊC6JTii:9C IDAT]@CAM愈j[kM#t2<'Ldj:UgÔW 9 bj:t-B{rbIV;pR9**4%9ĊBwoK$JH,><&ڜWgSXHe^"6෶3֙=0oSQk{[kٹxrE/Y~9\]ok~ox۳Gu ӷs̪ʃ]ۮ[9ؒu=+2vMArVxs6KMTcڎwT[1&ζtʼOS(t$UDD߄E1vYlLՠI=[YGn]r6AZka0lPTWфz 9A#/4+>-زAyW*"ĹUđgIs2С6J|-#!?Y2^(>:US.NyUt0 HumgR?=h&]as +=KWc)QhBlsvBk+t)q¬FGllt$]U~Bs[=Vz!YN<2$d㮓tF2Ӛ9G4g5iXT.r/-^H >wG!Kׯ.ZV:JGcz9I GK4q80UÂciۖy/H_\{}q02XbFE{φ\7 $,ebʹ(3OAz) E "+3:oIVځяaAH8#)+z[Do\Tj7U.,x 6u Tq^)42J򑘺-u:✵8Z]t> 'LXyrLZ>@ߔA nBf]*ZB'&rJ: GH7`{G?] Xytz',.l1cczIޅ2iX;8y .9 ]&c4.LEBї͠$ewdߵ1ŀMp5uS뉸cA,|wEe/8s*]5T$7Nm#PQ$ 6A"!QSXPդ"wPI{717=[[U-R($"U]e$5uxinatq7Ll>TJ},[=;zŶ{Tz8_|ʾ;?8`V(8սWrKRm̎ui6x|̴{6kSX{vsmLݴIUk$3G/lqr$0}*Uh860$my+jfT۱t5mi19X\,g,b =e ?S?^}m?{b'٪FC iڕE(k ~k|x4tTn2q-o# rj73K0&Or=}j쏙R~|F1W;M9-Yb I݋Gmf'!n w?v)osw~N4 u^C¶AT#!V+26t Z6Cn HJRKH]X:\ UρP}b4zo=B졲ޜkEaƔq5`^yDb^A45[VeDŽp@@3nnnf}ogSijXJ^|i Z8"+y[ -?fD5 4~!DBJHctM[8S;0Z`6? yP 7h*J޽O&{nRa=.I\PR i;|?]uJe4%R&6^}o#W=qᔖ W˓Y=߇"NLTu//!Ci!~Oϻl;uV $5I/h| PdhX_R*c%[fԵn^u9S̈JQ1.q^l}INQ-Δ|GWon@ Ӕ]#(<ϓ a}I"F'vA+]~g> 3yKuj(E"*3t\-Ԑ$=s oǣw罯f송nk cQnz XwJ{zga:u"܋S~AML36|RFX{47+矻qt1[xƥm .V sȖұ Y~6z߫{z{+_W6{ eiyRYE` ^xj(uc+uZDV30 ʾ lULŮ6uM(;tEـsGL$zG =p478.Gjߐ4UQH';#9ޡ6/āGOבKmK%nqP(uvQkʫW($TAۆ:aw zPa8-&B' lZ )'U+75؛R+@v`,cBI71.\ry[#,FO:Pyh {off&kAXsy׌+6<44 ҵ-h6 >&FSP40Ԇ#X*MWTPξ-gs)+!Mt-Rd&FmPI̳%C_&Sz72i!Cݷz&]^W2f@YE*W,;N=rƳJo-Y*;ḭ(#R(BQfYS`v^φq9^T^b"muj,_Lb6"cȬZm荈h'|M#K'rP ȘX%^M]Y#R'm8E,I{'zk`HA`mz*lDD]|c.ȜO6%&,  ^5UjP5 uJ!KcB Cy,ePTvXA^\~+"L&8զ19JKE% w͘)OZ(^`y]5?: 5uEnKB32 ^p;#bǯFHΫZNŪpKd$0ϚKr 8X?w`༱״T:_8 >&p)3! MOG]ɲF}4c:>p!VMׄvDռv.>[ר?k5NVMϫK/cRf*ng;&Dm**(K罷\Ej+LL2%w0g4!kHJ\q˯aPwV/[2V:p8 w0DgoOH熦RlY0i>Q U"zîz;FEnR1@)8v˒9g8Zċq1r%RId ʃnjj,Ԑ` '$+FlpM"Xw՟&6:R:29 Z JGђuNϿ)bi|i(Q+QB!)|r!| } lR8#|-sQ|0*3>xJp~,u!PIVq[[tG폍$<2D"8Qn hyÚ}zyG?o2r쌡w[]tYOZY5jmx+H/5طV dJ*$!vQ4U"\ѳPK&9͝U^rT>O'꺳̽\MVFG百m8\>Z7IbU2ƅ$] aOd o8<=|I{Ȟ{}tɲDk@g^?tgk4Dͤ})^=ǮIw/v0K"b6>ABוyh ˔+AX&ټ9Y2= i`UqTW|~겸2岣6V6 uY;V \hOo)SԤ IiqTTn½}*?jH'JFbg~ aBS}Ik-b֊FiN:e#̭KǷSp^8g V;(\@DVT6SJ1uj2=d:qy7f/7끟q 弜R%J}d$Qrd^ 43+kڡB첳:ĦWkػ]$twϾ̾i-VtpLPXp坍s ){ԛ8w;dkeF $Ɯ92Ӄ?~ 2R!$5&}`4di 3ߣE\@OIJiR5 +*Y Uz?" s\5T۸aymb< aez~ْN ~Guޅ$ƃF`qqD2;\D;&X0 {{T kݎ͡3OXE~|x!nC^c; ;<@d>քxt~n8 Q lRuÀPM}Q,h+^ My8W{, #&~!)s.ߵӘ2(ݛY 𗲎 },vhB@$[ 8 eF['K!Xqf ߐeaUPCT) a#pCseUYEK(i G$P 1/ ]WԸ0G$0jm *$hSca\}(+)2oNI~RCˠbsA)c3hLa˛ V+e>RI=}/qz9#adj2񕘝y!ja3/sJ56zT<>2[Wrҵvu:F90aCq&ra>أf8`ZLm- F["(&XoCn !CҊKjڕ(G*|FzyېbI[ˠ3OA|#S ) T2fuj֌"+ՐƆLvY}9p$%B1)pl3MG送.wɏ oTIDAT?#܂q9@>wE ȏxܴ?]~r?/kq9.r~Ho45^qYr\q9.r\ߓIIENDB`barry-0.18.5/desktop/images/sync-pushed.png0000644001161500056700000003476012242254476020154 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIMEtEXtCommentCreated with The GIMPd%n IDATx}[uܫN]&uՒuq-`[ILM08clLC~@G <`I A&FI&-۲%[VUէk1Z%U?luUsZs1^k{m^k{m^k{mzo^Vc?k?_^~Cm_{Wmz]>ʷx_nVAoz_vlN%VLHEӾ&_$c0 }Q ,G]D.{/R>Kz}A~f]~o{T1b:'+_w#,sMϩ[]#3=g={3{_7EMCRfӏ?cE-׈^&uPݫ>L6GMza۹!LyDA>rg|Goc͒ ʂ\>T Io|3HԪmw91=B0kN72$),T sr,X݇+ Y/ƔDa]`L' z/ C>@Iis^+!gugNA s#/<֔)KLJ1ƶ Qm?Me.Uapbؖ_[E8Mw=48Lga7Uژ7_74#QV%JIlQ;hO(P9G*>+}mIPP ;R:|8eu-Jz )CdӓgtL֫ĥ* Ren#N xzL#"CA$vաg"%R܀@Wy.eGOR!zI떰"4Ô^c=ˇFAOyAv- Êhq" WoRolJ,P-xEb{j>#C"qɞq|P E % ~( a6Iږ)N P@jv!2;iy /2x kXCQ1/!]eaʬ FVp_i>\Ҳ1!hES0J Yrp:kN]贻:(U(ϋ1|PLжUaw%89'(5WwZRƔYR%TF1 ڐ$"![Z130YtQ\$#¿ߠn] $+3 @3zP1IŘvNye&SZQ<%V! ~"G24¿хK}ё'RWz@ /d4F)t) V|Ms,k暏5;ޅrkX)WKHwYXL/b *@H\ h U&) HAn @Jʜ2ť[!PjtKDMI'Hk¼vA%bpZ!#}@Nѕ%U;kδER6>6c= O|bE Qqb\QV7!Qeʵpv=hZ zSϺB GSDaD3NޢGq5$Fk1phel4x1V9nNvKN$䊍4 7Ã(sP`0w$tĩ“-& 럖1V*Ϛ$cIV..aFzfrI2"j]~T8)t:zb$Znb$0W&苸/5d.f 4EօXJiVd&E;Ą3IG- cdM35 6d[y AO4x i#韷4C68W< jH7;SzHjƤ)X—\e #d!*ҙr^ EeC<64k{4MׯPbYqz,a]hE*ϬL1m"Z}*5l,UT4CKBr.tQ-EaY&9B{d笓pq4kcftF(jIbOBr+\ލfR,:zςgxnz]ӵ:5h= b&h,P"A-~]㤽R_x)䦰9cj)tZE<+db[hȐHf(=,(,$8!v~N%= \=pvu_f{A ȩe>µ-PWCD_C1ڳZbۜ]􆠺Dˎ}"7Su8U!'/DT&ßd题Rޫ:Ȃ8zʙ kU Eiyޜ 6:9\@]&!*ԥkÐƈ詤r%#M#@ĒEY,m\Ttp!t 뵢Ghc$a/1z }]6J>u g=n)4bE!Uq^sr[V XjfTkJ~V$0 Y &HL픱.F삭cKpXC8D * cv)F6~lDXÔ{>ј{H=j4T l4rAX2RQvYJs:J MWc8M:[:oCiߡ%D$aƱUڋi E풴ks(̿5n& e&{(`C}߹v2Qx04R߅jdksm2ΐ 3-):7Pڰoɚ^xy L, obrQ`/W}Q=OnBv~sRZ&hאUVUC 'YK3"MGp,(&op?JO:T.GL8ICa0TO5za$oYڥHJ¿!: 2rhnt8v 704uMSٮ#ᆿ.7MƸ5"w0nm2ԏ; LD2JjMP€ƘpV]+ ciIO5x(&*I~nFfzu&{NՎlG8!*\{L/+F 8B5EGά1$i]4z䉖n8: S7347M r>N ( *2j7bΖ XP7^C ȪܼE%MatGnFUttgK 6ّKSJWv$E1sdD&Ky;W2~fCҴѢ”‘J6jV0wK8Z1 G$'[ _[hDXi:=!Gj5vrL/eZ ^ܞ+Ҋ?!iտ\\SE=%0D%AZuGAT `ػ,b8Y6oq "{05Ͷ4=#"][VB/hb AlHUs"?tu ^J##D fu0:j{RsQ5NJ>vJfA=xy@Pl:`Qoͮ^{ ;?[88W_~ o'-./X|{}OOaT0L]TXNeu')-MLF'Z~g047!UEn 8B0֡TX2Y<#7Qy=@plW!L0$@\3<~ڗ>gxٛ8<Ɲ7*N/( kWoHwtƢ3Ul ]osݶ9r<wg0]@p$30d`aMV_8%8ZPaK\`2f&C2W*ܺqVv6{Վ"FA}Zaj"'HXqP*\쿁[ \'A~},vh?r~[oa=_ qy7&_,cǸgqxx[85ƚA KPi rQLSaf!9 9>OoLBC:\-f ̰X5k AL&j3KHSv0btaL @8/C+ꫯN]}pػw7^|xCOrnܼ88^a2Re64h6QRL_$}n %(=!H=AD6n}fQع.637zShZ*_I$(OՍ02#u_Ғɔ9h )>[N䕤g^X@wVD!ÊHuYc26sH5fōyA<!\N.^7ʝ[..o}RP..q?{~w| _zo_ ~?*>Ԡ1k-fڸ5SGl(6IJ$5>`f +X :3'zNe6d#S<>S d^-cc-C6\!ۯW_;<7n??c8;>^k?Q,vp8yrC\=%{;8\^P1\(ᅧ'- z>j#eu N 1BZPrGuJIQLn'5" z]bn1 X]A޻56A̤Y* N`?W_8Ý[w`o  =|.n},k=;^,?NNo8ꥨbyYO ^V$0VѦz`ގ,Abd,o,b\;ݓ3\Xn3?]#+݉O/O]Nn@lCg,S^,_D5HLs8375u{Iʘ mȱD2줢9J` De/SE2vR9vݻLj{]Í_p7RGxx9Yxsx_u҇N)KPԁQv3!K݂nwE5 * -I;}B *:{#6E*vg*::bc5bҔ9zH 8?;Cb\/?xw{쓸[8}˝{G qO,tlWLJq/)e6TNDrH=0@-DCq:0.)nϻ/kF=6*e3 yk7+d0/Aȃn]Zøtt8]?uD62nUh?2d%yo-][-U_ؿ[: : ?X\^=xO7nvNqxӳg9Xxsg{7obg@(3on-;*BfEqiezwKI :ftХ>:9>O"@?ZXP>tϱ<6rn}]YE#5>==H\,S}݂[}W^{ /7 `ׯ⍏<W<;buW_n7+=?ԧ@ V)+ lM5vH)eM:E`k W^̫u3ĐH&el]Cl)ѿ<2yϒA8Bc.ې!]ΚU R(79D1,"DFM`+>XYG _ U}(''<[x8/))Wyw>N va|1D<Ƨ*T}tz[ tE c`y^}O=yf{YtabOnSZ%TK-6[kNQV-Қ֢$gg8 3Dϗpͷ /bS\5H3O,a MMɤfk#I`8 Mqs]:"\zoJj:8$9&ڬ~NXY ÅO31ɿo.<_}oo'D":;W^_?}X\c9S[^vhf9?5֕%l[-atIty8Y!AVߨ?O"b>1譵#+q8Fϱ-}l5^pefeWW퍰:rRpX`gi;QuP/aZxN>n4 |!'81؄ʉ^Es/Z(p3p¾JjV\btPu9鎒Dlh9b9 NSZ\)ZJqѻ#s׮??'mb`oo{+^|z g of(d-F6IZҍ=k&c4in1o>it:(}DͿjʈd%8+&ROfJWW&=vFZhUџMIun}q,~G/u `ΌC5(:wie ?@YHn T6Aq D*.U%o#y{{8?;<gDDv7b'Cj,*hpf5-xtO !GxKlK9 r}/5"9"E7cDYvEtv[7cG!Id*ҌNn03GN72񿓑H4jvWPHYS&#7g\Hfݍ}Aϥ7[gP^íK2\9F>i,LLTH\[DWtcsD#3I[EfHRt[LO~6w l9jAO*{Qt%!M)F$Γa_撘gKꤰjĢZX}M1ձawBĬV跂-CCN7f{'K9L(4%V`!ҢCyqa˾DPup6 a.#Dt&LqDb+(Xֈc&ӂ!B\=VpSC@wsK#%WqGwn jl茨=naҋCf1^OfE\HĬb#\c, h^h3Kqg"+wCGd3ٽIm]ȣ3&!u5|Ga6A\&.M  ̳ڃRԱ/9G.#jǟ]h ]!<6ĕG=} 5):Y5LHRr|!%k!ȑbP1,F=%Hl^z"M~"&,̐8B='$15,604طkG^4Wm-Q(b>TM5̒SG4zG(m } DI|Hӥb"}kZen00>&[2)w^0Վs<b1#/w^8*AEO,:|>IN#j HjT7Wy7_@VΊ>AƶfY-ַ9= +2W }1A5 ZqkD2F`_0IgFq3s'khhqi _RYafG1c ',I2.$"0 ŒBDgty@Dǯ8WXT%Ҧ$z;Jre&'1L#W^] J2=B]7@hIXzkZ]Dm4ә8_m8CwELR7OpՍ G"bۏ 󁦛yWf:H@,#%͚ Fi0 !1\̣Cw-6ndl80E! !.T:~'žˁSg0gx`ư!%l>GccNIA7XD!cJoijtsn9(HYVDd˧5T=nNkxg`yyA*!tB+˺9ɳŭ(#Zj#3gʷd pm`5'Fw[tFΧ.oVpy%AwJCtXVy爉w2q}4 Aj?xW+[]5$2\&=٭1*;"FLѰi0i;@;#L'`b*E; b1>΃yA*{+7!8<&sF:9/ cŐNֻS6\sɺcB-P"7-aN)6)k/Ff$'FUԘs T~F+ZkDoF1V5nԶUTZE mTDRn+4t6tM1) C *^_% IVV.,+Y{-8cBgF;`3 V~IʨCUD07.o#GuGQgsg_[y;[k!kUT 1t k:RyXSv7-~s7A!og:W{IAu9C,J[E} QڸLyc+e2; :$gI׷q(c[i1JisbiDs@G#M)!.>W ;J@G$\ד~펓:uX S ]iTŊd)@#Hd)ĕ.scYS*7U(#ɰ8NMXPrT5](A٧WIZ0Ggcɣϳkdf烬rW5.k <0|,B&KF̦91BhEH1 f亡R`T^JafS]4.{Ifxj&!x4Y Sx љx as5ad\jd3yX{8WEvYyE ϩ'ݖ_Yzz<T7p <ϡJf#Q3#L3EXG1E@>Ӵ iiz,\9MI#KCWo$* /D;^YĮ&%NҔFEh> ,ݯ}j4=83q.ri0*"­s";C>|نܣ˙8 KD>s1氒;kKT=F(cKNd@@sGLȔuXcaM9]<0(PM]@h:U1fɥlR 1k눀 LPH_Jc+ֹD;2IzºAKgS!n67Bmf52G&zLNFX^=āC^+ݙ! 1I5ֹI>^#i (0l9l NHDKgX',@ }-6}K6ʙY<*KfqsSU!y~J!zj1ӑR2 5ٶmR,$Fͦz0bf:_ͪk>!6(f=FŠkt"ok|LN ~ 8W 4Ĝ),dn<"&bVdvp>.v͟=Xccd!Z*"MI2V֤% K/ځHfHSTB :f1%$PJ/ ;\!p]|8kL;Ʈe/f#iqf,SV$F l1Y."%8kLzsڐ<Ӯ _j+Xx;p/t)MPڢ[(> E:j ߒ#I"|m~=`¸4in>8]+[fM!8CjETqImf7=zJ+!A?[I21u Qsǚ)\3!y͊84مx5!ӈTNB ,>hxs&ISGv/,Н:U1-֧>y|ӟ^k{=E=|~ iރj}?~s{/^k{m^k{m^k{mKym_w5IENDB`barry-0.18.5/desktop/images/apploader-pushed.png0000644001161500056700000003331212242254476021137 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME6QtEXtCommentCreated with The GIMPd%n IDATx}]̮UoB)miKO@`F؄ B^xcĄ 6*$(\X^ BlPXQ{?}Zc̹=oN>Zk9Ƙc|u:_|u:_|u:_΋7''=?t]]r}/} ß==_ǾK?'}Sc^o7z^Ƴlx׃g ||?}^KlLHE3&_$W|M(#ۯAK_rYD7sگ{k1Ư>׹_˯7 gkzN?/~9$Y_C}/7SEMCfT2~uEԍH'>e~2`ll{s1Nbi ~A"2 XH7{'w?5m[zyFM.5UŭvKh4Qcrub yDA>rg|GɷfleAR9)oBvo^M## sb!y'Li%epS_'0syr bsWr ٿ_ԔDc.0_F0ߋƐOn &ExK{%#dq?{9ᚦQ6I6_Hy0)%RƎ Qo= &y2b0=8.WVQ.3-9әFثM6fMlփm -bиF\O6IlnUDB9n3!AϸS}Nߝ@7N^NVe~ka#HW (U~D1B.^!@KO@!"6+ ?aQv0xL dIyk(E"8o:F9Qmxc!H=eC/6.\!c$??vFmADG4ꚤkFʦV #d!Iq%*H-3MyG.<.P H+) z S=Ǜz=і[7%x,^0=- 0eNHjAyKĔ@k6qY)ϫCq/f-#*S0P%AzL|?m8봀4"2@\&)B;!= xx t R=fSFF%'[Š S{]SAOyAN-JHaGT|g7)䁏Eǟm%^ǙȐi/FcGe3}e\e3_kU"|H!sD9%!I1VR7!;A CNNă@Qx">OL~I2(/ Sf]5%E|0sI˙2ƂDm~7M$*Q''@giPb9u'vP(1P=M1PT%|PJvXbp;1'AK0%1L\ոL5Ԇ' b=< ͢"ubW a~Ph`OϘ@$c!9fLzFHC6:?D8e&)iSU {c"OD4>21SS"V[|Ms,]k暏5;ޅrkX)׌KHwY0~&՗Q1`l*w&nt31E'0Ob"aJRr-0(RE-2Lq)QH(ݑ$bS ң0+xt(O=r$ 8.k5d/fZK]IR9۞9V~4I}, πc=%O|bE Qqb4q\Ѷ[̨pr-]5E޴Hb;6zn Q` u[0ƑHq-j F+KeؤZY渹d.W8> eQ4<.5`H.S'G)M?OcT=5H*!$l:m.)aFzfyrt9$C)*,^n.F0S`CşA)6RPyۀyYrRs<9x, jH7;SzHjƢbIc Քgidf[byg9bHg䉊t$&HQhg`H18D#ώӘ` BkRyfe!h YlS `ZrbF5w N(|DD n( S2F#;gO2E1 V.PʓęWiR,:3zς6ma3<7G?適NpM#(cO$b-KHD_W8iB}<):2EhΘlEjMV1% nl E%іQ&NSڏ _b?p<"1# W]eYdz DzQn`n1J'$ ,*zcsbbLAc 8=R,;iL5ԱV|&RbB"ubRNDJyQ +W*:AH$3nu$OAP6Şo..RECwd..u{(9mTGO%mkiF"$u%-*eET KOЦ^+f;M9l]MbZnF'7e/!i Zp6bq+ڶA'핻߲ tTMQum~H 1 + aUC)c/F삣cKpX!R,w CjibmZ_.%\^&okr'?SGҘJu!ֲBS)xr ?㖫[QpQ&wOz?b0/WyX $ 8D5yᤤkL>=cUW|-bmjj^/3ޠGҟ }Uu:%F<[F*nGuN'CiRļ*4cޔٞԙm}H`.`Ƕ4&7>;4*.%i*̿5n& e&{(`C߹v2Qx04RGo@OzrdH愙QXamReM/<S"MTL.jr(ߣ=4))>k?'eVQ .[UYd4.i$gEH3E`-(!o:q?J/:T.GLXޤ0F{'ˎ^ADUiCUWSC($SGwv 70p&T{$\r?. n[#rGS)#HL`41fWB߶5AMG ᙍ1ᬺH{W (iIO5x(&*I~nEfzu&{NlG8!*xL/+F 8BDGά1$i]4z䉑8: S7347M tXfQc9 2+_w^YՒ)MUEǴI9~f$`Cy$P=teD8^37!@KZi[x'SgV0$M$WuRW:[7&HN6$n-.b"ZU#A>d<KٰV7g@Zqg,^Ȩ[µ7*jy-!Z,A@iխDX6'Ar@ٻ(1,ynQ{jդAB7}@[3X !FOWB\CX!f@ǽF(#F(fw0:gj<{RبcEX; K><%Q(]6A,xHffWpW ~W>8u]><_ _$ֽɱHEմ/?V:1օ,7aV2uDSH*ߌDT !C-@B0֡T2Y"OQsy=@6+C&rj91ǿA3svy0X +vbnvX#"˃S[z!b8ek5Ì46wF@b;YR˘ɤè4{#Hg|·7Γ(Z̭H ^K_^y o-ڮC}s;[_ȏ BR8@$e"Ϸs0 dr9uފȾ0׃BޡvHlPiv;&D "WY tx{Q;NR{23ǝ'>BЙ+lUUk_cx{לq/c;_?0]@p$+0d `aM/\͒- -Y.ee&CͶ7n_øF+ ;j^cŤG L ADqn( MNCWci|ˇ}Ɩ>@ps7_|}*ts`- ]&,An]zL6GaZ2MMĝ!9fkpuLiQ[j(̰X k AL)j3+H%2eaԟ$)[~_x 5p {ps~׏o-G/Hm!r+@hd|' ;b JMmEXQң.ekx|-B "nB0]/icD 7+ 񄨱& iVDsٷaǨ!iW͂'UE!j T.|Վ|u2},n_kz VޟeG_Ç = .//xw.prJ/Fd1Xε31[ami;ʌBp}.e03S5g,ɇYhc룥g ȰT0DjW|NYw{K%8 alehцuH ruϸ!nps2x( 55 0 W?,# ѡ͔sU#eu . 41BL!4i4Q]i{w4?jɭpAoh΀U]wF?¼m%O¾\L}W3=>W7p ^|+_ǣW/\^7s˻߂XQ Vc)fE6PBvk,d6q1B6ʨVNG;%K}5LC(p\\ E;x bNE:W>)P.PzCMi b]34gugwÅ?2)@G.a*zBlַ"2h7I76իvd m&P')7.1k1x nx;Ŧj;KQXKnD"@jUI V͔`,HE%e3 o0C`5x/Ii{9@ІK$3I*?+p 0HTR%n7*-Wރq>...\ݻE #p.p}G[ۇx/GxmF$I:eɺ]ݡjZxe--8vWTӥ& mI;}zw!]B֑u-Wٌ_ۜak舓 FISFn4yԚS N^x?}GEm|c=(& F15 zØfiOG0.)nϻof2Rwl&:?;~z̀(-<}֣5 UG;a&*-`nmJor@*1 cC6GOӔEGHZ$|J$d#e>!Zu_b7BUԘX5FcI擿7"mV\^MZt>T,*J{;l}msi8:fǔ-UR#l%;ľ%q2$7_E7+GÃD%z&l|R:"`ڬbTat转11M+P2G%&gqWD7,X4ve;vB!YbSIﹲ*H!a7!8DI:DÓŴ VZ(,me1oyj(GQ6$ "#%D33"DcKs('fMS4 !X9!I;L:zrRX$ZyV T;w/vnIu3?'#7_(as0⒧DF$/hB yn1dYӴ*{쵖IDATB;}!İ 2qlG1++QpNQՇ]nS^[nP>{?8`ޣViTsP=V's(H)f9]~`sF5~Do 2ZFBL{,&&~>UBhE69U+ 5I~q?kw z |&~_'G|Tu1խ8aIƗ% #8Df[UƲ[D+qszfK6&D ~oZj:$9&:~NXY § &A>w^|q-ԧa^TNe${Zkl*S[qZBuEry8Y!1AVߨ?O"eè0A-Á4ڴHH<}l0og稁} [rId.*5^@ 9G%]BM'6)}55EeDy\C.Lԡ1؄ʅ^EsoXZhp3p¾JjE(α.'Qm"90hw'GGlk^{m2,LNPG9}w'tZ(Ҙ7`?q$%DokudۢHYb-Y>yugңio9aggVٔTgF9_ݻxG|ۿ{1?Gp=|w|4a#wK_ьբa#V*4'R:\Oto v+qf2ǝo@ѡm)E^r"(ڙHN T6Aq{sCG/KUΓ.׏/| [On1"6|o/=HofdBvRTLw5sP2@7pU 3w{M黮5MDAݏ楻ŵHo2 inL%iw]"V䭩䬞~=x^qqX7$-c Uܽw/o/;[:Tf+9FME ,wKbǨ!7|ө,a7[u$^Lt\!y7l55g3Z CDMΈ3 &1dfm5zTmjoY$>'|΅Hz)f>.s,`U@#opgFYb;Xy%Xz'LLvovDe%A:ҦT7s X 4%l0ZhJSǾ HtwVTN][$vyTM5 fIȝ#Rj#&i$!`qpT݅!j g 5 l2# ?-̋tRVD{^݈? TȭN GU>8akp`JB1Ai4J$vՒM6Hܥ1Z!b8e\4@3?4^nZ rEªPt8㙨§\vcrc:aj`fwyMފّZ$b18eE::9 ux4Qa0>#|+.z8h[#ď1n5`k'MIXZVE`|X=Q Bwnpp;.wY:U9t9tH6ɑC49 t*wAf>GgG>l)INa&0:i]!% bF ',I2.$"0ŒBDgty@Dᶔ$}9krSLsd%/@yRNa _K7pNqCodmT@8:9B`PWyxbӆ4(QE[w;\cҧTCvCMwovD$ҊB1myW6ӈ+0AKIFb+1pPl%vLgS"|.|< F~ u S,:jC *}j+//&lPMGWGb*8O>k:Fk뼋d;ʳd疊h}UI* 7y%k~pmxN'V܆>HR&Ҭ J`),ccE2y6|"mQjH;fIr4>̙Q(2Z"[Oɖos>;b(N b"j$%9h _7A|@Jmι栜~>ɖOk l``驘ͣ>@JWGg3GPn]\V~Cv;m,{0>95j6?;ÈdӊS=zS@ <-\RZaY%;_ja0b3g #&R&#=*Z*yk?xW+[]5$\2\&٭1*;7"F&:#6>mhW)OLߑ ʍ: yICPsh3#yL.tکs^Ƹ!(Xw=m0 瘓ukB#P"75-aN)j5elI#3B+5fZbP*hEKbGla1.:'|/#q'(-R{afN=&ʹV3Û>@F7bhSSC>|8 >Okh&޾r5r@:32a'QduIJ2&*^`.o#GuG\9<՝-Ƶ5*T=3``Bw-RG*/k*n&#F o.&=(M ]GqG$ \ 0ĢT%]D9~kffeOUs|XfwRAu6I΢9on-c)Zy1 ̨Rq%ض^wt> X}u* c+VX,5R3IosWD:eLSe2!SJnRca7t[$`NQ3tn;t$Hc ɥl}MA)il5cuD@Bc(B/-؊=hWbVuX7hjJޟ7`N"-b|,'4._M>ܐbHS7ǖ8{vzm:1 0kttpXG@xAט.E6j X@.~ \8W 4X\),dn<"bVdp>.q͟=ر1zL}$H+kҒ%טv`R)i B[bAU7偤םr`И-2XLg"O_`a<4NU/gL3cyJ:1J0ݫ4d&d^v2 wqgڐ<Ӯ_jan,Cٗ8]Jvh;QN·%Hҳn۬_0.M[o1}qb*hn bSX{$I*R%VvCӱ}~d.b2玝)\+!y͊8 مx !ӈT.B ,>hxsj#R;UDI*u9?p-8_7k[tkϺA> |׻o/~O<_~r[|u:_|u:_|u:_"PcOpMbIENDB`barry-0.18.5/desktop/images/browsedatabases-pushed.png0000644001161500056700000003300012242254476022333 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME1"֌FMtEXtCommentCreated with The GIMPd%n IDATx}ϯu^WXqld-DQ#E# )2a` !@DA(),,9rwWwzm;笵qUԾ~wskv:]tuN:]tuN:]tuNקOoNDu>%ןFĿwho 8)#;᫾q>ŶM6[x>[oANo|%k/2I}<+r&_4"8ܾn& .~^msWgɜox_g״1Ư>ױ_u_7dzji[^#Þ'z?gyVߴAW,=3PhBJzJePeܽ\\cÃ6lՂ/0u-ghqCH@|뼙=ͱ,H\rgoɷ"C衘g ]L !2'<9^X}тYZI̧=sIp{7I+w6z}d;tJ` ?R7o̺2G]PUL|M#t;R,߱8!†fs$lqӶe/jϩ,n>-/SjtgFՉ)i}@F7 ><>"%Q⯰fl$hAR93,o6o*U7#b9߀<\XZ Z"vTɘ9<9bsWb ٿ)G rw>O#"!)ߋOf4ƶ^+ !Kxkd٘G U,tGLKtؖsSL|g>h*ѶВ-o[X'd'Tigm- G &1R(|ĩM6NNƢ2\O6>yꑊP(m([)}FQ&8s:!G0$j|Yo"lX0A*~zBDܓqKl)H趧{j|W3ۓͱ!\zʶOrIHmdIOlbF U+2eрBzLTm]?}xmE߃ d{3}RYjءCV| kt;{ȍ&ҭܠf$D& h~LO!:U0y:H i<,z|#])T-'ʁBpl' ]Zjm"3fGzH{:A A&Y((cU6I7T鋝)[bB5O$Ha0 =)?kJL="@BXI.0bt*8**$*JTHZ;MyBG,<,P +) z S>z>Ѧ[7 <eF I3 oFL M"Q(ȔIḗ}fgʠhEci( =Z菤u/:-Cc yd?M`HOs34}<%q)[31#H蒓-!EÔ{qCT#wPxвQvD[MMIbF~Xd{kyR">t|F$ETN{Cj4tđJL93ZHO*d( D"i;LL=H1FqBД* $+d F 2(#v5i>S&AI![\3,(. ; 3bf~z,*F'iQv3u(c^b# Ѡ[8zgaRLXU {s"OE/{@ q}е$ eNa4=.5w$PĩÓ#& `KgO L8R-70% \(M>ZN $C267CB6ˮ) Orm&j^=V MBq4\-4Z$hqjbҬt;';Ĉ31@Єa!]ԁ)RyۀyQrRr<9x( j7;,\=)MV_ǢBIcդgi#W,l8TA[,m vT{"4g&eZcUN3C=@H2aaDeIit(bm) 14>g 3x"} G(P>-XTk A0W@)FgV \P3)4&!o eG%>D>&:*C EdXFCd`މH15jpA~JU'y8H#-bd7֭1#HM'~bV"E.y%͊r͑&p! ~4䨃@i߃ʩ<"MV-w$rٺjX17#L_Г蛲TuP 4%|{XifŊ-Ы%*b{y@G DjA5UGґgGR@IJB\QY<N{1eH/Y`HD J i}edA{`Q1;:eҊ?ᖫQbQ"w7P[6Kc(\;Fc4/T-\!W_ƪ+$|-BmjjZ/HfoPӣ?> UACE#wt͑Arx(j7fru8sufK/F#J8PD$)Ʊ-1{{Yt.Q 07U9֔ȻMB:0U{@`C^;NL@ kMiij?e*퀆6k3 ?/!"MZP ?Ct~C_u\,0B{'ˎ^8ہDU,+ѩEQHTFs(f,a%A7LU8MUP]ZBT{$\rh g "#:f ,B2w%dm[t <1&U'ixL6Eqx&8;nYz&VdFXEjswԹ z(r4^RFPjF(r&5&fcҺ.hȓ#57%[8p&mY%EHEDXϟnIIJaa!V&E^0lΊ䘭,nGsjKL$Ir@ TO30#QjCO|9syj{#^nxIgF<}tl9܌z^~I{/}5$dn}" XH.iQ7O}+E#=J8zԾ"MU,re+Tctk,,F%6Φ?㋋wy;YZusyyW6:c)7lPvc2])-x4S堹7njn]*L$KX( +ƶ)yX$k4oz<']tU JvlY[e;J,_O~AzeRZ\^^Ƌ LE ˹b&g+[u$D1Ib"O SD.B&@p,:3%fZ-=dt%SS<>#ծHLp;SuТ zssϞ=?&ح3{ۑO=_]`m|)}u`BVdjHRQ0~' "u}>T΀e]^{ zlGyJoȿOuaa_bs.xqу7o~Enbo(}+НwOCbop(~,y{]LȎ~̆4N!FՐԪb$)@@9ēe4Q(WMgٌE8NBTQU׋cxxV|/?'/vhFjZuRT,B)6>4N}-9=%+$?Ծ,aȷ,MvfTEoIݜG TLd!ی:2}q݋xUH{exX}aMD<}2wnOc fzҽUEUY6D5H.LbM-h9)k$m@> r.pT~6Gk ,DHXR%j7nbx;3sv%틸ɫ8k->g/m16Y$$ݮlZxe,|*g6gNf]UAU:ݽZGrzh8Z " 49r9x='T֜Qxx瑙qf;##>xv/nygޭ*ɤ2i=XXi61"F i} .=q wJ(ΝfǎpJt4 v0Y EoAŭ[q;ֽ[ß %ef|:^d!n:ϮwCh+]ÜQ%bXߜ%6ͧxz:@?WW{lw6D ׳ՎBB[7<-sLIOZ|&_ܼQx~}_F$|{[g->zz_ًTG) "Q;G| Ŕ@dT+U^lcqv~{M<뛏mO8[ POH j1GǗ?w/]ƝNmT3 QTCjՑ+viDoBbQ$4EJKz`p³Á8ڴr$_?z3ɳs\- 1au&v{q0Ͼ$w?گEuĘd愥Ϲ[ 41{NQabp< Svhr `~XWT{jJXWS@ȕ9Cd:J5מQ\LD8FENߝ(S]Ww_7q~~n"B9}Z<(y<|Ag?wc{"#)qJIktww!ěcL3BRf!U#M Z3; `kg!)ciKp+YROdJkWw&=C?#O*CŎ?}W8;?%R;Txzy\ܾ⬵jR]:]n}+ZX+{}JEoqҹz"I-9G.oA3O6Sʔ"忎@ο,v&}55(nonHEXq;72p)XB| )cνY/Fs4MUBvR TLv5qPr.ý)QaF>~M黪5MfAL慺ŵn<$=' .K (Krr=h"EjLysr,rltdU$,'K wS"Ǭ!>i> İ-@:!'nl:Qx;d5G99?n:2Dj}[P.7礳/V!)tE'"b=T;F_jǝYTa(M9-L#w>5P)@)iP49]eԎB]1fNnxmG#%hjv栗Κ *b IzUzfN7IΑ-2m?#u5Ž$Jsb ';Z-2]].&tH ƛbћƤWN&ϱQtشEZd&EN,%M>k dŐΑo RoE>Г;CS ($-ϓ/0E$lIj2i~n#Q>oݜYyT)З-|sO/#{ǟSu4y*J2 pLR|yJ\_G>),]!G\ im^_`RYUN]{JH?n =&|= C-ƃJ"ܬe A;Z,s1ۂ ։FZri:;= Dӂ|`qTKTQ F0; rbB뼫3Q<{ RDk^݈?I#:.(IV6B ط)I.Cc&( "({mPPHB!W3saQKcBp,3hb=_='&4ZnXREʃPt8Q9'],5*c7YyMފ١Z$s2AÍyG'PgOSE ᯫ3g:C4jX=Bh8jŢ&}o,}z/VE`|NY;78^v];:e9t}**t$MnD3U@o>=c}>ʈgCx!Hb 647XB-לJ- . `^_5k)9/1i\B6Թ!MKçYXX:ϣ0&lJ`),ccQEEq`1'[V&E4); ~'== a2fQڀiM;׷Dj_|}kwPD~D,In fLf~/u),M9眃bGβ'B$Asv qu#V9C;0RI3|́<ʥK< #|(5ICY\Ǜdu9,J[REs s]垪0gw€Kk1.:jhbE]1; 04*]>muyGCؗ瀄FN8;%|^S\^'$jowFès^Ow:NY{h5H}BOҕoM6-ͥ$FȖKȕD.sc]}e{ʕ . %ͤ!&bB%-xT=@AKHNH&& B~#l< Ȗq8e ~2;m1F0b2 fyɕ iLrd)F`u'w鲦nXyda~hLGw5LYFr xJěj)cɸznGn :CpVvYWic l}MAAil5ayD!}yF,Pr:b%ZE&$=_MIB09IEDzar%Mz-& NX^=6@!vAL$)@o^ΦCG 2 ҪٶX  -rBX}`+3" `C1b 20'Q:vQin.3C¥9(.2ɧ4K end;RE`n`@OLe4|U~tܿYvtpF\G:(&_ciCب-s~VU7`\&hTb=sbxXt)Zt?[3`FC4ܹ3k%$OY!! 8dEe9 ~4k3G9&Sǰv/%6Г:Yr4-~wqN/Nt ONt}'oAקx>_|;aD|#"t?OקӈƶO:]tuN:]tuN:]tu~!Kd4/IENDB`barry-0.18.5/desktop/images/modem-normal.png0000644001161500056700000003454012242254476020275 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME >9ftEXtCommentCreated with The GIMPd%n IDATx}ۯgqe:/ mAbh{~߭VZe^k{m^k{m^k{my~ fN3~;\z]_?>96i3^foٟ-{ bfWx^?^+^1W֛^_^|Ѯ'z{! Jc< n!y475zЩG1Mqa{V{5\o>n~gI1no̴#\c2^ast}.yck>}y?!Ͼwx7nmtFb{0tf?bL -xYHAt/ILJdb,A>G6lɗ #E[Hi@#N ;z7S#gAszy܂"Pg&/ Py֟Q (tCDD@Oz<⚘Sdw&f>`q=mzyY@]UͧvK{}  s1;c8ōLz&1HG6CH7q1ͭ&ao2 ȃXJ&d 4f2beuUɭ-,?j9a眜'߀-0v% 65?s?{9݃}ƣan59dAPtDi K"MomDI=n,b,v \jOMNhPLLs kH[BǦJ3kc/%<|7[qbe 9R%mAډFwy͏A[6/'}QBmN=דOzb B?tl=c8rDM6Y^ּ萷@"lBd0A*yN&"LƤ@\}$~e=Y[7 ]t~!bA+CvG_hٷ+X}^QY1 cSS0i,eQ a}yj$l}"C 'G!մ_ޛ |x|WK %pYQC^.0ﲘWdwK0absOL(WW\) Ya2(#vi>\  FIDB8Xoy'afAIq@}@ݼH #bĝذ~pX02iM8/$ P=D(2HT}RT ۚ+yz boxIVP &V\ON c5s읇ysskP[Iװ#) DGEN/9G(,@Hnя33>Y$H0 1Q "3@e"zH$d@I'=VIJl;Q="0v00!GvՙDI*kp=XM]GeR{:9g\ 'F_Ʊ'`Q0ka')ȕ *R 7CC2aaU&nefcv0zw!vm)G]DYE3Nț^GjIdעǠr2U6$8xQ#l7vR RH%^y9*ɤK4$F5@!H.S'IE?6"$c':No aPh0>Nn0sb/a ơY$wZŠ<3ddQf@5,(,ȍ<ʀAPm9F/eS~`uDcX(KdP"%(Je(|:3w Tj#AH$^7M]Ah hAPpa.F(pj_|씞r9jd:t(yX KE!1{A 걎eB4~ŌD':H- 7楮,FtLz4 Ե$DE54r=6*çyFGzHdܢR?{.*cxX<P mbXhiq0~f>KnXGo^\՞Rhs Zs6b>j2\,Azbʸ1^-@{ Ѐ̨:\?blH 1 MW٨PyS9eL@XD )*A)C*nb-Z.%\BweCaN0o hF\gNiy2 +\NjSU)Spud+ $P묕YhpԢJsLizpBL#PJE7^px@t J+HT3-zB ),k–dYK6Ŀb De4wlJRN*+x *-&,uIrѤ.nQA2"݊CY-nT1IUPM`RJeM֟t [Ruj@*|&?EJvH/ F Sj)r&1:I'QQ-O`F_n[ߴP 8ziCArm'bAS ҄ERhGbԈ\fv{w%G?,س3ٙnsꫯ;|okW,2is dU2a *Mij\$s%cפL\$ǦELާcWU'4(W䖳ֈ Q^O br#4dLYHbwa$a _裏.0|ssg?3<٩SWf+_9} 7\wz=BgRA>0k>u"3JjB"% ɭn6I:عoVfsjnnqx,uB^4P{2$ Ŵ4N eo]DZ+<|+?󆧞2x1K >h_7ixm4OD㞃*'3+0#\U\,gwJzB 2vR'xE Pͧ:Ze"g6C96q'=,uw:k%%x%%ʹ9Y۹n^koi'4{1Ï~dC~]ַb57 Re Dm"2 Z"284͵!>YߺDܜǑQWsbHs"#֘ľ;v:q\,6[6Y86aiwc~fcl[,~wvvtϜ1;s⦛lp݆6._[o-i_!1Vڭ ;dSG1IDb')T15f" ы!Eia6jܡTL y˰rWψjg|pl^A*Y~txHa!ä7?蔇ԛ׵aII!*2i,^V0[⎊׷ER뇩|RO6ЛpQQev2/%wDC!Ԥ7ggrW&$u}/m\hx!fbۿ=Jx7fOsfokW+_i`oכ8!܉P]ڒZ=(ly[\ qB %UCPnKG9%q)fG~syG~զ:7=Z58k S_,*-BdJsSP+;F]`׵4UČY)}u7## .RKVmdaLEyIM4^(0 \͹i 'liZ nN2x\]lx; oz*H ^oN8wn5x}SOyf3( Lr$l}@l.L\kbBs 1 3E:,TI$V.$^6r 49fH<FRQ9m/:`}Ka$tD|I/[\u3ftwvOnq|_n;g7cvf7dvʒ<ŋ !I]USKzYB~p2g!z$>_ju!B֑q-Vٰˏ>zrj@Z;AnoyX J{1,0\uɓ劧^eϝ3I^g{gւgmI[ T듖ܶ‘{HEcZB> .jQӜqIF/3ô߽ H)V|lT͔΍_ _ KnCs &Lhդ@\G fGޞyРm ;g=fq@3*ñcJ EJW0GL_vX3o6➻xIzuΥ**k2(vm=BZ|g3l+ak|S7f/[qr/.٫Z8Cݓw'N/SVfjw%/1?vlɕE, s r{{Gfy;5X g{v㽌'ѽ ŭn=}\oɜ ͑rOYAF[Lwseajdc$ LrrK_T6åv;i/ko8sE'NR=98#Μ.+4 3C(UZs0a6:wM]6'H2fUISe Z jvMAnTZ_>R*a݂N_@OeIVcϤp&Y-˗/~]\2B.D|NNqA,d?={;ѥG8YabSwn1 ӿߚRĖ{V|Ħq:߃u[.Z dgx>$&p j: LfT>a͆ZK_җ_߾ =: MV4Ⲵ e㷅N4 FD\v/>hp=7XG֘a1}MIDAT7r7js!d=bv1 #_IԦsp;Qاmz `yL kG _={֮:׾\GvCG+oŽiX}IVqȰ2Yu!/1ʢmE"\b'buey/mX%5_海[=(fu ڜ8vึݟu,PyoW6JUDbhrqpg]i|onf?mϟOػKTAdM2; ,1c#/VoHψS5Zdo"%C(n":Gd$qJnVyDHC5uI! [SKjP6d'u1/ra0jݸ*OJݨ7{oo~]z? .؉o ;o|)E4yI>Uf9~LVh5=hl]FM2o'GETIF$1% Fē |*eՒ* j!^asҥK/~}QG?j's}}Mv@Ұ߬0UR;.Iڗ%%ΗZ\qhQ+ϋm&{o`8/֊8m亸E8%8xk:0I$R9\ +Ԙ`GAH# .Dbb0Ψ9̾oO7ȺMRɊ(^lִT1 f vE*dU+&vn硉^ aɢQ~Eʌ{6o؃(9QZ[́xllcmaRKpE Jbdɬ:uu%g?kЇ즛n;>ۉ'Ϯz;dg_D~!)Ep \S@f?} 1u`JHm+&|-p+UmhMŔB*4a˕ `łr?q0SRh4E֬u}ҥKwvvz]:ŋv%;={n6O~bG;|gǎ˗mgw7]# J324O>辻D}FjfXl3i=BD'Ff=C7Beђh`dildq=AE{9 .V, `tʤ?钪ʬh~K?~ ;/d%gwyK0"oO}Sv)ݵGvq{=yyl0~D jkÌEzDrbmc@:M[UcԟE۝ek/m%L)z^s TUH?eR4z8;6֑37|7~{oɓv̙=/_?ͻ./ɇ/9r$fnDmT^uOhJ *LEA=JpzUּ9SCwUu,*d{irjϩA R#=XC<E%bM d2M9v'.7}~,ڋxGS MlR<ucщ eR kL}s(~Fż 53P XKOLU(‹{{Zj 5׽4w }D7 1WC]M(`Y4#&h^;|G-!h(kq_WtOy5,6GXծ~ggw7NnDIXXֆ!4%^+][PjN̲BUpTos3y(0ژe |ILP%c?qv.(mIVs2B žI‚wa3AY"4  P;a$ʇsD.ʹ ]),t_n=' M)xaF$m7aLPC0%I,Njnb?T[18;DL\=dsPs42['g /܊ $k #|2Nz0`nn [N^M*ib"6AJ`t`\Nj(k 8Údwp%]㋹t 1rl#qr&T A>z*?IHOGi>n,"u] v`cB)U ᓏǰ]**PȊΞJemsϋy jk |jզY% 6k)GkyC|y$ɂq>#y)5ôЌ[647[g547$5Er-&v捚vz lYmWZq\+dj $I9숄SuevӦ-א*&?@_Igb1E)qKi0K>CL%T%03E1 {N$ Ȃ `΃aF:hK[Uv9×J6H9L&/V#f51S sds >8K;'פK/3z>, 0~.(VSټ9XM4RAAb0Ͳ۴ PwfJ1q㽦EZJ1'WvMCw/v+GP(ҌB!ՑOs6i|tpT F.rRMͅfd#wIG B.vNݻ"YÉA0Eh*}!*9E\TTԡKr$Mb&̪x[RBj˒Z]%kkRUy&` \%f3DQePW0nxAno.8_ ۜs۽&eN%e<NO6|+fc M@ьP̬0-V1s8R*qR$%RMKgo+Uy.\EC|P65dQC\Q u> } sk: M`Tk#-ґNQ/MU0W>pLkڳ8f_[y6jIWYS!#&D h"$#EE\1nDg/o⃂Dunڜ5eq9T$JZRI!QazHRRL?P쪶vdwR'רm3dtkP:6;$a*DukFׇ`/YH@rk;ă>.[ W ;;J#R缞P#e;d8aIܬTAɯI.-u%g*II#e)HD] f,&WUVXDRgXLZ)b`JUY$uz ɜĩ@+F$A摆7F%:Y)Hzߕ) c$>i6lMFNi 4Hɹ\I/UvJ΀* s=EEt954y1da~̤0)L2j>aIԒ\:C /]$ AMP` ɠq5|wIHza1dL&׃3 |(\-CUԴ9TR#,ۣ,D uYjxEk#+q5iR{2z% IMx!J 3:_B&A736S%)͍QȖ'`TTԿq&ݻȌiP2"Bs";C>% Vʋ¥Ğ[H.{R LjJ;y!I=;ͦm(/mź(Xc {>k0 `X*y^>P&_vD>Եt&7(dAأLbӺI=DO5͢5z7K1HCxNACD`Xaf|i͇i/03P'X*4mtlDQ:iR/qnUE5V1zX"HAYpb/&=<"ՄLP/i l6 Z#fc>`$ct"UopBDڴC:l8#Q̄#xVR1T 5\*q K6v% 1g*N"MgHhEn :TY=52FYOTWK2'-QXrsQxYcxbNJȘ2u60ZwRi@c{>dZ0wAo n,u6FL=SX[)VF1K{V?LDO"li'CxjB,Uka-|ፅ7:K*m7eVr0|=e=.5|ҨeABf!6d8#Å@ڋTqI.X{$JR%VVCC}<'򁐄: p}XӅkF$Y!N I;dH"S6shh U$,-OdGB`cxwc <7^o`{m-E}{!^FjAoq{^sg_?y̮11^&cfv]_ۡ^k{m^k{m^k{moIIENDB`barry-0.18.5/desktop/images/media-normal.png0000644001161500056700000003576712242254476020267 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME37g$tEXtCommentCreated with The GIMPd%n IDATx}kYUs>}z " `"")Mia%,/I,/Th#U1DJ#=$*ta`"0Fftt{Y{=΁>&:t}okg=YZ_k}Z_k}Z_k}חŧW}{Wm=\Kz?O)6IߵKw-{WYUͧx[o|>魯x~Ѯxޏ! Jex/Ԃ p/{ΫiɋO=cj&P #ksU?k;۽R%}NDiv= {gP :';}-pns5S[]#ޟדܳ~nCu {  ua^~DM,x[H!W^&:6zusd_\mS6|mقOo0|-1yG-N/;Rp>h) O[t{S:ndӓg:[ CKKBDG~ìr0xL!ZPE,b湺.6I |#NNV 5Tms:$ 0# @z, "j'&nMCKX/Ђb6wT8qԿ%"c:FTC_=4. }$HpaŢO/ d,@I0p[tٽ`/[&ja T;#%&Jir:@WԴװ"EŔ~q2(/Sf^ժl% V@;0_OC+q*Q'ON2%A)NϚS~Jtڨ.&fc'Kw4cpڡD + 2f3i\nm1[VdwM0qbsBOL(WwZ\)Úҗ"vPtjCܓli^NWÄ͢"ubW ?S,(f60ȧg`b1wNbʶAˤhy%iBC5D%ajta:ё'RW 2h1,}е<`nEM̵d06X3|-yT.4FzuГQqfI|ԙ -_{R|9*2h A5X@at@31bF`&L S65 !{vuRȰp)92KH$d@IN~{%I$)V&`]b@.3!p-. *,h::o:LK!!Pe,m/g}\'XpdE+CT`-( ݪL ܑ]9EÀ:C GSF-v ˆfP7Y8ɮXÑa1vsmg8J\ɩ0Ձ`\=/Kld-`0W$tĩ“" _mD5H,F$,:-.NaZfs:$CNihLm #,*_N<$71ZrbOǑBE\dw23fjB4EօsZ' iȝ̒f 1ə[{9=̩a/!ϋoC)-_r:<%c;K6#0+1IX(Uܭ@^9V72gK2cyņ#d!*L>QrsL²!Pb98B-C-1ײ8Q_Pȳ4&XªЊDbڄߋT7ْ~0WQZr[5W v(gDBiVƘe#Gv*',^+0+3BQ+w]_9.̆Lno? J. ;9ItNrA84K4E˒hm" g>@­O'79,1RsTdSYRk钍nV!CB԰($ܲ7:yS6c9z/eS~`G4tޗ=0_ D,8<*uaYX[L_ b"zh*jmsbbtBc x&Xv὘émJQzrm"娉Y/Ka(Wu q3AH(32ߜ<gXE$o..RDCW\Ҏ01"8z*i\HxvV, [YgEEg w  uVt m#M!9.A%uJgcu StOuKR unJ͜uXԪkN5.mzRʸ9^-@[`XjfT\cH 1 a+d6*Gҩ2Vh]U,2rUR+A%CjnX>]J_mL4&OdE8fybmHeTCr#[QQFwO|r5 8_i,9AR aƢR'_y=CyĮ2!Fr]űx̤Fk!y:/i8X3/1p䌖̓t[Q,.2{zG-6>J4c =)U<c/Rem"-jDVJ+[ܘ(͵ةP]`-[jZhw7pl/3^C}رFY%11吀=FȟZ=%aK80X6/abfRL??3jm{4izFD:ХE_JR AlHѢU}6tyyxYO6RpCLj T:*k jau8j̭J]/>DMN$X[ix+r 9PUbcB3)62&`zO]T .DN֌.<2݄تKuqwC#|31JZUh :N*jVK %'=X"H "|7 &4%tr&KX\8nGԳ><{9;/rݝ{կ U沵DN<邃a1k&Cg-.lrZD*N-EMES.J, ՞fV33Z1!Z>KbSq4tX*!~ZfҗA"As>y< +L<9n使w?~E\ 7q[o#9G~p)ozӛ@zիکRZ~vZJ'{E{E:A{?[׋n,Pr?uQrhcSz.,RA}52zCxome-q>dݔ>fEjKhW uȠ)ɒRm$ڠy} oϼ3_xcc~w-oy o~%ڤK:r.E.~g+WHE@h8V"Yҽr8(Z7%;\|Iq+2em,m-:<@ 1fP =)Z|w{?ݝ}sq]wo{PJN>W\pH5cL(Tڵ5 uWVn>7"(5!z m@0BK:#sRЀFOQ9q>rdŢ= @]@1-2 wgim.}?8vGo.EUH_5b 0#VSSzLa1%=2"PT>ΛA!"u& oc ¨ՙ́4Ѭ-KJ$|=&9Ag9w~xb;w=n&&._6Ʌ xw?7Û~oW?}뉭Sީ='zARjT yb,F$QBAkmH o]x"$>-όXvX6+"U9BhI۰c!Jbbn9$T1@I(!p@\ĹsPJ9;GǩSSN/9>O=<'soS7ܴk&6hLZt襰nؑ':L&xRI5>Scfv&8Q3<ڣ3VhY>1wu LNYv }mNe9=-xb40LW4X܃`@gb{{'O&677/:t-r͇{s?UCGm!4@z"NXtŲmpYCkz2R"a~TDHF{cI ;cѵ 6qܠs7Jh 8R 9,/lk1Cn8yyg{{{s{{GI;v {I;v GG?Q?ǎÑ#Gp|B\fYQ]RJ3sOA@-oB^cBSWdj)խAN\dofEoIXU*SĠA:+]YVk{eYZڷMG$xXr!o966ɋR vvvplmmx`{{gΜwމ .ɓrJP{>Y,!;aW΂܏$cdw ]`Zz=֨{u7䌮%zًرx^Vb5 A9͍s.Sf f{2cbEFj$lA 1 3u wI$Zn${ٵDg hMU%H Wb5K +9r59m\n .ŋ+<|h?CoO[:R- j)"3=tD ESf.oS{Vq(I0+)~P!jkߛ;S/09?#5V[4X<'sdc$M\[xO+k&vqz +xhg/'_-7\7=O}qx sm˗ɩq<5YwtFBN1mC6G;YzRI3Ҫ* W6pFmڲ!ʨeb4U-m;p AZml BIDATd5׹r! ?K~xޏw|a_3NƯas y ?'cw'obWkg-KRQr:^ T@Ut̢¿u־VDۉ\R;朦IƦ0=&oX8RՔj$A%+o=BYqjFJIrRo<ϙϙWv/onnl7=x O>_'|WoOaI0n Tat,6yE@EsXR Э Xb_%RQ8(6+ڸGo&u{`?=[}eeeC; oB#0#+GƋ(8y&_;|e^y7<~ 8gAVqm,fAX![)I: jy|g~*({YBِ2Ju T´hm\_,fC7X`d-s6ƝI}NX(d"g~%F \L M7ue"p!|C%/8~x/{շ{IA`“^`Dγ3(tLfeOM{]$]|- ɨb.[|YSU V&e8]b2q@dJUpQd"UEKjD+ A67G.nu 7t zg/agwN+<0ߍXaP>{O{ҫ 4+'D\W$:NZPIDi^* eYƒ\W=2ݿVkr!DVƛȌNb"8y}yNHEj+,rZHՅ״&]뀅yZv|e^3=H (K:r >/87ވ@c<7mZhN?cgϜ>T]TV{ߐE$5wh 6{?|O+wۏ9swn?|x{rqy"b7xnyÇq Hri0‘06wE$rkC.{j+ey-m]2ghdbTxT @zsP!Ωr;ehϒ%ufeC 9DcTJ@wT}x+C kY|P4$Y6AiUҟuI *np͗NC?_~_Oo8yxpg?7>V޺5_?'o{u~n|3Ͽp >\ QVBڹ Jd{]1@j.!6>St}-T\m^zz-SVkϥA S#,sKƀem 鐊@ nL2Z>Qȍ>x;_v"ĥg~_{ϑ;gWѓb }jTfy1o02cCx b DA2\³mG gxX쬀V [Hn_Y10OzPY(ͳqBx|[ =ؙw=yK7wvw 'n/LMk=3&L bƘl9 Y'IĖubyj.WfWE9¢J:}|pj%:(J^30TU PwWS(M6w*$K\ 55} c")*і[aˋifE+,(]L))=B7]&04ԏô8|S#&L97 /FG4}Unf5RT *+=__E$I U1ϓX᱊+NOU j"-YNL4ڹJ_M&*#k2F6ɽbڠCm?8!I7 #V:NEBrnј0[q 'Aš͌13iyQXƝ](BV]\6Z_s3Q0(9. `gUK:7$J=L}XL=JYͮrv'E}Mr&~}ky 6O;&a#UwI,WO&&d_>WwH Hy zڟ0qDJzؾ #fl1p8Ge]C!a =ˀCUZ傒ok?bH٘p3P6$>QAnz0d6ifɕ*f  u儭űEl eץmB:dN* n2LHK]KG}.֢'B׻gA#Iҡ6"#fݜ!ԏ yL HLB|P})E`0]rRi).Du͋ g 3c&5I`d=S{̆)LFpKα=rs*rL+ wWX\+K6:XCG2nb 17f:<`mrrYe)yN>XSdz=o=Ca,`7pe1mYK<&Xt/}|iQR"X 6rVF@'#״V⿎ 6Qb(VQtKR];.;J2sSv$[^ڻZbt~Iv_F'LC#3,"\:'R^1dc̗mR^.džaNh#>T8V v::ϖ+"2Ʃ{P1w7.)iq ]v`1 h:U6fCK Jq+m,K/!]u*Y Hܬa4|%yBZx~?jAo8 $R~Cj"|kC<\horCINFX^=IZ-W2C2yͳ"~troJhD %4J?N)vki Ҟ^6 Y*A14m:>xX)IHAYhb/rj6^ݑ!e.So26H:3|e ?5C:l*8cQ̄# |< A*E^b =f]pljQ;}I1z} nca`<؁%\'%dJ I :fe@|`9sw0Լ] b؃ƈgZ<3o+(%Ô!=nLAHmbI"je'xx@6sZh /u%.JKt+4+@O÷̑g X,]&,&-]w:i&l#3)\Z{5F\R gR=ThWlV@LBCXхkF$YF|tȜ $4Lep([m2IIXO0ZB}[ ?x;^\e=k}߂\Ck=dKZ]v}kj/ޱ/QxPZ_k}Z_k}Z_/ZMIENDB`barry-0.18.5/desktop/images/misc-normal.png0000644001161500056700000003705012242254476020126 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME:u{tEXtCommentCreated with The GIMPd%n IDATx}iWu^zzO=hV$  c .'$G\.H)S*evˮ*qJ%S0f !$DˠYԣzzΏs߯4wkm6f]kvͮ5f]kvͮ5f]kvͮym?o_hf1f5GfO]_fX4w67w{n~gvͮ4s^o6aϥxzk6ߵSX 0]VN-HstW+)ыN=|>m~&Pt3C6~{iU|, z9>}]86-־C<茗[k=p8a?wޏ0s\>r{6tF9b~0uf߽G&,$t/ILJd.A>G6Foɗ 躖#ER[Ha@Nu;z7S#gszqܜʷmyaEG8\7{LAZh"ʢ͋LƪY8An8Pa"@nF;y6wnu>@SoνxnGfꡀUL|M#ZFGr]|<@cNy]N@9\t' Pōgڅ]EY|jD'WO:(;Ӹў7Ix >{s%v\6F5?KjZ d EG6ny!$ NtГ&zb1̕O]yrAO %=gcXLG&^7Uؘ7_M lx2ya>EpBy}ˊͶ DNFqyA6NN?eQBN=דOH)-U_3f9_ǁ#$E"TdZ7 zTdVKd"dL/{/6'&#ÞkfX@p} P3^"x}xm &yTE|xݔtBhc8&sr}lXnTP52.GjXW rTK  @)$!(gO.>w(5/W'=EafKRD8O-⭳U]ti#P4XwC&VFn8u<$E"YrG\mMƜH쾄el2\IR  j=.oBhrAkЦ$(A1h*8uOGG5I6ЏR#0A7 [^>䡓 Eq$d0[bAOާ|'|HF҇ ,^ -# 50eVHA Srrc3K&ffdJjel9>1Xe1U7 Z|? _q;́$rg" \7u'.r)o5y5!0@wv5| 钴 hޘfD[6MIZ|;MxYdý%7xy>V״<#,jFT!V>mU O2O S:-păR$O d&( D 6q99 ȩ< Sy>Ɓ.MXi'&zٔB%EPV1]U J$4+XZaCm &|Z FV >iL phCSFu8(81Pb>A<^h+ W%p(}Cy6 "U.2%s |b@ξB*L%8Vl!.u2b= ի<{-sމx YPR]_n^ $g5/bĝX~U00i)/q^bH"A8z(#PIw^ؖ] h@+L{ÓL$}е< ՠoEN̕di0X3|-޹[sn j+֡&=Œ#JȇsTeP6qs1(TY$T7 Q)#(y-(gNE:'!RLxsc$&Ze]x`w 5wczDwQI4I>`>nq aA]Q)Dܜ3.ȇ@"1>cIZ|YqVOxb"+\ ,EOfr4 !y*ef׽v0z{!vm!G]DYF7Xw(y[.6vm+\ʩ ԁ8a቗;tɀ9@3;9qd;H?lc)̮A`1"a"iy!T -Gي@4 &UMAcɦ}<劋/qwr:1zl)4]ĉR sc&/Hq&Ѻ :@~.lv,Yl&I$`l>x (?.!J@Zϛ ̋lNjxNLX!l{`I\@ѭrnEcv#c>(2l8_)=3rkX JnIb,ppK4$KbdݽpL~B!#R(A:ZeN%{%g*r4BK BTtƊJTRt[HŊ0f%32z)D LtgJDח½sa[K&݉]ςTvgon7g7q4ԤEɒpm$" G>A\O'79L0RsPdYk̐鐍.V CDհ0D2'7M(bmJ ɿaji;/y3th2TQCgQ`n!JM|$Xի.o(i]Z7f%>^*Z*% '&{*9jd:t(y@‹B`5Ub8h kN|r)oK]Y Mf㦘FD'oN& *O(եSiEpTr&mYA (%1\-Sv|(VZ^-48|I?3%a W-L^5Wi/NjI)IZsVb>7jR],NUĔq%^b[dAr5l Qu[*c!|=r3#) %4I\YdB}ɖ>F3bCp&XNCX\ JRqۢR前,4lcѩ~j>+1λ!kDRSA\s ?-n2GF =ҹt MJebv.M!X`vW?χ=wC:Qr5%HjmPң)\>m 4u79oznDf C:@ :OoPa-ϵBem"MlDR )ܘ(εء&]`.j[]jZ w7 qd/#Z}رZ%0aL[Wvo!Xn2 gթ2;|˜a47d1960[#F<.9ъ=E N b9$wjR2?[ vZC:YSpB Boں B&"y+uHQzG% s3O11ھ]ꏍ\)y{Zɉ8Gi6^8dj"T[[IH 5%ŝkJ\' (ʹW~'}gMq#,[|&?;m<0 7Q|h20zeh)U;۬ ES?'Ҁ@L|rd08S̖;Jx}!^Z^9jfdW_}OrrĽmgY:+M_㍘InzY @Nx9iU2)`M˓5%D W`U%?}7[K46ͣS- \'3ɟt3!㍘ NAJ;A&Q]/>ݿxn~_wx4)]XX|’Jx}斗mmm=IjlK7\vm# Z2X  ڐ^:D^ |&J6>2CБ!͊V ZcZgl%[Ble}ډ y['l7f{xnnm[>w|yηF#;{1H(S\[[ݹb˫fnv1?zn~wZTnMؑ':L'xA5ݮJ" Q*!y3C ָ}2i2T-]]4>#S5VyIIw - ;'/?pޫ|?C53n׽wlneu=뫫+-3| _#G̙䓇p5/]te4r^7O] R^׆B&DBޡFz `zω;*jAI%} ^D-F˼<{[46&=;ҩG͏\@?`b'cnfm >[^zk)Ϝ9cNu[o}=_>|v}nxv^{WOYzb~—}_9KHi 7lys6llTb(HJus:SY[I[@=$kOX@iyM,˵4HI͍T7dmXMG$0-].پ·_옟5K)٠E;r}_.nsqJ}г麫ڷwatϗ.#׽Q::J"Hl*-\dJcSPkdwZkh'҄2ZwI]Z͎gC-%5!x[2p5Fl8RPre2)rɹ S`h4]||ׅW;vmΝcFv1sw۳gN[ֹÏn .pj*>v^+9j> 0B%!16GuCɁШ@6~̏p>jfFZ|_+o)C᠜FE $n *h&:TbuKȊAIW5,Q)@7 ץ7ϟ~/O䮝Ͽ|:uz:[݋} ].+Oٵ|k›I@FHFv'q%vUFcNQQ=g3=eĖ %^J4&OfA [qk8 \UZT{J:Qb٬ 9.1"7gڳC<,I b>t^_r+>CynxϿM|K>o~˶|=K/5{'pP{$mPKL5<ƚ hX(ryp"mp "n>5Ղ>XcEJ﷪lN6vlZYK4mL;!ʊtӱ@W$%o:\X,e~7W>bFy|7n~/{щ;ߜx!kЀ[t {E1AQfB_%StvwV4eS4PJ?:-8%DJseϓ@D?E|Y g5;J0OωJIҬ3*N_?'7-g]Gma>;cfkv /M7d{>K'g՗NY R'*Bǩj135b,9HB9r&6#S21ijWKO4sIDAT*rL%f|,@[]nm}2zٮY MA=F<]NI_r-켽{lyuɻ?f?k/F9UBoQ peH|zLjODIG>y6Ԫ?`qEcКۺ'N/eK.]q=p%2w23/N#L֘#ES}WI)IZ|u!@fv֛nAʀ& Ґ h-eH2zWm߾c9u3sGoEWw>xVV;s){k8޹m|OO|XQxъbpo2%ݝj\L],h`?b>oEqvH5{.֔[:g $b24V)1== ZZM&P@Ʌ{ƈou҆bI UY-DtŜbڂ<#/O^x}S?4%;#vesi٣Gwo{/E{ǝX]Z^2fKKKoqZ[g5Y⦶Gwг] 'tvu,^߯*0L5)I:u_b=Knj/ [xk=ɤS(*iԠU\MHs9{W nm;^m`n՗gK.Ď:r_k]t¤ڕ7vEW_}w={q$o|ÛV<ڇ?'ߝB&_7FѿKMP(KMaTUUfX=7("vRBB\%kO)3t^.}%EB.MA"T"44A`_:^1ks߰.εC}W~~V쪛^ x}w; oСCvy}{?ի>][sMkZZ1 f3=W%k5և@VUT?@{oos pw#'f<yAWIC찴n+;>}>xn]j//|O-95ھkae6WtlZYZJ/}gϜ<k^?޽{ٱGqѵx2Qٙr)Ԩs<Đ;ujxivDshPאKq)4t6!豢urtٳ3gNΜo/,-\pd3gO=76_`6??;,{җʿy-}$gW9jFV,an,,xE3;,P-PlV@"`MljߐF nsss㹱c=--/}ޮuVÏ⺋p9h1kiDAݛ.,4ZuPyA_K]ekX\}`\>. ˮsOKnr D%ޒ(U\{Փϝ;rxܭ7x#~b47>7m}Νٻg+EnvE,aueX]_5hdzJcFްrTn1BHxEj Uq4TL "yN) h[ܿ-͍["je8 \Q -BM)?Atbo@ ͲQ!3ūRG$CqtO{Uiw%p]iC:l<%H UBj6Uk+"Sj瀹x@Gu1Í4(ɑ(=MSnE5K}]^@^ߞsNhS.&ư+w:H` u\b-u'Da2 05eFmV} U$6cP!U0'{TkwtЩHB~x=R$!?s@&H6$o0#Z s^{!| yK}"t~*R Sf{y`;ՎtD?f` I^ŗ+a8JJݯ9Y0gP”a6[6d7[geT%Ec EFYYQ;=X6\ "mWmY$s\+dj N r믦KM[.O!UtP~urS!虘yt2xvNduu( &3EĪVF!2D6uBk%&C&.r/13l=L&MoN@Gh)OD'OQ.9).n쐟NvՠF7m; E1P)tAc5eqYX,/1ja{>w-Ȥ(-j)pVRN>k*{)8Bf "l6=[Y7˻me#/ת]t)!B]&pAź=tK]7u>, 0YGP], t" 4wqK>$Ն\d%U~ !]eJIS]\Z |J)vF+i&ˈ>DcM;qT^۲ Aa%Gԍ$yKg~cJfXQ(Auk.1֑9+3x".s(k7Q@s(qA=EN&׃=u|(\ Z+o`"L=FXGA1Xo\eix֣rW/5pOD^7⿊ < /xSke;d'ӛLܔFyh͝`([ZZRSƞs">)LM:Zft~bH_$AcKy*\F)/KAs!AcDa%a;+y!4!z*hy+5(A=0krjz4r^ XdhZW8HV+X*eLDM{=&3ryO8ˆgC5J؂~߻gM 7zR rBm¨d!bQ{VDvp.r@şՓ"c$Q!Z u$ I+r%6רmX2&9%nf#L rvS JjQuS\ˁ3tuK* mgeVJa9"̝5|Ҩ6"&MͤCmp<$^DM삵{T,U`iE5D((Z볥@sQ>P'IۧtɝeVHA.Hk~$)FW:UsF@Lj2S([nc$ai)GxXD 6 n؂}S}5\i6kvm܂,Άlv}]Kߩqv}^>5:׋?_o>3[?w=95f]kvͮ5f]kvͮ5f]kvuˢH7IENDB`barry-0.18.5/desktop/images/migratedevice-normal.png0000644001161500056700000003567212242254476022013 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME69ftEXtCommentCreated with The GIMPd%n IDATx}kgU|Z{$'\ B@ EAkvXhQQVcP+PJ (Q p$CnZk}w[\߀k{osg>fk{m^k{m^k{m^~323r;\s:efoy6 3q9u8o3{_wi}?]quYԻG 0(MߔE~㹽]qOnG:榾F/:?Ʀ)C1̢|}~;bL?W˽+YD~,ۀ~fZ E\hc0^astu.yck>x?G6hɗ #Oo:^r yCH;5xuLuhs%P=q b>0Gmya@:B7DDLAZh"-LΪY:Am8Pi"@nF?:y6wņnm>@HSo.xaGfڡUL|M#A ]|<@k`NH]O@Y\  Pmg]EY|j'DݧPO:;;ځӹџ7Ix ͐< \b,DVd~ Y]џao4 ȃXJ&;d 4hf2bmuUɭ-L?j9a'wqh ֻs?{w9!{dhG7BMkrza >舖&@",,DʰnzݤNYD[b[LNhP Lc H[BۦJ3+c LKxo(, s3okK,+ۂ@#v o6mN?uQBmN=דOH)&͛/zOd5{Wq  ly!o "Eل6 3f كULDIqOŦde$tw 8l H^!P`8B[]\hϾ 8XʴQNhAHm@dAMY L U#ah@>8z uU GcFXM0l22Zrܢm,weS aXfQLOߘ6IL?crb*<%!g.ʾ>'w( -/SV'=EafKREn'Bpj.Ndx(@ѾO"-#Mҁ\Y$B~@hCuP6@IXP[ݗtrlVM Q7W;@ !d۬Ǵ "M(MN hbpj45(Fu7ME{Q.)^*cF<ţ.Ay+BG < 0 z(\,q]'di cx<1L ׼H .ȬQ@CfmrsR7!rS;#<> y>Ɓ.MYi-'&FنR%ePV1] ̼UKJ8:,[vX~@>E #r4:xzvR5/Q N2ԇO*iDC ,J?PBg3!\fe1[6dwI0a`sOL(WW\)ê3$ԥ-QFzzs5\tj' `· 2%E1"@B{PpT0Oh~EC ŚyIhy)io!BqQFF E5<ѐ'W יdIkuy:5ފҁaf[0/]pn j+j֡%Ւ#j(sTeP7 K Bt@31UcFa&)F!Zv: AZd؂8p虈(% Y&b/yuNjky}4%`<~Eu&%[ rBŞ@l‚2=E~vBCeѧq XtXK0~0.O,Sd+ATnX/i ͪ ܞ]1@*C  ESFW-v8!ozQ$1]>=G+SeC}d0ێPJSA 1ec14k/Kld%` W$Pĩ" cKgq  \7( \e+uܞwLG'$C07qM媋ēq[ r9z)4]NՁ\ 48 a' !̒ΦsLR@Pz!2956@]y uxP2ҒK{^0/:o;Cs<9}<$3e+8bb9& Ű=iٍYxQf,opRzm1KgpJnIbc:C5C51WQ9Q_?YGi T9E"ڀߊթo&L\ENfhIAfYN\1JQs ^ cP9(#JTx,FIlNHv}逫ܻv4Ad҃8X9",𚍝v0=C}s+'YtM'8 ú%Q5Kµ KE:|Zo'79L0RsTd,;sQ2JTd(3F[FiAߨ6D-2)?>", F%`fP"]P&a*},j-$S!k`y% 9mb4Bc@ ʆ Ltu؇0[1USZc䗛ExDQ#ӡ3F^PnyX&AWXXSt"YL|c\"n(cIϛbF9"rTz\nΧS<#M`ˣQ=x$d@nQf)ӟ51,xPv|(Z,48}I?3%a ,LY-h/AjM)9kvuUN5i.l y=1e\l\Y5BDh@ jfT\b,H 1 MW٨PyS9elL@XD )tTRTľh}$pyb# Mߕm 4OهdE8fybͨ2PJV~*h[!R'M(('L”4\ )fg*j F|p!]2 Fr]5^FR#iAGP |X 8rB? ݈( u=>؁Dt&!ޠVk}鯥lElDR )ܘ(͵ةYt.Q 0t!5-͛8t`T she-[0m(A{?ƳZTTeN>aN0o (F\gNiy2LI,r9KNebOS+H'X 9ZgTĴL^!Fà<ǀY6' I!$d=}@)˃.nBQ)y*`$ZQC${'%m"YܥHf_g:9`]#V;(I9"S#70+'Wi1anJu?+/7MFpprEVzqTQȪ~a)JQa CUrUCSB$QOzNҧjaɚS.ˠFoM W%qhaP C3E$T1 $j]!4 苇jA"U&dN܈;@,`4-Ȯ8-4Ө%v&`P* Wj[ऩIF!7=+:LI( N;r@UR CIY}X#NgM%Tq$S33~DW"&sPj EKA0qdi3S?%Ǫ*+FJաns$Ƃcgä mX ]Y1$F; Rdd-uMgfqqʵםI]c(yG Ju{T#Arf޵N"Ii#̨`;Ѥ@iB}1AӦbeTM:]R% cIPYD,*f* T:˖,jg'*!u8LjĭF]>̋DMN$XT[ih+:QʹZ 4$'4b#b EުA@BD`OS~-MH-[''0%oC"z !A& B ҡj9YG? YXo s!L (#XeƾsU";+ vǨ 8MKlѫ%{ApWrF^ ӜT̴H6d]&cAOe1` TH$2X 2 =pVvHPKr smq.=U MX$vAp$FAqв77{{^/x&_tmgN൯+ W|swO.Dcӓ)hfō%4rQ]g&96$(b{>fq_rѩ#f iܿAD0CLT2LYHb7w%k7uO5^u߽s|9!{26];yrkv^o/^K?v%} H ILvg]KӠQGIN}eeRFs]( #T$uA/H2g 艝lFj}BlLP͍7NEl 5>sO#QaD}&5hwo}K+.zӞ4;u#]|*;6;n<}Y~^}m/xNUo'O\} "D'JP#`DIZY(TXc@ е@>S-X:o>D*;,r$m#TЄʉAQIJԲOBDeq#Hy/;ܝ'=vﴏ~[;Խnyg=Ѕoz]?&:E"O)BܨpQ;qBLyH BPm}Է.4$Kd3c!b5ĐfE+G1} vls7@Qrl٘v,dї@(\˞7_pS.ۮ>yw{ەk^x][b!ߴ/~7뷞 ^IP/\ؠ1k$fJ5aGl(2IHIJd&@ B"(șD3C ոC㣡f4ja 䮎!Ym)Վ(ټɃ/śny駟|Ѵ9~NN^*?̇?R_h )΍=xLaX`X߃,3xьk6}lzvoh됹sF Qpxef {Zp9~_m"fupbc'] ?yCsϧ>yޙ]t ezv|_ׯ?=og~EVpis:bZ\ G;)*Th}zo>Cv(2e36-ӟ}y ?< bQ\`N =`9tN w'ȩE_Om$:-<仟zKѿޥ?E྇K/ϟ[:0`ݬJ{v/Q{ۦEYGL  3R;ۡEܣZr[oMۿѳKy&,yZ1C9 af:鴭 )ٵ77hկ|]w߽e 9e'ϿOΦ{{v$:oxLfsultfˋ7['ˮ^=b0qraڳF{%ϝ]de-ͪ#ksIrWoa632C1;%  9|$H ?3﹃ќA2e0슋sg~|bg;]jn>CCzHfv#ƺ h}B> .*9XˀĆbm*ߦ ٹkshؒʃ@s L@`?pf_z oi?~3gN=epb#?vمMY53Wt sĠE.QkF U^2hf.^ҳsci i${,w661ιCտ}oףɤkE!W²9Ӳ/_bRfNO+o)w?[ϼkO<_cε?f;c6`j|c-P}魯߻3w~Չ+ӏQ$Kf~ kf|k) x eEq[][Q&,Cm}M@}Q~G%"|`Ȏ *2[K#˃.чQdVSEPXw=S|T'Ž{~η}[nocSbբ{?eff3߱>gf{o-U_a!H-eZ!q)mE)kve0n9Z/YAEbuYUTd-F¬ӶykIDATXzeb4U&dA-Hdn%d4uL'λlݿ;ۍV_z [O{}q_h7>9W=xCU/z`Yg+`B. : iN 7BLIj 3à!sin[q~!|dž?^~叻cH\,e{7?si{}̧;/8{_a}}>ɯS3 :CC@$j_VtǦK V*!рlpՋW57Y0(J$:;K :!DdZ3+3T;Z̅7YQfv9}GKr>%VV˥jjiW|=_7{_sۧs}'gO=t]|Y}O߾=>/Ï_ys&-&*cTt*up)sH YP<ڐ2L5nP;` .:S~"E> q)"5JBkiFB’U<zRxJ0\o\dLݹ`9W!+,{X/|jiW-ZlZ]7~z5'εe,ϰ߻۾%_N{|>bga31c#/7Votfȑ@]do"s!"j65jEW&DfG$k 6&ȁSKjDxQ.ܺHF5_v+r|~rb}9> VK/X.\,Q UO/؟7>O}oڻkU7رcӈX*1 V/E, ړ 0Z6Do&sWk5wPkn =d,1P.d*FGē |*AIRl5X,Xھ/ ,V/X.Z,|X`\`X`XzVf0'v0g\?Og +9[}v V&f>U-mwZfX+|ݕ3G.VDV;IǟIwlNgf3nsn@2QC},c}!\]TNTVsQVhmBc-̻8+xؠ8X"wFjM%`A29N oȭ-^]ep2h%`X, ;[bwvv؏bcXXZ1ၙl>n8<;wb;[ :[+|32%*DvZ^]պu mMM%$CHLR}o l?:eԡC)иIqyyih0DieҟtIU V4ߙcg>jE,vHrccX,+kf$k=[]&:Ԙ|9v}f,U]"}+ZG2e{Drbec@: [UcԟE۝eBS[h S&;6@9>(R=#ºF>`tHPDRmyαbZZ,lZaZ[.op&z|g'f> !g6òl&ЂrNFYA~>Y!P;3-*o$Fz isU ͚UhvUvi":*ZUGiB<(jSy75HA$蒇ﲺD0[# \,Yٰr 3Xp i^B0i1BH*jY"!C*ؐװw}g!q֮H٫:ja"w7`@溗N} 楦ȭfVvuc}!i qzãM)VMlG-!h$lUoAdFb15 aUm`#+';8ȓ?w)D$@W 5ux!jҶʁbi 2硊/B : BAs+FS#3ʼn[Af*T ,l2W AO R>Y>Ѓ{TVBXS 9'ԓ?r]hjӜ:D0* hnB(M[uhU".;L !,EԧHYUNXnJ̃ð`+6sDWDmiRta,(^@ADdu 6""豀 p 2KX k(#E^34 D$XjQ{6)Jz Қ{^ڕ s0ڛ6 sA1Rו k x]u-MN),a5Q`[R+ߒ.L\! ilw[%x ":fVGjwPjT0hv UҞhנ8+%A",Tt9p#hC0͟7-DטtخFi0DV9KeHG :3z}M@b$LF,5%5-AX2HG0%MZu.0P5 ,̴04ȯI Tj'!!Wu5¸:ZrSv3Z27V,NiVu]PjNG(B:ρ樲ϵG Z:$Vt?C|&BmAiK>w,#TJ2HK1(m J(5*N˟!S["aj^Ľ*N)ݥZ!Jo=1(b/̓w҆br#hҪorsIJuK3zR 5ϚhM'jMϭo"V4"W9IaQĭ3Q{wM&AHXzX# ԩYZQUF#XzWdJȹJ"M>FE azwDڿa@΂3؆$6쐊~9ȅK+ȥj y# ʆ!?9Z{'gNj ޼VIBj|:Jq{eM?e)YZ>H~nj%؟N<*€cX.=HȊ XzMeH:v+ء\1'] D.wQZD m fܯ9,3 w0ez{M > :{q%w^[RH Lʊ遘ƲF궵^-wdyqiLH NzE'$#L=6M\@ ,L/is =3!R&OΏ8= U)"ִDڙ"=q&TjS3d͉d$Źh\\ay0hBbij.gRdWF%'׀re&yM  "Bl1@y0RN5I;BV&(/V{)Rl,L@!$C@-ȇa'p* J~MrAn[,?adL&׃# |(\ZګYh  84.) դKܓC-HD^X/J!v;J2qS5Z-O`A~m]ke5~qv]ldZ4(3"Bs";oC>% Rʋ¥u=\ K *# +y{Y Hc4A΃XIo")#<&$]=s_3=>;Epjjl#\Ejc%8[߻ BfM" !}u>͆m(/}ۊMQ+W1 |`zy,-<OZS!NR~j"|k]`BriTt~;ABf!6d8#@'ɵYS%"Z6b(#KXZY  6lh.B$cCGSfw?^k{m^k{m^k{Mg4@IENDB`barry-0.18.5/desktop/images/MainButtons.xcf0000644001161500056700000025751112242254476020152 0ustar cdfreycdfreygimp xcf filexCC_+ Unnamed#2 4A A(A A(C=A(C=A(C=A(C=BC=BC=BA BA BA BA A( Unnamed#1 *A A A A C=A C=A C=A C=BC=BC=BA BA BA BA A Unnamed @@@@CC@CC@CC@CCBCCBCCB@B@B@`B@@S gimp-commentCreated with The GIMPgimp-image-grid(style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 32.000000) (yspacing 32.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) E 3(#+/W7?HRP\h1rzew?F^S6Media     h2_gimp-text-layer(text "Media") (font "Sans") (font-size 18.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "c") (base-direction ltr) (color (color-rgb 0.000000 0.000000 0.000000)) (justify center) (box-mode dynamic) (box-unit pixels) 6&66 cF "BqA\܊! EC3@9dO3682$#5FH  tdc   ,FHWa^&e67O"Cԕ6! ^,Browse     T&^gimp-text-layer(text "Browse\nDatabases") (font "Sans") (font-size 18.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "c") (base-direction ltr) (color (color-rgb 0.000000 0.000000 0.000000)) (justify center) (box-mode dynamic) (box-unit pixels) U^, m^,    v66 u6 wu   r@?BwX YuuNKtljIWZIYH(q    I  % OUX[\'wU WuRQE H7wv@,n 4  _  ECEC ECR33322672FHtt  tS   ~WWFHW^O"AO"67O"4i !@(((L\܊  6dO3 >5 / , ea^&e  އ Cԕ6w L\܊ Ll6dO3l6>5>I/I/ O O, E ea^&eE e@އ Cԕ6@އ />,Device Switch     g']gimp-text-layer(text "Device\nSwitch") (font "Sans") (font-size 18.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "c") (base-direction ltr) (color (color-rgb 0.000000 0.000000 0.000000)) (justify center) (box-mode dynamic) (box-unit pixels) >,>,   n 42 _1 \܊ oM\܊RqcdO3A(sd9dO35)2[5uc S   ~,[I/ dc O  ZE era8@އ tM+Sync     o0O gimp-text-layer(text "Sync") (font "Sans") (font-size 18.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "c") (base-direction ltr) (color (color-rgb 0.000000 0.000000 0.000000)) (justify left) (box-mode dynamic) (box-unit pixels) -d+-x+-A;!Q")V!&' oM{{ulaۨ[29$ sd9A`W0[*g?M #D8 LaZi(3ra8SZu4<%tMa%*$%CM, Backup & ...     a((/gimp-text-layer(text "Backup &\nRestore") (font "Luxi Sans") (font-size 18.000000) (font-size-unit pixels) (hinting yes) (autohint yes) (antialias yes) (language "c") (base-direction ltr) (color (color-rgb 0.000000 0.000000 0.000000)) (justify center) (box-mode dynamic) (box-unit pixels) 17M,1O7M,1c6    sTU^~' }]Bi$EI$و]_ c\Z ۙg$%i&c?v@D[@PcvKAE - DcTV]xѴYv ``l`˭rX'<&LF,|7<<<Rމ 5TTWqY3& E~Y!t^k"Yd'TTT[p5tP5?eeb#] (]@@A}EK}Kx@@8rlx@[N A ,N&dh&vFY]`[xB[Fb/υ~+ /<<<D 'u#"W(4 97I :n Aǯ 8%\x -i3^k"?@8 Y]υ:&  go-jump.png     &-\8L 8` 8pi9:>=<==:93:Amf=;+9>m~qnr`;=3Cpkjgrp:; Ah[fea]_f: 9S;998;J~\XTVL7 3qI;;BfRPPh: HY89TPPQJ: z{:;bPPvk:MjR9ixPPf;if;;PPPX:`Y 7BPPT9YM:9=PPT99:3O@I;EPPUF;.J9>qvSPPS?<J9;ezWPPXv<7NL7:W{\PP^h::OM &9KwbPPc[:1Q 7BoheK9U 3+gk4' `  yu YaG< 6*#     s  Qi  ! 7M        M emblem-photos.png     '-[@ @ @,+=>>?>===>?EGHaM~R=>CH`FJNS=?FUKFJNZS=@CCuG`FHJLLHB=+"+F>L5-''(&&))1$B:.(>?>===>?EGHaM~R=>CH`FJNS=?FUKFJNZS=@CCuG`FHJLLHB=+"+F>L5-''(&&))1$B:.(LWSI=24:DG0% +^IFGI@:7678=EGD=' +Pil[MJJGHJN[gA% ;{fsymJ!^5 Kנrf]ULD;3*"&|F ]کfRDEMaBZM d|ڋ~Kdf bڤz^AMKdf bol_Kdf bμx2\Kdf cЫIEKd. hĨڝYOd! h[2CRb P中F>R߳a gھں^h2 .eՠf>Yfǡg]&E`ddbd`J#I,+=>>?>===>?EGHaM~R=>CH`FJNS=?FUKFJNZS=@CCuG`FHJLLHB=+"+F>L5-''(&&))1$B:.( 0.FI>LWSI=24:DG/ VIFGI@:7678=EGD< Pil[MJJGHJN[gA `fsymJ!T ɀmof]ULD;3*"z SgeZSOID7* ˇT?B:( Ίw_A-( uwcP<( zbbP<(  ̈kOI<( wubH4( ^\P<( *ySC8( ryN8(Ed7)Qs:j|oV2N,;g;u K              ! / 1 ] /  k+ = 8" 4l<( 'F߭mE6#(3b/.gH;057 740;I`/.fII HJ_/.eHH GJ^/.eHG GFI]/.cGGF FEG\/.bFF EDF[/.a8>@@>:Z/._/7X/.^/7V/.]/2V/.\/2U/.[/2T/.PL JL. -.. "76675oqqk>54uUF978 879Ql?74uCE EQh64s6́:n54q4Ҡ7m54p4żѡ7l54o4ԡ7k54n4١7j54m4ܢ7i54l4½7h54l4ɾ7g54j4Ŀ7f54j5ӂ:d54j>EEBd54iI?5:; ;96?Kc54hKK JILa54fJJ IHK`54fII HGJ_54dHH GFH^54bGG FEG\54b;@CC@>[54`5YY[\YY:Z54_5\dYYY:X54^58X54]58W54\58V54RQNN3%4334#"9877897looi?76qQE965 56:Pj?76qB- .Pe76p8ixf;k76m6[oto^^ml_II^[J6p9k76l6[ihdXVgeXAAWSB.k9j76l6h^djZE9FO89QM?.k9h76l6vhohJ/(-"%j9g76k6OPWO1*3=Upummori9f76j6FZ\R96K>"$)%#6j9e76i6{>SVK20IL@*-IG:)i9d76h6v7KNE//HK?)-IH:)n9c76g7_mzzii{|ueh||ri`:b76g>-  .Aa76eG>73 347>H_76eGG FH^76cFF EH]76cFE EDG\76aEED DCE[76`DD CBDZ76_;fg()XTTRKC<557Gq?q@ "H43RRg()WTTRKC<557P?.+)..;Jj()ZTTRKC<557Q.-~[0 7..G()[TTRKC<557B. CP*#A4.=((~[TTRKC<5575. @~Y8AB.4()|ZTTRKC<5570. ۭtKLJ.0~()x[TTRKC=]_^8.) $lsX\C.7xu))gxbYSORaT449./4";\hj\k0.8;-&%/Xq|}tbE(..6@$1DR[sE..#&+.)% +..>YUYisG..(..0?G@/..,+/../'-,,-+)&Oқۣ}q]SV]]US988<<786!$((%!)#[6( 3'(())(N]afkptO(,,),@)()4F_uXSX^chh瀐{U++,)J`FFXvtus{()~rVXFF[X]cgllohmsu((^Q:jFFxNeni_UQXxuj]b()7HIIZSsdI@xhh2()`l>657BdwbWTUTd_?khh()[WWUNF>657RgWliWOXliI`Cgh()[WWUNF>657LwDqC %K:9UTh()ZWWUNF>657VD40*44@Nk()]WWUNF>657W43~[0 844L()^WWUNF>657F4# CP*#A94B((^WWUNF>657;4 @~Y8AF4:()}]WWUNF>65764 ۭtKLM46~()z^WWUNF?]_^>4, $lsX]G4>yu))h{e\VRUcU44<44";\hj\l64;;-&%/YsvdF(44:@$1DR[sI44#&+.)% /44BYVYitK44+3445DKE544116446,-2322.&OҙۢzoFORZZQN455<<56!$(($!)"X4( 3'(())(NY]afkoL(++),@)()3F^sTOTY^cc}xS++,)J_FFWropow|()|mTTFFXUY^cggkchrr(([P8gFFtKdqndYSVtpf]a()4GIIXRugLBtccb()[h:335?b|cXUVUd`Cgcc()WSSQJB:335NhYmjXPYliJcEbc()WSSQJB:335KxFrE %M<;WSc()VSSQJB:335VE61*66APg()YSSQJB:335W65~[0 966N()ZSSQJB:335H6% CP*#A;6D((~ZSSQJB:335<6 @~Y8AG6;()|YSSQJB:33586! ۭtKLN68{{()xZSSQJB;[]]?6- $lsX]H6>uq))fwaXRNQ`S33>664";\hj\l86=:-&%.Wp{|sbD(66;@$1DR[sK66#&+.)% 166CYVYitL66-4667EMF766237667.-55441&O9# 6!j? .Sx {cr#  ﲌ`/NМVKK _R9'&+,,3N<,  $\c$ network-wireless.png     '-V] ] ]B rNv 272%N]GIۦFfsU %ճ>֔E؛ 7$AB ʘfG/;ZωdWK@66@KW嶀sxƞogs絏zˠΐᲨܩ|huӜϸÉr^QQ^sȮЛ٣m鵞̈́޸22)2y)orNv 272%N]GIۦFfsU %ճ>֔E؛ 7$AB ʘfG/;ZωdWK@66@KW嶀sxƞogs絏zˠΐᲨܩ|huӜϸÉr^QQ^sȮЛ٣m鵞̈́޸22)2y)orNv 272%N]GIۦFfsU %ճ>֔E؛ 7$AB   73M,$/4773*   preferences-system.png     ',Th h ig ΢ 黐 雇£⽍¿ɑ򍸏º؈ّĖ녑جؐʚ 펓׼؊Π ̠Π𪈇ϢΤ3^Χʐ"&U.忏!'“O-踑 $vo\Wm6f鮒 #mtZC:c)Q駓 #$tuZI:U?"硓&!,{rpN:TB""囔 ";yT9RA""ݗ!'SX8OI""˷ӌ >X8FQ!мŝ FP8<[%Ѝ"ck?5V; z{#]VVT! C!/1   5g  Ϥ 鼒ȳ 霋ϭ⾏͘ʓʤ򏹑“Ĵ؊ȳڒʞ녓جّΡ 푕׼ّҦ ̦Ҩ𪈋ϧҫIWrҮʒKOyTïKQӰuU蹓JM]v鰓 ILdYTk驔 JOjYufM碕MKUmYshLD圕JMerYqgLDݙJQzvXmpKD˷ӎJgyWdvLLѼşJlyX\O@яMcVzcD z}4Mty|K C5KY\J.8:5g Π 麎 陃ݻ⼊ڥȎֳ򊶌ׅоٍЪ녏ج،ҭ 팑׼יְ ֲ̯𪂃ϯֵַȍīι徍ԩ跎Ǿ鬏 쇉ɻ饐 ꆊɺ矐茈”嘐󆇞Зݕ󈍰ܜ˷ӊᤀмśѭtЊ6| vy_ CcW.fh:5g=n F u >. 7@ \GU1P0}  6O ̉O E _ O-D8 .*bN 7 Bk gGLnQy>X]E`D  k !# ur ^H4,$!&,23E*  $ju60)"  ,_i9#   folder.png     ',Ss s s`GzwwxvGGxzoGGrpGGmzŰsoonnmkGGmslGGo¬iGGifGGfs77 676558GGeT 8GGbN 9GG_D9GG^=7GGZ8Ŗ|4GGWFĘq5GGUU d6GGRbT2GGPoj E3GGNqo~xww:3GGK_g~oop4GGI]`piiku6GG~Oiywwyq8GGD~Jxh9GG>p:[]]F0GG0<46653GGGGcG`GzwwxvGGxzoGGrpGGmzŰsoonnmkGGmslGGo¬iGGifGGfgg fgfeffiGGeviGGbujGG_nʺiGG^kѹgGGZhظdGGWrعĖeGGU}Ի NjeGGRλ~dGGPŶ rfGGNifGGKxfGGI|gGG~siGGD~sgGG>tht^GG0Veffa-GG GGcG`GzwwxvGGxzoGGrpGGmzİsoonnmkGGmslGGoiGGifGGf GGe ܧGGb קGG_ӨGG^ϧGGZʣGGWäGGU 佤GGR䵣GGP ᬦGGNݧGGKפGGIGG~̧GGD~åGG>xGG0yJGGGGcG`j$r JzeQ=( K>  %<>996@<*  b address-book-new.png     &,R{ { {ʆxdB77 69ͳ?յ Qĝ aͤyΣȫۿUtuȱsrǬT{v5rɳ򪢕JÇr6yɳIq6ɳL6ʳ^5ɳu8ȳ8dz8ؾų9׻ij9ֺó t9ֹ´ T797zjrvy ym_86i[967[[[;6[^[?$7h|kD+">|^[[ YG/#676 67667'ANjnRII HJQƱ a϶ rԺDžչĕіݵd͇~ӢfӇIȑ򇖱\ΓGȋZʡ}HȌY Hșl'GȮ.cFHȾȐ1WWJȾĠ4KgKȾ7@uKȾ;4KȾ aJɿ <IKIӊy {nJIykKHHkkkM+IkmkQ1IxyW9-Qnkkji iX>-EHHIH H4A#$OQUasyy xy;L\e|~ /=F4Mp ߈ FymBR~ ߔ2 jʜ`Ap̽ݠQ %qe?nۮaUOKx͵غp,S\J@dΰ>  %CTJSi̱ìу Afϵ¨˨d w޵Ω̨l{) wްʨĭxo= w޲ͩɨαy޻϶Ⓩ&x˪μǵ5cFy׵ݭ>WWzϱʼۼDKgzοL@uyU4z ۂy ayyx⫝ yxꞬyxxٔʔ{ExӔޖ}QuɝӞ_K~ gItxxTA V)]Z7tJM?%i;fM:ZZg rV}w ! k&~'#  DIO !!    audio-x-generic.png     (,Q ) 9UWZZ]^`WXZ^^ZkbW [Y^^Zpe\ ZǹbW Zǿe] ZIJ}eZ Zi[]^Z_eX Zt[\^[ZYU`c[ [^X`cX [^UbbU []U``Y [\I`_U [Z@`_^ [Z`^Z [Z`]` [[a\[ [[`\U U\UZYI[]\^^][[]Y]]gld[Z[\mŮZU[\|¦[U]´\\d˺]Wbʷ]U[Ǵ^XC\~a\R\||_\M;Y\\[\X?,UZZYYN- Uegfkk`fefljgxoe dfllgzsc hpf gľrd gϾqc gŽugkjflqj ggikgedUnqd hlbnnb hjjonj hjqnnd himnma hgnkk hgnki hgnj` hhmim hhmij UfUggmekikkih]djksxrhgdjzλhqhjͶhUjõikrǺjhoŴjbi²kdQioi`ilhXEfiidG0bfgffY5 )EXa /[ӿ  KmΫfk v~t_NEIOQS" Z<;?L`veO;.S! PYc`VJ:#Q P&+Q PP NN KK H$H DE @@ << 77 22 +-$-'-&(#][+?{F(+÷{[8#1hC+%prc3)$C8m\/)$ #*,*%!#(/20'  &R#Nz& 8v$ # !   [.          L B v,<c` Z4]!@e*  !#$*.25750)  5UkphXC/ "'+./.*"  &*'     network-workgroup.png     (,P) = Mm ^^^^{{^^{{^`^{t{^``^{S{^``^{SSS{^``^{SS{^`ҳ`^{{ue^ ^``^^``^^fs^{{Ƴ^`ҳ`^^{{^``^^{t{^``[^^{S{^``}o^{SSS{^`~۵`^{SS{^`|`^{{^``^^``^^fssi]^^``դ^^`׽׽׽`북^^`ضضض`c^ ^Y`ٯٯٯ`u``U``Um ^^^^{{^^{{^`^{{^``^{ڂ{^``^{{^``^{{^`ҳ`^{{ue^ ^``^^``^^fs^{{ų^`ҳ`^^{{^``^^{{^``[^^{ڂ{^``}o^{{^`~۵`^{{^`|`^{{^``^^``^^fssi]^^``դ^^`׽׽׽`북^^`ضضض`c^ ^Y`ٯٯٯ`u``W``Wm ^^^^{{^^{{^`^{{^``^{{^``^{{^``^{{^`ҳ`^{{ue^ ^``^^``^^fr^{{ų^`ҳ`^^{{^``^^{{^``[^^{{^``|n^{{^`~۵`~~^{{^`|`~~^{{^``~~^^``~~~~^^frrh\^^``~~գ~~^^`׽׽׽`부^^`ضضض`~~~~b^ ^Y`ٯٯٯ`t~~``S``Sm33   -5 -A      3          %%   (%  "- "%! &"&%p media-floppy.png     '+HJ ^ nA,%%*(%'qed%'poc%'nnba%'ml`%'kk_^%'ji]%'hh\[%'gfZY%&eeYX%&dcWV%&bbVU%&a`TS%&__SR%&^]]\[[ZZYYXWWVVUTTSSRRQP}%&\\[[YSR RTUQPOOy%&[ZZYSSOONMu%&YYXXRkRRmRNMLLr%&XWWVRRIIRÿRLLKJo%&VVUTRRIIRRKJIIj%&UTTSRRIIRRIIHGg%&SSRQRRIIRRHGFFd%&SQQPRRIIR~yRFFEDa%%dpQONReRRb}xsoREDCC\%'ayxvR{wrmkkR^]\ZX%%%R%#`A?877=9՘7:,7:Ϟ7:͜7:˙7:ȗ7:ƕ7:Ó7:7:~}79|{79zy79xw79vu79~}||{zyxxwvutts79mTR RTgsrrq79TTqppo79~}|RlRRoRonnm79}|{zRRggRÿRmlkk79{zyxRRggRRkjii79yxwvRRggRRihgg79wvutRRggRRgfee~79vtsrRRggR~yRedccz77{sqpRfRRc}xsoRcba`v7"9zR{wrmkkRxvusr777R74`Ah__gc~}|zyxvutt_a;_a_a_a_a_a_a_a_a_a_a_a_a_aԾ_aҼUR RU_aкVV_`θRoRRrR_`˶RRRÿR_`ɴRRRR_`ƲRRRR_`ŰRRRR_`¯RRR~yR__RjRRf}xsoR_>aR{wrmkkR_0__R_Y`A R +e#  /;ACC=?7*##xicon     IF&xbxd<2x icon mask Jx'3xv#!C *  &     "      "#$%&&''&%&$#"  !$%'()+,,--,*)(&%  "%'*+-.012343433210/-,  #&(+.01356899::9887531 #&),.2468:;=>?@@AA@?><;:8 !%(+/258:?BDGHJKLMNMNNMLKJHGE  #(,037;>ADFIKMOPQSTTUTTSSQPOMJ  %)-259<@DFILOQSTVXYZ[[\[[ZYXWUSQ  %).26:>BFILORUWY[]^`aa`_][YW   %)/37;?DGKNRUX[]_bcefghhgfedb_]   %*/38DKRX^dkrx &,29?FLSY_fmszſ &,39@FMSZ`gmt{  &-4:AGMTZagnu{  '.4:AGNU[ahnv|  '.4:AHNT[bhou|  &-4:AHNU[bhov|  &-3:AGMT[ahnu{ %,39@GMTZ`gmtz %,29?FLSY_flsyľ $*27>DKRX^ekqx~¼< 9 7 5 3#! 2)(%#  0/-+)&#  /641.,)&#  .<9742/+)$" -B@>:741.*&# ,HFCA>:730,($  $NLJGC@<952-)%  *TROLIFB>:62.*%!)[XUROKGC@<83.)%! (a^ZXTPMIE@<73.)$  (fca^ZVRNJEA=73-)$ 'mifc_[WSOJFA<72-(# &rolhd`\XSOJF@;72,'! &xtqnifa]XTOIE@:50*% %~zwsojfa]XSNIC>84.(" %僀|xtpkfa\WRMGB=71+& $剅}xtojea\VPKE?:4/)# $䎊~ytoie_ZTOIC=72,& #䓏}xsnhb]WRLG@;4/)# "{wrkf`ZTOJC>71,% #㞙ztojc]XQKF@:4.(""㢝}xrmf`ZTNHB<60*# "㦡{uoid]WQKE>82+% "⫦~xrkf_YSMG@:3.' !⯪{tmhb\UOHB<5.("Ⳮ|wpjc]VPIC=70*# !ⶰ~xrkd^XQKE>81*$ !⸲yrlf`YSLF?92,% !⻴{tngaZSMF@93,& !⼶{togaZTMG@:3-&  !⾷|vnha[UNG@:4.&  !⾷|uohb[UNGA:4.'  !⽷{vohb[TNGA:4-'  !⼶{tnhaZTNG@:4-'   ⻵ztnfaZTMF@93,& !⸳yslf`YRLE?93,% !⶯~xrke_WRKD>81+$ !3"=J}g!`X' #*06=CJPV]cipv}þ "(/5EJQW]diou{ #*06CJOUZ`fkrw| #)/4;AFLRX]chnsx|  &,27=CINTZ_ejnsx} #).4:@EKPU[`ekpty} &+17CHNSW\afjoswz~ %*05:?DIOSX]aejnqtx{~~{ !&+16;@FJNTX\`dhlorvxz|~~}{xv #(-27=@FJOSW[_bfjmortvxyz{||zyxwuro #)-38=AEINRUY^`dgilnpqsttuvutssqpnkj  $)/37BEILORUWY\]^``abaaba_^]\YW  %).159=@DFJLOQRUVXYZZ[ZYWWUSQ $(,/36:=@CFHKMNPQRTTUTTRPOLK #&*.157:=@CEFHJKLMNMNNMMLKJHGD !%(,/258:<>@BCDFFGGHGFFECB@> #&),.1468:;<>??AA@?>=;:8  #&)+-/2456899::;::9977532  #%(*,-/0132433433210.-+ !#%'(**+--,+)('%  !"#$&&'&%$#" "   $ &  )  ,D2OLⲭ}wpic\WPJC=70*# !⯩ztnha[UNHB;5/)"!㫦~xrle`ZSLF@:4-'  "㧢{uoic]VQKE>81+% "㣞~xrlgaZTNHC<60*# "㝙zuoid^XRLF@:4-'!"䙔|vqlf`[UOJC>72+%  䓐}xsmhb]XRLF@:4/(# #䎋}xsoid_YTNIC>82,& #剅}ytpje`[VQKE@:5/)# $僀|xsokfb\WRMGB<71+& $~{vsokfa]XSNIC>83-(" xuqmifa]XTNIE?;50*% %rolhd`\XSOJEA;61,&" &mjgb_[WSOJF@<73.(" &fca]ZVRNJEA=73-)$ 'a^[WTPLIEA<73.)%  ([XUROKGD?;83/)%! (TROLIEB>:72.)%! 'OLIFC@<951-)%! *HFCA>:730,($  +C@=;741.*&" ,<:742/+($!   641.,)&"  ./.,)&#! /)(%#  0$! 2 3 5 7 9{b((8 n 7d<2x selection~     3x.:x-0 ;79898989899999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999927M8M8M8M8MM9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M278888999999999999999999999999999999999999999999999999992O45r666888888888888888888888888888888888888888888888888881@9 @M @ @ >999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999>MMM9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M9M>999999999999999999999999999999999999999999999999999A         & (  A @ !    &   "         <       &     5<         ,   8 "  &<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<d<2xSelection Mask ^x^_1_=x_____!_%_)_-d<2barry-0.18.5/desktop/images/modem-focus.png0000644001161500056700000004130312242254476020117 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME tEXtCommentCreated with The GIMPd%n IDATx}ۯiU9uTuq+( mֶ#rQVlM 1i׎1V4J:tP(C Hbc¥TQ콾mvQS6~PZ79c q:N8tqc$8-q:N8tq:N?ޘ׽:!Oۯ uo{| ==amYI$7yp2z\i31>=:oP7|S?j\F3~~IUQ@=cגo^zN߮H?/kI#œNVJߞ_;3e7~8ϝ% *x4_#띿gzzr߷C,?Gcǟ_ӄW7Ao4./̧D/Ϳ\q$5 Pwʸ{C\\ νO0? S‚lA?C6~CRӸG86 sMV(l΍o<ko DqE1@!͛\F29=h"r fxjjU]4҃3 #g y.9m:އ -|gѫ%O7s]特)ф:fNhg qYpM`a Ƣ2={iqчm^6<^\v|*wᓢw:˽[sYt\h$$!{y (o܋nă0.8f ѳadOwbznRX;R.?SXIDؾc?cJŒ9wJ6J:5aԅ zd~/k;KF xg!|g>P.".KNY.yof%D­sׄ]ß{:IODxiT0F\Ly}'bxBiY)qvfsme7fy#7XVt ͍SNd!?Ϝ=Y .y=NMGBMnR 9a+q3n!DмxЅsuqǴ%Ml%ET ndr 果j̄1¢sOjZWrLOKfϋ qNj_)6 ٟ't…P-GҦGjqC,>n}nA"Mb.HTcⶁP}Kƌ\pexd+T<Hr7N1 3)@ɗ٩OY.7R-7`f43pkx0ZˁHT0ԐSU]KJXcQ)M$=2jpnl=?swxe:oݼ1;f"[~M a]`)iB cBܯ冚a/I:|V 1|j)-|//IgtKL#)m~=f@(>3U;#5TKKC !D]uDGI6HEQѤRȣRP: 7~/:=#6տ5:&7345>O`hm\(3| 'r ;[)C f;A[ }QyP@f0QVЍC7{Wa">>m7c-2jkQv/b.0ܡv"XC+bT6+b`TDʹCΏ( VVҸ收W]-bW bti9 Jpƪy] T}aC}̋L>dw2|cSR~#j&i"of̶эfFf,44|TSDH $J)󢲑<X5cQ9/(lU&e.Qح瘪PڂvvmDJȖO{չ͌fq!9d|3?mYHפb8"@\(Fe|q|]lzq>dz<_hKqZ`y 4Rh՜H f5`&ryT㑏Z L"H5 Q2J4b*GHFc x~,EKKanKwk朏!jzx s wEAu\zx.1xk_#dWjT2m.8+LC:̰m)%%@ P][V[ 6)F;lmH3ɍ0^4-?oؘ l%Lg@dPԇ E(ETRȭHXΏfбFñ;K8B@L3c000E"C!l5,EcD-emsYccG;j>NRpI &yYՀxFX `FhcE U$i[vq8BvNHPuюR"PercQٌ x~T9 LHT$wO8(` [ C $*51\9Z*=P%ωJe05>9 ]7\ BrcĹ04`Ѯlz 6:nkm>ZL`g]Yd5ѷ0 ,PP$Rp4F P Y+杩O9X$ z -x`|9W8 n$z.]jmηElmVzR1SM ӴP4i^j2#Ja2սݱٶmT֪7`U/23f `oМ taKDKˊ X$E`ǂ"Gi(g(9eb\G {ݬƒ#^C{`(tZrJ'RW2c9_l6Tռ$) ܜXLvemƊXmzkaF͌f@kpqVb!_VOdb!@*FPHI$JuIgB }*=54n_I3CԎܙtZ[::b~btBsy!e;G/(kk&Hm2V Ы3sSa O t9V4iz`WZ~q0maFbfG!46Ifho|bxSee3@VWaMR{ &jXbKE<6KEjKQB]~۹qȹ|yn(Tb1m3ϵҤ<{ȴUȐ̰CFera((Ig__KTB]'蓺6 aerǨ h'{ ijX5@Rk2V",G,(T]웄;hQ*=B30g3ՄSZuA0jL>]N7 gEΓ#^# ℴa+>b&0 7W'4='|TfB RRTT}Ec {TyIj4KWhE$WKXA0 z}ٱ|{+ ;ܠe 6~M\>L^),)\[X=7kS!J#%5J2\4ۙ]01bB%Liɕ !ۣXlĖsU#07V㨨[59hFuCvZ~컙R[ý(")jnCX{PĠVO %Ɉb~N/TW-9hȟ +q-3l0 #cx9NY9p {6r4b}83\-!ߌfmrPm+!UtGiFጥ?"6?t"%,:Iԥ]T>@iiBD=#(4Vp'"xJ$yHb:檡Tx&\x~b(4p^#@L#P8&vu9AWoCa;hF:kэg[34n3j$3CdYSŪdV$lri7,HV-Q MAE^alص3TwYCv˓3ذ槫T×M1[BQOi9찡Vcܬy b`MͰm ޵طh$PhȬ ,r?iJUQ jܣJZ7z X]X#tw^Fqibղc}m55)Y-=&7eMGCU^HZ!eN9.Qꘕhm w $$m M yg.pCdc| ]rQ\zrFn$\V47!FndZsq;&84[SGd(:Q.,jJak#bڇ+I,ᐛ)RI1!s~a);7j=)fnB. }y=N#JE^L쉕ra*QŽ /UdnQ쬢[CKihVЬJ5fn]`+Wi֌{6C-dKٯ2QZTTeaLV!PY HZTxxUTnQ )At[H-ʳr$ӡ.ʵfmefqqWk7٦N*ԓu K <8/( t0-bgry ni#ZxՑ+pG C-Ds%K.,F-F; [sE PHYiCbLƂU`jəDk"P 5x6,z~ 1*DQ\&8 ڵ0밓c5L(bZ/F3HXS#͵ͺ^ڌ>z K0OuTȚvNyj0M `ёyVx6sQkܥ48yb4//zQФCD=tーۣ$/)Lg FUYi-"K dQȀ:  !h"kr0| ,Nf}ـQ+Вj#tvl_$=wN'3y"YtG1dlQC_}F00}/_p *SOx-_ ?#}_M{ xzz^r_Z3W3谁ANJ06-vfj}xƨjb#UF!(cJXƇ%.0%.֞9pH!E-7E CJ$s 8.ڇ(eGNLT+I!WeczJ{ n.t~:pΡ;fԪˣFIs[3gnt.jty lezy[p)>0Mׁn!Z1B ^ 赯zrh%txL j)'\uV$&1:Kyʷ䔪8k!GYOB;٧s,v uQ&;)gTNa= y/ڀyFj CڢnU=yWkٹryj5+Wr f(>8~=@' ҵkkזmKX3?ߐ+q0[^6 5jFԼ5^8ZFқd Nv{1yu4T_عyO\9L߸s8(;3aZ,F2oUDW٪ΘP=$x뭰^y~{oBy!'Qz79ρ]6po\q,y&'28yw pmC}2B٘UP"[]ƽ!-c2֔[}U2' ɷug܍޸& H) sĸhD38-5ܕNM.f]mMO ?:_'w >xy\nFiB- ;g֥ﰝ '~,aX\ XL-T^AP C2e gZІ`gN#y$X;Wwίàtgsz}7 n )"9#Er!م6;-^~c/nf.H}xQo"K{hꛀ~Y&ň%zҾz 3]-ᑆ$ f!,xE1Q70à1fd'os!p*O9v}, -!o`.\_g;0z!K ! !GO5f N%Xtk$rsbcL4"aWfx'w {/^=8+_BYyt!|ǜ.}@s%~gyD ]:%¦u!<\裹H{؂(! R(r܆Sv C6p6Cuk|猾^gݐ .dȑ/-ĚQwe0B ؘd}1j߻nU}A-ʃb9mZ H3 (U7" ܅ҔN !τTYg(NTػ1`qbH5Cu8=+=^͢f&0B&6 Re*j#@e܎gb,__ ox>O'o {?שiu,ACERm̎ui6xמLm>I39v{r $3G/lqr$.npNO `7WpC>/3I ޟ@SơZ;=tqQ4%!Z"𶷽 o˿Mo[g3<*[E*9#üJư", /KHDjvDzb{$dzK+;5Mp͚Wٺ71Pjf|/|uɥUX͒%AԽHG'}f4Yx{(hgjggxw[7_ =GznĜ P]wSZmC !&]kRR8֩N;CLiIXGw~u?zs6u866:.p(,DKkoWYcVʷbgggx[ނ__ߏ~>(>O{V,P._Z%-`A7Ȋ DxgEH$2M[MkQи1?]M,1MȱӜ/@%\Qh L[Va^ (=:7h*J^hceׄ`ltQ(T@־8^rʶm/QAO=Ľދ7񍐄ooo;~W~p~~+W&Bwh|׽^ U ]8*U8TZHDF!|2@nN\:oE1lNQ5Sg30T ^t"EgCx#;Oi,?!Maǎ$mXjaWQBǨb\'nn]w'+_J{'wd6G< V4WU]~8zj r >[n_8=YQu4dJ'z)Cսe"ᔖ>qjg2 7CnIN]0%ImmM_;!7";!ސJLkczJ(Hė5+d1F Jypw9T%}>̮ڷvoww|ןsϗ=λm[s*XZ?] oJ j=}k& %@߈i~Q F iUW So9=Ōr09ZMyv97%[{4eW~HkCunFA0ξ$AlT%ب}0/c(իW׾Gҳ*=mS8p؎0ԍya,_ VRw[hZB@iZCRoTM݇'O(\|R))ݶ-1y~] u` oøtu)!nfl !9lUe"='|mǿrOm& ZQhv'm:uE*Šʕʭv}Dˉ.?d6B)fa@*KOzOCf5mp 2Qwi!!˳"^s?C lfIVXi#vB:qɩ8_{ڼ3b0MX,m[*qsBu1i3/k __;TݐQH92 jNn5Em+Wr~w]v 1qނm"JzRFXW%w0{QzSS)BZ 6v`,c~nr-'\ʔ8 ྖK;h`-nv6v9Q<\73_3Lb p_.)IwI0u&5w͸}KDQjpy[ i.w @&]>4wUiC4 Cm:tyŪQξ-g>%Ϝ(4IGΟlN},Ff8-Dy6P/W¤ `2J̼cb!S-Ø˭ rt5]-2HZ^P| @zKkQ HžйCxnqmeljs\CIid2_(X"ԿlECȟXp& F= YY~(K'rϡ6 sXP;|R" Cm۝ޥ%x`_qU|BlFଷJͭju=#'+]t9+<^vF.:BսJ[;3zk-Dl:r B5+1=qYˆn}f묥/_zgӼ6CQaZmCTT"0yWN1f`$/WɁYѓ&+4D2Z: GH6F(360K B5>pKd$*(QjT2ɘ>o7LQ&cXswqkp*Gߠ1yQhabܟ)jx-|.G`qQGWq(yOE4\FU ! I%vDռ u.>[ר5ؚ`gyp@aۍ4@[oktTu#?;mrA HjP,zX3ΟlϘx=$qr*72c ?;%lR8D.gvLOqoK'BdKhR1I+4F'S;eIüKg3GF$wqV}Ys3hFa`|dǸ#*3"YsPCoqdŨG9/6{nK_fS?C#LluDeud0snȇAHͭAmhz#[7P, #"j% ^_H7$eO0Ddi=dLu\ʄ}[3ˇ1>2¤&]g|;X4BC%;2#.r?(.V}226S<\zGm͸8 WG>PgGM%H԰M-m++?,MXU3- 3φP_=n4Pl:B`Sۨ!F O0D/QfR*B. [;<2D"8: "m<~洱d.>ú']z5?9SQU# J$'J2KG50_jJ}[_ z>2U"\ѳPK&w9͝U^rT>O'꺳̽yjAG百m8\>#yͮ=<}0UH<]]:\u7>~@ڱFg`'P@]{Zv&*XI**7>#+eLJUo]ܭSyʲ7Qg9Ia#B+|CMy>CwP調u:tn&}XB5P䀋UU& z!90QQCu^S}4:ϑ8RV, a#x ҅nd yiD*tDyp9Wp:W^=B?zGt ?&7qXY/\1t.tm;MҬ *G֒ m$~PM:ݯ) *U89+Ck{?G(sH=ڑqmGU*o84<3sivuiwb_}؁ 7"BZHvt ].^Y1 HS(u;Rh|ʾwĊQ} '`'[Wka3F{!"0MqFz3'Gu{=QLà͌0DsAiBNP\LBkɱeY;/k5Zp:(Lׯx䱥Y{XXq }^ZWg*u+yV(lseã;^j{ ]ZfL[[mQ qeߓDUek=tWEP'#K\#পՊp\ث[;E JIjȨM= ~^'vЃ6} u9ЯMCeCCwʽBh8LA|9+4hvvh%W=Z6qRkEy4'z z sT${d\jrctv``9ZҞ$J̧ZTASs>v!̗P}e͝5{끟q 弜RP.1tKF%]L敾$q7~9w׎-՝!6ݾZK?7a∾SRgsʐa0S+Ush'MikJ&!!}|x=cr\H!cQ$l*b"n5%=Irsr$b,]it]0_ M y}hmCnFjkq0-wI #ju2PG,Va1{6duPru ?V{( Gn2ԑz6ɾmdEk.Cj{yB<ܚӸPоpۥ#<v8(Ǫ @+݇Bc`INw¼lvLʄ(ajf3Rƪ`6O=L-@CZgs 2y-Vѽdhy6"TuGQ؁}%A C?v&Ľ v!iPJMqr&B{g/dE\.Whh9t 2jw2'p]; #ҽ)xbvh;B@zN0MLyLf4,Vݘ!Xqf ߐeaUPCT) a#p.9v*/h"%4SdxqM>5B.WXyh */^RIDATƅ1="Wchg8W4%)F%ט kCYIy~sJC -+A(3 (&^w&UJQb{i^o0Z-e|%fg^Zph˜0~niܹ֕tm8/]Qh11Lu |9}\؆iv*G.Ptp#HU3MG送.}y-8 +[t:ܬ<tOwq t?Ow~q:N8t\|H45qZ'<tq:N8t!N9BNIENDB`barry-0.18.5/desktop/images/misc-pushed.png0000644001161500056700000003575512242254476020140 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME:7X{mtEXtCommentCreated with The GIMPd%n IDATx}Y̥WSkTv<jiN)J"E<%Q)CjEBD O`c3c1Ox(r\*?ݝsj/qUδ^{5_k~ͯ5_k~ͯ5_k~ͯen _o {?ٳ O/,ίصӽ) _c~Ea}l6Ȯ8ίl7_¯+n W|/>2NMy^4?w1 cgǀ?k7˽=Kz|>L~Rǧ;CLl@׵$>܇.Ϸn:^r y2|v뼙=>@y(< |8 _}."F-@½&Ϡc0wDE-bpcauÉ ami˧lt0fácl}L‡xso7#֮Yz(L|M#Zם\,6ea<@cN- y]N@LŝODvۺ^xhY㳫(OjVεމi֞7Ix ֛J%֬l6тRs*:ba,rTR6 Z ShL+W߂[iDl&>g<|0Cݕ6Pcә_C2,<OscIts6)ٶax+B6>0ٛ.{Ɯ&58`A6Je`˄;BI-{:)F)k^;En\dM~O?k+_p'Ce%X{8L%!^7Uؘ7_M lx2ƛ|02C!p+,յEsF@JVG7_m8i8A)޺)ctIZY4oLz 3-ĭZmC8 FV}h'㙢2Ys2AYLEy`_3o\r(Y6 yXjd`q>1urg_]!hrJ[8Vl,.u2b= ի<6=qnw ,SR]/P7/v3bz5/b߉;yje,]yL8z([{,D5K'+dF+L{ÓL2 d I1t.OCV[s%Y1֌1fܑ{[3zUPqbIt-JȇτsT ˠlc ΉvrNT0S ٠XH,` f7S\G.PQ8sj.S^I@IO~F&IJl;aVFwr 9Hb eVYZ4bF9M@T9BsQK9.Czr)"MƖ׃{ K8-,eoEye W  C|-ZFڈt5j,1l᪅ &*U-)<7)@bΪ]\,Rfe[8WSƕxm" Dp S@͈["1#'?3b"΅)}fڅE3r"eEɕ!7-Z.\BO)R'L V$c6+.ֈ*dO5cInp9rn_(u1UmNG 8|ɵw$F\ʅs9ĝ49zU!k-aenEMIe j$6(b\> kVu:  "R';M(ѝ((6:L43o|zU\R4oS 5$U± X\iqKTA-3KMMB:`T1}رfɰaL+AP@.,eR3}˜aޔin [ sc)rz60X4h5qr9pkMr7BV~s`Zg+DRUkh$0fMBsEfnm@)!/׃)Q8C" d{8tdOdFv e]LkSBC#7CDe4Px{ ;)mU9MЪ@XӒpߕ&n@ܚ!VX0"ݚɏۈ t=e̢*!߆5a쎰ƸfՉ]M@KfU&jN劺(5!J\C / Fs(BEE$T1j]&4J8*1O$׎է70cK{/C-VJ!-DNcRj"T[$E?ݒ5%Jr.'Yʐ9jN#Z:v J-pL$NtNCƪqG ǭ'*?ЙKYfQw7AZ4٤Fd 'w,,-[>cWqӯ! ũWŻo\z18y|x&CjEcI46\8YEF Ǐ;jW-3Y;|WFfk|^ T,[;Ŵ2GuiLoC8^i"aCUMҙ ),,| X"exKVeȑ xLzh4Na076 o;v ǏǕz, xEZ +քIz$q"1@n5f" Q*!y3C Qk>}f4󈰄Ů.Yu) 9K$!"4BMXv.9\q%s.=|#76C/-N"xk/>M\A&=78C[߇"z:2eડZY$H;)TqczwT48լ~'DMS"$j1 ]; Bt¼G͏\@?`b'cnf=í7߆ک7p c,..ޅ'\xk ?MB޽>$ֶ ^7^{RRqgm9.sNȖz͆8NU!ԪT79%q5 C26d JMk,UeYA7=pv0UO Mq <1߈~/η߄%lmm!Tdv܉GG^}ø"^y\w`ݻSXu_@bBUCi*Qe$TE46E#RR(.O*K*OjݍYEzxf1Ԃ)ox^R"9% 9fkiH 2WrSS"eh4W㼫ލ|8v5ܹ۷oǶm0p|{x+9j>E!D^a3ߟݛ|J \##GuXɁЩ:lfH:CĜh>W8xl|@ #e((ǽ>@U$7**PfJV 줫6*7"N)[~%F}ewN8W5b޽%_7\w-.w>~SX_؉K}gHx3 (T8,I*4Sx߭km/\;uF^up X_[3y iqA;H%@90~b"g*~ ts0a6ڋJ{llv*9q\I2}J*>YE\TO?>߿v;9D8IDAT?X/K/w}}5 [qx/mLW6!͐*:,J:MU>J|c1Tk3,uA乸p)cim c-R߭1Ո[5V%Ӧߜ* s̎+55jn956 O|woFxS?o(Ahg1U{1?|෰m>o8K_g;}7o.},'p~xѯ?.N{ʔJwwqp?2u=P'qiIL)jBbQ_Jr7->9X >Lr&ØirV7Q(6DaBIMuLYNI1ڂ<#艗5|܁qac} (.Rvb5||f=.Ǖ܅/>p`fzzfH~B#yQ08@/0zV0 'Rfz?dx z(Y&4a\Bqz=QP.`Nu%ZDoFbz T3 J*5hWVd3W x_?5|߇1 [ O?WE]c'?Ď+pEW[ƒݏSNaaal߻X=,?S(P%atMʂҍ&(R0*3OSKxu,A JP'ZTK `ÁK߃Ed(Ԣ& ͵(juz{ <ԋK ;o;p%{/|/z.8pNb _z%]<|KKX]]ő#G=/K+ mvk t ˂ڇd؝zڭV3d$kM^|Rsܞ15-)&9]3|i9gz&X:Vk/ gB$&fT'/b]뷯?? <kNmg^¿㿇ۖEO֨xqqaڵ {cwS`GښnZҊY0f`ӮɥJ-UN]۹k#CQ~iY{oc愍 BVms >lXyS<[[ L찴n;-b<*'3Obaq\6<38g[1|k ;ۏ׽_WpݻwcqiǏ;[Lu.dVCԵCU-C׾\uXHc A:|->{BB)&,UV,%+ w^D8- uȣfmMedp{?>2򝧰m~[/ :w\u!.iX= eXܱxoaqǹ8~۷méSoox8I,,,baq6i;pS{3e%$WXWW!ij[R4!y$mX+ ,g=I(J4ԍ1qD#'Jcyg#I9RxF9kM&ZL+Kf Iƛsݷ\}{w^qZ˯<{;cX^Z2WQ!-0oaccZƣ¶|,-oƄ(hR*"̱ߺQ,}+a5OSC 슐;j&:ܭan,,xE37Ӑ0Elc} 2Uh/gg`-ᔾ!FyPuh3+/߿Şi G_}J:g,F #KKXZZFZacm-fŅ%,./cqq)j7[dѸ&JwN4fMeV*Tk{}W%!+V%Wkv%\hǥXģS蒳5a,ȕ0[Ce㳪cln,ceekN[^? x7v\AJ#mXX\9+wc1x"8VAցrD d`Gn\P^GC!A ؂IETN\ ڤ\@IPO-rSX+#f bys;=(eQȉ[kBK-/cyy Bo(M-ɧB1%-nv 5v'YsEiaYM)?ހͲMr\c݋WH g =Mr^UZQ⋲1-NX`SUGk5Qy5jșEӺe٤Eb~(as5S[l FUG$3i}odw*0f\~ɵӖyh[ǝ)rE9GXD<cgYWK}lkz'(ndnP,aDҶO#PWi&||;ݻuѕ4Y~2 ZQI%MW+Ri(fx]L.[Xkŵ%_mРe(ȩ2YAEy'q9BPIMxqFCV!-uauXrJFMhDW͚Ӥ)CԶPz>?C ݂Z`HKU-;,R>COۀŇlU)=&L3N@&8Jqǰ,sKpafE\\Pt{TH`27Kɤg('^&V|$f f J'S"w"BA$Eϳ(bڨ>J@٥Xv=,A4k E u𜌈Acx,1Eo&usnO.ܥv_[>3 ]M.@@Ӥ5jx5ڜXU$͝r?Œ-@l*1$Ȃh7*8Y0bLKH4̍\UQv48]Mp$ J"c0v%2[+K˂)ڜ7I:UGT7͂ ԀOxI$kse2ō`tA7sgw֡HC+q̘zLHM{i^2Jz6D niM}'I_$99 ]N5pǶncg9@nN0g3~}KY)sv(qzE:9xiʭ\ҠE_W{:tԽd=Ѧ]L|yٍaw+WNJzE2a  =ʀgԔ5f52}**djN:5ܒA^P߳Gi>n,)DVIuE͒7ڑV5E2aw|<Gwy5 {C)^0jG:mh>9h$2uLd8Avm5ݨmln/ VK^ž[{h(++jbˆkADjQIKiT1 ;1Haz)vЖSHߨ@[:ީLtEi9ՓYr9NdU49UjkU@ѬQL%0 ^vXt@l*?[Л—JL& 7V#b5Pgɜ:(uC~:UY༩T+@͘b_Aky`:z=+1vHE|Eq=?EZw;Խ ^&PPG>=[ΡnfB鑗ka.n!ʇƀ0U4Xn)r1Bi!b:zVQ3ԡ{Y؎3v6!$U.f6T ^YV]7k EjStզ%\cUROq׺mK6_d17#Shp|ֵ'(놚W4^XսuϥȊs@K")0xF?RX٫nEMuumڹȸ*ڹgCڤfI3y{`z!EoE@$҅W7/EɅy79(y3Nu.)LM>Z=}Z'W:JӺnmèqZ?6#7#9!wh@*q٤V+:RAZ Q"op5AFEIw6[*ItҌ(v&w]-Y1TۛyCz`QiЦ),ˉ˸j`HO/:G.2IT]%$B0HIEvj쏇@8rb9ĵCb I,Elc+z ȶGj+4SW%1М`/jI@xcll5 ! oN ()< *3 ]q'A:bJzt1c` UIcd9jg6vrJ9Ż|E,lKCRoOlRQρZH*cc) QhO!YհE__*f{R%*yHRo+4pt&ةH*/ ʵkgiLRlX!rޠΧbgva2zC4t@=&g fڣЂxPG.dpbZ׼v0Q0hr5DFwPKdE -" `7nZhR"K1nDa/k']9khq'AqIr(kCX5s.YC_JU)dwBaڿC鬙uB"$ZgMPZG$P7[I%^wd 6!p {y$'yϫ˖Չk\@`!u|?aVBr aYי Me 8TAI.(!t%GT&@ͻg#UMv)xG-!5rM\eCAg^ ~|ݿ$bi(1XV]lNFAQN88m\ANzcA+`|W.+Ix ;Wu6= S2btJ+\ѺAr(iuukUbMz˕hA\P'_-pRaUv/NG= ,HA-M@I~(ŋL)˪FkL Xw-hIC291gY$e)&y>dz1ߺ<BXn!`]CQޡhPRIa1¢= B8E] OcoZi\M_jSL\$*gEgtX++Y$;9 dd7kE>5[ZZRSŞs">)LM:Zft~bH/_۠1ʥ*\F)/KB8-䅬ѣW2Lz62©]{b 2_k^+ZRN d=M{йKrquA ," }e>n 'Km4hW:bdeXM^iVfkAjMz]YBm%𮮍7p.: ձ0^ {{L!"nKR/Ue"sO5͢ ̈Vn^&k 2Zm4@J=:\z Y%r(ft9 4m5I'ozb487UE5V 9!(+.2Χvh3Io:lA%Pd[\Nl6惙}PWbՓ߫.XC{=&3ryO8C&UH JlA.Yȍ^l-u+mJs0QBGN]7먜>IL1ըz} ]9ik6v Ӹ)LsJܚ2uly`R֠Z_NUw8C[SEhg'<L6w=ӤCBndd{5ՍItMLAę=d<Zא; i>\ˁ3tuK* mges˿a9"̝5|Ҩ6"ms7d5ՅFk/RKrlv=P{*)(Z볥@sQ>N!>O#;ˬH]XAHS;Jj,& JNM5C /L'UMdkTq>ᓟM|: :Vv| |[ooCw9BhXk~ͯ5_k~ͯ5_k~ͯ5_sMhIENDB`barry-0.18.5/desktop/images/scanning.xcf0000644001161500056700000022402312242254476017477 0ustar cdfreycdfreygimp xcf fileCCK gimp-commentCreated with The GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches)  XLogo     _{ @ L *   ( 8  6!6 $# 1lapM6.0풖H4SOBC,퉓I|XEg}l,{8AuO5YN0Z/lV,8iPv8{+>TS>7*;8NusG\*SANox`~`+g5xR@s%utH(n1su+5NEUFL6MMko^'R*5sTe@Wx_)@zTmu@KvZ*I~2ik=Cdq=(bE"5,*3M\`~Eid7`.~zaU ^=F@;GA#.M9]E8,7?<A@5%@@:<#n*:;@=D:!AA/3;:9)86)<+&9737#6122.12+!+  >!1H@02IA0*#n=/[=?"\=+:@@=?$;$)4>@45@=#=@.2A?8== 2$*":6,-=?:+0*,!'+5-+);Y38'i- 672 1---++,,+*+-앏JcnNCX+lEuA_ev5-;9sUc{4>+fV?.A8@Q7[`Ayn.Y@guGvH.gk=m|=vVh@SA1aBhMpEfh1Vg\XBDt31Oz+JD@94BF?\gY[6Y|78#F 4   G   ,    -  .(  *.  $ .   1 81N 1# 4/ 6 8  Y:*0n==#G@7D+'@B=@@39@@==:(+2-1=9$+B<4:&.W@#"%):D-KD9.L?B&F@ S9,=?22'.(9-/5C?2$,)1&9)!16V)-J81J<w*5%@811#0;TC646)(+&&F56L@%59%8" ,.///2 2 2 579 @@@@@@@@@@@@''''dB2! Background       '( W4]81Sw !$'vwxwxxyzz{z{|}}~~}~xtvvwwvwwxzzyz{|{||vwxyzz{|}}~}}~xuvvwvwvwxxyzzyz{zz{{|{||}|}||}wwxxyyzy{{|}~~}~~ytvwvvwwxxyyzyyzz{|{}|}~~}~}wwxxyyz{{|{|}~~}~~zuuwwvwxxyzyzz{z{{||}~}}~}}~~}~}}xxyzyyz{{|}}~|vvwwxxyzzyz{{|{||}~}~}}~~~~xyz{{||}}~~|vwwxyzyzz{{|}~}~}~~~yzyyz{||}}~}~wwvwxyyz{|}}~}}~݁zyyz{{||}~~}wvwwxxyyzyzz{{|}}~}~~}~yzz{{|}~~}}~xwwxxyzyzyz{{||}}~}~}}~z{|}~}}~~ywwxxyzyyz{||}~}}~{|}~}}~|wxxyyzyzz{||}~}~~{||~}~~xxyzyzz{||}}~~}~~|}~xxyyz{|}~}~|}~{xyyzzyz{||}~~}~~}~xzzyyz{||}~}~~}~yyzz{||}}~~腆~}zyzyzz{{|}~~}~yzyzz{{|}}~}~~yzyz{{||}}~|yyz{{|}~}~~񀁀炃yyz{{|}|}~~񀁀{yz{||}}~yz{{|}}~}~z{|}}~~抁yz{|}~}}~􁂂yz{||}}~셆}{{||~~{|}~}~z||}}~z{|}}~끂~||}}~||}}~~摐||}~}||}~}~兂{}~}~~~}}~ω}}~}~}~~򉊋󓋊|}}򀁁}~~񉊋}~􄅅}~~󅆆􎏏}~⃄锕oc^[\^cjv~yogca[\\[Z_gt~𒓒hddffe]\\]^]^]\鏐xhceffega\\]]^_^^_^쎍dcefeege\]^^_`فmbdeefa\^_^^__``_`__􀁀􌍎~adedfefgfgg]^^_``_``a`󂃄rbddefefggha^^_`__`a`aajcceefghhig^``_`aabcbcaca닊hbcdeefghihc``_`aabccbcbc脃gdceefgfghjji`__a`abcbcbcbccdbgbddeeffgghijje_`aabbcbcbcdccdd烂kccdeeffghhiijj``abbcde␑rabdeefefghhjjig`aabccbcddefeefeffezbbddefefghiikeabbcbbdeeffgeffdccdfeffghjjijkcabccdefeeffgfgg􆇇fbbceefghiijkjbccdeefgfghhghhghꈉybbcdeefgghiijklfbcbcdeffegghi샄ebccdeegfhhijjkkmbcbcedfefggiihjijijijraccdfegghijijkljbbcddeefgghijjkj􎏐`ccdeeghiijikkmhbcdefegfhiijijikklkmmkpaccdefefhhiijllfcdeegijkmllm𗙘𕖖 옗󘓔昗򚙘񚛕򔕖ꜛ뙚񠚙񜗖𠡡똗桠񡢣🞞ܤ߅碡󢔌χ醇ᡢ򈉊қ쟞􊋊⠡򜛜˞𠟠犋𠟡     55$#%!!         󰱰            񳲲곲 򳲳ﲳ𱲱䱲񲱲󱲱󭰰|}||{|{|{{zzyzyyzyyxwvwvuutsttsrrqqpponnmlmm}}|}|}}||{z{{zzyxwvutsttsrqqppopoonmll~~}~~}}~}~}}||{zyzzyxxwvwwvvuttsttssrqqpponnml}}~}~}~~}}|{zyzzyyxxwvwvvutssttrrqqpooponnm~~~}~}|{|{z{zzyzyyxwwvwvvuuttsrrqpoopon~~}~}}~~}|{z{zyzyyxwvvwvuutsttsrrqqpopon~~}~}~~}}||{zyyzyyxxwvutsrqppopo~}~}~~}}||{{zzyyzyyxxwvwwvvttsttsrqqop~}~}}|{|{{zyzzyyxxwvwvvuttsqp~}~~}}|{zyzyxxwwvwwvuuttstssqq~}|{zyzzyxxwwvuustssrrq~}~}||{zyzyxwwvvustsrrq~}}~~}}||{zzyyxwvuutstsrq~~}~}||{zzyxxwvvwvuutstsr ~}{zyzyyxwvwvuuts~}|{{|}~~|{zzyzyxxwwvvuutst 󅄅|yxwvvuttstvxz{{zyzxxwwut}{zyyxwvuvttssrstvyzzyxxwvwvuuts}{{zyzyyzxyxxwwvuttsstssrrppquyyxxwwvut~}|}|{{zyzyyxxwvvwwuutrqqpoprtyxwwvvuu}}~~}|{zyyzzxyxwvvwwvuttssrpopnotwxwwvu􋇁~~}~}~~}}|{zyxwwvtutssrqqoponnrwwv~}~}}||{zyyzyyxxwwvuuttstssrrqpoponmmsvv􊄁~}~~}|{zyxwvutsttrrqppoonnlnt~}~}}||{zyzyyxxwwvwvvutstssrrpponnmml~}~}}|{{zyzzyyxxvwwvvttssrrqqpponmml~~|}{{zxwvwvuutstsrrqqooml~~}~}}||{{zyxywwvwvuutstssrqppoonnl􃂃~}}~~}}|{zzyzyxxwwvuttsrqqpoom~~}~}||{zzyxwvvtustssqqpoon~}|{zyzyxxvvwvuutssrqpoppn~~}~~}}{{zzyxxwwvwvuttsqpopn~}~~}||{zzyxwvwvuuttssqqpoo򀁁~}~}||{{zyxxwwvuttstsrrppo~}|{{yywvwvutstsrrppo򆇆~|{zyyxvwvuttsrrqqo݁~}~}}|{{zyzyxxwwvvuttsrqqpӆ~~}~}}||{yyzyxwvwvutstsqqp灀~}~|}{zzyyxxwvwuvttrq񄃃}}|{zzyxxvwvvttssrq򊉊焃}}~}||{zyzyxvvtustrsq~}~}|{{zyyxxwwvutstssq}}~}||zyzzxxvvuttssq󄃄}}|{zzyxxvwvvttrlꋊ~~}|z{yzxxvvutstr]_q󃄃~}}{zxwwvvutstr__b󋊊}}~||{zyzywwvutstr`_`__}򊋋~}}|{{zyzyxwvwuuss`a``^~}~~||zyzyxwwvvutss`a`_`_^~}~||{zzyxxvwvuttsbbaab`ac}}|{{yzxxvvtstbcbaba`_m}~}|{zzyxwvvuttbcbccab`_󋊈}~||{yzyywvvtssccbcba`n~}}{zyywvtseddcbbc󇈇~}~}|{yyxwvttedcbbc_~}||zzyywwvutteefeecdbc`w~~}|{{zyywvwvutsffeddbcan튋}}||{zyywwvuushgffeccbmꊋ}~|{zyzywvwvutsihgfefeccbo釆}~||zyzywwvuusjiiggeedcay~~}|zyzyxvwvttjijhgfedc`}||{|~~~|zyxwvvtsmkkihffdbh~}}~||{{yy}}~||zyzyxwwvtusllkjiffcbw~~}~}||{zzy{}}||{zyywwvvtt󒓒萑󕖖𘙙钑󚙙 𔕔𔕕򑒒򟝚򔕔􏐏 󒑑圚򖗖񗖖񛚛𒓒񖕖񕖖쐑𗖗󟞞򗖗㓔𔕔曚󚙚󔕕蘙򇈇󑉉񓒒󇏡癘딕튈혗ꊋ򜚛򔕕랟镔瞝ꔕ#򯮮! 殯 󰱱筮뭮!  򰱱      򯰮  ﱲ ﯰ      򱲱      ﭬ  lkjjihggffeedccbaa`_``_^d􈇈mkkjjigfefeddccbaa`_`__\vlmklkjijiihgffefeddccba`__`_^\llkjijjhhfgefeeddccba`_``^]snmlmlljjijihhffeecbaa_`__a놅nmmlkjjihggeffdccbccaa`__^]u򅄋nmlmmkkjiihggffeeddbba`_`^\Їoonmlmmkkjijiihhfefddccbcbaa__^vponnmllmljjijiiggfecbcba``_`_eponmlljkjijhhggfefddcbcaa``_`]qopponnmlmkjjijhhggeefedcbcba`_`^dڇppoponmmlmlkkijhhgffeecba_^󉈇qppnmkjigffedca``_`_qrqpoponnmlmkljkijihgfefeddcbba``_bꈇrrqpponmmlmlkkjijiiggffedcbbcb`_`\ssrqpoponmmlkkijihhffecbcb``__fssqopoonlmlkjjihhfefeddbcbba``]tsrrpoponmmlkjijihggfefeccbcb``__w酄stsrrpqopoommkjiihgfgfefecbcbaa``jچtssrrqqopoonmlmlkjjihhggfeedccaa`_`膅utstsrqppoonnlmlljijhhgfeffddccba``^~uttrqpoonnmlmlkkjiihhffefddccba`__gvuusstrqqpoonlmmlkjiihgfeedcbcba`_^wutstsrrqpoponmllmkkjjiihfefeedcbcb`__~pvuussrrqoponmllkjjijhhfeedcbcba`_rlmtvtssrrpoppnmmllkjjihgffeddbcba``i뇆llkrutstsqqopoomllkkjijihggeedcbcba`a僋mlkknuttsrqpoponmmllkkiigfecca]lljlsttrrpopnnmlmlkiihgfeecba^uЂmlmlkjkttrrqqpoonnlmlljjiighfefedbcbba`e댋nmllkjjstsrqpoomlmlkkjjighgeffddbcba`^nmlmllkiktssqpponmmlkkiihhffefedbb`^ommkijsrrppopnnmmllkjiihgeffedcbb`_|onmlmkkjjilsqpponnlmkkjjihgfeedccbb``sponmlljimrrqopoommllkjijihgeedcbb`amoomljijhnqqoponmmlkjiijhgfefedbcaa_h膅opommlmkjijihqqpoomnlmljijjhhffecdbcaac⊉opommlmlkjijhirpoonlmlkjijihgffddca_pponmmlljigmrpoonmmlmkkijhhgfeeddbba]poonmlmlljjiighpqoonmmlmljijhhggeeddbcba^qopnnmllkljijhghqppnnmlmlkjjhhgefddbccb_xqpoonmllkijhhfnpoonmlmlkjiihhgffddcbcb`qppopommlkijhhgipoonlmllkjiihgeedcbcb`kȄqpoponmmlkjijiiheoppomlmlljjiihffeeccbcb`f􇅅qpoonnlmlkijiiggfppoolljijighfefecca`rpponmlmmkijiihgfmoonmlljijhgfefeccba_Ňsqqopnnmlmljijihgfiponnmlljjijhggffedccba_ۄsqqoonnmlmljjiihhffponmmlljjijhhffedccba_rqpponmllkljihggfkpnnmllkjjihfefedccbb_rqqopnmllkjiihhffgpnnmljjijihgffedcbb_sqqoomllkkigfefnonmmlkijjihgffeddbca_srqqoomlkjjihgfflnnlmkjjiihgffdedcba_trqoonmlkkijhhfeeionmlmljijhigfefddbca_ъssrpoonnmmlkjijhgfeegonnlmlkijihggeedbca_trrpoponmmlkjjihffeennlmkkijhiggeeddbca_srrqponnljhfemnmlmlkijihggfeddbca_trrpponnmmlkjjhfefejnmmkijhiggefdccbb_srrpponnmmlkjjhgffeinmmkjhggefddbcba󉈇trqqonmlmkjjhgfedfommkijhhggeeddbcaesrrppomlmlkjijhhfeomlmlkjjhhggfddcbcaksrrppommlkjjiihffenmmklkjjhhggefddbcaqsrrppomlmlkjjihhgfeednmmlkkijhhgfefdcbc`ytqqpopomlmlkjjhfeddnmmllkijhhggeeddbb`srqpopomlmlkjjihhffeddnmmlkkijhhfeefdbcc_񇆇򝜝񞝝񜝜쉈ꋊ䟞ޓ덎󟞟ꊋ쟡퇅䞟雟󈇈򑒑ᛝ𑐑󈇈ܛ㈉򍎎䛜܍󈇈젢鈇盚򉈇盚匋럏ꈇމ팎ퟞꞟϞ󇈆틌󝜛捎늉撐厍򋌊ݝ䛜󊉊󌍌𞝜񍎍㞝򟠞􊋊񜛜􊋊犉芍抋댍ꞟ􊋋𠡠󋊊抋񈆞   򲱱   竮       񱰱 﫯򮯮   򭮭򲱱簱𭮮   诮󯰰񰯰 󫯳󫭳󭮭𬭬󭮮򭮭򯰯򫲳筮𬭬𬭭򫲲񬫬﫬݅ȃ񃈇뀁󘙜ᛚ띜윟򜝙̝͝ߝﰱ󯱱򯱲󯰰ccbdeeffhjijjlmleddfeffgiijijklmmlnonno𐑒x`ccddfefghiiklmdceffgghijjklmlmmnoopꏐ`bbcedfeggijijkkmmceefghhijjkkllmoopoqq󎍎~abbceefgijjklmmkcdfegghijjkllnopqrsnbcbceffhgijjkkmlmhdfegghhjijllmnoopqqsst܋fbccdefefhhiijklmmnfdfefgiijllmnoopqrstuvŎ`cbddfegfhhjikklmmoeefehhijijjmlmnpoqrtsuvw֍vacbddeegghijjklmmlndeefhhjijklmmooqrstvvxeacbddfeghhjkmlnmdfefhijikkllmopprtuwvx_bbcddffggiijllnmeeffhiijkllmnoopqsttuwwy_bbcddffghhjijllmnmeffghiijklmmpoqqsttuvxzx`bbcddffggijjlmlmmegijijllmmoppqrssuuwxzpbbcdeefhgiiklmmoleeggiikklmmnpprrtsuvwxzlabbceeffhhijklmmnnlefggijikkmlnnpprrstuvwxyibbcceefhhjjklmmolefghhiiklmlnnpprstsuvvxygabcceefhhjiikmlmnomefggijkkllmnnpprrttuvvxz֑ebccddeefhhijjklmmnomefghiikkmllnooprrttvwycbbcceeffhiijjklmmnomefhhijjllmmnnpprrtsuvwwybbcefefhhijjklmmnonefhgijjkmlnnprtsuuwwybbcdeefhhijjlmnonefhhijikmlmmnppqrsttuwxxbbceefhiijijlmmnopefhgiijklmlnnoqqssttuwwx숉cabcceefhhjijklmmnopffhijiklmmnooqqssttvwwdbbcceefhhijjlmmnopgffgiijklmlmnooqqsstvwvfabcdeefghijjlmopjfghhiijlmmnopprrssuuww񉊋hbbceeghijijlmlmoolegghiijllmmoppqrrttuuwkabccdefeghijijllmmnoneggijjkllnoppqsstvv숉nbaccdeeghijiikllmnoofgghhjiklmlmnooqprrstuvtabccdefeghiijkllmnnogefghiikkmlnopopqrtstt}`acbdeegijiklmlnooifgghiikkmnppoprstst_acbddfefgiijikkmlnnokfgghiijkklmlnoppqqssts󎐐_abbddeffijkmlnmolefggiijlnooppqrsstjabbddeffhjkmlnoneefggiijkllmlnoopprrss|_bccdeffhjijjlmmnohefghhjjklnopoqrrs`bccddeefhhijllmnnkeffghjiijkllmnnoppqrrgbbcedfeghiikllnefghijjijkllnnopqq刉oaaccddfeghhiijlmmlmngfefghijijklmlmnopoop`accdeegghijjkmlmmnjfeefhiijiklmmlnnopp҃`abbddefeghhijjkkmlmnmdffghijjlmmlmnopo펏t`bbdceefghhijjlmlnngeefhhijijklmmlnopp`bccddfgiijjlmmlnmdfefghhijijklmlmnnokbbccdfeggiijikklmmofefegghhijijklmlmmn숉}`bbcddegfghhjjkllmlmideffgghihjjkjkmlmn䈉bacbddeffgghiijlkmlmmcefegfhihiijkklmlm㈊`bbcddeffgghijjkmnhcdeeffghijiijkllm剋hbcbcddffgfhiiklmmdeefegfhhijjikkmmِ|`bcbddefefhhijijkkllmhcdffeffghijjikk󋌌fbbcdeffgghiijkklmlmbdeefeffghiijikk䄅acbcceeghjijjklmmhbdefeffgghiijijrbcbbdeegfhhjiijjkmlldcdefeefgghiijjcbcbcdefeffgiijklmibceefghjڌ`cbbcefeegghijiijklmmebdeedffghiracbcddefefghhjjijkkllccdefgheaccdefefghiijijllmhbcddeffefggcaccdeefggiijkmdbbccddefeef`bccdefeefhhiijjkllkcbcbcddffefwabccddefefgghhiijjklibccbcddeffqaccddeeffghhijijkkgbccbcddeelacbddeefgghijjkldbbcbbdcd~퍎lbbcddeffghjiijjbabbcd㈉jbbcdcdeeffghhijijjbabbcbݑnbbcddefeeffghijjiiki`aabcbnbccdefghhijjikg``aabvacbcdeffefgghhiijikg_``b~{cbcbddeffeffhhijf``뛝㠟󍎎𛜝ފ𛜜폋扊񒑒Ş򊌋􍏏順墡񍎎⠡늋󝜝񐇈菎𡎇劋㍎矞𞝞򍎏ؑ鎍󊋊猍蕜퐊񋊋󏐑𠋈򐌊󝜝늋𜛜򡏈菎񎍎𝇈ۍ񆇉܍񍏐􏎏鞟ግ򡢡󋊊덎ي瞟㍌񠋈֍ŗ훜튌ݟ늋뢡싊鞟읞ꢡ󛜝񡢢񜛜𡠡⊋꟞䊋ܟڜ䌋쟠닌➟䡢𫬬󬭭򬭭ﭮ񱲳ﮭ孬䯮򮭮񬭭󰯯񯮯볰򭯮򱲲籰ꬭ񱲳򱳲䬭񯰯򬫭ﰱ󮭭񱳳񬫬󭬭豳  󱲳 챲𰱰nmkjgece~~~}}{zzyzy|}}|{zyyxwvvtpomjgcf~~}}~||{{zzyy~~}{{zzxxwvvutstrrpkeh򎍍}~|z{yyx~~}||{zzxwwvvutsttut~~~}~}}||{zyyw~~}~|{zzxwwuttssuvxz~}~~}|{{zzyx~~||z{yyxxvwuusswxz}~~~}~}||{y}}||{zyyxwwvuttsxz|~~~}~}|}||{{~}}{|zzxywwvtussz{}~~}~~}|}}||}~~}|{zzxxwwvuttry{}~~~~~}~}}|}|}}~}||zzxvwuutstsqz|}~}}~}~}}|}|}}|}|}||{zzyyxwvvuutssrqz|}~}~~}~~}~}|}}||{|zywvwvutssrqz|}~~}~}}|}||{||{{yzyyxwvwvuttsrrpz|}~}}|}{||{||{|{{z{{z{zyzyyxxwwvvuuttsqqpz||~~}|{||{|{{z{{z{zyzyyxxwvwvuustsrqpoz{|~}년|{{||{|z{z{z{{z{zzyzyxyxxwvvtsrrppz{|}}~{zz{z{z{zyzyyzyxwvvuttstsrqppy{{}~}~{zzyzyzyzzxyxxvwwutstrrqpopyz{|}~~|yyz zyzyyxwvutsrqqpopozyz{|}}xzzyxyywxwwxvvwwuvutstrsqrppomyzy{|}~~󀁀xxyxyxxwvwvuutsrrpomxyzz{}}~~xxwxxwxxwxwwvwvvutsstrrqpopoonlxyzz{{|}~}~~|wvwwxwwvwvuttstssrrppooponmmwxyzz{{|~~wwvvwvwvvuwvuutssttssqqpoppnommlvwxzyz{{|}~~}~xvvwvwvvwuutstssrrqpopponnmmlwwxyyzz{{|}}~~}~~uvvuvtutuutsstssqrqpponmmlkwvwyzyzz{||}}~}~~~yuutuuttuuttstsstssrqponmnllmlkvwwxyyzyz{{|}~~}}~~~~tuussttstrsqrrqqopnmnmlmlljvvwxyz{|}~}~{ssttsststsstssrrqrqppomlkjuvvwxyyz{{z||}}~}~ysttstrssrqoponmlmllkituvwvwwxyyzyzz{|}~}}wrssrsrqqrqppopponnmlmllkjjijstuvwwvwxyyz{|}|}}vrrqrrqpoppoonommlmllkkjiijitstuuvwvwwyzyz{|{|vqqpqqppoopononnmmlkkjjijiisttuuvwvwwxxyyzzyzyzz{z{{|{wppopopponnmlkjijiihhssttutvvwwxyzyzxropponnmnllkjijihhrstsstuuvwwvwwxwxyyzyzyvoonmlklkkjihggqqrstsstuuvwxyxy ysomnmmlmmlmllkljjihgfgjpqrsststuuvwwvwwvwxxyxwxxyyxywuollmllkjiihginppopqrrstuuvwvwvvwwxwxwwxwwvwwvrpnlkjjiknpqqppopqrrstsstuuvuvwwvwvvwvwvwvvwvvuutsqpoopoqrrqrqqppopoopqqrsttsttuvuvuvvwvvwwvwvtuututtsrqqppooponooppqpqrsstsststuu vutststtsrsrqqoponmnnopooppqrqrrssttssttsttuttuututtsttsttssrsrrqponmmnoppoopqqrrsrssttsstst tststtsrqpomnllmmnoppopprststtsttsststtsrqpopoppoonnmmlmmllnonoopqrqrsstsstsrqpopoonnmmlmllmnmnnopopoppqrqponmllmllkkllmmnopopqppqqrqrrpqqpoponommlmllkjklmmllmmnnopoopqppopopopoonnmlmmlkkjklmmlmnnopopoppooppoppopoppnonnmmlkjijkllmnoopopoppoponmlmlklkkjjijjijjijjkklkklmlmllmnnonmnmmllmmlkkjiijiihiijklmlmmlmmlmmnmnmnmlmlkjijjiihhghiijkjkkllmllmllmllmmnmmnmlmllkjiijjihigghiijiijjklmlmllmlmllmlmmklkkjjijihgfghijjiijklmlmmllmmllkjijihgfeffgfgghiijijijjkjjkjkklkkjijijiihhgfefeffgfghhiijkjkjjijijiijjiihgfgffeffeedeffeffghijijijjijijiijijijijiijijjihihggfgfefefeddcddeffeeffgghghiijijjijijjiijiihghggfeffeedcdccdefeffgffgghhghhiihihhii hgfefeefedcbcdeefeffgghgghghhghggfefed cdcddefefghggfggfefeefefddedccbabbccbcddcddeefeffeffggf fefedcbcbbabaabcbbcbccddedeeffefefeffedcbcbbaa``򏎍ꗘ蔕򕔕񔓓햕򑒒ퟞ򘚛𘖗甓󝞞񖗖򕔔ꐑᑒ엔𐑏 㑒񒑒󘙙󕔔뗘󕔕􋌋 񐑑쑐󏎎􎍎쑐鍎󍌌   󊉊 󱲲    󰯱 򯰰   󭮮 𬯯  򬯯򬭬ﯮ 󯰯    #孮𮬭 𭬭񬭬  "   󭬭 trqpoomlmlkjjihhffeednmmlkkijhhffeccbc`틊sqqpoomlmkkjihggffeddnmllkkijhgffedccbesqqopoommlkkjihhgfeednllkkihfedcbcisqpoponnlmljiihggefdenmllkijigffefedcbcn鏎rqpponlmkkjiihhgefddgmmkkjiggeefecbcbt䄃rppopnnlmkkjjhhggffdcimmkkjihgfeecbba}Ӊrpoponnlmkkjjhhfgefdckmmkkjijigffeecbcaqpopoommlkkiihffeedcmlmkkjiihggefedcbb`슋qopoommlkkijghfefecenlmlkjiigefedcbbh捌popoomlmkjjiggefecfnlkkjiiggeffedbc`xpopnnmmkkjiiggeedimmlkkijihffdbc_ppnlkjiigefddkllkkijjhggffedbccdoonnmmllkjjhhggffdcdnllkjjijhgfefedcbcmponmmlkjiihgffdchmlkkjjhgefeeccavЃoonmlmlkjjighgffeecmmlkkjijigfeffecbcaÇonmllmkjjihhgffeecgmmlkjjiihggefedccbaommkjiigfefddjlmkkjjiihffefddbc`r덌nmllkjiihhgefddmlkjjijigfeffddbc`nlmlljijjihgffeeckmmlljiijhgeefeccbgmmlkjiighfeecfnlmkjjijhggfeeddccbr茋lmmkjiigfefddknlljigefeecbca􂁀llkjjiihhgefdcgnlmkkigfefeccbmkkjijighgffeddmmlljijhhffefddbcaw劉kkjijihhgfeedlmlmkjjijihffefddbccb遀jjijjhhggefddinlmljjigffefedccbokjiihgfeedhomllkjjijigffeecbca򊉉jiihgfefeenmlmlljkiighgffedbb򓒑iihfdgnmllmkjjiihffefedbcc`~jihgffeffemmljihggfefeccbcfihghfefegnnllmllkjiihhggffedcbcaxihggffehonnlmllkkiihgffefddbcb`hffefkonnmmlkkjiggffedcbcc`zえgfgegnonmmllklkjjihhggefedccbf郂~gffjponmmlmlkjjihggeffddcbbaz폎fjoppnmnlmllkjijhhfefedccbbّnpponnlmlljjhgefeccbcc`ppnmlkjijihhgffedccbbn팋ponnmllkjjijihigffedccbcb`늋~onnmmlkkijjihhfgeedccbbc_w󁀀nmllkjijiighgfefddccbah쇈nmlmllkjijjhhggfeedcdbca`팋lmmlkkjijjihggffeedcbba_s􉇈mllkjijiihhffefeddbcbaillkjjijihhgffeddcbbaa`lkkjijihhfdba^~jiijjhihgffefeddcbcbaaqijjiihgefeedcbcbbac񇆅ijiihggffeedccb`cjiihhgffeddcbcbaa`߅hhggffefeddccbcbb`zhggffefeeddbcbb`w~gffedcbbccba`n낁fgffdcbcbba`oeefeeddccb`_j郂efeeddcbccba`_neddccbba`^kހddccbccbbaa_p􃂂dbbccbaa`_pcbcbba``_y􏎎ccbb`a`a|醅bba`_aҊa``__i쇆``__\x__dჄ~~ωۈ㌋𒑐돐랝ꈉ䋌ۛ򈉇荎򉈉䚙򋊋튋曚ߊ񊋊􊉈썌؊򉊈Қ蠟񋊋🝞ڛ񢡢򋌊􍌋󌋋􌍌򛚚Ҋ݊򛚚􊋏勌硠񍎎񛚚󘙗隙퍎𜝜󍎌󟠟󛚛񚙘뚛򝜝囚扊󛜛㛜񛜛򜛛󈉉򟠟𛚛񈇈ߜ폢򛚚퉈ퟞ흞䞝虘凍띞󟞟򲳲󬫫쭬ﮯ쭬񫭫񭮮񱲱שׂ񫬭󬭭򫬫묭ﭬ鯭󬭭 𭬭髲謭𭬬  񫬫 שּׂ󱰱  ﮲  ʀ~~򇆀~򇈇切򃁆􂁅􀁄ˁ~~~~~~~~~}~~}~~}|}~|}~~}||~}}|~}}||{z~~}}|{z~}}|z}~}|{{zy~}||{{yy잝ݘܘꗘ𛜜򚛜욙ꚙ󗙙U撓cbccdeeffefgghhiijjg__䐒mabddeefeffgghghijjg`accddeeffghijjh~jbccddeffgfghhi~葒dbcddeefeffgghhi􉊊󞟞񡢢   쳲 򳲳@`aabcbbcdeddefefeedcbcbba`_`abccbcdccded dcba`_`__``abbcbcbbccd dcbcba`_`_\qi`_`_`_``aabcbcbcbcbbcbcbaa`_`__^fihc^_``_``a`aabcbcba`_``_b    @`^pۅ~}c|~~⌐냂~~}턃~}}񋊊ꄃ~}~~}}񉖣򛜚󚙚훜𝞝@}|{zzx}|{{zyyx}|{{zzyx{|zzyyx{{zyyxxw𖗖'dB2!barry-0.18.5/desktop/images/scanning.png0000644001161500056700000006335712242254476017516 0ustar cdfreycdfreyPNG  IHDR,sRGBbKGD pHYs.#.#x?vtIME! tEXtCommentCreated with The GIMPd%n IDATx|mmYv4w{mwW;qؖ#BdA`+"@(V D7 $2"p"%&#p, J !n;mwz}{9kcsjU{}^k9cL?#@` k{־3ty$(s}b a07e(נ~\o1p_~=ߓ_^ a\?+??zކ`A<SFop$@kK큍M&'^gL| {vgjxv}% l7ھnBcZ?Ը=j{}o-U"C6adCozSq"QWP۔vl3lpC/&3_oE<_A ~kkmm3{q(~1ү_ﱭM>czx#{nɩjkYN/@9 RDȡ >U_h=԰о\)ǸAÑZ#O>?k(0TJ<㳭Ϭ(gInYr,/Upvmn xDe9<,=%I ~<ղS9\;:j 9l#6Iscd x+wbis0s8vI@AN˼<8%DM-g_Ss 9f`f1fJ<rhTߖxi|8^#M{u"N'߬heғwFr}qt,A1G;GZ0 ]ӓ&F6{lflĚ?  1# ;hGȆ<1Zǁ C%ZH5FP&𻠽. Q$:ŀܫR8B66DMt]鵐ԴBza;۽ n" 4B%G4zA{ERډbȦ"kv]wJJw"k;qX)jcZ6֝mPP`k4.^kUL"K1^a,ue@E".m}p2q vH_H#Z+rwf_9rT:YH-l; O]&" .O-3m.2?{yha3\k7 (t7ì)#G`hƷy356"0Ѹ?RL:d^gjEM -7gg&_ؖoSOM̋q~J̈́2>UTu§7Aoϫ;\!%4ϋdQp8_T-7F hߧ:SiڼzJ9rk!J1d+acQ>CYBo*{\&*m ࡘ_WZFzGVTzppM~%]0#,Ap,k[3bhE 7) `ǜZ߸} qŪn涃FcKYۆPFZ8B&@zct#͕żfMoL8)f܀ZQ&ErsC֚[#5[!nh?"6zT=c ׷VG<&kԿ~-noj$͵~NϿL@HZ֌F upvz ԅ^$ɟ_KQ8J 9vKccכYbF3t(l>y;6nKܭR9NPu 9Dѣ~( _ 0nUlQV룭Nw+ D]jr V'*;+U+FB7 7" Sjb!9:;FMM(%w[|u\ X#_F3?KjlWGھ5lDL'-cd~|d>vxs'40'-9($iB{Q> 7#m| (Fg@ 88UXC\|:|Zch F.ѣ -pQ1DtqPҩC3"_sb޻U+xmbݬa۽9 ͌Ӷ$0!;33_=s:/i]1/,J#YnYboQw z'vd,5*m>B>ynv}OulZ:l6&RF&SQ+Qڑ́cNX*ƮCić4F=V-l3<@=SFmu)LSV>oSE"X+pZgvD2la_Ca7rx7uL eŋ,1M_Wapc̅8UJhބk@R$.Sڰ!@buLbHdʢFEœDU } =`O]\*":>p!i늁OI "IQ}]\CvsHQԙ ۷DNA4m(j:P$~X lu [Bs N,F ^C5`sR∝GWj4Z;X"nUe^xkm+f + =2V3cFޠ[rlhCsރ}"smlUSCч#H|]D$\O(* B\IwCiN3B).bR$sm˓M3kJ훣7 ݮK G^LD<8:JA9Bpq8TO]YIN0<[iKko$Wy>==:U/`S@ $^ Pyo$.'p ޽qoE:I~_O-$aNU^AWyNz[Za;n-tQFA?I-@E"n}H G0m\E(کzqBRx[dndߺ("gJIkR3ĸc:yS~Dۅ"9É8a1Y]Hk=zq`rV")Z&lHUȡ^U\h lܪwũ͆% PR )H2Ӄ)q: 2mI'k( ET&IM.ח9c-c`rsArF7Q`rQ!t^1Gãt 2Zyy$.ՍifhLA$5O"])b''0&= rzpZtd?, 9)¦KHK bЀ[R#Gh.@E sN]p^'B\%sU"i ZsS]!I S4yX1e9a0.>HHȽ{ZVŭ(wu@vgaJ6=}7< jDJD9ˤm+.O({k$zmV%l f2~д|YV=q?^Cdv\+R:LuQ@wZ>؛/˦f uu".OOΜ1l-{l%!Y,k9~olʏwO״-Q?xxF/KE/=cyYp-bBxHZ;:aU3WRcFlJwm2WZc,Ъ(2n~uh)F^+UP;+)?UIbZol~ f3+=srIQcBOe4i"i_@j"mzx-IJb>TJ0=(":3D՟{{LnU|DSqx]DZD2qieqX*35Ǹ56ar&?gRQ]1wzAvtEEm¨Si-ċD"b۶D֮do3eLä&֛&m-qc뽸L MzsF ,-MR-Qdgv:)&2DhZ)Z܋P{f$t=h)uF}iq˪LkӎnQd&t /)kqSL3ˀ"k--חĮ;eNng(q:#CS҃v5AfNHr8iY4QBE"F!P2Kels\9(fق`.꿨Zv'6?ot{R>pR-!ٕ%; ӱ[=@NI4-;0zCݻNNĤ&x&'JwIoByJ%Q@z#R!~%s{ya&M7HCZn_A*  Cd2rW_0SZ \hkJ1S(A{cQ [S09-m{w gb{f _ѕ2ÑC"ilt2,q\IhЙT.ź":Z!뻳ӆK S{pK։,qab&#o GZPx,Q7h6 f2!d]#]wR.1|=%ʘZǯIiΖ,^k4FI^5_|i$yCX34K .FN{RNyuAeu0cofl ŕQעa|E Ⱥ6;N6g#\p"yѮe8XT`AXXVY-M#mr+3VH?f'*,7"x ,BT$qRn9$LaThQ%TJj[b{#SuIKNΆ+A8ŝ!ehᏙn+ԧeLeҍjRI!Y/Ow/*]#}1\;3:_p4smfn?DXSG6CͼnQSvUߍU/|p/V""o݅H EU̳;`Mt&Ft1P'ɡ$\.֊ 5jtĿ8XO͑E*,\m2^Tyv IDAT̈́m) Q"4k}@'OwQEŃCa5mv]+pYWD _ {ígn\*VLfF6 ?G,L͝ͰiA=YSZ ]BCe\gC6qC` CS!㭕!Nb'c%vKA&r͒E.&'k:[\3` b&E ]ԝCvyL'| +Nj`8?$\ :Z*e)UFJ"J^E$[SIj(8Z5%tP}}܈ʆZp6̈́Oߨ; *멈jYA"c0ůDj} 'dV<6&iC̶'#,rE eTEQ}J w.N8>eMA5<RxWxƂ=`oCґτ8R 7HԠ]%6LuiADY1VEprP#A&2DA=Ng4_bXri0i/:N]@l1`L ND0)PJSNԠIT(5*Nc:bt ña Nm?݇}n} e4X@ M'kOjr vD޿BB񩛣2%H4z,ךӍ]Gc5\y;țjB$npec4KF$mMXz3o" Q*?IݱZbUwqda,q#<`pV??r OQ7+Hwk-,|bLT6ol}#<D7_U!~~s8\]A=Gg_~_o ˗=m8ڗtjD3Qw@DtZ xXgx|k1NrsəR)=:_Q*?LJs]⥿faMӍ~N6{Wg6 E^wn,nS,I`1~Njp$;87\h3^N="N-Ld M~2٤?b`|_i1~:s % e6n}6ܝ#7~~/3QAkiA:^,9D6:zIWBٗ>#,_tȌO5=Ϯ}i gHe&" p12MMb"vJzâdVOH ˜JG6ۼf!߁D)D3JgEeXL!ѭ{l*?z >zt| ûG/Gu|\>|?{x' o(r' tsڈlMheWzbg2X}dr2-X窦-D4sǠcb3" DZ0.vNTV/9%pȪ4޷&RDmFQJ:M7ʀyy-yk^^SY3 E o%u|>߾u,>~Mق7C w^</p`= ࿺q|>gOd~,2 ]a786^ؿM ^]ywUsxx+ڏa\; ҃/W=SJ{@R7ʠjSsVFJ5cSlN5z ]ߠS"@C`h'_MCF'xq_*aZՑ]4>81vGYq̐57F fѬgZdPNkt2 >fCl!jqSX\[/*WuO[p~\N]/ǫ]Y=Q{ ,?zn:0Hn0Й8SOax⼄k-Ӣͩc]kdבbRl~Qd-P{Sy**TpȪe$Y8R- آcA? :)&Q"Iq1P4bp5ް-3RO}?~o ;k-|to!NA_.77w{+Ëp>F9/̊[6І^sFp0p'228<9kh߃qq8V+~KHP 6pt}šER"ULn ,m'(Eٺ 1B!j J"z55PT&S]5F~9S+?_] r8~;;];]ሊ:Wc_Ƌvg2~?u ,WR Dl&V糅'K(TjSm\us0~=%Yz!$s,IIyf 2$2QLzXc~V>9\n43t ˫JH`FI[\; ܽo> +xήޏ+;Ʋǟb;Ň_K po3X)#jw6w]WʚKl8ӏ/fx Uw Ҽh3 ;װՀN\]y6bֳ,~wMlذ@+ƀ-h-|m^> laXATLNn x;+&)ۀTެ=#_Ҵ =x'O>Հ;waq;v/:ӟpt{pW]|>}x]m4ZT\FХm"Vb1kK1 6h*IjS28lbӜ^r"#|Bz.H|$03g* h1o0 Ԉπ7J2$8TR7Gn)5my/_G1&M/}|Ãq3 Հ/p#>zk]nwyu9}zߎ;o_| CwRek0v룢J ajW;]̫Ϟa)juؗvFs٘^f=#- bvP֣ħ~jd O]d=Tge @ ZDߕB7dGcn7v%,ʈPJvmQ+ 3I $QK5uN77q~&Km\/;Vwn<7yxp~7grOy 75;Yl8ϧ6lbIWA':5}㔲HbiB Ίo,xMZ[])aGs8+!LƤn}E9)m#OlJI$EN Mp%KdQןkwدØ!OC zMRv0.ċT;uU#]P W6zxO~ީ QO'|~J,tKA9jԡH.Å]^mx8I45)*]SNGbՍdN^ $Fj@k^O_<2Fv$.Fnը.Jqɏ )ggDpu,#B\0L8 )nC:lvozøqZՂxoçNq2OϞgww_Ǐ_}" W"WZICaR xDQ[ Ej VW*s2n%W5.*Uͺ*ApJЧC}B=(NB،]:Q:Aɘ>b{Qx61iѓK﹞ķUN>A+ԛWᓸO?}||P`O\}gy MO}F0FS:ZҒ5^X6{N;ءf;V`C)$f4:{+&^CFOt=EMJ8D2Xk4ԴQHX# i !&ttŃqbIkF,B-}{ m ?C_z~q +Qm˸8TQ07eY>: L:ZC]v6.՘Dَ5X LT`HZl\ظS5Z(d0<ڠKx ڠ;BřވUpb_QvirfΦ2vI߆f`NEЍW5NSiD}?W{W_s-|5vgg6ܼP2WF1J eͶers}pwv?y>"Eldma$Ʈƫ5x O:fJ(ppm7Gƴ2fx M5^$> 8:X'Y]hs3PѴ"n;k;1D?ps3_S?}"Zfu vҩ..MNh⿲8X;/8TV2v&_S fJ{n ;[ 8NN܍@cH77baKg,kDAnl…8pVneg;wiެ J$kYBf6'O#8; Hw^;/>b鮶\C5&}'P\MKwv[ѕ)e'|M5"ϚKh&qd2fS[މVڕ2}_J7אXD^شqE3 aHLwT*Qxg4&oQ^rG^Nfp*<+W"!뺉ǜxL>D C+j^Ev w45SauhnE=[$  |_+7pfX?*lF#/?YE8h~H491|ÊiS1&|2IV}8ӱ%>ljUn *oiF/" *B[S,C%{CutW<VCn/%Asr1N?u]5eb7,84} 7#g?żٶ6lHm)銑lͤ8 +.ߵ#7lY{蕊`ij齐먏(#)<䪶תVF:MKN:hܞWAztSqܖHMH!3mpvŒcI*O$[1{  ZP4L4ޝN/^"5XD"wY\ϝ551qv'B B8%>\$F=[2&F,5wcHyk8NȄFFnЬ fݙjcHHo\wydTk's$BDy<Ɖg&RS V%˲? &M&r(fc1IpMÓURFUIyDl 03X IDAT#dsMK%1#TtdgjFmC )Ƨi/ ke2Ƃfl%zԤ8&m2sDqpS(ܰ%i(2ZS]MZKpE6uAUU1L*Gs[+E Sݲ]_U3MjA3mVbCCzJ d [ġIGU䅂YO^"U ,c]Ba}6vyCс4x(iO0 9R=VkTf*. dFAaBe%(*cvnN6cd>=Lcj#ln}ubKvHϠ M T 4ԣ1mw©#>a QSN So4sb_5ٿ$>o2l*xX l'hxo?Upaq4(}uN:9g⹍]yG.Lw,iGwܒʑLʘg\STi[c(Gehmf{d aD -k; B -jN(k# R/ NSho i̴h Ëe mN//mfhn4C޺VÐ]1I }l)m'tj@͙tP/ԟ!E{n5eoz6D_  z?+yހ.FxR,`dfQ hs W:!` ! ]۠J7l,)2G!/6 ]ns%n&'?": g!`QP̈]it/]F"͐Ȅp/u>scI.$@'2ҜřDIJ؆SNgYᑌN׉}؊b(Efo#Ed+D a]е+M]a` C+ߑ*)kɌ9GIkлlp&j!0\~iNG} M9nHjW_7X]-̅~UrG?N(zʓ{9, ]?6h$fWQFVe_F4"vKو~K0%틫?<./2S|P1F18O1=݄o.`t91V*fe^J)iS柧 Y%H7AkAߨqgȲ%Hnv}ge@$M2T4BqÔFZةd.dmHӟgq7uB7i:(ةڬMRH-D jhYGtk SP>o;[OCD17>pC0B t~^Ҳ#7M#Ηep0~NX4:`Rh U( ѫ o1+BdҜ/%~i5` ;^澄)OSRu["6*t2ZSAUԦ\F2w=df[ΰ+NЭ?4lhP^0զ+|dDy+44@3,h+ڍ(ܚ+\!M^2 J`D/#B7xyahH6t)tkwM>nB tw8iD@p& Ǥ]1fLEcB][ s&i a%m:cJ?S<ѕMoSھ^ Wخ] ZJqpV}לFsQ6LyJo*,9PL٬xݝ SP ԆߘC6!iX S?1A5ڵfycg@AϘ(">CDHsŌS-<<Ե\Mil"*/2]dfo H73psc:$L.&©{&j&LcX냈d-/+iix[Qi,o%Es^*.ם.t؅[;yf2YEG$`K-n؂Zɷdva)י|tb8FaĘhgtA7N zPX^fq]d5HtF@yBQT6Lm"}f%Dʢ]mHjN*!h|F&D>B! JΖҦX6M5yyZ#\49iЉX&/0y ^J-գHﶖv,瀨bP ƒA ԖHkH.~V؝^yȨп:%ȐI?g5X }{E_MՖ[5};hMҾQ'v.5G;ǺRSj?wUK Ki WCibЍ$f5tZl:Q_?y#^mtEEsėt@e WL)7#5R&>L椦-ք 75]R $)Z$*Ǩgs>plpy!gHM#6*4*2U/(ۢII%l"+k&j.l4Z ;AsCqR:%י'\ݺj֞&]6 ~V[0v4v̛TU ƺKG'8F 3o SgEP9픚RY,afK5k F3158F7*QZi=RTح=#$rB 6N5Âr41; _+W-ifi B "tc_'v8YEndOp̮]aڣmR&hH#ċ)Ii WNmSPFWts9ġܤ7/>k_k qnJm|!;d-jt"޻N1CaO_Z]%hKfs>6Nk9G5v3pj5O҉̠+Q[V5W=L15]txMKyTSH imhU\?'J4:jچú1.Ϧ0tṲ̋!ea܅X2- #d{/^XgY%sCD]eZ,Y/}962I#;H{+OpD#B<,"VY~Da԰nr PY"Laل.{t#|ó-љ҈nU㻿k5O&!3=5"8㜎?pi5Z^4::/:j6l}<[Fμ0)^lzduZ}&4:kC^37<{cIAPEt@oq`j+DuDtMwKR8~j2@'Eq ByeUӅOS7fLgh0Yt&D<`OA}k|!|PQAߨp}wth`k_Q里OUt;tĉ# :PHbo}l "M̶۞߷¦X#R˪&d1elT%ߧEmp5rn#'3!1s#w( AE0dm+d6[LQjDEtH@Kя6qw`渑q>:#Br8F(G)D{PtN WڷCKyh9H`I'a/ӓk ] -m ҭ'#"Aa39 Ğ?û;R|Y]/vGQ*rS͈<,;`qb2Nk PsaI'-̦Qn xEL4HSM=%]jc-s5H3fnx5hCO]/ҭ+1k5`2Px:@ ~C Vum!e'LXd8zYY }[%;[;!Y<=/)B`kKC>@;Ƹ_nZIJ&j]YB3˄1*֞iPS.D=j843~ dLawpyT^9*ZWSL 5{#CĢp2M }2L\$e0lY#\[gzztAnd ;jD̮0W`2]W-+[dPfJ 0%;Z#HIP:a0x[)nYJdFR=K%|< ϾU69 ֲD|M%I?G:8ki,I^ehA$~OΖVO B`  =VD7hI;2H!LK>7-&4ހ>,JB{m>zV_yI7](h0c 1C):OM;.{o:MqjJnyJ]~ PIGN$ %bfNzd&*id 0Q Ž Ly"IDAT6؇9g>IB (mXmMrmWpyOŪh0!i`bu!g@ q>!cziMǫkpVAqpldM:#'e̢̛ʑpkO7S74p/WT 6hTh~haV]DƬBI2e<)001ve$aZԄ5ŵET{O3+#aSYS H㫴MEĩ/gwTa&Qɐ7;2R A`M Y!AѩH8%ڤ/KÄ7X?kLz]` r|3q3OuZ ,B-Xz=wO>PPV2gUѝ1hUK9YBǠLTcv_Dzz5Lp2&E/$LЃ0ݯ`Ձ2ƀJ['w(gBpI V0s8JO7U Q`Q\VX(dI-VE![6ͧt-{b)%p1eP~H?7o?ʘ;O-" r\Q3v GQ6UG}5{MDg=΂ΰ U!]$3$p-U5瞋 Fei`9G"&=cRݕ >CyqFkr\E)ϼUTiQrʕ\(bcfAtsm[|ص aX빝hM1&PzrX}J+)UA70ʡ [o&|O3Z-ovJ b&vHqΕh7ıHkpML0F8v"NEXxL'צ(JknNN@qpƮI@4s#e6c(QwOe~q%)59@s۝_#ѓ}|_v=@8݆g\֨|Qb+&FZJ=mJSqvFaK:e(/l!ehY[HIۘ =m&#>hSDtӳ1Ŧec]/x|. -GSIDJHb _sE%49msSD>W֖mnB8[#fSɭmt3p9XPC[S;΋D- [C4.fz٪e!xIENDB`barry-0.18.5/desktop/images/misc-focus.png0000644001161500056700000004347412242254476017764 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME9R<tEXtCommentCreated with The GIMPd%n IDATxkgu%~SUU._07lmsMw4ݠZh?3Z34?ԣQOw+N0v0!\;@`lS|)^{xn{?{ I>/2ugk{{qn$ޅcw{{.So]޺{v_;w? e{Ow_,?="$KSwvc%=6vȡ{?u}==K>~@yk.[~PU%hkE>P 3VOʿid_g>p'soWOݵ #œNV%?1b K j8,:sك4]H]/tO_ֹ I=(C]x(}q538>0|7Li4@ŵd9?TÆ4<'`ނ^3ku H&+4l=k"b)ofp-^AE[[0#P36*p<{\PÃ3 #gm y9\{sEwi&v|,DX^7f4u/2 'C͸̷pM`b ڢ2=Zz;C0|aCŰ=%s||ӽriVpfap7H=O0sKxܽ\<|WTpG[$jVҌn8F\_P꺩Hhi2ح}툁p }8cu7V[h"_m¹Y8c̬&ϒ$JP52 Qk}Oj̄¢s a]/"=-5๝!.x ܆r1B13 gR w iS z]nJohfT>pea!ëS6d&D :A뤔b-7`rXfTv/6+yi13AXџ֕b&8&]ntǟ2R\!:\-b%.zVE E_~#9l2h4+˫όfb RңPCW]E#d uBD6)%r-)% _$r-Mo MjLrP/>Lα)㩖fk >rn񊡀BG8[YAs]2‹x~l"8(1VSzs1E))/ƤZ(H95YD%$j$FRH j%3]1fh `]L Ň`+хOP1 *U( A ¬8.2hU,km;9f2p{)vhlaH`l$,BC1 7kJ6qUJ 9?1ARZTJI&+!%NJ[ uK#vsL{aeS 6\x" ȖOkc#)! 8f TPL@zP1Q#>s.ֽl;0k5qKȊ8ND.<W+) 4raMl0{4('QkV {rЬ5~MLmXzd~jp! 1'ɱlcMƌX6MjQ0ьfFb 5v8sbFF)d:Y&BSDHImJBX )\TAp|1_$%Ό--ռ2hة#,:?@^(4RFqҋB6A XzUgntzKt%]Ce2F/V2LH U(d6Zd4L͐oR4/Rbzu2l0IJ0U!-@`L`ʷkc$ B{HVJX+W/;w69/-J 7mVgjt rVt8n\-:J/Jg` PB]&蝺65a 1VY@QNvEjaUţif)ùVB+U"Z 'tX_D2WRX&0)2!QyOörHk)նJt ¶TNmkg1 PUfro!6.tW*3!ۃr\) BJv*Fu: { eʡd[[U*;SաMh .g:_|yòj@E/Rzsc.^T1 ևfP+NV f!^:rhe)5VS6\a2[ 깵fO̅\=.3qī%BA 2wkBb%7D$ LlD`2` ($D~m=킭c֝Ʀ-dD8(TOPBQƵ xE1rhUu9 O<2s5ub'3[B(c3ɬR2N?H ieuF:+].YqIjKʎ"W(I$1WK0%qA0$9j}:|K+ ;\e 6~-M\>LR)lP٦?$znMM(4 WdB*#&TɁ9m89g@G( -\~Պ`7 6ռ82jn5xxQP]j&nVs/B@\ALېbb."*#1(%DI2"w@wC?MPW-9h1~BO'ՎCl{B92=aotx1EQj#g;FVqgZ缣$q 6uU"ʵ)skxe=*5JB((Gġ~fH2˄N:yi'| J*Q sH& u)3%+lj{B< %A 똫R,56hu1\zY'1XO b ic (ڎA\IVh)3\]D5MhQrL ɓfMU+yKDʩh$01S 1r׍ВFA4&1y !cNGP l\z ۀ[|8 j6U!le} ctG^rzέ> ` Wfcsmi*>E#iBnGz%N`sT =*t٥9HZRu穵b!FY.;_)g5%唭=h ]pHs{Ny`+uJ6;э$Af04!"Ts0C=}"}w82pZn5t:i^bʜ;תBfb3< ݛP:vrG~_QUQT6PykJM4a  e'܅URIm$L}ԉeR8I"n\yX EdvM5slB.3XK,_G 㵘Z+´DE` ;Z_&}bgݢHJMCfT0sK ^_S1Yj@ l \Z~bz(@$P` 1ZkȄZOFMV5);ErMHKܢ<+;@(::Z"׬ٿ_'sn|1K)dm¬Uw<8/( 02E3p2XFJ "W.a70ZK\bLܛtvL}Z2$ Tj'Ř *T3V>[I*sS#Y}bhU(x꼨XvPPD(^O}.e8ʪTBD/{< 3ՠXaw:EZK1bc)N kRzkB^h5&N RIRY*=bY}Ij"{b eSyf[pzCYlF֩ci|mpdrHlu+0Mj]1|ii.!*gq(#Cգ  0hNv7=J59G-m=SI|k%AV~b{ ;3J.0[%PM?c9 +#Vȹn:(ժ`\st\)EEb) (X \>\&8 ڵ 2ìB0U+Er*͌ʪ#bE&6zs3zhJ31yBw/WZ_vUO;ݳwxi#碠Ax]z饗>oUr."S2^!6 WIJWLij;o.B4oTbY+c܈N,Δ1-puHqvZAUQZiK ,ZĨ\,5i@NSބ&y PYjX3^hӧN̟~]_Go~G\Cgеwk:RWv"/}7~ߺuss;οkFdE2V=5iiŬ9厐\/rSಬ?8(^-w ws(u"sP`*iK0ta*1 x9(0yYBQyq#،ٻY̷1p*'Xl){4Z/fbȊ"b}g~xG˯{w_wg؝&Ӛ<}^?s磏=u^}ԓO^ɑR:rj]z^UR-C:eWD}clߟ؟G)غBgVך;ju3ZT9>;oor} NuTxAtG b=E߭TJenME09¢^{uο? JJ[[[73=.1bUbX>}f>vۏ?y-޾ڳw/. }ߟr2fS?\!dO$F?zMnL+QA606j=:ej; 2`%9KT[hl2%t ZM'd[A׼ZmlZ!ӸWO?k}^+p=} {:i٭/VO J֢1,#*Rڹ- 㱲"i&Sk1\!C[G'qIa1jDg/y#zї=1>E%Z娸(= I1ꚅs JSa,&Ȯ4+d istחgmo/\-OM#:ZVX;<<3jGEϞ9]mgΜz <`ۊ]* 蔛$ X!4{ninb!>_|PX|Vfbam㰢ֵ* C? N?7VPUj\֚ɝ:{rS2Ŀͷ_{|ԏ<~S[}yxkzip)lĊcHN8}Y9xϟxY7_O&h$<2^x)RE28?CL:2CRQQ(Dj}pÁH3;hMPcOC?>!BǝQO\hC=}C^͇ג]W=s+/*F/R6"c`64 Hp&9{"Wt*8SY\эjkխhB煨864Vߥ܇xz f -Ҡh ks-6jLi刚,KU}um-( SClޣu;={`^Fd=x {9|k_%\i.>|_G֗}NZ/sI+mwZV 1(L+RȚvr X4F]ƶݴy8ȁ\Kmj:^U{Ôf</r:RM[:V*̃`nM)Y9y{:\) o݀[y?f@=&*DrHZPu;Qcr"C,Moylݶosxq=Sw[]';@KEՑ xހݬJ҇>?| |==oyF^sgA=~cp 7^c;O>&u&7A@R< 5CgzةTaXXYO&K9pTA !Fb&0pv;3B/ޜ)P]t _ZeS?}7}p| 'ܯ/w40M=n^xkkl@N"#/T&5Y&; eŊY|2@E&(O.ĢF׏^Owwo'<1<Ǐzkw'/%d8z(۷;SZf4sdp {P麕FUŸ$u1 na$ß9Kd; |Gs il՘8m;bkC֊V5eӺ|63_\?'wj&<"?m<.J|gӥ?x?_HVC̎?[o?rT9t[ T[WjZ}HP<shKdrEJ%4QC^ P2si>/(MV"V2W3)|猾l+>)zwΆX0ԡaP']Ô\N\Գ?ſ7M8{4=^|9\vxΞ>qn|yW zӧO]|/?'X-}vVA>ʃ***5 3z HHWr^׉a2:}H+ 6$X+ bHC{V{ҼEh$:rR˭bV,Rh5{Ln%o]tUqE<,.R<bNEϣY: ޘ3L+Y 5zQ ]sIn-,9E[:9(fzr|4 Z)߾#[xwvpsm^/~xSq tĉ_>,5 7[}cc{]{oͅoPVXWz@{CJ>G` }*tH,C,^B4愦"=J>W7k7Už ÿgaG?셇s7%S.{OСC ǿu7yjr"'|C1VߞO"Jۆf@< H0|Pհ0Ox8!P\ӻ{ÁŽ}z ;:W윬yŔʀTkmJYK_uG:Z=>}a6U_~{\:sLػw"-m=˫Ǐ>on>6l_|1T,'E*+˗ ajIA][zGwhBVþtj1M5 *4PI-X0Hp8[@rF ꊒ;hX9!%'s.Bvm9qt]7^O܇~d#ϧ:?ڷo_ڷo_ܿ_4)%Si c'&f5"^֚&zFf(t0sS4=6j4s\ xz>F9HcՐnN(펙hip9P 0$&)wzrQ8~ܰu*;ܿӯo^}y% ^yk3OolߟߏĉXVgO:{v NĩSxiPƖ6BNw+j0dF .a&cӟqEލ"^s?>̼q6D J]K(쓰6/ƣ8LQ;#/-xr;SٖR⊪NuOAfDny: *N5pwwTe\}*™=CAXX*&eG/<8U "ؙ^0=gn0zYC5}I킍zB"!!TbJ%WJmZ &&wa1PIAʀI[˻c㔺]af%~ ecȥ sAñֈnr/xL7d89\*yES<9/Jh JufgB$76!n\#UBE*J_ץ瑣WhH Uԍ?>;]qlQyeCAcFD5,ԐSxdŨG/cmܦM{+34(-#=JPțAHŭFmWn+ِNoR 8!/GJEԜ(g;/.FO0Ddi=Mu\n ی#|-sQ$|t1*3>pyJHs~,5bPIzI"F4kh[\ʘʼoOA%CY7%zRXEeR95ê257,AIq`NTZ8P_=b4Pb+|b|zS p{Rkk p'="Hܸ32ۦ#D`x=Q\4^kMN0)fNg)U;j@ÿwRbϔCk!; RD^qHqީ4<d#K O ku*r4!_Հpy,QL7 471mqZ,sїؼu\I2rk~F;loZY9*^mFh sы{*V/Ԟy0ܯR+U#J<̈́= qdaXEչ@ܱZFg`'?;$uT0 lI*qdTý}ueˏ̕2̜#wrNP7w /;~#BCsWD2.Bs&+ky_::7x,ޜi krE2rZj5ZɨaQqc\*HUIT*ԯ;>҂B:d a06,Ylc%v>ܦ\/kF?zGt ;hzlNxCKBײXG0l5WbJI5e}A $ϊdj$Q&$iٰ1;tqa9{Rn0Ł;WMB/ކرmvm"~B𨚑2A-r(wc1tȊÀatYk 1hP#~*|Jhɜۧqzb0\Cy&)HŒ -bfi:.#l}!/$z4 C4ٝ gVy9M CsfR]=H-*c}aA?>DS8}VC*De5xy/׎_(?oUyUBRվ")2׹Q6< |fw!T^ˌ}i?2VܯA+!E.2&H\4 ̀l#a(,<  ӭĢ()}YUrma=BZ?j/$/:]U_fE!"96xns>͇:9w}4 Еh1GB;~<\憘19cU}= ydEȓԠjwp)-S \ A ,;f:r +EpAmVE ԐQ7*)>p84y[APq֕gk8C]hېF٠+^!4la-GCqǜ{i^  ʋTg/_!.[jh_2mA=anD|| Y$ךݩ;jyԜ F'Y"2fLA*IASnP!!Lg=n3_B"6o.MK(#t3GFB"``c^NW)p(%#]̶'JX7~\ ڱYugn_Ms -Scwwˬ{:IZ?R>2< !Xni>bzatc!{IDATvMiE{H"zpO1c;wخkT{TpZPybU1]e>J*{YםABQ0JKkd~w@~%h(̋CO6 |"C༲14-8 uA #j֩u2PPFc*; eL.Uʹ^9ÏU=#OQH\rlbFF,dYJZ^f}饳61KG -&@=VP@9W"DPw=뎡¼8D+jG4hYPomP4b.Ty@ }aZbh@a^DpxKi~׍y 8(t[LK.(iй k.s Uz?"`(y 3mT;U껄Rasf;Z;z<qC+X\- wQ.Xɸ>=t^mXn[Qʉ'XEL݋TS]cGahp @Xǚ.؅A)m44+{awXU %jGޢNIE5II8w= #R =Uo M-D[HUso:439Ū ]\?k8 Ґ4̅#x+(_ņ["9*wh"Y(1L v@P Ab^63 qƘnWchg8ϡBÔ@ 5:PX]ca;Шq~sJM -+A(G@Qr5M Wx?Alc}1˞-#SY_s\õѰޙ7rJYkl x|dɝ Űׁ7& S3/ w50׆ʑ $Ǡ(.~ _Ks-]w&( B~:HX6L7h*qI^nXJXZ>Ptp#wG{e}{!"A^{.]=vc=vc=vcՀx]IENDB`barry-0.18.5/desktop/images/barry_logo_icon.xpm0000644001161500056700000001736512242254476021103 0ustar cdfreycdfrey/* XPM */ static const char * barry_logo_icon_xpm[] = { "32 32 355 2", " c None", ". c #1D5E1B", "+ c #0D3C0B", "@ c #12540F", "# c #114B0E", "$ c #195516", "% c #123F0F", "& c #1C6318", "* c #216E1D", "= c #1C6D19", "- c #1F701B", "; c #174115", "> c #052D05", ", c #185715", "' c #0D340B", ") c #243B25", "! c #236B21", "~ c #0C2B0A", "{ c #1D6B19", "] c #0E360D", "^ c #1B6B17", "/ c #6C2F46", "( c #615155", "_ c #700F34", ": c #4D0521", "< c #16170B", "[ c #164612", "} c #361018", "| c #2E1115", "1 c #154A12", "2 c #0F380D", "3 c #124610", "4 c #1A4314", "5 c #923659", "6 c #96073E", "7 c #90093D", "8 c #48071F", "9 c #9A1046", "0 c #950A40", "a c #8B083B", "b c #340B1C", "c c #9C1147", "d c #980A41", "e c #530523", "f c #4F202E", "g c #872D4D", "h c #860639", "i c #42081F", "j c #943A5D", "k c #8F1845", "l c #433138", "m c #890437", "n c #930A3F", "o c #8B0A3C", "p c #49051F", "q c #950B40", "r c #7C0935", "s c #580425", "t c #970A40", "u c #940A40", "v c #87093A", "w c #45011B", "x c #94053C", "y c #960A41", "z c #67072C", "A c #7D0232", "B c #96093F", "C c #6C0026", "D c #7B103A", "E c #8D0A3D", "F c #860839", "G c #380317", "H c #41051C", "I c #750831", "J c #4F0521", "K c #350416", "L c #590626", "M c #8C093C", "N c #4E0521", "O c #300315", "P c #840A39", "Q c #5A0526", "R c #2F0213", "S c #6C072F", "T c #56001C", "U c #380217", "V c #69062D", "W c #500421", "X c #76193C", "Y c #A50B47", "Z c #380418", "` c #981446", " . c #9B0A42", ".. c #7B0835", "+. c #2B0413", "@. c #920D40", "#. c #9C0B42", "$. c #3E041A", "%. c #540C28", "&. c #A5104A", "*. c #3E0219", "=. c #372029", "-. c #3B1021", ";. c #BB5D80", ">. c #91083D", ",. c #810937", "'. c #380318", "). c #A3174C", "!. c #8C093B", "~. c #4E0622", "{. c #981146", "]. c #750832", "^. c #730932", "/. c #950D41", "(. c #47071F", "_. c #8F0C3E", ":. c #5C0023", "<. c #AE466E", "[. c #53293A", "}. c #98003B", "|. c #940B40", "1. c #8E0A3D", "2. c #41041C", "3. c #9D0C44", "4. c #4E0421", "5. c #960B41", "6. c #970B41", "7. c #6F082F", "8. c #780833", "9. c #89093B", "0. c #88093A", "a. c #850939", "b. c #600629", "c. c #830938", "d. c #7E0936", "e. c #600729", "f. c #93053C", "g. c #670226", "h. c #840939", "i. c #7F0837", "j. c #350317", "k. c #800837", "l. c #520623", "m. c #7F0936", "n. c #40031A", "o. c #730731", "p. c #250210", "q. c #750732", "r. c #740832", "s. c #48051F", "t. c #280110", "u. c #6E072E", "v. c #310315", "w. c #730831", "x. c #35091A", "y. c #45041D", "z. c #550F2B", "A. c #46041D", "B. c #4C0520", "C. c #360317", "D. c #4D0420", "E. c #900B3E", "F. c #6B0C31", "G. c #9B1348", "H. c #960A40", "I. c #6F0730", "J. c #5E1632", "K. c #9B1549", "L. c #990B41", "M. c #27000F", "N. c #521A30", "O. c #351923", "P. c #B7416E", "Q. c #91093D", "R. c #73052F", "S. c #9A345B", "T. c #92073D", "U. c #910A3F", "V. c #540422", "W. c #A42F5C", "X. c #93073D", "Y. c #65072B", "Z. c #870A3A", "`. c #40041B", " + c #93093F", ".+ c #570424", "++ c #78163B", "@+ c #5F0224", "#+ c #402D34", "$+ c #9B033E", "%+ c #7A0834", "&+ c #7F0735", "*+ c #540523", "=+ c #6D072E", "-+ c #970A41", ";+ c #920A3F", ">+ c #830838", ",+ c #8F0A3D", "'+ c #4B0420", ")+ c #760832", "!+ c #5A0324", "~+ c #490A22", "{+ c #87083A", "]+ c #7E0836", "^+ c #320316", "/+ c #69072C", "(+ c #6B072D", "_+ c #3D041A", ":+ c #900A3D", "<+ c #940B3F", "[+ c #43041C", "}+ c #64072B", "|+ c #710730", "1+ c #3D0319", "2+ c #28000F", "3+ c #62062A", "4+ c #45051D", "5+ c #22020E", "6+ c #350013", "7+ c #2A0211", "8+ c #330315", "9+ c #5C0727", "0+ c #60092B", "a+ c #7E0835", "b+ c #45051E", "c+ c #64062B", "d+ c #370116", "e+ c #2E0213", "f+ c #7E103B", "g+ c #A02C59", "h+ c #7A0733", "i+ c #820938", "j+ c #610327", "k+ c #B03B69", "l+ c #55162D", "m+ c #953459", "n+ c #8F073C", "o+ c #4A0721", "p+ c #98194A", "q+ c #93093E", "r+ c #63072A", "s+ c #6E0930", "t+ c #AB476E", "u+ c #94083D", "v+ c #4E0723", "w+ c #9B1247", "x+ c #830937", "y+ c #43031C", "z+ c #9D0D44", "A+ c #58011F", "B+ c #6C0027", "C+ c #990B42", "D+ c #750833", "E+ c #870939", "F+ c #930B40", "G+ c #5F0528", "H+ c #65062B", "I+ c #350519", "J+ c #3B0218", "K+ c #390318", "L+ c #550524", "M+ c #63072B", "N+ c #980B42", "O+ c #7B0834", "P+ c #340316", "Q+ c #3E031A", "R+ c #2B0010", "S+ c #661E3A", "T+ c #560726", "U+ c #3F0117", "V+ c #A02857", "W+ c #9A0940", "X+ c #41041B", "Y+ c #401123", "Z+ c #510422", "`+ c #370418", " @ c #5B0425", ".@ c #79133A", "+@ c #A00A44", "@@ c #6E042D", "#@ c #802A4B", "$@ c #9B0E44", "%@ c #8A0539", "&@ c #9E184C", "*@ c #590526", "=@ c #971446", "-@ c #960940", ";@ c #400C20", ">@ c #9B2453", ",@ c #880839", "'@ c #870D3D", ")@ c #940A3F", "!@ c #47031D", "~@ c #760732", "{@ c #481227", "]@ c #670128", "^@ c #800B39", "/@ c #6D082F", "(@ c #9C0B43", "_@ c #560424", ":@ c #68062C", "<@ c #40051C", "[@ c #530E29", "}@ c #41031B", "|@ c #610326", "1@ c #850A39", "2@ c #42061C", "3@ c #680029", "4@ c #4D0421", "5@ c #700731", "6@ c #800836", "7@ c #45031D", "8@ c #883856", "9@ c #660329", "0@ c #68082D", "a@ c #9C174A", "b@ c #921E4A", "c@ c #56001F", "d@ c #BA4E77", "e@ c #67032A", "f@ c #5C1E35", "g@ c #580525", "h@ c #42041C", "i@ c #810938", "j@ c #44041D", "k@ c #740831", "l@ c #330214", "m@ c #4F0823", "n@ c #7A0130", "o@ c #2B000E", "p@ c #8F073B", "q@ c #4A021F", "r@ c #A22354", "s@ c #9D0B43", "t@ c #40031B", "u@ c #810736", "v@ c #191013", "w@ c #422F36", "x@ c #461529", "y@ c #3F031A", "z@ c #5C0628", "A@ c #67062B", "B@ c #5B0526", "C@ c #A40A46", "D@ c #7F0535", "E@ c #A9124C", "F@ c #590425", "G@ c #7C0735", "H@ c #890739", "I@ c #371A25", "J@ c #230913", "K@ c #460B22", "L@ c #131615", "M@ c #161716", "N@ c #1B181A", " ", " . + @ # ", " $ % & * = - ; ", " > , ' ) ! ~ { ] ^ ", " / ( _ : < [ } | 1 2 3 4 ", " 5 6 7 8 9 0 a b c d e f g h i j k l ", " m n o p d q r s t u v w x y z A B C ", " D E F G H I J K L M N O P Q R S 0 T ", " U V W X Y Z ` ...+.@.#.$.%.&.e *.=. ", " -.;.>.,.'.).!.~.{.u ].^./.n 0 (._.M :.<. ", " [.}.|.1.2.3.v 4.5.6.7.8.9.0.a.b.c.d.e.f. ", " g.h.i.j.8.k.l.m.n.o.p.q.r.s.t.u.v.w.q. ", " x.N y.z.A.B.C.D.E.: F.G.H.I.J.K.L.M.N. ", " O.P.Q.R.S.T.U.V.W.X.Y.Z.|.|.H.`.1. +.+++@+ ", " #+$+|.%+&+|.1.*+X.q =+].-+;+>+`.,+E '+)+!+ ", " ~+{+]+^+/+(+_+:+<+0.[+}+|+1+2+3+4+5+6+ ", " 7+8+: 9+0+a+b+V c+d+e.e+f+g+h+i+j+k+l+ ", " m+n+ .o+p+q+v r+s+t+u+,+v+w+0 x+y+z+A+ ", " B+q C+y.Q.|.0 D+E+F+u :+2.,+0.G+H+)+I+ ", " J+K+w.,+E+L+M+N+M O+P+Q+R+S+T+U+ ", " V+W+X+Z Y+Z+`+ @b.X+.@+@@@#@$@%@ ", " &@n .*@=@-@;@>@,@z '@)@q.!@~@{@ ", " ]@^@(+_+/@r _+(@;+)+_@:@<@[@}@ ", " |@1@2@3@4@5@6@7@8@9@0@a@>+ ", " b@n+c@d@e@f@g@h@H.i@j@k@l@ ", " m@n@o@p@q@r@s@j@t@K+u@v@ ", " w@x@y@z@A@L B@C@D@ ", " E@H.F@G@H@I@ ", " J@K@L@M@N@ ", " ", " ", " "}; barry-0.18.5/desktop/images/apploader-normal.png0000644001161500056700000003375312242254476021150 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIMEctEXtCommentCreated with The GIMPd%n IDATx}]u^g=x"DDBy$HqxHH  ^'^$PAHBX A$Bpd@C}眵>g<]R)wwUݺ9{^;xu:^xu:^xu:^k}÷?XD|GD|xň?6AD|9ĶA"j~um~u|~}wK}r֓}_}[>+ϭO*?! k"E#zߑ`D:"kw ,:M+>;?|W Xܯ˯N{Ys4-aY~g~~Y~~^—>~:}O%7\fxv⣮Yy(`*R&>Ʀ:uX% 16-E8 i7{ߟ'a-S=xQ&P|NeqmyNR?3`NNI#7IXQ)1V@y .bM|CW%c=y=B0N񩐔kK+AKߏOu:3D,ߓR` ٿQS@4ksmQ\=wwE&1R(|ĩM6NN?cQBmNx'faa9\ˁ#zyHsA6a, } Y~"{_^!@\zEzn:i^_7bAiy7a~XhW!\ߕm 9786ɒRŌ3V1dʢk/Ru njH^8Qm ۳?O~kBR$E4д *xdd% kt;{ȍ7M߱[AHM [B_'* Tـ|?"Gȷ9ҕB*K߂yh!LqRХK@!2mVzDw۩;`DIykH"8U׎ t&ƒ 8}=e^l2\ID) 4d;Ƕ 2#i8>sF66 \`&t|F$EԎ҆Sչf$)q?(0֪D~P!sbJD-ICv:;W21FqBД* $+d F 2(#v5i>S&AI![\wމj?LhTbd ͋rC1a?=sT ~s̋(;n:ꋦyKl!~"G2LJjxatN e+&9dB1t)B@PPB.5oi3ZO5hkFI fǥG$ѻ' (9*dQBR N4Ȱ[20qLA ̛)b *1( jp`JfNBH5Iy+MJ'kļ~LL%b<~&(,‘iq3-(uT%us=^sƭh2ѷ8Xh\ 4"H $7+YaJU)f@^-lMQeVZ*k ZzϪBvmjn QQA yKFĴ?UR24xY+KK*>pS$aX,US<"X6ET|]j!H.S'GIM?]X<{j` 6Jܘ”0rax4Mp{k9:P Ɉڔ N ,^n*kz԰6c":p 2eB 22?o0/J6XNT[=&w&6 MB ٮ\tS9.L҈$h }GX>ᔿRym1- XX$kT6hg`H`shBGi@KBkTy2E,6kS BRE&IZRbF;RE] >"3F QsH2<)Ifs :3$q&!7wݿ]HL+,hvm`0^H%ɦAYXkS̐F(1!̀zXQ"mYR<ʄAJc;&g W@\3`u@u_fMxkFX"wx2pv Qk A0W@)FgV \P3)4&!o eG%>D>&:*COEdXFø_ >@D)'5jpA~JU'yuFZ =o,Z̴Fj7>4X68){MƼAu&L2Y>#l4#X%GJ\L;y*krA"w V4"q}SJ?fкo ٞs$zbɸ ^*Q!7ZP#noHFY{t#) $ !ըpDkC1eH/]"BP"J%Tڴ]2\"oA1aJ= L=(է=kE'(-+<'ǐV \%3BŠ/WA(V7XpѼTRR^mS$0A6sYGRWf655an$7џănkڠΡɢ5&!Y7X:A= MguܨaҷIJ*qlKc(^li`KAU5n}N2 F߷׎S?S6O"D1KS*سB&! u@&C8'tZuSPnGa1~s)<mnr;iKNeT't d+! ,)>kMiijR!j=D;a,LBEHӢG7#SʔBrd5:@S>YüHdYKi¿Z9De4wb=O+]ڝaDZʪ .-!*[*rh2l8XVƵoo=iuP]IM7EsܕmM GuV'x&8;nIz[aqϩQ6;ȍgxIal-C%zșԐ<яI뺠Q#tdM6I.4dv-rnj t2=@.~# vvUmW2WWx4 a'rSU9mR>3Y9hG^R2w"y0N&$Ngced#jALퟙä4ZTR8MD ˦T!XwK(Z&qkP^^* ЊRjuhT35v$a/hJ Ԟ@Ԋ럱xm##{nijڪʼnk_o9YsZ2;hٳ:3Jn(J({7E J뢴~0*8}OͶ-T+!h 4ck렅las$С"?{yyY/q/*R,fw0a"Q(gQNJ>vP&A!ْ~=H?hIEEeE]usߵNnO{ͱHgBj`+b7ɿ\+l9䥧89;TdV !A-I5"%XЈZ,`lNx#j T& $Ǩ?zzNޭ/'~O&5$n,rMt ?Wd })]戈vvyEnf1p3(hSlguC>jqqt ~8gătƷh/{<|x܄Ebn}D~wzi|W_{3ƛݖ??ٵODkx17/Oӿ)8BFPIr ""Osja!V&E^0lΊ䘭,nGsjKL$Ir@ TW03p3) =4OWuOT}3kX~,/w񽟏?[;|]+#ߎ蝟|Jt-:3+0Sd `aM2ȞvR@of`mH T}}BuE5p$lFk εN遥9 #5 jB_=ğ|裁ǸؿEf]]Dsx#/]\oĹtԢ*Ua *5wlRdRi&qu%FW|8lFEx"C5{L: Qbta ~>W#iD^D䫱E̸x#.߸WŽt?V\- 禭R}`5|@D8gy,z ȭn!t*< Rʍ^"O!H)ʓzT[ktmGi ~Hôݍ$}m@OYq!: Y'KX[SXWF#x rn%ϒ+<̷rw;vqq va\<.wӈ['5yhJ͆$Tq;i1b”lB)CrV7}5.kgxW,1Qca<`5ٷ`Q=ҮknnjZv-P^edz׾)./^w>~!}.>|o;3iDN^Dc7k1-frʸHiutI M.B&@p,:3%fZ-=dt%SS<>#ծQL )1w3b4 qa㽱۷gr8y_wośCܹB:=\ƭ[8xQ5mX E:>F:^ 4'= iC 4!UNIRd&Moes'h8P*-Yβp>fyoD5{uL@mj\k<8{xnQD}ݗ#vĭ}8i@-^ӓ9^#H qgBvf UG8ؔP(;AS`ctWDG(3_I~}7X#No9YT<Ά,:/ \ߒ&9ƃ@sfX23u#zr 8<|89$hŭӈۧ''&e܊}q@,i|c S$kU{:%(RQ"a1lx?!܁9k\fbl3*I3=Kjڦ^3! 90IEgisKX| ֟(6SUnLJ^ݸ}O899ݫ۷_vh(2'$nʼnx> khjD 2:,I:4ۧzu,) ߻'ܮjY͙2@\. *jnn9f {^C( S 49r9x='T֜P dމ3/Ž;?yFEm֜7L|$?sLfIE ev{Tm@҆\=θXn w ;‘*}exl:YY%F>OI5 yXv-+-wxx+?`akG\N;ܳwby" nF4/*)Rԩ.Q{F:,Lo>Kf3׹(h<SRC'ܳwgW}Rx2F8?)cV&rrF_¦bm1%uO#ըXZEH8 flKo%b?0?/Et/e>U[K+cbUb:fI3F rq o  B0yqbRyP&%Ku,{DHWKS]%CMZ1nm?G6d^+vX ހFK/ &(ћFss(f CBZ*PJM@v_LÿM}׾n&Ϡ(,㘝qug,[P;TF29d#LYG\ ϑieDETu4Sy4q_q f 1t /I%H4.4\Cܖ 'J0P>  RuQVeaP=l})VЯˤw\ٵcdi(GJAJ}$)ǤSH/FUؠڬS2}Vi̓dCbhCm@Y4 ك Ajcԭ<6IDAT"C97inJOA(DlTƜKw2 ":&ZdSx͇qNn2YtjwA͗7K8)蟏L.2;?F5x BA q#\b#Cda'(z9өA6b^ ba4|ņ'Oq1o>_m$^iOnejd@GKS{Sjs"˿Hϣ 0 z^s:'!|XjkXOΤw bY B "'AG~%nݿ-o;'/`?hJc˵YpΏƦ2:W\[N;O%z?YurHhR#dA j Lhʑk+zAsA%x\- 1a"Kx}vA=,j(Ƕ9as.luΨ 0f)*lU ΃baUac̏ JsoB͔R *x@:@и(yݾy`q:%F;Q$h=*myn[owk{_=`NZ7´L6UHZ뜾{ T1Z(m[`?'q7ĵ:g2ۂw2ǭr%$IM=Ej[y؎ʢ? U(gsrv/}}|W>wyH]|y~{ݫ%]:]n}+ZX+{}JEoqҹD,~NWƀL0Zhc,:SE'ζRy=/uDxeQ~`7k@}  )+.Y%znƗ_=}ߋo+}1k"<^7%N{,V>ƺ^ΕM*&Y.ý)QaFy1}Wڣ,I޼P;MR`Sv珤g0QSNXG4BR*IIܪLMjN{|oϓu7ܧ۷o?zoC/?xgn5-Iپw 2ЖjMXo$0PnHDṒd45'3Zxahhabm7*5bitE{wۿoxx}⼭*Mz"w=} ݅AՅwlq%ـJ9rNYGUo8cf˜.ww"ʹp7ăTP|Tm`5fZ#3gw/߿ٜC_& jm?^!jW%𪩷XotcDy"#z:2[WSK2A̞+S=R'm!mlOZ)-Ogf 3lWnRfT7 G&M-+ 1u(wU:y,dFeG4_ DhH| dtG20ydUj咺9SMF@t9)[Vߴ@6gE@Jcp]Mu1_+D ʤ`R+A_.j3 럡8|@T@٘/A_C3!D)ɚl9\]´akz)|1Z0w~(4\P3+98@|tɸ¬b&)<&cy1zKMR֏?BSm)EIX9O-#aʇ5)&ԹD2%Xe >u16uZ+`P72Fe E'-JJ v/|nnF!B kpnI=,kF*{iJE"(0#b1xlFR XJ2Ů-k@*Gò8uSs<E.|4 x#?PڦwOHHjh*}l+/HqsR *X:NSٵV&yޅ-8;ú])sIE}ʨynh m{X Q J$O=`J;b(!$4[$7KrPx3&L3InnIG Hai9CO,}"Di20fWw0TLQ@e{r퀇eq(.q,lr+h AZh|ce~CjAf΅osǚdQؚ!ޔ PUjiPX&wK멆!>sL.2 AF節FR! n 2@_,ukHdMz)ܭр,썈IYgV&ג\ChrhW(c 8K3\>  =` …VB\̑vڱ/ aɐһ) A+h8ǜ[k$/)ָ8qJU$ה/o.\ԎdP)Jj4ђ< zŬzXe I싴 Ej5gvA&ZMc_1)@Ԑ.Oo0N¬SZ;ZI/d5+932aR_3Id%mĮ*$KDh( a#(:΋90H+dž* c0] G0߈^E&w:}x3`м.`E)wKr$73aJI3DqZ;Üݱ :/u$dN[K{PVcw0RahU*D}.ׇ` / >qwHK0w{IsMzޟxU"q y=Q'j8g a[kXtw;8$QNe#JWZ)5ZشX4"[.aO#W%<[ύu֞)fTUp L(l& 6 /h5 ŋeplr^B2uj7@21I: ifcQ0 2Fr>edkij} ( LN[L/-313Cv4C}^e%v7nIN2ISz5ɖX0_ZYS&΍@I&Uj6|v 8˗6V^TK]\ Acaşa՝ ^Rê A?2YSg\NȏrQRnVKf+> HOQƍPM_@<7\ӃtUBr1[_SPPZ!?:fMXz`Hx1IҗulETpe*zú IWSY!pZ^EDzar%Mz-M*, 0>{{lƁC^kәI Y}PmRt.{$m:84YHjǪAuaLQzl0q,': K+3" `C1b 2麓njF2뤇E}{b "P䐢 ΩI>m̀tY_h },sXMł5bl6փA>1ѰnVm2X^)/:tփ6(WAz ט.E6j \@.~7ܓ )b=sbxXt)ZtAV6@=-"LISXDB :F1^wRiBc7?db19Б Xh+Ҟ4LU/fL2cOYEb1L+l~1-\.Bẙ3{<>[;KyvuZT 4tcv_tIMPܢۡl: gD(* fg:ݶIO?0)\5Lb("|lC3mR{HpOKrDN6{`iU2!BA>?[3`FC4y` JHlB"CvA^cq"P1shf xs"MKK;BUEI@ܯA~3|敏:^vx]?<|_-;^_Cף6|&"x{<??]/Dă==^_##?~x+:^xu:^xu:^xבD3IENDB`barry-0.18.5/desktop/images/media-pushed.png0000644001161500056700000003517312242254476020256 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME4(K.[tEXtCommentCreated with The GIMPd%n IDATx}mU{gʼn qiIQ*HBET@CB4|O"* ~ _BmH AQBp0Ml?23s8yg D2U♹swgk{m^k{m^k{m^ϋ/?? U^ϓ_yV5o[<vL >޷=|_*ɇu9:o< <^%/o%@&$iɋd}`~~|~`._~~qw{h_3{v)b sxN_K7\yMV׈}~y$[P3cG75Y!ڃԅW{~DM,x[H!W^&:6zusd_\mS6|mقOo0|-ٳ/AYz)>"бu311{?@-t(b<=`B/}/".L'P胩3ȴy( }LD[uɂi1X5XO{N3 &m'dC+ltl2=r:tև~O>[7\ĸfP*&=ڦ 뎱!K7&'D[g<dqM)4}f"-z"6uh5qaWW/Q):ӭĎ~ ndz@od}l3d+|_a͒ ʂ\p*ߤB2 ̃AF%m]mbBv3kN/2wɭ,.Z=s眜'w8]ńRMg} 'FDa]`L_B0~^Ǣ0I|s6) lsY/QJ6|[Y>?pubؘ `217%fb Dԅ({>)Me.QapX-{9;,>*ܟi pșδ%a7Uژ7_XlŴD6u܉X̢P:+}mܐP ;\:|r}ЖSdO[t{S:ndӓgY8kɅ*! hlA:n1}ZlܻX vT&\ܭXAAbNH3.gdu,S?cIҢlOxmGX T Q~扢4\|t.=$/K4HYa:2B4H;:bYĂ3-IXHIݗtrl…l!I  OcY&VF]ĤͲih +ZPn2'~Y I1R#*!94. }$Hp<64IEvі%~( n.LEuC1AjgЀĔ@)-64"SWm,f񙜏%*SbYPMTkM[|qiwiȐ9:LTCpqej.$xn҂|Һ%,0XjՈ5(|~gX"/`[`X n4_$n Lx[d˽XPxE>v״=#C,qt q|PVF" d?$a6qV.&u#=1HC5P A(C\C">'ZOL^ÚS%;ĵˠc0;Ly!T,W3.cLX].X% IƳd7(eYsONĬB}t7@Q/ KC3BF,a1_?KڐX٢5ĉ =1}rW_!hqZ$FȒk6LK_؍vCjҩ qO"z:3E'E1" Ů@BXP(l`O~CcźmMX5NyX,t>D8^3LTFvK^DGGH^i^e cXNkwy5݊k҉alf[Z@]hnn+֡'͒3Z(RsTe6 kF.fc U& H@Ȟ,yA@-2l!5sd)oN$E't$$6ŝ $\Kx@~Ew&9${iEwK=8\GgRusδE\62-kgc]c$>Ă#+\,(c,Kt2pGZxv=h\ zS{!vm)]DaD3NެGjIdbTٰdlYf9Ͷ3RT@B0@.XNp8p3ỳ9(3X;qd;HJY]blD"BY. in/; AO1Q)MpE5Ӊ'⶘&FAN s8Rhl\CbL-ѐ@hȺ:@C6tV͊LuWghLRPVj12956d[y AwxH2ҖK`^pRxsx84ԐߠBL.!m(Hc̱9 _r|k6篜![ P%7$),%#2)1s- <+^Oc% H䙙)MhX Nz-s5I%!e 9Ys`'X:[(͊LtYGhD JPʝdWƽ͸XLCHeLu? J. ;9ItNrA8jzҋ%ݢeIb puJ!{֧]^HSMgJQUtʳBK6Y eRâpBQ:Nڏ ɿaO ni8;/{g=M>A Ȯe>µVWCH^C0ڽbۜ􂠺n.4Fx/pj[|l Q&R1I"'툔ZLǯ$V)"YL|s^Hn҂`4EhbS]q6FGO%-+iZ"8Dlq-,e墢3KO:_+&Z S}1-Q -L]=i/!jK)Թ) Z7sbqM1sMVm^]OJw5'+Weh,7Pk@͌sV {QI &a$,qFUs#$rXgvV!,!R,J cLv)F6~lDXk>2{H=<lS\ JcYnyp9 v7/T& 6W#Ks`NrEѼs{&rh_`VKVfq,j*/3ڠGH | u6K AX2RQ'(ٝhR$6>J4c =)U<c/Rem"-jDVJ+[ܘ(͵ةP]`-[jZhw7pl/3^C}رFYdXӘrH#O|jҫ̵@zO"ʛl)[2^oLSE‹T˕_""nBv~{bZ&(אۢi*G!fqڬ%QhtNrH#i&JE7mDPMO:\,p&5teOdYFv]JS@#'1$Q<"<1@c $}3 *sFv]nro 7[#rEi&-H}AL`'1fUBM-kꎨƄgՅ]MnL<"9Y .0L - WLrH=ciRR6Y$Rֆ(2斻edfqqɵ׋>Z=%aK80X6Arw1Hps3)m5 \~g=4=#"[RB/%hb)jQ6h骾@`t:ɏ<](9i6JL48<:#} !<ŧ E^>/$jK¢3QǬ ]j9{8t_{w}ϟ 1&ILFX*ښ:Jj++j7q@HI=A˄6n%}f9c) q׈ hu m(‚ga@9W=P@´4㋞5;<< ._?8~a4Kq 7ߊ}7o$iɯT11 +WU`Ou3Ŕ@ 8@GR-\:o> Dי*,r&*rrRTsrM,,)P,l=ꞝm݆K.駟#Ν;;ԧp?ޅџ= Ӿ]b&z)[3vɦb*|cjLA'jf'Z{}2k2;殎aY} )Κl2He9=-xb4dIQ+ZpAK ];pYbwwGGGtx8v"|$WT  Z!,E۩nyCh~ȃ}E5) escۂґIMO[j[Vi3E>ǒw Ǹk;,C@&p y !%?7 ʨ {;`NǮ8~8Hɓxӛބn ;;;g{{{? .'Nӧ_yG֠?,%d!Cy Tx>AZtLۄki ~-W}vFR$KPC.G갫n?m3DzutƵ"(` 6^l "a_FYfU/ƀx[Dgg`w2.|#?;8<.\xgϞ!N8EKxWCR$P弅CLin AvnݳJhg^wC)]'h,kP` Z͉My^5#SuXm3_K秋zb'ĩSOӧqxx .駟ƕ+WpIRp1'.Sf f{22j5PXX6sݿ Zc~snqD{`9)ZZ3&ǪIp牄+Mqta@ ü°6G.&ˍImyy^5xѧptt+Wx)?~ǎ^6gϞ[ Z*7.61XdծOMg^~Jd [ZΨSZr&A׫ ݁Ҧ5Yjq(R W.,#6V0eAiȍbt>Js ¡Ҿӕ*~r vvvpy<8::-k.Ξ=3g$磸棔X#rlE/$&^ZYQ`LZ'E^ȏȊ͌/C$+|l #U~]e3As.W Ȋ_"3 zytS 1ٮĘښןo Nm݆Ǐcooǎ.pplwA&.KuR&9FYWMжarsE9V>cX+NE[ O.]N:7\-7=| ן<7vO|WS}G|Ai*/d*s0a6:dse'*d<)pe l1n`ж-Z+6HZ/)D=pDL8g iΕ I#=w]C=;aoǗp_3<_M?;']=]v̭MnX4hY2R헳MbJc-{N$N1#R;'Lh[pŒ[IDATT5if:IrP[x# :n؂t)INͱ9Sܝ9S4EwRO%px!` xYh>|G5U3x)|/? D@8uѺi*ֲTvtDGhJ)(gԕTTrBmܣ{}66W_YpN0`Z)Gu//8{f_{W7\O\< 3 UQ$J5ZTnT"9)JLC@PTKkEJՖe"p1/A8uxo՜NK0(g${ꂝ*9."c2-#.~Jd/LlAhnq@zsԭj@rC5uI!raNWzX xl[ź@LE5¤J 7\]TuRb ` ne; Crx+?C~򧁅nRJ\SOM/ۨ 1PlҺF]GHb-6(7;tv5}C_kH^i&g݅bwiS!l^0l>|EUƤ H)9 {0wz\Ư?x#Ї/5w_zzر;څ_| yNH֘I]Agnd+*(H# nSG>?rrҞCapk*g 3x&DulJH"'Փ*-h?ұ@8 .$bb)GqZ-/>p7/~^W߶ܺ+O~}#;; \K+8< \>'fr2RkZ*p$"xDnm2śjiDodDY}jERGyƘ@@jmJp$Ǻ& }MyDp0(*8] EUR^΁/'Ưƫ_x]O>|׷\v<}g~{WqԬb w4o)*Dj*JT(B)/0"U[)RAA6CO5sEy@"{xYA6&I8(5-e=WD$nZMF JmQ%勪Dz@w z=>|ׯu߾k< KSr߷r̙pI\x!nvvqtL]LcBYmy&D/Z\xT @zӡ*^sNMXVgɒ:wJTkC{?A.Pc2D)%uIfңhm9}FiUҟuI *nSt}-P+Ghқ#hHV=)L]vCBmXcդK  -"!"a'èkPՠpÍA7ſ§?;?_e?{/Oݎ_V{9zrˋW&HYIF:^֓p83J[n+q?3.僦cDZwΞ 7gΜkJdH B⌔DLzdT!ExsroS9 ru/՝Jzp8e*nf($|_IJ7Z,Nq5%<5)}{ɓ;y W.gpzc8qbǎi&cF{xwْAI(ȃH/]j>{f3\j:KkwbuWbR%EK,9ö9rg`h+FS9"3ʼn[Af ӧq 8Y$!wW2o+ڂO"{U%kI[,iavGn -z~b IOs(i+B9Uʲp! k%1+0zE)_va"6L5aq.o#"E곸HYUMMX֜Jʃ`m(7sD(Nc?^`ujF7Ƃ[*(X֐cZ2M[ ~+Л$u]vN^OTK򝱋m?[M=#b:LzqcHϐF(:ҦlM+S 44&h"f-($)G]#jşh !83Wpfk ި *'w)7l: yI5 G ǜU,Ýf2b)a@f)1%Ȓ %D?!YYKi 3kMVL}UB{G#S$G0KLnwT=M-jσ;&awcu˂5F2[V`wTZ¼H'5`A@%39}f'^-AQV}FQ[*x'57^sp@e+T~!5Sbe{gdQ>#^YXM{k]OyI[sd~ݕ 2I5Ub_-DLz3:HdI*I P3Kq3s'khhF] 1x3w"Kp?(f9ȖH$tAl3z,`Bo!_:= "(WXT)Vێré:yMN"B9Ay8RN $hWjysmw(/6 FFXG'stH̨`PUy̲E.Qmj%pURI>kj}A:"(SD[n9A,/me#4t1d,at>4ԆAܥ~wb>b")˔q ݆g}0Y؎kvz#T>*} *+=__E!IEYr]+ؘ!'G+F[]:yVDQ Ka}m20Ndk=Q$/v x`ư!%lK&5]xU~¿,j N.4a!u(5~ǺO,u"d˧50śM8Zi L:xnsBКQ Nl)U0} Cv7;%-7feN{c6P\ӌ(w&w],YQT9gp`J_\Pm-9bsRi6&- OT dbo0kr冸k%EHa9akqe,B`ul[PN 8 p041)Փy%Ϯ%7d]U2x?Nt/zhk2b͉IBhI/ FvT{ew8qb I qR$:i>a ܒsl\: /C]A<|2. 5 XCw󍙴,XGEvY~ErfSO ,z*z< XoPއ*][bΌ0a% d!LӢ.E@ pmd4&/ p.P&]jo[";Rb׎K%NܔFEhgXЫ_{ZkYN/iiHadEKDw+} Z˙ؐ , }RǘJÑwB$5Rݢl,^zktfF#J;BiB߸$Kݘeg@f])!XU\kH:Wژ I.֏.(ŭY,#'Fvvթf-7,7YAsg]!~*ށ$IW]-Swmbt&7$dENcI9Īuےz+1Dr&)ZI}sì2nJZQ 5)(k2vj3):jAj[:`!5m6僑ytf4,V ?5C:l*8cQ̄# |< A*E^b =3*8Xda7E![:cAYǬSrCZr`=%2tPEg'LcgSϴxf,sb Sl1."%8Lzs?ݮ _k o,BYlP"(-ѭvoӬ=j ߒ2GExwb5zҤ"cs眬Xl օ YSi%"z6a(3KXZY vl%\$)0D5]fDPQi kC%R9154li;8JHSTf›Ն9(#R9fUX:1.ٟk{uv vznpy;yx]^omvwms{=Oe}o^k{m^k{m^k{x͒ЋIENDB`barry-0.18.5/desktop/images/logo_NetDirect.xpm0000644001161500056700000005657112242254476020637 0ustar cdfreycdfrey/* XPM */ static const char * logo_NetDirect_xpm[] = { "91 34 1096 2", " c None", ". c #9CBEDB", "+ c #9BBEDB", "@ c #9CBDDB", "# c #9BBDDB", "$ c #9BBDDA", "% c #A1BEDB", "& c #A6BFDC", "* c #AAC0DC", "= c #AFC0DD", "- c #B0C0DD", "; c #AEBFDC", "> c #ABBFDC", ", c #A8BFDC", "' c #A4BEDB", ") c #A1BDDB", "! c #9CBDDA", "~ c #A2BEDB", "{ c #AABFDC", "] c #B1C0DD", "^ c #B8C2DE", "/ c #BEC2DF", "( c #BDC2DE", "_ c #BAC2DE", ": c #B4C1DE", "< c #ABC0DC", "[ c #A5BFDC", "} c #9EBEDB", "| c #9FBEDB", "1 c #A8BEDC", "2 c #B9C2DE", "3 c #C1C3DF", "4 c #C7C4E0", "5 c #B7C1DE", "6 c #ADC0DC", "7 c #9CBFDB", "8 c #9CBFDC", "9 c #9CBEDC", "0 c #9DBEDB", "a c #9DBEDC", "b c #9DBFDB", "c c #9DBFDC", "d c #9BBEDA", "e c #9EBFDC", "f c #A7C0DC", "g c #B1C1DD", "h c #BBC2DF", "i c #C5C4E0", "j c #CAC4E0", "k c #C4C4E0", "l c #BAC2DF", "m c #B0C1DD", "n c #9EC0DB", "o c #9EC0DC", "p c #9FC0DC", "q c #9EC0DD", "r c #9FC0DD", "s c #9FC1DD", "t c #A0C0DD", "u c #A0C1DC", "v c #A0C0DC", "w c #A0C1DD", "x c #A1C1DD", "y c #A1C2DD", "z c #A1C2DC", "A c #A1C2DE", "B c #A2C2DD", "C c #9EBFDB", "D c #9FC1DC", "E c #A1C1DC", "F c #A3C1DD", "G c #ADC2DD", "H c #B8C2DF", "I c #C1C4E0", "J c #C3C4E0", "K c #B9C3DF", "L c #AEC1DD", "M c #A5C2DD", "N c #A2C2DE", "O c #A3C2DD", "P c #A3C2DE", "Q c #A3C2DC", "R c #A4C2DD", "S c #A6C2DE", "T c #A7C2DD", "U c #A8C2DE", "V c #A9C2DE", "W c #A8C2DD", "X c #A4C1DD", "Y c #A4C3DE", "Z c #A3C3DE", "` c #A4C3DF", " . c #A4C4DE", ".. c #A5C4DF", "+. c #A4C4DF", "@. c #A5C4DE", "#. c #A5C5DF", "$. c #A2C3DE", "%. c #A6C3DE", "&. c #B0C4DE", "*. c #BAC4DF", "=. c #CAC5E0", "-. c #CBC5E1", ";. c #C6C4E0", ">. c #BBC4DF", ",. c #B1C4DE", "'. c #A7C4DF", "). c #A6C5DE", "!. c #A6C4DF", "~. c #A6C5DF", "{. c #A7C5DF", "]. c #A7C4DE", "^. c #A9C4DE", "/. c #ACC4DF", "(. c #AEC5DF", "_. c #B0C4DF", ":. c #B4C5DF", "<. c #B9C4E0", "[. c #BFC5E0", "}. c #C8C5E0", "|. c #C9C5E0", "1. c #C6C5E0", "2. c #C1C5E0", "3. c #BAC4E0", "4. c #B1C5E0", "5. c #A8C5DE", "6. c #A8C6E0", "7. c #A8C6DF", "8. c #A9C6DF", "9. c #A8C7E0", "0. c #A9C6E0", "a. c #A9C7E0", "b. c #AAC7E0", "c. c #AAC7E1", "d. c #A7C5E0", "e. c #A7C6DF", "f. c #A8C5DF", "g. c #A9C7DF", "h. c #A9C5DE", "i. c #AFC5E0", "j. c #B9C5DF", "k. c #C3C5E0", "l. c #B6C5E0", "m. c #AEC6DF", "n. c #A9C8E0", "o. c #AAC8E0", "p. c #ABC7E0", "q. c #ABC8E1", "r. c #AAC8E1", "s. c #ABC8E0", "t. c #ACC8E1", "u. c #B3C7E0", "v. c #C0C5E1", "w. c #C8C5E1", "x. c #B9C6E0", "y. c #ACC8E0", "z. c #ACC9E1", "A. c #ADC9E2", "B. c #ADC9E1", "C. c #ADCAE1", "D. c #AECAE2", "E. c #AEC9E1", "F. c #AECAE1", "G. c #ACC9E2", "H. c #ADC8E0", "I. c #B6C7E0", "J. c #BFC5E1", "K. c #BFC6E1", "L. c #B5C7E0", "M. c #AFCBE1", "N. c #AECBE2", "O. c #AFCBE2", "P. c #AFCAE2", "Q. c #B0CBE2", "R. c #B0CBE3", "S. c #BAC8E1", "T. c #BEC7E1", "U. c #B1CCE3", "V. c #B1CCE2", "W. c #B2CCE3", "X. c #B2CDE3", "Y. c #B2CCE4", "Z. c #AFCBE3", "`. c #B0CCE2", " + c #B0CCE3", ".+ c #B1CBE2", "++ c #B2CAE2", "@+ c #BAC9E1", "#+ c #C2C7E1", "$+ c #C9C5E1", "%+ c #BFC7E1", "&+ c #B7CAE2", "*+ c #B1CDE3", "=+ c #A3B7D7", "-+ c #A0B2D5", ";+ c #B3CDE3", ">+ c #4A9BCE", ",+ c #067BC0", "'+ c #0A7DC1", ")+ c #B4CEE4", "!+ c #1481C3", "~+ c #3E95CB", "{+ c #B4CDE4", "]+ c #B3CEE4", "^+ c #B3CDE4", "/+ c #B5CEE4", "(+ c #C7C6E1", "_+ c #B5CFE4", ":+ c #B5CFE5", "<+ c #B5CEE5", "[+ c #B6CFE4", "}+ c #B6CFE5", "|+ c #A7C8E2", "1+ c #92BEDD", "2+ c #B7D0E5", "3+ c #B4CDE3", "4+ c #B3CEE3", "5+ c #B4CFE4", "6+ c #B5CEE3", "7+ c #BCCAE2", "8+ c #C4C7E1", "9+ c #CAC5E1", "0+ c #C2C7E2", "a+ c #BACCE2", "b+ c #B7D0E4", "c+ c #6A5EAA", "d+ c #5A479E", "e+ c #B6D0E4", "f+ c #B7CFE4", "g+ c #B7CFE5", "h+ c #479ACE", "i+ c #0078BF", "j+ c #047ABF", "k+ c #0F7FC2", "l+ c #3B94CB", "m+ c #B8D0E5", "n+ c #B8D0E6", "o+ c #B8D1E6", "p+ c #B8D1E5", "q+ c #B9D1E5", "r+ c #B9D1E6", "s+ c #C8C6E1", "t+ c #C7C7E1", "u+ c #B9D2E6", "v+ c #BAD1E5", "w+ c #BAD2E6", "x+ c #BAD1E6", "y+ c #BAD2E7", "z+ c #70AED6", "A+ c #97C1DE", "B+ c #BAD3E6", "C+ c #BBD3E6", "D+ c #BBD2E7", "E+ c #B9D0E5", "F+ c #BDCDE4", "G+ c #C4C9E2", "H+ c #C5C8E2", "I+ c #BECDE4", "J+ c #6B5FAA", "K+ c #BBD2E6", "L+ c #BBD3E7", "M+ c #BCD3E7", "N+ c #489BCE", "O+ c #9FC5E0", "P+ c #9DC4E0", "Q+ c #A7C9E2", "R+ c #BCD4E7", "S+ c #BDD3E6", "T+ c #BDD4E7", "U+ c #C0CFE5", "V+ c #C1CFE5", "W+ c #BED4E7", "X+ c #BDD5E7", "Y+ c #BED5E7", "Z+ c #BED4E8", "`+ c #BED5E8", " @ c #BFD5E8", ".@ c #72B0D7", "+@ c #9BC3E0", "@@ c #BCD3E6", "#@ c #BDD2E6", "$@ c #C3CBE4", "%@ c #C9C6E1", "&@ c #B8AFD5", "*@ c #9A8CC3", "=@ c #C5C2DF", "-@ c #A9A6D0", ";@ c #8079B8", ">@ c #7A74B5", ",@ c #8F91C4", "'@ c #B8CDE4", ")@ c #B6C9E2", "!@ c #8E90C4", "~@ c #807DBA", "{@ c #A3AED3", "]@ c #9296C7", "^@ c #5F4DA1", "/@ c #543E9A", "(@ c #9396C7", "_@ c #9FA8D0", ":@ c #C0D5E8", "<@ c #A9CAE3", "[@ c #61A7D3", "}@ c #499BCE", "|@ c #5FA6D3", "1@ c #4A9CCF", "2@ c #C0D6E8", "3@ c #7EB5D9", "4@ c #78B3D8", "5@ c #8FBEDE", "6@ c #B2CFE5", "7@ c #78B3D9", "8@ c #ADCCE4", "9@ c #A9CBE3", "0@ c #5DA6D2", "a@ c #5AA4D2", "b@ c #C2D3E6", "c@ c #99B2D9", "d@ c #5D9BCF", "e@ c #4C95CC", "f@ c #629DCF", "g@ c #A6B7DB", "h@ c #C4CEE5", "i@ c #C1D7E8", "j@ c #C2D7E9", "k@ c #C2D7E8", "l@ c #C1D6E8", "m@ c #8BBCDD", "n@ c #57A3D1", "o@ c #5BA5D2", "p@ c #92C0DE", "q@ c #7CB5DA", "r@ c #499CCF", "s@ c #62A8D4", "t@ c #79B3D9", "u@ c #BDD4E8", "v@ c #C3D8E9", "w@ c #BFD6E8", "x@ c #C0D6E9", "y@ c #C1D6E9", "z@ c #C2D1E6", "A@ c #C7CAE3", "B@ c #968BC2", "C@ c #492F92", "D@ c #8480BC", "E@ c #4B3193", "F@ c #5F4EA2", "G@ c #6454A5", "H@ c #C0D5E7", "I@ c #A9B5D7", "J@ c #543E99", "K@ c #4E3595", "L@ c #6252A4", "M@ c #533E9A", "N@ c #807BB9", "O@ c #9EA4CE", "P@ c #493092", "Q@ c #6C5EAA", "R@ c #C4D7E9", "S@ c #90BFDE", "T@ c #087CC0", "U@ c #2A8CC8", "V@ c #C4D9EA", "W@ c #107FC2", "X@ c #3F96CC", "Y@ c #9CC5E1", "Z@ c #6AACD6", "`@ c #0B7DC1", " # c #1983C3", ".# c #C5C5E1", "+# c #4592CB", "@# c #0178BF", "## c #68ABD5", "$# c #C5DAEB", "%# c #C6D9EA", "&# c #BDD5E8", "*# c #3793CB", "=# c #4299CD", "-# c #B5D1E7", ";# c #C7DAEA", "># c #C3D9E9", ",# c #C4D8E9", "'# c #C4D8EA", ")# c #C5D8EA", "!# c #C5D9EA", "~# c #C5D8E9", "{# c #C6D1E6", "]# c #C9C8E2", "^# c #C9CBE3", "/# c #C6D4E7", "(# c #9596C7", "_# c #59459D", ":# c #B4C1DD", "<# c #C6D9EB", "[# c #847FBB", "}# c #A6AED4", "|# c #C0D1E5", "1# c #56419B", "2# c #6554A5", "3# c #BDCCE3", "4# c #C7DAEB", "5# c #837EBB", "6# c #A1A7CF", "7# c #6E60AB", "8# c #5C499F", "9# c #BED5E9", "0# c #1281C3", "a# c #6BADD6", "b# c #83B9DC", "c# c #047AC0", "d# c #C8DBEB", "e# c #1080C2", "f# c #4097CD", "g# c #A0C7E2", "h# c #087BC0", "i# c #2586C5", "j# c #3C8FC9", "k# c #599ACE", "l# c #077AC0", "m# c #669FD0", "n# c #86AED7", "o# c #489BCF", "p# c #91C0DF", "q# c #CBDDEC", "r# c #4F9FD0", "s# c #57A3D2", "t# c #87BADD", "u# c #4B9DCF", "v# c #6BADD7", "w# c #85BADC", "x# c #4E9FD0", "y# c #69ACD6", "z# c #82B9DC", "A# c #CBDDED", "B# c #C8DCEB", "C# c #C9DCEB", "D# c #C9DBEB", "E# c #C7DBEA", "F# c #C9D2E7", "G# c #CAC8E2", "H# c #CACCE4", "I# c #CAD7E9", "J# c #C9DCEC", "K# c #CADCEC", "L# c #9899C8", "M# c #9A9CCA", "N# c #CADDEC", "O# c #B5C0DD", "P# c #9797C7", "Q# c #9797C8", "R# c #B3BCDB", "S# c #CADBEB", "T# c #5D499F", "U# c #7062AC", "V# c #CCDDEC", "W# c #CCDDED", "X# c #82B9DB", "Y# c #82B8DB", "Z# c #CCDEED", "`# c #CCDEEC", " $ c #1B85C5", ".$ c #4199CD", "+$ c #A3C9E3", "@$ c #0B7CC1", "#$ c #A3B9DB", "$$ c #BDBFDF", "%$ c #057AC0", "&$ c #6EA1D1", "*$ c #CCD1E6", "=$ c #CDDEED", "-$ c #CDDEEC", ";$ c #288CC8", ">$ c #3994CB", ",$ c #BCD6E9", "'$ c #0379BF", ")$ c #CFE0EE", "!$ c #CFE0ED", "~$ c #CEDEED", "{$ c #3190CA", "]$ c #0C7EC1", "^$ c #3693CB", "/$ c #7DB6DB", "($ c #A7CCE5", "_$ c #D0E0EE", ":$ c #CCDDEB", "<$ c #CCD5E8", "[$ c #CBC8E2", "}$ c #CBCBE3", "|$ c #CCD8EA", "1$ c #CDDFED", "2$ c #CEDFED", "3$ c #CDDFEE", "4$ c #9A9ACA", "5$ c #B6BFDC", "6$ c #CEDFEE", "7$ c #BBC6E1", "8$ c #9796C8", "9$ c #7B72B4", "0$ c #4A3092", "a$ c #8179B8", "b$ c #817AB9", "c$ c #817AB8", "d$ c #5C489E", "e$ c #523A97", "f$ c #D0E0ED", "g$ c #7163AD", "h$ c #5BA6D3", "i$ c #C4DBEB", "j$ c #D1E0EE", "k$ c #D1E1EE", "l$ c #56A3D2", "m$ c #1180C2", "n$ c #4399CE", "o$ c #A7CBE5", "p$ c #5799CE", "q$ c #90AFD7", "r$ c #308FC9", "s$ c #4199CE", "t$ c #4299CE", "u$ c #1A85C4", "v$ c #087CC1", "w$ c #92C1E0", "x$ c #94C3E1", "y$ c #D3E3EF", "z$ c #D3E2EF", "A$ c #D3E2F0", "B$ c #D4E2EF", "C$ c #80B8DB", "D$ c #ABCEE6", "E$ c #D4E2F0", "F$ c #D4E3EF", "G$ c #D0E1EE", "H$ c #CFDBEB", "I$ c #CCCBE4", "J$ c #CBC7E2", "K$ c #CED7E9", "L$ c #D1E0ED", "M$ c #D2E2EE", "N$ c #D1E1EF", "O$ c #D2E1EF", "P$ c #D2E2EF", "Q$ c #9C9CCA", "R$ c #C0C9E2", "S$ c #9A98C8", "T$ c #766AB0", "U$ c #6553A5", "V$ c #D2E1ED", "W$ c #7264AD", "X$ c #5E4A9F", "Y$ c #D4E3F0", "Z$ c #0179BF", "`$ c #D5E3EF", " % c #D5E3F0", ".% c #63AAD6", "+% c #459ACE", "@% c #A7C5E2", "#% c #79A6D3", "$% c #85AED6", "%% c #7FB7DC", "&% c #A6CCE4", "*% c #D7E5F0", "=% c #D7E5F1", "-% c #D8E5F1", ";% c #D8E6F1", ">% c #81BADC", ",% c #AED1E7", "'% c #D4E4F0", ")% c #CFD4E8", "!% c #CECEE5", "~% c #D4E1EE", "{% c #D6E4F0", "]% c #D5E4F0", "^% c #D7E4F1", "/% c #9F9DCB", "(% c #BEC6E0", "_% c #D7E4F0", ":% c #D6E5F0", "<% c #C2CBE2", "[% c #9C9AC9", "}% c #8880BC", "|% c #4B3192", "1% c #D3E0EE", "2% c #D8E5F0", "3% c #7364AD", "4% c #5E4AA0", "5% c #D9E5F0", "6% c #D9E5F1", "7% c #6EB0D8", "8% c #B8D5E9", "9% c #D9E6F1", "0% c #D9E6F2", "a% c #4B9ED0", "b% c #D9E7F1", "c% c #1181C3", "d% c #4191CA", "e% c #A2B5DA", "f% c #7BA6D3", "g% c #D0CFE6", "h% c #D6E0EE", "i% c #A4CBE5", "j% c #99C6E2", "k% c #DBE7F1", "l% c #DBE7F2", "m% c #DBE8F2", "n% c #9EC8E4", "o% c #8DC0E0", "p% c #DCE8F2", "q% c #DCE7F2", "r% c #8BBEDF", "s% c #5EA8D5", "t% c #6FB0D9", "u% c #DCE8F3", "v% c #84BBDE", "w% c #B2D2E8", "x% c #DCE9F3", "y% c #DDE8F3", "z% c #D8E2F0", "A% c #CECCE5", "B% c #D1D6E9", "C% c #DAE7F1", "D% c #DAE6F2", "E% c #DAE7F2", "F% c #A29FCC", "G% c #C2C8E1", "H% c #C6CDE4", "I% c #9E9BCA", "J% c #B1B2D7", "K% c #A8A6D0", "L% c #DBE6F2", "M% c #6855A6", "N% c #7566AF", "O% c #7465AE", "P% c #5F4AA0", "Q% c #ACD0E7", "R% c #51A1D1", "S% c #DDE9F2", "T% c #BED8EB", "U% c #097DC1", "V% c #D4D7EA", "W% c #4291CA", "X% c #87BCDE", "Y% c #DEEAF3", "Z% c #1080C3", "`% c #439ACF", " & c #DFEAF4", ".& c #57A5D3", "+& c #1C86C6", "@& c #57A5D4", "#& c #0D7EC1", "$& c #3191CB", "%& c #D9E8F2", "&& c #E0EBF4", "*& c #CBE0EE", "=& c #1381C4", "-& c #4C9FD0", ";& c #87BDDF", ">& c #A3CBE5", ",& c #E1EBF4", "'& c #DDE9F3", ")& c #DAE4F0", "!& c #CDC9E3", "~& c #D5DAEB", "{& c #DEE9F3", "]& c #DEEAF4", "^& c #A4A0CD", "/& c #C5CAE2", "(& c #CAD0E5", "_& c #A19DCB", ":& c #DEE8F3", "<& c #6C5AA8", "[& c #513896", "}& c #A19DCA", "|& c #C5C9E2", "1& c #8276B6", "2& c #B3B2D6", "3& c #E0EBF3", "4& c #7B6DB2", "5& c #503896", "6& c #A8A4CF", "7& c #BCBDDC", "8& c #3E98CD", "9& c #298DC8", "0& c #479CCF", "a& c #0D7FC1", "b& c #107EC2", "c& c #4494CC", "d& c #ACC6E2", "e& c #89BEDF", "f& c #E3EDF5", "g& c #E3EDF4", "h& c #2189C7", "i& c #4A9ED0", "j& c #2088C7", "k& c #0479BF", "l& c #B3D4E9", "m& c #82BBDE", "n& c #499DD0", "o& c #067AC0", "p& c #B9D7EB", "q& c #E4EEF6", "r& c #9AC7E4", "s& c #057BC0", "t& c #1482C4", "u& c #D1E3F0", "v& c #E5EEF6", "w& c #E1ECF4", "x& c #E0EAF3", "y& c #CECBE4", "z& c #D4D4E9", "A& c #E2ECF5", "B& c #E2ECF4", "C& c #E3ECF4", "D& c #E2EDF5", "E& c #E3ECF5", "F& c #A7A2CE", "G& c #C9CDE4", "H& c #E4EDF5", "I& c #CED2E8", "J& c #A39ECC", "K& c #E4EDF6", "L& c #D8DEED", "M& c #7969B0", "N& c #523A98", "O& c #A5A0CD", "P& c #E5EEF5", "Q& c #B5B4D7", "R& c #523B98", "S& c #7463AD", "T& c #D5E6F2", "U& c #429ACF", "V& c #2887C6", "W& c #5698CD", "X& c #CDC8E2", "Y& c #B7D6EB", "Z& c #8CC0E0", "`& c #E6EFF6", " * c #E7F0F6", ".* c #E7EFF6", "+* c #E7EFF7", "@* c #8CC1E0", "#* c #1985C4", "$* c #A3CCE5", "%* c #E8F0F6", "&* c #88BEDF", "** c #1180C3", "=* c #1E87C6", "-* c #AACFE7", ";* c #E9F1F7", ">* c #E8F0F7", ",* c #E1EDF5", "'* c #459BCF", ")* c #D4E5F1", "!* c #D9DBEC", "~* c #E3EAF3", "{* c #E6EEF6", "]* c #E8EFF7", "^* c #E5EDF5", "/* c #E1E8F2", "(* c #E7EFF5", "_* c #E1E8F3", ":* c #E5ECF5", "<* c #D9DDEC", "[* c #C1C0DE", "}* c #E3E9F3", "|* c #E9F0F7", "1* c #E4E9F3", "2* c #E4EBF3", "3* c #E9F1F8", "4* c #E7EEF6", "5* c #DFE2EF", "6* c #B3C2E0", "7* c #91AFD7", "8* c #A3B6DA", "9* c #CDD1E7", "0* c #D8E0EF", "a* c #E0EDF4", "b* c #E4EEF5", "c* c #E9F0F6", "d* c #E7F0F7", "e* c #EBF2F8", "f* c #EBF2F7", "g* c #B9D8EB", "h* c #A7CEE7", "i* c #BBD9EC", "j* c #E8F1F7", "k* c #ECF3F9", "l* c #ECF2F8", "m* c #ECF2F9", "n* c #ECF3F8", "o* c #B8D7EB", "p* c #A8CFE7", "q* c #C0DCED", "r* c #EAF1F8", "s* c #EDF4F8", "t* c #EDF3F8", "u* c #DDEBF4", "v* c #C9E1EF", "w* c #D0E5F1", "x* c #EEF4F9", "y* c #EAF1F7", "z* c #D5D4E8", "A* c #E9EFF6", "B* c #EBF1F7", "C* c #EBF3F8", "D* c #EDF3F9", "E* c #EDF4F9", "F* c #EDF2F7", "G* c #E2E5F1", "H* c #D8D6E9", "I* c #CDC7E2", "J* c #CCC7E2", "K* c #D6D4E8", "L* c #E2E4F0", "M* c #ECF2F7", "N* c #EFF4F9", "O* c #EFF5F9", "P* c #EEF4FA", "Q* c #EEF5F9", "R* c #EFF4FA", "S* c #EFF5FA", "T* c #F0F5F9", "U* c #F0F5FA", "V* c #F0F6FA", "W* c #F1F5FA", "X* c #F1F6FA", "Y* c #F2F6FA", "Z* c #F2F7FB", "`* c #F2F7FA", " = c #EEF3F9", ".= c #E0E1EE", "+= c #DEDDED", "@= c #F0F6F9", "#= c #EFF4F8", "$= c #E4E5F1", "%= c #D8D5EA", "&= c #CEC9E3", "*= c #DAD8EA", "== c #E5E7F2", "-= c #F3F6FB", ";= c #F3F7FB", ">= c #F3F7FA", ",= c #F4F8FB", "'= c #F3F8FB", ")= c #F4F7FB", "!= c #F4F8FC", "~= c #B6AED5", "{= c #E0E0EE", "]= c #F5F8FC", "^= c #F5F9FB", "/= c #D2D0E6", "(= c #E6E6F1", "_= c #A297C9", ":= c #F5F9FC", "<= c #F6F8FC", "[= c #F6F9FC", "}= c #F6F9FB", "|= c #F3F6FA", "1= c #E1E1EF", "2= c #D9D7EA", "3= c #EDEEF5", "4= c #F4F7FA", "5= c #F5F8FB", "6= c #F4F9FB", "7= c #EEF1F7", "8= c #E2E2EF", "9= c #D6D3E8", "0= c #CCC6E1", "a= c #D4D0E6", "b= c #E0DFEE", "c= c #ECEDF6", "d= c #F7F9FC", "e= c #F7FAFC", "f= c #F6FAFC", "g= c #D0CCE4", "h= c #A397C8", "i= c #D8D5E9", "j= c #BDB6D8", "k= c #A69BCA", "l= c #E8E8F2", "m= c #E7E7F2", "n= c #A59BCA", "o= c #CCC8E2", "p= c #DCDAEB", "q= c #C2BDDC", "r= c #E9EAF4", "s= c #F8FAFD", "t= c #F0F1F7", "u= c #ACA2CE", "v= c #B1A8D1", "w= c #F6F8FA", "x= c #C8C3DE", "y= c #A599C9", "z= c #E1E0EE", "A= c #978BC2", "B= c #D2CEE4", "C= c #F5F6F9", "D= c #C3BDDC", "E= c #7B69B0", "F= c #A297C8", "G= c #C0B9DA", "H= c #F7F9FB", "I= c #B6ACD3", "J= c #ACA1CD", "K= c #C7C0DE", "L= c #B5ACD3", "M= c #BDB7D9", "N= c #EFF0F7", "O= c #B4ABD2", "P= c #F8F9FB", "Q= c #FBFCFD", "R= c #E7E6F2", "S= c #DBD8EB", "T= c #D2CEE5", "U= c #DDDBEC", "V= c #E5E4F0", "W= c #ECECF5", "X= c #F1F2F7", "Y= c #F4F6FA", "Z= c #F7FAFB", "`= c #F8FBFD", " - c #F8FAFC", ".- c #F9FBFD", "+- c #F8FBFC", "@- c #F5F7FB", "#- c #EAE9F3", "$- c #DEDBEC", "%- c #D1CCE4", "&- c #D1CCE5", "*- c #DDDAEC", "=- c #EAE8F3", "-- c #F6F7FA", ";- c #FAFCFD", ">- c #FAFCFE", ",- c #FBFCFE", "'- c #EBEBF4", ")- c #7A68AF", "!- c #E4E2F0", "~- c #7461AB", "{- c #A89DCB", "]- c #9F92C5", "^- c #D5CFE5", "/- c #8574B6", "(- c #8271B4", "_- c #7F6DB2", ":- c #A396C8", "<- c #9C8EC3", "[- c #BAB1D5", "}- c #A69ACA", "|- c #FCFDFE", "1- c #BBB3D6", "2- c #9283BD", "3- c #B9AFD5", "4- c #C3BCDB", "5- c #8877B7", "6- c #E2DEEE", "7- c #7664AD", "8- c #9A8BC2", "9- c #B8AED4", "0- c #9D91C5", "a- c #F3F2F8", "b- c #816FB3", "c- c #9586BF", "d- c #C5BEDC", "e- c #B3AAD1", "f- c #ADA2CE", "g- c #9081BC", "h- c #715DA9", "i- c #DEDAEB", "j- c #7662AC", "k- c #9788C1", "l- c #B8AFD4", "m- c #E7E4F1", "n- c #FFFEFF", "o- c #FBFDFE", "p- c #FBFDFD", "q- c #FCFCFD", "r- c #FAFBFC", "s- c #F7F6FB", "t- c #F1F2F8", "u- c #EFEEF6", "v- c #ECEBF5", "w- c #ECEAF4", "x- c #EDECF5", "y- c #EEEDF5", "z- c #EFEFF6", "A- c #F7F6FA", "B- c #F9FAFC", "C- c #FDFEFE", "D- c #FDFDFE", "E- c #F9FAFD", "F- c #E1DEEE", "G- c #D5D0E7", "H- c #D3CDE5", "I- c #DFDAEC", "J- c #F8F7FB", "K- c #FDFFFE", "L- c #FEFEFF", "M- c #FEFFFF", "N- c #FEFEFE", "O- c #FEFFFE", "P- c #FFFFFF", "Q- c #DFDBEC", "R- c #9687C0", "S- c #8473B5", "T- c #A194C6", "U- c #C5BCDC", "V- c #FDFCFD", "W- c #7966AE", "X- c #6E59A8", "Y- c #B2A8D1", "Z- c #A395C7", "`- c #A194C7", " ; c #BFB6D8", ".; c #D6D0E6", "+; c #A396C7", "@; c #EAE7F2", "#; c #B2A7D0", "$; c #7F6EB2", "%; c #AB9FCC", "&; c #7663AD", "*; c #BAB0D5", "=; c #9D90C4", "-; c #F3F1F8", ";; c #8270B4", ">; c #D7D1E7", ",; c #7B68B0", "'; c #A092C5", "); c #D5D0E6", "!; c #F8F7FA", "~; c #7D6BB1", "{; c #8776B7", "]; c #DAD5E8", "^; c #CEC7E1", "/; c #E1DCED", "(; c #D8D4E8", "_; c #E3DFEF", ":; c #FAFAFC", "<; c #9080BC", "[; c #8F80BC", "}; c #9B8CC2", "|; c #AFA4CF", "1; c #806EB3", "2; c #8574B5", "3; c #BBB2D6", "4; c #B5AAD2", "5; c #8D7DBB", "6; c #8C7CBA", "7; c #BDB4D7", "8; c #C8C0DE", "9; c #DBD6E9", "0; c #AEA3CE", "a; c #D7D1E6", "b; c #8270B3", "c; c #8676B6", "d; c #D3CDE4", "e; c #AA9ECB", "f; c #A79BCA", "g; c #D8D2E7", "h; c #7866AE", "i; c #9B8DC3", "j; c #9383BE", "k; c #9485BE", "l; c #E4E0EE", "m; c #CCC5E0", "n; c #8B7BB9", "o; c #9688C0", "p; c #C6BEDD", "q; c #8675B6", "r; c #DDD8EA", "s; c #F9F8FB", "t; c #E4E1EF", "u; c #DAD6E9", "v; c #CFCAE3", "w; c #D8D3E8", "x; c #EBE9F3", "y; c #F6F5FA", "z; c #C9C2DF", "A; c #FBFAFC", "B; c #F2F1F7", "C; c #E1DDEE", "D; c #D3CEE6", "E; c #D7D3E8", "F; c #F0EEF6", "G; c #FCFBFD", "H; c #F6F6FA", "I; c #F1EFF6", "J; c #E9E6F2", "K; c #E6E3F0", "L; c #E3E0EF", "M; c #E1DEED", "N; c #E2DFEE", "O; c #E8E6F2", "P; c #EEECF5", "Q; c #F5F4F9", "R; c #FBFBFC", "S; c #F8F8FB", ". . + + @ # # . . . . . . . + + # + + + . . + + + + # . . # . + + @ . . . @ . + + + . . + . + . + + # . . . + + @ . + . + . . # . @ # + + + + + . + # + . + + + + . + . + + . . . + # ", ". # . + + + + + . . @ + . + + + # + . . @ + . + . + + + + . + + . + @ @ + . . . . @ . + . # . + + . . . + . # . . . + $ % & * = - ; > , ' ) ! . . . . . . . + . + . . . @ + + . . + + ", ". + + + @ + + + + . . . + + @ . + + . + + + . + . . + . + . + . . # . + . + # + + + + + . + . . + + . + ! ~ { ] ^ / ( _ : < [ } . + + + + . + @ @ + . + . + . . @ . + + + + + + @ . . ", "# @ . . @ + . + + . . + + + # . + . + + . + + + . . . . . . . + . . + + . . + . . + @ @ + . @ | 1 - 2 3 4 3 5 6 [ @ . . + . . . . . . . + + + + . @ + + 7 7 7 8 9 7 9 0 . 8 a b b c b ", "+ # # . + + + # . + + + + d + + . + . . + + . + + + + . + 7 . . . 0 9 9 b a b a c b e f g h i j k l m & e e n e o o p p p p q r r s t p u v v w w t t t w x x w y x x w z x x x A B B ", "e c c C o b o e o o o p e p p p p p r r D v s r u w w w v v u x w u w x E x F G H I j j J K L M B N N O N B P Q R S T U V V W U X B Y Y Y Z Y Y Z ` . .Y ...Y +...@.@.@.@.......#.#.", "B N B B B B B $.Z N $.O P N O Z Z Z Y Z Z Z Z Z .Y Y .@.Y .Y ....%.&.*.k =.-.;.>.,.'.).!.~...~.~.'.).~.{.].^./.(._.:.<.[.}.-.-.|.1.2.3.4.5.6.6.7.8.9.6.7.8.0.0.a.a.b.b.a.a.b.b.b.c.", "~.).~.~.{.~.~.{.~.{.~.{.{.d.{.e.6.e.f.f.7.6.6.6.7.9.8.7.7.g.h.i.j.k.=.-.|.2.l.m.n.b.b.a.b.o.b.b.p.q.r.p.s.q.s.s.q.q.q.q.t.t.s.u.v.-.-.-.-.-.w.x.y.z.A.A.z.A.B.B.C.B.A.B.B.C.D.D.D.E.F.", "p.b.b.b.q.q.o.s.q.s.s.q.s.z.t.q.q.y.t.z.z.z.t.z.z.B.G.H.I.J.w.-.-.w.K.L.E.A.D.F.D.F.D.D.D.D.D.F.D.M.N.O.O.O.O.P.O.Q.O.Q.Q.O.R.Q.Q.S.-.-.-.-.-.-.T.U.V.U.U.V.W.U.U.U.U.W.X.W.Y.W.W.X.X.", "P.D.P.P.O.O.P.O.O.O.Q.Z.O.Q.Q.Q.`.Q.Q. +`..+U. +++@+#+$+-.-.w.%+&+.+X.*+W.Y.W.=+-+X.X.Y.;+X.W.;+;+;+>+,+'+)+!+,+~+{+]+^+)+)+{+/+)+)+(+-.-.-.-.-.$+/+_+:+_+<+/+[+:+:+:+}+|+1+1+Z.}+[+2+", ";+;+X.^+;+)+^+^+3+4+]+{+)+)+]+)+)+)+)+)+5+6+7+8+9+-.-.$+0+a+6+}+:+}+:+}+[+}+b+c+d+e+f+}+}+b+b+g+2+2+h+i+j+2+k+i+l+m+n+o+m+p+p+q+r+r+s+-.-.-.-.-.t+u+v+u+w+w+x+w+w+y+w+w+z+i+i+A+B+C+D+", "2+2+2+2+2+2+m+2+n+p+m+m+m+o+m+n+r+m+E+F+G+9+-.-.9+H+I+q+x+u+w+w+u+w+w+w+w+y+w+J+d+K+D+C+y+D+L+M+L+K+N+i+j+M+O+P+Q+M+R+M+S+M+M+T+M+U+-.-.-.-.-.9+V+W+T+T+T+X+X+Y+Z+`+Y+ @.@i+i++@ @ @ @", "L+C+D+L+M+M+M+L+C+@@M+@@M+@@M+R+#@$@%@-.&@*@=@-@;@>@,@'@W+W+`+)@!@>@~@{@ @m ]@^@/@(@_@ @:@<@[@}@|@<@1@i+j+2@3@4@5@6@4@7@8@9@0@a@b@%@c@d@e@f@g@h@i@j@k@l@m@n@N+o@p@j@j@q@r@i+i+s@t@u@v@", "w@:@:@:@2@2@x@2@x@x@x@2@x@y@z@A@9+-.-.-.B@C@D@E@F@d+C@G@H@j@I@J@K@L@M@C@N@O@P@C@C@P@Q@R@S@T@i+i+i+'+U@i+j+V@W@i+X@Y@i+i+Z@`@i+ #.#+#i+i+i+i+@###$#%#&#*#i+i+i+i+i+=#v@T@i+i+i+i+i+-#;#", ">#V@,#v@,#,#'#)#)#!#V@~#{#]#-.-.-.9+^#/#(#C@_#:#<#%#[#C@}#|#1#2#3#4#R@5#C@6#%#7#8#;#%#9#0#i+`@a#b#*#i+i+c#d#e#i+f#g#i+i+h#@#i#j#k#i+l#m#n#o#i+i+p#q#r#i+i+s#t#u#i+i+v#w#x#i+i+y#z#V@A#", "d#d#d#d#d#B#C#D#d#E#F#G#-.-.-.9+H#I#J#K#L#C@M#K#N#N#O#C@P#Q#C@R#A#q#q#S#T#7#q#U#T#V#W#X#i+i+Y#Z#`#B# $i+c#Z#e#i+.$+$i+i+@$#$-.$$%$i+&$*$=$-$;$i+>$,$'$i+x#)$!$~${$]$^$)$/$i+i+($_$_$_$", "`#Z#W#=$Z#-$Z#:$<$[$-.-.-.-.}$|$1$2$2$3$4$C@5$2$2$6$7$C@8$9$0$a$b$c$b$b$d$e$f$g$T#_$_$h$i+i+i$j$k$_$l$i+c#j$m$i+n$o$i+i+p$-.-.q$i+i+r$s$t$s$u$i+v$w$i+i+x$y$z$A$z$B$B$z$C$i+i+D$E$F$F$", "G$j$k$G$k$j$H$I$-.-.-.-.J$K$L$M$N$O$P$P$Q$C@>.P$P$P$R$C@S$T$0$U$U$U$U$U$U$U$V$W$X$F$Y$l$i+Z$M$`$ % %.%i+%$`$m$i++%@%i+i+#%-.-.$%i+i+,+T@T@T@T@T@T@%%i+i+&%*%*%=%-%=%-%;%>%i+i+,%-%;%-%", "'%Y$`$ %B$)%-.-.-.-.-.!%~%{%]%{%{%{%{%^%/%C@(%_%_%:%<%C@[%}%|%1%*%-%=%2%=%-%;%3%4%5%6%7%i+i+8%9%9%0%a%i+%$b%c%i+d%e%i+i+f%g%h%i%i+i+j%k%l%m%l%l%l%n%i+i+o%p%q%l%r%s%t%u%v%i+i+w%p%x%y%", "9%9%9%z%A%-.-.-.-.-.B%6%b%C%D%E%C%C%E%l%F%C@G%l%l%m%H%C@I%J%C@K%p%m%m%L%M%N%p%O%P%x%p%Q%i+i+R%l%S%T%U%i+j+V%W@i+W%e%i+i+X%Y%Y%=%Z%i+`%m% &u%.&+&@&'%#&i+$&%&&&*&=&i+-&&&;&i+i+>&,&&&,&", "'&'&)&!&-.-.-.-.-.~&{&{&Y%{&Y% &Y%Y%]&]&^&C@/& & & &(&C@_&:&<&[&}&(&|&1&C@2&3&4&5&6&7&,&8&i+i+9&0&a&'$i+%$-.b&i+c&d&i+i+e&f&f&g&e&i+i+h&i&j&i+k&l&f&m&i+i+h&n&0#i+o&p&q&r&i+i+s&t&u&v&", "w&x&y&-.-.-.-.-.z&A&B&A&C&C&f&D&f&f&A&E&F&C@G&f&f&H&I&C@J&K&L&M&C@C@C@N&O&P&H&Q&R&C@S&v&T&U&i+i+i+V&W&i+%$X&W@i+i&Y&i+i+Z&`& *.*+*@*=&i+i+i+#*$*%*.*%*&***i+i+i+=*-*;*>*,*'*i+i+i+)*;*", "v&!*-.-.-.-.-.-.~*{*.*`&`&.*+* *.* *+*]*^*/*^*+*%*>*(*_*:*%*>*>*<*[*t+}*>*>*;*|*%*1*2*3*4*5*6*7*8*9+w.9*0*;*D&a*b*c*,*,*d*e*f*e*e*e*`&g*h*i*j*k*l*m*n*l*`&o*p*q*r*n*n*s*t*s*u*v*w*e*x*", "y*z*-.-.-.-.-.-.A*f*B*e*e*B*f*f*e*C*e*e*l*l*C*n*e*l*n*m*n*t*k*l*D*t*s*s*t*s*t*D*E*F*G*H*I*-.-.J*K*L*M*x*x*N*O*P*Q*N*O*O*N*R*O*S*T*T*T*O*U*T*U*T*U*T*V*U*W*V*V*X*W*X*X*X*X*X*Y*X*Z*Y*`*", " =.=-.-.-.-.-.-.+=P*O*N*N*R*R*O*N*T*O*O*T*U*U*@=V*U*T*T*V*X*X*X*W*X*X*Y*Y*X*#=$=%=I*-.-.&=*===T*-=;=Z*;=`*-=;=>=>=;=;=;=,=,=;=,='='=)=,=,=,=!=~={=]=^=,=/=(=_=:=]=^=^=^=:=<=:=[=}=[=[=", "|=`*1=X&-.-.-.-.-.2=3=>=4='=)='='=)=,=;=,=,=,=,=,=5=5=5=6=5=]=5=:=5=]=7=8=9=0=-.-.a=b=c=^=d=e=f=f=g=h=i=H*j=k=l=m=n=o=p=q=n=r=s=t=u=v=w=x=y=z=A=-.B=C=D=E=F=G=H=I=J=t=K=L=M=N=u=O=P=Q=", "[=f=e=4=R=S=T=0=-.-.-.T=U=V=W=X=Y=Z=`=`=`= -`=.-.-.-+-.-.-.-.-@-#-$-%--.-.&-*-=---;->-;-;-Q=Q=,-'-)-!-~-{-]-^-/-(-a=_-:-<-[-}-|-1-2-3-4-5-6-7-8-9-0-a-b-c-d-)-e-f-I*g-h-i-j-f-k-l-m-n-", ">-,-o-,-p-p-q-r-s-t-u-v-'-w-x-y-z-a-A-B-|-C-C-|-C-C-D-E-y-F-G--.-.H-I-#-J-K-L-M-N-L-n-O-P-P-P-P-Q-R-P-S-T-U-V-W-X-Y-Z-`- ;.;+;P-@;#;$;R-%;P-&;8-*;=;-;;;`->;,;';);!;~;,;P-{;];#;~;^;P-", "n-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-!;w-/;a=-.X&(;_;y-:;P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-D-<;[;};|;1;2;3;4;5;6;7;8;9;0;P-a;b;c;d;5-5;e;f;g;h;i;j;7;k;6;l;(-2;m;n;P-o;p;(-q;r;P-", "P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-s;y-t;u;v;&=w;6-x;y;N-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-|;z;P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-", "P-P-P-P-P-P-P-P-P-P-P-P-A;B;@;C;(;D;E;Q-m-F;s;P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-J-:;P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-", "P-P-P-P-G;H;I;w-J;K;L;M;N;O;P;Q;G;P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-", "P-P-P-R;S;:;V-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-", "P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-P-"}; barry-0.18.5/desktop/images/background.xcf0000644001161500056700000416570212242254476020032 0ustar cdfreycdfreygimp xcf v002XCC#S gimp-commentCreated with The GIMPgimp-image-grid(style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 32.000000) (yspacing 32.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) <=rBarry Desktop       )gimp-text-layer (text "Barry Desktop") (font "Luxi Sans") (font-size 18.000000) (font-size-unit pixels) (hinting yes) (autohint yes) (antialias yes) (language "c") (base-direction ltr) (color (color-rgb 0.823529 0.685610 0.041984)) (justify left) (box-mode dynamic) (box-unit pixels) rr As%xTU^~%TV_|5'%d }E~E~ӶrYI$و]_p5p5Zj/Z?t%ibb ]@D[@\gEF}PcvKA@xAN _2aTV]xYv TTXtF'<&zZ/# : ;]f;LLL ..$3&Bi $E^k"Yd' TTT[ۙg$?&eec?v (EK@@8rlE A ,-&DdhcY]`[xB[rXυ~F+ )...9 XHeader      X amyX   ) = Q e y   ! 1 A Q a q   ! 1 A Q a q !1AQaq!1AQ         @@@@@,nK7%XFooter     #<X` $0X$4DTdt$4DTdt$4DTdt$4DXl         @@@,nK7%XBackground filter;      XX2BRbr"2BRbr"2BRbr"2BRbr.BVj~         @@@,nK7%X Background     X %1X@a17Ë -`O\}$YFjgV'J~lr *Nerc,Ps 2p?ZaoI'o8;[m}CΈ+  󠟟 󢡢  򬫬𨧨ÿ                                                                                      󧦦      󨧨            𳲲 󭮭                                                     +                        򤥤   񦥥륦   )  멨 󩨨  󩪫   󬫫 뭬  󮭮               *       #            (        &       3 $ +       %  9= Z                  󢩩                 󮯮   󱲲                                                        #                        ꛜ힟󠡠㝩󟠟񟠠                                                                     򍎎򒓓󗖖󚛚     𾿿            򻼻   񾿿                                      ~}~}}|~~~}~}}||}}~~~}}|}~~~}}|~}~}}~~}}|}~}~}~}}~~~}}~}~~~}~}~~~}}~}~~~~~~~~~~~􀁁~󃄃󁂂񎏏񊉉   񵶵   򵴴  ︹  񴵴󵶵                                                          |{zyzzyzyxx|{|{{z{zzyzxyxxw|{zyxyxyxx|{zyzyyxw}|{||{{zyx󽾽|}|{||{{z{zzyx||{zyx~}||{|{{zyx|}||{z{zzyx{}}|{|{{z{zzyx}|{zyzyyxw{}|{|{{zyzyyxw~}}|{z{zzyxz}}|{zyx~}}|{z{{zyx|~~}}|{|{{zzyxyxx~}~}||{zyxyxx|}~~}|{zyxw~}~~}}|{||{{zyzxyyx}~~}|{||{{zyzyyx~}|{zyxw~~}|{||{{zyzzyyxw~~~}|{zyx~~~}|{||{{zzyzyyxxw~~~}|{z{zyzyyx~}|{zyx~~}|{zyxyxx~~}~}}|}||{zyxwz~}|{zyzzyyxw~}|}||{z{{zzyyxw~~~}}~}}|{zyzzyyxw~}|}}||{{zyxyxx~}|}}||{z{zzyx~}|{zyx~}|{|{z{{zzyxyyxx{~}~}}|{zyx~~}}|{|{{z{zzyx~}|}||{zyxyxxwx~}~}}|{z{zzyyx~}~}}|{|{{zyzyyxyxxz~}|}||{zyzzyxyyxx~~}~~}}|{|{{z{zyyxyxx~}|{|{z{zzyxwx~~~}~}}||}||{zyx~}|}||{zyxyxx}~}}|{|{zzyxw~}|{zyzyxyxx~~~}~}}|{z{zzyx{~~~}|{z{zzyxyxxw~}~}}|{zyx~~~}}|}}||{zzyxz~~}|{z{zzyzyxx~~~}~}}|{|{{zyxyyxx~}|{zyxyxwy~}~}}|{zyxyxx~}|{|{{zyx~~}~}~||{z{zzyxyxxy~~}~~}}||{zyx~~}~}}|}||{{|{zzyxyxx~}~}}||{z{zyyzyxyxxy~~}}~}|}||{|{{zyx‚~~~}~~}||}}|{{zyzyyx~}|}||{{zyzyyx{~}~}||{zyzyyxxӰԱ԰Ա񯰰 Ӱ԰ӱ ӱԱԲղԱԱ ղԱ󯰯ղղԳղճճճճղ ճճղճճ ֳճմ  ֳֳ                                         񲱲ﰯ󲱱󻼻񱲲󵶵                                                                 񭮭                   󵴵                                                                                   ﹸ       𼻼¹ù ĺ                                                            #                             򸷸 󹸹    ﹺ   򺻺                      ~||}|} Ĺxxwxwxxwxxwx}  &                               ¾󱳶     4( -              0$ 1                     ﰱ    󶷷 򺻻 뽾                                                                 򣤣󦧧󧨧𯰯                                                  ꚛ󕔔򜛜񖗖򔕤󗘗󣤣񝜜󢣡  󾿾                                                     󇈇󌍌[ 촵   񼽼  󾽼񷸷                                          ~~}~}}|{zyxyww~~~}|{z{zzyxyxw~~~}~}}|}||{|{{zyyxw~}|{|{{z{{zzyxw~}|{zyx~}|{|{{zyxy~~~}|{zyx~}|{|{{zyxw~~~}~}}||{zyzyyx~~}~}||{zyzyyxyxx~}~}}|{zyzyyx~}|{|{{zyxyxxƒ~}|{zyx„~}|}||{|{{z{zzyxyxw~}|{{zyx„~}|{|{z{{zzyxx„~~~}|{|{{zyxw~}|}||{|{{zzyx~}|}||{{zyx~~~}~}}|{zyzyxx~}~}}||{zyx~}}~}||{zyx„~~}|{|{{zyxywx~~~}|}||{zyzyyxw~}~}}|}|{|{{zyxw~}|{zyx~~}|}||{{zyxwx~~}~~}}|}||{|{{zzyxÄ~}|{zyx~~}|}||{zyzzyyxxw~~~}|{zyx~ą~~~}~}}|{|{{zzyxÅ~}|{zyzyyxxwą~}|z{zzyxw}~}~}}||{zyx~}|{zyxÅ􃄃~}~}}|{|{{zzyxy~}|{zyxxą~}~}}|{zyxwÅ~~~}}|{||{{zzyxw~}~}}|{z{zyzzyyxxą~}|{z{zyyzyyxÅ~}~}}|}|{{|{{zzyzyyxxz~}|{zyzzyxyxwxĆ􀁀~~~}|{zyxwÅ~}|}||{{zyxw􂃂~}|{zyzyyxą~}|{zyxyxw~}|{|{zzyx򄅄~~~}|{||{{zzyxyxxzĆ~}|{z{zzyyxĆ~~~}||{zyzzyyxyxxw~}|{zyxw~}|{zyxw~}~}}|{zyx~}|{|{{z{zyyx~}|{z{zzyx~}|{zyzyyxyxx}~~}|}||{|{z{{zyzyyxyĆ~~~}~}}|{zyzyyxyxxĆ~}|{|{z{zzyxw~}|{zyzyyxņ~~~}|{zyzzyyxyxxĆ~~}|{z{{zzyx򴳴״ִִִ ִִ ״ ״ִ ֵ״׵״׵׵ ׵ص찱׵׵ ׵ ص׵׵ضص׶׶ ׶                                 쾿򷸷󵶵𻼼                                                    񭮭󱲱𲱲򮯮              𷶷󲱲򾰰󵴵󳲳컺ôôôôĴĵô󶵶                                                                      򾿿Żļ |xxzxxxwxxyſzxxà{xxyxxyywxxyxyyxxyxyy|wxxyzźwxxyzyz{xxyzyzzžwxxyxyyzŰxxyzyyzz{zğyxxyxyyz{z{z{z{xxyxyyzyzyzz{zz{Ÿwwxxyxyyzyzz{zz{{|xxyzyzz{|{yxxyxyzzyzz{z{{|{|xwxyxyyzyzz{z{z{z{|{|{||Ēwxxyzyz{|}xxyz{|{||Šxxyzyzz{|{{||}‹xxyz{|}xxyzyzz{|{||}|}|}}~xxyzyzz{zz{{|{||}~xwyyz{|{||}|}}~Ñxxyz{|}||}}~}}~~wxxyz{z{z{{|}~}}~xxyz{z{{|{||}}|}}~}}~~Ŧxxyzyzz{|{|{||}|}|}}~~ywxxyzyzz{zz{{|{|}|}}~}xxyzyzz{z{{|}|}}~~„wxxyxyyzyyzz{z{{|}|}}~~~Đxxyzyzz{|{{||}|}}~}~~~xxyz{|{||}|}}~~}~~űyxxyzyzz{z{{|{||{|}}|}}~wxyxxyz{|}~~~ŏxxyzyyzz{z{{|{||}~~xxyz{z{{|}|}}~~{xxyz{z{{|}|}~~~Ĉwxxyzyzz{|}|}}~}~~xxyxxyyzz{|}|}~~zxxyyz{z{|{{|}~~Ċxxyz{z{{|}~}~~wxxyzyzz{|{||}}~~~}xxyxyyzyzz{z{{|}~}~~Ŕxxyz{|}~}~~~xwxxyyxyzyzz{|}~ĉxxyz{z{{|}~}~~wxxyyz{z{{|}~xxyzyyzz{|}~xxyxyyzyyz{zz{{|}|}}~~~ſ~wxxyyz{|{||}~~xxyxyyz{{z{{|}||}}~}~}~~ſ|xxyz{z{{|}~xxyz{z{{|{||}~~ſ{xxyz{|}~xxyz{|}|}}~~~xxyzz{zz{|{||}}~}~~~~      Ŵ ѽ ӽտİ˴ӻ ů  Ҹ ǰպͲïպѴ̯ Ư׼ַַַָֺ ָ  ؽ򯮯®Ǯͮ󲱱Ұֵĭ ͮ ղ Ʈ񲱲ѯ׷ ĮѮ ƭձή׷ɮֲĮղհ®հĭֱ                               ó~x xyxxyxxyx xwx}|x xyxyxyxyxwŹyx xyxxyxyyxy yxyxyxyxxxxwwxxyxyyxyyzyyxyyxyxyyxxwxïzxxyxyxxyxy yzyyzzyzyyxyyxyyx~xxwxxyxyyzyyzyzzyyzyyzyzyyzyxy xyxyyzyyzzyzyzzyzzyzzyzyzzyyxyxxyxyyzyzyzz{zz{z{zz{zyyzz yxyzyyzyyzz{zz{{z z{ zyxyyzyyzyzz{zz{z{{z{{z{{zz{z{zz{zzyzyyzyyzz{zz{{z{{z{{z{zzyzyyzyz{z{z{{z{{|{{|{{|{{|{{|{{|{{z{{z{z{zzyzyzz{z{ {|{{||{|{|{{z{z{{ z {|{||{||{| |{||{|{{|{{z{zz{zz{zz{z{ {|}|}|}||{|{{z{z{{|{||}|}}|}|}}|}||}||{|{{z{{z{{|{|{||}||}|}||}}|}}|}}|}||{|{{|{|{||}||}||} }~} }|}|{|}|}}~}~}}~~}~~}~}}~}}|}|}||{|{|{||}|}~}~~}~~}~~}~~}~~}~~}|}}|}||{{||}|}|}}~}~~}~}~}}~}}|}|}||}|}}~}~}~~~~~~~~~}~}}~}}|}|}}~}}~~~~~~~~~~}~}}|}~}}~~~~~~~~~}~}}|}||}}~}~~~~~~~~~}~}}~~~}~}~~~~~~~}~}}~~~ ~~~}~~~~~~~ ~~~ 􂃂ꅄ   󉈈  􅆅􋌌ĺ ǻ Ķ ƶ ̻  !       򯰰  󰱰            󳴴󴳴 쳴 󳴳  󵴵    񶷷 󶵵򹸹 󹸹           -+                     x{󻼻xxw{xxyxxyx{yyxyxxwyxyxxzyyxyxxwyzyzyyxyxx{zzyzyyxwzyzyxz{z{zzyx{z{zzyx{|{{z{{zyyzyyxx|{{zyzzyyxx|{zyx||{z{zzyyxy}|}||{zyzyyx}||{|{{zyyx}|}}|{zyxyxx}}|{|{{zyx}}|{zyxw~~}|{||{z{zzyyxy~~}}|{zyx~~~}|{zyzyxx~~}~}}|{zyzyyxw~~}~}}|{zyxyxx}~~}||{zyzyxx~}|{zyx~~}|{|{{zyzyyx򼻼~}~}||{zyyxw~}|{zyx}~~~}|{zyx~}|{{zzyx~}|{zyx~~}|{zyx~}|{zyxxy~~~}||{|{{zzyyx~~}|}|{{zzyyxxw~}||{zyx~~}||{zyxx~~}}||{zzyyxx~|{zyzyyx~}|{|{zzyxx~~}}|{{zzyxx~}||{zyyxyxۅ~~}}||{zzyyxx}}|{{zyxy~}||{zyy~~}||{zzx~}|{{zyzxx建~||{zzyyx񅄃~~}||zzy󹺹߆~~}||{{yzyx燆~}|{{zzyx{󆅄~}}{{yxxӹ~}|{zzyyz䉈~}}|{zzyx芉~}{{zyyѮҮѯѯѰѰѰ󰱰ұѰұѱұѲѳѴѴѵѵҵѶҶѶҷи亹                                   ﴵ񱰯ﭮ𫩪񭬫󶷶﨩󴳴                                                        󟠟񠟟󢡠󖧧򖧧񗘗񝜜                                                     򆗗􍎍񍌍򌍌񐑐󉈇 񻺺 𽾽򶷶   ﷸ 󶷶￾ 񷸷                                                     ~}~}}|{zyzyyxyxxņ~~~}|{zyxĆ~}~}}||{zyxĆ~}~}}|{|{{z{{zzyxņ~~~}}|{||{zzyxć~}|{z{zzyxw|Ć~}|{zyxwzĆ~}|{z{z{zzyxwĆ~}~}}|{zyzyxyyxwĆ~~}|{|zzyxyxxć~~~}~}}||{zyxwx~}~~}|{zyxw~}~}}|{zyxyyxxņ~}|{|{{zyzzyyxwĆ~~~}|{zyxņ~~}~~}|}||{{zyx~}~~}}||{zyxyxx~}~}}|{zyzyyxyxxć~~}~}}|}||{{zyzyyxx~~~}~}}|{z{zzyxĆ~}|{zzyxyyxx~}|}}||{z{zzyyx~}|{zyxwć~}|{zyzzyyxxć~}~~}}|{|{{zzyzyyx~}~}}|{zyxć~~~~}|}}||{zyx~}|{||{{zyxwĆ~}~}}|}}||{zyx~}~}|}||{zyxŇ~~~}}|}||{z{{zzyx~~~~}|}|{||{zyxyxxć~~}|{zyx~}|{zyx~~~}~}||{zyx~}|{|{{zyxyxxć~}|{|{{zzyxwĆ~}|{|{z{z{zzyxyxwĆ~}|}|{{|{{zzyxyxx~}~}}|{|{{z{zyzyyxņ~~~}|{zyxĆ~~~}|{z{{zzyzyyxyxxņ􅆅~}|}|{{zyxyxwĆ~}|{|{{zyzyzyyxx}Ć~~}~~}}|{|{{zyxyxx|ć~~~~}|{||{z{zzyxyxxĆ~}|{|{{zyxyxxņ~}|{z{zzyxwĆ~~~}|{zyzyyxĆ~~}}~}|}||{{zyzyxxĆ~}|{zyxĆ~}}~}}||{zyxwĆ~}|{zyxyxxĆ~~~}}|{z{{zzyyxyxxć~~}~~}}|}||{{z{zzyyxwĆ~~~}|{|{{zyzyyxyxxzĆ~~~}~}}|}}|{{z{{zzyyxyxx󅆅~~~}|}||{z{zzyxw~}|}|{{|{{zyxyyxxĆ~~~}~~}||{|{{z{zzyxw~}|}||{zyzyyxyxwĆ~}|}||{|{zzyxyxxw~}|{zyxą~}|{z{zzyxyxxwx ׵ض ׶󰯮׵ضض 󭮮ضضض򰯯ض  ׶ض󳲲׵󳴴ض׶׵׵ ض ׵ص                                     񾿿򹸸                                                                         񱲱򰱰󮵴󰯰򰯯        ŵŵŶŶźņżyţxōxyxwxwxńxxxxyũxxxxxyyyxxyxxyxxywxxyxxžxwxyxwxxyyxxyxxyxyƈwyyxy}xxyyxxyxxwwxxyxxyxxyxxywxxyņxxyy}xyxyyyxxyſxxyyzwxxyŲwxxywxxyyxxyzţxxyţxxyšxxyxyyřxxyŚwxxyxyyxxyxxyzxxyƙwxyxyyřwxyxyywxxyxxyxxyxyy ض Ԯ Ʈٺ֯ ˮӮɮٴ Ԯ̮®ԭͮĮԮϮȮîٿ ٺ֮ԭ Юέˮ ɭƭƮŮƮ                                        xxyz{|}~}~~Ąwxxyyzyzz{{|{||}~Ůxxyzyyzz{|{}|}}~xxyz{|}|}}~~źyxxyzyzz{|}~}~~śxxyz{|}~}~~xxyxyyzyzz{|}|}}~􁀀ūxxyxyyzz{|{||}~Ŏwxxyyzyzz{{|{||}||}}~}}~~~ywxxyz{|}~~wxxyz{|{||}}~~xyxyyzyzz{|}~xyz{|}|}}~~~~xxyzyzz{|{||}~~􇆇xxyxyyzz{|{||}}~xxyz{|{||}~xyyxzyzz{|}~}~~xyxyyzz{z{{|}~~xxyz{z{{|{|}}|}~~~xyz{z{{|}~xxyyzyzz{|}~}~~xxyyz{zz{|{||}~y{|}~yyz{|}~xyz{|{|}}~xyyz{|}|}}~~yzyz{{z{{|}~}~~yz{|{||}~~yyz{|}~yzyzz{|}||}~yyz{z{{||}~}}~~yyz{z{{|}}~~yz{|{||}}~yyzz{z{z{{|}~~~yz{|{||}}~}~~yzyyzz{|}~yzz{|}~yzyzz{{|{||}}~}~~yyzz{|}~yzz{|}~}~yzz{|}~zyzz{z{||}~~zz{||}~}~~yzz{|}~~yzy{z{{|}~}~~yzz{z{|{||}~yzz{|}~~~zz{zz{||}~}~~򈇇zz{|}~z{|{||}}~}}~~yzz{|{||}~}~yzz{|}|}}~yyz{{|}|}}~~~yyzz{||}~yyz{z{{|}|}}~~zz{|}~yzz{{|}~~z{z{{||}|}}~yzz{|}~}~~~yzz{|{{||}||}}~zz{|{||}}~}~~zz{||}|}|}~}~~zyzz{{|}~}~~yzz{|{{|}}~Ǯش𴳳̭Ү®ײʭغԯŮ󶵵 𰯰  򯮯                                                          򜝝򸷸󽾾󹸸 ·÷÷ķĸ ķĸøĸ󾽾ĸĸøĸ𻺺ĸĸĸøøøøøø¸                                                 勉}|{zyyx捌~||zzyyێ~~|{zyx㎍~}{zyy돎~|{zx鐏|{zy撑}{zx铒|z|픓|z} 񞟟𞟠蛜 朝頡粝洳瞟峲屠屲塢갠鰱籰梣찱  򥦧󡢡󭮭   񩪪    復 𹸹ѻѻлﹸ񹸶仺[Ͻ򿾾Ͽ                                        %            !  󱲱񱲱񣱲﨧 򦥥                                                                       񡢡󛜛陘򣤣󛚚󕔔🠟󚛚񑒑       󾿾                                                    􉊊􏐏􆇆􌋌 춷󺻻 쵶        𴳴󴵴                                          ~}|{|{{zyzyyxyxx}Ć~}~||{zyzzyyxx~}~}}||{|{{zyxwĆ~}|{zyxw~~~}|{|{zzyxĆ~}|}||{zyxxyxx~~}}|{zyxyxxÅ~~~}~~}}|{zyzyyxą~~~}|{zyxw~}|}||{|{{zyzxyxyxxĆ~}|}||{zyxyxxwÅ~}|{zyx~~}|{zyxÅ~~}}|}||{zyzzyxyxwÅ~~~~}}|}||{z{zzyyxyxx~}|{zyx~}~}|}}||{{zyzzyx~}|{|{{zzyxw~}|{|{{zyx|~~~}~}||{zyxą~}~~}}|{zyxÄ~~}|{zyxÅ~~~}|}|{{z{zyyxw~}|{zyx~~~~}|{|{{zzyxÄ~}|{|{{zyyxw~~~}}|{zyx„~~~~}}|{|{{zyxywy~}|{|{{zzyx~}|}}||{zyzyyxw~}|}||{zyzyyxx~}|}||{|{{zyxwx„~~}~}}|}}||{zyzzyx„~}|{zyzyyxxyxx~}|}||{{z{zzyxyxxƒ~}|{zyxyÃ~}|{zyxyxx~}|{zyzyyxyxx󂁂~}|{|{{zzyx~}|{z{zyzyyxyxxy~~~}|{zyx~}|{z{zyyxƒ~~~}}~}}|{||{{z{zzyzyyx~~~}|{zyzyyx~}|}||{||{z{zzyxyxxw~}|}||{zyzyyxyxx~}~}}||{zyx{~}~}}|{zyzyyxx~}~}}|{zyzyxyxyxx~}|}||{zyxwy~~}~}}|{|{{zyxƒ~~}}|{zyyzyxx~}~~}}|}|{|{{z{{zzyxyxx~}|{zyx~}|}|{|{{zyx~}~}|}||{zyzyyx~}|{z{zzyzyyx~~}|{|{{zyxywx~}|{z{zzyxwy~}|}{{z{zzyxw~}|}{||{{zzyx~~~}|{zyxz~~~}|}||{zyx~~~}|{zyxyxx׵׶ صص󱰯׵ ׵ص׵׵󴳳׵󵴴׵ִ״״ֵ״ ִִִִ׳ ִ״ֳ񮯮ִճ ճֲճ                                             ﹺ                                                                      򰱰󯰯򰯮򯰯                           wwyxxyzţxxyxxyŭxwyxxyyxxyŷxwxxyyzxxyzxxyxyy}xxyyzxxyyŎxxyxyŖwxyxyyşxxyxxyŲwxyxyyxxy|xxyyxņxxyxyƓxxyxxyxyxxyxxy{xxyxxxyxxxyxxxxx{xxwxxŞxxxwxyxxƇxxxxxxzxxxwă򽼽ĶŵŵŵŵŵŵŵĵĴŮŮˮˮϮЮ֮ׯ ٰ îɮήԮٽĮʭҭׯٷȮѭ ®ͮծ ͭ֯ Ʈҭ                                          z{|}~~zz{|{}||}}~yzz{{|}~~~yzz{|}|}}~}~~zyzz{|}|}}~zz{|{{||}}~yzz{|}~~zz{|{||}}~~~yzz{z{{|}~yyzz{{|{||}}~yzz{|}||}}~~z{z{{||}~yz{|}}~}}~~~yz{|}~}~~yzyzz{{|}~yyzz{|}~zyzz{|}|}}~zyyzz{{|{{||}~}~~yzyzz{|}~yz{|{||}}~}~~yz{|}|}}~~yz{z{|{||}~~yz{|{||}~xyzz{|{||}}~xyyz{|}}~yyz{z{{||}~}~~yz{z{{|}~󀁂xxyzyzz{|{|}|}~~xyyz{z{{|}~yxyyz{|{||}~~}~~yxyyz{|}|}}~~xyyz{|}~xyxyyzz{zz{{||}~xxyyz{|}~}~~xxyz{|}~􇆇xyxyyzz{|{|}}~xxyyz{z{{|}~~wxyyzyyzz{{|}~xxyyz{|}||}}~}~~xyz{|}~~}~~󄃄wxxyyz{|}~xyz{z{{||}~}~~~wxyyxyyz{|}~遀wxyxyyzyz{{|{|}|}}~}~~xxyxyyz{|{||}~~~~xxyxyyz{zz{{|}|}}~Ɨxxyxyyz{|}|}}~Ŵxxyyxyyz{|}~}~~~Ăwxyxyyzz{|}|}~}}~~~~Şxxyz{{|}~}~~~􅄅źyxxyz{|{||}}~Ŋwxyxyyz{z{|{||}}~xxyz{|}~}~~}wxxyz{|{||}~řxxyz{|}~Źxxyxyyz{|}~xxyz{|{{||}}~섃ŭwxyxxyyz{|}~łxxyzyz{{|}~~~xxyyz{|{||}~}~~}xxyz{z{{|}~xxyz{|}|}}~zxxyyxyyz{z{z{|{||}|}}~~}~~xxyz{z{{|}|}}~󵴴 򴳴  ̮ױؿέس ®үٸɭ ֱﴳѮ 񵴵ظˮ ƭֱ ®կ                                                 􊋋󔓔񐏐񙘙𕖕󒑑񇈇폐񍌌󎍎 󻼼¸𿾿¸󺹹 񼻻    󺹺  [ 񻺻     𷸸                                                            򟞟                  󔓓                  ¾ ¿¾                 󼻻              !         #!             򜛜         ꔕ 옗  򕔔  𒓒                                          𾽽               򻼼                          4       򎍍􎏎 񏐐             ﷽                                                    􃂃~~~~􄅄~~~~􃄃~~~~~}~~~~}~~}~}~~~~}~}~}~~~}~}|~}~}}~}|}~}|~}|󂃂~~~}|}||~~~}~}}|{~}~}}|}||~}|{~~}|{~}|{~~~}|{~~~}|}}||{|{{~}|{~}|{z~~~}~}~}}|}||{z~~}|{~~~}~}}|{~}|{||{{z~}~}}|{z{z~~~}|}||{z{zz~}|{zy~}|{|{z{{zzyz~}~}}|{zyyz󹺹 󷸸 󲳲       򶷶                                                  ~}|}||{zyxyxw~}~~}||}|{||{{zyx~}|}||{zyzyyx~~~}}|}}||{|{{zyxyxx~~~}~}|}||{|{{z{zyzzyyxyxwx~}|{z{{zyyzyyx}~}|{|{|{z{zzyzyyx~}|{z{zzyxwx~}|{|{{z{{zzyxyyxx~~}~}||{|{{z{zzyx~}|{z{zyzyzyxyxx~~~}|}||{zyx~}~}~}}|{zyxwy~~}|{z{zzyxyxx~}|{z{zzyx~}|{z{zzyyxyyxw~}|{z{zzyx~}|{|{{zyzyyxx~~~}|{z{zzyxyxx~}~~}}|{zyyzyyxyx~~}|}||{zyx~~~}|}}||{|{{zzyxyyx{~|}||{|{{zyxw~}|}}||{zyzzyyxz~~~}|{|{{zyx~}|{zyzyyxz~~}~}}|}||{{zyzyzyxyxxw~}|{z{zzyzxxyxxwy~}|{zyx}}|}|{|{{zyxz}~}}|}||{|{{zyx}}~|}}||{z{zzyxz}}|{z{zyzzyyxw}|{|{z{zzyxw|}}|{|{z{{zyzyzyyx꾿}|}|}|{||{{z{zzyxw~}||{zyxyxxw|}}||{zyzyyxx}|}||{z{zzyxw|}||{zyx||{z{zyzzyyxwx||{zyzyxyyxx||{{zyzyyxw|||{{zyzyyx|{{zyzyxxyxx|{{z{zzyzyyxyxxwx|{{zyx{{zyzyyx|{z{{zzyzzyyxyxxw{zz{zzyxywx{{z{{zzyxyxx{{zzyx{zyx{z{zzyyxwxzyzzyxyyxzyx}zyxxyxxzyxyzyyzyyxx}yzzyyxyxxyyxwxzyyxxwyyxyyxxyyxw  ղղղ  ԲԱԱ ԱձԱ Աӱ ӱӱӰӰ԰ ӰӰӰӯ ӰӰӰ ҰӰӯ ү ӯ  Ү ү                                      󲳲󾿾󶷷ﮯ󳴳𹺹                                                                󫰱頻󨭮                        ó´򻺻ó´³켻ﷶ³²򽼽򲱲                                                              zxxyz{|{||}}~}~~򂁁xxyzyzz{|{{|}|}}~Ÿyxxyz{z{{|}~wxxyxyyz{|}|}}~~yxxyz{z{{|}||}}~xxyzyzz{|{||}|}}~~}~~|xxyxyyzyzz{|}~Ɲxxyz{|}~~xxyyz{z{||}||}}~}}~~~wxxyz{|}~~Åxxyz{z{{|}|}}~}~~Űxxyz{|{||}|}~}~~~xxyxyyz{|}~}~~~yxxyz{|}|}}~}~~xwyyxyyz{|{||}~~‚xxyxyyzyzz{zz{{|{||}}~ůxxyxxyyz{z{z{||}~}~~Ƒxxyxyyzyzz{z|{||}~~ľ}xxyzyzz{z{{|}~Ŧxxyz{z{||{{|}||}}~~}~ōwxyxyyz{|}~~ż}xxyzyyzz{|}~}}~~ŧxxyzyzz{z{{|}~~wxxyyz{||}~~~Ž}xxyz{|{|}|}}~~xxyxyyz{|{||}~}~~~Ɨwxxyyxyyzz{zz{|{||}~†xxyz{|}|}}~}~~{xxyzyzz{zz{{|}~ŧxxyxxyyz{z{{|}~}}~xxyxxyyzyyz{{|}||}~}}~}~~xxyxxyz{z{{|{||}~|wxxyz{zz{{|}~xwxxyyzyzz{zz{{|}~wxxyz{z{z{{|{||}~Őxxyxyzzyzz{|}xxyz{z{{|}|}}|}}Żxxyzyz{{z{{||{{||}|xxyz{z{{|{||}|}}xxyz{|{|}xxyzyzz{|{{||}Śwxxyzyzz{|wxxyyzyyzz{{z{{|{{||čwwxxyzyzz{|xwxxyyz{|wxxyxyyz{|xxyxyyz{wxxyz{z{zz{{|xxyxyxyzyzz{zz{{žwxxyxyyz{xxyxyyzwwxyxxyyzŽwxxyxyyzzŠwxxyzyzzwxxyzyzēxwxxyzyzśxxyxyyywxxy|wxxyxyyzxxyxxyxxyxxyxxyyxxŮ|xxӯ󴳳Ѯӯ ԰® ֱǮ׵ͮүíֳ̮ټ ԱǮ ӱȭ԰ʮ ؿ󮯮ֵЯǮ   ֶұ̮ îػֵӱаʮƮ ׹ָ ִ Դ ԴԵ  ԴԴԴ Զָ ֺ׽ Ư̰ϱӶֻḭ̂                                   􊉉񃂂򇈇~~~~~}~~~}~~~}~~~}}~~~}~~ }~~|}}~}|}}~}~~}||}}~}~~ |}~~~􁀀|}~||}}|}}~}}~~~~||{||}}|}}~}~}~~~~ |}~ {|}~}}~~~~~{|{||}~}~~}~~~z{{|}|}}~z{z{||{{||}|}~}}~~{z{{|}~~~z{{|}~}~~~~ z{z{{||{||}|}}~}~~~~􁀁z{|}|}}~~~z{|{||}|}}~}~~yz{z{z{{|{||}~}~~~~yyzyzz{|{{|{||}|}}~}~~ yzyyz{z{{||{||}~}~~~ yz{zz{|{|{||}|}}~}~~~yyz{zz{z{{|}~}~}~~~ xxyyz{|}|}}|}}~~~yyxyyz{|{||}| }~~        󳴴                     𯰰  󳴳  򴳴                                              󍎍       􊉊          􅆅􇆃   텄󄅄  􃄃􂃂      [       󻺺         񺹺        ﷸ     췶򷶶 󶷷򶵵      󶵶   򵴵  򴵴򴳴        &! )       &       % % ) %           􍎑     􋌌     􍎍    󉊊       􊉊  򆈉          󆇆                               򸹹󹺹    񷸸    𷸸𶷸  췸  񷸷           쵶    賴     $    &"           #!  '#     􂃃  ~ ~~~~~~ ~~~~}~~~}~~~}~}} ~~~~}~}~~~~}~}}~~~}|}~~~}|}|~~~~}|}}| ~}| ~~~}~}}|}}| ~}~}|~}~}~}}|{|{~~~}~}}|}||}}||{|{{~~~~}~}|{|{~~~~} |{~~~}|}|}||{|{{z ~}~~}~}}|}}|{||{{z~~~~}~}}|}||}||{{z{{zz~~~}~}}~}}|{|{|{{z{zz~}~}~~}}|}}||{z{zz~~}|}}||{|{{z{zzyz~~~~}~~}}|{|{{zy~~~}~}}|}||{||{{z{z{zzy~~~~~}~~}|}||}||{{|{{zy~~~~~~}~}~}}|{ zyzyy                         󱲶             񯴴                                             $      ~}|{zy~~~}|}}||{zyzyy~~~}|{z{zzyzyzyy~}|{z{zyzyy~~~}|}|{||{{zyx~}~}}|}||{z{zyzyyx~~~}|{|{zzyzyyx~}|{zz{zzyxy~~~}~}}|{zyx~~~}~~}}|{|{{z{zzyxw~}|{zyxwx~~~}~}}|}|{|{{zyxw~~~}~}}|}||{z{{zzyzyyxĂ~}~}|}||{zyxł~~}~}}|{z{zzyzyyxyxx{Ń~~~}|}||{zyxwxł~~~~}|{z{{zzyyx~}~}|{z{zzyx~~~~}|{z{zzyzyyxyxxwxŁ~~~}~}}|{z{{zzyx~~~}|{|{{|{{zyzzyyxw}ā~~~}~}}|{z{{zzyzyyxyyxxy~}|{z{zzyx~}|{|{zyxyxxÀ~~~}|}}||{z{zyzzyyxwÀ~~~~}|{|{{zyzyxyyx~~}}~}}|{z{zzyzyyxw~~}|{|{{z{{zyxyxx€~~~}|{z{z{zzyyxw~}~}}||{zyzyyxyxxw~~~}~}|{zyxw~~~}~}}|}|}||{|{{zyxyxx~~~}~}}|}||{|{{z{zzyx~}~}}|{z{zzyxyxx~}|{z{zzyzyyxyxx~~}|}||}||{ zyxw~~}|{||{zzyxyxxw~~}~}}|{|{{z{zzyxyxx}}~~}|}}|{z{zzyx~}}~}}|{||{zz{{zzyzzyyx~}}|{|{{z{zzyzyyx}} |{z{zzyxyx}}||}||{|{z{{zzyzzyyxw||{zyzzyyxyxxw|}||{|{z{{z{zzyyzyyxyxxwx}||{z{z{zzyzyyxy||{|{{z{zzyx{|{zyzyyxyxxwx|{|{{zyx{{z{z{zyyzyyxw{zyzzyxyyx{zyxyxw|z{{z{zzyzyyxw{zyzyyxyxxzyzyyxyxxzyzzyxyxx|{zzyyxyxwzyzyzyyxwyzyzyyxxyxxwxzyxwyyxyxyxxyx|xyyxwyxyxxy򰯯     ״ سس ׳  س׳س ׳ײײ  ֲֲױױ󭮮ֲ  ֱֱֲձֱ  հְհհ԰ կԯկկ կ Ӯ  ӯ                                           yxyxxyxyxx{xyxxwxxyxxxyxx򻼼x{򺻺ﶵ򲾾 Ѯ Ѯ ҮѮѯ                                                                 񴳲𪫫󭮮                                                            򤥤                                 xxwźźĹĺùø  Ҷֽ              xyxyyzyzz{z|{{||}|}|}}~}}~~~~xxyxyzyyzz{|{||}||}}~}~~{xxyxxyzyzyzz{{z{{|{|}|}||}}~}}~}~~~~~xxyxyyz{z{z{{|{||}|}|}|}} ~~~xwxxyzyzz{z{{|{||}|}}~~~~|xxyxyyzyzz{|{||}|}}|}}~}}~}~~~~wxx yzyzz {|}|}}|}}~}~~Ģzxxyzyzz{|{||}|}}~}~}~}~~wxxyzyzz{z{z{{|{|}||}}~àzxxyxyy z{|{{|{||}|}}~}xwxxyzyzyzz{z{|{|}||}}|}}~}}ģ|xxyxyyzyzyzz{|{{|{|{||}|}}wxxyxyyz{zz{z{{|{||}ĭxxyxyzyyzz{z{zz{|{|{||}zxxyxyyxyyzyzz{zz{{ |ƺxwwxxyz{zz{zz{{|{{||  ѵ ֽʰ ӷ ů ѶĮ зư Ժ ˳  ¯һ              񁂂~~~~~ ~~ ~~~~~~}}~}~~~~~~}~}}~}~}~~~~~~ }}~}}~}~~~~~|}~} ~~~~~~~ }~}}~~}}~~~~~~~~~~~}||}|}}|}}~}}~}~~}~~~~~~~~~~   𳲲   򱲲     !   *+&       ~~ ~~  ~~ ~~~~~~~~}~~}}~~ ~}~}}~~ ~}~~}~~~~~}~~}~}}|}||~~~~~~~~~~}~}~}}~}}|}}|}~~~~~~~~~~~ ~}~}~}}|}||}}|}||   𲳳  󲳲                 ~~~~~}~}}|}||{zyzyzyyxyy~~~~}~}}|}||{||{{zyzyyx~~~~}~}|}||{z{zzyzzyx~~~~}~}}|}||{|{{|{{z{zzyx~~~}~}~}}|}||{|{|{{z{zzyzyyxyyxx~~~}~~}|}|}|}||{z{zyzyyzyyxyxxz~~ }|}}|}||{||{{|{{z{{zzyzyzyyxyxx~~}~}}|}}||{||{|{{z{{z{zzyzyyzyyxyxw~~~}|}|{||{|{{z{zzyzyx }|}||{|{|{{z{zzyzz yx}~}}|}||}||}||{|{|{|{{z{{zzyzyyxyxxw}}}|}||{|{||{{z{zyzyyxyxxwy}||}|}||{||{{z{zz{zzyyzyyzyyxyxx|}||{||{z{z{zzyzzyyxyxxyyxx}||{||{{||{{z{zyzyzyyxyxxw||{||{|{{z{z{zzyzzyyzzyxxyxyxx~        ² ر ױ ױ  ױװ ذ򯰰װ            yxxwxxxxy  Ӯ ӭ                 󰱱񹺹                                            ,nK7%XBottom     XX(&Lpy8D I Xs T g l 8 `  = c P ֢  ( 9 b   / Y   8`` M0Y}N0F3YDȴ?¨¨èĩĩ񲱳ŪŽŠxđxyřxxyţxxy󺹺Ŭxxyyzŵ|xxyzzxyyz{yyzyz{Ïxyyzśxyyz{{ũxyxyyzz{||ŵzxxyyz{{|xxyyz{{|}𻼼ˆxxyyz{{|}xxyyzz{z||}|~xxyyz{|}Ŵyxyyzz{||}~žxxyyzz{|}}~Îxxyyz{z{||}}~}~~ĝxyyz{|}~Űyxyyz{|}~~xyyzz{|}~Éxyy{|}~~ŝxyyz{|}|}~~Űyxxyyzz{{||}~~xxyzz{|}~~ōxxyyz{{|}~ţxyyzy{{|}~ŷzxyyzz{|}~xxyzz{|}}~~ęxxyyz{{||}~򸹹Űxyyz{|}~Ŀxyyzz{||}~~œxyyz{||}~~ūxxzy{{|}~ž~xxyyzz{|{}}~􀁀Őxxyyz{{|}~Ūxxz{|}~ž~xyzz{|}~œxxyyzz{||}~~ŭxxyz{||}}~xyyz{{|{||}}~Ŗxxyyzz{||}~ųxxyyzz{{|}~~…xxyzz{{|}}~Šxxyyzz{{}|}}~~ź{xxyzz{{||}~ďxyyz{{|}}~񅆆ūwxyyzz{{|}}~xyyzz{{|{}}~~xyyz{{|}~~zxyzz{|}}~ִָ׻ŮˮϰӲֵ׺ɮϯԲ׷Ǯϯճ׹îͯӱ®̮ԲŮЯֶ̮ղʮԱɮԱˮղؾή׵ĭҰʮֳү                                              Śxyyz{|}~šxxyyzz{||}~Ţxyxyyz{|}}~~ţxyyz{|}~ţxxyyzz{|}~xxyyzz{{|}|}}~~ūyxyy{z{||}~zxyy{z{{|}}~Ŵ{xxyyz{zz{{|}}~yyz{|{||}}~xyyz{|}~xyyzyz{z||}~xyyzz{||}~}~xyyzz{{||}~~򃄃yzz{||}~~􀁁yzz{{||}~z{|{||}~~~{z|{||}}~{|}~~{||}}~~||}~{|}}~||}}~~铒|}}~~|}}~}~~~~~핔~􍎍~񈉈􃄄򆇇򙚙󢇇菎ŭƮƮŮʯʮ蹺ίΰѱ´ôôĵĶŶƷƷ                                                    퓒盚󧦧𭬬󦥦򤥥򯰰󸷸ùùźźżƼǼȼǽɾɾʿʿʿ                                                                 󩪩󥤤쭬鮯 µķżxĶyxxİxxyxxyðxxyxyyij~xyxyyxyyzwxxyyz{zzéyxxyxxyyz{}xxyz{z{{yxxyyzyzz{z{{|{||wxyyz{|{{||}}xxyxyyz{|{{||}żzxxyyxyzyyzz{|{||}|}|}}~}               ʿķͿο³ɸ˹ų°ӿ                                                                     󼻼  񼽼     ý}{wxxwxwwx}}ù{xxyxyxxyyxyxxyxxyxyxyxyyxxyxx}ļzxxyxyyxyyxyyxyyxyyxyxſxwxxyxyxxyyzyyzzyzyzyyzyyzyyxyxxyzyzyzzyzz{zzyzyzyyzzyyxyxyyzyzyzyyzz{z{{zz{z{{z{z{z{z{zzyzyxyxyyzyzz{zz{z{{|{zyzzyzz{z{{|{{||{|{||{||{||{{||{|{{z {|{|{|{||}|}||}}|}|}|}||}||}||{|{{|z{|{|{{||}||}|}}|}|}}|}}|}}|}|}||}||}|}||{{z{{|{|{||}~}}~}~}~~}}~}~}}~~}}|{|{||}}||}|}}~}~}~~} ~}~~}~}~}~~}~}~}}|}||}|}}~}~}~~~~~~~~~~~~~~~~~}||}}~}}~~~~~~~~~~~|}}~~}~~~~ }~}}~~~}~~    '                               ¿ﭮĿý 󯮯ú ɾ       𱲲           1 . "    "                 . 񣤤 򮯯   xyx|yxyxyxxywxzyyxyxxz{zyzzyzyyxyxxyz{{zz{zzyzyyx{zyxyyxx||{|{{z{{z{zzyyzxyxxw||{||{{zyzyyxyxxy}|}|}||{|{{zyxw}~}|}||{zyzyyxy~~}~~}}~}}|{|{{z{{zzyx~~~~}~}~}~}}|}||{z{{zzyzyyx}~~~}~}}|{|{zyzyyxyxz~~~}|{z{zzyxyxz                           ҮҮ Ӯ ӯ԰ձ Ա  ղղղ     "                      򓔓鞟󝞞񪩪󝱰󴳲󩨩󹺸﫬ﻼ                                                       ~}{|{{zyyx~}|{zyy~}{|{{zzy}~}||{zyy~}|{z~}|}{|{{z~}|{~}||{~}|{|􍎍~~}|~}||뒑~}|򎍎~~}~~}~~}~~~􅄅푒򈇈􋊉웜󺻻񺻺󹸸                                              xxyyyxyyyxx|󻺺zyyxx󹸸zzyyxx{zzyyxx{zzyyx{{zzyyx{yx||{{zyyxxz|{zyyx||{zzyx}|{zyx}}|{zx~}}|{zyx~~}||{zzyx|ﲱ~}}|}||{{zyyx~~}}|{zyx~~}|zyxx~}}|}|{{zzyxz~~}|{{zyx~}|{zzyyx~~}}|{zyxx~}||{zyxz~~}}|{{z{zyyxx~}|{zyx򵴴~~}|{{zzyxyx~}}|{zyzyxx~~~}}|{zzyxx~}~}}||{{zzyyxw~}|{zyyxz~}|}{{zyyx~~}||{|z{yyx~~}|{zyyxy~}~}}|{{zyzyyx󷶵~}~}}||{{zyyx~}|{zyxxz~}|{{zyx񻺺~}}||{zzyxw~}}|{zzyyxx{]~|{zyx~}|{{zyx~~}|{zyx~}||{zyx~}}||{zyy~~}|{zyyxx~~}||{|zzyx~}|{zyxx~~}|{zzyx~}|{zyxz~}}||{zyx~}||{{zyx~}|{zyyx~~}||{z{zyyxx~~}||{{z{zyy~}|{z{zzyxx~~}{zyzxx{򻌋~}|{{zyyxx~}}|{{zyyz񇆆~~|{zyxx~~}||{{zyxy~~}|{{zzyx˯ʰ˰˰̰˱̱γγγ󱲱ϴϴϴежзжѷѸѷ𯰯ҸҸҹӸӹҹԹ                                           󧦦򨧨񩨧񯮭񯮮𴳳谯                鼽ďxyyz{|}~󇆇xyxyzz{||}~}~~Âxxyzz{|}}~~Ģxxyyzz{|}|}}~ſ|xyyz{|}~ŗxxyyz{{|~Źyxyyzz{|}}~􅆆Ŏxxyyz{{||}}~ůxxyzz{|}~xyyz{||}~~Ūxxyyzz{||}~Áxxyy{{|}~􋌋xxyyzz|}~~턅~xyyz{{|}}~Šxyyz{{|}}~~ſ|xyyzz{|{||}~~Ŝxyyzyz{{||}~}~~󎏿{xyyzz{{||}}~~Ŝxxyzz{||}~㏾ſ{xyyzz{{||}}~Ŝxyyzz{||}~~ſ{yxyz{{|}}~xxyzz{{|}~􊋋ſ{yyzz{{|}}~~􁀂􇈈Ŝxxyzz{||}|}~|xxyyz{{||~šxxyzz{||}~~~yyz{|~}~Ŧxxyzz{||}~āxyyzz{{||}}~~Ūxxyyzz{||}~~ʼnxyzz{||}~xxyyzz{{|}}~ŏxxyy{z{||}~􉊊źyxxyzz{||}~~Śxyyz{|}}~~|xyyz{||}}~~xxyzz{{|}~򂃃xyyz{||}}~Ůxxyyz{{|}}~~ďxyzyz{{||}~~􄅄xxyyzz{{|}}~~śxyyz{||}}~~~xyyz{{||}~~ūxxyyz{{|}~~뇈Ōxyzyz{{||}~~󈉉ĺyyz{|}}~śxyyz{{||}}~~xyyzz{{|}}~~􋌌xyyzz{{|}}~~xxyyz{{|}}~~yxyyz{|{}}~~܍xxyyz{|{|}}~씕xyzyz{{||}~~yyzz{|}~yz{|}~yyzz{||}|}~~މyzz{|}}~~yzz{||}}~~뗘yyzz{||}}~~yz{{||}}~zz{{|}}ӌzz{||}}~~񙚚zz{||}}~~돎̮״Ůհѯ̮ɮ׳ƮֱĮհհ­԰򴳳԰򳴴հ®ֱŮױǮ񼻼׳ʮέػүְƮ󼽾״̮ػүײʮү𾽾ײ˭񳴴󿾿                                          袣󒓓際񫬬𑒒񫪫줥𖗘򔕕񪫬屲頻𲳳񬭮첳񴵴︹򞟟ƸǸɹɹɺʺɺʺɻ˻˻˼˼ͼͽξξξϾϾϾϾпϿпѿ                                                     򰯰񨩪󮯮ﶷª񱲲«󺻺īŭžŵĦzxÖxyy򶵶񼽽ľxxyyŷxxyzŭ{xxyyzŤzxxyzzy{Ěxxyz{Ñxxyzz{xxyyz{|žxxyz{|𰱱Žxxyyz{|xyyzz{||}Źxxyzz{|}Ÿyxyyz{|}~Źxyyzz{|}~Źxxyyz{{|}~}Źxyyzz{|{{|}}~}~Źxyyz{||}~Žxyxyzz{|}~ſxxyyzz{|}}~xxyzz{|}~뷸xxyyzz{|}~xyyz{|{||}}~xyyz{|}~Ũyxyyz{|}~~Ųyxyyzy{{|}~ź~xxyzz{|}|}~~xyyzyzz{{||}~~xyyz{|~xyyz{z|{||}~~xxyzz{{|}ź|xyyz{|}}~}~~xyyz{z||}~󺻻xyyz{|}~ŧxxyzz{||}~~ĸ|xyyzyz{{|}}~Æxxyyzz{{|}~~xxyyz{z{{|}}~򅆅ůxxyyz{|}}~ſyxyzz{||}~xyyzz{{|{|}}~Īxyxyzz{|}Ž}xyyzz{{|}~~xxyyzz{||}~ϳǯԸг˰Ư׼ָԶԵѲѲѲѲѲѲҲԵյָ׺î󲳳ȮίҲֵ®ˮѰֵؽǮҰ̮ղػɮ԰ػ                                                 ĸzxxyz{|}~}}~~~yxxyz{|}~~zxxyxyyzz{|}~}~~zxyxyyzz{|}~â}xxyyz{|{||}~xxyzyzz{|}|}}~xxyzyyz{z{{|}~}~~򂁂yxxyz{|{|}}|}}~~~xxyyz{z{{|{|}||}}~}~~~~xxyz{z{{|}~}~~~ģ{xxyyzzyz{z{||}~~ķxxyzyz{{|}~򀁁zxyyz{|}~źxxyyzyz{{|}~ħ|xxyz{|}~}~~~wxyyz{|{||}}~~űxxyzz{|{}}|}}~~Ġyxyyz{|}~xxyzyzz{{|}~xyxyyz{z{{|}|}~~xyyz{z{{||}}~yz{|}}~~yyzz{{|}~~~zz{{|}~}~z{|}~}}~{|}|}}~~{||}~{|}}|}~~|}~|}~}}~}}~􋊋~}~~~~~~򌋌𑒒𗖗󓒓񞝞Ѽ Ѽ ӿű˴ѹʲӺůѷį󵴵ҸȰռͳî 󻺻󱲲¶·ø                                          ~~   󁂂  腄    򉈈 񊋊                            𴳴    󶵶򶵵   鷶     𹸸  𹺺     󾽾񽾾 !񼽼                      .     %        )       &')     ~~~}|}||{||{{zyzzyyxxz~}|}||{zyx|~~~~}|}}||{zyx~}|{zyxÂ~}~}|}||{zyzyyxxwă~}|{zyxyxz~}~}}|{zyzyxxŅ~}|{zyxń~}|{zyx}~}|}|{{zyzyyx~~~}|{z{zzyxy~~~}}|}}|{||{{zzyx~~~}~}}|}||{{zy~}~~}||{z~}~}||{z{z ~~}}~}}||{~}|}|{{|~~}|~}~}}||~}|󆅄~}~}~}󌍌~􋌋󇆇󉜜ֳ״״׵ش ǵ     𼻼    󻺹 񻼼                                                    󳲳뽼x~yxxyxyxyyxzzzyyxzyx{zyxyyz{{zzyx{{zyyx||{{zyx}||{zyx}뽾}|{{zyzyyxy}}|}|{{zyx~}~}||{zyx~~}}|{zyx~~}}|{zyx~~~}}||{zyxx~~}|{zyxyx~~}||{zyx~}~}||{zyx~}|{zyzyyxw~}~|}||{zzyxx~}|{{zyx~~~}||{zyzyyxx~}}|{{zzyxy󺹺~}|{zyyx|~}||{zyx~}|{zyyx~~}}||{zyxx~~}|{zyw~~}|{zyx~}|{z{zzyxx|򼻻~}||{|{zzyyxx~}||{zyx~~}|{{zzyx~~}}|{{zyyx}눇~}}|}|{{zzyx~~}|{zzyyx~}}|{zzyyxy~}|{{zyyxy󿾽~}|{yx~~}||{{zzyyxy~}}|{{zyxx~}|{|{zzyxx~~~}}|{{zyx|~}|{zyyxx~}}||{zzyxx~~}||{{zyyx~~}}|zyx~}}|{zyxx~~~}}|{zyxx~}}|{{zyxz~~}||{zzyyx~~}}|{{zyyxxyˮˮ̮񰯮̯̰ͰΰͰα󯮯βϲϳдѵдѶѶѶѷҷӷҷҷҸӸԹԹԺ                                            󕔕󞝞󖕖򧦦𘗗𗖶𜛜򙘗󚙚𱰰𝜜󳲲먧󝜝󬫫󜛚򟠟백夣򶵶㨧ۤⳲ                                                       ~}|{{zy𽼍~~}|{{zyyxx~~~}||{{zzyyxy~~}}|{{zzyyxՀ~~}}||{{zzyxyy~}}|{zzyyx~~}}||{{zzyxx~~}||{{zyxx~}~}||{{zyyxz~~}||{zyyxx~}}|{zzyyx|~~}||{zyyxx~~}{zyxy~~~}|{{zzyxx~~}|}{{zyx~}}|{zyyx~}}|{zyx򈇇~}|{{zyyxy~~}|{zyx􁀀~~}|}|{{yx~~}}|{{zyx󂁁~~}}|{{zyxx~~}||{{zyxx~}|{{zzyyxx~}}|z{zyxx|”~~}}|{zzyxx”돎~}||{yx•~~}|{zyxÖ~}}|{zzyxxÕ~~}||{{zyyxÖ~~}}|{{zyyxxÖ~}{zyxxÖ~}}||{{zzyyxz~~}}|{{zyyxx×~~|{zyxė~}|{zzyyė~}||zyxxŗ~~}||{{zyxxĘ߀~}~}|{{zzyyxxŘ~}}|{{zyyxŗ򕔕~}}||z{zyyxŘ~~}}|{{zyxx~}}|{{zzyyx~}}|{{zyx~~}|{{zxz󕔔~~}}||{{zzyxw񈇇~~}||{zyx~~}}|{{zyzyx󒑑~}||{zzy픓~}}||{z{zyyᓒ~}}||{zzyx󉈈}~||{zyy~}}|{zzyy󏎎~~}}||{{zyy肁~~}}|{{zyz~~}||{zyz󅆅~}||{zz󖕕񌋋~}|{zz􆇅~}}|{{y~~}}|{{z~}{웚񍌌~}}||{{z~}}{z~}}||{{ԺԺԺԻ򵶵ԻԻջռռռռսֽֽ򷶵ֽֽֽ׾׾׾׾׾׿׿ؿؿؿؿ󶷷뮯񯰯                                                ︷泿󼻻񺹹࿾𹸸꺹⸷[󻺺~wxxxyﻺxxyxyxyxx򽼻yyxyyy}྽zyxxyywzyyzzyx}󽼼zzyxxѼҲѭҮѮҮҮүҮҮүҮӯү               z{{|}}~큂锕z{{||}~~{{|}~~z{{|}~~񃄄{||}~~􇈈똙{||}}~~||}~||}~툉{|}}~|}}~𙚚{|}~~߇|}}~~󇈈|}}~~󛜜|}}~~󕔕}}~}~}~~휝}}~𚛛}}~~킃돎}~~󅆆}~~}~󄅅󜝝~~󍎎暛~~𝜝~흞~~󏐐󗘘򋌌𜝝~󝞞񗘘숉덎뛜񎏏˙󕖖󢣁ꋌߋߎꏎ甕痘􉊊򗘙􋌌򥂃򊋋롢򙚛懈¯¯¯ð±񺹺ððððñ󻼽ı𽼽IJııIJŲŲIJŲųŲŲųƳƳųƳųƳƳƳƴƳdzdzƴ                                                 󼜜ﶷ󭮮򤥤𩪪羞򵶶󠡡񩪪󫬬󯰱ḷ䷸¡򼽾¡󤥥󭮮󶷷¡¢â꣤â񦧧󸹹â򾿿ã袣谱Ģģ걲Ţ󳴴ţţţ㨩驪ūœ갱~Ųx뷸Ŝxņx󱲲żxxŨxyڷŔxxāxyźxxyxyy󵶶œxyzŁxyz𳴴żwyyz찱ũxxyy娩뼽ŘxxyyױήԯɮҮǮؽӮɮ                                             Ūxxyyzz{{|}}~~Ŀxyyzz{{|}~Ŗxyyzz{|}~Ųxxyz{{|}~„xyyzz{{|}~Šxyyz{|}}轾ż{xyzy{{|}~őxxyzz{|}}~űxxyzz{|}~xxyzz{||}}~Ŧxxyz{{|}~xyyz{{||}~􍎎xxyzz{{||}~~ž|xyyz{||}~~xyyz{{||}~Żzxxzz|}~脅Œxyyzz{{|}~Ÿyxxyy{{|}~Œxyyzz{{|}~~yxyyz{{|}~Œxxyzz{|{||}}~䏐źyxyyzz{{||}}~~ŗxxyzz{{|}~Ľzxyyzz{{|}}~􏐐Ŝxxyyz{{|}~~|yyz{{||}~~ģxyyzz{}~xyyzz{{|}}~񑒑ŭwyyz{|}}~~獎Ōxyyzz{|}~}~ĸxxyyzz{{||}~~řxyyzz{{||}~~|xxzy{{|}~ŧxxyyz{{|}}~~ňxxyzz{|{|}}~Ÿxxyzz{{||}~~Śxxyzz{{|}}~xyyzz{{|}}~~ůxxyzz{|}~œxyyz{{|}}~~񊋋{xxyzz{|}}~~Ūwyyzz{|~Ŏxxyzz{{|}}~~񒓓zyyz{{|}}~xxyyzz{||}~󕖖xxyz{{}~󀁁퓔zxyyzz{||}~~xyyz{||}~}xyyzz{||}}~~򗘗xxyzz{||}}~xyyz{{}|}}~xyz{{}|~}莏yyz{{||}~~ދyzz{{|}}~yyzz{||}}~yz{{|}~ꀁzz{|}}yz{{||}}~~苌yz{|{|}}~yz{{||}~~ٗzz{||}}~~z{{||}}~~z{{|}}~}󇈈ꏐz{{|}}~ʮղͮ״ĮӯͮǮֱî԰ؿӯѮ񯰰Ү󺹺Үؿӯ®ֱŮ׳ˮٹѮݽؿְȮ񰯰Ѯر𶵶ְ̮ɮセٺ鵴ԯǮ﾿¯¯¯                                         󣤣󮯮򱲖򜝝줥񠡡󛜜󢣣ﻛ𹺻Ź񺹹ƺƺǺȻȻɼʼʽʽ̾;οοο                                                       𧦦               ²|}z||zxxyxyxxyx|xxyxyyzyyx}|xxyyxyyzyyzzyzyzyyxzſ|xxyzyzz{z{z{zz{zyyzyyüĥ~xxyyzyzz{z{ {zyxyyļxxyzyz{{z{{|{||{{||{zyxļŦ{xxyyz{|}||}}|}}|{zyxýxyyz{|}|}~}~}||}||zyxxŽxxyyz{|}~}~}~~}~}}|{zyx                         žŸ Ƕ  DZҸǰ󰯯־ӷ            #"       &        '        򙘗󨩩񨧨򟞞흞񟞞񟞞󠟟򲱱򩨧󴳳򬫫裢񢡠ﴳ𩨨զ򥤤歬𮯮잝󿾾ݳ򡠠ೲ亹𮭬П⡠뫪                                                  ~~}|{zzyyxx~}}|{zzyx~}|{zzyyxx񅄄~~}||{zzyyxy򿐏~~}}|{zyyxx~~|{yxz~~}|{{zzyyxx}|{zyxx~~}||{zyyxx~~}}|{zzyyx~~|{zyyxx񄃃~~}||{zyyx~~}}||{zyyx{~~}||{{zzyxx~~}{zyx僂~~}}|{z{zyyxx~~}}|{|zzyxx•񁀀~~}}||{{zyy•~}|{{zzxyw•~}}|{{zzx•~}}||{{zyy~~}||{zyyxx–~|}{{zyxÖ~~|{zyyxÖ~~}}|{zzyxyÖ눇~~}}|{zzyx×~}}|{{zzyxx×~}||{zyyxØ~~}}|{{zyyxx𒑑~~}}||{zzyyxė䂁~~}}||{zzyyxØ~}||{{zyzyxØ~~}|}{{zxę򊉉~}}||{zzyxxę􍌌~}||{{zzyyxę~~}||{zzyyxř~~|{zyx|ř~}}|{|zzyyxř݃~}||{{zzyyxwĚ~}}||{zzyyxĚ󅄄~~}||{{zyxŚ솅~}~||{{zyŚ򌋋~}}||{zyzyx{Ě򎍍₁}~}||{zzyyxx񒑑~}{zyyx򔓓~~}}||z{zyyx눇~}||zyxxބ~~}||{{zzyxx񔓒텄~}}|}|zzyx􏐏~~}||{zzy򕔔~}||{{zyyx퓔􇆆~}~}}{{zzyyx|~~}|{{zzywۂ~}}||{{zzxyx򏎍~~}}|{{zyyxw~~}}{{zyyx䕖~~||{zzyyxx䍌~~}}|{zzyyx땔~~}}||{{yx𔓓~~}||{{zyyxx~}|{zzyyx~~}||{{zyyxx򕔔򊉉~}||{zzyyx~~}}||zzyxx󵶵Ի򳲳Իռռռռռռֽֽֽ־׿׿׿׿׿׿                                           河󧦥鿾󩨨񮭭𨧧ꮭ򣢢񨧦ﳲ깸墡殮󿾾竪캹ꦥ򸷷󪫪橨񭮭󢡠򰯯𷶶辽󰯯򰯯𶵵򺹹ꪩ﨩󤥣磻训㿾󤣣죢񦥥짦譬⾽鿾殭𧦦緶楤񲱱򿾾죢難ﷶ󴳳                                                  톅~~~}||{𒑑~~}}||{{끀~~}}||{~~}}||{~}|{䓒~~}}|{{󓒒~~}}|~~}}||󎍍~}|~~}}||Γ~}~}}|~}}|𘗗醅~~}||𛚚~}}|󓒒􇆆~~}|~}}~~}鋊~~}|₃~~}}탂~~}}~~}|~}}򃂂~}}󙘗~}옗~~}󕖕~~~~}㒓~}ؗ~}~~}~}~~~~~~󓒒勊~~򞝜򑐐~~א~鐏~~畔~🞞􏎍~~򊉉~쑐~󆅅쑐梡ʃ~ۃ~򌋊~퐏~雚󍌌雚킁~~𜛛ꄃ~ꑐ~񈇇򇆆~~񽾽񱲱󿾾                                                 zyyxxzzyyxzzyxzzyyxx{zzyyxzzyx{zzyxx{zzyy{{zyyxx{{zzyxx{{zyxx{{zzyxx|{{zyxx{zyyxx|{{zzyxx||{zyyxx|{zzyyx||{zyyx|{z{zyyx|{zzyx|{zzxyx|{zyyx||{{zzyyx}|{{zyyԕ||{z{zyyx}|{{zzyx}||{zzyxx}|{{zzyyx}||zyxx}|{zzyxx}}|{{zzyxx߿}}||{zzyyx}}||{{yyx}||{zyy꿾}}||{{zzyy}￾}}||{zzyyxx}||{zzyxx~}||{{zyyx}}||{zzyyx}}{zyx}|{zyyx~}}|{{zzyyx}}||{z{yyx~}||{zzyyx~}||{zyyx}~}|{{zyyx~}}||{zzyyx~~||{zzyx|~}}||{{zyyx|~}}||zyxx~}||{zyxx~~}|{{zyxx~~}|{|{zzyxx~}}||{{zyyxx~}}|{{zyyxx}~}||{{zzyxx}~}||{zzyxx~~}}|{{zzyyx~~}}|{{zyyx~}}||zyx~}}|{zzyyw~}}{zyw~}}|{{zzyxx~}}||{{zzyyxүӯԯӰӯӰӰ԰ձձ԰ԱԱձԱԱԱԱԱԲԱձղ 𤥂ㆅꛜ􆇇ޛ茍厏ܚ򗘘񟠠󢣣ؕ唕򐑑򕖗󤣤瓒爉􌍍앖򍎎󓔔܏줥󎏏楦򜝝돐򜝝⦧钓򙚚팋󞟟􏐐񃄄裤獵딕򓔔򈉉򘙙𕖗藘흞򡢢뇈󠡡򒓓򦧃᝜񣤤򔕕򝞞򟠠ǴǴƴdzdzǴǴﻺǴǴ󷶶ȴ󻼼ǴȴȵȵȴȴȵȵȵȴȴǴǴǵǴȴ                                               ňxxyz𮯯{yxyzŴwxyyz򩨩ťxxyyzŗxyyzzʼnxyyzz쪫{yxzz{Źxxyzzūxxyzz󬭭xyy{Œxyyzz{꾿ņxxyz{{󪫫򺻻{xyzz{ⲳxyyz{{xxyzz{Ŧxxyyz{|xyyz{{幸œxyy{ʼnxxzz{|Łxyyzz{{ﭮ{xyy{|xyyzz{|ŷxxyyz{{|쩪ŭxxyyz{{ŧxyzz{|竪پšxxyz{{||𴵵řxyzz{{|켽Ŕxxzz{|躹ŏyyz{|ʼnxxyy{{|Ňxyzz{|ﰱłxyzz{{|񸷸}xyzz{|}|yyzz{|{|뮯yxxzz{||}xyyzz{|󴵵xxyzz{{|}򬭭wyyzz{{|}xxyzz{{|}Żxxyyz{{||ﴵwxxyzz{||⭬xyyzz{|ﯰĶxxz{||Ŷxyyz{||ľxxyzz{{||xxyz{{|}򻼼xyyzz{|xyyz{||wyyzz{{||𳴵|xyyzz{{}|xyyzz{{}|xyyz{{|﫬ņxyzz{{|ﵶxyyzz{||󳲳ཾōxxyzz{{|򯰰񼽽xxyzz{{|就řxyyz{{||Ŝxyyzz{{|ţxyyzz{{|ﴵŪxyyz{z{|򨩩Űxyy{|鱲ķxxyy{{먩xxyzz{{|ꪫ|xyzz{|طװϮǭطװҮʮîٵׯӭͮȮ®ׯԭЭˮȮĮسذׯծ֮֮֮ӭЮЮЭЮծ֮֮ծ֮رضع®Ʈɮ̮Ѯխ                            {|}~򆇇뙚{{||}~~{{||}䑒z{|}}~~󓔕z{||}}~~傃㒓{{||}~~{||}~{|}}~떗{||}}~􇈈{|}}~쌍||}~򕖖{|}}~ᓔ||}}~~􃄄{|}}~~|}}~~퓔|}}~~񃄄撓|}}~󎏐󚛜||}~~||}}~薗|}}~~遂𙚚|}}~|}}򋌌|}~~|}~~|}}~|}}~~|}~~}}~~}~򂃃򒓓񛜜|}~~僄}~ꀁ㕖|}~~􌍍}~~􀁁󉊊֑}}~~㋌򜝞}}~~}~~}~~큂Π|}~~}}~𕖖}~琏}~~툉흞}}~~􅆆}}~뜝|}~܊}~~}}~憇}}~~ⅆꝞ|}~󛜝|}~}~癚|}~~鐑}~~􌍍뚛|}~~𑒒}}~~閗}}~~}}~􍌍|}~~쌍|}}~􃄄|}}~~|}~~|}~~񖗗|}}~~}}~쇈ߙ|}}~~ðððïðððİðı󽾽ðıñİİİıðıİıİñİðıñİ                                               䠡뫬줥骩䧨󫬬񼽽碣󵶶آ🠡𮯯Ÿ좣 罾Ÿꩪセàßﴳß󢣤񯰰񼽾 ϮààﲳĠ庻ĠĠ殮򻼽麻ġﭮġﴵĠĠ߶šﱲĠⴵġ諬Ġġ󬭭šġߪšġ󰱱⺻ŠġשּׂĠꫬ澿Ġ歮ĠꮯĠ򥦦Ġ姨۷Ġ嵶ġ𭮯򸹹á緸àà𯰰ß墣벳𳴴 𩪪뵶ß򦥦趷àݡ                                                Źxyxyzz{|}|}}~~~}|{zzyxIJ~xyyz{|}~}~~~}|{zzyŲ{xyyzz{{|{||~}~~~}{zŸxyyz{|{||}~~~}}||{zxyyz{|}~}|zxyyz{|}~}|{ŕxxyyz{{|}|}}~~~|{ŧxxyzz{||}~򂁀~~|Ź{xxyzz{||}内}}Èxyyz{{|}~ }ţxxyzz{{||}}~~ż|xyzz{|}}~~~œxxyzz{{||}~􈇆~Ŵxxyyz{{|}}~~􈇆~xyyzz{||}~匋Ŵyxxzz{{|}}~~ߌōxxzyz{{|}}~~xyyzz{{|}~~򎌈}Řxyzz{|}~섅󐌃|xyzz{||}}~~􌍍ĩxyyz{{|}~떘ōxyyz{{||}}~ąſzxyyz{|{||}~͇ĩxxyz{z{|}}~~Ɖőyxyyz{|}|}~~ߌ~yxzz{|}}~ːŶxxyyz{{|}}~~ᐑŤxyyzz{||}~~ЇŔxyzz{{||}~~όŃxyyzz{{||~~̄yxyzz{{|}}ŷxxyzz{{||}}~ψūxyyzz{{||~~njŢxxyy{{||}~}~ɈŚyxyzz{||}~~ȉőxxzz{{||}~~Džōxyzz{{|}}~~΂ņxyzz{||}~~ݍņxyzz{{|~܌łxyzz{{}~푒|xyzz{{||}~ꓔ~yyz{{||}}~띜Ňxyyzz{||}~ǁćxyyzz{|}}~֊Ĉxyyz{{|}}~ۛŐxxyy{{||}}~ĕxxzz{{|}}~燈ŝxyzz{||~Ŧxxyyz{{||~}~퐑Ųxxyz{z||}}~żxyyzz{{|}}~쉊|yyzz{{|}}~~䂃ĉxyyzz{||}~~䃄ӗėxyyzz{|}|}}򎏏xxyzz{{|}~~ĺxyyzz{||}~~xyyz{{||}}~~Ŕyyz{||}~Ūxyyz{||}}~~ſzyyzz{||}}~~xyyz{{||}~}~ţxxyzz{|}}~yxxyz{{||}}~~xyyz{{|}}~~Ҳαΰ ѲԲ׶ȮѰ 򶵶Ʈ Ӱ ήή빺ѮֱɮغԯȮټرЮƭܸؾش֮ЮɭĮػعضضسذزصصطػؾ®ȮήӮطɮҮؽɭծٸŮӮ                                       z⣢y򸷶yx֡yyzy{󾽼ԡzyx❜{zx{zy󨧦➝{{y󱰰󧦧|zy괳ޥ|zy겱ܜ|zy󫪩ˢ|{yП|zy罹|z꟞{yҧ{뛋ﮭ⣢򮭭𪩩거𤣤񦥦򬭬񢣢󙘘 罹 񘗗 ¯°°                                     "           ꜛĎ~~}}|{{zzyyx􏎎ˁ~~}}|{|{zzyxw~}}||{{zzyyx󙘗􍌌ԅ~~}}||{{zzyxx~~}}|{zzyxwօ~~}}||{{zzyxx틊~~}||{zzyx掍~}}|{{zyyx}~}~}||{{zzxx큀~~}}||{{zzyx񙘗苊~}}|{zzyy뉈~}}|{zzx~~}||{{zyyx􍌌~}|}||zzyyw~}{zyyx~|{zyyxy񘗗~~}}||{{zzxy~Ś~}}|{{zyxxř~~}}||zzyxxř嘗񈇇~}}|{zzyyxę𘗗~~}||{zyyxxĚ󆅅~}||{zyxyę􊉉~~}|{{zzyxxę򅄃~}}|{{zzyyxĘ~~|{zyxxę~~}}|{zzyxxŘ懆~~}}||{{zyyzĘꆅ~~}||{{zzxØ퓒~|}||{zzyyxØ~}}||{zzyyxxė񉈈~}}|{{zzy{×킃~~}}||{{zzyy×􁀀~~}}|{{zzyxx×~~}|{{zyyxxÖ~~}||{{zzyyxÕ~~}}|{{zzyyx~~}|{|zzyyxw~}|{zyxx•~~}||{zzyyx”~~}}|{{zyxw•􋊋~}|z{yyxx”~}}|{zzyyxx򅄄~~}|{zyxxy~}||{zyyxx󁀀~~}}||{zzyx~}}|{{zzyx~~}|{zyyxx򏎎~~}|{zy{󏐏~~}}|{zzyxx~~}}|{zzxyy~}}||{zyxy􃄃~~}|{{zyyxx~}}||{{zyyx~}|{{zyyx~}||{{zyx~}|{yzyxx~~}}|{zyyxx~}}||{zyxz~}}|{zyyxx~}}||{{zzyxx~~}}|{zyyx~~}||{zyx~}}|{zy~}}|{zzyx󾿾򯰰ؿ鱰ؿ󵶵ؿ׿׿׾󽾽ֿ־־ֽֽֽֽﴳ򰱰ռռռջջԺԹԹ󰱰ԺԹӸ                                       忾ݪ孬򶵵𣤣꽼򫪪𺹸触𼻻񨧧죤󿾾櫪寮㥤򷶶馥񦥥㰯󮭭粱𸹷שׂ򥤤쿾򧦦󲱱梡쵴򦥥睊񣢢Ѯߢ㰯򶵵ٟ𳲱㪩ﲱힿ򭬬ﹸ򝾽ﭬ󞝝                                             ⑐~ؑ~읜ꈇ샂~󟞟~엖ܘ~띜򇆅~~~~~ㄅ~~ء~~狊~~玍~ބ~~~~랝~~~~~}񊉊~}~}艈~~}~}~~}򛚚쏐~~}쌋~~}ϒ~}~~~}~~}}񘗗~~}|𛚚ي~~}}􄃃~~}}ߞ~~}~~}얕~~|}~~}}|~~|}邁~~}}|~~}}||ꘗ~}||~}}||񂁀~~}}|{~~}}|{~}|~~}||蕔}|{񕔓~~|{蘗򆅅~~}||{{쓒~}||{{񕔔~}}|{{~~}}||z攓~}|{z~}}||{{󍌌~}}|{z~}||{zz~~}||{zz񵶵򼽼겳𷶷򸹸񾿾                                                  ~}|{{yx~~}}{{zyxx~}}||{{zyxx~~}||{{zyyxx~|}|{{zyyx~~}||{{zzyxx~~||{zzyw~}||{zxyx~}}|{{zyyxx}}||{zyx}~}}|{{zzyyx}~}||{zzyx~}}||{{zzyx}|{zyyx}}||{{zzyx}|{zyy~}||{{zzyxx~}}|{{zyyx~}}|{{zyyx}|{yzxx~||{zyyx}}{|{zyyx}|{zzyxx~||{zyxx|}}||{{zyyx}}|{{zzy~||{{zyyx}||{{zyyxx}|{{zyxx￾}||{zzyyxx||{zyxx||{{zzyyxx}||{zzyyx}||{{zzyyx||{{zzyyx}|{{zyyxx}|{zzyyxx|{zzyyxx|{{zyyxy꽾}{{zzyyx|{zzyyx|{{zzyyx|{{zyxw|{zzyxx|{zzyyxy𾽽{{zzyyx|{{yyx{z{yyx|zzyyx{zzyx{zzyyx{zzx{{yyx{zyyxx{zzyxyzyxzzyx{zyyxzyyxw켻zyyxyzxxyyxxyxxzyx~ձԱԱձԱ԰԰񱰰ձ԰ԱԱ԰԰԰԰ӰӰӰ԰Ӱӯӯӯ󯮯ӯӮҮ  㝞򕖗񦃄㟠댍󚛛샄򔕕椥𐑑򙚛񡢢􇈈좣削󤥥␑ӌސ󥂂󚛛󤥥󉊊񗘘棤󤥂򊉊󓔔颡ꑒ͞놇󍎏񤂃񤁂㑒񠡡ꡢ󓔔𐑑욛ކ𒓓蜝󞟟񎍎ፎ萑󐑒󎍎ۙޑ𔕕풑󔕕𞟟񋌌󚛜~~턅򑒒~󂁂~~󄅅枟~~랟}~ȴǴ򶵶dzƴƴǴdzƳƴdzǴdzǴdzƳƳƲųƲŲųŲŲIJŲIJ񿾿ı󼻻ñıı彼ı                                             Ńyyzz{򵶷xyzz{{򮯰󷸸yyz{|紵şxxyzz{{Ūxxyz{z{Ŵxyyz{廼žxxyzz{{yyz{ىxyyzz{黼ŕxyzz{񸹺Ţxyyz{wxyzz{żxyyz{~xyyz{澿ŋxxyzz򸹹Śxyyzz𩪪xxyyz㴵xyyzz򫬬񵶷{xyzzŊyyzz󽾿xxyzūxyy磌ŽxxyyŁxyzŔxyz󩪪𱲲Ŧxyyxxyxy󩪪򲳳Œxy𰱲xxﹸŻxyŃyřx弽Ůx{쨩񨩩żţţ󧨨줥ģģާĢﹺĢ᷸â󭮮񸹹á馧áá񫬬á󾿿á㻼á쾿 󹺺믰򦧦ؾîɭέծŮͮӮظȮЮׯʭӮؽƮѮױǮӮشְ̮ػ                                           |}}~~䒓||}~~ᘙ||}~~잟|}}~~ݒ||}}~~{}}~񅆆͟||}~~||}~{||~~||}}~{||}~~{|}~}󆇇쎏{{|}}~{|}}~~얗{{|}}~~z{|}}~풓z||~욛z{||}}~~z{||~􌍌z{||}}~򓔔z{||}}~~󀁁ꈉz{|}~󚛛z{{||}~~z{||}}~~z{{|}~~陚yzz{|}|}~~ޔzz{{||}}~~yzz{{|}}~~󗖗yy{{|}}~~򎏏y{z{||}}~~󎏏yzz{||}}~~셆yz{||}}~~yzyz{{|}}~앖xyzz{{|}}~~xyyz{{|}xyyz{{||}|}~xxyz{{|~񄅅yyz{||}~xyyz{{||}~xxyzz{{|}}~~𗘘xxyyzz{{||}~~ዌņxyzz{|~Šxyyzz{{}~Źxxyyz{{||}}~~𔕖ņxyyzz{{|}}~~Šxxyzz{|}}~~Ľyxyyzz{{|}}~~Ōyxyz{{||}~Ũxyyzz{||}~~|yyzz{|}}~􊋊yxyzz{{||~}~Ųxyyz{|}}~~򆅆󔕕Ńxxyzz|}~~šxyyz{||}~~ſzyyz{{|}}~Ŕxxzyz{{|}~~ųxxyzy{{|}~~풑Ňxxyy{{|}|~~Ũxxyzz{{||}~~xyyzz{{||}}Ğxyyzz{||}~žzxyyzz{{||}~~꒓ŗxyyzz{{||}}~Ÿyxxyzz{||}}~~İïð𯯯¯¯¯󿾿򰲲񾽾ĮҮضîҮĮӮǮհؾήĮԯήȮײ®ԯ񴳴𼻼ؾѯ                                              ꭮ 𣤥ŸŸŸ覧𡢣Ỽ걲𧨨獵𰱱𯮯衢縹󥦦ﭮ򟠠𪫫켽򽾾뮭夣񸹹򤣤򶵶ꚜ읞𡢢񲱕񢣣󠟠𬭬񫪫ппϿξ;ξ;ͽ˼̼̽                                           ūxyyzz{||}}~~xxyzz{{|}}~Ŝxyyzz{||}~żyxyyz{{||}~Œxxyzz{{|}}~ĸxyyz{|}~ōxxyzz{{||}}~~ŷyxyzz{|}}~œxyyzz{{||}~~Żzxyzz|{|}}~ěxyyzz{{|{}}~~xyyzz{||}}~ūxxz{||}}~Đxxyyzz{{||}}~~ꋊļ|xyyzz{||~䋿Ũxxyyzz{{||}|~~􉈉Œxxyzz{|}~쾿xxyzz{|}|}~~zxyzz{|{||}~~񆇆ŧyyz{||}}~Řxyyz{|}~~xxyyzz{{||}~󆅆xyyz{{|{||}}~~Ľxxyyzz{{|}~Ÿxyyz{|}~xyyzyz{z{||}~Ĺxyyz{|}~Ÿxyyz{||}~~~xxyyz{||}~~Ľxxyyz{}~}~~xxyyz{{|}~xxyyz{|}~Ŭ|xyxzyzz{{|}~~~Źxxyyz{|{||}~˜xxyyz{|{|}|}|}}~xxyzz{|}||}~}~~xyyz{|}~}~~Űxxyz{zz{|{{||}~󿾿Þ|xxyz{|{||}żxxyzyzz{|{||Ŵxxyxyyz{|{||yxyxyyzyyz{zz{|ųyxxyyz{z{ź}xxyzyz{zxxyzyywxxyxyyĴxxyxyĹ}xxõñ백ʮױ®ӮؽѮ麮ЮؽүֲʮӰɮִЯǮؿ׹ֵ ԳҲѲѱѲҵԷֻ®ʰ Ҷ ֿͲսʹð ӽϺϺ λǷ³ƻ                                        󌋌  񏐏   񇈇醅󇈇  ~~~~~}~~~}~||~~~}||~}~~}}|}|{~~~}|{~}~}}|}||{~}~}}~}}|{z~~~~~~}|}||{z{zz~~~~~~~}}~~}}|}||{|{{z{zzy}~}~~~~~~~~~~~~}~}}|}||{zy}~}~}~~}}~~}~}~~}~~}~}~}~}}|}|}||{z{zzyzyyxyx|| }~}~}~}~}}|}||{zyyzzyyx||{||}|| }|}||{|{{|{{z{{zzyx{{|{||}| |{|{{z{{zzyzyyxyxxzz{z{{|{|{|{||{|{||{{z{{zzyzyzzyyxzz{z{{z{{z{zzyzyzyyxzyyzzyzyzz{z{z{zz{zzyzzyxyxyxx{yxyyzyzzyzzyzzyzyyzzyzyyxyxx~x yzyzyyzyzzyzyyxyxxzxxyxxyxyxyxxyxxyyxyxxyyxyxxžyx xyxxy󇆎      𽾽   󽼼           񵶶 򶵵       󳲲 ﱲ겱 د  د ׮ ּž                              ~}|{zyx~}|{zyzyxy󽼼~~}|{zyx~}|{zyx~}|}|{{zyyxxy񻈈~}||{zzyxx܂~}~}}|{{zzyzyxx~~}|{zyx}~~~}}||{z{zzyyxx~}}|{{zx~}}||{zzyxx~~~}}||{zyzyyx~}}|{zyx~~~}}||{{zzyxyz~}|{|{{zyxx~}~}}||{zyx~}|{zzyx~}|{zyyx~}|{zyx~~}~}||{zyyxw~~~}}|}||{{zyxyx~~~}}|{zyx~}~}||{zy~~}|{z{zyy~~~}|{z{zyzyxy{󺹺~}||{zyx~}||{|zzyx~~}|{z{zzyyx~}||}||{{zyxxy}}||{zyx||{|{zzyxw|{{|{{zzyxz|{{zyx{z{{yyz{zzyyxyxxzyxyx}ﻺyyxy貱yxyxxyxwx򽾽򫿿ﹺԸӷҶ󱲱ѶѵҴѴϲϱΰͯͯͮ                                                        ﷶ✛󠟟󮭭򣢢򸷷񨧧񥤤񠟞旖藍󯮯񕔔▕򡠡ꔕ򽼻󼽼                                                        ~}}|{{zz~~}}||{zzy~~}}||{zz~}}|{zyz눇~}}|{zzyꈇ~~}||{zyy~~}||{{zyy~}}|{zyzx~}||{{zyyx~}}|{zzyx~}}|{zzyxy􃂂~~}}|{zzyyx~~}||{{zzyx~}||{zzyyx~}}|{{yx񎍍~~}||{{zzyyx~}|{{zzyxx~ė~}}|{zyxxŘ󄃃~}}|{zyxwŗ鉈~~}}|{zzyyx~ė甓~~}||{zyxxŗ~~}}||{zzxyxė~~}}|z{yyxx×󂁁~~}|}{{zyyxÖ~}||{{zyyxxÖ~}}||{{yxÕ~~}}|{{zyyxÕ~}|}||{{zyyx{Õ~}|{zyxÕ~~}||{{zyyxx”~~}}|{|{{zyyx”~}~||{zzyyxx”~~}||{zzyxy”~~}}||{zzyx~}}||{{zzyyxx“~}}||{zyzxx~}}|{{zyyxx~}||{zzyyx{~}}||{zyyx~}||{zyxxy~~}}|{{z{yyx~}||{z{zyxyx~~}||{|z{zzyx󎍎~}}|{zyzyxx~~}~}||{yx򄃃~~}}|{{zyx~~}|}|{zzyx~~}|{{zzyyxx~}~|}{|{zzx|~}}{zyx􈇇~}}|}{{zyx|~~}}||{{zyyx~~}|{{zyxx|~}}|{{zyx~~}}||{zxy~}|{zyxx~}||{zzyyx~~~}}||{{zzxyx~}~}}|{{zzyx~~}}|{z{yyx~~}}||{zzy~~}||{z{zyyx~~}|{zzyyx~~}|{{zyyxzﹸ󸷷̿ؿؿؿ׿ؿ׿׾ؾ򼻼׽׽ֽֽֽռռռռջ벱ջջ󰱰Ӻӹӹӹ򯮯ԹӹӹӸ                                     yxx򽼻yyxyxxyx󽼼xxxxyzy𻺹xx𺹄黺칸򺹸𸷷ﻺ򻺺񶵴뷶鶵󵴳ߴ빸긷糲򺹹񯻻泲үүҮҮҮѮ              }~~}~󅆆}~~􄅆}~~󕖖|}~~󌍎}}~}}~񜝝|}}~~냄|}}~~||}~~{|}}~~||}~}~󒓓{|}}~싊{|}}~󂃃锕{{|}}~~{{||}~~z{||}~~왚z{||}}~~􏐐z{{||}}~ꏐz{|}}~~z{{|}~葒z{{||}~~z{|}}~~􎏏z{{|}~~엘yzz{{||}~~yyz{{|}}~葒yyzz{||~yz{|}~~yz{{}~}~yyz{z{||}~~xxyy{{|}}~~񕖖xxyzz{||}~񓔕xxyzz{||}}~~􋌌}yyz{z||}~~xxyy{{|}}~xxyzz{{||}~嗘Ņxxyyz{{||}}~~퇈ġxxyzz{||~ľyxyyz{z{|}}~Őxxyzz{||}}~ůxxyyz{{|}~򍎍Ăxxyzz{{||}}~şxxyyz{{||}}~𕔕żzxyyzz{||}~xyyz{{|}~󒓓űxxz{|}}~Ąxyy{|{|}}~~鐑ţxxyzz{{|}}~~|xxzz{||}}~~葒Řxyyzz{{||}}~Źxyyz{||}}~~푒ōxxyzz{|}}~~Űxyyzz{{|}}~ąxxyyz{{|}~~􁂃Ŧxxyyz{{||}~}~xyyzz|}|}~~şxxyzz{||}}~􏐐|yy{|}Řxxyzz{|}~~yxyzz{|}~Œxxyzz{{||}~yxyyz{{||}~ŏxxyzz{||}~~Ĵxxyyz{{||}}~ñð񵴵ðð°¯񵴵¯ЮشŮ鼻ԯػ̮׳îԯͮ״ŮկٿҮ̮׵Ǯױîհ򺹺ؿӯѯϮ                                                             ۹򱲲򾿿򫬬󼽾󯰱빺󫬬ﻼ򻼽ﹺ󡢢梣򢣣校󠡡𸘙裤򰱲񝞝򴕖𜝝𮯯󫬫򱲓񡢡󕖖ѿпоϿпϾϾξνͽͼͼ̼̻˼                                              őxxyyzz{|}}~Ŵxyy{|}}~􄅅Ŏxxyzz{{||}~~Ųxxyyzz{{||}}~~ʼnxyyzz{{||}~~xyyz{{||}}~~ʼnxyyz{{||}}~~Ŵyxyzz{|}~~ߋōxyyzz{{||}~~xxyyzz{||}}~􄅅œxyyz{|}}~~Źzxyzz{|}}~xxyyz{{||}}~ž{xxyzz{{||}~덽Šxyyz{{|}~~Âyyz{||}~~Ŭxxyyz|}~ċxyyz{z{||}}~yxyyz{{||}}~~Śxyyzyz{{|}}~xyyz{}󊋋Ūxxyzz{{|}}~~Ōyyz{{|}}~}~ź{xxyy{z{{|}}~šxyyz{{|}}~~Æxyyzz{{|{|}}~ŵyxyyz{{|}~}~ŝxxyyz{z{|}|}}~~Åxxyyz{{||}~톇ŵzxxyyzz{||}~~Şxyyz{|}~xxyyz{{}|}}~~{xyyzz{||}~~ťxxyyzz{{||}}Đxxyzz{{|}~xyyzy{{|}~񽼽yxyyzz{||}~~şxxz{|}|}}~𶷸čxxyzz{|}~~ſxyyz{||}}~}~~Ŵyxxyyz{{}|}}~Ŧxxyzz{}|}~~ŕwxxyyzz{{||}~xyyz{|}}~Žxxyyzz{{||}}~Ŵzyyz{||}}~xxyzz{||}~Ŝxxyyzz{|}}~Ēxxyyz{|{||}~}~~xxyyz{|}~Žxxyyzz{||}~xyyz{|}~|xyy{|}~Ůyyxyzz{|}~ūxxyyzz{|}~}~ţxxyyzz{}|}}~򵶵ţxyyz{|}xxyyzyz{{|}Ěxxyz{|xxyyzz{|Śxxyyzz{{|Śxxyz{Śxyxyzz{z{xyyzϮ򹸹ήͮϮϮ񸹸ؼѯհĮ򸷸׳ʮѯֱɭүĮϯ­׵Ю®ضҰǮػճίĮ׺ԳϯǮֶԱ󰯰ίɮ®׸ԴҲΰ̮ʮŮŮ                                        񛜜񨩨쪏􏐐􊋋񌋌񑒑󄅅甓~~~~}~~}~}~|}~}~~|}~||}~{|}}~}~~{|}~~ɻǹȹȹǹŸŸŷķöõ𾽾񻼼                                                         󫪫                    ǿƾľ     󼻼                                                 󹺹     򵶵򳴳         槨            󘙙򚛚                         "    %          !           H     . )   $%     򵴴󰱱񪩪󭬫򝜜󪩩󦥤𖗖𜛜󏐏                                                              󉣣􈡡򈉈򅆅󓒒~~}~}~}~}~~}􅆅~~}}|~~}|{~~}|{{~~~}}||{{􆇆~}|{~~}}||{zz~|}||{{zz~}|{|{zz~~}||{zyy~}|}|{{zyx~}~}||{|{{zyyxx~}}|{zyx|~}||{zyy|~}|{zyxx|ō~}}|{z{zzyŌ~~}}|}|{{z{zyyxċ~}|}{{zyxË~}|{zyxË~}|{zyxyxŠ~~}|{yzyyxx‰~}|{zyx渹򹺺𼽽κعع׹׸׸ַ                                             ~~}}|{{yx񁀀~}}||{{zzy~忾~}}||{zzyyxx~~}||{zzyyxx~~}|}|{zzyxx~~}|{zzyyxx󾽽~}}||{{zyx}~~}}||{zyyxᄑ~}||{zzyxx~}|{zyyxy~}|{zyxx~~}||{{zyx~|{zzyxy~~}}|{{zzyyx~}|{zy⻺~~}}|{zzyx~}|{zyyx򹸸~}|}|{{zyyx~}|}|{{zzyzyxx񸷷~~}|{|zzyxx~~}}||{zy􀁀~~}}||{{zyx{񸷷~}|}||{{zzyxx~|{zyxx}|{zyxx~~}~}||{{zyzyxy~|}||{{zyyx~~}|{{zyx~}|{zyx~}}|{zzyxy~}{zyyxx~}|{z{zyyxx~}|{zzyxx~}~}||{{zzyxx}~~}|{zyxz򲱱~~}}|{|{zzyxw~}}|{{zyx~}}||{yx~}}||{{zzyx}|{zyx|}||{zzyxxz|{zyxx|{|{zzyyxxw|{z{zyyx{zyyxx{zzyxxzzyxxzzyxxﯮyzyyxyxyyx}𰯰xx|x||ﯮҸҸҸѷҷҶѵеϵϴϳγγββ񰱰̰˯̯˯̯˰ˮʰ                                        򵴴󳲳񮭭򤣭            ōxxyzz{{|}~Ŵxyyzz|}~ʼnyyz{{|}~xyxyzz{{||}~~ʼnxyyz{{||}~ůxxyzz{||}~~Ōxyzz{}~xxyyz{{|}~~Ŏxxyyz{{||}~~xxyyzz{{|}}~~őxxyyz{{||}~~Ÿxyyz{|{|}~~򄅄ŕxxyyzz{||}~~zxyyzz{||}}~~Ŝxxyyzz{{||}~ſ}xyyzz{{|}}~~ ήط̭̮ϮϮѮӯ®Ա          򘗘짨󙚚ꚛ ̻ʹ                 ŜxyyzxxyyzyxyyzŬzxyy|xxŸxŽ񺻺︹Īêé© ŮǮʯΰѲӵ                   z{||}~z{{|}~yzz{|}~yyzz{|}~}~~yyzz{|}~xxyyzz{{|{||}~xxyyz{|}~xyz{|{}|}}~Õxxyz{|}~}~~Šyxxyz{{|}~|xxyz{|}|}}~~ŷxxyz{||}~}~~xxyzz{z{|{||}~񆅆Üxxyyz{|}~~Ū|xyyz{z{{|}~}~~xxyyz{|}~  ׾Į˰дչɰѵ                    󙘘                                  𽾾 -       &       󋊋  󻼻                   ~}|{zyxy~}|{zyxz~}|{zyxx|~~}|}||{|z{zzyx~}||{zyx~}|{|{{zyxx~}|{zyx~~~}|{z{zzyyxx{~}|{z{zzyxyx~}|{zyx~}~}||{|{{zyx~}~|}||{{|{zzyzyxx}~}|}||{{z{zyzyyxx~}|{zzyx~~}~~|}||{|{zzyx}~}|{{zyx ׷ֶնյյԵԵӴӳӳ             򪩪򨩧򰱰礣󧦥                         ,nK7%XSelection Mask 2XVXz~ "&*.26:>BFJNRVZ^bfjnrvz~@,nK7%barry-0.18.5/desktop/images/background.png0000644001161500056700000043066412242254476020034 0ustar cdfreycdfreyPNG  IHDRXʙsRGBbKGD pHYs.#.#x?vtIME )W+stEXtCommentCreated with The GIMPd%n IDATxY$K(YDC>0b{5bz/wc|-GDv7I2cqw3SaaaƷ/=Aglw}Ϳ㛃g{7?af[>v&>7ίMH,oV^x_+ྮGfW/`h ^#lydl38V<^,_~77"|?ARcq~)s#|^xp/ٽcM⓻3sm?Ͼ>e`^?o,GDs;(Gz oqmsx+ xg <;je!}i8R"?X[=$Mux0Ijhe6=(OǿC*Kn#=FA@L6'Plr2ֹb82&Ǻ$G̗8fg~>[ewL>wڵ~bZ]y[p1#pi}VŸ\a]bO8hu3}eL^8\,ȹ)FZ8#%h%Cw +e1\ bOղ?~FmDL2H^?^~b"a͢JWhF3bE_%m0${R.=qwI?^!a)A1͌GrAay:DC?L[af]҅SK=,n#Cv%pŃoWc珃D @5g>'߄2z'.1)($mYL}H!FJDlz{p1CΘUect+(??tDA}pk iaxUk7Ao +8>|Jy& K!?L'Q<$A[fv+!Tht L \jg %: β14rB r{Q^ P X+]|ބJ =:|w:h&{+_zAbx\၄!QY&qBz􆁊vtH%']l(Igm&Wn/A*B BQQ9@>S@kҹ~&i]\;7q_#g]+:$QR#Qg0zB>a[=8HD;m[V@i6vyT3Kxp*&*/.k9G# Z"tL2L&i,3 Nw9ʙiRW%nV|PIt`4@$)ݱ&Ӹ1;oE@tN!FV]/DM}IsĖጚd KtM p59ċ0+p؛>ZCXm{!>aydIJo-@ub;,kRܥc@WʅD[$#>&~A?bʲI߮1BA,0+H( ǫoB kR8=#Z z\!9WC;(|ϭABo3<SEʑd=cm6ίlut\ {)Ժk+Lɯ_.*fu뢐% @gZWA^ޚV_0ָvg=QjXuJ(4hƒIM҃n.L)&+s Ab{Wi4kv6p^|ՙA1[W-t.OgU'p&NoowDxSqiyS$^ř<41bB~kOJ 1:,~Sv>ԫa@-A6[$a A3=oBb3C2ج{B[;@+\JkЭ bBM;J6'P7E-_b\jk7%ݯ#ŭJ5`@W &Gk=5lf@Fߝ@H!HAS"w {kBg|.Ztӑeɣ8NO.صaT1f@Yoxmp!p4cRdfIML_e4iiinAP?݃(/\<9>X 6=†<&#d#׿5FEIhP .@$/CfIl]ʳsGd)ӓepƮpk㼀&^6J譒q3:>(sF斋gQ¯#GϤ[,(?~&@E[0ƅ3yҼ-f" 1OF!G5AS5ݪW +x3ENYw&U_]~uW_1@;C>[UI׵f76pLХN,hu#sȺ@vYWl;ľ-=NS gBJUt/ľY-l^/cдP}ysjt*'Oȵښa%,p.j`MB>rQ#e6@f(MNqoG#YRv+]}uuCL}NG, 8%dhȬHV`*V&+U>3 +mM C,D^!CnmwYdnck8U8\8pɐw.%!̯CDE (i}ϺbU@!•\XI)0]1 zA 2?6{<"tmw7m#+8 RΈVlkCc1:řru.GJgU&+Jh-?F1 &XϘ%anöӘ )ϓ#%Y(NW/`e}{CZV `߆J.R)VӸKx" v!F "<͒a$Α6PT?&!- J`jB,p-26|J(^NF9.#oZBE/|œ0j qăB0_Mt\g#gݼ:> Z^b\L:~F| D^'g [! .]@ k)X`!2F% FZ3&L*?rYܫbQ\q|9v4}er^ٓf挣t!ˉɎ7W XA+AGDwvv'1؄\~j%(|ĉ1"ͱS}rz& FJ#e.A7- L0䫮7 "Ƌ20Fʊ^q;ZA%K?T6B.MTD,}d^pdHWxc €@*:31UqCF;9B.-סZ ZHhEb0 @Fwa<Y#!Bݓ'޷s-I4ѡt>⯤N*.c<h!Nv{0:;1T^֋:̲%1{C$+Dv'^8 |fjyXTUj1ȕ̈B嗙ջgš@qG0*LlZyFBLSRiTXX>ͤ, 94fD!GZbD';.A$J-$#{m]@rhd.EiA\56|]rIsj(n5׈s~kEFvo6h=RԒ(o׽J6D=c*.S37W!+lBB\-ZT^D9EK{` ][=[&իmMf.P)A!i[쫴n˜RWV`Uޓ89F6">{ Dxr&sQF{9ًXOnf?uVyd5=ǎ5#^Ӄd!{q [[V2XY,\_ ܒ:4 mz_Oa0ڔJz! j ̼OzoB0 bK F ]GY#s+oϮ ԊDPEHL8lJ2 3%)ԉuv~!3&#wQu0Z Xn]ZNĸ:+ˁKΧ#E/~x6tI`k=UY+E8Np6`^UlJK`0ym \}7]Ia ФIg>>K״䄔L&b%OF ɏCـW~* &Փ\tw Nj9eoyَ`$O4rksb9VlWbU#HN)*~&3Nag(bk\+`Zw@~}J|:Ԥ(r't;y`ׇ|HbWjzܭ?_QkaS,?x9odα`_6/ 5٨8{E{7IJrh&b4HVޠ]gD'NGCs[3ԵܔWuRdR䃱W Fm61VXݣO a8Z'tPQYTԴ!_Hzk`΅Y%=m,q.WeAr$ t\+5BEqK$AKz4_I"-j?;E;>wz^فM =&Uz[xKʒȒT3OW^Ź_ {dJPAHqh&j wngj}-,I{%>S]?8TLk-zorzuYb5Q,+p(> 5AVsQ>}r+JhXҡ WX]J7=vEɽD~eNs*n.K%}̀WLR^C^Q mI,PLs%[݄V"Vvpu[BFV^(gx@gC YNWzN½[S>Oo A-Sŏ;h(H,ňfB Y0Z~Mr)BG!H+ n}z#M= ?ATfHh`ZC1T63CQjޟlP /B?f[SC3Y+_m1tbOem(3~c&~?M<qLxj:3NC_AFmФ?A!A ֬L&к6щ9-\de6QA .A_գIh?ظÉ⎨xjls?6(= a CMsヲ)Kp '68hM3^t`W5 03=A$ !r6dr/<:KqSC`6ta$3n"\f#vRX+c0frˍen-ovRDy.sAW7O!wEsCE-.$KYB_қmb-r6HmZX0Lt&3oWQaUO&Uh"9GA*܏Z-U`s=F5HWYJME;ĆMdngHDj6llq24 #ws/iSrv0*pb&ҫ/c:3DDM&E]S5X<?I&#{? x:aedG 4h>YhPRaG* 9a 4iO`ӈO*4 'AT +:L*}&h@J^ZW}{,+heUA?Q(67*p$*dl| Ӿ|a @hh -t݋Ÿ;hbNϭBNHdH-jû_Y Pى8;뾍`S瑔a6 n'5Z3^Pie:金`^"j76z++1^wq8ʧHH6f3(zv6,!ѴdB%/V=i[A7{q@ATAZM.ZIwD2}E <51 l1A(ٓD}cɏo52-EB`O`*>7? Wz۟[VPpؑLp=4beƂrqB$`w?0/Um6g͘ !l)aAV GAhaoLLMa&,u `g6Wh@o<0_H p %ɦ[)K `^0 I9=["~=!аBcN̖ 1a4HvS)[y,T];UIq'd@f*nt&$:YrQjc~UѢZJ)!ڒHZnGE N+'5`:CjJc1SC54كB N^-,`C6!|9(Jf2C 6땬X&p`EhƠR!ۍ ɇVij|љnPfopa4fcOd/J ikHVEGúFrjͤXdw0wЁIK5obirItT]g63}HH,**h:X>Gː:5:BO#SԉSׇwqĹ`4 q!߼6Nk$=Kr6*%i$(6ȃÿS }vAホp I9(+|B Y'!g2Tm%Ueì.50?ܚ3i[A[LJ# IDATRk( ]J}w}Dg Vfñ:P E:PMmоwnt/3q6`AcW;""[$do@^'.Th;9']#q} bq!ln$.Q" ShQ>fDa! wI濲pKXE "Qnm32ba2iCOh5XF$JZRJ63BSf2d]χ'JL,"Ep)`Va Cce'*6`y< lJM2&(E)xOvނ 棉V|e%ts&c8t(]$ԕ ,Π\ZdGa0v<&HW?pVGU; u puH“zA!cEΤޚXn& }1MpFy`U V>9vVIs"w?"s 'HXe/j+^@d|+ʕ;ro?5F<}q.ppIF:euW&Y]# BEwGXr,{Pdf{2$0Z‹]t-)@3N eկz7] q>2W50? oG3(zNA<|o!p F?Yj݄[/\ ng3C[T&u^3ւFYޜLL. &,$,&Q*Z*##ixHm8wB{@\St !Ї)ǰK<~&.#Ť^BLYECypt`C &\Vk՗J7)&؍mq0BV[Σ"*P$9dFZ4z.az&9\4>ʹ|fN/ as7/C<&}%t*{zʢ%yL~upPlRKӝuӯBfU=f׷UIZe+ +m~# &β)2eBrG#:=KSfN:+rU|LcÉ:̢A.; ?9JJh&dpV蔵1b +&yLq5X/e/8GϮj5$k`&F7TgܛCo8r^ i,7 r*[QLeㅔn%IHs\tE|}`;'(4O-FlboSfKʢ{OW { `g``RXvЬX+/h4ԆME=mMiaHq}ۣv'}WV-w+/B:(8kcA$ *]x[a# 4Uٰ}zӔ]`@ۆ[0dze4IvǏv@opLɐ:H)deWdN.emb3,V "HN=cيx;%Gy[J>h\V,Cw;PFX um2Hjz@%]G^{K:anQx"BE, .='mw5/@+Iby῀*z*5ۡ$Y#W\(>e%ZBF8NKc:xiEAf=|dgK@ Lw ]YQ|&uڀª'пM{~-<mzx%]6YG[l).DI6F!%4QwRw(;\1(#s#_ZIZ|5f@ Io `?[\Y89τ4Bg6EO1)P6 >^ց;f6!$6k$٘Gmy/f|ޗW y` pg$A0) ` W7ATkkt삔0߂7h윶#Q|hP ^d“aP k#f '? I9L~E;a_Uٰ(ɸ:CQh( \tob7S"Y}a rK4tbYv9w 2Pr|Tƹ[BFAa#_O&'fXG?{lg%]~Gحx-7|T h쫇uvweMf"F(}_OM֫V@IFۖG'ӚAݜ3PY/oo yx`aõʌpO, I]0ZR6Qv' ^LJ*oMHw~m=q3BR"IRt+Ѣ}h# FkژsfpRs(0sv݊e$_dL +YM"=gr&0.SQZr+1y-YcHOS1əZSZ7~5 JT ڹɣ 3fAOgjʉx.HH:Ϥֽfc((ﴟwЦMIP3">"+|t,=tؼ=Z3WfpL G0(5'2=!4O:Av{<r77ؒKN˼Ƃ@Dra)8ab=Ic<&h6z=KuXg3& c5eJh0<9U0)1dn$vZC)epfr:]VD[K d1QDLzU Y X42Mض\q ᬍ{ ퟇Z%%tp%[nJ N%y$5( ;v֟E\y2kKX*2G̺D0{ ޷xJAjq }(O³~jOT@A\E7">hlG/=m9IÀ52΁8 /J-*?18-y7lz2@~%ilşgёkU6u])>!C1XAMD.DQ,GfmNh1աtզI3"'J/uY(Yp²9sY C-$~Cx{f60ig̑܊̡_ܓѹRX 2^6㻊&^bcotO 6$atb̴IZi":Vyvb(ZUIJvE(|ZoV3v<,6{r0W7[u!+"o! =_ܠ(qխ k &?lpk@w! ZdD>L\lh/3 IXHV;it '5gH^E}K&dIjz} #a&1";SH cX"Ey_Ѷ-*}"A \9A:&s'ki%Iɶ>ִ2YRȃlIr-Qn=xuxsfb$.^Jͯ#cNAnI^c xsĆ XVk2\(ZkHJ &۵RC e֡^͢t/L:=1vpwX~'+7d)xN<ހZTXg J` eT0GFhޛ+nlE1]FTȰEAV;O#42ܣd y`eE_S:x.f $F)?d*?Y;2jY~Q?[p iֆbx` d>$E>G-V jM:E ~^8^X$C4X[/k]xp1K Eͨ'ԇA0ѬN.4"TQJJe6gו \m*ʉSLH]%yz250~ڲVNw+vƴX/W5τi Eˁ(4w=>/fZL/hL U+,+xh:,#7 8ww%]rjrbt#CuNo 8*7$f)}CCTaEw4e<{q %O2Y8x#~R"iwrCc4>P|.4O:=2P nK_Rk1E`4 ^ X4H }'=P02َ(!%+ab›PP)& M[ \e$JAJq=8UѕY˻Q42UQ^DH$C"b~0 "QHI@oޗcp};1zZSX+X˽Ӯ 2q("1}g C)#W2C,).)zk&k;} k]qٞҏC?xOa`\84&U[>ċ?eqAӞCn.t'&C E#X+cj`)zYҰFʽAqC%t*ܚ<VkDI\ >j- CfR"rs@ߖkTVgur% _jH^Esuϐmf5[TPYܙuF6) Z-LmVT92цu88Υ0=;=`=Afj0PRf.A: 4 άԹ#iDV4#p'$:kSY/k%c`doO~ ]^%Ndy|:<9YB_63`h&a?n15e>NQq"^uQ8 eSqg_Vl(D@gϩAzu)2%8)j`pȠic,I|ݜ7Xـ H5@X!S蹱Q\VQcB>3:DdIqk`fbT&3&(%.h‡JO^u4 {"LW=.ywMwB/3y]~=&/$TtMr}ܭ@tDK+hf ؛E(4N9`RIچ^4Y{*^K)?ńaP xλ̏LJx?_;lѥwy{&]H΄:eQZawگR};8LD'Tޒ`㥬'| ,vC[ᨻTgU=#̐$k:P x7yN{ӡ6kD+Q>^7<5'5~42ʉHȅys L\8cȍvd Tѕ3yȷBZյc_F-/d`wB]=w _rAX7HW[ E@vYCOp^d |*Lf q S悊!DEs,Mkbq7ӓg$cX@ v(6c ? IDATSK;Гn5^j#=QǮ93yVdmW2u*p2\$)8?W1:>]@*ҠZWj]\?z<fmGPhBSi=5SBH yTVuVYjL-K\2-}Q =ϝfjǯ'V5:ŕCo}Al'H܀xt.SWDGC"Dh$!LSwbY݇im{#MGԃ TT~1;:0Ȣ4rupWfyZ>37WY@A .jo 23FʲƗu$Hd3 eO?Mn77| lNOѾ!޻j!im ,JlWWhS Rg{z*H㮏Қܮ= 0y6[HL`YI$W)`FRƒU P@d *y ??v=g`-Rf-i;#Q:K`ruʤpX@CFegm  q?*=Q8d)CN$QOfAnY͘Y<*a~T9O^TFBRԓNX恸E}F{ "5 t,‚ˠOf*+SMI5Ñ:C6a]xCNfmCׁ :}Dj8As$Rej0BBO(Q"?")my"ĚoZ^p'a7;-'Hu1D|FE}QNЩÐ{s jW+jhX1ecD^Cwfc ژE/?us*ZEA%$T eɈQ9Nhi#ñYQ o"s](q"vAZkp/eVۣY8) 3Օ.Pf\޿5>w93h*Af*R8855&/:r}I^QH_h[, v=Tj;k8~`sٯw>yn%WtwƩ l3xqEĵhr[PmllZw"5Qiu%EsKﴟof?qoR+[% j3*a_Y /ؠqӈ\VD5_kp1ܫ5kr݁&$ 9"*tf7pCNp|ۤq:t]yԄG`g1ZũG~3*ꂌi?rz"=4a~%.y^ 4\:pz$2DyTP~5,FDrD ]) 0ȐM= AEYZXesDL{INϤosOPT=$QQCrEEJv@?"4r;I?7X7ؕ068ùɧ`̗gT#{HDvG>C\G3һaJ'jx 2R MXG1C┹ήn#}s-ČwTǥ9tXuh~RW6 SKy$wк)0tdZ.l q A3_۰&+sKvz^ 겱LٍP Vt59o> ưHr? `348(\;"ǎ܈erlv"a#1g yYvӻHq}`޵|+-H4K hS;2RhF&I \Vž3ۚPtTµRQaVkt ]x-nDž ?bEnSl}vu;7d^ y:-"泑iJMF(k+*=@Cr#>Ympzi_&҇(̅x\!c'fh] * !M`3d< zĐkFvb#\I\{2:F0%B]$Lhe"В|ZА j9q߸v[lYotV#OD&Ri 6} *.ap0xxGC'@cxg%U1~g;ם.K?DKt ?)T1]THVߜF B5 *.N$?R`UcV%sLoحR•CH}ּH1;Pe %HP55M,5]_ʁIs2a<hخ#J> z(2u r `jS^Ĕk +.W"k0@>C݋0k?x]X1cS`8]JdZF>[@xۍ6hL",#sMߖ,^˱n^aL̮#R0"ć'N}Tm T.9dڎܪ heGicʨJP>y3q/ilvnr*/{%kߕg, %&ߎ["pc+jxzc<™NXi&O~ *+zGhu> )< ElD3@]&fg]V?~=#Pk8j^pLPT#1$6@xJz4'`󡿟Coq>u8#kulۮplV Lfz>Dnըjp Z AO7eU.$-%ŕ*rtW.N L^-`x~?yH&91'k K!xpIL9R 1bEaa r]1&sʞ N9+H4L%DfB'4p؎1)7%gp :*Y"HyXؑXoeS7vs,Nk,nl;"l*ȵ;s' c7*P \S5/ 90”BeXU|/u;b`2ڤMav8.}J׃q}͟XlqNW~N*&5ٽޗL}W-G8x mqpi 8UL=ԬI)M[,V#0U>Qgr<&Ҩea{>Tdg;[87.?#':ҹ?уUB\bxh*gV_gadbՒR\XO>73*?T&##Eg\7BGhԢz~?A{pb2H|->Cpl?W@Uh=-kg r/2F<{_o7|*:mg.T!w9EC5- 5xX4Il5v {L&ɛ #}ۧKPU&1[ {ynVAM:DOJ4A%iQZ@jk<68Wq]}/PU1 ;"s_ / |VXs.]4ԧ^_/Aeq_<(-Ιx度הl,¥x8&4+}Ҿ@uF7c*XNVM12:y;\jyMzrh\(ڒ.6˖CG~DGrE Z@)A #Yf;\^#6Y:[L ^^ncY5q0}ˮ#ɒEJN&OؿFc5JR(=z:@3QӸѽ %Uӝ $g{+Z i{ؿ{oXZO WV. ҤnBN<`Tdph!v)Cv#bml+-mFBXe?ѣd gkh ;t0oDLЈ*!k!bsM AT(啸,h[*Н%{DzXͲǺǤy>R?:8Yw/y`@ߊ#XAzGX[p4xF|AzGLoa+UխȘp} 36Q[x5]۽1"\Q.V4@@U5ELH8b0p+D:]3X M|c{ra⩉_+ |q(-/$ r;rN,1`/cȰȬ)÷LI1#}$ϡAuqSU'j5yI}M*;eR/vW>qg䡕)91]L-V#9'0icځWV lp|\xv{ 4\eJ^pYEt7?K|lq@q) \?B`eT l&sVߌ0FWxt? }24nA/¨^?-jzO iNQDVLEYYdNgOl튛LZ# s4RύC9qo4"Ӵsca1cþL (qc&`srF\:F(wD|P'E,%.4 xe?ͦu 3c3{|!:dL֠i+̊B^yg.vKi[F#d9a-ˊxSw:R2h] s0Y 6DePPlQN]ƵETuC~~$wVd||n` 1! D{Pz"dq֛P!J7,ԥDovN"_TdbK (匔d;)v#OK%N`Cac!em);b uC(|djMl:hn$ ]q(&{Kpv}`jQd:(^:(!p>Cnvn@rq(i] OBQV&HЃ"tZُ6n*ѯ]p"ſU`dFh9v;Ahy2w'fGφ?e]t@P' cϕgf*m<\pNwG5KARG,垱:O4tDYD\ie=Z+2I%udH#-קݶg ՗6VRFNe͚|~޷ːzS/ɂ bc 絕:&pkDgG V{Ӷ*}$|ilrJ{Bf&*s3V IsWh? BąA vNo''?긦)c #X.z : GgS,uz&Ə|~nlTuXQQņNn{2Y!/c>,jku47D6 -q"Ÿ#xY3;nuêQhԄ:`T5i]K=m99_]~IB>Q-4e^wFVJy8 &Eȡ%}%, am&% I7MXmz*_ CEL~9/6Km{8 FBLӞ?H[p*z S9v.3E9:q,)=3HNh6/YM{m*h> M ׺RIőUyhbjQ|ѹ o|_L=^֣^7 ֕Jt$"c8+PkQ r9%}ik\:˂5j˄ި|WEKa3DH PܓW'/B9.¥AMxdC/RO>VdJGWUO2aZH]{D dܮS_mބ'Ng5 / 91Fp"c9Z1&_OupHt]l5䅠 xGn`$\LVt֠[j5,IMѓHG~Y0ecC3Gp:\HP Kq3[hDdhgHJp>+g{~fUyfTPUa'-P_-y"*~[361r*|>W^aOi`A=񆒰1RC$V5*!tZB&4ʲxQ=T~7sbJh&TNuBj TpEb14=C?ŠS!UDCV7qYSP`Hp C܂R  CiUWK7eb"d̘|bL %]r?fZWjq&yտ:̟[mw&T_^ܵX۽:0c\Go!u+X(.{<\̲͙y^J-g8M|[OLTS-y!GOޢ'& q@GsШ)6A1=sJT0@T+MphN޷)_+ut$Dk"QX!tM;p*ش,oՔ&"!i0bDaM+*۳r@x2 j>%(5ۤ1'YO?C"æFdL \+~pn3:J u%d-@`_IXC짍6ԨnzU;D5#~{;$h)o {nY:܄y nF̣Q };(1 F$P:$u&m4L$dAvxׂV~go4ȁs K#,aqNB:f"Lnf`!;!1b4W:J=^VPl;dXN`'׏-VGiG-ޜ c]XB:Sz?dv-,FD4J 0ɗ n;H'1HEQ9exzvHZpa-*o3.}5xVD*T޷(A#ZѷkP|Fg0Z\lv"/tSEEѩC1=䊖2i݅nm%'PMG{tr3EAFrdį&%h[2ǛHkV@fBːbi4y eXvF$Y8@aiBPN5#Um/ͭIJ;G xGLǰ F%~i0% 'pma ;>ƒeՔdE (h6v,P c}MV;+| 9 L }^.3VwSן9Ne;)V/QF{;m烝̥e,GQszqXR̻;}pP8Կs0׾\a?"PPw|!28ـD ҂,CN0Z~?6ؘ ptQchld͇ST̅'_J02Pc@zIrI?_:~3uQ̭X5:ra;.1Hׅ2Y&eO{|j!OKJ"P**ۛO3S E۹RqڝϜK}~m"X~JCD?!`UD%ԛq3 Yxlnûxyv]ҕYM@éfO+a3cӵQIӄϹn%0Ýv;_DPR hK!>EUnSd5"!o#G"QB8_5rIl|$;8(+ӻ^JMU 秲n(e6Ĥ (.+V %p4ĺ&;A> 4 E*ɱ"DA>S\R_[(:&Oos°~ODnU,vc_#UWs4 >970bWX<,3TN'&M\-@2y|$d$fLEsB oBAXOQ yv|QŨ[\@7nA.nؚRa SYtYĪMMyjK$ݙ* <աW//S:_U LP^H7qsm3v9`!FE!XYDR}h_ ᰦP1iڕ3[-'alnU&-4zQX]jj=k `[QI-ۢĕ|剼R@YadfnʩxBpU˕5@Zo}Wy!cΚGΦbi^HW r{3mn8 ^lv)B!gG0MBssAyپm$I 3L:H"EQX`POrd"vwf2wxZd1;t& l@!m,_ܴJRn}qrUaR26fa3H{96A84ӅaY:D3-A"Ĝ\S^'0 3=˛Q4.aJZ JU]ۜmf\̋\3`k(òe%D`Q1Tnm 6I:ڨH]*#<{5Ղf%BQcxa99g\PËmaaHlG(̉S͙t2G]g&A}H冟evXdSl>V[043;LY 2]ehOB-7L%0a%EP P=ץW9mRI -rtPȢx+ -4M2[`Sgb՞F>p.O?cDuFA>+X7 ԍɨnGQQ]CJnjP. rwWqقEC.[Jzcr!Q7u0vwMd*OGuD+I8@ˁݮ")Sy\fWg"/K;h:5D3!<˯e-Ȝͅ˯1!/ؑ;#>& Na R ^ 2UDm.W4KA eW6T\#+DJ)<N j12%8Ҷ'h[fu>,x,P\ JZn.vjծg"K³f^3(EE0"OBt?@[框1T;77dsѺwػ-_dmhNQO*Q7Z*Boqy,b ~G zy*x,t 1,T{pj> Td8yEjؚc;d,Ǯ,b~FTt7tV{vv'>pt?/ie Gɺ:7y.Qj\]Ojt-e&t5 Qt]6iQh"xDXO,Ag:7"ޑ^Q{@)>X;/pa!2 Tf1yF}"MIqL/j k%j0B\v k`xkEp߾/i{+=Fh $#t_10'F-h "RIhM-$Fw*&Fı 1+C4eQ ~hv|< [r->a UXLT'_"Y3=t߰0EiE40l94&rʭ>+QEoJ8Zp`ϲ(~ (d:|E{YL9A*~e$Q*zV \PS~w "L^Zd9}TH=tڱ9ǑS?AxU"#O,Ɲ ~c6, %`˩ﰓpk'A~psR,bd&GVňar=6W4_?2OUK7w(#}*HЕ 5 "Qcu=֨@^2.\*H>)N02}HC/_- TaYD)Z|kZHȤ3yT/cRbpXԦ&eWC=Qzx8Ah*ѧ]imGC*V;j_'{ Z:,dB1ᒊzyDd jc+BEt{mth:_ ӽU=sxF~NB>}Ǎ&I>}lx#4ֆkɣ:g1eƣwEp\( ROrmSCI2ҿ|Q2N t\ݰp` > 8zaYP;ǕAZT]r*ƫþ{}**u~lޗs 4˙qi6-Er  7nwEKP#>h':D*>Ma2HFd ?COT4  -%N/0~WW`~{| W"1aw+d[B&r9eų82uI6 Z< 3A뒵F9͙ZBr" lD?`0Hԝ=Lnw9vK8ZuBk<hcLuY0KS\&FyFWv*&M0 texq)Lpb/a4ɵ/5ͨxEtV?ﳸ+{[3H4Ez~qhLTٿQIהg ~qIlKXMa.F8f}/^dѮkjrœj,;X0,$d$21]a7w|#KfjAT }k/ջ- ᗬ&t #<Awg珹T ( r*YX6OA~R!y@y j6,RBy IDATd~x+]j81pD4Q dNQ:v>ؒkA{l3H)Z4z+Lh8DUPo_̐R uvOf__ ïsH=@a==xk-;BxC;v9iِ-e; 1C DIiFT( DGD OV}lOQ=97p(DHk|lƲdb$ޱ8p|hV6UQ}ᵥq(5-SrZN?-]D2'B 0DŽmH+$% #kj +|2ǝqOm/8o T_{Ou~#m@H'm0eaݧm;#([8CX}Kj*tbU*@/͝Rra\1 oڇ_Jcbv'd#;;ZyU{A$͂ R2&XEDO3QXjP cNzvAp!ل2|w~.18БfiW+úxƒ'S/U/=npÊt>L65d(*ZƠnEUD|mѤt v=> +^R6`z'HFƆ^=\^|~syѬK(qQjqaw(d`f3NB4 O}^مux3,uiZWZy+dDR82,F[Gz5a+ heUxSE<;Y;;o`4'Ї.frߚ=Ƞ=`NB jJAv:BYR}fxf}W ) -?+ N4E 'Z]9}XI>,]Auv{t4ޙFLi ]#ͧӸfzŠC8C^mS mc< )XR`C,",]h]*7hQK7>\c8|Ogpc@}Þ<x{ljL p6&gSS71\5v?7QËr'bhѐ)pJ2>E+.rgD ^.ϤkJ}9{(&' #mf:>Wi\_n[ler9C`HӛpUD]L@D=h96i9 Xh hZi4K_鿕ruӘ]9FM Ci9aj-i;LmtXJfOSnna3 ŊzvUgwkrnvWT=aI6H&Tq/Ը |ӣeRsa ܯ[m]c#k_QYi2Վfev&v+yeKqen/AU=/t6XҚu^fc.x Ӆd_Щg mȹD5~DE @TgkG챞Q*DTO eynEa5ap|Tu9g2":" C->gNSw_{XE.3kKkc[|12I <D6<h1>Z>b 0-sS}|(u=X ^gփ:{L&D7-PQ/dgܶp]eϨEfۣƋEN!q~f*wzN6=co,0sD`zWN4kEH 'bC>űx 3hZo'KUSERkGJAgƿwٽ[#EsP$k8 $ZE3& qp{;V)"]\]`dkəsjꌞ=IÜZ?@^^(2˔I @%+>-*zԴbvB̨:Z"=C3֘hpJBDHZQ҆ED+]y$UAMɪ|B`ܬ|2rȩt[P6CX08f`Mu[.Eo5kUȞ;[O\9EbqPZ8xyqt& G7ϊ6[F b<ݭ9_oG.3DH̆j̬W7rbDg\e􀻒–_3?9'O鶱LQ=k UT.a F'v` 30F饡gz~ǯ VJcGAYs eu?Lɠ:X"J̇8%tQK8D/JG9G-yO{}KV'JƷ2[R&!5+ż:Jc Uj}2*,P"أ_E>0շXL֮JHy]r3Al<}=K{A +e괋XvA+F/ \DE 8(1&tzZ+ɹx2 AʦXмy i`D]ǝ^J-r}d>. yᙀUBC吆BJ+ˡ0y -!t14u)z/ z9\YLќ%+l˶Ύ}^mkAI\)UdVE4gHGm;!"[Bs/ FNn.RGAO-yldYY7 >+TƉ8q8l 0:"2ROh;Hp`,K0x|5.PVkI:y]o 4zcݼA1Լ@Ta3MmvvϹi|Hcji5086nW"y+D?P:XLsڥo='q{˭$7h~:3L-B֎es' ?=3<5=d.(k*z=Y$!$!I"K`JiZ|SnJDD3\?uD\r0sh% Kqj>GY &1I1#Y%|մ^R'Zɢ2yX)#yLA¡İUIYWqjAL~ڍc0 &:TbZX_\ip%B#ZΚaVF5?,ݓXܵvIrc`5_W9QkX gZvxq&. g,SZDKdCm,|óIMZѨu3; @˺n3ʃOm|p6/+ᢰ)etY!E3Vf**<2(@3,\17?>#=pN~D6H S^,tqmΌ6MHj^bэ fQ(儨haMp?E+2~F Ogw^t{˜5W> j>+C:-YJYvbFՈG7,M>>U08XwDqcM y_1d`E҃3m[ rELL E_n.~G̘6$يD;E{幔<,)Ӫ4ri a li8dO6-oo$.2:vh4x}AZ|M&./3>NT&4=qc'<.D[͢f+2_B62ܧ4[ˡ]u)bo$_D:o3p}jLCy֌IXO\YD]RꛏK;fHLt.MT:'*4lSd}/|s4?+tqͼޚH䓝}lۃY O,R҂6l:_;GaZZ _@ pW^0}+rqf܋fmbLp )l],ϕ +OM<ޚr{?ȣ"-%sjQ_N/.|UTy`0٩4arW6~UϺ4\*l) *Z!ij14VHL)Qhط}T* ~Cxna-Yɾya lPҴ$͋@drs;M5Ne/LxY**$t=7^h;WY9Q̆Gc >yhCEy 旕b?=I!aJ[l d7L5 D`Ρzn&C0Cs fʥj㲉WC4Ot%L~ca[ſszz Σ6:0ԢՓ5>izUάum_z&r.*^AѺȂ,dA\pPL FvR]XW؋€Y[<'Fc8?5C4YbLW킠 u]}f/gdZ6yyăߓY(v(fmScV%€ip9n/O3M~ų$r81e[ai'_t x-S / ]fE,p1tDK/a !o=6G1jDЊ˻fv-@vvB|' ~ %i}ӚpH.J:s WAk݉L>i3y66S3bO$ }m{/b ׽?^:yE41W(1s>`=WOjA3^+73+ٳ ݝ\;zA8g,|_VQZ.\\SDt@9J:]f B4IK'5Zb[Ը3"ה+0N.|fbATC?< 7#0@.ENu !X|5I=\ _B"7Ɲ,̕PtO-jңv)9X,Q O 4%r`@u.'d섯"Kw%4pE̅W]#|0BdOUT~,*VT {KXZn&lዏqqt9o^Zjh#JSՌyXs^D1} ~cJb5ZTIxwD!ڥ:Aa-f p}ii"ꉎ~W`?||3Fue{jپ$0聦 ng_n+eRoX-b"- 1$cqxld,3DyzD _m-k+TU9 fy&XhO+|ڂ\a>0O"X(]Z|G/$Bt>{hcFVN1q"fQ!=[v? 7G+b1 &Pk0EM:>lZ(5Ex4d.':3^$1ym A?t0MwIFmMTNV;dvj}s"0l'/mj2w2ɱ= xdG'i!0;F`3B'r鑎9RAoUxݹsM[).(P% Q~k=iA}fd*N<՟Y3_CQ$ܲgtSnB>]1L9QW"`[ʐ &@<zkߧOTp*DP (癡_^S2d^ 6P)IhJd5>`3QXN%.1_Ɍfpde=+rɂ~-m ]Zol:zaBBlBPlO*56=<8$^ҔI6>e=>uxYSC "yR 6w F9_'F-t`B^h% ѽIMz'C 8Dt{:( Fx΃\鹹48QՅ/r9ϓo 4kҍo#ڍu"P?V#%sƅz5hC*os0 rdL«35݈&cՂjpcgAZcJ!3ʼnrVzV UFU׮[{n02X㰨 b(*%smA[s;yML[ XY(EpNc+8 ocm/=ǞH|Ai+{ "Ο=UJ vtx*Zd*fjxɕ;*?RrcW-l*y V/-gۙZ!:ìoA T_t lvRF.ꇃ) ${m IDATN`; 1RXLI%t1J4.qg{6 Nl?"CvNt_cah<YT3@aagS֊KHu"yD36 P9U;A &}1BX WK=pSsⲇqZЌ5E)!n 'eD\h4",RMKY EB!#Kil`xawV1wOz2nJWsgcb,b Q1zHC1fmCؔp_ ck̇~b39}8)=*[n?jLChuV[s;]n4E] ; 7PƎP6nZ$]Vy߿sp|? n$3K~,sU &2L(fR8J:z{Ԙ/-X9f4(E 8|놉0jb҈xoQ0B7(V=@ DpJs5yPM zf"&4KaNsc:E~,vMJaN5}_yk( 犈lF[CV_XjdphTqgxyin%;g${Rr ODSjYP*z˴XÞ< ^W9!tT9W Ip-z(ujF'2HO  Ѱa)@,IWX YQF6 ԰'OkR)$B=>2.KKf= t js) J/,LbKD0ƚ|16N}Bj^:ʞ$ւt2D݉ANz_Eq!чR@*xtDG5sehٖoqDm( :2,4Xn1(P ߳(y P 8jk/kɹmCa~&zlCC~\Oa˰fƱ gʡ5M,I#WCEay6~X@ a-.t̙B}E0 ;l># RΕ̩oֳq;tXB=JS̩(Dހh30v^@AڇܭQdJY_i5udH~xQ2? Uc'sxΌHQZ(uA1-7{ÿ\9EЭ=k<⎈`_Qtz]6"+R3 >ݥx,u4 {\=;vFyhvL[@hF}O&n(1iBeQ%0=_q#11uy=l9o It};L"/j{% 2 VpwXd3KөRb~jwr@0c8%{"3]l@(}ˍ=EÑ" "Sħ@|)⫷ͧ~B~.ޜE6zEj90/. UK̳h7>b&t65G+ڴeQX9oY}z^ ͫ<4>̙ SXD8qv]5 Yy6y=0yQF?T !Tq 5>ɗ->Drc|mqXw<GDr~}O"+~y-w_5s6 saIg.MzS;2%clHǖ 2U\r KanllH\$={@Q/:6 hB2GľY"~ӈunګ<1\<"O=S G{n b6obiDxqp9B~=b;u\ɐ/'@sf=h²0K;]=f0$/$]&a:C4CvxUUMV:R$Q/4 ПhQ0?}1&`~Ü0hf~-FmTC# ).i~mc}Bk+QQEhjDkLaybCЍ3HZN 8WC]L"~ZG,J9Y5!" (Dz#|?? GB?3qe~{;E|[kDSO_h1.("(k1sMwzޞZdK;cY&3lsmHzZo`Ƹ E)3&:7RK\=" uP (\j6Vt-{т72~s5@'Ԃ0IݭaׄދY6.mF3bX}c?Fk7:scLgi1eЪ\xrѶsCP{1E6AC(cqm fĔHWhzZ(UxTR;T_X>crc-e_>6#ή2M%c<}xɘ_?>Wo߮0Bc:Q$MIjhNxnԁㅚ&o_K (LJBej2^wT `Ht:χTU Pr% j]9<Dv){替^fP ra]-w_ {. q 4/8)+sSZ@'(9:)LfMtTQhU Y6p:Dm>a-">ltzp?X'K!;9] jh>S{ 1*K͜jLN Vk5)1 7noǟ"Нld6Df -X9FG-a[Oi87eA $ނx]^nA4c 2=I d/?sc\t%f)DAj4h>6vR3_c>}H8_9,vZX,cojrȳ.:W4"vS_ ef" B ]2qrq_;u(E6\ dyR[Fb袹qC6INJUӋR^TQU pF!Bnz& n}lY'$r,JL=dvt\>W3A+!r,k깻dyLn2&Z-?:AB`h~ɚ 3uEEYVEY#R㟿.ͧ_ +v愨 B|DkK, {hp /!h딵 Q(w s*N)OLWh3UT% hhG{t D6Иi2:*!w.虱'"~qBh94ml Ž]>x f;'}[<,P+*P,q#`UY ;C_, >Ccz{~}Պ+ 3G:VX/m+jcU=>'{'CEHAnhtH=3}" `Ψ`!u. >0`EՁ~ 񿿿?QhMhM;+x?ybQG f L2WtŒ0K՛ -#Sn=APDַK^Ӳ--fL&鱴̸l*rmZfSoh J, ؎> @-&t1gmILI}ܷͧOj])4A+F){+c"غH,OhV& .U 5ȩX,xBPkQɸP7\5| ~_d&h?}VzLѵ^Z!" S*H~{kN*‹E"䮪+?!"=&RI m(޾!k{zG[|]hs4hL| Gz'Ou_{{?ǧ)r{V %t);1TnqgM;TqW:]i8r5y^vo2ңVc ak* ^Gv@fLzCa#k 4Q AĪu-rh5 d]Ķ__}B(r@"5(⩷]6϶iI'~XrbMY8-dsӉ# :tjs O7Vi!D,&/Cbv=]WEZ;!r:S_SLKryBn342_l)^?Y>wMϢ7?:Du6[?P­̢[ڼQօsδUAec"Dt74J/x!__~ow;^ 6WY 6環bӞՕYMݦ̕ BԔTJ⤽(iRhB 矞M:ўǴ.#"c7wʮ=lz{!]&?jzZ/?/\ ;ݻAC3Gb,\A2jklS_S[.BS#Аc)c, 0%FqwݡAU+ZVI[dU9c& Zf|;W vM%j5"0'dHoƹ&χD"!w"(Y^YX1[_ǟ?Ň54!ĉ7R_ gQдT__n4ϊVz(]|gI7֎Lzgc0 mK"LaxHsa W ɝ9)2"7"ĀJZgyxË́L*;}Ԅ"j0(=l`00c("M {!rO'_rwtNjuk~r1Zķgd5f_D?guazOŅhŒRPxmaX!p>=h=b=F/)ӎ"UbL>3KDVsa{A(iemcwۯ_Rt{8=g jY1&sHw(~#6lsϛm:nD8 V]Yn"@} X>9철ƺܫgR 9[)K2[_ܑCX]x[\mHzX2jgfȣr lB<-v ^jgLIs>)D60x!BDஂ?Xʗ &TŃiӠM˨Ojd#&Q(REn.swEe%r IO9L X;{| ~31#K➗ji `&/:YZ|]1$gr2mMrV}BmE2wP6WI|ø3j0WPL\zy&GYX@ h Ŵ=1PwBܶI9s^x9VTvmp#wnǘhe>(6?(t5Y$dAMs8/+C3zŐiNŖ|R& ͕uTc7tm[?IFT1%HdcPs/x7G*C8.\\P+R25_GkegraL =n@axus7.̢3tN1SHQ`LV %58{ r:[`J*3L-3&Fꯆ?wu ؍|]Dys`ZLF!C?HFn侅ieno$$YMYڜM&]$w;R^`*_;/7EhɪmXz4^e7]!k,=`nG7ƁI&iZi`r@)X`5 tzӄTl-v! Zl_4hKD{SVYknӌzGzOD]wj B< Wt~M)=;20G3>eh*w2]^j#YbbTmt3yOFwd42(h(]"'t늚60>-J .W4>>S|MrXMbԟ0!|cNV#̼CBY?YQ7}ZtM't81hOho`C@0SmжS鑌t;'.8RM WhFrG3@RR6ݎ9?_>oְ^Y g|phEs:߾6ǮFe­ [_Ѵ)̗ ݐ-6Nn[3u(la}M4wybLGvNP\/ԅ xXr=XS3{ *%If/X9q* rC$ջq,/崬kcv(UG\E-NCQ|uChX'[ED0ţDQf#7o_?3lӲӞdY*r54X$o8=OF|Cll&E>SfmRźf bs]|[, RUmcq 3>ƼtXdh|?dW贴D{S&HBHY>iX.+K=^Wgy86 ھ`{Xܚ ;)?K'_/T!0 heGrz Q{هQa˳ߪb IDAT'LiL:Wc<;N|ʞySv 2eU" ?sM?n4E1MT8,ꝕ|lUlT`ktlil;ɔiFkGi ze5tאPS`V"-xuh2CQP^@zA=֊fS6)PP `;j 9+9>b}E#;Ŷ%B!eʝԨļ{q>E{A)+Uu^{xHVN~Α/%se.jUװ`aIWDѩ1ud::KsKN0q}HW֋&cO cܨt„Vͥǣ "ښG_n <۲]1aزAq_S~c:yIf sy3=eG c,q#GQv@ A[Hh_,qsY#yi i]FNSRTE5U!i[GsBwPZ 3˸ĞrqPlS݄ >4B-3siz<KGt㺦vw"aV?۪)X*5qU0ȕ**ߚʫA9_t0=UP M#ۿ<o`"ocFY:ڂNёѬ##Ol=GQNڧ[LN*'z5qv6aF#!x*\QETԁURGV/zgRӦ}[b*zHhU|tmVXMehžbrylmOJ#X8 a`ijٜu[yr6'F<ƘMd{{wΒ@*o?>wv p @ ͂&LD n]bf[YV t7+?o$ kRrBuBG5> OرEfa"k҃y $dž¢xՙxAe_J(mi[ݐ# pzoP~ Z#(U1!vM!lQPͲ\v[A3q7NϚZ :؟CnMslt1WJk2džPF!*-E`Omh../і@]ݕ?F qjvs:84 8#dz|ʩ<%JQ@o?ܚ4kP*~ 3JjO0brʦ}"a}y]f] ZXyw[ DVMm~PV::;|@?ia8Z\Z S`@mغI }3 3Y>k y S{{tHCqdvp;N (α Ϧb|ӄgp|Jl2VへwdB%┎zMqy1Z;R T̟ر΋3I]N0-o|܎E`nd=`l\kHy7+rj/wޠon]-hP5pNGD|`?l.tw/kYV.E"R_{n.k^TƟ?l-)xY]"WXMmauF#%䭑}ׄP.*J1:/)٢"-iq1_Yb~s Yc.^6sG6*.AAs;*V0Ar*W9O$p0e.ZNcklZhh\!9 rވ?X^(XC1X4k PbDž|'˪z `} OQ5^o?م4!މÍJȩVLDİ60F-"tRR>'(A7-= /\ )BlFL8 "LuQTBSZU֌WIbGb otx,ӌ _¸&8Z:7)'hbel:Qm;}A# 3+/ jE뻸 6nKm@5< n߭L(<Fl\!4k>9ZT q>8Mi0];J3c_ǿ~w;*=GlTċ {g#L ]/]ޫ,%]ǚu:Zpu@~#_nV`Sk?wMb4NT,8,hJNύZm'[r6aϓrIs|&/׹}Q|=27WmBփ2dAt.,9KFq{\(b7K SAR%3@aMߑpdS.^iaAcg0Q_JXpz بw \6{0yȩcqr93ELϷ[i E< =M-wm qb5r!ӫ!ĴDX%m fv|l`-˲XVQ읢^HEݴSb>1e+ЙN5ѕ=uiLv g+Я:H}pvh jx1^3"KH b GLBՀo;DA} ;O1ZCpӉ¹D`T1z>;sht'bWeGJNϒ0&Y][. 'b65Ҧf$_j41Qz֑mr$I⢹ƀYiA#XM hƋjضҷ?-j5$ST8G_CHo9:"ՖetF"4a/܈iۙj![-77l@cဃ[sƒZ8 sK[^I#3I^Ld bu'`؞9h&#! Lel.&vTg*l.=#C"*E *l=Μ^^0\Fty#ߦ=AE)(C_]|aZ,su*V%!!,fiS j{7$r`x[n<.Y ztXAk4Gi&|1't꼭 j$.-G|o#pe48@#8ErڐqC](WCk1 hcBQ&]4}{C{VKqEEK%rR drԌh\vHg4}Ы;_F a4X|$%N"$rȄ\m4myT"7{:v2AAg {3BqeHHK6)":c-B ۲D5"ƔơX-bUQ3;n,HuRޢޠ& {[90у́hf!5iX(ű8F?˓NǦoTZ[ `#޷A#!һ'zJ@to?mA.4W#r7皨!¼`|VqP]`q-~zߚGJiJM88c.PQP6޽sl :4WM!Z+P3#$7;rks}sӉ.׋IW!\7n/L\h,#$F:+kXp_#|>%N܄ z '>ׯbKKj#9n\<.xI0ilT _tTzaCCc5I/Ԥ⛆ᎥJ `a\O'w5VUa)LEhZ#r3Ka9]җ?>.󧿓Or%,*,%QmXy2fފ\VSp!b l`-pd/Œ2hl?|⧧[-ͲPb6σ4c\ࣵ/ggZ4JF-lhRa 2g(zǥV,WR>h>/MT԰G4Q'.:wL)fg37I3r=Q7MaC}=c"g ~feO*=xIeQó+e_x!J5clެ?MkΓ;Pd1:@<$"F#{`O VSZIZLaP1[hfDHj[2R0bxtN#~آ Y :a)\q[=Ny!lɅ+C?<}0L<-m3fS^Y/FB$S8P2"yrXSz \r pO,͓.T:;d zP؄~x" #Ң׆e̍`m-GI) &3z'\RCFLj~ʄ밍0Sofk\'d5эϳKa@Q\gOÏNLSt{yExk}\uj_׋ gi0aQxRTl*iBϛ,tN-/%3BM!Y% y C4i0(f=3,kh. 레hU䛣S!'s6dqC4{s3Iawß 4f+p\(yy.U_ۦ@=P~KUi«) %D^K7./yf :-WJP(ևq\";Ot6d9Als|yG ׳%0aMOʦt?ݭ?>R;=+kvJ`5btf%|##W.<LЩ.0Q+}C:cpf,;iDĬ aD| ˭p&{Zv0 +b["(DO ^}NapN - sɍOBkn-z?YTJx8Ҹ\%Nup8I+lqGټ^5Dsk`(>FJ_)tRhcMSrAADiN|NEb蟟2uIvNNezk+*} ]2{08."Wo*GHO~N"W^*]ռ X5SM_ j,6Trco5'/GMQ']yKW.P<248,] ̞A%_h(4guڡ&\?g`\]VZ=̤kJ|?Pqں jx١2ۼN]tZ5]sE+0mOYD<]B] ̔GB v`KoBU1o%Ʊ64iP VjKH-oF<3M:>]B$>l_pLᣫߧFLK>:^ͺKfΪ2\v(t{ Yu?);<̥Ȭj">0}Kj4 %kdfObpmŞ)piupg1Q"RҪ=̲ޞL=97zs *9R!2噸9q3HclW; IDATugݷ?8eX*AQ:S} t@Fmt-\!Ur#VE2z(WM1@'4cY t,YHxo*O*]5#0id34G?X )8ƒVKWqRl&*y! Xru Qtmʜ{uAJ,L1Dm޵3 dFžxJ=ǽxǩSMruT nH}oH6QW3$}LQ?]U;q4&UcVOˍ"7|ܫI hAHۑJ?KEH0 E}7VZ1y^h F~rp\ 3$;)!F%s_x*s4e(ٸ7AB2EMmS}0D)S`}t< hunD8nWMjts臯tP9sHj1[w^z̗e-VtC6pᰤ \3S31y@١DޯΎ5mpӆ(c8 S@PڙF RW+Qg۲Ư@k 铛=:Mg7tyl z$ 輨Us'3( )C}#׺ Us\_hz<(" BQaHӪ=wք~_ų>n?6] f7!a?\%Tg,I#nwd2-%RK::e6LM#fM^d`~{ +o oS!\S `4zcx/YNowva{vfr CJT{<@\~M^tjpΔg%:mHQjkUQvzpTGNJ̕5@ʭbIc N{א:|O+ZH#DYi&V66pXa_`Z/&CYP .X.#tP rY#*oVN,kKoWKDݵ;V(7SV, kM`w2?IA.&> zpWe[ۈ9SL1nPx~s91dIH:ydA;x{e=*\Q:hHĵc`G*etֻ!8yxez|F@spš4;\TI۶$=-١V͖2'L6e[#7toNӠ712-aZk.'Og=P=;P˽rLNmRG-=[ϲljkjb;l4Hѿs} .-To@Ҹ#cE4,蕁#&N0.`ǜIe26Asj"ڡw]fW5`a{Y4udkSm uH%=0?դ=-k@3^a! Tf. zŚ'3^f9DuE1~ >AJ3/t:Okc;gW+80?F 4):np~c5rMHhx1CeV;ȸ z*IS8A__/ƶFD- րD\9TTvwT _ QI q atg֨!ȅs *?Ws M .Vy}";ײxm=l&U QESɉx%4#}™@ %5=w85Q@i~[s,BUg@_IJGQs [ѰE+x$nG.Q`sh5,io_kL'նQC.LEelVSe?DEfAvs9= 9rn=4A_#} T#:Ld.G @Q5Q0h|HdU$~ykp7MXARゎ_-G؎!f7!l;5[\O3 ksEa߳7Y.-hOL =r ( LfqSso.q8w-|pPTה;wz|?`qO¶?g5 wzNF#o:DHJ}@fY}SmdV%P-cG5f+wSse=[ ϩө=bvJA gG#p4bqѝowMÁ$>O.FWwi_#WE c)6g1_ŖjLyg Xx\f8va;†}?#|;m^B݀Lej&krwxaVDGtܲ^\`S O ɹ1.L0˟9C<N daBa\׾`|ke =,Ȣzoa_Cp4OE-XǪʁ]p+zDDk`2)אQ_?`ivyh+]AzՉ1K4F pQXX48ΛN&幦!X _)T2:xɗ΀&eJi\o &qĪ1^ X  i눸 sULw;JRbsWir~* p9҈}CQ:j'fDؚ_";沃QyzP(\) Ϻr4NӕU]c2<M)--.`2zY|NH:Oy_=d}нTtԈ&c2&}H0h"U Oh__ g--8 ѩ^dʺ\A)Q:rAڔcuNb idz}"˱8P|K3n>[R--]KLGJ˳mP>_-^HVǓ>m mΏ?l'ZdEVՠuU>HSs}o'4f|>u`WĬb2> bi([{bHB>iS>P87 buȗ3 rF՝"p~N"Z31lTa frA%.aQ}M6vN &KIQByU/򀬈5>k\4 @ W~UT  jbA=_x=Ґ'!!j7Dl~ xdi);.vJo 264(@ࢡ0ī yE\E7= #Vs6:+?O!Zm|d׭^WES)ݛm,zED(5Z:U!GB]Hi!X3j6朵L{M)*-Ԏ۟3wVmqM$;VQlv؅}g3[7%ܾ\?a lSKCT̸xf5k,DD<1;?{=@}P48ѰP}Rdl2 waÓxyjePe!*оE Ey \hq C Mia٪_#^Q4'*$%!8 \*iowCcG?nU1rD zbeP`v( Z*M,jQlx?ѳku29MCi`2=_ ZnȖs OuNϛnANHj;d??QY3Lv,#PcB&/ ba4> L"XqK8@C xKѽB,u}h8O>;!o&xkZ$7$fel&y ,Ncna .ǁAj@:x {Ysk=h&QQثaN0anlxs7a5xߎyX.&lw @< q4Hp+?-}у.-)T»L!WN:aKРQ`G\9H6 :c/keKY& }zT\I@Ӟ>NKͣZY;tx<N \p j`=G`]?>  A.ptnv_ןn\0Q :Zy yHӌH ^ȯu&G RuNc̜$Y2T /zex0W0؁Tొ[>oޥ8>dXA w\Əz8;#iu}1]l KVܿW jqR47eKJsQx^V0V]Wn҆h+j _. Ǐ >K HYBN˝*י[NQ2/~ʶ&ka" :6=C/SD[ݬLBs¢aW#̖`YCbnS!&R| cWMh>+TqoL?.ņ;r#Xt9^`oO[x,G@Jz\Mv47p neqOX'7yz?HGL>}t%5ԋ UcmH)҈&:5SjRH#7϶6>SА'1w9AW3IUW6-#J/o[ 9NfSȤ ՖaG8RE f *ߟ=f/hTWžfV;B; 3ug86y-2 TErTX!d0恦kP:d}XDArW:Q͕/3L)礹 [1\U-@u1w.KM߂}A=5fv3"?"}N'" Qoa_e P kV萛Q=Ҡ^'<Є"D=(Uu YУ<`')lH&LlhQX4u P,L M*5QR$G'G)¡ f-αco _12{)*/5L.w,oM{J 0|L&dz%¢0VhQkl_c^t*{@(AV@U궸ȩN၇eubu9Ȑ~d;T%tdMT~ߡJ.T2߾A/q5![E1" ~x&b 喅4C2  ]Iՠ~!ۍHr2[Uk9`pXBcCwbCi扴 *YsgttǕ!s  X.P$ʔ}8zسP4]rR;Vر᷼[U۵O .ϓO@ؕk=}ye<v.NWhȀAd>R:ׯ~l5YGVR#PȈw/e@l"^7k8@L9yͤ c#B@+ئd|{Svp⤣tA]Yd'/0⤋d@39*ٗSSp, @Tdx&zLm'm S.Hv?R@1q. .g>wx)OUEĺsPWǭ|tTy F,H&, vڗy%V7 N Tm[r'GfHJ XcrL`tj' s¤6b5a: xLc{ }1V!CF8"51m(aS/i陀dсӟ1v4y&o4cGt%w #; vžn. R 􁤕A sdždD+nǿA lp ™\3++ ?҇Xѿ &xk o#Bgɶ KTA} ]=\xdk&_)6T7!mZRLO+u"~3I54. ;+Zm?*{"S^%$YFlӎP}$d"-cZ)V._w4/9 ݰK>Xߘ;}LRR'A7VNfZ=dAfM\`dOà3EQsmT\u=Ը@*SN0M<ýxCYsy4۩ݓ YTMq>Tdؙ > ZΥguQ}PNcۛh Sž.?od 1' kO*rj!ȴ#6D<7d;Q\hTSqb _㺾˚B!ʂ62W+PKuF-N(4 /B5$"~jV8m| V/dB)Ra.>B~Ǐx/\Uxj~㺳yF ?&DavZ6vDA銆ж6a,ky`Lw4W~<ːу_ iD*Iʐ4 yxˉ$Sk:;=u}-3SO&.u-)²Rp>;?,Si' 'F5NFh#3?)jA}<}ťm /(/}JO~ 1ؑ+X&l |2Yea<.`reF} qgK$4"䧔mS]Yܮ5 K#)RZ>=nH~cGܰ!9"r:] bhFW] ?X6\7 3 avrԨlpΞ)/dio@F5ĿiDf>{پ7V(W4 OW׸677t4/vݢzM;azZllH2T>_B\ɥѳFuCy,2uQ.zMbH|}x]){y^p tODeOC$“heչ9a֘? S[O\w߬'OO*],Hκ,ʦ|y)^ԝghӇ97K l[;h'^dįoIasq0-}.`S\,rxw:d,fx fԔ6Φ 0bMWWJCצzx݊|`e>Oo+YL՚L-'ZgnUVӲ_c1@l` d6?sIH[P qQ6lc͹oq"st&^Q zv3gpҐSCaZ BV#&*#0&Q`c* c3X\k%݊t~Y+vt93LƗ;O).{$Iiz3~}{Խ%#p_߷0EhCx/#b4Dp4eVEВ^b/ #x%Dml n!-I? ~(`(ഠ۰iX0OѪOD*&Spҝu\~ѡjk<\ݟQVH"G4sM! V+ \4~Nc#yY8TPďlc:+:MA4h;kZQR%m#%nTG(Uu->)#*7*L5HmKj5v;d]տ|RJ0k'E8?\IO(n~|w~-!!4[lݥ h@ޏ>kwGl٤Je(._Le'o6}ƈi"$gX+ާQ Xߵl .ICg5f:"9&<[@G|kVcj%52:D0Sb +er%hEvezr.GBoŕS&eװ0|/R/Yk=ο,C8SdT1OR!Mn~y38#=a8koO8͕sYS`wƹشF6=+D ;I"jʔ?k1_[6uƅ!82dvqe=T;{ۄN^Grqc:YMˋ Fn$]"Mԃ`GI1}u  rݢ8[z2S}B] F>81bYj&\ Cj˔œt+Yl&8dኛ?,%Ȟ$0wAWHEf#׊=^!I\A|0/NKmOQE0?~ˣ3Y 0&Ȩ/QP,."k .=w'qF%m+q ꆫHB'^h2R6ë"s#xp7۩f%羡e5#XaB0؎&ڣvG|8/ WQ:j_,fTD \ԇǙw%/mVj{WQ  C /:E.$sbHa4gKsQZ$*Mqruۧ|\B;*ʑIuo~c+^5^&!UZG>?ǜHѦR qt`يSg)) +s2wq100RSʪJ3Նc^hhS(qwq 6yR1[F`lZSĵżc2wuֵ HF16{ H%UE>r* wO⷟_DcY6݌ka(@]:}\ /ɹsԘx60Z83 fU3boq1("`ElJf#FFy1s-P4o ZO,LAD OwΦٓd5a6CSyV|z~0}We`%'И ˪B4=] 1}X&Aўԝ*5HQ3O πZ (Z5vjto#]pɪV77ԃFW`!h[p?#kRʆw9f9ngZS8u !ܻa:#x7nCdC]) 8c1?}Ja REəD:X Yny0w~x}xN%]Is$.$g~J`O{'5HX.:st~r!NmRҢFb{/qho,hE7UD0H8/?'T+~IT1$PR3;3-K*!`;h1ڦic7ƠfGl<Rft|Y'VlWh.|`q4n 5s,0XHt?+ `slD(٦)pB4Ps6齴3ʵӥcUp/\=82Nd`U3I$QCqjpQ6<3l/Iuj/b#Yt=rUMFI$bY͎( `-7i ?@Ƙ%^%YV傦ݧ# aiYs-_'; 5Lƶ8Ze)0PZqC\bw^+m ̢'<]hh ]OgU0c7X놂" #cfw8pqC8NMF1`ߢlH+B.JCqQ\s(.'|ץ}퇹s _* ~שx8r8hSޡsҍ74w\f$^D ׌'4 tg tN<0T ]̳G-/&#jBcuOr"M4a3N!}1)Ǩә bzpl~4 7>< MwlAA_HKryg\ O4ѫBiNeÆ{(4uK IR&o`%np}^i1o bcۼ(aw"k4'i_ͯ+QBw'qC[$1j,ĽwƯ;L:.+U]4WeC s<0!靯hsX"- )=L5}̏4?ew\tkq kQ`M" U٬b2P7jQV`Fg֕0ڔ#PqPH=ގLaP960H*pOJ(#uI (b7Rdgjl>o!E J l؊[𛊦h|+rw@z DC˽Y1d]zIHSjJ6A yH$A [zG]0z6 g\ݟˏy 1*[ 9J%C z,X @Cp#D37"{w±; ,QFGuh(c,ZFCS[8ʹ:Ge^Z%0ۓC jݱʀ*.6%U;s%KEIpl\EM*#goPH-z$h5!H^Zt]EYs%)M(E0P8X==~z~cT;mybMuycAUj ^! 2VheslYmSL9ްvXOWa#j`19v]'AsҼٽG'?*L C V xTj]Kcܜ2)&oTS-YtYU^pr[`jÌY>#GGy_v7^ZkadŬA&?׮rR]"DJMa`&8PrP8/ sTӆLbL"# IDATitJ^,l/KQBAP%^e"``i Fw/6Boݡ?뻖 y40[OT=ܸ9oiRg9?bZt9N.&Fb( SNMSrRQЈ|睌?H7%?wbRHVѲ?ͤR8NqNT?BGQB&tgyI  Ev00aw1q쥑Y\?VX9Q|?xi'ls9>/$nFCQ5'dV">Hpd?.gF%xd \B,ZĐ刅C }2ytaqQh+y+Fcf֓&S3^fuB<^8'Oڒ=Ү@S>J^;<(kKGucndv=l ïvG cKJi 6*ÊV e6rJٽ10U(ف #v˵62c \T-3":b\80J^XyQDRV ZT4)m4H /~C oϙ7Ψp k |Zyh(62}a``zuΘ.\La&f8>V*U=]ܩ\~7yc8ͱ3 Az ҥݧM, O!?~k3T7f,@݈E8 dGY:L EXd?vSOR4 '2#c3H%|Dai0r'8%S7"A1 y9]6iӈ\#j?La  zd #`B^qa pE⥾UNnG2 ť} 뉿S}0trzuXN'=,554 IᒝjNBXR~ A,9 q ^J z9Tbxvº@JYF)Ձd-t)d젱3`EA#35?{G^Yxcr??|ߨL%M;YgrN?s ;c!8eBVJ˂ Zf#VΆ DȋWT'`3hLETGh㺸HѦ1JW` &5,3Jl!3J`(O_NޑMڙW9DqR^oJGϡ ;~!nvlS%n" ˷#RbÑC/RِC,=M/ZKkgj8L8IzBjEqS<:՟Aa‘͠1QXJxF{*CϦl317r/SY -'դւϟa~7u=6P]-g0>:q5[m)N r[İtGGJ_5xd_3 aN7y拼3r4ҤW|dY24mĀ4/V6eъQ:n{b1j8!KȝȆ4/':T,jFzo_984N8} 6&>: q:+t? ϛƚJ|v[]eul l2lDyA3PB$o%"g)W>r7)Zf`ro} !ȱ??.rEU x7ƘAo;q.cmٌvmBѴ@\Ĺ;G>Vm򖬐lǯiS 1BB|sp0wMlJO6ZH/Asʄ;."4?j٭2R]܉؆aU _8 tYgm:s">  =\˷ApQ4WyPL:n_7WQ<(r@Si*@M,A yϿ:50 dQW2K@˸y1y S{<[udbXKP&֢qQZ<脐ZFA1LPb uҵQunm;R'z>)^5Qح7~bJ )B8[勉a^3cžXQ] ~uM>6W;cn7$P?zwSI_ڂڝ^@P uIk T.m5+H6c)\PͲ*bL~EJaB%bʙKƓk.ҦLx)spF*u0h MãOچHY=! |!R|`q4𣙺ZV?l*Zd)[<5bBa(RP[{893A =h5t HꚈ6K0~8g^fv(Ƒgѽ4-+G&xI~”Zʩz40G<9Ǵ83ϒŒ2Q6|b(zLeo/4"|rYCz- ㄋY[i;ෳ>|g O f͕E a,vgC+I)IhyR#0TL {\6+uVY"DH#1d$ߛ?xA Bj o =pA+&x_ m7~1vV![4Jm-Ο^ ܧ4YKbIV1j3^|FR-&)|3aq,O1h'Šv$ U/Mk'dFe1S甋ZK]uÄ^_$BqL4Άeql=V|T)i!u &"1/3̵6RzP<:^OmcRIe,R 07YZGry;aXc};(,Ehzk F>㱠\uEލG̰pMlwYnLY 'ƆbW!Xb>(?4L͍^UqZ,hl  RY7^GJ. e|uEdUpz +L3isYkx353Hj1\!<;?Ϣ%Xy/[%nZxlyb>w(pVՐ"B͖ɯLq.!l]f?u`1al]Y9 -9WC R(E0 8)c(yɫzXH vK(~ELXюڈ9i*u`7Hj*(O~8bn:}L ?u ly-f(iя+"D[K'>4RJ$B!G[)P< ΃r1"sNWi~#l~*r>P)bV$Q9F 9O9clf#K- ~ 1;ˋܧ0{ ?DGzׄUY5lF?ۃ1<aZ^Q\ʹHt( h39(WLzmt]^|@/HVLӥPrLWGBH;8e7?䈒Yخc֣oߴfB ; GV=Cm`;S̈́5#=ً1E z+ w'l\ȪʞLyU=sэV,UNG=}mA#7_wYDbCHv=SO\Q켡ƍ[X a$ۢb;%y JdN2 .<( T=Kz*40HbUm*'jE1zŰN# u*_qᡜ5Qug@Wj[ yyMv#ʐS,P 3`f :Wjb \79jnc+lC Y(>{_ ( PQN5/8Ɉ>8ܸzS6З Y_w9-Ш:{A&RxR1.BrY/p>{ Dy^7'a3,:8xCL;qQl}yE|zY!]'J'$0AZ ,{_Bl %L6R ?&bʅlv@XY!˔T:qzba<XzNd=;B16eEF.?{ xN Eru!-`_Bs z3V*H 1;y O(jRjz~p*uO0=,PIitB,:3KQ晗)"=Dq@,YcY8F SD@2Crqv:ZKפP5_m` \ =/H<} {=<7T?/^wRw* 'Nuzl(K-ft+l V P0sp.j\@pܰNሗ _kt%? &=`]MYW 3s _ 8 !me5r!>bbݥ[WgM dcoX|pvx]\ik Bc1M+K(ƁG&i] mӄ' iɋ1MWo *cf@n*k >'L#6igb]TvzKÂ3brG˃"{%P^쨲&K ܡ,8l*D'9L& H goˆQB^ pռv aU=pf[z.  m='LױKB1,)Q8;in,sJ eο^}ͣ/|V\ 9B\պ\7=mir0dž 7A5M&xii5.4)!lO.h|F1݋1j;IprEiM3MyTeߜt4< R>o9׈zignq>VxWE}dC Lhнй /x0n}R( hшy7Q_NK-qoxDa5)ي` c@фdT>Ipe E#o_XkLcsٍ=aQՎpYK"h*eo)fH2vS^eZlҬ1#O1Rd7-QWЧ*'Vs 7:4hZd$_"$%+n+H5@pwT018x,cG?TePSO:㭥xMs"夥!^_d<`<5nweLf:5\Tu0nx^$i>yv r2`̧# {o; SJ}"K޿?>:o҉5qȵTc\grW-f|.p-  %}$B2}|M“6 9y~70bPScA:Sk<;/.p ٠av*YhDqzH J i@͜_d Ns4mOY~F<hu+hDho]WWL-״G#殙p+Zl T+ԏhڞ܌Y̔붣oݗPCr"\1bO3ӐHGrjaMͦ/YX{Ƃ@8Zr8+Vq^KةA1%y5{oaB l\Gak|Lͣ6\H cTl#ܼz|x`sX1߸19w)^Am8'C~wO?#dx"rQ[5e#P0y">l;;qMSbZgâ]t&pg6,dCR]\L\:W+Wft7~+3xcή1plwhŞvy?|dͱz +\?VS;-H32w%ruu /$TlQ|uY,%i* `Dҋ=|zD }+S&X_'=tr#:H GPc%c}~?َX ;MP IDAT3 43CBNcxL 39lR}rQlHw?^mهoÕFh#znp6Yz#q^ӛ'mYQEcuT ֟=,R4 #gZ*uLVrb=ʞVwjL8du$JQ)5kz FdB:7/j9:Yj >&ap1;>WLUrv{⃂Was ԝ h

:3 E[>륭BMsegT$g@Mbz GMWʐw0_ Ѝ  nTT 5NuZs#H]/*s?k%(٥ ::q`%â,EpA}H^Hf;@=N 2yM562a_btYıH!1u{Ŗ> ,"6K_'kq>?B0 ] ,,);fP(&3*^, fRpB垇y3=|#x&=0$=lR^>mɥ!I&D.Ǩ:+$#E/8P#B"޹At83. /)jۮ# 6 Y403f H}Ӣr` NpXv=k,Y#FѳzZCʤntֵw4BaWIrq뜹c$ztE:= c i<,+jo=ofLKgT+%6jUМjR;!)}VY?)fvo} Gv#ޔ4eƕ 5N?ϻZ 분aB!-MD{qؔŏnk ِolc< Ւb4@0fr\c fLD R\]7W4lTmSGayLѣr8'49>MbF o؞ 6`cCݡ^u}LQHU`>d°Pʄ>s&$Wq2`4^>ͦSKPռǤQ,Nn٦$4|6L:&W .l#F=P_m>J2S1;L}iOf1bnsb;P.tbєJ&Jmx6=HSoѹ{(3<lP|P :>tql%E7 !r|Z#}!F M9Ix3E lЋ}{k[tBCn]\n E8y)l5X9,j(<{D^GGn>_n['`u>^qeE H\`,d5?w֡ j{C0.2Wj|JBŽmj2s>JR1 NMF|Xݢ膝Vl!THȲJMnmAG 7 mULAH/cQ?nۖ[NYEo] 9| ?\< N6y$\U$=jIPPhbNt@fv^EY2=JD&t≰ؗp47%0lpatp?Zz_sHy3`.rڣ A[}83+I5dif /|<S YapmeBv*|vc1*+G~M&"݀dcfhVC9WY`),х(qZ]l&[m!4~\FFDhƾ[Mv!v9y>^zD󦳌uj([EIɐ @3C^`CW%N.),9YK# +Ly\Ԕ5L߄ f(B3D#͠6 Sp-P^?ƿH [XaV{:h4XG.}Q8&R)S{ӘP3<䍠qd2\'Q;༩ H= m2xz06޳C 2XC&埌RQk?8rۡEڴJ,vjCx[t-șvck`0䨁ؼkT7"SkX-*rkgO\ƶ $T}P!4SSV,ɧ4Y쾗q4qg1zAo}N֖BLNh1Ao24s*Ah'BStްZcڐzvXv=lb 7l(2Ե0I8MCCh"늃5T'R g7te*lj4'o/"05d>D=u3,=)e(̾F8EVY]Q'Mu-=2U4et0 ‡zlYN.8 i^"c~ދB]! Q}e3n<4&b+,02Gby!Yb ׈ r}.'#A804~ՕeSZA0j.@y OE!4F9tY9c }S~"/\t=AWt6A*E^輪 ܇ x19Ai3:|H<*뫱6 @-A@u6 $M} fG~Mj04Ċ_ImAu?zP hȃvnQ4?,^.X N޻/eNs6k۹{|-Qm)rn>R3Ե+_\ݞ{poնV3VY4g bCyԛШ ^`?L^MzPpHqF(48r]un6֎ m|*yEn1zh]Pɿ/ĈS⻅v3rLCV c7 +q28cӔ*`(6f}usԜ]LFhF)P7,OJY*OdIa:Cg%*O0PKf mޫSVdվI4N+H3GTE12L UQl_C*ht7(J6R/#]3&?qX7k.>ƒoRq_1bES7P0?E2(L6a:3B !+8알bh||^2VM9lI78$|^VRheQ0Ԙun0e:}Su rvc}y|Mk#˜ʢ}<蠂ٚCm!8sT|>~|0{*#bW43Dq 6):iݬtH!nCU\d i;6 MV,k d哎m`82eGlUy%<>Pϫˈ&D?ޭ]$3DKwtOυ\2yeWdA'# &U-{T^"<h3M ~&Zy~Sl1LYX q)Ȝ40|( ?Mc!wolahpN**Ԋo; G8(!UB[8$X\\!Ƅg_[?YI&,h$+ YծoGRԠu/j|ޱ0? ~)ZID߀15@ 2^t}>Hga ,S5&R:17۷n2'tO %ǟ㨇CwXú oLui |-F>8&&fs4Qq\Ô5JZ/v 60Glyu*C9T6A9xIp;(/E=hn-fr,&дDe YQ5VEx~Gu\&g̓Cʲ4B[ug"CJFEFv*vb b<uOĂE=ԏ-SHϽ:pIAxtqU}bjl 4JY9:e/5i:,J,)= OƊ2Zf\Κ<;~T~YՂ>EHC#5'oj,G+1F`HWΡ \;ň>hLLJ:?_|9iGTU@ذyTb -!`9R1謹[=[fU|J{W2ޟbkf#]XC$+ qlD3:*U~l]lAg0X#XmfCvA~*AZlt zSi\DyNrHy gg沎s7bˁlӼsK_N4`+QYiG5pcՇ* EѶw䉼|8R=`Jq.Q4&5g+q(-5;,VZwKw]VlpǂFɄ/8X6_j|Q\,D7 3g.btTJ }>\&MF6pGj@Eg(g ,Zݝ7YpVd|XPUCqWZ% A-+1Ivr EugNADPIGgoȾ\aZ.A_,z9(Se" џ`eW7y=O+}^nc?` 0XNs79'咺 9ɂZfLd bՑ)D;3P~3#ûGZHz$*:WI'!ыaX`2Բ~!d 9Pbu=" 97DlsDcC, @įٞ*?TGzF=opʄ\!d,Jʃ@:x58'+M#X 38B,9tuBxm `D`!kZ'93N30F$%9vtS_:`,|l!PP^(sԻ3}$!5"+-`٭w;or υX'Yo5E<,<`|F F5Sy:{jo\"Dݑ$<y2ȽJ6 hKMgh:c.$,D)}<g#z.Hv*U\ )fpt@R7cRU0X_`ߙ+PR7T7}U3טMmػvx Hчc5{MҀ3*h_.6HRg7 xė yдT S $ WE5KjcC=(5B#w6ܚfO;rre?_q4jPɬ<7S];8%}ֻz9o&:~ٸy;dn * IDAT1cz*GuDFӹ\5g .4ѻI|.;vuJ5aT{cnJ*f &L.ߞ0 UR#lyڸ6dL @*fjb A6#UHSKYdEQX cxi7s\7=Q|C'OAh bD|@i %LQM;ufe7AXD5y Fu/()ܵ sgGA9LrFDhc񧯨ܚZ=)`s6\ %s~mbL(v4ޱ'Lɇ&pR ;P:IG' |+Pw'ȓ6Cڦ9}UGe5:cOwg176:lcI%~<">O- *D-PyGk>r]8Q;O9u! iҨUFyDѓYT>mQ!JMSz.N,# Mİ1v`=-/F:1RѷF+}yFy,i6.0?58mtLG{9& ghez_t]i[0L͸$ I8 海!TnF,{oNG33mnʏ71*C[D_7!y5kH*{¡ATsЈD̅AV,,n>AaJ_^"fj M^.;px;_cݧt7}L4 U?F{@rTU Mo63bo9z;Ρ;Al[%WVe)ʶ*Nj޿N;(ȶR00)w'wj) Nqwd$x@=H(7%f>0.0 lS.IFXId7&vw#QE+,74\j96\QIdboXtOICE`:Kcdo7O?MGjb55`"?و4لUv=uW$ :626+P^01Rv-e:xi`J &լ3vpQb3(%#z ? ke4kZ%} =A}S{˓ ^*?l "XT)X]=daAaA\z.U!Z{6Y{Wd59I`gpsOm2LTA4ȦΰݔʨCjQ:DJ`܉nzwGro:[LCE"XuC#Y\6kS(ݠg91<ۓ*Gm>K&T`bY:qIM"۫ iGlet[h)6y{?Rx@јO>GbT,c6sf,eUzHPr=S2)rEETu~qg~Ԡv1SYyӂp>-5tza}<0gM{ (D9RJ[ʜb?U3ܬe^|5Mgg0UfCgN~.dUsǁ2 & (*/`xho+8(xb\.;4+S1= $ЛpN;Ts2q5 1 7[!raFip;|SdHF{vs޸MSp}xMm g֛-hABDHf A".t.Vl Ԧx3 F9S#dݚD1dA ǐ}ȫV!SiQ:hp >ImSrݲBTYjb fЖU?zy(:i=5`HV` .(Eq+D1n"w2R,11cuUA:(4.@2 9|yQ󦩅QaX`i"8O.H I[HѲ ӾÆutpK_WC: FF7P\gjxSCna'&nёNM)&+z>B>%:x|}alt1?BE:SĴLq,N&eP& Cg|e&STc1NB;8Gi/^6dDQqv6Y'6w%in}fBs>o?CVu,HbdMP q>Qp> Hب umyJsLкW}\2VOQMl_SץL_lH5|VȐ;.Hݚ8Vޕшu=s$J0l4,S>8:LJ#g(QQkwiφ40k d_ⶱGx :ksSF3tq C^,fLjאVgl[Jj0[n_%n7{%5;/.,&Jqx0}:л܏n,їw1 eƔ7hxUTX!;4mSI-!k!/ᢛ".ӕWqIzG[ۆ`Ȉk48,vkwMs?"gmD4,]ynI$R0NB A!'sd3d=4gɺOٽG7KU7EYL-,x/nmX< > vEz2;C2ۏg1M=8^ iv#gr0hRWo3Z _lWPb6gN o{zɘܺn{v m26'[A?rEsbĿw&$2;!$&@GetSMf/nirlVN SBNLJ|ӤlzO&CqE@n -3G:}9">c s?وb6/UU`˓߷o zY&Dgj(/¬hIW`颎[kDLЌ>o >^tϐYG兔3Z~3_4PssoT[pE&Qi0nT " 6!`+l](MԦA.k>pGudCU;xP: `hDH+]U^o>jayݾ77s@U_s&Ov,{ŬkFEpBK't Z95ϣg7P"y BgquX@MAlاnW 9k37>?ZHUQ4.f{IP8*o2z]E;vxƟ% a}$o0?NjfEڴw@39;83w{RU1@6JpyEwP M&]#A鼾؁ Ro@\nBØ2K8v>)j.͟nI$.ѫEqu\齍Bө홥Ҕ0YOutiq-}V`Źe4ر=E)@)>2(wALY&w_hus*?Z) M Ue]DDORܰLab>  jiCkӳ{ }}|"|VCwSf[6mk0oSzLݷ|>ۧGLn*!VYd*pqjb"65N5CdqXnqv5k#10kq8#ybInTL ҮFyC1k7޷9f*tG$[A01_b$f3Q믛мEȾ8(g]j* MsWv;ۥ;2g9R#:}V>7)׹by! ,I!NfͪC>d:ҀZp/s8,q&=w6הpŭh0zF 2_O?;*CÂ[AM28l~!ZKl6\<>H+\ab}Lf KftuP"у\[9ⅵ3f{#B(;Ԓ{5p3N)P"6FD*h^zfʊyRC\yoF%Q'a5 O"lȿ<"~ ƶKC,rLLzG*X W!@INm 7^ 7N.ߞ8nSwpk)|qN^2G{Ɇ }'9TiTi ∎o2>Q]4Bѭא~mL ҒpRL'ux^l!rJF[pmg0X;UTtޚ.(+7Иbllx\ߤ}{OJ_tg4LO ۵`XKآ!CaL}x 5ׁ"&mFt IϹY`TL*WS q{YCyooi!nfdgFIs$8yᖜuY$b`A:bl=E[yr8iZ]I3Ŭܷaai) iẂ\NYŎ;c8B"Q(z—墢"SRml_@M]Ng>\^};BIa_H :).({7;rY>-mB Vmd)wf\r8lاĵ"J.]C‘4…#s:VrGǣnWc=qNH#?E#Puݡ=$0jLO9 KH gp19OUeoVis\i|a_Ō#=)2)6<=h."]HM4Wgms9438T7XX-1ө01:O)*jXCJsU9w:%Tw+i5``RY &e$3`,E> fx/_G :;`ĄO3tw>g&kh,dZV⤨VRA-kڧfK Ԭ`%\76wۦJGKM "N[E*NMjǬ"r r:Ad 3=DAW'\fI+4JHvLT4EƓ0+Mg)0:B+]Cs'!OB*f&ˁaqS~R1?dT~ )}CL]ʞD0Ő'V U'y,q2W`~*C׊׹Gܒoq,Ji@!(ap& "ÙOТQSNOP3סdOC# s0Cg"fRKPS8CgcpyM@@Lk`{D4n mNar3։yCR;<We#/8 WuK3 \EoqztFNާx'F O?Fы2ɱ] IDATFeX8χ?f,i.m4bTMRI"m4EP@]7udfk} f5W:aC?ƍ5F#'TR7T6GOz*-#iD:*h ƆNN)6VF^U,:*/ Jנ53S9$ *ñ9aY|Gc]6 <)'>N"' qp N3;=zA9f&PYq@ij~;ͅV~4l0txT-,W4DKO#밍rl-(/9憕ƍO[b$ D?X'"$<ɑoWM͊S {0R盓)z?D#ta]vh,_gNTGM9–j~G}+ac YдTHCfgܠexGߢWh{+S-N(HJ=LJiT؏#cݠ` X×yҒ#a_~a&6ZkgAi*L`e9 @(ԾE '(?tY$^Xk%_uHX=2Vzk:'hɮ.;">ΐqT@Hi<-GmxyvPۥoVU޴Ց}Bo"+>џ'Fi60U Ša|xNmJ]k9m;^ppɱFIu6<>dԁ8j8#:5>¬GAg#qJpe2 @wjMb/[Bû=XA6H<{@i{.,Lл|fdx_0W1/5AbF۲clUGFA[ꖈs؊JBr|2'wDYC9|mɒ<]nW uɪȐ}ːNZ9[w[)1%|/f./(P:T>2k":iEO=؊mqR;Uw6qy%";Ϣfl l-?|:$DL{"L["gdkty:ZXm iz{5:mݾd0}uA:)x ztbnOH.\&](IQ=ICam8 YE beN<#uy(mԾ((&ϕ_} 1ɦΤS {SL09o?2wp bxjcxjM:Z %woykn%AW Tj (Qw9+#|J}O9"D.u8!) E+Ȩ' ;%}2 aj6 _]迼 g.X0*H K BSR+èdLm +Jt=NbC1X(va+t]`j GЬEt#_a[_3@ۺ`h8@M˓p C}#4 gw`8b, $[A]0Bg@@OW OAC// OP}*⾵?8eKlenBPn-] 5ޘ:SHGt27]REm(*vfr8[۶-#B^)WF3k ȏwu~}F<-,DթnYqgQ҆^ԋdc5-ړ[>b#g"N*-Qq=c(-M6O(0d)ͥX\B.zǪgvOn) -ٽ:ׇu 3mal ~$D1Bv6E{ N];)BI'I&7h #⧏6#TlDy5/F4>_S '[͙K [7M?1XK^Z|*Fa9&,sh<5-l֗v{R[AJs A!wi HVuv2OƙfA7I+20v; .w~)ˇe pUZz3۪LmҘ}GBɞ-u@i B㚾^KCN@iZ Cb;[x \wYIrwEVJ-f6XjYGىg6WCK)eS9aɌ㶲! kAb:J3 B f䱸mJ=úœ 4%}M.Zx1cpE >OD/]jX&XL6\ĪfX3ʺ'.0ŃޮSO!>@i9U61«jZl,BΟk"h Nٿ?~~fؠBfFg9'^?Œ;f*"a10| g(">rtp^P@faC=BriQ"A, pҾQ gͫ1nwqH<"cuO2T&u;Q1]מ"4 Lass{k 9n)#N^i"+k:n1Wa15dnu5"" ɦ~Lq̒y /^篇IU.aNLVCT;θbLH"^1!#|Ш6ӱp }07NΙiupYu+k";O!O>!_SHvYm3Or2+ %lHVQ^V %KX,VN: l>fa* y qڌ4(,ń~=,uޣ:qHIӰG\K,bL~E8_Y[JեjWh#M{ _ʡ~<*h͍+[Mw8㰯M" Ի="V o߶f#ыбQ l~#57$(έO]ulLjx[A";] a;>_G‡\5:9gV5<=&a"vC@,z1л P&ϯD=r  =:T0G_xg}?"k%(H,H挡ٙrItϣn,t=c։=)bgN0@ urb(ukb ^gsxLtԾH9~q33Q0m({ġA oFAg| akڞ)"h~i=ﰜ;d. "bLNU{O(i5{QH= zN:=4,n̅h1lBz&C&OSG{W[ΰwr`s3#*Zo&Y%9DCB4_$])>ldmx}s8ڶfE]nqЩYH- $҅NQ*<] iO4HC7.6 Ֆ V8|[_8iFD$9tE,$Ŕ]VG3?p `Ay0Ǚ3ȏx{L33xK ݟG+cr6-eNp{^hwr>`S$eö__{h4MaOuˍ&z*ntawlH ~׾kK!2̟뷇}r_Nn-*mc";l+=}iq/[{*'&yXbz.lUzQVX6C&[sD,S-~{)ajF@6,w[s]S=9pq&+xt¤)") ,S"z߬ GƄ(hCn Tqh_Ɋ@Q|sä%$azgmQ\@Y؈#y z ir$Y'n1gI.tmqFF7KFspp 殺ϑzaQ,S'z HFNRMErZ8{叹u>9ǹQl9ѵH$ѳJg8* t/ԠG:#X?ZFQ&$@2nn\_9_  v&>{B.ay{W'. SXGq:y,s`K1̴ Drt*E [w!%*ь[_LxNdrtlc7Vjۖb@}k><ǚd#!ZUmm^+  1491rLDaܓ_/ٸ1oCb;r4@燓3eCIV{$8lT|"3DZ2 &%LŖx~AīRpg<{Ѽ mM7C JF8뛑1y!L#5hr-G/!+7LgiB R3syN6ОE3zFAGBjO罞>0;eղ|pLs)sg@Ŀ1 󺂮9bp PY#Ԃ\bhM쉊vr{+b"J%+Ƒ M\QA:je߱<t1t{uH@JnSTʃLA Hʑ[8PQ67{aE8!fEWl+*]d􅚷P>* Ϙ/:Al!A]ls׿^ԌF윚cmAӪkiå\]FpI}.KG <>>Op7angw ,r%ה[ $|{ݯ،&y&9Pކ|CJ"n(̾4r\Q HrCytki;Suwx'p1-L@:Wz:" [  H(&KLml\aM 7 1%{6(3۱_5pz8M偹0nQS=({8nռH-hܱY[c$D6IdJJd #X| ڡ4.Mu`PVhzr6Ҳ !hI\D,T';-J~-ہ__G^߾|fCz ڭ SE2IyܙiC+|g\cz aX438R|@cs_C{(mM>Y IDATA $+ڬ2qqz╲oJLG|90,p'½<0c^k3_n.höv! )ecݓ=slp=d/(H˟Pdڐ5(!~ ZrVY>XZHCCǹ$Y3UXhΝFGFx"ԧ‘`q1fEq87:2,B9PPݮhѦ=hOcj;{BiO+ y }AWA{i}|KيfOG>9+Wf RuBj4b_߾ ;_C~Uii%&OEq7Y2PgC%wgKĿHً; FIFfɔ-3r,[ !LF͠nKuΰGݳ,hln\R]Iр<9?05 \͸0\kBIoߏӗh(a)% 5E$n,i8Os2ع; tv=5nWG.D'!ٖh YX];[cҜmqA[$v4(x!Ռ9 [(!zL㭗T#ӡU_C#؀iVv=\c%8To"tArSݘӑӓ֚HVViJ Mp J9f93zkMlF5h?}q|>l+T[k[QU9 j/I=ae70 7D5&pQ_gAC~BrIh˼qgOwE$O7+3~`FNH!4wʄ>}OQ|a=#!T_ AOGAxmt|gy{굄(  8O1Pt2:!24fFijrs#S6 >=ߞ&?#?*ӄ%9ɛCFwP׮EOWq>) mψeJ ܾQ-d蚠qaZ{5 Yxg2i@8ԼNa-O~r! %n%342zB"nUDeYT4V(ji<;uW$,=CkW>VP0/F0&j N&Oǿ2Y My}Fm{pjR<=w\ ]0(T3> S\b! fGݰI @XumPĴi8ke-;N>Ƙ bJaj3J=BOZd?Pp ^qg'K;^I2o3g8"] :$liFxJa;?.gc@ˋ|/}Ԉ2£ڊ8EHN‑ciҺ}0()+'ief%CMT0H㙛Tm-wX2xi`mmUG`0^ T1ji ݩ4(}vy#<9 ?ώ xEڬmZۀ8$΅5F1}YBxy d8`"KoJ]ֆ+d t:% N\70 ($ŻbC2L0kg.$פ~ܧ)/99f~҇T$\*gK Q"-OԑўDjE Sa X!R%K;t*JkTiKqM4⼶G\{7=ruPxyJh ?{ ┴ͪs1v1H:HgY뮖u0#ǹWp\:76v4:H,dˊ^pZ: J#_? :XJ]4w<7BJU|d)ZYnwdfEZ!"gg$A&qߊ8fԆRZ ?w/YHkc;:@{:Q^!fYgT/iuPtJ7&]=0S({,|c}߁DgX{tL4e({4m@ꌢ`-pQX{CVwϏd# k q< dI[cmZp%]~eJ,\y m}~.e]J\ g> jbL O|JawO1?`{&4gh9Cƫ9 ڐ@2jci!55K`gk˩aiĝcu~+tcyτO~vF<Þ 5U ? MmtDzG<Qc(4R /⦠FKw4^yVܯ'  \*Ԭd"6"qH!KM'Y*UâCϝS,n:(ApϤۼQ-5;O3ȍ|2ŀv[]DiOf^Ȕ7QWrib#R# 4.Ays0;3jcrc-$΂:_-fMy%6¦hD#p;Ab&!>mxe=-`8Ln|' 4aQ9ҞGNNtٛʮK* HTF0*/7WBṗ.Q*iTCg=sN0Y)LGbPhA1753F Zu0{Ž|(!q;91ݩfwy-~5Qٚ9 -(8"JΒejFBk#'Cf@h[},:IF fgآ l ,Ɣkqi-#Iʒ]u!1˜|&N;7#NI lNvuDߞ7COSsF8H9\Ӻ7e+o%]#K+mqQt MԏG\Q.Md?$b uݭ$V442uR6d36QUO)4$I(̝b?}cNO7^UR"Bo/-c9:8;;SJʮLT_Tw.uy蹡uZi-!}LD]ɕĝhJD|s .==^bPcBsc%7IZ–o*SoG?'6쐯B^OVoWa w*,e쒉y/ci?BT5zKk4'Ŀ/orWawQfl"Er$uo;Fw|O&6.50G%^kRKJBZG5'EDTs+n(}#amd 1yΦx4X.thRYc:5)ho{s Ǵ5(/v2Q\^ȑ ËZMq<ͮ8؉eA ,fM'A+Y Cl!gԂo?njOpL36#_@b=$s pV;xWRf.JI6?aMw Ui†Jm툿| -=/#V%+e:H@<@/HXRf5@( 8޹C Nq4l@C#s).VIGs  oҰC 7=crg?o5Nůa(N'0$0ĸ9OtG(vçm' _0BϑqTd=\gYro%#\+ZC#ŸL$fxE8m8Yn$W_SKEIz$WXJ#c.TeqUDz+g>RԮRIpz4$,*97 b7НCOtQyQn^su(#Qgz1v[M5sCsd+K;w)H~pjJsorra6hX65"9Ab$|4$|x75bqvPh(ƌf+_5b)hB]PlNLA |Ҝ L(0[06^0GZi  SYl?\lp4Aysuz Կs4 m¯*5ъNk-n4:sD>.gm2X1ՏƓ U"v/)Y6',m[P?RڂV;kØZLfH*Hzø鄳Q%Oj٬gȵLS]r25WLzr<IW戚dhGgВ'ir>w,H<GN5@Rl뵷;x0mR,]uxQ76ENb+?-Lgzu/-1ҘU`i+м>bpP^]U7. D~i'>k7']aЇaw\BRy)ԌKoF//jp0[й>6Ŀ" FELMeR'gJa#f&g궷u1"7lҗɝՏGĿ,1vrk ګ.rvqK-24:ŷL[Wۆ` +xPB:. YGG_A 6:NS:XOQqty?xw^wav&S=t߂u $F׻_q 끂0EC!B ]tŏ&9HVy:՟B_C@{#'_lRWw~e/!ކT.Lvk9x^ۥvyZAvmۤ\Ac.ln!M2-.DMA kr y*)+dD%A[BjuAry)iNC9JP95U&. s u=,Z"$L2F+4/H0 zrdc:4/1kq֧i݋A ?y9>NjOK)bW✶ Nуhel )),gCI-dƣ Զ"AxUԉMQ=9~#@sgh?_徐ehLMkSorzh /͞fP=T/і|ݟH!]ѵyf_H`='jA;9~&LX{8QAz^/nmD|y *1dTѪ:DHbN sfUMgPȉJ)J,'ol֛u1y/G y-gǣɄ"Vʚ7ƥsS 6=QҾ'ۍ~}6074TuUijatr8:m Ê,l. BB+2D3qx":䗙 $J>6P˜VƎGZg2WViF#EPޮK%dk`z|EH>7PmN b)9 K.MTWxon8jtUe:p4?PE 8ˌE"xQc]ӺgHIoRA@jK2SP!N)8"Z>VwIH7= YGSF#2/kS748a>4]3UFD^[sRH;L^OԵMF5V*Os|(I^.nZtj"hfCo&} 3motxwa*Zf.1g!Y,]Lxw?+=M摼&KIkH7JsG -Plhl6D7\}H^&sbn&|Xe*lGȰU0kV_c;rn f㈸9J#{k!18XCNDxD-pŅPiDwU|Jbl6uUIwjÑ@X&KSb}2AuR >2a~~~zU:XL߲NAsd b.7obVAs1v6:KJJzkO斸!]] e֗JYbz)FTGDdO sP`̱pV=G ) Nc.pRr`aD#\f۴W1QSRj` |5{yϸ+oDQ( -HW1[Um͍eZ[cbGk9DԮ"R%̺7E:k?a5 '[1όarhzw4'귓ǚdtr]ݲtHF~yNbkv }@xoL":ljAS@fSTHG0b0rQ2Ta]cNLܫb6Lءi{i.O10#6L[5Y3WazY>yz>C .>dM@D]B(sy$'$VJ#J'Qa$GȻu'gd P 2LҟL̋Lv,dpcam؁};5y>שATsvQy\"Df1bD}yr {t0˪6G6oJx3|l&ݏ*gCrpL;twx ﺏaћֻ#dT~2ݑ$=gNd'ymQ4BuRPv;Š@T4e\  X^HjJhe[po0pه UJ9J89<Y#!V})\"イmBr섢@B3:Bl2qOPjC*d<6H'Mخ@uo9X;H( QU>};;Cj =:ذ3nJз<`:3h8q䈏b糙\eR`TxԤʺӁ+`vkU^:m n[}U(;e\3Xx}V]7ADؚlUa(qw'k#t<<:f<,{*ՏfN3ك@51^gtKcGl'3UI޴.uo@ОtyU5i;<h Nb ى@3le .(\{Gg# ByL vI_xq/!l*2ǿRA```I/dYdyxC i&t8u8qZo. 兪H%`K$uL?SPp>Ԙz  uyC xiu3b˱xğ٘RYybtRFz'W|)gp.;x}&1ʡ o8~q:}[@,P &(F4kTzϓ ^sl5waɠۘ"}MwtZI7RzGS9(\#Yiq:o+d;`P]ny>޸(q4Pvh'K! &w0@K2lG9Pl2Xj't/9W3շ f)锫u #h Ị<ƛK6io()7dg["iϦw9ІɏȆƉˠ4C2GYہZMC&(Tp$ vӼ@*,7'768S_dTQv8ob *"i*!S9Vb 5<bSڝzv}+_suV @s݊`Ωn(gL)d7Q"lhZ" T/8Qt 48ckI64h!L $,*RR"1 欮BEI4Dڹ4=~_~U-5\G}H3:o|ؽ7,i9sRV%{t'"%>T YWG,hHE5KZ8mz+<8%ٱ.=KLnzPA9kgU#hV0Yl25\\> 5@IQ/"?TJhOPo^`pҙf/XؔHK,\6xHRӂR 3ŵG&v*onb]n,\(!*B>Y},Ě1BfK=a(J3$XCf=`$dktV-Q_c*3{g$<7U3DL[Ǽy$B%xG*,X7t;q#LTDiȉk2\+ث]ʳ.[y9=CCuhgC*.X{ G)5 !xlXġFģ,ZKq݀QEl/;!\ iGQ no LxH$Q| 1/V{D'DJZ쾚{k=QlD/1 wc4e&:-y1_;=5<`#abw[qrKhPX&;kY]|@rv \Rݡ%ݣCő~=LRA>߂o]7U ѣڛu_~}iZNOO f1Gc໧66W|zh6-mqh%?`ݔ XRx, KgE?};|'bߺ|!}(=E_ؽeB!s(xύ,x Tޝլ1B jZB%2+s͌q21dcIZRV!J[@KcbA10joV4]zčnfvssu-0y,Svy.8_<e4Sh ip@OFT\ȕs)B»cytᅮYjPy=y$hT24e~i@7abqZGk}f4HCaB3jJEJӦ)Q^"{]G;- ,X:x ߃͓˘Yf{[.nV _npGsP4؝gY'!;A*6;4ш/"ߣ!DʗOz a[y/0>aVZb-bٚ! 2 8({aP7ZZ@,p2EOz>)KdwIPuU1D' c$GZ`Gl۽cq%u}PFS_n&E՜M' {,}C @#Yn1/L=[)xa}m_~sOOQ{6GtFqt_w1R !|MJ.Y'a}0{7zؙO# 4O~LJ0Rz:4mT^YhdKi)&<ӊj߭s\L;z-)3xe6I?sJhq"kGYݯ,xزA31zm|wW 2M@lb}Rb3iE5 k)tZf0v:KC'ypo@)>"8,yl7liw6j°s|ØD&GL:pG͝n_}Ā1j/u91ilv\:v-4pX^!;8furIAƔ;"єˁ4zpʦ76՗95Z{y1˖Ly]o"9X 8&;|RF:: r&~a5VQ|rl[8pͷXh*}(/`no1-,_zb㆖!?qXdZk)AmMo*I];w{r1\.UH.rXsL<87s87}g(99;S :"œH<틩 GklfDnPlv8fc-2lX*\'Wzzf!t=gc\n 9?=axpݝ:.{z} bP۟ [ DE$q=lp}%J'wPCS,.+6DSQ-=ldS:['`dtLB؛2vUhۆ`+ag|7#]S uTa A3,eM=r-&-w3oH S2buZvG8ڍ#{ y]݃D.v__)9]TUl 4)`JBE/WѢc{(,fv掫[VKsgi2 IDAT,"2hW90B8C]pu0qMv rVBF t5DtA,!0S}Mt#$bW8-G - 6d1_¯pؘpDv'&*flEtƶҿ4tJLb|DF=cgLEGhf;rltShs*EoU>lJwh> QPg7F:Eݨ31{;J?[ݮeDtBsݿhZY 'E@Kq1s"Ѡ⸧(^nK Ґj&5KIfꐲvD[}ם|2, :j0Pz?4+?ԟCn|2SMM=>w}~@Dk`Q̃Æ}cv! 4S :,TpgvxR@d"* ѝGvt]DAߙ`uN"zS#Åw|E抄DD2JiT:,a &v園M@Z2F*.$)ێj!ue`X#IA ߾},kL*{s]8"h˪BcbUZ VP :>HԱekks[ 7uI湙ih،"/cg|Aܛ0sc­9PPѫH"t b6;;Z24dD{b<3Al`]I645ӎ bq7,+p =c0,JWLI>*k=Fer%{fky0#FeF%5<'R޷zN?,b*sdZf%{E*eF4hV z#:T|@Ԧp`Ĉ(:݃%DӗR%EY1oq $ {qFFhmJG[ƕI'u)5Aω6IAgM6Їq6n ' {BIci W@U{`9PsS5-Ʋ<"ь,~eJ\^q|rQ!QwѶ.VFl7g"h} ,&FXB Yn2٪~62*bsB/YËܪi{7gOg#ɪX%)R**t%y铖4-6V' lؚͭwh8:PJD|ۋ<Ģ9tg36YI.6{hs=l@b`}p&7n{mC evQǷ2)ZF `꛱KsˀbA P0sv2 /S|%y{(wa@X2 fspIscdJI0 E9 %쎰t[B|J%@y爨VGL>BAM*:6b*[$uu_Ѥ?IwxA8پ _9BQ NtB>}']q_G$6 ܐwG`;_@H¸|<=F-%jL5{,ŮoyOϛr`#bm5x؜oӌ>$gZw7[_!zgm6̧;T.Zn:MI;m]zԑfod*OwV86Ǝqi&mX9~'hW"ūc'φd`"/G05HQEQOWVyNPөu8>f߶b.HΨ#OΊT al<(Y|9 /srd;&T ^V_X,4ȅt؎|U[v7NmIAuj}9*=Vk:GnW;?O4[n zԥlG3[IB~&p A kBL6M1D?>Q&cptL|/0A "!73D5-!͚czl .?--wv8@fumt[Szt{924͔iT!bpf}=RiaK"m Vo6uP*DPFA&KClN0/i}Ӣ:㴭_Ekv_+߈Ѕv_w*,4VgJ YQS^W@-s0v3chQS;x>Ł4r/>8$ ۞"c {?|&l:o EIb].GuwV{˓.E.pRRmŅ|SgN~Bɕƍ1{@%[jZvhX${VߥCPNVǖDFq+i:gi)޸, a›6G _T(,5{@k8^MӮi?/f#EkY ;oNx?Skx¦. Oi>sIH +_@8An;TiYq.n+eш=5hž 캻0"F `t_+~_nkz̵:1vY &z/ZU<'GHT'`7rof} `?}?d5qW먃Q6bbC4Tշ?߬Fш@DqtG\nGw+ef ElRHiko} ƶ.nWt+Lr2Ift̟Ho؋>￳C]ĆwF0H eOeB&gBicCkmϕE>׆I}lnҚqv{gy@kmh =L]q/WPae:?mҐbD辬"kYv!Zw>QhDwi4ss[{_urOX60ڋ6(klu}1]a8’I?啷2Q7cbhoM5L M^>2bDSKoOpop!nЃ3ڹw&iy]rV'gSb H@dfDo?X>™ ZχA!Il(BCӔYv7~)I4-di&9=Cw`PO67yj0>XVխ(q}Xc@ಕ F 42ުCho_Mb3슱{̎ _Sy}u_oʧ{F֧2L'nʹ w؛eSWOOhm$mC;'(&{Ψ:%":yQLfeo!)zrܯS-NE :lpzy1Ry~]C>/kDXM3iά3mv(]`yZ2rҼo&CfAHeSFn*56j>D|Vty}s(8ј{m ) TIϒ5MTGg5PNG-_-0|f 3xLˌ**eOI!8PaKC9ha}xoDpڤ'xRM=zL)^]rsn 9nvM;ֹGm5%5u{$m\8p(0Y{8C5褒0GMwrGg8s,}\owS8t] "+nt'ǓS!V>J>'L3ob>o$T@!.yt.#̺! lTtY:GMk[2AUGlqY8NyTfR7D!YrpY?ZG /⊜-$-a|66TAyIhi.EHWm0ٝ~vn`FsT]*xqZGb^`O=S9Zn߼,š%YcG,iU\ Kۄ羴q]Ys34يQUz' tEŮn*6}n]b~k 0(htm]6>ԺXgyd(~"PyˈFNjd_7>2 aBf/[^pKx0@(p-uAg+ "tԘzo!a #"ɤ;xĠAG[';ǁ J^qzx QlOCeM-lZHI9}^ah: 4ҥXK '´ELD✸H7[Q߬K(~ԦcAQF =˧ Ե;Q :B2z?%bAfPh{!tY (U4ahh;+ < [XmA=Ou2N Ok>Ta}B< P# Ve7aC6oE&d!RA%(h; VNAS)oߏa|.պJ@iS([OTF]6̣iSB }DcdʈXáػ˙MTA]PS+4aIE~6򤽍B{vܬ%hz fnKlE(G?[T=Ƒ''8T}( ^`Zܦ͆T-zgI!Ōîo˲hX- bp(ZTi -2t|؆>,˝~lɝK6?Q $:t/$\\>ub)~f_YZT)DT!{\v9890xPAaT<6j#{ }bnجJ1wl.% /&NB$^ljʧb*(ǜ=CMF.tnFA Թ4fu=Ќ?] 9II_7͇ղxo"}+m8&ªp #bwk _Գj bxb1`XE_#Y)Jц=~T? w_?m{`:CMIed 'li3{uPIӉdHtskQ4,v4Hވz1al| Ln@~Kk/.)dv#wb㉔>L歉TG&!aS,<)V@da[nL64X}:RөIq=u܎Z# et6RW`8P`͖1'@12CM͞=/(;Yɷ* 'aj3^U|o1Kk]s:]ByT#8*%D5{9_?_yy_kZK)qfPθ̤-m|c/'ռpn+~ %9;f$ASr 16nVwMw.ZH!/.z4=n 2|溽` zx7 PE:>#$Io爮ТϞ2д Gw3p 6lp˯Wuo)f-(A/Vh*yR*F{R uGll0 PGiKL%Db!߻7V8SekџXQХ07 Ms#nOK]@₇{.>,~"R*O͆z 5>Β!HQ-sdht8$Y/75G~ :zzy?pIdab0 0\@9y:ʳ{F<|)7DfeHmqPzF/xN!QP4MU0$ei2̡E<tS|yB3P2{e0[쏟noo8H#w}`{8 IY?x׌VrkɌMܘ:g9kIGCo=9M3]gG`\dz+衻b\nW4p<,`v_R-l_e+rI*sD} H6 M$ iGRExܗG .nfm;*"3RM _λ_"˺j}q,CV)i-OŹ>p얖ǵu׾՗>ougsK5R\x4ǴgYCppiR!醯x5&!@r[M/uwMbn)4ZGipO=(5b/fϓl-mSMy[IJF`G)i͈TYZZpL+гSLd?AeݙX,z[ŎS݈h[`9TwU MF=6u%kv31Z^s|S ]g+h" _oLH,[!&+m+^gJlHsSÝu6upF*RCee$jɄYn=ݖ>҄>;TamK Töar6SpeHi G st?<bžq4t)4a#{벛9Wx6; *GS_5ɲ9;CX0yonO+3Re9ئN1킮T#j/DpI z?cu1WPp0?ا;9hdwTͥ0"qܫ㧟̷od Zpq1. ? 87A({6uE Q)O!܏F8+RQƃ"=IpR<;Ejsj| HPm tyJPhzz8#״C:"+(3kLf_3NTXYtjLHg#0h*gX 6Q=¨Ъ8\8}N ('x :n(T͂ Ne3{rX.^M26L!lG ]+G^ bt|BX\rkG%o@AUl1h`-aF:тRTdٛfHOWݾj-Qn)K*(wٔYXW(H~tfAaS&H {6Hrm)z. ҳP$H.=oo"һ&&! pF?͜^LOi꬞#M,Zb̾TpkӭlJH!n7Cv" ^ߦ{9O4 ڿ/0Ue%zp_=bqpiZxhݸ?|m5?ݜPf]QC+ uD201w_mo)KZ;./`m=,yLeq`Qs> 3B0=Zyئ(,Q,oTnfOk.!8򃷿)k؛n^=|&Gb$iA)TS+`qq d B`-aQJ:}܋MxP}ĚvޫV'KZ{s҈ztjk w`&E0ś|[&X4-dAӝn@ycs "6(F@SEEI=oo7`6y~WAZ5TO Ld9QduvJ  /B8'໔;z'%W6#oH-Kz=pzXXta݉fJLe1H(OƬͱ Lpf5tƪ(%'teSX*df.i'%dqo؛BKczj ^9E.j/uQϧl('a(EuyL rs\Giw9 'R>!lf9@zch"W]jQh(AѲ䧽b/d=l?sYὉjxף3 d8hI= ۿ)ݗ|x_mmJϓGa=B|D>;sgFOL?eE)^C޶O( 倸Oiˈb _``pVF{Y2+dc0}zH' M<%v6ոPwUW7 Iܹ_jw뵔]g(lqC2W]vz0 = 9 x Z>a1}Uœ0ZT-Ѣ`O޶χ IxIv|>9Kg%K"* oV!H-o,GL0$Ɂ~!z  Ax ̸`rɢ +"v>h&"`=NẌǡ^.~mY"őwc'KQ4uRSH2NG,㏦xQ#@߬^).giշ=*15D f޵~q dә2*g>\~dTd`rc]XY~cY0|67c;LALrtHw 'aBYmYCBDE+d4MaAi4@FD mPmO[Z?zY)֨.7{{Gͫ)Rٰ<ڦX:;W<^⎄LUg"N8;jv[\w|p^$ϴ@yl}VzcCԽ1s% ?/ O+KscYo+!դ;6n(̗o:8GMWFgӕ!:¾a^o>cTab; j4HPQ:^u[ao6{}ksf ܶş->(yM'bh_ޑR7Wá5~񓷘ݔʍSLx= 5HhNX eokEW=X'd'ҍ&_#f!kSM% G} B5jk(vahCid/n-ή1+} 2Aĉ Z L=QlOT2&6>qķĺ ӜC UfZ%7W7v;艰/M~֑ bž~G% ]+{֣C J젼6OW|b7 gQBZZJ6 ú wmс;x.% e޵s'f9&s[2C"(bl[k<ąNw*m/Fjډ"x5b.fLl=X`s;BHQD*ʈ^Ђ87?ӻR2*J1tHmwWfr$fx)Pޗ,(I8:P>NYF-5JWDfRp^DhAc\fHwL %"hog`v쟩87H^n|o>lAE N m'x$!>rUQnܒlSP{x1eQ+ȡ_jf|"uأ<,yKYN͎=فۻ իp,jC.pGƢc\nc+ՋDg[ _;Cs_*#X8 Mwݎcfvcs+ژ_86XDeXk eFHP@K_Wg4ʴ* *I;LS*eڸ;Sh(=4K072M9*'?1@Tij̐i f.=޲OSq*%&E;Fzn]>邮xRTzQ-2׃Y[3]%Mo٬Y¦fҲ{xv5Sj\̢n3FP!eYZ,H hN@3ё =΢=X?IDATE:6v_v7?-ET).ˏw{_b'hrD + ^=[ jentҁ%cZq 0Hg]UȃEqB!%Iayi.Rh10;g$d@HH~ v{]+D#E~L Jx>PELǨ04]yٱ[}a JF 9Ms'}SM:t:+1G8(|] )*;q& ]r3`Cȳ{GCwccxBGpGlsI|>([d@`5(LJ`yTxר޲ .wqM{bE+/  At2j}YjLKX ʩXƱh9%d71YƝ;L4EzRIqm='ba^TAdf %Qgպ0(V}_?V--00SdD` /e(@ؔ2b IR &ݩ<6numϯk5[Dm]$)aAl/DRm@sDL ;Z V Jx]~HQ"W7J\n +4gb>b!E'= ?+n4E@^'w=sSlֻ_?폟V c<ӋMOsnA I%F3hIM{ 'mcg=leGw)fCt륙6rN;b vEQxN - n{CpěTXƐ Ugg/Bk9{OQ6>ᤏ>#Q4l8kkB,tب%g~fL ds-sU\2T@Q =춘ܢzκrwBV!9h9DSY, DeE_I^A%JSŒP;)9~ so>)C_N+)k#a%00HB-]thytn XV 6 ϿߝìKboi;Xy2E(xzI=9>TH >p}t'K=yMwov  jQch14mL!v33U/ oN4 FpS(Vk5)ɞ_G)cb{w?iO 8tTps 4D sSa䗃pRΫ>LEO2 M̙ NKh-77o>+>hT͚NPNCcb!nL99thNW8#e}o[~j~Pqxf'r|>8Ed&<#)O5Efh )6H8g!*M?I< An5禉M@g'< 6{Tm,RLMJXRvńoe7 ɵ,"PqccK-Ԗ,/^~Nmㆤvuak?tIC_ai'a.;!k@[S7>#5L6(RAAzFbx} ()Jff}HsoJBswx#y0 R`0 ŵSǃgME?0Y!!vtr>Cȱ'#kT 5cj /C2Wz+Ru{yK ,J=*Ulj)HݰE8 ~Af^ =݊&!!I`oh_׆fX=r5|~`$9NxPNW,0}%ezR }V1Lt6h-Oq(̸ֺAv=]! ],Ft+,_u%*zReYwZ>[:~v#nW*t/_ןb7~ݍV v nHuww-!xREdd2U T7)C"im2 ?ںqJ|C͑eϩQmX۶Qdv/,m1BG!~l45tL%6kkzZ%kk\s5\s5,kkf5\s5\s5,kkf5\s5\s5 kkf5\s5\s5 kkY`5\s5\s5 kkY`5\s5\skkkXs5\s5\skkkXs5\s5\kkkXs5\s5\kk\s5\s5\kk\s5\s5,kk\s5\s5,kkf5\s5\s5 kkf5\s5\s5 kkY`5\s5\s5 kkY`5\s5\skkkY`5\s5\skkkXs5\s5\skkkXs5\s5\kk4IIENDB`barry-0.18.5/desktop/images/Makefile.am0000644001161500056700000000135212242254476017227 0ustar cdfreycdfreydist_image_DATA = \ background.png \ scanning.png \ apploader-focus.png \ apploader-normal.png \ apploader-pushed.png \ backuprestore-focus.png \ backuprestore-normal.png \ backuprestore-pushed.png \ browsedatabases-focus.png \ browsedatabases-normal.png \ browsedatabases-pushed.png \ migratedevice-focus.png \ migratedevice-normal.png \ migratedevice-pushed.png \ media-focus.png \ media-normal.png \ media-pushed.png \ misc-focus.png \ misc-normal.png \ misc-pushed.png \ modem-focus.png \ modem-normal.png \ modem-pushed.png \ sync-focus.png \ sync-normal.png \ sync-pushed.png EXTRA_DIST = \ MainButtons.xcf \ scanning.xcf \ Makefile.am \ README \ background.xcf \ barry_logo_icon.xpm \ logo_NetDirect.xpm barry-0.18.5/desktop/images/backuprestore-pushed.png0000644001161500056700000003235712242254476022051 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME,1^ktEXtCommentCreated with The GIMPd%n IDATx}_u$7WCRb- -DK bgKYmATK,OR*hт >hj*h%|ߞ>Zs149?ڛs}[k9s̈u_~ݯu_~ݯu_~ݯ?"Doz\?|?="w=v=O|3i/qޣ/A޼| roow%B&Y_/?YaH~ш^?;?{H/{/w^A^'4> R]ic}.ױ_ۯN{Ys-aY~g~yY~K|׽A^(oZ sa~~f<Z𲐒^#׷{ R?@[~z(fg&_7H"qvn̺a0kуXv."Z0+" [T ;ԁg{6D({ wxNdG=#ۡ>2[zyea'>ϨCWz06 yE aoc(5Y6 ZקN ˛ ĬJ&{ {0''kK+AK߮:snΓO PGrb O$Ly/>#2mXOzyhhl9qnpzmcd A&RC% CR}32Btۼ례nҬSYخOk_' %`{ϴ8Lm !^6f&?AӁq'x<¢(p(D(c,IhXفʡi1tJmSأ9Cn\O<6IǑnU #!X7 NH@3gz o C2su*x-^YD[6GVHeG0O -=٪' ]Zj"30#=$Ƚ;N؁c ZۓE,a~-ADM%#qb''fdksID) 4d[XC &$+i (J7")vQ!QFByl4\>baCa@\IAcv5Jh9>h 6<`<3-# u0e$Π1%'761Vm43#SW'^63:+*1P&Af4I_uZ"2$AXI?M0`Ls34}%q)Gd@CtI疐"aʳ׸~s'(d i l!}QCE7oR_xo#?;@JJMgDRD7FDiDT$)q?(P_]"?]CMvMM?dL=F~b"+\ *rq܄Ȋ*+Rܣ]"Л~V&h3}7FW#v :Nț^Gp5$ŵ1-ʦ^YzܲHTK $ bSAM9@OpJ ;%q;I(8R9SS1.!ȍy! ãEi 䀒dHFJ~T8#dS>:zb$WݖnG`Oc$tCN:r!<͠uArݦ)kVfK9!Fq ͇tM`-~_D!"SV!- /yǂyѲvRr<89xh j7;,\=)MV_ǦBKcդgi#W,l8TA[,쌼QyE5I@*D<3tw1F .bn4QBc4F`t <]"F_ZQ}*3\_H$CK BTdI:Yc*hb&GXu36*H;03Q+M+ ԗmR,(ӐzRςca'347yG89i= Eza[,{ @`бiBK>NnDJ3X̀Hc*K̐F(!̀zXQ"mYRD^TJcm"֨Q'Fa8Y'()V.֯ة$iELƾH2Dgr'69a!*\T겎˓rJ.7iG"OK:JwqQYI<P ZYZ4HպjX1Wf."J.Ja>aкʷWfW-Vm^ ^O,W56˻\*&R j :DocI!&)dqFe$Z;eh]`u,"g"Qf'(1&Fڈ! Sa<q\{:ʠ 릳 yz=7zoXgm";8MDҺ i;#J7>iE'ssPsoMi[$ Q6c+e-d1,Bӱ5堂=;< W뒁C:8'tZuSPn`Faa1~s hmI Y_d"|CXR}*?ğݮm*퀁60 ?/!"M^P ?Kt~Cu\,0B{'ˉ^8ہD],kiDHTFsKG;t ;i SsNSt \;uÙF5wJnAmfd/&] ~;8ahO5Ƥ$^ɦVdz,J]F-F6ZT+Zy L0҅tUtM3% v@ՔR8YÛv,fC-q|33~u Q ɕ(bwK(Z&qkP ʂF+FJաi5~`ŖӟA +%P{VIP+A칥_7'e}}dQ|Ckɜ< b hx({F5n4:1oȓ&pE CS:- `3XЊZ,`N[(5&|z$,g3~aO?=/y>Z_[矋3-22.^O2.^\Y>a2PJ̕m*9"&dUoeRdߘCvHj`i w;S \Bg" Hlyz9nR\{2` qPDG:vꈳK_q\?yWӪ?qy4r*P&.r#v!%si.e `TH_0%ki3Dl }p^7ZaYT-k#"pD޾WA` A.(胂]h"d\fj._yf1l)fP#Kfs%ԤL<kznIhWKوZRkdsŇfdQlA'2ҿ[ bאΔ P҅"y\"/>R㓟 c!)AL}3vy-z ȭn!}O@vAjݹыB[)d3)EyR\NԐ[n5|!% v"R t["c.]vnFrNyJ@hmh#OpEPSV\@4FVx;v +6ds׼!̋YY1KK6u!#yՐd !n'c?F,u_(iQ2 (ͽ!cwwsRaz&Y꓍wB!56H!Êv Y} v9)Y6~j^Iwd/QnƄ=>^ZyR U\|۹e1 +B`#Qfʿ^ MnB&R X6UhGC룭g *pX>1#ɝܮv7Edߙ[6m8KnXA.xONQ|)}u`aBvd HRQO⎚Gj@! P9;Cbp z׀ aޱ.,Kl`wcEWb=\.=}撺ڟlyg]LȮ~̆4NCd#jHj՝ttSYGI[[idr dM4J:, Ic T9ʲzÓ`ѓ@tLGj|5(Vf(U/B LwY\*#RlJ}(h4۝)Z+#@5=k$+>$?Ծlaȷ,;>]a EoIݜ7 TLd!ی>znX\j (Mbus@b.B\tʫe I̪Ar}fpnjCHAH%=mS/HȐcv(RQYcl[#aKݸU$)-AMZ<ʂ j^'%vU`S(%e{`JE:I ;}~jw!TW!wstFhnv*h{u {^CGGܬrL|ʞakNT:y :{L*F(&؃5 h!b68m=yyҬT-MA}k KDȋF^a"bANNmz &;_Zwx^># 4Iӟ;qTCh+]Ü%bX_͒A)^2ν5PG%Gy9mk]M%ѾͮK/d=9wnx[򙒚/T_9<~]'~*ΫZ;(ap~lRM+Ǭ=r4"`/aS:g۪Fk!q`, l[o%b?0?/Et8}ر]Y #I"Ȍ|7G~`}O<1={/9/R\>A -B3 imł.Ybf;F'm9֦ln:W5l}/e| 򭟈K!>WU`]#A18=5t/(c?d @28ui*T8hTɀ"N,Tz7EpʂMcà8Z=k|Slu21\Ia7(bE ski_WN7Wӆ(ّbuB Uƨ Tu*Ц55_k:ߴyl(W}6$i Qq\Rkkn1Bܤ)]?YRsvoݩ7eAA'M?tLFR6yx8 35뭷ޒ 5E-fΛ9~|Tb)OIG|druA!o5d 6J>P"[ s8?Aێ`:XG _GU~("HU_d q/h/m&ѩJgGbϰ!N}(H7M"dIyVN̓Wb?ha)UT+&%rett9)GI`' ( .&,NhO'mF%D\.G_{o_|ZO!"/ktA: BmMҍ>P#i5}$\Bf2KIȇT4%l}dۂ퇤a.qkldI=cz)/d^=[y؎ʢ? "b<?w4 l0ݩI-szzE^.kx#xqH]:]i}+Z+{}NEoqҹ~"8sc@&m[lj1w|w)^k 4p-@:!'nl:x;d5GߜN"59 -(s uGM4XpN˭/'CU5$H #L 6Se"8Kz]r}/3M9.ww"ʹp$4f LbӵƬ+6:e*jYCGXf6濹>jHNuSorc/"Fq:Tj{I͕0pOlx%QjaJhhY,_ n$)Gi6%`!èj<*'Ca۰֪0F.2Q8i4$!6rQ,(0Aq"YdM |'PCm P҈ > dA$Xz(=Ĥ=& IFj4v1iHtO z)8@s<2#}@fFQ`./sAAIiOP!TaA:mSsyB7AC\6.E jY܃2رӋDu'Ee0&TX[SaQr7<-טtVm95La\>TXsfH7wwsUW0oI!EǍ9roґd;l#@} 2d8fҒW@ T _l]"i^<́fʇ5sD.3 )Ħm|y$7>p"S0f>ѹ ;<g8qJ١bg,)WȡBa(ONwkOl)K T^ˏ3磌x6+ lb$ʾna(Ҏ%8Кdlo|w ꛶ᬨHi,nסi[jQIT&j^ rSiXz$AK7:rDTA٘/A_C3!EidMV$vP6l^/ِol-҃.9L%01 E1si!747ìba7n 1zK|Lǟ*9OX%v29B79Ć(sd%8/AyR6~! _^әMf^P. 2Fe E'mNJ v/|nl`\D3-ܺpvR Ko횕^Hm>r.6w6lDyuhVa,v0Jy`xՏm+Ꝥьg"|Zsp>m(Cmӻ2_"vpfdЛ*0gاird[L, M_MI ]ɑ*vOI i4-e)6Z]ؒUޚRYPծ``R5OP ͓#vf΅@[¼8$>01 6kѥm0M !&󨼢u7ʢk<:,jrx*}CRK󝲃gl|҃s:pFL,i6 zѴssKǾw :IA7HD͖rK oƄi&Rjts9(3gv>"HS}] <4yPG t٨ty8psl%MMnePz=hW`ҟE*`ߐ.;w㯃sӡ!q2(.Vh@6\>+ImPiayh ehrwj0Y3wI2r}O4 !-M|N۟4^Ǖv`k]C-õlQ?c?#,c"F&vd n j;J',$v#W|ކͣ}5 6Ƀ#cg_¸!)XwSLo92Wpk$/)]P/\8H>mknS^r$';Jyvj̽Ġ Uv_ь na1.<'u/҂gGb$tC̞:`{LhRg6}~j0J!Sr:`ٟbOv o_:k: 07Q3O;:(%YNQoCUH0חрQ8=]{[y;Zs!+UTp@l ZT=T|6F,ol&>(5IC\Ǜdu9,J[RE5nłrO1U5>0Zg}LNj_m-C+FyVHifv8dY[o;\Mlľ<$4pz!#@皤?) R{D0FzOԾ8㯫NUj`0+mpA#lZ,?KI@-Ց+] ƺY-ku\2JICMF>K*6Z`,CbY}f\[{ܧM: 8LL.Gl< j"o;]ٸl2@t?Acܝ^fh#N13Y4B&׃;M߀- x(Cef(5DN<-BdM]aOct4&=f7M H| i|3+Ji=Noǝd4*5kFTkMQ2}7q<a#teXfuNڼq/m=9\#Rld3 LjÊ?î;[UYfL^vʈf'#O9w rraQw5&]c36ӧxn'tUFr1[SPPZ!?:fMXz`Hz1<8sVpe*zlº IwS sD%iolFiذj#|jjEt}Iņ>KW0D](g"$'xMY"~PrZhŐTͶ~8uկ}`+3" `C3b 60'Q:B ?6-ZTL=t/([.2ɧJG%22k])ڦX0Fz0 'J ;_fWbb: A; =^tńkK6ڂ?g%_m#6a6N%1w*& GM.ݮ |jĉFhSާUMIkL5aZ¿$X`1>t_N ~fr8Z!^'|$6vETo1re|ΟZb]|1#\.BL9NzMٺ6(ӴkעZXKmе5Kj m9+ @IVQc(=y.L F- E W VP :M!!=:. Yl$ջHe*-wC^mE@0N!~<µ'۬Ȓ]Bd2H&@̲CFՏfmP<0'$q֎~DA.7b/V/Vܯ[p׋o/oz__z ~{zv ̧?y=tND_~ݯu_~ݯu_~ݯuP^:X|RIENDB`barry-0.18.5/desktop/images/browsedatabases-focus.png0000644001161500056700000004025612242254476022175 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME/TtEXtCommentCreated with The GIMPd%n IDATx}ۯYVsn&^ !!1xIT` >?`|?>hD/<؄F MWuW>5|X9ZT96~e5s1q9.r\q9]{9.Q_q9.e||ş$og__O/d ?S~=d/—$vd&b7n2o@޼M||=(N Ώj\F3^s/?TL({RM/%ߨ:9;߿k~"%O:[)%~;?wgo8_~ }! gkzN5=sד;gg~{՟]3« 7 >Ko:W\a!ɽGs\X"(CF7>_'w}ض a亰P1,nk$|\vl g #ro{O0噮os(?CENAV]Qъ[nl3Y0g݀쁘! ;VcV-Ϙ0c~R=VB]g _!n\`L# #({Q]3,)i?\bv/;@aޚapcAѵH;ۢn,=Q]LCh,5:]V(g祿vN  .J6܉< [ß{:IODxiT0F\Ly}'bxBiY)qvfsme3Nc< ϛ o,JF+]Fw6[*Xl6c!]]aRr&3buC(neZ~1@"b0Blgqzʉ1UsB' >G/h }t$4V޾n@C&"@q7 ~B͋ ]8W7G}L\bY *]DuXF&=!@`myLA*,:ׯuտ Ty!nM6a0bdx#| 9TМ[Bp#NF3'DL 9O,<^^ p,J:lMb#S1ǽ3?Z{WӺcf,Wџֵb&8&]ntǟ` azNw1tFĤ[llH0S#2|,mrn󊡀ta"z;Ira">>tc-2hQv/b.0ܡv"XC+T+b`TDʵS( VVҸ收W]-bW btS 8cռ|*f=A_P"6]L@-!ؔ#JoZd"MS N,֪]+I.aqI A" r.b.Sy3<zDNpDZCjjIYܚMcD-em9Ӭ1sѣc5v'_i) x$9j@V&$*m޻r'HVt0-!ZMDLDrD2m1L /cMDdrks{!VHc8?bRt㠝 v2ڝVWaa0V`-@7G ,˗2R7f2E ʙDP f8H`ajż+)'C:9dt[]yaL/ ۍW(qaRks5%.bso#jL5 $NBC!ҤyIʌ*YTvNfqS![ޤU_ef=F3ߠ9#a–5HU,j)ɹH 4EB18J)uQZPk 3=ѹf+qG {ݬƒ#^C;~I@]qfTؓfmkfdj)+|͜/6|jrJnIj,d&scE;=hAhF3Y3'?@X(pԓ,3Y*?AHb)P()RR!üzץ~PBJu ,E -l$#wfl)Πᤎ_42zМCH&|mc@ 4zutfntzP> Y@ϮqqHӻ젝 G53< YVvM"SG{+۸Ë*+sj  L{H0AT X-Xv^*Rs] Ϊ]Cˣ0tGÍoy&C=@e"M5- XGEI: _@=AԵhԸ Ǩlw=v:jtjX5L oZ]ݝQ4x:ȓUqtn05h?GGڰು<2=V% Zmoy> q`J,v}]YPj m҅E/Pk2λ$C|ꝣ_x7=L_г7i/r()tč ևf{'+C\h52ٝ5NG5\a8*[ 깍fO\=.Jm8R bѪDF͌,@! SMP{"pI|Uyz"B?nўvѱNi aɈ;A\M$Ҵ W2U-UU0&yIj4KWhE$WK\A0 yz}ٹ|;n2v~+9%Cb fqmj2DiF2{\ɓZ f;&FL9m82o!Ău{ іrDp;zajb <ͨn(sn5Pˏ}7SjkEd E mH}/Ac$Q;bx^Oe7=SzZ<deW;]e&5Ё rd /g>0+h맣3Zy]rD7ΟhQr̨ ɓfMuy[EʥiS Y1vσ0FA4: y !cDP lD'famOW7 e ×M1[BQx竤Oi9tVcܬy b`Mp ޵؏h$PhȬ ,r?iJUQ jܣJZ7z X]X3tw^Fqibղc%;jvks7]1+ .FII&P\ƶ| ]rQ\zrFNn$N\V4#Lo2C8QO}GUEIDQ[Bխ Ђ3C`2 V(kNKT1NÕ$Ipʊ֔IF$ܐD̝L537!yE<֎+DQqS5{b\JT+[U5[w;DԒo44R[>J:8tzeكl*(ŪXAEQ( ;dub 00^4:A'gGuJՋlrMH C nQ يN_+R~ꚵ]en:=MsUJ'n#Vxp^JQVa^[*E30X[Ekl"YbhU(x꼨DQF(("F{/ȧb|2̲*ыϞ f"+ؽ"YV+ qPUqG#!N<A Ǽ'hx{Q{ȯco:5)ŨVS#GZF((X_@Pvgvݮi:NZ03A =LF|`h$oV V9' B0l(#CݣI/ Fd'g#K[zԓs6K}3u4n;p2+ Z-ytV5 Zi!͊jyT=3pf')^죕 #[H!@GdC7Џgdlku,ժ`\+I:Vc󔢢 O! *vi`u^E,G%?hfTUtkj$vYk^GǨuH+K_wGƏfV~G7~o^j(h^/"2ЪeJ)0*8`}Bze5"+8i|Az+imTb[+c܈I,.Jȹ9\u0`lRT]BkNmrl*zyu:j,CUaEpzγ^c"X5W?G9:n綯__~ӑKw/ES g=@NYdłwQ;BjI]˪c7*}qPwyM]LŴdN7 pSpMЍXDZs` (b<⒃x1*$!"T51NՄbx+tØJk*J _җ;t_7?~O hg׼9sIzkޣ\xKw {x߿xw)w~~4bFz2e*XfZ5VJ%oV0ᩫ,/p6R.[YU'f]vz 4R.ÍjZkN_ңޝ6jD ]ƅ]rFmM4:&IIkо7vvs yLj|@b-6-^Yؘ8htgѻeŵ\ C=P=CW] Xq0 'Lٛݐdx]=y_WIz6EC<}9; :=Ȼ5+TAE/^QU'+X uxTQH^j}pÁH]D!FSg4%U=iC<2,+Az#W5:m׸KSi^qrYJoǏ\i2oCk3>Eo„}o\垕"Bd@5 p(,d'`NAlFh?q0Apo5˨RF`hIWFy:s6/;S<,DQ?~L0jcpA L>e{-O0t˻{w^?ş#rQ堍·w߆$ҜjXT;Y[i~9OX7m uQ&;)gTNa= yoڀ?Jz+XgjM5F5\ܩ%R޽Wxo~Ч},W.qxi|걃*P;ak51wk=#=g[Qy@)2Hj3W0~چ4xCu<xC,y|H5AQ`l/@A4Wn}KuƄڕfgC@>_~)zӸ./=\<|rD= _To<+ ]g4DpK8;Wd̑8-w<="B[E9p&̞<'z!mQkQ A1ΒG)fTbOWM"8喎/rtHTeIlN&0 M oltq]:z|&x.e$Dxg~RK Dbc$Z[9KO1fV?6Z8d4esӑ8/Sr[wiW QΞ z D-YN<2$d㶓tF2Ӛ9G4g5iXT.r/q?w++<*] uN>u=zz{:)w?:OꚟyX--MDmClu'K6N5م-1bLcTbL8V޻A_tY"" kg 9$b}ÅH>RT,6zCWEƺnj=?<5@ӧ+<*/@̈·YӋ4^CNC#O!'׶{ImjrQwq)b2T5H<*4Q?%n7IwCdڬv1EM[y @)88 w֫^#C^9ٓKfPvv c3"6諮ݏ6mOnD>F@ӍvFRf[PG"nrj73K0&O }j쏙R~|6#ӭ&霖,E|#6.M^/*|.z.WއK_~_o{P4 ub|6m^0ƱNqڹ JYIi2{졲ޜkEaƔr5`^yDb^A45[VeDŽruueWM/\nߛO~gOKBJ^|iep:M4R:9YacIT@r#W:FkD݂3;%3 ~ЂyQps;^3nT}eELܢ% z.)]T_ՓV94;_^+*v]ui>@`h<ڊq:?[{܇}%4QRkTDTL)R g8x;qGD93V6 ٦g,z,(z8Qo}k*'40c#}tl!g(Rî*%㶷Q4%ͮ[[鷯ݻU~PIz# P>^W_>Y#BamѰ'SF44WbGz.)-}x'pC>qd"S=< ^6ܭ\-DwCEgHSz_{LB{Z[(W*m=w{|^\e׃HPBPm"(oV" (Scn='Izu@㵦[`cdhy/)@X3 Z7JgHe|Wz)fDN8/6$˨gJ+n7 iʮVCu^DA0ξӤvPBF`S ̡Ӎdmruj 19O¥5/ fk cQ5Qiu;-|-Io!7|S!bm@hI:D4c'ru3͊.BNA̭8q6E*G\X5pK!wy6 \k?ޑBO&ۛyq ISB:qɩ8yg$PGQP %J]\렋(܅X8Ts\T^b"muj,_Lb6"cȬZm荈h'|M#K'rP ȘX%^MҮ\v۶;3N[KGމ=uX;뭪QzuFNW"s>T,<IWw`UՑn*,[c$ Q;qYˆn}fMFw .zg&Wč jWT̘Jhɻrft筃t/YˮRy E"7zMD/8Deu !: *.\gnlDR%J* 8X?w`༱״T:_8 >&p)3͐VSZ$Q8YhfL޻1 bUBzÎw>ԮBgt7u & @y4$? 5oAٙl ZHE6>\Ej+ɉD;BW`g3I[\ݱ8} b+zvސmX-PVgq ,&qW`Ϻߞy Md%ru>`|Jh„iսHCdKlR1@)P;eIÜNqg-Ž8 PTF:K ȹ 1ۣ9p,9Y!z $+2唎#maL@F Ak34^GJTVGhoPȇAOUtyM)K'LCZ~ƸW6 IY# 1}S(~XgSՐ5nimTg|;~Jp~,u!PIdžtrknxK=)u*yA4% 2p輬^Bj$513Qê65$Ԥ80ǵZ8|.?zm4Pl:B`Sۨ!F O0D/Q}\d*B.mxwky- RD:kL~, $2v hq.GJ}Bpf-d0p1,%C!Ԍc&b,P1=/0e L_ ^kRXTAqUegBED 3><2D"8ܮC7m<~a~lFؼݷu 9MvgG]tYOZY5jmx+H/Vu5RjkSPjKEȣgHMn9͝U^r4&꺳̽\MVFG#uj׊$UI>l&tQ6L@>qd^ #|I{Ȟ) H7P2R;|W u !OY&QsӇ/!>0nj>!L˦d y3c%v9fUwc-7x䤀v༪;׹2˕2ޢ1t.tm;MҬ *g5/6J?_&ה* IɞFdR&lsGFxׂ֓W~@Ѭ̌)$z9H9u14DjA(o/l[ENB! Q7ke#5st\%&ɰܰ9b (񃆒K=0/gjC!Pp >tEaSG]#c42b}bdEk.xE6K 1KGym8(Ǫ Qk@+L3C JA ^J3vu/^5Binyٌ=*2L$'j/]bu1F$Cr - Bwᙋ%6u:+(_␕TuTӆd)vS!nC9T1ب7F/e~"0a% !$ә'"i&ARs&ZOW TV75"8sBG |'NWܥ9co&:~K l(O% \&\B "хQowʋpC{_DcJ~+lԅkH٣^ }!Ӵ\.85JU$Q0͑c !a1,Gx&Kǜp.%?%+1fKW.8f-TTk vqHSio67~ sCez~ْV ~Guޅ$MׇZ#WG"mQ.d\&aobj !vQԳ9tr ^bOo3{(kbcGahp@~ l& a+D-UH! BIXL(3WԽ:(qXAFRQM?9BR]"#k1dDQ7/eAXfR6B@$[ 8m[2LíӥpD83 o@\ G*(_cņ[זyY#+ZHs %2͔a(`4 \a$e3+𪼐_ 2[Wrҵvu:F90aCq&ra>أf0|-U\x&zPKs-SwyI(ǪЬC.ⒾB=v%JS%12H/bR,>1 u:ukt)u1Ho$v "v!! Cf¬Zf("\ il!4kYKIIи1sLb $ALQ:`{˭%g˟ ܂q9@\n&>[Wx9 @˿%?y9sm}_q9.Cz .x9.e1_ r\q9.r\q9Dbf,pwIENDB`barry-0.18.5/desktop/images/media-focus.png0000644001161500056700000004236612242254476020107 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME3,muOtEXtCommentCreated with The GIMPd%n IDATx}k̮Uu0C;Lm!@-<`Ѧ4&&F1!QѤj( h9X*:SzCsس}Z뾟o=a$3;uukc?c!? v?~c.o'LJo2׿<;nxȷ?.$GƱ?>Oqq|6ri׷Ls}{뻪$2rM%Cń'ߴy[Fϙϡ< \Ew-HSo˯m9d7~ύ% j8,:)ztfڱ7).~߃c<(?܋ă0.ͻ8b QfdwFIcH8<J%Sz̹WƓ*Y\(묿s¨c?J^uL%w6)i>brkv8&<1k^bp.@ߡvbA9bHg ED#UeB<+Ŗ?oxhY@ -pn;5a$'"{705_7*_f676N>g [3kk/0cG0Zа|ip mQ2[277gR0be 2 ݐIo2-Vgy;: g9,k8"E`L{8);VogELip#AYO"Ŧ`u"1W(fXmC~> f pɏi1KX>KBB +%BB&D(=y\1F{ |~TuU G𷣃qŏ7sϓFS:B(FΣEæGjqC,6jȻ|n@6!Dı FB- G䪅+c K)X"o I?ɐeq7pYCDZ2X=ێɔ׉Bz\|#!N\ 9-= lX iL#n^&ܻpaz>γ8|QaQN.m×ad PMWrDI@!Ӳi\([J$KZaRJZZchM{`ͼ0<[Hm=-)f 79 ~~ ME9aZTጼuGny(r€|&X r:9;9څF \f.wF+9lƞXx*==ecI@6`*(%JI)U;b-7`rXfTv/6+yi13AXџ֕b&8&]ntǟ2R\!:\-b%.zIy"o\ h4ŝgFlgdl)yc!ȫ.墑`5i$aMHZVR"WI)!*[ 7~.:=#6=4m>Oᙠhmj_(=| 'r cw6S$8S-|,mm9ECЅp$ݻm.c#wBp1fQ*cU`"cn'RR^I5"PrH%jDJ&AIԚ$t")$wXcƉ|E/pLik%z&P|] OàX5+Tݠ/z"6]L@M!_۔Eh;$ȹE=,ۡ3eɆAT# 0.߬+d4㪔(r~.b UTJIu;!%&RU်%SjXYƮ HZwrpXfq"9}G~ڴ=ЯIŔĸ{' s5c;b˶ üVÈDY(D[cp@%Fb07A3#|tUq|.*R%$i'i) (&SZE$hMISSaK7k9;BkՂ. $zuЋt$]b\=qWCZ֮ըeP[]W{tPɗ:apWl;KҍS@S[`˲ܑf&3 af%iK~^l0XJ HO*11  )%)Q%IɘVa1hMѰ&ʻ N-d\X?;;Hd:-M?.t YgmrklQ1z4qrIj@VkIm˝[J[2hة#,:?@^(4RFqҋB6w` clApx *N37U:*Ao|@_I`E㐺wY vPl K63lW< VM"SE{3[͋*+s* ,L{H0A)e &-jLXh/9J rsgs( QpfkNyiF7/ѐ!GaHɅB$wjf|o(5jީka#Pqf&l q:r;vK_(H3-εZBL8qSE8ŧ$ ٽȔrMƒ$0iȄDžH8*ʽ#KWV)նJt ¶TNmkg1 PUfro!6ntW#Z3̳U;G* |3C=\0uAB_ȥ*Pqd,f>4ðX܆_tb0 99C+,[A,rÒٺ\HXwVϭ7~b.pֈ%^-!JH[Kh+$"Qea'&=PHF;UQ$:G{[b;M[;ȈHq(TOQBQƵ xE1rhUu9 Or J|a4pØǭA!Q(MԝU]§alVcܬx b`NͰ,޵ؗh$PhmH ,r?)JUQ rܣJJ7z];O8 1r1-95,SV{ }YZ;-2vs`+uJ6;э$Af04!"T3硞 ;s JhJxr-: 4e/dQ֍ĎkU^3rfycbMzW;#j}(H*|IC5&0$&C`ى2waiT󫍤W:!73+Z]&%$%_DfnPI1&$2d<QTz͞X))h|ቪ;et#+7 UP ,%tJz=XTRjeҪ u+c%G"AX"m9Za"ja<i X)JwWKvJًln)EyVvdSt:t r-E'YٿߛNOjl\'cRɺۈUwR:Q&|9 A \ V<Bk%ȕA؍~m,9X&K!&5]|-S߹VQ$RJĐ1!@%Jr&g+ ps8u$oB 1eXkԮ  / GYyZŃ{OG|sQ  }^IjQD+ PeﱰK!!N<B Ǽ&hzVkȯmͯ*5($ŨRS!GF((&X @PgvT:&N? OF GF ĶQn Ӥw쟖f V9' 8 BpP٠{ UJ p ` qќdod)+zAjr[^f zn5:8J^ívn޴G~=~/'~]{̭7wGG;޺0Tf5Ji"͒ry;e=XYI)9(e:joi.Б[NK ~r@WF`oksjuQUft\)EE,.B.TxZS0kc35LՊo+b\J/B3HXQ#ŵͺ^܌zܾ}x7y13|w}H v 8|fQ*A*8Q %B/dɱZ|!#BUoj=p^˲/|Bc˯Oؙ[DAN^b϶>֒rq獩wawݔ̷1p*_Hz4Z/75koH9JEDVx}^tqY_u_xo}[oy[lf0&7:ri]z^UΒBvmG1 Zp^w-Fwn3Zo~;obng0V bEn 4RNÍCqMmQs-ߩ>ݑBz\eiRC #Ue.LIߔP:Z슊vx?~xm|ēO>-K)͇?jFKpb.B F%ˎO1)ܖkXYK4)\::[ Q+$*={רu>h~Ћ-@a, B(2hb8#_; J\|G6Gw5f%el!Mr S|7oĵkO} W\^:v;ܾ}ɍ7O}~o~gk5KO^) 9.T,ڋjE.tMMQcAۚ=5Ng)ZT, M(f}0+j];Y`cy6FAq-[С@o(.ՓXk&wn^xQy{(ҥK8}4^qs=|2.]˗/㫾x~:~GsW[_]jͬ]VȻyxnr]x)RE28?CL+*"%3$E݌BDT@y$ њzǞ~}8LICZ;< uyǩ Yi5dtD >A(Rhsѻ怞o_**Q q4!.^nnu]qMlvpppIt駮^5Gw._B;m`c92h* S%2Eb١-66$yo}~ݏbjPzK;@0kK or}OZ=qGN[}lT wٞ^O82tjU8<<ĩS@gϞ\rKEg̙3>ׯOƅ "sӅxјβWg0-T1 j7Zr8XE$WQ-jeяҥK8Dm4(q)q-ltj=ꡗ8"!^%Ð[Dp76raY]ŮRuMd[m:,VK_b]Wpy\v O>$um NΜ9Ӽŋqq7,Yhl=]l +gRw2!dicz"$[ n.t~:f1;J:n$uo[>{6s#Nn-|~6=:Wnf #LĴ>뭉Ük?o_x, ^gy[/u-ɫaŋp~<> V?c=]K<ٔSv,.Lr r/IbSN̙3888n!_OG>wxꩧ7}><.[fU]ˮ[uHD $d<[9 qWY?tnT"")y{^h;6az&)MwՈțAM8"c.YrR rϽ˲/WGO?7n͛{ ᯾/[Mf~ї\Ya0lPTW]QzT9A-/a\ҧje8^ͳ7[EhO=)OBFHq>rmC)D~EÑŘt Hul~_辗|=oW_=~Wu͛sG{o+Oc4I<ڊok@-S *&`{CI1e/2gǘIs#)RY?Տ3:vё/Srwlsf ^1G3z7бp?|ՂBRXuBne,zzN ^92nDCRR\ؐV'pf 6TR9`Jca[Sw@ &]qh-.ĜA;rj9Dm{Nv*$MjWvxs_'1\=_{qK{.< vكs$GT㐊Љʆ,تO|cV Jq8F_ eCFPOY;8y .9 Uf :K L b0@>lj;eww۝X Mb 46ʥr4SlLc*a߭Sm=u͹ďX|>+yOx*SHJ'?*?y,8Ca*T䈬xy`S`oee)6vey1NAs%w3 {oq͝ikw 3F"#&1#Q3\Ybe0.ɘѵEyHcj.J*ur,m0Hi@R^Jg]:qiܣW/8; ݙm 7~=ppPA>ܵkTT=!yyn,r#uBeb2GkFCt;8*X/l1wNo>{]{z['#lZlfNoDJ,C,^B4R/kKI>>yK쵯;k8)~_~X}x)7oڳ+&#iaWr\$bR=*EƂukR% 31O=vڹρQQQ%q7!Pޜk=0qstD'bїK) I%ObݱӐם9Xs Қ^[Gyѽ}^տ =~|Y<#'H?ܺC,4.]_̹+dsaX5ig-R rNZ!U]>)>~~~PƖ6BNw+[v[#aK{f`{"»q6 \Ħ~?c =mo Q ^ [iQ}/y=lXQ;#/-xr;SٖRhZ*Ky= ZŋWm>wsׯn޸adH/\8:љgrVo nk,JPrMpZȪ4v0I ttp'?FN 3-YS.+U7jrL@Sq=Z,:hwnry(#ɖraGOU58VA2b#˱yՌKUcCCsP,k[rmx;{M_8K < Ceh%<6Ll١X,y(.*K ؼWF\UPJd*lD(4[aj4 )gAqzKp+;,puG @y&9P=CA- 4]9ǘ.wZ4 'd%&W$Jp(GSы:Iod:ʋJ.Ѯ OՇ["'ATR'c0Eayciît}FQZϧ!5 9NR ḋ}l򱏦MH?QZqqoSk\PMݫULʎ^ l۷Vuϫ!o[k ߅, JHE"6%%$)^K"&&ˉDG{m{03MmjC%nq˯aPwNB݅. (}9=:m&#>k~ 7p&9*F_mMjX|iS-<9/Jh Jufg}mC:LEzQ: XA&0bbUK#G'kUW')0D$uD7;]ql4z&9ΑnϨ ]ɇc3M Q)vBy5,Ԑ໩ܕpУͱ6\{nkfC7V]gh7<(-9yE B*nWU#&%}TX)n:RjHe>S߇.TQnMِn!+QYSBcBtl4*bĭJ`TC&RRTuєJ4hh=8ZO LK +*ARle BMs\;:H{=:#JkUlOO" CnOjbmXCxXM9k^EtŇڦKi3;BaFOCD*sL~S, c'2V hQWj) Pڄ`E*~H/$ʈC"T'h@n2%F|)cST7UhpU^PmWD53:<2DO%5U@>[l޺ ddV˭QbEloTQhV6G݃h qӋ{V+5d2)>uaĒ4b*4 y,]&7ٙp/.\Pc2~rrA}7Z#BW#cOI*RLkU';n%pK1>&y5@k !Ag.0{Mʳyd9`Z'{WV^A)H:Q@ܱZFg`'?Q@MvȱUn`RG3:IF:GZG1Iil=1TG~WqfB.S_ Eg::'vʻP&joг9 uD(w/f>‹17K7g65ʊVm^C\$F2N"Ybm,o8axfl._s$gIz 16^y|M-jێFc0OM^ >zx7CO8 HF&u;RGk|ZۍwĊV̹}j '`;ԛWk/}9+fThD:*@I܈g%N6M09zH ɣ^# Ë]ꘝS2-w̬IW3kՃز2h4̋>֪s5[8R虙ȵ^{XXr u^mZWe*$U+*un 8z(߫$ECk*.Ǖ* 셱]VCl᧳1'l@DF< Fm Ol#a(l< ӭĵ{"qR+E~'4T%ۮHHVrm-XNlr b~iOY OիN@AxB(H*uh*| B迹7f/7%~yd/Dn6tr[2(Y1sa$D\,3|?Bû]H!ݾJ %9 cˬ{:IX61,'8ǻwKYӫkJCM,BtnTq#}>lsGFGU 'hXO. l_E2({YדABQ0u%wd~w@~%h(̋CO6 |"C\s`ˍ:gcP m2P7ʘ,G]iѽr=#OQ6H\rlbFFld/YJ./^'>& m☊ۥ#68PhU1zP3WbfЕxiɷu8\6ӻFݟWF7#aa?aQRa<™ɉ .qu8+tg56?݇g.7p\s8Y!L[ Д:9.^s (HjYDK %aqlؽ\3Ǹ8ч:Q)_I&{|'YSF`54x[b^.5IDAT9b1{g% y\v&89%7Eu S'_K}Vg8Z]c CFY> vo)Za  U$Qc1BXcF}A0:L DlpNJ~t*rj҅>9Pw!s vq n1â anez~ٔD ~Guމ7n˃P7>jpglscC'uцHxUxH^Ut/1=51֏豣CzK4@~ lpcM['А}@fA P7 ִr䊺߶~ꉦ:HX:6$ O4f\7@W֮R1r6i@Q )8u:u{F0'J] H]HÐK!3aZz("\ m!X]U~`b@z[齪yi+0=Ē>7?/ cpq㙻5>vYwn ?#8? GLJ鲾cq! ׸?~1 r?c?a$_ A|phު:Uǚk9cc?cP 3VOʿid_g>p'soWOݵ #œNV-?1bK j8,:5<7W1 Mx}}QX6vwy{&Ƞ- q{! '1,#m3 $=^ᓢwO:l˭[}Ù97H=O0s[xi<Ҽ+*ZqX8`܍-5+iFA7`@!%;Vc![",߱1%ǜI x[% w51 tq'A)ދ鯤f؞6냮+1z))7~i3h2+ n0(!%dma)Ě(/&T~Vo{]D4R]j.+˳R^l4 (!n]p's&l~9DDwF5FFk"S{Ʀz аC!qkvf}mo 0G>4,'oZ1+;H(vy3oDb`YvrnHۤ7r↳_tM`"b0Bl&=bc3"pO&}^4'uSbd[yp+v3n!DPxЅsyhqǴY%M,%!!ITjdrP <.Ԙ =HECu >?@ú_D{Zj2CAʛ yI)p!ASn#آaSF #58x!qV5]WHTg T "MXeI#ȅ#r•r?,R7rM$ydȲɸc!"}X-bCmdDjh!=.l'~.\o4zt/]u8lxհ~=sEYp>t(փH^K|%e9YC6d&@.,FR0dvȴlZ>7ʖą(vl$ɒVVAX=wX3/ 9v[@KMB.8DSQdNGxzXz}h*pF#7bdx)|9H TМ[Bp#Uv.F3;DcO O,<^$  `%Hk֤Ms10kI,3{d*raj~Guƴ ,PoOK1Obxz.7T{Iρ` ajNRw1tF=ŤOᙠhmj_(=| 'r c5)㩖fk >6rn񊡀BG8[YAO>u]6‹x~l!(1VKzs1E))/ƤZ (H9XD%$jMJw X;ZID8ma{&P|] OàX5+Tݠ/z"6]L@M!_۔Eh$ȹE=,ۡ3eɆAT# 0.߬+d4㪔(r~.b UTJIu;!%&RU်%SjXYƮ HZwrpXfq"9}G~ڴ=ЯIŔĸ{' s5c;b˶üVÈDY(D[cpbfْs#m1dٛF呍G>*8Gh>AQ)QҔd)"SLkxczǩǩ0׊d5ǜ!jjx s wEAU\y.1x_-dkWjT2.+LC:̰mx&%)@ P][VY )wF-eYH3Ʌ0^4%?/X ,% Lg@dPԇ IHIŔĔU䒤dL&hXZ]D]] {2.x C M$2 –SH_:FцmrklQ1z4 7/拤#CԶܙ忚[*:b~tBsy)eG-(ks&H- 2VЫ=sSf  t9V4{`%ΰd#13vţ je$r1U7CKѼHY該2R˰")TRQIL`2)"dI`*W/;w69/-J 7mVgjt rVt8n\-:J/Jg` PB]&蝺65afrGl ('#lii尪yQ43ؒ\+*A-ʄw:\Dl/Q|JJ" J+L)d, IVLHT^싄;p5`Rmk@D+l LԶV]QzF_e&Wvb]F7 {EΓ#^^- ba3>bV&pnwhxu*x^)w 99jQ 0b s,2RUY֐S` Ōlr ())W۩)?tkšC=M^@`̪ѩ&]X4t }}upry3bhU><{aYst)=91uSt/uڋ\J GbC3 {mNV f!^:rhe%5vK6\aX2[ 깵fO̅\=.3qī%BA 2wkBb%7D$ ,lD`2`ք h'*<*=DhO`Xui a)NvvI6Jb0|x^Y(ʸVOӷ6f @?1i-CZY\g`hYq.v10ù%2LV)lP?$zn&CFHzo+yCpSogvÁ*HWbѺ=łhK,9w_# -50pa6Z[ -fT5iIǾ.܋$25"WS6 H Jj,t1QH1]|o|/OSe6} o{ OUid]8t9l0 #cxNY9p {6r2b}8\<%!_bsP-^+!UTG)Fጥ>"m~53KEJY&tTK;){@*iBD=̍#(ԥXVV1xJɍ! 1W l56hu3,=,m'fKp141Pqt r_QLWoݒKwЌU. ϖbn4(J9HzFm*ɼHX"T4o)ok-Q EAE^alصT7^%@']]ަ*-LG^PA n 0qkPHwT5 3tti}v-(c7+o3,Kw-/%I+Zv[>+tORjTҍ+f" i%Sk7NB\v̿dKn+%唋czC_t4VAK8='nx%JMft#I M y/pCdcG&t^]˭B:MK,3su#cZUL\lY^ߘ{jUN|b+*J"_*oMI& ɐ(Xv]X.FRă܇+ILᐛ.IqpCR/"3orIԤcWtcmq|EQ(*bjfO fv| JUM2Eۑܕ䛆b*Ta:j%N#bճԶjA6*HXAIQ&H;dybVȄZOF-VR"E9&C nQ wC}\Kkf(.j-uIdRJ5Yw0R@W $v/g!(b6RZhWr9qԯ̀{H=Y 8.Zl0pV=,ܛtvL}ZEHY*CbLƄ`*əD+$p 9ϩx֑,z 1*DQm'xxcxާ{O.nl5Nxɣq#Tk$D%vzZ `+SN/rQp u$\#dC7ЏgZ!&fTq$XSb) (X \>\&8 ڵ an# ۊX$K̨: VHlqm<7V}d/-_ا?ӟ gX,O^}zsOoo+_ݍޯ4ɔCLAH)M`UzA+ƖIx.fX QeaԿfs#:"p8)c-Zꬍ\=`8(K{89|'wq`+N_@FGx|ܼ>ݨ󋄏p|}9L,#\xKW o P{b|4-Z娸)G)n$ *)t[_cZ:Gx6{?CҧăGz.tSkb C{4կR`*`e_'ZbeX*\JP(Y"+=4NMUBϬ_߷\{?O1ulC9 L fy~*'vhpؚq\kvn-;X-adRy \Flc>?Gb=w~pv( o~-0 ,8~nM<|v6X/`+5 ^0$_.„uo\枥"Bd@& UXDii;lMA z+.wpDa"0{ڠFy:s/ۧ@3tL&2.¨sU;\]dœ>lvx˯؟cJ IDAT5л_ŭӆ{w>  LJ-P"><]ܸbs7{'z HE*B`I A[*~Z x9G):#Tk&WltZuk9Py!8 ͽwkj(&!FIVmrbmef_ೈlU}umE7ђV^=1{Vźl8;or~HXⵐHl0c=8h'r).ƍyݯ^LV{Y{뵬bQrVJSё5EZj8X4fPXZ#n߼XU}u@ mZ6x^*aJ+nƅdo?:ȇ̳zzmSwgo*cI)i`Jy[HvOΰ<~ ~_55-[ o />)DP^2+XķX5vOaZF+/*6QeR2ѠiIsb12]x!E-7E CJ$:#GAqUb#OQc˒'#@.T< w#t[bx zxc}= wb=>ƒ{! ׄ_O9N _=|W_wݯ8t k /#%^v#ĤpqLm$-a% n.t~:C)v̎R. 'sۖoϰ\)2ʂbws S?>۝^F UnmksH;}c;8bx{w#\M\Mnõ^{_iT =-ʉ);z_&YuH^6:Kyʷ䔪k!GYvvqO!xn(EPL o62g1U.g4/eg԰AuE5F1nٯg GBRZXs7pg9[mV8ص욪3%Yw r c_${3o0چmi8x,2?煶c@%3)>EëYDWSw7ڣvM<||p|󊴮ԫ/ݻ-'9N^`yry-g n{!p>voc7of˓^Ϩ]wWJx 8O),'c|́PkK{ѦU_{JD[P{X5zu>5zѠ:Ig~I99OSh (.://×ocyrЪ{7N޽sܙ|.Kׯ\>]t݃'T|)3 A#GVJzXv,i(QU5y %n[Б+DY{LesQfSnkD dz&PB 4@cԓGyUrc=:zt/"1ÙAXuBn~3Vsb2nDCRR\ؐV'pf 6TR9`Jca[Sw@ N✵8ZHE&݆s͇<儩Tx5{[x_A YoR#C)UyՎuvv;>>(&$G1gzJ}ɳׯ5_0@'}c:Qِ:B[;oR##ay@oevaS8͉qmWჺFPOY;8y .9 Uf :KM b0@>lUfPv(Ol t[1$-25/Q목%td{?=>`3x)b!qt$,fc=%e:3xO=o/kQ*UTZBvm!PR$JNjq5_l UM*RmtC~H@U#   ~IvߞMt !`bRSe fY i5+7ݻk#޻wq|h-Şyzq#̴ F|_h=ܡSս<+w "7>!:8XpP( ֿ`]\~"OQEԾ.^//bLŠjBOJY8;U1tO؉8B%h> 1oؙmx"4=$xщQ,z Z21dBqlk_e%]o)K+)FIbm'1I)6s-׮_?vY15Bbm0'ZR4ԨWbEj.)M}x7Nfu|("6zx$mpz}'FqgcנhϴR iD(722dѼF+Kyp-%!N7o|~ kZ.97-mn9?3KOaIPjNTkE7f:u& %2Vk&AA]F p8R>SJQ1.q^}INQ-46_ڻ݀Sv珔8TYncL5Mpn!Tn6:_z<ӟ}Ξ onh'a eFՅtpx̖^|V<@J(^y:٣d&$PC7CĂ[kR޿_uln:Fa=S߬["\l᭾HD]rT+̉"KJǂH=|p`-)MTۑW32Lk"Wu󉆒7IR*55R쫜>r8 .aF1a=m DD>wl@Ĺ&zz2ak63op8!N8vF3߽Bm^-~8LQ;#/-xr;SٖR\P\V%uxn?yy!R =u[ŀXY!-"Xq[LV*@M'8ƊT- }So2"XM|1gd H71.9$20R;zG`Yҍx:Ea?-콙 7Xp{vsa$9W͸ L,cCCsP(J.݌-ڦ\ۛX'Ш{ Z=D0T"XJEWT*ϾͨMgRր4ѵSϓᐿp`q@-Hna@\ ]^W2f@YE*irm:B8uӞjkȔYurt{T135PUD)9XH/)pk;Og8s֜cs |J1:J6O&l1b3Ǡ:#a .Z8kt"oa10sc(׏:}l܍k4u`a.C.ی ƐVS\&mOG][>6yoi+ k;rQP EU8NݫULʎ^T5؊`'{+7KYHkuh;*%=AJ%"rŔy%WJmZ MD Am{03Mmj7JW0(ֻsw%F@8A"4Ώgtۇ ox=$qr*FCu=ϓ": Ԗ+֙ T@:I *L&0* W(}]BGN" jG@l0g{ܙx"mԔ25"`_grn)$r8˃njj9Y!OIV@S:i m274Dʽ>C#L,yDfu`x7jj!* &%}TDDA?c+ Q- i 1}](~X{SU5n+QYSBcB* ]owEXxKRC&RRTuє XHd^eTsUn\V"ŨRʒvR t~W+Ԫ؛+A6+=b}S; KxTka>LNM2qkgdM!Lfxwe~-m kT ]YJNdo]3bZHc#Xj!UIDGO:_IÍ@F#|>1C2}{Nu[`QQ6:Bk.%Q_I!:tcF/<6Eb~t.Ve$3CF?UԪke刪D֎[i|XI0RQyn}l@&ܯ"tbIJA×wA,K4E= խ7K`gZ߈te5D})Z=ǪNwOv0K^r"b6C}~y5@k !Ag.0{ͪ;tz`qDiirxUylU߯$Q\arQysq@EmtqE.P ;;$sٌ$UPHS{hR 1F`pv>) HP2*o]ܬSeomKO>9(}ɘ[>zSPGEvU2Q2blS,Bcsj(BŽBzil@BLI'?>O_jO7a:9VNY|ݳ׫ +GU8;[lLibl($c \!rE?0Xu5+iHRCF ߨ{oSAg{L,pg+4}~mbR(14x}+7h;z;wYG QHE}krKSt+PGo"a4T rjs'[ 6R PXXU1b?'NȧTAS}>X!!Lg=n3_B"6onM!@놟q y9] JnHd!ɼf 3s!n4UmSJ!vT:ĺWi\ػdss m@>L$,ple0b*0wYӫkJCM,BtnTq#}>lsGFGU 'hXO. l_E2({Y׫ABQ0u%P 2Dy{fs ,u: u38W6F?&s$ 7܍ 00l-ja1M*FCKU=`3/gj>C!Pp >tEaTZ%&ndvHC#+Z]pP3LwmL/fhT.a&$9B{` 434KLy/5B(ajz3Rª mԟy~0p@r63C2Ӄ?~ 2R*IDATBHkL/( nH1DkVŜb$.AJsJVU~DPls vq^ \690,Z VWM9wTGz<qC+X\- w6Q.بɸ>=t^mXn[Qʉ'XE~|x!nC^c; ;<@d>քu~n Q lRuÀPlMaXQ\Qj맞hzΣĹmaIE5II8w= #R Te6`hm!F>ɖnè1vc,bQR"pC7!i.}#xЯUbCX-kyYzWGV@J4SKс1|Ab^63 qbLH~b0! s0%)0hqFXsW9oNIRC5KbsB)c3hta7̢WxFџ eO CT2!6pmu8x4w捜0~nj֙9um8/]V(11Lu |9}\؆7i66T\x&zPKs-]wPC. !8CM 솵kToyC E 7ˣ(؆O: a5 :$7;F! Cf¬lNQdERCìIV_ Oqc!pl3M[送.W/OW?8l xzEGW<~z_7YG2?[c?.?b/A?c??c9IENDB`barry-0.18.5/desktop/images/backuprestore-normal.png0000644001161500056700000003275612242254476022054 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME+;VtEXtCommentCreated with The GIMPd%n IDATx}]uڮKDI*V V"Z ^PHO$x ?JS$(UZ U"MHۭU\_߳ak1\߱}){Zk9ƘcF\u.\r]u.\r]u.\r?/7'?/^nz\G/}olo93"~9.z>"~j[o;uڶoyl苀>z?#;bFd{2\kuk ,{29 ۀ_wN[i|.̯cq2]~pҟ=qoy?{=?۟׾sΨ?H_79F -xYHI#Ƿ{Y:}O%7\fxv⣮Yy(`*R&>Ʀ:ݹYJ]|fyCb-S=xQ&P|NeqmyOсӟu0v.V'vQ$|,f(|G6"q~wNbM|CW%ct<!fKYXJӧ:s.ΓO 0w% kr!w$ L^4$}sGd4ۤ06^цoYrg/'\ ecGՒ^J'r$(RddHio= &y"b0=<-but Z|r@Y鎾faa9\ۯ!G0$j|Yo"lX;(faكUk"2^gX/#۞ q)` (f8B;YRsp~WE~ܔLBhc$&KJ}b[3n6d_Z x)tHU3"{=co#.m ۳?O~kBR$E4д 5mXѰF8m- hFB$0ng}l'k[ Tـc"Gȷ9ҕB*K߂yh!LqRХK@!2mVzDw۩;`EIykH"8QVboIrw|$N_DO٢ blyR'@ ! 7-L!&'$\{D66 \`&lNM+BɩF)/ e 0 .ČpNzcmgH0W8SQ; m\@3}0e_kU"?]9fr3~N20D | ].Deh'&V_ FߓR;e8aJׅh(+G-B;< bVQTOJ.i1P蔻L2$]&@oJ*,d@- ﲘGv-p &,bN7#wTa0%Y!K06b\PDqOKj4JO2 bNWaG4#S_n^ $ϔ  @陳bc^lF~pW0Z_4=c^b# Ѡ[8zgaRLXU ;z*:'PIw ]kSVdbn8`M[ӻdn +)aqI /gd YTc3- 2LL0cSf2mH`ljfu t؂ 80s T%b3t'!lj$!b @1著+xt `zx$ 8$ʆLÂ*UfBCQF `QZN $C267i!yCՁeˍS'9\p5zx&o d.WԖ i υ& ! ,JsٸC84 MT65=pjXl} M8x2 i! %,'u*ǃӏ;=(ĐJ5IJ(]iVu/34Y+w6W*-vFލr^zM-  {MToQyt.F+SA[gV>M/$Udԡ%!fdI:Ycp ,U:>3sp mD,L09{,*HV;03Q+Mg/pC{H&=I#Sς6ma'347~GLMvs8z&酖Cn1X-EFZ$:CǮ!q~_ji+E*i`M6 "ZgL76zD dˆi˒ Q&SA4?c؍8ip}HA}gYDĢeU ECgѼ݂J%~btf 9cbLAcBP&zXrC᳙j©c8$=N~66k(t#@){A {Z'\_RamIH"uYva$ڥ g_N-B2;uD1~'+]ڝa¼! WM@ui Qp˵IP7 nwHmNL`՟tX4G] ~8a(ϐp.!]ֻ,T3a5*Ijg [aqϩQ6;ȍgxIal-C%zșԐ<яI뺠Q#Ob%_QhNLH:@*d>dz,J]F-FTmT2WWx4 a'rSU9mRN,lh#O̝HE1 p>E&P "udǰ&iբBir%X=!^^%-Aq`丵YABO /XF^XhHX):4FlXr0aojϊ jX6ȑ=45mUĵ7,ji-AYUr Q _F"%uQ??K fZM 5uBQh@xP<<ݬHทQdLF0TQk3RD6=Af1YlTű"TIouz0/LA N,*-,:G/Gt}ŗ~/_aDCIą}҂ƚ Ngy_s \+l9䥧89;TdV !A-@BquhD-06'|lwQ 2 dW{h13W<iBFp3#k}m."~GJddo?<@(`&UKܴR0GDT.6CMp.rk zRjej;DM Q,eQd)TB9cm2Mo#^yUع UB4b-PF7 h?ݲ55d= jgnMŴݍreH,dx.c rlN2&zWfBs |ebl3*I3=Kjڦ^3! 90IEgisKa^-0jbS=X&bQX:2vR'%vU`S(%e{UQ >09@w2|B B: ӫlFmΰ5htĹ;9 27ƻs.{N9 RwGp䰮At TPf7Mk+M%- 1Z:bAϻu2t}+z4+T=v#U~˦ >u5K|o$YE:Y޴7 yXv-+-)V_nod\]]Ž{j>׿_8>}AB:#Κa+4 M|͙4Ju,{'ڔEGHZ*lЂՈuCDoK>![U_b&kŰwAXU*PlM|syz*ݻo]G>><m2X d,0{;,}feNX7 h|]iZ-6N`2>  RuQVeaP s|Slu{g?2+HCm;#Lo #PĊAy޽1onkB Q-Ū sT*lPm֩@>Xp+s|i P^CJf13BNiPA.0!ST j4W@Hrzp8&9}{ 9TPAU95qzŭM#IfkQ#{&0\u˗hEnrB{SƄ0MKRM'\OܯF櫏džtIlrpӅLo|x8>կė_MrZ0}#<9IDAT#"g?oFIJYxӅ!Dz1̂s~56Щ-eZ-EuEry*ѫf!lYdGBSA '<[k++0:MK+G S<X%jiȌWGȧ/?m 1߿2#?~rlr+XO?y/(d.FS1I7Z@5;ͱh&St !)ԑ qΙ̝y[14%8n,'qL#ٺ$0l[y؎ʢ? "osϿ>ɏ/<ç}?zb04Sn}+ZX+{}JEoqҹ~to v81NϢ<Ptk2y#+" ̤| v^y߸ (|yXeߏ=!Ͼ}gyp@  x!;W] TS;8gB l D a4=Z{4bv?3ɛbGwڻi@ ln &w䒷\4ew\a ZeYcQZF<3O?7"ۄqur%9u੩p+:FE%֠pn\D?z'1m݇vHG"N+u47s.!flAa\ b*|g6λQJ'ZzGv*-&,^b> RDZ6P,3E\f!Ž#w>5P)@)iP49]eԎB]|Ezuf LbѵƬy[;N6:e*괜Rr07MQe3Oe3&U j-֛9':Gȶ~V\OGfj{I͕0pO)6mIKImOm6Y+%b1sۂoO*{a*ː&s1y2D-}=?Q-Zf:m$$ە|y WR"*~kQв)‡".̻L,-b;c[UB4V5̋}!lX+tKE#`D(4idjQt (V` 2KU\Cm P҈ [P: b,=]PF͞Cnbқf$kl4@ v1iHtO z)8@s<2#ٽAfBSQ`.镟$fL$ƴ'g :mSscEukEzIlP}ŰK㝈ZgmpJc>sO/#{ǟSu4y*62 pLR|yJ\_G>),]!G\ im^_`\UN]{JHoq][kPFYġBA~R5,104ȷsG^[>jM@ ӉFZr]mRL&fJ3O M0]] 3sׅ:LT9^yN)5/nDۈ琹x.(IV6B ط .Cc&( "(=mU" i^<́bʇ1sD.= )Ģm|yF4ZngҵpntTa /9]ouÚK t'kE2 14ܘG+xt yx4Q)1tهΐ: lVmk?p(+E'M.H` 2c5] P'`+܀3QvإP|3QY s\LWȡBa(ONwkO,)K4<|.?!֧x6+ lb$}0kCS~-4Jp>ry4*BcM*}+j*KupniҤܲ0Sr\5ÚBjXy}AN BBPi56g|FBS44#ьG64Gg֍4o D|7mo2YQ'=X6ܪCWӶ9Eʤ`R+65qؙP2mtQgcڿ ы~ A$c S9͓5Y9\]´ak 6E"iD&`(fVrp" 0"،<KGUv9×*ȴ~ήszEY"-og_N-#T={M,x u.̽!(Z OQ䣐y.f t8tw6*kw`(:h}VWR0|eR.Vi|z.XzK5h׌HC~NAT鋸9\ԡK9S55V]En)i!e,Fk [a].ٹJ\_V&QU<:ne\4U#; hm"fM 4 B2S7ŰZFZV*^QZ - 4on!)Hi8Ɲ H*bz۠sɺvJ"ޑ]0_ryS&L~w RPSVSF=wd*f$wDopUq>}u8#<H b.cDk:C=s kP#6%h2^% IyJ+vG+i6Θ3UxkE:muyGCؗ瀄FN8;%|^S\^'$jowFès^Ow:NY{rq[ߧ((]iׄ jabI\JRhl=\IRl=7GXzj\QL"l2,j-_Rk`K# d>d.ndb tQyGg7`ishrW6. <OX&w-ڈFL9 !8"sށ6$)Mb&X-g@ξ[]TL5u"' 3ce5E`t(h<la(4 of(ΐd}WB=6&XE2o\j #7y ϡx8A+F,mb#@³5dq0ɽ^!$n,Q ZƫV#[-P``!+VL㦮걌,pmswn]b Q@܈>QSjgnۍ40:ϋ&-y}I&iJOrv會1r fZ+#cĹv 3 $*2Ssώ!Qzݣʋe"KB^9#@p83 XjXy1y^vʈf%#O9w rrڗdShKe kzM\1+$5cքC$}iYVU ,REWuX7!jJޟy/#<߃ϔZ8US@7TKSS,p[.M*, 0>{{lƁC^kәI Y}PmRt.{$m:8tЊ TVͶ~X9\Ř.,CnN:B3^UG?uQDѹca@iE~iEY29җiM5)g}Z#H"vhb16 {h 7>tܿYvtpF\G:(&_ciCب-s~VUN#a6N%1W*& G  pp:8}ϚIjTVl=}Z_Eڔ$i&$,>\c6^T2%PoL󁤽r`ИXLGQ@ nݱXb.[m\fM1V"F{?Ә.f&i'Cn",]ikQ-|Ӎw}Ɋ%5Aqn逜$(|1Get&=|pi2}~HVt ̷I!P!=*. 9쁵IWTZEcld.u sn*n7nfq* r׿}KlLHD3~'$L~({5޻} "\^m9,s"M}}{g1tW{.+0?wtÑnxe4Oclugg{^Or} u.ϧ>Ͼ rC:h }a+1c" RgxbR2Fo>klxʆϱZim%{>({_o>^v yCH;5tX= ß{:QC1ŸA7H"6to9:L0gDE,aŪ!z0s,Tʆ۷tNس1烲СZ= -|ng]y(p-&=Ʀ q K7'X]GqҾ?V3w?m[zyZM.*S;%=>[uع\1Fd=o|$c![y[\M%5Kf0( r7KT $ImDJ&d 4f2X'2wɭ,n?j9s.Γ;mfB'1.0 /D#aǢ1I|s6)ls[/J6|[lpM݃( R&59D2 ӬR} @D_2Iۿa='2Ic%* nsŶ>/WGWw"gCEtw3-9ә#J3cFLKIlǝ, sm6זYq"Gn7?m8m;AEIA9eO6=yJ8C6M_Hf9_Q#&$jEǼ24mbg<&Gs51quOzB_7 t~-@W|0qg mwsb>6`ϋ>*"f?Abnq m1s>Ŵ39/T1&2lPL:z u k羍 elC۞}>8 % hA:n1}ZlʻXvt&gnVlPEKI 1'$3 oω) IҢlOxm#ljJ %oLK!!elco8,XKuy| (rer Bl1­̵z.B:C GSF-vBE3NެGjIdעǰr2U6,8xQ#l7vS SH-˥&а<e;ՀzG #N~iXmܔ:%2FpΘl=ԚrbR2ݲJ dH(3E[F<2!v~lL {Hp}LKA@}3 }ޑ]8P>V@H^%^EpuCqlN,]Ih zAPpDˎ}#|SM8uUI>JO^ hc)GMLϘ$uƋbbNDJ^#A&WXX[t,Qfd.u$iAP6>:'ysu"rTq\FEpTr& zHdQܢR?G.*&cxZt mbZhi 1fj0p=}⪎Bu3g.dE!Uq'^sr[fr5̨:\?cH 1 a+d62!1S> EF`b(T2&֢R免l4و)|e0Y~x$١X'Rh%+t?23)rp9 N7/ 6#Ks`N(vh^xRҹpax=׹g/ %_g rXLj$6B-5U‘;x-#}ێr݉1)MbD3F9M:幨HVws  $tV81)QkCkS=Mfх$%ZT[jZhw7pl/3^C}qFYdXXrH'jһu@fO"ʛl)2^oLm)Eb"*&5sJ}BD4ߣ5 SuNOLDr #\Jh\0fmBsEI3Y` (-?tzC5 Ps9"Mj c˞ɲ/ $]g%Ph$JU#¬: ;+*뜦 *-0$\yh7K˭Ɉ w?nX8{!E7eYPoۚ#?˜Pǽk (iIwDQL^7$}z*֑9+ krc8^pjY cIԺNht5"\9gw ߊo翁箜C{݃yGd(tHD 4w$^:doEe_A!P9pe$c(5FR6\bD BWY4thkQs?v $d0/0;O WOt~3CkW}Wπz ?#.]+W,["<==˗?ף[xrj\:z~ \,BvTk‚oIr);7(g2$V0{wYhEagc q ),{,SAQ#)c1 kABΞ}};q9<&W??N'>$NMd{)7@V%ҔnUzL2Ga\2uMJ=Mrr=>VYs]WА\[BZ3*>3l&ECxbMw SɨԟL '{{nu Ҿ'OO/ڛߌ|'7iX/_}݋GŹg#qn^*hWND}FuB JMHmAr+@hyY';jBtFo m(‚蒭&& ȍz98KixC $LL$s\={ v Zgp򱏡}3׾"p$_N%GWd1<7 Rm LۈEd'd+Dehֆՠօ'+y3* :VcaMڬT5&oÎQ5C.bge󒅺!j T|Ur_A_%SO# ?>8h4p AcbJ,vk0Ү(*= TI M,B"@:cQxf|6f;=>ZjY> K0wu ȚLNYvAzg~GX6v]2(71A??. ~G74iW;HF?'>>Y\{8!<޼-+tK{],M"S4 *4&xOIVLj'D kz8]fj1 ]Argc< VrW%0{/} VᇁY s_O_2p= wܳC&ď(#vsNҖfE6PЄXl4b$(BJu{:)-Ь,HSi4( Yʲ9AT0/,;< /;wnstox1g/|xgwwzў}ַ.(-.}8\p)MAQdw ]`1Z*bFfZfpt PtDQ/Y,Y0e5!xQ[KDUIk;2Yw6Hlx"7 +|r{vAs?9xw_or&@j0"סMgV]^, 37f!`M-:sR$m :Akr*yΤges(L<T ˍdk^d۸w8~Gm<3 2A>{kr86Oy}]i9u~Cqhi8Xm[K=ul\}\ezfISzDDPQN.^^Ro~q;y^G5𮻀;4s~Ɋ2ՓS3yB#/>3RL-bfU;LF/ζ"q8^-g>UUlU!ͮݱ%>CjYˇ(iMr^lbmSbYbX>:wwh-YgVz 7m7fAߛ L]fTm nm.m?>/y䑝m׾ܹgYǘh2I5Oh6~_DkdK{,:L7JK8p8|`߭n f8}&7,khbNCm7o _9l`->mذ kWdv^xy|ߏ׿ns}UkNNL)6c c{|D8IDATieV1_ԅD'v%dlc.Ҷ--{/bhz^6붋XR5h{J9iq97MC~sjʯdm-z5Ϻfz!:._G~JTAgM2; ,1c#/OVoȈK5Zd/L.QA*c9WzOh2ĂNVGf5S" >fH˾O6o] Ĥ\T#LDׁm{{o ;oFz)%4yYt0٦,lBݜNo09J#|͆Qkּe$vrRDii)b}2^bG8\*atX.h9jUɪ%U@Z2J3^gs Gm|#,7E֐FUV.AIԾ,}8_nq!r UF_rO`/J턦81s]"\}lZk:I$J9\z`}NX^ » >L3j[''x_}Å c$Hel״T1 e wEoa]j U+vn Fץn(9YZ[́ڴHٸq+ NQ,u).ișN$:|~~ ??x>(~~;~i|Žދ[,,Q/l2.3kwYa)Ԡ !XmBc傯EE˼7-4Rx~KjR\fr{ d{(tPE4 N]tm(P֭tydԥkM/"裏0~}CDKK=^B-\[Ν^ V%F']ε Iuw87ۢ?Hm }b{\LZu|4I40Sp4V,6=Rk`hDiUҟuIuUeU4w O}3w]xW^ţ> % #=~~ /^)Ν;g.Vk z+pw_ƅvݨU]U.}+Z=aŢOq"suGpuWƠu0ZpUcҟ۝eoh~gB[R2Dўtt B%%(n_ߐe$Uݹ^/ho;NO׷}u]/\O3/)xxc}q*-xZoNNw  |z>Sh"wKbQCRmTMՇ`A "y&ꦢ%jfpys.CLb}sſY1rט*рuK+gh''xq l7Y&B_}rrz+^sݸ diIͪ“%/3X XKOLW(›{{"5D ^;E>"M7 1*"JZQHY4# pbѺE -%:Ěew|=ҝr"^|OM[#jJ=6r Ν '{/B7TS@zn@RЬ;#/:Ѷ,#t5L$"LE0jMVN[ԶNJ, XtbR:$.тHP4S)ج}L&rYϟS\.!: }=޹^B3`IC{O-"|F-Be:oQ𾺘\ZIsoQJ~k(hrZ)K|1;1ok?'%V`!2C~qaDŽe]d8]KKE#]"G7u3[]zrHI`OcfSte<4D|EmSdAT$E3* û%ޜ3$զ>rj sڛ7 s!1RJ GG/X hh=KLqgA) 򈩉_e3ٌ+@1uMytZ+D #CKd~$2yp[Nb 26Biӡ9}7M5a:Fcsb= S s7388_-7Qj+&gGb vnnFXfiLET[eҠC_{OBԥYgQՐm+X{P7Fݭ&^4;b)CkYGܐ1 3 y^tBό/>A*HnާȡCaOYS.،2{dT=s}>Zi{eMaHr 66o(-9/"O=T,yRmy0!boOڴҀUR] UKyM.\"B@yRN @ rL8ovbR'b5[e.%iWWa0X?&'8F ֖w+X¼!aMxLYؚ IҘf!KB~EnEmt oٹdU^b"NYg.t!s9pRLǫf H-dKŷJar b`5 29hy3MF/|.)JM>r/+z$i=6kQM8Z崆WHmRZ\V%΅-jM!ch0۟Q"ߖ1ҿ!.,M&jɒOqO3Hs|Xb'ޤ,*O 䇖tXVMY/RM5s33S\&K{ETVVe"][ܯ\lqmp2镥j98Vڹa10^J@U0i;@J^+M9cJE; D?չ1oHa~s+fFeHY)wծg3 >W0nBx!n.4_ ۚ0[Mʜ2} ɉ 3bM1(Dwj%,aLK>~UZD -TVi~J8R׌kC=s4kt!6)l5TS\Y u> hAtʡ"^{Lit$өfKS!%mdk(˚,W֥wjIWT jRyﱢ"k1n`/o҃BDunٜ5e_rHj(gC\up.T~vU_;dwRAgרm3dv[kXVmwL`+-p73*UwI,O&d_2wH pl}^C^' $l*ER纞3T3gb}C2@J냒g-V-SIJA,[,aTW'$rl76,5r%bZ piRgX.Z)b֨4,.Uck7tP$sM[=y#MoLLYKd?滪p8eh~ cZ^Zzh{2brJ;<іArM1 zRq/0gS\TDSCӅ fxJj"!HU Ә=rs*rL+ wq3S5$)e\jd3iY199G,철v ctHGg|T++]$Ldt7*fEk>3[Y:Jƕs9L*3,"\:'RY1dcmR^.Q{ a.hK * c +y+lX$5RӢ,fky`\Ԭh@Xddj^7hWbfuX7h;ZYyW,J|TnsW]-SwmmvX,r2RǢ$M챥Mb׺I6"U5uHnI[L+sИ*P(56xvX_aދ1"8Ti+ JS&YeܔTcg2A,G ʆ+L詝 xtGZrKZG-HPRIEE[ Ic)`2WfMNWDa;b%*(^cyA؈-d?{Uւp\DhSWbsŨd!ss"SpyӇ.#[њg%HZ(,,,LqS3u>0-7$,(חnA *B\c,g26F,=晱CR΅R2L+U tc2]Dj[qVs/;ë TmnW0N7^ܡKV.JKt;ݕM^׿am)s$YwmVӯLX.M[o}^qb*h^ERk/R%"f6{`(+KXZY Nl-\$)0D=]VDPH }6ܛ\5^#XN͜d{ s*#R9fUX:r0.o<~'p׿x _=z__ 8Wu q<׫;?u:^xu:^xu:^x¢ IENDB`barry-0.18.5/desktop/images/browsedatabases-normal.png0000644001161500056700000003340712242254476022346 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME0(/BtEXtCommentCreated with The GIMPd%n IDATx}]u^g=3cȱ#! p7\ A\ (B2#r d35]z9k}OMW=U>9gkG_k_k_k}:/|7տϾ="߮)Fool9Dį7]_7HD{j~u_ydzk?uGwZߗ /AZuI#H^}_aUҳ_/1w=✯ >3"ϸ}~M=W{/^A^'si~}.{:}O%7\fxv⣮Yy(`*R&>Ʀ:e˅I=y@kNB,|' 3R дmƋ5s(OmKp8QcbubyꑊP(m([)}FQ&8s:!G0$j|Yo"lX0A*~zBDܓqKl)H趧{j\uX+ø4α.,)BϹ Xe+"F?Arnq &!m1s%>-R7lg/Tc<ȔEc:jAAik#..HyY@gh>,jIhفʡi1tjN"angqqIr;t+7 IpBa+?S}NmU 7L^NRez+a#HW ,U~ r\&[3IAB/=o[ Yiem1B%"EJGY]i&ƒ 8}=e^l2\ID) 4d;Ƕ 2#@Pbp4JrQcPāsѮ@m|cyz/zZFjaʜ8 aĔ$"ŽLi^t{7[|lv [4F2 ңMHZL24=ւ8$A\]!="u.K4P۠!zSӊP)wT#w)/ e 0 .ČpNzcm6a4q3")vD;Sչf$ωaʤ?(0֪D~P!sbJD-ICvr#u!~NOpES k/AY`t1Nu!fl% Q60Ψ?`(`@ Ƴyd 85/|#:n x|W %\~)d@- ﲘGv0[»LXĜSoG+M`JB`:lĸ.s2bW㞖3hةdzfAEqi F~@ݼH)733g?P1J?I;Ǽ،`hzǼFA!Rq(ä=vTtN e &9dB1t)O,[A.5oi3ZO5hkFI fǥG$ѻ' (9*dQBR N4Ȱ[20qLȤ"TbQ *a *)P$ҝj$ N׈yO\KxcEM&QHY>`GlH_δ]X2uT%us{[!!(elcoq(XK^Eka+YaJU)f@^,lMQeVZ*k $ Л6~V&h3}7FW#v:Nț^Gp5$ŵ1-ʦZYz\HTK $ b/T|ta@SxRxAr E:<9Njc쩁QƼ ãEi] 䀒dHFԦf1-dS>o:zb$Gݖ nF`Oc$t7MJr t-XTk A0W@)FgV \P3)4&!o eG%>D>&:*CWlcFB>1" d)(Pרuq+VAiS$3nug.%75d}S? h Q|E.JNS#MȣiE'ssPsoMi[$ Q6ϔ [n)Y!DXT]N9"r=+-6[-0eFXv ʨfO.,)VBXR}*?ğծTˢzV^BYlED-(!o>pi: FdF?Hd{'p,v)mCYWS"#NQxI$Jvo0&lwp˵IP7 nwHm.7?&h2 p:SQ!QC]rÝCwYTg)jTq0&0Io?"35*RSmPգwL%D 6Z"TK0B3!5y4uAFJx$МtTɹ-}l XZ,E9 BPq ^!\[`4MUEIdI`CyAjJ܉8^Û8 SZi RNaRV-*D)&W\'kx%9nL\6 5H()Ҩ   +V9@H@= \cKRN6MY$A92疦\ƟE=7%0=K8VTkAˈwXĠ.J[g l[IB6}@3fZ(M>]=Hr*C "1B`v !jyF',&88V0 ;}? ~&~66@DHGh` eQ MslD.RAP)1oȓ&pE CS:Y-j LbsDZ֡X؜,V]G>#&|z$,篖HN%ΌVikwyJA0\ *}S*;mT˩ |S9Z)íԡZk(hSlguC>jqqt ~ayLv:Hhp>wnBŽp1Gg''?9}kw/o ޞ{K'2#@7"Ԥ-D#hB-)\iqXAd*s9u6#o^OdQa^AB\2*SBl@.LR 'GGGx,ecp$o߾GίO#go_?9)8ɐK]РDIܙwQ<JzBH=BBVPX}O@vUB4b-PF7 h?ݲ55d^N Ċg2$ ivLܸySx7—[/rܹsgmz^~Aw+_K{F2WaYqiWTˇB6z@>}m@OA!: Ye"W۱BCX4Չ̵ aVrmCl֋/^{5NNNYZzHǏ-{4>pYq;i1b”lB)CrV7}5.kgxW,Qca<`5ٷ`Q=.z:SkI Pdm‰(cN?"H/}R*Z ''7 \i1Vƭ:dm$1XI"25>`& j*g,LɇYhqGK224a THva>N5/RxU4N ),:߹󙃧OytONF[_7?_>L'U+H鳮L"SXmю?K=dw⎚w#>iCrvpfu.޻pg0*''sm%wXؗj5Sqv݃w{9+_|Mn&A(ſ5J"ԗP(ղxpuY2!;528M"iTCRn:MM#ODqTZ^6e38 }a^APoQ& Zfq]*g/RsfOŃǧ;щ!b_8㣓yuRT,B)6>4N}-9=eiJ$?Ծ,aȷ,MvfTEoIݜsiҜ3Ȗ͈ɸqyݻqH[g~ayD<9:ӸqxxI݀$\ HEHNy5uoa(>#^4ޣ.$m@> r.pT~6Gk䋮RF.$j7nbxJ'/p+^}8:CxFqz4^sƭa5gxʒtCc}jWJȒ[pJEڜI ;}B B: ӫlFmΰ5htewed,ow' ]P=[sC-OoFfA'Iǭ 7m16̉P.&؃5 h&F i} .=θXssλo%fǎpJt4|;W^z=NN?Q8:9Gg8^AG^}! :rAJ-B?:rrF_¦bm1%uO#U3*BY0(x~`#\zפw,;?x-*{}pIdNr7QvufՆ,f'qpV܉qt|SFgy^og/2#?<7>~r0#Κa+4 M|͙!*mdjs0a<6:isɶ6esё8f4J:,`5bdlVlWXZe1G(j T?=zS<_Gxѣxax$N9=;8=d'F<9>{Ͼ d,0{;,}f||>Kƒ{Oϥ3OY!c 1M+P1 @L_u9TnUYhr;}9>۩e6۟\Ia7H^^'.Dqtvv_~TA-2FUؠڬS2}ViAx^ !6,LKfz g vvOs̡47 Br6C*c;הbӣ+Q%`ca M7Nqݎ"/y_s,1tE/wkL{ (& &~:BizxrOQ%\!Mȱӳh88xF23>x$n >l2 \546>a/20|P;m"%Z0^1!Lp{ӒTӉED6ks&cåtIBXxbxBd&F7x|>_?.y_{?ow߹ƛoWQ|E{Zkl*S[qZȕnTWBز6*Hi)u=XA:'LpwѦ#yx.5ȱϔ!&;l"3N_}W~ۛ?k_j5cۜ9:r 0f)*lU ΃baUac̏ JsoB͔R *x ȕҹ(t2d)Q_k4Z݉"9EQi;_|饳_o;?z 7o:{>~^LgExxg^{g^9yfbu*՛RWclVf㤥sվ1 -Ę;i>;o@ɿm)E^_Y5a&snHEXq;72[7:ư˄, )cƛᾳYC8Khƺ^+1*OA=aeW=%*hg1}Wڣ,I޼P;MR`Sv珤g0C.y5H]vByQ5 R{DLWݼ99Z9j'K wS"Ǭ!>i> İ-@:!'nl:Qx4š#l)Cf 1` J_+W;fPhtE'"b=T;x-~AżI*, Y iâ{2;%ـJ9rNuH qlӥ]M(|Ei-WZWGN'7𿣑H4M5;AsK`rsǚ *b UC^5͜nH#Zdd~V\OGfj{Ib1 ~-uq]paSl?h[&\dk(7IMc"LiL@XJnK} nZ1(y!#x|R'w, SY4̓/0E$lIj2i~n#Qľ'ٮK0yT)-t[@N>ja-dbU'PmRȧf^l5x`K4 YeZish">M$DuB";(v$LZLzzjꌧFL nX:^̇ZQx0MH`2lwT43d6t* 7`7mIsA5RJ|w#, hHuvo%⸳Ĕy%XKz' 􎠠$ƴ'g@8aeuڦTsՕ%AM\.w"k!=(Aff 5hpHj!4TO`pf%6fvkQzGIXD#S96)&3u KSw{@Ч 7%1 |zv.`v$ʉU]뼫3Q<{ ;#ּtm#~ C.>㹠t$Y3cߦ$aû pt+PhT _;S콷AAU" i^<́bʇ1sD.= )Ģm|yF4ZnXREʃPt83)Ϥ:ESh~EJxunziVt2V#Ų#r/O"pJӯ9Ȃ颒\%usv7v4o D|卺Nz lUmsV]5.3I)2WEm.j3 럡˴qӡ#w*?1^kz&aKL02iʁ: [K6Rsl}Y98747ìb3ZS,U _< ;Jen;rjĂPܕ0GyR6~koE~^?pNq#CpmTPt9Bv``WX‡]v'pwaJH[E[wN`-ՠ]3PKE"(iF`}仉69+f6lwuhRa,v0nLh`cV?ĩx9(§5w y܆26˻{fdЛ(0{اi ȶj94}71'5:tv :GzƢfªHڍ?%-Q,hmwaK6vΰr`\%ʨynh mDy2UoT.L*v{˝6f&U_L!dUd3(ݍ(ظ-&Ϧ9߲R5)ڥNL3= a2fQڀiM;׷Dj_|}kwP]l,In fLf~/FnM^:kb䠘~"}zgY!O 9;8ArZvaf+!xB;K8y64FyC]uHT6vY̜ ʏ5È|2zOA.N\!$2RTN< ²L4;_ZO5| ƻH$ZIvjO/T~y;Ե!aQ?c=#,c7"F&ݥ 1.1 X}na}ѵlTTEBVݡi5[ӼЦ#y0svlBw2#{m6GP 1')KJ{Gv|9!N)j2[]+h>HAyNY5O|g2C&hFKr na1.<'u/҂gGb$tC̞:`{LhRg6}~ jЦdSC>u8  ҊJڅ} k|逨3&xfdr^Y3O:(%NQ/CUH0WрQ8=]{[yB$^Ȋ}UT=0!K`B#|4q7_aC, MuW&gy]5 RTHd3LHw-lf{[]5LJ9ct~_Z묏Ivɜ7VsG+ZyVHifV8dYl[;\M,ľ<$4pz^!-@皤?) P{D0FzOԾq_8Uö!0c0+pA-lZ,?KI @-Ց+] ƺKf~ʕ . %ͤ!&bB%-xT=@AKHNH&& Bga#l< Cv,*b,+IvK:m^wIӨ9`L:2}7qn7O`3(N|8 f9G&K=ܖ& NX^=6@!vAL$)@o^ΦCG h@plq^il[ ,HC9!>0OYNkUft}s'z:L" *oO+K+ʒ͑HkIy@=:AXaM#E[ ֈXTFWYbb:A+ =^TńkL"m}.J J\k¹"LƩz JQd!h=.ݞN:Y36F[OyW6%IDZI3 טv@3뢅I-Tc| iuGA)6,4pC&Q%P7[w,؆,V#iSf@)ձQ,i^4E73{<>[;KyvuZT 4tcv_tIMPܢۡl: gD(* fgsk4&K[ EBWʤCm(pf~D bɽTqInf=MRTr7D((:gk&sQ=̨`;wLZ ɓmVAd.kl~2Bbj f١sc² Boy`NDI2ciiG?Rj=?Kû }wͯ_?W߂.A/?OuI#G>Oug^oλzD)F7V_k_k_?9 k:IENDB`barry-0.18.5/desktop/images/README0000644001161500056700000000021512242254476016050 0ustar cdfreycdfreyThe icons come from the Tango Desktop Project: http://tango.freedesktop.org/Tango_Desktop_Project A special thanks to them for their work! barry-0.18.5/desktop/images/migratedevice-pushed.png0000644001161500056700000003442412242254476022005 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME7$iDtEXtCommentCreated with The GIMPd%n IDATx}[ЭYU?ot#n" *!@+$jr)+/IU*}0TR)X 4x#\Ehtgcεz:jWߗ[9c uN:]tuN:]tuN:]t=6/Y/x~k/; z\/~mǞΟt=Ʈ~[{Q3> qm}lǟt=? rN__ lvsG[ ь/z`|~`{AK?k;ǽR%}NļiqY=|18x.n8 iLlIY?|}7Y!ƃ{~|M,x[H!r/I]Ldr.)N>6jɷ ٷ,uxف~vju31ͱz?@-t(b?0/AQ (|CDd<9>K&b,ھd (V $SӿBlCA7 s>(LSGx놋/N|5|2`llйGr|cqBM?y kaN,|' c5iqQݶ7$Ώ-n=_bߣSuPgZՉ)ndz@7A>gzKTϱfleAg7 `QdlLƁ gr+)KۿO96sWr3Th y@M1K 8g/'\S <cAiMN/̿84;&<L>sPF7iS1DmbWl(^|%!g:Ӗo}TicF|}lb4hic>-EtBy}y$ 5NcSl(f40ȧg`b1wNbʎ1]QV<к{[JquI$>/=) f!apO46h-40qLAb0` 9-0(E-$fNR2# wn$Ħ[;ɼ?W'g0PzdwѝI ՐnqK[LꖢvyΙBCFq$`Yx8AO,8ȕ!*R0!6Ŵ* 2³F"PЛ6 D3h3}O]< $ 8nzq$1]ZTٰdlE,\fNWr*Lu ! l,f8?xmTGO%-kiZ"Dq-,esb2KO&_+c&Z S}1-Q 7-L_37i/!H)i Z7s6b@1ۣMVm^5]OJw5+We,7P@͌noH̅3ώPBf*yS9eJXd\ )+A%Cjnb-Z_.%\^Fo+r'Z~Gu&VBS)/i8XSX (A2R')ٝ$69J4cޔYZTmuH|Z0pHJWic6>;4j]KRAΙ5vy2=w'lJ%1(Q!KP@-e23M}œQ=7Эe`K1ޖ9zdj L(Q1 P˕_""nBv~{bZ&gkTUzHv@Y6kK.Hzk@i#׃)QloPcKXTO|a$m!YVR V_N FN$Q͝<".3s'ǔA1sdX'K3p "W̊iU˜‘Jbj0WK8Zfp2%x\1!VZNwsʑ{B2ˤ lX ˳rH ֆ(2斻Z>Z=7%aK8PJu+ V*ր͑bP.D Ii+(f0pyM=4=#"[RB/%hb+Q6h@t:ɏE^.j $pB!1BDI`vI C-!Jg QŃgMY,2XVNì6ܺ+7!W(. yHfbW,i^ pH,&4b#c Ejմ.O`+d1օL7af2ju]H,ߌDT !C-S@B0ҡarx|~]gΝOW9xc+BSX xN * U(-s\ȓ@RҎr TX?-I.evL$6 X}}" (l{53E>88|a*"x$vCp,Fa8UhM}ݿF3^/7>hg _|{/>7ῼ+=x ~ήrg,LXJS!W1q5)=4} ꄆr6ךQTa3(kܿc &W&JF͔%6(tfRpx_…?ϿOߎ_0~KqUn/}^zKw~o÷՟>EGPh&G3ٝvmMV%5{c&$RROP  ^ dϬPlFj5!R7SDfaAyHJ~_tp ȕRB "p7/ffx\ ~{xs{/|ogS_ .\z}p#e__ozzTE N&zP#(\ (JOu+Ŕ@,e,"POTΛA!"uʂEBaTN.4;{a^h%%xe%MѣWx+_o>8~\s9zxӿ ܯc]\|h#?;Mx_/=30"'DinT u⤖lyH ڐUߺD^K|&[= vX6+"U9BhI۰cTX7@Qټd.h'2@Z_,O㫟lnok~.^xnƧw8*\ 7q.> }/;o><׎^3AcbJ,vkƎ=QLe4O s`,B"(ڙD3 1kR̚ MydXcFgBwrf> һ&8K;²뒡E.&5\0[?U/Q;+vW{x okc x܍;^tzygVHF22r6*̽B&BQC G8U;,.E[2.4`v&-p:;xZ+CWyy{&5?s5@}̹gO}M.|+ބ'i_]%#^z+'O~C\|wYu_fE6PЄXl4b$(BJu{:)-Ь,HSi4( Yʲ9AT\ծ,oI}oiڸi5s=ϰa|f㾬w֞p}׾6NgNx 0ÓE6QO|>=ϛ3]r+4}!4}0MyF<dm}&3pXn+Cg۽{0NIi}bq_mIUdQ c$d2^՘ع ?=}n{e#Ah-컿y?g MOz*_\-n9np$L±Q7!q<|gr?M$ 7lgA}w}78 ,LqޚpmSqּh#QKxHSM@0pdzw@o~~Ǘ~} oz §qϙp>]=j]%OJ٭,BZpΨSr&A׫ ,frHn1ʺ>xhm5ԴubKHSFnyTS &#ej<; +2)T|?u⥇pUxB^hRs"0Ș hkFkfB $<%X~d@@Bck%T͔΍_^3 +JDx9Jҭ{i Ia!۵ Cg n{z6h|S_z>q^?y#"Oܸݝy4kۤt sĢEa8J5#*f/l3+ r/Yε4PE%߫*˦Thۋ6y.AEGE(ѹ+Eds5֗/1ICp'iO~lfkowx;>_+^r\}8߮q?wvb?᭿f7|տ>>[. kP( #G-eh`$+fStʊnKgQ%*KmK&LΏ#AQ*2gKY\}\ezfISzxh_Ϗ/k{}/..~ pΧ#z]x׽/~ 0~qbj)i\gQS̽ìji1|B/*"xSZU%& .XQ7P-+yVl]WHZ/1*(AgmŢt݌` X_{?-O+w#<繷y7}ps\sqxɭƧ>)}m7|XV\^M'Z̥Te^ IűJ-h)r}һ RlgxMr0~CM׿`@v"f ފ{/M=:0>EO}%[8-}eԤŴ ZY(,k-eQQRceo ,H覴30#F[;W9PN͊"h)H[w.]B&?nlʟ~y+^U7\KqO oU}$~r%H@.8 9r*P-|4Y 9/=G!n6gMݪ  eMSKjF<ۂyb] &a|% oR'\;n.v@ =kxՋOx{߈v<ầww>; /h8C.u׀ClS9(*/,P_fMY{J+sZ(9''U];j͚9!j$/wYLbt.]ZTK%k6vQ1ҊqP zw;b8Vd7n$^t ߎ}R\+oVĶbMF.W.AIԾ,}}D f[CpHU|Vn'4ĉcBXEN'YUZ1W1qe9c5{ .$bb)ti7bK& ym'}߂4n%`Lb[db`B-*f>?`zWzܥPbAYv;OFfHL7֏]H.u=B0JYZ[́ڴHH\`6;V).iș ghY vܟ@pGm԰ZC4b k`|mx n[[Y3V&I Ĩ>Arc!crFs"wFCr! &$=V.ZW${úB)',M z8UN$EÏZNKd|S§J.ZJ6D>ـݎqwnCvFj٥ a †vFv5=g+|+2Eg%N5AVBn]g Ͷhz!U Z3m֞gQIǂDSq͂pdңim9m33LKgTќ? ҥqFLطgMMf! zy9*ֻJ٥/EV57xHBLIܹ#}c:-[9g!YYvmKxZV6ٱDсtv B&(Pߐe$UݹF 3?q96w7x Cv_4Фj3jIofdv03^aLA=JHeV=*Lk{}#(f#Byjq-j[y4Ha$蒏6k.+ DTFY|V,Bŭ`;C7_R8!M0XA5IF:^֓E thY["#覔l8&!ܰUu,Q+oCprf9yD@;2BK"rlëwuWbQŢs!qY<,oEEo&bj4e)N"2C,PO,t:T,\1z&||;JBTS,IZ'01jM%1Ժ-ӝybԲeM^+i>@-Jio -@NYu BIXXކ!ER #~rdNvftzQh-ڧ 6R2}cI[~C n%ԟN<_d_>x R> 5UKڶ9öO;͚B`R,j? b.BGMPݯ9X0g>/0eSz{&hˆf~+ ^uw]W7h wzmUmWOte‚LjRM+@_,bÎHX4-Rixd~AurcQa%D )(qʰ5 Mm--nJuI -qf`p3jrD2)"ƅ$]d[,uG &|T߳A{ߤk 98RS+!yM.\"B@yRN @ rLI{>,:S:|D:NhIv`]hJ>GmH%iѡW%Xd铫!fƻr#hiE'r9,2L-G^U XR2RBaiOe)󝨅fb#wY B.䧠Nݻ"bA]`v/5VSAPe%#\~s "񋴈9?;]H*1WUEVn~/*jK6k-b--YNL4ڹ"_-* κ{ ֖w+X¼1aޭQ$ 6zMO9~6?Ҁ\nEmt o(>׉H-;P8 G4A !CkV(*q.lQ+h C]uN|[Kj)o 5͈rguS=%&%`iT~Z8%?4òh|j|X1t.2YLT%,B .)/z ˁ-.3\^&Y1J;w7,F&V # 6U{+cc 8gLߑC'Abcll7 ) onuRH9#v*eENV]\6RUbYqYN! wxk9Gb~{ISϒ~Ղ0#9Q!T;bcF)NV$ޘbV5EL\!̜tQ}eYb v **zxhB mR6زkx}܇7'@J;Z)dMZcB{F+= Ӷ ?qI}Ȓ'(Q0irf& ut~,WT jbXQV5I7b~s7A!og:=RDW帜.!Z-$ِ(s3+kv]5ۇN0"Β\~-E5[V4IA]6O;&a*N$uNקa [u;8}]>!\^wV"Hs]Ow*NNRcpvʺ-J߇1,>(w jHb2IJLuuJ.}c3Y+W*f 7 u傭"6Y`JCRu 8vHe^A2qj`hbR t'y%nՂl S">i6q #fݜ!ԏ &HLB|P})E`D<="n^,0>[+!.#S јg6Lc6[r ϩʭ32#ɧ_ 'aO)P3 5|ߘI~TIn83´be{43M6"+b"7lWF@ C-ԬIvHGg|T++]$ީ_Vݨ1`ly fZk-1iYĹ vFf&LC.21W6dz)/W !kCX. {RǘJ;y!I=ƴ(Gˤ+"2ƩY{P1w7nꎶƒa7t[ H좌gB5}ipw@ӑt"1+I.WV{۬Y^[$o'lCB}iQVRvpe*fXu枯$C0IU$EW]-SwmmX,r2RǢ$M챥Mb׺I6"kEi۠yQBk @ÔWZ6@ ꁰ{N֋1"8TiӗOx\uʤvR_0ҟjr A"HApw% =S?HK~ImlZ#fS> dF3bX{=æ3vJ8CUP ZT)[c~rѫ<BЦĺ!QB#bQ)hEn :]=2F5YOTWK2'-QXrsYxYc6 Y(/$qKg,(}`ZnHkYPJ/ 6;!Ep*B>< X5d'3[mXz3cywX dVݫ4d&$^v2 Wrg?ݮ_kao,CY(]Jvh;7Vd5oK#q"m~=`riR2u~Hm-TA,Z{5*.1kD^YjtPt*gk| &N!?wµ"ʬDjA2ɌtjȜ $4Lep(|[mT$uO0BTq~ދt W; :]WA; z _= S>z ^o7oO6~۶}N:]tuN:]tuN:]t"@>IENDB`barry-0.18.5/desktop/images/migratedevice-focus.png0000644001161500056700000004225412242254476021634 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME6 2tEXtCommentCreated with The GIMPd%n IDATx}{̭yUzֻϙ 3܆aptaHUP"&Xl5iKڴ5شFmMc#D41T^eU.an03|߻񻭵~70^~zֳ%?c?$ c`c7?yc^ox+yv/#"/oxˏ9 'D/@D-?r3I֛s|ȫƱ?Du}Qȣq| s}폿(v/yc~ohʚe45"0/"2&DH9c7wXߎrNo>H;/kICƓQbJ)c[ׅ:6e|kO5=~o}~?'ws=O~}-~?Dxu P;}3.>\6Cw}i{< aRX<wϟR )='`Tot{cֵx x ~Y@]$h丙e$[܃苶-"`G']u9[0 .x (C.y.9m: -|gѫ%O7c^)cS@}ф:C_+63o*EAlo1@t{sIvDmzdP1,nk$|A\lF ļD# y` #]FHG9<q^dw6auq8,A܍!C݀쁐!;V@)["B;csn'7a.u)s!\`HC*dys5_xM?mV3xESSo|iSp2c n ZS I;ۢnS--aYLCh,:\VHgŲvXO .Jfy\lӑL"~OF ڽahf`Ck?OxccVPڡsfJܺX[ٳ~ DDT1 G>4'?nZ5;H(-vy3o be 2U!% o2=VG88 †L/:d XDF(@ 0<@*ԹJ'徯E_'i!զ`u, Cm7f_h!Dxseq`)iQ՞KXx+B5h:Pc&,A2,8#uAiq!nx [^Q(2'^jpj6 4. PLϤ $CC'g>TgV:H߀  ;bbXx*#*݊H1EV @ p55;j=7՞2Gb\M{ٌgnԴv 筫76njXAͯRɣ?!_L<kv!G &*0>GptǗ#)&m6 `QE iY}P-vTk(R<BYJ Ijb\ fUI3`%i&R Vm9EV1:T}iߔ} Dzж2§|I+L@zZe,X0J틺+2%e={Iw\ dGEQG %ZjT4/.0ءv"b4 (d .j ASQhWؙpcH (aj% .^@Ni[%ڔ=StC!JpS,nT<5AX5/+ܠ/zyGV&oJ"Kn\D" S@USe)iF"RXR U{RLs8fW[<_K qR`y DA䢪ե 袢Z o"0j./x裫#@˹PU 4T$w$W(b ”0#8\}٢a*a*bF>a͜a dVMBFQ ģKk$WU8 c ʸ,eTr3tpΉxvIb T֭U{Bw,U*5@Uyd@-L`"<=Z>b3,J3fJ`1vRFQF[;$C@H)G="{' €` B"iGAԔuMG ^9Cq E: 9$=>3\@T ݂EE tb( zUX^QE*Z)Q\1PS1):+i$` E5BmQ@Mp$$*m޻b'H` [ ރ $2519Z*< P%ωJe 5>: M7\ Brcı0رJ3NEw =+jQQEEk!PDh#EtRQMPj ea[1RdU,0TDj1&fbr_=$;H[@S}/rp]Ope5L,\69:QGKLUv$P|HƱ&+f1S۩."XM XU ]cT7HPbe&"|FkP`)j$F(EW#DV)eYfV@D@CPUl`h\E ƒ#l>'aw嚕Raί2c9_lړT<$) ܜXHzb]`iFS*PUVqbę|-FPr6uLI 4@I ¼r݇V@(+BJuU`$/拤Z!XOj{R_-pAAQ`etBsp$eG+0ks\:d̐u WIGF9%@J+th.NEuTb$*](@1ZPX -oRt/Rcx,u l4Q6ARhV,0)VnVQt'J{)H͡,]ӣ0pÍozCݽDGe "M5- )2p?ſTaO05Z>ka#`af&6cOKUcT.Z)ZpN ![KpTbF {)H lb_H9[DDJZkkX!Vᣙj}cdSEX}*]}n')Ff/սzbitih4$_FTLV)4)[X=7 sSJFJj$7ȕ<1eqhgvĈ @ 15'g1XhBEIԜʯA ]Zޡ8 jnuxzPƦ]k&nVw/1ARAmP[bH%5z: @ .7;4zoAsDVOՎCl F=p`rd /G0+:RW"-Vjɹ6 AmFR!_jM[UN@𽅃^UhH`AQ9i$ PŤ6j,m+zZ"+IJzQZ3(P[Gjsؒ uZZ~ 8{%G[kVfVIұr'Z`| LPq׮U7П9YaU|{ R{*XTG D.mfkf cW 'ZR|7җZr*KhUhTI>kOAҒ¨7Ī78F%ԅ~22hIi]rnsWg9nǤ.%UEzje ,Zp\,-i_X - V!\Ӱ`xƳ*^c X8Fc:ֻ?]7>sM2!N8^zW+_vK7?O<͡T)K8D;rRp&=-px1k,#᫜4hm!v'Ы.?bC^s9R1m(WӍQpM݂+ P!Yh΁5E J'"F=$7<éPt4Œf"^[iUe&b~wѳ7_z&EyrpxF ?ɷut~{%g.X0`CMR%Z1ȨX#BKVț 0T34<5Փivf$) swEAo]2A2i7/9*JG>79HzwZخ[4ҔDE}Qi2%#1mPT\Noүk.+pO  or{>*ٯE? s*lR0t,;X;j&Rڥ-W+㱱*J_5cBҳ|ZyF;xE0i![ʬ)سVN~nϲ$ *_gj:%Rd$V~&Qvo?+/x>)?} O}OOrx䁃[λ$_oS_}u?xWC9Rv^-- UEvC 9>`[ĝUX:&IAkо7Dfmͭc,i3?Ӫŷ8yja}Ⱒ޵F<asr5<{#ySn!a%]tE8㶬[7;uv O 7g|Są77m+~yO'|?vēϖMNrȍ7\ggO跾\>MWi "ZJ8.U#N鉕֊cbwV)10m?tNMՖPƳ;ۿo[}':=ދS{)DucƸN.@GMLYIwt3]"f#kĕ+-N%:r^ܥ40xOk'/o7~w_{Ko>x׿7㧞sO~3iψRDNGnAkw|^÷(E%݈ ԅv ~tc.?w>8!]<ƒXAMy%wsˉSg|ŝs韪6|_ڥ|r8O*>2|06wC"M.7*tYtq_owQn]eش$SS|>vjk9F^@:yj=~b)Iwv!a Wah$(OKu}s_$$n_nvyO|;G>N}O^һ ˴&"z飮8}}s?\ȉI9X4iyn6r )#mHo<}}to5-)U be= Vg#CL(!1R6;w:g1AgCXO*i^Gm_JzK DY*˜lmsbCf{ןZoS~6/n9!n_يo}kҏ{;īo)GUV4 s3D![G; 0͘qSeQ"(!{^h;6%R)Q9M\ 7hpD$ţvVDD<}r{W|"K/3?w߾{ B= 䄞''d-'^{qK>~N)O|g83)abo.J*K7ъ1@W5/69 zԋ3m[bNCSt|rcW65G 1s+9 Jj>`?=вЩԱXЪV=n?K_pW}?x>)9}4O=x> O\?q3w;'\sO dMu5A޺!Zh=>p/3iTpւJ95EX^/A􅹙zw0:W{zVIg5^iuO _b_=n<ƺfj=Dvrw'/9XÝ亊q5̄$m]W8G~?~;.{泯ZN^tSi$5xkatq3>uA 6`5ho7tRE#Evxlzxu5FeUh,n\i̇Oo}/\}W>u' 7s/|O}X[\BQv5c*M2yXjiݭUDdE˷%s_fأ\ m\atà{>B6MP&'a3׽(\iSB3=NyInwu K;vª-<$%R*=pf1lVup]I#Vl53SUloG>_y?}JW=_7_ßZ2YpaS$m5n,tBk!b5&!mȇhΒTn2vmV;-?y+j{0 cBd!+mc|y:$ÒKkXZuf{M?yR-q1gl]wEQ86):Lh%Բd=\ոb]W(P3/;W_;V;RFh[]"ff\Ūm[ϧjr>XdQjIR׸SgvNB/@hN*2O^<{$N ]SHZy86::ͣ厳P؞"`Eb^j(2^7TQcVLM,a(%ꫝf qϸU2ld`eY( Su[*;JnM0Jj8UJ:R #)aFA1Lxlfg>VU][.Uh;[h`j'\ 0%bEuVU]56Wd'9h`XS S\\D}&5"JAQͩyj/Iܭ\wHwCN/NϐP弐Q, EpXs ,kk4l0E ȃ{o ki*'N0W麮j$ Rf):BZm&_U}O$%I]BZ*X8YRs4aT_b*c%Q-(s(H.#N+`L#bTLilFuETS&k{4e~HUCuE,'L @qLkiRsG(!Uzzy>nz (ز[4Xì:]:͑s WZ3^ ߛZJ{[a:8&z9Qso(LsHn¥.>i "lGk4ckfFXs!vWtwsMn\`3sF Ȇ`Ѫ./˩A2z:Mͥ4% oqOr~܂GG_蟘LsJڻouSIA@ J,E#t ѫuA N=rXk-$P*Hw :@/I*윷2q0,dXT8]Ս%@92P 8O1< фliވHYo]j~{Rp4t":ol A%1@%^ u 6H޳FMpڶݙ< rDCOWg  :h;d8@Y|atEűĐs /'u[B!^ jA3Pb10GlKB\6 Fewm5 ]oY$Xc]W~15`2q!PHܨ06 C("ەaG;4]3cmzNV9!+pp"t" ݨF42 7;ѥN-)svbX}Ez"Έr 8 ~S:0I >#8AҪYL%㶧]e[cM4GU! k;"KQP ES8+&uG,vDTNpݽaۍ8:Pіw4JA 5J!¬Zs%T#Wh+d}tx&J1iv8GEȐpȆic]+swF@"y\'D(g31U ^}9KaWÔD'׽/ߑ.Bg>v{Si4PLVBWm3;M, úz2  *6KʘG.$*R$dP/MvĈ;K/v6ıV` T=G#==4#WI^ 3 Q|9`P9Zp,Alv\n=w{CIC7Z]g%*ox)QX۲,jAV6=5YM3V >P*g1 4CrUV чg)8i\}Fœ(ƀ>%ixFg|;X4B诡..&rQ*ϜRF:hJ@@g%fE ᤮uZ[k$%1')+UujխYjb3, #ϯf4Ph:8^9?%)nObm}0ay!q4Kq3;BFj"v"sL)CYjDX.,U1t4 CF-3pe X!UMYHX7}r{c>`!@8֠-HGWu&z.%S_I!:tc6g.v&#Y z,,džZ QhzKä8}D?]ԑ|PGyNj)9vuvC= 9ɼYQyLqvؘ6EP"h] \!পpK{5o]5u x'=IllϹ>"!SW u^ll@shFgow wvBuc}0Je"*@Ϊ._ *O´\ؾFeHad$YABQԕB-H%0+4dl.СmD*Q7se#5m12wMrnHH =gX蓁*%Pru] ?V'{(R\=݆dب#.rѱud;$Ʈ^L[C/O*TNۘ^6F%D]s"L+c(8F!g4LBHW JRɷuH.S#ԞF!pFa4#E0q $iDH$'p;#4^7A ziB`}\ùo}xbzu:)8d%UY.8@/:@#-gd \G֡\!h@,x@}abe4.?LgX+I7 #hVz:=HX܍z?v:|&@== 5@ClZc 2y-VѽĬ~K;^gPW~D]$xh_o 6$\X a#;KfA P16]M(Q&Ds% #H2I D*E!d?G^ֆ^5P1f0qS0|k \0xU^H cGٯYpiJR iIM<\ch,̹e%EPSZ̥S1H4MFf+f꾜zZ_L`b$[Tcel*31;BِVK=\[ ySMѣ":; Űׁ7F S 3/ d]=jډCT6*G.<#t[ =~a斡; |PU աYG!ҌKjvڙ([*|ō(JlC'$NChnN<.NA.4aL5"[SfY7E,E$Shܘ1&1nmxi/ =ؒͯW ߂?@ߢ%|sk"rK8 䆷"="_BGD{c??yoc?c7g"XIENDB`barry-0.18.5/desktop/images/sync-normal.png0000644001161500056700000003540312242254476020147 0ustar cdfreycdfreyPNG  IHDRxsRGBbKGD pHYs.#.#x?vtIME(oE{tEXtCommentCreated with The GIMPd%n IDATx}[euwWWUm;qM0 xH|$G|"$@^M"A mm[u{Ι|co}sk9ciZ^ky-嵼Z^ky-嵼Z^ky-y_{]]ޮCr]7̧~u6ǎrs,뒙찾OA,㕆kuٿro7-|ۮ[/^OA_(QYq?[ ͵◟໿p^9=5">Nf_~5| ?;L{55{}{Yel~;(υut[ݯ7 gkxN?w~9Do,7?Mv3.?w?#,$[tj硔7W~lxІ#× 躖#:~Ɂ?a:;:orhs> \?@97[̓讟 ʛ0EG8\7{6haE,ڼhoOnN"Tx 7xNoZ>ѭ>G8@So7{‰v"O`lyuݝ6k]9]TГ=hqu)b`0f)4mzqY5vaǏϩ,n>C^"ktFމiў7I#!FyI{!"+ &!0n,W%e=Qä?"?BZ Z"TVsy pB3֦Ky 3|/>RؤP6^цO8Í9.{dW%s !酅O 2#ZNE 7! -C}ݤ^OYx]T:gŶx=YpAOn(K@7\?Sêg:–W4uSq{ßi4O^'xy0¢.]᜸!}wMZ| 0@ywN5|?BZY4oBz) 3-Q#\>xYd{KR"}ipQDT.>sbi#_KDtBfJDuEͤCruuoCǸɛ Dk6BQ!/N]eXaʨ GV"_b Zh?`(`@34(0P)wu8(eOweޤ|POŃ5l&DTû,&f \xg |bȝsu)U(L%+1PDk㞖5HS(=qw":&hTp; 3bzB`ZTR1欄c^F~p^0R^49c^b [8zf=U /l˩?h@+< ΆL؄cZSFjoE& Y ֌5xKsvrz̭Ac%^5:TR3.]"uDyB|P_2GoTe38 2LT0Sf92驳HT7*Qב *<TSU" $d~T$~X$DlR:h(_#s.nC@.j2TFyMS=0uSGURPukθ"RT6p kSb 0>2EVDEUi n5t Vʮ{a &U@ 銾FW#v8!oz(!yV.dly[YƸe*8>' n^d9oT0€';9qd;I8RSb,BDӐBZ. rin/G'JQ$M<Ձy˕S'^6pm:zl%4]ĉ sS&/H1Oh] .5QAH`,RwN6wg8B[DjXl":p 2B 2R?o*0/l9]9 ~<31B \t!r ݋9,|QT,l8TA[y>Z$7$fl`|8B! `! EeC <2OcKZ3*SAk>M$Ud4BK BtƎ*TQt-EMrR^PA굶3 :$&!1h\b¤;itsY ;,lgyOzNpN#@EOC%- K½HH_g8yB}R=aDJ3&eRbW3C]DAH2aaDeNi(bm* _`?8<^# zT%m?" "MQ&Q*},7[R!Kbf 9bTACsS&XrCᵙ©eX$=Jfl"֨Q'FaY. A R(Wޫ:q=P 5S$3ougN%7y5He? ԵPDEJ]q9[O%nKiGeo{ĒEQL.\WpN<P 굼Fh `Q'|:#\0yAW^RB)g.%w}ԤX-Ы%*Fg{-p5lԌ:-H 1q) M+jThҡb4.P:g"&NPbH%Ml{K'5!F9H><8R uJ 4O=1x([n%5{ I}7:.7+u%:Hك`v4 cڝƯ^<ﹻ(zH]U)iFR{Nk?ev hh%ta gEH3DG[P ?Et~+;|?wrrr ~pcۿ~p-\}Ɯ/^ٟOIE6A@BD"03Ƽ&@–I^r%ڂ7!Uj B ֡X"Yc:"FX 63Crr ޿go}gxdiﰛwn!;Z,%N׎ ( qG^\| {d })]戈˩Ȑs}S^[zRjeŶngQ-#."v/3%>܄&y.!aFQc[g|hy.]m6a+vr`͏|xcןWWDDhjDí$E E?ݒ5-aD2S̭[;zƐ8+4S \BD$W t1Xu4s?a=sHhCY tx+k_ҕ[Oo{?{dfm֥ٻZ"̀'/聙" mAA+e1TH_y,"X "6STy}BF+ ;j'pc( \i7IOU7H̃C 8R4DWVvWpӆ416ܱ͵m[_cO,lkzphy^htn^ڶC<9YD L bmTY5LXJM,v!h85if& ɱ@1Z|;$ԉCHوZRkx㊏WlA'21Qa^@KF˔ P h6q[ump 4ت% ;lvvraӎvazxѦSWlZ?t6]wof^-Ea&C,Yv-Cz%ۍP#T0uDn fY 2 ;b 5 TpOl2O} b3L D UŴpLnv<=5Whm-=>m۵'y{Ϳ ?z4*n1B S堹7$nzon+Izfb!5H!Êv Yc0Zg͂ Be}ى y 'KK;k߾w.& N7O[Ogk~<%Kәzph213-zU;x~As޲'33?s \j1Vƭ:dD1Ib"' 31(MPU}Ƽљ)P m=Y&CEXqGVg$wva>8O5/\xd~B!׿ytmv~}wl:۰Wn_ol wan6nݱ^{†MNNf6_ln{c{;QהP|)kCg!B"#HdB#c=E[.;j5SBrbAo*g#[:CuyF]2TCOzNROA~>PYCgO8cஙM fqn<}櫋qfkpt: vކܶK;XqCoۀ#o˜ үёِƩ:HZu3)I#ФY:ēe48P*-Yβnp>za^PoQ;& Zո]`nLJG;l6M,Tjr25sƪN6[]-d>߶\Jwo?wjÿ{lk:y$ Mi jX+}-1"@uzVrӔ~PnGF8@]ZedzcmF%=!2x[2p7i眚4LkmkM%| ]ΧHzD&e._PRxz+泙܃7K_\lG{ah69:mvOl9monMl5KnTmQ Ad6gu^Tn䭲aP u|s,oΕYAjj)E;=f rQ,ҽHf.lmط-"1y[ sfuaf`;[[WNa$eO hʂH QMoA =`2N)b9q&)h9" Mw*)*5GNWUDPhrq1Nq2oJW5bnFzЭۏ>M,d+ k7>=h^͛-?2]P&lF_wE)9׍e!o2d zWuNaZU*ŁB#}!aN'Q9."V.FWyx*?_Yl}cc~p5ݺy6֒LMR:߾nnn/ݾsh'' ~ˏooax&l7A;P[6Lo$ruOV:>o q=g3_;s{뫻;3m*c/, C)4qzmȧGN$[et5[6n&Z`UGMrRM;:9DV90_Dql8=; B1\t!2;lds_yv=؇VWW:|W +鵫͓+G'1qjkыo,8Gƪ2:=W%kmםvJY[#)=GNZk[Vp 6C9ϱN9aRK@ ZAd 67Klm]x oks&)l>$|}0˃zXr%Pms,ޱ[ 41{NQ&QY/>} l7}{Z={Yl{0֗y7xl霏x?17dQG81vϢbWhL)eJ#ߏ@Y9a&=ltnH %D뭺#'3ߙMO̳sՑ70ocL$}#Oknnm9R4Vq uS{ܑT&[;8{372ܫj43tjRӸ7N޼P!vd Lu?1 Iw]{孡Y)-.̮\{Gyگݿ7Cn4յ~?& \{xj*"X*jѾ*? |bF-(˛A Aȥͬ?yK'[[foXڭ|Pl![g;ݙ=Pn2 fۨ)B[6P2{uGm"8KzgF T!k{IhӢϽ˺i; Xt"M-gZNnxG#%լ677?zcFR#-FGk|qP%Z5MnH#-\R.|u5\$c+s)`xKalO긎)vM$D(E gP0c FӂzBjꌧFL v%oGwjwEKOegG!uxLSi1f9T#!zf1Nj^4puvO%4K.镯$f5AFIMn˟Bީ-PjS+3+қT( Ov u^25AI=OʪK@u4y*J2 pDãZE}U& RrY|!ë#-':;r!yQ{J-tz7Y!.D YH!qPyP͚YR{۹#/Y[^jM@,NT3vI1騩4UzG@d}qjqWKTvJZ,.Q쨉*ܫ0LhKGq;.(IrmJȱoP᝛ tD+PhT w=f# H;JhLPf%2Z8e63ib+=_='B- RNʃPڴ87wVLH]0 /^];ois7#8Xun"VT"Ti9h aQQģPg7<5&_Wg>tiXjSUM=Xu4ӭDYu:icAJ!"Y0|;'ܐ cwp']Г~r 1rlʓ=;ir:Ts$<.?!xhWVITbֆK;i|:yB$'na2mPZen0;-ul/LPr\kk nb(r!L G!4*3Qc>áySi:hِ0^@Y7R.Ws u)e:t5mZԭxqK &ؽ1N 8lPøiӑ#dmDw5=0.R&O3ΩΖuzK6l~]PH'4\0S[p"A44@G.-bj.gR?䜞aQHS+Z1{Mtx uv̱!:(:Z ؁/S#NX?ʋf9%lj -j4E'#>=+)UzaewҢŭ;N,.҇TvMCEw/vDP$ҌB!mqume㕗ka.bFu ,R%VbM͍f<=4w !6 e.|j:lF *3}|l+//&f]̑֩*vOI 5Z<",YyM ]Q)sjA* 7yȻYztrhgAHD8#iV4HBd8l[ tHC9!>0OYnf1TЦ>`oUK?u#ӣs€=P9%}1ᡩO2'd[RNQ6#{hѬzzUrLLMg=&3ry8HgC5K6ڂ߻g%JkAǹ‚S@̞Bƣ t<\\G?k&1bc$Q!Z*.k>^}{_/E3YCr]7OSV,嵼Z^ky-嵼Z^ky-嵼Z^G?4QLEIENDB`barry-0.18.5/test/0000755001161500056700000000000012242254476013233 5ustar cdfreycdfreybarry-0.18.5/test/ptyio.cc0000644001161500056700000000335212242254476014711 0ustar cdfreycdfrey/// /// \file ptyio.cc /// Simple test program for pppob's -t pty option. /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include #include #include #include #include #include #include #include using namespace std; struct ioconfig { int read; int write; }; void* readwrite(void *arg) { struct ioconfig *io = (struct ioconfig *) arg; for (;;) { char buffer[4096]; ssize_t count = read(io->read, buffer, sizeof(buffer)); write(1, "Got data: ", 10); write(1, buffer, count); write(io->write, buffer, count); } return 0; } int main(int argc, char *argv[]) { if( argc < 2 ) return 1; int slave = open(argv[1], O_RDWR); if( slave == -1 ) return 2; // set raw mode struct termios tp; tcgetattr(slave, &tp); cfmakeraw(&tp); tcsetattr(slave, TCSANOW, &tp); struct ioconfig io1, io2; io1.read = 0; io1.write = slave; io2.read = slave; io2.write = 1; pthread_t iot1, iot2; pthread_create(&iot1, NULL, &readwrite, &io1); pthread_create(&iot2, NULL, &readwrite, &io2); pthread_join(iot1, NULL); pthread_join(iot2, NULL); return 0; } barry-0.18.5/test/fhbuild.cc0000644001161500056700000002077512242254476015172 0ustar cdfreycdfrey/// /// \file fhbuild.cc /// Compile-time test to make sure all FieldHandle<> templates /// and classes are complete. /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include #include using namespace std; using namespace Barry; void DumpId(const FieldIdentity &id) { cout << " sub = " << (id.HasSubfields ? "true" : "false") << ", parent = " << (id.ParentName ? id.ParentName : "NULL") << endl; cout << " FieldTypeCode = " << id.FieldTypeCode << endl; cout << " Ldif = " << (id.Ldif ? id.Ldif : "NULL") << ", ObjectClass = " << (id.ObjectClass ? id.ObjectClass : "NULL") << endl; cout << " Iconv = " << (id.IconvNeeded ? "true" : "false") << endl << endl; } void DumpEnumConstants(const EnumConstants *ec) { cout << " Available constants:" << endl; EnumConstants::EnumConstantList::const_iterator b = ec->GetConstantList().begin(), e = ec->GetConstantList().end(); for( ; b != e; ++b ) { cout << " " << b->DisplayName << " (" << b->Name << ")" << " = " << b->Value << endl; } cout << endl; } template struct FieldHandler { const RecordT &m_rec; FieldHandler(const RecordT &obj) : m_rec(obj) { } void operator()(EnumFieldBase *ep, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << ep->GetName(ep->GetValue(m_rec)) << " (" << ep->GetValue(m_rec) << ")" << endl; DumpId(id); DumpEnumConstants(ep); } void operator()(typename FieldHandle::PostalPointer pp, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << m_rec.*(pp.m_PostalAddress).*(pp.m_PostalField) << endl; DumpId(id); } template void operator()(TypeT RecordT::* mp, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << m_rec.*mp << endl; DumpId(id); } }; class VirtualFieldHandler : public FieldValueHandlerBase { public: /// For type std::string virtual void operator()(const std::string &v, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << v << endl; DumpId(id); } /// For type EmailAddressList virtual void operator()(const EmailAddressList &v, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << v << endl; DumpId(id); } /// For type Barry::TimeT virtual void operator()(const Barry::TimeT &v, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << v << endl; DumpId(id); } /// For type uint8_t virtual void operator()(const uint8_t &v, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << (unsigned int) v << endl; DumpId(id); } /// For type uint16_t virtual void operator()(const uint16_t &v, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << v << endl; DumpId(id); } /// For type uint32_t virtual void operator()(const uint32_t &v, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << v << endl; DumpId(id); } /// For type uint64_t virtual void operator()(const uint64_t &v, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << v << endl; DumpId(id); } /// For type bool virtual void operator()(const bool &v, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << v << endl; DumpId(id); } /// For type int32_t virtual void operator()(const int32_t &v, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << v << endl; DumpId(id); } /// For type EmailList virtual void operator()(const EmailList &v, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << v << endl; DumpId(id); } /// For type Date virtual void operator()(const Date &v, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << v << endl; DumpId(id); } /// For type CategoryList virtual void operator()(const CategoryList &v, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << v << endl; DumpId(id); } /// For type PostalAddress virtual void operator()(const PostalAddress &v, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << v << endl; DumpId(id); } /// For type UnknownsType virtual void operator()(const UnknownsType &v, const FieldIdentity &id) const { cout << id.DisplayName << " (" << id.Name << "): " << v << endl; DumpId(id); } }; void TestContact() { Contact contact; contact.RecType = 8; contact.RecordId = 100000; contact.EmailAddresses.push_back("cdfrey@foursquare.net"); contact.EmailAddresses.push_back("cdfrey@netdirect.ca"); contact.Phone = "519-555-1212"; contact.Fax = "no fax"; contact.HomeFax = "home fax"; contact.WorkPhone = "work 51235"; contact.WorkPhone2 = "work2 12351234"; contact.HomePhone = "home 12341234"; contact.HomePhone2 = "home2 4234234"; contact.MobilePhone = "mobile 88888"; contact.MobilePhone2 = "mobile2 23424"; contact.Pager = "pager 123412342"; contact.PIN = "PIN 1234"; contact.Radio = "CBC"; contact.OtherPhone = "other 12341234"; contact.FirstName = "Chris"; contact.LastName = "Frey"; contact.Company = "Company naaaaaaaaaaame"; contact.DefaultCommunicationsMethod = "E"; contact.JobTitle = "Programmer"; contact.PublicKey = "seeeecrit"; contact.URL = "http://netdirect.ca/~cdfrey/"; contact.Prefix = "nothing"; contact.Notes = "This is a notes field that can hold mega data"; contact.UserDefined1 = "user 1"; contact.UserDefined2 = "user 2"; contact.UserDefined3 = "user 3"; contact.UserDefined4 = "user 4"; contact.Image = "no image available"; contact.Nickname = "LRU"; Date d; d.FromYYYYMMDD("20120101"); contact.Birthday = d; contact.WorkAddress.Address1 = "work address 1"; contact.WorkAddress.Address2 = "work address 2"; contact.WorkAddress.Address3 = "work address 3"; contact.WorkAddress.City = "work city"; contact.WorkAddress.Province = "work Province"; contact.WorkAddress.PostalCode = "work PostalCode"; contact.WorkAddress.Country = "work Country"; contact.HomeAddress.Address1 = "home address 1"; contact.HomeAddress.Address2 = "home address 2"; contact.HomeAddress.Address3 = "home address 3"; contact.HomeAddress.City = "home city"; contact.HomeAddress.Province = "home Province"; contact.HomeAddress.PostalCode = "home PostalCode"; contact.HomeAddress.Country = "home Country"; contact.Categories.push_back("office"); contact.Categories.push_back("entertainment"); FieldHandler handler(contact); ForEachField(Contact::GetFieldHandles(), handler); cout << "================================================" << endl; VirtualFieldHandler vhandler; ForEachFieldValue(contact, vhandler); } void BlankTestAll() { VirtualFieldHandler vhandler; cout << "All parsers......" << endl; #undef HANDLE_PARSER #define HANDLE_PARSER(tname) \ cout << "Record: " << #tname << endl; \ cout << "===================================================" << endl;\ tname obj##tname; \ FieldHandler fh##tname(obj##tname); \ cout << "By member pointer..." << endl; \ ForEachField(tname::GetFieldHandles(), fh##tname); \ cout << "\nBy value..." << endl; \ ForEachFieldValue(obj##tname, vhandler); \ cout << endl; ALL_KNOWN_PARSER_TYPES cout << "All builders........" << endl; #undef HANDLE_BUILDER #define HANDLE_BUILDER(tname) \ cout << "Record: " << #tname << endl; \ cout << "===================================================" << endl;\ tname bobj##tname; \ FieldHandler bfh##tname(bobj##tname); \ cout << "By member pointer..." << endl; \ ForEachField(tname::GetFieldHandles(), bfh##tname); \ cout << "\nBy value..." << endl; \ ForEachFieldValue(bobj##tname, vhandler); \ cout << endl; ALL_KNOWN_BUILDER_TYPES } int main() { TestContact(); BlankTestAll(); } barry-0.18.5/test/data.cc0000644001161500056700000000700612242254476014456 0ustar cdfreycdfrey/// /// \file data.cc /// Tests for the Data classes /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include #include "libtest.h" #include #include #include #include #include using namespace std; using namespace Barry; static bool Equal(const Data &d1, const Data &d2) { return d1.GetSize() == d2.GetSize() && memcmp(d1.GetData(), d2.GetData(), d1.GetSize()) == 0; } bool TestData() { // typedef std::vector DataVec; // DataVec array; // if( !LoadDataArray("data/parsed.log", array) ) { // cout << "Can't load file" << endl; // return 1; // } // DataVec::iterator i = array.begin(); // Data::PrintAscii(false); // for( ; i != array.end(); i++ ) { // cout << "Endpoint: " << i->GetEndpoint() << endl; // cout << *i; // cout << "\n\n"; // } Data d; TEST( d.GetBufSize() == 0x4000, "Unexpected default buffer size"); const char *str = "hello world"; Data ed(str, strlen(str)); TEST( ed.GetSize() == strlen(str), "Incorrect GetSize() on external data"); TEST( ed.GetData() == (unsigned char*) str, "GetData() external data pointer not the same"); bool caught = false; std::string msg; try { ed.ReleaseBuffer(1); } catch( std::logic_error &e ) { caught = true; msg = e.what(); } TEST( caught == true, "ReleaseBuffer() didn't catch GetBuffer() order: " << msg); TEST( ed.GetBuffer() != (unsigned char*) str, "Data::GetBuffer() did not copy on write correctly"); d = ed; TEST( Equal(d, ed), "Real copy didn't work"); caught = false; try { ed.ReleaseBuffer(1300); } catch( std::logic_error & ) { caught = true; } TEST( caught == true, "Data::ReleaseBuffer() did not catch overflow"); ed.QuickZap(); TEST( ed.GetSize() == 0 && ed.GetData(), "QuickZap did not work"); const unsigned char *old = ed.GetBuffer(); Data ed2(str, strlen(str)); ed = ed2; TEST( ed.GetData() == (unsigned char* )str, "operator=() did not recognize easy external data copy"); TEST( ed.GetBuffer() == old, "GetBuffer() did not recover existing memBlock"); TEST( Equal(ed, ed2), "Data not equal!\n" << ed << endl << ed2); const char *str2 = " and goodbye"; const char *str3 = "hello world and goodbye"; ed2.Append(str2, strlen(str2)); Data ed3(str3, strlen(str3)); TEST( Equal(ed2, ed3), "Append failed"); old = ed.GetData(); size_t old_size = ed.GetSize(); ed.Prepend("pre", 3); TEST( (ed.GetData() + 3) == old, "Prepend buffer failed: " << (void*)old << ":\n" << Data(old, old_size) << (void*)ed.GetData() << ":\n" << ed); ed.Prechop(3); TEST( ed.GetData() == old, "Prechop failed"); cout << "Examples of Diff() output" << endl; Data one, two; one.GetBuffer()[0] = 0x01; one.ReleaseBuffer(1); two.GetBuffer()[0] = 0x02; two.ReleaseBuffer(2); cout << Diff(one, two) << endl; cout << Diff(two, one) << endl; two.GetBuffer(); two.ReleaseBuffer(32); cout << Diff(one, two) << endl; return true; } NewTest testdata("Data classes", &TestData); barry-0.18.5/test/libtest.h0000644001161500056700000000205712242254476015056 0ustar cdfreycdfrey/// /// \file libtest.h /// Routines for testing the Barry libraries /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_LIBTEST_H__ #define __BARRY_LIBTEST_H__ #define TEST(t, err_msg) \ if( !(t) ) { \ std::cout << err_msg << std::endl; \ return false; \ } typedef bool (*testfunc)(); void AddTest(const char *name, testfunc test); struct NewTest { explicit NewTest(const char *name, testfunc test) { AddTest(name, test); } }; #endif barry-0.18.5/test/libtest.cc0000644001161500056700000000277112242254476015217 0ustar cdfreycdfrey/// /// \file libtest.cc /// Routines for testing the Barry libraries /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "libtest.h" #include #include #include using namespace std; typedef std::pair TestPair; typedef std::vector TestList; TestList& GetTests() { static TestList tests; return tests; } void AddTest(const char *name, testfunc test) { GetTests().push_back(TestPair(name, test)); } int main() { int failures = 0; TestList::iterator b = GetTests().begin(), e = GetTests().end(); for( ; b != e; ++b ) { cout << "Testing: " << b->first << "... " << flush; if( !(*b->second)() ) { failures++; cout << "FAILED" << endl; } else { cout << "passed" << endl; } } if( failures ) { cout << dec << failures << " tests failed" << endl; } else { cout << "All tests passed" << endl; } return failures ? 1 : 0; } barry-0.18.5/test/buildtest.sh0000755001161500056700000001777512242254476015612 0ustar cdfreycdfrey#!/bin/bash # # Edit these settings to reflect your system # MAKEOPTS=-j2 export CC="ccache gcc" export CXX="ccache g++" # Make sure any errors stop the test set -e Usage() { echo "Main Barry build test script. Tests the master branch by default." echo echo "Usage:" echo " ./buildtest.sh [commit] [/path/to/libopensync-0.22.tar.bz2]" echo echo "Or, write a ~/.barrytest2 file that contains shell commands" echo "setting OSYNCROOTDIR to the directory you used as a --prefix" echo "when building your own libopensync." echo echo "Note that this directory must be writable by the user that" echo "runs the test, as the plugin will be installed during the" echo "build test." echo echo "You can also set OSYNCROOTDIR_0_40 to the 0.4x opensync directory." echo } if [ "$1" = "-h" ] ; then Usage exit 1 fi # # Check whether the desktop 0.22/0.4x optional build tests can be done # DESKTOP_OPTIONAL_BUILD_TEST=1 if pkg-config --list-all |grep opensync ; then DESKTOP_OPTIONAL_BUILD_TEST=0 echo echo "A version of opensync is already installed on your" echo "system in default directories. Therefore the" echo "tests of the optional desktop builds cannot be done," echo "and will therefore be skipped." echo echo "Press enter to continue..." read fi LIBUSB_0_1_OPTIONAL_BUILD_TEST=1 if ! pkg-config --list-all | grep "libusb " ; then LIBUSB_0_1_OPTIONAL_BUILD_TEST=0 echo echo "No libusb 0.1 library found in pkgconfig, will" echo "not perform libusb 0.1 based tests." echo echo "Press enter to continue..." read fi LIBUSB_1_0_OPTIONAL_BUILD_TEST=1 if ! pkg-config --list-all | grep "libusb-1.0 " ; then LIBUSB_1_0_OPTIONAL_BUILD_TEST=0 echo echo "No libusb 1.0 library found in pkgconfig, will" echo "not perform libusb 1.0 based tests." echo echo "Press enter to continue..." read fi # # Jump to directory that script is located, if necessary # if [ "$(dirname $0)" != "." ] ; then cd "$(pwd)/$(dirname $0)" echo "You ran the script outside the directory it is in." echo "Changing directory to: $(pwd)" echo "If this is not desired, abort now..." sleep 1s fi if [ -d "build" ] ; then echo "'build' directory already exists, exiting..." exit 1 fi BASEPATH=$(pwd) COMMIT="$1" OSYNCSOURCE="$2" if [ -z "$COMMIT" ] ; then COMMIT="master" fi mkdir -p build # # Do we have a ~/.barrytest2 config? # if [ -f ~/.barrytest2 ] ; then . ~/.barrytest2 fi # # First, build opensync in a local directory # if [ -n "$OSYNCROOTDIR" ] ; then echo "Using opensync rootdir: $OSYNCROOTDIR" elif [ -z "$OSYNCROOTDIR" -a -n "$OSYNCSOURCE" ] ; then echo "Extracting opensync sources and building..." (cd build && tar xjf "$OSYNCSOURCE" && \ cd libopensync-0.22 && \ ./configure -prefix="$BASEPATH/build/osyncrootdir" && \ make $MAKEOPTS install) OSYNCROOTDIR="$BASEPATH/build/osyncrootdir" else Usage exit 1 fi if [ -n "$OSYNCROOTDIR_0_40" ] ; then echo "Using opensync-0.4x rootdir: $OSYNCROOTDIR_0_40" fi # # Move .. barry into its own buildable directory # echo "Moving barry [$COMMIT] into it's own directory..." sleep 2s mkdir -p build/barry (cd "./$(git rev-parse --show-cdup)" && git archive --prefix="" "$COMMIT") | \ tar -C build/barry -xf - cp -a build/barry build/barry-orig # # Prepare for Barry building # cd build/barry export PKG_CONFIG_PATH="$BASEPATH/build/rootdir/lib/pkgconfig:$OSYNCROOTDIR/lib/pkgconfig:$OSYNCROOTDIR_0_40/lib/pkgconfig" # # Create configure script # ./buildgen.sh # # Build and test as individual packages # echo "Individual package build test..." rm -rf "$BASEPATH/build/rootdir" export CXXFLAGS="-Wall -Werror -O0 -g" ./configure --prefix="$BASEPATH/build/rootdir" --disable-boost make $MAKEOPTS make distclean ./configure --prefix="$BASEPATH/build/rootdir" --disable-sync make $MAKEOPTS make distclean ./configure --prefix="$BASEPATH/build/rootdir" --enable-boost --with-zlib make $MAKEOPTS make install make distclean cd gui export CXXFLAGS="-Wall -Werror -ansi -pedantic -O0 -g" ./configure --prefix="$BASEPATH/build/rootdir" make $MAKEOPTS make install make distclean cd .. cd opensync-plugin export CXXFLAGS="-Wall -Werror -O0 -g" ./configure --prefix="$BASEPATH/build/rootdir" make $MAKEOPTS make install make distclean cd .. cd opensync-plugin-0.4x export CXXFLAGS="-Wall -Werror -O0 -g" ./configure --prefix="$BASEPATH/build/rootdir" make $MAKEOPTS make install make distclean cd .. cd desktop export CXXFLAGS="-Wall -Werror -O0 -g" ./configure --prefix="$BASEPATH/build/rootdir" make $MAKEOPTS make install make distclean cd .. if [ "$DESKTOP_OPTIONAL_BUILD_TEST" = "1" ] ; then BACKUP_PKG_CONFIG_PATH="$PKG_CONFIG_PATH" echo "Testing optional desktop builds in 10 seconds..." sleep 10s cd desktop # Test only 0.22 export PKG_CONFIG_PATH="$BASEPATH/build/rootdir/lib/pkgconfig:$OSYNCROOTDIR/lib/pkgconfig" export CXXFLAGS="-Wall -Werror -O0 -g" ./configure --prefix="$BASEPATH/build/rootdir" make $MAKEOPTS make install make distclean # Test only 0.4x export PKG_CONFIG_PATH="$BASEPATH/build/rootdir/lib/pkgconfig:$OSYNCROOTDIR_0_40/lib/pkgconfig" export CXXFLAGS="-Wall -Werror -O0 -g" ./configure --prefix="$BASEPATH/build/rootdir" make $MAKEOPTS make install make distclean # Restore path export PKG_CONFIG_PATH="$BACKUP_PKG_CONFIG_PATH" # Test without evolution (EvoSources.cc dummy code) export CXXFLAGS="-Wall -Werror -O0 -g" ./configure --prefix="$BASEPATH/build/rootdir" --without-evolution make $MAKEOPTS make install make distclean cd .. fi # # Build and test as one package # echo "Single build test..." rm -rf "$BASEPATH/build/rootdir" export CXXFLAGS="-Wall -Werror -O0 -g" ./configure --prefix="$BASEPATH/build/rootdir" \ --enable-boost \ --enable-gui \ --enable-opensync-plugin \ --enable-opensync-plugin-4x \ --enable-desktop make $MAKEOPTS install make distclean ./configure --prefix="$BASEPATH/build/rootdir" \ --enable-gui \ --enable-opensync-plugin \ --enable-opensync-plugin-4x \ --enable-desktop make $MAKEOPTS make distclean # # Test libusb selection from configure # using with and without selection # if [ "$LIBUSB_0_1_OPTIONAL_BUILD_TEST" = "1" -a "$LIBUSB_1_0_OPTIONAL_BUILD_TEST" = "1" ] ; then echo "Testing choosing libusb options..." # Test that libusb 1.0 is chosen by default ./configure --prefix="$BASEPATH/build/rootdir" make $MAKEOPTS install ldd $BASEPATH/build/rootdir/lib/libbarry.so | grep libusb-1.0.so rm -rf "$BASEPATH/build/rootdir" make distclean # Test that libusb 0.1 is chosen if not libusb 1.0 ./configure --prefix="$BASEPATH/build/rootdir" \ --without-libusb1_0 make $MAKEOPTS install ldd $BASEPATH/build/rootdir/lib/libbarry.so | grep libusb-0.1.so rm -rf "$BASEPATH/build/rootdir" make distclean # Test that libusb 0.1 is chosen if explicitly asked for ./configure --prefix="$BASEPATH/build/rootdir" \ --with-libusb make $MAKEOPTS install ldd $BASEPATH/build/rootdir/lib/libbarry.so | grep libusb-0.1.so rm -rf "$BASEPATH/build/rootdir" make distclean fi # # Test that cleanall cleans up all traces # echo "Testing buildgen cleanall..." ./buildgen.sh cleanall cd "$BASEPATH" diff -ruN build/barry-orig build/barry cd build/barry # # Test 'make dist' (the dist family of targets leaves build evidence # behind, so do this after the cleanall check) # echo "Testing 'make dist'..." rm -rf "$BASEPATH/build/rootdir" ./buildgen.sh ./configure \ --enable-gui \ --enable-opensync-plugin \ --enable-opensync-plugin-4x \ --enable-desktop make dist mkdir ../disttree tar -C ../disttree -xjf barry-*.*.*.tar.bz2 make distcheck make distclean # remove the dist tarballs rm -f barry-*.*.*.tar.{bz2,gz} # compare our tree with the disttree cd .. # skip: # autom4te.cache - autogenerated stuff we don't care about # debian - dist tarball shouldn't have to care about that # m4/ - more autogenerated stuff we dont' care about # po/ - unsure # diff -ruN \ --exclude=autom4te.cache \ --exclude=debian \ --exclude='*.m4' \ --exclude=po \ --exclude=po-osyncwrap \ barry disttree/barry-*.*.* # # Success # cd "$BASEPATH" rm -rf "$BASEPATH/build" echo "All tests passed." barry-0.18.5/test/Makefile.am0000644001161500056700000000202712242254476015270 0ustar cdfreycdfreyEXTRA_DIST = buildtest.sh nightly.sh #DEFAULT_INCLUDES = INCLUDES = #AM_CXXFLAGS = -ansi -Wall -fno-strict-aliasing -g AM_CXXFLAGS = -Wall -g # To use gettext datadir = @datadir@ localedir = $(datadir)/locale DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@ noinst_HEADERS = libtest.h noinst_PROGRAMS = libtest fhbuild ptyio libtest_SOURCES = \ date.cc \ data.cc \ libtest.cc libtest_LDADD = \ ../src/libbarry.la \ @BOOST_LDADD@ $(LTLIBINTL) $(LTLIBICONV) libtest_LDFLAGS = @BOOST_LIB_PATH@ libtest_CXXFLAGS = $(AM_CXXFLAGS) if WITH_BOOST libtest_CXXFLAGS += -D__BARRY_BOOST_MODE__ -D_REENTRANT @BOOST_INC_PATH@ endif if WITH_SYNC libtest_LDADD += ../src/libbarrysync.la $(GLIB2_LIBS) libtest_CXXFLAGS += -D__BARRY_SYNC_MODE__ $(GLIB2_CFLAGS) endif if WITH_BACKUP libtest_LDADD += ../src/libbarrybackup.la libtest_CXXFLAGS += -D__BARRY_BACKUP_MODE__ endif fhbuild_SOURCES = fhbuild.cc fhbuild_LDADD = ../src/libbarry.la $(LTLIBINTL) $(LTLIBICONV) fhbuild_CXXFLAGS = $(AM_CXXFLAGS) ptyio_SOURCES = ptyio.cc ptyio_CXXFLAGS = $(AM_CXXFLAGS) barry-0.18.5/test/nightly.sh0000755001161500056700000000035712242254476015255 0ustar cdfreycdfrey#!/bin/bash set -e cd $(dirname "$0")/../maintainer ./release.sh 0 18 5 master barrychroots ./release.sh 0 18 5 master barryremote cd ../test git clean -xdf ./buildtest.sh echo echo "Success." echo "Everything built without failure." barry-0.18.5/test/date.cc0000644001161500056700000000322612242254476014462 0ustar cdfreycdfrey/// /// \file date.cc /// Tests for the Date class /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include #include "libtest.h" #include #include #include #include using namespace std; using namespace Barry; bool TestDate() { struct tm t; memset(&t, 0, sizeof(t)); t.tm_year = 111; t.tm_mon = 1; t.tm_mday = 28; Date d(&t); TEST( d.ToYYYYMMDD() == "20110228", "ToYYYYMMDD() failed"); TEST( d.ToBBString() == "28/02/2011", "ToBBString() failed"); ostringstream oss; oss << hex << d; TEST( oss.str() == "2011/02/28", "Stream output failed: " << oss.str()); Date d2; d2.FromTm(&t); TEST( d2.ToYYYYMMDD() == "20110228", "FromTm() failed"); struct tm myt; d.ToTm(&myt); d2.FromTm(&myt); TEST( d2.ToYYYYMMDD() == "20110228", "ToTm() failed"); d2.FromBBString(d.ToBBString()); TEST( d2.ToYYYYMMDD() == "20110228", "FromBBString() failed"); d2.FromYYYYMMDD(d.ToYYYYMMDD()); TEST( d2.ToYYYYMMDD() == "20110228", "FromYYYMMDD() failed"); return true; } NewTest testdate("Date class", &TestDate); barry-0.18.5/src/0000755001161500056700000000000012242254476013043 5ustar cdfreycdfreybarry-0.18.5/src/sha1.h0000644001161500056700000000563512242254476014061 0ustar cdfreycdfrey/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is SHA 180-1 Header File * * The Initial Developer of the Original Code is Paul Kocher of * Cryptography Research. Portions created by Paul Kocher are * Copyright (C) 1995-9 by Cryptography Research, Inc. All * Rights Reserved. * * Contributor(s): * * Paul Kocher * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */ /* Copied from the git sources, with the following revision history: commit 77ab8798d3f8df39877235be17bb6e70077aaba2 Author: Junio C Hamano Date: Tue Nov 1 10:56:03 2005 -0800 Fix constness of input in mozilla-sha1/sha1.c::SHA1_Update(). Among the three of our own implementations, only this one lacked "const" from the second argument. Signed-off-by: Junio C Hamano commit cef661fc799a3a13ffdea4a3f69f1acd295de53d Author: Linus Torvalds Date: Thu Apr 21 12:33:22 2005 -0700 Add support for alternate SHA1 library implementations. This one includes the Mozilla SHA1 implementation sent in by Edgar Toernig. It's dual-licenced under MPL-1.1 or GPL, so in the context of git, we obviously use the GPL version. Side note: the Mozilla SHA1 implementation is about twice as fast as the default openssl one on my G5, but the default openssl one has optimized x86 assembly language on x86. So choose wisely. */ #ifndef __BARRY_SHA1_H__ #define __BARRY_SHA1_H__ #include "dll.h" #define SHA_DIGEST_LENGTH 20 namespace Barry { struct BXEXPORT SHA_CTX { unsigned int H[5]; unsigned int W[80]; int lenW; unsigned int sizeHi,sizeLo; }; BXEXPORT void SHA1(const void *dataIn, int len, unsigned char *hashout); BXEXPORT void SHA1_Init(SHA_CTX *ctx); BXEXPORT void SHA1_Update(SHA_CTX *ctx, const void *dataIn, int len); BXEXPORT void SHA1_Final(unsigned char hashout[20], SHA_CTX *ctx); } #endif barry-0.18.5/src/controller.cc0000644001161500056700000001462712242254476015547 0ustar cdfreycdfrey/// /// \file controller.cc /// High level Barry API class /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "controller.h" #include "controllerpriv.h" #include "common.h" #include "protocol.h" #include "protostructs.h" #include "data.h" #include "endian.h" #include "platform.h" #include #define __DEBUG_MODE__ #include "debug.h" namespace Barry { // // Controller constructor // /// Constructor for the Controller class. Requires a valid ProbeResult /// object to find the USB device to talk to. /// /// \param[in] device One of the ProbeResult objects from the /// Probe class. /// \param[in] default_timeout Override Usb::Device's default timeout /// Controller::Controller(const ProbeResult &device, int default_timeout) : m_priv(new PrivateControllerData(device, default_timeout)) { dout(_("Controller: Using non-threaded sockets")); SetupUsb(device); } // // Controller constructor // /// Constructor for the Controller class. Requires a valid ProbeResult /// object to find the USB device to talk to. /// /// \param[in] device One of the ProbeResult objects from the /// Probe class. /// \param[in] queue Plugin router object for reading data /// from sockets. /// \param[in] default_timeout Override Usb::Device's default timeout /// Controller::Controller(const ProbeResult &device, SocketRoutingQueue &queue, int default_timeout) : m_priv(new PrivateControllerData(device, queue, default_timeout)) { dout(_("Controller: Using threaded socket router")); SetupUsb(device); // set the queue to use our device queue.SetUsbDevice(&m_priv->m_dev, device.m_ep.write, device.m_ep.read); } void Controller::SetupUsb(const ProbeResult &device) { unsigned char cfg; if( !m_priv->m_dev.GetConfiguration(cfg) ) throw Usb::Error(m_priv->m_dev.GetLastError(), _("Controller: GetConfiguration failed")); if( cfg != BLACKBERRY_CONFIGURATION || MUST_SET_CONFIGURATION ) { if( !m_priv->m_dev.SetConfiguration(BLACKBERRY_CONFIGURATION) ) throw Usb::Error(m_priv->m_dev.GetLastError(), _("Controller: SetConfiguration failed")); } m_priv->m_iface = new Usb::Interface(m_priv->m_dev, device.m_interface); if( device.m_needSetAltInterface ) { m_priv->m_iface->SetAltInterface(device.m_altsetting); } if( device.m_needClearHalt ) { m_priv->m_dev.ClearHalt(device.m_ep.read); m_priv->m_dev.ClearHalt(device.m_ep.write); } } Controller::~Controller() { } /////////////////////////////////////////////////////////////////////////////// // protected members // // Tells device which mode is desired, and returns the suggested // socket ID to use for that mode. // uint16_t Controller::SelectMode(ModeType mode) { return SelectMode(mode, NULL); } // // Tells device which mode is desired, and returns the suggested // socket ID to use for that mode. // // If explicitModeName is not NULL then it will be used as the mode name. // Otherwise the default mode name for the given mode will be used. // It should be a nul terminated string if it is provided. // // The RawChannel mode requires an explicitModeName to be specified. // uint16_t Controller::SelectMode(ModeType mode, const char *explicitModeName) { // select mode Protocol::Packet packet; packet.socket = 0; packet.size = htobs(SB_MODE_PACKET_COMMAND_SIZE); packet.command = SB_COMMAND_SELECT_MODE; packet.u.socket.socket = htobs(SB_MODE_REQUEST_SOCKET); packet.u.socket.sequence = 0; // updated by Socket::Send() memset(packet.u.socket.u.mode.name, 0, sizeof(packet.u.socket.u.mode.name)); char *modeName = (char *) packet.u.socket.u.mode.name; if( explicitModeName ) { if( strlen(explicitModeName) >= sizeof(packet.u.socket.u.mode.name) ) { throw std::logic_error(_("Controller: explicit mode name too long")); } strcpy(modeName, explicitModeName); } else { // No modeName given, use the default switch( mode ) { case Bypass: strcpy(modeName, "RIM Bypass"); break; case Desktop: strcpy(modeName, "RIM Desktop"); break; case JavaLoader: strcpy(modeName, "RIM_JavaLoader"); break; case JVMDebug: strcpy(modeName, "RIM_JVMDebug"); break; case UsbSerData: strcpy(modeName, "RIM_UsbSerData"); break; case UsbSerCtrl: strcpy(modeName, "RIM_UsbSerCtrl"); break; case RawChannel: throw std::logic_error(_("Controller: No channel name given with RawChannel mode")); break; default: throw std::logic_error(_("Controller: Invalid mode in SelectMode")); break; } } // send mode command before we open, as a default socket is socket 0 Data command(&packet, btohs(packet.size)); Data response; try { m_priv->m_zero.Send(command, response); // get the data socket number // indicates the socket number that // should be used below in the Open() call MAKE_PACKET(modepack, response); if( modepack->command == SB_COMMAND_MODE_NOT_SELECTED ) { throw Error(_("Controller: requested mode not supported")); } if( modepack->command != SB_COMMAND_MODE_SELECTED ) { eeout(command, response); throw Error(_("Controller: mode not selected")); } // return the socket that the device is expecting us to use return btohs(modepack->u.socket.socket); } catch( Usb::Error & ) { eout(_("Controller: error setting desktop mode")); eeout(command, response); throw; } } // // OpenSocket // /// Can be called multiple times, in case of password retries. /// See also Mode::RetryPassword() /// SocketHandle Controller::OpenSocket(uint16_t socket, const char *password) { return m_priv->m_zero.Open(socket, password); } /////////////////////////////////////////////////////////////////////////////// // public API bool Controller::HasQueue() const { return m_priv->m_queue != NULL; } SocketRoutingQueue* Controller::GetQueue() { return m_priv->m_queue; } const ProbeResult& Controller::GetProbeResult() const { return m_priv->m_result; } } // namespace Barry barry-0.18.5/src/parser.h0000644001161500056700000003463112242254476014517 0ustar cdfreycdfrey/// /// \file parser.h /// Virtual parser wrapper /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_PARSER_H__ #define __BARRY_PARSER_H__ #include "dll.h" #include "data.h" #include "protocol.h" #include // for uint32_t #include #include // forward declarations namespace Barry { class IConverter; class Contact; class Message; class Calendar; class CalendarAll; class CallLog; class Bookmark; class ServiceBook; class Memo; class Task; class PINMessage; class SavedMessage; class Sms; class Folder; class TimeZone; class ContentStore; class HandheldAgent; } // // This macro can be used to automatically generate code for all known // record types. Just #undef HANDLE_PARSER, then #define it to whatever // you need, then use ALL_KNOWN_PARSER_TYPES. See parser.cc for // various examples. // // These are sorted so their GetDBName()'s will display in alphabetical order. // #define ALL_KNOWN_PARSER_TYPES \ HANDLE_PARSER(Contact) \ HANDLE_PARSER(Bookmark) \ HANDLE_PARSER(Calendar) \ HANDLE_PARSER(CalendarAll) \ HANDLE_PARSER(ContentStore) \ HANDLE_PARSER(Folder) \ HANDLE_PARSER(HandheldAgent) \ HANDLE_PARSER(Memo) \ HANDLE_PARSER(Message) \ HANDLE_PARSER(CallLog) \ HANDLE_PARSER(PINMessage) \ HANDLE_PARSER(SavedMessage) \ HANDLE_PARSER(ServiceBook) \ HANDLE_PARSER(Sms) \ HANDLE_PARSER(Task) \ HANDLE_PARSER(TimeZone) namespace Barry { // // Parser class // /// Base class for the parser hierarchy. /// /// This class provides the interface that the Controller class uses /// to pass raw data it reads from the device. The Controller, along /// with the Packet class, calls each of the virtual functions below /// in the same order. /// /// This class is kept as a pure abstract class, in order to make sure /// that the compiler will catch any API changes, for code derived /// from it. /// class BXEXPORT Parser { public: Parser() {} virtual ~Parser() {} /// Called to parse sub fields in the raw data packet. virtual void ParseRecord(const DBData &data, const IConverter *ic) = 0; }; // // NullParser class // /// If in debug mode, this class can be used as a null parser. /// Call Init() and the protocol will be dumped to stdout and /// no parsing will be done. /// /// Do NOT derive your own personal parser classes from this, /// unless you are perfectly confident that you will catch /// future API changes on the devel tree without the compiler's /// help. /// class BXEXPORT NullParser : public Parser { public: NullParser() {} virtual ~NullParser() {} virtual void ParseRecord(const DBData &data, const IConverter *ic) {} }; // // HexDumpParser // /// Dumps raw hex of the given DBData to the given stream. /// /// Do NOT derive your own personal parser classes from this, /// unless you are perfectly confident that you will catch /// future API changes on the devel tree without the compiler's /// help. /// class BXEXPORT HexDumpParser : public Parser { std::ostream &m_os; std::string m_last_dbname; public: explicit HexDumpParser(std::ostream &os); virtual void ParseRecord(const Barry::DBData &data, const IConverter *ic); }; // // DBNamesOnlyParser // /// Prints only the unique databases names found in the stream. /// /// Do NOT derive your own personal parser classes from this, /// unless you are perfectly confident that you will catch /// future API changes on the devel tree without the compiler's /// help. /// class BXEXPORT DBNamesOnlyParser : public Parser { std::ostream &m_os; std::string m_last_dbname; public: explicit DBNamesOnlyParser(std::ostream &os); virtual void ParseRecord(const Barry::DBData &data, const IConverter *ic); }; // // RecordParserBase // /// Abstract base class for the following RecordParser template, that exposes /// some information on the specifics that the record parser can handle. /// Specifically, it exposes the database name it is able to parse /// class BXEXPORT RecordParserBase : public Parser { public: // These functions are always valid, regardless of the // state of the parser. virtual const char * GetDBName() const = 0; virtual uint8_t GetDefaultRecType() const = 0; // These functions depend on the parser having just parsed // a record successfully. virtual bool IsRecordValid() const = 0; virtual uint8_t GetRecType() const = 0; virtual uint32_t GetUniqueId() const = 0; virtual void Dump(std::ostream &os) const = 0; }; // // Note: Store classes take parsed Record objects as a functor. // Parser classes deal with raw data, while Store classes deal with // parsed Record objects. // // // NullStore // /// A Storage class for RecordParser<> that does nothing, for the cases /// where you only want to dump parsed record data to a stream. /// template class NullStore { public: void operator() (const RecordT &r) { } }; // // DumpStore // /// A Storage class for RecordParser<> that dumps the parsed record data /// to the given stream. /// template class DumpStore { std::ostream &m_os; public: explicit DumpStore(std::ostream &os) : m_os(os) { } void operator() (const RecordT &r) { r.Dump(m_os); } }; // // RecordStore // /// A Storage class for RecordParser that stores a copy of the parsed record. /// template class RecordStore { public: RecordT m_rec; void operator() (const RecordT &r) { m_rec = r; } }; // // ParseDBData // /// Contains the proper way to convert a DBData object into a record. /// template void ParseDBData(const DBData &data, RecordT &rec, const IConverter *ic) { // start fresh rec = RecordT(); // parse rec.SetIds(data.GetRecType(), data.GetUniqueId()); size_t offset = data.GetOffset(); rec.ParseHeader(data.GetData(), offset); rec.ParseFields(data.GetData(), offset, ic); } // // RecordParser template class // /// Template class for easy creation of specific parser objects. This template /// takes the following template arguments: /// /// - RecordT: One of the record parser classes in record.h /// - StorageT: A custom storage functor class. An object of this type /// will be called as a function with parsed Record as an /// argument. This happens on the fly as the data is retrieved /// from the device over USB, so it should not block forever. /// /// Example LoadDatabase() call: /// ///

/// struct StoreContact
/// {
///     std::vector &array;
///     StoreContact(std::vector &a) : array(a) {}
///     void operator() (const Contact &c)
///     {
///         array.push_back(c);
///     }
/// };
///
/// Controller con(probeResult);
/// con.OpenMode(Controller::Desktop);
/// std::vector contactList;
/// StoreContact storage(contactList);
/// RecordParser parser(storage);
/// con.LoadDatabase(con.GetDBID("Address Book"), parser);
/// 
/// template class RecordParser : public RecordParserBase { StorageT *m_store; bool m_owned; RecordT m_rec; bool m_record_valid; public: /// Constructor that references an externally managed storage object. RecordParser(StorageT &storage) : m_store(&storage) , m_owned(false) , m_record_valid(false) { } /// Constructor that references a locally managed storage object. /// The pointer passed in will be stored, and freed when this class /// is destroyed. It is safe to call this constructor with /// a 'new'ly created storage object. RecordParser(StorageT *storage = 0) : m_store(storage) , m_owned(true) , m_record_valid(false) { } ~RecordParser() { if( this->m_owned ) delete m_store; } virtual StorageT* GetStore() { return m_store; } virtual const StorageT* GetStore() const { return m_store; } virtual void ParseRecord(const DBData &data, const IConverter *ic) { m_record_valid = false; ParseDBData(data, m_rec, ic); m_record_valid = true; if( m_store ) (*m_store)(m_rec); } // // RecordParserBase overrides // // These functions are always valid, regardless of the // state of the parser. virtual const char * GetDBName() const { return RecordT::GetDBName(); } virtual uint8_t GetDefaultRecType() const { return RecordT::GetDefaultRecType(); } // These functions depend on the parser having just parsed // a record successfully. virtual bool IsRecordValid() const { return m_record_valid; } virtual const RecordT& GetRecord() const { return m_rec; } virtual uint8_t GetRecType() const { return m_rec.GetRecType(); } virtual uint32_t GetUniqueId() const { return m_rec.GetUniqueId(); } virtual void Dump(std::ostream &os) const { m_rec.Dump(os); } }; // // AllRecordStore // /// Base class with overloaded functor behaviour for all available /// record classes. To be used with AllRecordParser. /// class BXEXPORT AllRecordStore { public: AllRecordStore() {} virtual ~AllRecordStore() {} #undef HANDLE_PARSER #define HANDLE_PARSER(tname) \ virtual void operator() (const Barry::tname &) = 0; ALL_KNOWN_PARSER_TYPES }; // // MultiRecordParser // /// Container parser class that accepts multiple Parser objects /// (often RecordParser<> objects but they don't have to be) and /// automatically routes incoming records to the appropriate parser. /// Note that this container owns *all* Parser objects, and will /// free them upon destruction. /// /// Incoming records that have no matching parser are passed to the /// default parser object, if one exists, otherwise they are dropped /// silently. The default parser object is also owned by the container, /// and will be freed on destruction. /// /// Do NOT derive your own personal parser classes from this, /// unless you are perfectly confident that you will catch /// future API changes on the devel tree without the compiler's /// help. /// class BXEXPORT MultiRecordParser : public Parser { typedef std::map map_type; Parser *m_delete_default; // if set, will be freed Parser *m_default; // used by all code for actual work // and may or may not be "owned" by us map_type m_parsers; public: // takes ownership of default_parser! explicit MultiRecordParser(Parser *default_parser = 0); // does not take ownership of the default_parser explicit MultiRecordParser(Parser &default_parser); ~MultiRecordParser(); /// Adds given parser to list and takes ownership of it void Add(const std::string &dbname, Parser *parser); /// Adds given parser to list and takes ownership of it void Add(RecordParserBase *parser); /// Creates a RecordParser<> object using the given record /// type and AllRecordStore. Does NOT take ownership of the /// store object, since it can be used multiple times for /// multiple records. template void Add(AllRecordStore &store) { Add( RecordT::GetDBName(), new RecordParser(store) ); } /// Two helper template functions that create the RecordParser<> /// automatically based on the function call. Both pointer and /// reference versions. template void Add(StorageT *store) { Add( RecordT::GetDBName(), new RecordParser(store) ); } template void Add(StorageT &store) { Add( RecordT::GetDBName(), new RecordParser(store) ); } /// Creates a RecordParser<> object for the given database name, /// using DumpStore<> with the given stream for the output, /// and adds it to list. /// Returns false if there is no known Record class for dbname. bool Add(const std::string &dbname, std::ostream &os); /// Creates a RecordParser<> object for the given database name, /// using the given store object. /// Returns false if there is no known Record class for dbname. bool Add(const std::string &dbname, AllRecordStore &store); // Parser overrides virtual void ParseRecord(const DBData &data, const IConverter *ic); }; // // AllRecordDumpStore // /// Derived from AllRecordStore, which just calls each record's /// Dump() member with the given stream. /// class BXEXPORT AllRecordDumpStore : public AllRecordStore { protected: std::ostream &m_os; public: explicit AllRecordDumpStore(std::ostream &os) : m_os(os) { } #undef HANDLE_PARSER #define HANDLE_PARSER(tname) \ virtual void operator() (const Barry::tname &); ALL_KNOWN_PARSER_TYPES }; // // AllRecordParser // /// Convenience parser that creates a MultiRecordParser with all known /// record parsers added. If an AllRecordStore pointer is passed in, /// this class takes ownership of it, and uses it as the store object /// for all the RecordParser<> objects it creates. If not, then /// a custom DumpStore<> object is created with the given stream /// for each RecordParser<> added. /// /// The default parser object behaves just like MultiRecordParser /// /// This class takes ownership of all pointers passed in. /// class BXEXPORT AllRecordParser : public MultiRecordParser { AllRecordStore *m_store; protected: // does not take ownership of store, by itself, // but the constructor that calls it might void AddRecords(std::ostream *os, AllRecordStore *store); public: // takes ownership of default_parser and store! explicit AllRecordParser(std::ostream &os, Parser *default_parser = 0, AllRecordStore *store = 0); // does not take ownership of default_parser or store AllRecordParser(Parser &default_parser, AllRecordStore &store); ~AllRecordParser(); }; // // TeeParser // /// Sends incoming DBData objects to all the parsers in its list. /// This parser container does NOT own the parsers added. /// class BXEXPORT TeeParser : public Parser { typedef std::vector parser_list_type; parser_list_type m_external_parsers, m_owned_parsers; public: TeeParser(); ~TeeParser(); /// Adds parser to internal list, and takes ownership of the /// pointer. void Add(Parser *p); /// Adds parser to internal list. Does NOT own the parser reference. void Add(Parser &p); void ParseRecord(const DBData &data, const IConverter *ic); }; } // namespace Barry #endif barry-0.18.5/src/cod-internal.h0000644001161500056700000001305112242254476015573 0ustar cdfreycdfrey/// /// \file cod-internal.h /// COD structure /// /* Copyright (C) 2008-2009, Nicolas VIVIEN Copyright (C) 2009, Josh Kropf See also: http://drbolsen.wordpress.com/2006/07/26/blackberry-cod-file-format/ http://drbolsen.wordpress.com/2006/08/11/10/ http://www.pkware.com/documents/casestudies/APPNOTE.TXT 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_COD_INTERNAL_H__ #define __BARRY_COD_INTERNAL_H__ #include "dll.h" #include #include #include "platform.h" // safe to include platform.h here, since // cod-internal.h is not installed either #if USE_PACK_PRAGMA #pragma pack(push, 1) #endif #define CODFILE_TYPE_SIMPLE {0xDE, 0xC0} #define CODFILE_TYPE_PKZIP {0x50, 0x4B} #define PKZIP_LOCAL_FILE_SIG {0x50, 0x4B, 0x03, 0x04} #define PKZIP_DIRECTORY_SIG {0x50, 0x4B, 0x01, 0x02} #define PKZIP_END_DIRECTORY_SIG {0x50, 0x4B, 0x05, 0x06} typedef struct BXLOCAL { uint16_t hour:5; uint16_t minute:6; uint16_t second:5; } ATTRIBUTE_PACKED msdos_time_t; typedef struct BXLOCAL { uint16_t year:7; // number of years since 1980 uint16_t month:4; uint16_t day:5; } ATTRIBUTE_PACKED msdos_date_t; typedef struct BXLOCAL { //uint8_t signature[4]; // PKZIP local file header 0x504B0304 uint16_t version_needed; // version needed to extract, 0x0A00 uint16_t general_flag; // general purpose bit flag, 0x0000 uint16_t compression_method; // compression method, 0x0000 = stored, no compression msdos_time_t last_mod_time; msdos_date_t last_mod_date; uint32_t crc_32; uint32_t compressed_size; // compression method is 'stored' uint32_t uncompressed_size; // both sizes are equal uint16_t file_name_length; uint16_t extra_field_length; //char file_name[variable]; //char extra_field[variable]; } ATTRIBUTE_PACKED pkzip_local_header_t; typedef struct BXLOCAL { //uint8_t signature[4]; // PKZIP central directory 0x504B0304 uint16_t version_madeby; // version used to compress, 0x0A00 uint16_t version_needed; // version needed to extract, 0x0A00 uint16_t general_flag; // general purpose bit flag, 0x0000 uint16_t compression_method; // compression method, 0x0000 = stored, no compression msdos_time_t last_mod_time; msdos_date_t last_mod_date; uint32_t crc_32; uint32_t compressed_size; // size of corresponding local file entry uint32_t uncompressed_size; // both sizes are equal uint16_t file_name_length; uint16_t extra_field_length; uint16_t file_comment_length; uint16_t disk_number; // number of the disk on which this file begins, always zero uint16_t internal_file_attr; // always zero uint32_t external_file_attr; // always zero uint32_t relative_offset; // offset from beginning of this disk (this zip file) // to start of corresponding local file entry //char file_name[variable]; //char extra_field[variable]; //char file_comment[variable]; } ATTRIBUTE_PACKED pkzip_directory_t; typedef struct BXLOCAL { //uint8_t signature[4]; // PKZIP end central directory 0x504B0506 uint16_t this_disk_number; // number of this disk, always zero uint16_t disk_with_first; // number of the disk with the start of // central directory, always zero uint16_t this_disk_entry_count; // total number of entries in the central directory on this disk uint16_t total_entry_count; // total number of entries in the central directory // always equals this_disk_entry_count uint32_t directory_length; // total size of the central directory uint32_t directory_offset; // offset from beginning of this disk (this zip file) // to the first central directory entry uint16_t file_comment_length; //char file_comment[variable]; } ATTRIBUTE_PACKED pkzip_end_directory_t; typedef struct BXLOCAL { uint16_t type; // Type // 50 4B uint8_t unknown1[8]; // // 03 04 0A 00 00 00 00 00 uint8_t unknown2[4]; // // AB 5C 6A 39 uint8_t unknown3[4]; // // BE 5C 58 D1 uint32_t size1; // COD size 0x0DCC // CC 0D 01 00 uint32_t size2; // COD size 0x0DCC // CC OD 01 00 uint8_t strsize; // Size of string // 19 uint8_t reserved2; // Reserved 0x00 // 00 uint8_t strfree; // Empty uint8_t // 04 uint8_t reserved3; // Reserved 0x00 // 00 } ATTRIBUTE_PACKED codfile_header_t; typedef struct BXLOCAL { uint32_t flashid; uint32_t section_number; // always 0 uint32_t vtable_pointer; // always 0 time_t timestamp; uint32_t user_version; uint32_t fieldref_pointer; uint16_t maxtype_list_size; uint16_t reserved; // always 0xFF int32_t data_section; // always 0xFFFF int32_t module_info; // always 0xFFFF uint16_t version; uint16_t code_size; uint16_t data_size; uint16_t flags; } ATTRIBUTE_PACKED code_header_t; typedef struct BXLOCAL { uint8_t flags; uint8_t version; uint16_t num_icalls; uint8_t num_modules; uint8_t num_classes ; uint16_t exported_string_offset; uint16_t data_uint8_ts_offset; uint16_t empty_field; uint16_t class_definitions; uint16_t array_of_unknow1_fields[14]; uint16_t aliases; uint16_t array_of_unknow2_fields[22]; } ATTRIBUTE_PACKED data_header_t; #if USE_PACK_PRAGMA #pragma pack(pop) #endif #endif barry-0.18.5/src/time.h0000644001161500056700000000547412242254476014164 0ustar cdfreycdfrey/// /// \file time.h /// Time related conversion routines. /// time_t is the POSIX time. /// min1900_t is the minutes from Jan 1, 1900 /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_TIME_H__ #define __BARRY_TIME_H__ #include "dll.h" #include // for struct timespec #include #include // // Calculate the number of minutes between Jan 01, 1900 and Jan 01, 1970 // // There are 17 leap years between 1900 and 1970 // (1969-1900) / 4 = 17.25 // // 1900 itself is not a leap year (not divisible by 400) // #define DAY_MINUTES (24 * 60) #define YEAR_MINUTES (365 * DAY_MINUTES) #define LEAP_YEAR_COUNT ((1970-1901) / 4) #define YEAR_COUNT (1970 - 1900) // therefore, the difference between standard C's time and min1900_t's // time in minutes: #define STDC_MIN1900_DIFF (YEAR_COUNT * YEAR_MINUTES + LEAP_YEAR_COUNT * DAY_MINUTES) namespace Barry { typedef long min1900_t; BXEXPORT min1900_t time2min(time_t t); BXEXPORT time_t min2time(min1900_t m); // FIXME - turn StaticTimeZone into a C typedef and wrap this in extern "C" // so the data can be used in both C and C++ libraries // // This is named StaticTimeZone since the time zone table is hard coded // in the library. If you want to know what the device's idea of time zones // is, then extract the time zone database using the TimeZone record class. // // See also the TimeZones class, which unifies access to the static and // dynamic time zone tables in one class API. // struct BXEXPORT StaticTimeZone { uint16_t Code; signed short HourOffset; signed short MinOffset; const char *Name; }; // FIXME - put this somewhere for both C and C++ #define STATIC_TIME_ZONE_CODE_ERR 0xffff BXEXPORT const StaticTimeZone* GetStaticTimeZoneTable(); BXEXPORT const StaticTimeZone* GetStaticTimeZone(uint16_t Code); BXEXPORT unsigned short GetStaticTimeZoneCode(signed short HourOffset, signed short MinOffset = 0); // Message time conversion stuff BXEXPORT time_t DayToDate( uint16_t Day ); BXEXPORT time_t Message2Time(uint16_t r_date, uint16_t r_time); // Thread timeout creation BXEXPORT struct timespec* ThreadTimeout(int timeout_ms, struct timespec *spec); // Utility functions BXEXPORT int DaysInMonth(struct tm &t); } // namespace Barry #endif barry-0.18.5/src/trim.h0000644001161500056700000000221512242254476014167 0ustar cdfreycdfrey// Found at: // http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring // Note that these functions trim the same arguments passed in, and do not // make copies. #ifndef __BARRY_TRIM_H__ #define __BARRY_TRIM_H__ #include #include #include #include namespace Barry { namespace Inplace { // Windows CE defines std::isspace(int) as a macro to a function with // two arguments with one prefilled, so a wrapper function is needed. static inline int isSpaceChar(int c) { return std::isspace(c); } // trim from start static inline std::string <rim(std::string &s) { std::string::iterator end(std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(isSpaceChar)))); s.erase(s.begin(), end); return s; } // trim from end static inline std::string &rtrim(std::string &s) { std::string::reverse_iterator start(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(isSpaceChar)))); s.erase(start.base(), s.end()); return s; } // trim from both ends static inline std::string &trim(std::string &s) { return ltrim(rtrim(s)); } }} // namespace Barry::Inplace #endif barry-0.18.5/src/vtodo.cc0000644001161500056700000001725712242254476014521 0ustar cdfreycdfrey/// /// \file vtodo.cc /// Conversion routines for vtodos (VCALENDAR, etc) /// /* Copyright (C) 2008-2009, Nicolas VIVIEN Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "vtodo.h" //#include "trace.h" #include #include #include #include #include namespace Barry { namespace Sync { ////////////////////////////////////////////////////////////////////////////// // Utility functions namespace { static void ToLower(std::string &str) { size_t i = 0; while( i < str.size() ) { str[i] = tolower(str[i]); i++; } } } ////////////////////////////////////////////////////////////////////////////// // vTodo vTodo::vTodo(vTimeConverter &vtc) : m_vtc(vtc) , m_gTodoData(0) { } vTodo::~vTodo() { if( m_gTodoData ) { g_free(m_gTodoData); } } bool vTodo::HasMultipleVTodos() const { int count = 0; b_VFormat *format = const_cast(Format()); GList *attrs = format ? b_vformat_get_attributes(format) : 0; for( ; attrs; attrs = attrs->next ) { b_VFormatAttribute *attr = (b_VFormatAttribute*) attrs->data; if( strcasecmp(b_vformat_attribute_get_name(attr), "BEGIN") == 0 && strcasecmp(b_vformat_attribute_get_nth_value(attr, 0), "VTODO") == 0 ) { count++; } } return count > 1; } // Main conversion routine for converting from Barry::Task to // a vTodo string of data. const std::string& vTodo::ToTask(const Barry::Task &task) { // Trace trace("vTodo::ToTask"); std::ostringstream oss; task.Dump(oss); // trace.logf("ToTask, initial Barry record: %s", oss.str().c_str()); // start fresh Clear(); SetFormat( b_vformat_new() ); if( !Format() ) throw ConvertError(_("resource error allocating vformat")); // store the Barry object we're working with m_BarryTask = task; // RFC section 4.8.7.2 requires DTSTAMP in all VEVENT, VTODO, // VJOURNAL, and VFREEBUSY calendar components, and it must be // in UTC. DTSTAMP holds the timestamp of when the iCal object itself // was created, not when the object was created in the device or app. // So, find out what time it is "now". time_t now = time(NULL); // begin building vCalendar data AddAttr(NewAttr("PRODID", "-//OpenSync//NONSGML Barry Task Record//EN")); AddAttr(NewAttr("BEGIN", "VTODO")); AddAttr(NewAttr("DTSTAMP", m_vtc.unix2vtime(&now).c_str())); // see note above AddAttr(NewAttr("SEQUENCE", "0")); AddAttr(NewAttr("SUMMARY", task.Summary.c_str())); AddAttr(NewAttr("DESCRIPTION", task.Notes.c_str())); AddAttr(NewAttr("CATEGORIES", ToStringList(task.Categories).c_str())); // Status if (task.StatusFlag == Barry::Task::InProgress) AddAttr(NewAttr("STATUS", "IN-PROCESS")); else if (task.StatusFlag == Barry::Task::Completed) AddAttr(NewAttr("STATUS", "COMPLETED")); else if (task.StatusFlag == Barry::Task::Deferred) AddAttr(NewAttr("STATUS", "CANCELLED")); else if (task.StatusFlag == Barry::Task::Waiting) AddAttr(NewAttr("STATUS", "NEEDS-ACTION")); // Priority if (task.PriorityFlag == Barry::Task::High) AddAttr(NewAttr("PRIORITY", "3")); else if (task.PriorityFlag == Barry::Task::Normal) AddAttr(NewAttr("PRIORITY", "5")); else AddAttr(NewAttr("PRIORITY", "7")); // StartTime if( task.StartTime.Time ) { AddAttr(NewAttr("DTSTART", m_vtc.unix2vtime(&task.StartTime.Time).c_str())); } // DueTime DueFlag if( task.DueTime.IsValid() ) { AddAttr(NewAttr("DUE", m_vtc.unix2vtime(&task.DueTime.Time).c_str())); } // FIXME - add a truly globally unique "UID" string? AddAttr(NewAttr("END", "VTODO")); // generate the raw VTODO data m_gTodoData = b_vformat_to_string(Format(), VFORMAT_TODO_20); m_vTodoData = m_gTodoData; // trace.logf("ToTask, resulting vtodo data: %s", m_vTodoData.c_str()); return m_vTodoData; } // Main conversion routine for converting from vTodo data string // to a Barry::Task object. const Barry::Task& vTodo::ToBarry(const char *vtodo, uint32_t RecordId) { using namespace std; // Trace trace("vTodo::ToBarry"); // trace.logf("ToBarry, working on vtodo data: %s", vtodo); // we only handle vTodo data with one vtodo block if( HasMultipleVTodos() ) throw ConvertError(_("vCalendar data contains more than one VTODO block, unsupported")); // start fresh Clear(); // store the vTodo raw data m_vTodoData = vtodo; // create format parser structures SetFormat( b_vformat_new_from_string(vtodo) ); if( !Format() ) throw ConvertError(_("resource error allocating vtodo")); string summary = GetAttr("SUMMARY", "/vtodo"); // trace.logf("SUMMARY attr retrieved: %s", summary.c_str()); if( summary.size() == 0 ) { summary = ""; // trace.logf("ERROR: bad data, blank SUMMARY: %s", vtodo); } string notes = GetAttr("DESCRIPTION", "/vtodo"); // trace.logf("DESCRIPTION attr retrieved: %s", notes.c_str()); string status = GetAttr("STATUS", "/vtodo"); // trace.logf("STATUS attr retrieved: %s", status.c_str()); string priority = GetAttr("PRIORITY", "/vtodo"); // trace.logf("PRIORITY attr retrieved: %s", priority.c_str()); string start = GetAttr("DTSTART", "/vtodo"); // trace.logf("DTSTART attr retrieved: %s", start.c_str()); string due = GetAttr("DUE", "/vtodo"); // trace.logf("DUE attr retrieved: %s", due.c_str()); // // Now, run checks and convert into Barry object // // FIXME - we are assuming that any non-UTC timestamps // in the vcalendar record will be in the current timezone... // This is wrong! fix this later. // // Also, we current ignore any time zone // parameters that might be in the vcalendar format... this // must be fixed. // Barry::Task &rec = m_BarryTask; rec.SetIds(Barry::Task::GetDefaultRecType(), RecordId); // Categories rec.Categories = GetValueVector("CATEGORIES","/vtodo"); // SUMMARY & DESCRIPTION fields rec.Summary = summary; rec.Notes = notes; // STATUS field if (status.size()) { ToLower(status); const char *s = status.c_str(); if (strstr(s, "in-process")) rec.StatusFlag = Barry::Task::InProgress; else if (strstr(s, "completed")) rec.StatusFlag = Barry::Task::Completed; else if (strstr(s, "cancelled")) rec.StatusFlag = Barry::Task::Deferred; else if (strstr(s, "needs-action")) rec.StatusFlag = Barry::Task::Waiting; else rec.StatusFlag = Barry::Task::NotStarted; } // PRIORITY field if (priority.size()) { ToLower(priority); const char *s = priority.c_str(); const int val = atoi(s); if (val < 4) rec.PriorityFlag = Barry::Task::High; else if (val < 7) rec.PriorityFlag = Barry::Task::Normal; else rec.PriorityFlag = Barry::Task::Low; } // STARTTIME & DUETIME if (start.size()) { rec.StartTime.Time = m_vtc.vtime2unix(start.c_str()); } if (due.size()) { rec.DueTime.Time = m_vtc.vtime2unix(due.c_str()); } std::ostringstream oss; m_BarryTask.Dump(oss); // trace.logf("ToBarry, resulting Barry record: %s", oss.str().c_str()); return m_BarryTask; } // Transfers ownership of m_gTaskData to the caller. char* vTodo::ExtractVTodo() { char *ret = m_gTodoData; m_gTodoData = 0; return ret; } void vTodo::Clear() { vBase::Clear(); m_vTodoData.clear(); m_BarryTask.Clear(); if( m_gTodoData ) { g_free(m_gTodoData); m_gTodoData = 0; } } }} // namespace Barry::Sync barry-0.18.5/src/ldifio.cc0000644001161500056700000000420712242254476014623 0ustar cdfreycdfrey/// /// \file ldifio.cc /// Storage, parser, and builder classes for ldif operations. /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "ldifio.h" namespace Barry { LdifStore::LdifStore(const std::string &filename) : m_ifs( new std::ifstream(filename.c_str()) ) , m_is(*m_ifs) , m_os(*m_ofs) // yes, this is a reference to a null ptr // but will never be used (see below as well) , m_end_of_file(false) , m_ldif("") { } LdifStore::LdifStore(std::istream &is) : m_is(is) , m_os(*m_ofs) , m_end_of_file(false) , m_ldif("") { } // output constructors LdifStore::LdifStore(const std::string &filename, const std::string &baseDN, const std::string &dnattr) : m_ofs( new std::ofstream(filename.c_str()) ) , m_is(*m_ifs) , m_os(*m_ofs) , m_end_of_file(false) , m_ldif(baseDN) { m_ldif.SetDNAttr(dnattr); } LdifStore::LdifStore(std::ostream &os, const std::string &baseDN, const std::string &dnattr) : m_is(*m_ifs) , m_os(os) , m_end_of_file(false) , m_ldif(baseDN) { m_ldif.SetDNAttr(dnattr); } // storage operator void LdifStore::operator() (const Contact &rec) { m_ldif.DumpLdif(m_os, rec); } // retrieval operator bool LdifStore::operator() (Contact &rec, const Barry::Builder &builder) { if( m_end_of_file ) return false; // there may be LDIF records in the input that generate // invalid Contact records, but valid Contact records // may come after.. so keep processing until end of stream while( m_is ) { if( m_ldif.ReadLdif(m_is, rec) ) return true; } m_end_of_file = true; return false; } } // namespace Barry barry-0.18.5/src/r_timezone.cc0000644001161500056700000002442412242254476015533 0ustar cdfreycdfrey/// /// \file r_timezone.cc /// Record parsing class for the timezone database. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2008, Brian Edginton 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "r_timezone.h" #include "record-internal.h" #include "protostructs.h" #include "data.h" #include "time.h" #include "iconv.h" #include "debug.h" #include #include #include #include "ios_state.h" #include #include "m_desktop.h" using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // TimeZone Class // TimeZone Field Codes #define TZFC_INDEX 0x01 #define TZFC_NAME 0x02 #define TZFC_OFFSET 0x03 #define TZFC_DST 0x04 #define TZFC_STARTMONTH 0x06 #define TZFC_ENDMONTH 0x0B #define TZFC_TZTYPE 0x64 #define TZFC_END 0xffff static FieldLink TimeZoneFieldLinks[] = { { TZFC_NAME, N_("Name"), 0, 0, &TimeZone::Name, 0, 0, 0, 0, true }, { TZFC_END, N_("End of List"), 0, 0, 0, 0, 0, 0, 0, false }, }; TimeZone::TimeZone() { Clear(); } TimeZone::TimeZone(int utc_offset) { Clear(); UTCOffset = utc_offset; } TimeZone::TimeZone(int hours, int minutes) { Clear(); // make sure that minutes are always positive, for our logic if( minutes < 0 ) minutes = -minutes; // calculate offset in total minutes UTCOffset = hours * 60; if( hours < 0 ) UTCOffset -= minutes; else UTCOffset += minutes; } TimeZone::~TimeZone() { } const unsigned char* TimeZone::ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { const CommonField *field = (const CommonField *) begin; // advance and check size begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size); if( begin > end ) // if begin==end, we are ok return begin; if( !btohs(field->size) ) // if field has no size, something's up return begin; if( field->type == TZFC_TZTYPE ) { if( ( TZType = field->u.uint32 ) != 1 ) { throw Error(_("TimeZone::ParseField: TimeZone Type is not valid")); } return begin; } // cycle through the type table for( FieldLink *b = TimeZoneFieldLinks; b->type != TZFC_END; b++ ) { if( b->type == field->type ) { if( b->strMember ) { std::string &s = this->*(b->strMember); s = ParseFieldString(field); if( b->iconvNeeded && ic ) s = ic->FromBB(s); return begin; // done! } } } switch( field->type ) { case TZFC_INDEX: Index = btohl(field->u.uint32); return begin; case TZFC_OFFSET: UTCOffset = btohs(field->u.int16); return begin; case TZFC_DST: DSTOffset = btohl(field->u.uint32); if (DSTOffset) { UseDST = true; } return begin; case TZFC_STARTMONTH: StartMonth = btohl(field->u.uint32); return begin; case TZFC_ENDMONTH: EndMonth = btohl(field->u.uint32); return begin; } // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; uf.data.assign((const char*)field->u.raw, btohs(field->size)); Unknowns.push_back(uf); // return new pointer for next field return begin; } void TimeZone::ParseHeader(const Data &data, size_t &offset) { // no header in Task records } void TimeZone::ParseFields(const Data &data, size_t &offset, const IConverter *ic) { const unsigned char *finish = ParseCommonFields(*this, data.GetData() + offset, data.GetData() + data.GetSize(), ic); offset += finish - (data.GetData() + offset); } void TimeZone::Validate() const { } void TimeZone::BuildHeader(Data &data, size_t &offset) const { // not yet implemented } void TimeZone::BuildFields(Data &data, size_t &offset, const IConverter *ic) const { // not yet implemented } void TimeZone::Clear() { RecType = GetDefaultRecType(); RecordId = 0; Name.clear(); Index = 0; UTCOffset = 0; UseDST = false; DSTOffset = 0; StartMonth = -1; EndMonth = -1; TZType = 0; Unknowns.clear(); } const FieldHandle::ListT& TimeZone::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; #undef CONTAINER_OBJECT_NAME #define CONTAINER_OBJECT_NAME fhv #undef RECORD_CLASS_NAME #define RECORD_CLASS_NAME TimeZone FHP(RecType, _("Record Type Code")); FHP(RecordId, _("Unique Record ID")); FHD(Name, _("TimeZone Name"), TZFC_NAME, true); FHD(Index, _("Index"), TZFC_INDEX, false); FHD(UTCOffset, _("TimeZone Offset in Minutes"), TZFC_OFFSET, false); FHD(UseDST, _("Use DST?"), TZFC_DST, false); FHD(DSTOffset, _("DST Offset"), TZFC_DST, false); FHD(StartMonth, _("Start Month"), TZFC_STARTMONTH, false); FHD(EndMonth, _("End Month"), TZFC_ENDMONTH, false); FHD(TZType, _("TimeZone Type"), TZFC_TZTYPE, false); FHP(Unknowns, _("Unknown Fields")); return fhv; } std::string TimeZone::GetDescription() const { ostringstream oss; oss << Name << " (" << (UTCOffset > 0 ? "+" : "") << dec << (UTCOffset / 60.0) << ")"; return oss.str(); } void TimeZone::Dump(std::ostream &os) const { ios_format_state state(os); static const char *month[] = { N_("Jan"), N_("Feb"), N_("Mar"), N_("Apr"), N_("May"), N_("Jun"), N_("Jul"), N_("Aug"), N_("Sep"), N_("Oct"), N_("Nov"), N_("Dec") }; os << _("TimeZone entry: ") << "0x" << setbase(16) << RecordId << " (" << (unsigned int)RecType << ")\n"; // cycle through the type table for( const FieldLink *b = TimeZoneFieldLinks; b->type != TZFC_END; b++ ) { if( b->strMember ) { const std::string &s = this->*(b->strMember); if( s.size() ) os << " " << b->name << ": " << s << "\n"; } } int hours, minutes; Split(&hours, &minutes); os << _(" Desc: ") << GetDescription() << "\n"; os << _(" Index: ") << "0x" < 0) && (StartMonth < 11)) os << _("Start Month: ") << gettext(month[StartMonth]) << "\n"; else os << _("Start Month: unknown (") << setbase(10) << StartMonth << ")\n"; if ((EndMonth > 0) && (EndMonth < 11)) os << _(" End Month: ") << gettext(month[EndMonth]) << "\n"; else os << _(" End Month: unknown (") << setbase(10) << EndMonth << ")\n"; } os << Unknowns; os << "\n\n"; } void TimeZone::Split(int *hours, int *minutes) const { *hours = UTCOffset / 60; *minutes = UTCOffset % 60; if( *minutes < 0 ) *minutes = -*minutes; } void TimeZone::SplitAbsolute(bool *west, unsigned int *hours, unsigned int *minutes) const { int tmphours, tmpminutes; Split(&tmphours, &tmpminutes); if( tmphours < 0 ) { *west = true; tmphours = -tmphours; } else { *west = false; } *hours = tmphours; *minutes = tmpminutes; } std::string TimeZone::GetTz(const std::string &prefix) const { int hours, minutes; Split(&hours, &minutes); // TZ variable uses positive for west, and negative for east, // so swap the hour value. Minutes is always positive for // our purposes, so leave it alone. hours = -hours; // standard time first ostringstream oss; oss << prefix << "ST" << hours << ":" << setfill('0') << setw(2) << minutes << ":00"; // daylight saving time next, if available if( UseDST ) { TimeZone dst(UTCOffset + DSTOffset); dst.Split(&hours, &minutes); // swap again for TZ semantics... hours = -hours; oss << prefix << "DT" << hours << ":" << setfill('0') << setw(2) << minutes << ":00"; // assume second Sunday of start month to first Sunday of // end month, since we don't have enough data to be more // precise oss << ",M" << (StartMonth + 1) << ".2.0"; oss << ",M" << (EndMonth + 1) << ".1.0"; } return oss.str(); } /////////////////////////////////////////////////////////////////////////////// // TimeZones Class TimeZones::TimeZones() { const StaticTimeZone *zones = GetStaticTimeZoneTable(); for( ; zones->Name; zones++ ) { TimeZone tz(zones->HourOffset, zones->MinOffset); tz.Index = zones->Code; tz.Name = gettext( zones->Name ); m_list.push_back(tz); } sort(begin(), end(), &TimeZone::SortByZone); } struct TimeZoneStore { TimeZones::ListType &m_list; TimeZoneStore(TimeZones::ListType &list) : m_list(list) { } void operator()(const TimeZone &rec) { m_list.push_back(rec); } }; TimeZones::TimeZones(Barry::Mode::Desktop &desktop) { unsigned int dbId = desktop.GetDBID( TimeZone::GetDBName() ); TimeZoneStore store(m_list); RecordParser parser(store); desktop.LoadDatabase(dbId, parser); sort(begin(), end(), &TimeZone::SortByZone); } bool TimeZones::IsLoadable(Barry::Mode::Desktop &desktop) { unsigned int num; return desktop.GetDBDB().GetDBNumber(TimeZone::GetDBName(), num); } TimeZones::iterator TimeZones::Find(int index) { for( iterator i = begin(), e = end(); i != e; ++i ) if( i->Index == index ) return i; return end(); } TimeZones::const_iterator TimeZones::Find(int index) const { return const_cast(this)->Find(index); } TimeZones::iterator TimeZones::FindByOffset(int utc_offset) { for( iterator i = begin(), e = end(); i != e; ++i ) if( i->UTCOffset == utc_offset ) return i; return end(); } TimeZones::const_iterator TimeZones::FindByOffset(int utc_offset) const { return const_cast(this)->FindByOffset(utc_offset); } void TimeZones::Dump(std::ostream &os) const { const_iterator b = begin(), e = end(); for( ; b != e; ++b ) { os << *b << endl; } } } // namespace Barry barry-0.18.5/src/getpwuidandroid.cc0000644001161500056700000000400412242254476016541 0ustar cdfreycdfrey/// /// \file getpwuidandroid.cc /// Replacements for getpwuid*() calls on Android /// /* Copyright (C) 2011, RealVNC Ltd. 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 in the COPYING file at the root directory of this project for more details. */ #include "getpwuid.h" #include #include #define SDCARD_PATH "/mnt/sdcard" static void fillInData(uid_t uid, char* emptyString, char* sdcardPath, struct barry_passwd* pwd) { pwd->pw_name = emptyString; pwd->pw_passwd = emptyString; pwd->pw_uid = uid; pwd->pw_gid = 0; pwd->pw_gecos = emptyString; // This is the important value for Barry, as it's where to store // config files. // // For Android the best place is probably on the sdcard, as then // it doesn't matter which application is calling it, as long // as it has android.permission.WRITE_EXTERNAL_STORAGE pwd->pw_dir = sdcardPath; pwd->pw_shell = emptyString; } extern "C" struct barry_passwd *barry_getpwuid(uid_t uid) { static char emptyString[1] = {0}; static char sdcardString[sizeof(SDCARD_PATH)] = SDCARD_PATH; static struct barry_passwd gPasswdStruct; fillInData(uid, emptyString, sdcardString, &gPasswdStruct); return &gPasswdStruct; } extern "C" int barry_getpwuid_r(uid_t uid, struct barry_passwd *pwd, char *buf, size_t buflen, struct barry_passwd **result) { if (buflen < sizeof(SDCARD_PATH)) return ERANGE; memcpy(buf, SDCARD_PATH, sizeof(SDCARD_PATH)); // Point all the empty entries at the '\0' at the end of the buffer fillInData(uid, buf + sizeof(SDCARD_PATH) - 1, buf, pwd); *result = pwd; return 0; } barry-0.18.5/src/xmlparser.h0000644001161500056700000000345212242254476015235 0ustar cdfreycdfrey/// /// \file xmlparser.h /// A simple XML parser (use callback on start, end and data block /// /* Copyright (C) 2010, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __XMLPARSER_H__ #define __XMLPARSER_H__ #include #include "dll.h" #include "a_common.h" namespace Barry { namespace XML { class BXEXPORT XMLParser : public xmlpp::SaxParser { public: XMLParser(std::istream& input, const char *charset="UTF-8"); virtual ~XMLParser(void); virtual bool Run(void); virtual const unsigned long GetDepth(void) const; protected: std::string charset; std::istream& input; unsigned long depth; // SaxParser overrides: virtual void on_start_document(); virtual void on_end_document(); virtual void on_start_element(const Glib::ustring& name, const xmlpp::SaxParser::AttributeList& properties); virtual void on_end_element(const Glib::ustring& name); virtual void on_characters(const Glib::ustring& characters); virtual void on_comment(const Glib::ustring& text); virtual void on_warning(const Glib::ustring& text); virtual void on_error(const Glib::ustring& text); virtual void on_fatal_error(const Glib::ustring& text); }; } // namespace XML } // namespace Barry #endif barry-0.18.5/src/r_folder.h0000644001161500056700000000547312242254476015021 0ustar cdfreycdfrey/// /// \file r_folder.h /// Record parsing class for the Folder database. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2007, Brian Edginton 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_FOLDER_H__ #define __BARRY_RECORD_FOLDER_H__ #include "dll.h" #include "record.h" #include #include #include namespace Barry { // forward declarations class IConverter; class BXEXPORT Folder { public: typedef Barry::UnknownsType UnknownsType; uint8_t RecType; uint32_t RecordId; std::string Name; uint16_t Number; // Not unique, used for ordering of subfolders - NOT level uint16_t Level; // From parent enum FolderType { FolderSubtree = 0, FolderDeleted, FolderInbox, FolderOutbox, FolderSent, FolderOther, FolderDraft = 0x0a }; FolderType Type; enum FolderStatusType { FolderOrphan = 0x50, FolderUnfiled, FolderFiled }; UnknownsType Unknowns; protected: static FolderType TypeProto2Rec(uint8_t t); static uint8_t TypeRec2Proto(FolderType t); public: Folder(); ~Folder(); // Parser / Builder API (see parser.h / builder.h) void Validate() const; const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); uint8_t GetRecType() const { return RecType; } uint32_t GetUniqueId() const { return RecordId; } void SetIds(uint8_t Type, uint32_t Id) { RecType = Type; RecordId = Id; } void ParseHeader(const Data &data, size_t &offset); void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); void BuildHeader(Data &data, size_t &offset) const; void BuildFields(Data &data, size_t &offset, const IConverter *ic = 0) const; // operations (common among record classes) void Clear(); void Dump(std::ostream &os) const; std::string GetDescription() const; bool operator<(const Folder &other) const { return Name < other.Name; } // database name static const char * GetDBName() { return "Folders"; } static uint8_t GetDefaultRecType() { return 0; } // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const Folder &msg) { msg.Dump(os); return os; } } // namespace Barry #endif // __BARRY_RECORD_FOLDER_H__ barry-0.18.5/src/a_library.cc0000644001161500056700000000341412242254476015320 0ustar cdfreycdfrey/// /// \file a_library.cc /// ALX Library class based on CODSection class /// /* Copyright (C) 2010, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include #include #include #include "a_library.h" #include "ios_state.h" namespace Barry { namespace ALX { Library::Library(void) : CODSection() { } Library::Library(const xmlpp::SaxParser::AttributeList& attrs) : CODSection(attrs) { } Library::~Library(void) { } void Library::Dump(std::ostream &os) const { ios_format_state state(os); os << _(" Library ") << name << " - " << version << std::endl; os << _(" ID : ") << id << std::endl; os << _(" Description : ") << description << std::endl; os << _(" Vendor : ") << vendor << std::endl; os << _(" Copyright : ") << copyright << std::endl; os << _(" Required : ") << (isRequired ? _("Yes") : _("No")) << std::endl; std::vector::const_iterator b = codfiles.begin(), e = codfiles.end(); os << _(" Files : ") << std::endl; for (; b != e; b++) os << " - " << directory << "/" << (*b) << std::endl; } } // namespace ALX } // namespace Barry barry-0.18.5/src/j_message.cc0000644001161500056700000000317312242254476015313 0ustar cdfreycdfrey/// /// \file j_message.cc /// JDWP USB message implementation /// /* Copyright (C) 2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #include "j_message.h" #include "debug.h" #include "data.h" namespace Barry { namespace JDWP { JDWMessage::JDWMessage(int socket) : m_socket(socket) { } JDWMessage::~JDWMessage() { } void JDWMessage::RawSend(Data &send, int timeout) { bool ret = m_jdwp.Write(m_socket, send, timeout); if (ret) barryverbose("JDWMessage::RawSend: Socket ID " << m_socket << "\nSent:\n" << send); } bool JDWMessage::RawReceive(Data &receive, int timeout) { bool ret; ret = m_jdwp.Read(m_socket, receive, timeout); if (ret) barryverbose("JDWMessage::RawReceive: Socket ID " << m_socket << "\nReceived:\n" << receive); return ret; } void JDWMessage::Send(Data &send, int timeout) { RawSend(send, timeout); } void JDWMessage::Send(Data &send, Data &receive, int timeout) { RawSend(send, timeout); RawReceive(receive, timeout); } bool JDWMessage::Receive(Data &receive, int timeout) { return RawReceive(receive, timeout); } }} // namespace Barry::JDWP barry-0.18.5/src/a_codsection.cc0000644001161500056700000000555012242254476016011 0ustar cdfreycdfrey/// /// \file a_codsection.cc /// COD structure for the ALX file parser /// /* Copyright (C) 2010, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include #include #include #include "a_codsection.h" namespace Barry { namespace { std::string trim(const std::string &str) { int i; int start, end; std::string s; const int len = str.size(); // ltrim for (i=0; (((str[i]==' ') || (str[i]=='\t') || (str[i]=='\r') || (str[i]=='\n')) && (i=0)); i--); end = i+1; s = str.substr(start, end-start); return s; } } namespace ALX { CODSection::CODSection(void) { isRequired = false; } CODSection::CODSection(const xmlpp::SaxParser::AttributeList& attrs) { isRequired = false; for (xmlpp::SaxParser::AttributeList::const_iterator iter = attrs.begin(); iter != attrs.end(); ++iter) { std::string attribut(iter->name); std::string value(iter->value); if (attribut == "id") SetID(value); } } CODSection::~CODSection(void) { isRequired = false; } void CODSection::SetID(const std::string& id) { this->id = id; } void CODSection::SetName(const std::string& name) { this->name = trim(name); } void CODSection::SetDescription(const std::string& description) { this->description = trim(description); } void CODSection::SetVersion(const std::string& version) { this->version = trim(version); } void CODSection::SetVendor(const std::string& vendor) { this->vendor = trim(vendor); } void CODSection::SetCopyright(const std::string& copyright) { this->copyright = trim(copyright); } void CODSection::SetDirectory(const std::string& directory) { this->directory = trim(directory); } void CODSection::SetRequired(const std::string& required) { std::string s = trim(required); if (s == "true") isRequired = true; else isRequired = false; } void CODSection::AddFiles(const std::string& files) { std::string file; std::istringstream iss(files); while( std::getline(iss, file) ) { file = trim(file); if (file.length() > 0) AddFile(file); } } void CODSection::AddFile(const std::string& file) { codfiles.push_back(file); } } // namespace ALX } // namespace Barry barry-0.18.5/src/configfile.cc0000644001161500056700000002445212242254476015466 0ustar cdfreycdfrey/// /// \file configfile.cc /// Barry configuraion class, for one device PIN /// /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "configfile.h" #include "error.h" #include "r_message.h" #include #include #include #include #include #include #include #include namespace Barry { bool ConfigFile::DBListType::IsSelected(const std::string &dbname) const { const_iterator i = begin(); for( ; i != end(); ++i ) { if( *i == dbname ) { return true; } } return false; } std::ostream& operator<< (std::ostream &os, const ConfigFile::DBListType &list) { os << _("DBListType dump:\n"); for( ConfigFile::DBListType::const_iterator i = list.begin(); i != list.end(); ++i ) { os << " " << *i << "\n"; } return os; } ////////////////////////////////////////////////////////////////////////////// // ConfigFile class members /// Loads config file for the given pin, and ends up in an /// unenlightened state. Throws ConfigFileError on error, /// but it is not an error if the config does not exist. /// Never use this if you have a DatabaseDatabase object! /// This ctor is only for temporary loading of config data. ConfigFile::ConfigFile(Barry::Pin pin) : m_pin(pin) , m_loaded(false) , m_promptBackupLabel(false) , m_autoSelectAll(false) { if( m_pin == 0 ) throw ConfigFileError(_("Configfile: empty pin")); BuildFilename(); BuildDefaultPath(); // this handles the situation that path is not set Load(); } /// Opens and loads config file for given pin, and calls Enlighten /// Throws ConfigFileError on error. Should never fail unless /// passed a bad pin. ConfigFile::ConfigFile(Barry::Pin pin, const Barry::DatabaseDatabase &db) : m_pin(pin) , m_loaded(false) , m_promptBackupLabel(false) , m_autoSelectAll(false) { if( m_pin == 0 ) throw ConfigFileError(_("Configfile: empty pin")); BuildFilename(); BuildDefaultPath(); Load(); Enlighten(db); } ConfigFile::~ConfigFile() { } void ConfigFile::Clear() { m_loaded = false; m_backupList.clear(); m_restoreList.clear(); m_deviceName.clear(); m_promptBackupLabel = false; m_autoSelectAll = false; } /// Attempt to load the configuration file, but do not fail if not available void ConfigFile::Load() { // start fresh Clear(); // open input file std::ifstream in(m_filename.c_str(), std::ios::in | std::ios::binary); if( !in ) return; std::string line; DBListType *pList = 0; while( std::getline(in, line) ) { std::string keyword; std::istringstream iss(line); iss >> keyword; if( keyword == "backup_list" ) { pList = &m_backupList; } else if( keyword == "restore_list" ) { pList = &m_restoreList; } else if( line[0] == ' ' && pList ) { pList->push_back(line.c_str() + 1); } else { pList = 0; // add all remaining keyword checks here if( keyword == "device_name" ) { iss >> std::ws; std::getline(iss, m_deviceName); if( m_deviceName.size() == 0 ) { // if there is a device_name setting, // then this value must hold something, // so that the user can ignore this // field, and not get pestered all // the time m_deviceName = " "; } } else if( keyword == "backup_path" ) { iss >> std::ws; std::getline(iss, m_path); if( (m_path.size() == 0) || !(CheckPath(m_path))) BuildDefaultPath(); } else if( keyword == "prompt_backup_label" ) { int flag; iss >> flag; m_promptBackupLabel = flag != 0; } else if( keyword == "auto_select_all" ) { int flag; iss >> flag; m_autoSelectAll = flag != 0; } } } m_loaded = true; } /// Saves current device's config, overwriting or creating a config file bool ConfigFile::Save() { using namespace std; if( !CheckPath(m_path, &m_last_error) ) return false; ofstream out(m_filename.c_str(), std::ios::out | std::ios::binary); if( !out ) { m_last_error = _("Unable to open file for writing: ") + m_filename; return false; } out << "backup_list" << endl; for( DBListType::iterator i = m_backupList.begin(); i != m_backupList.end(); ++i ) { out << " " << *i << endl; } out << "restore_list" << endl; for( DBListType::iterator i = m_restoreList.begin(); i != m_restoreList.end(); ++i ) { out << " " << *i << endl; } if( m_deviceName.size() ) { out << "device_name " << m_deviceName << endl; } if( m_path.size() ) { out << "backup_path " << m_path << endl; } out << "prompt_backup_label " << (m_promptBackupLabel ? 1 : 0) << endl; out << "auto_select_all " << (m_autoSelectAll ? 1 : 0) << endl; if( !out ) { m_last_error = _("Error during write. Config may be incomplete."); return false; } return true; } /// Compares a given databasedatabase from a real device with the /// current config. If not yet configured, initialize with valid /// defaults. void ConfigFile::Enlighten(const Barry::DatabaseDatabase &db) { if( !m_loaded ) { // if not fully loaded, we use db as our default list // our defaults are: backup everything, restore everything // except email m_backupList.clear(); m_restoreList.clear(); Barry::DatabaseDatabase::DatabaseArrayType::const_iterator i = db.Databases.begin(); for( ; i != db.Databases.end(); ++i ) { // backup everything m_backupList.push_back(i->Name); // restore everything except email (which could take ages) // and Handheld Agent (which seems write protected) if( i->Name != Barry::Message::GetDBName() && i->Name != "Handheld Agent" ) { m_restoreList.push_back(i->Name); } } } } // fill list with all databases from dbdb ConfigFile:: DBListType& ConfigFile::DBListType::operator=(const DatabaseDatabase &dbdb) { // start empty clear(); // copy over all DB names DatabaseDatabase::DatabaseArrayType::const_iterator i = dbdb.Databases.begin(), e = dbdb.Databases.end(); for( ; i != e; ++i ) { push_back(i->Name); } return *this; } /// Sets list with new config void ConfigFile::SetBackupList(const DBListType &list) { m_backupList = list; m_loaded = true; } void ConfigFile::SetRestoreList(const DBListType &list) { m_restoreList = list; m_loaded = true; } void ConfigFile::SetDeviceName(const std::string &name) { if( name.size() ) m_deviceName = name; else m_deviceName = " "; } void ConfigFile::SetBackupPath(const std::string &path) { if( path.size() && CheckPath(path) ) m_path = path; else BuildDefaultPath(); } void ConfigFile::SetPromptBackupLabel(bool prompt) { m_promptBackupLabel = prompt; } void ConfigFile::SetAutoSelectAll(bool asa) { m_autoSelectAll = asa; } ////////////////////////////////////////////////////////////////////////////// // GlobalConfigFile class members GlobalConfigFile::GlobalConfigFile() : m_loaded(false) , m_verboseLogging(false) { BuildFilename(); Load(); } GlobalConfigFile::GlobalConfigFile(const std::string &appname) : m_loaded(false) , m_appname(appname) , m_verboseLogging(false) { // there can be no spaces in the appname if( m_appname.find(' ') != std::string::npos ) throw std::logic_error(_("App name must have no spaces.")); BuildFilename(); Load(); } GlobalConfigFile::~GlobalConfigFile() { } void GlobalConfigFile::Clear() { m_loaded = false; m_lastDevice = 0; } void GlobalConfigFile::Load() { // start fresh Clear(); // open input file std::ifstream in(m_filename.c_str(), std::ios::in | std::ios::binary); if( !in ) return; std::string line; while( std::getline(in, line) ) { std::string keyword; std::istringstream iss(line); iss >> keyword; if( keyword == "last_device" ) { iss >> std::ws; m_lastDevice.Clear(); iss >> m_lastDevice; } else if( keyword == "verbose_logging" ) { int flag = 0; iss >> flag; m_verboseLogging = flag != 0; } else { // store any other keys as app keys if( keyword.substr(0, 2) == "X-" ) { iss >> std::ws; line.clear(); std::getline(iss, line); m_keymap[keyword] = line; } } } m_loaded = true; } /// Save the current global config, overwriting or creating as needed bool GlobalConfigFile::Save() { if( !ConfigFile::CheckPath(m_path, &m_last_error) ) return false; std::ofstream out(m_filename.c_str(), std::ios::out | std::ios::binary); if( !out ) { m_last_error = _("Unable to open file for writing: ") + m_filename; return false; } if( !(m_lastDevice == 0) ) { out << "last_device " << m_lastDevice.Str() << std::endl; } out << "verbose_logging " << (m_verboseLogging ? 1 : 0) << std::endl; // store all app keys keymap_type::const_iterator ci = m_keymap.begin(); for( ; ci != m_keymap.end(); ++ci ) { out << ci->first << " " << ci->second << std::endl; } if( !out ) { m_last_error = _("Error during write. Config may be incomplete."); return false; } return true; } void GlobalConfigFile::SetKey(const std::string &key, const std::string &value) { if( !m_appname.size() ) throw std::logic_error(_("Cannot use SetKey() without specifying an appname in the constructor.")); if( value.find_first_of("\n\r") != std::string::npos ) throw std::logic_error(_("SetKey values may not contain newline characters.")); std::string fullkey = "X-" + m_appname + "-" + key; m_keymap[fullkey] = value; } std::string GlobalConfigFile::GetKey(const std::string &key, const std::string &default_value) const { if( !m_appname.size() ) throw std::logic_error(_("Cannot use SetKey() without specifying an appname in the constructor.")); std::string fullkey = "X-" + m_appname + "-" + key; keymap_type::const_iterator ci = m_keymap.find(fullkey); if( ci == m_keymap.end() ) return default_value; return ci->second; } void GlobalConfigFile::SetLastDevice(const Barry::Pin &pin) { m_lastDevice = pin; } void GlobalConfigFile::SetVerboseLogging(bool verbose) { m_verboseLogging = verbose; } } // namespace Barry barry-0.18.5/src/ios_state.h0000644001161500056700000000317212242254476015211 0ustar cdfreycdfrey/// /// \file ios_state.h /// RAII class to save and restore iostream state /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_IOS_STATE_H__ #define __BARRY_IOS_STATE_H__ #include #include namespace Barry { // // ios_format_state // /// This class saves the following stream settings: /// - flags /// - precision /// - width /// - fill character /// /// and restores them in the destructor. /// class ios_format_state { public: typedef std::ios stream_type; private: stream_type &m_stream; std::ios_base::fmtflags m_flags; std::streamsize m_precision; std::streamsize m_width; stream_type::char_type m_fill; public: explicit ios_format_state(stream_type &stream) : m_stream(stream) , m_flags(stream.flags()) , m_precision(stream.precision()) , m_width(stream.width()) , m_fill(stream.fill()) { } ~ios_format_state() { restore(); } void restore() { m_stream.flags(m_flags); m_stream.precision(m_precision); m_stream.width(m_width); m_stream.fill(m_fill); } }; } #endif barry-0.18.5/src/j_record.cc0000644001161500056700000000363012242254476015143 0ustar cdfreycdfrey/// /// \file j_record.cc /// Internal record manipulation functions for JDWP classes /// /* Copyright (C) 2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #include "record-internal.h" #include "data.h" #include "protostructs.h" #include using namespace Barry::Protocol; namespace Barry { ////////////////////////////////////////////////////////////////////////////// // JDWField builder helper functions void AddJDWByte(Data &data, size_t &size, const uint8_t value) { size_t fieldsize = sizeof(uint8_t); unsigned char *pd = data.GetBuffer(size + fieldsize) + size; uint8_t *field = (uint8_t *) pd; *field = value; size += sizeof(uint8_t); } void AddJDWInt(Data &data, size_t &size, const uint32_t value) { size_t fieldsize = sizeof(uint32_t); unsigned char *pd = data.GetBuffer(size + fieldsize) + size; uint32_t *field = (uint32_t *) pd; *field = value; size += sizeof(uint32_t); } void AddJDWChar(Data &data, size_t &size, const void *buf, size_t bufsize) { size_t fieldsize = JDWP_FIELD_HEADER_SIZE + bufsize; unsigned char *pd = data.GetBuffer(size + fieldsize) + size; JDWField *field = (JDWField *) pd; field->size = be_htobl(bufsize); memcpy(field->u.raw, buf, bufsize); size += fieldsize; } void AddJDWString(Data &data, size_t &size, const std::string &str) { AddJDWChar(data, size, str.c_str(), str.size()); } } // namespace Barry barry-0.18.5/src/iconv.h0000644001161500056700000000734312242254476014341 0ustar cdfreycdfrey/// /// \file iconv.h /// iconv wrapper class, and pluggable interface for records /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_ICONV_H__ #define __BARRY_ICONV_H__ #include "dll.h" #include "data.h" #include #include namespace Barry { class IConverter; class IConvHandlePrivate; // // IConvHandle class // /// Wrapper class for a two-way iconv_t handle pair. Automatically /// handles closing in the destructor. // class BXEXPORT IConvHandle { friend class IConverter; std::auto_ptr m_priv; bool m_throw_on_conv_err; private: // no copying IConvHandle(const IConvHandle &other); IConvHandle& operator=(const IConvHandle &other); // private constructor, used only by IConverter IConvHandle(const char *fromcode, const char *tocode, bool throwable); // the heart of the conversion std::string Convert(Data &tmp, const std::string &str) const; public: // custom conversions from any to IConverter's 'tocode' IConvHandle(const char *fromcode, const IConverter &ic, bool throw_on_conv_err = false); // custom conversions from IConverter's 'tocode' to any IConvHandle(const IConverter &ic, const char *tocode, bool throw_on_conv_err = false); ~IConvHandle(); }; // // IConverter // /// Main charset conversion class, primarily focused on converting /// between the Blackberry charset and an application-specified one. /// Additional conversions are possible through custom IConvHandle, /// but the goal of this class design is to deal with _one_ /// application defined charset, and provide a means to convert /// to/from that charset to/from any other charset needed by /// the Blackberry. /// /// By default, this class assumes the Blackberry's charset is /// WINDOWS-1252, but some data, such as SMS message bodies, can have /// custom charsets as specified by the records. To convert from /// such a custom charset, use: /// /// // application sets up IConverter /// IConverter ic("UTF-8"); /// /// // somewhere in the library, needing to convert /// // from UCS2 to whatever the application selected /// IConvHandle ucs2("UCS2", ic); /// application_string = ic.Convert(ucs2, ucs2_string_data); /// /// // and to convert back... /// IConvHandle ucs2_reverse(ic, "UCS2"); /// ucs2_string = ic.Convert(ucs2_reverse, application_string_data); /// class BXEXPORT IConverter { friend class IConvHandle; IConvHandle m_from; IConvHandle m_to; std::string m_tocode; // internal buffer for fast conversions mutable Data m_buffer; public: /// Always throws ErrnoError if unable to open iconv. /// If throw_on_conv_err is true, then string conversion operations /// that fail will also throw ErrnoError. explicit IConverter(const char *tocode = "UTF-8", bool throw_on_conv_err = false); ~IConverter(); std::string FromBB(const std::string &str) const; std::string ToBB(const std::string &str) const; // Custom override functions, meant for converting between // non-BLACKBERRY_CHARSET charsets and the tocode set by the // IConverter constructor std::string Convert(const IConvHandle &custom, const std::string &str) const; }; } // namespace Barry #endif barry-0.18.5/src/pipe.cc0000644001161500056700000000311112242254476014303 0ustar cdfreycdfrey/// /// \file pipe.cc /// Connector class to join parsers and builders together /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "pipe.h" namespace Barry { Pipe::Pipe(Builder &builder) : m_builder(builder) { } Pipe::~Pipe() { } bool Pipe::PumpEntry(Parser &parser, const IConverter *ic) { // if false, end of series, so pass that on to the caller if( !m_builder.FetchRecord(m_buffer, ic) ) return false; // pass the data into the parser parser.ParseRecord(m_buffer, ic); return true; } /// Reads all items from builder, feeding them into the parser, /// until the builder's Retrieve() signals the end of the series. void Pipe::PumpSeries(Parser &parser, const IConverter *ic) { while( PumpEntry(parser, ic) ) ; } /// Reads all series from the builder, feeding them into the parser, /// until the builder's EndOfFile() is true. void Pipe::PumpFile(Parser &parser, const IConverter *ic) { while( !m_builder.EndOfFile() ) { PumpSeries(parser, ic); } } } // namespace Barry barry-0.18.5/src/version.h0000644001161500056700000000163212242254476014703 0ustar cdfreycdfrey/// /// \file version.h /// Provide access to library version information /// /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_VERSION_H__ #define __BARRY_VERSION_H__ #include "dll.h" namespace Barry { BXEXPORT const char* Version(int &logical, int &major, int &minor); } // namespace Barry #endif barry-0.18.5/src/router.cc0000644001161500056700000004073512242254476014703 0ustar cdfreycdfrey/// /// \file router.cc /// Support classes for the pluggable socket routing system. /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "router.h" #include "scoped_lock.h" #include "data.h" #include "protostructs.h" #include "protocol.h" #include "usbwrap.h" #include "endian.h" #include "debug.h" #include #include #include using namespace std; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // SocketDataHandler default methods void SocketRoutingQueue::SocketDataHandler::Error(Barry::Error &error) { // Just log the error eout("SocketDataHandler: Error: " << error.what()); (void) error; } SocketRoutingQueue::SocketDataHandler::~SocketDataHandler() { // Nothing to destroy } /////////////////////////////////////////////////////////////////////////////// // SocketRoutingQueue constructors SocketRoutingQueue::SocketRoutingQueue(int prealloc_buffer_count, int default_read_timeout) : m_dev(0) , m_writeEp(0) , m_readEp(0) , m_interest(false) , m_seen_usb_error(false) , m_timeout(default_read_timeout) , m_continue_reading(false) { pthread_mutex_init(&m_mutex, NULL); pthread_mutex_init(&m_readwaitMutex, NULL); pthread_cond_init(&m_readwaitCond, NULL); AllocateBuffers(prealloc_buffer_count); } SocketRoutingQueue::~SocketRoutingQueue() { // thread running? if( m_continue_reading ) { m_continue_reading = false; pthread_join(m_usb_read_thread, NULL); } // dump all unused packets to debug output SocketQueueMap::const_iterator b = m_socketQueues.begin(); for( ; b != m_socketQueues.end(); ++b ) { DumpSocketQueue(b->first, b->second->m_queue); } if( m_default.size() ) { ddout("(Default queue is socket 0)"); DumpSocketQueue(0, m_default); } } /////////////////////////////////////////////////////////////////////////////// // protected members // // ReturnBuffer // /// Provides a method of returning a buffer to the free queue /// after processing. The DataHandle class calls this automatically /// from its destructor. void SocketRoutingQueue::ReturnBuffer(Data *buf) { // don't need to lock here, since m_free handles its own locking m_free.push(buf); } // // QueuePacket // /// Helper function to add a buffer to a socket queue. /// Returns false if no queue is available for that socket. //// Also empties the DataHandle on success. /// bool SocketRoutingQueue::QueuePacket(SocketId socket, DataHandle &buf) { if( m_interest ) { // lock so we can access the m_socketQueues map safely scoped_lock lock(m_mutex); // search for registration of socket SocketQueueMap::iterator qi = m_socketQueues.find(socket); if( qi != m_socketQueues.end() ) { qi->second->m_queue.push(buf.release()); return true; } } return false; } bool SocketRoutingQueue::QueuePacket(DataQueue &queue, DataHandle &buf) { // don't need to lock here, since queue handles its own locking queue.push(buf.release()); return true; } // // RouteOrQueuePacket // /// Same as QueuePacket, except sends the data to the callback if /// a callback is available. /// /// This function duplicates code from QueuePacket(), in order to /// optimize the mutex locking. /// bool SocketRoutingQueue::RouteOrQueuePacket(SocketId socket, DataHandle &buf) { // search for registration of socket if( m_interest ) { // lock so we can access the m_socketQueues map safely scoped_lock lock(m_mutex); SocketQueueMap::iterator qi = m_socketQueues.find(socket); if( qi != m_socketQueues.end() ) { SocketDataHandlerPtr &sdh = qi->second->m_handler; // is there a handler? if( sdh ) { // unlock & let the handler process it lock.unlock(); sdh->DataReceived(*buf.get()); // no exceptions thrown, clear the // DataHandle, sending packet back to its // free list buf.reset(); return true; } else { qi->second->m_queue.push(buf.release()); return true; } } } return false; } // // SimpleReadThread() // /// Convenience thread to handle USB read activity. /// void *SocketRoutingQueue::SimpleReadThread(void *userptr) { SocketRoutingQueue *q = (SocketRoutingQueue *)userptr; // read from USB and write to stdout until finished q->m_seen_usb_error = false; while( q->m_continue_reading ) { try { q->DoRead(1000); // timeout in milliseconds } catch (std::runtime_error const &e) { eout(_("SimpleReadThread received uncaught exception: ") << typeid(e).name() << _(" what: ") << e.what()); } catch (...) { eout(_("SimpleReadThread recevied uncaught exception of unknown type")); } } return 0; } void SocketRoutingQueue::DumpSocketQueue(SocketId socket, const DataQueue &dq) { // dump a record of any unused packets in the queue, for debugging if( dq.size() ) { ddout(_("SocketRoutingQueue Leftovers: ") << dec << dq.size() << _(" packet(s) for socket: ") << "0x" << hex << (unsigned int) socket << "\n" << dq); } } /////////////////////////////////////////////////////////////////////////////// // public API // These functions connect the router to an external Usb::Device // object. Normally this is handled automatically by the // Controller class, but are public here in case they are needed. void SocketRoutingQueue::SetUsbDevice(Usb::Device *dev, int writeEp, int readEp, SocketDataHandlerPtr callback) { scoped_lock lock(m_mutex); m_dev = dev; m_usb_error_dev_callback = callback; m_writeEp = writeEp; m_readEp = readEp; } void SocketRoutingQueue::ClearUsbDevice() { scoped_lock lock(m_mutex); m_dev = 0; m_usb_error_dev_callback.reset(); lock.unlock(); // wait for the DoRead cycle to finish, so the external // Usb::Device object doesn't close before we're done with it scoped_lock wait(m_readwaitMutex); pthread_cond_wait(&m_readwaitCond, &m_readwaitMutex); } bool SocketRoutingQueue::UsbDeviceReady() { scoped_lock lock(m_mutex); return m_dev != 0 && !m_seen_usb_error; } // // AllocateBuffers // /// This class starts out with no buffers, and will grow one buffer /// at a time if needed. Call this to allocate count buffers /// all at once and place them on the free queue. After calling /// this function, at least count buffers will exist in the free /// queue. If there are already count buffers, none will be added. /// void SocketRoutingQueue::AllocateBuffers(int count) { int todo = count - m_free.size(); for( int i = 0; i < todo; i++ ) { // m_free handles its own locking m_free.push( new Data ); } } // // DefaultRead (both variations) // /// Returns the data for the next unregistered socket. /// Blocks until timeout or data is available. /// Returns false (or null pointer) on timeout and no data. /// With the return version of the function, there is no /// copying performed. /// /// This version performs a copy. /// bool SocketRoutingQueue::DefaultRead(Data &receive, int timeout) { DataHandle buf = DefaultRead(timeout); if( !buf.get() ) return false; // copy to desired buffer receive = *buf.get(); return true; } /// /// This version does not perform a copy. /// DataHandle SocketRoutingQueue::DefaultRead(int timeout) { if( m_seen_usb_error && timeout == -1 ) { // If an error has been seen and not cleared then no // more data will be read into the queue by // DoRead(). Forcing the timeout to zero allows any // data already in the queue to be read, but prevents // waiting for data which will never arrive. timeout = 0; } // m_default handles its own locking // Be careful with the queue timeout, since its -1 means "forever" Data *buf = m_default.wait_pop(timeout == -1 ? m_timeout : timeout); return DataHandle(*this, buf); } // // RegisterInterest // /// Register an interest in data from a certain socket. To read /// from that socket, use the SocketRead() function from then on. /// /// Any non-registered socket goes in the default queue /// and must be read by DefaultRead() /// /// If not null, handler is called when new data is read. It will /// be called in the same thread instance that DoRead() is called from. /// Handler is passed the DataQueue Data pointer, and so no /// copying is done. Once the handler returns, the data is /// considered processed and not added to the interested queue, /// but instead returned to m_free. /// /// Throws std::logic_error if already registered. /// void SocketRoutingQueue::RegisterInterest(SocketId socket, SocketDataHandlerPtr handler) { // modifying our own std::map, need a lock scoped_lock lock(m_mutex); SocketQueueMap::iterator qi = m_socketQueues.find(socket); if( qi != m_socketQueues.end() ) throw std::logic_error(_("RegisterInterest requesting a previously registered socket.")); m_socketQueues[socket] = QueueEntryPtr( new QueueEntry(handler) ); m_interest = true; } // // UnregisterInterest // /// Unregisters interest in data from the given socket, and discards /// any existing data in its interest queue. Any new incoming data /// for this socket will be placed in the default queue. /// void SocketRoutingQueue::UnregisterInterest(SocketId socket) { // modifying our own std::map, need a lock scoped_lock lock(m_mutex); SocketQueueMap::iterator qi = m_socketQueues.find(socket); if( qi == m_socketQueues.end() ) return; // nothing registered, done // dump a record of any unused packets in the queue, for debugging DumpSocketQueue(qi->first, qi->second->m_queue); // salvage all our data buffers m_free.append_from( qi->second->m_queue ); // remove the QueueEntryPtr from the map m_socketQueues.erase( qi ); // check the interest flag m_interest = m_socketQueues.size() > 0; } // // SocketRead // /// Reads data from the interested socket cache. Can only read /// from sockets that have been previously registered. /// /// Blocks until timeout or data is available. /// /// Returns false (or null pointer) on timeout and no data. /// With the return version of the function, there is no /// copying performed. /// /// Throws std::logic_error if a socket was requested that was /// not previously registered. /// /// Copying is performed with this function. /// bool SocketRoutingQueue::SocketRead(SocketId socket, Data &receive, int timeout) { DataHandle buf = SocketRead(socket, timeout); if( !buf.get() ) return false; // copy to desired buffer receive = *buf.get(); return true; } /// /// Copying is not performed with this function. /// /// Throws std::logic_error if a socket was requested that was /// not previously registered. /// DataHandle SocketRoutingQueue::SocketRead(SocketId socket, int timeout) { QueueEntryPtr qep; DataQueue *dq = 0; // accessing our own std::map, need a lock { scoped_lock lock(m_mutex); SocketQueueMap::iterator qi = m_socketQueues.find(socket); if( qi == m_socketQueues.end() ) throw std::logic_error(_("SocketRead requested data from unregistered socket.")); // got our queue, save the whole QueueEntryPtr (shared_ptr), // and unlock, since we will be waiting on the DataQueue, // not the socketQueues map // // This is safe, since even if UnregisterInterest is called, // our pointer won't be deleted until our shared_ptr // (QueueEntryPtr) goes out of scope. // // The remaining problem is that wait_pop() might wait // forever if there is no timeout... c'est la vie. // Should'a used a timeout. :-) qep = qi->second; dq = &qep->m_queue; } // get data from DataQueue // Be careful with the queue timeout, since its -1 means "forever" Data *buf = dq->wait_pop(timeout == -1 ? m_timeout : timeout); // specifically delete our copy of shared pointer, in a locked // environment { scoped_lock lock(m_mutex); qep.reset(); } return DataHandle(*this, buf); } // Returns true if data is available for that socket. bool SocketRoutingQueue::IsAvailable(SocketId socket) const { scoped_lock lock(m_mutex); SocketQueueMap::const_iterator qi = m_socketQueues.find(socket); if( qi == m_socketQueues.end() ) return false; return qi->second->m_queue.size() > 0; } // // DoRead // /// Called by the application's "read thread" to read the next usb /// packet and route it to the correct queue. Returns after every /// read, even if a handler is associated with a queue. /// Note: this function is safe to call before SetUsbDevice() is /// called... it just doesn't do anything if there is no usb /// device to work with. /// /// Timeout is in milliseconds. // This timeout is for the USB subsystem, so no special handling // for it is needed... just use usbwrap's default timeout. void SocketRoutingQueue::DoRead(int timeout) { class ReadWaitSignal { pthread_mutex_t &m_Mutex; pthread_cond_t &m_Cond; public: ReadWaitSignal(pthread_mutex_t &mut, pthread_cond_t &cond) : m_Mutex(mut), m_Cond(cond) {} ~ReadWaitSignal() { scoped_lock wait(m_Mutex); pthread_cond_signal(&m_Cond); } } readwait(m_readwaitMutex, m_readwaitCond); Usb::Device * volatile dev = 0; int readEp; DataHandle buf(*this, 0); // if we are not connected to a USB device yet, just wait { scoped_lock lock(m_mutex); if( !m_dev || m_seen_usb_error ) { lock.unlock(); // unlock early, since we're sleeping // sleep only a short time, since things could be // in the process of setup or teardown usleep(125000); return; } dev = m_dev; readEp = m_readEp; // fetch a free buffer Data *raw = m_free.pop(); if( !raw ) buf = DataHandle(*this, new Data); else buf = DataHandle(*this, raw); } // take a chance and do the read unlocked, as this has the potential // for blocking for a while try { Data &data = *buf.get(); if( !dev->BulkRead(readEp, data, timeout) ) return; // no data, done! MAKE_PACKET(pack, data); // make sure the size is right if( data.GetSize() < SB_PACKET_SOCKET_SIZE ) return; // bad size, just skip // extract the socket from the packet uint16_t socket = btohs(pack->socket); // if this is a sequence packet, handle it specially if( Protocol::IsSequencePacket(data) ) { // sequence.socket is a single byte socket = pack->u.sequence.socket; ////////////////////////////////////////////// // ALWAYS queue sequence packets, so that // the socket code can handle SyncSend() if( !QueuePacket(socket, buf) ) { // if no queue available for this // socket, send it to the default // queue QueuePacket(m_default, buf); } // done with sequence packet return; } // we have data, now route or queue it if( RouteOrQueuePacket(socket, buf) ) return; // done // if we get here, send to default queue QueuePacket(m_default, buf); } catch( Usb::Timeout & ) { // this is expected... just ignore } catch( Usb::Error &ue ) { // set the flag first, in case any of the handlers // are able to recover from this error m_seen_usb_error = true; // this is unexpected, but we're in a thread here... // Need to iterate through all the registered handlers // calling their error callback. // Can't be locked when calling the callback, so need // to make a list of them first. scoped_lock lock(m_mutex); std::vector handlers; SocketQueueMap::iterator qi = m_socketQueues.begin(); while( qi != m_socketQueues.end() ) { SocketDataHandlerPtr &sdh = qi->second->m_handler; // is there a handler? if( sdh ) { handlers.push_back(sdh); } ++qi; } SocketDataHandlerPtr usb_error_handler = m_usb_error_dev_callback; lock.unlock(); std::vector::iterator hi = handlers.begin(); while( hi != handlers.end() ) { (*hi)->Error(ue); ++hi; } // and finally, call the specific error callback if available if( usb_error_handler.get() ) { usb_error_handler->Error(ue); } } } void SocketRoutingQueue::SpinoffSimpleReadThread() { // signal that it's ok to run inside the thread if( m_continue_reading ) return; // already running m_continue_reading = true; // Start USB read thread, to handle all routing int ret = pthread_create(&m_usb_read_thread, NULL, &SimpleReadThread, this); if( ret ) { m_continue_reading = false; throw Barry::ErrnoError(_("SocketRoutingQueue: Error creating USB read thread."), ret); } } } // namespace Barry barry-0.18.5/src/convo.awk0000644001161500056700000000143212242254476014673 0ustar cdfreycdfrey# # This script is useful for turning a UsbSnoop log file into something # more readable. It assumes USB endpoints 0x05 and 0x82 # BEGIN { # 0 for down # 1 for up direction = 0; # boolean docopy = 0; } />>>/ { direction = 0; docopy = 0; print $0; } /<< namespace Barry { namespace Protocol { // This function is only valid for Packet, JLPacket, and JVMPacket structs, // as long as they don't differ from each other in header layout, when // it comes to the .size field. (see protostructs.h) void CheckSize(const Data &packet, size_t requiredsize) { const Packet *p = (const Packet *) packet.GetData(); // when packets are larger than 0xFFFF bytes, packet->size is no // longer reliable, so we go with the Data class size if( (packet.GetSize() >= 4 && btohs(p->size) != packet.GetSize() && packet.GetSize() <= 0xFFFF) || packet.GetSize() < requiredsize ) { BadSize bs(packet.GetSize() >= 4 ? btohs(p->size) : 0, packet.GetSize(), requiredsize); eout(bs.what()); eout(packet); throw bs; } } unsigned int GetSize(const Data &packet) { CheckSize(packet, 4); // when packets are larger than 0xFFFF bytes, packet->size is no // longer reliable, so we go with the Data class size if( packet.GetSize() > 0xFFFF ) { return packet.GetSize(); } else { const Packet *p = (const Packet *) packet.GetData(); return btohs(p->size); } } bool IsSequencePacket(const Barry::Data &data) { if( data.GetSize() == SB_SEQUENCE_PACKET_SIZE ) { MAKE_PACKET(rpack, data); if( rpack->socket == 0 && rpack->command == SB_COMMAND_SEQUENCE_HANDSHAKE ) { return true; } } return false; // not a sequence packet } }} // namespace Barry::Protocol barry-0.18.5/src/tarfile-ops-nt.cc0000644001161500056700000000473412242254476016226 0ustar cdfreycdfrey/// /// \file tarfile-ops-nt.cc /// Non-thread safe operation functions for a libtar-compatible /// zlib compression interface. /* Copyright (C) 2007-2013, Chris Frey 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 in the COPYING file at the root directory of this project for more details. */ #include "tarfile.h" #include #include #include #include #include #include namespace reuse { namespace gztar_nonthread { namespace { // array of compressed file handles... needed for architectures // where sizeof(int) != sizeof(gzFile) gzFile *gzHandles = 0; unsigned int gzArraySize = 0; } int open_compressed(const char *file, int flags, mode_t mode) { unsigned int index = 0; for( ; index < gzArraySize; index++ ) { if( gzHandles[index] == 0 ) break; } if( index >= gzArraySize ) { gzFile *h = (gzFile*) realloc(gzHandles, (gzArraySize + 100) * sizeof(gzFile)); if( h ) { gzHandles = h; gzArraySize += 100; } else { return -1; } } int fd = open(file, flags, mode); if( fd == -1 ) return -1; gzFile gfd = gzdopen(fd, (flags & O_WRONLY) ? "wb9" : "rb"); if( gfd == NULL ) { close(fd); return -1; } gzHandles[index] = gfd; return index; } int close_compressed(int fd) { unsigned int ufd = fd; assert( ufd < gzArraySize ); int ret = gzclose(gzHandles[ufd]); gzHandles[ufd] = 0; return ret; } ssize_t read_compressed(int fd, void *buf, size_t size) { unsigned int ufd = fd; assert( ufd < gzArraySize ); return gzread(gzHandles[ufd], buf, size); } ssize_t write_compressed(int fd, const void *buf, size_t size) { unsigned int ufd = fd; assert( ufd < gzArraySize ); return gzwrite(gzHandles[ufd], buf, size); } } // namespace gztar_nonthread tartype_t gztar_ops_nonthread = { (openfunc_t) gztar_nonthread::open_compressed, gztar_nonthread::close_compressed, gztar_nonthread::read_compressed, gztar_nonthread::write_compressed }; } // namespace reuse barry-0.18.5/src/dll.h0000644001161500056700000000513412242254476013772 0ustar cdfreycdfrey/// /// \file dll.h /// Macros for handling DLL/library API visibility /// /// Based on documentation at: http://gcc.gnu.org/wiki/Visibility /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_DLL_H__ #define __BARRY_DLL_H__ // // // Every non-templated class that is meant to be used by an application // must be declared as: // // class BXEXPORT ClassName {}; // // Every private (not protected or public) member function of an exported // class can be declared as: // // private: // BXLOCAL void HelperFunc(); // // Every non-templated function that is meant to be used by an application // must be declared as: // // BXEXPORT int GetAmount(); // BXEXPORT std::ostream& operator<< (std::ostream& os, const Obj &obj); // // // Everything else will be hidden, as per the build system's configuration. // // #if __BARRY_HAVE_GCCVISIBILITY__ #define BXEXPORT __attribute__ ((visibility("default"))) #define BXLOCAL __attribute__ ((visibility("hidden"))) #elif defined(WIN32) #ifdef __BARRY_LIBRARY_BUILD__ #define BXEXPORT __declspec( dllexport ) #define BXLOCAL #else #define BXEXPORT __declspec( dllimport ) #define BXLOCAL #endif // Disable "needs to have dll interface warning" which // comes from exporting classes which make use of non-exported // templated classes. #pragma warning(disable: 4251) #else #define BXEXPORT #define BXLOCAL #endif // // Add this to the end of variable argument function declarations. // For example: // // void log(const char *msg, ...) BARRY_GCC_FORMAT_CHECK(1, 2); // // This tells GCC that the first argument is the format string, and // the second is the first variable argument to check. // // If you use this inside a class, you need to allow for the invisible // 'this' pointer: // // class Trace { // public: // void logf(const char *msg, ...) BARRY_GCC_FORMAT_CHECK(2, 3); // }; // #if __GNUC__ #define BARRY_GCC_FORMAT_CHECK(a,b) __attribute__ ((format(printf, a, b))) #else #define BARRY_GCC_FORMAT_CHECK(a,b) #endif #endif barry-0.18.5/src/r_task.cc0000644001161500056700000003205412242254476014641 0ustar cdfreycdfrey/// /// \file r_task.cc /// Record parsing class for the task database. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2007, Brian Edginton 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "r_task.h" #include "r_calendar.h" // for CAL_* defines #include "r_recur_base-int.h" #include "record-internal.h" #include "protostructs.h" #include "data.h" #include "time.h" #include "iconv.h" #include "debug.h" #include #include #include #include "ios_state.h" using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // Task Class, static members // // Note! These functions currently only pass the same values through. // In actuality, these are technically two different values: // one on the raw protocol side, and the other part of the // guaranteed Barry API. If the Blackberry ever changes the // meanings for these codes, do the translation here. // Task::AlarmFlagType Task::AlarmProto2Rec(uint8_t a) { return (AlarmFlagType)a; } uint8_t Task::AlarmRec2Proto(AlarmFlagType a) { return a; } Task::PriorityFlagType Task::PriorityProto2Rec(uint8_t p) { return (PriorityFlagType)p; } uint8_t Task::PriorityRec2Proto(PriorityFlagType p) { return p; } Task::StatusFlagType Task::StatusProto2Rec(uint8_t s) { return (StatusFlagType)s; } uint8_t Task::StatusRec2Proto(StatusFlagType s) { return s; } /////////////////////////////////////////////////////////////////////////////// // Task Class // Task Field Codes #define TSKFC_TASK_TYPE 0x01 #define TSKFC_TITLE 0x02 #define TSKFC_NOTES 0x03 #define TSKFC_DUE_TIME 0x05 #define TSKFC_START_TIME 0x06 // This is fuzzy... most devices seem // to anchor this value == to DUE_TIME #define TSKFC_DUE_FLAG 0x08 #define TSKFC_STATUS 0x09 #define TSKFC_PRIORITY 0x0a #define TSKFC_ALARM_TYPE 0x0e #define TSKFC_ALARM_TIME 0x0f #define TSKFC_TIMEZONE_CODE 0x10 #define TSKFC_CATEGORIES 0x11 #define TSKFC_ALARM_FLAG 0x12 #define TSKFC_END 0xffff static FieldLink TaskFieldLinks[] = { { TSKFC_TITLE, N_("Summary"), 0, 0, &Task::Summary, 0, 0, 0, 0, true }, { TSKFC_NOTES, N_("Notes"), 0, 0, &Task::Notes, 0, 0, 0, 0, true }, { TSKFC_START_TIME, N_("Start Time"), 0, 0, 0, 0, &Task::StartTime, 0, 0, false }, { TSKFC_DUE_TIME, N_("Due Time"), 0, 0, 0, 0, &Task::DueTime, 0, 0, false }, { TSKFC_ALARM_TIME, N_("Alarm Time"), 0, 0, 0, 0, &Task::AlarmTime, 0, 0, false }, { TSKFC_END, N_("End of List"), 0, 0, 0, 0, 0, 0, 0, false }, }; Task::Task() { Clear(); } Task::~Task() { } const unsigned char* Task::ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { const CommonField *field = (const CommonField *) begin; // advance and check size begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size); if( begin > end ) // if begin==end, we are ok return begin; if( !btohs(field->size) ) // if field has no size, something's up return begin; if( field->type == TSKFC_TASK_TYPE ) { if( field->u.raw[0] != 't' ) { throw Error(_("Task::ParseField: Task Type is not 't'")); } return begin; } // cycle through the type table for( FieldLink *b = TaskFieldLinks; b->type != TSKFC_END; b++ ) { if( b->type == field->type ) { if( b->strMember ) { std::string &s = this->*(b->strMember); s = ParseFieldString(field); if( b->iconvNeeded && ic ) s = ic->FromBB(s); return begin; // done! } else if( b->timeMember && btohs(field->size) == 4 ) { TimeT &t = this->*(b->timeMember); t.Time = min2time(field->u.min1900); return begin; } } } // handle special cases switch( field->type ) { case TSKFC_PRIORITY: if( field->u.raw[0] > TR_PRIORITY_RANGE_HIGH ) { throw Error(_("Task::ParseField: priority field out of bounds")); } else { PriorityFlag = PriorityProto2Rec(field->u.raw[0]); } return begin; case TSKFC_STATUS: if( field->u.raw[0] > TR_STATUS_RANGE_HIGH ) { throw Error(_("Task::ParseField: priority field out of bounds")); } else { StatusFlag = StatusProto2Rec(field->u.raw[0]); } return begin; case TSKFC_TIMEZONE_CODE: if( btohs(field->size) == 4 ) { TimeZoneCode = btohs(field->u.code); TimeZoneValid = true; } else { throw Error(_("Task::ParseField: not enough data in time zone code field")); } return begin; case TSKFC_DUE_FLAG: // the DueDateFlag is not available on really old devices // such as the 7750, and if the DueTime is available, // we'll just save it. There is no further need for this // value that we know of yet, so just ignore it for now. return begin; case TSKFC_ALARM_FLAG: // the AlarmFlag is not available on really old devices // such as the 7750, and if the AlarmTime is available, // we'll just save it. There is no further need for this // value that we know of yet, so just ignore it for now. return begin; case TSKFC_ALARM_TYPE: if( field->u.raw[0] > TR_ALARM_RANGE_HIGH ) { throw Error(_("Task::ParseField: AlarmType out of bounds")); } else { AlarmType = AlarmProto2Rec(field->u.raw[0]); } return begin; case TSKFC_CATEGORIES: { std::string catstring = ParseFieldString(field); if( ic ) catstring = ic->FromBB(catstring); Categories.CategoryStr2List(catstring); } return begin; } // base class handles recurring data if( RecurBase::ParseField(field->type, field->u.raw, btohs(field->size), ic) ) return begin; // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; uf.data.assign((const char*)field->u.raw, btohs(field->size)); Unknowns.push_back(uf); // return new pointer for next field return begin; } void Task::ParseHeader(const Data &data, size_t &offset) { // no header in Task records } void Task::ParseFields(const Data &data, size_t &offset, const IConverter *ic) { const unsigned char *finish = ParseCommonFields(*this, data.GetData() + offset, data.GetData() + data.GetSize(), ic); offset += finish - (data.GetData() + offset); } void Task::Validate() const { RecurBase::Validate(); } void Task::BuildHeader(Data &data, size_t &offset) const { // no header in Task records } // // Build // /// Build fields part of record. /// void Task::BuildFields(Data &data, size_t &offset, const IConverter *ic) const { data.Zap(); // // Note: we do not use the FieldLink table, since the firmware // on many devices apears flakey, so we try to write as close to // the same order as we see coming from the device. Unfortunately, // this doesn't really help, for the Tasks corruption bug, but // we'll keep the flexibility for now. // // tack on the 't' task type field first BuildField(data, offset, TSKFC_TASK_TYPE, 't'); // Summary / Title if( Summary.size() ) { std::string s = (ic) ? ic->ToBB(Summary) : Summary; BuildField(data, offset, TSKFC_TITLE, s); } BuildField(data, offset, TSKFC_STATUS, (uint32_t) StatusRec2Proto(StatusFlag)); BuildField(data, offset, TSKFC_PRIORITY, (uint32_t) PriorityRec2Proto(PriorityFlag)); if( TimeZoneValid ) { // the time zone code field is 4 bytes, but we only use // the first two... pad it with zeros uint32_t code = TimeZoneCode; BuildField(data, offset, TSKFC_TIMEZONE_CODE, code); } // make sure StartTime matches DueTime, by writing it manually... /// not sure why StartTime exists, but oh well. :-) if( DueTime.IsValid() ) { // we use DueTime here, with the START_TIME code, // instead of StartTime, since the function is const BuildField1900(data, offset, TSKFC_START_TIME, DueTime); // then DueTime, with flag first, then time BuildField(data, offset, TSKFC_DUE_FLAG, (uint32_t) 1); BuildField1900(data, offset, TSKFC_DUE_TIME, DueTime); } if( AlarmTime.IsValid() ) { BuildField(data, offset, TSKFC_ALARM_FLAG, (uint32_t) 1); BuildField(data, offset, TSKFC_ALARM_TYPE, AlarmRec2Proto(AlarmType)); BuildField1900(data, offset, TSKFC_ALARM_TIME, AlarmTime); } // Categories if( Categories.size() ) { string store; Categories.CategoryList2Str(store); BuildField(data, offset, TSKFC_CATEGORIES, ic ? ic->ToBB(store) : store); } // Notes if( Notes.size() ) { std::string s = (ic) ? ic->ToBB(Notes) : Notes; BuildField(data, offset, TSKFC_NOTES, s); } if( Recurring ) { CalendarRecurrenceDataField recur; BuildRecurrenceData(StartTime.Time, &recur); BuildField(data, offset, RecurBase::RecurringFieldType(), &recur, CALENDAR_RECURRENCE_DATA_FIELD_SIZE); } // and finally save unknowns UnknownsType::const_iterator ub = Unknowns.begin(), ue = Unknowns.end(); for( ; ub != ue; ub++ ) { BuildField(data, offset, *ub); } data.ReleaseBuffer(offset); } void Task::Clear() { // clear the base class first RecurBase::Clear(); // our variables... RecType = GetDefaultRecType(); RecordId = 0; Summary.clear(); Notes.clear(); Categories.clear(); UID.clear(); StartTime.clear(); DueTime.clear(); AlarmTime.clear(); TimeZoneCode = GetStaticTimeZoneCode( 0, 0 ); // default to GMT TimeZoneValid = false; AlarmType = Date; PriorityFlag = Normal; StatusFlag = NotStarted; Unknowns.clear(); } const FieldHandle::ListT& Task::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; #undef CONTAINER_OBJECT_NAME #define CONTAINER_OBJECT_NAME fhv #undef RECORD_CLASS_NAME #define RECORD_CLASS_NAME Task FHP(RecType, _("Record Type Code")); FHP(RecordId, _("Unique Record ID")); FHD(Summary, _("Summary"), TSKFC_TITLE, true); FHD(Notes, _("Notes"), TSKFC_NOTES, true); FHD(Categories, _("Categories"), TSKFC_CATEGORIES, true); FHP(UID, _("UID")); // FIXME - not linked to any device field?? FHD(StartTime, _("Start Time"), TSKFC_START_TIME, false); FHD(DueTime, _("Due Time"), TSKFC_DUE_TIME, false); FHD(AlarmTime, _("Alarm Time"), TSKFC_ALARM_TIME, false); FHD(TimeZoneCode, _("Time Zone Code"), TSKFC_TIMEZONE_CODE, false); FHP(TimeZoneValid, _("Time Zone Code Valid")); FHE(aft, AlarmFlagType, AlarmType, _("Alarm Type")); FHE_CONST(aft, Date, _("Date")); FHE_CONST(aft, Relative, _("Relative")); FHE(pft, PriorityFlagType, PriorityFlag, _("Priority")); FHE_CONST(pft, High, _("High")); FHE_CONST(pft, Normal, _("Normal")); FHE_CONST(pft, Low, _("Low")); FHE(sft, StatusFlagType, StatusFlag, _("Status")); FHE_CONST(sft, NotStarted, _("Not Started")); FHE_CONST(sft, InProgress, _("In Progress")); FHE_CONST(sft, Completed, _("Completed")); FHE_CONST(sft, Waiting, _("Waiting")); FHE_CONST(sft, Deferred, _("Deferred")); FHP(Unknowns, _("Unknown Fields")); // and finally, the RecurBase fields RECUR_BASE_FIELD_HANDLES return fhv; } std::string Task::GetDescription() const { return Summary; } void Task::Dump(std::ostream &os) const { ios_format_state state(os); static const char *PriorityName[] = { N_("High"), N_("Normal"), N_("Low") }; static const char *StatusName[] = { N_("Not Started"), N_("In Progress"), N_("Completed"), N_("Waiting"), N_("Deferred") }; static const char *AlarmTypeName[] = { N_("None"), N_("By Date"), N_("Relative") }; os << _("Task entry: ") << "0x" << setbase(16) << RecordId << " (" << (unsigned int)RecType << ")\n"; // cycle through the type table for( const FieldLink *b = TaskFieldLinks; b->type != TSKFC_END; b++ ) { if( b->strMember ) { const std::string &s = this->*(b->strMember); if( s.size() ) os << " " << gettext(b->name) << ": " << Cr2LfWrapper(s) << "\n"; } else if( b->timeMember ) { TimeT t = this->*(b->timeMember); if( t.IsValid() ) os << " " << gettext(b->name) << ": " << t << "\n"; } } os << _(" Priority: ") << gettext(PriorityName[PriorityFlag]) << "\n"; os << _(" Status: ") << gettext(StatusName[StatusFlag]) << "\n"; if( AlarmType ) { os << _(" Alarm Type: ") << gettext(AlarmTypeName[AlarmType]) << "\n"; } if( TimeZoneValid ) os << _(" Time Zone: ") << gettext(GetStaticTimeZone(TimeZoneCode)->Name) << "\n"; // print recurrence data if available RecurBase::Dump(os); if( Categories.size() ) { string display; Categories.CategoryList2Str(display); os << _(" Categories: ") << display << "\n"; } os << Unknowns; os << "\n\n"; } bool Task::operator<(const Task &other) const { if( StartTime != other.StartTime ) return StartTime < other.StartTime; if( AlarmTime != other.AlarmTime ) return AlarmTime < other.AlarmTime; int cmp = Summary.compare(other.Summary); if( cmp == 0 ) cmp = Notes.compare(other.Notes); return cmp < 0; } } // namespace Barry barry-0.18.5/src/router.h0000644001161500056700000002235212242254476014540 0ustar cdfreycdfrey/// /// \file router.h /// Support classes for the pluggable socket routing system. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_ROUTER_H__ #define __BARRY_ROUTER_H__ #include "dll.h" #include #include #include #include #include #include "dataqueue.h" #include "error.h" #include "usbwrap.h" namespace Barry { class DataHandle; class BXEXPORT SocketRoutingQueue { friend class DataHandle; public: // Interface class for socket data callbacks // See RegisterInterest() for more information. class BXEXPORT SocketDataHandler { public: // Called when data is received on the socket // for which interest has been registered. // // The lifetime of the data parameter is only valid // for the duration of this method call. virtual void DataReceived(Data& data) = 0; // Called when an error has occured on the socket // for which interest has been registered. // // The lifetime of the error parameter is only valid // for the lifetime of this method call. virtual void Error(Barry::Error &error); virtual ~SocketDataHandler(); }; typedef std::tr1::shared_ptr SocketDataHandlerPtr; // Simple wrapper template class for SocketDataHandler which provides a basic data recieved callback template class SimpleSocketDataHandler : public SocketDataHandler { void (*m_callback)(T&, Data*); T& m_context; public: SimpleSocketDataHandler(T& context, void (*callback)(T& context, Data* data)) : m_callback(callback) , m_context(context) {} virtual void DataReceived(Data& data) { m_callback(m_context, &data); } }; struct QueueEntry { SocketDataHandlerPtr m_handler; DataQueue m_queue; QueueEntry(SocketDataHandlerPtr h) : m_handler(h) {} }; typedef std::tr1::shared_ptr QueueEntryPtr; typedef uint16_t SocketId; typedef std::map SocketQueueMap; private: Usb::Device * volatile m_dev; volatile int m_writeEp, m_readEp; volatile bool m_interest; // true if at least one socket has an interest. // used to optimize the reading mutable pthread_mutex_t m_mutex;// controls access to local data, but not // DataQueues, as they have their own // locking per queue pthread_mutex_t m_readwaitMutex; pthread_cond_t m_readwaitCond; bool m_seen_usb_error; SocketDataHandlerPtr m_usb_error_dev_callback; DataQueue m_free; DataQueue m_default; SocketQueueMap m_socketQueues; int m_timeout; // thread state pthread_t m_usb_read_thread; volatile bool m_continue_reading;// set to true when the thread is created, // then set to false in the destructor // to signal the end of the thread // and handle the join protected: // Provides a method of returning a buffer to the free queue // after processing. The DataHandle class calls this automatically // from its destructor. void ReturnBuffer(Data *buf); // Helper function to add a buffer to a socket queue // Returns false if no queue is available for that socket // Also empties the DataHandle on success. bool QueuePacket(SocketId socket, DataHandle &buf); bool QueuePacket(DataQueue &queue, DataHandle &buf); bool RouteOrQueuePacket(SocketId socket, DataHandle &buf); // Thread function for the simple read behaviour... thread is // created in the SpinoffSimpleReadThread() member below. static void *SimpleReadThread(void *userptr); void DumpSocketQueue(SocketId socket, const DataQueue &dq); public: SocketRoutingQueue(int prealloc_buffer_count = 4, int default_read_timeout = USBWRAP_DEFAULT_TIMEOUT); ~SocketRoutingQueue(); // // data access // int GetWriteEp() const { return m_writeEp; } int GetReadEp() const { return m_readEp; } // These functions connect the router to an external Usb::Device // object. Normally this is handled automatically by the // Controller class, but are public here in case they are needed. // // If DoRead encounters an error, it sets a flag and stops // reading. To recover, you should handle the Error() call in // the callback, fix the USB device, and then call // ClearUsbError() to clear the flag. // void SetUsbDevice(Usb::Device *dev, int writeEp, int readEp, SocketDataHandlerPtr callback = SocketDataHandlerPtr()); void ClearUsbDevice(); bool UsbDeviceReady(); Usb::Device* GetUsbDevice() { return m_dev; } void ClearUsbError(); // This class starts out with no buffers, and will grow one buffer // at a time if needed. Call this to allocate count buffers // all at once and place them on the free queue. void AllocateBuffers(int count); // Returns the data for the next unregistered socket. // Blocks until timeout or data is available. // Returns false (or null pointer) on timeout and no data. // With the return version of the function, there is no // copying performed. // // Timeout is in milliseconds. Default timeout set by constructor // is used if set to -1. bool DefaultRead(Data &receive, int timeout = -1); DataHandle DefaultRead(int timeout = -1); // Register an interest in data from a certain socket. To read // from that socket, use the SocketRead() function from then on. // Any non-registered socket goes in the default queue // and must be read by DefaultRead() // If not null, handler is called when new data is read. It will // be called in the same thread instance that DoRead() is called from. // Handler is passed the DataQueue Data object, and so no // copying is done. Once the handler returns, the data is // considered processed and not added to the interested queue, // but instead returned to m_free. void RegisterInterest(SocketId socket, SocketDataHandlerPtr handler); // Unregisters interest in data from the given socket, and discards // any existing data in its interest queue. Any new incoming data // for this socket will be placed in the default queue. void UnregisterInterest(SocketId socket); // Reads data from the interested socket cache. Can only read // from sockets that have been previously registered. // Blocks until timeout or data is available. // Returns false (or null pointer) on timeout and no data. // With the return version of the function, there is no // copying performed. // // Timeout is in milliseconds. Default timeout set by constructor // is used if set to -1. bool SocketRead(SocketId socket, Data &receive, int timeout = -1); DataHandle SocketRead(SocketId socket, int timeout = -1); // Returns true if data is available for that socket. bool IsAvailable(SocketId socket) const; // Called by the application's "read thread" to read the next usb // packet and route it to the correct queue. Returns after every // read, even if a handler is associated with a queue. // Note: this function is safe to call before SetUsbDevice() is // called... it just doesn't do anything if there is no usb // device to work with. // // Timeout is in milliseconds. Default is default USB timeout. void DoRead(int timeout = -1); // Utility function to make it easier for the user to create the // USB pure-read thread. If the user wants anything more complicated // in this background thread, he can implement it himself and call // the above DoRead() in a loop. If only the basics are needed, // then this makes it easy. // Throws Barry::ErrnoError on thread creation error. void SpinoffSimpleReadThread(); }; // // DataHandle // /// std::auto_ptr like class that handles pointers to Data, but instead of /// freeing them completely, the Data objects are turned to the /// SocketRoutingQueue from whence they came. /// class BXEXPORT DataHandle { private: SocketRoutingQueue &m_queue; mutable Data *m_data; protected: void clear() { if( m_data ) { m_queue.ReturnBuffer(m_data); m_data = 0; } } public: DataHandle(SocketRoutingQueue &q, Data *data) : m_queue(q) , m_data(data) { } DataHandle(const DataHandle &other) : m_queue(other.m_queue) , m_data(other.m_data) { // we now own the pointer other.m_data = 0; } ~DataHandle() { clear(); } Data* get() { return m_data; } Data* release() // no longer owns the pointer, and does not free it { Data *ret = m_data; m_data = 0; return ret; } // frees current pointer, and takes ownership of new one void reset(Data *next = 0) { clear(); m_data = next; } Data* operator->() { return m_data; } const Data* operator->() const { return m_data; } DataHandle& operator=(const DataHandle &other) { if( &m_queue != &other.m_queue ) throw std::logic_error("Trying to copy DataHandles of different queues!"); // remove our current data clear(); // accept the new m_data = other.m_data; // we now own it other.m_data = 0; return *this; } }; } // namespace Barry #endif barry-0.18.5/src/m_mode_base.cc0000644001161500056700000001115612242254476015610 0ustar cdfreycdfrey/// /// \file m_mode_base.cc /// Base for mode classes /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "m_mode_base.h" namespace Barry { namespace Mode { ////////////////////////////////////////////////////////////////////////////// // Mode base class Mode::Mode(Controller &con, Controller::ModeType type) : m_con(con) , m_modetype(type) , m_ModeSocket(0) { } Mode::~Mode() { } // // Open // /// Select device mode. This is required before using any other mode-based /// operations, such as GetDBDB() and LoadDatabase(). /// /// This function opens a socket to the device for communicating in Desktop /// mode. If the device requires it, specify the password with a const char* /// string in password. The password will not be stored in memory /// inside this class, only a hash will be generated from it. After /// using the hash, the hash memory will be set to 0. The application /// is responsible for safely handling the raw password data. /// /// You can retry the password by catching Barry::BadPassword and /// calling RetryPassword() with the new password. /// /// \exception Barry::Error /// Thrown on protocol error. /// /// \exception std::logic_error() /// Thrown if unsupported mode is requested, or if socket /// already open. /// /// \exception Barry::BadPassword /// Thrown when password is invalid or if not enough retries /// left in the device. /// void Mode::Open(const char *password) { if( m_ModeSocket ) { m_socket->Close(); m_socket.reset(); m_ModeSocket = 0; } m_ModeSocket = m_con.SelectMode(m_modetype); RetryPassword(password); } // // Open // /// Select device mode. This is required before using any other mode-based /// operations, such as GetDBDB() and LoadDatabase(). /// /// This function opens a socket to the device for communicating in Desktop /// mode. If the device requires it, specify the password with a const char* /// string in password. The password will not be stored in memory /// inside this class, only a hash will be generated from it. After /// using the hash, the hash memory will be set to 0. The application /// is responsible for safely handling the raw password data. /// /// It uses the provided name as the name for the socket used in this mode. /// Usually this shouldn't be needed unless using the raw channel mode. /// /// You can retry the password by catching Barry::BadPassword and /// calling RetryPassword() with the new password. /// /// \exception Barry::Error /// Thrown on protocol error. /// /// \exception std::logic_error() /// Thrown if unsupported mode is requested, or if socket /// already open. /// /// \exception Barry::BadPassword /// Thrown when password is invalid or if not enough retries /// left in the device. /// void Mode::Open(const char *password, const char *name) { if( m_ModeSocket ) { m_socket->Close(); m_socket.reset(); m_ModeSocket = 0; } m_ModeSocket = m_con.SelectMode(m_modetype, name); RetryPassword(password); } // // RetryPassword // /// Retry a failed password attempt from the first call to Open(). /// Only call this function in response to Barry::BadPassword exceptions /// that are thrown from Open(). /// /// \exception Barry::Error /// Thrown on protocol error. /// /// \exception std::logic_error() /// Thrown if in unsupported mode, or if socket already open. /// /// \exception Barry::BadPassword /// Thrown when password is invalid or if not enough retries /// left in the device. /// void Mode::RetryPassword(const char *password) { if( m_socket.get() != 0 ) throw std::logic_error(_("Socket alreay open in RetryPassword")); m_socket = m_con.OpenSocket(m_ModeSocket, password); // success... perform open-oriented setup OnOpen(); } void Mode::OnOpen() { } // FIXME - is this necessary? and if it is, wouldn't it be better // in the m_jvmdebug mode class? I'm not convinced that applications // should have to bother with socket-level details. //void Mode::Close() //{ // if( m_ModeSocket ) { // m_socket->Close(); // m_socket.reset(); // m_ModeSocket = 0; // } //} }} // namespace Barry::Mode barry-0.18.5/src/m_ipmodem.cc0000644001161500056700000003262112242254476015324 0ustar cdfreycdfrey/// /// \file m_ipmodem.cc /// Mode class for GPRS modem mode (using endpoints on /// modern devices) /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "m_ipmodem.h" #include "controller.h" #include "controllerpriv.h" #include "data.h" #include "debug.h" #include #include #include "sha1.h" namespace Barry { namespace Mode { const char special_flag[] = { 0x78, 0x56, 0x34, 0x12 }; // 0x12345678 const char start[] = { 0x01, 0, 0, 0, 0x78, 0x56, 0x34, 0x12 }; const char pw_start[] = { 0x01, 0, 0, 0, 1, 0, 0, 0, 0x78, 0x56, 0x34, 0x12 }; const char stop[] = { 0x01, 0, 0, 0, 0, 0, 0, 0, 0x78, 0x56, 0x34, 0x12 }; ////////////////////////////////////////////////////////////////////////////// // Mode::IpModem class IpModem::IpModem(Controller &con, DeviceDataCallback callback, void *callback_context) : m_con(con) , m_dev(con.GetPrivate()->m_dev) , m_continue_reading(false) , m_callback(callback) , m_callback_context(callback_context) { memset(m_session_key, 0, sizeof(m_session_key)); } IpModem::~IpModem() { try { Close(); } catch( std::exception &DEBUG_ONLY(e) ) { dout(_("Exception caught in IpModem destructor, ignoring: ") << e.what()); } } bool IpModem::SendPassword( const char *password, uint32_t seed ) { if( !password || strlen(password) == 0 ) { throw BadPassword(_("Logic error: No password provided in SendPassword."), 0, false); } int read_ep = m_con.GetProbeResult().m_epModem.read; int write_ep = m_con.GetProbeResult().m_epModem.write; unsigned char pwdigest[SHA_DIGEST_LENGTH]; unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4]; unsigned char pw_response[SHA_DIGEST_LENGTH + 8]; uint32_t new_seed; Data data; if( !password || strlen(password) == 0 ) { throw BadPassword(_("No password provided."), 0, false); } // Build the password hash // first, hash the password by itself SHA1((unsigned char *) password, strlen(password), pwdigest); // prefix the resulting hash with the provided seed memcpy(&prefixedhash[0], &seed, sizeof(uint32_t)); memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH); // hash again SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest); // Build the response packet const char pw_rsphdr[] = { 0x03, 0x00, 0x00, 0x00 }; memcpy(&pw_response[0], pw_rsphdr, sizeof(pw_rsphdr)); memcpy(&pw_response[4], pwdigest, SHA_DIGEST_LENGTH); memcpy(&pw_response[24], special_flag, sizeof(special_flag)); // Send the password response packet m_dev.BulkWrite(write_ep, pw_response, sizeof(pw_response)); m_dev.BulkRead(read_ep, data); ddout("IPModem: Read password response.\n" << data); // Added for the BB Storm 9000's second password request if( data.GetSize() >= 16 && data.GetData()[0] == 0x00 ) { try { m_dev.BulkRead(read_ep, data, 500); ddout("IPModem: Null Response Packet:\n" << data); } catch( Usb::Timeout &DEBUG_ONLY(to) ) { // do nothing on timeouts ddout("IPModem: Null Response Timeout"); } } // // check response 04 00 00 00 ....... // On the 8703e the seed is incremented, retries are reset to 10 // when the password is accepted. // // If data.GetData() + 4 is = to the orginal seed +1 or 00 00 00 00 // then the password was acceppted. // // When data.GetData() + 4 is not 00 00 00 00 then data.GetData()[8] // contains the number of password retrys left. // if( data.GetSize() >= 9 && data.GetData()[0] == 0x04 ) { memcpy(&new_seed, data.GetData() + 4, sizeof(uint32_t)); seed++; if( seed == new_seed || new_seed == 0 ) { ddout("IPModem: Password accepted.\n"); #if SHA_DIGEST_LENGTH < SB_IPMODEM_SESSION_KEY_LENGTH #error Session key field must be smaller than SHA digest #endif // Create session key - last 8 bytes of the password hash memcpy(&m_session_key[0], pwdigest + SHA_DIGEST_LENGTH - sizeof(m_session_key), sizeof(m_session_key)); // blank password hashes as we don't need these anymore memset(pwdigest, 0, sizeof(pwdigest)); memset(prefixedhash, 0, sizeof(prefixedhash)); return true; } else { ddout("IPModem: Invalid password.\n" << data); throw BadPassword(_("Password rejected by device."), data.GetData()[8], false); } } // Unknown packet ddout("IPModem: Error unknown packet.\n" << data); return false; } ////////////////////////////////////////////////////////////////////////////// // protected API / static functions void *IpModem::DataReadThread(void *userptr) { IpModem *ipmodem = (IpModem*) userptr; int read_ep = ipmodem->m_con.GetProbeResult().m_epModem.read; Data data; while( ipmodem->m_continue_reading ) { try { ipmodem->m_dev.BulkRead(read_ep, data, 5000); // is it a special code? if( data.GetSize() > 4 && memcmp(data.GetData() + data.GetSize() - 4, special_flag, sizeof(special_flag)) == 0 ) { // log, then drop it on the floor for now ddout("IPModem: Special packet:\n" << data); continue; } // call callback if available if( ipmodem->m_callback ) { (*ipmodem->m_callback)(ipmodem->m_callback_context, data.GetData(), data.GetSize()); } // else { // // append data to readCache // FIXME; // } } catch( Usb::Timeout &DEBUG_ONLY(to) ) { // do nothing on timeouts ddout("IPModem: Timeout in DataReadThread!"); } catch( std::exception &e ) { eout(_("Exception in IpModem::DataReadThread: ") << e.what()); } } return 0; } ////////////////////////////////////////////////////////////////////////////// // public API void IpModem::Open(const char *password) { int read_ep = m_con.GetProbeResult().m_epModem.read; int write_ep = m_con.GetProbeResult().m_epModem.write; unsigned char response[28]; uint32_t seed; Data data; // check that we have endpoints for the modem const Usb::EndpointPair &pair = m_con.GetProbeResult().m_epModem; if( !pair.IsComplete() ) { std::ostringstream oss; oss << _("IP Modem not supported by this device: ") << "read: " << std::hex << (unsigned int) pair.read << " write: " << std::hex << (unsigned int) pair.write << " type: " << std::hex << (unsigned int) pair.type; eout(oss.str()); throw Barry::Error(oss.str()); } // clear halt when starting out only if needed if( m_con.GetProbeResult().m_needClearHalt ) { m_dev.ClearHalt(pair.read); m_dev.ClearHalt(pair.write); } // Send stop command ddout("IPModem: Sending Stop Response:\n"); m_dev.BulkWrite(write_ep, stop, sizeof(stop)); try { m_dev.BulkRead(read_ep, data, 500); ddout("IPModem: Stop Response Packet:\n" << data); } catch( Usb::Timeout &DEBUG_ONLY(to) ) { // do nothing on timeouts ddout("IPModem: Stop Response Timeout"); } // Send start commands to figure out if the device needs a password. ddout("IPModem: Sending Start Response:\n"); m_dev.BulkWrite(write_ep, pw_start, sizeof(pw_start)); m_dev.BulkRead(read_ep, data, 5000); ddout("IPModem: Start Response Packet:\n" << data); // check for 02 00 00 00 SS SS SS SS RR 00 00 00 0a 00 00 00 PP PP PP PP PP 00 00 00 78 56 34 12 if( data.GetSize() >= 9 && data.GetData()[0] == 0x02 && memcmp(data.GetData() + data.GetSize() - 4, special_flag, sizeof(special_flag))== 0 ) { // Got a password request packet ddout("IPModem: Password request packet:\n" << data); // Check how many retries are left if( data.GetData()[8] < BARRY_MIN_PASSWORD_TRIES ) { throw BadPassword(string_vprintf(_("Fewer than %d password tries remaining in device. Refusing to proceed, to avoid device zapping itself. Use a Windows client, or re-cradle the device."), BARRY_MIN_PASSWORD_TRIES), data.GetData()[8], true); } memcpy(&seed, data.GetData() + 4, sizeof(seed)); // Send password if( !SendPassword(password, seed) ) { throw Barry::Error(_("IpModem: Error sending password.")); } // Re-send "start" packet ddout("IPModem: Re-sending Start Response:\n"); m_dev.BulkWrite(write_ep, pw_start, sizeof(pw_start)); try { m_dev.BulkRead(read_ep, data); ddout("IPModem: Start Response Packet:\n" << data); } catch( Usb::Timeout &to ) { // do nothing on timeouts ddout("IPModem: Start Response Timeout"); } } // send packet with the session_key unsigned char response_header[] = { 0x00, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0xc2, 1, 0 }; memcpy(&response[0], response_header, sizeof(response_header)); memcpy(&response[16], m_session_key, sizeof(m_session_key)); memcpy(&response[24], special_flag, sizeof(special_flag)); ddout("IPModem: Sending Session key:\n"); m_dev.BulkWrite(write_ep, response, sizeof(response)); if( data.GetSize() >= 16 ) { switch(data.GetData()[0]) { case 0x00: // Null packet break; case 0x02: // password seed received memcpy(&seed, data.GetData() + 4, sizeof(uint32_t)); if( !SendPassword( password, seed ) ) { throw Barry::Error(_("IpModem: Error sending password.")); } break; case 0x04: // command accepted break; default: // ??? ddout("IPModem: Unknown response.\n"); break; } } // see if the modem will respond to commands const char modem_command[] = { "AT\r" }; m_dev.BulkWrite(write_ep, modem_command, strlen(modem_command)); m_dev.BulkRead(read_ep, data); ddout("IPModem: Test command response.\n" << data); if( data.GetSize() >= 1 ) { switch(data.GetData()[0]) { case 0x00: // Null packet try { m_dev.BulkRead(read_ep, data, 5000); ddout("IPModem: AT Response Packet:\n" << data); } catch( Usb::Timeout &DEBUG_ONLY(to) ) { // do nothing on timeouts ddout("IPModem: AT Response Timeout"); } break; case 0x02: // password seed received if( !password || strlen(password) == 0 ) { throw BadPassword(_("This device requested a password."), data.GetSize() >= 9 ? data.GetData()[8] : 0, false); } else { // added for the Storm 9000 memcpy(&seed, data.GetData() + 4, sizeof(seed)); if( !SendPassword( password, seed ) ) { throw Barry::Error(_("IpModem: Error sending password.")); } } break; case 0x04: // command accepted break; case 0x07: // device is password protected? throw BadPassword(_("This device requires a password."), 0, false); default: // ??? ddout("IPModem: Unknown AT command response.\n"); // treat this unknown data as a serial response if( m_callback ) { (*m_callback)(m_callback_context, data.GetData(), data.GetSize()); } break; } } ddout("IPModem: Modem Ready.\n"); // spawn read thread m_continue_reading = true; int ret = pthread_create(&m_modem_read_thread, NULL, &IpModem::DataReadThread, this); if( ret ) { m_continue_reading = false; throw Barry::ErrnoError(_("IpModem: Error creating USB read thread."), ret); } } void IpModem::Write(const Data &data, int timeout) { if( data.GetSize() == 0 ) return; // nothing to do // according to Rick Scott the m_filter is not needed with the ip modem // but with the 8320 with Rogers, it doesn't seem to connect without it // If this is a performance problem, perhaps make this a runtime // option. m_dev.BulkWrite(m_con.GetProbeResult().m_epModem.write, m_filter.Write(data), timeout); } void IpModem::Close() { // This is the terminate connection sequence // that resets the modem so we can re-connect // without unpluging the USB cable or reseting // the whole device. // This works on a BB 8703e a with password. other BB's?? unsigned char end[28]; int read_ep = m_con.GetProbeResult().m_epModem.read; int write_ep = m_con.GetProbeResult().m_epModem.write; Data data; //0 0 0 0 b0 0 0 0 0 0 0 0 0 c2 1 0 + session_key + special_flag ddout("IpModem: Closing connection."); memset(end, 0, sizeof(end)); end[4] = 0xb0; end[13] = 0xc2; end[14] = 0x01; memcpy(&end[16], m_session_key, sizeof(m_session_key)); memcpy(&end[24], special_flag, sizeof(special_flag)); m_dev.BulkWrite(write_ep, end, sizeof(end)); //0 0 0 0 20 0 0 0 3 0 0 0 0 c2 1 0 + session_key + special_flag memset(end, 0, sizeof(end)); end[4] = 0x20; end[8] = 0x03; end[13] = 0xc2; end[14] = 0x01; memcpy(&end[16], m_session_key, sizeof(m_session_key)); memcpy(&end[24], special_flag, sizeof(special_flag)); m_dev.BulkWrite(write_ep, end, sizeof(end)); //0 0 0 0 30 0 0 0 0 0 0 0 0 c2 1 0 + session_key + special_flag // The session_key is set to 0x0's when there is no password. memset(end, 0, sizeof(end)); end[4] = 0x30; end[13] = 0xc2; end[14] = 0x01; memcpy(&end[16], m_session_key, sizeof(m_session_key)); memcpy(&end[24], special_flag, sizeof(special_flag)); m_dev.BulkWrite(write_ep, end, sizeof(end)); m_dev.BulkWrite(write_ep, stop, sizeof(stop)); // stop the read thread if( m_continue_reading ) { m_continue_reading = false; pthread_join(m_modem_read_thread, NULL); } else { // otherwise, drain the last read try { m_dev.BulkRead(read_ep, data, 5000); ddout("IPModem: Close read packet:\n" << data); } catch( Usb::Timeout &DEBUG_ONLY(to) ) { // do nothing on timeouts ddout("IPModem: Close Read Timeout"); } } ddout("IPmodem: Closed!"); } }} // namespace Barry::Mode barry-0.18.5/src/mimeio.h0000644001161500056700000000671512242254476014504 0ustar cdfreycdfrey/// /// \file mimeio.h /// Storage, parser, builder classes for MIME objects /// (vcard, vevent, vtodo, vjournal) /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_MIMEIO_H__ #define __BARRY_MIMEIO_H__ #include "dll.h" #include "builder.h" #include "vcard.h" #include "vevent.h" #include "vjournal.h" #include "vtodo.h" #include #include #include #include namespace Barry { class Contact; class Calendar; class CalendarAll; class Memo; class Task; // // Template classes to write MIME data to stream, from record. // template class MimeDump { public: static void Dump(std::ostream &os, const Record &rec) { os << rec << std::endl; } static bool Supported() { return false; } }; template <> class MimeDump { public: static void Dump(std::ostream &os, const Barry::Contact &rec) { Barry::Sync::vCard vcard; os << vcard.ToVCard(rec) << std::endl; } static bool Supported() { return true; } }; template <> class MimeDump { public: static void Dump(std::ostream &os, const Barry::Calendar &rec) { Barry::Sync::vTimeConverter vtc; Barry::Sync::vCalendar vcal(vtc); os << vcal.ToVCal(rec) << std::endl; } static bool Supported() { return true; } }; template <> class MimeDump { public: static void Dump(std::ostream &os, const Barry::CalendarAll &rec) { Barry::Sync::vTimeConverter vtc; Barry::Sync::vCalendar vcal(vtc); os << vcal.ToVCal(rec) << std::endl; } static bool Supported() { return true; } }; template <> class MimeDump { public: static void Dump(std::ostream &os, const Barry::Memo &rec) { Barry::Sync::vTimeConverter vtc; Barry::Sync::vJournal vjournal(vtc); os << vjournal.ToMemo(rec) << std::endl; } static bool Supported() { return true; } }; template <> class MimeDump { public: static void Dump(std::ostream &os, const Barry::Task &rec) { Barry::Sync::vTimeConverter vtc; Barry::Sync::vTodo vtodo(vtc); os << vtodo.ToTask(rec) << std::endl; } static bool Supported() { return true; } }; // // Builder class, for reading MIME stream data and loading into // a DBData record. // class BXEXPORT MimeBuilder : public Barry::Builder { std::auto_ptr m_ifs; std::istream &m_is; public: explicit MimeBuilder(const std::string &filename); explicit MimeBuilder(std::istream &is); bool BuildRecord(DBData &data, size_t &offset, const IConverter *ic); bool FetchRecord(DBData &data, const IConverter *ic); bool EndOfFile() const; // return false at end of file, true if a record was read static bool ReadMimeRecord(std::istream &is, std::string &vrec, std::vector &types); // returns true if item is a member of types, doing a // case-insensitive compare static bool IsMember(const std::string &item, const std::vector &types); }; } #endif barry-0.18.5/src/r_message.h0000644001161500056700000000316112242254476015162 0ustar cdfreycdfrey/// /// \file r_message.h /// Blackberry database record parser class for email records. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_MESSAGE_H__ #define __BARRY_RECORD_MESSAGE_H__ #include "dll.h" #include "r_message_base.h" namespace Barry { // // NOTE: All classes here must be container-safe! Perhaps add sorting // operators in the future. // /// \addtogroup RecordParserClasses /// @{ class BXEXPORT Message : public MessageBase { public: Message() { // must call this again, since base class can't call ours Clear(); } void Clear() { MessageBase::Clear(); RecType = GetDefaultRecType(); RecordId = 0; } // database name static const char * GetDBName() { return "Messages"; } static uint8_t GetDefaultRecType() { return 0; } // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const Message &msg) { msg.Dump(os); return os; } /// @} } // namespace Barry #endif barry-0.18.5/src/fifoargs.cc0000644001161500056700000001225712242254476015161 0ustar cdfreycdfrey/// /// \file fifoargs.cc /// Class for passing command line arguments via fifo instead /// of command line. /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "fifoargs.h" #include "error.h" #include "common.h" #include #include #include #include #include #include #include #include #include using namespace std; namespace Barry { ////////////////////////////////////////////////////////////////////////////// // FifoArgs class std::ostream& FifoArgs::Write(std::ostream &os) const { if( m_pin.Valid() ) os << "Pin " << m_pin.Str() << endl; if( m_password.size() ) os << "Password " << m_password << endl; if( m_log_filename.size() ) os << "LogFilename " << m_log_filename << endl; if( m_use_serial_mode ) os << "UseSerialMode" << endl; if( m_verbose ) os << "Verbose" << endl; return os; } std::istream& FifoArgs::Read(std::istream &is) { string line, token, arg; // start fresh Clear(); while( getline(is, line) ) { istringstream iss(line); iss >> token >> ws; if( token == "Pin" ) iss >> m_pin; else if( token == "Password" ) getline(iss, m_password); else if( token == "LogFilename" ) getline(iss, m_log_filename); else if( token == "UseSerialMode" ) m_use_serial_mode = true; else if( token == "Verbose" ) m_verbose = true; } return is; } void FifoArgs::Clear() { m_pin.Clear(); m_password.clear(); m_log_filename.clear(); m_use_serial_mode = false; m_verbose = false; } ////////////////////////////////////////////////////////////////////////////// // FifoServer class FifoServer::FifoServer(const FifoArgs &args) : m_args(args) , m_created(false) { int m_fifo = mkfifo(BARRY_FIFO_NAME, 0660); if( m_fifo != 0 ) throw ErrnoError(_("Cannot open Barry argument fifo"), errno); m_created = true; } FifoServer::~FifoServer() { Cleanup(); } bool FifoServer::Serve(int timeout_sec) { if( !m_created ) return false; // man fifo(7) says that opening write-only in non-blocking mode // will fail until the other side opens for read. So continue // to attempt opens until out of time. timeout_sec *= 4; while( timeout_sec-- ) { // attempt to open in non-blocking mode // // Security Note: // -------------- // This should be safe from symlink attacks, since // mkfifo(), in the constructor, will fail if any other // file or symlink already exists, and therefore we will // never get to this open() call if that fails. And if // mkfifo() succeeds, then we are guaranteed (assuming /tmp // permissions are correct) that only root or our own // user can replace the fifo with something else, such // as a symlink. // // The server side is not intended to run as root, yet // if it is, then we are still safe, due to the above logic. // The client side can run as root (depending on what pppd // does with pppob), and has no control over creation of // the fifo, but only opens it for reading, never for // creation or writing. (See FifoClient() below.) // // Therefore, we can only be attacked, via symlink, // by root or ourselves. // int fd = open(BARRY_FIFO_NAME, O_WRONLY | O_NONBLOCK); if( fd == -1 ) { usleep(250000); continue; } ostringstream oss; m_args.Write(oss); int written = write(fd, oss.str().data(), oss.str().size()); close(fd); // only success if we wrote all the data return written == (int)oss.str().size(); } // timeout return false; } void FifoServer::Cleanup() { if( m_created ) { unlink(BARRY_FIFO_NAME); m_created = false; } } ////////////////////////////////////////////////////////////////////////////// // FifoClient class FifoClient::FifoClient() { } /// Tries to open the fifo and read the arguments from it. /// If it fails in any way, or timeout, returns false. bool FifoClient::Fetch(int timeout_sec) { // See man fifo(7). Should always succeed, as long as // the file exists and permissions allow. int fd = open(BARRY_FIFO_NAME, O_RDONLY | O_NONBLOCK); if( fd == -1 ) return false; string sbuf; timeout_sec *= 4; while( timeout_sec-- ) { char buf[4096]; int r = read(fd, buf, sizeof(buf)); if( r == 0 ) { // only consider this the end of file if // we've already read something, otherwise we close // before the server has a chance to speak up if( sbuf.size() ) break; else usleep(250000); } else if( r < 0 ) { usleep(250000); continue; } else { timeout_sec++; sbuf.append(buf, r); } } close(fd); // parse istringstream iss(sbuf); m_args.Read(iss); return true; } } // Barry namespace barry-0.18.5/src/r_hhagent.h0000644001161500056700000000706112242254476015157 0ustar cdfreycdfrey/// /// \file r_hhagent.h /// Blackberry database record parser class for Handheld Agent records /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_HHAGENT_H__ #define __BARRY_RECORD_HHAGENT_H__ #include "dll.h" #include "record.h" namespace Barry { // forward declarations class IConverter; // // NOTE: All classes here must be container-safe! Perhaps add sorting // operators in the future. // /// \addtogroup RecordParserClasses /// @{ // // Handheld Agent record class // /// Represents a single record in the Handheld Agent database. /// class BXEXPORT HandheldAgent { public: typedef Barry::UnknownsType UnknownsType; // // Record fields // // contact specific data uint8_t RecType; uint32_t RecordId; std::string MEID; std::string Model; std::string Bands; std::string Pin; // may not be valid for every record std::string Version; std::string PlatformVersion; std::string Manufacturer; std::string Network; UnknownsType Unknowns; public: const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); public: HandheldAgent(); ~HandheldAgent(); uint32_t GetID() const { return RecordId; } std::string GetFullName() const; const std::string& GetEmail(unsigned int index = 0) const; // Parser / Builder API (see parser.h / builder.h) void Validate() const; uint8_t GetRecType() const { return RecType; } uint32_t GetUniqueId() const { return RecordId; } void SetIds(uint8_t Type, uint32_t Id) { RecType = Type; RecordId = Id; } void ParseHeader(const Data &data, size_t &offset); void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); void BuildHeader(Data &data, size_t &offset) const; void BuildFields(Data &data, size_t &offset, const IConverter *ic = 0) const; // operations (common among record classes) void Clear(); // erase everything void Dump(std::ostream &os) const; std::string GetDescription() const; // Sorting - use enough data to make the sorting as // consistent as possible bool operator<(const HandheldAgent &other) const; // database name static const char * GetDBName() { return "Handheld Agent"; } static uint8_t GetDefaultRecType() { return 0; } static uint32_t GetMEIDRecordId() { return 0x3000000; } static uint32_t GetUnknown1RecordId() { return 0x4000000; } static uint32_t GetUnknown2RecordId() { return 0x5000000; } static uint32_t GetUnknown3RecordId() { return 0x7000000; } static bool IsSpecial(uint32_t record_id); // utility functions static bool IsESNHex(const std::string &esn); static bool IsESNDec(const std::string &esn); static std::string ESNDec2Hex(const std::string &esn); static std::string ESNHex2Dec(const std::string &esn); // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<< (std::ostream &os, const HandheldAgent &hha) { hha.Dump(os); return os; } /// @} } // namespace Barry #endif barry-0.18.5/src/r_dbdb.cc0000644001161500056700000001176112242254476014574 0ustar cdfreycdfrey/// /// \file r_dbdb.cc /// DatabaseDatabase record parser class /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "record.h" #include "record-internal.h" #include "data.h" #include "protocol.h" #include "debug.h" #include using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // DatabaseDatabase class DatabaseDatabase::DatabaseDatabase() { } DatabaseDatabase::~DatabaseDatabase() { } template void DatabaseDatabase::ParseRec(const RecordType &rec, const unsigned char *end) { } template const unsigned char* DatabaseDatabase::ParseField(const unsigned char *begin, const unsigned char *end) { // check if there is enough data for a header const unsigned char *headend = begin + sizeof(FieldType); if( headend > end ) return headend; // get our header const FieldType *field = (const FieldType *) begin; // advance and check size begin += sizeof(FieldType) - sizeof(field->name) + ConvertHtoB(field->nameSize); if( begin > end ) // if begin==end, we are ok return begin; if( !ConvertHtoB(field->nameSize) ) // if field has no size, something's up return begin; Database db; db.Number = ConvertHtoB(field->dbNumber); db.RecordCount = ConvertHtoB(field->dbRecordCount); db.Name.assign((const char *)field->name, ConvertHtoB(field->nameSize) - 1); Databases.push_back(db); return begin; } void DatabaseDatabase::Parse(const Data &data) { // check size to make sure we have up to the DBAccess operation byte if( data.GetSize() < (SB_PACKET_DBACCESS_HEADER_SIZE + 1) ) return; MAKE_PACKET(pack, data); const unsigned char *begin = 0; const unsigned char *end = data.GetData() + data.GetSize(); switch( pack->u.db.u.response.operation ) { case SB_DBOP_GET_DBDB: // using the new protocol if( data.GetSize() > SB_PACKET_DBDB_HEADER_SIZE ) { begin = (const unsigned char *) &pack->u.db.u.response.u.dbdb.field[0]; // this while check is ok, since ParseField checks // for header size while( begin < end ) begin = ParseField(begin, end); } else dout("DatabaseDatabase: not enough data for parsing"); break; case SB_DBOP_OLD_GET_DBDB: // using the old protocol if( data.GetSize() > SB_PACKET_OLD_DBDB_HEADER_SIZE ) { begin = (const unsigned char *) &pack->u.db.u.response.u.old_dbdb.field[0]; // this while check is ok, since ParseField checks // for header size while( begin < end ) begin = ParseField(begin, end); } else dout(_("DatabaseDatabase: not enough data for parsing")); break; default: // unknown protocol dout(_("Unknown protocol")); break; } } void DatabaseDatabase::Clear() { Databases.clear(); } namespace { bool NameSort(const DatabaseDatabase::Database &one, const DatabaseDatabase::Database &two) { return one.Name < two.Name; } bool CountSort(const DatabaseDatabase::Database &one, const DatabaseDatabase::Database &two) { return one.RecordCount < two.RecordCount; } } void DatabaseDatabase::SortByName() { std::sort(Databases.begin(), Databases.end(), NameSort); } void DatabaseDatabase::SortByRecordCount() { std::sort(Databases.begin(), Databases.end(), CountSort); } unsigned int DatabaseDatabase::GetTotalRecordCount() const { unsigned int sum = 0; DatabaseArrayType::const_iterator b = Databases.begin(); for( ; b != Databases.end(); ++b ) { sum += b->RecordCount; } return sum; } bool DatabaseDatabase::GetDBNumber(const std::string &name, unsigned int &number) const { DatabaseArrayType::const_iterator b = Databases.begin(); for( ; b != Databases.end(); ++b ) if( b->Name == name ) { number = b->Number; return true; } return false; } bool DatabaseDatabase::GetDBName(unsigned int number, std::string &name) const { DatabaseArrayType::const_iterator b = Databases.begin(); for( ; b != Databases.end(); ++b ) if( b->Number == number ) { name = b->Name; return true; } return false; } void DatabaseDatabase::Dump(std::ostream &os) const { DatabaseArrayType::const_iterator b = Databases.begin(); os << _("Database database:\n"); for( ; b != Databases.end(); b++ ) { os << _(" Database: ") << "0x" << setbase(16) << b->Number << " '" << b->Name << "' (" << _("records: ") << setbase(10) << b->RecordCount << ")\n"; } } } // namespace Barry barry-0.18.5/src/builder.h0000644001161500056700000001575412242254476014656 0ustar cdfreycdfrey/// /// \file builder.h /// Virtual protocol packet builder wrapper /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_BUILDER_H__ #define __BARRY_BUILDER_H__ #include "dll.h" #include "data.h" #include #include // // This macro can be used to automatically generate code for all known // record types. Just #undef HANDLE_BUILDER, then #define it to whatever // you need, then use ALL_KNOWN_BUILDER_TYPES. See parser.cc for // various examples. // // These are sorted so their GetDBName()'s will display in alphabetical order. // #define ALL_KNOWN_BUILDER_TYPES \ HANDLE_BUILDER(Contact) \ HANDLE_BUILDER(Calendar) \ HANDLE_BUILDER(CalendarAll) \ HANDLE_BUILDER(ContentStore) \ HANDLE_BUILDER(Memo) \ HANDLE_BUILDER(Task) \ namespace Barry { // forward declarations class IConverter; // // Builder class // /// Base class for the builder functor hierarchy. /// /// This defines the API used by the Controller and Packet classes /// for building a raw device record to write to the device. /// class BXEXPORT Builder { public: Builder() {} virtual ~Builder() {} /// Called to build the record field data. Store the raw data /// in data, using offset to know where to write. Be sure to /// update offset, and be sure to adjust the size of the data /// packet (possibly with Data::ReleaseBuffer()). /// /// Returns true if successful, and false if at the end of /// the series. Note that if EndOfFile() is false after /// this function returns false, then there may be another /// series available, which the next call to BuildRecord() /// will determine. /// virtual bool BuildRecord(DBData &data, size_t &offset, const IConverter *ic) = 0; /// Same as BuildRecord, but does not care about any offsets. /// The caller should call DBData::GetOffset() afterward /// to discover if there is an offset to the result. /// /// This is usually the fastest of the two functions, since /// extra copying may be required if a specific offset is /// given. When building records from Record classes, both /// functions are the same speed. But when building records /// from the device, the device decides the offset, so FetchRecord() /// is faster, since BuildRecord requires a copy to adjust /// to the right offset. /// /// The caller should use the function that results in the least /// amount of copying for the caller. If the caller doesn't /// care about where the resulting record is in data, use /// FetchRecord(). /// virtual bool FetchRecord(DBData &data, const IConverter *ic) = 0; /// Sometimes a builder can have multiple databases stored /// in it, so when Build/Fetch returns false, check if there /// is more data with this function. This function is /// not used by database-oriented functions, but by pipe- /// oriented functions. virtual bool EndOfFile() const = 0; }; // // DBDataBuilder // /// Wrapper class around a DBData object, to make it easy to pass a DBData /// object into a function or API that requires a builder. The main /// advantage to this is that the Builder API allows for movement of /// data, depending on the required offsets. /// class BXEXPORT DBDataBuilder : public Builder { const DBData &m_orig; public: explicit DBDataBuilder(const DBData &orig); virtual ~DBDataBuilder(); virtual bool BuildRecord(DBData &data, size_t &offset, const IConverter *ic); virtual bool FetchRecord(DBData &data, const IConverter *ic); virtual bool EndOfFile() const; }; // // SetDBData // /// Contains the proper way to convert a record object into a DBData object. /// template void SetDBData(const RecordT &rec, DBData &data, size_t &offset, const IConverter *ic) { // Make sure record is valid before building it. // This can throw Barry::ValidationError rec.Validate(); // Build the DBData object data.SetVersion(DBData::REC_VERSION_1); data.SetOffset(offset); data.SetDBName(RecordT::GetDBName()); data.SetIds(rec.GetRecType(), rec.GetUniqueId()); rec.BuildHeader(data.UseData(), offset); rec.BuildFields(data.UseData(), offset, ic); } // // RecordBuilder template class // /// Template class for easy creation of specific protocol packet builder /// objects. This template takes the following template arguments: /// /// - RecordT: One of the record classes in record.h /// - StorageT: A custom storage functor class. An object of this type /// will be called as a function with empty Record as an /// argument. The storage class is expected to fill the /// record object in preparation for building the packet /// out of that data. These calls happen on the fly as the data /// is sent to the device over USB, so it should not block forever. /// /// Example SaveDatabase() call: /// ///
/// FIXME
/// 
/// template class RecordBuilder : public Builder { StorageT *m_storage; bool m_owned; bool m_record_loaded; bool m_end_of_file; RecordT m_rec; public: /// Constructor that references an externally managed storage object. RecordBuilder(StorageT &storage) : m_storage(&storage) , m_owned(false) , m_record_loaded(false) , m_end_of_file(false) { } /// Constructor that references a locally managed storage object. /// The pointer passed in will be stored, and freed when this class /// is destroyed. It is safe to call this constructor with /// a 'new'ly created storage object. RecordBuilder(StorageT *storage) : m_storage(storage) , m_owned(true) , m_record_loaded(false) , m_end_of_file(false) { } ~RecordBuilder() { if( this->m_owned ) delete m_storage; } virtual bool BuildRecord(DBData &data, size_t &offset, const IConverter *ic) { if( m_end_of_file ) return false; if( !(*m_storage)(m_rec, *this) ) { m_end_of_file = true; return false; } SetDBData(m_rec, data, offset, ic); return true; } virtual bool FetchRecord(DBData &data, const IConverter *ic) { size_t offset = 0; return BuildRecord(data, offset, ic); } virtual bool EndOfFile() const { return m_end_of_file; } }; // // RecordFetch template class // /// Generic record fetch class, to help with using records without /// builder classes. /// template class RecordFetch { const RecordT &m_rec; mutable bool m_done; public: RecordFetch(const RecordT &rec) : m_rec(rec), m_done(false) {} bool operator()(RecordT &rec, Builder &) const { if( m_done ) return false; rec = m_rec; m_done = true; return true; } }; } // namespace Barry #endif barry-0.18.5/src/ldifio.h0000644001161500056700000000403512242254476014464 0ustar cdfreycdfrey/// /// \file ldifio.h /// Storage, parser, and builder classes for ldif operations. /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_LDIFIO_H__ #define __BARRY_LDIFIO_H__ #include "dll.h" #include "ldif.h" #include #include #include namespace Barry { class Builder; // // LdifStore // /// Storage class suitable for use in a RecordParser<> or RecordBuilder<>. /// Be sure to use the input constructors for RecordBuilder<> objects /// and output constructors for RecordParser<> objects. /// /// Examples: /// Read contacts from an ldif stream on stdin: /// new RecordBuilder( new LdifStore(cin) ); /// /// Write contacts to an ldif stream on stdout: /// new RecordParser( /// new LdifStore(cout, baseDN, dnAttr) ); /// class BXEXPORT LdifStore { std::auto_ptr m_ifs; std::auto_ptr m_ofs; std::istream &m_is; std::ostream &m_os; bool m_end_of_file; Barry::ContactLdif m_ldif; public: // input constructors LdifStore(const std::string &filename); LdifStore(std::istream &is); // output constructors LdifStore(const std::string &filename, const std::string &baseDN, const std::string &dnattr); LdifStore(std::ostream &os, const std::string &baseDN, const std::string &dnattr); // storage operator void operator() (const Contact &rec); // retrieval operator bool operator() (Contact &rec, const Builder &builder); }; } #endif barry-0.18.5/src/tzwrapper.cc0000644001161500056700000001603212242254476015412 0ustar cdfreycdfrey/// /// \file tzwrapper.cc /// Timezone adjustment class, wrapping the TZ environment /// variable to make struct tm -> time_t conversions easier. /// /* Copyright (C) 2010-2013, Chris Frey , To God be the glory Released to the public domain. Included in Barry and Barrified the namespace July 2010 */ #include "tzwrapper.h" #include #include #include using namespace std; namespace Barry { namespace Sync { time_t utc_mktime(struct tm *utctime) { time_t result; struct tm tmp, check; // loop, converting "local time" to time_t and back to utc tm, // and adjusting until there are no differences... this // automatically takes care of DST issues. // do first conversion tmp = *utctime; tmp.tm_isdst = -1; result = mktime(&tmp); if( result == (time_t)-1 ) return (time_t)-1; if( gmtime_r(&result, &check) == NULL ) return (time_t)-1; // loop until match while( check.tm_year != utctime->tm_year || check.tm_mon != utctime->tm_mon || check.tm_mday != utctime->tm_mday || check.tm_hour != utctime->tm_hour || check.tm_min != utctime->tm_min ) { tmp.tm_min += utctime->tm_min - check.tm_min; tmp.tm_hour += utctime->tm_hour - check.tm_hour; tmp.tm_mday += utctime->tm_mday - check.tm_mday; tmp.tm_year += utctime->tm_year - check.tm_year; tmp.tm_isdst = -1; result = mktime(&tmp); if( result == (time_t)-1 ) return (time_t)-1; gmtime_r(&result, &check); if( gmtime_r(&result, &check) == NULL ) return (time_t)-1; } return result; } struct tm* iso_to_tm(const char *timestamp, struct tm *result, bool &utc, bool *zone, int *zoneminutes) { memset(result, 0, sizeof(struct tm)); // handle YYYY-MM-DDTHH:MM:SS.uuu-HH:MM format // by stripping out the dashes and colons string ts = timestamp; string::iterator i = ts.begin(); bool date = true; while( i != ts.end() ) { if( *i == 'T' ) date = false; if( (date && *i == '-') || *i == ':' ) ts.erase(i); else ++i; } int found = sscanf(ts.c_str(), "%04d%02d%02dT%02d%02d%02d", &(result->tm_year), &(result->tm_mon), &(result->tm_mday), &(result->tm_hour), &(result->tm_min), &(result->tm_sec)); result->tm_year -= 1900; result->tm_mon -= 1; result->tm_isdst = -1; if( found == 3 ) { // only a date available, so force time to 00:00:00 result->tm_hour = 0; result->tm_min = 0; result->tm_sec = 0; } else if( found != 6 ) { return 0; } utc = ts.find('Z', 15) != string::npos; if( zone && zoneminutes ) { *zone = false; size_t neg = ts.find('-', 15); size_t pos = ts.find('+', 15); if( neg != string::npos || pos != string::npos ) { // capture timezone offset size_t it = neg != string::npos ? neg : pos; it++; string offset = ts.substr(it); int hour, min; found = sscanf(offset.c_str(), "%02d%02d", &hour, &min); if( offset.size() == 4 && found == 2 ) { *zone = true; *zoneminutes = hour * 60 + min; if( neg != string::npos ) *zoneminutes *= -1; } } } return result; } std::string tm_to_iso(const struct tm *t, bool utc) { char tmp[128]; int cc = snprintf(tmp, sizeof(tmp), "%04d%02d%02dT%02d%02d%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec ); if( cc < 0 || (size_t)cc >= sizeof(tmp) ) return ""; if( utc ) { if( (size_t)cc >= (sizeof(tmp) - 1) ) return ""; // not enough room for Z tmp[cc++] = 'Z'; tmp[cc] = 0; } return tmp; } TzWrapper& TzWrapper::SetOffset(int zoneminutes) { // // Set a custom TZ with the offset in hours/minutes. // // Note that TZ sees negative offsets as *ahead* of // UTC and positive offsets as behind UTC. Therefore, // Berlin, one hour ahead of UTC is -01:00 and // Canada/Eastern standard time is +05:00. // // This is exactly opposite to the ISO timestamp format // which would have +01:00 and -05:00 respectively, // and therefore exactly opposite to the sign of zoneminutes. // // We use a fake timezone name of XXX here, since it // doesn't matter, we are only interested in the offset. char buf[128]; sprintf(buf, "XXX%c%02d:%02d", (zoneminutes < 0 ? '+' : '-'), abs(zoneminutes) / 60, abs(zoneminutes) % 60 ); return Set(buf); } time_t TzWrapper::iso_mktime(const char *timestamp) { bool utc, zone; struct tm t; int zoneminutes; if( !iso_to_tm(timestamp, &t, utc, &zone, &zoneminutes) ) return (time_t)-1; TzWrapper tzw; if( utc ) { tzw.SetUTC(); } else if( zone ) { tzw.SetOffset(zoneminutes); } return tzw.mktime(&t); } }} // namespace Barry::Sync #ifdef TZ_TEST_MODE #include using namespace std; using namespace Barry::Sync; int main() { time_t now = time(NULL); cout << "TZ: " << TzWrapper().ctime(&now); cout << "UTC: " << TzWrapper("").ctime(&now); cout << "UTC: " << TzWrapper().SetUTC().ctime(&now); cout << "SysLocaltime: " << TzWrapper().SetUTC().SetSysLocal().ctime(&now); cout << "TZ: " << TzWrapper().SetUTC().SetDefault().ctime(&now); cout << "Canada/Eastern: " << TzWrapper("Canada/Eastern").ctime(&now); cout << "Canada/Pacific: " << TzWrapper("Canada/Pacific").ctime(&now); { TzWrapper tzw("UTC"); cout << "UTC: " << ctime(&now); } cout << "TZ: " << ctime(&now); // test iso_mktime()... the test values assume a Canada/Eastern TZ cout << "Using Canada/Eastern:" << endl; TzWrapper tzw("Canada/Eastern"); const char *iso1 = "20100430T231500"; const char *iso2 = "20100501T031500Z"; time_t t1 = TzWrapper::iso_mktime(iso1); time_t t2 = TzWrapper::iso_mktime(iso2); cout << " " << iso1 << ": (" << t1 << ") " << ctime(&t1); cout << iso2 << ": (" << t2 << ") " << ctime(&t2); if( t1 == t2 ) cout << "t1 == t2: passed" << endl; else cout << "t1 != t2: ERROR" << endl; time_t t3 = TzWrapper::iso_mktime("2010-05-01T03:15:00.000Z"); cout << ctime(&t3); if( t2 == t3 ) cout << "t2 == t3: passed" << endl; else cout << "t2 != t3: ERROR" << endl; time_t t4 = TzWrapper::iso_mktime("2010-05-01T04:15:00.000+01:00"); cout << ctime(&t4); if( t3 == t4 ) cout << "t3 == t4: passed" << endl; else cout << "t3 != t4: ERROR" << endl; time_t t5 = TzWrapper::iso_mktime("2010-05-01T00:15:00.000-03:00"); cout << ctime(&t5); if( t4 == t5 ) cout << "t4 == t5: passed" << endl; else cout << "t4 != t5: ERROR: t4: " << t4 << " t5: " << t5 << endl; if( TzWrapper::iso_mktime("20100430") != (time_t)-1 ) cout << "Date check: passed" << endl; else cout << "Date check: ERROR" << endl; cout << "t1: " << tm_to_iso(gmtime(&t1), true) << endl; bool utc, zone; int zoneminutes; struct tm zonetest; if( !iso_to_tm("2010-05-01T04:15:00.000-", &zonetest, utc, &zone, &zoneminutes) ) cout << "iso_to_tm failed wrongly: ERROR" << endl; if( zone ) cout << "zone true?: ERROR" << endl; else cout << "zone fail check: passed" << endl; if( !iso_to_tm("2010-05-01T04:15:00.000-010", &zonetest, utc, &zone, &zoneminutes) ) cout << "iso_to_tm failed wrongly: ERROR" << endl; if( zone ) cout << "zone true?: ERROR" << endl; else cout << "zone fail check2: passed" << endl; } #endif barry-0.18.5/src/vjournal.h0000644001161500056700000000362612242254476015063 0ustar cdfreycdfrey/// /// \file vjournal.h /// Conversion routines for vjournals (VCALENDAR, etc) /// /* Copyright (C) 2008-2009, Nicolas VIVIEN Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_SYNC_VJOURNAL_H__ #define __BARRY_SYNC_VJOURNAL_H__ #include "dll.h" #include "vbase.h" #include "vformat.h" #include "r_memo.h" #include #include namespace Barry { namespace Sync { // // vJournal // /// Class for converting between RFC 2445 iCalendar data format, /// and the Barry::Memo class. /// class BXEXPORT vJournal : public vBase { // external reference vTimeConverter &m_vtc; // data to pass to external requests char *m_gJournalData; // dynamic memory returned by vformat()... can // be used directly by the plugin, without // overmuch allocation and freeing (see Extract()) std::string m_vJournalData; // copy of m_gJournalData, for C++ use Barry::Memo m_BarryMemo; protected: bool HasMultipleVJournals() const; public: explicit vJournal(vTimeConverter &vtc); ~vJournal(); const std::string& ToMemo(const Barry::Memo &memo); const Barry::Memo& ToBarry(const char *vjournal, uint32_t RecordId); char* ExtractVJournal(); void Clear(); // This is the v-name of the innermost BEGIN/END block static const char* GetVName() { return "VJOURNAL"; } }; }} // namespace Barry::Sync #endif barry-0.18.5/src/restore.cc0000644001161500056700000002520212242254476015036 0ustar cdfreycdfrey/// /// \file restore.cc /// Builder class for restoring from Barry Backup files /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "restore.h" #include "tarfile.h" #include "error.h" #include #include #include #include #include using namespace std; namespace Barry { namespace { int CountFiles(reuse::TarFile &tar, const Barry::Restore::DBListType &restoreList, Barry::Restore::DBListType *available, bool default_all_db) { int count = 0; std::string name, last_name; bool good = false; while( tar.ReadNextFilenameOnly(name) ) { std::string::size_type pos = name.rfind('/'); if( pos == std::string::npos ) continue; // bad name std::string dbname = name.substr(0, pos); if( dbname != last_name ) { last_name = dbname; good = (default_all_db && restoreList.size() == 0) || restoreList.IsSelected(dbname); if( good && available ) available->push_back(dbname); } if( good ) count++; } return count; } } ////////////////////////////////////////////////////////////////////////////// // Static Restore members /// Splits a tarpath of the form "DBName/DBID" into separate string values. /// Returns true if successful, false if tarpath is a bad name. bool Restore::SplitTarPath(const std::string &tarpath, std::string &dbname, std::string &dbid_text, uint8_t &dbrectype, uint32_t &dbid) { std::string::size_type pos = tarpath.rfind('/'); if( pos == std::string::npos ) return false; // bad name dbname = tarpath.substr(0, pos); dbid_text = tarpath.substr(pos + 1); if( dbname.size() == 0 || dbid_text.size() == 0 ) return false; // bad name std::istringstream iss(dbid_text); unsigned int temp; iss >> std::hex >> dbid >> temp; dbrectype = (uint8_t) temp; return true; } ////////////////////////////////////////////////////////////////////////////// // Restore - constructors Restore::Restore(const std::string &tarpath, bool default_all_db) : m_tarpath(tarpath) , m_default_all_db(default_all_db) , m_tar_record_state(RS_EMPTY) , m_rec_type(0) , m_unique_id(0) { try { m_tar.reset( new reuse::TarFile(tarpath.c_str(), false, &reuse::gztar_ops_nonthread, true) ); } catch( reuse::TarFile::TarError &te ) { throw Barry::RestoreError(te.what()); } } Restore::~Restore() { } ////////////////////////////////////////////////////////////////////////////// // Restore - Protected helpers bool Restore::IsSelected(const std::string &dbName) const { // if in skip list, always return false, // if nothing is in the main list, use default // otherwise, only return true if specifically selected if( m_dbSkipList.IsSelected(dbName) ) return false; else if( m_dbList.size() == 0 ) return m_default_all_db; else return m_dbList.IsSelected(dbName); } ////////////////////////////////////////////////////////////////////////////// // Restore - Public API void Restore::AddDB(const std::string &dbName) { if( find(m_dbList.begin(), m_dbList.end(), dbName) == m_dbList.end() ) { // only add it if it is not already in the list m_dbList.push_back(dbName); } } void Restore::Add(const DBListType &dbList) { for( DBListType::const_iterator i = dbList.begin(); i != dbList.end(); ++i ) { AddDB(*i); } } void Restore::Add(const DatabaseDatabase &dbdb) { for( DatabaseDatabase::DatabaseArrayType::const_iterator i = dbdb.Databases.begin(); i != dbdb.Databases.end(); ++i ) { AddDB(i->Name); } } void Restore::AddSkipDB(const std::string &dbName) { if( find(m_dbSkipList.begin(), m_dbSkipList.end(), dbName) == m_dbSkipList.end() ) { // only add it if it is not already in the list m_dbSkipList.push_back(dbName); } } void Restore::SkipCurrentDB() { // skip all records until next DB try { Restore::RetrievalState state; while( (state = Retrieve(m_record_data)) == RS_NEXT ) { std::cerr << _("Skipping: ") << m_current_dbname << "/" << m_tar_id_text << std::endl; m_tar_record_state = RS_EMPTY; } if( state == RS_DBEND ) { // process the end of database, so that user is free // to call GetNextMeta() or Retrieve() or BuildRecord() m_tar_record_state = RS_NEXT; } } catch( reuse::TarFile::TarError & ) { m_tar_record_state = RS_EOF; } } unsigned int Restore::GetRecordTotal() const { return GetRecordTotal(m_tarpath, m_dbList, m_default_all_db); } unsigned int Restore::GetRecordTotal(const std::string &tarpath, const DBListType &dbList, bool default_all_db) { unsigned int count = 0; std::auto_ptr tar; try { // do a scan through the tar file tar.reset( new reuse::TarFile(tarpath.c_str(), false, &reuse::gztar_ops_nonthread, true) ); count = CountFiles(*tar, dbList, 0, default_all_db); } catch( reuse::TarFile::TarError &te ) { throw Barry::RestoreError(te.what()); } return count; } Barry::Restore::DBListType Restore::GetDBList() const { return GetDBList(m_tarpath); } Barry::Restore::DBListType Restore::GetDBList(const std::string &tarpath) { std::auto_ptr tar; DBListType available, empty; try { // do a scan through the tar file tar.reset( new reuse::TarFile(tarpath.c_str(), false, &reuse::gztar_ops_nonthread, true) ); CountFiles(*tar, empty, &available, true); return available; } catch( reuse::TarFile::TarError &te ) { throw Barry::RestoreError(te.what()); } } bool Restore::GetNextMeta(DBData &data) { // always use m_record_data here, so that we don't lose access // to the actual record data for future calls to BuildRecord() // and FetchRecord() if( m_tar_record_state == RS_EMPTY ) { Retrieve(m_record_data); } // fill in the meta data that will be returned in the next call // to BuildRecord() or FetchRecord()... this is only valid if // the state is RS_NEXT switch( m_tar_record_state ) { case RS_NEXT: data.SetVersion(Barry::DBData::REC_VERSION_1); data.SetDBName(m_current_dbname); data.SetIds(m_rec_type, m_unique_id); data.SetOffset(0); return true; default: return false; } } ////////////////////////////////////////////////////////////////////////////// // Barry::Builder overrides Restore::RetrievalState Restore::Retrieve(Data &record_data) { // don't do anything unless we're empty if( m_tar_record_state != RS_EMPTY ) return m_tar_record_state; // search for a valid record for(;;) { // load record data from tar file std::string filename; if( !m_tar->ReadNextFile(filename, record_data) ) { // assume end of file return m_tar_record_state = RS_EOF; } m_tar_record_state = RS_UNKNOWN; // split record filename into dbname and ID std::string dbname; if( !SplitTarPath(filename, dbname, m_tar_id_text, m_rec_type, m_unique_id) ) { // invalid filename, skip it std::cerr << _("Skipping invalid tar record: ") << filename << std::endl; continue; } // are we working on the same dbname as last time? // if so, go ahead! if( m_current_dbname == dbname ) { return m_tar_record_state = RS_NEXT; } // DIFFERENT DBNAME from here on down! m_tar_record_state = RS_DBEND; // does the filter allow this record? // if not, skip it and continue looking if( !IsSelected(dbname) ) { continue; } // all checks pass, load the new dbname, and return DBEND // if we are on a dbname boundary if( m_current_dbname.size() == 0 ) { // this is the first time through Retrieve, so ok m_tar_record_state = RS_NEXT; } m_current_dbname = dbname; return m_tar_record_state; } } bool Restore::BuildRecord(Barry::DBData &data, size_t &offset, const Barry::IConverter *ic) { // in this case, we are loading into m_record_data anyway, // so no special handling is needed, like FetchRecord() needs. switch( Retrieve(m_record_data) ) { case RS_NEXT: { data.SetVersion(Barry::DBData::REC_VERSION_1); data.SetDBName(m_current_dbname); data.SetIds(m_rec_type, m_unique_id); data.SetOffset(offset); int packet_size = offset + m_record_data.GetSize(); unsigned char *buf = data.UseData().GetBuffer(packet_size); memcpy(buf + offset, m_record_data.GetData(), m_record_data.GetSize()); offset += m_record_data.GetSize(); data.UseData().ReleaseBuffer(packet_size); // clear loaded flag, as it has now been used m_tar_record_state = RS_EMPTY; return true; } case RS_EMPTY: case RS_UNKNOWN: default: throw std::logic_error(_("Invalid state in Restore::BuildRecord()")); case RS_DBEND: // process the end of database by returning false // the next round will be valid, so set to RS_NEXT m_tar_record_state = RS_NEXT; return false; case RS_EOF: // always return false at end of file return false; } } bool Restore::FetchRecord(Barry::DBData &data, const Barry::IConverter *ic) { // if the record has not yet been loaded, we can optimize // the buffer, and pass in our own... otherwise, just copy // the current buffer from m_record_data // // it is assumed here that Builder users will not alternate // between calls to BuildRecord() and FetchRecord() // if( m_tar_record_state == RS_EMPTY ) { // BUT, if RS_DBEND is the next value, then we need // to save the data for the next round... this // optimization is almost more bother than it's worth :-) if( Retrieve(data.UseData()) == RS_DBEND ) { m_record_data = data.GetData(); m_tar_record_state = RS_NEXT; return false; } } else { data.UseData() = m_record_data; } switch( m_tar_record_state ) { case RS_NEXT: data.SetVersion(Barry::DBData::REC_VERSION_1); data.SetDBName(m_current_dbname); data.SetIds(m_rec_type, m_unique_id); data.SetOffset(0); // clear loaded flag, as it has now been used m_tar_record_state = RS_EMPTY; return true; case RS_EMPTY: case RS_UNKNOWN: default: throw std::logic_error(_("Invalid state in Restore::FetchRecord()")); case RS_DBEND: // process the end of database by returning false // the next round will be valid, so set to RS_NEXT m_tar_record_state = RS_NEXT; return false; case RS_EOF: // always return false at end of file return false; } } bool Restore::EndOfFile() const { return m_tar_record_state == RS_EOF; } } // namespace Barry barry-0.18.5/src/record.h0000644001161500056700000010665312242254476014505 0ustar cdfreycdfrey/// /// \file record.h /// Blackberry database record classes. Help translate data /// from data packets to useful structurs, and back. /// This header provides the common types and classes /// used by the general record parser classes in the /// r_*.h files. Only application-safe API stuff goes in /// here. Internal library types go in record-internal.h /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_H__ #define __BARRY_RECORD_H__ #include "dll.h" #include #include #include #include #include #include #ifdef WINCE /* The WinCE compiler v14.00.60131 doesn't like using operator= from base classes, so don't * confuse it with a using directive. */ #define USE_BASE_ASSIGNMENT_OPERATOR #else #define USE_BASE_ASSIGNMENT_OPERATOR using base_type::operator=; #endif // forward declarations namespace Barry { class Data; } namespace Barry { // // NOTE: All classes here must be container-safe! Perhaps add sorting // operators in the future. // // stream-based wrapper to avoid printing strings that contain // the \r carriage return characters class BXEXPORT Cr2LfWrapper { friend BXEXPORT std::ostream& operator<< (std::ostream &os, const Cr2LfWrapper &str); const std::string &m_str; public: explicit Cr2LfWrapper(const std::string &str) : m_str(str) { } }; BXEXPORT std::ostream& operator<< (std::ostream &os, const Cr2LfWrapper &str); /// Struct wrapper for time_t, to make sure that it has its own type, /// for overload purposes. Some systems, like QNX, use a uint32_t typedef. /// /// If Time contains 0, it is considered invalid/uninitialized when using /// IsValid(). Validity has no affect on comparison operators. struct BXEXPORT TimeT { time_t Time; TimeT() : Time(0) { } explicit TimeT(time_t t) : Time(t) { } void clear() { Time = 0; } bool IsValid() const { return Time > 0; } bool operator< (const Barry::TimeT &other) const { return Time < other.Time; } bool operator== (const Barry::TimeT &other) const { return Time == other.Time; } bool operator!= (const Barry::TimeT &other) const { return !operator==(other); } }; BXEXPORT std::ostream& operator<< (std::ostream &os, const TimeT &t); struct BXEXPORT CommandTableCommand { unsigned int Code; std::string Name; }; class BXEXPORT CommandTable { public: typedef CommandTableCommand Command; typedef std::vector CommandArrayType; CommandArrayType Commands; private: BXLOCAL const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end); public: CommandTable(); ~CommandTable(); void Parse(const Data &data, size_t offset); void Clear(); // returns 0 if unable to find command name, which is safe, since // 0 is a special command that shouldn't be in the table anyway unsigned int GetCommand(const std::string &name) const; void Dump(std::ostream &os) const; }; BXEXPORT inline std::ostream& operator<< (std::ostream &os, const CommandTable &command) { command.Dump(os); return os; } struct BXEXPORT RecordStateTableState { unsigned int Index; uint32_t RecordId; bool Dirty; unsigned int RecType; std::string Unknown2; }; class BXEXPORT RecordStateTable { public: typedef RecordStateTableState State; typedef unsigned int IndexType; typedef std::map StateMapType; StateMapType StateMap; private: mutable IndexType m_LastNewRecordId; private: BXLOCAL const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end); public: RecordStateTable(); ~RecordStateTable(); void Parse(const Data &data); void Clear(); bool GetIndex(uint32_t RecordId, IndexType *pFoundIndex = 0) const; uint32_t MakeNewRecordId() const; void Dump(std::ostream &os) const; }; BXEXPORT inline std::ostream& operator<< (std::ostream &os, const RecordStateTable &rst) { rst.Dump(os); return os; } struct BXEXPORT DatabaseItem { unsigned int Number; unsigned int RecordCount; std::string Name; }; class BXEXPORT DatabaseDatabase { public: typedef DatabaseItem Database; typedef std::vector DatabaseArrayType; DatabaseArrayType Databases; private: template void ParseRec(const RecordType &rec, const unsigned char *end); template const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end); public: DatabaseDatabase(); ~DatabaseDatabase(); void Parse(const Data &data); void Clear(); void SortByName(); void SortByRecordCount(); unsigned int GetTotalRecordCount() const; // returns true on success, and fills target bool GetDBNumber(const std::string &name, unsigned int &number) const; bool GetDBName(unsigned int number, std::string &name) const; void Dump(std::ostream &os) const; }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const DatabaseDatabase &dbdb) { dbdb.Dump(os); return os; } struct UnknownData { std::string raw_data; const std::string::value_type* data() const { return raw_data.data(); } std::string::size_type size() const { return raw_data.size(); } void assign(const std::string::value_type *s, std::string::size_type n) { raw_data.assign(s, n); } bool operator==(const UnknownData &other) const { return raw_data == other.raw_data; } bool operator!=(const UnknownData &other) const { return !operator==(other); } bool operator< (const UnknownData &other) const { return raw_data < other.raw_data; } }; struct BXEXPORT UnknownField { uint8_t type; UnknownData data; bool operator==(const UnknownField &other) const { return type == other.type && data == other.data; } bool operator!=(const UnknownField &other) const { return !operator==(other); } bool operator< (const UnknownField &other) const { return type < other.type && data < other.data; } }; typedef std::vector UnknownsType; BXEXPORT std::ostream& operator<< (std::ostream &os, const UnknownsType &unknowns); // simple string email type and list... keep this a simple string list, // so it can be reused for other address-like data, like phone numbers. // If you need something more complex, use EmailAddress below or // create a new type. typedef std::string EmailType; class BXEXPORT EmailList : public std::vector { public: typedef std::vector base_type; public: using base_type::size; using base_type::begin; using base_type::end; using base_type::at; using base_type::rbegin; using base_type::rend; using base_type::empty; using base_type::resize; using base_type::reserve; using base_type::front; using base_type::back; using base_type::push_back; using base_type::pop_back; using base_type::insert; using base_type::erase; using base_type::swap; using base_type::clear; using base_type::operator[]; USE_BASE_ASSIGNMENT_OPERATOR }; BXEXPORT std::ostream& operator<< (std::ostream &os, const EmailList &list); // struct, attempting to combine name + email address, for mail struct BXEXPORT EmailAddress { std::string Name; std::string Email; EmailAddress() { } /// Converts "Name " into Name + Address /// Will also handle just a plain address too. explicit EmailAddress(const std::string &complex_address); void clear() { Name.clear(); Email.clear(); } size_t size() const { return Name.size() + Email.size(); } bool operator==(const EmailAddress &other) const { return Name == other.Name && Email == other.Email; } bool operator!=(const EmailAddress &other) const { return !operator==(other); } bool operator< (const EmailAddress &other) const { // sort by email only, since not every address has a name return Email < other.Email; } }; BXEXPORT std::ostream& operator<<(std::ostream &os, const EmailAddress &msga); class BXEXPORT EmailAddressList : public std::vector { public: std::string ToCommaSeparated() const; void AddCommaSeparated(const std::string &list); }; BXEXPORT std::ostream& operator<<(std::ostream &os, const EmailAddressList &elist); struct BXEXPORT PostalAddress { std::string Address1, Address2, Address3, City, Province, PostalCode, Country; std::string GetLabel() const; void Clear(); bool HasData() const { return Address1.size() || Address2.size() || Address3.size() || City.size() || Province.size() || PostalCode.size() || Country.size(); } bool operator==(const PostalAddress &other) const { return Address1 == other.Address1 && Address2 == other.Address2 && Address3 == other.Address3 && City == other.City && Province == other.Province && PostalCode == other.PostalCode && Country == other.Country; } bool operator!=(const PostalAddress &other) const { return !operator==(other); } bool operator< (const PostalAddress &other) const { return GetLabel() < other.GetLabel(); } }; BXEXPORT std::ostream& operator<<(std::ostream &os, const PostalAddress &msga); struct BXEXPORT Date { int Month; // 0 to 11 int Day; // 1 to 31 int Year; // exact number, eg. 2008 Date() : Month(0), Day(0), Year(0) {} explicit Date(const struct tm *timep); bool HasData() const { return Month || Day || Year; } void Clear(); void ToTm(struct tm *timep) const; std::string ToYYYYMMDD() const; std::string ToBBString() const; // converts to Blackberry string // format of DD/MM/YYYY bool FromTm(const struct tm *timep); bool FromBBString(const std::string &str); bool FromYYYYMMDD(const std::string &str); bool operator==(const Date &other) const { return Month == other.Month && Day == other.Day && Year == other.Year; } bool operator!=(const Date &other) const { return !operator==(other); } bool operator< (const Date &other) const { // YYYYMMDD as integer unsigned int v1 = Year * 10000 + Month * 100 + Day; unsigned int v2 = other.Year * 10000 + other.Month * 100 + other.Day; return v1 < v2; } }; BXEXPORT std::ostream& operator<<(std::ostream &os, const Date &date); class BXEXPORT CategoryList : public std::vector { public: typedef std::vector base_type; public: /// Parses the given comma delimited category string into /// this CategoryList object, appending each token to the vector. /// Will clear vector beforehand. void CategoryStr2List(const std::string &str); /// Turns the current vectory into a comma delimited category /// string suitable for use in Calendar, Task, and Memo /// protocol values. void CategoryList2Str(std::string &str) const; USE_BASE_ASSIGNMENT_OPERATOR }; BXEXPORT std::ostream& operator<<(std::ostream &os, const CategoryList &cl); ////////////////////////////////////////////////////////////////////////////// // Generic Field Handles /// \addtogroup GenericFieldHandles /// Generic field handle classes, used to reference and work /// with record members in a flexible, indirect way. /// /// There are two ways to access device record data. The obvious /// way is to instantiate a record class, such as Contact, and /// access the public data members of that class to read and /// write. If you always work with the same record class, this /// works fine. /// /// The other way is to have a list of pointers to members. /// For example, you may wish to compare two records, without /// actually caring what data is in each one. You can compare /// at the record class level, with Contact one, two; and then /// if( one == two ), but this will not tell you what field in /// the record changed. /// /// This last feature is what Generic Field Handles are meant to /// fix. Each record class will contain a GetFieldHandles() /// member function, which will return a list of type /// FieldHandle::ListT (currently a std::vector<>) /// objects, for that specific record. For example, Contact /// would fill the ListT with FieldHandle objects. /// Each FieldHandle<> object contains a C++ pointer-to-member, /// which the FieldHandle refers to, as well as a FieldIdentity /// object. The FieldIdentity object contains various identitying /// information, such as the C++ variable name, an English /// (or localized language) display name of the field, suitable /// for user prompts, and other data more useful to the library. /// /// The FieldHandle<> object has two member functions: Value() /// and Member(). /// /// Value() will call a callback function with the _value_ of /// the variable that FieldHandle<> points to. For example, /// if the FieldHandle<> points to a std::string record member /// variable, then Value() will pass that string value in as /// an argument, along with a reference to the FieldIdentity /// object. Value() requires a callback object and a record /// object to perform this callback. /// /// Member() will call a callback function/functor with the /// pointer-to-member pointer and the FieldIdentity object. /// This allows the programmer to create a functor with multiple /// record objects, perhaps two objects to compare individual /// fields, and use the pointer-to-member to access the field /// data as needed. /// /// For now, all data and callbacks are const, meaning that it /// is not possible (without const_casting) to write to the /// record via the pointers-to-members. This design decision /// may need to be revisited someday, depending on its usefulness. /// /// @{ // // FieldIdentity // /// This class holds data that identifies a given field in a record. /// This is fairly constant data, referenced by the FieldHandle class. /// The information in here should be enough to show the user what kind /// of field this is. /// struct BXEXPORT FieldIdentity { // useful public data const char *Name; // C++ name of field member variable in // record class std::string DisplayName; // localized display name of field // in UTF8 // FIXME - should we leave localization // to the application? // subfield detection bool HasSubfields; // true if this field has subfields const char *ParentName; // name of field member variable that // this field is a member of, or NULL // if this field is a member of the // record class. // For example, Contact::PostalAddress // would have HasSubfields == true, // and ParentName == NULL, while all // its subfield strings would have // HasSubfields == false and // ParentName == "WorkAddress" or // "HomeAddress". // The application could then decide // whether to process only main fields, // some of which have subfields, // or only individual subfields. // internal field data int FieldTypeCode; // device type code for this field. // if -1, then this is a conglomerate // C++ field, such as // Contact::PostalAddress, not a device // field. // If -1, then none of the following // fields are valid. const char *Ldif; // matching LDIF field name, or NULL const char *ObjectClass; // matching LDIF object class, or NULL bool IconvNeeded; // if true, the device's data needs to // be passed through an IConverter FieldIdentity(const char *name, const std::string &display_name, int type_code = -1, bool iconvneeded = false, const char *ldif = 0, const char *oclass = 0, bool has_sub = false, const char *parent = 0 ) : Name(name) , DisplayName(display_name) , HasSubfields(has_sub) , ParentName(parent) , FieldTypeCode(type_code) , Ldif(ldif) , ObjectClass(oclass) , IconvNeeded(iconvneeded) { } }; // // EnumConstants // /// This is the base class for the hierarchy of classes to define /// enum record members. This is the base class, which contains the /// common code for creating and defining a list of enum constants for /// a given enum field. The next derived class is EnumFieldBase, /// which defines the virtual API for talking to a given enum field /// in a given record. The next derived class is EnumField, /// which implements the pointer-to-member and virtual API for a given /// enum type in a given record class. /// /// For example, the Bookmark record class has the following enum field: /// ///
///	enum BrowserIdentityType
///	{
///		IdentityAuto = 0,
///		IdentityBlackBerry,
///		IdentityFireFox,
///		IdentityInternetExplorer,
///		IdentityUnknown
///	};
///	BrowserIdentityType BrowserIdentity;
/// 
/// /// The EnumConstants class will hold a vector of EnumConstant structs /// defining each of the identity constants: Auto, BlackBerry, FireFox, /// InternetExplorer, and Unknown. /// /// The derived class EnumFieldBase will define two additional /// pure virtual API calls: GetValue(const Bookmark&) and /// SetValue(Bookmark&, int). /// /// Finally, the derived class EnumField /// will implement the virtual API, and contain a pointer-to-member to /// the Bookmark::BrowserIdentity member field. /// /// The FieldHandle class will hold a pointer to /// EnumFieldBase, which can hold a pointer to a specific /// EnumField<> object, one object for each of Bookmark's enum types, /// of which there are currently 3. /// class BXEXPORT EnumConstants { public: /// This defines one of the enum constants being defined. /// For example, for an enum declaration like: /// enum Mine { A, B, C }; then this struct could contain /// a definition for A, B, or C, but only one at at time. /// All three would be defined by the EnumConstantList. struct EnumConstant { const char *Name; //< C++ name of enum constant std::string DisplayName; //< user-friendly name / meaning int Value; //< constant enum value EnumConstant(const char *name, const std::string &display, int value) : Name(name) , DisplayName(display) , Value(value) { } }; typedef std::vector EnumConstantList; private: EnumConstantList m_constants; public: virtual ~EnumConstants() {} /// Adds a constant definition to the list void AddConstant(const char *name, const std::string &display, int val); /// Returns a vector of EnumConstant objects, describing all enum /// constants valid for this enum field. const EnumConstantList& GetConstantList() const { return m_constants; } /// Returns the EnumConstant for the given value. /// Throws std::logic_error if not found. const EnumConstant& GetConstant(int value) const; /// Returns the constant name (C++ name) based on the given value. /// Throws std::logic_error if not found. const char* GetName(int value) const; /// Returns the display name based on the given value. /// Throws std::logic_error if not found. const std::string& GetDisplayName(int value) const; /// Returns true if the value matches one of the constants in the list. bool IsConstantValid(int value) const; }; // // FieldValueHandlerBase // /// This is a pure virtual base class, defining the various types that /// record fields can be. To be able to handle all the types of data /// in all records, override these virtual functions to do with the /// data as you wish. /// /// All data from the records and fields will be passed in by value. /// i.e. if field is string data, the overloaded std::string handler /// will be called, and a refernce to the string will be passed in. /// /// The advantage of using this virtual class is that less code will be /// generated by templates. The disadvantage is that this is less flexible. /// You will only get called for one field and record at a time. /// So you can't do comparisons this way. /// class BXEXPORT FieldValueHandlerBase { public: virtual ~FieldValueHandlerBase() {} /// For type std::string virtual void operator()(const std::string &v, const FieldIdentity &id) const = 0; /// For type EmailAddressList virtual void operator()(const EmailAddressList &v, const FieldIdentity &id) const = 0; /// For type Barry::TimeT virtual void operator()(const Barry::TimeT &v, const FieldIdentity &id) const = 0; /// For type uint8_t virtual void operator()(const uint8_t &v, const FieldIdentity &id) const = 0; /// For type uint16_t virtual void operator()(const uint16_t &v, const FieldIdentity &id) const = 0; /// For type uint32_t virtual void operator()(const uint32_t &v, const FieldIdentity &id) const = 0; /// For type uint64_t virtual void operator()(const uint64_t &v, const FieldIdentity &id) const = 0; /// For type bool virtual void operator()(const bool &v, const FieldIdentity &id) const = 0; /// For type int32_t virtual void operator()(const int32_t &v, const FieldIdentity &id) const = 0; /// For type EmailList virtual void operator()(const EmailList &v, const FieldIdentity &id) const = 0; /// For type Date virtual void operator()(const Date &v, const FieldIdentity &id) const = 0; /// For type CategoryList virtual void operator()(const CategoryList &v, const FieldIdentity &id) const = 0; /// For type PostalAddress virtual void operator()(const PostalAddress &v, const FieldIdentity &id) const = 0; /// For type UnknownsType virtual void operator()(const UnknownsType &v, const FieldIdentity &id) const = 0; }; /// /// EnumFieldBase /// template class EnumFieldBase : public EnumConstants { public: /// Return value of enum in rec virtual int GetValue(const RecordT &rec) const = 0; /// Set value of enum in rec /// Throws std::logic_error if value is out of range virtual void SetValue(RecordT &rec, int value) = 0; }; /// /// EnumField /// template class EnumField : public EnumFieldBase { EnumT RecordT::* m_mp; public: explicit EnumField(EnumT RecordT::* mp) : m_mp(mp) { } virtual int GetValue(const RecordT &rec) const { return rec.*m_mp; } virtual void SetValue(RecordT &rec, int value) { if( !this->IsConstantValid(value) ) throw std::logic_error("Bad enum value in EnumField"); rec.*m_mp = (EnumT) value; } }; // // FieldHandle // /// This is a template class that handles pointers to members of multiple /// types of data and multiple types of records. /// /// This class contains a union of all known data pointers in all records. /// Therefore this class can hold a pointer to member of any record class. /// /// To do something with the field that this FieldHandle<> class refers to, /// call either Value() or Member() with appropriate callback functors. /// Value will pass a reference to the field. You can use an object /// derived from FieldValueHandlerBase here. Member() will pass a pointer /// to member. Your functor will need to contain the record data in order /// to access its data via the pointer to member. /// /// The template functor callback that you pass into member must be /// capable of this: /// ///
///	template <class RecordT>
///	struct Callback
///	{
///		RecordT m_rec;
///
///		void operator()(typename FieldHandle::PostalPointer pp,
///			const FieldIdentity &id) const
///		{
///			PostalAddress pa = m_rec.*(pp.m_PostalAddress);
///			std::string val = pa.*(pp.m_PostalField);
///			...
///		}
///
///		template <class TypeT>
///		void operator()(TypeT RecordT::* mp,
///				const FieldIdentity &id) const
///		{
///			TypeT val = m_rec.*mp;
///			...
///		}
///	};
/// 
/// /// You don't have to use a TypeT template, but if you don't, then you must /// support all field types that the record class you're processing uses. /// /// template class FieldHandle { public: typedef FieldHandle Self; typedef std::vector ListT; // Need to use this in the union, so no constructor allowed struct PostalPointer { PostalAddress RecordT::* m_PostalAddress; std::string PostalAddress::* m_PostalField; }; // So use a factory function static PostalPointer MakePostalPointer(PostalAddress RecordT::* p1, std::string PostalAddress::* p2) { PostalPointer pp; pp.m_PostalAddress = p1; pp.m_PostalField = p2; return pp; } private: union PointerUnion { std::string RecordT::* m_string; // index 0 EmailAddressList RecordT::* m_EmailAddressList; // 1 Barry::TimeT RecordT::* m_time; // 2 PostalPointer m_postal; // 3 uint8_t RecordT::* m_uint8; // 4 uint32_t RecordT::* m_uint32; // 5 EmailList RecordT::* m_EmailList; // 6 Date RecordT::* m_Date; // 7 CategoryList RecordT::* m_CategoryList; // 8 // GroupLinksType RecordT::* m_GroupLinksType; // 9 UnknownsType RecordT::* m_UnknownsType; // 10 bool RecordT::* m_bool; // 11 uint64_t RecordT::* m_uint64; // 12 uint16_t RecordT::* m_uint16; // 13 PostalAddress RecordT::* m_PostalAddress; // 14 // used by non-union m_enum below: // 15 int32_t RecordT::* m_int32; // 16 }; int m_type_index; PointerUnion m_union; EnumFieldBase *m_enum; // never freed, since this is a // static list, existing to end of // program lifetime FieldIdentity m_id; public: // 0 FieldHandle(std::string RecordT::* mp, const FieldIdentity &id) : m_type_index(0) , m_enum(0) , m_id(id) { m_union.m_string = mp; } // 1 FieldHandle(EmailAddressList RecordT::* mp, const FieldIdentity &id) : m_type_index(1) , m_enum(0) , m_id(id) { m_union.m_EmailAddressList = mp; } // 2 FieldHandle(Barry::TimeT RecordT::* mp, const FieldIdentity &id) : m_type_index(2) , m_enum(0) , m_id(id) { m_union.m_time = mp; } // 3 FieldHandle(const PostalPointer &pp, const FieldIdentity &id) : m_type_index(3) , m_enum(0) , m_id(id) { m_union.m_postal = pp; } // 4 FieldHandle(uint8_t RecordT::* mp, const FieldIdentity &id) : m_type_index(4) , m_enum(0) , m_id(id) { m_union.m_uint8 = mp; } // 5 FieldHandle(uint32_t RecordT::* mp, const FieldIdentity &id) : m_type_index(5) , m_enum(0) , m_id(id) { m_union.m_uint32 = mp; } // 6 FieldHandle(EmailList RecordT::* mp, const FieldIdentity &id) : m_type_index(6) , m_enum(0) , m_id(id) { m_union.m_EmailList = mp; } // 7 FieldHandle(Date RecordT::* mp, const FieldIdentity &id) : m_type_index(7) , m_enum(0) , m_id(id) { m_union.m_Date = mp; } // 8 FieldHandle(CategoryList RecordT::* mp, const FieldIdentity &id) : m_type_index(8) , m_enum(0) , m_id(id) { m_union.m_CategoryList = mp; } // 9 // FieldHandle(GroupLinksType RecordT::* mp, const FieldIdentity &id) // : m_type_index(9) // , m_enum(0) // , m_id(id) // { // m_union.m_GroupLinksType = mp; // } // 10 FieldHandle(UnknownsType RecordT::* mp, const FieldIdentity &id) : m_type_index(10) , m_enum(0) , m_id(id) { m_union.m_UnknownsType = mp; } // 11 FieldHandle(bool RecordT::* mp, const FieldIdentity &id) : m_type_index(11) , m_enum(0) , m_id(id) { m_union.m_bool = mp; } // 12 FieldHandle(uint64_t RecordT::* mp, const FieldIdentity &id) : m_type_index(12) , m_enum(0) , m_id(id) { m_union.m_uint64 = mp; } // 13 FieldHandle(uint16_t RecordT::* mp, const FieldIdentity &id) : m_type_index(13) , m_enum(0) , m_id(id) { m_union.m_uint16 = mp; } // 14 FieldHandle(PostalAddress RecordT::* mp, const FieldIdentity &id) : m_type_index(14) , m_enum(0) , m_id(id) { m_union.m_PostalAddress = mp; } // 15 FieldHandle(EnumFieldBase *enum_, const FieldIdentity &id) : m_type_index(15) , m_enum(enum_) , m_id(id) { } // 16 FieldHandle(int32_t RecordT::* mp, const FieldIdentity &id) : m_type_index(16) , m_enum(0) , m_id(id) { m_union.m_int32 = mp; } /// Extracts FieldIdentity object from FieldHandle<> const FieldIdentity& GetIdentity() const { return m_id; } /// Calls the matching virtual function in FieldValueHandlerBase, /// passing in the value of the field that this FieldHandle<> /// refers to, and a referenct to the FieldIdentity object. /// Caller must pass in a RecordT object as well. void Value(const FieldValueHandlerBase &vh, const RecordT &rec) const { switch( m_type_index ) { case 0: vh(rec.*(m_union.m_string), m_id); break; case 1: vh(rec.*(m_union.m_EmailAddressList), m_id); break; case 2: vh(rec.*(m_union.m_time), m_id); break; case 3: vh(rec.*(m_union.m_postal.m_PostalAddress).*(m_union.m_postal.m_PostalField), m_id); break; case 4: vh(rec.*(m_union.m_uint8), m_id); break; case 5: vh(rec.*(m_union.m_uint32), m_id); break; case 6: vh(rec.*(m_union.m_EmailList), m_id); break; case 7: vh(rec.*(m_union.m_Date), m_id); break; case 8: vh(rec.*(m_union.m_CategoryList), m_id); break; // case 9: // vh(rec.*(m_union.m_GroupLinksType), m_id); // break; case 10: vh(rec.*(m_union.m_UnknownsType), m_id); break; case 11: vh(rec.*(m_union.m_bool), m_id); break; case 12: vh(rec.*(m_union.m_uint64), m_id); break; case 13: vh(rec.*(m_union.m_uint16), m_id); break; case 14: vh(rec.*(m_union.m_PostalAddress), m_id); break; case 15: vh(m_enum->GetValue(rec), m_id); break; case 16: vh(rec.*(m_union.m_int32), m_id); break; default: throw std::logic_error("Unknown field handle type index"); } } /// Calls the callback functor with two arguments: the pointer to /// member that this FieldHandle<> contains, and the FieldIdentity /// object. It is assumed that the functor will either contain /// or know where to find one or more records of type RecordT. template void Member(const CallbackT &func) const { switch( m_type_index ) { case 0: func(m_union.m_string, m_id); break; case 1: func(m_union.m_EmailAddressList, m_id); break; case 2: func(m_union.m_time, m_id); break; case 3: func(m_union.m_postal, m_id); break; case 4: func(m_union.m_uint8, m_id); break; case 5: func(m_union.m_uint32, m_id); break; case 6: func(m_union.m_EmailList, m_id); break; case 7: func(m_union.m_Date, m_id); break; case 8: func(m_union.m_CategoryList, m_id); break; // case 9: // func(m_union.m_GroupLinksType, m_id); // break; case 10: func(m_union.m_UnknownsType, m_id); break; case 11: func(m_union.m_bool, m_id); break; case 12: func(m_union.m_uint64, m_id); break; case 13: func(m_union.m_uint16, m_id); break; case 14: func(m_union.m_PostalAddress, m_id); break; case 15: func(m_enum, m_id); break; case 16: func(m_union.m_int32, m_id); break; default: throw std::logic_error("Unknown field handle type index"); } } }; /// Factory function to create a FieldHandle<> object. template FieldHandle MakeFieldHandle(TypeT RecordT::* tp, const FieldIdentity &id) { return FieldHandle(tp, id); } /// Calls FieldHandle<>::Member() for each defined field for a given record /// type. Takes a FieldHandle<>::ListT containing FieldHandle<> objects, /// and calls Member(func) for each one. template void ForEachField(const HandlesT &handles, const CallbackT &func) { typename HandlesT::const_iterator b = handles.begin(), e = handles.end(); for( ; b != e; ++b ) { b->Member(func); } } /// Calls FieldHandle<>::Value() for each defined field for a given record. /// Takes a RecordT object and calls Value(vh, rec) for each FieldHandle<> /// object in the record's FieldHandles set. template void ForEachFieldValue(const RecordT &rec, const FieldValueHandlerBase &vh) { typename FieldHandle::ListT::const_iterator b = RecordT::GetFieldHandles().begin(), e = RecordT::GetFieldHandles().end(); for( ; b != e; ++b ) { b->Value(vh, rec); } } // // FieldHandle setup macros // // #undef and #define the following macros to override these macros for you: // // CONTAINER_OBJECT_NAME - the new FieldHandles will be .push_back()'d into // this container // RECORD_CLASS_NAME - the name of the record class you are defining, // i.e. Barry::Contact, or Barry::Calendar // // plain field, no connection to device field #define FHP(name, display) \ CONTAINER_OBJECT_NAME.push_back( \ FieldHandle(&RECORD_CLASS_NAME::name, \ FieldIdentity(#name, display))) // record field with direct connection to device field, no LDIF data #define FHD(name, display, type_code, iconv) \ CONTAINER_OBJECT_NAME.push_back( \ FieldHandle(&RECORD_CLASS_NAME::name, \ FieldIdentity(#name, display, type_code, iconv, \ 0, 0))) // record field with direct connection to device field, with LDIF data #define FHL(name, display, type_code, iconv, ldif, oclass) \ CONTAINER_OBJECT_NAME.push_back( \ FieldHandle(&RECORD_CLASS_NAME::name, \ FieldIdentity(#name, display, type_code, iconv, \ ldif, oclass))) // a subfield of a conglomerate field, with direct connection to device field, // with LDIF data #define FHS(name, subname, display, type, iconv, ldif, oclass) \ CONTAINER_OBJECT_NAME.push_back( \ FieldHandle( \ FieldHandle::MakePostalPointer( \ &RECORD_CLASS_NAME::name, \ &PostalAddress::subname), \ FieldIdentity(#name "::" #subname, display, \ type, iconv, ldif, oclass, \ false, #name))) // record conglomerate field, which has subfields #define FHC(name, display) \ CONTAINER_OBJECT_NAME.push_back( \ FieldHandle(&RECORD_CLASS_NAME::name, \ FieldIdentity(#name, display, \ -1, false, 0, 0, true, 0))) // create a new EnumField<> and add it to the list... use the new_var_name // to add constants with FHE_CONST below #define FHE(new_var_name, record_field_type, record_field_name, display) \ EnumField \ *new_var_name = new \ EnumField \ (&RECORD_CLASS_NAME::record_field_name); \ CONTAINER_OBJECT_NAME.push_back( \ FieldHandle(new_var_name, \ FieldIdentity(#record_field_name, display))) // same as FHE, but for when RECORD_CLASS_NAME is a template argument #define FHET(new_var_name, record_field_type, record_field_name, display) \ EnumField \ *new_var_name = new \ EnumField \ (&RECORD_CLASS_NAME::record_field_name); \ CONTAINER_OBJECT_NAME.push_back( \ FieldHandle(new_var_name, \ FieldIdentity(#record_field_name, display))) // add constant to enum created above #define FHE_CONST(var, name, display) \ var->AddConstant(#name, display, RECORD_CLASS_NAME::name) /// @} } // namespace Barry /// \addtogroup RecordParserClasses /// Parser and data storage classes. These classes take a /// Database Database record and convert them into C++ objects. /// Each of these classes are safe to be used in standard /// containers, and are meant to be used in conjunction with the /// RecordParser<> template when calling Controller::LoadDatabase(). /// @{ /// @} #ifndef __BARRY_LIBRARY_BUILD__ // Include all parser classes, to make it easy for the application to use. #include "r_calendar.h" #include "r_calllog.h" #include "r_bookmark.h" #include "r_contact.h" #include "r_cstore.h" #include "r_memo.h" #include "r_message.h" #include "r_servicebook.h" #include "r_task.h" #include "r_pin_message.h" #include "r_saved_message.h" #include "r_sms.h" #include "r_folder.h" #include "r_timezone.h" #include "r_hhagent.h" #endif #endif barry-0.18.5/src/error.cc0000644001161500056700000000467412242254476014516 0ustar cdfreycdfrey/// /// \file error.cc /// Common exception classes for the Barry library /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "error.h" #include #include #include using namespace std; namespace Barry { ////////////////////////////////////////////////////////////////////////////// // BadSize exception BadSize::BadSize(const char *msg, unsigned int data_size, unsigned int required_size) : Barry::Error(GetMsg(msg, data_size, required_size)) , m_packet_size(0) , m_data_buf_size(data_size) , m_required_size(required_size) { } BadSize::BadSize(unsigned int packet_size, unsigned int data_buf_size, unsigned int required_size) : Barry::Error(GetMsg(packet_size, data_buf_size, required_size)) , m_packet_size(packet_size) , m_data_buf_size(data_buf_size) , m_required_size(required_size) { } std::string BadSize::GetMsg(const char *msg, unsigned int d, unsigned int r) { std::ostringstream oss; oss << msg << ": " << _("Bad packet size, not enough data: ") << _("DataSize(): ") << d << ". " << _("Required size: ") << r; return oss.str(); } std::string BadSize::GetMsg(unsigned int p, unsigned int d, unsigned int r) { std::ostringstream oss; oss << _("Bad packet size. Packet: ") << p << ". " << _("DataSize(): ") << d << ". " << _("Required size: ") << r; return oss.str(); } ////////////////////////////////////////////////////////////////////////////// // ErrnoError exception ErrnoError::ErrnoError(const std::string &msg) : Barry::Error(msg) , m_errno(0) { } ErrnoError::ErrnoError(const std::string &msg, int err) : Barry::Error(GetMsg(msg, err)) , m_errno(err) { } std::string ErrnoError::GetMsg(const std::string &msg, int err) { std::ostringstream oss; oss << msg << ": (errno " << err << ") " << strerror(err); return oss.str(); } } // namespace Barry barry-0.18.5/src/a_application.h0000644001161500056700000000245012242254476016020 0ustar cdfreycdfrey/// /// \file a_application.h /// ALX Application class based on CODSection class /// /* Copyright (C) 2010, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_A_APPLICATION_H__ #define __BARRY_A_APPLICATION_H__ #include #include "dll.h" #include "a_codsection.h" namespace Barry { namespace ALX { class BXEXPORT Application : public CODSection { public: Application(void); Application(const xmlpp::SaxParser::AttributeList& attrs); virtual ~Application(void); virtual void Dump(std::ostream &os) const; }; inline std::ostream& operator<<(std::ostream& os, const Application& app) { app.Dump(os); return os; } } // namespace ALX } // namespace Barry #endif barry-0.18.5/src/vformat.h0000644001161500056700000001623112242254476014675 0ustar cdfreycdfrey/* * Copyright (C) 2003 Ximian, Inc. 2005 Armin Bauer * * Copyright (C) 2003 Ximian, Inc. * * 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. * * Author: Chris Toshok (toshok@ximian.com) * Author: Armin Bauer (armin.bauer@opensync.org) * */ #ifndef _VFORMAT_H #define _VFORMAT_H #include "dll.h" #include #include #ifdef __cplusplus extern "C" { #endif typedef enum { VFORMAT_CARD_21, VFORMAT_CARD_30, VFORMAT_NOTE, VFORMAT_EVENT_10, VFORMAT_EVENT_20, VFORMAT_TODO_10, VFORMAT_TODO_20, VFORMAT_JOURNAL } b_VFormatType; typedef struct b_VFormat { //b_VFormatType type; GList *attributes; } b_VFormat; #define CRLF "\r\n" typedef enum { VF_ENCODING_RAW, /* no encoding */ VF_ENCODING_BASE64, /* base64 */ VF_ENCODING_QP, /* quoted-printable */ VF_ENCODING_8BIT } b_VFormatEncoding; typedef struct b_VFormatAttribute { char *block; /* "vtimezone/standard", or "vevent", depending on current begin/end location... may be null */ char *group; char *name; GList *params; /* b_VFormatParam */ GList *values; GList *decoded_values; b_VFormatEncoding encoding; gboolean encoding_set; } b_VFormatAttribute; typedef struct b_VFormatParam { char *name; GList *values; /* GList of char*'s*/ } b_VFormatParam; /*b_VFormat *vcard_new(b_VFormatType type); b_VFormat *vcard_new_from_string (const char *str, b_VFormatType type); //char *vcard_to_string(VFormat *card, VFormatType format); VFormat *vnote_new(void); VFormat *vnote_new_from_string(const char *str); //char *vnote_to_string(VFormat *note); VFormat *vevent_new(void); VFormat *vevent_new_from_string(const char *str); //char *vevent_to_string(VFormat *event); VFormat *vtodo_new(void); VFormat *vtodo_new_from_string(const char *str);*/ //char *vtodo_to_string(VFormat *todo); /* mostly for debugging */ b_VFormat *b_vformat_new(void); b_VFormat *b_vformat_new_from_string(const char *str); void b_vformat_dump_structure(b_VFormat *format); char *b_vformat_to_string(b_VFormat *evc, b_VFormatType type); time_t b_vformat_time_to_unix(const char *inptime); void b_vformat_free(b_VFormat *format); /* attributes */ b_VFormatAttribute *b_vformat_attribute_new (const char *attr_group, const char *attr_name); void b_vformat_attribute_free (b_VFormatAttribute *attr); b_VFormatAttribute *b_vformat_attribute_copy (b_VFormatAttribute *attr); void b_vformat_remove_attributes (b_VFormat *vformat, const char *attr_group, const char *attr_name); void b_vformat_remove_attribute (b_VFormat *vformat, b_VFormatAttribute *attr); void b_vformat_add_attribute (b_VFormat *vformat, b_VFormatAttribute *attr); void b_vformat_add_attribute_with_value (b_VFormat *vformat, b_VFormatAttribute *attr, const char *value); void b_vformat_add_attribute_with_values (b_VFormat *vformat, b_VFormatAttribute *attr, ...); void b_vformat_attribute_add_value (b_VFormatAttribute *attr, const char *value); void b_vformat_attribute_set_value (b_VFormatAttribute *attr, int nth, const char *value); void b_vformat_attribute_add_value_decoded (b_VFormatAttribute *attr, const char *value, int len); void b_vformat_attribute_add_values (b_VFormatAttribute *attr, ...); void b_vformat_attribute_remove_values (b_VFormatAttribute *attr); void b_vformat_attribute_remove_params (b_VFormatAttribute *attr); b_VFormatAttribute *b_vformat_find_attribute (b_VFormat *evc, const char *name, int nth, const char *block); /* attribute parameters */ b_VFormatParam* b_vformat_attribute_param_new (const char *param_name); void b_vformat_attribute_param_free (b_VFormatParam *param); b_VFormatParam* b_vformat_attribute_param_copy (b_VFormatParam *param); void b_vformat_attribute_add_param (b_VFormatAttribute *attr, b_VFormatParam *param); b_VFormatParam *b_vformat_attribute_find_param(b_VFormatAttribute *attr, const char *name, int level); void b_vformat_attribute_add_param_with_value (b_VFormatAttribute *attr, const char *name, const char *value); void b_vformat_attribute_add_param_with_values (b_VFormatAttribute *attr, b_VFormatParam *param, ...); void b_vformat_attribute_param_add_value (b_VFormatParam *param, const char *value); void b_vformat_attribute_param_add_values (b_VFormatParam *param, ...); void b_vformat_attribute_param_remove_values (b_VFormatParam *param); gboolean b_vformat_attribute_has_param(b_VFormatAttribute *attr, const char *name); /* b_VFormat* accessors. nothing returned from these functions should be freed by the caller. */ GList* b_vformat_get_attributes (b_VFormat *vformat); const char* b_vformat_attribute_get_group (b_VFormatAttribute *attr); const char* b_vformat_attribute_get_name (b_VFormatAttribute *attr); const char* b_vformat_attribute_get_block (b_VFormatAttribute *attr); GList* b_vformat_attribute_get_values (b_VFormatAttribute *attr); /* GList elements are of type char* */ GList* b_vformat_attribute_get_values_decoded (b_VFormatAttribute *attr); /* GList elements are of type GString* */ const char *b_vformat_attribute_get_nth_value(b_VFormatAttribute *attr, int nth); /* special accessors for single valued attributes */ gboolean b_vformat_attribute_is_single_valued (b_VFormatAttribute *attr); char* b_vformat_attribute_get_value (b_VFormatAttribute *attr); GString* b_vformat_attribute_get_value_decoded (b_VFormatAttribute *attr); GList* b_vformat_attribute_get_params (b_VFormatAttribute *attr); const char* b_vformat_attribute_param_get_name (b_VFormatParam *param); GList* b_vformat_attribute_param_get_values (b_VFormatParam *param); const char *b_vformat_attribute_param_get_nth_value(b_VFormatParam *param, int nth); /* special TYPE= parameter predicate (checks for TYPE=@typestr */ gboolean b_vformat_attribute_has_type (b_VFormatAttribute *attr, const char *typestr); /* Utility functions. */ char* b_vformat_escape_string (const char *str, b_VFormatType type); char* b_vformat_unescape_string (const char *str); #ifdef __cplusplus } #endif #endif /* _VFORMAT_H */ barry-0.18.5/src/vtodo.h0000644001161500056700000000354312242254476014354 0ustar cdfreycdfrey/// /// \file vtodo.h /// Conversion routines for vtodos (VCALENDAR, etc) /// /* Copyright (C) 2008-2009, Nicolas VIVIEN Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_SYNC_VTODO_H__ #define __BARRY_SYNC_VTODO_H__ #include "dll.h" #include "vbase.h" #include "vformat.h" #include "r_task.h" #include #include namespace Barry { namespace Sync { // // vTodo // /// Class for converting between RFC 2445 iCalendar data format, /// and the Barry::Task class. /// class BXEXPORT vTodo : public vBase { // external reference vTimeConverter &m_vtc; // data to pass to external requests char *m_gTodoData; // dynamic memory returned by vformat()... can // be used directly by the plugin, without // overmuch allocation and freeing (see Extract()) std::string m_vTodoData; // copy of m_gJournalData, for C++ use Barry::Task m_BarryTask; protected: bool HasMultipleVTodos() const; public: vTodo(vTimeConverter &vtc); ~vTodo(); const std::string& ToTask(const Barry::Task &task); const Barry::Task& ToBarry(const char *vtodo, uint32_t RecordId); char* ExtractVTodo(); void Clear(); // This is the v-name of the innermost BEGIN/END block static const char* GetVName() { return "VTODO"; } }; }} // namespace Barry::Sync #endif barry-0.18.5/src/m_desktoptmpl.h0000644001161500056700000000562212242254476016103 0ustar cdfreycdfrey/// /// \file m_desktoptmpl.h /// Ease of use templates for the Desktop mode class /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_M_DESKTOPTMPL_H__ #define __BARRY_M_DESKTOPTMPL_H__ #include "dll.h" #include "m_desktop.h" #include "parser.h" #include "builder.h" namespace Barry { namespace Mode { BXEXPORT void LoadDatabase(unsigned int dbId, Parser &parser); BXEXPORT void SaveDatabase(unsigned int dbId, Builder &builder); template void Desktop::LoadDatabaseByType(StorageT &store) { unsigned int dbId = this->GetDBID( RecordT::GetDBName() ); Barry::RecordParser parser(store); this->LoadDatabase(dbId, parser); } template void Desktop::SaveDatabaseByType(StorageT &store) { unsigned int dbId = this->GetDBID( RecordT::GetDBName() ); Barry::RecordBuilder build(store); SaveDatabase(dbId, build); } template void Desktop::LoadDatabaseByName(const std::string &name, StorageT &store) { #undef HANDLE_PARSER #define HANDLE_PARSER(rtype) \ else if( name == Barry::rtype::GetDBName() ) \ LoadDatabaseByType(store); if( !name.size() ) throw Error("Empty database name in LoadDatabaseByName"); ALL_KNOWN_PARSER_TYPES else throw Error("Unknown database name in LoadDatabaseByName: " + name); } template void Desktop::SaveDatabaseByName(const std::string &name, StorageT &store) { #undef HANDLE_BUILDER #define HANDLE_BUILDER(rtype) \ else if( name == Barry::rtype::GetDBName() ) \ SaveDatabaseByType(store); if( !name.size() ) throw Error("Empty database name in SaveDatabaseByName"); ALL_KNOWN_BUILDER_TYPES else throw Error("Unknown database name in SaveDatabaseByName: " + name); } template void Desktop::AddRecordByType(uint32_t recordId, const RecordT &rec) { unsigned int dbId = this->GetDBID( RecordT::GetDBName() ); // FIXME - I know this is a convenience template, but it still // hurts making a temporary copy just to set the record ID... // create a better API for this. RecordT r = rec; r.SetIds(RecordT::GetDefaultRecType(), recordId); Barry::RecordFetch fetch(r); Barry::RecordBuilder > build(fetch); this->AddRecord(dbId, build); } }} // namespace Barry::Mode #endif barry-0.18.5/src/time.cc0000644001161500056700000002572712242254476014325 0ustar cdfreycdfrey/// /// \file time.cc /// Conversion between time_t and cenmin_t and back. /// time_t is the POSIX time, seconds from Jan 1, 1970 /// min1900_t is the minutes from Jan 1, 1900 /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "time.h" #include "endian.h" #include "debug.h" #include "platform.h" namespace Barry { StaticTimeZone Zones[] = { { 0x0000, -12, 0, "Eniwetok, Kwajalein" }, // (-12) { 0x0001, -12, 0, "Midway Island, Samoa" }, // (-12) { 0x0002, -10, 0, "Hawaii" }, // (-10) { 0x0003, -9, 0, "Alaska" }, // (-9) { 0x0004, -8, 0, "Pacific Time (US & Canada), Tijuana" }, // (-8) { 0x000a, -7, 0, "Mountain Time (US & Canada)" }, // (-7) { 0x000f, -7, 0, "Arizona" }, // (-7) { 0x000d, -7, 0, "Chihuahua, La Paz, Mazatlan" }, // (-7) { 0x0014, -6, 0, "Central Time (US & Canada)" }, // (-6) { 0x0021, -6, 0, "Central America" }, // (-6) { 0x0019, -6, 0, "Saskatchewan" }, // (-6) { 0x001e, -6, 0, "Mexico City" }, // (-6) { 0x0023, -5, 0, "Eastern Time (US & Canada)" }, // (-5) { 0x002d, -5, 0, "Bogota, Lima, Quito" }, // (-5) { 0x0028, -5, 0, "Indiana (East)" }, // (-5) { 0x0032, -4, 0, "Atlantic Time (Canada)" }, // (-4) { 0x0037, -4, 0, "Caracas, La Paz" }, // (-4) { 0x0038, -4, 0, "Santiago" }, // (-4) { 0x003c, -3, -30, "Newfoundland" }, // (-3.5) { 0x0046, -3, 0, "Buenos Aires, Georgetown" }, // (-3) { 0x0041, -3, 0, "Brasilia" }, // (-3) { 0x0049, -3, 0, "Greenland" }, // (-3) { 0x004b, -2, 0, "Mid-Atlantic" }, // (-2) { 0x0053, -1, 0, "Cape Verde Island" }, // (-1) { 0x0050, -1, 0, "Azores" }, // (-1) { 0x0055, 0, 0, "Dublin, Edinburgh, Lisbon, London (GMT)" }, { 0x005a, 0, 0, "Casablanca, Monrovia (GMT)" }, { 0x006e, 1, 0, "Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna" }, // (+1) { 0x0071, 1, 0, "West Central Africa" }, // (+1) { 0x005f, 1, 0, "Belgrade, Bratislava, Budapest, Ljubljana, Prague" }, // (+1) { 0x0069, 1, 0, "Brussels, Copenhagen, Madrid, Paris" }, // (+1) { 0x0064, 1, 0, "Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb" }, // (+1) { 0x008c, 2, 0, "Harare, Pretoria" }, // (+2) { 0x0087, 2, 0, "Jerusalem" }, // (+2) { 0x0073, 2, 0, "Bucharest" }, // (+2) { 0x0078, 2, 0, "Cairo" }, // (+2) { 0x0082, 2, 0, "Athens, Istanbul, Minsk" }, // (+2) { 0x007d, 2, 0, "Helsinki, Riga, Tallinn" }, // (+2) { 0x0096, 3, 0, "Kuwait, Riyadh" }, // (+3) { 0x009b, 3, 0, "Nairobi" }, // (+3) { 0x009e, 3, 0, "Baghdad" }, // (+3) { 0x0091, 3, 0, "Moscow, St. Petersburg, Volgograd" }, // (+3) { 0x00a0, 3, 30, "Tehran" }, // (+3.5) { 0x00a5, 4, 0, "Abu Dhabi, Muscat" }, // (+4) { 0x00aa, 4, 0, "Baku, Tbilisi, Yerevan" }, // (+4) { 0x00af, 4, 30, "Kabul" }, // (+4.5) { 0x00b9, 5, 0, "Islamabad, Karachi, Tashkent" }, // (+5) { 0x00b4, 5, 0, "Ekaterinburg" }, // (+5) { 0x00be, 5, 30, "Calcutta, Chennai, Mumbai, New Delhi" }, // (+5.5) { 0x00c1, 5, 45, "Kathmandu" }, // (+5.75) { 0x00c3, 6, 0, "Astana, Dhaka" }, // (+6) { 0x00c8, 6, 0, "Sri Lanka" }, // (+6) { 0x00c9, 6, 0, "Almaty, Novosibirsk" }, // (+6) { 0x00cb, 6, 30, "Rangoon" }, // (+6.5) { 0x00cd, 7, 0, "Bangkok, Hanoi, Jakarta" }, // (+7) { 0x00cf, 7, 0, "Krasnoyarsk" }, // (+7) { 0x00d2, 8, 0, "Beijing, Chongqing, Hong Kong, Urumqi" }, // (+8) { 0x00d7, 8, 0, "Kuala Lumpur, Singapore" }, // (+8) { 0x00e1, 8, 0, "Perth" }, // (+8) { 0x00dc, 8, 0, "Taipei" }, // (+8) { 0x00e3, 8, 0, "Irkutsk, Ulaan Bataar" }, // (+8) { 0x00eb, 9, 0, "Osaka, Sapporo, Tokyo" }, // (+9) { 0x00e6, 9, 0, "Seoul" }, // (+9) { 0x00f0, 9, 0, "Yakutsk" }, // (+9) { 0x00f5, 9, 30, "Darwin" }, // (+9.5) { 0x00fa, 9, 30, "Adelaide" }, // (+9.5) { 0x0104, 10, 0, "Brisbane" }, // (+10) { 0x0113, 10, 0, "Guam, Port Moresby" }, // (+10) { 0x00ff, 10, 0, "Canberra, Melbourne, Sydney" }, // (+10) { 0x0109, 10, 0, "Hobart" }, // (+10) { 0x010e, 10, 0, "Vladivostok" }, // (+10) { 0x0118, 11, 0, "Magadan, Solomon Islands, New Caledonia" }, // (+11) { 0x011d, 12, 0, "Fiji, Kamchatka, Marshall Islands" }, // (+12) { 0x0122, 12, 0, "Auckland, Wellington" }, // (+12) { 0x012c, 13, 0, "Nuku'alofa" }, // (+13) { 0, 0, 0, 0 } }; min1900_t time2min(time_t t) { if( t == 0 ) return htobl(0xffffffff); min1900_t r = t / 60 + STDC_MIN1900_DIFF; return htobl(r); } time_t min2time(min1900_t m) { if( (unsigned long) btohl(m) == 0xffffffff ) return 0; else return (btohl(m) - STDC_MIN1900_DIFF) * 60; } // // GetStaticTimeZoneTable // /// Returns a pointer to an array of StaticTimeZone structs. /// The last struct contains 0 in all fields, and can be used as /// an "end of array" marker. /// const StaticTimeZone* GetStaticTimeZoneTable() { return Zones; } // // GetStaticTimeZone // /// Searches the internal timezone code table for the given Code /// and returns a pointer to a StaticTimeZone struct found. If the /// code is not found, a pointer to a valid StaticTimeZone struct is /// is still returned, but the struct's Code contains STATIC_TIME_ZONE_CODE_ERR, /// and the name is "Unknown time zone" (which is translatable with gettext). /// The unknown timezone is the same offset as GMT. /// const StaticTimeZone* GetStaticTimeZone(uint16_t Code) { static StaticTimeZone Unknown = { STATIC_TIME_ZONE_CODE_ERR, 0, 0, N_("Unknown time zone") }; for( StaticTimeZone *z = Zones; z->Name; z++ ) { if( Code == z->Code ) return z; } return &Unknown; } // // GetStaticTimeZoneCode // /// Searches the internal timezone table for the first matching /// Code. If no matching Code is found, STATIC_TIME_ZONE_CODE_ERR is returned. /// /// This function does not adjust for daylight saving time. /// uint16_t GetStaticTimeZoneCode(signed short HourOffset, signed short MinOffset) { for( StaticTimeZone *z = Zones; z->Name; z++ ) { if( HourOffset == z->HourOffset && MinOffset == z->MinOffset ) return z->Code; } return STATIC_TIME_ZONE_CODE_ERR; } /// This routine takes the day of the year and /// returns a time_t adjusted from the first of /// the year. /// /// FIXME This function assumes the year hasn't changed, /// but I don't have enough information to determine /// where the year is in this header info /// time_t DayToDate( uint16_t Day ) { struct tm *now, then; time_t t = time( NULL ); now = localtime( &t ); // need this to get year // set to Jan 1 midnight, this year; then.tm_sec = 0; then.tm_min = 0; then.tm_hour = 0; then.tm_mday = 0; then.tm_mon = 0; then.tm_year = now->tm_year; then.tm_isdst = -1; t = mktime(&then); t -= 60*60; // need to subract an hour t += Day * 24 * 60 * 60; // Add the day converted to seconds return t; } // // Message2Time // /// Localize the funky math used to convert a Blackberry message /// timestamp into a time_t. /// /// Both r_date and r_time are expected to be fed in from the /// Protocol::MessageRecord struct in raw form, without endian /// conversion. This function handles that. /// time_t Message2Time(uint16_t r_date, uint16_t r_time) { dout("Message2Time(0x" << std::hex << btohs(r_date) << ", 0x" << btohs(r_time) << ")"); uint16_t day = ( btohs(r_date) & 0x01ff ) - 0x29; time_t result = DayToDate( day ); result += (time_t)( btohs(r_time)*1.77 ); dout("Message2Time result: " << ctime(&result)); return result; } // // ThreadTimeout // /// Creates a pthread_cond_timedwait() compatible timespec struct, /// based on a given timeout in milliseconds. Note that the resulting /// timespec is time-sensitive: the 'timer' starts as soon as this function /// returns, since timespec is a specific time in the future, /// and ThreadTimeout() calculates it based on the current time. /// /// Returns the spec pointer, to make it easy to use with /// pthread_cond_timedwait() /// struct timespec* ThreadTimeout(int timeout_ms, struct timespec *spec) { struct timeval now; #ifndef WIN32 gettimeofday(&now, NULL); #else SYSTEMTIME st; FILETIME ft; LONGLONG ll; GetSystemTime(&st); SystemTimeToFileTime(&st, &ft); /* Now convert the file time to a timespec */ ll = (static_cast(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; // Adjust the offset to 100ns periods from UNIX epoc ll -= 116444736000000000; // Adjust the offset to micro-seconds since the UNIX epoc ll /= 10; now.tv_sec = static_cast(ll / 1000000); now.tv_usec = static_cast(ll % 1000000); #endif spec->tv_sec = now.tv_sec + timeout_ms / 1000; spec->tv_nsec = (now.tv_usec + timeout_ms % 1000 * 1000) * 1000; return spec; } // // DaysInMonth // /// Returns the number of days in the month, given the tm_mon and tm_year /// as specified in the struct tm argument. It _does_ take leap year into /// account. /// BXEXPORT int DaysInMonth(struct tm &t) { int year = t.tm_year + 1900; switch( t.tm_mon ) { case 1: if( year % 400 == 0 || (year % 100 != 0 && year % 4 == 0) ) return 29; else return 28; case 4: case 6: case 9: case 11: return 30; default: return 31; } } } // namespace Barry #ifdef __TEST_MODE__ #include #include using namespace std; using namespace Barry; void display(const char *msg, time_t t) { cout << msg << ": " << ctime(&t); cout << msg << " seconds: " << setbase(10) << t << "(0x" << setbase(16) << t << ")" << endl; cout << msg << " minutes: " << setbase(10) << (t/60) << "(0x" << setbase(16) << (t/60) << ")" << endl; cout << endl; } void calc(const char *msg, time_t t, min1900_t dbval) { cout << msg << endl; display(" Initial time", t); display(" DB Val", min2time(dbval)); } int main() { struct tm start; time_t t; // set to Oct 4, 2005, 2pm; start.tm_sec = 0; start.tm_min = 0; start.tm_hour = 14; start.tm_mday = 4; start.tm_mon = 9; start.tm_year = 105; start.tm_isdst = -1; t = mktime(&start); calc("Oct 4", t, 0x0350c118); // comparison t = time(NULL); min1900_t m = time2min(t); time_t tc = min2time(m); cout << "Original time: " << t << endl; cout << "time2min: " << m << endl; cout << "min2time: " << tc << endl; if( t == (tc + t % 60) ) cout << "Success! (orig == converted + mod)" << endl; else cout << "Failed!" << endl; // time zone cout << "Should say Eastern: " << GetStaticTimeZone(0x23)->Name << endl; cout << "should say Unknown: " << GetStaticTimeZone(0xffff)->Name << endl; } #endif barry-0.18.5/src/a_common.h0000644001161500056700000000157512242254476015014 0ustar cdfreycdfrey/// /// \file a_common.h /// ALX file parser common header /// /* Copyright (C) 2010, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_A_COMMON_H__ #define __BARRY_A_COMMON_H__ #include #include #endif barry-0.18.5/src/strnlen.h0000644001161500056700000000323312242254476014702 0ustar cdfreycdfrey/// /// \file strnlen.h /// Header for strnlen() call, for systems that don't have GNU. /// /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_STRNLEN_H__ #define __BARRY_STRNLEN_H__ #include "config.h" // strnlen.h is not installed, so this is safe #include #if defined(WIN32) && !defined(WINCE) #define HAVE_WORKING_STRNLEN 1 #endif // this is always defined by configure, if not, then the autoconf // sources changed (likely in /usr/share/autoconf/autoconf/functions.m4) // and configure.ac is no longer accurate #ifndef HAVE_WORKING_STRNLEN #error Configure.ac is not accurate. Read comments in strnlen.h. #endif // now, if defined and set to 0, then strnlen() either does not exist at all, // or is broken (on AIX) #if !HAVE_WORKING_STRNLEN // so define our own version... #ifdef __cplusplus extern "C" { #endif size_t barry_strnlen(const char *s, size_t maxlen); #ifdef __cplusplus } #endif // and override the system's name so we call our own #define strnlen(s,l) barry_strnlen(s,l) #endif // !HAVE_WORKING_STRNLEN #endif // __BARRY_STRNLEN_H__ barry-0.18.5/src/j_server.h0000644001161500056700000000514312242254476015036 0ustar cdfreycdfrey/// /// \file j_server.h /// Java Debug server classes /// /* Copyright (C) 2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYJDWP_SERVER_H__ #define __BARRYJDWP_SERVER_H__ #include "dll.h" #include "j_manager.h" #include "dp_codinfo.h" #include "m_jvmdebug.h" #include "threadwrap.h" #include #include namespace Barry { namespace JDWP { class BXEXPORT JDWServer { public: typedef void (*ConsoleCallbackType)(const std::string &); private: Barry::Mode::JVMDebug *jvmdebug; int acceptfd; int sockfd; std::string address; int port; bool loop; bool targetrunning; std::string password; Barry::JVMModulesList modulesList; // List of COD applications installed on the device Barry::JDG::DebugFileList debugFileList; // List of debug file on the host JDWAppList appList; // List of BlackBerry application (an application contents several COD files) Barry::JDG::ClassList visibleClassList; // Visible class list from JDB std::auto_ptr handler; ConsoleCallbackType printConsoleMessage; void CommandsetProcess(Barry::Data &cmd); void CommandsetVirtualMachineProcess(Barry::Data &cmd); void CommandsetEventRequestProcess(Barry::Data &cmd); void CommandVersion(Barry::Data &cmd); void CommandIdSizes(Barry::Data &cmd); void CommandAllClasses(Barry::Data &cmd); void CommandAllThreads(Barry::Data &cmd); void CommandSuspend(Barry::Data &cmd); void CommandResume(Barry::Data &cmd); void CommandClassPaths(Barry::Data &cmd); void CommandSet(Barry::Data &cmd); // void BackgroundDeviceProcess(); protected: public: JDWServer(Barry::Mode::JVMDebug &device, const char *address, int port); ~JDWServer(); void SetPasswordDevice(std::string password); void SetConsoleCallback(ConsoleCallbackType callback); bool Start(); // starts new thread bool AcceptConnection(); bool AttachToDevice(); bool InitVisibleClassList(); bool Hello(); void Run(volatile bool &stopflag); void DetachFromDevice(); bool Stop(); // cancels thread if still running, and // cleans up Start() }; }} // namespace Barry::JDWP #endif barry-0.18.5/src/dp_parser.h0000644001161500056700000000224612242254476015177 0ustar cdfreycdfrey/** * @file dp_parser.h * @author Nicolas VIVIEN * @date 2009-08-01 * * @note CopyRight Nicolas VIVIEN * * @brief COD debug file parser * * @par Modifications * - 2009/08/01 : N. VIVIEN * - First release * * @par Licences * Copyright (C) 2009-2010, Nicolas VIVIEN * * 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 in the COPYING file at the * root directory of this project for more details. */ #ifndef __BARRYJDG_PARSER_H__ #define __BARRYJDG_PARSER_H__ #include #include #include namespace Barry { namespace JDG { std::string ParseString(std::istream &input, const int length); uint32_t ParseInteger(std::istream &input); } // namespace JDG } // namespace Barry #endif barry-0.18.5/src/tzwrapper.h0000644001161500056700000001535012242254476015256 0ustar cdfreycdfrey/// /// \file tzwrapper.h /// Timezone adjustment class, wrapping the TZ environment /// variable to make struct tm -> time_t conversions easier. /// /* Copyright (C) 2010-2013, Chris Frey , To God be the glory Released to the public domain. Included in Barry and Barrified the namespace July 2010 */ #ifndef __TZWRAPPER_H__ #define __TZWRAPPER_H__ #include "dll.h" #include #include #include namespace Barry { namespace Sync { /// Parses ISO timestamp in the format of YYYYMMDDTHHMMSS[Z] /// or YYYY-MM-DDTHH:MM:SS.uuu-HH:MM /// and places broken down time in result. /// The trailing Z is optional in the format. /// If the Z exists, utc will be set to true, otherwise false. /// If zoneminutes is not null, and if a timezone offset is /// specified, it will be filled in and *zone set to true. /// Otherwise, *zone will be set to false. /// Returns NULL on error. /// Thread-safe. BXEXPORT struct tm* iso_to_tm(const char *timestamp, struct tm *result, bool &utc, bool *zone = 0, int *zoneminutes = 0); /// Turns the struct tm into an ISO timestamp in the format /// of YYYYMMDDTHHMMSS[Z]. The Z is appended if utc is true. /// This function assumes that t contains sane values, and will /// create the target string directly from its content. /// Returns the ISO timestamp, or empty string on error. /// If t contains sane values, this function should never fail. /// Thread-safe. BXEXPORT std::string tm_to_iso(const struct tm *t, bool utc); /// utc_mktime() converts a struct tm that contains /// broken down time in utc to a time_t. This function uses /// a brute-force method of conversion that does not require /// the environment variable TZ to be changed at all, and is /// therefore slightly more thread-safe in that regard. /// /// The difference between mktime() and utc_mktime() is that /// standard mktime() expects the struct tm to be in localtime, /// according to the current TZ and system setting, while utc_mktime() /// always assumes that the struct tm is in UTC, and converts it /// to time_t regardless of what TZ is currently set. /// /// The difference between utc_mktime() and TzWrapper::iso_mktime() /// is that iso_mktime() will parse straight from an ISO string, /// and if the ISO timestamp ends in a 'Z', it will behave like /// utc_mktime() except it will alter the TZ environment variable /// to do it. If the ISO timestamp has no 'Z', then iso_mktime() /// behaves like mktime(). /// BXEXPORT time_t utc_mktime(struct tm *utctime); // // class TzWrapper // /// Wrapper class for the TZ environment variable. This class allows /// setting TZ to any number of variables, and will restore the original /// setting on destruction. /// /// By default, TzWrapper does not change the environment at all, but /// only saves it. Alternately, you can use the timezone constructor /// to save and set a new timezone on the fly. /// /// Each Set() and Unset() function returns a reference to TzWrapper, /// so that you can chain function calls like this: /// /// time_t utc = TzWrapper("Canada/Pacific").mktime(&pacific_tm); /// /// In addition, there are two static utility functions used to /// convert ISO timestamps to struct tm* and time_t values. /// /// Note: This class is not thread-safe, since it modifies the TZ /// environment variable without locking. If other threads /// use time functions, this may interfere with their behaviour. /// class BXEXPORT TzWrapper { std::string m_orig_tz; bool m_tz_exists; bool m_dirty; protected: void SaveTz() { char *ptz = getenv("TZ"); if( ptz ) m_orig_tz = ptz; m_tz_exists = ptz; } void RestoreTz() { if( m_dirty ) { if( m_tz_exists ) Set(m_orig_tz.c_str()); else Unset(); m_dirty = false; } } public: /// Does not change TZ, only saves current setting TzWrapper() : m_dirty(false) { SaveTz(); } /// Saves current setting and sets TZ to new timezone value. /// If timezone is null, it is the same as calling Unset(). explicit TzWrapper(const char *timezone) : m_dirty(false) { SaveTz(); Set(timezone); } ~TzWrapper() { RestoreTz(); } /// Set TZ to a new value. If timezone is null, it is the /// same as calling Unset(). /// /// If timezone is an empty or invalid timezone string, it /// is the same as calling SetUTC(). TzWrapper& Set(const char *timezone) { if( timezone ) setenv("TZ", timezone, 1); else unsetenv("TZ"); tzset(); m_dirty = true; return *this; } /// Deletes TZ from the environment, which has the same effect /// as calling SetSysLocal(). This is not a permanent /// condition, since TZ will be restored to original state /// upon destruction. TzWrapper& Unset() { unsetenv("TZ"); tzset(); m_dirty = true; return *this; } /// Set timezone to UTC TzWrapper& SetUTC() { return Set(""); } /// Set timezone via offset in minutes /// Negative minutes goes west, positive goes east /// i.e. -05:00 is EST TzWrapper& SetOffset(int zoneminutes); /// Use system localtime. This overrides any TZ value that the /// user may have set before running your program. TzWrapper& SetSysLocal() { return Unset(); } /// Use the default TZ value that the user set before running /// this program. In most cases, this will be the user's /// preferred local timezone. TzWrapper& SetDefault() { RestoreTz(); return *this; } /// Same as SetDefault() TzWrapper& SetOrig() { return SetDefault(); } // // C library wrappers, for calls like: // time_t t = TzWrapper("Canada/Pacific").mktime(tm); // char* asctime(const struct tm *t) const { return ::asctime(t); } char* asctime_r(const struct tm *t, char *buf) const { return ::asctime_r(t, buf); } char* ctime(const time_t *t) const { return ::ctime(t); } char* ctime_r(const time_t *t, char *buf) const { return ::ctime_r(t, buf); } struct tm* gmtime(const time_t *t) const { return ::gmtime(t); } struct tm* gmtime_r(const time_t *t, struct tm *result) const { return ::gmtime_r(t, result); } struct tm* localtime(const time_t *t) const { return ::localtime(t); } struct tm* localtime_r(const time_t *t, struct tm *result) const { return ::localtime_r(t, result); } time_t mktime(struct tm *t) { return ::mktime(t); } // // Additional utility functions // /// Converts an ISO timestamp (YYYYMMDDTHHMMWW[Z]) into a /// unix time_t. If the 'Z' UTC flag is not specified, then /// the timestamp will be assumed to be in the current /// default timezone. Otherwise, SetUTC() will be used for the /// conversion. /// /// This function uses an internal TzWrapper to adjust TZ /// if necessary, which is why it is a static function /// of TzWrapper, instead of a standalone function. /// static time_t iso_mktime(const char *timestamp); }; }} // namespace Barry::Sync #endif barry-0.18.5/src/clog.h0000644001161500056700000000171612242254476014145 0ustar cdfreycdfrey/// /// \file clog.h /// C oriented logging routines for Barry /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_CLOG_H__ #define __BARRY_CLOG_H__ #include "dll.h" #ifdef __cplusplus extern "C" { #endif BXEXPORT void BarryLogf(int verbose, const char *msg, ...) BARRY_GCC_FORMAT_CHECK(2, 3); #ifdef __cplusplus } #endif #endif // __BARRY_CLOG_H__ barry-0.18.5/src/barryalx.h0000644001161500056700000000175112242254476015044 0ustar cdfreycdfrey/// /// \file barryalx.h /// Main header file for libbarryalx /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_BARRYALX_H__ #define __BARRY_BARRYALX_H__ // Include only the public backup / restore headers // (not tarfile) #include "a_common.h" #include "a_codsection.h" #include "a_library.h" #include "a_application.h" #include "a_osloader.h" #include "a_alxparser.h" #endif barry-0.18.5/src/ldif.cc0000644001161500056700000005206312242254476014276 0ustar cdfreycdfrey/// /// \file ldif.cc /// Routines for reading and writing LDAP LDIF data. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "ldif.h" #include "record.h" #include "r_contact.h" #include "base64.h" #include #include #include #include #include "ios_state.h" #define __DEBUG_MODE__ #include "debug.h" namespace Barry { const ContactLdif::NameToFunc ContactLdif::FieldMap[] = { { "Email", N_("Email address"), &ContactLdif::Email, &ContactLdif::SetEmail }, { "Phone", N_("Phone number"), &ContactLdif::Phone, &ContactLdif::SetPhone }, { "Fax", N_("Fax number"), &ContactLdif::Fax, &ContactLdif::SetFax }, { "WorkPhone", N_("Work phone number"), &ContactLdif::WorkPhone, &ContactLdif::SetWorkPhone }, { "HomePhone", N_("Home phone number"), &ContactLdif::HomePhone, &ContactLdif::SetHomePhone }, { "MobilePhone", N_("Mobile phone number"), &ContactLdif::MobilePhone, &ContactLdif::SetMobilePhone }, { "Pager", N_("Pager number"), &ContactLdif::Pager, &ContactLdif::SetPager }, { "PIN", N_("PIN"), &ContactLdif::PIN, &ContactLdif::SetPIN }, { "FirstName", N_("First name"), &ContactLdif::FirstName, &ContactLdif::SetFirstName }, { "LastName", N_("Last name"), &ContactLdif::LastName, &ContactLdif::SetLastName }, { "Company", N_("Company name"), &ContactLdif::Company, &ContactLdif::SetCompany }, { "DefaultCommunicationsMethod", N_("Default communications method"), &ContactLdif::DefaultCommunicationsMethod, &ContactLdif::SetDefaultCommunicationsMethod }, { "WorkAddress1", N_("Work Address, line 1"), &ContactLdif::WorkAddress1, &ContactLdif::SetWorkAddress1 }, { "WorkAddress2", N_("Work Address, line 2"), &ContactLdif::WorkAddress2, &ContactLdif::SetWorkAddress2 }, { "WorkAddress3", N_("Work Address, line 3"), &ContactLdif::WorkAddress3, &ContactLdif::SetWorkAddress3 }, { "WorkCity", N_("WorkCity"), &ContactLdif::WorkCity, &ContactLdif::SetWorkCity }, { "WorkProvince", N_("WorkProvince / State"), &ContactLdif::WorkProvince, &ContactLdif::SetWorkProvince }, { "WorkPostalCode", N_("Work Postal / ZIP code"), &ContactLdif::WorkPostalCode, &ContactLdif::SetWorkPostalCode }, { "WorkCountry", N_("WorkCountry"), &ContactLdif::WorkCountry, &ContactLdif::SetWorkCountry }, { "JobTitle", N_("Job Title"), &ContactLdif::JobTitle, &ContactLdif::SetJobTitle }, { "PublicKey", N_("Public key"), &ContactLdif::PublicKey, &ContactLdif::SetPublicKey }, { "Notes", N_("Notes"), &ContactLdif::Notes, &ContactLdif::SetNotes }, { "Image", N_("Contact photo"), &ContactLdif::Image, &ContactLdif::SetImage }, { "WorkPostalAddress", N_("Mailing Work address (includes address lines, city, province, country, and postal code)"), &ContactLdif::WorkPostalAddress, &ContactLdif::SetWorkPostalAddress }, { "HomePostalAddress", N_("Mailing home address (includes address lines, city, province, country, and postal code)"), &ContactLdif::HomePostalAddress, &ContactLdif::SetHomePostalAddress }, { "FullName", N_("First + Last names"), &ContactLdif::FullName, &ContactLdif::SetFullName }, { "FQDN", N_("Fully qualified domain name"), &ContactLdif::FQDN, &ContactLdif::SetFQDN }, { 0, 0, 0 } }; bool ContactLdif::LdifAttribute::operator<(const LdifAttribute &other) const { // the dn attribute always comes first in LDIF output if( name == "dn" ) { if( other.name == "dn" ) return false; // both dn, so equal return true; } else if( other.name == "dn" ) return false; return (order < other.order && name != other.name) || (order == other.order && name < other.name); } bool ContactLdif::LdifAttribute::operator==(const LdifAttribute &other) const { return name == other.name; } /////////////////////////////////////////////////////////////////////////////// // ContactLdif class ContactLdif::ContactLdif(const std::string &baseDN) : m_baseDN(baseDN) { // setup some sane defaults Map("mail", &ContactLdif::Email, &ContactLdif::SetEmail); Map("facsimileTelephoneNumber", &ContactLdif::Fax, &ContactLdif::SetFax); Map("telephoneNumber", &ContactLdif::WorkPhone, &ContactLdif::SetWorkPhone); Map("homePhone", &ContactLdif::HomePhone, &ContactLdif::SetHomePhone); Map("mobile", &ContactLdif::MobilePhone, &ContactLdif::SetMobilePhone); Map("pager", &ContactLdif::Pager, &ContactLdif::SetPager); Map("l", &ContactLdif::WorkCity, &ContactLdif::SetWorkCity); Map("st", &ContactLdif::WorkProvince, &ContactLdif::SetWorkProvince); Map("postalCode", &ContactLdif::WorkPostalCode, &ContactLdif::SetWorkPostalCode); Map("o", &ContactLdif::Company, &ContactLdif::SetCompany); Map("c", &ContactLdif::WorkCountry, &ContactLdif::SetWorkCountry); SetObjectClass("c", "country"); Map("title", &ContactLdif::JobTitle, &ContactLdif::SetJobTitle); Map("dn", &ContactLdif::FQDN, &ContactLdif::SetFQDN); Map("displayName", &ContactLdif::FullName, &ContactLdif::SetFullName); Map("cn", &ContactLdif::FullName, &ContactLdif::SetFullName); Map("sn", &ContactLdif::LastName, &ContactLdif::SetLastName); Map("givenName", &ContactLdif::FirstName, &ContactLdif::SetFirstName); Map("street", &ContactLdif::WorkAddress1, &ContactLdif::SetWorkAddress1); Map("postalAddress", &ContactLdif::WorkPostalAddress, &ContactLdif::SetWorkPostalAddress); Map("homePostalAddress", &ContactLdif::HomePostalAddress, &ContactLdif::SetHomePostalAddress); Map("note", &ContactLdif::Notes, &ContactLdif::SetNotes); // FIXME - jpegPhoto looks like the only LDIF field for photo // images... it is unknown which format will come from the // BlackBerry in the Image field, so we can't guarantee // that Image will be in JPG. This mapping can be done manually // from the btool command line with "-m jpegPhoto,Image,Image" // Reading photos from LDIF should be fine, since the BlackBerry // seems to handle most formats. // Map("jpegPhoto", &ContactLdif::Image, &ContactLdif::SetImage); // add heuristics hooks Hook("cn", &m_cn); Hook("displayName", &m_displayName); Hook("sn", &m_sn); Hook("givenName", &m_givenName); // set default DN attribute SetDNAttr("cn"); } ContactLdif::~ContactLdif() { } void ContactLdif::DoWrite(Barry::Contact &con, const std::string &attr, const std::string &data) { // valid? if( attr.size() == 0 || data.size() == 0 ) return; // now have attr/data pair, check hooks: HookMapType::iterator hook = m_hookMap.find(attr); if( hook != m_hookMap.end() ) { *(hook->second) = data; } // run according to map AccessMapType::iterator acc = m_map.find(attr); if( acc != m_map.end() ) { (this->*(acc->second.write))(con, data); } } void ContactLdif::Hook(const std::string &ldifname, std::string *var) { m_hookMap[ldifname] = var; } const ContactLdif::NameToFunc* ContactLdif::GetField(const std::string &fieldname) const { for( const NameToFunc *n = FieldMap; n->name; n++ ) { if( fieldname == n->name ) return n; } return 0; } std::string ContactLdif::GetFieldReadName(GetFunctionType read) const { for( const NameToFunc *n = FieldMap; n->name; n++ ) { if( read == n->read ) return n->name; } return _(""); } std::string ContactLdif::GetFieldWriteName(SetFunctionType write) const { for( const NameToFunc *n = FieldMap; n->name; n++ ) { if( write == n->write ) return n->name; } return _(""); } bool ContactLdif::Map(const LdifAttribute &ldifname, const std::string &readField, const std::string &writeField) { const NameToFunc *read = GetField(readField); const NameToFunc *write = GetField(writeField); if( !read || !write ) return false; Map(ldifname, read->read, write->write); return true; } void ContactLdif::Map(const LdifAttribute &ldifname, GetFunctionType read, SetFunctionType write) { m_map[ldifname] = AccessPair(read, write); } void ContactLdif::Unmap(const LdifAttribute &ldifname) { m_map.erase(ldifname); } // // SetDNAttr // /// Sets the LDIF attribute name to use when constructing the FQDN. /// The FQDN field will take this name, and combine it with the /// baseDN from the constructor to produce a FQDN for the record. /// bool ContactLdif::SetDNAttr(const LdifAttribute &name) { // try to find the attribute in the map AccessMapType::iterator i = m_map.find(name); if( i == m_map.end() ) return false; m_dnAttr = name; return true; } bool ContactLdif::SetObjectClass(const LdifAttribute &name, const std::string &objectClass) { AccessMapType::iterator i = m_map.find(name); if( i == m_map.end() ) return false; LdifAttribute key = i->first; AccessPair pair = i->second; m_map.erase(key); key.objectClass = objectClass; m_map[key] = pair; return true; } bool ContactLdif::SetObjectOrder(const LdifAttribute &name, int order) { AccessMapType::iterator i = m_map.find(name); if( i == m_map.end() ) return false; LdifAttribute key = i->first; AccessPair pair = i->second; m_map.erase(key); key.order = order; m_map[key] = pair; return true; } std::string ContactLdif::Email(const Barry::Contact &con) const { return con.GetEmail(m_emailIndex++); } std::string ContactLdif::Phone(const Barry::Contact &con) const { return con.Phone; } std::string ContactLdif::Fax(const Barry::Contact &con) const { return con.Fax; } std::string ContactLdif::WorkPhone(const Barry::Contact &con) const { return con.WorkPhone; } std::string ContactLdif::HomePhone(const Barry::Contact &con) const { return con.HomePhone; } std::string ContactLdif::MobilePhone(const Barry::Contact &con) const { return con.MobilePhone; } std::string ContactLdif::Pager(const Barry::Contact &con) const { return con.Pager; } std::string ContactLdif::PIN(const Barry::Contact &con) const { return con.PIN; } std::string ContactLdif::FirstName(const Barry::Contact &con) const { return con.FirstName; } std::string ContactLdif::LastName(const Barry::Contact &con) const { return con.LastName; } std::string ContactLdif::Company(const Barry::Contact &con) const { return con.Company; } std::string ContactLdif::DefaultCommunicationsMethod(const Barry::Contact &con) const { return con.DefaultCommunicationsMethod; } std::string ContactLdif::WorkAddress1(const Barry::Contact &con) const { return con.WorkAddress.Address1; } std::string ContactLdif::WorkAddress2(const Barry::Contact &con) const { return con.WorkAddress.Address2; } std::string ContactLdif::WorkAddress3(const Barry::Contact &con) const { return con.WorkAddress.Address3; } std::string ContactLdif::WorkCity(const Barry::Contact &con) const { return con.WorkAddress.City; } std::string ContactLdif::WorkProvince(const Barry::Contact &con) const { return con.WorkAddress.Province; } std::string ContactLdif::WorkPostalCode(const Barry::Contact &con) const { return con.WorkAddress.PostalCode; } std::string ContactLdif::WorkCountry(const Barry::Contact &con) const { return con.WorkAddress.Country; } std::string ContactLdif::JobTitle(const Barry::Contact &con) const { return con.JobTitle; } std::string ContactLdif::PublicKey(const Barry::Contact &con) const { return con.PublicKey; } std::string ContactLdif::Notes(const Barry::Contact &con) const { return con.Notes; } std::string ContactLdif::Image(const Barry::Contact &con) const { return con.Image; } std::string ContactLdif::WorkPostalAddress(const Barry::Contact &con) const { return con.WorkAddress.GetLabel(); } std::string ContactLdif::HomePostalAddress(const Barry::Contact &con) const { return con.HomeAddress.GetLabel(); } std::string ContactLdif::FullName(const Barry::Contact &con) const { return con.GetFullName(); } std::string ContactLdif::FQDN(const Barry::Contact &con) const { std::string FQDN = m_dnAttr.name; FQDN += "="; AccessMapType::const_iterator i = m_map.find(m_dnAttr); if( i != m_map.end() ) { FQDN += (this->*(i->second.read))(con); } else { FQDN += _("unknown"); } FQDN += ","; FQDN += m_baseDN; return FQDN; } bool ContactLdif::IsArrayFunc(GetFunctionType getf) const { // Currently, only the Email getter has array data if( getf == &ContactLdif::Email ) return true; return false; } void ContactLdif::ClearArrayState() const { m_emailIndex = 0; } void ContactLdif::SetEmail(Barry::Contact &con, const std::string &val) const { con.EmailAddresses.push_back(val); } void ContactLdif::SetPhone(Barry::Contact &con, const std::string &val) const { con.Phone = val; } void ContactLdif::SetFax(Barry::Contact &con, const std::string &val) const { con.Fax = val; } void ContactLdif::SetWorkPhone(Barry::Contact &con, const std::string &val) const { con.WorkPhone = val; } void ContactLdif::SetHomePhone(Barry::Contact &con, const std::string &val) const { con.HomePhone = val; } void ContactLdif::SetMobilePhone(Barry::Contact &con, const std::string &val) const { con.MobilePhone = val; } void ContactLdif::SetPager(Barry::Contact &con, const std::string &val) const { con.Pager = val; } void ContactLdif::SetPIN(Barry::Contact &con, const std::string &val) const { con.PIN = val; } void ContactLdif::SetFirstName(Barry::Contact &con, const std::string &val) const { con.FirstName = val; } void ContactLdif::SetLastName(Barry::Contact &con, const std::string &val) const { con.LastName = val; } void ContactLdif::SetCompany(Barry::Contact &con, const std::string &val) const { con.Company = val; } void ContactLdif::SetDefaultCommunicationsMethod(Barry::Contact &con, const std::string &val) const { con.DefaultCommunicationsMethod = val; } void ContactLdif::SetWorkAddress1(Barry::Contact &con, const std::string &val) const { con.WorkAddress.Address1 = val; } void ContactLdif::SetWorkAddress2(Barry::Contact &con, const std::string &val) const { con.WorkAddress.Address2 = val; } void ContactLdif::SetWorkAddress3(Barry::Contact &con, const std::string &val) const { con.WorkAddress.Address3 = val; } void ContactLdif::SetWorkCity(Barry::Contact &con, const std::string &val) const { con.WorkAddress.City = val; } void ContactLdif::SetWorkProvince(Barry::Contact &con, const std::string &val) const { con.WorkAddress.Province = val; } void ContactLdif::SetWorkPostalCode(Barry::Contact &con, const std::string &val) const { con.WorkAddress.PostalCode = val; } void ContactLdif::SetWorkCountry(Barry::Contact &con, const std::string &val) const { con.WorkAddress.Country = val; } void ContactLdif::SetJobTitle(Barry::Contact &con, const std::string &val) const { con.JobTitle = val; } void ContactLdif::SetPublicKey(Barry::Contact &con, const std::string &val) const { con.PublicKey = val; } void ContactLdif::SetNotes(Barry::Contact &con, const std::string &val) const { con.Notes = val; } void ContactLdif::SetImage(Barry::Contact &con, const std::string &val) const { con.Image = val; } void ContactLdif::SetWorkPostalAddress(Barry::Contact &con, const std::string &val) const { // FIXME; // throw std::runtime_error("SetWorkPostalAddress() not implemented"); // std::cout << "SetWorkPostalAddress() not implemented: " << val << std::endl; } void ContactLdif::SetHomePostalAddress(Barry::Contact &con, const std::string &val) const { // FIXME; // throw std::runtime_error("SetHomePostalAddress() not implemented"); // std::cout << "SetHomePostalAddress() not implemented: " << val << std::endl; } void ContactLdif::SetFullName(Barry::Contact &con, const std::string &val) const { std::string first, last; Contact::SplitName(val, first, last); con.FirstName = first; con.LastName = last; } void ContactLdif::SetFQDN(Barry::Contact &con, const std::string &val) const { throw std::runtime_error("not implemented"); } void ContactLdif::ClearHeuristics() { m_cn.clear(); m_displayName.clear(); m_sn.clear(); m_givenName.clear(); } bool ContactLdif::RunHeuristics(Barry::Contact &con) { // start fresh con.LastName.clear(); con.FirstName.clear(); // find the best match for name... prefer sn/givenName if available if( m_sn.size() ) { con.LastName = m_sn; } if( m_givenName.size() ) { con.FirstName = m_givenName; } if( !con.LastName.size() || !con.FirstName.size() ) { std::string first, last; // still don't have a complete name, check cn first if( m_cn.size() ) { Contact::SplitName(m_cn, first, last); if( !con.LastName.size() && last.size() ) con.LastName = last; if( !con.FirstName.size() && first.size() ) con.FirstName = first; } // displayName is last chance if( m_displayName.size() ) { Contact::SplitName(m_displayName, first, last); if( !con.LastName.size() && last.size() ) con.LastName = last; if( !con.FirstName.size() && first.size() ) con.FirstName = first; } } return con.LastName.size() && con.FirstName.size(); } // // DumpLdif // /// Output contact data to os in LDAP LDIF format. /// void ContactLdif::DumpLdif(std::ostream &os, const Barry::Contact &con) const { ios_format_state state(os); // start fresh ClearArrayState(); // setup stream state os.setf(std::ios::left); os.fill(' '); if( FirstName(con).size() == 0 && LastName(con).size() == 0 ) return; // nothing to do os << "# Contact 0x" << std::hex << con.GetID() << ", " << FullName(con) << "\n"; // cycle through the map for( AccessMapType::const_iterator b = m_map.begin(); b != m_map.end(); ++b ) { // print only fields with data std::string field; do { field = (this->*(b->second.read))(con); if( field.size() ) { os << b->first.name << MakeLdifData(field) << "\n"; if( b->first.objectClass.size() ) os << "objectClass: " << b->first.objectClass << "\n"; } } while( IsArrayFunc(b->second.read) && field.size() ); } os << "objectClass: inetOrgPerson\n"; // last line must be empty os << "\n"; } bool ContactLdif::ReadLdif(std::istream &is, Barry::Contact &con) { std::string line; // start fresh con.Clear(); ClearHeuristics(); // search for beginning dn: line bool found = false; while( std::getline(is, line) ) { if( strncmp(line.c_str(), "dn: ", 4) == 0 ) { found = true; break; } } if( !found ) return false; // storage for various name styles std::string coded, decode, attr, data; bool b64field = false; // read ldif lines until empty line is found while( getline(is, line) && line.size() ) { if( b64field ) { // processing a base64 encoded field if( line[0] == ' ' ) { coded += "\n"; coded += line; continue; } else { // end of base64 block... ignore errors, // and attempt to save everything decodable... // the LDAP server sometimes returns incomplete // base64 encoding, but otherwise the data is fine base64_decode(coded, decode); DoWrite(con, attr, decode); coded.clear(); b64field = false; } // fall through to process new line } // split into attribute / data std::string::size_type delim = line.find(':'), dstart; if( delim == std::string::npos ) continue; attr.assign(line, 0, delim); dstart = delim + 1; while( line[dstart] == ' ' || line[dstart] == ':' ) dstart++; data = line.substr(dstart); // is this data base64 encoded? if( line[delim + 1] == ':' ) { coded = data; b64field = true; continue; } DoWrite(con, attr, data); } if( b64field ) { // clean up base64 decoding... ignore errors, see above comment base64_decode(coded, decode); DoWrite(con, attr, decode); coded.clear(); b64field = false; } return RunHeuristics(con); } void ContactLdif::DumpMap(std::ostream &os) const { ios_format_state state(os); os.setf(std::ios::left); os.fill(' '); os << _("ContactLdif Mapping:\n"); // cycle through the map for( AccessMapType::const_iterator b = m_map.begin(); b != m_map.end(); ++b ) { os << " " << std::left << std::setw(20) << b->first.name << "-> " << GetFieldReadName(b->second.read) << " / " << GetFieldWriteName(b->second.write) << "\n"; // find read/write names if( b->first.objectClass.size() ) { os << " " << std::setw(20) << " " << "objectClass: " << b->first.objectClass << "\n"; } } os << _(" >>> DN attribute: ") << m_dnAttr.name << "\n"; } std::string ContactLdif::MakeLdifData(const std::string &str) { std::string data = ":"; if( NeedsEncoding(str) ) { std::string b64; base64_encode(str, b64); data += ": "; data += b64; } else { data += " "; data += str; } return data; } // // RFC 2849 // // Must not contain: // 0x00 (NUL), 0x0a (LF), 0x0d (CR), or anything greater than 0x7f // // First char must meet above criteria, plus must not be: // 0x20 (SPACE), 0x3a (colon), 0x3c ('<') // bool ContactLdif::NeedsEncoding(const std::string &str) { for( std::string::size_type i = 0; i < str.size(); i++ ) { unsigned char c = str[i]; switch( c ) { case 0x00: case 0x0a: case 0x0d: return true; case 0x20: case 0x3a: case 0x3c: if( i == 0 ) return true; } if( c > 0x7f ) return true; } return false; } } // namespace Barry barry-0.18.5/src/base64.h0000644001161500056700000000035212242254476014300 0ustar cdfreycdfrey#ifndef __BARRY_BASE64_H__ #define __BARRY_BASE64_H__ #include // in-memory encode / decode bool base64_encode(const std::string &in, std::string &out); bool base64_decode(const std::string &in, std::string &out); #endif barry-0.18.5/src/r_hhagent.cc0000644001161500056700000003013112242254476015307 0ustar cdfreycdfrey/// /// \file r_hhagent.cc /// Blackberry database record parser class for Handheld Agent records /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "r_hhagent.h" #include "record-internal.h" #include "protostructs.h" #include "iconv.h" #include "time.h" #include #include #include #include #include "ios_state.h" #define __DEBUG_MODE__ #include "debug.h" using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // HandheldAgent class // Common field codes #define HHAFC_END 0xffff // Field codes for record 3000000 #define HHAFC3_MODEL 0x03 #define HHAFC3_BANDS 0x07 #define HHAFC3_VERSION 0x08 #define HHAFC3_NETWORK 0x0f #define HHAFC3_PIN 0x10 #define HHAFC3_MEID 0x11 // Field codes for record 7000000 #define HHAFC7_FIRMWARE 0x13 #define HHAFC7_MANUFACTURER 0x14 #define HHAFC7_MODEL 0x15 #define HHAFC7_PLATFORM 0x17 // These fields are only valid for RecordId 0x3000000 static FieldLink HandheldAgentFieldLinks_3000000[] = { { HHAFC3_MODEL, N_("Model"), 0, 0, &HandheldAgent::Model, 0, 0, 0, 0, true }, { HHAFC3_NETWORK, N_("Network"), 0, 0, &HandheldAgent::Network, 0, 0, 0, 0, true }, { HHAFC3_BANDS, N_("Bands"), 0, 0, &HandheldAgent::Bands, 0, 0, 0, 0, true }, { HHAFC3_MEID, N_("MEID/ESN"), 0, 0, &HandheldAgent::MEID, 0, 0, 0, 0, true }, { HHAFC3_PIN, N_("PIN"), 0, 0, &HandheldAgent::Pin, 0, 0, 0, 0, true }, { HHAFC3_VERSION, N_("Version"),0, 0, &HandheldAgent::Version, 0, 0, 0, 0, true }, { HHAFC_END, N_("End of List"),0, 0, 0, 0, 0, 0, 0, false } }; // These fields are only for RecordId 0x4000000 static FieldLink HandheldAgentFieldLinks_4000000[] = { { HHAFC_END, N_("End of List"),0, 0, 0, 0, 0, 0, 0, false } }; // These fields are only for RecordId 0x5000000 static FieldLink HandheldAgentFieldLinks_5000000[] = { { HHAFC_END, N_("End of List"),0, 0, 0, 0, 0, 0, 0, false } }; // These fields are only for RecordId 0x7000000 static FieldLink HandheldAgentFieldLinks_7000000[] = { { HHAFC7_MODEL, N_("Model"), 0, 0, &HandheldAgent::Model, 0, 0, 0, 0, true }, { HHAFC7_MANUFACTURER,N_("Manufacturer"),0,0,&HandheldAgent::Manufacturer,0, 0, 0, 0, true }, { HHAFC7_FIRMWARE, N_("Firmware"), 0, 0, &HandheldAgent::Version, 0, 0, 0, 0, true }, { HHAFC7_PLATFORM, N_("Platform"), 0, 0, &HandheldAgent::PlatformVersion, 0, 0, 0, 0, true }, { HHAFC_END, N_("End of List"),0, 0, 0, 0, 0, 0, 0, false } }; // Use this table for default application style records static FieldLink HandheldAgentFieldLinks_Default[] = { { HHAFC_END, N_("End of List"),0, 0, 0, 0, 0, 0, 0, false } }; // Use this for display / Dump() etc... includes all fields static FieldLink HandheldAgentFieldLinks_All[] = { { 0, N_("Model"), 0, 0, &HandheldAgent::Model, 0, 0, 0, 0, true }, { 0, N_("Network"), 0, 0, &HandheldAgent::Network, 0, 0, 0, 0, true }, { 0, N_("Manufacturer"),0,0, &HandheldAgent::Manufacturer,0, 0, 0, 0, true }, { 0, N_("Bands"), 0, 0, &HandheldAgent::Bands, 0, 0, 0, 0, true }, { 0, N_("MEID/ESN"), 0, 0, &HandheldAgent::MEID, 0, 0, 0, 0, true }, { 0, N_("PIN"), 0, 0, &HandheldAgent::Pin, 0, 0, 0, 0, true }, { 0, N_("Version"), 0, 0, &HandheldAgent::Version, 0, 0, 0, 0, true }, { 0, N_("Platform"), 0, 0, &HandheldAgent::PlatformVersion, 0, 0, 0, 0, true }, { HHAFC_END, N_("End of List"),0, 0, 0, 0, 0, 0, 0, false } }; HandheldAgent::HandheldAgent() { Clear(); } HandheldAgent::~HandheldAgent() { } const unsigned char* HandheldAgent::ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { const CommonField *field = (const CommonField *) begin; // advance and check size begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size); if( begin > end ) // if begin==end, we are ok return begin; if( !btohs(field->size) ) // if field has no size, something's up return begin; // cycle through the type table FieldLink *b = HandheldAgentFieldLinks_Default; if( RecordId == 0 ) { // internal consistency check... all parsing code should // call SetIds() first, and HandheldAgent relies on this, // so double check, and throw if not throw std::logic_error(_("HandheldAgent requires SetIds() to be called before ParseField()")); } else if( RecordId == GetMEIDRecordId() ) { b = HandheldAgentFieldLinks_3000000; } else if( RecordId == GetUnknown1RecordId() ) { b = HandheldAgentFieldLinks_4000000; } else if( RecordId == GetUnknown2RecordId() ) { b = HandheldAgentFieldLinks_5000000; } else if( RecordId == GetUnknown3RecordId() ) { b = HandheldAgentFieldLinks_7000000; } for( ; b->type != HHAFC_END; b++ ) { if( b->type == field->type ) { if( b->strMember ) { std::string &s = this->*(b->strMember); s = ParseFieldString(field); if( b->iconvNeeded && ic ) s = ic->FromBB(s); return begin; // done! } else if( b->timeMember && btohs(field->size) == 4 ) { TimeT &t = this->*(b->timeMember); dout("min1900: " << field->u.min1900); t.Time = min2time(field->u.min1900); return begin; } else if( b->addrMember ) { // // parse email address // get dual addr+name string first // Note: this is a different format than // used in r_message*.cc // std::string dual((const char*)field->u.raw, btohs(field->size)); EmailAddress a; // assign first string, using null terminator // letting std::string add it for us if it // doesn't exist a.Email = dual.c_str(); // assign second string, using first size // as starting point a.Name = dual.c_str() + a.Email.size() + 1; // if the address is non-empty, add to list if( a.size() ) { // i18n convert if needed if( b->iconvNeeded && ic ) { a.Name = ic->FromBB(a.Name); a.Email = ic->FromBB(a.Email); } EmailAddressList &al = this->*(b->addrMember); al.push_back(a); } return begin; } } } // handle special cases // switch( field->type ) // { // } // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; uf.data.assign((const char*)field->u.raw, btohs(field->size)); Unknowns.push_back(uf); // return new pointer for next field return begin; } void HandheldAgent::ParseHeader(const Data &data, size_t &offset) { // no header in HandheldAgent records } void HandheldAgent::ParseFields(const Data &data, size_t &offset, const IConverter *ic) { const unsigned char *finish = ParseCommonFields(*this, data.GetData() + offset, data.GetData() + data.GetSize(), ic); offset += finish - (data.GetData() + offset); } void HandheldAgent::Validate() const { } void HandheldAgent::BuildHeader(Data &data, size_t &offset) const { // no header in HandheldAgent records } // // Build // /// Build fields part of record. /// void HandheldAgent::BuildFields(Data &data, size_t &offset, const IConverter *ic) const { } void HandheldAgent::Clear() { // clear our fields RecType = GetDefaultRecType(); RecordId = 0; MEID.clear(); Model.clear(); Bands.clear(); Pin.clear(); Version.clear(); PlatformVersion.clear(); Manufacturer.clear(); Network.clear(); Unknowns.clear(); } const FieldHandle::ListT& HandheldAgent::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; #undef CONTAINER_OBJECT_NAME #define CONTAINER_OBJECT_NAME fhv #undef RECORD_CLASS_NAME #define RECORD_CLASS_NAME HandheldAgent FHP(RecType, _("Record Type Code")); FHP(RecordId, _("Unique Record ID")); // These fields are only valid for RecordId 0x3000000 FHD(MEID, _("MEID/ESN"), HHAFC3_MEID, true); FHD(Model, _("Model"), HHAFC3_MODEL, true); FHD(Bands, _("Bands"), HHAFC3_BANDS, true); FHD(Pin, _("PIN"), HHAFC3_PIN, true); FHD(Version, _("Version"), HHAFC3_VERSION, true); FHD(Network, _("Network"), HHAFC3_NETWORK, true); // These fields are only for RecordId 0x7000000 FHD(PlatformVersion, _("Platform Version"), HHAFC7_PLATFORM, true); FHD(Manufacturer, _("Manufacturer"), HHAFC7_MANUFACTURER, true); FHP(Unknowns, _("Unknown Fields")); return fhv; } std::string HandheldAgent::GetDescription() const { ostringstream oss; oss << _("Handheld Agent: ") << "0x" << hex << RecordId; return oss.str(); } void HandheldAgent::Dump(std::ostream &os) const { ios_format_state state(os); os << _("HandheldAgent entry: ") << "0x" << hex << RecordId << " (" << (unsigned int)RecType << ")\n"; // cycle through the type table for( const FieldLink *b = HandheldAgentFieldLinks_All; b->type != HHAFC_END; b++ ) { if( b->strMember ) { const std::string &s = this->*(b->strMember); if( s.size() ) os << " " << gettext(b->name) << ": " << s << "\n"; } else if( b->timeMember ) { TimeT t = this->*(b->timeMember); if( t.Time > 0 ) os << " " << gettext(b->name) << ": " << t << "\n"; else os << " " << gettext(b->name) << ": disabled\n"; } else if( b->addrMember ) { const EmailAddressList &al = this->*(b->addrMember); EmailAddressList::const_iterator lb = al.begin(), le = al.end(); for( ; lb != le; ++lb ) { if( !lb->size() ) continue; os << " " << gettext(b->name) << ": " << *lb << "\n"; } } } // print any unknowns os << Unknowns; } bool HandheldAgent::operator<(const HandheldAgent &other) const { return RecordId < other.RecordId; } bool HandheldAgent::IsSpecial(uint32_t record_id) { return record_id == GetMEIDRecordId() || record_id == GetUnknown1RecordId() || record_id == GetUnknown2RecordId() || record_id == GetUnknown3RecordId(); } // // The ESN number is in two parts. When in decimal, the first 3 // characters are one number, then the rest. In hex, the first 2 // digits are the same number, then the rest. Both are padded // with zeros. // // For example, hex: 4c070068 dec: 07600458856 // hex: [4c]070068 dec: [076]00458856 // // Returns an empty string on error. // bool HandheldAgent::IsESNHex(const std::string &esn) { const char *hex = "0123456789ABCDEFabcdef"; size_t npos = string::npos; if( esn.size() == 8 && esn.find_first_not_of(hex) == npos ) { return true; } return false; } bool HandheldAgent::IsESNDec(const std::string &esn) { const char *dec = "0123456789"; size_t npos = string::npos; if( esn.size() == 11 && esn.find_first_not_of(dec) == npos ) { return true; } return false; } std::string HandheldAgent::ESNDec2Hex(const std::string &esn) { string empty; if( esn.size() != 11 ) return empty; unsigned int part1, part2; istringstream iss(esn.substr(0, 3)); iss >> dec >> part1; if( !iss ) return empty; iss.str(esn.substr(3)); iss.clear(); iss >> dec >> part2; if( !iss ) return empty; ostringstream oss; oss << setfill('0') << setw(2) << hex << part1; oss << setfill('0') << setw(6) << hex << part2; if( !oss ) return empty; return oss.str(); } std::string HandheldAgent::ESNHex2Dec(const std::string &esn) { string empty; if( esn.size() != 8 ) return empty; unsigned int part1, part2; istringstream iss(esn.substr(0, 2)); iss >> hex >> part1; if( !iss ) return empty; iss.str(esn.substr(2)); iss.clear(); iss >> hex >> part2; if( !iss ) return empty; ostringstream oss; oss << setfill('0') << setw(3) << dec << part1; oss << setfill('0') << setw(8) << dec << part2; if( !oss ) return empty; return oss.str(); } } // namespace Barry barry-0.18.5/src/pipe.h0000644001161500056700000000345012242254476014153 0ustar cdfreycdfrey/// /// \file pipe.h /// Connector class to join parsers and builders together /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_PIPE_H__ #define __BARRY_PIPE_H__ #include "dll.h" #include "builder.h" #include "parser.h" namespace Barry { // // class Pipe // /// Reads data from a builder and feeds it into a parser. /// class BXEXPORT Pipe { Builder &m_builder; DBData m_buffer; public: explicit Pipe(Builder &builder); ~Pipe(); /// Access the builder... mostly useful for finding out /// the database name for the next series, if using multiple /// parser objects. const Builder& GetBuilder() const { return m_builder; } /// Reads one item from the builder and feeds it into the parser /// and returns the builder Retrieve status. bool PumpEntry(Parser &parser, const IConverter *ic = 0); /// Reads all items from builder, feeding them into the parser, /// until the builder's Retrieve() signals the end of the series. void PumpSeries(Parser &parser, const IConverter *ic = 0); /// Reads all series from the builder, feeding them into the parser, /// until the builder's EndOfFile() is true. void PumpFile(Parser &parser, const IConverter *ic = 0); }; } // namespace Barry #endif barry-0.18.5/src/data.cc0000644001161500056700000003631512242254476014273 0ustar cdfreycdfrey/// /// \file data.cc /// Classes to help manage pre-determined data files. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "data.h" #include #include #include #include #include #include #include #include #include "ios_state.h" //#define __DEBUG_MODE__ #include "debug.h" using namespace std; namespace Barry { inline bool IsHexData(const std::string &s) { const char *str = s.c_str(); for( int i = 0; i < 4 && *str; str++, i++ ) if( *str != ' ' ) return false; for( int i = 0; i < 8 && *str; str++, i++ ) { const char *hexchars = "0123456789abcdef"; if( strchr(hexchars, *str) == NULL ) return false; } if( *str != ':' ) return false; return true; } /////////////////////////////////////////////////////////////////////////////// // Data class bool Data::bPrintAscii = true; Data::Data() : m_memBlock(new unsigned char[BARRY_DATA_DEFAULT_SIZE + BARRY_DATA_DEFAULT_PREPEND_SIZE]) , m_blockSize(BARRY_DATA_DEFAULT_SIZE + BARRY_DATA_DEFAULT_PREPEND_SIZE) , m_dataStart(m_memBlock + BARRY_DATA_DEFAULT_PREPEND_SIZE) , m_dataSize(0) , m_externalData(0) , m_external(false) , m_endpoint(-1) { memset(m_memBlock, 0, m_blockSize); } Data::Data(int endpoint, size_t startsize, size_t prependsize) : m_memBlock(new unsigned char[startsize + prependsize]) , m_blockSize(startsize + prependsize) , m_dataStart(m_memBlock + prependsize) , m_dataSize(0) , m_externalData(0) , m_external(false) , m_endpoint(endpoint) { memset(m_memBlock, 0, m_blockSize); } Data::Data(const void *ValidData, size_t size) : m_memBlock(0) , m_blockSize(0) , m_dataStart(0) , m_dataSize(size) , m_externalData((const unsigned char*)ValidData) , m_external(true) , m_endpoint(-1) { } Data::Data(const Data &other) : m_memBlock(other.m_blockSize ? new unsigned char[other.m_blockSize] : 0) , m_blockSize(other.m_blockSize) , m_dataStart(m_memBlock + other.AvailablePrependSpace()) , m_dataSize(other.m_dataSize) , m_externalData(other.m_externalData) , m_external(other.m_external) , m_endpoint(other.m_endpoint) { // copy over the raw data if( !m_external ) memcpy(m_memBlock, other.m_memBlock, other.m_blockSize); } Data::~Data() { delete [] m_memBlock; } // // MakeSpace // /// Reallocates buffers so that it is safe to write desiredsize data /// to m_dataStart after it returns. All existing data is preserved. /// /// This function also performs any copy on write needed. /// /// If desiredprepend is nonzero, then at least desiredprepend bytes /// of prepend space will exist in the buffer after return. /// If desiredprepend is zero, defaults will be used if needed. /// void Data::MakeSpace(size_t desiredsize, size_t desiredprepend) { // use a default prepend size if none currently available size_t prepend = std::max(AvailablePrependSpace(), desiredprepend); if( !prepend ) prepend = 0x100; // GetBufSize() returns 0 if m_external is true if( GetBufSize() < (desiredsize + prepend) || (desiredprepend && AvailablePrependSpace() < desiredprepend) ) { // get a proper chunk to avoid future resizes desiredsize += 1024 + prepend; // desired size must be at least the size of our current // data (in case of external data), as well as the size // of our desired prepend space if( desiredsize < (m_dataSize + prepend) ) desiredsize = m_dataSize + prepend; // setup new zeroed buffer... reuse m_memBlock if it // exists (see operator=()) unsigned char *newbuf = 0; if( m_memBlock && m_blockSize >= desiredsize ) { newbuf = m_memBlock; } else { newbuf = new unsigned char[desiredsize]; memset(newbuf, 0, desiredsize); } // copy valid data over if( m_external ) { memcpy(newbuf + prepend, m_externalData, m_dataSize); // not external anymore m_external = false; } else { memcpy(newbuf + prepend, m_dataStart, m_dataSize); } // install new buffer if we've allocated a new one if( m_memBlock != newbuf ) { delete [] m_memBlock; m_memBlock = newbuf; m_blockSize = desiredsize; } // update m_dataStart m_dataStart = m_memBlock + prepend; } } size_t Data::AvailablePrependSpace() const { if( m_external ) return 0; else return m_dataStart - m_memBlock; } void Data::InputHexLine(istream &is) { ios_format_state state(is); unsigned int values[16]; size_t index = 0; size_t address; is >> setbase(16) >> address; if( !is ) return; // nothing to do is.ignore(); // eat the ':' while( is && index < 16 ) { is >> setbase(16) >> values[index]; if( is ) index++; } dout("InputHexLine: read " << index << " bytes"); MakeSpace(address + index); // make space for the new m_dataSize = std::max(address + index, m_dataSize); while( index-- ) m_dataStart[address + index] = (unsigned char) values[index]; return; } void Data::DumpHexLine(ostream &os, size_t index, size_t size) const { ios_format_state state(os); os.setf(ios::right); // index os << " "; os << setbase(16) << setfill('0') << setw(8) << index << ": "; // hex byte data for( size_t i = 0; i < size; i++ ) { if( (index+i) < GetSize() ) { os << setbase(16) << setfill('0') << setw(2) << setprecision(2) << (unsigned int) GetData()[index + i] << ' '; } else { os << " "; } } // printable data if( bPrintAscii ) { locale loc = os.getloc(); os << ' '; for( size_t i = 0; i < size && (index+i) < GetSize(); i++ ) { ostream::traits_type::char_type c = GetData()[index + i]; os << setbase(10) << (char) (std::isprint(c, loc) ? c : '.'); } } os << "\n"; } void Data::DumpHex(ostream &os) const { for( size_t address = 0; address < GetSize(); address += 16 ) { DumpHexLine(os, address, 16); } } unsigned char * Data::GetBuffer(size_t requiredsize) { if( requiredsize == 0 ) { // handle default, use data size requiredsize = m_dataSize; } MakeSpace(requiredsize); return m_dataStart; } /// Returns size of buffer returned by GetBuffer(). Note that this does not /// include available prepend space. size_t Data::GetBufSize() const { if( m_external ) return 0; else return m_blockSize - (m_dataStart - m_memBlock); } void Data::ReleaseBuffer(int datasize) { if( datasize < 0 && datasize != -1) throw std::logic_error(_("Data::ReleaseBuffer() argument must be -1 or >= 0")); if( m_external ) throw std::logic_error(_("Data::ReleaseBuffer() must be called after GetBuffer()")); if( !(datasize == -1 || (unsigned int)datasize <= GetBufSize()) ) throw std::logic_error(_("Data::ReleaseBuffer() must be called with a size smaller than the original buffer requested")); if( datasize >= 0 ) { m_dataSize = datasize; } else { // search for last non-zero value in buffer m_dataSize = GetBufSize() - 1; while( m_dataSize && m_dataStart[m_dataSize] == 0 ) --m_dataSize; } } /// Append bytes of data based on str void Data::AppendHexString(const char *str) { MakeSpace(m_dataSize + 512); std::istringstream iss(str); unsigned int byte; while( iss >> hex >> byte ) { MakeSpace(m_dataSize + 1); m_dataStart[m_dataSize] = (unsigned char) byte; m_dataSize++; } } /// set buffer to 0 and remove all data void Data::Zap() { if( !m_external ) memset(m_memBlock, 0, m_blockSize); m_dataSize = 0; } Data & Data::operator=(const Data &other) { if( this == &other ) return *this; if( other.m_external ) { // just copy over the pointers m_externalData = other.m_externalData; m_external = other.m_external; m_dataSize = other.m_dataSize; m_endpoint = other.m_endpoint; } else { // don't remove our current buffer, only grow it if needed MakeSpace(other.m_dataSize); memcpy(m_dataStart, other.m_dataStart, other.m_dataSize); // then copy over the data state m_dataSize = other.m_dataSize; m_endpoint = other.m_endpoint; } return *this; } void Data::MemCpy(size_t &offset, const void *src, size_t size) { unsigned char *pd = GetBuffer(offset + size) + offset; memcpy(pd, src, size); offset += size; // if the new end of data is larger than m_dataSize, bump it if( offset > m_dataSize ) m_dataSize = offset; } void Data::Append(const void *buf, size_t size) { // MemCpy updates m_datasize via the offset reference MemCpy(m_dataSize, buf, size); } void Data::Prepend(const void *buf, size_t size) { MakeSpace(0, size); m_dataStart -= size; m_dataSize += size; memcpy(m_dataStart, (const unsigned char*) buf, size); } /// Removes size bytes from the beginning of the buffer. /// If GetSize() is less than size, then all bytes will be chopped /// and GetSize() will end up 0. void Data::Prechop(size_t size) { // chopping all the bytes that we have? if( size >= GetSize() ) { QuickZap(); return; } if( m_external ) { m_externalData += size; m_dataSize -= size; } else { m_dataStart += size; m_dataSize -= size; } } istream& operator>> (istream &is, Data &data) { data.InputHexLine(is); return is; } ostream& operator<< (ostream &os, const Data &data) { data.DumpHex(os); return os; } /////////////////////////////////////////////////////////////////////////////// // Diff class Diff::Diff(const Data &old, const Data &new_) : m_old(old), m_new(new_) { } void Diff::Compare(ostream &os, size_t index, size_t size) const { ios_format_state state(os); size_t min = std::min(m_old.GetSize(), m_new.GetSize()); // index os << "> "; os << setbase(16) << setfill('0') << setw(8) << index << ": "; // diff data for( size_t i = 0; i < size; i++ ) { size_t address = index + i; // if data is available, print the diff if( address < min ) { if( m_old.GetData()[address] != m_new.GetData()[address] ) { // differ, print hex os << setbase(16) << setfill('0') << setw(2) << setprecision(2) << (unsigned int) m_new.GetData()[address] << ' '; } else { // same, just print spaces os << " "; } } else { // one of the buffers is shorter... if( address < m_new.GetSize() ) { // new still has data, print it os << setbase(16) << setfill('0') << setw(2) << setprecision(2) << (unsigned int) m_new.GetData()[address] << ' '; } else if( address < m_old.GetSize() ) { // new is out of data and old still has some os << "XX "; } else { // no more data, just print spaces os << " "; } } } // printable data, just dump new if( Data::PrintAscii() ) { os << ' '; for( size_t i = 0; i < size && (index+i) < m_new.GetSize(); i++ ) { int c = m_new.GetData()[index + i]; os << setbase(10) << (char) (isprint(c) ? c : '.'); } } os << "\n"; } void Diff::Dump(std::ostream &os) const { ios_format_state state(os); if( m_old.GetSize() != m_new.GetSize() ) os << _("sizes differ: ") << m_old.GetSize() << " != " << m_new.GetSize() << endl; size_t max = std::max(m_old.GetSize(), m_new.GetSize()); for( size_t i = 0; i < max; i += 16 ) { m_old.DumpHexLine(os, i, 16); Compare(os, i, 16); } } ostream& operator<< (ostream &os, const Diff &diff) { diff.Dump(os); return os; } /////////////////////////////////////////////////////////////////////////////// // DBData class /// Default constructor, constructs an empty local Data object DBData::DBData() : m_version(REC_VERSION_1) // a reasonable default for now , m_localData(new Data) , m_data(*m_localData) { } /// Copy constructor - always creates an internal Data object, and /// uses Data object's copy constructor to make it. /// Copies all meta data as well. DBData::DBData(const DBData &other) : m_version(other.m_version) , m_dbName(other.m_dbName) , m_recType(other.m_recType) , m_uniqueId(other.m_uniqueId) , m_offset(other.m_offset) , m_localData(new Data(other.m_data)) , m_data(*m_localData) { } /// Constructs a local Data object that points to external memory DBData::DBData(const void *ValidData, size_t size) : m_version(REC_VERSION_1) // a reasonable default for now , m_localData(new Data) , m_data(*m_localData) { } DBData::DBData(RecordFormatVersion ver, const std::string &dbName, uint8_t recType, uint32_t uniqueId, size_t offset, const void *ValidData, size_t size) : m_version(ver) , m_dbName(dbName) , m_recType(recType) , m_uniqueId(uniqueId) , m_offset(offset) , m_localData(new Data(ValidData, size)) , m_data(*m_localData) { } /// If copy == false, constructs an external Data object, no local. /// If copy == true, constructs an internal Data object copy DBData::DBData(Data &externalData, bool copy) : m_version(REC_VERSION_1) // a reasonable default for now , m_localData(copy ? new Data(externalData) : 0) , m_data(copy ? *m_localData : externalData) { } DBData::DBData(RecordFormatVersion ver, const std::string &dbName, uint8_t recType, uint32_t uniqueId, size_t offset, Data &externalData, bool copy) : m_version(ver) , m_dbName(dbName) , m_recType(recType) , m_uniqueId(uniqueId) , m_offset(offset) , m_localData(copy ? new Data(externalData) : 0) , m_data(copy ? *m_localData : externalData) { } DBData::~DBData() { delete m_localData; } Data& DBData::UseData() { // make sure m_data is not external anymore m_data.GetBuffer(); return m_data; // return it } // Note: this copy operator does not change what m_data references... // whatever m_data references in the constructor is what will be changed // in this copy. // Note also that the copy *will* involve a memcpy, and maybe a memory // allocation as well. DBData& DBData::operator=(const DBData &other) { if( this == &other ) return *this; // copy the data block m_data = other.m_data; // copy the metadata CopyMeta(other); return *this; } /////////////////////////////////////////////////////////////////////////////// // Utility functions static bool IsEndpointStart(const std::string &line, int &endpoint) { if( strncmp(line.c_str(), "sep: ", 5) == 0 || strncmp(line.c_str(), "rep: ", 5) == 0 ) { endpoint = atoi(line.c_str() + 5); return true; } return false; } bool LoadDataArray(const string &filename, std::vector &array) { ifstream in(filename.c_str()); return ReadDataArray(in, array); } bool ReadDataArray(std::istream &is, std::vector &array) { if( !is ) return false; bool bInEndpoint = false; unsigned int nCurrent = 0; size_t nLargestSize = 0x100; while( is ) { string line; getline(is, line); int endpoint; if( bInEndpoint ) { if( IsHexData(line) ) { istringstream sline(line); sline >> array[nCurrent]; continue; } else { nLargestSize = std::max(nLargestSize, array[nCurrent].GetBufSize()); bInEndpoint = false; } } // check if this line starts a new endpoint if( IsEndpointStart(line, endpoint) ) { bInEndpoint = true; Data chunk(endpoint, nLargestSize); array.push_back(chunk); nCurrent = array.size() - 1; } } return true; } } // namespace Barry barry-0.18.5/src/m_raw_channel.cc0000644001161500056700000001714612242254476016160 0ustar cdfreycdfrey/// /// \file m_raw_channel.cc /// Mode class for a raw channel /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Portions Copyright (C) 2010 RealVNC Ltd. 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "m_raw_channel.h" #include "semaphore.h" #include "data.h" #include "protocol.h" #include "protostructs.h" #include "packet.h" #include "endian.h" #include "error.h" #include "usbwrap.h" #include "controller.h" #include #include #include #include #include "protostructs.h" #include "debug.h" namespace Barry { namespace Mode { /////////////////////////////////////////////////////////////////////////////// // RawChannel SocketDataHandler callback class for data socket class RawChannelSocketHandler: public SocketRoutingQueue::SocketDataHandler { RawChannel &m_raw_channel; public: RawChannelSocketHandler(RawChannel &raw_channel) : m_raw_channel(raw_channel) {} virtual void DataReceived(Data &data) { m_raw_channel.HandleReceivedData(data); } virtual void Error(Barry::Error &error) { SocketDataHandler::Error(error); m_raw_channel.HandleError(error); } virtual ~RawChannelSocketHandler() {} }; /////////////////////////////////////////////////////////////////////////////// // RawChannel SocketDataHandler callback class for zero socket class RawChannelZeroSocketHandler: public SocketRoutingQueue::SocketDataHandler { RawChannel &m_raw_channel; public: RawChannelZeroSocketHandler(RawChannel &raw_channel) : m_raw_channel(raw_channel) {} virtual void DataReceived(Data &data) { m_raw_channel.HandleReceivedZeroPacket(data); } virtual void Error(Barry::Error &error) { SocketDataHandler::Error(error); m_raw_channel.HandleError(error); } virtual ~RawChannelZeroSocketHandler() {} }; /////////////////////////////////////////////////////////////////////////////// // RawChannel Mode class RawChannel::RawChannel(Controller &con, RawChannelDataCallback &callback) : Mode(con, Controller::RawChannel) , m_callback(&callback) , m_send_buffer(NULL) , m_zero_registered(false) , m_pending_error(NULL) { CheckQueueAvailable(); InitBuffer(); } RawChannel::RawChannel(Controller &con) : Mode(con, Controller::RawChannel) , m_callback(NULL) , m_send_buffer(NULL) , m_zero_registered(false) , m_pending_error(NULL) { CheckQueueAvailable(); InitBuffer(); } void RawChannel::CheckQueueAvailable() { if( !m_con.HasQueue() ) { throw Barry::Error(_("RawChannel: No routing queue set in controller")); } } void RawChannel::InitBuffer() { m_send_buffer = new unsigned char[SB_CHANNELPACKET_HEADER_SIZE + SB_CHANNELPACKET_MAX_DATA_SIZE]; } RawChannel::~RawChannel() { UnregisterZeroSocketInterest(); delete[] m_send_buffer; delete m_pending_error; } void RawChannel::OnOpen() { // Enable sequence packets so that DataSendAck callback and close can be // implemented m_zero_registered = true; SocketRoutingQueue::SocketDataHandlerPtr zeroCallback; zeroCallback.reset(new RawChannelZeroSocketHandler(*this)); m_con.GetQueue()->RegisterInterest(0, zeroCallback); // Get socket data packets routed to this class as well if a // callback was provided, otherside just get the data packets // placed into a queue for the socket. if( m_callback ) { SocketRoutingQueue::SocketDataHandlerPtr callback; callback.reset(new RawChannelSocketHandler(*this)); m_socket->UnregisterInterest(); m_socket->RegisterInterest(callback); } else { // sockets already register themselves by default, // so no need to do anything in this case } } void RawChannel::HandleReceivedZeroPacket(Data &data) { Protocol::CheckSize(data, SB_PACKET_HEADER_SIZE); MAKE_PACKETPTR_BUF(packet, data.GetData()); if( packet->socket != 0 ) { UnregisterZeroSocketInterest(); SetPendingError(_("RawChannel: Got packet not for socket-zero")); } switch( btohs(packet->command) ) { case SB_COMMAND_CLOSE_SOCKET: case SB_COMMAND_REMOTE_CLOSE_SOCKET: // Stop listening to socket 0 messages // so that socket close work. UnregisterZeroSocketInterest(); if( m_callback ) { m_callback->ChannelClose(); } break; default: UnregisterZeroSocketInterest(); if( m_callback ) { m_callback->ChannelError(_("RawChannel: Got unexpected socket zero packet")); } else { SetPendingError(_("RawChannel: Got unexpected socket zero packet")); } break; } } void RawChannel::HandleReceivedData(Data &data) { // Only ever called in callback mode ValidateDataPacket(data); MAKE_CHANNELPACKETPTR_BUF(packet, data.GetData()); // Should be a socket packet for us, so remove packet headers Data partial(packet->u.data, data.GetSize() - SB_CHANNELPACKET_HEADER_SIZE); if( m_callback ) { m_callback->DataReceived(partial); } else { SetPendingError(_("RawChannel: Received data to handle when in non-callback mode")); } } void RawChannel::HandleError(Barry::Error &error) { std::ostringstream errorOss; errorOss << _("RawChannel: Socket error received, what: ") << error.what(); if( m_callback ) { m_callback->ChannelError(errorOss.str().c_str()); } else { SetPendingError(errorOss.str().c_str()); } } void RawChannel::UnregisterZeroSocketInterest() { if( m_zero_registered ) { m_con.GetQueue()->UnregisterInterest(0); m_zero_registered = false; } } void RawChannel::SetPendingError(const char *msg) { if( !m_pending_error ) { m_pending_error = new std::string(msg); } } /////////////////////////////////////////////////////////////////////////////// // public API void RawChannel::Send(Data &data, int timeout) { size_t packetSize = SB_CHANNELPACKET_HEADER_SIZE + data.GetSize(); if( packetSize > SB_CHANNELPACKET_HEADER_SIZE + SB_CHANNELPACKET_MAX_DATA_SIZE ) { throw Barry::Error(_("RawChannel: send data size larger than MaximumPacketSize")); } if( m_pending_error ) { throw Barry::Error(*m_pending_error); } // setup header and copy data in MAKE_CHANNELPACKETPTR_BUF(packet, m_send_buffer); packet->size = htobs(packetSize); std::memcpy(packet->u.data, data.GetData(), data.GetSize()); Data toSend(m_send_buffer, packetSize); m_socket->SyncSend(toSend, timeout); if( m_pending_error ) { throw Barry::Error(*m_pending_error); } } void RawChannel::Receive(Data &data,int timeout) { if( m_callback ) { throw std::logic_error(_("RawChannel: Receive called when channel was created with a callback")); } if( m_pending_error ) { throw Barry::Error(*m_pending_error); } // Receive into a buffer m_socket->Receive(m_receive_data, timeout); // Then transfer across, skipping the header ValidateDataPacket(m_receive_data); MAKE_CHANNELPACKETPTR_BUF(packet, m_receive_data.GetData()); size_t len = packet->size - SB_CHANNELPACKET_HEADER_SIZE; memcpy(data.GetBuffer(), packet->u.data, len); data.ReleaseBuffer(len); } void RawChannel::ValidateDataPacket(Data &data) { Protocol::CheckSize(data, SB_CHANNELPACKET_HEADER_SIZE); MAKE_CHANNELPACKETPTR_BUF(packet, data.GetData()); if( packet->size != data.GetSize() ) { throw std::logic_error(_("RawChannel: Data size doesn't match packet size")); } } size_t RawChannel::MaximumSendSize() { return SB_CHANNELPACKET_MAX_DATA_SIZE; } }} // namespace Barry::Mode barry-0.18.5/src/xmlparser.cc0000644001161500056700000000545712242254476015402 0ustar cdfreycdfrey/// /// \file xmlparser.cc /// A simple XML parser (use callback on start, end and data block /// /* Copyright (C) 2010, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include #include "xmlparser.h" namespace Barry { namespace XML { XMLParser::XMLParser(std::istream& input, const char *charset) : xmlpp::SaxParser() , input(input) { this->depth = 0; this->charset = charset; } XMLParser::~XMLParser(void) { } const unsigned long XMLParser::GetDepth(void) const { return depth; } bool XMLParser::Run(void) { try { set_substitute_entities(true); parse_chunk(""); std::string line; while( getline(input, line) ) { parse_chunk(line); } finish_chunk_parsing(); } catch (const xmlpp::exception& ex) { std::cout << "libxml++ exception: " << ex.what() << std::endl; return false; } return true; } void XMLParser::on_start_document() { std::cout << "on_start_document()" << std::endl; } void XMLParser::on_end_document() { std::cout << "on_end_document()" << std::endl; } void XMLParser::on_start_element(const Glib::ustring& name, const xmlpp::SaxParser::AttributeList& attributes) { std::cout << "Start:" << name << std::endl; depth++; // Print attributes: for (xmlpp::SaxParser::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter) { std::cout << " Attribute name=" << iter->name << std::endl; std::cout << " , value= " << iter->value << std::endl; } } void XMLParser::on_end_element(const Glib::ustring& name) { std::cout << "End:" << name << std::endl; depth--; } void XMLParser::on_characters(const Glib::ustring& text) { std::cout << " Data:" << text << std::endl; } void XMLParser::on_comment(const Glib::ustring& text) { std::cout << "on_comment(): " << text << std::endl; } void XMLParser::on_warning(const Glib::ustring& text) { std::cout << "on_warning(): " << text << std::endl; } void XMLParser::on_error(const Glib::ustring& text) { std::cout << "on_error(): " << text << std::endl; } void XMLParser::on_fatal_error(const Glib::ustring& text) { std::cout << "on_fatal_error(): " << text << std::endl; } } // namespace XML } // namespace Barry barry-0.18.5/src/r_cstore.cc0000644001161500056700000001504112242254476015173 0ustar cdfreycdfrey/// /// \file r_cstore.cc /// Blackberry database record parser class for /// Content Store records. /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "r_cstore.h" #include "record-internal.h" #include "data.h" #include #include #include #include "ios_state.h" #define __DEBUG_MODE__ #include "debug.h" using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // ContentStore class // ContentStore field codes #define CSFC_FILENAME 0x01 // may not always be a complete file,but // a folder name as well #define CSFC_FOLDER_FLAG 0x05 #define CSFC_FILE_DESCRIPTOR 0x06 #define CSFC_FILE_CONTENT 0x07 #define MAX_CONTENT_BLOCK_SIZE 0xfffe ContentStore::ContentStore() { Clear(); } ContentStore::~ContentStore() { } const unsigned char* ContentStore::ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { const CommonField *field = (const CommonField *) begin; // advance and check size begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size); if( begin > end ) // if begin==end, we are ok return begin; if( !btohs(field->size) ) // if field has no size, something's up return begin; switch( field->type ) { case CSFC_FILENAME: Filename = ParseFieldString(field); return begin; case CSFC_FOLDER_FLAG: FolderFlag = false; { // the CSFC_FOLDER_FLAG field seems to always // contain the string "folder".. so check for it string s = ParseFieldString(field); if( s == "folder" ) { FolderFlag = true; } } return begin; case CSFC_FILE_CONTENT: if( FileSize ) { // size already received, append data to FileContent FileContent.append((const char*)field->u.raw, btohs(field->size)); } else { FileSize = btohll(field->u.uint64); } return begin; case CSFC_FILE_DESCRIPTOR: // need to parse this further, but until then, just // store it as a chunk of data FileDescriptor.assign((const char*)field->u.raw, btohs(field->size)); return begin; } // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; uf.data.assign((const char*)field->u.raw, btohs(field->size)); Unknowns.push_back(uf); // return new pointer for next field return begin; } void ContentStore::ParseHeader(const Data &data, size_t &offset) { // no header to parse } void ContentStore::ParseFields(const Data &data, size_t &offset, const IConverter *ic) { const unsigned char *finish = ParseCommonFields(*this, data.GetData() + offset, data.GetData() + data.GetSize(), ic); offset += finish - (data.GetData() + offset); } void ContentStore::Validate() const { } void ContentStore::BuildHeader(Data &data, size_t &offset) const { } void ContentStore::BuildFields(Data &data, size_t &offset, const IConverter *ic) const { data.Zap(); if( !Filename.size() ) throw BadData(_("Content Store must have a name.")); if( !FolderFlag && !FileContent.size() ) throw BadData(_("Content Store item without any data.")); // Filename BuildField(data, offset, CSFC_FILENAME, Filename); // Folder? if( FolderFlag ) { BuildField(data, offset, CSFC_FOLDER_FLAG, string("folder")); } else { // write file descriptor first BuildField(data, offset, CSFC_FILE_DESCRIPTOR, FileDescriptor.data(), FileDescriptor.size()); // a normal file... the file content is given: // 64 bit size // content in blocks of 0xfffe bytes until done // all with the same ID // force the size to actual, and write it first uint64_t RealSize = FileContent.size(); BuildField(data, offset, CSFC_FILE_CONTENT, RealSize); // write data in blocks of 0xfffe bytes for( size_t foff = 0; foff < FileContent.size(); ) { size_t blocksize = FileContent.size() - foff; if( blocksize > MAX_CONTENT_BLOCK_SIZE ) blocksize = MAX_CONTENT_BLOCK_SIZE; BuildField(data, offset, CSFC_FILE_CONTENT, FileContent.data() + foff, blocksize); // advance foff += blocksize; } } // and finally save unknowns UnknownsType::const_iterator ub = Unknowns.begin(), ue = Unknowns.end(); for( ; ub != ue; ub++ ) { BuildField(data, offset, *ub); } data.ReleaseBuffer(offset); } void ContentStore::Clear() { RecType = GetDefaultRecType(); RecordId = 0; Filename.clear(); FolderFlag = false; FileContent.clear(); FileDescriptor.clear(); Unknowns.clear(); // internal variables FileSize = 0; } const FieldHandle::ListT& ContentStore::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; #undef CONTAINER_OBJECT_NAME #define CONTAINER_OBJECT_NAME fhv #undef RECORD_CLASS_NAME #define RECORD_CLASS_NAME ContentStore FHP(RecType, _("Record Type Code")); FHP(RecordId, _("Unique Record ID")); FHD(Filename, _("File or Folder Name"), CSFC_FILENAME, true); FHD(FolderFlag, _("Folder Flag"), CSFC_FOLDER_FLAG, false); FHD(FileContent, _("File Content"), CSFC_FILE_CONTENT, false); FHD(FileDescriptor, _("File Descriptor"), CSFC_FILE_DESCRIPTOR, false); FHP(Unknowns, _("Unknown Fields")); return fhv; } std::string ContentStore::GetDescription() const { return Filename; } void ContentStore::Dump(std::ostream &os) const { ios_format_state state(os); os.setf(ios::left); os.fill(' '); os << _("ContentStore: ") << "0x" << hex << RecordId << " (" << (unsigned int)RecType << ")\n"; os << _(" Filename: ") << Filename << endl; os << _(" Folder: ") << (FolderFlag ? "yes" : "no") << endl; os << _(" BB Size: ") << dec << FileSize << endl; os << _(" Actual Size: ") << FileContent.size() << endl; os << _(" Descriptor:\n") << Data(FileDescriptor.data(), FileDescriptor.size()) << endl; os << _(" Content:\n") << Data(FileContent.data(), FileContent.size()) << endl; // and finally print unknowns os << Unknowns; } bool ContentStore::operator<(const ContentStore &other) const { return RecordId < other.RecordId; } } // namespace Barry barry-0.18.5/src/r_recordstate.cc0000644001161500056700000001012312242254476016207 0ustar cdfreycdfrey/// /// \file r_recordstate.cc /// RecordStateTable database record parser class /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "record.h" #include "record-internal.h" #include "data.h" #include #include using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // RecordStateTable class RecordStateTable::RecordStateTable() : m_LastNewRecordId(1) { } RecordStateTable::~RecordStateTable() { } const unsigned char* RecordStateTable::ParseField(const unsigned char *begin, const unsigned char *end) { const RecordStateTableField *field = (const RecordStateTableField *) begin; // advance and check size begin += sizeof(RecordStateTableField); if( begin > end ) // if begin==end, we are ok return begin; State state; state.Index = btohs(field->index); state.RecordId = btohl(field->uniqueId); state.Dirty = (field->flags & BARRY_RSTF_DIRTY) != 0; state.RecType = field->rectype; state.Unknown2.assign((const char*)field->unknown2, sizeof(field->unknown2)); StateMap[state.Index] = state; return begin; } void RecordStateTable::Parse(const Data &data) { size_t offset = 12; // skipping the unknown 2 bytes at start if( offset >= data.GetSize() ) return; const unsigned char *begin = data.GetData() + offset; const unsigned char *end = data.GetData() + data.GetSize(); while( begin < end ) begin = ParseField(begin, end); } void RecordStateTable::Clear() { StateMap.clear(); m_LastNewRecordId = 1; } // Searches the StateMap table for RecordId, and returns the "index" // in the map if found. Returns true if found, false if not. // pFoundIndex can be null if only the existence of the index is desired bool RecordStateTable::GetIndex(uint32_t RecordId, IndexType *pFoundIndex) const { StateMapType::const_iterator i = StateMap.begin(); for( ; i != StateMap.end(); ++i ) { if( i->second.RecordId == RecordId ) { if( pFoundIndex ) *pFoundIndex = i->first; return true; } } return false; } // Generate a new RecordId that is not in the state table. // Starts at 1 and keeps incrementing until a free one is found. uint32_t RecordStateTable::MakeNewRecordId() const { // start with next Id m_LastNewRecordId++; // make sure it doesn't already exist StateMapType::const_iterator i = StateMap.begin(); while( i != StateMap.end() ) { if( m_LastNewRecordId == i->second.RecordId ) { m_LastNewRecordId++; // try again i = StateMap.begin(); // start over } else { ++i; // next State } } return m_LastNewRecordId; } void RecordStateTable::Dump(std::ostream &os) const { ios::fmtflags oldflags = os.setf(ios::right); char fill = os.fill(' '); bool bPrintAscii = Data::PrintAscii(); Data::PrintAscii(false); os << _(" Index RecordId Dirty RecType") << endl; os << "------- ---------- ----- -------" << endl; StateMapType::const_iterator b, e = StateMap.end(); for( b = StateMap.begin(); b != e ; ++b ) { const State &state = b->second; os.fill(' '); os << setbase(10) << setw(7) << state.Index; os << " 0x" << setbase(16) << setfill('0') << setw(8) << state.RecordId; os << " " << setfill(' ') << setw(5) << (state.Dirty ? _("yes") : _("no")); os << " 0x" << setbase(16) << setfill('0') << setw(2) << state.RecType; os << " " << Data(state.Unknown2.data(), state.Unknown2.size()); } // cleanup the stream os.flags(oldflags); os.fill(fill); Data::PrintAscii(bPrintAscii); } } // namespace Barry barry-0.18.5/src/pppfilter.h0000644001161500056700000000303612242254476015223 0ustar cdfreycdfrey/// /// \file pppfilter.h /// Data filter class, to morph PPP data into something that /// the Blackberry / Rogers / ISP can handle. /// This logic is based partly on XmBlackBerry's /// gprs_protocol_fix.c program. /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_M_PPPFILTER_H__ #define __BARRY_M_PPPFILTER_H__ #include "dll.h" #include "data.h" namespace Barry { class BXEXPORT PppFilter { private: Data m_writeBuf; // used for 0x7e handling // write flags bool m_ppp_mode; unsigned char m_last; BXLOCAL const Data& GetBuffer() const; // not implemented, since // Write can return either m_writeBuf or data, and // so this would be useless and unsafe BXLOCAL void Filter(Data &dest, const Data &src, unsigned int destoffset); public: PppFilter(); bool PppMode() const { return m_ppp_mode; } const Data& Write(const Data &data); Data& Write(const Data &data, unsigned int prepend); }; } // namespace Barry #endif barry-0.18.5/src/m_serial.cc0000644001161500056700000001056612242254476015155 0ustar cdfreycdfrey/// /// \file m_serial.cc /// Mode class for serial / GPRS modem mode /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "m_serial.h" #include "controller.h" #include "protostructs.h" #include "endian.h" #include "debug.h" #include namespace Barry { namespace Mode { ////////////////////////////////////////////////////////////////////////////// // Mode::Serial class Serial::Serial( Controller &con, DeviceDataCallback callback, void *callback_context) : m_con(con) , m_ModeSocket(0) , m_CtrlSocket(0) , m_callback(callback) , m_callback_context(callback_context) { if( !m_con.HasQueue() ) throw std::logic_error(_("A SocketRoutingQueue is required in the Controller class when using Mode::Serial.")); } Serial::~Serial() { } ////////////////////////////////////////////////////////////////////////////// // protected API / static functions void Serial::DataCallback(Serial &ser, Data *data) { ddout("Serial::DataCallback called"); if( data->GetSize() <= 4 ) return; // nothing to do // call callback if available if( ser.m_callback ) { (*ser.m_callback)(ser.m_callback_context, data->GetData() + 4, data->GetSize() - 4); } // else { // // append data to readCache // FIXME; // } } void Serial::CtrlCallback(Serial &ser, Data *data) { // just dump to stdout, and do nothing ddout("CtrlCallback received:\n" << *data); } ////////////////////////////////////////////////////////////////////////////// // public API void Serial::Open(const char *password) { if( m_ModeSocket ) { m_data->Close(); m_data.reset(); m_ModeSocket = 0; } if( m_CtrlSocket ) { m_ctrl->Close(); m_ctrl.reset(); m_CtrlSocket = 0; } m_ModeSocket = m_con.SelectMode(Controller::UsbSerData); m_data = m_con.OpenSocket(m_ModeSocket, password); m_CtrlSocket = m_con.SelectMode(Controller::UsbSerCtrl); m_ctrl = m_con.OpenSocket(m_CtrlSocket, password); // register callback for incoming data, for speed SocketRoutingQueue::SocketDataHandlerPtr data_callback (new SocketRoutingQueue::SimpleSocketDataHandler(*this, DataCallback)); m_data->UnregisterInterest(); m_data->RegisterInterest(data_callback); SocketRoutingQueue::SocketDataHandlerPtr ctrl_callback (new SocketRoutingQueue::SimpleSocketDataHandler(*this, CtrlCallback)); m_ctrl->UnregisterInterest(); m_ctrl->RegisterInterest(ctrl_callback); const unsigned char start[] = { 0, 0, 0x0a, 0, 0x01, 0x01, 0xc2, 0x00, 0x40, 0x00 }; Data block(start, sizeof(start)); m_ctrl->RawSend(block); } void Serial::Close() { ddout("Serial:: Closing connection."); } /* // FIXME - if this behaviour is truly common between modes, create // a common base class for this. void Serial::RetryPassword(const char *password) { if( m_data.get() || m_ctrl.get() ) throw std::logic_error("Socket already open in Serial::RetryPassword"); m_data = m_con.m_zero.OpenDBSocket(m_ModeSocket, password); m_ctrl = m_con.m_zero.OpenDBSocket(m_CtrlSocket, password); // register callback for incoming data, for speed m_data->UnregisterInterest(); m_data->RegisterInterest(DataCallback, this); } */ /* // can be called from separate thread void Serial::SerialRead(Data &data, int timeout) { m_socket.Receive(data, timeout); } */ void Serial::Write(const Data &data, int timeout) { if( data.GetSize() <= 0 ) return; // nothing to do if( !m_data.get() ) throw std::logic_error(_("Must call Open() before Write() in Mode::Serial")); // filter data for PPP, and prepend 4 bytes Data &filtered = m_filter.Write(data, 4); // setup header (only size needed, as socket will be set by socket class) unsigned char *buf = filtered.GetBuffer(); MAKE_PACKETPTR_BUF(spack, buf); spack->size = htobs(filtered.GetSize()); // send via appropriate socket m_data->RawSend(filtered, timeout); } }} // namespace Barry::Mode barry-0.18.5/src/platform.h0000644001161500056700000000352012242254476015040 0ustar cdfreycdfrey/// /// \file src/platform.h /// Platform-specific details for the Barry library /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2010, RealVNC Ltd. 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_PLATFORM_H__ #define __BARRY_PLATFORM_H__ #include // threading and struct timespec ////////////////////////////////////////////////////////////////////////////// // All GCC specific detail #if defined( __GNUC__ ) #define ATTRIBUTE_PACKED __attribute__ ((packed)) #define USE_PACK_PRAGMA 0 #else #define ATTRIBUTE_PACKED #define USE_PACK_PRAGMA 1 #endif ////////////////////////////////////////////////////////////////////////////// // All Windows specific detail #if defined( WIN32 ) && !defined( WINCE ) // On Windows, we must call usb_set_configuration() before claim_interface() #define MUST_SET_CONFIGURATION 1 #else #define MUST_SET_CONFIGURATION 0 #endif #if defined( WINCE ) #define vsnprintf _vsnprintf #endif ////////////////////////////////////////////////////////////////////////////// // All FreeBSD / BSD specific detail #if defined( __FreeBSD__ ) #endif ////////////////////////////////////////////////////////////////////////////// // All Mac OS X specific detail #if defined( __APPLE__ ) && defined( __MACH__ ) #endif #endif barry-0.18.5/src/strnlen.c0000644001161500056700000000161112242254476014673 0ustar cdfreycdfrey/// /// \file strnlen.c /// Implementation of strnlen() call, for systems that /// don't have GNU. /// /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "strnlen.h" size_t barry_strnlen(const char *s, size_t maxlen) { size_t len = 0; while( len < maxlen && s[len] ) len++; return len; } barry-0.18.5/src/r_contact.h0000644001161500056700000001115112242254476015167 0ustar cdfreycdfrey/// /// \file r_contact.h /// Blackberry database record parser class for contact records. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_CONTACT_H__ #define __BARRY_RECORD_CONTACT_H__ #include "dll.h" #include "record.h" #include #include #include #include #include namespace Barry { // forward declarations class IConverter; // // NOTE: All classes here must be container-safe! Perhaps add sorting // operators in the future. // struct BXEXPORT ContactGroupLink { uint32_t Link; uint16_t Unknown; ContactGroupLink() : Link(0), Unknown(0) {} ContactGroupLink(uint32_t link, uint16_t unknown) : Link(link), Unknown(unknown) {} }; /// \addtogroup RecordParserClasses /// @{ // // Contact record class // /// Represents a single record in the Address Book Blackberry database. /// class BXEXPORT Contact { public: typedef Barry::CategoryList CategoryList; typedef ContactGroupLink GroupLink; typedef std::vector GroupLinksType; typedef Barry::UnknownsType UnknownsType; typedef Barry::EmailType EmailType; typedef Barry::EmailList EmailList; // // Record fields // // contact specific data uint8_t RecType; uint32_t RecordId; EmailList EmailAddresses; /// This field, Phone, is deprecated. It is possible /// to write to this field to the Blackberry, /// but modern devices won't let you add it /// through their GUIs. This field only seems /// to exist on the 7750. While other devices /// accept the field and display it, it is /// not accessible by default. std::string Phone; std::string Fax, HomeFax, WorkPhone, HomePhone, MobilePhone, MobilePhone2, Pager, PIN, Radio, WorkPhone2, HomePhone2, OtherPhone, FirstName, LastName, Company, DefaultCommunicationsMethod, JobTitle, PublicKey, URL, Prefix, Notes, UserDefined1, UserDefined2, UserDefined3, UserDefined4, Image, Nickname; Date Birthday; Date Anniversary; PostalAddress WorkAddress; PostalAddress HomeAddress; // Categories are not allowed to have commas in them. // A category name containing a comma will be split into // two categories, not only by this library, but by the // device itself. CategoryList Categories; GroupLinksType GroupLinks; UnknownsType Unknowns; private: bool m_FirstNameSeen; public: const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); public: Contact(); ~Contact(); uint32_t GetID() const { return RecordId; } std::string GetFullName() const; const std::string& GetEmail(unsigned int index = 0) const; // Parser / Builder API (see parser.h / builder.h) void Validate() const; uint8_t GetRecType() const { return RecType; } uint32_t GetUniqueId() const { return RecordId; } void SetIds(uint8_t Type, uint32_t Id) { RecType = Type; RecordId = Id; } void ParseHeader(const Data &data, size_t &offset); void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); void BuildHeader(Data &data, size_t &offset) const; void BuildFields(Data &data, size_t &offset, const IConverter *ic = 0) const; // operations (common among record classes) void Clear(); // erase everything void Dump(std::ostream &os) const; std::string GetDescription() const; // Sorting - use enough data to make the sorting as // consistent as possible bool operator<(const Contact &other) const; // database name static const char * GetDBName() { return "Address Book"; } static uint8_t GetDefaultRecType() { return 0; } // helpers static void SplitName(const std::string &full, std::string &first, std::string &last); static std::string Email2CommaString(const EmailList &list); static void CommaString2Email(const std::string &list, EmailList &result); // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<< (std::ostream &os, const Contact &contact) { contact.Dump(os); return os; } /// @} } // namespace Barry #endif barry-0.18.5/src/a_library.h0000644001161500056700000000240412242254476015160 0ustar cdfreycdfrey/// /// \file a_library.h /// ALX Library class based on CODSection class /// /* Copyright (C) 2010, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_A_LIBRARY_H__ #define __BARRY_A_LIBRARY_H__ #include #include "dll.h" #include "a_codsection.h" namespace Barry { namespace ALX { class BXEXPORT Library : public CODSection { public: Library(void); Library(const xmlpp::SaxParser::AttributeList& attrs); virtual ~Library(void); virtual void Dump(std::ostream &os) const; }; inline std::ostream& operator<<(std::ostream& os, const Library& app) { app.Dump(os); return os; } } // namespace ALX } // namespace Barry #endif barry-0.18.5/src/cbarry.h0000644001161500056700000002125212242254476014500 0ustar cdfreycdfrey/** * \file cbarry.h * Main header file for Barry C API - incomplete */ /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_CBARRY_H__ #define __BARRY_CBARRY_H__ /* * Supporting C headers */ #include "dll.h" #include #include #ifdef __cplusplus extern "C" { #endif /* * Barry C API * * All functions that can fail will either return a handle, which can * be compared to NULL, or return int, which will == -1 on error. * * Functions that return a "count" can also fail, but rarely (such as * if you pass in a bad handle). */ /* Handle types */ typedef void* probe_handle_t; typedef void* con_handle_t; typedef void* state_table_handle_t; typedef void* record_handle_t; typedef void (*process_record_callback_t)(int record_type, record_handle_t filled_record); typedef void (*fill_record_callback_t)(int record_type, record_handle_t empty_record); /* Record type codes */ #define BARRY_RECORD_CONTACT 1 #define BARRY_RECORD_MESSAGE 2 #define BARRY_RECORD_CALENDAR 3 #define BARRY_RECORD_SERVICEBOOK 4 /* Record field type codes */ #define BARRY_FIELDTYPE_NUMBER 1 /* uint32_t */ #define BARRY_FIELDTYPE_STRING 2 /* null terminated or raw str */ #define BARRY_FIELDTYPE_TIME 3 /* time_t */ #define IS_NUMBER(fieldcode) (((fieldcode & 0xff0000) == 0x010000) #define IS_STRING(fieldcode) (((fieldcode & 0xff0000) == 0x020000) #define IS_TIME(fieldcode) (((fieldcode & 0xff0000) == 0x030000) /* Contact record field codes */ #define BARRY_CONTACT_RECORDID 0x010101 /* uint32_t */ #define BARRY_CONTACT_EMAIL 0x020102 /* strings below... */ #define BARRY_CONTACT_PHONE 0x020103 #define BARRY_CONTACT_FAX 0x020104 #define BARRY_CONTACT_WORKPHONE 0x020105 #define BARRY_CONTACT_HOMEPHONE 0x020106 #define BARRY_CONTACT_MOBILEPHONE 0x020107 #define BARRY_CONTACT_PAGER 0x020108 #define BARRY_CONTACT_PIN 0x020109 #define BARRY_CONTACT_FIRSTNAME 0x02010a #define BARRY_CONTACT_LASTNAME 0x02010b #define BARRY_CONTACT_COMPANY 0x02010c #define BARRY_CONTACT_DEFAULTCOMMMETHOD 0x02010d #define BARRY_CONTACT_ADDRESS1 0x02010e #define BARRY_CONTACT_ADDRESS2 0x02010f #define BARRY_CONTACT_ADDRESS3 0x020110 #define BARRY_CONTACT_CITY 0x020111 #define BARRY_CONTACT_PROVINCE 0x020112 #define BARRY_CONTACT_POSTALCODE 0x020113 #define BARRY_CONTACT_COUNTRY 0x020114 #define BARRY_CONTACT_TITLE 0x020115 #define BARRY_CONTACT_PUBLICKEY 0x020116 #define BARRY_CONTACT_NOTES 0x020117 /* Message record field codes */ #define BARRY_MESSAGE_FROM_NAME 0x020201 /* all strings */ #define BARRY_MESSAGE_FROM_EMAIL 0x020202 #define BARRY_MESSAGE_TO_NAME 0x020203 #define BARRY_MESSAGE_TO_EMAIL 0x020204 #define BARRY_MESSAGE_CC_NAME 0x020205 #define BARRY_MESSAGE_CC_EMAIL 0x020206 #define BARRY_MESSAGE_SUBJECT 0x020207 #define BARRY_MESSAGE_BODY 0x020208 /* string or raw */ /* Calendar record field codes */ #define BARRY_CALENDAR_ALLDAYEVENT 0x010301 /* true/false number */ #define BARRY_CALENDAR_SUBJECT 0x020302 /* strings... */ #define BARRY_CALENDAR_NOTES 0x020303 #define BARRY_CALENDAR_LOCATION 0x020304 #define BARRY_CALENDAR_NOTIFICATIONTIME 0x030305 /* time_t... */ #define BARRY_CALENDAR_STARTTIME 0x030306 #define BARRY_CALENDAR_ENDTIME 0x030307 #define BARRY_CALENDAR_INTERVAL 0x010308 /* number */ #define BARRY_CALENDAR_RECURRINGENDTIME 0x030309 /* time_t */ #define BARRY_CALENDAR_PERPETUAL 0x01030a /* true/false number */ #define BARRY_CALENDAR_TIMEZONE 0x01030b /* numeric code */ /* Service Book record field codes */ #define BARRY_SERVICEBOOK_RECORDID 0x010401 /* number */ #define BARRY_SERVICEBOOK_NAME 0x020402 /* strings... */ #define BARRY_SERVICEBOOK_HIDDENNAME 0x020403 #define BARRY_SERVICEBOOK_DESCRIPTION 0x020404 #define BARRY_SERVICEBOOK_DSID 0x020405 #define BARRY_SERVICEBOOK_BESDOMAIN 0x020406 #define BARRY_SERVICEBOOK_UNIQUEID 0x020407 #define BARRY_SERVICEBOOK_CONTENTID 0x020408 #define BARRY_SERVICEBOOK_CONFIG_FORMAT 0x010409 /* number */ /* Initialization */ BXEXPORT void barry_init(int data_dump_mode); BXEXPORT const char *barry_version(int *major, int *minor); /* Error string retrieval */ BXEXPORT const char *barry_get_last_error(); /* Probe API */ BXEXPORT probe_handle_t barry_probe(void); BXEXPORT void barry_probe_close(probe_handle_t handle); BXEXPORT int barry_probe_count(probe_handle_t handle); BXEXPORT int barry_probe_find_active(probe_handle_t handle, uint32_t pin); BXEXPORT void barry_probe_result(probe_handle_t handle, int index, struct ProbeResult *result); /* Controller API */ BXEXPORT con_handle_t barry_con_open(struct ProbeResult *result); BXEXPORT void barry_con_close(con_handle_t handle); BXEXPORT int barry_con_mode(con_handle_t handle, int mode); BXEXPORT int barry_con_get_dbid(con_handle_t handle, const char *dbname); BXEXPORT int barry_con_get_db_count(con_handle_t handle); BXEXPORT int barry_con_get_db_info(con_handle_t handle, int index, unsigned int *number, unsigned int *record_count, char *name, int name_buf_size); BXEXPORT int barry_con_add_record(con_handle_t handle, unsigned int dbid, record_handle_t rec); BXEXPORT int barry_con_get_record(con_handle_t handle, unsigned int dbid, unsigned int state_table_index, record_handle_t *rec); BXEXPORT int barry_con_set_record(con_handle_t handle, unsigned int dbid, unsigned int state_table_index, record_handle_t rec); BXEXPORT int barry_con_clear_dirty(con_handle_t handle, unsigned int dbid, unsigned int state_table_index); BXEXPORT int barry_con_delete_record(con_handle_t handle, unsigned int dbid, unsigned int state_table_index); BXEXPORT int barry_con_load_database(con_handle_t handle, unsigned int dbid, process_record_callback_t callback); BXEXPORT int barry_con_save_database(con_handle_t handle, unsigned int dbid, fill_record_callback_t callback); /* State table API */ BXEXPORT state_table_handle_t barry_get_state_table(con_handle_t handle, unsigned int dbid); BXEXPORT void barry_free_state_table(state_table_handle_t handle); BXEXPORT int barry_make_new_record_id(state_table_handle_t handle); BXEXPORT int barry_get_state_count(state_handle_t handle); BXEXPORT int barry_get_state(state_table_handle_t handle, unsigned int index, uint32_t *record_id, int *dirty_flag); /* note: not every index from 0 to "state_count" is guaranteed to exist... check the return value */ BXEXPORT int barry_get_state_by_record_id(state_table_handle_t handle, unsigned int rec, unsigned int *index, int *dirty_flag); /* Record API */ BXEXPORT record_handle_t barry_create_record(int record_type); BXEXPORT void barry_free_record(record_handle_t handle); BXEXPORT uint32_t barry_rec_get_num(record_handle_t handle, int field_type); BXEXPORT int barry_rec_set_num(record_handle_t handle, int field_type, uint32_t val); BXEXPORT const char *barry_rec_get_str(record_handle_t handle, int field_type); BXEXPORT int barry_rec_set_str(record_handle_t handle, int field_type, const char *str); BXEXPORT const char *barry_rec_get_raw(record_handle_t handle, int field_type, int *raw_size); BXEXPORT int barry_rec_set_raw(record_handle_t handle, int field_type, const char *buf, int size); BXEXPORT time_t barry_rec_get_time(record_handle_t handle, int field_type); BXEXPORT int barry_rec_set_time(record_handle_t handle, int field_type, time_t t); /* Calendar record special API */ BXEXPORT int barry_calendar_set_daily(record_handle_t handle); BXEXPORT int barry_calendar_set_monthly_by_date(record_handle_t handle, int day_of_month); BXEXPORT int barry_calendar_set_monthly_by_day(record_handle_t handle, int day_of_week, int week_of_month); BXEXPORT int barry_calendar_set_yearly_by_date(record_handle_t handle, int day_of_month, int month_of_year); BXEXPORT int barry_calendar_set_yearly_by_day(record_handle_t handle, int day_of_week, int week_of_month, int month_of_year); BXEXPORT int barry_calendar_set_weekly(record_handle_t handle, int weekday_bits); BXEXPORT int barry_calendar_get_fixme_need_read_access_to_this /* Time zone API */ BXEXPORT const TimeZone* barry_get_time_zone_table(); BXEXPORT const TimeZone* barry_get_time_zone(uint16_t code); BXEXPORT uint16_t barry_get_time_zone_code(signed short hour_offset, signed short min_offset); /* returns TIME_ZONE_CODE_ERR on error*/ #ifdef __cplusplus } #endif #endif barry-0.18.5/src/usbwrap_libusb.h0000644001161500056700000000311412242254476016236 0ustar cdfreycdfrey/// /// \file usbwrap_libusb.h /// USB API wrapper for libusb version 0.1 /// /* Copyright (C) 2005-2013, Chris Frey Portions Copyright (C) 2011, RealVNC Ltd. 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __SB_USBWRAP_LIBUSB_H__ #define __SB_USBWRAP_LIBUSB_H__ #include "usbwrap.h" #include #include #if defined( WIN32 ) // On Windows systems, usb.h includes which defines min/max, // which causes trouble for other headers #undef min #undef max #endif namespace Usb { class DeviceIDImpl { public: struct usb_device* m_dev; }; struct DeviceHandle { struct usb_dev_handle* m_handle; }; struct DeviceListImpl { std::vector m_devices; }; struct EndpointDescriptorImpl { struct usb_endpoint_descriptor m_desc; }; struct InterfaceDescriptorImpl { struct usb_interface_descriptor m_desc; }; struct ConfigDescriptorImpl { struct usb_config_descriptor m_desc; }; struct DeviceDescriptorImpl { struct usb_device* m_dev; struct usb_device_descriptor m_desc; }; }; // namespace Usb #endif // __SB_USBWRAP_LIBUSB_H__ barry-0.18.5/src/backup.h0000644001161500056700000000277512242254476014474 0ustar cdfreycdfrey/// /// \file backup.h /// Special parser class to support creation of Barry Backup files /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYBACKUP_BACKUP_H__ #define __BARRYBACKUP_BACKUP_H__ #include "dll.h" #include "parser.h" #include #include // forward declarations namespace reuse { class TarFile; } namespace Barry { class BXEXPORT Backup : public Barry::Parser { public: typedef std::map StatsType; private: std::auto_ptr m_tar; std::string m_current_dbname; std::string m_tar_id_text; std::string m_record_data; StatsType m_stats; public: explicit Backup(const std::string &tarpath); ~Backup(); void Close(); void ClearStats(); const StatsType& GetStats() const { return m_stats; } // Barry::Parser overrides virtual void ParseRecord(const Barry::DBData &data, const Barry::IConverter *ic); }; } // namespace Barry #endif barry-0.18.5/src/modem.h0000644001161500056700000000207012242254476014314 0ustar cdfreycdfrey/// /// \file modem.h /// Modem API base class for the various serial/modem /// modes available on the Blackberry. /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_MODEM_H__ #define __BARRY_MODEM_H__ #include "dll.h" namespace Barry { class Data; class BXEXPORT Modem { public: virtual ~Modem() {} virtual void Open(const char *password = 0) = 0; virtual void Close() = 0; virtual void Write(const Data &data, int timeout = -1) = 0; }; } #endif barry-0.18.5/src/pin.h0000644001161500056700000000303512242254476014003 0ustar cdfreycdfrey/// /// \file pin.h /// class for device PIN notation /// /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_PIN_H__ #define __BARRY_PIN_H__ #include "dll.h" #include #include namespace Barry { class BXEXPORT Pin { uint32_t pin; public: Pin(uint32_t pin__ = 0) : pin(pin__) {} bool Valid() const { return pin != 0; } void Clear() { pin = 0; } std::string Str() const; uint32_t Value() const { return pin; } Pin& operator=(uint32_t p) { pin = p; return *this; } bool operator==(uint32_t rhs) const { return pin == rhs; } bool operator==(const Pin &rhs) const { return pin == rhs.pin; } bool operator!=(uint32_t rhs) const { return pin != rhs; } bool operator!=(const Pin &rhs) const { return pin != rhs.pin; } }; // no ostream operator, since we want to encourage users to call str()... // but istream may be useful BXEXPORT std::istream& operator>>(std::istream &is, Pin &pin); } // namespace Barry #endif barry-0.18.5/src/i18n.h0000644001161500056700000000233512242254476013776 0ustar cdfreycdfrey/// /// \file i18n.h /// Common internationalization defines, via gettext /// NOTE! This is a private header, not to be installed! /// /* Copyright (C) 2009, Nicolas VIVIEN Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_PRIVATE_I18N_H__ #define __BARRY_PRIVATE_I18N_H__ #include #include // Set the DEFAULT_TEXT_DOMAIN so that gettext.h uses dgettext() // instead of gettext(). This way we don't have to call textdomain() // and hope that nobody changes it on us later. #define DEFAULT_TEXT_DOMAIN PACKAGE #include "gettext.h" #define _(String) gettext (String) #define N_(String) String #endif barry-0.18.5/src/r_memo.h0000644001161500056700000000454512242254476014502 0ustar cdfreycdfrey/// /// \file r_memo.h /// Record parsing class for the memo database. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2007, Brian Edginton 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_MEMO_H__ #define __BARRY_RECORD_MEMO_H__ #include "dll.h" #include "record.h" #include #include #include namespace Barry { // forward declarations class IConverter; class BXEXPORT Memo { public: typedef Barry::UnknownsType UnknownsType; uint8_t RecType; uint32_t RecordId; std::string Title; std::string Body; CategoryList Categories; UnknownsType Unknowns; public: const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); public: Memo(); ~Memo(); // Parser / Builder API (see parser.h / builder.h) void Validate() const; uint8_t GetRecType() const { return RecType; } uint32_t GetUniqueId() const { return RecordId; } void SetIds(uint8_t Type, uint32_t Id) { RecType = Type; RecordId = Id; } void ParseHeader(const Data &data, size_t &offset); void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); void BuildHeader(Data &data, size_t &offset) const; void BuildFields(Data &data, size_t &offset, const IConverter *ic = 0) const; // operations (common among record classes) void Clear(); void Dump(std::ostream &os) const; std::string GetDescription() const; bool operator<(const Memo &other) const; // database name static const char * GetDBName() { return "Memos"; } static uint8_t GetDefaultRecType() { return 0; } // or 0? // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const Memo &msg) { msg.Dump(os); return os; } } // namespace Barry #endif barry-0.18.5/src/dataqueue.h0000644001161500056700000000516712242254476015203 0ustar cdfreycdfrey/// /// \file dataqueue.h /// FIFO queue of Data objects /// /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_DATAQUEUE_H__ #define __BARRY_DATAQUEUE_H__ #include "dll.h" #include #include #include namespace Barry { class Data; // // DataQueue class // /// This class provides a thread aware fifo queue for Data objects, /// providing memory management for all Data object pointers it contains. /// /// It uses similar member names as std::queue<>, for consistency. /// class BXEXPORT DataQueue { // always use the raw_push() and raw_pop() functions typedef std::list queue_type; pthread_mutex_t m_waitMutex; pthread_cond_t m_waitCond; mutable pthread_mutex_t m_accessMutex; // locked for each access of m_queue queue_type m_queue; protected: void raw_push(Data *data); Data* raw_pop(); public: DataQueue(); ~DataQueue(); // frees all data in the queue // Pushes data into the end of the queue. // The queue owns this pointer as soon as the function is // called. In the case of an exception, it will be freed. // Performs a thread broadcast once new data has been added. void push(Data *data); // Pops the next element off the front of the queue. // Returns 0 if empty. // The queue no longer owns this pointer upon return. Data* pop(); // Pops the next element off the front of the queue, and // waits until one exists if empty. If still no data // on timeout, returns null. // Timeout specified in milliseconds. Default is wait forever. Data* wait_pop(int timeout = -1); // Pops all data from other and appends it to this. // After calling this function, other will be empty, and // this will contain all its data. // In the case of an exception, any uncopied data will // remain in other. void append_from(DataQueue &other); bool empty() const; // return true if empty size_t size() const; void DumpAll(std::ostream &os) const; }; inline std::ostream& operator<< (std::ostream &os, const DataQueue &dq) { dq.DumpAll(os); return os; } } // namespace Barry #endif barry-0.18.5/src/threadwrap.h0000644001161500056700000000272612242254476015364 0ustar cdfreycdfrey/// /// \file threadwrap.h /// RAII Wrapper for a single thread. /// /* Copyright (C) 2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_THREADWRAP_H__ #define __BARRY_THREADWRAP_H__ #include "dll.h" #include namespace Barry { class BXEXPORT Thread { public: struct CallbackData { void *(*callback)(Barry::Thread::CallbackData *data); // user-accessible data volatile bool stopflag; void *userdata; explicit CallbackData(void *userdata); }; private: pthread_t thread; int m_socket; CallbackData *m_data; public: // Note: the data pointer passed into callback is not the same // as userdata. The data pointer is a pointer to CallbackData // which will contain the userdata pointer. Thread(int socket, void *(*callback)(Barry::Thread::CallbackData *data), void *userdata); ~Thread(); /// Sets stopflag in the callback data to true void StopFlag(); }; } // namespace Barry #endif barry-0.18.5/src/version.cc0000644001161500056700000000265012242254476015042 0ustar cdfreycdfrey/// /// \file version.cc /// Provide access to library version information /// /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "version.h" #include "config.h" #ifdef WORDS_BIGENDIAN #define BARRY_VERSION_STRING "Barry library version " BARRY_VER_STRING " (big endian)" #else #define BARRY_VERSION_STRING "Barry library version " BARRY_VER_STRING " (little endian)" #endif #define BARRY_VERSION_LOGICAL BARRY_LOGICAL #define BARRY_VERSION_MAJOR BARRY_MAJOR #define BARRY_VERSION_MINOR BARRY_MINOR namespace Barry { /// Fills major and minor with integer version numbers, and /// returns a string containing human readable version /// information in English. const char* Version(int &logical, int &major, int &minor) { major = BARRY_VERSION_MAJOR; minor = BARRY_VERSION_MINOR; return BARRY_VERSION_STRING; } } // namespace Barry barry-0.18.5/src/a_codsection.h0000644001161500056700000000376212242254476015656 0ustar cdfreycdfrey/// /// \file a_codsection.h /// COD structure for the ALX file parser /// /* Copyright (C) 2010, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_A_CODSECTION_H__ #define __BARRY_A_CODSECTION_H__ #include #include "dll.h" #include "a_common.h" namespace Barry { namespace ALX { class BXEXPORT CODSection { protected: std::string id; std::string name; std::string description; std::string version; std::string vendor; std::string copyright; std::string directory; bool isRequired; std::vector codfiles; public: CODSection(void); CODSection(const xmlpp::SaxParser::AttributeList& attrs); virtual ~CODSection(void); virtual void Dump(std::ostream &os) const = 0; virtual void SetID(const std::string& id); virtual void SetName(const std::string& name); virtual void SetDescription(const std::string& description); virtual void SetVersion(const std::string& version); virtual void SetVendor(const std::string& vendor); virtual void SetCopyright(const std::string& copyright); virtual void SetDirectory(const std::string& directory); virtual void SetRequired(const std::string& required); virtual void AddFiles(const std::string& files); virtual void AddFile(const std::string& files); }; inline std::ostream& operator<<(std::ostream& os, const CODSection& cod) { cod.Dump(os); return os; } } // namespace ALX } // namespace Barry #endif barry-0.18.5/src/usbwrap_libusb_1_0.cc0000644001161500056700000006733212242254476017047 0ustar cdfreycdfrey/// /// \file usbwrap_libusb_1_0.cc /// USB API wrapper for libusb version 1.0 /// /* Copyright (C) 2005-2013, Chris Frey Portions Copyright (C) 2011, RealVNC Ltd. 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "usbwrap_libusb_1_0.h" #include "debug.h" #include "data.h" #include #include #include #include #include #ifndef __DEBUG_MODE__ #define __DEBUG_MODE__ #endif #include "debug.h" namespace Usb { // helper functions to make deleting pointers in maps and vectors easier template static void deletePtr(T* ptr) { delete ptr; } template static void deleteMapPtr(std::pair ptr) { delete ptr.second; } // lookup table translating LIBUSB errors to standard Linux errors static const struct { int libusb; int system; } errorCodes[] = { { LIBUSB_SUCCESS, 0 }, { LIBUSB_ERROR_IO, -EIO }, { LIBUSB_ERROR_INVALID_PARAM, -EINVAL }, { LIBUSB_ERROR_ACCESS, -EACCES }, { LIBUSB_ERROR_NO_DEVICE, -ENODEV }, { LIBUSB_ERROR_NOT_FOUND, -ENOENT }, { LIBUSB_ERROR_BUSY, -EBUSY }, { LIBUSB_ERROR_TIMEOUT, -ETIMEDOUT }, { LIBUSB_ERROR_OVERFLOW, -EOVERFLOW }, { LIBUSB_ERROR_PIPE, -EPIPE }, { LIBUSB_ERROR_INTERRUPTED, -EINTR }, { LIBUSB_ERROR_NO_MEM, -ENOMEM }, { LIBUSB_ERROR_NOT_SUPPORTED, -ENOSYS }, // There isn't an errno.h value for generic errors, so // return success, which, for TranslateErrcode(), means error. { LIBUSB_ERROR_OTHER, 0 } }; static const int errorCodeCnt = sizeof(errorCodes) / sizeof(errorCodes[0]); /////////////////////////////////////////////////////////////////////////////// // Global libusb library context static libusb_context* libusbctx; /////////////////////////////////////////////////////////////////////////////// // Static functions std::string LibraryInterface::GetLastErrorString(int libusb_errcode) { switch( libusb_errcode ) { case LIBUSB_SUCCESS: return _("Success"); case LIBUSB_ERROR_IO: return _("IO Error"); case LIBUSB_ERROR_INVALID_PARAM: return _("Invalid parameter"); case LIBUSB_ERROR_ACCESS: return _("Access"); case LIBUSB_ERROR_NO_DEVICE: return _("No device"); case LIBUSB_ERROR_NOT_FOUND: return _("Not found"); case LIBUSB_ERROR_BUSY: return _("Busy"); case LIBUSB_ERROR_TIMEOUT: return _("Timeout"); case LIBUSB_ERROR_OVERFLOW: return _("Overflow"); case LIBUSB_ERROR_PIPE: return _("Pipe"); case LIBUSB_ERROR_INTERRUPTED: return _("Interrupted"); case LIBUSB_ERROR_NO_MEM: return _("No memory"); case LIBUSB_ERROR_NOT_SUPPORTED: return _("Not supported"); case LIBUSB_ERROR_OTHER: return _("Other"); default: return _("Unknown LIBUSB error code"); } } // Helper function to translate libusb error codes into more useful values // // Note that this function assumes that libusb_errcode contains an error. // It is helpful enough to return 0 if libusb_errcode contains 0, but // if it is a positive success value (such as for a read or write) // it will still return 0, since it won't find a corresponding errno code. // // Since this function assumes that libusb_errcode is already an error, // it also assumes the caller already *knows* that it is an error, and // therefore a return of success is an "error" for this function. :-) // int LibraryInterface::TranslateErrcode(int libusb_errcode) { for( int i = 0; i < errorCodeCnt; ++i ) { if( errorCodes[i].libusb == libusb_errcode ) return errorCodes[i].system; } // default to 0 if unknown eout("Failed to translate libusb errorcode: " << libusb_errcode); return 0; } bool LibraryInterface::Init(int *libusb_errno) { // if the environment variable LIBUSB_DEBUG is set, that // level value will be used instead of our 3 above... // if you need to *force* this to 3, call SetDataDump(true) // after Init() if( !libusbctx ) { int ret = libusb_init(&libusbctx); // store errno for user if possible if( libusb_errno ) *libusb_errno = ret; // true on success return ret >= 0; } return true; } void LibraryInterface::Uninit() { libusb_exit(libusbctx); libusbctx = NULL; } void LibraryInterface::SetDataDump(bool data_dump_mode) { if( !libusbctx ) { Init(); } if( !libusbctx ) { // Failed to init, can't do much but return dout("SetDataDump: Failed to initialise libusb"); return; } if( data_dump_mode ) libusb_set_debug(libusbctx, 3); else libusb_set_debug(libusbctx, 0); } /////////////////////////////////////////////////////////////////////////////// // DeviceIDImpl DeviceIDImpl::DeviceIDImpl(libusb_device *dev) : m_dev(dev) { libusb_ref_device(m_dev); // Libusb 1.0 doesn't provide busnames or filenames // so it's necessary to make some up. std::ostringstream formatter; formatter << "libusb1-" << static_cast(libusb_get_bus_number(m_dev)); m_busname = formatter.str(); formatter << "-" << static_cast(libusb_get_device_address(m_dev)); m_filename = formatter.str(); } DeviceIDImpl::~DeviceIDImpl() { libusb_unref_device(m_dev); } /////////////////////////////////////////////////////////////////////////////// // DeviceID DeviceID::DeviceID(DeviceIDImpl* impl) : m_impl(impl) { } DeviceID::~DeviceID() { } const char* DeviceID::GetBusName() const { return m_impl->m_busname.c_str(); } uint16_t DeviceID::GetNumber() const { return libusb_get_device_address(m_impl->m_dev); } const char* DeviceID::GetFilename() const { return m_impl->m_filename.c_str(); } uint16_t DeviceID::GetIdProduct() const { int ret = PRODUCT_UNKNOWN; struct libusb_device_descriptor desc; int err = libusb_get_device_descriptor(m_impl->m_dev, &desc); if( err == 0 ) ret = desc.idProduct; return ret; } std::string DeviceID::GetUsbName() const { // for libusb 1.0, we can use bus name and number... // and we stay away from the product ID, since that requires // communication with the device, which may not be possible // in error conditions. std::ostringstream oss; oss << GetBusName() << ":" << GetNumber(); return oss.str(); } /////////////////////////////////////////////////////////////////////////////// // DeviceList DeviceList::DeviceList() : m_impl(new DeviceListImpl()) { m_impl->m_list = NULL; m_impl->m_listcnt = 0; m_impl->m_listcnt = libusb_get_device_list(libusbctx, &m_impl->m_list); if( m_impl->m_listcnt < 0 ) { throw Error(m_impl->m_listcnt, _("Failed to get device list")); } for( int i = 0; i < m_impl->m_listcnt; ++i ) { // Add the device to the list of devices DeviceID devID(new DeviceIDImpl(m_impl->m_list[i])); m_impl->m_devices.push_back(devID); } } DeviceList::~DeviceList() { if( m_impl->m_list ) { libusb_free_device_list(m_impl->m_list, 1); } } std::vector DeviceList::MatchDevices(int vendor, int product, const char *busname, const char *devname) { std::vector ret; int err; std::vector::iterator iter = m_impl->m_devices.begin(); for( ; iter != m_impl->m_devices.end() ; ++iter ) { struct libusb_device* dev = iter->m_impl->m_dev; // only search on given bus if( busname && atoi(busname) != libusb_get_bus_number(dev) ) continue; // search for specific device if( devname && atoi(devname) != libusb_get_device_address(dev) ) continue; struct libusb_device_descriptor desc; err = libusb_get_device_descriptor(dev, &desc); if( err ) { dout("Failed to get device descriptor: " << err); continue; } // is there a match? if( desc.idVendor == vendor && ( desc.idProduct == product || product == PRODUCT_ANY )) { ret.push_back(*iter); } } return ret; } /////////////////////////////////////////////////////////////////////////////// // Device Device::Device(const Usb::DeviceID& id, int timeout) : m_id(id), m_handle(new DeviceHandle()), m_timeout(timeout) { dout("libusb_open(" << std::dec << id.m_impl.get() << ")"); if( !&(*id.m_impl) ) throw Error(_("invalid USB device ID")); int err = libusb_open(id.m_impl->m_dev, &(m_handle->m_handle)); m_lasterror = err; if( err ) throw Error(err, _("Failed to open USB device. Please check your system's USB device permissions.")); } Device::~Device() { dout("libusb_close(" << std::dec << m_handle->m_handle << ")"); libusb_close(m_handle->m_handle); } bool Device::SetConfiguration(unsigned char cfg) { dout("libusb_set_configuration(" << std::dec << m_handle->m_handle << ", 0x" << std::hex << (unsigned int) cfg << ")"); int ret = libusb_set_configuration(m_handle->m_handle, cfg); m_lasterror = ret; return ret >= 0; } bool Device::ClearHalt(int ep) { dout("libusb_clear_halt(" << std::dec << m_handle->m_handle << ", 0x" << std::hex << ep << ")"); int ret = libusb_clear_halt(m_handle->m_handle, ep); m_lasterror = ret; return ret >= 0; } bool Device::Reset() { dout("libusb_reset_device(" << std::dec << m_handle->m_handle << ")"); int ret = libusb_reset_device(m_handle->m_handle); m_lasterror = ret; return ret == 0; } bool Device::BulkRead(int ep, Barry::Data &data, int timeout) { ddout("BulkRead to endpoint 0x" << std::hex << ep << ":\n" << data); int ret; do { int transferred = 0; data.QuickZap(); ret = libusb_bulk_transfer(m_handle->m_handle, ep |= LIBUSB_ENDPOINT_IN, data.GetBuffer(), data.GetBufSize(), &transferred, timeout == -1 ? m_timeout : timeout); if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) { m_lasterror = ret; // only notify of a timeout if no data was transferred, // otherwise treat it as success. if( ret == LIBUSB_ERROR_TIMEOUT ) { if( transferred == 0 ) throw Timeout(ret, _("Timeout in BulkRead")); else dout("Read timed out with some data transferred... possible partial read"); } else if( ret != LIBUSB_ERROR_TIMEOUT ) { std::ostringstream oss; oss << _("Error in libusb_bulk_tranfer(") << m_handle->m_handle << ", " << ep << ", buf, " << data.GetBufSize() << ", " << transferred << ", " << (timeout == -1 ? m_timeout : timeout) << ")"; throw Error(ret, oss.str()); } } if( transferred != 0 ) data.ReleaseBuffer(transferred); } while( ret == LIBUSB_ERROR_INTERRUPTED ); return ret >= 0; } bool Device::BulkWrite(int ep, const Barry::Data &data, int timeout) { ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << data); int ret; do { int transferred; ret = libusb_bulk_transfer(m_handle->m_handle, ep | LIBUSB_ENDPOINT_OUT, const_cast(data.GetData()), data.GetSize(), &transferred, timeout == -1 ? m_timeout : timeout); if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) { m_lasterror = ret; // only notify of a timeout if no data was transferred, // otherwise treat it as success. if( ret == LIBUSB_ERROR_TIMEOUT && transferred == 0 ) throw Timeout(ret, _("Timeout in BulkWrite")); else if( ret != LIBUSB_ERROR_TIMEOUT ) throw Error(ret, _("Error in BulkWrite")); } if( ret >= 0 && (unsigned int)transferred != data.GetSize() ) { dout("Failed to write all data on ep: " << ep << " attempted to write: " << data.GetSize() << " but only wrote: " << transferred); throw Error(_("Failed to perform a complete write")); } } while( ret == LIBUSB_ERROR_INTERRUPTED ); return ret >= 0; } bool Device::BulkWrite(int ep, const void *data, size_t size, int timeout) { #ifdef __DEBUG_MODE__ Barry::Data dump(data, size); ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << dump); #endif int ret; do { int transferred; ret = libusb_bulk_transfer(m_handle->m_handle, ep | LIBUSB_ENDPOINT_OUT, (unsigned char*)const_cast(data), size, &transferred, timeout == -1 ? m_timeout : timeout); if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) { m_lasterror = ret; // only notify of a timeout if no data was transferred, // otherwise treat it as success. if( ret == LIBUSB_ERROR_TIMEOUT && transferred == 0 ) throw Timeout(ret, _("Timeout in BulkWrite (2)")); else if( ret != LIBUSB_ERROR_TIMEOUT ) throw Error(ret, _("Error in BulkWrite (2)")); } if( ret >= 0 && (unsigned int)transferred != size ) { dout("Failed to write all data on ep: " << ep << " attempted to write: " << size << " but only wrote: " << transferred); throw Error(_("Failed to perform a complete write")); } } while( ret == LIBUSB_ERROR_INTERRUPTED ); return ret >= 0; } bool Device::InterruptRead(int ep, Barry::Data &data, int timeout) { ddout("InterruptRead to endpoint 0x" << std::hex << ep << ":\n" << data); int ret; do { int transferred = 0; data.QuickZap(); ret = libusb_interrupt_transfer(m_handle->m_handle, ep | LIBUSB_ENDPOINT_IN, data.GetBuffer(), data.GetBufSize(), &transferred, timeout == -1 ? m_timeout : timeout); if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) { m_lasterror = ret; // only notify of a timeout if no data was transferred, // otherwise treat it as success. if( ret == LIBUSB_ERROR_TIMEOUT ) { if( transferred == 0 ) throw Timeout(ret, _("Timeout in InterruptRead")); else dout("Read timed out with some data transferred... possible partial read"); } else if( ret != LIBUSB_ERROR_TIMEOUT ) throw Error(ret, _("Error in InterruptRead")); } if( transferred != 0 ) data.ReleaseBuffer(transferred); } while( ret == LIBUSB_ERROR_INTERRUPTED ); return ret >= 0; } bool Device::InterruptWrite(int ep, const Barry::Data &data, int timeout) { ddout("InterruptWrite to endpoint 0x" << std::hex << ep << ":\n" << data); int ret; do { int transferred; ret = libusb_interrupt_transfer(m_handle->m_handle, ep | LIBUSB_ENDPOINT_OUT, const_cast(data.GetData()), data.GetSize(), &transferred, timeout == -1 ? m_timeout : timeout); if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) { m_lasterror = ret; // only notify of a timeout if no data was transferred, // otherwise treat it as success. if( ret == LIBUSB_ERROR_TIMEOUT && transferred == 0 ) throw Timeout(ret, _("Timeout in InterruptWrite")); else if( ret != LIBUSB_ERROR_TIMEOUT ) throw Error(ret, _("Error in InterruptWrite")); } if( ret >= 0 && (unsigned int)transferred != data.GetSize() ) { dout("Failed to write all data on ep: " << ep << " attempted to write: " << data.GetSize() << " but only wrote: " << transferred); throw Error(_("Failed to perform a complete write")); } } while( ret == LIBUSB_ERROR_INTERRUPTED ); return ret >= 0; } // // BulkDrain // /// Reads anything available on the given endpoint, with a low timeout, /// in order to clear any pending reads. /// void Device::BulkDrain(int ep, int timeout) { try { Barry::Data data; while( BulkRead(ep, data, timeout) ) ; } catch( Usb::Error & ) {} } // // GetConfiguration // /// Determines the currently selected USB configuration, returning it /// in the cfg argument. /// If unsuccessful, returns false. /// bool Device::GetConfiguration(unsigned char &cfg) { int config = 0; int result = libusb_get_configuration(m_handle->m_handle, &config); if( result >= 0 ) cfg = config; m_lasterror = result; return result >= 0; } // Returns the current power level of the device, or 0 if unknown int Device::GetPowerLevel() { struct libusb_config_descriptor* cfg = NULL; int ret = 0; int result = libusb_get_active_config_descriptor(m_id.m_impl->m_dev, &cfg); m_lasterror = result; if( result == 0 ) { ret = cfg->MaxPower; } if( cfg ) libusb_free_config_descriptor(cfg); return ret; } std::string Device::GetSimpleSerialNumber() { std::string sn; struct libusb_device_descriptor desc; int ret = libusb_get_device_descriptor(m_id.m_impl->m_dev, &desc); m_lasterror = ret; if( ret == 0 ) { char buf[1024]; ret = libusb_get_string_descriptor_ascii(m_handle->m_handle, desc.iSerialNumber, (unsigned char*)buf, sizeof(buf)); if( ret > 0 ) sn.assign(buf, ret); else m_lasterror = ret; } return sn; } bool Device::IsAttachKernelDriver(int iface) { int ret; ret = libusb_kernel_driver_active(m_handle->m_handle, iface); if (ret == 0) { dout("interface (" << m_handle->m_handle << ", 0x" << std::hex << iface << ") already claimed by a driver of unknown name."); return true; } return false; } // Requests that the kernel driver is detached, returning false on failure bool Device::DetachKernelDriver(int iface) { int result = libusb_detach_kernel_driver(m_handle->m_handle, iface); m_lasterror = result; return result >= 0; } // Sends a control message to the device, returning false on failure bool Device::ControlMsg(int requesttype, int request, int value, int index, char *bytes, int size, int timeout) { int result = libusb_control_transfer(m_handle->m_handle, requesttype, request, value, index, (unsigned char*)bytes, size, timeout); m_lasterror = result; return result >= 0; } int Device::FindInterface(int ifaceClass) { struct libusb_config_descriptor* cfg = NULL; int ret = libusb_get_active_config_descriptor(m_id.m_impl->m_dev, &cfg); if( ret == 0 ) { for( int i = 0; cfg->interface && i < cfg->bNumInterfaces; ++i ) { const struct libusb_interface& iface = cfg->interface[i]; for( int j = 0; iface.altsetting && j < iface.num_altsetting; ++j ) { const struct libusb_interface_descriptor& id = iface.altsetting[j]; if( id.bInterfaceClass == ifaceClass ) return id.bInterfaceNumber; } } } if( cfg ) libusb_free_config_descriptor(cfg); return ret; } /////////////////////////////////////////////////////////////////////////////// // Interface Interface::Interface(Device &dev, int iface) : m_dev(dev), m_iface(iface) { dout("libusb_claim_interface(" << dev.GetHandle()->m_handle << ", 0x" << std::hex << iface << ")"); int ret = libusb_claim_interface(dev.GetHandle()->m_handle, iface); if( ret < 0 ) throw Error(ret, _("claim interface failed")); } Interface::~Interface() { dout("libusb_release_interface(" << m_dev.GetHandle()->m_handle << ", 0x" << std::hex << m_iface << ")"); libusb_release_interface(m_dev.GetHandle()->m_handle, m_iface); } // // SetAltInterface // /// Sets the currently selected USB alternate setting of the current interface. /// The iface parameter passed in should be a value specified /// in the bAlternateSetting descriptor field. /// If unsuccessful, returns false. /// bool Interface::SetAltInterface(int altSetting) { int result = libusb_set_interface_alt_setting( m_dev.GetHandle()->m_handle, m_iface, altSetting); m_dev.SetLastError(result); return result >= 0; } ////////////////////////////////////////////////////////////////// // DeviceDescriptor DeviceDescriptor::DeviceDescriptor(DeviceID& devid) : m_impl(new DeviceDescriptorImpl()) { if( !devid.m_impl.get() ) { dout("DeviceDescriptor: empty devid"); return; } m_impl->m_devid = devid; int ret = libusb_get_device_descriptor(devid.m_impl->m_dev, &m_impl->m_desc); if( ret != 0 ) { dout("Failed to read device descriptor with err: " << ret); return; } dout("device_desc loaded" << "\nbLength: " << std::dec << (unsigned int) m_impl->m_desc.bLength << "\nbDescriptorType: " << std::dec << (unsigned int) m_impl->m_desc.bDescriptorType << "\nbcdUSB: 0x" << std::hex << (unsigned int) m_impl->m_desc.bcdUSB << "\nbDeviceClass: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceClass << "\nbDeviceSubClass: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceSubClass << "\nbDeviceProtocol: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceProtocol << "\nbMaxPacketSize0: " << std::dec << (unsigned int) m_impl->m_desc.bMaxPacketSize0 << "\nidVendor: 0x" << std::hex << (unsigned int) m_impl->m_desc.idVendor << "\nidProduct: 0x" << std::hex << (unsigned int) m_impl->m_desc.idProduct << "\nbcdDevice: 0x" << std::hex << (unsigned int) m_impl->m_desc.bcdDevice << "\niManufacturer: " << std::dec << (unsigned int) m_impl->m_desc.iManufacturer << "\niProduct: " << std::dec << (unsigned int) m_impl->m_desc.iProduct << "\niSerialNumber: " << std::dec << (unsigned int) m_impl->m_desc.iSerialNumber << "\nbNumConfigurations: " << std::dec << (unsigned int) m_impl->m_desc.bNumConfigurations << "\n" ); // Create all the configs for( int i = 0; i < m_impl->m_desc.bNumConfigurations; ++i ) { std::auto_ptr ptr(new ConfigDescriptor(*this, i)); (*this)[ptr->GetNumber()] = ptr.get(); ptr.release(); } } DeviceDescriptor::~DeviceDescriptor() { // Delete any pointers in the vector std::for_each(begin(), end(), deleteMapPtr); } /////////////////////////////////////////////////////////////////// // ConfigDescriptor ConfigDescriptor::ConfigDescriptor(DeviceDescriptor& dev, int cfgnumber) : m_impl(new ConfigDescriptorImpl()) { m_impl->m_desc = NULL; int ret = libusb_get_config_descriptor(dev.m_impl->m_devid.m_impl->m_dev, cfgnumber, &(m_impl->m_desc)); if( ret != 0 ) { dout("Failed to read config descriptor with err: " << ret); return; } dout(" config_desc #" << std::dec << cfgnumber << " loaded" << "\nbLength: " << std::dec << (unsigned int) m_impl->m_desc->bLength << "\nbDescriptorType: " << std::dec << (unsigned int) m_impl->m_desc->bDescriptorType << "\nwTotalLength: " << std::dec << (unsigned int) m_impl->m_desc->wTotalLength << "\nbNumInterfaces: " << std::dec << (unsigned int) m_impl->m_desc->bNumInterfaces << "\nbConfigurationValue: " << std::dec << (unsigned int) m_impl->m_desc->bConfigurationValue << "\niConfiguration: " << std::dec << (unsigned int) m_impl->m_desc->iConfiguration << "\nbmAttributes: 0x" << std::hex << (unsigned int) m_impl->m_desc->bmAttributes << "\nMaxPower: " << std::dec << (unsigned int) m_impl->m_desc->MaxPower << "\n" ); // just for debugging purposes, check for extra descriptors, and // dump them to dout if they exist if( m_impl->m_desc->extra ) { dout("while parsing config descriptor, found a block of extra descriptors:"); Barry::Data data(m_impl->m_desc->extra, m_impl->m_desc->extra_length); dout(data); } // Create all the interfaces for( int i = 0; i < m_impl->m_desc->bNumInterfaces; ++i ) { const struct libusb_interface* interface = &(m_impl->m_desc->interface[i]); if( !interface->altsetting ) { dout("ConfigDescriptor: empty altsetting"); // some devices are buggy and return a higher bNumInterfaces // than the number of interfaces available... in this case // we just skip and continue continue; } for( int j = 0; j < interface->num_altsetting; ++j ) { std::auto_ptr ptr( new InterfaceDescriptor(*this, i, j)); (*this)[ptr->GetNumber()] = ptr.get(); ptr.release(); } } } ConfigDescriptor::~ConfigDescriptor() { // Delete any pointers in the vector std::for_each(begin(), end(), deleteMapPtr); if( m_impl->m_desc ) { libusb_free_config_descriptor(m_impl->m_desc); m_impl->m_desc = NULL; } } uint8_t ConfigDescriptor::GetNumber() const { if( !m_impl->m_desc ) // Return an invalid config number return 0; return m_impl->m_desc->bConfigurationValue; } ///////////////////////////////////////////////////////////////////////// // InterfaceDescriptor InterfaceDescriptor::InterfaceDescriptor(ConfigDescriptor& cfgdesc, int iface, int altsetting) : m_impl(new InterfaceDescriptorImpl()) { m_impl->m_desc = NULL; // Find the descriptor m_impl->m_desc = &(cfgdesc.m_impl->m_desc ->interface[iface] .altsetting[altsetting]); dout(" interface_desc #" << std::dec << iface << " loaded" << "\nbLength: " << std::dec << (unsigned) m_impl->m_desc->bLength << "\nbDescriptorType: " << std::dec << (unsigned) m_impl->m_desc->bDescriptorType << "\nbInterfaceNumber: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceNumber << "\nbAlternateSetting: " << std::dec << (unsigned) m_impl->m_desc->bAlternateSetting << "\nbNumEndpoints: " << std::dec << (unsigned) m_impl->m_desc->bNumEndpoints << "\nbInterfaceClass: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceClass << "\nbInterfaceSubClass: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceSubClass << "\nbInterfaceProtocol: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceProtocol << "\niInterface: " << std::dec << (unsigned) m_impl->m_desc->iInterface << "\n" ); if( !m_impl->m_desc->endpoint ) { dout("InterfaceDescriptor: empty interface pointer"); return; } // Create all the endpoints for( int i = 0; i < m_impl->m_desc->bNumEndpoints; ++i ) { std::auto_ptr ptr ( new EndpointDescriptor(*this, i)); push_back(ptr.get()); ptr.release(); } // just for debugging purposes, check for extra descriptors, and // dump them to dout if they exist if( m_impl->m_desc->extra ) { dout("while parsing interface descriptor, found a block of extra descriptors:"); Barry::Data data(m_impl->m_desc->extra, m_impl->m_desc->extra_length); dout(data); } } InterfaceDescriptor::~InterfaceDescriptor() { // Delete any pointers in the vector std::for_each(begin(), end(), deletePtr); } uint8_t InterfaceDescriptor::GetClass() const { return m_impl->m_desc->bInterfaceClass; } uint8_t InterfaceDescriptor::GetNumber() const { if( !m_impl->m_desc ) // Return an invalid interface number return 0; return m_impl->m_desc->bInterfaceNumber; } uint8_t InterfaceDescriptor::GetAltSetting() const { if( !m_impl->m_desc ) // Return an invalid setting number return 0; return m_impl->m_desc->bAlternateSetting; } ///////////////////////////////////////////////////////////////////////////////// // EndpointDescriptor EndpointDescriptor::EndpointDescriptor(InterfaceDescriptor& intdesc, int endpoint) : m_impl(new EndpointDescriptorImpl()), m_read(false), m_addr(0), m_type(InvalidType) { // Copy the descriptor m_impl->m_desc = &(intdesc.m_impl->m_desc->endpoint[endpoint]); dout(" endpoint_desc #" << std::dec << endpoint << " loaded" << "\nbLength: " << std::dec << (unsigned ) m_impl->m_desc->bLength << "\nbDescriptorType: " << std::dec << (unsigned ) m_impl->m_desc->bDescriptorType << "\nbEndpointAddress: 0x" << std::hex << (unsigned ) m_impl->m_desc->bEndpointAddress << "\nbmAttributes: 0x" << std::hex << (unsigned ) m_impl->m_desc->bmAttributes << "\nwMaxPacketSize: " << std::dec << (unsigned ) m_impl->m_desc->wMaxPacketSize << "\nbInterval: " << std::dec << (unsigned ) m_impl->m_desc->bInterval << "\nbRefresh: " << std::dec << (unsigned ) m_impl->m_desc->bRefresh << "\nbSynchAddress: " << std::dec << (unsigned ) m_impl->m_desc->bSynchAddress << "\n" ); // Set up variables m_read = ((m_impl->m_desc->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN); m_addr = (m_impl->m_desc->bEndpointAddress & LIBUSB_ENDPOINT_ADDRESS_MASK); int type = (m_impl->m_desc->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK); m_type = static_cast(type); // just for debugging purposes, check for extra descriptors, and // dump them to dout if they exist if( m_impl->m_desc->extra ) { dout("while parsing endpoint descriptor, found a block of extra descriptors:"); Barry::Data data(m_impl->m_desc->extra, m_impl->m_desc->extra_length); dout(data); } } EndpointDescriptor::~EndpointDescriptor() { } } // namespace Usb barry-0.18.5/src/m_jvmdebug.h0000644001161500056700000000735512242254476015345 0ustar cdfreycdfrey/// /// \file m_jvmdebug.h /// Mode class for the JVMDebug mode /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2008-2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_M_JVMDEBUG_H__ #define __BARRY_M_JVMDEBUG_H__ #include "dll.h" #include "m_mode_base.h" #include "socket.h" #include "record.h" #include "data.h" namespace Barry { // forward declarations class Parser; class Builder; class Controller; class JVMModulesEntry; class JVMThreadsEntry; class BXEXPORT JVMModulesList : public std::vector { public: typedef std::vector base_type; typedef base_type::iterator iterator; typedef base_type::const_iterator const_iterator; public: void Parse(const Data &entry_packet); void Dump(std::ostream &os) const; }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const JVMModulesList &list) { list.Dump(os); return os; } class BXEXPORT JVMModulesEntry { public: uint32_t Id; uint32_t UniqueID; std::string Name; public: void Dump(std::ostream &os) const; }; class BXEXPORT JVMThreadsList : public std::vector { public: typedef std::vector base_type; typedef base_type::iterator iterator; typedef base_type::const_iterator const_iterator; public: void Parse(const Data &entry_packet); void Dump(std::ostream &os) const; }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const JVMThreadsList &list) { list.Dump(os); return os; } class BXEXPORT JVMThreadsEntry { public: uint32_t Id; uint8_t Byte; uint32_t Address; uint32_t Unknown01; // FIXME - perhaps should not expose // these to the app level, until we // have a name for them, since they // might change without notice uint32_t Unknown02; uint32_t Unknown03; uint32_t Unknown04; uint32_t Unknown05; uint32_t Unknown06; public: void Dump(std::ostream &os, int num) const; }; namespace Mode { // // JVMDebug class // /// The main interface class to the java program debugger protocol /// /// To use this class, use the following steps: /// /// - Create a Controller object (see Controller class for more details) /// - Create this Mode::JVMDebug object, passing in the Controller /// object during construction /// - Call Open() to open database socket and finish constructing. /// class BXEXPORT JVMDebug : public Mode { private: bool m_Attached; protected: void ThrowJVMError(const std::string &msg, uint8_t cmd); ////////////////////////////////// // overrides virtual void OnOpen(); public: JVMDebug(Controller &con); ~JVMDebug(); ////////////////////////////////// // API void Close(); void Attach(); void Detach(); // mid-attachment operations void Unknown01(); // FIXME - make these into a proper API, or // hide under protected: void Unknown02(); void Unknown03(); void Unknown04(); void Unknown05(); void Unknown06(); void Unknown07(); void Unknown08(); void Unknown09(); void Unknown10(); void GetModulesList(JVMModulesList &mylist); void GetThreadsList(JVMThreadsList &mylist); int GetConsoleMessage(std::string &msg); bool GetStatus(int &status); bool WaitStatus(int &status); void Go(); void Stop(); }; }} // namespace Barry::Mode #endif barry-0.18.5/src/r_cstore.h0000644001161500056700000000563612242254476015046 0ustar cdfreycdfrey/// /// \file r_cstore.h /// Blackberry database record parser class for /// Content Store records. /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_CSTORE_H__ #define __BARRY_RECORD_CSTORE_H__ #include "dll.h" #include "record.h" #include #include #include #include #include namespace Barry { // forward declarations class IConverter; // // NOTE: All classes here must be container-safe! Perhaps add sorting // operators in the future. // /// \addtogroup RecordParserClasses /// @{ // // Content Store record class // /// Represents a single record in the Content Store Blackberry database. /// class BXEXPORT ContentStore { public: typedef Barry::UnknownsType UnknownsType; // // Record fields // // contact specific data uint8_t RecType; uint32_t RecordId; std::string Filename; bool FolderFlag; std::string FileContent; std::string FileDescriptor; UnknownsType Unknowns; private: uint64_t FileSize; public: const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); public: ContentStore(); ~ContentStore(); // operations (common among record classes) void Clear(); // erase everything void Dump(std::ostream &os) const; std::string GetDescription() const; // Sorting - use enough data to make the sorting as // consistent as possible bool operator<(const ContentStore &other) const; // Parser / Builder API (see parser.h / builder.h) void Validate() const; uint8_t GetRecType() const { return RecType; } uint32_t GetUniqueId() const { return RecordId; } void SetIds(uint8_t Type, uint32_t Id) { RecType = Type; RecordId = Id; } void ParseHeader(const Data &data, size_t &offset); void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); void BuildHeader(Data &data, size_t &offset) const; void BuildFields(Data &data, size_t &offset, const IConverter *ic = 0) const; static const char * GetDBName() { return "Content Store"; } static uint8_t GetDefaultRecType() { return 0; } // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<< (std::ostream &os, const ContentStore &cstore) { cstore.Dump(os); return os; } /// @} } // namespace Barry #endif barry-0.18.5/src/controllerpriv.h0000644001161500056700000000424412242254476016304 0ustar cdfreycdfrey/// /// \file controllerpriv.h /// Private data for the Controller class /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_CONTROLLERPRIVATE_H__ #define __BARRY_CONTROLLERPRIVATE_H__ #include "probe.h" #include "pin.h" #include "socket.h" #include "router.h" #include "m_ipmodem.h" namespace Barry { class Controller; class PrivateControllerData { friend class Controller; // DO NOT add your Mode class to this list unless it *needs* // low level access to things like Usb::Device. By adding // your Mode class to this list, you are making it non-portable. friend class Barry::Mode::IpModem; private: ProbeResult m_result; Usb::Device m_dev; Usb::Interface *m_iface; Pin m_pin; SocketZero m_zero; SocketRoutingQueue *m_queue; //< ptr to external object; no delete private: PrivateControllerData(const ProbeResult &device, int default_timeout) : m_result(device) , m_dev(device.m_dev, default_timeout) , m_iface(0) , m_pin(device.m_pin) , m_zero(m_dev, device.m_ep.write, device.m_ep.read, device.m_zeroSocketSequence) , m_queue(0) { } PrivateControllerData(const ProbeResult &device, SocketRoutingQueue &queue, int default_timeout) : m_result(device) , m_dev(device.m_dev, default_timeout) , m_iface(0) , m_pin(device.m_pin) , m_zero(queue, device.m_ep.write, device.m_zeroSocketSequence) , m_queue(&queue) { } public: ~PrivateControllerData() { // detach the router from our device if( m_queue ) { m_queue->ClearUsbDevice(); m_queue = 0; } // cleanup the interface delete m_iface; } }; } // namespace Barry #endif barry-0.18.5/src/probe.h0000644001161500056700000001142112242254476014322 0ustar cdfreycdfrey/// /// \file probe.h /// USB Blackberry detection routines /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_PROBE_H__ #define __BARRY_PROBE_H__ #include "dll.h" #include "usbwrap.h" #include "pin.h" #include #include #include namespace Barry { class Probe; struct BXEXPORT ProbeResult { friend class Probe; Usb::DeviceID m_dev; unsigned char m_interface; unsigned char m_altsetting; Barry::Pin m_pin; Usb::EndpointPair m_ep; Usb::EndpointPair m_epModem; // Specifies if it's necessary to clear halt on the // endpoints before using them. On some devices such // as the 8830 it's essential to clear halt. On other // devices such as the Curve 8520 calling clear halt // can cause them to get into a state where they drop // packets. bool m_needClearHalt; // Specifies if it's necessary to call usb_set_altinterface() // before attempting to use the end points for this device. // // This can help to re-synchronize the state between the USB // host and the device. However it can also cause usb-storage // URBs to be lost on some device, so it's only used as a // last resort. bool m_needSetAltInterface; uint8_t m_zeroSocketSequence; std::string m_description; // data from a possible ConfigFile (filled in automatically by // the probe code if available) std::string m_cfgDeviceName; private: // All ProbeResult objects should come from Probe, therefore // this constructor is private to force the issue. ProbeResult() : m_dev(0), m_interface(0), m_pin(0) , m_needClearHalt(false), m_needSetAltInterface(false) , m_zeroSocketSequence(0) {} public: void DumpAll(std::ostream &os) const; bool HasIpModem() const { return m_epModem.IsComplete(); } std::string GetDisplayName() const; bool operator==(const Barry::Pin &pin) const { return m_pin == pin; } }; BXEXPORT std::ostream& operator<< (std::ostream &os, const ProbeResult &pr); class BXEXPORT Probe { public: typedef std::vector Results; enum LogExceptionBits { LOG_BUSY = 0x0001, LOG_ACCESS = 0x0002, LOG_PERM = 0x0004 }; private: Usb::DeviceList m_devices; Results m_results; unsigned int m_log_exceptions; std::vector m_fail_msgs; int m_fail_count; bool m_epp_override; Usb::EndpointPair m_epp; BXLOCAL bool CheckSize(const Data &data, unsigned int required); BXLOCAL bool ParsePIN(const Data &data, uint32_t &pin); BXLOCAL bool ParseDesc(const Data &data, std::string &desc); protected: void ProbeMatching(int vendor, int product, const char *busname, const char *devname); void ProbeDevice(Usb::DeviceID& devid); void ProbeDeviceEndpoints(Usb::Device &dev, Usb::EndpointPairings &ed, ProbeResult &result); bool ProbePair(Usb::Device &dev, const Usb::EndpointPair &ep, uint32_t &pin, std::string &desc, uint8_t &zeroSocketSequence, bool &needClearHalt); bool ProbeModem(Usb::Device &dev, const Usb::EndpointPair &ep); public: /// log_exceptions is a bitmask of low level USB errors to /// log instead of throw on. If 0, all USB errors will cause /// an exception, and thereby stop the probe. If the error /// is set in the bitmask, the exception will be caught, and /// logged in m_fail_msgs, which can be retrieved through /// GetFailCount() and GetFailMsg(). If auto_dump_log is true, /// all logged messages will be dumped as well, via the eout() macro, /// to make sure they are seen, even if the application /// programmer doesn't deal with them via the API. Probe(const char *busname = 0, const char *devname = 0, const Usb::EndpointPair *epp = 0, unsigned int log_exceptions = LOG_BUSY | LOG_ACCESS | LOG_PERM, bool auto_dump_log = true); const Results& GetResults() const { return m_results; } int GetCount() const { return m_results.size(); } int GetFailCount() const { return m_fail_count; } const std::string& GetFailMsg(int index) const { return m_fail_msgs.at(index); } const ProbeResult& Get(int index) const { return m_results.at(index); } int FindActive(Barry::Pin pin = 0) const; // returns -1 if pin not found // or if no devices static int FindActive(const Results &results, Barry::Pin pin = 0); static int Find(const Results &results, Barry::Pin pin = 0); }; } // namespace Barry #endif barry-0.18.5/src/vbase.h0000644001161500056700000001037712242254476014324 0ustar cdfreycdfrey/// /// \file vbase.h /// Base class for vformat support /// /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_SYNC_VBASE_H__ #define __BARRY_SYNC_VBASE_H__ #include "dll.h" #include "vsmartptr.h" #include "vformat.h" #include "error.h" #include namespace Barry { class CategoryList; } namespace Barry { namespace Sync { // // vTimeConverter // /// A virtual base class that the plugins may override, to do /// time related conversions. Default implementations for these /// functions are provided, but may be overrided depending on need. /// /// We do this in a "callback" style, so that it doesn't matter what /// version of the opensync library we link against, in case the /// user wishes to use the opensync time functions. /// class BXEXPORT vTimeConverter { public: virtual ~vTimeConverter() {} /// Convert a time_t into an ISO timestamp string /// Throws Barry::ConvertError on error, but these errors /// must be rare. virtual std::string unix2vtime(const time_t *timestamp); /// Convert an ISO timestamp string into a time_t, using /// the current system timezone if vtime is not in UTC. /// Returns (time_t)-1 on error. virtual time_t vtime2unix(const char *vtime); /// Convert a VEVENT alarm duration string in the format /// of "[+-]P.W.DT.H.M.S" where the periods represent numbers /// and each letter besides P and T represent Week, Day, /// Hour, Minute, and Second respectively. virtual int alarmduration2sec(const char *alarm); }; typedef Barry::vSmartPtr vAttrPtr; typedef Barry::vSmartPtr vParamPtr; typedef Barry::vSmartPtr gStringPtr; // // vAttr // /// Class for reading a b_VFormatAttribute. Reading does not require /// memory management, so none is done. /// class BXEXPORT vAttr { b_VFormatAttribute *m_attr; public: vAttr() : m_attr(0) { } vAttr(b_VFormatAttribute *attr) : m_attr(attr) { } vAttr& operator=(b_VFormatAttribute *attr) { m_attr = attr; return *this; } b_VFormatAttribute* Get() { return m_attr; } // These functions do not throw an error if the value // is NULL or does not exist (for example, if you ask for // value #5 and there are only 4). std::string GetName(); std::string GetValue(int nth = 0); std::string GetDecodedValue(); std::string GetParam(const char *name, int nth = 0); std::string GetAllParams(const char *name); }; // // vBase // /// Base class containing vformat helper API. /// class BXEXPORT vBase { // internal data for managing the vformat b_VFormat *m_format; public: protected: vBase(); explicit vBase(b_VFormat *format); virtual ~vBase(); b_VFormat* Format() { return m_format; } const b_VFormat* Format() const { return m_format; } void SetFormat(b_VFormat *format); void Clear(); vAttrPtr NewAttr(const char *name); vAttrPtr NewAttr(const char *name, const char *value); void AddAttr(vAttrPtr attr); void AddValue(vAttrPtr &attr, const char *value); void AddEncodedValue(vAttrPtr &attr, b_VFormatEncoding encoding, const char *value, int len); void AddParam(vAttrPtr &attr, const char *name, const char *value); void AddCategories(const Barry::CategoryList &categories); std::string GetAttr(const char *attrname, const char *block = 0); std::vector GetValueVector(const char *attrname, const char *block = 0); vAttr GetAttrObj(const char *attrname, int nth = 0, const char *block = 0); std::vector Tokenize(const std::string &str, const char delim = ','); std::string ToStringList(const std::vector &list, const char delim = ','); }; }} // namespace Barry::Sync #endif barry-0.18.5/src/iconv.cc0000644001161500056700000001067212242254476014476 0ustar cdfreycdfrey/// /// \file iconv.cc /// iconv wrapper class, and pluggable interface for records /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "iconv.h" #include "common.h" #include "error.h" #include "config.h" #include #include #include #include using namespace std; namespace Barry { ////////////////////////////////////////////////////////////////////////////// // IConvHandlePrivate class class IConvHandlePrivate { public: iconv_t m_handle; IConvHandlePrivate() { } }; ////////////////////////////////////////////////////////////////////////////// // IConvHandle class IConvHandle::IConvHandle(const char *fromcode, const char *tocode, bool throw_on_conv_err) : m_priv( new IConvHandlePrivate ) , m_throw_on_conv_err(throw_on_conv_err) { m_priv->m_handle = iconv_open(tocode, fromcode); if( m_priv->m_handle == (iconv_t)(-1) ) { throw ErrnoError(std::string("iconv_open failed: from ") + fromcode + " to " + tocode, errno); } } IConvHandle::IConvHandle(const char *fromcode, const IConverter &ic, bool throw_on_conv_err) : m_priv( new IConvHandlePrivate ) , m_throw_on_conv_err(throw_on_conv_err) { m_priv->m_handle = iconv_open(ic.m_tocode.c_str(), fromcode); if( m_priv->m_handle == (iconv_t)(-1) ) { throw ErrnoError(std::string("iconv_open failed: from ") + fromcode + " to " + ic.m_tocode, errno); } } IConvHandle::IConvHandle(const IConverter &ic, const char *tocode, bool throw_on_conv_err) : m_priv( new IConvHandlePrivate ) , m_throw_on_conv_err(throw_on_conv_err) { m_priv->m_handle = iconv_open(tocode, ic.m_tocode.c_str()); if( m_priv->m_handle == (iconv_t)(-1) ) { throw ErrnoError(std::string("iconv_open failed: from ") + ic.m_tocode + " to " + tocode, errno); } } IConvHandle::~IConvHandle() { iconv_close(m_priv->m_handle); } std::string IConvHandle::Convert(Data &tmp, const std::string &str) const { size_t target = str.size() * 2; char *out = 0, *outstart = 0; size_t outbytesleft = 0; std::string ret; iconv_t cd = m_priv->m_handle; // this loop is for the very odd case that the output string // needs more than twice the input size for( int tries = 0; ; tries++ ) { const char *in = str.data(); size_t inbytesleft = str.size(); out = outstart = (char*) tmp.GetBuffer(target); outbytesleft = tmp.GetBufSize(); iconv(cd, NULL, NULL, NULL, NULL); // reset cd's state size_t status = iconv(cd, (ICONV_CONST char**) &in, &inbytesleft, &out, &outbytesleft); if( status == (size_t)(-1) ) { if( errno == E2BIG && tries < 2 ) { target += inbytesleft * 2; // try again with more memory... continue; } // should never happen :-) // but if it does, and we get here, check // whether the user wants to be notified by // exception... if not, just fall through and // store as much converted data as possible ErrnoError e(string("iconv failed with string '") + str + "'", errno); if( m_throw_on_conv_err ) { throw e; } else { cerr << e.what(); // return the unconverted string return str; } } else { // success break; } } // store any available converted data ret.assign(outstart, out - outstart); return ret; } ////////////////////////////////////////////////////////////////////////////// // IConvHandle class IConverter::IConverter(const char *tocode, bool throw_on_conv_err) : m_from(BLACKBERRY_CHARSET, tocode, throw_on_conv_err) , m_to(tocode, BLACKBERRY_CHARSET, throw_on_conv_err) , m_tocode(tocode) { } IConverter::~IConverter() { } std::string IConverter::FromBB(const std::string &str) const { return m_from.Convert(m_buffer, str); } std::string IConverter::ToBB(const std::string &str) const { return m_to.Convert(m_buffer, str); } std::string IConverter::Convert(const IConvHandle &custom, const std::string &str) const { return custom.Convert(m_buffer, str); } } // namespace Barry barry-0.18.5/src/a_osloader.h0000644001161500056700000000477212242254476015336 0ustar cdfreycdfrey/// /// \file a_osloader.h /// OS files parser (multi ALX files parser) /// /* Copyright (C) 2010, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_A_OSLOADER_H__ #define __BARRY_A_OSLOADER_H__ #include #include #include #include "dll.h" #include "a_application.h" #include "a_library.h" #include #define OS_LANG_ENGLISH "" #define OS_LANG_ARABIC "0x0001" #define OS_LANG_CATALAN "0x0003" #define OS_LANG_CZECH "0x0005" #define OS_LANG_GERMAN "0x0007" #define OS_LANG_SPANISH "0x000a" #define OS_LANG_FRENCH "0x000c" #define OS_LANG_HEBREW "0x000d" #define OS_LANG_HUNGARIAN "0x000e" #define OS_LANG_ITALIAN "0x0010" #define OS_LANG_JAPANESE "0x0011" #define OS_LANG_KOREAN "0x0012" namespace Barry { namespace ALX { class BXEXPORT OSLoader { public: typedef std::tr1::shared_ptr CODSectionPtr; typedef std::vector CODSectionList; typedef std::map PropertyMap; private: std::string sfifile; CODSectionList applications; CODSectionList libraries; PropertyMap properties; public: OSLoader(void); ~OSLoader(void); void Load(const std::string& path); /// Load ALX file, and if enable is true, register the applications /// and libraries found inside it with this OSLoader class. void LoadALXFile(const std::string& alxfile, const bool enable=true); void Dump(std::ostream &os) const; void AddProperties(const std::string& property, const std::string& value); void AddProperties(const xmlpp::SaxParser::AttributeList& attrs); void SetSFIFile(const std::string& name); bool IsSupported(const xmlpp::SaxParser::AttributeList& attrs); void AddApplication(CODSectionPtr app); void AddLibrary(CODSectionPtr lib); }; inline std::ostream& operator<<(std::ostream& os, const OSLoader& osloader) { osloader.Dump(os); return os; } } // namespace ALX } // namespace Barry #endif barry-0.18.5/src/m_ipmodem.h0000644001161500056700000000414612242254476015167 0ustar cdfreycdfrey/// /// \file m_ipmodem.h /// Mode class for GPRS modem mode (using endpoints on /// modern devices) /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_M_IPMODEM_H__ #define __BARRY_M_IPMODEM_H__ #include "dll.h" #include "modem.h" #include "usbwrap.h" #include "data.h" #include "pppfilter.h" #include #define SB_IPMODEM_SESSION_KEY_LENGTH 8 namespace Barry { // forward declarations class Controller; namespace Mode { class BXEXPORT IpModem : public Modem { public: typedef void (*DeviceDataCallback)(void *context, const unsigned char *data, int len); private: Controller &m_con; Usb::Device &m_dev; PppFilter m_filter; // used for 0x7e handling // thread data volatile bool m_continue_reading; pthread_t m_modem_read_thread; // external callbacks DeviceDataCallback m_callback; void *m_callback_context; unsigned char m_session_key[SB_IPMODEM_SESSION_KEY_LENGTH]; // = { 0x00, 0, 0, 0, 0, 0, 0, 0 }; private: BXLOCAL bool SendPassword(const char *password, uint32_t seed); protected: static void *DataReadThread(void *userptr); public: IpModem(Controller &con, DeviceDataCallback callback, void *callback_context); ~IpModem(); ////////////////////////////////// // general operations void Open(const char *password = 0); void Close(); ////////////////////////////////// // UsbSerData mode - modem specific // void Read(Data &data, int timeout); // can be called from separate thread void Write(const Data &data, int timeout = -1); }; }} // namespace Barry::Mode #endif barry-0.18.5/src/usbwrap.h0000644001161500056700000002305612242254476014705 0ustar cdfreycdfrey/// /// \file usbwrap.h /// USB API wrapper /// /* Copyright (C) 2005-2013, Chris Frey Portions Copyright (C) 2011, RealVNC Ltd. 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __SB_USBWRAP_H__ #define __SB_USBWRAP_H__ #include "dll.h" #include #include #include #include #include "error.h" #define USBWRAP_DEFAULT_TIMEOUT 30000 // Matches any product ID when calling DeviceList::MatchDevices #define PRODUCT_ANY 0x10000 // Indicates an unknown product ID #define PRODUCT_UNKNOWN 0x20000 namespace Barry { class Data; } /// Namespace for the libusb-related wrapper classes. This namespace /// may change in the future. namespace Usb { /// \addtogroup exceptions /// @{ /// Thrown on low level USB errors. class BXEXPORT Error : public Barry::Error { int m_libusb_errcode; public: Error(const std::string &str); Error(int libusb_errcode, const std::string &str); // can return 0 in some case, if unknown error code int libusb_errcode() const { return m_libusb_errcode; } // returns a translated system error code when using libusb 1.0 // returns 0 if unknown or unable to translate int system_errcode() const; }; class BXEXPORT Timeout : public Error { public: Timeout(const std::string &str) : Error(str) {} Timeout(int errcode, const std::string &str) : Error(errcode, str) {} }; /// @} // Private struct for holding library specific // a unique identifier to a connected device. class DeviceIDImpl; class BXEXPORT DeviceID { public: std::tr1::shared_ptr m_impl; public: // Takes ownership of impl DeviceID(DeviceIDImpl* impl = NULL); ~DeviceID(); const char* GetBusName() const; uint16_t GetNumber() const; const char* GetFilename() const; uint16_t GetIdProduct() const; // Utility function: returns a string that uniquely identifies // the bus and device, regardless of which libusb you're using std::string GetUsbName() const; }; // Private struct for holding a library specific // device handle struct DeviceHandle; // Static functions for setting up USB // The interface that usbwrap.cc uses // to interact with the USB library class BXEXPORT LibraryInterface { public: static std::string GetLastErrorString(int libusb_errcode); /// Returns 0 if unable to translate libusb error code. /// Note that this function assumes you already know that libusb_errcode /// contains an actual error code, and so returns 0 (success) /// for an unknown error. This means that "success" means error /// if you use this function correctly, but if you pass in a success /// code (>= 0) it will always return 0 as well. static int TranslateErrcode(int libusb_errcode); /// Returns true on success... pass in a pointer to int /// if the low level error code is important to you. static bool Init(int *libusb_errno = 0); static void Uninit(); static void SetDataDump(bool data_dump_mode); }; // Forward declaration of descriptor types. class BXEXPORT DeviceDescriptor; class BXEXPORT ConfigDescriptor; class BXEXPORT InterfaceDescriptor; // Private struct for holding library specific // information about endpoint descriptors struct EndpointDescriptorImpl; // Encapsulates an endpoint descriptor class BXEXPORT EndpointDescriptor { public: enum EpType { ControlType = 0, IsochronousType = 1, BulkType = 2, InterruptType = 3, InvalidType = 0xff }; private: const std::auto_ptr m_impl; bool m_read; uint8_t m_addr; EpType m_type; private: EndpointDescriptor(const EndpointDescriptor& rhs); // Prevent copying public: EndpointDescriptor(InterfaceDescriptor& dev, int endpoint); ~EndpointDescriptor(); bool IsRead() const; uint8_t GetAddress() const; EpType GetType() const; }; // Private struct for holding library specific // information about interface descriptors struct InterfaceDescriptorImpl; // Encapsulates an interface descriptor // // The inherited vector methods look up endpoints class BXEXPORT InterfaceDescriptor : public std::vector { friend class EndpointDescriptor; public: typedef std::vector base_type; private: const std::auto_ptr m_impl; private: InterfaceDescriptor(const InterfaceDescriptor& rhs); // Prevent copying public: InterfaceDescriptor(ConfigDescriptor& cfgdesc, int iface, int altsetting); ~InterfaceDescriptor(); uint8_t GetClass() const; uint8_t GetNumber() const; uint8_t GetAltSetting() const; }; // Private struct for holding library specific // information about config descriptors struct ConfigDescriptorImpl; // Encapsulates a configuration descriptor // // The inherited map methods look up interface descriptors class BXEXPORT ConfigDescriptor : public std::map { friend class InterfaceDescriptor; public: typedef std::map base_type; private: const std::auto_ptr m_impl; private: ConfigDescriptor(const ConfigDescriptor& rhs); // Prevent copying public: ConfigDescriptor(DeviceDescriptor& dev, int cfgnumber); ~ConfigDescriptor(); uint8_t GetNumber() const; }; // Private struct for holding library specific // information about a device descriptor struct DeviceDescriptorImpl; // Encapsulates a device descriptor // // The inherited map methods look up config descriptors class BXEXPORT DeviceDescriptor : public std::map { friend class ConfigDescriptor; public: typedef std::map base_type; private: const std::auto_ptr m_impl; private: DeviceDescriptor(const DeviceDescriptor& rhs); // Prevent copying public: DeviceDescriptor(DeviceID& devid); ~DeviceDescriptor(); }; // Private struct for holding library specific // information for devices. struct DeviceListImpl; class BXEXPORT DeviceList { private: // Private implementation structure const std::auto_ptr m_impl; private: DeviceList(const DeviceList& rhs); // Prevent copying public: DeviceList(); ~DeviceList(); std::vector MatchDevices(int vendor, int product, const char *busname, const char *devname); }; struct PrivateDeviceData; class BXEXPORT Device { private: Usb::DeviceID m_id; const std::auto_ptr m_handle; int m_timeout; int m_lasterror; private: Device(const Device& rhs); // Prevent copying public: Device(const Usb::DeviceID& id, int timeout = USBWRAP_DEFAULT_TIMEOUT); ~Device(); ///////////////////////////// // Data access const Usb::DeviceID& GetID() const { return m_id; } const Usb::DeviceHandle* GetHandle() const { return &*m_handle; } int GetLastError() const { return m_lasterror; } //< not thread safe... //< use the error code stored in the exceptions to track //< errors in threaded usage void SetLastError(int err) { m_lasterror = err; } int GetDefaultTimeout() const { return m_timeout; } ///////////////////////////// // Device information int GetPowerLevel(); int FindInterface(int ifaceClass); std::string GetSimpleSerialNumber(); ///////////////////////////// // Device manipulation bool SetConfiguration(unsigned char cfg); bool ClearHalt(int ep); bool Reset(); bool IsAttachKernelDriver(int iface); bool DetachKernelDriver(int iface); ///////////////////////////// // IO functions bool BulkRead(int ep, Barry::Data &data, int timeout = -1); bool BulkWrite(int ep, const Barry::Data &data, int timeout = -1); bool BulkWrite(int ep, const void *data, size_t size, int timeout = -1); bool InterruptRead(int ep, Barry::Data &data, int timeout = -1); bool InterruptWrite(int ep, const Barry::Data &data, int timeout = -1); void BulkDrain(int ep, int timeout = 100); bool ControlMsg(int requesttype, int request, int value, int index, char *bytes, int size, int timeout); ///////////////////////////// // Combo functions bool GetConfiguration(unsigned char &cfg); }; class BXEXPORT Interface { Device &m_dev; int m_iface; public: Interface(Device &dev, int iface); ~Interface(); bool SetAltInterface(int altSetting); }; // Map of Endpoint numbers (not indexes) to endpoint descriptors struct BXEXPORT EndpointPair { unsigned char read; unsigned char write; EndpointDescriptor::EpType type; EndpointPair(); bool IsTypeSet() const; bool IsComplete() const; bool IsBulk() const; }; class BXEXPORT EndpointPairings : public std::vector { public: typedef std::vector base_type; private: bool m_valid; public: EndpointPairings(const std::vector& eps); ~EndpointPairings(); bool IsValid() const; }; class BXEXPORT Match { private: std::vector m_list; std::vector::iterator m_iter; public: // Due to USB libraries having different ownership ideas // about device IDs, Match objects must be constructed // with a device list. Match(DeviceList& devices, int vendor, int product, const char *busname = 0, const char *devname = 0); ~Match(); // searches for next match, and if found, fills devid with // something you can pass on to DeviceDiscover, etc // returns true if next is found, false if no more bool next_device(Usb::DeviceID& devid); }; } #endif barry-0.18.5/src/m_serial.h0000644001161500056700000000417712242254476015020 0ustar cdfreycdfrey/// /// \file m_serial.h /// Mode class for serial / GPRS modem mode /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_M_SERIAL_H__ #define __BARRY_M_SERIAL_H__ #include "dll.h" #include "modem.h" #include "socket.h" #include "data.h" #include "pppfilter.h" namespace Barry { // forward declarations class Controller; namespace Mode { class BXEXPORT Serial : public Modem { public: typedef void (*DeviceDataCallback)(void *context, const unsigned char *data, int len); private: Controller &m_con; SocketHandle m_data; SocketHandle m_ctrl; uint16_t m_ModeSocket; // socket recommended by device // when mode was selected uint16_t m_CtrlSocket; // PPP filtering PppFilter m_filter; // UsbSerData cache // Data m_readCache; // external callbacks DeviceDataCallback m_callback; void *m_callback_context; protected: static void DataCallback(Serial &context, Data *data); static void CtrlCallback(Serial &context, Data *data); public: Serial(Controller &con, DeviceDataCallback callback, void *callback_context); ~Serial(); ////////////////////////////////// // general operations void Open(const char *password = 0); // FIXME password needed? if not, // then we can remove it from // the Modem base class void Close(); void RetryPassword(const char *password); ////////////////////////////////// // UsbSerData mode - modem specific // void Read(Data &data, int timeout); // can be called from separate thread void Write(const Data &data, int timeout = -1); }; }} // namespace Barry::Mode #endif barry-0.18.5/src/vcard.h0000644001161500056700000000417512242254476014322 0ustar cdfreycdfrey/// /// \file vcard.h /// Conversion routines for vcards /// /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_SYNC_VCARD_H__ #define __BARRY_SYNC_VCARD_H__ #include "dll.h" #include "vbase.h" #include "r_contact.h" #include #include namespace Barry { namespace Sync { // // vCard // /// Class for converting between RFC 2425/2426 vCard data format, /// and the Barry::Contact class. /// class BXEXPORT vCard : public vBase { // data to pass to external requests char *m_gCardData; // dynamic memory returned by vformat()... can // be used directly by the plugin, without // overmuch allocation and freeing (see Extract()) std::string m_vCardData;// copy of m_gCardData, for C++ use Barry::Contact m_BarryContact; protected: void AddAddress(const char *rfc_type, const Barry::PostalAddress &addr); void AddPhoneCond(const std::string &phone); void AddPhoneCond(const char *rfc_type, const std::string &phone); void ParseAddress(vAttr &adr, Barry::PostalAddress &address); void ParseCategories(vAttr &cat, Barry::CategoryList &cats); public: vCard(); ~vCard(); const std::string& ToVCard(const Barry::Contact &con); const Barry::Contact& ToBarry(const char *vcal, uint32_t RecordId); const std::string& GetVCard() const { return m_vCardData; } const Barry::Contact& GetBarryContact() const { return m_BarryContact; } char* ExtractVCard(); void Clear(); // This is the v-name of the innermost BEGIN/END block static const char* GetVName() { return "VCARD"; } }; }} // namespace Barry::Sync #endif barry-0.18.5/src/vevent.cc0000644001161500056700000005716512242254476014677 0ustar cdfreycdfrey/// /// \file vevent.cc /// Conversion routines for vevents (VCALENDAR, etc) /// /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2010, Nicolas VIVIEN Copyright (C) 2009, Dr J A Gow 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "vevent.h" //#include "trace.h" #include "log.h" #include "time.h" #include "common.h" #include #include #include #include #include #include using namespace std; namespace Barry { namespace Sync { ////////////////////////////////////////////////////////////////////////////// // vCalendar vCalendar::vCalendar(vTimeConverter &vtc) : m_vtc(vtc) , m_gCalData(0) { } vCalendar::~vCalendar() { if( m_gCalData ) { g_free(m_gCalData); } } const char *vCalendar::WeekDays[] = { "SU", "MO", "TU", "WE", "TH", "FR", "SA" }; uint16_t vCalendar::GetWeekDayIndex(const char *dayname) { for( int i = 0; i < 7; i++ ) { if( strcasecmp(dayname, WeekDays[i]) == 0 ) return i; } return 0; } void vCalendar::CheckUnsupportedArg(const ArgMapType &args, const std::string &name) { if( args.find(name) != args.end() ) { barrylog(string_vprintf(_("ERROR: recurrence rule contains %s, unsupported by Barry. MIME conversion will be incorrect."), name.c_str())); barryverbose(_("Record data so far:\n") << m_BarryCal); } } std::vector vCalendar::SplitBYDAY(const std::string &ByDay) { std::vector v = Tokenize(ByDay); // BlackBerry recursion only supports one specification... // i.e. only 3rd Wed of month, not 3rd Wed and 2nd Fri of month... // if there's more than one item in v, warn the user, and just // use the first item if( v.size() > 1 ) { barrylog(string_vprintf(_("Warning: multiple items in BYDAY, not supported by device (%s). Using only the first item."), ByDay.c_str())); barryverbose(_("Record data so far:\n") << m_BarryCal); } return v; } uint16_t vCalendar::GetMonthWeekNumFromBYDAY(const std::string& ByDay) { std::vector v = SplitBYDAY(ByDay); if( !v.size() || v[0].size() < 2 ) { return 0; } else { int week = atoi(v[0].substr(0,v[0].length()-2).c_str()); if( week < 0 ) { // assume 4 weeks per month int pos_week = 4 + (week + 1); if( pos_week < 1 || pos_week > 4 ) { pos_week = 1; } barrylog(string_vprintf(_("Warning: negative week in BYDAY (%d), unsupported by device. Converting to positive week, based on 4 week months: %d."), week, pos_week)); barryverbose(_("Record data so far:\n") << m_BarryCal); week = pos_week; } return week; } } uint16_t vCalendar::GetWeekDayIndexFromBYDAY(const std::string& ByDay) { std::vector v = SplitBYDAY(ByDay); if( !v.size() || v[0].size() < 2 ) return 0; return GetWeekDayIndex(v[0].substr(v[0].length()-2).c_str()); } // month_override is specified in 1-12, or -1 to use m_BarryCal.StartTime uint16_t vCalendar::GetDayOfMonthFromBYMONTHDAY(const ArgMapType &args, int month_override) { time_t starttime = m_BarryCal.StartTime.Time; struct tm datestruct; localtime_r(&starttime,&datestruct); if( month_override != -1 ) datestruct.tm_mon = month_override - 1; int monthdays = DaysInMonth(datestruct); ArgMapType::const_iterator vi = args.find("BYMONTHDAY"); if( vi == args.end() ) throw std::logic_error(_("Called GetDayOfMonthFromBYMONTHDAY() without a BYMONTHDAY")); int val = atoi(vi->second.c_str()); if( val == 0 ) { barryverbose(_("Warning: BYMONTHDAY of 0, assuming 1.\n") << _("Record data so far:\n") << m_BarryCal); val = 1; } else if( val > monthdays ) { barryverbose(string_vprintf(_("Warning: BYMONTHDAY larger than month (%d days). Assuming 1.\n"), val)); barryverbose(_("Record data so far:\n") << m_BarryCal); val = 1; } else if( val < 0 ) { // See 4.3.10 RRULE in RFC 2445 // negative values mean "last n day of month", so // convert to the fixed day, and then use that positive // value instead, as an approximation int pos_day = monthdays + (val + 1); if( pos_day < 1 || pos_day > monthdays ) { pos_day = 1; } barrylog(string_vprintf(_("Warning: negative BYMONTHDAY (%d), unsupported by device. Converting to positive day of month: %d."), val, pos_day)); barryverbose(_("Record data so far:\n") << m_BarryCal); val = pos_day; } return val; } bool vCalendar::HasMultipleVEvents() const { int count = 0; b_VFormat *format = const_cast(Format()); GList *attrs = format ? b_vformat_get_attributes(format) : 0; for( ; attrs; attrs = attrs->next ) { b_VFormatAttribute *attr = (b_VFormatAttribute*) attrs->data; if( strcasecmp(b_vformat_attribute_get_name(attr), "BEGIN") == 0 && strcasecmp(b_vformat_attribute_get_nth_value(attr, 0), "VEVENT") == 0 ) { count++; } } return count > 1; } void vCalendar::RecurToVCal() { using namespace Barry; using namespace std; Barry::Calendar &cal = m_BarryCal; if( !cal.Recurring ) return; vAttrPtr attr = NewAttr("RRULE"); switch( cal.RecurringType ) { case Calendar::Day: // eg. every day AddValue(attr,"FREQ=DAILY"); break; case Calendar::MonthByDate: // eg. every month on the 12th // see: DayOfMonth AddValue(attr,"FREQ=MONTHLY"); { ostringstream oss; oss << "BYMONTHDAY=" << cal.DayOfMonth; AddValue(attr, oss.str().c_str()); } break; case Calendar::MonthByDay: // eg. every month on 3rd Wed // see: DayOfWeek and WeekOfMonth AddValue(attr, "FREQ=MONTHLY"); if( cal.DayOfWeek <= 6 ) { // DayOfWeek is unsigned ostringstream oss; oss << "BYDAY=" << cal.WeekOfMonth << WeekDays[cal.DayOfWeek]; AddValue(attr, oss.str().c_str()); } break; case Calendar::YearByDate: // eg. every year on March 5 // see: DayOfMonth and MonthOfYear AddValue(attr, "FREQ=YEARLY"); { ostringstream oss; oss << "BYMONTH=" << cal.MonthOfYear; AddValue(attr, oss.str().c_str()); } { ostringstream oss; oss << "BYMONTHDAY=" << cal.DayOfMonth; AddValue(attr, oss.str().c_str()); } break; case Calendar::YearByDay: // eg. every year on 3rd Wed of Jan // see: DayOfWeek, WeekOfMonth, and // MonthOfYear AddValue(attr, "FREQ=YEARLY"); if( cal.DayOfWeek <= 6 ) { // DayOfWeek is unsigned ostringstream oss; oss << "BYDAY=" << cal.WeekOfMonth << WeekDays[cal.DayOfWeek]; AddValue(attr, oss.str().c_str()); oss.str(""); oss << "BYMONTH=" << cal.MonthOfYear; AddValue(attr, oss.str().c_str()); } break; case Calendar::Week: // eg. every week on Mon and Fri // see: WeekDays AddValue(attr, "FREQ=WEEKLY"); { ostringstream oss; oss << "BYDAY="; for( int i = 0, bm = 1, cnt = 0; i < 7; i++, bm <<= 1 ) { if( cal.WeekDays & bm ) { if( cnt ) oss << ","; oss << WeekDays[i]; cnt++; } } AddValue(attr, oss.str().c_str()); } break; default: throw ConvertError(_("Unknown RecurringType in Barry Calendar object")); } // add some common parameters if( cal.Interval > 1 ) { ostringstream oss; oss << "INTERVAL=" << cal.Interval; AddValue(attr, oss.str().c_str()); } if( !cal.Perpetual ) { ostringstream oss; oss << "UNTIL=" << m_vtc.unix2vtime(&cal.RecurringEndTime.Time); AddValue(attr, oss.str().c_str()); } AddAttr(attr); /* bool AllDayEvent; /// /// Recurring data /// /// Note: interval can be used on all of these recurring types to /// make it happen "every other time" or more, etc. /// bool Recurring; RecurringCodeType RecurringType; uint16_t Interval; // must be >= 1 time_t RecurringEndTime; // only pertains if Recurring is true // sets the date and time when // recurrence of this appointment // should no longer occur // If a perpetual appointment, this // is 0xFFFFFFFF in the low level data // Instead, set the following flag. bool Perpetual; // if true, this will always recur uint16_t TimeZoneCode; // the time zone originally used // for the recurrence data... // seems to have little use, but // set to your current time zone // as a good default uint16_t // recurring details, depending on type DayOfWeek, // 0-6 WeekOfMonth, // 1-5 DayOfMonth, // 1-31 MonthOfYear; // 1-12 unsigned char WeekDays; // bitmask, bit 0 = sunday #define CAL_WD_SUN 0x01 #define CAL_WD_MON 0x02 #define CAL_WD_TUE 0x04 #define CAL_WD_WED 0x08 #define CAL_WD_THU 0x10 #define CAL_WD_FRI 0x20 #define CAL_WD_SAT 0x40 */ } namespace { struct tm GetConstLocalTime(const time_t &t) { struct tm datestruct; localtime_r(&t, &datestruct); return datestruct; } } void vCalendar::RecurToBarryCal(vAttr& rrule, time_t starttime) { using namespace Barry; using namespace std; Barry::Calendar &cal = m_BarryCal; // Trace trace("vCalendar::RecurToBarryCal"); std::map pmap; pmap["SU"] = CAL_WD_SUN; pmap["MO"] = CAL_WD_MON; pmap["TU"] = CAL_WD_TUE; pmap["WE"] = CAL_WD_WED; pmap["TH"] = CAL_WD_THU; pmap["FR"] = CAL_WD_FRI; pmap["SA"] = CAL_WD_SAT; const struct tm datestruct = GetConstLocalTime(starttime); int i=0; unsigned int count=0; string val; ArgMapType args; do { val=rrule.GetValue(i++); if(val.length()==0) { break; } string n=val.substr(0,val.find("=")); string v=val.substr(val.find("=")+1); args[n]=v; // trace.logf("RecurToBarryCal: |%s|%s|",n.c_str(),v.c_str()); } while(1); // now process the interval. cal.Recurring=TRUE; if(args.find(string("INTERVAL"))!=args.end()) { int interval = atoi(args["INTERVAL"].c_str()); if( interval < 1 ) { // force to at least 1, for math below interval = 1; } cal.Interval = interval; } else { // default to 1, for the math below. // RecurBase::Clear() does this for us as well, but // best to be safe cal.Interval = 1; } if(args.find(string("UNTIL"))!=args.end()) { cal.Perpetual = FALSE; cal.RecurringEndTime.Time = m_vtc.vtime2unix(args["UNTIL"].c_str()); if( cal.RecurringEndTime.Time == (time_t)-1 ) { // trace.logf("osync_time_vtime2unix() failed: UNTIL = %s, zoneoffset = %d", args["UNTIL"].c_str(), zoneoffset); } } else { // if we do not also have COUNT, then we must be forerver if(args.find(string("COUNT"))==args.end()) { cal.Perpetual=TRUE; } else { // we do have COUNT. This means we won't have UNTIL. // So we need to process the RecurringEndTime from // the current start date. Set the count level to // something other than zero to indicate we need // to process it as the exact end date will // depend upon the frequency. count=atoi(args["COUNT"].c_str()); if( count == 0 ) { throw std::runtime_error(_("Invalid COUNT in recurring rule: ") + args["COUNT"]); } } } // we need these if COUNT is true, or if we are a yearly job. // TO-DO: we must process COUNT in terms of an end date if we have it. // warn the user about unsupported arguments CheckUnsupportedArg(args, "BYSETPOS");// FIXME - theorectically supportable CheckUnsupportedArg(args, "BYYEARDAY"); CheckUnsupportedArg(args, "BYWEEKNO"); CheckUnsupportedArg(args, "WKST"); CheckUnsupportedArg(args, "BYSECOND"); CheckUnsupportedArg(args, "BYMINUTE"); CheckUnsupportedArg(args, "BYHOUR"); // Now deal with the freq if(args.find(string("FREQ"))==args.end()) { // trace.logf("RecurToBarryCal: No frequency specified!"); return; } if(args["FREQ"]==string("DAILY")) { cal.RecurringType=Calendar::Day; if(count) { // add count-1*interval days to find the end time: // i.e. if starting on 2012/01/01 and going // for 3 days, then the last day will be // 2012/01/03. // // For intervals, the count is every interval days, // so interval of 2 means 2012/01/01, 2012/01/03, etc. // and the calculation still works. cal.RecurringEndTime.Time = starttime + (count-1) * cal.Interval * 24*60*60; } } else if(args["FREQ"]==string("WEEKLY")) { cal.RecurringType=Calendar::Week; // we must have a dayofweek entry if(args.find(string("BYDAY"))!=args.end()) { std::vector v=Tokenize(args["BYDAY"]); // iterate along our vector and convert for(unsigned int idx=0;idx28 and the resulting // month falls on a February. We don't need // to worry about day of week as mktime() // clobbers it. // // We let mktime() normalize any out of range values. int add = (count-1) * cal.Interval; tempdate.tm_year += (tempdate.tm_mon+add)/12; tempdate.tm_mon = (tempdate.tm_mon+add)%12; // Just in case we're crossing DST boundaries, // add an hour, to make sure we reach the ending // month, in the case of intervals tempdate.tm_hour++; cal.RecurringEndTime.Time = mktime(&tempdate); } } else if(args["FREQ"]=="YEARLY") { bool need_assumption = true; if(args.find(string("BYMONTH"))!=args.end()) { cal.MonthOfYear=atoi(args["BYMONTH"].c_str()); if( cal.MonthOfYear < 1 || cal.MonthOfYear > 12 ) { // doh... default to starttime's month cal.MonthOfYear = datestruct.tm_mon + 1; } if(args.find(string("BYMONTHDAY"))!=args.end()) { cal.RecurringType=Calendar::YearByDate; cal.DayOfMonth=GetDayOfMonthFromBYMONTHDAY(args, cal.MonthOfYear); need_assumption = false; } else { if(args.find(string("BYDAY"))!=args.end()) { cal.RecurringType=Calendar::YearByDay; cal.WeekOfMonth=GetMonthWeekNumFromBYDAY(args["BYDAY"]); cal.DayOfWeek=GetWeekDayIndexFromBYDAY(args["BYDAY"]); need_assumption = false; } else { // fall through to assumption below... } } } if( need_assumption ) { // otherwise use the start date and translate // to a BYMONTHDAY. // cal.StartTime has already been processed // when we get here we need month of year, // and day of month. cal.RecurringType=Calendar::YearByDate; cal.MonthOfYear=datestruct.tm_mon; cal.DayOfMonth=datestruct.tm_mday; barrylog(_("Warning: YEARLY VEVENT without a day type specified (no BYMONTHDAY nor BYDAY). Assuming BYMONTHDAY, using day and month of start time.")); barryverbose(_("Record data so far:\n") << cal); } if(count) { // convert to struct tm, then simply add to the year. // // Note: intervals do work in the device firmware, // but not all of the devices allow you to edit it // with their GUI... hmmm... oh well, allow it // anyway, and do the multiplication below. struct tm tempdate = datestruct; tempdate.tm_year += (count-1) * cal.Interval; cal.RecurringEndTime.Time = mktime(&tempdate); } } // unsigned char WeekDays; // bitmask, bit 0 = sunday // // #define CAL_WD_SUN 0x01 // #define CAL_WD_MON 0x02 // #define CAL_WD_TUE 0x04 // #define CAL_WD_WED 0x08 // #define CAL_WD_THU 0x10 // #define CAL_WD_FRI 0x20 // #define CAL_WD_SAT 0x40 } // Main conversion routine for converting from Barry::Calendar to // a vCalendar string of data. const std::string& vCalendar::ToVCal(const Barry::Calendar &cal) { // Trace trace("vCalendar::ToVCal"); std::ostringstream oss; cal.Dump(oss); // trace.logf("ToVCal, initial Barry record: %s", oss.str().c_str()); // start fresh Clear(); SetFormat( b_vformat_new() ); if( !Format() ) throw ConvertError(_("resource error allocating vformat")); // store the Barry object we're working with m_BarryCal = cal; // RFC section 4.8.7.2 requires DTSTAMP in all VEVENT, VTODO, // VJOURNAL, and VFREEBUSY calendar components, and it must be // in UTC. DTSTAMP holds the timestamp of when the iCal object itself // was created, not when the object was created in the device or app. // So, find out what time it is "now". time_t now = time(NULL); // begin building vCalendar data AddAttr(NewAttr("PRODID", "-//OpenSync//NONSGML Barry Calendar Record//EN")); AddAttr(NewAttr("BEGIN", "VEVENT")); AddAttr(NewAttr("DTSTAMP", m_vtc.unix2vtime(&now).c_str())); // see note above AddAttr(NewAttr("SEQUENCE", "0")); AddAttr(NewAttr("SUMMARY", cal.Subject.c_str())); AddAttr(NewAttr("DESCRIPTION", cal.Notes.c_str())); AddAttr(NewAttr("LOCATION", cal.Location.c_str())); string start(m_vtc.unix2vtime(&cal.StartTime.Time)); string end(m_vtc.unix2vtime(&cal.EndTime.Time)); string notify(m_vtc.unix2vtime(&cal.NotificationTime.Time)); // if an all day event, only print the date parts of the string if( cal.AllDayEvent && start.find('T') != string::npos ) { // truncate start date start = start.substr(0, start.find('T')); // create end date 1 day in future time_t end_t = cal.StartTime.Time + 24 * 60 * 60; end = m_vtc.unix2vtime(&end_t); end = end.substr(0, end.find('T')); } AddAttr(NewAttr("DTSTART", start.c_str())); AddAttr(NewAttr("DTEND", end.c_str())); // FIXME - add a truly globally unique "UID" string? AddAttr(NewAttr("BEGIN", "VALARM")); AddAttr(NewAttr("ACTION", "AUDIO")); // notify must be UTC, when specified in DATE-TIME vAttrPtr trigger = NewAttr("TRIGGER", notify.c_str()); AddParam(trigger, "VALUE", "DATE-TIME"); AddAttr(trigger); AddAttr(NewAttr("END", "VALARM")); if( cal.Recurring ) { RecurToVCal(); } AddAttr(NewAttr("END", "VEVENT")); // generate the raw VCALENDAR data m_gCalData = b_vformat_to_string(Format(), VFORMAT_EVENT_20); m_vCalData = m_gCalData; // trace.logf("ToVCal, resulting vcal data: %s", m_vCalData.c_str()); return m_vCalData; } // Main conversion routine for converting from vCalendar data string // to a Barry::Calendar object. const Barry::Calendar& vCalendar::ToBarry(const char *vcal, uint32_t RecordId) { using namespace std; // Trace trace("vCalendar::ToBarry"); // trace.logf("ToBarry, working on vcal data: %s", vcal); // we only handle vCalendar data with one vevent block if( HasMultipleVEvents() ) throw ConvertError(_("vCalendar data contains more than one VEVENT block, unsupported")); // start fresh Clear(); // store the vCalendar raw data m_vCalData = vcal; // create format parser structures SetFormat( b_vformat_new_from_string(vcal) ); if( !Format() ) throw ConvertError(_("resource error allocating vformat")); string start = GetAttr("DTSTART", "/vevent"); // trace.logf("DTSTART attr retrieved: %s", start.c_str()); string end = GetAttr("DTEND", "/vevent"); // trace.logf("DTEND attr retrieved: %s", end.c_str()); string subject = GetAttr("SUMMARY", "/vevent"); // trace.logf("SUMMARY attr retrieved: %s", subject.c_str()); if( subject.size() == 0 ) { subject = ""; // trace.logf("ERROR: bad data, blank SUMMARY: %s", vcal); } vAttr trigger_obj = GetAttrObj("TRIGGER", 0, "/valarm"); string location = GetAttr("LOCATION", "/vevent"); // trace.logf("LOCATION attr retrieved: %s", location.c_str()); string notes = GetAttr("DESCRIPTION", "/vevent"); // trace.logf("DESCRIPTION attr retrieved: %s", notes.c_str()); vAttr rrule = GetAttrObj("RRULE",0,"/vevent"); // // Now, run checks and convert into Barry object // // FIXME - we are assuming that any non-UTC timestamps // in the vcalendar record will be in the current timezone... // This is wrong! fix this later. // // Also, we currently ignore any time zone // parameters that might be in the vcalendar format... this // must be fixed. // Barry::Calendar &rec = m_BarryCal; rec.SetIds(Barry::Calendar::GetDefaultRecType(), RecordId); if( !start.size() ) throw ConvertError(_("Blank DTSTART")); rec.StartTime.Time = m_vtc.vtime2unix(start.c_str()); if( !end.size() ) { // DTEND is actually optional! According to the // RFC, a DTSTART with no DTEND should be treated // like a "special day" like an anniversary, which occupies // no time. // // Since the Blackberry doesn't really map well to this // case, we'll set the end time to 1 day past start. // rec.EndTime.Time = rec.StartTime.Time + 24 * 60 * 60; } else { rec.EndTime.Time = m_vtc.vtime2unix(end.c_str()); } // check for "all day event" which is specified by a DTSTART // and a DTEND with no times, and one day apart if( start.find('T') == string::npos && end.size() && end.find('T') == string::npos && (rec.EndTime.Time - rec.StartTime.Time) == 24 * 60 * 60 ) { rec.AllDayEvent = true; } rec.Subject = subject; rec.Location = location; rec.Notes = notes; if(rrule.Get()) { RecurToBarryCal(rrule, rec.StartTime.Time); } // convert trigger time into notification time // assume no notification, by default rec.NotificationTime.Time = 0; if( trigger_obj.Get() ) { string trigger_type = trigger_obj.GetParam("VALUE"); string trigger = trigger_obj.GetValue(); if( trigger.size() == 0 ) { // trace.logf("ERROR: no TRIGGER found in calendar entry, assuming notification time as 15 minutes before start."); } else if( trigger_type == "DATE-TIME" ) { rec.NotificationTime.Time = m_vtc.vtime2unix(trigger.c_str()); } else if( trigger_type == "DURATION" || trigger_type.size() == 0 ) { // default is DURATION (RFC 4.8.6.3) string related = trigger_obj.GetParam("RELATED"); // default to relative to start time time_t *relative = &rec.StartTime.Time; if( related == "END" ) relative = &rec.EndTime.Time; rec.NotificationTime.Time = *relative + m_vtc.alarmduration2sec(trigger.c_str()); } else { throw ConvertError(_("Unknown TRIGGER VALUE")); } } else { // trace.logf("ERROR: no TRIGGER found in calendar entry, assuming notification time as 15 minutes before start."); } std::ostringstream oss; m_BarryCal.Dump(oss); // trace.logf("ToBarry, resulting Barry record: %s", oss.str().c_str()); return m_BarryCal; } // Transfers ownership of m_gCalData to the caller. char* vCalendar::ExtractVCal() { char *ret = m_gCalData; m_gCalData = 0; return ret; } void vCalendar::Clear() { vBase::Clear(); m_vCalData.clear(); m_BarryCal.Clear(); if( m_gCalData ) { g_free(m_gCalData); m_gCalData = 0; } } }} // namespace Barry::Sync barry-0.18.5/src/ldif.h0000644001161500056700000002244212242254476014136 0ustar cdfreycdfrey/// /// \file ldif.h /// Routines for reading and writing LDAP LDIF data. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_LDIF_H__ #define __BARRY_LDIF_H__ #include "dll.h" #include #include // forward declarations namespace Barry { class Contact; } namespace Barry { // // ContactLdif // /// Class for generating LDIF output based on a Barry::Contact record object. /// This class supports LDIF attribute mapping, and a heuristics mechanism /// for parsing LDIF fields that may not have consistent data. /// /// To use this class, create an instance of it, then call DumpLdif(), passing /// the Contact record object to base the work on. Output will be written /// to the stream you provide. ReadLdif() goes in the other direction. /// /// To override LDIF attribute mapping, call Map() or Unmap() as appropriate. /// /// To get a list of supported Barry::Contact field names, call GetFieldNames(). /// This function returns a pointer to an array of ContactLdif::NameToFunc /// structures, ending with NameToFunc::name as null. You can cycle through the /// array with code like this: /// ///
///	for( ContactLdif::NameToFunc *n = o.GetFieldNames(); n->name; n++ ) {
///		...
///	}
/// 
/// /// Note that all Get/Set functions used in attribute mapping are virtual, /// and can be overridden by a derived class. This includes the heuristics /// functions, which are called by DumpLdif(). /// /// Note that the description field in NameToFunc is translatable. /// You can pass it to gettext() for a translated string. /// class BXEXPORT ContactLdif { public: typedef std::string (ContactLdif::*GetFunctionType)(const Barry::Contact&) const; typedef void (ContactLdif::*SetFunctionType)(Barry::Contact&, const std::string &) const; /// Used to create a List of supported Barry field names, including /// calculated names, such as full postal address. struct NameToFunc { const char *name; const char *description; GetFunctionType read; SetFunctionType write; }; struct LdifAttribute { std::string name; std::string objectClass; int order; LdifAttribute() : order(0) {} LdifAttribute(const char *name, const std::string &oc = "") : name(name), objectClass(oc), order(0) {} LdifAttribute(const std::string &name, const std::string &oc = "") : name(name), objectClass(oc), order(0) {} bool operator<(const LdifAttribute &other) const; bool operator==(const LdifAttribute &other) const; }; struct AccessPair { GetFunctionType read; SetFunctionType write; AccessPair() : read(0), write(0) {} AccessPair(GetFunctionType r, SetFunctionType w) : read(r), write(w) {} }; typedef std::map AccessMapType; typedef std::map HookMapType; protected: static const NameToFunc FieldMap[]; AccessMapType m_map; std::string m_baseDN; HookMapType m_hookMap; LdifAttribute m_dnAttr; void DoWrite(Barry::Contact &con, const std::string &attr, const std::string &data); // Array getter state mutable unsigned int m_emailIndex; // name heuristics std::string m_cn, m_displayName, m_sn, m_givenName; // heuristics hooking - saves each found value in the variable // pointed at by var void Hook(const std::string &ldifname, std::string *var); public: explicit ContactLdif(const std::string &baseDN); virtual ~ContactLdif(); const NameToFunc* GetFieldNames() const { return FieldMap; } const NameToFunc* GetField(const std::string &fieldname) const; std::string GetFieldReadName(GetFunctionType read) const; std::string GetFieldWriteName(SetFunctionType write) const; bool Map(const LdifAttribute &ldifname, const std::string &readField, const std::string &writeField); void Map(const LdifAttribute &ldifname, GetFunctionType read, SetFunctionType write); void Unmap(const LdifAttribute &ldifname); void SetBaseDN(const std::string &baseDN) { m_baseDN = baseDN; } bool SetDNAttr(const LdifAttribute &name); bool SetObjectClass(const LdifAttribute &name, const std::string &objectClass); bool SetObjectOrder(const LdifAttribute &name, int order); // // Access functions // virtual std::string Email(const Barry::Contact &con) const; virtual std::string Phone(const Barry::Contact &con) const; virtual std::string Fax(const Barry::Contact &con) const; virtual std::string WorkPhone(const Barry::Contact &con) const; virtual std::string HomePhone(const Barry::Contact &con) const; virtual std::string MobilePhone(const Barry::Contact &con) const; virtual std::string Pager(const Barry::Contact &con) const; virtual std::string PIN(const Barry::Contact &con) const; virtual std::string FirstName(const Barry::Contact &con) const; virtual std::string LastName(const Barry::Contact &con) const; virtual std::string Company(const Barry::Contact &con) const; virtual std::string DefaultCommunicationsMethod(const Barry::Contact &con) const; virtual std::string WorkAddress1(const Barry::Contact &con) const; virtual std::string WorkAddress2(const Barry::Contact &con) const; virtual std::string WorkAddress3(const Barry::Contact &con) const; virtual std::string WorkCity(const Barry::Contact &con) const; virtual std::string WorkProvince(const Barry::Contact &con) const; virtual std::string WorkPostalCode(const Barry::Contact &con) const; virtual std::string WorkCountry(const Barry::Contact &con) const; virtual std::string JobTitle(const Barry::Contact &con) const; virtual std::string PublicKey(const Barry::Contact &con) const; virtual std::string Notes(const Barry::Contact &con) const; virtual std::string Image(const Barry::Contact &con) const; // calculated values... virtual std::string WorkPostalAddress(const Barry::Contact &con) const; virtual std::string HomePostalAddress(const Barry::Contact &con) const; virtual std::string FullName(const Barry::Contact &con) const; virtual std::string FQDN(const Barry::Contact &con) const; // // Array modifier functions for above Access functions // virtual bool IsArrayFunc(GetFunctionType getf) const; void ClearArrayState() const; // // Write functions // virtual void SetEmail(Barry::Contact &con, const std::string &val) const; virtual void SetPhone(Barry::Contact &con, const std::string &val) const; virtual void SetFax(Barry::Contact &con, const std::string &val) const; virtual void SetWorkPhone(Barry::Contact &con, const std::string &val) const; virtual void SetHomePhone(Barry::Contact &con, const std::string &val) const; virtual void SetMobilePhone(Barry::Contact &con, const std::string &val) const; virtual void SetPager(Barry::Contact &con, const std::string &val) const; virtual void SetPIN(Barry::Contact &con, const std::string &val) const; virtual void SetFirstName(Barry::Contact &con, const std::string &val) const; virtual void SetLastName(Barry::Contact &con, const std::string &val) const; virtual void SetCompany(Barry::Contact &con, const std::string &val) const; virtual void SetDefaultCommunicationsMethod(Barry::Contact &con, const std::string &val) const; virtual void SetWorkAddress1(Barry::Contact &con, const std::string &val) const; virtual void SetWorkAddress2(Barry::Contact &con, const std::string &val) const; virtual void SetWorkAddress3(Barry::Contact &con, const std::string &val) const; virtual void SetWorkCity(Barry::Contact &con, const std::string &val) const; virtual void SetWorkProvince(Barry::Contact &con, const std::string &val) const; virtual void SetWorkPostalCode(Barry::Contact &con, const std::string &val) const; virtual void SetWorkCountry(Barry::Contact &con, const std::string &val) const; virtual void SetJobTitle(Barry::Contact &con, const std::string &val) const; virtual void SetPublicKey(Barry::Contact &con, const std::string &val) const; virtual void SetNotes(Barry::Contact &con, const std::string &val) const; virtual void SetImage(Barry::Contact &con, const std::string &val) const; virtual void SetWorkPostalAddress(Barry::Contact &con, const std::string &val) const; virtual void SetHomePostalAddress(Barry::Contact &con, const std::string &val) const; virtual void SetFullName(Barry::Contact &con, const std::string &val) const; virtual void SetFQDN(Barry::Contact &con, const std::string &val) const; // // Name heuristics // virtual void ClearHeuristics(); virtual bool RunHeuristics(Barry::Contact &con); // // Operations // void DumpLdif(std::ostream &os, const Barry::Contact &contact) const; bool ReadLdif(std::istream &is, Barry::Contact &contact); // returns true on success void DumpMap(std::ostream &os) const; static std::string MakeLdifData(const std::string &str); static bool NeedsEncoding(const std::string &str); }; BXEXPORT inline std::ostream& operator<< (std::ostream &os, const ContactLdif &ldif) { ldif.DumpMap(os); return os; } } // namespace Barry #endif barry-0.18.5/src/dp_codinfo.cc0000644001161500056700000003510512242254476015462 0ustar cdfreycdfrey/** * @file dp_codinfo.cc * @author Nicolas VIVIEN * @date 2009-08-01 * * @note CopyRight Nicolas VIVIEN * * @brief COD debug file parser * RIM's JDE generates several files when you build a COD application. * Indeed, with the COD files for the device, we have a ".debug" file. * This file is usefull to debug an application from JVM. * This tool is a parser to understand these ".debug" files. * * @par Modifications * - 2009/08/01 : N. VIVIEN * - First release * * @par Licences * Copyright (C) 2009-2010, Nicolas VIVIEN * * 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 in the COPYING file at the * root directory of this project for more details. */ #include "i18n.h" #include #include #include #include #include #include "dp_parser.h" #include "dp_codinfo.h" #include "ios_state.h" #include "debug.h" #define COD_DEBUG_APPNAME_HEADERFIELD 0x0 #define COD_DEBUG_UNIQUEID_HEADERFIELD 0x8 #define COD_DEBUG_NONE_FIELD 0x0 #define COD_DEBUG_BOOLEAN_FIELD 0x1 #define COD_DEBUG_BYTE_FIELD 0x2 #define COD_DEBUG_CHAR_FIELD 0x3 #define COD_DEBUG_SHORT_FIELD 0x4 #define COD_DEBUG_INT_FIELD 0x5 #define COD_DEBUG_LONG_FIELD 0x6 #define COD_DEBUG_CLASS_FIELD 0x7 #define COD_DEBUG_ARRAY_FIELD 0x8 #define COD_DEBUG_VOID_FIELD 0xA #define COD_DEBUG_DOUBLE_FIELD 0xC using namespace std; namespace Barry { namespace JDG { // Public API //------------ #define DEBUG_FILE_EXT ".debug" void SearchDebugFile(DebugFileList &list) { DIR *path; struct dirent *entry; path = opendir("."); while( (entry = readdir(path)) ) { int offset; if (strlen(entry->d_name) < strlen(DEBUG_FILE_EXT)) continue; offset = strlen(entry->d_name) - strlen(DEBUG_FILE_EXT); if (!strcmp(entry->d_name + offset, DEBUG_FILE_EXT)) { ifstream file(entry->d_name); CodInfo info; // Parse header section info.ParseHeaderSection(file); // Add element to list list.AddElement(info.GetUniqueId(), info.GetAppName(), entry->d_name); } } closedir(path); } bool LoadDebugInfo(const DebugFileList &list, const char *filename, CodInfo &info) { if (filename == NULL) return false; DebugFileList::const_iterator b = list.begin(); for( ; b != list.end(); b++ ) { const DebugFileEntry &entry = (*b); if( entry.fileName == filename ) { info.LoadDebugFile(filename); return true; } } return false; } bool LoadDebugInfo(const DebugFileList &list, const uint32_t uniqueId, const std::string module, CodInfo &info) { DebugFileList::const_iterator b = list.begin(); for( ; b != list.end(); b++ ) { const DebugFileEntry &entry = (*b); if ((entry.uniqueId == uniqueId) && (entry.appName == module)) { info.LoadDebugFile(entry.fileName.c_str()); return true; } } return false; } // DebugFileList class //------------------------ void DebugFileList::AddElement(uint32_t uniqueid, const std::string &appname, const std::string &filename) { DebugFileEntry entry; entry.uniqueId = uniqueid; entry.appName = appname; entry.fileName = filename; push_back(entry); } void DebugFileList::Dump(std::ostream &os) const { ios_format_state state(os); const_iterator i = begin(), e = end(); os << _(" UniqueID ") << "|"; os << _(" Module Name ") << "|"; os << _(" File Name ") << endl; os << "------------+"; os << "--------------------------+"; os << "--------------------------"; os << endl; for( ; i != e; ++i ) { (*i).Dump(os); } } void DebugFileEntry::Dump(std::ostream &os) const { ios_format_state state(os); os << " 0x" << setfill('0') << setw(8) << hex << uniqueId << " |"; os << " " << appName << setfill(' ') << setw(24) << " |"; os << " " << fileName << endl; } // ClassList class //--------------------------- void ClassList::CreateDefaultEntries() { ClassEntry entry; // 1 entry.classPath = "com.rim.resources"; entry.className = "net_rim_rimsecuridlibRIMResources"; push_back(entry); // 2 entry.classPath = "net.rim.device.cldc.impl.softtoken.rimsecuridlib"; entry.className = "RimSecurIDLib"; push_back(entry); // 3 entry.classPath = "net.rim.device.cldc.impl.softtoken.rimsecuridlib"; entry.className = "RimDatabaseFullException"; push_back(entry); // 4 entry.classPath = "net.rim.device.cldc.impl.softtoken.rimsecuridlib"; entry.className = "RimDecryptFailException"; push_back(entry); // 5 entry.classPath = "net.rim.device.cldc.impl.softtoken.rimsecuridlib"; entry.className = "RimDuplicateNameException"; push_back(entry); // 6 entry.classPath = "net.rim.device.cldc.impl.softtoken.rimsecuridlib"; entry.className = "RimDuplicateTokenException"; push_back(entry); // 7 entry.classPath = "net.rim.device.cldc.impl.softtoken.rimsecuridlib"; entry.className = "RimInvalidParamException"; push_back(entry); // 8 entry.classPath = "net.rim.device.cldc.impl.softtoken.rimsecuridlib"; entry.className = "RimSecurIDLib"; push_back(entry); // 9 entry.classPath = "net.rim.device.cldc.impl.softtoken.rimsecuridlib"; entry.className = "RimWrongDeviceIDException"; push_back(entry); // 10 entry.classPath = "net.rim.device.cldc.impl.softtoken.rimsecuridlib"; entry.className = "RimWrongFormFactorException"; push_back(entry); } // CodInfo class //------------------------ bool CodInfo::LoadDebugFile(const char *filename) { uint32_t field; if (filename == NULL) return false; ifstream file(filename); // Parse header file ParseHeaderSection(file); // Parse type area zone ParseTypeSection(file); // FIXME : ??? field = ParseInteger(file); // Read 0x0 field = ParseInteger(file); // Read 0x1 // FIXME : ??? field = ParseInteger(file); // Read 0x0 field = ParseInteger(file); // Read 0x0 or 0xA if (field == 0xA) { // Parse ressource area zone ParseResourceSection(file); } return true; } uint32_t CodInfo::GetUniqueId() { return uniqueId; } string CodInfo::GetAppName() { return appName; } // Private API - Section parsing //------------------------------- void CodInfo::ParseHeaderSection(istream &input) { uint32_t type; type = ParseNextHeaderField(input); if (type != COD_DEBUG_UNIQUEID_HEADERFIELD) return; type = ParseNextHeaderField(input); if (type != COD_DEBUG_APPNAME_HEADERFIELD) return; } void CodInfo::ParseTypeSection(istream &input) { uint32_t type; uint32_t count; uint32_t nbr, check; // Read number of declared type content into this section nbr = ParseInteger(input); // Read each object count = 0; while (!input.eof()) { type = ParseNextTypeField(input); if (type == COD_DEBUG_NONE_FIELD) break; count++; } // Read again number of declared type content into this section // We have to find the same value check = ParseInteger(input); // Checking... this code only exists in __DEBUG_MODE__ only, so // make sure unused variables are always "used" (void)nbr; (void)check; dout("Nbr = " << dec << nbr << " / Count = " << dec << count << " / check = " << check); } void CodInfo::ParseResourceSection(istream &input) { uint32_t len; uint32_t type; uint32_t unknown01; uint32_t unknown02; uint32_t unknown03; uint32_t unknown04; uint32_t unknown05; uint32_t unknown06; uint32_t unknown07; string name; // type = 1 for (int i=0; i<10; i++) { type = ParseInteger(input); len = ParseInteger(input); name = ParseString(input, len); unknown01 = ParseInteger(input); unknown02 = ParseInteger(input); unknown03 = ParseInteger(input); dout("JDGCodInfo::parseRessource" << "\n Name : " << name << "\n unknown01 : " << hex << unknown01 << "\n unknown02 : " << hex << unknown02 << "\n unknown03 : " << hex << unknown03); } // type = 2 type = ParseInteger(input); len = ParseInteger(input); name = ParseString(input, len); unknown01 = ParseInteger(input); unknown02 = ParseInteger(input); unknown03 = ParseInteger(input); unknown04 = ParseInteger(input); unknown05 = ParseInteger(input); unknown06 = ParseInteger(input); unknown07 = ParseInteger(input); dout("JDGCodInfo::parseRessource" << "\n Name : " << name << "\n unknown01 : " << hex << unknown01 << "\n unknown02 : " << hex << unknown02 << "\n unknown03 : " << hex << unknown03 << "\n unknown04 : " << hex << unknown04 << "\n unknown05 : " << hex << unknown05 << "\n unknown06 : " << hex << unknown06 << "\n unknown07 : " << hex << unknown07); // type = 1 type = ParseInteger(input); len = ParseInteger(input); name = ParseString(input, len); unknown01 = ParseInteger(input); unknown02 = ParseInteger(input); unknown03 = ParseInteger(input); unknown04 = ParseInteger(input); dout("JDGCodInfo::parseRessource" << "\n Name : " << name << "\n unknown01 : " << hex << unknown01 << "\n unknown02 : " << hex << unknown02 << "\n unknown03 : " << hex << unknown03 << "\n unknown04 : " << hex << unknown04); // type = 0 type = ParseInteger(input); len = ParseInteger(input); name = ParseString(input, len); unknown01 = ParseInteger(input); unknown02 = ParseInteger(input); unknown03 = ParseInteger(input); unknown04 = ParseInteger(input); unknown05 = ParseInteger(input); dout("JDGCodInfo::parseRessource" << "\n Name : " << name << "\n unknown01 : " << hex << unknown01 << "\n unknown02 : " << hex << unknown02 << "\n unknown03 : " << hex << unknown03 << "\n unknown04 : " << hex << unknown04 << "\n unknown05 : " << hex << unknown05); // make sure that unused variables are always "used" when // not in __DEBUG_MODE__ (void)type; (void)unknown01; (void)unknown02; (void)unknown03; (void)unknown04; (void)unknown05; (void)unknown06; (void)unknown07; } // Private API - Field parsing //------------------------------- uint32_t CodInfo::ParseNextHeaderField(istream &input) { uint32_t type = ParseInteger(input); switch (type) { case COD_DEBUG_UNIQUEID_HEADERFIELD: ParseUniqueId(input); break; case COD_DEBUG_APPNAME_HEADERFIELD: ParseAppName(input); break; default: type = 0xFFFFFFFF; } return type; } uint32_t CodInfo::ParseNextTypeField(istream &input) { uint32_t type = ParseInteger(input); switch (type) { case COD_DEBUG_NONE_FIELD: break; case COD_DEBUG_BOOLEAN_FIELD: ParseBoolean(input); break; case COD_DEBUG_BYTE_FIELD: ParseByte(input); break; case COD_DEBUG_CHAR_FIELD: ParseChar(input); break; case COD_DEBUG_SHORT_FIELD: ParseShort(input); break; case COD_DEBUG_INT_FIELD: ParseInt(input); break; case COD_DEBUG_LONG_FIELD: ParseLong(input); break; case COD_DEBUG_CLASS_FIELD: ParseClass(input); break; case COD_DEBUG_ARRAY_FIELD: ParseArray(input); break; case COD_DEBUG_VOID_FIELD: ParseVoid(input); break; case COD_DEBUG_DOUBLE_FIELD: ParseDouble(input); break; default: dout("Type unknown ! " << hex << type); type = 0xFFFFFFFF; } return type; } void CodInfo::ParseUniqueId(istream &input) { uniqueId = ParseInteger(input); } void CodInfo::ParseAppName(istream &input) { uint32_t len = ParseInteger(input); appName = ParseString(input, len); } void CodInfo::ParseBoolean(istream &input) { uint32_t len = ParseInteger(input); string str = ParseString(input, len); dout("JDG::CodInfo::ParseBoolean\n name : " << str); } void CodInfo::ParseByte(istream &input) { uint32_t len = ParseInteger(input); string str = ParseString(input, len); dout("JDG::CodInfo::ParseByte\n name : " << str); } void CodInfo::ParseChar(istream &input) { uint32_t len = ParseInteger(input); string str = ParseString(input, len); dout("JDG::CodInfo::ParseChar\n name : " << str); } void CodInfo::ParseShort(istream &input) { uint32_t len = ParseInteger(input); string str = ParseString(input, len); dout("JDG::CodInfo::ParseShort\n name : " << str); } void CodInfo::ParseInt(istream &input) { uint32_t len = ParseInteger(input); string str = ParseString(input, len); dout("JDG::CodInfo::ParseInt\n name : " << str); } void CodInfo::ParseLong(istream &input) { uint32_t len = ParseInteger(input); string str = ParseString(input, len); dout("JDG::CodInfo::ParseLong\n name : " << str); } void CodInfo::ParseClass(istream &input) { uint32_t len; ClassEntry object; dout("JDG::CodInfo::ParseClass"); len = ParseInteger(input); object.className = ParseString(input, len); object.type = ParseInteger(input); object.unknown02 = ParseInteger(input); object.unknown03 = ParseInteger(input); object.id = ParseInteger(input); len = ParseInteger(input); if (len == 0) object.classPath = "com.barry." + appName; else if (len != 0xFFFFFF) object.classPath = ParseString(input, len); len = ParseInteger(input); object.sourceFile = ParseString(input, len); object.unknown05 = ParseInteger(input); object.unknown06 = ParseInteger(input); object.unknown07 = ParseInteger(input); object.unknown08 = ParseInteger(input); classList.push_back(object); dout("\n name : " << object.className << "\n path : " << object.classPath << "\n type : " << hex << object.type << "\n unknown02 : " << hex << object.unknown02 << "\n unknown03 : " << hex << object.unknown03 << "\n id : " << hex << object.id << "\n source file : " << object.sourceFile << "\n unknown05 : " << hex << object.unknown05 << "\n unknown06 : " << hex << object.unknown06 << "\n unknown07 : " << hex << object.unknown07 << "\n unknown08 : " << hex << object.unknown08); } void CodInfo::ParseArray(istream &input) { uint32_t len = ParseInteger(input); string str = ParseString(input, len); dout("JDG::CodInfo::ParseArray\n name : " << str); } void CodInfo::ParseVoid(istream &input) { uint32_t len = ParseInteger(input); string str = ParseString(input, len); dout("JDG::CodInfo::ParseVoid\n name : " << str); } void CodInfo::ParseDouble(istream &input) { uint32_t len = ParseInteger(input); string str = ParseString(input, len); dout("JDG::CodInfo::ParseDouble\n name : " << str); } /* void CodInfo::ParseType2(istream &input) { uint32_t value; uint32_t len = ParseInteger(input); string str = ParseString(input, len); dout("Type2 : " << str); value = ParseInteger(input); value = ParseInteger(input); value = ParseInteger(input); value = ParseInteger(input); value = ParseInteger(input); value = ParseInteger(input); } */ } // namespace JDG } // namespace Barry barry-0.18.5/src/vcard.cc0000644001161500056700000003661112242254476014460 0ustar cdfreycdfrey/// /// \file vcard.cc /// Conversion routines for vcards /// /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "vcard.h" #include #include #include #include namespace Barry { namespace Sync { ////////////////////////////////////////////////////////////////////////////// // Utility functions namespace { void ToLower(std::string &str) { size_t i = 0; while( i < str.size() ) { str[i] = tolower(str[i]); i++; } } } ////////////////////////////////////////////////////////////////////////////// // vCard vCard::vCard() : m_gCardData(0) { } vCard::~vCard() { if( m_gCardData ) { g_free(m_gCardData); } } void vCard::AddAddress(const char *rfc_type, const Barry::PostalAddress &address) { // add label first vAttrPtr label = NewAttr("LABEL"); AddParam(label, "TYPE", rfc_type); AddValue(label, address.GetLabel().c_str()); AddAttr(label); // add breakout address form vAttrPtr adr = NewAttr("ADR"); // RFC 2426, 3.2.1 AddParam(adr, "TYPE", rfc_type); AddValue(adr, address.Address3.c_str()); // PO Box AddValue(adr, address.Address2.c_str()); // Extended address AddValue(adr, address.Address1.c_str()); // Street address AddValue(adr, address.City.c_str()); // Locality (city) AddValue(adr, address.Province.c_str()); // Region (province) AddValue(adr, address.PostalCode.c_str()); // Postal code AddValue(adr, address.Country.c_str()); // Country name AddAttr(adr); } /// Add phone conditionally, only if phone has data in it. This version /// does not add a TYPE parameter to the item. void vCard::AddPhoneCond(const std::string &phone) { if( phone.size() ) { vAttrPtr tel = NewAttr("TEL", phone.c_str()); AddAttr(tel); } } /// Add phone conditionally, only if phone has data in it void vCard::AddPhoneCond(const char *rfc_type, const std::string &phone) { if( phone.size() ) { vAttrPtr tel = NewAttr("TEL", phone.c_str()); AddParam(tel, "TYPE", rfc_type); AddAttr(tel); } } void vCard::ParseAddress(vAttr &adr, Barry::PostalAddress &address) { // RFC 2426, 3.2.1 address.Address3 = adr.GetValue(0); // PO Box address.Address2 = adr.GetValue(1); // Extended address address.Address1 = adr.GetValue(2); // Street address address.City = adr.GetValue(3); // Locality (city) address.Province = adr.GetValue(4); // Region (province) address.PostalCode = adr.GetValue(5); // Postal code address.Country = adr.GetValue(6); // Country name } void vCard::ParseCategories(vAttr &cat, Barry::CategoryList &cats) { int i = 0; std::string value = cat.GetValue(i); while( value.size() ) { cats.push_back(value); i++; value = cat.GetValue(i); } } // Main conversion routine for converting from Barry::Contact to // a vCard string of data. const std::string& vCard::ToVCard(const Barry::Contact &con) { // Trace trace("vCard::ToVCard"); std::ostringstream oss; con.Dump(oss); // trace.logf("ToVCard, initial Barry record: %s", oss.str().c_str()); // start fresh Clear(); SetFormat( b_vformat_new() ); if( !Format() ) throw ConvertError(_("resource error allocating vformat")); // store the Barry object we're working with m_BarryContact = con; // // begin building vCard data // AddAttr(NewAttr("PRODID", "-//OpenSync//NONSGML Barry Contact Record//EN")); std::string fullname = con.GetFullName(); if( fullname.size() ) { AddAttr(NewAttr("FN", fullname.c_str())); } else { // // RFC 2426, 3.1.1 states that FN MUST be present in the // vcard object. Unfortunately, the Blackberry doesn't // require a name, only a name or company name. // // In this case we do nothing, and generate an invalid // vcard, since if we try to fix our output here, we'll // likely end up with duplicated company names in the // Blackberry record after a few syncs. // } if( con.FirstName.size() || con.LastName.size() ) { vAttrPtr name = NewAttr("N"); // RFC 2426, 3.1.2 AddValue(name, con.LastName.c_str()); // Family Name AddValue(name, con.FirstName.c_str()); // Given Name AddValue(name, ""); // Additional Names AddValue(name, con.Prefix.c_str()); // Honorific Prefixes AddValue(name, ""); // Honorific Suffixes AddAttr(name); } if( con.Nickname.size() ) AddAttr(NewAttr("NICKNAME", con.Nickname.c_str())); if( con.WorkAddress.HasData() ) AddAddress("work", con.WorkAddress); if( con.HomeAddress.HasData() ) AddAddress("home", con.HomeAddress); // add all applicable phone numbers... there can be multiple // TEL fields, even with the same TYPE value... therefore, the // second TEL field with a TYPE=work, will be stored in WorkPhone2 AddPhoneCond("voice,pref", con.Phone); AddPhoneCond("fax", con.Fax); AddPhoneCond("voice,work", con.WorkPhone); AddPhoneCond("voice,work", con.WorkPhone2); AddPhoneCond("voice,home", con.HomePhone); AddPhoneCond("voice,home", con.HomePhone2); AddPhoneCond("msg,cell", con.MobilePhone); AddPhoneCond("msg,pager", con.Pager); AddPhoneCond("voice", con.OtherPhone); // add all email addresses, marking first one as "pref" Barry::Contact::EmailList::const_iterator eai = con.EmailAddresses.begin(); for( unsigned int i = 0; eai != con.EmailAddresses.end(); ++eai, ++i ) { const std::string& e = con.GetEmail(i); if( e.size() ) { vAttrPtr email = NewAttr("EMAIL", e.c_str()); if( i == 0 ) { AddParam(email, "TYPE", "internet,pref"); } else { AddParam(email, "TYPE", "internet"); } AddAttr(email); } } if( con.JobTitle.size() ) { AddAttr(NewAttr("TITLE", con.JobTitle.c_str())); AddAttr(NewAttr("ROLE", con.JobTitle.c_str())); } if( con.Company.size() ) { // RFC 2426, 3.5.5 vAttrPtr org = NewAttr("ORG", con.Company.c_str()); // Organization name AddValue(org, ""); // Division name AddAttr(org); } if( con.Birthday.HasData() ) AddAttr(NewAttr("BDAY", con.Birthday.ToYYYYMMDD().c_str())); if( con.Notes.size() ) AddAttr(NewAttr("NOTE", con.Notes.c_str())); if( con.URL.size() ) AddAttr(NewAttr("URL", con.URL.c_str())); if( con.Categories.size() ) AddCategories(con.Categories); // Image / Photo if (con.Image.size()) { vAttrPtr photo = NewAttr("PHOTO"); AddEncodedValue(photo, VF_ENCODING_BASE64, con.Image.c_str(), con.Image.size()); AddParam(photo, "ENCODING", "BASE64"); AddAttr(photo); } // generate the raw VCARD data m_gCardData = b_vformat_to_string(Format(), VFORMAT_CARD_30); m_vCardData = m_gCardData; // trace.logf("ToVCard, resulting vcard data: %s", m_vCardData.c_str()); return m_vCardData; } // // NOTE: // Treat the following pairs of variables like // sliding buffers, where higher priority values // can push existings values from 1 to 2, or from // 2 to oblivion: // // HomePhone + HomePhone2 // WorkPhone + WorkPhone2 // Phone + OtherPhone // // // class SlidingPair // // This class handles the sliding pair logic for a pair of std::strings. // class SlidingPair { std::string &m_first; std::string &m_second; int m_evolutionSlot1, m_evolutionSlot2; public: static const int DefaultSlot = 99; SlidingPair(std::string &first, std::string &second) : m_first(first) , m_second(second) , m_evolutionSlot1(DefaultSlot) , m_evolutionSlot2(DefaultSlot) { } bool assign(const std::string &value, const char *type_str, int evolutionSlot) { bool used = false; if( strstr(type_str, "pref") || evolutionSlot < m_evolutionSlot1 ) { m_second = m_first; m_evolutionSlot2 = m_evolutionSlot1; m_first = value; m_evolutionSlot1 = evolutionSlot; used = true; } else if( evolutionSlot < m_evolutionSlot2 ) { m_second = value; m_evolutionSlot2 = evolutionSlot; used = true; } else if( m_first.size() == 0 ) { m_first = value; m_evolutionSlot1 = evolutionSlot; used = true; } else if( m_second.size() == 0 ) { m_second = value; m_evolutionSlot2 = evolutionSlot; used = true; } return used; } }; // Main conversion routine for converting from vCard data string // to a Barry::Contact object. const Barry::Contact& vCard::ToBarry(const char *vcard, uint32_t RecordId) { using namespace std; // Trace trace("vCard::ToBarry"); // trace.logf("ToBarry, working on vcard data: %s", vcard); // start fresh Clear(); // store the vCard raw data m_vCardData = vcard; // create format parser structures SetFormat( b_vformat_new_from_string(vcard) ); if( !Format() ) throw ConvertError(_("resource error allocating vformat")); // // Parse the vcard data // Barry::Contact &con = m_BarryContact; con.SetIds(Barry::Contact::GetDefaultRecType(), RecordId); vAttr name = GetAttrObj("N"); if( name.Get() ) { // RFC 2426, 3.1.2 con.LastName = name.GetValue(0); // Family Name con.FirstName = name.GetValue(1); // Given Name con.Prefix = name.GetValue(3); // Honorific Prefixes } con.Nickname = GetAttr("NICKNAME"); vAttr adr = GetAttrObj("ADR"); for( int i = 0; adr.Get(); adr = GetAttrObj("ADR", ++i) ) { std::string type = adr.GetAllParams("TYPE"); ToLower(type); // do not use "else" here, since TYPE can have multiple keys if( strstr(type.c_str(), "work") ) ParseAddress(adr, con.WorkAddress); if( strstr(type.c_str(), "home") ) ParseAddress(adr, con.HomeAddress); } // // NOTE: // Treat the following pairs of variables like // sliding buffers, where higher priority values // can push existings values from 1 to 2, or from // 2 to oblivion: // // HomePhone + HomePhone2 // WorkPhone + WorkPhone2 // Phone + OtherPhone // SlidingPair HomePair(con.HomePhone, con.HomePhone2); SlidingPair WorkPair(con.WorkPhone, con.WorkPhone2); SlidingPair OtherPair(con.Phone, con.OtherPhone); // add all applicable phone numbers... there can be multiple // TEL fields, even with the same TYPE value... therefore, the // second TEL field with a TYPE=work, will be stored in WorkPhone2 vAttr tel = GetAttrObj("TEL"); for( int i = 0; tel.Get(); tel = GetAttrObj("TEL", ++i) ) { // grab all parameter values for this param name std::string stype = tel.GetAllParams("TYPE"); // grab evolution-specific parameter... evolution is too // lazy to sort its VCARD output, but instead it does // its own non-standard tagging... so we try to // accommodate it, so Work and Home phone numbers keep // their order if possible int evolutionSlot = atoi(tel.GetAllParams("X-EVOLUTION-UI-SLOT").c_str()); if( evolutionSlot == 0 ) evolutionSlot = SlidingPair::DefaultSlot; // turn to lower case for comparison // FIXME - is this i18n safe? ToLower(stype); // state const char *type = stype.c_str(); bool used = false; // Check for possible TYPE conflicts: // pager can coexist with cell/pcs/car // fax conflicts with cell/pcs/car // fax conflicts with pager bool mobile_type = strstr(type, "cell") || strstr(type, "pcs") || strstr(type, "car"); bool fax_type = strstr(type, "fax"); bool pager_type = strstr(type, "pager"); if( fax_type && (mobile_type || pager_type) ) { // conflict found, log and skip // trace.logf("ToBarry: skipping phone number due to TYPE conflict: fax cannot coexist with %s: %s", // mobile_type ? "cell/pcs/car" : "pager", // type); continue; } // If phone number has the "pref" flag if( strstr(type, "pref") ) { // Always use cell phone if the "pref" flag is set if( strstr(type, "cell") ) { used = OtherPair.assign(tel.GetValue(), type, evolutionSlot); } // Otherwise, the phone has to be "voice" type else if( strstr(type, "voice") && con.Phone.size() == 0 ) { used = OtherPair.assign(tel.GetValue(), type, evolutionSlot); } } // For each known phone type // Fax : if( strstr(type, "fax") && (strstr(type, "pref") || con.Fax.size() == 0) ) { con.Fax = tel.GetValue(); used = true; } // Mobile phone : else if( mobile_type && (strstr(type, "pref") || con.MobilePhone.size() == 0) ) { con.MobilePhone = tel.GetValue(); used = true; } // Pager : else if( strstr(type, "pager") && (strstr(type, "pref") || con.Pager.size() == 0) ) { con.Pager = tel.GetValue(); used = true; } // Check for any TEL-ignore types, and use other phone field if possible // bbs/video/modem entire TEL ignored by Barry // isdn entire TEL ignored by Barry else if( strstr(type, "bbs") || strstr(type, "video") || strstr(type, "modem") ) { } else if( strstr(type, "isdn") ) { } // Voice telephone : else { if( strstr(type, "work") ) { used = WorkPair.assign(tel.GetValue(), type, evolutionSlot); } if( strstr(type, "home") ) { used = HomePair.assign(tel.GetValue(), type, evolutionSlot); } } // if this value has not been claimed by any of the // cases above, claim it now as "OtherPhone" if( !used && con.OtherPhone.size() == 0 ) { OtherPair.assign(tel.GetValue(), type, evolutionSlot); } } // scan for all email addresses... append addresses to the // list by default, but prepend if its type is set to "pref" // i.e. we want the preferred email address first vAttr email = GetAttrObj("EMAIL"); for( int i = 0; email.Get(); email = GetAttrObj("EMAIL", ++i) ) { std::string type = email.GetAllParams("TYPE"); ToLower(type); bool of_interest = (i == 0 || strstr(type.c_str(), "pref")); bool x400 = strstr(type.c_str(), "x400"); if( of_interest && !x400 ) { con.EmailAddresses.insert(con.EmailAddresses.begin(), email.GetValue()); } else { con.EmailAddresses.push_back( email.GetValue() ); } } // figure out which company title we want to keep... // favour the TITLE field, but if it's empty, use ROLE con.JobTitle = GetAttr("TITLE"); if( !con.JobTitle.size() ) con.JobTitle = GetAttr("ROLE"); con.Company = GetAttr("ORG"); con.Notes = GetAttr("NOTE"); con.URL = GetAttr("URL"); if( GetAttr("BDAY").size() && !con.Birthday.FromYYYYMMDD( GetAttr("BDAY") ) ) throw ConvertError(_("Unable to parse BDAY field")); // Photo vCard ? vAttr photo = GetAttrObj("PHOTO"); if (photo.Get()) { std::string sencoding = photo.GetAllParams("ENCODING"); ToLower(sencoding); const char *encoding = sencoding.c_str(); if (strstr(encoding, "quoted-printable")) { photo.Get()->encoding = VF_ENCODING_QP; con.Image = photo.GetDecodedValue(); } else if (strstr(encoding, "b")) { photo.Get()->encoding = VF_ENCODING_BASE64; con.Image = photo.GetDecodedValue(); } // Else // We ignore the photo, I don't know decoded ! } vAttr cat = GetAttrObj("CATEGORIES"); if( cat.Get() ) ParseCategories(cat, con.Categories); // Last sanity check: Blackberry requires that at least // name or Company has data. if( !con.GetFullName().size() && !con.Company.size() ) throw ConvertError(_("FN and ORG fields both blank in VCARD data")); return m_BarryContact; } // Transfers ownership of m_gCardData to the caller. char* vCard::ExtractVCard() { char *ret = m_gCardData; m_gCardData = 0; return ret; } void vCard::Clear() { vBase::Clear(); m_vCardData.clear(); m_BarryContact.Clear(); if( m_gCardData ) { g_free(m_gCardData); m_gCardData = 0; } } }} // namespace Barry::Sync barry-0.18.5/src/protocol.h0000644001161500056700000001600612242254476015060 0ustar cdfreycdfrey/// /// \file protocol.h /// USB Blackberry bulk protocol API constants /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_PROTOCOL_H__ #define __BARRY_PROTOCOL_H__ // packet commands (Packet.command: has response codes too) #define SB_COMMAND_ECHO 0x01 #define SB_COMMAND_ECHO_REPLY 0x02 #define SB_COMMAND_RESET 0x03 #define SB_COMMAND_RESET_REPLY 0x04 #define SB_COMMAND_FETCH_ATTRIBUTE 0x05 #define SB_COMMAND_FETCHED_ATTRIBUTE 0x06 #define SB_COMMAND_SELECT_MODE 0x07 #define SB_COMMAND_MODE_SELECTED 0x08 #define SB_COMMAND_MODE_NOT_SELECTED 0x09 #define SB_COMMAND_OPEN_SOCKET 0x0a #define SB_COMMAND_CLOSE_SOCKET 0x0b #define SB_COMMAND_CLOSED_SOCKET 0x0c #define SB_COMMAND_REMOTE_CLOSE_SOCKET 0x0d #define SB_COMMAND_PASSWORD_CHALLENGE 0x0e #define SB_COMMAND_PASSWORD 0x0f #define SB_COMMAND_OPENED_SOCKET 0x10 #define SB_COMMAND_PASSWORD_FAILED 0x11 #define SB_COMMAND_SEQUENCE_HANDSHAKE 0x13 #define SB_COMMAND_DB_DATA 0x40 #define SB_COMMAND_DB_FRAGMENTED 0x60 #define SB_COMMAND_DB_DONE 0x41 // JavaLoader commands #define SB_COMMAND_JL_HELLO 0x64 // This could be a general ACK in both directions #define SB_COMMAND_JL_HELLO_ACK 0x65 // From device after host HELLO #define SB_COMMAND_JL_GOODBYE 0x8d #define SB_COMMAND_JL_SET_UNKNOWN1 0x70 // Initial sequence, 0 #define SB_COMMAND_JL_SET_COD_FILENAME 0x80 #define SB_COMMAND_JL_SET_COD_SIZE 0x67 // Always big endian #define SB_COMMAND_JL_SEND_DATA 0x68 #define SB_COMMAND_JL_SET_TIME 0x7c #define SB_COMMAND_JL_GET_SCREENSHOT 0x87 #define SB_COMMAND_JL_DEVICE_INFO 0x71 #define SB_COMMAND_JL_OS_METRICS 0x78 #define SB_COMMAND_JL_BOOTROM_METRICS 0x79 #define SB_COMMAND_JL_GET_DIRECTORY 0x6d #define SB_COMMAND_JL_GET_DATA_ENTRY 0x6e // Used for both DIR and SCREENSHOT #define SB_COMMAND_JL_GET_SUBDIR 0x7f #define SB_COMMAND_JL_GET_SUBDIR_ENTRY 0x7d #define SB_COMMAND_JL_ERASE 0x69 #define SB_COMMAND_JL_FORCE_ERASE 0x7b #define SB_COMMAND_JL_UNKNOWN3 0x63 #define SB_COMMAND_JL_GET_LOG 0x73 #define SB_COMMAND_JL_GET_LOG_ENTRY 0x74 #define SB_COMMAND_JL_CLEAR_LOG 0x88 #define SB_COMMAND_JL_SAVE_MODULE 0x7e #define SB_COMMAND_JL_WIPE_APPS 0x6a #define SB_COMMAND_JL_WIPE_FS 0x6b #define SB_COMMAND_JL_LOG_STRACES 0x8e #define SB_COMMAND_JL_RESET_FACTORY 0x91 // JavaLoader response #define SB_COMMAND_JL_ACK 0x64 #define SB_COMMAND_JL_READY 0x01 #define SB_COMMAND_JL_RESET_REQUIRED 0x78 // Occurs after GOODBYE when handheld reset is required #define SB_COMMAND_JL_COD_IN_USE 0x6c // Perhaps "BUSY" is also a good name? #define SB_COMMAND_JL_COD_NOT_FOUND 0x69 #define SB_COMMAND_JL_NOT_ENOUGH_MEMORY 0x6a // Occurs when the internal memory isn't enough to install the new COD file #define SB_COMMAND_JL_NOT_SUPPORTED 0x71 // Occurs when device does not support a command // JavaLoader data #define SB_DATA_JL_SUCCESS 0x64 // Device has accepted the data packet #define SB_DATA_JL_INVALID 0x68 // Device returns this code if the application isn't valid. // JDWP Command set list #define JDWP_CMDSET_VIRTUALMACHINE 1 #define JDWP_CMDSET_REFERECENTYPE 2 #define JDWP_CMDSET_CLASSTYPE 3 #define JDWP_CMDSET_ARRAYTYPE 4 #define JDWP_CMDSET_INTERFACETYPE 5 #define JDWP_CMDSET_METHOD 6 #define JDWP_CMDSET_FIELD 8 #define JDWP_CMDSET_OBJECTREFERENCE 9 #define JDWP_CMDSET_STRINGREFERENCE 10 #define JDWP_CMDSET_THREADREFERENCE 11 #define JDWP_CMDSET_THREADGROUPREFERENCE 12 #define JDWP_CMDSET_ARRAYREFERENCE 13 #define JDWP_CMDSET_CLASSLOADERREFERENCE 14 #define JDWP_CMDSET_EVENTREQUEST 15 #define JDWP_CMDSET_STACKFRAME 16 #define JDWP_CMDSET_CLASSOBJECTREFERENCE 17 #define JDWP_CMDSET_EVENT 64 // JDWP Command list - VirtualMachine #define JDWP_CMD_VERSION 1 #define JDWP_CMD_ALLCLASSES 3 #define JDWP_CMD_ALLTHREADS 4 #define JDWP_CMD_DISPOSE 6 #define JDWP_CMD_IDSIZES 7 #define JDWP_CMD_SUSPEND 8 #define JDWP_CMD_RESUME 9 #define JDWP_CMD_CLASSPATHS 13 // JDWP Command list - EventRequest #define JDWP_CMD_SET 1 // JVMDebug commands #define SB_COMMAND_JVM_UNKNOWN01 0x53 #define SB_COMMAND_JVM_UNKNOWN02 0x01 #define SB_COMMAND_JVM_UNKNOWN03 0x6f #define SB_COMMAND_JVM_UNKNOWN04 0x8a #define SB_COMMAND_JVM_UNKNOWN05 0x90 #define SB_COMMAND_JVM_UNKNOWN06 0x44 #define SB_COMMAND_JVM_UNKNOWN07 0x45 #define SB_COMMAND_JVM_UNKNOWN08 0x54 #define SB_COMMAND_JVM_UNKNOWN09 0x33 #define SB_COMMAND_JVM_UNKNOWN10 0x46 #define SB_COMMAND_JVM_UNKNOWN11 0x0e #define SB_COMMAND_JVM_UNKNOWN12 0x50 #define SB_COMMAND_JVM_UNKNOWN13 0x0d #define SB_COMMAND_JVM_UNKNOWN14 0x85 #define SB_COMMAND_JVM_UNKNOWN15 0x84 #define SB_COMMAND_JVM_GET_MODULES_LIST 0x8d // Get all Java modules list with their address and ID #define SB_COMMAND_JVM_GET_THREADS_LIST 0x08 // Get all threads currently running in the virtual machine #define SB_COMMAND_JVM_GET_CONSOLE_MSG 0x40 // Get console message #define SB_COMMAND_JVM_GO 0x02 // Go #define SB_COMMAND_JVM_GET_STATUS 0x06 // Get status #define SB_COMMAND_JVM_SET_BREAKPOINT 0x21 // Set breakpoint #define SB_COMMAND_JVM_RM_BREAKPOINT 0x22 // Remove breakpoint #define SB_COMMAND_JVM_STOP 0xa502 // JavaDebug response #define SB_COMMAND_JVM_GET_DATA_ENTRY 0x06 // mode constants #define SB_MODE_REQUEST_SOCKET 0x00ff // object and attribute ID codes (for ZeroPacket::GetAttribute()) // meanings for most of these are unknown #define SB_OBJECT_INITIAL_UNKNOWN 0x14 #define SB_ATTR_INITIAL_UNKNOWN 0x01 #define SB_OBJECT_PROFILE 0x08 #define SB_ATTR_PROFILE_DESC 0x02 #define SB_ATTR_PROFILE_PIN 0x04 #define SB_OBJECT_SOCKET_UNKNOWN 0x04 // param command parameters //#define SB_PARAM_DEFAULT 0xff // DB Operation Command #define SB_DBOP_ADD_RECORD 0x41 #define SB_DBOP_CLEAR_DATABASE 0x43 #define SB_DBOP_GET_DBDB 0x4a #define SB_DBOP_OLD_GET_DBDB 0x4c #define SB_DBOP_GET_COUNT 0x4e #define SB_DBOP_GET_RECORDS 0x4f #define SB_DBOP_OLD_GET_RECORDS 0x42 #define SB_DBOP_OLD_GET_RECORDS_REPLY 0x44 #define SB_DBOP_GET_RECORD_STATE_TABLE 0x53 // replies with 0x60, 0x41 #define SB_DBOP_SET_RECORD_FLAGS 0x54 // replies with 0x41 // used to clear dirty flag #define SB_DBOP_GET_RECORD_BY_INDEX 0x46 // replies with 0x44 // John's device uses 0x50, with a reply of 0x4f (!) // Then uses 0x55 as usual // Delete uses 0x50/0x4f to check as well, then uses 0x52 as // usual to do the actual delete. #define SB_DBOP_SET_RECORD_BY_INDEX 0x55 // replies with 0x41 #define SB_DBOP_DELETE_RECORD_BY_INDEX 0x52 // intellisync does a GET(0x46) // first, probably to make sure // it has the right data and // record #endif barry-0.18.5/src/fifoargs.h0000644001161500056700000000512412242254476015016 0ustar cdfreycdfrey/// /// \file fifoargs.h /// Class for passing command line arguments via fifo instead /// of command line. /// /* Copyright (C) 2012-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_FIFOARGS_H__ #define __BARRY_FIFOARGS_H__ #include "dll.h" #include "pin.h" #include namespace Barry { // // FifoArgs // /// Contains argument variables to be passed through the FIFO. /// It is no coincidence that there is a close connection to this /// set of arguments and the arguments given to the pppob program. /// struct BXEXPORT FifoArgs { Pin m_pin; std::string m_password; std::string m_log_filename; bool m_use_serial_mode; bool m_verbose; FifoArgs() : m_use_serial_mode(false) , m_verbose(false) { } std::ostream& Write(std::ostream &os) const; std::istream& Read(std::istream &is); void Clear(); }; // // FifoServer // /// Accepts a FifoArgs struct, and creates the necessary fifo for transfer. /// To use, create the object, then execute the program (eg. pppob), and /// then call Serve() with a given timeout in seconds. /// /// This class deletes the fifo in the destructor, or explicitly, with /// the Cleanup() call. /// /// Only arguments that are valid are sent. /// class BXEXPORT FifoServer { const FifoArgs &m_args; bool m_created; public: explicit FifoServer(const FifoArgs &args); ~FifoServer(); /// Serves the given arguments through the fifo. Returns /// false on timeout. bool Serve(int timeout_sec); /// Deletes the fifo. Called automatically by destructor. void Cleanup(); }; // // FifoClient // /// Searches for a fifo and opens and reads it if available. Use /// Fetch() with a given timeout to perform the read attempt. /// Use GetArgs() to access the filled FifoArgs struct. /// class BXEXPORT FifoClient { FifoArgs m_args; public: FifoClient(); /// Tries to open the fifo and read the arguments from it. /// If it fails in any way, or timeout, returns false. bool Fetch(int timeout_sec); const FifoArgs& GetArgs() const { return m_args; } }; } // Barry namespace #endif barry-0.18.5/src/a_alxparser.cc0000644001161500056700000001527112242254476015661 0ustar cdfreycdfrey/// /// \file a_alxparser.cc /// ALX file parser (for one file) /// /* Copyright (C) 2010, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include #include #include #include "a_alxparser.h" namespace Barry { namespace ALX { ALXParser::ALXParser(OSLoader& osloader, std::istream& input) : XML::XMLParser(input, "ISO-8859-1") , osloader(osloader) { node = MAIN_NONE; subnode = SUB_NONE; m_register = true; } ALXParser::~ALXParser(void) { } bool ALXParser::Run(const bool enable) { m_register = enable; return XMLParser::Run(); } void ALXParser::on_start_document() { // std::cout << "on_start_document()" << std::endl; } void ALXParser::on_end_document() { // std::cout << "on_end_document()" << std::endl; } void ALXParser::on_start_element(const Glib::ustring& name, const xmlpp::SaxParser::AttributeList& attrs) { depth++; buffdata = ""; switch (node) { case MAIN_NONE: if (name == "loader") node = IN_LOADER; // else // exit(-1); break; case IN_LOADER: subnode = SUB_NONE; if (name == "system") { node = IN_SYSTEM; } else if (name == "application") { node = IN_APPLICATION; m_codsection.reset( new Application(attrs) ); } else if (name == "library") { node = IN_LIBRARY; m_codsection.reset( new Library(attrs) ); } break; case IN_SYSTEM: if (name == "directory") subnode = IN_DIRECTORY; else if (name == "osfiles") { subnode = IN_OSFILES; } else if (name == "application") { node = IN_SYSTEM_APPLICATION; subnode = SUB_NONE; m_codsection.reset( new Application(attrs) ); } else if (name == "library") { node = IN_SYSTEM_LIBRARY; subnode = SUB_NONE; m_codsection.reset( new Application(attrs) ); } else if ((subnode == IN_OSFILES) && (name == "os")) osloader.AddProperties(attrs); break; case IN_LIBRARY: case IN_APPLICATION: case IN_APPLICATION_APPLICATION: case IN_SYSTEM_APPLICATION: case IN_SYSTEM_LIBRARY: if (subnode == SUB_NONE) { if ((node == IN_APPLICATION) && (name == "application")) { node = IN_APPLICATION_APPLICATION; m_savecodsection = m_codsection; m_codsection.reset( new Application(attrs) ); } else if (name == "name") subnode = IN_NAME; else if (name == "description") subnode = IN_DESCRIPTION; else if (name == "version") subnode = IN_VERSION; else if (name == "vendor") subnode = IN_VENDOR; else if (name == "copyright") subnode = IN_COPYRIGHT; else if (name == "directory") { if (osloader.IsSupported(attrs)) subnode = IN_DIRECTORY; } else if (name == "language") { if (osloader.IsSupported(attrs)) subnode = IN_LANGUAGE_SUPPORTED; else subnode = IN_LANGUAGE; } else if (name == "required") subnode = IN_REQUIRED; else if (name == "fileset") { if (osloader.IsSupported(attrs)) subnode = IN_FILESET; } } break; default: break; } } void ALXParser::on_end_element(const Glib::ustring& name) { depth--; switch (node) { case MAIN_NONE: // exit(-1); break; case IN_LOADER: if (name == "loader") node = MAIN_NONE; break; case IN_SYSTEM: if (name == "system") { subnode = SUB_NONE; node = IN_LOADER; } switch (subnode) { case IN_DIRECTORY: if (name == "directory") subnode = SUB_NONE; break; case IN_OSFILES: if (name == "osfiles") subnode = SUB_NONE; else if (name == "os") osloader.SetSFIFile(buffdata); break; default: break; } break; case IN_LIBRARY: case IN_APPLICATION: case IN_APPLICATION_APPLICATION: case IN_SYSTEM_APPLICATION: case IN_SYSTEM_LIBRARY: if (name == "application") { if (m_register) osloader.AddApplication(m_codsection); subnode = SUB_NONE; if (node == IN_APPLICATION) node = IN_LOADER; else if (node == IN_SYSTEM_APPLICATION) node = IN_SYSTEM; else if (node == IN_APPLICATION_APPLICATION) { node = IN_APPLICATION; m_codsection = m_savecodsection; } } else if (name == "library") { if (m_register) osloader.AddLibrary(m_codsection); subnode = SUB_NONE; if (node == IN_LIBRARY) node = IN_LOADER; else if (node == IN_SYSTEM_LIBRARY) node = IN_SYSTEM; } switch (subnode) { case IN_NAME: if (name == "name") { m_codsection->SetName(buffdata); subnode = SUB_NONE; } break; case IN_DESCRIPTION: if (name == "description") { m_codsection->SetDescription(buffdata); subnode = SUB_NONE; } break; case IN_VERSION: if (name == "version") { m_codsection->SetVersion(buffdata); subnode = SUB_NONE; } break; case IN_VENDOR: if (name == "vendor") { m_codsection->SetVendor(buffdata); subnode = SUB_NONE; } break; case IN_COPYRIGHT: if (name == "copyright") { m_codsection->SetCopyright(buffdata); subnode = SUB_NONE; } break; case IN_DIRECTORY: if (name == "directory") { m_codsection->SetDirectory(buffdata); subnode = SUB_NONE; } break; case IN_LANGUAGE: if (name == "language") { subnode = SUB_NONE; } break; case IN_LANGUAGE_SUPPORTED: if (name == "language") { subnode = SUB_NONE; } else if (name == "name") { m_codsection->SetName(buffdata); } break; case IN_REQUIRED: if (name == "required") { subnode = SUB_NONE; m_codsection->SetRequired(buffdata); } break; case IN_FILESET: if (name == "fileset") { subnode = SUB_NONE; } else if (name == "files") { m_codsection->AddFiles(buffdata); } break; default: break; } break; default: break; } } void ALXParser::on_characters(const Glib::ustring& data) { buffdata.append(data); } void ALXParser::on_comment(const Glib::ustring& text) { // std::cout << "on_comment(): " << text << std::endl; } void ALXParser::on_warning(const Glib::ustring& text) { // std::cout << "on_warning(): " << text << std::endl; } void ALXParser::on_error(const Glib::ustring& text) { // std::cout << "on_error(): " << text << std::endl; } void ALXParser::on_fatal_error(const Glib::ustring& text) { std::cout << "on_fatal_error(): " << text << std::endl; } } // namespace ALX } // namespace Barry barry-0.18.5/src/connector.cc0000644001161500056700000001405312242254476015347 0ustar cdfreycdfrey/// /// \file connector.cc /// Base class interface for handling Mode connections to device /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "connector.h" #include "router.h" #include "controller.h" #include "m_desktop.h" #include "debug.h" #include using namespace std; using namespace Barry; namespace Barry { ////////////////////////////////////////////////////////////////////////////// // Connector base class // we use a const char *password here because we don't want the // responsibility of clear its memory... that's the application's job Connector::Connector(const char *password, const std::string &locale, Barry::Pin pin) : m_password(password) , m_needs_reconnect(false) , m_ic(locale.c_str()) , m_probe_result(FindDevice(pin)) , m_connect_count(0) , m_last_disconnect(0) , m_bpcopy("", 0, 0) { } Connector::Connector(const char *password, const std::string &locale, const Barry::ProbeResult &result) : m_password(password) , m_needs_reconnect(false) , m_ic(locale.c_str()) , m_probe_result(result) , m_connect_count(0) , m_last_disconnect(0) , m_bpcopy("", 0, 0) { } Connector::~Connector() { } Barry::ProbeResult Connector::FindDevice(Barry::Pin pin) { Barry::Probe probe; int i = probe.FindActive(pin); if( i != -1 ) return probe.Get(i); else throw Barry::PinNotFound(pin, probe.GetCount()); } void Connector::ClearPassword() { // blank the memory first size_t len = m_password.size(); while( len ) { len--; m_password[len] = '0'; } // free it m_password.clear(); } void Connector::SetPassword(const char *password) { ClearPassword(); m_password = password; } bool Connector::Connect() { Disconnect(); bool started = false; for(;;) { try { if( !started ) { started = true; StartConnect(m_password.c_str()); } else { RetryPassword(m_password.c_str()); } FinishConnect(); m_connect_count++; return true; } catch( BadPassword &bp ) { if( bp.out_of_tries() ) { throw; } m_bpcopy = bp; // fall through to password prompt } // ask user for device password ClearPassword(); if( !PasswordPrompt(m_bpcopy, m_password) ) { // user wants out return false; } } } void Connector::Disconnect() { m_needs_reconnect = false; if( !IsDisconnected() ) { DoDisconnect(); m_last_disconnect = time(NULL); } } bool Connector::Reconnect(int total_tries) { int tries = 0; while(1) try { tries++; Disconnect(); if( m_connect_count ) { // let the device settle... this seems to help prevent // the firmware hang, and therefore ultimately speeds // up the sync if( (time(NULL) - m_last_disconnect) < 2 ) { // don't bother sleeping if 2 seconds have // already passed sleep(1); } // temporary fix for odd reconnect message... // without this probe, the reconnect will often fail on // newer Blackberries due to an unexpected close socket // message. // // It is unclear if this is really a message from // the device, but until then, we add this probe. m_probe_result = FindDevice(m_probe_result.m_pin); } return Connect(); } catch( Usb::Timeout & ) { if( tries >= total_tries ) { throw; } else { dout(_("Timeout in Connector::Reconnect()... trying again")); } } } bool Connector::ReconnectForDirtyFlags() { if( m_needs_reconnect ) { return Reconnect(); } else { return true; } } void Connector::RequireDirtyReconnect() { m_needs_reconnect = true; } ////////////////////////////////////////////////////////////////////////////// // DesktopConnector class DesktopConnector::DesktopConnector(const char *password, const std::string &locale, Barry::Pin pin, Barry::SocketRoutingQueue *router, int connect_timeout) : Connector(password, locale, pin) , m_router(router) , m_connect_timeout(connect_timeout) { } DesktopConnector::DesktopConnector(const char *password, const std::string &locale, const Barry::ProbeResult &result, Barry::SocketRoutingQueue *router, int connect_timeout) : Connector(password, locale, result) , m_router(router) , m_connect_timeout(connect_timeout) { } void DesktopConnector::StartConnect(const char *password) { // Note that there is a firmware issue that causes the firmware // to sometimes hang during a connect and it fails to respond // to a Desktop::Open() call. To work around this, set the // timeout to something lower than the usual 30 seconds. // The default in DesktopConnector is 10 seconds, which should // be fine. // // If this bug triggers, a Timeout exception will be thrown, // which will be caught by the Reconnect() method, and Reconnect() // will retry according to the total number of retries it is // set to do. // if( m_router ) { m_con.reset( new Barry::Controller(m_probe_result, *m_router, m_connect_timeout) ); } else { m_con.reset( new Barry::Controller(m_probe_result, m_connect_timeout) ); } m_desktop.reset( new Barry::Mode::Desktop(*m_con, m_ic) ); m_desktop->Open(password); } void DesktopConnector::RetryPassword(const char *password) { m_desktop->RetryPassword(password); } void DesktopConnector::FinishConnect() { } void DesktopConnector::DoDisconnect() { m_desktop.reset(); m_con.reset(); } bool DesktopConnector::IsDisconnected() { // return true if DoDisconnect can safely be skipped return !m_con.get() && !m_desktop.get(); } bool DesktopConnector::IsConnected() { if( m_con.get() && m_desktop.get() ) return true; return false; } } barry-0.18.5/src/data.h0000644001161500056700000001677012242254476014140 0ustar cdfreycdfrey/// /// \file data.h /// Class to deal with pre-saved data files /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __SB_DATA_H__ #define __SB_DATA_H__ #include "dll.h" #include #include #include #include #define BARRY_DATA_DEFAULT_SIZE 0x4000 #define BARRY_DATA_DEFAULT_PREPEND_SIZE 0x100 namespace Barry { class BXEXPORT Data { unsigned char *m_memBlock; //< pointer to full memory block //< can be null if external size_t m_blockSize; //< size of m_memBlock buffer allocated unsigned char *m_dataStart; //< pointer to start of internal data //< can be null if external, and can //< start somewhere in the middle of //< m_memBlock if internal with a //< prepend buffer size_t m_dataSize; //< number of bytes of actual data // copy on write feature const unsigned char *m_externalData; bool m_external; // meta data int m_endpoint; // output format flags static bool bPrintAscii; protected: void MakeSpace(size_t desiredsize, size_t desiredprepend = 0); size_t AvailablePrependSpace() const; public: Data(); explicit Data(int endpoint, size_t startsize = BARRY_DATA_DEFAULT_SIZE, size_t prependsize = BARRY_DATA_DEFAULT_PREPEND_SIZE); Data(const void *ValidData, size_t size); Data(const Data &other); ~Data(); void InputHexLine(std::istream &is); void DumpHexLine(std::ostream &os, size_t index, size_t size) const; void DumpHex(std::ostream &os) const; int GetEndpoint() const { return m_endpoint; } const unsigned char * GetData() const { return m_external ? m_externalData : m_dataStart; } size_t GetSize() const { return m_dataSize; } unsigned char * GetBuffer(size_t requiredsize = 0); /// Returns size of buffer returned by GetBuffer() size_t GetBufSize() const; void ReleaseBuffer(int datasize = -1); void AppendHexString(const char *str); /// set buffer to 0 size, but don't bother overwriting memory with 0 void QuickZap() { m_dataSize = 0; } void Zap(); // does a memset too Data& operator=(const Data &other); // // Utility functions // // Writing data... basically does a memcpy(dst,src,sizeof(src)) // for each type. Does no endian conversions. // dst is calculated as buffer + offset. // The buffer is expanded automatically if needed. // The offset is advanced by the size of the data. // GetSize() will increase automatically if the result of // the MemCpy() goes beyond the existing data size. // void MemCpy(size_t &offset, const void *src, size_t size); void Append(const void *buf, size_t size); void Prepend(const void *buf, size_t size); void Prechop(size_t size); template void SetValue(size_t &offset, ValueT value) { this->MemCpy(offset, &value, sizeof(value)); } // static functions static void PrintAscii(bool setting) { bPrintAscii = setting; } static bool PrintAscii() { return bPrintAscii; } }; BXEXPORT std::istream& operator>> (std::istream &is, Data &data); BXEXPORT std::ostream& operator<< (std::ostream &os, const Data &data); class BXEXPORT Diff { const Data &m_old, &m_new; BXLOCAL void Compare(std::ostream &os, size_t index, size_t size) const; public: Diff(const Data &old, const Data &new_); void Dump(std::ostream &os) const; }; BXEXPORT std::ostream& operator<< (std::ostream &os, const Diff &diff); // utility functions BXEXPORT bool LoadDataArray(const std::string &filename, std::vector &array); BXEXPORT bool ReadDataArray(std::istream &is, std::vector &array); // // DBData // /// Database record data class. The purpose of this class is to contain /// the raw data that flows between low level activity such as device /// read/writes, backup read/writes, and record parsing. /// /// This class contains the low level record data block, unparsed, as well /// as the surrounding meta data, such as the database name it belongs /// to, the Unique ID, the Rec Type, and format version/type based on what /// commands were used to extract the data from the device. (When using /// newer commands, the format of the records, potentially including the /// individual field type codes, are different.) /// /// Possible bi-directional data flow in all of Barry: /// Note that this class, DBData, represents the data+meta stage. /// /// data+meta <-> device /// data+meta <-> backup file /// data+meta <-> record object /// record object <-> boost serialization /// contact record object <-> ldif /// /// Possible uni-directional data flow in all of Barry: /// /// record object -> text dump /// class BXEXPORT DBData { public: enum RecordFormatVersion { REC_VERSION_1, REC_VERSION_2 }; private: // record meta data RecordFormatVersion m_version; std::string m_dbName; uint8_t m_recType; uint32_t m_uniqueId; size_t m_offset; // the raw data block, internal Data *m_localData; // the data block to use... could be external or internal, // and does not change for the life of the object Data &m_data; public: /// Default constructor, constructs an empty local Data object DBData(); /// Copy constructor - always creates an internal Data object, and /// uses Data object's copy constructor to make it. /// Copies all meta data as well. /// If you want to optimize the copy, use one of the constructors /// below. DBData(const DBData &other); /// Constructs a local Data object that points to external memory DBData(const void *ValidData, size_t size); DBData(RecordFormatVersion ver, const std::string &dbName, uint8_t recType, uint32_t uniqueId, size_t offset, const void *ValidData, size_t size); /// If copy == false, constructs an external Data object, no local. /// If copy == true, constructs an internal Data object copy /// For speed, set copy to false. /// If you want Copy On Write behaviour, similar to Data(buf,size), /// then use the above (buf, size) constructor, not this one, /// since this constructor uses Data's copy constructor. DBData(Data &externalData, bool copy); DBData(RecordFormatVersion ver, const std::string &dbName, uint8_t recType, uint32_t uniqueId, size_t offset, Data &externalData, bool copy); ~DBData(); // access meta data RecordFormatVersion GetVersion() const { return m_version; } const std::string& GetDBName() const { return m_dbName; } uint8_t GetRecType() const { return m_recType; } uint32_t GetUniqueId() const { return m_uniqueId; } size_t GetOffset() const { return m_offset; } const Data& GetData() const { return m_data; } Data& UseData(); // operations void SetVersion(RecordFormatVersion ver) { m_version = ver; } void SetDBName(const std::string &dbName) { m_dbName = dbName; } void SetIds(uint8_t recType, uint32_t uniqueId) { m_recType = recType; m_uniqueId = uniqueId; } void SetOffset(size_t offset) { m_offset = offset; } void CopyMeta(const DBData &src) { m_version = src.m_version; m_dbName = src.m_dbName; m_recType = src.m_recType; m_uniqueId = src.m_uniqueId; m_offset = src.m_offset; } DBData& operator=(const DBData &other); }; } // namespace Barry #endif barry-0.18.5/src/r_calllog.cc0000644001161500056700000002454712242254476015324 0ustar cdfreycdfrey/// /// \file r_calllog.cc /// Record parsing class for the phone call logs database. /// /* Copyright (C) 2008-2009, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "r_calllog.h" #include "record-internal.h" #include "protostructs.h" #include "data.h" #include "time.h" #include "iconv.h" #include #include #include "ios_state.h" using namespace std; using namespace Barry::Protocol; namespace Barry { #define MILLISECONDS_IN_A_SECOND 1000 time_t CallLog::GetTime() const { return (time_t)(Timestamp / MILLISECONDS_IN_A_SECOND); } CallLog::DirectionFlagType CallLog::DirectionProto2Rec(uint8_t s) { return (DirectionFlagType)s; } uint8_t CallLog::DirectionRec2Proto(DirectionFlagType s) { return s; } CallLog::PhoneTypeFlagType CallLog::PhoneTypeProto2Rec(uint8_t s) { return (PhoneTypeFlagType)s; } uint8_t CallLog::PhoneTypeRec2Proto(PhoneTypeFlagType s) { return s; } /////////////////////////////////////////////////////////////////////////////// // CallLog Class // CallLog Field Codes #define CLLFC_CALLLOG_TYPE 0x01 #define CLLFC_DIRECTION 0x02 #define CLLFC_DURATION 0x03 #define CLLFC_TIMESTAMP 0x04 #define CLLFC_STATUS 0x06 #define CLLFC_UNIQUEID 0x07 #define CLLFC_PHONE_TYPE 0x0b #define CLLFC_PHONE_NUMBER 0x0c #define CLLFC_PHONE_INFO 0x0d #define CLLFC_CONTACT_NAME 0x1f #define CLLFC_END 0xffff static FieldLink CallLogFieldLinks[] = { { CLLFC_PHONE_NUMBER, N_("Phone number"), 0, 0, &CallLog::PhoneNumber, 0, 0, 0, 0, true }, { CLLFC_CONTACT_NAME, N_("Contact name"), 0, 0, &CallLog::ContactName, 0, 0, 0, 0, true }, { CLLFC_END, N_("End of List"), 0, 0, 0, 0, 0, 0, 0, false } }; CallLog::CallLog() { Clear(); } CallLog::~CallLog() { } const unsigned char* CallLog::ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { const CommonField *field = (const CommonField *) begin; // advance and check size begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size); if( begin > end ) // if begin==end, we are ok return begin; if( !btohs(field->size) ) // if field has no size, something's up return begin; if( field->type == CLLFC_CALLLOG_TYPE ) { if( field->u.raw[0] != 'p' ) { throw Error( _("CallLog::ParseField: CallLogType is not 'p'") ); } return begin; } // this is always the same as the RecordID from the lower level // protocol, so we throw this away for now if( field->type == CLLFC_UNIQUEID) return begin; // cycle through the type table for( FieldLink *b = CallLogFieldLinks; b->type != CLLFC_END; b++ ) { if( b->type == field->type ) { if( b->strMember ) { std::string &s = this->*(b->strMember); s = ParseFieldString(field); if( b->iconvNeeded && ic ) s = ic->FromBB(s); return begin; // done! } else if( b->timeMember && btohs(field->size) == 4 ) { TimeT &t = this->*(b->timeMember); t.Time = min2time(field->u.min1900); return begin; } } } // handle special cases switch( field->type ) { case CLLFC_STATUS: // single byte... size check above checks for non-zero already switch (field->u.raw[0]) { case 0x00: StatusFlag = Barry::CallLog::OK; break; case 0x01: StatusFlag = Barry::CallLog::Busy; break; case 0x09: StatusFlag = Barry::CallLog::NetError; break; default: StatusFlag = Barry::CallLog::Unknown; } return begin; case CLLFC_DIRECTION: if( field->u.raw[0] > CLL_DIRECTION_RANGE_HIGH ) { throw Error( _("CallLog::ParseField: direction field out of bounds") ); } else { DirectionFlag = DirectionProto2Rec(field->u.raw[0]); } return begin; case CLLFC_PHONE_TYPE: if( field->u.raw[0] > CLL_PHONETYPE_RANGE_HIGH ) { PhoneTypeFlag = Barry::CallLog::TypeUnknown; } else { PhoneTypeFlag = PhoneTypeProto2Rec(field->u.raw[0]); } return begin; case CLLFC_PHONE_INFO: switch (field->u.raw[0]) { case 0x03: PhoneInfoFlag = Barry::CallLog::InfoKnown; break; case 0x80: PhoneInfoFlag = Barry::CallLog::InfoUnknown; break; case 0x40: PhoneInfoFlag = Barry::CallLog::InfoPrivate; break; default: PhoneInfoFlag = Barry::CallLog::InfoUndefined; } return begin; case CLLFC_DURATION: if( btohs(field->size) >= sizeof(field->u.uint32) ) { Duration = btohl(field->u.uint32); return begin; } break; case CLLFC_TIMESTAMP: if( btohs(field->size) >= sizeof(field->u.timestamp) ) { Timestamp = btohll(field->u.timestamp); return begin; } break; } // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; uf.data.assign((const char*)field->u.raw, btohs(field->size)); Unknowns.push_back(uf); // return new pointer for next field return begin; } void CallLog::ParseHeader(const Data &data, size_t &offset) { // no header in CallLog records } void CallLog::ParseFields(const Data &data, size_t &offset, const IConverter *ic) { const unsigned char *finish = ParseCommonFields(*this, data.GetData() + offset, data.GetData() + data.GetSize(), ic); offset += finish - (data.GetData() + offset); } void CallLog::Validate() const { } void CallLog::BuildHeader(Data &data, size_t &offset) const { // not yet implemented } void CallLog::BuildFields(Data &data, size_t &offset, const IConverter *ic) const { // not yet implemented } void CallLog::Dump(std::ostream &os) const { ios_format_state state(os); uint32_t timestamp = Duration; int32_t days, hours, minutes, secondes; static const char *DirectionName[] = { N_("Received"), N_("Sent"), N_("Call Missing (Messagerie)"), N_("Call Missing") }; static const char *StatusName[] = { N_("OK"), N_("Busy"), N_("Error"), N_("Not supported by Barry") }; static const char *PhoneInfoName[] = { N_("Undefined"), N_("Known phone number"), N_("Unknown phone number"), N_("Private phone number") }; static const char *PhoneTypeName[] = { N_("Unknown"), N_("Office"), N_("Home"), N_("Mobile"), N_("Not supported by Barry") }; os << _("CallLog entry: ") << "0x" << setbase(16) << RecordId << " (" << (unsigned int)RecType << ")\n"; time_t t = GetTime(); os << _(" Timestamp: ") << ctime(&t); os << _(" Direction: ") << gettext( DirectionName[DirectionFlag] ) << "\n"; os << _(" Status: ") << gettext( StatusName[StatusFlag] ) << "\n"; os << _(" Phone info: ") << gettext( PhoneInfoName[PhoneInfoFlag] ) << "\n"; os << _(" Phone type: ") << gettext( PhoneTypeName[PhoneTypeFlag] ) << "\n"; os << _(" Duration: "); // Days : days = (int) (timestamp / (60 * 60 * 24)); timestamp = timestamp - (days * (60 * 60 * 24)); // Hours : hours = (int) (timestamp / (60 * 60)); timestamp = timestamp - (hours * (60 * 60)); // Minutes : minutes = (int) (timestamp / 60); timestamp = timestamp - (minutes * 60); // Secondes : secondes = timestamp; if (days > 1) os << setbase(10) << days << _(" days "); else if (days > 0) os << setbase(10) << days << _(" day "); os << setfill ('0') << setw(2) << setbase(10) << hours; os << ":"; os << setfill ('0') << setw(2) << setbase(10) << minutes; os << ":"; os << setfill ('0') << setw(2) << setbase(10) << secondes; os << "\n"; // cycle through the type table for( const FieldLink *b = CallLogFieldLinks; b->type != CLLFC_END; b++ ) { if( b->strMember ) { const std::string &s = this->*(b->strMember); if( s.size() ) os << " " << gettext(b->name) << ": " << s << "\n"; } else if( b->timeMember ) { TimeT t = this->*(b->timeMember); if( t.Time > 0 ) os << " " << gettext(b->name) << ": " << t << "\n"; else os << " " << gettext(b->name) << ": " << _("unknown") << "\n"; } } os << Unknowns; os << "\n\n"; } void CallLog::Clear() { RecType = GetDefaultRecType(); RecordId = 0; Duration = 0; Timestamp = 0; ContactName.clear(); PhoneNumber.clear(); DirectionFlag = Barry::CallLog::Receiver; StatusFlag = Barry::CallLog::Unknown; PhoneTypeFlag = Barry::CallLog::TypeUnknown; PhoneInfoFlag = Barry::CallLog::InfoUndefined; Unknowns.clear(); } const FieldHandle::ListT& CallLog::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; #undef CONTAINER_OBJECT_NAME #define CONTAINER_OBJECT_NAME fhv #undef RECORD_CLASS_NAME #define RECORD_CLASS_NAME CallLog FHP(RecType, _("Record Type Code")); FHP(RecordId, _("Unique Record ID")); FHD(Duration, _("Duration of Call in Seconds"), CLLFC_DURATION, false); FHD(Timestamp, _("Timestamp of Call in Milliseconds"), CLLFC_TIMESTAMP, false); FHD(ContactName, _("Contact Name"), CLLFC_CONTACT_NAME, true); FHD(PhoneNumber, _("Phone Number"), CLLFC_PHONE_NUMBER, true); FHE(dft, DirectionFlagType, DirectionFlag, _("Direction of Call")); FHE_CONST(dft, Receiver, _("Received Call")); FHE_CONST(dft, Emitter, _("Placed the Call")); FHE_CONST(dft, Failed, _("Failed Call")); FHE_CONST(dft, Missing, _("Missed Call")); FHE(sft, StatusFlagType, StatusFlag, _("Status of Call")); FHE_CONST(sft, OK, _("OK")); FHE_CONST(sft, Busy, _("Busy")); FHE_CONST(sft, NetError, _("Network Error")); FHE_CONST(sft, Unknown, _("Unsupported Status")); FHE(ptf, PhoneTypeFlagType, PhoneTypeFlag, _("Phone Type")); FHE_CONST(ptf, TypeUndefined, _("Undefined")); FHE_CONST(ptf, TypeOffice, _("Office")); FHE_CONST(ptf, TypeHome, _("Home")); FHE_CONST(ptf, TypeMobile, _("Mobile")); FHE_CONST(ptf, TypeUnknown, _("Unknown")); FHE(pif, PhoneInfoFlagType, PhoneInfoFlag, _("Phone Info")); FHE_CONST(pif, InfoUndefined, _("Undefined")); FHE_CONST(pif, InfoKnown, _("Phone Number is Set")); FHE_CONST(pif, InfoUnknown, _("Phone Number Not Set")); FHE_CONST(pif, InfoPrivate, _("Phone Number is Private")); FHP(Unknowns, _("Unknown Fields")); return fhv; } std::string CallLog::GetDescription() const { return ContactName; } } // namespace Barry barry-0.18.5/src/r_sms.cc0000644001161500056700000003435712242254476014511 0ustar cdfreycdfrey/// /// \file r_sms.cc /// Record parsing class for the SMS database. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2009, Ryan Li(ryan@ryanium.com) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "r_sms.h" #include "record-internal.h" #include "protostructs.h" #include "data.h" #include "time.h" #include "debug.h" #include "iconv.h" #include "strnlen.h" #include #include #include #include "ios_state.h" using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // Sms Class // SMS Field Codes #define SMSFC_METADATA 0x01 #define SMSFC_ADDRESS 0x02 #define SMSFC_BODY 0x04 // SMS Field Sizes and Header Sizes #define SMS_ADDRESS_HEADER_SIZE 0x04 #define MILLISECONDS_IN_A_SECOND 1000 time_t Sms::GetTime() const { return (time_t)(Timestamp / MILLISECONDS_IN_A_SECOND); } time_t Sms::GetServiceCenterTime() const { return (time_t)(ServiceCenterTimestamp / MILLISECONDS_IN_A_SECOND); } void Sms::SetTime(const time_t timestamp, const unsigned milliseconds) { Timestamp = (uint64_t)timestamp * MILLISECONDS_IN_A_SECOND + milliseconds; } void Sms::SetServiceCenterTime(const time_t timestamp, const unsigned milliseconds) { ServiceCenterTimestamp = (uint64_t)timestamp * MILLISECONDS_IN_A_SECOND + milliseconds; } Sms::Sms() { Clear(); } Sms::~Sms() { } #define CHECK_FLAG(flags, bitfield) ((flags & (bitfield)) != 0) const unsigned char* Sms::ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { const CommonField *field = (const CommonField *)begin; // advance and check size begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size); if (begin > end) // if begin==end, we are ok return begin; if (!btohs(field->size)) // if field has no size, something's up return begin; switch (field->type) { case SMSFC_METADATA: { if (btohs(field->size) < SMS_METADATA_SIZE) break; // size not match const SMSMetaData &metadata = field->u.sms_metadata; NewConversation = CHECK_FLAG(metadata.flags, SMS_FLG_NEW_CONVERSATION); Saved = CHECK_FLAG(metadata.flags, SMS_FLG_SAVED); Deleted = CHECK_FLAG(metadata.flags, SMS_FLG_DELETED); Opened = CHECK_FLAG(metadata.flags, SMS_FLG_OPENED); IsNew = metadata.new_flag != 0; uint32_t status = btohl(metadata.status); switch (status) { case SMS_STA_RECEIVED: MessageStatus = Received; break; case SMS_STA_DRAFT: MessageStatus = Draft; break; default: MessageStatus = Sent; // consider all others as sent } ErrorId = btohl(metadata.error_id); Timestamp = btohll(metadata.timestamp); ServiceCenterTimestamp = btohll(metadata.service_center_timestamp); switch (metadata.dcs) { case SMS_DCS_7BIT: DataCodingScheme = SevenBit; break; case SMS_DCS_8BIT: DataCodingScheme = EightBit; break; case SMS_DCS_UCS2: DataCodingScheme = UCS2; break; default: DataCodingScheme = SevenBit; // consider all unknowns as 7bit } return begin; } case SMSFC_ADDRESS: { uint16_t length = btohs(field->size); if (length < SMS_ADDRESS_HEADER_SIZE + 1) // trailing '\0' break; // too short length -= SMS_ADDRESS_HEADER_SIZE; const char *address = (const char *)field->u.raw + SMS_ADDRESS_HEADER_SIZE; Addresses.push_back(std::string(address, strnlen(address, length))); return begin; } case SMSFC_BODY: { // // Some SMS bodies contain a null terminator // in the middle, and it is unknown at the moment // why this is. For regular 8bit char strings, // we just strip out the nulls. For UCS2 // 16bit char strings, we strip out the // 16bit nulls. // // Any further information on why these null // terminators appear is welcome. // const char *str = (const char *)field->u.raw; uint16_t maxlen = btohs(field->size); if (DataCodingScheme != UCS2) { for (uint16_t i = 0; i < maxlen; ++i) { if (str[i]) // if not null, push it Body += str[i]; } } else { for (uint16_t i = 0; maxlen && i < (maxlen-1); i += 2) { if (str[i] || str[i + 1]) // if not null, push it Body += std::string(str + i, 2); } } if (ic) { if (DataCodingScheme == SevenBit) { // SevenBit -> UTF-8 -> ic's tocode IConvHandle utf8("UTF-8", *ic); Body = ic->Convert(utf8, ConvertGsmToUtf8(Body)); // convert the Body string from GSM 03.38 defined to UTF-8 } else if (DataCodingScheme == EightBit) Body = ic->FromBB(Body); else { IConvHandle ucs2("UCS-2BE", *ic); Body = ic->Convert(ucs2, Body); } } return begin; } } // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; uf.data.assign((const char*)field->u.raw, btohs(field->size)); Unknowns.push_back(uf); // return new pointer for next field return begin; } void Sms::ParseHeader(const Data &data, size_t &offset) { // no header in SMS records } void Sms::ParseFields(const Data &data, size_t &offset, const IConverter *ic) { const unsigned char *finish = ParseCommonFields(*this, data.GetData() + offset, data.GetData() + data.GetSize(), ic); offset += finish - (data.GetData() + offset); } void Sms::Validate() const { } void Sms::BuildHeader(Data &data, size_t &offset) const { // not yet implemented } void Sms::BuildFields(Data &data, size_t &offset, const IConverter *ic) const { // not yet implemented } void Sms::Clear() { RecType = GetDefaultRecType(); RecordId = 0; MessageStatus = Unknown; DeliveryStatus = NoReport; IsNew = NewConversation = Saved = Deleted = Opened = false; Timestamp = ServiceCenterTimestamp = 0; DataCodingScheme = SevenBit; ErrorId = 0; Addresses.clear(); Body.clear(); Unknowns.clear(); } const FieldHandle::ListT& Sms::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; #undef CONTAINER_OBJECT_NAME #define CONTAINER_OBJECT_NAME fhv #undef RECORD_CLASS_NAME #define RECORD_CLASS_NAME Sms FHP(RecType, _("Record Type Code")); FHP(RecordId, _("Unique Record ID")); FHE(mt, MessageType, MessageStatus, _("Message Status")); FHE_CONST(mt, Unknown, _("Unknown")); FHE_CONST(mt, Received, _("Received")); FHE_CONST(mt, Sent, _("Sent")); FHE_CONST(mt, Draft, _("Draft")); FHE(dt, DeliveryType, DeliveryStatus, _("Delivery Status")); FHE_CONST(dt, NoReport, _("No Report")); FHE_CONST(dt, Failed, _("Failed")); FHE_CONST(dt, Succeeded, _("Succeeded")); FHP(IsNew, _("Is New?")); FHP(NewConversation, _("New Conversation")); FHP(Saved, _("Saved")); FHP(Deleted, _("Deleted")); FHP(Opened, _("Opened")); FHP(Timestamp, _("Timestamp in Milliseconds")); FHP(ServiceCenterTimestamp, _("Service Center Timestamp")); FHE(dcst, DataCodingSchemeType, DataCodingScheme, _("Data Coding Scheme")); FHE_CONST(dcst, SevenBit, _("7bit")); FHE_CONST(dcst, EightBit, _("8bit")); FHE_CONST(dcst, UCS2, _("UCS2")); FHP(ErrorId, _("Error ID")); FHD(Addresses, _("Addresses"), SMSFC_ADDRESS, true); FHD(Body, _("Body"), SMSFC_BODY, true); FHP(Unknowns, _("Unknown Fields")); return fhv; } std::string Sms::GetDescription() const { if( Addresses.size() ) return Addresses[0]; else return _("Unknown destination"); } void Sms::Dump(std::ostream &os) const { ios_format_state state(os); os << _("SMS record: ") << "0x" << setbase(16) << RecordId << " (" << (unsigned int)RecType << ")\n"; time_t t = GetTime(); os << "\t" << _("Timestamp: ") << ctime(&t); if (MessageStatus == Received) { t = GetServiceCenterTime(); os << "\t" << _("Service Center Timestamp: ") << ctime(&t); } if (ErrorId) os << "\t" << _("Send Error: ") << "0x" << setbase(16) << ErrorId << "\n"; switch (MessageStatus) { case Received: os << "\t" << _("Received From:\n"); break; case Sent: os << "\t" << _("Sent to:\n"); break; case Draft: os << "\t" << _("Draft for:\n"); break; case Unknown: os << "\t" << _("Unknown status for:\n"); break; } os << "\t"; os << Addresses << "\n"; if (IsNew || Opened || Saved || Deleted || NewConversation) { os << "\t"; if (IsNew) os << _("New "); if (Opened) os << _("Opened "); if (Saved) os << _("Saved "); if (Deleted) os << _("Deleted "); os << _("Message") << (NewConversation ? _(" that starts a new conversation") : "") << "\n"; } os << "\t" << _("Content: ") << Body << "\n"; os << "\n"; } // // This function helps to convert GSM 03.38 defined 7-bit // SMS to UTF-8. // Detailed information can be found in: // ftp://ftp.3gpp.org/Specs/html-info/0338.htm (Official) // http://en.wikipedia.org/wiki/SMS#GSM // std::string Sms::ConvertGsmToUtf8(const std::string &s) { // // This array stores the GSM 03.38 defined encoding's // corresponding UTF-8 values. // For example: GsmTable[0] = "\x40", which refers to // a "@" in UTF-8 encoding. // The 0x1b item, leads to the extension table, using // the char right next to it as the index. // According to the official specification, when not // able to handle it, it should be treated simply as // a space, which is denoted in UTF-8 as "\x20". // static const std::string GsmTable[0x80] = { // 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 "\x40", "\xc2\xa3", "\x24", "\xc2\xa5", "\xc3\xa8", "\xc3\xa9", "\xc3\xb9", "\xc3\xac", // 0x00 "\xc3\xb2", "\xc3\x87", "\x0a", "\xc3\x98", "\xc3\xb8", "\x0d", "\xc3\x85", "\xc3\xa5", // 0x08 "\xce\x94", "\x5f", "\xce\xa6", "\xce\x93", "\xce\x9b", "\xce\xa9", "\xce\xa0", "\xce\xa8", // 0x10 "\xce\xa3", "\xce\x98", "\xce\x9e", "\x20", "\xc3\x86", "\xc3\xa6", "\xc3\x9f", "\xc3\x89", // 0x18 "\x20", "\x21", "\x22", "\x23", "\xc2\xa4", "\x25", "\x26", "\x27", // 0x20 "\x28", "\x29", "\x2a", "\x2b", "\x2c", "\x2d", "\x2e", "\x2f", // 0x28 "\x30", "\x31", "\x32", "\x33", "\x34", "\x35", "\x36", "\x37", // 0x30 "\x38", "\x39", "\x3a", "\x3b", "\x3c", "\x3d", "\x3e", "\x3f", // 0x38 "\xc2\xa1", "\x41", "\x42", "\x43", "\x44", "\x45", "\x46", "\x47", // 0x40 "\x48", "\x49", "\x4a", "\x4b", "\x4c", "\x4d", "\x4e", "\x4f", // 0x48 "\x50", "\x51", "\x52", "\x53", "\x54", "\x55", "\x56", "\x57", // 0x50 "\x58", "\x59", "\x5a", "\xc3\x84", "\xc3\x96", "\xc3\x91", "\xc3\x9c", "\xc2\xa7", // 0x58 "\xc2\xbf", "\x61", "\x62", "\x63", "\x64", "\x65", "\x66", "\x67", // 0x60 "\x68", "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", // 0x68 "\x70", "\x71", "\x72", "\x73", "\x74", "\x75", "\x76", "\x77", // 0x70 "\x78", "\x79", "\x7a", "\xc3\xa4", "\xc3\xb6", "\xc3\xb1", "\xc3\xbc", "\xc3\xa0" // 0x78 }; // // This sparse array stores the GSM 03.38 defined // encoding extension table. // The \x1b item is also preserved, for possibly // another extension table. // static const std::string GsmExtensionTable[0x80] = { // 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 "", "", "", "", "", "", "", "", // 0x00 "", "", "\x0c", "", "", "", "", "", // 0x08 "", "", "", "", "\x5e", "", "", "", // 0x10 "", "", "", " ", "", "", "", "", // 0x18 "", "", "", "", "", "", "", "", // 0x20 "\x7b", "\x7d", "", "", "", "", "", "\x5c", // 0x28 "", "", "", "", "", "", "", "", // 0x30 "", "", "", "", "\x5b", "\x7e", "\x5d", "", // 0x38 "\x7c", "", "", "", "", "", "", "", // 0x40 "", "", "", "", "", "", "", "", // 0x48 "", "", "", "", "", "", "", "", // 0x50 "", "", "", "", "", "", "", "", // 0x58 "", "", "", "", "", "\xe2\x82\xac", "", "", // 0x60 "", "", "", "", "", "", "", "", // 0x68 "", "", "", "", "", "", "", "", // 0x70 "", "", "", "", "", "", "", "" // 0x78 }; std::string ret; unsigned len = s.length(); for (unsigned i = 0; i < len; ++i) { unsigned char c = (unsigned char) s[i]; if (c > 0x7f) // prevent from illegal index continue; else if (c == 0x1b) { // go to extension table if (i < len - 1) { c = (unsigned char) s[++i]; if (c <= 0x7f) // prevent from illegal index ret += GsmExtensionTable[c]; } } else ret += GsmTable[c]; } return ret; } } // namespace Barry barry-0.18.5/src/record-internal.h0000644001161500056700000000771712242254476016320 0ustar cdfreycdfrey/// /// \file record-internal.h /// Support functions, types, and templates for the /// general record parsing classes in r_*.h files. /// This header is NOT installed for applications to /// use, so it is safe to put library-specific things /// in here. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_INTERNAL_H__ #define __BARRY_RECORD_INTERNAL_H__ #include #include "protostructs.h" #include "error.h" #include "endian.h" #include "record.h" // forward declarations namespace Barry { class Data; class IConverter; } namespace Barry { template const unsigned char* ParseCommonFields(RecordT &rec, const void *begin, const void *end, const IConverter *ic = 0) { const unsigned char *b = (const unsigned char*) begin; const unsigned char *e = (const unsigned char*) end; while( (b + COMMON_FIELD_HEADER_SIZE) < e ) b = rec.ParseField(b, e, ic); return b; } // Does not exist, so error will be caught by linker instead of at runtime. void ConvertHtoB_Not_Implemented(); // Use templates here to guarantee types are converted in the strictest manner. template inline SizeT ConvertHtoB(SizeT s) { ConvertHtoB_Not_Implemented(); // throw Error("Not implemented."); } // specializations for specific sizes template <> inline uint8_t ConvertHtoB(uint8_t s) { return s; } template <> inline uint16_t ConvertHtoB(uint16_t s) { return htobs(s); } template <> inline uint32_t ConvertHtoB(uint32_t s) { return htobl(s); } template <> inline uint64_t ConvertHtoB(uint64_t s) { return htobll(s); } template struct FieldLink { int type; const char *name; const char *ldif; const char *objectClass; std::string RecordT::* strMember; // FIXME - find a more general EmailAddressList RecordT::* addrMember; // way to do this... Barry::TimeT RecordT::* timeMember; PostalAddress RecordT::* postMember; std::string PostalAddress::* postField; bool iconvNeeded; }; void BuildField1900(Data &data, size_t &size, uint8_t type, time_t t); inline void BuildField1900(Data &data, size_t &size, uint8_t type, const Barry::TimeT &t) { BuildField1900(data, size, type, t.Time); } void BuildField(Data &data, size_t &size, uint8_t type, char c); void BuildField(Data &data, size_t &size, uint8_t type, uint8_t c); void BuildField(Data &data, size_t &size, uint8_t type, uint16_t value); void BuildField(Data &data, size_t &size, uint8_t type, uint32_t value); void BuildField(Data &data, size_t &size, uint8_t type, uint64_t value); void BuildField(Data &data, size_t &size, uint8_t type, const std::string &str); void BuildField(Data &data, size_t &size, uint8_t type, const void *buf, size_t bufsize); void BuildField(Data &data, size_t &size, const Barry::UnknownField &field); void BuildField(Data &data, size_t &size, uint8_t type, const Barry::Protocol::GroupLink &link); std::string ParseFieldString(const Barry::Protocol::CommonField *field); std::string ParseFieldString(const void *data, uint16_t maxlen); // Functions to help build JDWP command packets void AddJDWByte(Barry::Data &data, size_t &size, const uint8_t value); void AddJDWInt(Barry::Data &data, size_t &size, const uint32_t value); void AddJDWChar(Barry::Data &data, size_t &size, const void *buf, size_t bufsize); void AddJDWString(Barry::Data &data, size_t &size, const std::string &str); } // namespace Barry #endif barry-0.18.5/src/r_task.h0000644001161500056700000001041712242254476014502 0ustar cdfreycdfrey/// /// \file r_task.h /// Record parsing class for the task database. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2007, Brian Edginton 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_TASK_H__ #define __BARRY_RECORD_TASK_H__ #include "dll.h" #include "record.h" #include "r_recur_base.h" #include #include #include namespace Barry { // forward declarations class IConverter; // // Task record class // /// Task record class. Note that there is a bug in many device firmwares. /// /// If you extract a Tasks record, and then write it back via /// SetRecordByIndex(), on many devices that I tested, it ends up /// corrupting the record on the device, and the GUI on the device /// appears messed up. (It shows the first few fields twice) /// Such a corrupt record also loses the due date. /// /// The workaround, when working with the Tasks database, is to /// first DeleteByIndex() and then AddRecord() via the Desktop mode class, /// using the same record ID. This works, but is unfortunately /// cumbersome. /// /// See the Desktop GUI and the opensync plugins for examples of this /// workaround. /// /// Ideally, we should test a Tasks sync on Windows, and see how /// the Windows software handles this. There may be some protocol /// changes that will be needed in future Barry versions. /// class BXEXPORT Task : public RecurBase { public: typedef Barry::UnknownsType UnknownsType; uint8_t RecType; uint32_t RecordId; std::string Summary; std::string Notes; CategoryList Categories; std::string UID; Barry::TimeT StartTime; // most devices set this the same as // DueTime... this is a read-only // variable. By setting DueTime, // the library will write StartTime // for you automatically Barry::TimeT DueTime; Barry::TimeT AlarmTime; uint16_t TimeZoneCode; bool TimeZoneValid; // true if the record contained a // time zone code enum AlarmFlagType { Date = 1, Relative }; AlarmFlagType AlarmType; enum PriorityFlagType { High = 0, Normal, Low }; PriorityFlagType PriorityFlag; enum StatusFlagType { NotStarted = 0, InProgress, Completed, Waiting, Deferred }; StatusFlagType StatusFlag; // unknown UnknownsType Unknowns; protected: static AlarmFlagType AlarmProto2Rec(uint8_t a); static uint8_t AlarmRec2Proto(AlarmFlagType a); static PriorityFlagType PriorityProto2Rec(uint8_t p); static uint8_t PriorityRec2Proto(PriorityFlagType p); static StatusFlagType StatusProto2Rec(uint8_t s); static uint8_t StatusRec2Proto(StatusFlagType s); public: Task(); ~Task(); // Parser / Builder API (see parser.h / builder.h) void Validate() const; const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); uint8_t GetRecType() const { return RecType; } uint32_t GetUniqueId() const { return RecordId; } void SetIds(uint8_t Type, uint32_t Id) { RecType = Type; RecordId = Id; } void ParseHeader(const Data &data, size_t &offset); void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); void BuildHeader(Data &data, size_t &offset) const; void BuildFields(Data &data, size_t &offset, const IConverter *ic = 0) const; // operations (common among record classes) void Clear(); void Dump(std::ostream &os) const; std::string GetDescription() const; bool operator<(const Task &other) const; // database name static const char * GetDBName() { return "Tasks"; } static uint8_t GetDefaultRecType() { return 2; } // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const Task &msg) { msg.Dump(os); return os; } } // namespace Barry #endif barry-0.18.5/src/j_message.h0000644001161500056700000000236512242254476015157 0ustar cdfreycdfrey/// /// \file j_message.h /// JDWP message classes /// /* Copyright (C) 2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYJDWP_MESSAGE_H__ #define __BARRYJDWP_MESSAGE_H__ #include "j_jdwp.h" namespace Barry { namespace JDWP { class JDWMessage { private: int m_socket; JDWP m_jdwp; void RawSend(Barry::Data &send, int timeout = -1); bool RawReceive(Barry::Data &receive, int timeout = -1); protected: public: JDWMessage(int socket); ~JDWMessage(); void Send(Barry::Data &send, int timeout = -1); // send only void Send(Barry::Data &send, Barry::Data &receive, int timeout = -1); // send+recv bool Receive(Barry::Data &receive, int timeout = -1); }; }} // namespace Barry::JDWP #endif barry-0.18.5/src/backup.cc0000644001161500056700000000451112242254476014620 0ustar cdfreycdfrey/// /// \file backup.cc /// Special parser class to support creation of Barry Backup files /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "backup.h" #include "tarfile.h" #include "error.h" #include #include #include namespace Barry { Backup::Backup(const std::string &tarpath) { try { m_tar.reset( new reuse::TarFile(tarpath.c_str(), true, &reuse::gztar_ops_nonthread, true) ); } catch( reuse::TarFile::TarError &te ) { throw Barry::BackupError(te.what()); } } Backup::~Backup() { try { Close(); } catch( Barry::BackupError & ) { // throw it away } } void Backup::Close() { if( m_tar.get() ) try { m_tar->Close(); m_tar.reset(); } catch( reuse::TarFile::TarError &te ) { throw Barry::BackupError(te.what()); } } void Backup::ClearStats() { m_stats.clear(); } ////////////////////////////////////////////////////////////////////////////// // Barry::Parser overrides void Backup::ParseRecord(const Barry::DBData &data, const Barry::IConverter *ic) { m_current_dbname = data.GetDBName(); std::ostringstream oss; oss << std::hex << data.GetUniqueId() << " " << (unsigned int)data.GetRecType(); m_tar_id_text = oss.str(); if( m_current_dbname.size() == 0 ) throw Barry::BackupError(_("Backup: No database name available")); if( m_tar_id_text.size() == 0 ) throw Barry::BackupError(_("Backup: No unique ID available!")); m_record_data.assign( (const char*)data.GetData().GetData() + data.GetOffset(), data.GetData().GetSize() - data.GetOffset()); // save to tarball std::string tarname = m_current_dbname + "/" + m_tar_id_text; m_tar->AppendFile(tarname.c_str(), m_record_data); // add stats m_stats[m_current_dbname]++; } } // namespace Barry barry-0.18.5/src/r_bookmark.h0000644001161500056700000000624612242254476015352 0ustar cdfreycdfrey/// /// \file r_bookmark.h /// Record parsing class for call logs /// /* Copyright (C) 2008-2009, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_BOOKMARK_H__ #define __BARRY_RECORD_BOOKMARK_H__ #include "dll.h" #include "record.h" #include #include #include namespace Barry { // forward declarations class IConverter; class BXEXPORT Bookmark { public: typedef Barry::UnknownsType UnknownsType; uint8_t RecType; uint32_t RecordId; uint8_t Index; std::string Name; std::string Icon; std::string Url; enum BrowserIdentityType { IdentityAuto = 0, IdentityBlackBerry, IdentityFireFox, IdentityInternetExplorer, IdentityUnknown }; BrowserIdentityType BrowserIdentity; enum DisplayModeType { DisplayAuto = 0, DisplayColomn, DisplayPage, DisplayUnknown }; DisplayModeType DisplayMode; enum JavaScriptModeType { JavaScriptAuto = 0, JavaScriptEnabled, JavaScriptDisabled, JavaScriptUnknown }; JavaScriptModeType JavaScriptMode; UnknownsType Unknowns; protected: const unsigned char* ParseStruct1Field(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); const unsigned char* ParseStruct2(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); public: Bookmark(); ~Bookmark(); // Parser / Builder API (see parser.h / builder.h) void Validate() const; const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); uint8_t GetRecType() const { return RecType; } uint32_t GetUniqueId() const { return RecordId; } void SetIds(uint8_t Type, uint32_t Id) { RecType = Type; RecordId = Id; } void ParseHeader(const Data &data, size_t &offset); void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); void BuildHeader(Data &data, size_t &offset) const; void BuildFields(Data &data, size_t &offset, const IConverter *ic = 0) const; // operations (common among record classes void Clear(); void Dump(std::ostream &os) const; std::string GetDescription() const; // Sorting - use enough data to make the sorting as // consistent as possible bool operator<(const Bookmark &other) const; // database name static const char * GetDBName() { return "Browser Bookmarks"; } static uint8_t GetDefaultRecType() { return 1; } // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const Bookmark &msg) { msg.Dump(os); return os; } } // namespace Barry #endif barry-0.18.5/src/r_calllog.h0000644001161500056700000000747212242254476015164 0ustar cdfreycdfrey/// /// \file r_calllog.h /// Record parsing class for call logs /// /* Copyright (C) 2008-2009, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_CALLLOG_H__ #define __BARRY_RECORD_CALLLOG_H__ #include "dll.h" #include "record.h" #include #include #include namespace Barry { // forward declarations class IConverter; class BXEXPORT CallLog { public: typedef Barry::UnknownsType UnknownsType; uint8_t RecType; uint32_t RecordId; uint32_t Duration; //< duration of call in seconds uint64_t Timestamp; //< timestamp of call in milliseconds //< use GetTime() to convert to //< a time_t std::string ContactName; std::string PhoneNumber; enum DirectionFlagType { Receiver = 0, //< We have received a call Emitter, //< We have composed a call Failed, //< We have missing a call and the //< emitter is arrived on our //< answering machine Missing //< We have missing a call. The //< emitter has stopped the //< communication. }; DirectionFlagType DirectionFlag; enum StatusFlagType { OK = 0, // Busy, //< We have sent the emitter on our //< answering machine NetError, //< Network communication error Unknown //< Not supported by Barry CallLog parser }; StatusFlagType StatusFlag; enum PhoneTypeFlagType { TypeUndefined = 0, TypeOffice, TypeHome, TypeMobile, TypeUnknown // To be completed (Office2, Home2, Pager ???) }; PhoneTypeFlagType PhoneTypeFlag; enum PhoneInfoFlagType { InfoUndefined = 0, InfoKnown, //< PhoneNumber should be set InfoUnknown, //< PhoneNumber isn't set InfoPrivate //< PhoneNumber is private }; PhoneInfoFlagType PhoneInfoFlag; UnknownsType Unknowns; protected: time_t GetTime() const; static DirectionFlagType DirectionProto2Rec(uint8_t s); static uint8_t DirectionRec2Proto(DirectionFlagType s); static PhoneTypeFlagType PhoneTypeProto2Rec(uint8_t s); static uint8_t PhoneTypeRec2Proto(PhoneTypeFlagType s); public: CallLog(); ~CallLog(); // Parser / Builder API (see parser.h / builder.h) void Validate() const; const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); uint8_t GetRecType() const { return RecType; } uint32_t GetUniqueId() const { return RecordId; } void SetIds(uint8_t Type, uint32_t Id) { RecType = Type; RecordId = Id; } void ParseHeader(const Data &data, size_t &offset); void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); void BuildHeader(Data &data, size_t &offset) const; void BuildFields(Data &data, size_t &offset, const IConverter *ic = 0) const; // operations (common among record classes) void Clear(); void Dump(std::ostream &os) const; std::string GetDescription() const; // Sorting bool operator<(const CallLog &other) const { return Timestamp < other.Timestamp; } // database name static const char * GetDBName() { return "Phone Call Logs"; } static uint8_t GetDefaultRecType() { return 0; } // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const CallLog &msg) { msg.Dump(os); return os; } } // namespace Barry #endif barry-0.18.5/src/connector.h0000644001161500056700000001405312242254476015211 0ustar cdfreycdfrey/// /// \file connector.h /// Base class interface for handling Mode connections to device /// /* Copyright (C) 2011-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_CONNECT_H__ #define __BARRY_CONNECT_H__ #include "dll.h" #include "iconv.h" #include "pin.h" #include "probe.h" #include #include #include namespace Barry { class SocketRoutingQueue; class Controller; namespace Mode { class Desktop; } class BXEXPORT Connector { protected: std::string m_password; bool m_needs_reconnect; Barry::IConverter m_ic; Barry::ProbeResult m_probe_result; int m_connect_count; time_t m_last_disconnect; // bad password status BadPassword m_bpcopy; protected: // helper functions static Barry::ProbeResult FindDevice(Barry::Pin pin); // required overrides by derived classes virtual void StartConnect(const char *password) = 0; virtual void RetryPassword(const char *password) = 0; virtual void FinishConnect() = 0; virtual void DoDisconnect() = 0; /// slightly different than IsConnected()... this returns true /// even if there is a partial connection in progress... /// i.e. this returns true if DoDisconnect() can be safely skipped virtual bool IsDisconnected() = 0; public: Connector(const char *password, const std::string &locale, Barry::Pin pin = 0); Connector(const char *password, const std::string &locale, const Barry::ProbeResult &result); virtual ~Connector(); IConverter& GetIConverter() { return m_ic; } const IConverter& GetIConverter() const { return m_ic; } Barry::ProbeResult& GetProbeResult() { return m_probe_result; } const Barry::ProbeResult& GetProbeResult() const { return m_probe_result; } const Barry::BadPassword& GetBadPassword() const { return m_bpcopy; } virtual void ClearPassword(); virtual void SetPassword(const char *password); /// Returns true if connected, false if user cancelled, throws /// Barry exception on error. Note that in the case of a bad /// password, this will return false on the first password try, /// unless you override PasswordPrompt() below. In the default /// case, a false here means the password was invalid, and you /// should use GetBadPassword() to report the error. virtual bool Connect(); /// Disconnects from the device virtual void Disconnect(); /// Returns same as Connect(), but normally remembers the password /// and so avoids prompting the user if possible. Password prompts /// are still possible though, if you have called ClearPassword(). /// /// It is valid to call Reconnect() without ever calling Connect(), /// since Reconnect() is simply a wrapper that handles retries. virtual bool Reconnect(int total_tries = 2); /// Calls Reconnect() (and returns it's result) only if you have /// called RequireDirtyReconnect(). Otherwise, does nothing, but /// returns true. virtual bool ReconnectForDirtyFlags(); /// Returns true if connected, false if not virtual bool IsConnected() = 0; /// This function flags the Connector object so that a future /// call to ReconnectForDirtyFlags() will actually Reconnect(). /// This is needed in cases where you are updating the device, /// and require that the dirty flags on the device itself are /// properly cleared and updated. In this case, you must call /// ReconnectForDirtyFlags() before Desktop::GetRecordStateTable(). /// Disconnecting from the device, or reconnecting, clears the flag. virtual void RequireDirtyReconnect(); // // Callbacks, overridden by the application // /// App should prompt user for password, fill password_result with /// what he enters and then return true. Return false if user /// wishes to stop trying. /// /// This function is *not* called from inside a catch() routine, /// so it is safe to throw exceptions from it if you must. virtual bool PasswordPrompt(const Barry::BadPassword &bp, std::string &password_result) = 0; }; class BXEXPORT DesktopConnector : public Connector { Barry::SocketRoutingQueue *m_router; std::auto_ptr m_con; std::auto_ptr m_desktop; int m_connect_timeout; protected: virtual void StartConnect(const char *password); virtual void RetryPassword(const char *password); virtual void FinishConnect(); virtual void DoDisconnect(); virtual bool IsDisconnected(); public: // Override the timeout due to a firmware issue... sometimes // the firmware will hang during a Reconnect, and fail to // respond to a Desktop::Open(). To work around this, we // set the default timeout to 10 seconds so that we find this // failure early enough to fix it within opensync's 30 second timeout. // Then if we get such a timeout, we do the Reconnect again and // hope for the best... this often fixes it. // DesktopConnector(const char *password, const std::string &locale, Barry::Pin pin = 0, Barry::SocketRoutingQueue *router = 0, int connect_timeout = 10000); DesktopConnector(const char *password, const std::string &locale, const Barry::ProbeResult &result, Barry::SocketRoutingQueue *router = 0, int connect_timeout = 10000); virtual bool IsConnected(); virtual bool PasswordPrompt(const Barry::BadPassword &bp, std::string &password_result) { // default to only trying the existing password once return false; } // // Do not use these functions if IsConnected() returns false // Controller& GetController() { return *m_con; } Mode::Desktop& GetDesktop() { return *m_desktop; } const Controller& GetController() const { return *m_con; } const Mode::Desktop& GetDesktop() const{ return *m_desktop; } }; } #endif barry-0.18.5/src/j_manager.cc0000644001161500056700000000217612242254476015303 0ustar cdfreycdfrey/// /// \file j_manager.cc /// Application management classes /// /* Copyright (C) 2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #include "j_manager.h" #include "dp_codinfo.h" #include "debug.h" namespace Barry { namespace JDWP { // JDWAppInfo class //------------------ void JDWAppInfo::Load(JDG::CodInfo &info) { dout("JDWAppInfo::load" << endl); // Assign uniqueId uniqueId = info.GetUniqueId(); // Add Class (concat with a previous list) JDG::ClassList *list = &(info.classList); classList.insert(classList.end(), list->begin(), list->end()); } }} // namespace Barry::JDWP barry-0.18.5/src/vjournal.cc0000644001161500056700000001202312242254476015210 0ustar cdfreycdfrey/// /// \file vjournal.cc /// Conversion routines for vjournals (VCALENDAR, etc) /// /* Copyright (C) 2008-2009, Nicolas VIVIEN Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "vjournal.h" //#include "trace.h" #include #include #include #include namespace Barry { namespace Sync { ////////////////////////////////////////////////////////////////////////////// // vJournal vJournal::vJournal(vTimeConverter &vtc) : m_vtc(vtc) , m_gJournalData(0) { } vJournal::~vJournal() { if( m_gJournalData ) { g_free(m_gJournalData); } } bool vJournal::HasMultipleVJournals() const { int count = 0; b_VFormat *format = const_cast(Format()); GList *attrs = format ? b_vformat_get_attributes(format) : 0; for( ; attrs; attrs = attrs->next ) { b_VFormatAttribute *attr = (b_VFormatAttribute*) attrs->data; if( strcasecmp(b_vformat_attribute_get_name(attr), "BEGIN") == 0 && strcasecmp(b_vformat_attribute_get_nth_value(attr, 0), "VJOURNAL") == 0 ) { count++; } } return count > 1; } // Main conversion routine for converting from Barry::Memo to // a vJournal string of data. const std::string& vJournal::ToMemo(const Barry::Memo &memo) { // Trace trace("vJournal::ToMemo"); std::ostringstream oss; memo.Dump(oss); // trace.logf("ToMemo, initial Barry record: %s", oss.str().c_str()); // start fresh Clear(); SetFormat( b_vformat_new() ); if( !Format() ) throw ConvertError(_("resource error allocating vformat")); // store the Barry object we're working with m_BarryMemo = memo; // RFC section 4.8.7.2 requires DTSTAMP in all VEVENT, VTODO, // VJOURNAL, and VFREEBUSY calendar components, and it must be // in UTC. DTSTAMP holds the timestamp of when the iCal object itself // was created, not when the object was created in the device or app. // So, find out what time it is "now". time_t now = time(NULL); // begin building vJournal data AddAttr(NewAttr("PRODID", "-//OpenSync//NONSGML Barry Memo Record//EN")); AddAttr(NewAttr("BEGIN", "VJOURNAL")); AddAttr(NewAttr("DTSTAMP", m_vtc.unix2vtime(&now).c_str())); // see note above AddAttr(NewAttr("SEQUENCE", "0")); AddAttr(NewAttr("SUMMARY", memo.Title.c_str())); AddAttr(NewAttr("DESCRIPTION", memo.Body.c_str())); AddAttr(NewAttr("CATEGORIES", ToStringList(memo.Categories).c_str())); // FIXME - add a truly globally unique "UID" string? AddAttr(NewAttr("END", "VJOURNAL")); // generate the raw VJOURNAL data m_gJournalData = b_vformat_to_string(Format(), VFORMAT_NOTE); m_vJournalData = m_gJournalData; // trace.logf("ToMemo, resulting vjournal data: %s", m_vJournalData.c_str()); return m_vJournalData; } // Main conversion routine for converting from vJournal data string // to a Barry::Memo object. const Barry::Memo& vJournal::ToBarry(const char *vjournal, uint32_t RecordId) { using namespace std; // Trace trace("vJournal::ToBarry"); // trace.logf("ToBarry, working on vmemo data: %s", vjournal); // we only handle vJournal data with one vmemo block if( HasMultipleVJournals() ) throw ConvertError(_("vCalendar data contains more than one VJOURNAL block, unsupported")); // start fresh Clear(); // store the vJournal raw data m_vJournalData = vjournal; // create format parser structures SetFormat( b_vformat_new_from_string(vjournal) ); if( !Format() ) throw ConvertError(_("resource error allocating vjournal")); string title = GetAttr("SUMMARY", "/vjournal"); // trace.logf("SUMMARY attr retrieved: %s", title.c_str()); if( title.size() == 0 ) { title = ""; // trace.logf("ERROR: bad data, blank SUMMARY: %s", vjournal); } string body = GetAttr("DESCRIPTION", "/vjournal"); // trace.logf("DESCRIPTION attr retrieved: %s", body.c_str()); // // Now, run checks and convert into Barry object // Barry::Memo &rec = m_BarryMemo; rec.SetIds(Barry::Memo::GetDefaultRecType(), RecordId); rec.Title = title; rec.Body = body; rec.Categories = GetValueVector("CATEGORIES","/vjournal"); std::ostringstream oss; m_BarryMemo.Dump(oss); // trace.logf("ToBarry, resulting Barry record: %s", oss.str().c_str()); return m_BarryMemo; } // Transfers ownership of m_gMemoData to the caller. char* vJournal::ExtractVJournal() { char *ret = m_gJournalData; m_gJournalData = 0; return ret; } void vJournal::Clear() { vBase::Clear(); m_vJournalData.clear(); m_BarryMemo.Clear(); if( m_gJournalData ) { g_free(m_gJournalData); m_gJournalData = 0; } } }} // namespace Barry::Sync barry-0.18.5/src/m_jvmdebug.cc0000644001161500056700000005470012242254476015477 0ustar cdfreycdfrey/// /// \file m_jvmdebug.cc /// Mode class for the JVMDebug mode /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2008-2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "m_jvmdebug.h" #include "data.h" #include "protocol.h" #include "protostructs.h" #include "packet.h" #include "endian.h" #include "error.h" #include "usbwrap.h" #include "controller.h" #include "cod.h" #include #include #include #include #include #include #include #include "ios_state.h" #include "debug.h" using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // JDModulesList class void JVMModulesList::Parse(const Data &entry_packet) { uint32_t count = 0; size_t size = entry_packet.GetSize(); while (count < size) { uint16_t len = 0; const unsigned char *ptr = (entry_packet.GetData() + count); Protocol::JVMModulesEntry *e = (Protocol::JVMModulesEntry *) ptr; len = SB_JVMMODULES_ENTRY_HEADER_SIZE + be_btohs(e->sizename); if( (count + len) > size ) break; JVMModulesEntry entry; entry.Id = be_btohl(e->id); entry.UniqueID = be_btohl(e->uniqueId); (entry.Name).assign((char *) (ptr + SB_JVMMODULES_ENTRY_HEADER_SIZE), be_btohs(e->sizename)); push_back(entry); count += len; } } void JVMModulesList::Dump(std::ostream &os) const { ios_format_state state(os); const_iterator i = begin(), e = end(); os << _(" ID ") << "|"; os << _(" UniqueID ") << "|"; os << _(" Module Name") << endl; os << "------------+"; os << "------------+"; os << "-------------"; os << endl; for( ; i != e; ++i ) { (*i).Dump(os); } } /////////////////////////////////////////////////////////////////////////////// // JVMModulesEntry class void JVMModulesEntry::Dump(std::ostream &os) const { ios_format_state state(os); os << " 0x" << setfill('0') << setw(8) << hex << Id << " |"; os << " 0x" << setfill('0') << setw(8) << hex << UniqueID << " |"; os << " " << Name << endl; } /////////////////////////////////////////////////////////////////////////////// // JVMThreadsList class void JVMThreadsList::Parse(const Data &entry_packet) { uint32_t count = 0; size_t size = entry_packet.GetSize(); while (count < size) { uint16_t len = 0; const unsigned char *ptr = (entry_packet.GetData() + count); uint32_t *e = (uint32_t *) ptr; len = sizeof(uint32_t); if( (count + len) > size ) break; JVMThreadsEntry entry; entry.Id = be_btohl(*e); push_back(entry); count += len; } } void JVMThreadsList::Dump(std::ostream &os) const { ios_format_state state(os); const_iterator i = begin(), e = end(); os << _(" Thread ") << "|"; os << _(" Address ") << "|"; os << _(" Byte ") << "|"; os << _(" Unknown01 ") << "|"; os << _(" Unknown02 ") << "|"; os << _(" Unknown03 ") << "|"; os << _(" Unknown04 ") << "|"; os << _(" Unknown05 ") << "|"; os << _(" Unknown06 ") << "|"; os << "------------+"; os << "------------+"; os << "------+"; os << "------------+"; os << "------------+"; os << "------------+"; os << "------------+"; os << "------------+"; os << "-------------"; os << endl; for(int k=0 ; i != e; ++i, k++ ) { (*i).Dump(os, k); } } void JVMThreadsEntry::Dump(std::ostream &os, int num) const { ios_format_state state(os); os << " " << setfill(' ') << setw(8) << dec << num << " |"; os << " 0x" << setfill('0') << setw(8) << hex << (Id) << " |"; os << " 0x" << setfill('0') << setw(2) << hex << (Byte) << " |"; os << " 0x" << setfill('0') << setw(8) << hex << (Address) << " |"; os << " 0x" << setfill('0') << setw(8) << hex << (Unknown01) << " |"; os << " 0x" << setfill('0') << setw(8) << hex << (Unknown02) << " |"; os << " 0x" << setfill('0') << setw(8) << hex << (Unknown03) << " |"; os << " 0x" << setfill('0') << setw(8) << hex << (Unknown04) << " |"; os << " 0x" << setfill('0') << setw(8) << hex << (Unknown05) << " |"; os << " 0x" << setfill('0') << setw(8) << hex << (Unknown06) << endl; } namespace Mode { /////////////////////////////////////////////////////////////////////////////// // JVMDebug Mode class JVMDebug::JVMDebug(Controller &con) : Mode(con, Controller::JVMDebug) , m_Attached(false) { } JVMDebug::~JVMDebug() { if( m_Attached ) Detach(); } /////////////////////////////////////////////////////////////////////////////// // protected members /////////////////////////////////////////////////////////////////////////////// // public API void JVMDebug::OnOpen() { } // FIXME - is this necessary? and if it is, wouldn't it be better // in the m_jvmdebug mode class? I'm not convinced that applications // should have to bother with socket-level details. void JVMDebug::Close() { if( m_ModeSocket ) { m_socket->Close(); m_socket.reset(); m_ModeSocket = 0; } } // // Attach // /// These commands are sent to prepare the debug communication. /// Must be called at the start of a JVMDebug session. /// void JVMDebug::Attach() { } // // Detach // /// Must be called at the end of a JVMDebug session. The JVM_GOODBYE /// command is sent to the device. /// void JVMDebug::Detach() { } void JVMDebug::ThrowJVMError(const std::string &msg, uint8_t cmd) { std::ostringstream oss; oss << msg << ": " << _("unexpected packet command code: ") << "0x" << std::hex << (unsigned int) cmd; throw Error(oss.str()); } // // Unknown 01 ??? // void JVMDebug::Unknown01() { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.Unknown01(); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::Unknown01(): ") + _("byte count mismatch"), expect); } } // // Unknown 02 ??? // void JVMDebug::Unknown02() { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.Unknown02(); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::Unknown02(): ") + _("byte count mismatch"), expect); } } // // Unknown 03 ??? // void JVMDebug::Unknown03() { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.Unknown03(); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::Unknown03(): ") + _("byte count mismatch"), expect); } } // // Unknown 04 ??? // void JVMDebug::Unknown04() { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.Unknown04(); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::Unknown04(): ") + _("byte count mismatch"), expect); } } // // Unknown 05 ??? // void JVMDebug::Unknown05() { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.Unknown05(); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::Unknown05(): ") + _("byte count mismatch"), expect); } } // // Unknown 06 ??? // void JVMDebug::Unknown06() { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.Unknown06(); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::Unknown06(): ") + _("byte count mismatch"), expect); } } // // Unknown 07 ??? // void JVMDebug::Unknown07() { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.Unknown07(); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::Unknown07(): ") + _("byte count mismatch"), expect); } } // // Unknown 08 ??? // void JVMDebug::Unknown08() { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.Unknown08(); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::Unknown08(): ") + _("byte count mismatch"), expect); } } // // Unknown 09 ??? // void JVMDebug::Unknown09() { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.Unknown09(); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::Unknown09(): ") + _("byte count mismatch"), expect); } } // // Unknown 10 ??? // void JVMDebug::Unknown10() { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.Unknown10(); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::Unknown10(): ") + _("byte count mismatch"), expect); } } // // Get Status // bool JVMDebug::GetStatus(int &status) { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.GetStatus(); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return false; // Read the data stream m_socket->Receive(response); MAKE_JVMPACKET(dpack, response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::GetStatus():") + _("byte count mismatch"), expect); } // Make sure we have a header to read CheckSize(response, SB_JVMPACKET_HEADER_SIZE + sizeof(dpack->u.status)); // Return status status = dpack->u.status; return true; } // // Wait Status // bool JVMDebug::WaitStatus(int &status) { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Prepare the command packet packet.GetStatus(); try { m_socket->Receive(packet.GetReceive(), 100); } catch (Usb::Timeout &DEBUG_ONLY(to) ) { return false; } expect = packet.Size(); if (expect == 0) return false; // Read the data stream m_socket->Receive(response); MAKE_JVMPACKET(dpack, response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::WaitStatus():") + _("byte count mismatch"), expect); } // Make sure we have a header to read CheckSize(response, SB_JVMPACKET_HEADER_SIZE + sizeof(dpack->u.status)); // Return status status = dpack->u.status; return true; } // // Get Console Message // Sample, display the output of System.out.println(...) and all JVM messages output // // Return the length message or -1 if message doesn't exit or is empty // int JVMDebug::GetConsoleMessage(std::string &message) { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.GetConsoleMessage(); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return -1; // Read the data stream m_socket->Receive(response); MAKE_JVMPACKET(dpack, response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::GetConsoleMessage():") + _("byte count mismatch"), expect); } // Make sure we have a header to read CheckSize(response, SB_JVMPACKET_HEADER_SIZE + sizeof(dpack->u.msglength)); // Length of message uint16_t length = be_btohs(dpack->u.msglength); if (length == 0) return -1; CheckSize(response, SB_JVMPACKET_HEADER_SIZE + sizeof(dpack->u.msglength) + length); // Parse the ID of nextmodules const unsigned char *ptr = (response.GetData() + SB_JVMPACKET_HEADER_SIZE + sizeof(dpack->u.msglength)); message.assign((char *) ptr, length); return length; } // // Get list of Java modules // void JVMDebug::GetModulesList(JVMModulesList &mylist) { uint32_t size = 0; uint32_t offset = 0; uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); do { // Send the command packet packet.GetModulesList(offset); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) break; // Read the data stream m_socket->Receive(response); // MAKE_JVMPACKET(dpack, response); // unused size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::GetModulesList():") + _("byte count mismatch"), expect); } // Make sure there's enough for packet header + module list // header + 4 bytes of ID CheckSize(response, SB_JVMPACKET_HEADER_SIZE + SB_JVMMODULES_LIST_HEADER_SIZE + 4); // Number of modules entries in the list // (Valid, but unused variable... disabled to stop compiler // warnings) // uint32_t count = be_btohl(dpack->u.moduleslist.nbr); // Size of modules list // I remove the header of packet (contains the field 'number of modules') // and 4 bytes (contains the field 'ID of next modules') size = bytereceived - SB_JVMMODULES_LIST_HEADER_SIZE - 4; // Parse the modules list mylist.Parse(Data(response.GetData() + SB_JVMPACKET_HEADER_SIZE + SB_JVMMODULES_LIST_HEADER_SIZE, size)); // Parse the ID of nextmodules size_t id_offset = SB_JVMPACKET_HEADER_SIZE + SB_JVMMODULES_LIST_HEADER_SIZE + size; const unsigned char *ptr = (response.GetData() + id_offset); CheckSize(response, id_offset + sizeof(uint32_t)); uint32_t *poffset = (uint32_t *) ptr; offset = be_btohl(*poffset); } while (offset != 0); // When the offset != 0, there is some modules } // // Get list of Java threads // void JVMDebug::GetThreadsList(JVMThreadsList &mylist) { uint32_t size = 0; uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.GetThreadsList(); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); // MAKE_JVMPACKET(dpack, response); // unused size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::GetThreadsList():") + _("byte count mismatch"), expect); } CheckSize(response, SB_JVMPACKET_HEADER_SIZE + SB_JVMTHREADS_LIST_HEADER_SIZE); // Number of threads entries in the list // (Valid, but unused variable... disabled to stop compiler warnings) // uint32_t count = be_btohl(dpack->u.threadslist.nbr); // Size of threads list // I remove the header of packet (contains the field 'number of threads') size = bytereceived - SB_JVMTHREADS_LIST_HEADER_SIZE; // Parse the threads list mylist.Parse(Data(response.GetData() + SB_JVMPACKET_HEADER_SIZE + SB_JVMTHREADS_LIST_HEADER_SIZE, size)); // Complete threads list JVMThreadsList::iterator b = mylist.begin(); for( ; b != mylist.end(); b++ ) { JVMThreadsEntry entry = (*b); // 1°/ // Send the command packet packet.Unknown11(entry.Id); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); MAKE_JVMPACKET(dpack, response); bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::GetThreadsList() (1):") + _("byte count mismatch"), expect); } CheckSize(response, SB_JVMPACKET_HEADER_SIZE + SB_JVMUNKNOWN01_HEADER_SIZE); // Save values entry.Byte = dpack->u.unknown01.byte; entry.Address = be_btohl(dpack->u.unknown01.address); // 2°/ if (entry.Address != 0) { // Send the command packet packet.Unknown12(entry.Address); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); MAKE_JVMPACKET(dpack, response); bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::GetThreadsList() (2):") + _("byte count mismatch"), expect); } // Save values CheckSize(response, SB_JVMPACKET_HEADER_SIZE + sizeof(dpack->u.address)); entry.Unknown01 = be_btohl(dpack->u.address); } else entry.Unknown01 = 0; // 3°/ // Send the command packet packet.Unknown13(entry.Id); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); dpack = (const Protocol::JVMPacket *) response.GetData(); bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::GetThreadsList() (3):") + _("byte count mismatch"), expect); } // Save values CheckSize(response, SB_JVMPACKET_HEADER_SIZE + sizeof(dpack->u.address)); entry.Unknown02 = be_btohl(dpack->u.address); // 4°/ // Send the command packet packet.Unknown14(entry.Id); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); dpack = (const Protocol::JVMPacket *) response.GetData(); bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::GetThreadsList() (4):") + _("byte count mismatch"), expect); } // Save values CheckSize(response, SB_JVMPACKET_HEADER_SIZE + SB_JVMUNKNOWN02_HEADER_SIZE); entry.Unknown03 = be_btohl(dpack->u.unknown02.address1); entry.Unknown04 = be_btohl(dpack->u.unknown02.address2); // 5°/ // Send the command packet packet.Unknown15(entry.Id); m_socket->Packet(packet); expect = packet.Size(); if (expect == 0) return; // Read the data stream m_socket->Receive(response); dpack = (const Protocol::JVMPacket *) response.GetData(); bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::GetThreadsList() (5):") + _("byte count mismatch"), expect); } // Save values CheckSize(response, SB_JVMPACKET_HEADER_SIZE + SB_JVMUNKNOWN02_HEADER_SIZE); entry.Unknown05 = be_btohl(dpack->u.unknown02.address1); entry.Unknown06 = be_btohl(dpack->u.unknown02.address2); // Save... (*b) = entry; } } // // Go // void JVMDebug::Go() { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.Go(); m_socket->Packet(packet); expect = packet.Size(); while (expect == 0) { m_socket->Receive(packet.GetReceive()); expect = packet.Size(); } // Read the data stream m_socket->Receive(response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::Go():") + _("byte count mismatch"), expect); } } // // Stop // void JVMDebug::Stop() { uint16_t expect = 0; Data command(-1, 8), response; JVMPacket packet(command, response); // Send the command packet packet.Stop(); m_socket->Packet(packet); expect = packet.Size(); while (expect == 0) { m_socket->Receive(packet.GetReceive()); expect = packet.Size(); } // Read the data stream m_socket->Receive(response); size_t bytereceived = response.GetSize() - SB_JVMPACKET_HEADER_SIZE; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJVMError(string("JVMDebug::Stop():") + _("byte count mismatch"), expect); } } }} // namespace Barry::Mode barry-0.18.5/src/j_jdwp.cc0000644001161500056700000000564512242254476014641 0ustar cdfreycdfrey/// /// \file j_jdwp.cc /// JDWP socket communication implementation /// /* Copyright (C) 2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "j_jdwp.h" #include "data.h" #include #include #include #include namespace Barry { namespace JDWP { /////////////////////////////////////////////////////////////////////////////// // JDWP::Error exception class static std::string GetErrorString(int errcode, const std::string &str) { std::ostringstream oss; oss << "("; if( errcode ) { oss << std::setbase(10) << errcode << ", "; } // oss << strerror(-libusb_errno) << "): " oss << "): "; oss << str; return oss.str(); } Error::Error(const std::string &str) : Barry::Error(GetErrorString(0, str)) , m_errcode(0) { } Error::Error(int errcode, const std::string &str) : Barry::Error(GetErrorString(errcode, str)) , m_errcode(errcode) { } /////////////////////////////////////////////////////////////////////////////// // JDWP::JDWP communication class JDWP::JDWP() { } JDWP::~JDWP() { } bool JDWP::Read(int socket, Barry::Data &data, int timeout) { int ret; do { data.QuickZap(); ret = read(socket, (char*) data.GetBuffer(), data.GetBufSize()); if( ret < 0 ) { ret = -errno; if (ret != -EINTR && ret != -EAGAIN ) { m_lasterror = ret; if( ret == -ETIMEDOUT ) throw Timeout(ret, _("Timeout in read")); else throw Error(ret, _("Error in read")); } } else data.ReleaseBuffer(ret); } while( ret == -EINTR ); return ret >= 0; } bool JDWP::Write(int socket, const Barry::Data &data, int timeout) { int ret; do { ret = write(socket, (char*) data.GetData(), data.GetSize()); if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) { m_lasterror = ret; if( ret == -ETIMEDOUT ) throw Timeout(ret, _("Timeout in write (1)")); else throw Error(ret, _("Error in write (1)")); } } while( ret == -EINTR || ret == -EAGAIN ); return ret >= 0; } bool JDWP::Write(int socket, const void *data, size_t size, int timeout) { int ret; do { ret = write(socket, (char*) data, size); if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) { m_lasterror = ret; if( ret == -ETIMEDOUT ) throw Timeout(ret, _("Timeout in write (2)")); else throw Error(ret, _("Error in write (2)")); } } while( ret == -EINTR || ret == -EAGAIN ); return ret >= 0; } }} // namespace JDWP barry-0.18.5/src/sha1.cc0000644001161500056700000001312712242254476014212 0ustar cdfreycdfrey/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is SHA 180-1 Reference Implementation (Compact version) * * The Initial Developer of the Original Code is Paul Kocher of * Cryptography Research. Portions created by Paul Kocher are * Copyright (C) 1995-9 by Cryptography Research, Inc. All * Rights Reserved. * * Contributor(s): * * Paul Kocher * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */ /* Copied from the git sources, with the following revision history: commit 77ab8798d3f8df39877235be17bb6e70077aaba2 Author: Junio C Hamano Date: Tue Nov 1 10:56:03 2005 -0800 Fix constness of input in mozilla-sha1/sha1.c::SHA1_Update(). Among the three of our own implementations, only this one lacked "const" from the second argument. Signed-off-by: Junio C Hamano commit cef661fc799a3a13ffdea4a3f69f1acd295de53d Author: Linus Torvalds Date: Thu Apr 21 12:33:22 2005 -0700 Add support for alternate SHA1 library implementations. This one includes the Mozilla SHA1 implementation sent in by Edgar Toernig. It's dual-licenced under MPL-1.1 or GPL, so in the context of git, we obviously use the GPL version. Side note: the Mozilla SHA1 implementation is about twice as fast as the default openssl one on my G5, but the default openssl one has optimized x86 assembly language on x86. So choose wisely. */ #include "sha1.h" namespace Barry { static void shaHashBlock(SHA_CTX *ctx); void SHA1(const void *dataIn, int len, unsigned char *hashout) { SHA_CTX ctx; SHA1_Init(&ctx); SHA1_Update(&ctx, dataIn, len); SHA1_Final(hashout, &ctx); } void SHA1_Init(SHA_CTX *ctx) { int i; ctx->lenW = 0; ctx->sizeHi = ctx->sizeLo = 0; /* Initialize H with the magic constants (see FIPS180 for constants) */ ctx->H[0] = 0x67452301; ctx->H[1] = 0xefcdab89; ctx->H[2] = 0x98badcfe; ctx->H[3] = 0x10325476; ctx->H[4] = 0xc3d2e1f0; for (i = 0; i < 80; i++) ctx->W[i] = 0; } void SHA1_Update(SHA_CTX *ctx, const void *_dataIn, int len) { const unsigned char *dataIn = (const unsigned char *) _dataIn; int i; /* Read the data into W and process blocks as they get full */ for (i = 0; i < len; i++) { ctx->W[ctx->lenW / 4] <<= 8; ctx->W[ctx->lenW / 4] |= (unsigned int)dataIn[i]; if ((++ctx->lenW) % 64 == 0) { shaHashBlock(ctx); ctx->lenW = 0; } ctx->sizeLo += 8; ctx->sizeHi += (ctx->sizeLo < 8); } } void SHA1_Final(unsigned char hashout[20], SHA_CTX *ctx) { unsigned char pad0x80 = 0x80; unsigned char pad0x00 = 0x00; unsigned char padlen[8]; int i; /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length */ padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255); padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255); padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255); padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255); padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255); padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255); padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255); padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255); SHA1_Update(ctx, &pad0x80, 1); while (ctx->lenW != 56) SHA1_Update(ctx, &pad0x00, 1); SHA1_Update(ctx, padlen, 8); /* Output hash */ for (i = 0; i < 20; i++) { hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24); ctx->H[i / 4] <<= 8; } /* * Re-initialize the context (also zeroizes contents) */ SHA1_Init(ctx); } #define SHA_ROT(X,n) (((X) << (n)) | ((X) >> (32-(n)))) static void shaHashBlock(SHA_CTX *ctx) { int t; unsigned int A,B,C,D,E,TEMP; for (t = 16; t <= 79; t++) ctx->W[t] = SHA_ROT(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1); A = ctx->H[0]; B = ctx->H[1]; C = ctx->H[2]; D = ctx->H[3]; E = ctx->H[4]; for (t = 0; t <= 19; t++) { TEMP = SHA_ROT(A,5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999; E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP; } for (t = 20; t <= 39; t++) { TEMP = SHA_ROT(A,5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1; E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP; } for (t = 40; t <= 59; t++) { TEMP = SHA_ROT(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdc; E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP; } for (t = 60; t <= 79; t++) { TEMP = SHA_ROT(A,5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6; E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP; } ctx->H[0] += A; ctx->H[1] += B; ctx->H[2] += C; ctx->H[3] += D; ctx->H[4] += E; } } barry-0.18.5/src/vbase.cc0000644001161500056700000002732212242254476014460 0ustar cdfreycdfrey/// /// \file vbase.cc /// vformat support routines in base class /// /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "vbase.h" //#include "trace.h" #include "vformat.h" // comes from opensync, but not a public header yet #include "tzwrapper.h" #include "r_contact.h" // for CategoryList #include #include #include #include #include #include using namespace std; namespace Barry { namespace Sync { ////////////////////////////////////////////////////////////////////////////// // vTimeConverter std::string vTimeConverter::unix2vtime(const time_t *timestamp) { struct tm split; if( !gmtime_r(timestamp, &split) ) { ostringstream oss; oss << _("gmtime_r() failed on time_t of: "); if( timestamp ) oss << *timestamp; else oss << _("(null pointer)"); throw Barry::ConvertError(oss.str()); } return tm_to_iso(&split, true); } time_t vTimeConverter::vtime2unix(const char *vtime) { return TzWrapper::iso_mktime(vtime); } // // The following implementation is taken from opensync's // opensync_time.c implementation with the following copyright // notices at the top as of July 2010: // // * Copyright (C) 2004-2005 Armin Bauer // * Copyright (C) 2006-2008 Daniel Gollub // * Copyright (C) 2007 Chris Frey // // License: LGPL 2.1 or later // int vTimeConverter::alarmduration2sec(const char *alarm) { int i, secs, digits = 0; int is_digit = 0; int sign = 1; // when ical stamp doesn't start with '-' => seconds after event int days = 0, weeks = 0, hours = 0, minutes = 0, seconds = 0; int len = strlen(alarm); for (i=0; i < len; i++) { switch (alarm[i]) { case '-': sign = -1; // seconds before event - change the sign case 'P': case 'T': is_digit = 0; break; case 'W': is_digit = 0; weeks = digits; break; case 'D': is_digit = 0; days = digits; break; case 'H': is_digit = 0; hours = digits; break; case 'M': is_digit = 0; minutes = digits; break; case 'S': is_digit = 0; seconds = digits; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (is_digit) break; if (sscanf((char*)(alarm+i),"%d",&digits) == EOF) return -1; is_digit = 1; break; } } secs = (weeks * 7 * 24 * 3600) + (days * 24 * 3600) + (hours * 3600) + (minutes * 60) + seconds; secs = secs * sign; // change sign if the alarm is in seconds before event (leading '-') return secs; } ////////////////////////////////////////////////////////////////////////////// // vAttr std::string vAttr::GetName() { std::string ret; if( !m_attr ) return ret; const char *name = b_vformat_attribute_get_name(m_attr); if( name ) ret = name; return ret; } std::string vAttr::GetValue(int nth) { std::string ret; const char *value = 0; if( m_attr ) { if( b_vformat_attribute_is_single_valued(m_attr) ) { if( nth == 0 ) value = b_vformat_attribute_get_value(m_attr); } else { value = b_vformat_attribute_get_nth_value(m_attr, nth); } } if( value ) ret = value; return ret; } std::string vAttr::GetDecodedValue() { std::string ret; GString *value = NULL; if( m_attr ) { if( b_vformat_attribute_is_single_valued(m_attr) ) { value = b_vformat_attribute_get_value_decoded(m_attr); } } if( value ) ret.assign(value->str, value->len); return ret; } std::string vAttr::GetParam(const char *name, int nth) { std::string ret; if( !m_attr ) return ret; b_VFormatParam *param = b_vformat_attribute_find_param(m_attr, name, 0); if( !param ) return ret; const char *value = b_vformat_attribute_param_get_nth_value(param, nth); if( value ) ret = value; return ret; } /// Does an exhaustive search through the attribute, searching for all /// param values that exist for the given name, and returns all values /// in a comma delimited string. std::string vAttr::GetAllParams(const char *name) { std::string ret; if( !m_attr ) return ret; b_VFormatParam *param = 0; for( int level = 0; (param = b_vformat_attribute_find_param(m_attr, name, level)); level++ ) { const char *value = 0; for( int nth = 0; (value = b_vformat_attribute_param_get_nth_value(param, nth)); nth++ ) { if( ret.size() ) ret += ","; ret += value; } } return ret; } ////////////////////////////////////////////////////////////////////////////// // vCalendar vBase::vBase() : m_format(b_vformat_new()) { } vBase::vBase(b_VFormat *format) : m_format(format) { if( !format ) throw Barry::Error(_("Cannot construct vBase with null format")); } vBase::~vBase() { if( m_format ) { b_vformat_free(m_format); m_format = 0; } } void vBase::SetFormat(b_VFormat *format) { if( !format ) throw Barry::Error(_("Cannot set vBase with null format")); if( m_format ) { b_vformat_free(m_format); m_format = 0; } m_format = format; } void vBase::Clear() { if( m_format ) { b_vformat_free(m_format); m_format = b_vformat_new(); } } vAttrPtr vBase::NewAttr(const char *name) { // Trace trace("vBase::NewAttr"); // trace.logf("creating valueless attr: %s", name); vAttrPtr attr(b_vformat_attribute_new(NULL, name)); if( !attr.Get() ) throw Barry::ConvertError(_("resource error allocating vformat attribute")); return attr; } vAttrPtr vBase::NewAttr(const char *name, const char *value) { // Trace trace("vBase::NewAttr"); /* some vCard values are positional (like name), so blank should be allowed... if( strlen(value) == 0 ) { trace.logf("attribute '%s' contains no data, skipping", name); return vAttrPtr(); } */ // trace.logf("creating attr: %s, %s", name, value); vAttrPtr attr(b_vformat_attribute_new(NULL, name)); if( !attr.Get() ) throw ConvertError(_("resource error allocating vformat attribute")); b_vformat_attribute_add_value(attr.Get(), value); return attr; } void vBase::AddAttr(vAttrPtr attr) { // Trace trace("vBase::AddAttr"); if( !attr.Get() ) { // trace.log("attribute contains no data, skipping"); return; } b_vformat_add_attribute(m_format, attr.Extract()); } void vBase::AddValue(vAttrPtr &attr, const char *value) { // Trace trace("vBase::AddValue"); if( !attr.Get() ) { // trace.log("attribute pointer contains no data, skipping"); return; } /* if( strlen(value) == 0 ) { trace.log("attribute value is empty, skipping"); return; } */ b_vformat_attribute_add_value(attr.Get(), value); } void vBase::AddEncodedValue(vAttrPtr &attr, b_VFormatEncoding encoding, const char *value, int len) { // Trace trace("vBase::AddValue"); if( !attr.Get() ) { // trace.log("attribute pointer contains no data, skipping"); return; } attr.Get()->encoding = encoding; attr.Get()->encoding_set = TRUE; b_vformat_attribute_add_value_decoded(attr.Get(), value, len); } void vBase::AddParam(vAttrPtr &attr, const char *name, const char *value) { // Trace trace("vBase::AddParam"); if( !attr.Get() ) { // trace.log("attribute pointer contains no data, skipping"); return; } /* if( strlen(value) == 0 ) { trace.log("parameter value is empty, skipping"); return; } */ b_VFormatParam *pParam = b_vformat_attribute_param_new(name); b_vformat_attribute_param_add_value(pParam, value); b_vformat_attribute_add_param(attr.Get(), pParam); } void vBase::AddCategories(const Barry::CategoryList &categories) { if( !categories.size() ) return; vAttrPtr cat = NewAttr("CATEGORIES"); // RFC 2426, 3.6.1 Barry::CategoryList::const_iterator i = categories.begin(); for( ; i < categories.end(); ++i ) { AddValue(cat, i->c_str()); } AddAttr(cat); } std::string vBase::GetAttr(const char *attrname, const char *block) { // Trace trace("vBase::GetAttr"); // trace.logf("getting attr: %s", attrname); std::string ret; const char *value = 0; bool needs_freeing = false; b_VFormatAttribute *attr = b_vformat_find_attribute(m_format, attrname, 0, block); if( attr ) { if( b_vformat_attribute_is_single_valued(attr) ) { value = b_vformat_attribute_get_value(attr); needs_freeing = true; } else { // FIXME, this is hardcoded value = b_vformat_attribute_get_nth_value(attr, 0); } } if( value ) ret = value; if( needs_freeing ) g_free((char *)value); // trace.logf("attr value: %s", ret.c_str()); return ret; } std::vector vBase::GetValueVector(const char *attrname, const char *block) { // Trace trace("vBase::GetValueVector"); // trace.logf("getting value vector for: %s", attrname); std::vector ret; const char *value = 0; bool needs_freeing = false; b_VFormatAttribute *attr = b_vformat_find_attribute(m_format, attrname, 0, block); if( attr ) { if( b_vformat_attribute_is_single_valued(attr) ) { value = b_vformat_attribute_get_value(attr); needs_freeing = true; } else { // nasty, but avoids tweaking vformat. int idx = 0; do { value = b_vformat_attribute_get_nth_value(attr, idx++); if( value ) { ret.push_back(value); } } while( value ); } } if( needs_freeing ) g_free((char *)value); return ret; } vAttr vBase::GetAttrObj(const char *attrname, int nth, const char *block) { // Trace trace("vBase::GetAttrObj"); // trace.logf("getting attr: %s", attrname); return vAttr(b_vformat_find_attribute(m_format, attrname, nth, block)); } std::vector vBase::Tokenize(const std::string& str, const char delim) { std::vector tokens; std::string::size_type delimPos = 0, tokenPos = 0, pos = 0; if( str.length() < 1 ) { return tokens; } while( 1 ) { delimPos = str.find_first_of(delim, pos); tokenPos = str.find_first_not_of(delim, pos); if( std::string::npos != delimPos ) { if( std::string::npos != tokenPos ) { if( tokenPos < delimPos ) { tokens.push_back(str.substr(pos, delimPos-pos)); } else { tokens.push_back(""); } } else { tokens.push_back(""); } pos = delimPos + 1; } else { if( std::string::npos != tokenPos ){ tokens.push_back(str.substr(pos)); } else { tokens.push_back(""); } break; } } return tokens; } std::string vBase::ToStringList(const std::vector &list, const char delim) { std::string str; for( unsigned int idx = 0; idx < list.size(); idx++ ) { if( idx ) { str += delim; } str += list[idx]; } return str; } }} // namespace Barry::Sync barry-0.18.5/src/usbwrap_libusb.cc0000644001161500056700000005266312242254476016411 0ustar cdfreycdfrey/// /// \file usbwrap_libusb.cc /// USB API wrapper for libusb version 0.1 /// /* Copyright (C) 2005-2013, Chris Frey Portions Copyright (C) 2011, RealVNC Ltd. 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "usbwrap_libusb.h" #include "debug.h" #include "data.h" #include #include #include #include #include #ifndef __DEBUG_MODE__ #define __DEBUG_MODE__ #endif #include "debug.h" namespace Usb { // helper function to make deleting pointers in maps and vectors easier template static void deletePtr(T* ptr) { delete ptr; } template static void deleteMapPtr(std::pair ptr) { delete ptr.second; } /////////////////////////////////////////////////////////////////////////////// // Static functions std::string LibraryInterface::GetLastErrorString(int /*libusb_errcode*/) { // Errcode is unused by libusb, so just call the last error return std::string(usb_strerror()); } int LibraryInterface::TranslateErrcode(int libusb_errcode) { // libusb errcode == system errcode return libusb_errcode; } bool LibraryInterface::Init(int *libusb_errno) { // if the environment variable USB_DEBUG is set, that // level value will be used instead of our 9 below... // if you need to *force* this to 9, call SetDataDump(true) // after Init() usb_init(); // Can never fail, so return success return true; } void LibraryInterface::Uninit() { // Nothing to do } void LibraryInterface::SetDataDump(bool data_dump_mode) { if( data_dump_mode ) usb_set_debug(9); else usb_set_debug(0); } /////////////////////////////////////////////////////////////////////////////// // DeviceID DeviceID::DeviceID(DeviceIDImpl* impl) : m_impl(impl) { } DeviceID::~DeviceID() { } const char* DeviceID::GetBusName() const { return m_impl->m_dev->bus->dirname; } uint16_t DeviceID::GetNumber() const { return m_impl->m_dev->devnum; } const char* DeviceID::GetFilename() const { return m_impl->m_dev->filename; } uint16_t DeviceID::GetIdProduct() const { return m_impl->m_dev->descriptor.idProduct; } std::string DeviceID::GetUsbName() const { // for libusb 0.1, we need both the bus name and the filename // and we stay away from the product ID, since that requires // communication with the device, which may not be possible // in error conditions. std::ostringstream oss; oss << GetBusName() << ":" << GetFilename(); return oss.str(); } /////////////////////////////////////////////////////////////////////////////// // DeviceList DeviceList::DeviceList() : m_impl(new DeviceListImpl()) { // Work out what devices are on the bus at the moment usb_find_busses(); usb_find_devices(); struct usb_bus* busses = usb_get_busses(); for( ; busses; busses = busses->next ) { struct usb_device* dev = busses->devices; for( ; dev; dev = dev->next ) { // Add the device to the list of devices std::auto_ptr impl( new DeviceIDImpl() ); impl->m_dev = dev; DeviceID devID(impl.release()); m_impl->m_devices.push_back(devID); } } } DeviceList::~DeviceList() { } static bool ToNum(const char *str, long &num) { char *end = 0; num = strtol(str, &end, 10); return num >= 0 && // no negative numbers num != LONG_MIN && num != LONG_MAX && // no overflow str != end && *end == '\0'; // whole string valid } // // Linux treats bus and device path names as numbers, sometimes left // padded with zeros. Other platforms, such as Windows, use strings, // such as "bus-1" or similar. // // Here we try to convert each string to a number, and if successful, // compare them. If unable to convert, then compare as strings. // This way, "3" == "003" and "bus-foobar" == "bus-foobar". // static bool NameCompare(const char *n1, const char *n2) { long l1, l2; if( ToNum(n1, l1) && ToNum(n2, l2) ) { return l1 == l2; } else { return strcmp(n1, n2) == 0; } } std::vector DeviceList::MatchDevices(int vendor, int product, const char *busname, const char *devname) { std::vector ret; std::vector::iterator iter = m_impl->m_devices.begin(); for( ; iter != m_impl->m_devices.end() ; ++iter ) { struct usb_device* dev = iter->m_impl->m_dev; // only search on given bus if( busname && !NameCompare(busname, dev->bus->dirname) ) continue; // search for specific device if( devname && !NameCompare(devname, dev->filename) ) continue; // is there a match? if( dev->descriptor.idVendor == vendor && ( dev->descriptor.idProduct == product || product == PRODUCT_ANY )) { ret.push_back(*iter); } } return ret; } /////////////////////////////////////////////////////////////////////////////// // Device Device::Device(const Usb::DeviceID& id, int timeout) : m_id(id), m_handle(new DeviceHandle()), m_timeout(timeout) { dout("usb_open(" << std::dec << id.m_impl.get() << ")"); if( !id.m_impl.get() ) throw Error(_("invalid USB device ID")); m_handle->m_handle = usb_open(id.m_impl->m_dev); if( !m_handle->m_handle ) throw Error(_("Failed to open USB device. Please check your system's USB device permissions.")); } Device::~Device() { dout("usb_close(" << std::dec << m_handle->m_handle << ")"); usb_close(m_handle->m_handle); } bool Device::SetConfiguration(unsigned char cfg) { dout("usb_set_configuration(" << std::dec << m_handle->m_handle << ", 0x" << std::hex << (unsigned int) cfg << ")"); int ret = usb_set_configuration(m_handle->m_handle, cfg); m_lasterror = ret; return ret >= 0; } bool Device::ClearHalt(int ep) { dout("usb_clear_halt(" << std::dec << m_handle->m_handle << ", 0x" << std::hex << ep << ")"); int ret = usb_clear_halt(m_handle->m_handle, ep); m_lasterror = ret; return ret >= 0; } bool Device::Reset() { dout("usb_reset(" << std::dec << m_handle->m_handle << ")"); int ret = usb_reset(m_handle->m_handle); m_lasterror = ret; return ret == 0; } bool Device::BulkRead(int ep, Barry::Data &data, int timeout) { int ret; do { data.QuickZap(); ret = usb_bulk_read(m_handle->m_handle, ep, (char*) data.GetBuffer(), data.GetBufSize(), timeout == -1 ? m_timeout : timeout); if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) { m_lasterror = ret; if( ret == -ETIMEDOUT ) throw Timeout(ret, _("Timeout in usb_bulk_read")); else { std::ostringstream oss; oss << _("Error in usb_bulk_read(") << m_handle->m_handle << ", " << ep << ", buf, " << data.GetBufSize() << ")"; throw Error(ret, oss.str()); } } else if( ret > 0 ) data.ReleaseBuffer(ret); } while( ret == -EINTR || ret == -EAGAIN ); return ret >= 0; } bool Device::BulkWrite(int ep, const Barry::Data &data, int timeout) { ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << data); int ret; do { ret = usb_bulk_write(m_handle->m_handle, ep, (char*) data.GetData(), data.GetSize(), timeout == -1 ? m_timeout : timeout); if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) { m_lasterror = ret; if( ret == -ETIMEDOUT ) throw Timeout(ret, _("Timeout in usb_bulk_write (1)")); else throw Error(ret, _("Error in usb_bulk_write (1)")); } } while( ret == -EINTR || ret == -EAGAIN ); return ret >= 0; } bool Device::BulkWrite(int ep, const void *data, size_t size, int timeout) { #ifdef __DEBUG_MODE__ Barry::Data dump(data, size); ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << dump); #endif int ret; do { ret = usb_bulk_write(m_handle->m_handle, ep, (char*) data, size, timeout == -1 ? m_timeout : timeout); if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) { m_lasterror = ret; if( ret == -ETIMEDOUT ) throw Timeout(ret, _("Timeout in usb_bulk_write (2)")); else throw Error(ret, _("Error in usb_bulk_write (2)")); } } while( ret == -EINTR || ret == -EAGAIN ); return ret >= 0; } bool Device::InterruptRead(int ep, Barry::Data &data, int timeout) { int ret; do { data.QuickZap(); ret = usb_interrupt_read(m_handle->m_handle, ep, (char*) data.GetBuffer(), data.GetBufSize(), timeout == -1 ? m_timeout : timeout); if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) { m_lasterror = ret; if( ret == -ETIMEDOUT ) throw Timeout(ret, _("Timeout in usb_interrupt_read")); else throw Error(ret, _("Error in usb_interrupt_read")); } else if( ret > 0 ) data.ReleaseBuffer(ret); } while( ret == -EINTR || ret == -EAGAIN ); return ret >= 0; } bool Device::InterruptWrite(int ep, const Barry::Data &data, int timeout) { ddout("InterruptWrite to endpoint 0x" << std::hex << ep << ":\n" << data); int ret; do { ret = usb_interrupt_write(m_handle->m_handle, ep, (char*) data.GetData(), data.GetSize(), timeout == -1 ? m_timeout : timeout); if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) { m_lasterror = ret; if( ret == -ETIMEDOUT ) throw Timeout(ret, _("Timeout in usb_interrupt_write")); else throw Error(ret, _("Error in usb_interrupt_write")); } } while( ret == -EINTR || ret == -EAGAIN ); return ret >= 0; } // // BulkDrain // /// Reads anything available on the given endpoint, with a low timeout, /// in order to clear any pending reads. /// void Device::BulkDrain(int ep, int timeout) { try { Barry::Data data; while( BulkRead(ep, data, timeout) ) ; } catch( Usb::Error & ) {} } // // GetConfiguration // /// Uses the GET_CONFIGURATION control message to determine the currently /// selected USB configuration, returning it in the cfg argument. /// If unsuccessful, returns false. /// bool Device::GetConfiguration(unsigned char &cfg) { int result = usb_control_msg(m_handle->m_handle, 0x80, USB_REQ_GET_CONFIGURATION, 0, 0, (char*) &cfg, 1, m_timeout); m_lasterror = result; return result >= 0; } // Returns the current power level of the device, or 0 if unknown int Device::GetPowerLevel() { if( !m_id.m_impl->m_dev->config || !m_id.m_impl->m_dev->descriptor.bNumConfigurations < 1 ) return 0; return m_id.m_impl->m_dev->config[0].MaxPower; } std::string Device::GetSimpleSerialNumber() { std::string sn; char buf[1024]; int ret = usb_get_string_simple(m_handle->m_handle, m_id.m_impl->m_dev->descriptor.iSerialNumber, buf, sizeof(buf)); if( ret > 0 ) sn.assign(buf, ret); return sn; } bool Device::IsAttachKernelDriver(int iface) { int ret; char buffer[64]; #if LIBUSB_HAS_GET_DRIVER_NP ret = usb_get_driver_np(m_handle->m_handle, iface, buffer, sizeof(buffer)); if (ret == 0) { dout("interface (" << m_handle->m_handle << ", 0x" << std::hex << iface << ") already claimed by driver \"" << buffer << "\""); return true; } m_lasterror = ret; #else m_lasterror = -ENOSYS; #endif return false; } // Requests that the kernel driver is detached, returning false on failure bool Device::DetachKernelDriver(int iface) { #if LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP int result = usb_detach_kernel_driver_np(m_handle->m_handle, iface); m_lasterror = result; return result >= 0; #else m_lasterror = -ENOSYS; return false; #endif } // Sends a control message to the device, returning false on failure bool Device::ControlMsg(int requesttype, int request, int value, int index, char *bytes, int size, int timeout) { int result = usb_control_msg(m_handle->m_handle, requesttype, request, value, index, bytes, size, timeout); m_lasterror = result; return result >= 0; } int Device::FindInterface(int ifaceClass) { struct usb_config_descriptor *cfg = m_id.m_impl->m_dev->config; if( cfg ) { for( unsigned i = 0; cfg->interface && i < cfg->bNumInterfaces; i++ ) { struct usb_interface *iface = &cfg->interface[i]; for( int a = 0; iface->altsetting && a < iface->num_altsetting; a++ ) { struct usb_interface_descriptor *id = &iface->altsetting[a]; if( id->bInterfaceClass == ifaceClass ) return id->bInterfaceNumber; } } } return -1; } /////////////////////////////////////////////////////////////////////////////// // Interface Interface::Interface(Device &dev, int iface) : m_dev(dev), m_iface(iface) { dout("usb_claim_interface(" << dev.GetHandle()->m_handle << ", 0x" << std::hex << iface << ")"); int ret = usb_claim_interface(dev.GetHandle()->m_handle, iface); if( ret < 0 ) throw Error(ret, _("claim interface failed")); } Interface::~Interface() { dout("usb_release_interface(" << m_dev.GetHandle()->m_handle << ", 0x" << std::hex << m_iface << ")"); usb_release_interface(m_dev.GetHandle()->m_handle, m_iface); } // // SetAltInterface // /// Uses the usb_set_altinterface() function to set the currently /// selected USB alternate setting of the current interface. /// The iface parameter passed in should be a value specified /// in the bAlternateSetting descriptor field. /// If unsuccessful, returns false. /// bool Interface::SetAltInterface(int altSetting) { int result = usb_set_altinterface(m_dev.GetHandle()->m_handle, altSetting); m_dev.SetLastError(result); return result >= 0; } ////////////////////////////////////////////////////////////////// // DeviceDescriptor DeviceDescriptor::DeviceDescriptor(DeviceID& devid) : m_impl(new DeviceDescriptorImpl()) { if( !devid.m_impl.get() ) { dout("DeviceDescriptor: empty devid"); return; } // Copy the descriptor over to our memory m_impl->m_dev = devid.m_impl->m_dev; m_impl->m_desc = devid.m_impl->m_dev->descriptor; dout("device_desc loaded" << "\nbLength: " << std::dec << (unsigned int) m_impl->m_desc.bLength << "\nbDescriptorType: " << std::dec << (unsigned int) m_impl->m_desc.bDescriptorType << "\nbcdUSB: 0x" << std::hex << (unsigned int) m_impl->m_desc.bcdUSB << "\nbDeviceClass: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceClass << "\nbDeviceSubClass: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceSubClass << "\nbDeviceProtocol: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceProtocol << "\nbMaxPacketSize0: " << std::dec << (unsigned int) m_impl->m_desc.bMaxPacketSize0 << "\nidVendor: 0x" << std::hex << (unsigned int) m_impl->m_desc.idVendor << "\nidProduct: 0x" << std::hex << (unsigned int) m_impl->m_desc.idProduct << "\nbcdDevice: 0x" << std::hex << (unsigned int) m_impl->m_desc.bcdDevice << "\niManufacturer: " << std::dec << (unsigned int) m_impl->m_desc.iManufacturer << "\niProduct: " << std::dec << (unsigned int) m_impl->m_desc.iProduct << "\niSerialNumber: " << std::dec << (unsigned int) m_impl->m_desc.iSerialNumber << "\nbNumConfigurations: " << std::dec << (unsigned int) m_impl->m_desc.bNumConfigurations << "\n" ); // Create all the configs for( int i = 0; i < m_impl->m_desc.bNumConfigurations; ++i ) { std::auto_ptr ptr(new ConfigDescriptor(*this, i)); (*this)[ptr->GetNumber()] = ptr.get(); ptr.release(); } } DeviceDescriptor::~DeviceDescriptor() { // Delete any pointers in the map std::for_each(begin(), end(), deleteMapPtr); } /////////////////////////////////////////////////////////////////// // ConfigDescriptor ConfigDescriptor::ConfigDescriptor(DeviceDescriptor& dev, int cfgnumber) : m_impl(new ConfigDescriptorImpl()) { // Copy the config descriptor locally m_impl->m_desc = dev.m_impl->m_dev->config[cfgnumber]; dout(" config_desc #" << std::dec << cfgnumber << " loaded" << "\nbLength: " << std::dec << (unsigned int) m_impl->m_desc.bLength << "\nbDescriptorType: " << std::dec << (unsigned int) m_impl->m_desc.bDescriptorType << "\nwTotalLength: " << std::dec << (unsigned int) m_impl->m_desc.wTotalLength << "\nbNumInterfaces: " << std::dec << (unsigned int) m_impl->m_desc.bNumInterfaces << "\nbConfigurationValue: " << std::dec << (unsigned int) m_impl->m_desc.bConfigurationValue << "\niConfiguration: " << std::dec << (unsigned int) m_impl->m_desc.iConfiguration << "\nbmAttributes: 0x" << std::hex << (unsigned int) m_impl->m_desc.bmAttributes << "\nMaxPower: " << std::dec << (unsigned int) m_impl->m_desc.MaxPower << "\n" ); // just for debugging purposes, check for extra descriptors, and // dump them to dout if they exist if( m_impl->m_desc.extra ) { dout("while parsing config descriptor, found a block of extra descriptors:"); Barry::Data data(m_impl->m_desc.extra, m_impl->m_desc.extralen); dout(data); } // Create all the interfaces for( int i = 0; i < m_impl->m_desc.bNumInterfaces; ++i ) { struct usb_interface* interface = &(m_impl->m_desc.interface[i]); if( !interface->altsetting ) { dout("ConfigDescriptor: empty altsetting"); // some devices are buggy and return a higher bNumInterfaces // than the number of interfaces available... in this case // we just skip and continue continue; } for( int j = 0; j < interface->num_altsetting; ++j ) { std::auto_ptr ptr( new InterfaceDescriptor(*this, i, j)); (*this)[ptr->GetNumber()] = ptr.get(); ptr.release(); } } } ConfigDescriptor::~ConfigDescriptor() { // Delete any pointers in the map std::for_each(begin(), end(), deleteMapPtr); } uint8_t ConfigDescriptor::GetNumber() const { return m_impl->m_desc.bConfigurationValue; } ///////////////////////////////////////////////////////////////////////// // InterfaceDescriptor InterfaceDescriptor::InterfaceDescriptor(ConfigDescriptor& cfg, int interface, int altsetting) : m_impl(new InterfaceDescriptorImpl()) { // Copy the descriptor m_impl->m_desc = cfg.m_impl->m_desc .interface[interface] .altsetting[altsetting]; dout(" interface_desc #" << std::dec << interface << " loaded" << "\nbLength: " << std::dec << (unsigned) m_impl->m_desc.bLength << "\nbDescriptorType: " << std::dec << (unsigned) m_impl->m_desc.bDescriptorType << "\nbInterfaceNumber: " << std::dec << (unsigned) m_impl->m_desc.bInterfaceNumber << "\nbAlternateSetting: " << std::dec << (unsigned) m_impl->m_desc.bAlternateSetting << "\nbNumEndpoints: " << std::dec << (unsigned) m_impl->m_desc.bNumEndpoints << "\nbInterfaceClass: " << std::dec << (unsigned) m_impl->m_desc.bInterfaceClass << "\nbInterfaceSubClass: " << std::dec << (unsigned) m_impl->m_desc.bInterfaceSubClass << "\nbInterfaceProtocol: " << std::dec << (unsigned) m_impl->m_desc.bInterfaceProtocol << "\niInterface: " << std::dec << (unsigned) m_impl->m_desc.iInterface << "\n" ); if( !m_impl->m_desc.endpoint ) { dout("InterfaceDescriptor: empty interface pointer"); return; } // Create all the endpoints for( int i = 0; i < m_impl->m_desc.bNumEndpoints; ++i ) { std::auto_ptr ptr ( new EndpointDescriptor(*this, i)); this->push_back(ptr.get()); ptr.release(); } // just for debugging purposes, check for extra descriptors, and // dump them to dout if they exist if( m_impl->m_desc.extra ) { dout("while parsing interface descriptor, found a block of extra descriptors:"); Barry::Data data(m_impl->m_desc.extra, m_impl->m_desc.extralen); dout(data); } } InterfaceDescriptor::~InterfaceDescriptor() { // Delete any pointers in the vector std::for_each(begin(), end(), deletePtr); } uint8_t InterfaceDescriptor::GetClass() const { return m_impl->m_desc.bInterfaceClass; } uint8_t InterfaceDescriptor::GetNumber() const { return m_impl->m_desc.bInterfaceNumber; } uint8_t InterfaceDescriptor::GetAltSetting() const { return m_impl->m_desc.bAlternateSetting; } ///////////////////////////////////////////////////////////////////////////////// // EndpointDescriptor EndpointDescriptor::EndpointDescriptor(InterfaceDescriptor& interface, int endpoint) : m_impl(new EndpointDescriptorImpl()), m_read(false), m_addr(0), m_type(InvalidType) { // Copy the descriptor m_impl->m_desc = interface.m_impl->m_desc.endpoint[endpoint]; dout(" endpoint_desc #" << std::dec << endpoint << " loaded" << "\nbLength: " << std::dec << (unsigned ) m_impl->m_desc.bLength << "\nbDescriptorType: " << std::dec << (unsigned ) m_impl->m_desc.bDescriptorType << "\nbEndpointAddress: 0x" << std::hex << (unsigned ) m_impl->m_desc.bEndpointAddress << "\nbmAttributes: 0x" << std::hex << (unsigned ) m_impl->m_desc.bmAttributes << "\nwMaxPacketSize: " << std::dec << (unsigned ) m_impl->m_desc.wMaxPacketSize << "\nbInterval: " << std::dec << (unsigned ) m_impl->m_desc.bInterval << "\nbRefresh: " << std::dec << (unsigned ) m_impl->m_desc.bRefresh << "\nbSynchAddress: " << std::dec << (unsigned ) m_impl->m_desc.bSynchAddress << "\n" ); // Set up variables m_read = ((m_impl->m_desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) != 0); m_addr = (m_impl->m_desc.bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK); int type = (m_impl->m_desc.bmAttributes & USB_ENDPOINT_TYPE_MASK); m_type = static_cast(type); // just for debugging purposes, check for extra descriptors, and // dump them to dout if they exist if( m_impl->m_desc.extra ) { dout("while parsing endpoint descriptor, found a block of extra descriptors:"); Barry::Data data(m_impl->m_desc.extra, m_impl->m_desc.extralen); dout(data); } } EndpointDescriptor::~EndpointDescriptor() { } } // namespace Usb barry-0.18.5/src/r_memo.cc0000644001161500056700000001455412242254476014641 0ustar cdfreycdfrey/// /// \file r_memo.cc /// Record parsing class for the memo database. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2007, Brian Edginton 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "r_memo.h" #include "record-internal.h" #include "protostructs.h" #include "data.h" #include "time.h" #include "iconv.h" #include #include #include "ios_state.h" using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // Memo Class // Memo Field Codes #define MEMFC_TITLE 0x01 #define MEMFC_BODY 0x02 #define MEMFC_MEMO_TYPE 0x03 #define MEMFC_CATEGORY 0x04 #define MEMFC_END 0xffff static FieldLink MemoFieldLinks[] = { { MEMFC_TITLE, N_("Title"), 0, 0, &Memo::Title, 0, 0, 0, 0, true }, { MEMFC_BODY, N_("Body"), 0, 0, &Memo::Body, 0, 0, 0, 0, true }, { MEMFC_END, N_("End of List"), 0, 0, 0, 0, 0, 0, 0, false } }; Memo::Memo() { Clear(); } Memo::~Memo() { } const unsigned char* Memo::ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { const CommonField *field = (const CommonField *) begin; // advance and check size begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size); if( begin > end ) // if begin==end, we are ok return begin; if( !btohs(field->size) ) // if field has no size, something's up return begin; if( field->type == MEMFC_MEMO_TYPE ) { if( field->u.raw[0] != 'm' ) { throw Error(_("Memo::ParseField: MemoType is not 'm'")); } return begin; } // cycle through the type table for( FieldLink *b = MemoFieldLinks; b->type != MEMFC_END; b++ ) { if( b->type == field->type ) { if( b->strMember ) { std::string &s = this->*(b->strMember); s = ParseFieldString(field); if( b->iconvNeeded && ic ) s = ic->FromBB(s); return begin; // done! } else if( b->timeMember && btohs(field->size) == 4 ) { TimeT &t = this->*(b->timeMember); t.Time = min2time(field->u.min1900); return begin; } } } // handle special cases switch( field->type ) { case MEMFC_CATEGORY: { std::string catstring = ParseFieldString(field); if( ic ) catstring = ic->FromBB(catstring); Categories.CategoryStr2List(catstring); } return begin; } // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; uf.data.assign((const char*)field->u.raw, btohs(field->size)); Unknowns.push_back(uf); // return new pointer for next field return begin; } void Memo::ParseHeader(const Data &data, size_t &offset) { // no header in Memo records } void Memo::ParseFields(const Data &data, size_t &offset, const IConverter *ic) { const unsigned char *finish = ParseCommonFields(*this, data.GetData() + offset, data.GetData() + data.GetSize(), ic); offset += finish - (data.GetData() + offset); } void Memo::Validate() const { } void Memo::BuildHeader(Data &data, size_t &offset) const { // no header in Memo records } // // Build // /// Build fields part of record. /// void Memo::BuildFields(Data &data, size_t &offset, const IConverter *ic) const { data.Zap(); // tack on the 'm' memo type field first BuildField(data, offset, MEMFC_MEMO_TYPE, 'm'); // Categories if( Categories.size() ) { string store; Categories.CategoryList2Str(store); BuildField(data, offset, MEMFC_CATEGORY, ic ? ic->ToBB(store) : store); } // cycle through the type table for( FieldLink *b = MemoFieldLinks; b->type != MEMFC_END; b++ ) { // print only fields with data if( b->strMember ) { const std::string &field = this->*(b->strMember); if( field.size() ) { std::string s = (b->iconvNeeded && ic) ? ic->ToBB(field) : field; BuildField(data, offset, b->type, s); } } else if( b->postMember && b->postField ) { const std::string &field = (this->*(b->postMember)).*(b->postField); if( field.size() ) { std::string s = (b->iconvNeeded && ic) ? ic->ToBB(field) : field; BuildField(data, offset, b->type, s); } } } // and finally save unknowns UnknownsType::const_iterator ub = Unknowns.begin(), ue = Unknowns.end(); for( ; ub != ue; ub++ ) { BuildField(data, offset, *ub); } data.ReleaseBuffer(offset); } void Memo::Dump(std::ostream &os) const { ios_format_state state(os); os << _("Memo entry: ") << "0x" << setbase(16) << RecordId << " (" << (unsigned int)RecType << ")\n"; os << _(" Title: ") << Title << "\n"; os << _(" Body: "); // The Body may have '\r' characters... translate them // in the output to make it look more pretty for( string::const_iterator i = Body.begin(); i != Body.end(); ++i ) { if( *i == '\r' ) os << "\n "; else os << *i; } os << "\n"; if( Categories.size() ) { string display; Categories.CategoryList2Str(display); os << _(" Categories: ") << display << "\n"; } os << Unknowns; os << "\n\n"; } bool Memo::operator<(const Memo &other) const { int cmp = Title.compare(other.Title); if( cmp == 0 ) cmp = Body.compare(other.Body); return cmp < 0; } void Memo::Clear() { RecType = GetDefaultRecType(); RecordId = 0; Title.clear(); Body.clear(); Categories.clear(); Unknowns.clear(); } const FieldHandle::ListT& Memo::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; #undef CONTAINER_OBJECT_NAME #define CONTAINER_OBJECT_NAME fhv #undef RECORD_CLASS_NAME #define RECORD_CLASS_NAME Memo FHP(RecType, _("Record Type Code")); FHP(RecordId, _("Unique Record ID")); FHD(Title, _("Title"), MEMFC_TITLE, true); FHD(Body, _("Body"), MEMFC_BODY, true); FHD(Categories, _("Categories"), MEMFC_CATEGORY, true); FHP(Unknowns, _("Unknown Fields")); return fhv; } std::string Memo::GetDescription() const { return Title; } } // namespace Barry barry-0.18.5/src/socket.h0000644001161500056700000001577512242254476014523 0ustar cdfreycdfrey/// /// \file socket.h /// Class wrapper to encapsulate the Blackberry USB logical socket /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_SOCKET_H__ #define __BARRY_SOCKET_H__ #include "dll.h" #include #include #include #include "router.h" #include "data.h" // forward declarations namespace Usb { class Device; } namespace Barry { class Packet; class JLPacket; class JVMPacket; class SocketRoutingQueue; } namespace Barry { class SocketBase; class Socket; typedef std::auto_ptr SocketHandle; class BXEXPORT SocketZero { friend class SocketBase; friend class Socket; Usb::Device *m_dev; SocketRoutingQueue *m_queue; int m_writeEp, m_readEp; uint8_t m_zeroSocketSequence; uint32_t m_sequenceId; // half open socket stata, for passwords bool m_halfOpen; uint32_t m_challengeSeed; unsigned int m_remainingTries; bool m_modeSequencePacketSeen; // pushback for out of order sequence packets Data m_pushback_buffer; bool m_pushback; private: static void AppendFragment(Data &whole, const Data &fragment); static unsigned int MakeNextFragment(const Data &whole, Data &fragment, unsigned int offset = 0); void CheckSequence(uint16_t socket, const Data &seq); void SendOpen(uint16_t socket, Data &receive); void SendPasswordHash(uint16_t socket, const char *password, Data &receive); // Raw send and receive functions, used for all low level // communication to the USB level. void RawSend(Data &send, int timeout = -1); void RawReceive(Data &receive, int timeout = -1); void Pushback(const Data &buf); protected: bool IsSequencePacketHidden() { return false; } public: explicit SocketZero(SocketRoutingQueue &queue, int writeEndpoint, uint8_t zeroSocketSequenceStart = 0); SocketZero(Usb::Device &dev, int writeEndpoint, int readEndpoint, uint8_t zeroSocketSequenceStart = 0); ~SocketZero(); uint8_t GetZeroSocketSequence() const { return m_zeroSocketSequence; } void SetRoutingQueue(SocketRoutingQueue &queue); void UnlinkRoutingQueue(); // Send functions for socket 0 only. // These functions will overwrite: // - the zeroSocketSequence byte *inside* the packet // - the socket number to 0 // void Send(Data &send, int timeout = -1); // send only void Send(Data &send, Data &receive, int timeout = -1); // send+recv void Send(Barry::Packet &packet, int timeout = -1); void Receive(Data &receive, int timeout = -1); // Opens a new socket and returns a Socket object to manage it SocketHandle Open(uint16_t socket, const char *password = 0); void Close(Socket &socket); }; class BXEXPORT SocketBase { bool m_resetOnClose; protected: void CheckSequence(const Data &seq); public: SocketBase() : m_resetOnClose(false) { } virtual ~SocketBase(); // // Virtual Socket API // virtual void Close() = 0; // FIXME - do I need RawSend? Or just a good fragmenter? virtual void RawSend(Data &send, int timeout = -1) = 0; virtual void SyncSend(Data &send, int timeout = -1) = 0; virtual void Receive(Data &receive, int timeout = -1) = 0; virtual void RegisterInterest(Barry::SocketRoutingQueue::SocketDataHandlerPtr handler = Barry::SocketRoutingQueue::SocketDataHandlerPtr()) = 0; virtual void UnregisterInterest() = 0; void ResetOnClose(bool reset = true) { m_resetOnClose = reset; } bool IsResetOnClose() const { return m_resetOnClose; } // // Convenience functions that just call the virtuals above // void DBFragSend(Data &send, int timeout = -1); void Send(Data &send, Data &receive, int timeout = -1); void Send(Barry::Packet &packet, int timeout = -1); // // Protocol based functions... all use the above virtual functions // // sends the send packet down to the device, fragmenting if // necessary, and returns the response in receive, defragmenting // if needed // Blocks until response received or timed out in Usb::Device void Packet(Data &send, Data &receive, int timeout = -1); void Packet(Barry::Packet &packet, int timeout = -1); void Packet(Barry::JLPacket &packet, int timeout = -1); void Packet(Barry::JVMPacket &packet, int timeout = -1); // Use this function to send packet to JVM instead of Packet function // FIXME void PacketJVM(Data &send, Data &receive, int timeout = -1); // Use this function to send data packet instead of Packet function // Indeed, Packet function is used to send command (and not data) // FIXME void PacketData(Data &send, Data &receive, bool done_on_sequence, int timeout = -1); // some handy wrappers for the Packet() interface void NextRecord(Data &receive); }; // // Socket class // /// Encapsulates a "logical socket" in the Blackberry USB protocol. /// By default, provides raw send/receive access, as well as packet /// writing on socket 0, which is always open. /// /// There are Open and Close members to open data sockets which are used /// to transfer data to and from the device. /// /// The destructor will close any non-0 open sockets automatically. /// /// Requires an active Usb::Device object to work on. /// class BXEXPORT Socket : public SocketBase { friend class SocketZero; SocketZero *m_zero; uint16_t m_socket; uint8_t m_closeFlag; bool m_registered; // buffer data std::auto_ptr m_sequence; protected: void ForceClosed(); // These "Local" function are non-virtual worker functions, // which are safe to be called from the destructor. // If you override the virtual versions in your derived class, // make sure your "Local" versions call us. void LocalClose(); void LocalUnregisterInterest(); uint16_t GetSocket() const { return m_socket; } uint8_t GetCloseFlag() const { return m_closeFlag; } Socket(SocketZero &zero, uint16_t socket, uint8_t closeFlag); public: ~Socket(); // // virtual overrides // void Close() { LocalClose(); } void RawSend(Data &send, int timeout = -1); void SyncSend(Data &send, int timeout = -1); void Receive(Data &receive, int timeout = -1); // Register a callback for incoming data from the device. // This function assumes that this socket is based on a socketZero // that has a SocketRoutingQueue, otherwise throws logic_error. // It also assumes that nothing has been registered before. // If you wish to re-register, call UnregisterInterest() first, // which is safe to call as many times as you like. void RegisterInterest(Barry::SocketRoutingQueue::SocketDataHandlerPtr handler = Barry::SocketRoutingQueue::SocketDataHandlerPtr()); void UnregisterInterest() { LocalUnregisterInterest(); } }; } // namespace Barry #endif barry-0.18.5/src/scoped_lock.h0000644001161500056700000000223712242254476015505 0ustar cdfreycdfrey/// /// \file scoped_lock.h /// Simple scope class for dealing with pthread mutex locking. /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_SCOPED_LOCK_H__ #define __BARRY_SCOPED_LOCK_H__ #include namespace Barry { class scoped_lock { pthread_mutex_t *m_mutex; public: scoped_lock(pthread_mutex_t &mutex) : m_mutex(&mutex) { while( pthread_mutex_lock(m_mutex) != 0 ) ; } ~scoped_lock() { unlock(); } void unlock() { if( m_mutex ) { pthread_mutex_unlock(m_mutex); m_mutex = 0; } } }; } // namespace Barry #endif barry-0.18.5/src/common.h0000644001161500056700000000375212242254476014513 0ustar cdfreycdfrey/// /// \file common.h /// General header for the Barry library /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_COMMON_H__ #define __BARRY_COMMON_H__ #include "dll.h" #include #define VENDOR_RIM 0x0fca #define PRODUCT_RIM_BLACKBERRY 0x0001 #define PRODUCT_RIM_PEARL_DUAL 0x0004 #define PRODUCT_RIM_PEARL_FLIP 0x8001 // 8200 series #define PRODUCT_RIM_PEARL_8120 0x8004 #define PRODUCT_RIM_PEARL 0x0006 #define PRODUCT_RIM_STORM 0x8007 #define PRODUCT_RIM_PLAYBOOK_NETWORK 0x8011 #define PRODUCT_RIM_PLAYBOOK_STORAGE 0x8020 #define BLACKBERRY_INTERFACE 0 #define BLACKBERRY_CONFIGURATION 1 #define BLACKBERRY_MASS_STORAGE_CLASS 8 #define BLACKBERRY_DB_CLASS 0xff #define IPRODUCT_RIM_HANDHELD 2 #define IPRODUCT_RIM_MASS_STORAGE 4 #define IPRODUCT_RIM_COMPOSITE 5 // minimum number of password tries remaining at which Barry gives up // for safety #define BARRY_MIN_PASSWORD_TRIES 3 #define BARRY_MIN_PASSWORD_TRIES_ASC "3" #define BLACKBERRY_CHARSET "WINDOWS-1252" #define BARRY_FIFO_NAME "/tmp/barry_fifo_args" namespace Barry { /// See also the LogLock class. BXEXPORT void Init(bool data_dump_mode = false, std::ostream *logStream = &std::cout); BXEXPORT void Verbose(bool data_dump_mode = true); BXEXPORT bool IsVerbose(); // utilitiy functions BXEXPORT std::string string_vprintf(const char *fmt, ...) BARRY_GCC_FORMAT_CHECK(1, 2); } // namespace Barry #endif barry-0.18.5/src/threadwrap.cc0000644001161500056700000000367512242254476015526 0ustar cdfreycdfrey/// /// \file threadwrap.cc /// RAII Wrapper for a single thread. /// /* Copyright (C) 2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "threadwrap.h" #include "error.h" #include namespace Barry { void *callback_wrapper(void *data) { Barry::Thread::CallbackData *cbdata = (Barry::Thread::CallbackData*) data; return (*cbdata->callback)(cbdata); } Thread::CallbackData::CallbackData(void *userdata) : callback(0) , stopflag(false) , userdata(userdata) { } Thread::Thread(int socket, void *(*callback)(Barry::Thread::CallbackData *data), void *userdata) : m_socket(socket) { m_data = new CallbackData(userdata); m_data->callback = callback; int ret = pthread_create(&thread, NULL, callback_wrapper, m_data); if( ret ) { delete m_data; throw Barry::ErrnoError(_("Thread: pthread_create failed."), ret); } } Thread::~Thread() { if( pthread_join(thread, NULL) == 0 ) { // successful join, thread is dead, free to free delete m_data; } else { // thread is in la-la land, must leak m_data here for safety } } void Thread::StopFlag() { // http://stackoverflow.com/questions/2486335/wake-up-thread-blocked-on-accept-call // set flag first, before waking thread m_data->stopflag = true; // shutdown the socket, but leave the fd valid, thereby waking up // the thread if it is blocked on accept() shutdown(m_socket, SHUT_RDWR); } } // namespace Barry barry-0.18.5/src/pin.cc0000644001161500056700000000205212242254476014137 0ustar cdfreycdfrey/// /// \file pin.cc /// class for device PIN notation /// /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include #include "pin.h" #include "ios_state.h" namespace Barry { std::istream& operator>>(std::istream &is, Pin &pin) { ios_format_state state(is); uint32_t newpin; is >> std::hex >> newpin; if( is ) pin = newpin; return is; } std::string Pin::Str() const { std::ostringstream oss; oss << std::hex << pin; return oss.str(); } } barry-0.18.5/src/socket.cc0000644001161500056700000007130512242254476014650 0ustar cdfreycdfrey/// /// \file socket.cc /// Class wrapper to encapsulate the Blackberry USB logical socket /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "socket.h" #include "usbwrap.h" #include "data.h" #include "protocol.h" #include "protostructs.h" #include "endian.h" #include "debug.h" #include "packet.h" #include "sha1.h" #include #include using namespace Usb; namespace Barry { ////////////////////////////////////////////////////////////////////////////// // SocketZero class SocketZero::SocketZero( SocketRoutingQueue &queue, int writeEndpoint, uint8_t zeroSocketSequenceStart) : m_dev(0) , m_queue(&queue) , m_writeEp(writeEndpoint) , m_readEp(0) , m_zeroSocketSequence(zeroSocketSequenceStart) , m_sequenceId(0) , m_halfOpen(false) , m_challengeSeed(0) , m_remainingTries(0) , m_modeSequencePacketSeen(false) , m_pushback(false) { } SocketZero::SocketZero( Device &dev, int writeEndpoint, int readEndpoint, uint8_t zeroSocketSequenceStart) : m_dev(&dev) , m_queue(0) , m_writeEp(writeEndpoint) , m_readEp(readEndpoint) , m_zeroSocketSequence(zeroSocketSequenceStart) , m_sequenceId(0) , m_halfOpen(false) , m_challengeSeed(0) , m_remainingTries(0) , m_modeSequencePacketSeen(false) , m_pushback(false) { } SocketZero::~SocketZero() { // nothing to close for socket zero } /////////////////////////////////////// // Socket Zero static calls // appends fragment to whole... if whole is empty, simply copies, and // sets command to DATA instead of FRAGMENTED. Always updates the // packet size of whole, to reflect the total size void SocketZero::AppendFragment(Data &whole, const Data &fragment) { if( whole.GetSize() == 0 ) { // empty, so just copy whole = fragment; } else { // has some data already, so just append int size = whole.GetSize(); unsigned char *buf = whole.GetBuffer(size + fragment.GetSize()); MAKE_PACKET(fpack, fragment); int fragsize = fragment.GetSize() - SB_FRAG_HEADER_SIZE; memcpy(buf+size, &fpack->u.db.u.fragment, fragsize); whole.ReleaseBuffer(size + fragsize); } // update whole's size and command type for future sanity Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) whole.GetBuffer(); wpack->size = htobs((uint16_t) whole.GetSize()); wpack->command = SB_COMMAND_DB_DATA; // don't need to call ReleaseBuffer here, since we're not changing // the real data size, and ReleaseBuffer was called above during copy } // If offset is 0, starts fresh, taking the first fragment packet size chunk // out of whole and creating a sendable packet in fragment. Returns the // next offset if there is still more data, or 0 if finished. unsigned int SocketZero::MakeNextFragment(const Data &whole, Data &fragment, unsigned int offset) { // sanity check if( whole.GetSize() < SB_FRAG_HEADER_SIZE ) { eout("Whole packet too short to fragment: " << whole.GetSize()); throw Error(_("Socket: Whole packet too short to fragment")); } // calculate size unsigned int todo = whole.GetSize() - SB_FRAG_HEADER_SIZE - offset; unsigned int nextOffset = 0; if( todo > (MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE) ) { todo = MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE; nextOffset = offset + todo; } // create fragment header unsigned char *buf = fragment.GetBuffer(SB_FRAG_HEADER_SIZE + todo); memcpy(buf, whole.GetData(), SB_FRAG_HEADER_SIZE); // copy over a fragment size of data memcpy(buf + SB_FRAG_HEADER_SIZE, whole.GetData() + SB_FRAG_HEADER_SIZE + offset, todo); // update fragment's size and command type Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) buf; wpack->size = htobs((uint16_t) (todo + SB_FRAG_HEADER_SIZE)); if( nextOffset ) wpack->command = SB_COMMAND_DB_FRAGMENTED; else wpack->command = SB_COMMAND_DB_DATA; // adjust the new fragment size fragment.ReleaseBuffer(SB_FRAG_HEADER_SIZE + todo); // return next round return nextOffset; } /////////////////////////////////////// // SocketZero private API // // FIXME - not sure yet whether sequence ID's are per socket or not... if // they are per socket, then this global sequence behaviour will not work, // and we need to track m_sequenceId on a Socket level. // void SocketZero::CheckSequence(uint16_t socket, const Data &seq) { MAKE_PACKET(spack, seq); if( (unsigned int) seq.GetSize() < SB_SEQUENCE_PACKET_SIZE ) { eout("Short sequence packet:\n" << seq); throw Error(_("Socket: invalid sequence packet")); } // we'll cheat here... if the packet's sequence is 0, we'll // silently restart, otherwise, fail uint32_t sequenceId = btohl(spack->u.sequence.sequenceId); if( sequenceId == 0 ) { // silently restart (will advance below) m_sequenceId = 0; } else { if( sequenceId != m_sequenceId ) { if( socket != 0 ) { std::string msg = string_vprintf(_("Socket 0x%x: out of sequence. (Global sequence: 0x%x. Packet sequence: 0x%x)"), (unsigned int)socket, (unsigned int)m_sequenceId, (unsigned int)sequenceId); eout(msg); throw Error(msg); } else { dout("Bad sequence on socket 0: expected: " << m_sequenceId << ". Packet sequence: " << sequenceId); } } } // advance! m_sequenceId++; } void SocketZero::SendOpen(uint16_t socket, Data &receive) { // build open command Barry::Protocol::Packet packet; packet.socket = 0; packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE); packet.command = SB_COMMAND_OPEN_SOCKET; packet.u.socket.socket = htobs(socket); packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send() Data send(&packet, SB_SOCKET_PACKET_HEADER_SIZE); try { RawSend(send); RawReceive(receive); if( Protocol::IsSequencePacket(receive) ) { m_modeSequencePacketSeen = true; // during open, we could get a sequence packet in // the middle, from the SelectMode operation RawReceive(receive); } } catch( Usb::Error & ) { eeout(send, receive); throw; } // receive now holds the Open response } // SHA1 hashing logic based on Rick Scott's XmBlackBerry's send_password() void SocketZero::SendPasswordHash(uint16_t socket, const char *password, Data &receive) { unsigned char pwdigest[SHA_DIGEST_LENGTH]; unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4]; // first, hash the password by itself SHA1((unsigned char *) password, strlen(password), pwdigest); // prefix the resulting hash with the provided seed uint32_t seed = htobl(m_challengeSeed); memcpy(&prefixedhash[0], &seed, sizeof(uint32_t)); memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH); // hash again SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest); size_t size = SB_SOCKET_PACKET_HEADER_SIZE + PASSWORD_CHALLENGE_SIZE; // build open command Barry::Protocol::Packet packet; packet.socket = 0; packet.size = htobs(size); packet.command = SB_COMMAND_PASSWORD; packet.u.socket.socket = htobs(socket); packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send() packet.u.socket.u.password.remaining_tries = 0; packet.u.socket.u.password.unknown = 0; packet.u.socket.u.password.param = htobs(0x14); // FIXME - what does this mean? memcpy(packet.u.socket.u.password.u.hash, pwdigest, sizeof(packet.u.socket.u.password.u.hash)); // blank password hashes as we don't need these anymore memset(pwdigest, 0, sizeof(pwdigest)); memset(prefixedhash, 0, sizeof(prefixedhash)); Data send(&packet, size); RawSend(send); RawReceive(receive); // blank password hash as we don't need this anymore either memset(packet.u.socket.u.password.u.hash, 0, sizeof(packet.u.socket.u.password.u.hash)); send.Zap(); // check sequence ID if( Protocol::IsSequencePacket(receive) ) { m_modeSequencePacketSeen = true; CheckSequence(0, receive); // still need our ACK RawReceive(receive); } // receive now holds the Password response } void SocketZero::RawSend(Data &send, int timeout) { Usb::Device *dev = m_queue ? m_queue->GetUsbDevice() : m_dev; if( !dev ) throw Error(_("SocketZero: No device available for RawSend")); // Special case: it seems that sending packets with a size that's an // exact multiple of 0x40 causes the device to get confused. // // To get around that, it is observed in the captures that the size // is sent in a special 3 byte packet before the real packet. // Check for this case here. // if( (send.GetSize() % 0x40) == 0 ) { Protocol::SizePacket packet; packet.size = htobs(send.GetSize()); packet.buffer[2] = 0; // zero the top byte Data sizeCommand(&packet, 3); dev->BulkWrite(m_writeEp, sizeCommand, timeout); } dev->BulkWrite(m_writeEp, send, timeout); } void SocketZero::RawReceive(Data &receive, int timeout) { if( m_pushback ) { receive = m_pushback_buffer; m_pushback = false; return; } if( m_queue ) { if( !m_queue->DefaultRead(receive, timeout) ) throw Timeout(_("SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)")); } else { m_dev->BulkRead(m_readEp, receive, timeout); } ddout("SocketZero::RawReceive: Endpoint " << (m_queue ? m_queue->GetReadEp() : m_readEp) << "\nReceived:\n" << receive); } void SocketZero::Pushback(const Data &buf) { if( m_pushback ) throw Error(_("Multiple pushbacks in SocketZero!")); m_pushback = true; m_pushback_buffer = buf; } /////////////////////////////////////// // SocketZero public API void SocketZero::SetRoutingQueue(SocketRoutingQueue &queue) { // replace the current queue pointer m_queue = &queue; } void SocketZero::UnlinkRoutingQueue() { m_queue = 0; } void SocketZero::Send(Data &send, int timeout) { // force the socket number to 0 if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) { MAKE_PACKETPTR_BUF(spack, send.GetBuffer()); spack->socket = 0; } // This is a socket 0 packet, so force the send packet data's // socket 0 sequence number to something correct. if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) { MAKE_PACKETPTR_BUF(spack, send.GetBuffer()); spack->u.socket.sequence = m_zeroSocketSequence; m_zeroSocketSequence++; } RawSend(send, timeout); } void SocketZero::Send(Data &send, Data &receive, int timeout) { Send(send, timeout); RawReceive(receive, timeout); } void SocketZero::Send(Barry::Packet &packet, int timeout) { Send(packet.m_send, *packet.m_receive, timeout); } void SocketZero::Receive(Data &receive, int timeout) { RawReceive(receive, timeout); } // // Open // /// Open a logical socket on the device. /// /// Both the socket number and the flag are based on the response to the /// SELECT_MODE command. See Controller::SelectMode() for more info /// on this. /// /// The packet sequence is normal for most socket operations. /// /// - Down: command packet with OPEN_SOCKET /// - Up: optional sequence handshake packet /// - Up: command response, which repeats the socket and flag data /// as confirmation /// /// \exception Barry::Error /// Thrown on protocol error. /// /// \exception Barry::BadPassword /// Thrown on invalid password, or not enough retries left /// on device. /// SocketHandle SocketZero::Open(uint16_t socket, const char *password) { // Things get a little funky here, as we may be left in an // intermediate state in the case of a failed password. // This function should support being called as many times // as needed to handle the password Data send, receive; ZeroPacket packet(send, receive); // save sequence for later close uint8_t closeFlag = GetZeroSocketSequence(); if( !m_halfOpen ) { // starting fresh m_remainingTries = 0; // this gets set to true if we see a starting sequence packet // during any of our open and password commands... After // a mode command (like "RIM Desktop", etc.) a starting // sequence packet is sent, and may arrive before or after // the socket open handshake. m_modeSequencePacketSeen = false; // go for it! SendOpen(socket, receive); // check for password challenge, or success if( packet.Command() == SB_COMMAND_PASSWORD_CHALLENGE ) { m_halfOpen = true; m_challengeSeed = packet.ChallengeSeed(); m_remainingTries = packet.RemainingTries(); } // fall through to challenge code... } if( m_halfOpen ) { // half open, device is expecting a password hash... do we // have a password? if( !password ) { throw BadPassword(_("No password specified."), m_remainingTries, false); } // only allow password attempts if there are // BARRY_MIN_PASSWORD_TRIES or more tries remaining... // we want to give the user at least some chance on a // Windows machine before the device commits suicide. if( m_remainingTries < BARRY_MIN_PASSWORD_TRIES ) { throw BadPassword(string_vprintf(_("Fewer than %d password tries remaining in device. Refusing to proceed, to avoid device zapping itself. Use a Windows client, or re-cradle the device."), BARRY_MIN_PASSWORD_TRIES), m_remainingTries, true); } // save sequence for later close (again after SendOpen()) closeFlag = GetZeroSocketSequence(); SendPasswordHash(socket, password, receive); if( packet.Command() == SB_COMMAND_PASSWORD_FAILED ) { m_halfOpen = true; m_challengeSeed = packet.ChallengeSeed(); m_remainingTries = packet.RemainingTries(); throw BadPassword(_("Password rejected by device."), m_remainingTries, false); } // if we get this far, we are no longer in half-open password // mode, so we can reset our flags m_halfOpen = false; // fall through to success check... } // If the device thinks that the socket was already open then // it will tell us by sending an SB_COMMAND_CLOSE_SOCKET. // // This happens most commonly when using raw channels which // haven't been cleanly closed (such as by killing the process // running Barry) and so the device still thinks the socket // is open. // // Retrying the open will usually succeed, but relies on the // device software re-creating the channel after it's closed // so return an error here instead of automatically retrying. if( packet.Command() == SB_COMMAND_CLOSE_SOCKET ) { throw SocketCloseOnOpen(_("Socket: Device closed socket when trying to open (can be caused by the wrong password, or if the device thinks the socket is already open... please try again)")); } if( packet.Command() != SB_COMMAND_OPENED_SOCKET || packet.SocketResponse() != socket || packet.SocketSequence() != closeFlag ) { eout("Packet:\n" << receive); throw Error(_("Socket: Bad OPENED packet in Open")); } // if no sequence packet has yet arrived, wait for it here if( !m_modeSequencePacketSeen ) { Data sequence; RawReceive(sequence); if( !Protocol::IsSequencePacket(sequence) ) { // if this is not the sequence packet, then it might // just be out of order (some devices do this when // opening the JavaLoader mode), so as a last // ditch effort, do one more read with a short // timeout, and check that as well Data late_sequence; RawReceive(late_sequence, 500); if( !Protocol::IsSequencePacket(late_sequence) ) { throw Error(_("Could not find mode's starting sequence packet")); } // ok, so our ditch effort worked, but now we have // a leftover packet on our hands... do a temporary // pushback Pushback(sequence); } } // success! save the socket Socket *sock = new Socket(*this, socket, closeFlag); SocketHandle sh(sock); // if we are running with a routing queue, register the // socket's interest in all its own data. By default, this // data will be queued without a callback handler. // If other application code needs to intercept this with // its own handler, it must call UnregisterInterest() and // re-register its own handler. if( m_queue ) { sock->RegisterInterest(); } return sh; } // // Close // /// Closes a non-default socket (i.e. non-zero socket number) /// /// The packet sequence is just like Open(), except the command is /// CLOSE_SOCKET. /// /// \exception Barry::Error /// void SocketZero::Close(Socket &socket) { if( socket.GetSocket() == 0 ) return; // nothing to do // build close command Barry::Protocol::Packet packet; packet.socket = 0; packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE); packet.command = SB_COMMAND_CLOSE_SOCKET; packet.u.socket.socket = htobs(socket.GetSocket()); packet.u.socket.sequence = socket.GetCloseFlag(); Data command(&packet, SB_SOCKET_PACKET_HEADER_SIZE); Data response; try { Send(command, response); } catch( Usb::Error & ) { // reset so this won't be called again socket.ForceClosed(); eeout(command, response); throw; } // starting fresh, reset sequence ID if( Protocol::IsSequencePacket(response) ) { CheckSequence(0, response); // still need our ACK RawReceive(response); } Protocol::CheckSize(response, SB_SOCKET_PACKET_HEADER_SIZE); MAKE_PACKET(rpack, response); // The reply will be SB_COMMAND_CLOSED_SOCKET if the device // has closed the socket in response to our request. // // It's also possible for the reply to be // SB_COMMAND_REMOTE_CLOSE_SOCKET if the device wanted to // close the socket at the same time, such as if the channel // API is being used by the device. if( ( rpack->command != SB_COMMAND_CLOSED_SOCKET && rpack->command != SB_COMMAND_REMOTE_CLOSE_SOCKET ) || btohs(rpack->u.socket.socket) != socket.GetSocket() || rpack->u.socket.sequence != socket.GetCloseFlag() ) { // reset so this won't be called again socket.ForceClosed(); eout("Packet:\n" << response); throw BadPacket(rpack->command, _("Socket: Bad CLOSED packet in Close")); } if( socket.IsResetOnClose() ) { Data send, receive; ZeroPacket reset_packet(send, receive); reset_packet.Reset(); Send(reset_packet); if( reset_packet.CommandResponse() != SB_COMMAND_RESET_REPLY ) { throw BadPacket(reset_packet.CommandResponse(), _("Socket: Missing RESET_REPLY in Close")); } } // // and finally, there always seems to be an extra read of // // an empty packet at the end... just throw it away // try { // RawReceive(response, 1); // } // catch( Usb::Timeout & ) { // } // reset socket and flag socket.ForceClosed(); } ////////////////////////////////////////////////////////////////////////////// // SocketBase class SocketBase::~SocketBase() { } void SocketBase::CheckSequence(const Data &seq) { // FIXME - needs implementation } // // DBFragSend // /// Sends a fragmented Desktop / Database command packet. /// Assumes that 'send' contains a valid packet, which may or may not /// need fragmentation. If it does, fragmentation will be done /// automatically. /// void SocketBase::DBFragSend(Data &send, int timeout) { MAKE_PACKET(spack, send); if( send.GetSize() < MIN_PACKET_SIZE || (spack->command != SB_COMMAND_DB_DATA && spack->command != SB_COMMAND_DB_DONE) ) { // we don't do that around here eout("unknown send data in DBFragSend(): " << send); throw std::logic_error(_("Socket: unknown send data in DBFragSend()")); } if( send.GetSize() <= MAX_PACKET_SIZE ) { // send non-fragmented SyncSend(send, timeout); } else { // send fragmented unsigned int offset = 0; Data outFrag; do { offset = SocketZero::MakeNextFragment(send, outFrag, offset); SyncSend(outFrag, timeout); } while( offset > 0 ); } } // // Send // /// SyncSends 'send' data to device, and waits for response. /// /// \returns void /// /// \exception Usb::Error on underlying bus errors. /// void SocketBase::Send(Data &send, Data &receive, int timeout) { SyncSend(send, timeout); Receive(receive, timeout); } void SocketBase::Send(Barry::Packet &packet, int timeout) { Send(packet.m_send, *packet.m_receive, timeout); } // sends the send packet down to the device, fragmenting if // necessary, and returns the response in receive, defragmenting // if needed // Blocks until response received or timed out in Usb::Device // // This is primarily for Desktop Database packets... Javaloader // packets use PacketData(). // void SocketBase::Packet(Data &send, Data &receive, int timeout) { // assume the common case of no fragmentation, // and use the receive buffer for input... allocate a frag buffer // later if necessary Data *inputBuf = &receive; receive.Zap(); DBFragSend(send, timeout); Receive(*inputBuf, timeout); std::auto_ptr inFrag; bool done = false, frag = false; int blankCount = 0; while( !done ) { MAKE_PACKET(rpack, *inputBuf); // check the packet's validity if( inputBuf->GetSize() > 0 ) { blankCount = 0; Protocol::CheckSize(*inputBuf, SB_PACKET_HEADER_SIZE); switch( rpack->command ) { case SB_COMMAND_SEQUENCE_HANDSHAKE: CheckSequence(*inputBuf); break; case SB_COMMAND_DB_DATA: if( frag ) { SocketZero::AppendFragment(receive, *inputBuf); } else { // no copy needed, already in receive, // since inputBuf starts out that way } done = true; break; case SB_COMMAND_DB_FRAGMENTED: // only copy if frag is true, since the // first time through, receive == inputBuf if( frag ) { SocketZero::AppendFragment(receive, *inputBuf); } frag = true; break; case SB_COMMAND_DB_DONE: // no copy needed, already in receive done = true; break; default: { std::ostringstream oss; oss << _("Socket: (read) unhandled packet in Packet(): ") << "0x" << std::hex << (unsigned int)rpack->command; eout(oss.str()); throw Error(oss.str()); } break; } } else { blankCount++; //std::cerr << "Blank! " << blankCount << std::endl; if( blankCount == 10 ) { // only ask for more data on stalled sockets // for so long throw Error(_("Socket: 10 blank packets received")); } } if( !done ) { // not done yet, ask for another read, and // create new buffer for fragmented reads if( frag && !inFrag.get() ) { inFrag.reset( new Data ); inputBuf = inFrag.get(); } Receive(*inputBuf); } } } void SocketBase::Packet(Barry::Packet &packet, int timeout) { Packet(packet.m_send, *packet.m_receive, timeout); } void SocketBase::Packet(Barry::JLPacket &packet, int timeout) { if( packet.HasData() ) { SyncSend(packet.m_cmd); PacketData(packet.m_data, *packet.m_receive, false, timeout); } else { PacketData(packet.m_cmd, *packet.m_receive, false, timeout); } } void SocketBase::Packet(Barry::JVMPacket &packet, int timeout) { PacketJVM(packet.m_cmd, *packet.m_receive, timeout); } // sends the send packet down to the device // Blocks until response received or timed out in Usb::Device // // This function is used to send packet to JVM void SocketBase::PacketJVM(Data &send, Data &receive, int timeout) { if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) || ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) { // we don't do that around here throw std::logic_error(_("Socket: unknown send data in PacketJVM()")); } Data &inFrag = receive; receive.Zap(); // send non-fragmented RawSend(send, timeout); Receive(inFrag, timeout); bool done = false; int blankCount = 0; while( !done ) { // check the packet's validity if( inFrag.GetSize() > 6 ) { MAKE_PACKET(rpack, inFrag); blankCount = 0; Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE); switch( rpack->command ) { case SB_COMMAND_SEQUENCE_HANDSHAKE: CheckSequence(inFrag); break; default: { std::ostringstream oss; oss << _("Socket: (read) unhandled packet in Packet(): ") << "0x" << std::hex << (unsigned int)rpack->command; eout(oss.str()); throw Error(oss.str()); } break; } } else if( inFrag.GetSize() == 6 ) { done = true; } else { blankCount++; //std::cerr << "Blank! " << blankCount << std::endl; if( blankCount == 10 ) { // only ask for more data on stalled sockets // for so long throw Error(_("Socket: 10 blank packets received")); } } if( !done ) { // not done yet, ask for another read Receive(inFrag, timeout); } } } // sends the send packet down to the device // Blocks until response received or timed out in Usb::Device void SocketBase::PacketData(Data &send, Data &receive, bool done_on_sequence, int timeout) { if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) || ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) { // we don't do that around here throw std::logic_error(_("Socket: unknown send data in PacketData()")); } Data &inFrag = receive; receive.Zap(); // send non-fragmented SyncSend(send, timeout); Receive(inFrag, timeout); bool done = false; int blankCount = 0; while( !done ) { // check the packet's validity if( inFrag.GetSize() > 0 ) { MAKE_PACKET(rpack, inFrag); blankCount = 0; Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE); switch( rpack->command ) { case SB_COMMAND_SEQUENCE_HANDSHAKE: // CheckSequence(inFrag); if( done_on_sequence ) done = true; break; case SB_COMMAND_JL_READY: case SB_COMMAND_JL_ACK: case SB_COMMAND_JL_HELLO_ACK: case SB_COMMAND_JL_RESET_REQUIRED: done = true; break; case SB_COMMAND_JL_GET_DATA_ENTRY: // This response means that the next packet is the stream done = true; break; case SB_DATA_JL_INVALID: throw BadPacket(rpack->command, _("file is not a valid Java code file")); break; case SB_COMMAND_JL_NOT_SUPPORTED: throw BadPacket(rpack->command, _("device does not support requested command")); break; default: // unknown packet, pass it up to the // next higher code layer done = true; break; } } else { blankCount++; //std::cerr << "Blank! " << blankCount << std::endl; if( blankCount == 10 ) { // only ask for more data on stalled sockets // for so long throw Error(_("Socket: 10 blank packets received")); } } if( !done ) { // not done yet, ask for another read Receive(inFrag); } } } void SocketBase::NextRecord(Data &receive) { Barry::Protocol::Packet packet; packet.size = htobs(7); packet.command = SB_COMMAND_DB_DONE; packet.u.db.tableCmd = 0; packet.u.db.u.command.operation = 0; Data command(&packet, 7); Packet(command, receive); } ////////////////////////////////////////////////////////////////////////////// // Socket class Socket::Socket( SocketZero &zero, uint16_t socket, uint8_t closeFlag) : m_zero(&zero) , m_socket(socket) , m_closeFlag(closeFlag) , m_registered(false) , m_sequence(new Data) { } Socket::~Socket() { // trap exceptions in the destructor try { // a non-default socket has been opened, close it LocalClose(); } catch( std::runtime_error &DEBUG_ONLY(re) ) { // do nothing... log it? dout("Exception caught in ~Socket: " << re.what()); } } //////////////////////////////////// // Socket protected API void Socket::ForceClosed() { m_socket = 0; m_closeFlag = 0; } void Socket::LocalClose() { LocalUnregisterInterest(); m_zero->Close(*this); } void Socket::LocalUnregisterInterest() { if( m_registered ) { if( m_zero->m_queue ) m_zero->m_queue->UnregisterInterest(m_socket); m_registered = false; } } // // Send // /// Sends 'send' data to device, no receive. /// /// \returns void /// /// \exception Usb::Error on underlying bus errors. /// void Socket::RawSend(Data &send, int timeout) { // force the socket number to this socket if( send.GetSize() >= SB_PACKET_HEADER_SIZE ) { MAKE_PACKETPTR_BUF(spack, send.GetBuffer()); spack->socket = htobs(m_socket); } m_zero->RawSend(send, timeout); } void Socket::SyncSend(Data &send, int timeout) { RawSend(send, timeout); Receive(*m_sequence, timeout); if( !Protocol::IsSequencePacket(*m_sequence) ) throw Barry::Error(_("Non-sequence packet in Socket::SyncSend()")); CheckSequence(*m_sequence); } void Socket::Receive(Data &receive, int timeout) { if( m_registered ) { if( m_zero->m_queue ) { if( !m_zero->m_queue->SocketRead(m_socket, receive, timeout) ) throw Timeout(_("Socket::Receive: queue SocketRead returned false (likely a timeout)")); } else { throw std::logic_error(_("NULL queue pointer in a registered socket read.")); } ddout("Socket::Receive: Endpoint " << (m_zero->m_queue ? m_zero->m_queue->GetReadEp() : m_zero->m_readEp) << "\nReceived:\n" << receive); } else { m_zero->RawReceive(receive, timeout); } } void Socket::RegisterInterest(SocketRoutingQueue::SocketDataHandlerPtr handler) { if( !m_zero->m_queue ) throw std::logic_error(_("SocketRoutingQueue required in SocketZero in order to call Socket::RegisterInterest()")); if( m_registered ) { throw std::logic_error(string_vprintf(_("Socket (%u) already registered in Socket::RegisterInterest()!"), (unsigned int)m_socket)); } m_zero->m_queue->RegisterInterest(m_socket, handler); m_registered = true; } } // namespace Barry barry-0.18.5/src/a_application.cc0000644001161500056700000000347012242254476016161 0ustar cdfreycdfrey/// /// \file a_application.cc /// ALX Application class based on CODSection class /// /* Copyright (C) 2010, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include #include #include #include "a_application.h" #include "ios_state.h" namespace Barry { namespace ALX { Application::Application(void) : CODSection() { } Application::Application(const xmlpp::SaxParser::AttributeList& attrs) : CODSection(attrs) { } Application::~Application(void) { } void Application::Dump(std::ostream &os) const { ios_format_state state(os); os << _(" Application ") << name << " - " << version << std::endl; os << _(" ID : ") << id << std::endl; os << _(" Description : ") << description << std::endl; os << _(" Vendor : ") << vendor << std::endl; os << _(" Copyright : ") << copyright << std::endl; os << _(" Required : ") << (isRequired ? _("Yes") : _("No")) << std::endl; std::vector::const_iterator b = codfiles.begin(), e = codfiles.end(); os << _(" Files : ") << std::endl; for (; b != e; b++) os << " - " << directory << "/" << (*b) << std::endl; } } // namespace ALX } // namespace Barry barry-0.18.5/src/cod.h0000644001161500056700000000501412242254476013761 0ustar cdfreycdfrey/// /// \file cod.h /// COD file API /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_COD_H__ #define __BARRY_COD_H__ #include "dll.h" #include "data.h" #include #include #include #include namespace Barry { // // SeekNextCod // /// Seeks the input stream to the next packed sibling .cod file and returns /// the packed .cod file size. When all siblings have been read, zero is /// returned. /// /// When input stream does not contain the signature for a packed .cod file, /// it's assumed the entire stream is the .cod file. /// /// \param input stream to read from /// /// \return size of next packed .cod file, or 0 finished reading .cod files /// size_t SeekNextCod(std::istream &input); /// /// The CodFileBuilder class is used to assemble multiple .cod files into /// a single packed .cod file using the pkzip file format. /// class BXEXPORT CodFileBuilder { std::string m_module_name; size_t m_module_count; unsigned int m_current_module; std::ostringstream m_directory; public: CodFileBuilder(const std::string &module_name, size_t module_count = 1); ~CodFileBuilder(); /// /// Writes packed .cod file header to the output stream, and appends /// an entry to the central directory. If the module count used to /// create CodFileBuilder is equal to one, the call is ignored. /// /// Note: it is the caller's responsibility to write the actual /// COD file data after calling this function. /// /// \param output stream to write to /// /// \param buffer buffered .cod file data, input to CRC-32 function /// /// \param module_size total size of .cod file data /// void WriteNextHeader(std::ostream &output, const uint8_t* buffer, uint32_t module_size); /// /// Write the central directory and central directory ending indicator /// to the output stream. /// /// \param output stream to write to /// void WriteFooter(std::ostream &output); }; } #endif barry-0.18.5/src/dp_parser.cc0000644001161500056700000000335212242254476015334 0ustar cdfreycdfrey/** * @file dp_parser.cc * @author Nicolas VIVIEN * @date 2009-08-01 * * @note CopyRight Nicolas VIVIEN * * @brief COD debug file parser * RIM's JDE generates several files when you build a COD application. * Indeed, with the COD files for the device, we have a ".debug" file. * This file is usefull to debug an application from JVM. * This tool is a parser to understand these ".debug" files. * Obviously, the file contents only some strings and 32 bits words. * * @par Modifications * - 2009/08/01 : N. VIVIEN * - First release * * @par Licences * Copyright (C) 2009-2010, Nicolas VIVIEN * * 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 in the COPYING file at the * root directory of this project for more details. */ #include #include #include "dp_parser.h" #include "endian.h" using namespace std; namespace Barry { namespace JDG { string ParseString(istream &input, const int length) { int i; string str; for (i=0; i #include #include #include #include #ifndef __DEBUG_MODE__ #define __DEBUG_MODE__ #endif #include "debug.h" // Pull in the correct Usb::LibraryInterface #if defined USE_LIBUSB_0_1 #include "usbwrap_libusb.h" #elif defined USE_LIBUSB_1_0 #include "usbwrap_libusb_1_0.h" #else #error No usb library interface selected. #endif namespace Usb { /////////////////////////////////////////////////////////////////////////////// // Usb::Error exception class static std::string GetErrorString(int libusb_errcode, const std::string &str) { std::ostringstream oss; oss << "("; if( libusb_errcode ) { oss << std::dec << libusb_errcode << " (" << LibraryInterface::TranslateErrcode(libusb_errcode) << "), "; } oss << LibraryInterface::GetLastErrorString(libusb_errcode) << "): "; oss << str; return oss.str(); } Error::Error(const std::string &str) : Barry::Error(str) , m_libusb_errcode(0) { } Error::Error(int libusb_errcode, const std::string &str) : Barry::Error(libusb_errcode == 0 ? str : GetErrorString(libusb_errcode, str)) , m_libusb_errcode(libusb_errcode) { } int Error::system_errcode() const { return LibraryInterface::TranslateErrcode(m_libusb_errcode); } /////////////////////////////////////////////////////////////////////////////// // EndpointPair EndpointPair::EndpointPair() : read(0), write(0), type(EndpointDescriptor::InvalidType) { } bool EndpointPair::IsTypeSet() const { return type != EndpointDescriptor::InvalidType; } bool EndpointPair::IsComplete() const { return read && write && IsTypeSet(); } bool EndpointPair::IsBulk() const { return type == EndpointDescriptor::BulkType; } /////////////////////////////////////////////////////////////////////////////// // EndpointPairings EndpointPairings::EndpointPairings(const std::vector& eps) : m_valid(false) { // parse the endpoint into read/write sets, if possible, // going in discovery order... // Assumptions: // - endpoints of related utility will be grouped // - endpoints with same type will be grouped // - endpoints that do not meet the above assumptions // do not belong in a pair EndpointPair pair; if( eps.size() == 0 ) { dout("EndpointPairing:: empty interface pointer"); return; } std::vector::const_iterator iter = eps.begin(); while( iter != eps.end() ) { const EndpointDescriptor& desc = **iter; if( desc.IsRead() ) { // Read endpoint pair.read = desc.GetAddress(); dout(" pair.read = 0x" << std::hex << (unsigned int)pair.read); if( pair.IsTypeSet() && pair.type != desc.GetType() ) { // if type is already set, we must start over pair.write = 0; } } else { // Write endpoint pair.write = desc.GetAddress(); dout(" pair.write = 0x" << std::hex << (unsigned int)pair.write); if( pair.IsTypeSet() && pair.type != desc.GetType() ) { // if type is already set, we must start over pair.read = 0; } } pair.type = desc.GetType(); dout(" pair.type = 0x" << std::hex << (unsigned int)pair.type); // if pair is complete, add to array if( pair.IsComplete() ) { push_back(pair); dout(" pair added! (" << "read: 0x" << std::hex << (unsigned int)pair.read << "," << "write: 0x" << std::hex << (unsigned int)pair.write << "," << "type: 0x" << std::hex << (unsigned int)pair.type << ")"); pair = EndpointPair(); // clear } ++iter; } m_valid = true; } EndpointPairings::~EndpointPairings() { } bool EndpointPairings::IsValid() const { return m_valid; } /////////////////////////////////////////////////////////////////////////////// // EndpointDescriptor bool EndpointDescriptor::IsRead() const { return m_read; } uint8_t EndpointDescriptor::GetAddress() const { return m_addr; } EndpointDescriptor::EpType EndpointDescriptor::GetType() const { return m_type; } /////////////////////////////////////////////////////////////////////////////// // Match Match::Match(DeviceList& devices, int vendor, int product, const char *busname, const char *devname) : m_list(devices.MatchDevices(vendor, product, busname, devname)) , m_iter(m_list.begin()) { } Match::~Match() { } bool Match::next_device(Usb::DeviceID& devid) { if( m_iter != m_list.end() ) { devid = *m_iter; ++m_iter; return true; } return false; } } // namespace Usb barry-0.18.5/src/iconvwin.cc0000644001161500056700000000610012242254476015203 0ustar cdfreycdfrey/// /// \file iconvwin.cc /// iconv wrapper class for Windows /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "iconv.h" #include "common.h" #include "error.h" #include #include #include #include using namespace std; namespace Barry { ////////////////////////////////////////////////////////////////////////////// // IConvHandlePrivate class class IConvHandlePrivate { public: }; ////////////////////////////////////////////////////////////////////////////// // IConvHandle class IConvHandle::IConvHandle(const char *fromcode, const char *tocode, bool throw_on_conv_err) : m_priv( new IConvHandlePrivate ) , m_throw_on_conv_err(throw_on_conv_err) { } IConvHandle::IConvHandle(const char *fromcode, const IConverter &ic, bool throw_on_conv_err) : m_priv( new IConvHandlePrivate ) , m_throw_on_conv_err(throw_on_conv_err) { } IConvHandle::IConvHandle(const IConverter &ic, const char *tocode, bool throw_on_conv_err) : m_priv( new IConvHandlePrivate ) , m_throw_on_conv_err(throw_on_conv_err) { } IConvHandle::IConvHandle(const IConvHandle &other) { /* This is private to prevent copying, so shouldn't ever be called. * However MSCL still generates refernces to it, so it needs to be provided. */ throw std::logic_error("IConvHandle copy constructor: should never be called."); } IConvHandle::~IConvHandle() { } IConvHandle& IConvHandle::operator=(const IConvHandle &other) { /* This is private to prevent copying, so shouldn't ever be called. * However MSCL still generates refernces to it, so it needs to be provided. */ throw std::logic_error("IConvHandle operator=(): should never be called."); } std::string IConvHandle::Convert(Data &tmp, const std::string &str) const { // FIXME - need to add Windows support return str; } ////////////////////////////////////////////////////////////////////////////// // IConvHandle class IConverter::IConverter(const char *tocode, bool throw_on_conv_err) : m_from(BLACKBERRY_CHARSET, tocode, throw_on_conv_err) , m_to(tocode, BLACKBERRY_CHARSET, throw_on_conv_err) , m_tocode(tocode) { } IConverter::~IConverter() { } std::string IConverter::FromBB(const std::string &str) const { return m_from.Convert(m_buffer, str); } std::string IConverter::ToBB(const std::string &str) const { return m_to.Convert(m_buffer, str); } std::string IConverter::Convert(const IConvHandle &custom, const std::string &str) const { return custom.Convert(m_buffer, str); } } // namespace Barry barry-0.18.5/src/r_contact.cc0000644001161500056700000005741012242254476015335 0ustar cdfreycdfrey/// /// \file r_contact.cc /// Blackberry database record parser class for contact records. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "r_contact.h" #include "record-internal.h" #include "protocol.h" #include "protostructs.h" #include "data.h" #include "time.h" #include "error.h" #include "endian.h" #include "iconv.h" #include "trim.h" #include #include #include #include #include #include "ios_state.h" #define __DEBUG_MODE__ #include "debug.h" using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // Contact class // Contact field codes #define CFC_EMAIL 1 #define CFC_PHONE 2 #define CFC_FAX 3 #define CFC_WORK_PHONE 6 #define CFC_HOME_PHONE 7 #define CFC_MOBILE_PHONE 8 #define CFC_PAGER 9 #define CFC_PIN 10 #define CFC_RADIO 14 // 0x0e #define CFC_WORK_PHONE_2 16 // 0x10 #define CFC_HOME_PHONE_2 17 // 0x11 #define CFC_OTHER_PHONE 18 // 0x12 #define CFC_MOBILE_PHONE_2 19 // 0x13 #define CFC_HOME_FAX 20 // 0x14 #define CFC_NAME 32 // 0x20 used twice, in first/last name order #define CFC_COMPANY 33 #define CFC_DEFAULT_COMM_METHOD 34 #define CFC_ADDRESS1 35 #define CFC_ADDRESS2 36 #define CFC_ADDRESS3 37 #define CFC_CITY 38 #define CFC_PROVINCE 39 #define CFC_POSTAL_CODE 40 #define CFC_COUNTRY 41 #define CFC_TITLE 42 // 0x2a #define CFC_PUBLIC_KEY 43 #define CFC_GROUP_FLAG 44 #define CFC_GROUP_LINK 52 #define CFC_URL 54 // 0x36 #define CFC_PREFIX 55 // 0x37 #define CFC_CATEGORY 59 // 0x3B #define CFC_HOME_ADDRESS1 61 // 0x3D #define CFC_HOME_ADDRESS2 62 // 0x3E // If the address 3 isn't mapped then it appears // in the same field as address2 with a space #define CFC_HOME_ADDRESS3 63 // 0x3F #define CFC_NOTES 64 // 0x40 #define CFC_USER_DEFINED_1 65 // 0x41 #define CFC_USER_DEFINED_2 66 // 0x42 #define CFC_USER_DEFINED_3 67 // 0x43 #define CFC_USER_DEFINED_4 68 // 0x44 #define CFC_HOME_CITY 69 // 0x45 #define CFC_HOME_PROVINCE 70 // 0x46 #define CFC_HOME_POSTAL_CODE 71 // 0x47 #define CFC_HOME_COUNTRY 72 // 0x48 #define CFC_IMAGE 77 // 0x4D #define CFC_BIRTHDAY 82 // 0x52 #define CFC_ANNIVERSARY 83 // 0x53 #define CFC_MAYBE_CATEGORYID 84 // 0x54 #define CFC_UNIQUEID 85 // 0x55 #define CFC_NICKNAME 86 // 0x56 #define CFC_INVALID_FIELD 255 // Contact code to field table static FieldLink ContactFieldLinks[] = { { CFC_NICKNAME, N_("Nickname"), 0,0, &Contact::Nickname, 0, 0, 0, 0, true }, { CFC_PHONE, N_("Phone"), 0,0, &Contact::Phone, 0, 0, 0, 0, true }, { CFC_FAX, N_("Fax"), "facsimileTelephoneNumber",0, &Contact::Fax, 0, 0, 0, 0, true }, { CFC_HOME_FAX, N_("HomeFax"), 0,0, &Contact::HomeFax, 0, 0, 0, 0, true }, { CFC_WORK_PHONE, N_("WorkPhone"), "telephoneNumber",0, &Contact::WorkPhone, 0, 0, 0, 0, true }, { CFC_HOME_PHONE, N_("HomePhone"), "homePhone",0, &Contact::HomePhone, 0, 0, 0, 0, true }, { CFC_MOBILE_PHONE, N_("MobilePhone"),"mobile",0, &Contact::MobilePhone, 0, 0, 0, 0, true }, { CFC_MOBILE_PHONE_2,N_("MobilePhone2"),0,0, &Contact::MobilePhone2, 0, 0, 0, 0, true }, { CFC_PAGER, N_("Pager"), "pager",0, &Contact::Pager, 0, 0, 0, 0, true }, { CFC_PIN, N_("PIN"), 0,0, &Contact::PIN, 0, 0, 0, 0, true }, { CFC_RADIO, N_("Radio"), 0,0, &Contact::Radio, 0, 0, 0, 0, true }, { CFC_WORK_PHONE_2, N_("WorkPhone2"), 0,0, &Contact::WorkPhone2, 0, 0, 0, 0, true }, { CFC_HOME_PHONE_2, N_("HomePhone2"), 0,0, &Contact::HomePhone2, 0, 0, 0, 0, true }, { CFC_OTHER_PHONE, N_("OtherPhone"), 0,0, &Contact::OtherPhone, 0, 0, 0, 0, true }, { CFC_COMPANY, N_("Company"), "o",0, &Contact::Company, 0, 0, 0, 0, true }, { CFC_DEFAULT_COMM_METHOD,N_("DefaultCommMethod"),0,0, &Contact::DefaultCommunicationsMethod, 0, 0, 0, 0, true }, { CFC_ADDRESS1, N_("WorkAddress1"), 0,0, 0, 0, 0, &Contact::WorkAddress, &PostalAddress::Address1, true }, { CFC_ADDRESS2, N_("WorkAddress2"), 0,0, 0, 0, 0, &Contact::WorkAddress, &PostalAddress::Address2, true }, { CFC_ADDRESS3, N_("WorkAddress3"), 0,0, 0, 0, 0, &Contact::WorkAddress, &PostalAddress::Address3, true }, { CFC_CITY, N_("WorkCity"), "l",0, 0, 0, 0, &Contact::WorkAddress, &PostalAddress::City, true }, { CFC_PROVINCE, N_("WorkProvince"), "st",0, 0, 0, 0, &Contact::WorkAddress, &PostalAddress::Province, true }, { CFC_POSTAL_CODE, N_("WorkPostalCode"), "postalCode",0, 0, 0, 0, &Contact::WorkAddress, &PostalAddress::PostalCode, true }, { CFC_COUNTRY, N_("WorkCountry"), "c", "country", 0, 0, 0, &Contact::WorkAddress, &PostalAddress::Country, true }, { CFC_TITLE, N_("JobTitle"), "title",0, &Contact::JobTitle, 0, 0, 0, 0, true }, { CFC_PUBLIC_KEY, N_("PublicKey"), 0,0, &Contact::PublicKey, 0, 0, 0, 0, false }, { CFC_URL, N_("URL"), 0,0, &Contact::URL, 0, 0, 0, 0, true }, { CFC_PREFIX, N_("Prefix"), 0,0, &Contact::Prefix, 0, 0, 0, 0, true }, { CFC_HOME_ADDRESS1,N_("HomeAddress1"), 0,0, 0, 0, 0, &Contact::HomeAddress, &PostalAddress::Address1, true }, { CFC_HOME_ADDRESS2,N_("HomeAddress2"), 0,0, 0, 0, 0, &Contact::HomeAddress, &PostalAddress::Address2, true }, { CFC_HOME_ADDRESS3,N_("HomeAddress3"), 0,0, 0, 0, 0, &Contact::HomeAddress, &PostalAddress::Address3, true }, { CFC_NOTES, N_("Notes"), 0,0, &Contact::Notes, 0, 0, 0, 0, true }, { CFC_USER_DEFINED_1, N_("UserDefined1"), 0,0, &Contact::UserDefined1, 0, 0, 0, 0, true }, { CFC_USER_DEFINED_2, N_("UserDefined2"), 0,0, &Contact::UserDefined2, 0, 0, 0, 0, true }, { CFC_USER_DEFINED_3, N_("UserDefined3"), 0,0, &Contact::UserDefined3, 0, 0, 0, 0, true }, { CFC_USER_DEFINED_4, N_("UserDefined4"), 0,0, &Contact::UserDefined4, 0, 0, 0, 0, true }, { CFC_HOME_CITY, N_("HomeCity"), 0,0, 0, 0, 0, &Contact::HomeAddress, &PostalAddress::City, true }, { CFC_HOME_PROVINCE,N_("HomeProvince"), 0,0, 0, 0, 0, &Contact::HomeAddress, &PostalAddress::Province, true }, { CFC_HOME_POSTAL_CODE, N_("HomePostalCode"), 0,0, 0, 0, 0, &Contact::HomeAddress, &PostalAddress::PostalCode, true }, { CFC_HOME_COUNTRY, N_("HomeCountry"),0,0, 0, 0, 0, &Contact::HomeAddress, &PostalAddress::Country, true }, { CFC_IMAGE, N_("Image"), 0,0, &Contact::Image, 0, 0, 0, 0, false }, { CFC_INVALID_FIELD,N_("EndOfList"), 0, 0, 0, 0, 0, 0, 0, false } }; Contact::Contact() : RecType(Contact::GetDefaultRecType()), RecordId(0), m_FirstNameSeen(false) { } Contact::~Contact() { } const unsigned char* Contact::ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { const CommonField *field = (const CommonField *) begin; // advance and check size begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size); if( begin > end ) // if begin==end, we are ok return begin; if( !btohs(field->size) ) // if field has no size, something's up return begin; // cycle through the type table for( FieldLink *b = ContactFieldLinks; b->type != CFC_INVALID_FIELD; b++ ) { if( b->type == field->type ) { if( b->strMember ) { std::string &s = this->*(b->strMember); s = ParseFieldString(field); if( b->iconvNeeded && ic ) s = ic->FromBB(s); return begin; // done! } else if( b->postMember && b->postField ) { std::string &s = (this->*(b->postMember)).*(b->postField); s = ParseFieldString(field); if( b->iconvNeeded && ic ) s = ic->FromBB(s); return begin; } else { break; // fall through to special handling } } } // if not found in the type table, check for special handling switch( field->type ) { case CFC_EMAIL: { std::string s = ParseFieldString(field); if( ic ) s = ic->FromBB(s); EmailAddresses.push_back( s ); } return begin; case CFC_NAME: { // can be used multiple times, for first/last names std::string *name; if( FirstName.size() || m_FirstNameSeen ) { // first name already filled, use last name name = &LastName; m_FirstNameSeen = false; } else { name = &FirstName; m_FirstNameSeen = true; } *name = ParseFieldString(field); if( ic ) *name = ic->FromBB(*name); } return begin; case CFC_GROUP_LINK: // just add the unique ID to the list GroupLinks.push_back( GroupLink(field->u.link.uniqueId, field->u.link.unknown)); return begin; case CFC_GROUP_FLAG: // ignore the group flag... the presense of group link items // behaves as the flag in this class return begin; case CFC_CATEGORY: { std::string catstring = ParseFieldString(field); if( ic ) catstring = ic->FromBB(catstring); Categories.CategoryStr2List(catstring); } return begin; case CFC_BIRTHDAY: { std::string bstring = ParseFieldString(field); Birthday.FromBBString(bstring); } return begin; case CFC_ANNIVERSARY: { std::string astring = ParseFieldString(field); Anniversary.FromBBString(astring); } return begin; case CFC_UNIQUEID: // this is a duplicate of the UniqueID that comes from // the envelope part of the protocol... just throw this // away, since when we upload it, we need to use a // consistent UniqueID / RecordID from the API return begin; } // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; uf.data.assign((const char*)field->u.raw, btohs(field->size)); Unknowns.push_back(uf); // return new pointer for next field return begin; } void Contact::ParseHeader(const Data &data, size_t &offset) { // no header to parse in Contact records } void Contact::ParseFields(const Data &data, size_t &offset, const IConverter *ic) { const unsigned char *finish = ParseCommonFields(*this, data.GetData() + offset, data.GetData() + data.GetSize(), ic); offset += finish - (data.GetData() + offset); } void Contact::Validate() const { if( !GetFullName().size() && !Company.size() ) { throw Barry::ValidationError(_("A contact record must contain either a First/Last name, or a Company name.")); } } void Contact::BuildHeader(Data &data, size_t &offset) const { // no header in Contact records } // // BuildFields // /// Build fields part of record /// void Contact::BuildFields(Data &data, size_t &offset, const IConverter *ic) const { data.Zap(); // Sanity check: the Blackberry requires at least a name or // a company name for each address record. if( !GetFullName().size() && !Company.size() ) throw BadData(_("Contact must have name or company name.")); // check if this is a group link record, and if so, output // the group flag if( GroupLinks.size() ) BuildField(data, offset, CFC_GROUP_FLAG, 'G'); // special fields not in type table if( FirstName.size() ) { std::string s = ic ? ic->ToBB(FirstName) : FirstName; BuildField(data, offset, CFC_NAME, s); } if( LastName.size() ) { if( !FirstName.size() ) { // order matters with first/last name, and if // last name exists, and first name doesn't, // insert blank first name ahead of it BuildField(data, offset, CFC_NAME, ""); } BuildField(data, offset, CFC_NAME, ic ? ic->ToBB(LastName) : LastName); } // FIXME // // add unknown data // char buffer[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; // BuildField(data, offset, 0x54, buffer, 8); // With the BlackBerry Storm, I have to add this entry. // Otherwise the uniqueId of this contact is reseted ! // The device seems accept the multiple contact with the same uniqueId, // but the synchronization process uses this uniqueId to identify the contact. // add uniqueId BuildField(data, offset, CFC_UNIQUEID, RecordId); // add all email addresses EmailList::const_iterator eai = EmailAddresses.begin(); for( ; eai != EmailAddresses.end(); ++eai ) { if( eai->size() ) { BuildField(data, offset, CFC_EMAIL, ic ? ic->ToBB(*eai) : *eai); } } // cycle through the type table for( FieldLink *b = ContactFieldLinks; b->type != CFC_INVALID_FIELD; b++ ) { // print only fields with data if( b->strMember ) { const std::string &field = this->*(b->strMember); if( field.size() ) { std::string s = (b->iconvNeeded && ic) ? ic->ToBB(field) : field; BuildField(data, offset, b->type, s); } } else if( b->postMember && b->postField ) { const std::string &field = (this->*(b->postMember)).*(b->postField); if( field.size() ) { std::string s = (b->iconvNeeded && ic) ? ic->ToBB(field) : field; BuildField(data, offset, b->type, s); } } } // save any group links GroupLinksType::const_iterator gb = GroupLinks.begin(), ge = GroupLinks.end(); for( ; gb != ge; gb++ ) { Barry::Protocol::GroupLink link; link.uniqueId = htobl(gb->Link); link.unknown = htobs(gb->Unknown); BuildField(data, offset, CFC_GROUP_LINK, link); } // save categories if( Categories.size() ) { string store; Categories.CategoryList2Str(store); BuildField(data, offset, CFC_CATEGORY, ic ? ic->ToBB(store) : store); } // save Birthday and Anniversary if( Birthday.HasData() ) BuildField(data, offset, CFC_BIRTHDAY, Birthday.ToBBString()); if( Anniversary.HasData() ) BuildField(data, offset, CFC_ANNIVERSARY, Anniversary.ToBBString()); // and finally save unknowns UnknownsType::const_iterator ub = Unknowns.begin(), ue = Unknowns.end(); for( ; ub != ue; ub++ ) { BuildField(data, offset, *ub); } data.ReleaseBuffer(offset); } void Contact::Clear() { RecType = GetDefaultRecType(); RecordId = 0; EmailAddresses.clear(); Phone.clear(); Fax.clear(); HomeFax.clear(); WorkPhone.clear(); HomePhone.clear(); MobilePhone.clear(); MobilePhone2.clear(); Pager.clear(); PIN.clear(); Radio.clear(); WorkPhone2.clear(); HomePhone2.clear(); OtherPhone.clear(); FirstName.clear(); LastName.clear(); Company.clear(); DefaultCommunicationsMethod.clear(); JobTitle.clear(); PublicKey.clear(); URL.clear(); Prefix.clear(); Notes.clear(); UserDefined1.clear(); UserDefined2.clear(); UserDefined3.clear(); UserDefined4.clear(); Image.clear(); Nickname.clear(); Birthday.Clear(); Anniversary.Clear(); WorkAddress.Clear(); HomeAddress.Clear(); Categories.clear(); GroupLinks.clear(); Unknowns.clear(); m_FirstNameSeen = false; } const FieldHandle::ListT& Contact::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; #undef CONTAINER_OBJECT_NAME #define CONTAINER_OBJECT_NAME fhv #undef RECORD_CLASS_NAME #define RECORD_CLASS_NAME Contact // first number is priority of fields... 0 being most critical fields FHP(RecType, _("Record Type Code")); FHP(RecordId, _("Unique ID")); FHP(EmailAddresses, _("Email Addresses")); FHP(FirstName, _("First Name")); FHP(LastName, _("Last Name")); FHL(Company, _("Company"), CFC_COMPANY, true, "o", 0); FHL(JobTitle, _("Job Title"), CFC_TITLE, true, "title", 0); FHD(Prefix, _("Prefix"), CFC_PREFIX, true); FHD(Nickname, _("Nickname"), CFC_NICKNAME, true); FHD(Phone, _("Phone (deprecated)"), CFC_PHONE, true); FHL(Fax, _("Work Fax"), CFC_FAX, true, "facsimileTelephoneNumber", 0); FHD(HomeFax, _("Home Fax"), CFC_HOME_FAX, true); FHL(WorkPhone, _("Work Phone"), CFC_WORK_PHONE, true, "telephoneNumber", 0); FHD(WorkPhone2, _("Work Phone 2"), CFC_WORK_PHONE_2, true); FHL(HomePhone, _("Home Phone"), CFC_HOME_PHONE, true, "homePhone", 0); FHD(HomePhone2, _("Home Phone 2"), CFC_HOME_PHONE_2, true); FHL(MobilePhone, _("Mobile Phone"), CFC_MOBILE_PHONE, true, "mobile", 0); FHD(MobilePhone2, _("Mobile Phone 2"), CFC_MOBILE_PHONE_2, true); FHD(OtherPhone, _("Other Phone"), CFC_OTHER_PHONE, true); FHL(Pager, _("Pager"), CFC_PAGER, true, "pager", 0); FHD(PIN, _("PIN"), CFC_PIN, true); FHD(Radio, _("Radio"), CFC_RADIO, true); FHD(DefaultCommunicationsMethod, _("Default Communications Method"), CFC_DEFAULT_COMM_METHOD, true); FHD(PublicKey, _("Public Key"), CFC_PUBLIC_KEY, false); FHD(URL, _("URL"), CFC_URL, true); FHD(Notes, _("Notes"), CFC_NOTES, true); FHD(UserDefined1, _("User Defined Field 1"), CFC_USER_DEFINED_1, true); FHD(UserDefined2, _("User Defined Field 2"), CFC_USER_DEFINED_2, true); FHD(UserDefined3, _("User Defined Field 3"), CFC_USER_DEFINED_3, true); FHD(UserDefined4, _("User Defined Field 4"), CFC_USER_DEFINED_4, true); FHD(Image, _("Image"), CFC_IMAGE, false); FHD(Birthday, _("Birthday"), CFC_BIRTHDAY, true); FHD(Anniversary, _("Anniversary"), CFC_ANNIVERSARY, true); FHC(WorkAddress, _("Work Address")); FHS(WorkAddress, Address1, _("Work Address 1"), CFC_ADDRESS1, true, 0, 0); FHS(WorkAddress, Address2, _("Work Address 2"), CFC_ADDRESS2, true, 0, 0); FHS(WorkAddress, Address3, _("Work Address 3"), CFC_ADDRESS3, true, 0, 0); FHS(WorkAddress, City, _("Work City"), CFC_CITY, true, "l", 0); FHS(WorkAddress, Province, _("Work Province"), CFC_PROVINCE, true, "st", 0); FHS(WorkAddress, PostalCode, _("Work Postal Code"), CFC_POSTAL_CODE, true, "postalCode", 0); FHS(WorkAddress, Country, _("Work Country"), CFC_COUNTRY, true, "c", "country"); FHC(HomeAddress, _("Home Address")); FHS(HomeAddress, Address1, _("Home Address 1"), CFC_HOME_ADDRESS1, true, 0, 0); FHS(HomeAddress, Address2, _("Home Address 2"), CFC_HOME_ADDRESS2, true, 0, 0); FHS(HomeAddress, Address3, _("Home Address 3"), CFC_HOME_ADDRESS3, true, 0, 0); FHS(HomeAddress, City, _("Home City"), CFC_HOME_CITY, true, 0, 0); FHS(HomeAddress, Province, _("Home Province"), CFC_HOME_PROVINCE, true, 0, 0); FHS(HomeAddress, PostalCode, _("Home Postal Code"), CFC_HOME_POSTAL_CODE, true, 0, 0); FHS(HomeAddress, Country, _("Home Country"), CFC_HOME_COUNTRY, true, 0, 0); FHP(Categories, _("Categories")); // FHP(GroupLinks, _("Group Links")); FHP(Unknowns, _("Unknown Fields")); return fhv; } std::string Contact::GetDescription() const { string desc = GetFullName(); if( desc.size() == 0 && Company.size() ) return Company; return desc; } // // GetFullName // /// Helper function that returns a formatted full name /// std::string Contact::GetFullName() const { std::string Full = FirstName; if( Full.size() && LastName.size() ) Full += " "; Full += LastName; return Full; } // // GetEmail // /// Helper function that always returns a valid string. The string /// may be empty if there is no address at the specified index. /// const std::string& Contact::GetEmail(unsigned int index) const { static const std::string blank; if( index < EmailAddresses.size() ) return EmailAddresses[index]; return blank; } void Contact::Dump(std::ostream &os) const { ios_format_state state(os); os.setf(ios::left); os.fill(' '); os << _("Contact: ") << "0x" << setbase(16) << GetID() << " (" << (unsigned int)RecType << ")\n"; // special fields not in type table os << " " << setw(20) << _("FirstName"); os << ": " << FirstName << "\n"; os << " " << setw(20) << _("LastName"); os << ": " << LastName << "\n"; // cycle through email addresses EmailList::const_iterator eai = EmailAddresses.begin(); for( ; eai != EmailAddresses.end(); ++eai ) { if( eai->size() ) { os << _(" Email : ") << *eai << "\n"; } } // cycle through the type table for( FieldLink *b = ContactFieldLinks; b->type != CFC_INVALID_FIELD; b++ ) { // special case: don't dump the raw image data, but // leave that for a special hex dump if( b->type == CFC_IMAGE ) continue; const std::string *pField = 0; if( b->strMember ) { pField = &(this->*(b->strMember)); } else if( b->postMember && b->postField ) { pField = &((this->*(b->postMember)).*(b->postField)); } // print only fields with data if( pField && pField->size() ) { os << " " << setw(20) << gettext(b->name); os << ": " << Cr2LfWrapper(*pField) << "\n"; } } if( Categories.size() ) { string display; Categories.CategoryList2Str(display); os << _(" Categories : ") << display << "\n"; } // print Birthday and Anniversary if( Birthday.HasData() ) { os << _(" Birthday : ") << Birthday << "\n"; } if( Anniversary.HasData() ) { os << _(" Anniversary : ") << Anniversary << "\n"; } // print any group links GroupLinksType::const_iterator gb = GroupLinks.begin(), ge = GroupLinks.end(); if( gb != ge ) os << _(" GroupLinks:\n"); for( ; gb != ge; gb++ ) { os << _(" ID: ") << "0x" << setbase(16) << gb->Link << "\n"; } // print Image in hex dump format, if available if( Image.size() ) { Data image(Image.data(), Image.size()); os << _(" Photo image:\n"); os << image << "\n"; } // and finally print unknowns os << Unknowns; } bool Contact::operator<(const Contact &other) const { // old sorting mechanism, to put group links at the bottom //return GroupLinks.size() == 0 && other.GroupLinks.size() > 0; // testing - put group links at the top //return GroupLinks.size() > 0 && other.GroupLinks.size() == 0; // usually one of these fields is filled in, so compare // them all in a ( LastName + FirstName + Company ) key style int cmp = LastName.compare(other.LastName); if( cmp == 0 ) cmp = FirstName.compare(other.FirstName); if( cmp == 0 ) cmp = Company.compare(other.Company); return cmp < 0; } void Contact::SplitName(const std::string &full, std::string &first, std::string &last) { first.clear(); last.clear(); string::size_type pos = full.find_last_of(' '); if( pos != string::npos ) { // has space, assume last word is last name last = full.c_str() + pos + 1; first = full.substr(0, pos); } else { // no space, assume only first name first = full.substr(0); } } std::string Contact::Email2CommaString(const EmailList &list) { ostringstream oss; for( EmailList::const_iterator i = list.begin(); i!=list.end(); ++i ) { if( i != list.begin() ) oss << ", "; oss << *i; } return oss.str(); } /// Replaces the EmailAddresses list with the parsed results of /// list. If list is empty, then EmailAddresses will also be empty. /// Note that incoming addresses need to be in simple format, not /// complex formats like "Name " but just /// "user@example.com". This is a device limitation. /// /// Any complex email addresses found in the list will be dropped, /// with a message sent to the debug output stream. void Contact::CommaString2Email(const std::string &list, EmailList &result) { // start fresh result.clear(); // parse the comma separated list istringstream iss(list); string address; while( iss >> ws && getline(iss, address, ',') ) { // trim any trailing whitespace in the address Inplace::rtrim(address); // is this a complex address? like: // Chris Frey // The device only accepts the plain // "cdfrey@foursquare.net" part here if( address.rfind('>') != string::npos ) { dout(_("Error: Cannot convert complex name+address to a simple contact email address, skipping: ") << address); continue; } // add to list if anything left if( address.size() ) { result.push_back(address); } } } } // namespace Barry barry-0.18.5/src/r_calendar.cc0000644001161500056700000004302512242254476015450 0ustar cdfreycdfrey/// /// \file r_calendar.cc /// Blackberry database record parser class for calendar records. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "r_calendar.h" #include "r_recur_base-int.h" #include "record-internal.h" #include "protocol.h" #include "protostructs.h" #include "data.h" #include "time.h" #include "error.h" #include "endian.h" #include "iconv.h" #include #include #include #include #include #include "ios_state.h" #define __DEBUG_MODE__ #include "debug.h" using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // Calendar class, static members // // Note! These functions currently only pass the same values through. // In actuality, these are technically two different values: // one on the raw protocol side, and the other part of the // guaranteed Barry API. If the Blackberry ever changes the // meanings for these codes, do the translation here. // Calendar::FreeBusyFlagType Calendar::FreeBusyFlagProto2Rec(uint8_t f) { return (FreeBusyFlagType)f; } uint8_t Calendar::FreeBusyFlagRec2Proto(FreeBusyFlagType f) { return f; } Calendar::ClassFlagType Calendar::ClassFlagProto2Rec(uint8_t f) { return (ClassFlagType)f; } uint8_t Calendar::ClassFlagRec2Proto(ClassFlagType f) { return f; } /////////////////////////////////////////////////////////////////////////////// // Calendar class // calendar field codes #define CALFC_APPT_TYPE_FLAG 0x01 #define CALFC_SUBJECT 0x02 #define CALFC_NOTES 0x03 #define CALFC_LOCATION 0x04 #define CALFC_NOTIFICATION_TIME 0x05 #define CALFC_START_TIME 0x06 #define CALFC_END_TIME 0x07 #define CALFC_ACCEPTED_BY 0x0b #define CALFC_VERSION_DATA 0x10 #define CALFC_INVITED 0x15 #define CALFC_ORGANIZER 0x16 #define CALFC_NOTIFICATION_DATA 0x1a #define CALFC_FREEBUSY_FLAG 0x1c #define CALFC_TIMEZONE_CODE 0x1e // only seems to show up if recurring #define CALFC_CLASS_FLAG 0x28 // private flag from outlook #define CALFC_CALENDAR_ID 0x2b // Calendar using (new devices have several calendar) #define CALFC_ALLDAYEVENT_FLAG 0xff #define CALFC_END 0xffff static FieldLink CalendarFieldLinks[] = { { CALFC_SUBJECT, N_("Subject"), 0, 0, &Calendar::Subject, 0, 0, 0, 0, true }, { CALFC_NOTES, N_("Notes"), 0, 0, &Calendar::Notes, 0, 0, 0, 0, true }, { CALFC_LOCATION, N_("Location"), 0, 0, &Calendar::Location, 0, 0, 0, 0, true }, { CALFC_NOTIFICATION_TIME,N_("Notification Time"),0,0, 0, 0, &Calendar::NotificationTime, 0, 0, false }, { CALFC_START_TIME, N_("Start Time"), 0, 0, 0, 0, &Calendar::StartTime, 0, 0, false }, { CALFC_END_TIME, N_("End Time"), 0, 0, 0, 0, &Calendar::EndTime, 0, 0, false }, { CALFC_ORGANIZER, N_("Organizer"), 0, 0, 0, &Calendar::Organizer, 0, 0, 0, true }, { CALFC_ACCEPTED_BY,N_("Accepted By"),0, 0, 0, &Calendar::AcceptedBy, 0, 0, 0, true }, { CALFC_INVITED, N_("Invited"), 0, 0, 0, &Calendar::Invited, 0, 0, 0, true }, { CALFC_END, N_("End of List"),0, 0, 0, 0, 0, 0, 0, false } }; Calendar::Calendar() { Clear(); } Calendar::~Calendar() { } const unsigned char* Calendar::ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { const CommonField *field = (const CommonField *) begin; // advance and check size begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size); if( begin > end ) // if begin==end, we are ok return begin; if( !btohs(field->size) ) // if field has no size, something's up return begin; // cycle through the type table for( FieldLink *b = CalendarFieldLinks; b->type != CALFC_END; b++ ) { if( b->type == field->type ) { if( b->strMember ) { std::string &s = this->*(b->strMember); s = ParseFieldString(field); if( b->iconvNeeded && ic ) s = ic->FromBB(s); return begin; // done! } else if( b->timeMember && btohs(field->size) == 4 ) { TimeT &t = this->*(b->timeMember); dout("min1900: " << field->u.min1900); t.Time = min2time(field->u.min1900); return begin; } else if( b->addrMember ) { // // parse email address // get dual addr+name string first // Note: this is a different format than // used in r_message*.cc // std::string dual((const char*)field->u.raw, btohs(field->size)); EmailAddress a; // assign first string, using null terminator // letting std::string add it for us if it // doesn't exist a.Email = dual.c_str(); // assign second string, using first size // as starting point a.Name = dual.c_str() + a.Email.size() + 1; // if the address is non-empty, add to list if( a.size() ) { // i18n convert if needed if( b->iconvNeeded && ic ) { a.Name = ic->FromBB(a.Name); a.Email = ic->FromBB(a.Email); } EmailAddressList &al = this->*(b->addrMember); al.push_back(a); } return begin; } } } // handle special cases switch( field->type ) { case CALFC_APPT_TYPE_FLAG: switch( field->u.raw[0] ) { case 'a': // regular non-recurring appointment Recurring = false; return begin; case '*': // recurring appointment Recurring = true; return begin; default: throw Error(_("Calendar::ParseField: unknown appointment type")); } break; case CALFC_ALLDAYEVENT_FLAG: AllDayEvent = field->u.raw[0] == 1; return begin; case CALFC_TIMEZONE_CODE: if( btohs(field->size) == 2 ) { // good data TimeZoneCode = btohs(field->u.code); TimeZoneValid = true; } else { throw Error(_("Calendar::ParseField: not enough data in time zone code field")); } return begin; case CALFC_FREEBUSY_FLAG: if( field->u.raw[0] > CR_FREEBUSY_RANGE_HIGH ) { throw Error(_("Calendar::ParseField: FreeBusyFlag out of range")); } FreeBusyFlag = FreeBusyFlagProto2Rec(field->u.raw[0]); return begin; case CALFC_CALENDAR_ID: if( btohs(field->size) == 8 ) { CalendarID = btohll(field->u.uint64); } else { throw Error(_("Calendar::ParseField: size data unknown in calendar field")); } return begin; case CALFC_CLASS_FLAG: if( field->u.raw[0] > CR_CLASS_RANGE_HIGH ) { throw Error(_("Calendar::ParseField: ClassFlag out of range" )); } ClassFlag = ClassFlagProto2Rec(field->u.raw[0]); return begin; } // base class handles recurring data if( RecurBase::ParseField(field->type, field->u.raw, btohs(field->size), ic) ) return begin; // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; uf.data.assign((const char*)field->u.raw, btohs(field->size)); Unknowns.push_back(uf); // return new pointer for next field return begin; } void Calendar::ParseHeader(const Data &data, size_t &offset) { // no header in Calendar records } void Calendar::ParseFields(const Data &data, size_t &offset, const IConverter *ic) { const unsigned char *finish = ParseCommonFields(*this, data.GetData() + offset, data.GetData() + data.GetSize(), ic); offset += finish - (data.GetData() + offset); } void Calendar::Validate() const { RecurBase::Validate(); } void Calendar::BuildHeader(Data &data, size_t &offset) const { // no header in Calendar records } // // Build // /// Build fields part of record. /// void Calendar::BuildFields(Data &data, size_t &offset, const IConverter *ic) const { data.Zap(); // output the type first BuildField(data, offset, CALFC_APPT_TYPE_FLAG, Recurring ? '*' : 'a'); // output all day event flag only if set if( AllDayEvent ) BuildField(data, offset, CALFC_ALLDAYEVENT_FLAG, (char)1); // cycle through the type table for( const FieldLink *b = CalendarFieldLinks; b->type != CALFC_END; b++ ) { if( b->strMember ) { const std::string &s = this->*(b->strMember); if( s.size() ) BuildField(data, offset, b->type, (b->iconvNeeded && ic) ? ic->ToBB(s) : s); } else if( b->timeMember ) { TimeT t = this->*(b->timeMember); if( t.Time > 0 ) BuildField1900(data, offset, b->type, t.Time); } else if( b->addrMember ) { const EmailAddressList &al = this->*(b->addrMember); EmailAddressList::const_iterator lb = al.begin(), le = al.end(); // add all entries in list for( ; lb != le; ++lb ) { // skip empty entries if( !lb->size() ) continue; std::string Name = lb->Name, Email = lb->Email; // do i18n conversion only if needed if( b->iconvNeeded && ic ) { Name = ic->ToBB(Name); Email = ic->ToBB(Email); } // // Build an addr+name field, each string // null terminated. // Note: this is a different format than // what is used in r_message*.cc // std::string field(lb->Email.c_str(), lb->Email.size() + 1); field.append(lb->Name.c_str(), lb->Name.size() + 1); BuildField(data, offset, b->type, field.data(), field.size()); } } } // handle special cases if( Recurring ) { CalendarRecurrenceDataField recur; BuildRecurrenceData(StartTime.Time, &recur); BuildField(data, offset, RecurBase::RecurringFieldType(), &recur, CALENDAR_RECURRENCE_DATA_FIELD_SIZE); } if( TimeZoneValid ) BuildField(data, offset, CALFC_TIMEZONE_CODE, TimeZoneCode); BuildField(data, offset, CALFC_FREEBUSY_FLAG, FreeBusyFlagRec2Proto(FreeBusyFlag)); BuildField(data, offset, CALFC_CLASS_FLAG, ClassFlagRec2Proto(ClassFlag)); // If CalendarID is defined and most of supported ! // (by default 0xffff ffff ffff ffff) if( CalendarID != (uint64_t) -1 ) BuildField(data, offset, CALFC_CALENDAR_ID, CalendarID); // and finally save unknowns UnknownsType::const_iterator ub = Unknowns.begin(), ue = Unknowns.end(); for( ; ub != ue; ub++ ) { BuildField(data, offset, *ub); } data.ReleaseBuffer(offset); } void Calendar::Clear() { // clear the base class too RecurBase::Clear(); // clear our fields RecType = GetDefaultRecType(); RecordId = 0; AllDayEvent = false; Subject.clear(); Notes.clear(); Location.clear(); NotificationTime.clear(); StartTime.clear(); EndTime.clear(); Organizer.clear(); AcceptedBy.clear(); Invited.clear(); FreeBusyFlag = Free; ClassFlag = Public; CalendarID = btohll((uint64_t) -1); TimeZoneCode = GetStaticTimeZoneCode(0, 0); // default to GMT TimeZoneValid = false; Unknowns.clear(); } const FieldHandle::ListT& Calendar::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; #undef CONTAINER_OBJECT_NAME #define CONTAINER_OBJECT_NAME fhv #undef RECORD_CLASS_NAME #define RECORD_CLASS_NAME Calendar #define ALL_COMMON_CALENDAR_FIELDS \ FHP(RecType, _("Record Type Code")); \ FHP(RecordId, _("Unique Record ID")); \ \ FHP(AllDayEvent, _("All Day Event")); \ FHD(Subject, _("Subject"), CALFC_SUBJECT, true); \ FHD(Notes, _("Notes"), CALFC_NOTES, true); \ FHD(Location, _("Location"), CALFC_LOCATION, true); \ FHD(NotificationTime, _("Notification Time (0 is off)"), \ CALFC_NOTIFICATION_TIME, false); \ FHD(StartTime, _("Start Time"), CALFC_START_TIME, false); \ FHD(EndTime, _("End Time"), CALFC_END_TIME, false); \ FHD(Organizer, _("Organizer"), CALFC_ORGANIZER, true); \ FHD(AcceptedBy, _("Accepted By"), CALFC_ACCEPTED_BY, true); \ FHD(Invited, _("Invited"), CALFC_INVITED, true); \ \ FHE(fbf, FreeBusyFlagType, FreeBusyFlag, _("Free or Busy Flag")); \ FHE_CONST(fbf, Free, _("Free")); \ FHE_CONST(fbf, Tentative, _("Tentative")); \ FHE_CONST(fbf, Busy, _("Busy")); \ FHE_CONST(fbf, OutOfOffice, _("Out of Office")); \ \ FHE(cf, ClassFlagType, ClassFlag, _("Event Class")); \ FHE_CONST(cf, Public, _("Public")); \ FHE_CONST(cf, Confidential, _("Confidential")); \ FHE_CONST(cf, Private, _("Private")); \ \ FHP(TimeZoneCode, _("Time Zone Code")); \ FHP(TimeZoneValid, _("Time Zone Validity")); \ \ FHP(Unknowns, _("Unknown Fields")); ALL_COMMON_CALENDAR_FIELDS // the fields unique to Calendar, or different in CalendarALL FHD(CalendarID, _("Calendar ID"), CALFC_CALENDAR_ID, false); // and finally, the RecurBase fields RECUR_BASE_FIELD_HANDLES return fhv; } std::string Calendar::GetDescription() const { return Subject; } void Calendar::DumpSpecialFields(std::ostream &os) const { ios_format_state state(os); static const char *ClassTypes[] = { N_("Public"), N_("Confidential"), N_("Private") }; static const char *FreeBusy[] = { N_("Free"), N_("Tentative"), N_("Busy"), N_("Out of Office") }; os << _(" Calendar ID: ") << "0x" << setbase(16) << CalendarID << "\n"; os << _(" All Day Event: ") << (AllDayEvent ? "yes" : "no") << "\n"; os << _(" Class: ") << ClassTypes[ClassFlag] << "\n"; os << _(" Free/Busy: ") << FreeBusy[FreeBusyFlag] << "\n"; if( TimeZoneValid ) os << _(" Time Zone: ") << gettext(GetStaticTimeZone(TimeZoneCode)->Name) << "\n"; } void Calendar::Dump(std::ostream &os) const { ios_format_state state(os); // FIXME - need a "check all data" function that make sure that all // recurrence data is within range. Then call that before using // the data, such as in Build and in Dump. os << _("Calendar entry: ") << "0x" << setbase(16) << RecordId << " (" << (unsigned int)RecType << ")\n"; DumpSpecialFields(os); // cycle through the type table for( const FieldLink *b = CalendarFieldLinks; b->type != CALFC_END; b++ ) { if( b->strMember ) { const std::string &s = this->*(b->strMember); if( s.size() ) os << " " << gettext(b->name) << ": " << s << "\n"; } else if( b->timeMember ) { TimeT t = this->*(b->timeMember); if( t.Time > 0 ) os << " " << gettext(b->name) << ": " << t << "\n"; else os << " " << gettext(b->name) << ": " << _("disabled") << "\n"; } else if( b->addrMember ) { const EmailAddressList &al = this->*(b->addrMember); EmailAddressList::const_iterator lb = al.begin(), le = al.end(); for( ; lb != le; ++lb ) { if( !lb->size() ) continue; os << " " << gettext(b->name) << ": " << *lb << "\n"; } } } // print recurrence data if available RecurBase::Dump(os); // print any unknowns os << Unknowns; } bool Calendar::operator<(const Calendar &other) const { if( StartTime < other.StartTime ) return true; else if( other.StartTime < StartTime ) return false; // times are equal, so secondary sort based on Subject + Location int cmp = Subject.compare(other.Subject); if( cmp == 0 ) cmp = Location.compare(other.Location); return cmp < 0; } /////////////////////////////////////////////////////////////////////////////// // Calendar-All class // calendar-all field codes #define CALALLFC_CALENDAR_ID 0x02 // Calendar using (new devices have several calendar) #define CALALLFC_MAIL_ACCOUNT 0x03 #define CALALLFC_UNIQUEID 0x05 #define CALALLFC_CAL_OBJECT 0x0a #define CALALLFC_END 0xffff void CalendarAll::Clear() { Calendar::Clear(); MailAccount.clear(); } const FieldHandle::ListT& CalendarAll::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; #undef CONTAINER_OBJECT_NAME #define CONTAINER_OBJECT_NAME fhv #undef RECORD_CLASS_NAME #define RECORD_CLASS_NAME CalendarAll ALL_COMMON_CALENDAR_FIELDS // Calendar:: field, but with a CalendarAll ID FHD(CalendarID, _("Calendar ID"), CALALLFC_CALENDAR_ID, false); // add the fields specific to CalendarAll FHD(MailAccount, _("Mail Account"), CALALLFC_MAIL_ACCOUNT, true); // and finally, the RecurBase fields RECUR_BASE_FIELD_HANDLES return fhv; } void CalendarAll::ParseHeader(const Data &data, size_t &offset) { const unsigned char *b = (const unsigned char*) (data.GetData() + offset); const unsigned char *e = (const unsigned char*) (data.GetData() + data.GetSize()); while( (b + COMMON_FIELD_HEADER_SIZE) < e ) { const CommonField *field = (const CommonField *) b; // advance and check size b += COMMON_FIELD_HEADER_SIZE + btohs(field->size); if( b > e ) // if begin==end, we are ok continue; if( !btohs(field->size) ) // if field has no size, something's up continue; // handle special cases if( field->type == CALALLFC_CAL_OBJECT ) { b -= btohs(field->size); // end of header break; } switch( field->type ) { case CALALLFC_CALENDAR_ID: if( btohs(field->size) == 8 ) { CalendarID = btohll(field->u.uint64); } else { throw Error(_("CalendarAll::ParseField: size data unknown in calendar field")); } continue; case CALALLFC_MAIL_ACCOUNT: MailAccount = ParseFieldString(field); continue; case CALALLFC_UNIQUEID: if( btohs(field->size) == 4 ) { RecordId = btohl(field->u.uint32); } else { throw Error(_("CalendarAll::ParseHeader: size data unknown in calendar field")); } continue; } // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; uf.data.assign((const char*)field->u.raw, btohs(field->size)); Unknowns.push_back(uf); } offset += b - (data.GetData() + offset); } void CalendarAll::DumpSpecialFields(std::ostream &os) const { ios_format_state state(os); Calendar::DumpSpecialFields(os); os << _(" Mail Account: ") << MailAccount << "\n"; } } // namespace Barry barry-0.18.5/src/builder.cc0000644001161500056700000000363212242254476015004 0ustar cdfreycdfrey/// /// \file builder.cc /// Virtual protocol packet builder wrapper /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "builder.h" #include #include namespace Barry { ////////////////////////////////////////////////////////////////////////////// // DBDataBuilder class DBDataBuilder::DBDataBuilder(const DBData &orig) : m_orig(orig) { } DBDataBuilder::~DBDataBuilder() { } bool DBDataBuilder::BuildRecord(DBData &data, size_t &offset, const IConverter *ic) { if( offset == m_orig.GetOffset() ) { data = m_orig; } else { // copy the metadata data.CopyMeta(m_orig); // copy the buffer, to the new offset if( m_orig.GetOffset() > m_orig.GetData().GetSize() ) throw std::logic_error(_("DBDataBuilder: offset greater than size")); size_t actual = m_orig.GetData().GetSize() - m_orig.GetOffset(); size_t total = offset + actual; unsigned char *buf = data.UseData().GetBuffer(total); memcpy(buf + offset, m_orig.GetData().GetData() + m_orig.GetOffset(), actual); data.UseData().ReleaseBuffer(total); // set the new offset data.SetOffset(offset); } return true; } bool DBDataBuilder::FetchRecord(DBData &data, const IConverter *ic) { data = m_orig; return true; } bool DBDataBuilder::EndOfFile() const { return true; } } // namespace Barry barry-0.18.5/src/bmp.h0000644001161500056700000000236312242254476013776 0ustar cdfreycdfrey/// /// \file bmp.h /// BMP conversion routines /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_BMP_H__ #define __BARRY_BMP_H__ #include "dll.h" #include #include namespace Barry { class Data; class JLScreenInfo; BXEXPORT size_t GetBitmapHeadersSize(); BXEXPORT size_t GetTotalBitmapSize(const JLScreenInfo &info); BXEXPORT void ScreenshotToRGB(const JLScreenInfo &info, const Data &screenshot, Data &buffer, size_t offset, int depth, bool invert, bool overwrite_alpha = false, uint8_t alpha = 0xFF); BXEXPORT void ScreenshotToBitmap(const JLScreenInfo &info, const Data &screenshot, Data &bitmap); } #endif barry-0.18.5/src/barrysync.h0000644001161500056700000000172312242254476015233 0ustar cdfreycdfrey/// /// \file barrysync.h /// Main header file for libbarrysync /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_BARRYSYNC_H__ #define __BARRY_BARRYSYNC_H__ // Include the Sync and vFormat support classes #include "tzwrapper.h" #include "vbase.h" #include "vcard.h" #include "vevent.h" #include "vjournal.h" #include "vtodo.h" #include "mimeio.h" #endif barry-0.18.5/src/r_bookmark.cc0000644001161500056700000002645412242254476015513 0ustar cdfreycdfrey/// /// \file r_bookmark.cc /// Record parsing class for the phone browser bookmarks database. /// /* Copyright (C) 2008-2010, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "r_bookmark.h" #include "record-internal.h" #include "protostructs.h" #include "data.h" #include "time.h" #include "iconv.h" #include "debug.h" #include #include #include #include "ios_state.h" using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // Bookmark Class // Bookmark Field Codes #define BMKFC_BOOKMARK_TYPE 0x01 #define BMKFC_STRUCT1 0x11 #define BMKFC_STRUCT2 0x12 #define BMKFC_END 0xffff // Bookmark Struct1 section codes #define BMK1SC_HOMEPAGE_KEY 0x85 // default section on 9550... // has browser dropdown grayed // out #define BMK1SC_BOOKMARK_ID 0x87 // when user adds a bookmark #define BMK1SC_BOOKMARK_ID2 0x84 // only Nicolas sees this? #define BMK1SC_NAME 0x04 #define BMK1SC_ICON 0x05 #define BMK1SC_FOLDERS 0x81 //static FieldLink BookmarkFieldLinks[] = { // { BMKFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false } //}; Bookmark::Bookmark() { Clear(); } Bookmark::~Bookmark() { } const unsigned char* Bookmark::ParseStruct1Field(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { // grab section type const uint8_t type = *begin; begin += 1; if( begin > end ) return begin; switch( type ) { case BMK1SC_HOMEPAGE_KEY: case BMK1SC_BOOKMARK_ID: case BMK1SC_BOOKMARK_ID2: { const BookmarkId *id = (const BookmarkId*) begin; begin += BOOKMARK_ID_SIZE; if( begin > end ) return begin; // not sure where id->bookmark_id links to, so ignore // for now... Index = id->index; } return begin; case BMK1SC_NAME: case BMK1SC_ICON: { const VarStringField *f = (const VarStringField*) begin; begin += VARSTRING_FIELD_HEADER_SIZE; if( begin > end ) return begin; const uint16_t size = be_btohs(f->be_size); if( f->present == 1) { // if field is defined begin += size; if( begin > end ) return begin; switch( type ) { case BMK1SC_NAME: Name = ParseFieldString(f->data, size); break; case BMK1SC_ICON: Icon = ParseFieldString(f->data, size); break; default: throw std::logic_error("Bookmark: Check case statement. Should never happen."); break; } } else if( f->present == 0 && size > 0xA0 ) { // FIXME - a size of 0xA5 seems to occasionally // appear, with 5 bytes of id-looking data // we just skip it here.... note this // may be a different field, but it meshes // itself into the ICON section somehow, // that is unclear // // example with the A5, before modification to add '?' // Type: 0x11 Data: // 00000000: 85 9b ed ca 13 00 04 01 00 09 48 6f 6d 65 20 50 ..........Home P // 00000010: 61 67 65 81 b9 fc f8 f6 c2 e3 a4 d5 08 01 05 00 age............. // 00000020: 00 a5 b8 f0 97 e4 3a 00 00 01 ......:... // // example without the A5, after record modified: // Type: 0x11 Data: // 00000000: 85 9b ed ca 13 00 04 01 00 0a 48 6f 6d 65 20 50 ..........Home P // 00000010: 61 67 65 3f 81 b9 fc f8 f6 c2 e3 a4 d5 08 01 05 age?............ // 00000020: 00 00 00 00 00 01 ...... // begin += size & 0x0F; } } return begin; case BMK1SC_FOLDERS: { //const BookmarkFolders *f = (const BookmarkFolders*) begin; begin += BOOKMARK_FOLDERS_HEADER_SIZE; if( begin > end ) return begin; // currently don't know how to link these to // anything else in the device.... skipping } return begin; /* case 0x08: isdefined = *b; b += sizeof(uint8_t); if (isdefined == 1) { // if field is defined const uint16_t size = be_btohs(*((const uint16_t *) b)); b += sizeof(uint16_t); b += size; } break; */ default: // if we are 3 bytes away from the end, these are the // display, javascript, and browser identity flags // (make sure to account for the type we ate above) if( (end - begin) == 2 ) { if ((Barry::Bookmark::DisplayModeType) *(begin - 3) > Barry::Bookmark::DisplayUnknown) DisplayMode = Barry::Bookmark::DisplayUnknown; else DisplayMode = (Barry::Bookmark::DisplayModeType) *(begin - 3); if ((Barry::Bookmark::JavaScriptModeType) *(begin - 2) > Barry::Bookmark::JavaScriptUnknown) JavaScriptMode = Barry::Bookmark::JavaScriptUnknown; else JavaScriptMode = (Barry::Bookmark::JavaScriptModeType) *(begin - 2); if ((Barry::Bookmark::BrowserIdentityType) *(begin - 1) > Barry::Bookmark::IdentityUnknown) BrowserIdentity = Barry::Bookmark::IdentityUnknown; else BrowserIdentity = (Barry::Bookmark::BrowserIdentityType) *(begin - 1); } // if we are at the beginning, this could be the 7750 // with its odd no-code ID... the 7750 seems to have // a BOOKMARK_ID record without any code byte, // so check that the data looks like this: // XX XX XX XX 00 // with the 4 byte ID and the index of 0, being the // first default bookmark else if( (begin + 3) < end && begin[3] == 0 ) { // recurse into ourselves return ParseStruct1Field(begin + 4, end, ic); } else { ddout("Bookmark parser: unknown section type: " << std::hex << (unsigned int) type); } break; } return begin; } const unsigned char* Bookmark::ParseStruct2(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { // first field in struct2 seems to always be the URL // grab size and advance over string, checking sizes const StringField *field = (const StringField*) begin; begin += STRING_FIELD_HEADER_SIZE; if( begin > end ) return begin; const uint16_t size = be_btohs(field->be_size); begin += sizeof(uint16_t) + size; if( begin > end ) // if begin==end, we are ok return begin; Url = ParseFieldString(field->data, size); // FIXME - more fields after this, but unknown meaning return begin; } const unsigned char* Bookmark::ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { const CommonField *field = (const CommonField *) begin; // advance and check size begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size); if( begin > end ) // if begin==end, we are ok return begin; if( !btohs(field->size) ) // if field has no size, something's up return begin; const unsigned char *b = field->u.raw; const unsigned char *e = begin; // handle special cases switch( field->type ) { case BMKFC_STRUCT1: while (b <= e) { b = ParseStruct1Field(b, e, ic); } return b; case BMKFC_BOOKMARK_TYPE: // above size check guarantees at least one byte, // so this is safe if( field->u.raw[0] != 'D' ) { throw Error( _("Bookmark::ParseField: BookmarkType is not 'D'") ); } return begin; case BMKFC_STRUCT2: begin = ParseStruct2(b, e, ic); return begin; } // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; uf.data.assign((const char*)field->u.raw, btohs(field->size)); Unknowns.push_back(uf); // return new pointer for next field return begin; } void Bookmark::ParseHeader(const Data &data, size_t &offset) { // no header in Bookmark records } void Bookmark::ParseFields(const Data &data, size_t &offset, const IConverter *ic) { const unsigned char *finish = ParseCommonFields(*this, data.GetData() + offset, data.GetData() + data.GetSize(), ic); offset += finish - (data.GetData() + offset); } void Bookmark::Validate() const { } void Bookmark::BuildHeader(Data &data, size_t &offset) const { // not yet implemented } void Bookmark::BuildFields(Data &data, size_t &offset, const IConverter *ic) const { // not yet implemented } void Bookmark::Dump(std::ostream &os) const { ios_format_state state(os); static const char *DisplayModeName[] = { N_("Automatic"), N_("Enabled"), N_("Disabled"), N_("Unknown") }; static const char *JavaScriptModeName[] = { N_("Automatic"), N_("Enabled"), N_("Disabled"), N_("Unknown") }; static const char *BrowserIdentityName[] = { N_("Automatic"), N_("BlackBerry"), N_("FireFox"), N_("Internet Explorer"), N_("Unknown") }; os << _("Bookmark entry: ") << "0x" << setbase(16) << RecordId << " (" << (unsigned int)RecType << ")" << " (" << _("index ") << (unsigned int)Index << ")\n"; if( Name.size() ) os << _(" Name: ") << Name << "\n"; if( Icon.size() ) os << _(" Icon: ") << Icon << "\n"; if( Url.size() ) os << _(" Url: ") << Url << "\n"; os << _(" Display mode: ") << gettext( DisplayModeName[DisplayMode] ) << "\n"; os << _(" JavaScript mode: ") << gettext( JavaScriptModeName[JavaScriptMode] ) << "\n"; os << _(" Browser Identity: ") << gettext( BrowserIdentityName[BrowserIdentity] ) << "\n"; os << Unknowns; os << "\n\n"; } bool Bookmark::operator<(const Bookmark &other) const { int cmp = Name.compare(other.Name); return cmp < 0; } void Bookmark::Clear() { RecType = GetDefaultRecType(); RecordId = 0; Index = 0; Name.clear(); Icon.clear(); Url.clear(); BrowserIdentity = IdentityUnknown; DisplayMode = DisplayUnknown; JavaScriptMode = JavaScriptUnknown; Unknowns.clear(); } const FieldHandle::ListT& Bookmark::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; #undef CONTAINER_OBJECT_NAME #define CONTAINER_OBJECT_NAME fhv #undef RECORD_CLASS_NAME #define RECORD_CLASS_NAME Bookmark FHP(RecType, _("Record Type")); FHP(RecordId, _("Unique Record ID")); FHP(Index, _("Bookmark Field Index")); FHP(Name, _("Site Name")); FHP(Icon, _("Site Icon")); FHP(Url, _("Site URL")); FHE(bit, BrowserIdentityType, BrowserIdentity, _("Browser Identity")); FHE_CONST(bit, IdentityAuto, _("Auto detect browser")); FHE_CONST(bit, IdentityBlackBerry, _("BlackBerry browser")); FHE_CONST(bit, IdentityFireFox, _("FireFox browser")); FHE_CONST(bit, IdentityInternetExplorer, _("Internet Explorer browser")); FHE_CONST(bit, IdentityUnknown, _("Unknown browser")); FHE(dmc, DisplayModeType, DisplayMode, _("Display Mode")); FHE_CONST(dmc, DisplayAuto, _("Automatic")); FHE_CONST(dmc, DisplayColomn, _("Column")); FHE_CONST(dmc, DisplayPage, _("Page")); FHE_CONST(dmc, DisplayUnknown, _("Unknown")); FHE(jsm, JavaScriptModeType, JavaScriptMode, _("JavaScript Mode")); FHE_CONST(jsm, JavaScriptAuto, _("Automatic")); FHE_CONST(jsm, JavaScriptEnabled, _("Enabled")); FHE_CONST(jsm, JavaScriptDisabled, _("Disabled")); FHE_CONST(jsm, JavaScriptUnknown, _("Unknown")); FHP(Unknowns, _("Unknown Fields")); return fhv; } std::string Bookmark::GetDescription() const { return Name; } } // namespace Barry barry-0.18.5/src/Makefile.am0000644001161500056700000002140212242254476015076 0ustar cdfreycdfrey # The following version numbers are: current:revision:age # # See also: http://sources.redhat.com/autobook/autobook/autobook_91.html # # Current - number of the current interface of the library # Revision - implementation number of most recent interface # Age - number of previous additional interfaces supported by this library # # Libtool uses the following calculation for Linux: # # major = current - age # suffix = major.age.revision # # Therefore a libtool version of 1.4.0 will translate to a filename of: # libbarry.so.1.0.4 # # Other operating systems just use current.revision, most of the time, # and age is only used to subtract from current. # # Therefore, if you are careful never to increment the major version # unless there is an incompatible break, you can get away with a # two digit version number, and leave age as 0, always. # # Only ever increment the first 2 numbers in this version: # The first number represents libmajor, the second libminor. # So version 0.17.1 will look like 17:1:0 LIB_BARRY_VERSION = @BARRY_MAJOR@:@BARRY_MINOR@:0 # Disable the default -I. -I$(srcdir) -I$(topdir), etc, but $(top_builddir) is # needed for config.h DEFAULT_INCLUDES = -I$(top_builddir) #INCLUDES = $(USB_LIBRARY_CFLAGS) $(OPENSSL_CFLAGS) INCLUDES = $(USB_LIBRARY_CFLAGS) #AM_CXXFLAGS = -ansi -Wall -fno-strict-aliasing -g -D__DEBUG_MODE__ AM_CFLAGS = -Wall -fno-strict-aliasing -g -D__BARRY_LIBRARY_BUILD__ AM_CXXFLAGS = -Wall -fno-strict-aliasing -g -D__BARRY_LIBRARY_BUILD__ AM_LDFLAGS = if WITH_GCCVISIBILITY AM_CFLAGS += -D__BARRY_HAVE_GCCVISIBILITY__ -fvisibility=hidden #AM_CXXFLAGS += -D__BARRY_HAVE_GCCVISIBILITY__ -fvisibility=hidden -fvisibility-inlines-hidden AM_CXXFLAGS += -D__BARRY_HAVE_GCCVISIBILITY__ -fvisibility=hidden #AM_LDFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden AM_LDFLAGS += -fvisibility=hidden endif include_barrydir = ${includedir}/barry@BARRY_MAJOR@/barry ## ## Boost library usage - required for serialization support, but optional ## #BOOSTFLAG = -D__BARRY_BOOST_MODE__ -I../../../../boost/rootdir/include/boost-1_33_1 #LDBOOST = ../../../../boost/rootdir/lib/libboost_serialization-gcc-mt-1_33_1.a ##BOOSTFLAG = ##LDBOOST = # Heavy duty C++ warnings #WARNFLAGS = -ansi -pedantic -Wall -W -Wold-style-cast -Wfloat-equal -Wwrite-strings -Wno-long-long #WARNFLAGS = -ansi -pedantic -Wall -W -Weffc++ -Woverloaded-virtual -Wold-style-cast -Wfloat-equal -Wwrite-strings -Wno-long-long -Werror #LDFLAGS = ../../external/rootdir/libusb/lib/libusb.a $(LDBOOST) $(LDDEBUG) # To use gettext datadir = @datadir@ localedir = $(datadir)/locale DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@ # # libbarry - main USB protocol interface library # libbarryalx - ALX library # libbarrydp - '.debug' parser library # libbarryjdwp - java debug server library # libbarrysync - utility functions and classes for syncing and vformats # libbarrybackup - utility classes for reading/writing Barry backup files # lib_LTLIBRARIES = libbarry.la libbarrydp.la libbarryjdwp.la if WITH_SYNC lib_LTLIBRARIES += libbarrysync.la endif if WITH_BACKUP lib_LTLIBRARIES += libbarrybackup.la endif if WITH_ALX lib_LTLIBRARIES += libbarryalx.la endif include_barry_HEADERS = barry.h barrysync.h barrybackup.h barryalx.h \ dll.h \ builder.h \ common.h \ configfile.h \ controller.h \ xmlparser.h \ a_common.h \ a_codsection.h \ a_library.h \ a_application.h \ a_osloader.h \ a_alxparser.h \ m_mode_base.h \ m_desktop.h \ m_raw_channel.h \ m_desktoptmpl.h \ m_ipmodem.h \ m_serial.h \ m_javaloader.h \ m_jvmdebug.h \ data.h \ error.h \ ldif.h \ ldifio.h \ log.h \ parser.h \ pin.h \ probe.h \ protocol.h \ record.h \ recordtmpl.h \ modem.h \ r_recur_base.h \ r_calendar.h \ r_calllog.h \ r_bookmark.h \ r_contact.h \ r_cstore.h \ r_folder.h \ r_hhagent.h \ r_memo.h \ r_message_base.h \ r_message.h \ r_pin_message.h \ r_saved_message.h \ r_servicebook.h \ r_sms.h \ r_task.h \ r_timezone.h \ dataqueue.h \ router.h \ socket.h \ time.h \ threadwrap.h \ vsmartptr.h \ version.h \ pppfilter.h \ sha1.h \ iconv.h \ cod.h \ bmp.h \ s11n-boost.h \ dp_codinfo.h \ j_manager.h \ j_server.h \ vformat.h \ vbase.h \ vcard.h \ vevent.h \ vjournal.h \ vtodo.h \ mimeio.h \ scoped_lock.h \ semaphore.h \ backup.h \ restore.h \ pipe.h \ connector.h \ trim.h \ fifoargs.h \ tzwrapper.h noinst_HEADERS = cbarry.h \ i18n.h gettext.h \ base64.h \ record-internal.h \ r_recur_base-int.h \ bmp-internal.h \ cod-internal.h \ controllerpriv.h \ packet.h \ protostructs.h \ debug.h \ endian.h \ strnlen.h \ getpwuid.h \ platform.h \ dp_parser.h \ j_message.h \ j_jdwp.h \ tarfile.h \ usbwrap_libusb.h \ usbwrap_libusb_1_0.h \ ios_state.h \ clog.h # Include the windows-only and android-only code files here too EXTRA_DIST = convo.awk \ legal.txt \ iconvwin.cc \ getpwuidandroid.cc \ configfilewin32.cc libbarry_la_SOURCES = dll.h \ builder.h builder.cc \ parser.h parser.cc \ time.h time.cc \ fifoargs.h fifoargs.cc \ base64.h base64.cc \ bmp.h bmp-internal.h bmp.cc \ cod.h cod-internal.h cod.cc \ data.h data.cc \ pin.h pin.cc \ probe.h probe.cc \ common.h common.cc \ configfile.h configfile.cc \ configfileunix.cc \ error.h error.cc \ ldif.h ldif.cc \ ldifio.h ldifio.cc \ log.h log.cc \ socket.cc \ router.cc \ dataqueue.cc \ threadwrap.cc \ protocol.h protostructs.h protocol.cc \ record.h recordtmpl.h record-internal.h record.cc \ r_recur_base.h r_recur_base-int.h r_recur_base.cc \ r_calendar.h r_calendar.cc \ r_calllog.h r_calllog.cc \ r_bookmark.h r_bookmark.cc \ r_command.cc \ r_contact.h r_contact.cc \ r_cstore.h r_cstore.cc \ r_hhagent.h r_hhagent.cc \ r_dbdb.cc \ r_folder.h r_folder.cc \ r_memo.h r_memo.cc \ r_message_base.h r_message_base.cc \ r_recordstate.cc \ r_servicebook.h r_servicebook.cc \ r_sms.h r_sms.cc \ r_task.h r_task.cc \ r_timezone.h r_timezone.cc \ packet.h packet.cc \ controller.h controller.cc \ pipe.h pipe.cc \ m_mode_base.h m_mode_base.cc \ m_desktop.h m_desktop.cc \ m_raw_channel.h m_raw_channel.cc \ m_ipmodem.h m_ipmodem.cc \ m_serial.h m_serial.cc \ m_javaloader.h m_javaloader.cc \ m_jvmdebug.h m_jvmdebug.cc \ connector.h connector.cc \ version.h version.cc \ pppfilter.h pppfilter.cc \ sha1.h sha1.cc \ iconv.h iconv.cc # Now sort out USB files if USE_BARRY_SOCKETS include_barry_HEADERS += usbwrap.h libbarry_la_SOURCES += usbwrap.cc if USE_LIBUSB_0_1 libbarry_la_SOURCES += usbwrap_libusb.cc endif if USE_LIBUSB_1_0 libbarry_la_SOURCES += usbwrap_libusb_1_0.cc endif endif # USE_BARRY_SOCKETS #libbarry_la_LIBADD = $(LTLIBOBJS) $(USB_LIBRARY_LIBS) $(OPENSSL_LIBS) libbarry_la_LIBADD = $(LTLIBOBJS) $(USB_LIBRARY_LIBS) $(ZLIB_LIBS) @LTLIBICONV@ \ $(NETWORK_LIBRARY_LIBS) libbarry_la_LDFLAGS = -version-info ${LIB_BARRY_VERSION} libbarrydp_la_SOURCES = \ dp_parser.h dp_parser.cc \ dp_codinfo.h dp_codinfo.cc libbarrydp_la_LIBADD = libbarry.la libbarrydp_la_LDFLAGS = -version-info ${LIB_BARRY_VERSION} libbarryjdwp_la_SOURCES = \ j_record.cc \ j_jdwp.h j_jdwp.cc \ j_message.h j_message.cc \ j_server.h j_server.cc \ j_manager.h j_manager.cc libbarryjdwp_la_LIBADD = libbarry.la libbarrydp.la $(USB_LIBRARY_LIBS) $(NETWORK_LIBRARY_LIBS) libbarryjdwp_la_LDFLAGS = -version-info ${LIB_BARRY_VERSION} if WITH_SYNC libbarrysync_la_SOURCES = \ vformat.h vformat.c \ vbase.h vbase.cc \ vcard.h vcard.cc \ vevent.h vevent.cc \ vjournal.h vjournal.cc \ vtodo.h vtodo.cc \ mimeio.h mimeio.cc \ tzwrapper.h tzwrapper.cc # if we set CFLAGS and CXXFLAGS ourselves, we need to include # AM_*FLAGS as well... this only seems to matter for compile flags, # not link flags libbarrysync_la_CFLAGS = $(AM_CFLAGS) $(GLIB2_CFLAGS) libbarrysync_la_CXXFLAGS = $(AM_CXXFLAGS) $(GLIB2_CFLAGS) libbarrysync_la_LIBADD = libbarry.la $(GLIB2_LIBS) libbarrysync_la_LDFLAGS = -version-info ${LIB_BARRY_VERSION} endif if WITH_BACKUP libbarrybackup_la_SOURCES = \ tarfile.cc tarfile-ops-nt.cc \ backup.h backup.cc \ restore.h restore.cc libbarrybackup_la_CFLAGS = $(AM_CFLAGS) $(LIBTAR_CFLAGS) $(LIBZ_CFLAGS) libbarrybackup_la_CXXFLAGS = $(AM_CXXFLAGS) $(LIBTAR_CFLAGS) $(LIBZ_CFLAGS) libbarrybackup_la_LIBADD = libbarry.la $(LIBTAR_LIBS) $(LIBZ_LIBS) libbarrybackup_la_LDFLAGS = -version-info ${LIB_BARRY_VERSION} endif if WITH_ALX libbarryalx_la_SOURCES = \ xmlparser.h xmlparser.cc \ a_common.h \ a_codsection.h a_codsection.cc \ a_library.h a_library.cc \ a_application.h a_application.cc \ a_osloader.h a_osloader.cc \ a_alxparser.h a_alxparser.cc libbarryalx_la_CXXFLAGS = $(AM_CXXFLAGS) $(LIBXMLXX_CFLAGS) libbarryalx_la_LIBADD = libbarry.la $(LIBXMLXX_LIBS) libbarryalx_la_LDFLAGS = -version-info ${LIB_BARRY_VERSION} endif ##if DO_TEST ## bin_PROGRAMS += test-base64 test-data test-time ## ## test_base64_SOURCES = base64.h base64.cc ## test_data_SOURCES = data.h data.cc ## test_time_SOURCES = time.h time.cc ##endif barry-0.18.5/src/s11n-boost.h0000644001161500056700000005317012242254476015130 0ustar cdfreycdfrey/// /// \file s11n-boost.h /// Non-intrusive versions of serialization functions for the /// record classes. These template functions make it possible /// to use the record classes with the Boost::Serialization /// library. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_S11N_BOOST_H__ #define __BARRY_S11N_BOOST_H__ #include "dll.h" #include "record.h" #include /////////////////////////////////////////////////////////////////////////////// // special versions // // BARRY_BASE_S11N_VERSION - the base version where all record data is // stored so it can be fully retrieved and // uploaded to the handheld device later. // BARRY_POD_MAP_VERSION - if these templates are called with a version // equal or greater than this, only mappable, // POD data is included in the serialization // #define BARRY_BASE_S11N_VERSION 0 #define BARRY_POD_MAP_VERSION 1000 // namespace boost::serialization, for the non-intrusive version namespace boost { namespace serialization { template void serialize(ArchiveT &ar, Barry::TimeT &t, const unsigned int ver) { ar & make_nvp("Barry::TimeT::Time", t.Time); } template void serialize(ArchiveT &ar, Barry::UnknownField &uf, const unsigned int ver) { ar & make_nvp("type", uf.type); ar & make_nvp("data", uf.data.raw_data); } template void serialize(ArchiveT &ar, Barry::Contact::GroupLink &g, const unsigned int ver) { ar & make_nvp("Link", g.Link); ar & make_nvp("Unknown", g.Unknown); } template void serialize(ArchiveT &ar, Barry::CategoryList &cl, const unsigned int ver) { std::vector &sl = cl; ar & make_nvp("CategoryList", sl); } template void serialize(ArchiveT &ar, Barry::EmailList &el, const unsigned int ver) { std::vector &sl = el; ar & make_nvp("EmailList", sl); } template void serialize(ArchiveT &ar, Barry::Contact &c, const unsigned int ver) { ar & make_nvp("RecType", c.RecType); ar & make_nvp("RecordId", c.RecordId); ar & make_nvp("EmailAddresses", c.EmailAddresses); ar & make_nvp("Phone", c.Phone); ar & make_nvp("Fax", c.Fax); ar & make_nvp("HomeFax", c.HomeFax); ar & make_nvp("WorkPhone", c.WorkPhone); ar & make_nvp("HomePhone", c.HomePhone); ar & make_nvp("MobilePhone", c.MobilePhone); ar & make_nvp("MobilePhone2", c.MobilePhone2); ar & make_nvp("Pager", c.Pager); ar & make_nvp("PIN", c.PIN); ar & make_nvp("Radio", c.Radio); ar & make_nvp("WorkPhone2", c.WorkPhone2); ar & make_nvp("HomePhone2", c.HomePhone2); ar & make_nvp("OtherPhone", c.OtherPhone); ar & make_nvp("FirstName", c.FirstName); ar & make_nvp("LastName", c.LastName); ar & make_nvp("Company", c.Company); ar & make_nvp("DefaultCommunicationsMethod", c.DefaultCommunicationsMethod); ar & make_nvp("Address1", c.WorkAddress.Address1); ar & make_nvp("Address2", c.WorkAddress.Address2); ar & make_nvp("Address3", c.WorkAddress.Address3); ar & make_nvp("City", c.WorkAddress.City); ar & make_nvp("Province", c.WorkAddress.Province); ar & make_nvp("PostalCode", c.WorkAddress.PostalCode); ar & make_nvp("Country", c.WorkAddress.Country); ar & make_nvp("JobTitle", c.JobTitle); ar & make_nvp("PublicKey", c.PublicKey); ar & make_nvp("URL", c.URL); ar & make_nvp("Prefix", c.Prefix); ar & make_nvp("Categories", c.Categories); ar & make_nvp("HomeAddress1", c.HomeAddress.Address1); ar & make_nvp("HomeAddress2", c.HomeAddress.Address2); ar & make_nvp("HomeAddress3", c.HomeAddress.Address3); ar & make_nvp("Notes", c.Notes); ar & make_nvp("UserDefined1", c.UserDefined1); ar & make_nvp("UserDefined2", c.UserDefined2); ar & make_nvp("UserDefined3", c.UserDefined3); ar & make_nvp("UserDefined4", c.UserDefined4); ar & make_nvp("HomeCity", c.HomeAddress.City); ar & make_nvp("HomeProvince", c.HomeAddress.Province); ar & make_nvp("HomePostalCode", c.HomeAddress.PostalCode); ar & make_nvp("HomeCountry", c.HomeAddress.Country); ar & make_nvp("Image", c.Image); ar & make_nvp("Nickname", c.Nickname); if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp("GroupLinks", c.GroupLinks); ar & make_nvp("Unknowns", c.Unknowns); } } template void serialize(ArchiveT &ar, Barry::EmailAddress &a, const unsigned int ver) { ar & make_nvp("Name", a.Name); ar & make_nvp("Email", a.Email); } template void serialize(ArchiveT &ar, Barry::EmailAddressList &eal, const unsigned int ver) { std::vector &v = eal; ar & make_nvp("EmailAddressList", v); } template void serialize(ArchiveT &ar, Barry::Message &m, const unsigned int ver) { ar & make_nvp("From", m.From); ar & make_nvp("To", m.To); ar & make_nvp("Cc", m.Cc); ar & make_nvp("Sender", m.Sender); ar & make_nvp("ReplyTo", m.ReplyTo); ar & make_nvp("Subject", m.Subject); ar & make_nvp("Body", m.Body); ar & make_nvp("Attachment", m.Attachment); ar & make_nvp("MessageRecordId", m.MessageRecordId); ar & make_nvp("MessageReplyTo", m.MessageReplyTo); ar & make_nvp("MessageDateSent", m.MessageDateSent.Time); ar & make_nvp("MessageDateReceived", m.MessageDateReceived.Time); ar & make_nvp("MessageTruncated", m.MessageTruncated); ar & make_nvp("MessageRead", m.MessageRead); ar & make_nvp("MessageReply", m.MessageReply); ar & make_nvp("MessageSaved", m.MessageSaved); ar & make_nvp("MessageSavedDeleted", m.MessageSavedDeleted); ar & make_nvp("MessagePriority", m.Priority); ar & make_nvp("MessageSensitivity", m.Sensitivity); if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp("Unknowns", m.Unknowns); } } template void serialize(ArchiveT &ar, Barry::Calendar &c, const unsigned int ver) { ar & make_nvp("RecType", c.RecType); ar & make_nvp("RecordId", c.RecordId); ar & make_nvp("AllDayEvent", c.AllDayEvent); ar & make_nvp("Subject", c.Subject); ar & make_nvp("Notes", c.Notes); ar & make_nvp("Location", c.Location); ar & make_nvp("NotificationTime", c.NotificationTime.Time); ar & make_nvp("StartTime", c.StartTime.Time); ar & make_nvp("EndTime", c.EndTime.Time); ar & make_nvp("Organizer", c.Organizer); ar & make_nvp("AcceptedBy", c.AcceptedBy); ar & make_nvp("Invited", c.Invited); ar & make_nvp("FreeBusyFlag", c.FreeBusyFlag); ar & make_nvp("ClassFlag", c.ClassFlag); ar & make_nvp("Recurring", c.Recurring); ar & make_nvp("RecurringType", c.RecurringType); ar & make_nvp("Interval", c.Interval); ar & make_nvp("RecurringEndTime", c.RecurringEndTime.Time); ar & make_nvp("Perpetual", c.Perpetual); ar & make_nvp("CalendarID", c.CalendarID); ar & make_nvp("TimeZoneCode", c.TimeZoneCode); ar & make_nvp("TimeZoneValid", c.TimeZoneValid); ar & make_nvp("DayOfWeek", c.DayOfWeek); ar & make_nvp("WeekOfMonth", c.WeekOfMonth); ar & make_nvp("DayOfMonth", c.DayOfMonth); ar & make_nvp("MonthOfYear", c.MonthOfYear); ar & make_nvp("WeekDays", c.WeekDays); if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp("Unknowns", c.Unknowns); } } template void serialize(ArchiveT &ar, Barry::CalendarAll &c, const unsigned int ver) { serialize(ar, static_cast(c), ver); ar & make_nvp("MailAccount", c.MailAccount); } template void serialize(ArchiveT &ar, Barry::CallLog &c, const unsigned int ver) { ar & make_nvp("RecType", c.RecType); ar & make_nvp("RecordId", c.RecordId); ar & make_nvp("Duration", c.Duration); ar & make_nvp("Timestamp", c.Timestamp); ar & make_nvp("ContactName", c.ContactName); ar & make_nvp("PhoneNumber", c.PhoneNumber); ar & make_nvp("DirectionFlag", c.DirectionFlag); ar & make_nvp("StatusFlag", c.StatusFlag); ar & make_nvp("PhoneTypeFlag", c.PhoneTypeFlag); ar & make_nvp("PhoneInfoFlag", c.PhoneInfoFlag); if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp("Unknowns", c.Unknowns); } } template void serialize(ArchiveT &ar, Barry::Bookmark &c, const unsigned int ver) { ar & make_nvp("RecType", c.RecType); ar & make_nvp("RecordId", c.RecordId); ar & make_nvp("Index", c.Index); ar & make_nvp("Name", c.Name); ar & make_nvp("Icon", c.Icon); ar & make_nvp("Url", c.Url); ar & make_nvp("BrowserIdentity", c.BrowserIdentity); ar & make_nvp("DisplayMode", c.DisplayMode); ar & make_nvp("JavaScriptMode", c.JavaScriptMode); if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp("Unknowns", c.Unknowns); } } template void serialize(ArchiveT &ar, Barry::ServiceBookConfig &c, const unsigned int ver) { ar & make_nvp("Format", c.Format); if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp("Unknowns", c.Unknowns); } } template void serialize(ArchiveT &ar, Barry::ServiceBook &c, const unsigned int ver) { ar & make_nvp("RecType", c.RecType); ar & make_nvp("RecordId", c.RecordId); ar & make_nvp("Name", c.Name); ar & make_nvp("HiddenName", c.HiddenName); ar & make_nvp("Description", c.Description); ar & make_nvp("DSID", c.DSID); ar & make_nvp("BesDomain", c.BesDomain); ar & make_nvp("UniqueId", c.UniqueId); ar & make_nvp("ContentId", c.ContentId); ar & make_nvp("Config", c.Config); if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp("Unknowns", c.Unknowns); } } template void serialize(ArchiveT &ar, Barry::Memo &m, const unsigned int ver) { ar & make_nvp("RecType", m.RecType); ar & make_nvp("RecordId", m.RecordId); ar & make_nvp("Title", m.Title); ar & make_nvp("Body", m.Body); ar & make_nvp("Categories", m.Categories); if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp( "Unknowns", m.Unknowns); } } template void serialize(ArchiveT &ar, Barry::Task &t, const unsigned int ver) { ar & make_nvp("RecType", t.RecType); ar & make_nvp("RecordId", t.RecordId); ar & make_nvp("Summary", t.Summary); ar & make_nvp("Notes", t.Notes); ar & make_nvp("Categories", t.Categories); ar & make_nvp("UID", t.UID); ar & make_nvp("StartTime", t.StartTime.Time); ar & make_nvp("DueTime", t.DueTime.Time); ar & make_nvp("AlarmTime", t.AlarmTime.Time); ar & make_nvp("TimeZoneCode", t.TimeZoneCode); ar & make_nvp("TimeZoneValid", t.TimeZoneValid); ar & make_nvp("AlarmType", t.AlarmType); ar & make_nvp("Interval", t.Interval); ar & make_nvp("RecurringType", t.RecurringType); ar & make_nvp("RecurringEndTime", t.RecurringEndTime.Time); ar & make_nvp("DayOfWeek", t.DayOfWeek); ar & make_nvp("WeekOfMonth", t.WeekOfMonth); ar & make_nvp("DayOfMonth", t.DayOfMonth); ar & make_nvp("MonthOfYear", t.MonthOfYear); ar & make_nvp("WeekDays", t.WeekDays); ar & make_nvp("PriorityFlag", t.PriorityFlag); ar & make_nvp("StatusFlag", t.StatusFlag); ar & make_nvp("Recurring", t.Recurring); ar & make_nvp("Perpetual", t.Perpetual); if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp( "Unknowns", t.Unknowns); } } template void serialize(ArchiveT &ar, Barry::PINMessage &p, const unsigned int ver) { ar & make_nvp("RecType", p.RecType); ar & make_nvp("RecordId", p.RecordId); ar & make_nvp("From", p.From); ar & make_nvp("To", p.To); ar & make_nvp("Cc", p.Cc); ar & make_nvp("Bcc", p.Bcc); ar & make_nvp("Subject", p.Subject); ar & make_nvp("Body", p.Body); ar & make_nvp("MessageRecordId", p.MessageRecordId); ar & make_nvp("MessageReplyTo", p.MessageReplyTo); ar & make_nvp("MessageDateSent", p.MessageDateSent.Time); ar & make_nvp("MessageDateReceived", p.MessageDateReceived.Time); ar & make_nvp("MessageTruncated", p.MessageTruncated); ar & make_nvp("MessageRead", p.MessageRead); ar & make_nvp("MessageReply", p.MessageReply); ar & make_nvp("MessageSaved", p.MessageSaved); ar & make_nvp("MessageSavedDeleted", p.MessageSavedDeleted); ar & make_nvp("MessagePriority", p.Priority); ar & make_nvp("MessageSensitivity", p.Sensitivity); if(ver < BARRY_POD_MAP_VERSION) { ar & make_nvp("Unknowns", p.Unknowns); } } template void serialize(ArchiveT &ar, Barry::SavedMessage &m, const unsigned int ver) { ar & make_nvp("RecType", m.RecType); ar & make_nvp("RecordId", m.RecordId); ar & make_nvp("From", m.From); ar & make_nvp("To", m.To); ar & make_nvp("Cc", m.Cc); ar & make_nvp("Bcc", m.Bcc); ar & make_nvp("Sender", m.Sender); ar & make_nvp("ReplyTo", m.ReplyTo); ar & make_nvp("Subject", m.Subject); ar & make_nvp("Body", m.Body); ar & make_nvp("Attachment", m.Attachment); ar & make_nvp("MessageRecordId", m.MessageRecordId); ar & make_nvp("MessageReplyTo", m.MessageReplyTo); ar & make_nvp("MessageDateSent", m.MessageDateSent.Time); ar & make_nvp("MessageDateReceived", m.MessageDateReceived.Time); ar & make_nvp("MessageTruncated", m.MessageTruncated); ar & make_nvp("MessageRead", m.MessageRead); ar & make_nvp("MessageReply", m.MessageReply); ar & make_nvp("MessageSaved", m.MessageSaved); ar & make_nvp("MessageSavedDeleted", m.MessageSavedDeleted); ar & make_nvp("MessagePriority", m.Priority); ar & make_nvp("MessageSensitivity", m.Sensitivity); if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp("Unknowns", m.Unknowns); } } template void serialize(ArchiveT &ar, Barry::Sms &m, const unsigned int ver) { ar & make_nvp("RecType", m.RecType); ar & make_nvp("RecordId", m.RecordId); ar & make_nvp("MessageStatus", m.MessageStatus); ar & make_nvp("DeliveryStatus", m.DeliveryStatus); ar & make_nvp("IsNew", m.IsNew); ar & make_nvp("NewConversation", m.NewConversation); ar & make_nvp("Saved", m.Saved); ar & make_nvp("Deleted", m.Deleted); ar & make_nvp("Opened", m.Opened); ar & make_nvp("Timestamp", m.Timestamp); ar & make_nvp("ServiceCenterTimestamp", m.ServiceCenterTimestamp); ar & make_nvp("DataCodingScheme", m.DataCodingScheme); ar & make_nvp("ErrorId", m.ErrorId); ar & make_nvp("Addresses", m.Addresses); ar & make_nvp("Body", m.Body); if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp("Unknowns", m.Unknowns); } } template void serialize(ArchiveT &ar, Barry::Folder &f, const unsigned int ver) { ar & make_nvp("RecType", f.RecType); ar & make_nvp("RecordId", f.RecordId); ar & make_nvp("FolderName", f.Name); ar & make_nvp("FolderNumber", f.Number); ar & make_nvp("FolderLevel", f.Level); ar & make_nvp("FolderType", f.Type); if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp( "Unknowns", f.Unknowns); } } template void serialize(ArchiveT &ar, Barry::TimeZone &t, const unsigned int ver) { ar & make_nvp("RecType", t.RecType); ar & make_nvp("RecordId", t.RecordId); ar & make_nvp("Name", t.Name); ar & make_nvp("Index", t.Index); ar & make_nvp("UTCOffset", t.UTCOffset); ar & make_nvp("UseDST", t.UseDST); ar & make_nvp("DSTOffset", t.DSTOffset); ar & make_nvp("StartMonth", t.StartMonth); ar & make_nvp("EndMonth", t.EndMonth); ar & make_nvp("TZType", t.TZType); if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp("Unknowns", t.Unknowns); } } template void serialize(ArchiveT &ar, Barry::ContentStore &c, const unsigned int ver) { ar & make_nvp("RecType", c.RecType); ar & make_nvp("RecordId", c.RecordId); ar & make_nvp("Filename", c.Filename); ar & make_nvp("FolderFlag", c.FolderFlag); ar & make_nvp("FileContent", c.FileContent); ar & make_nvp("FileDescriptor", c.FileDescriptor); // FileSize is not used for building, so no need to save it here if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp("Unknowns", c.Unknowns); } } template void serialize(ArchiveT &ar, Barry::HandheldAgent &h, const unsigned int ver) { ar & make_nvp("RecType", h.RecType); ar & make_nvp("RecordId", h.RecordId); ar & make_nvp("MEID", h.MEID); ar & make_nvp("Model", h.Model); ar & make_nvp("Bands", h.Bands); ar & make_nvp("Pin", h.Pin); ar & make_nvp("Version", h.Version); ar & make_nvp("PlatformVersion", h.PlatformVersion); ar & make_nvp("Manufacturer", h.Manufacturer); ar & make_nvp("Network", h.Network); if( ver < BARRY_POD_MAP_VERSION ) { ar & make_nvp("Unknowns", h.Unknowns); } } }} // namespace boost::serialization ////////////////////////////////////////////////////////////////////////////// // Helper wrapper templates for loading and saving records to an iostream namespace Barry { // Can be used as a Storage class for RecordBuilder<> template class BoostLoader { public: typedef RecordT rec_type; typedef std::vector list_type; private: list_type m_records; typename list_type::iterator rec_it; public: explicit BoostLoader(std::istream &is) { boost::archive::text_iarchive ia(is); ia >> m_records; rec_it = m_records.begin(); } list_type& GetRecords() { return m_records; } const list_type& GetRecords() const { return m_records; } // retrieval operator bool operator()(RecordT &rec, Builder &builder) { if( rec_it == m_records.end() ) return false; rec = *rec_it; ++rec_it; return true; } }; // Can be used as a Storage class for RecordParser<> template class BoostSaver { public: typedef RecordT rec_type; typedef std::vector list_type; private: std::ostream &m_os; list_type m_records; typename list_type::iterator rec_it; public: explicit BoostSaver(std::ostream &os) : m_os(os) { } ~BoostSaver() { WriteArchive(); } void WriteArchive() const { // write dbname first, so parsing is possible m_os << RecordT::GetDBName() << std::endl; // write boost archive of all records boost::archive::text_oarchive oa(m_os); // boost is fussy that the vector must be const // we do this explicitly, for documentation's sake const list_type &recs = m_records; oa << recs; m_os << std::endl; } list_type& GetRecords() { return m_records; } const list_type& GetRecords() const { return m_records; } // storage operator void operator()(const RecordT &rec) { m_records.push_back(rec); } }; // // BoostParser // /// This Parser turns incoming records (which can be of any record type /// included in ALL_KNOWN_PARSER_TYPES) into a Boost Serialization stream /// on the given iostream. /// /// This class is defined completely in the header, so that it is /// optional for applications to link against the boost libraries. /// class BXEXPORT BoostParser : public Barry::Parser { std::auto_ptr m_parser; std::ofstream *m_ofs; std::ostream &m_os; // references either an external object, // or *m_ifs... this is the reference to // use in the entire class... the constructor // sets it up std::string m_current_db; public: explicit BoostParser(const std::string &filename) : m_ofs( new std::ofstream(filename.c_str()) ) , m_os(*m_ofs) { } explicit BoostParser(std::ostream &os) : m_ofs(0) , m_os(os) { } ~BoostParser() { // flush any remaining parser output // (note this still potentially uses m_ofs, so do this first) m_parser.reset(); // cleanup the stream delete m_ofs; } void StartDB(const std::string &dbname) { // done with current parser, flush it's output m_parser.reset(); #undef HANDLE_PARSER #define HANDLE_PARSER(tname) \ if( dbname == tname::GetDBName() ) { \ m_parser.reset( \ new RecordParser >( \ new BoostSaver(m_os) ) ); \ return; \ } ALL_KNOWN_PARSER_TYPES // if we make it here, we don't have a record parser // for this dbname, so just dump it to stderr (not stdout, // since the user might be sending normal output there) m_parser.reset( new HexDumpParser(std::cerr) ); } void ParseRecord(const DBData &data, const IConverter *ic) { if( m_current_db != data.GetDBName() ) { StartDB(data.GetDBName()); m_current_db = data.GetDBName(); } m_parser->ParseRecord(data, ic); } }; // // BoostBuilder // /// This Builder class reads a boost serialization stream, and converts /// them into DBData records. Can only produce records for record types /// in ALL_KNOWN_BUILDER_TYPES. /// class BXEXPORT BoostBuilder : public Barry::Builder { std::auto_ptr m_builder; std::ifstream *m_ifs; std::istream &m_is; // references either an external object, // or *m_ifs... this is the reference to // use in the entire class... the constructor // sets it up public: explicit BoostBuilder(const std::string &filename) : m_ifs( new std::ifstream(filename.c_str()) ) , m_is(*m_ifs) { FinishDB(); } explicit BoostBuilder(std::istream &is) : m_ifs(0) , m_is(is) { FinishDB(); } ~BoostBuilder() { delete m_ifs; } void FinishDB() { // done with current builder m_builder.reset(); // read the next DBName std::string dbName; while( getline(m_is, dbName) ) { #undef HANDLE_BUILDER #define HANDLE_BUILDER(tname) \ if( dbName == tname::GetDBName() ) { \ m_builder.reset( \ new RecordBuilder >( \ new BoostLoader(m_is) ) ); \ return; \ } ALL_KNOWN_BUILDER_TYPES } } bool BuildRecord(DBData &data, size_t &offset, const IConverter *ic) { if( !m_builder.get() ) return false; bool ret = m_builder->BuildRecord(data, offset, ic); if( !ret ) FinishDB(); return ret; } bool FetchRecord(DBData &data, const IConverter *ic) { if( !m_builder.get() ) return false; bool ret = m_builder->FetchRecord(data, ic); if( !ret ) FinishDB(); return ret; } bool EndOfFile() const { return m_builder.get() ? false : true; } }; } // namespace Barry #endif barry-0.18.5/src/recordtmpl.h0000644001161500056700000001151112242254476015366 0ustar cdfreycdfrey/// /// \file recordtmpl.h /// Standalone templates related to the record classes. /// Split into a separate file to speed compile times. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_TEMPLATES_H__ #define __BARRY_RECORD_TEMPLATES_H__ #include "dll.h" #include #include #include namespace Barry { ////////////////////////////////////////////////////////////////////////////// // Generic Field Handles /// \addtogroup GenericFieldHandles /// @{ ////////////////////////////////////////////////////////////////////////////// // *NamedFieldCmp classes /// FieldSorter<> is a helper class for NamedFieldCmp<>, used as the /// callback for FieldHandle<>::Member(). It uses operator< to store /// a comparison result for the given record and field. template class FieldSorter { const RecordT &m_one, &m_two; mutable bool m_comparison, m_equal; public: FieldSorter(const RecordT &a, const RecordT &b) : m_one(a) , m_two(b) , m_comparison(false) , m_equal(false) { } bool GetComparison() const { return m_comparison; } bool IsEqual() const { return m_equal; } void operator()(EnumFieldBase *ep, const FieldIdentity &id) const { m_comparison = ep->GetValue(m_one) < ep->GetValue(m_two); m_equal = !m_comparison && !(ep->GetValue(m_two) < ep->GetValue(m_one)); } void operator()(typename FieldHandle::PostalPointer pp, const FieldIdentity &id) const { const std::string &a = m_one.*(pp.m_PostalAddress).*(pp.m_PostalField), &b = m_two.*(pp.m_PostalAddress).*(pp.m_PostalField); m_comparison = a < b; m_equal = !m_comparison && !(b < a); } template void operator()(TypeT RecordT::* mp, const FieldIdentity &id) const { m_comparison = m_one.*mp < m_two.*mp; m_equal = !m_comparison && !(m_two.*mp < m_one.*mp); } }; // // NamedFieldCmp<> // /// A comparison functor, intended to be used in std::sort(), which /// allows sorting by a particular record's member variable, selected /// by string name. eg. It allows you to sort a vector of Contact /// records by Name, HomeAddress, WorkPhone, or Company name, etc. /// /// This template takes the record type as template argument, and works /// with only that record type. /// /// If the given name is not found the FieldHandles for RecordT, this /// class will throw a std::logic_error exception. /// template class NamedFieldCmp { const std::string &m_name; public: NamedFieldCmp(const std::string &field_name) : m_name(field_name) { } bool operator() (const RecordT &a, const RecordT &b) const { bool comparison = false; std::string token; std::istringstream iss(m_name); while( std::getline(iss, token, ',') ) { typename FieldHandle::ListT::const_iterator fhi = RecordT::GetFieldHandles().begin(), fhe = RecordT::GetFieldHandles().end(); for( ; fhi != fhe; ++fhi ) { if( token == fhi->GetIdentity().Name ) { FieldSorter fs(a, b); fhi->Member(fs); comparison = fs.GetComparison(); if( fs.IsEqual() ) { // if equal, compare next token break; } else { // done! return comparison; } } } if( fhi == fhe ) throw std::logic_error("NamedFieldCmp: No field named '" + token + "' in '" + RecordT::GetDBName() + "'"); } // return last seen comparison return comparison; } }; class IConverter; class DBData; // // DBNamedFieldCmp // /// This class is a wrapper around the NamedFieldCmp<>, allowing you to /// sort a vector (or other container) of DBData objects. This class will /// parse each record before passing the result on to NamedFieldCmp<> /// and returning the result. All the parsing work is then thrown away, /// so this is more of a convenience class than for performance. /// /// This class expects that all the DBData given to it is one of the /// known records which have a parser. If the record unrecognized, it /// will throw a std::logic_error exception. /// class DBNamedFieldCmp { const std::string &m_name; const IConverter *m_ic; public: explicit DBNamedFieldCmp(const std::string &field_name, const Barry::IConverter *ic = 0); bool operator() (const Barry::DBData &a, const Barry::DBData &b) const; }; /// @} } // namespace Barry #endif barry-0.18.5/src/r_calendar.h0000644001161500056700000001211312242254476015304 0ustar cdfreycdfrey/// /// \file r_calendar.h /// Blackberry database record parser class for calendar records. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_CALENDAR_H__ #define __BARRY_RECORD_CALENDAR_H__ #include "dll.h" #include "record.h" #include "r_recur_base.h" #include #include #include #include #include namespace Barry { // forward declarations class IConverter; // // NOTE: All classes here must be container-safe! Perhaps add sorting // operators in the future. // /// \addtogroup RecordParserClasses /// @{ class BXEXPORT Calendar : public RecurBase { public: typedef Barry::UnknownsType UnknownsType; uint8_t RecType; uint32_t RecordId; // general data bool AllDayEvent; std::string Subject; std::string Notes; std::string Location; Barry::TimeT NotificationTime; // 0 means notification is off Barry::TimeT StartTime; Barry::TimeT EndTime; EmailAddressList Organizer; EmailAddressList AcceptedBy; EmailAddressList Invited; // list of invited people (email a /// /// Free Busy Flag /// /// This lists the available settings found in the device. /// This list is based on information from MS Outlook 2007 /// (Free ==0 and Busy == 2) /// This is FBTYPE in RFC2445 and is defined as /// FREE, BUSY, BUSY-UNAVAILABLE and BUSY-TENTATIVE /// enum FreeBusyFlagType { Free = 0, Tentative, Busy, OutOfOffice }; FreeBusyFlagType FreeBusyFlag; /// /// Class Flag /// /// This is also called classification in Evolution and it /// is the equivilant of public or private in outlook /// Private is set to 0x2 in Outlook /// RFC2445 CLASS is PUBLIC, PRIVATE, CONFIDENTIAL /// enum ClassFlagType { Public = 0, Confidential, Private }; ClassFlagType ClassFlag; uint64_t CalendarID; // Calendar ID (usefull if devices have several calendars) uint16_t TimeZoneCode; // the time zone originally used // for the recurrence data... // seems to have little use, but // set to your current time zone // as a good default bool TimeZoneValid; // true if the record contained a // time zone code, or in other words, // true if TimeZoneCode contains // valid data. Be sure to set this to // to true if you desire to write a // calendar item with a time zone // to the device, otherwise, the builder // code will skip the time zone. // unknown UnknownsType Unknowns; protected: static FreeBusyFlagType FreeBusyFlagProto2Rec(uint8_t f); static uint8_t FreeBusyFlagRec2Proto(FreeBusyFlagType f); static ClassFlagType ClassFlagProto2Rec(uint8_t f); static uint8_t ClassFlagRec2Proto(ClassFlagType f); virtual void DumpSpecialFields(std::ostream &os) const; public: const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); public: Calendar(); ~Calendar(); // Parser / Builder API (see parser.h / builder.h) void Validate() const; uint8_t GetRecType() const { return RecType; } uint32_t GetUniqueId() const { return RecordId; } void SetIds(uint8_t Type, uint32_t Id) { RecType = Type; RecordId = Id; } void ParseHeader(const Data &data, size_t &offset); void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); void BuildHeader(Data &data, size_t &offset) const; void BuildFields(Data &data, size_t &offset, const IConverter *ic = 0) const; // operations (common among record classes) void Clear(); void Dump(std::ostream &os) const; std::string GetDescription() const; // sorting bool operator<(const Calendar &other) const; // database name static const char * GetDBName() { return "Calendar"; } static uint8_t GetDefaultRecType() { return 5; } // or 0? // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const Calendar &msg) { msg.Dump(os); return os; } class BXEXPORT CalendarAll : public Calendar { public: std::string MailAccount; protected: virtual void DumpSpecialFields(std::ostream &os) const; public: // Parser / Builder API (see parser.h / builder.h) void ParseHeader(const Data &data, size_t &offset); void Clear(); public: // database name static const char * GetDBName() { return "Calendar - All"; } // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const CalendarAll &msg) { msg.Dump(os); return os; } /// @} } // namespace Barry #endif barry-0.18.5/src/r_saved_message.h0000644001161500056700000000333212242254476016344 0ustar cdfreycdfrey/// /// \file r_saved_message.h /// Blackberry database record parser class for saved email /// message records. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2007, Brian Edginton (edge@edginton.net) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_SAVED_MESSAGE_H__ #define __BARRY_RECORD_SAVED_MESSAGE_H__ #include "dll.h" #include "r_message_base.h" namespace Barry { // // NOTE: All classes here must be container-safe! Perhaps add sorting // operators in the future. // /// \addtogroup RecordParserClasses /// @{ class BXEXPORT SavedMessage : public MessageBase { public: SavedMessage() { Clear(); } void Clear() { MessageBase::Clear(); RecType = GetDefaultRecType(); RecordId = 0; } // database name static const char * GetDBName() { return "Saved Email Messages"; } static uint8_t GetDefaultRecType() { return 3; } // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const SavedMessage &msg) { msg.Dump(os); return os; } /// @} } // namespace Barry #endif // __BARRY_RECORD_SAVED_MESSAGE_H__ barry-0.18.5/src/dp_codinfo.h0000644001161500056700000000656112242254476015330 0ustar cdfreycdfrey/// /// \file dp_codinfo.h /// Debug file parsing /// /* Copyright (C) 2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYJDG_CODINFO_H__ #define __BARRYJDG_CODINFO_H__ #include "dll.h" #include #include #include #include namespace Barry { namespace JDG { class BXEXPORT DebugFileEntry { private: protected: public: std::string fileName; std::string appName; uint32_t uniqueId; void Dump(std::ostream &os) const; }; class BXEXPORT DebugFileList : public std::vector { public: typedef std::vector base_type; typedef base_type::iterator iterator; typedef base_type::const_iterator const_iterator; public: void AddElement(uint32_t uniqueid, const std::string &appname, const std::string &filename); void Dump(std::ostream &os) const; }; inline std::ostream& operator<<(std::ostream &os, const DebugFileList &list) { list.Dump(os); return os; } class BXEXPORT ClassEntry { private: protected: public: // For JDB int index; // Read from the ".debug" file std::string className; std::string classPath; std::string sourceFile; uint32_t type; uint32_t unknown02; uint32_t unknown03; uint32_t id; uint32_t unknown05; uint32_t unknown06; uint32_t unknown07; uint32_t unknown08; std::string GetFullClassName() { return classPath + "." + className; }; }; class BXEXPORT ClassList : public std::vector { public: typedef std::vector base_type; typedef base_type::iterator iterator; typedef base_type::const_iterator const_iterator; public: void CreateDefaultEntries(); }; class BXEXPORT CodInfo { private: uint32_t ParseNextHeaderField(std::istream &input); uint32_t ParseNextTypeField(std::istream &input); void ParseAppName(std::istream &input); void ParseUniqueId(std::istream &input); void ParseBoolean(std::istream &input); void ParseByte(std::istream &input); void ParseChar(std::istream &input); void ParseShort(std::istream &input); void ParseInt(std::istream &input); void ParseLong(std::istream &input); void ParseClass(std::istream &input); void ParseArray(std::istream &input); void ParseVoid(std::istream &input); void ParseDouble(std::istream &input); protected: public: uint32_t uniqueId; std::string appName; ClassList classList; bool LoadDebugFile(const char *filename); void ParseHeaderSection(std::istream &input); void ParseTypeSection(std::istream &input); void ParseResourceSection(std::istream &input); uint32_t GetUniqueId(); std::string GetAppName(); }; BXEXPORT void SearchDebugFile(DebugFileList &list); BXEXPORT bool LoadDebugInfo(const DebugFileList &list, const char *filename, CodInfo &info); BXEXPORT bool LoadDebugInfo(const DebugFileList &list, const uint32_t uniqueId, const std::string module, CodInfo &info); } // namespace JDG } // namespace Barry #endif barry-0.18.5/src/r_servicebook.h0000644001161500056700000000734012242254476016054 0ustar cdfreycdfrey/// /// \file r_servicebook.h /// Blackberry database record parser class for the /// Service Book record. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_SERVICEBOOK_H__ #define __BARRY_RECORD_SERVICEBOOK_H__ #include "dll.h" #include "record.h" #include #include #include #include #include namespace Barry { // forward declarations class IConverter; // // NOTE: All classes here must be container-safe! Perhaps add sorting // operators in the future. // /// \addtogroup RecordParserClasses /// @{ // This is a packed field, which is a group of fields packed in // variable length records inside one larger field of a normal record. class BXEXPORT ServiceBookConfig { public: typedef Barry::UnknownsType UnknownsType; uint8_t Format; UnknownsType Unknowns; public: const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); public: ServiceBookConfig(); ~ServiceBookConfig(); // Parser / Builder API (see parser.h / builder.h) void Validate() const; void ParseHeader(const Data &data, size_t &offset); void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); void BuildHeader(Data &data, size_t &offset) const; void BuildFields(Data &data, size_t &offset, const IConverter *ic = 0) const; void Clear(); void Dump(std::ostream &os) const; }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const ServiceBookConfig &msg) { msg.Dump(os); return os; } class ServiceBookData; class BXEXPORT ServiceBook { ServiceBookData *m_data; public: typedef std::vector UnknownsType; uint8_t RecType; uint32_t RecordId; std::string Name; std::string HiddenName; std::string Description; std::string DSID; std::string BesDomain; std::string UniqueId; std::string ContentId; ServiceBookConfig Config; UnknownsType Unknowns; public: const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); public: ServiceBook(); ~ServiceBook(); // Parser / Builder API (see parser.h / builder.h) void Validate() const; uint8_t GetRecType() const { return RecType; } uint32_t GetUniqueId() const { return RecordId; } void SetIds(uint8_t Type, uint32_t Id) { RecType = Type; RecordId = Id; } void ParseHeader(const Data &data, size_t &offset); void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); void BuildHeader(Data &data, size_t &offset) const; void BuildFields(Data &data, size_t &offset, const IConverter *ic = 0) const; // operations (common among record classes) void Clear(); void Dump(std::ostream &os) const; std::string GetDescription() const; // sorting bool operator<(const ServiceBook &other) const; // database name static const char * GetDBName() { return "Service Book"; } static uint8_t GetDefaultRecType() { return 0; } // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const ServiceBook &msg) { msg.Dump(os); return os; } /// @} } // namespace Barry #endif barry-0.18.5/src/configfilewin32.cc0000644001161500056700000001225112242254476016343 0ustar cdfreycdfrey/// /// \file configfilewin32.cc /// Barry configuration class, for one device PIN, using Win32 APIs /// /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) Portions Copyright (C) 2012, RealVNC Ltd. 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 in the COPYING file at the root directory of this project for more details. */ #include "configfile.h" #include "error.h" #include "r_message.h" #include #include #include #include #include #include // Returned by GetFileAttributes to indicate failure #define INVALID_ATTRIB 0xFFFFFFFF namespace Barry { /// Creates a tar.gz filename using PIN + date + time + label. /// Does not include any path, just returns a new filename. std::string MakeBackupFilename(const Barry::Pin &pin, const std::string &label) { using namespace std; SYSTEMTIME st; GetLocalTime(&st); std::string fileLabel = label; if( fileLabel.size() ) { // prepend a hyphen fileLabel.insert(fileLabel.begin(), '-'); // translate all spaces and slashes for( size_t i = 0; i < fileLabel.size(); i++ ) { if( fileLabel[i] == ' ' ) fileLabel[i] = '_'; else if( fileLabel[i] == '/' ) fileLabel[i] = '-'; else if( fileLabel[i] == '\\' ) fileLabel[i] = '-'; } } ostringstream tarfilename; tarfilename << pin.Str() << "-" << setw(4) << setfill('0') << st.wYear << setw(2) << setfill('0') << st.wMonth << setw(2) << setfill('0') << st.wDay << "-" << setw(2) << setfill('0') << st.wHour << setw(2) << setfill('0') << st.wMinute << setw(2) << setfill('0') << st.wSecond << fileLabel << ".tar.gz"; return tarfilename.str(); } void ConfigFile::BuildFilename() { TCHAR dirName[MAX_PATH]; CHAR dirNameA[MAX_PATH]; if( !SHGetSpecialFolderPath(NULL, dirName, CSIDL_APPDATA, TRUE) ) { throw ConfigFileError(_("BuildFilename: SHGetSpecialFolderPath failed"), GetLastError()); } if( WideCharToMultiByte(CP_ACP, 0, dirName, -1, dirNameA, MAX_PATH, NULL, NULL) <= 0 ) { throw ConfigFileError(_("BuildFilename: conversion failed"), GetLastError()); } dirNameA[MAX_PATH-1] = 0; // Make sure it's NUL terminated m_filename = dirNameA; m_filename += "\\.barry\\backup\\"; m_filename += m_pin.Str(); m_filename += "\\config"; } void ConfigFile::BuildDefaultPath() { TCHAR dirName[MAX_PATH]; CHAR dirNameA[MAX_PATH]; if( !SHGetSpecialFolderPath(NULL, dirName, CSIDL_APPDATA, TRUE) ) { throw ConfigFileError(_("BuildDefaultPath: SHGetSpecialFolderPath failed"), GetLastError()); } if( WideCharToMultiByte(CP_ACP, 0, dirName, -1, dirNameA, MAX_PATH, NULL, NULL) <= 0 ) { throw ConfigFileError(_("BuildFilename: conversion failed"), GetLastError()); } dirNameA[MAX_PATH-1] = 0; // Make sure it's NUL terminated m_path = dirNameA; m_path += "\\.barry\\backup\\"; m_path += m_pin.Str(); } /// Checks that the path in path exists, and if not, creates it. /// Returns false if unable to create path, true if ok. bool ConfigFile::CheckPath(const std::string &path, std::string *perr) { if( path.size() == 0 ) { if( perr ) *perr = _("ConfigFile::CheckPath(): path is empty!"); return false; } TCHAR dirName[MAX_PATH]; if( MultiByteToWideChar(CP_ACP, 0, path.c_str(), -1, dirName, MAX_PATH) <= 0 ) { if( perr ) *perr = _("Failed to convert to widechar"); return false; } dirName[MAX_PATH-1] = 0; // Make sure it's NUL terminated DWORD attrs = GetFileAttributes(dirName); if( (attrs != INVALID_ATTRIB) && ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) ) return true; for( int i = 0; dirName[i] != 0; ++i ) { if( dirName[i] != '\\' ) continue; // At a path separator, turn it into NUL so // that string handling APIs see just this part of the path dirName[i] = 0; DWORD attrs = GetFileAttributes(dirName); if( (attrs != INVALID_ATTRIB) && ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) ) continue; if( !CreateDirectory(dirName, NULL) ) { if( perr ) { *perr = _("failed to create directory"); } return false; } // Turn it back into a directory separator dirName[i] = '\\'; } return true; } void GlobalConfigFile::BuildFilename() { TCHAR dirName[MAX_PATH]; CHAR dirNameA[MAX_PATH]; if (!SHGetSpecialFolderPath(NULL, dirName, CSIDL_APPDATA, TRUE)) { throw ConfigFileError(_("BuildFilename: SHGetSpecialFolderPath failed"), GetLastError()); } if (WideCharToMultiByte(CP_ACP, 0, dirName, -1, dirNameA, MAX_PATH, NULL, NULL) <= 0) { throw ConfigFileError(_("BuildFilename: conversion failed"), GetLastError()); } dirNameA[MAX_PATH-1] = 0; // Make sure it's NUL terminated m_filename = dirNameA; m_filename += "\\.barry\\config"; // build the global path too, since this never changes m_path = dirNameA; m_path += "\\.barry"; } } // namespace Barry barry-0.18.5/src/usbwrap_libusb_1_0.h0000644001161500056700000000337012242254476016701 0ustar cdfreycdfrey/// /// \file usbwrap_libusb_1_0.h /// USB API wrapper for libusb version 1.0 /// /* Copyright (C) 2005-2013, Chris Frey Portions Copyright (C) 2011, RealVNC Ltd. 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __SB_USBWRAP_LIBUSB_1_0_H__ #define __SB_USBWRAP_LIBUSB_1_0_H__ #include "usbwrap.h" #include #if defined( WIN32 ) // On Windows systems, libusb.h includes which defines min/max, // which causes trouble for other headers #undef min #undef max #endif namespace Usb { class DeviceIDImpl { public: libusb_device *m_dev; std::string m_busname; std::string m_filename; public: DeviceIDImpl(libusb_device *dev); ~DeviceIDImpl(); }; struct DeviceHandle { libusb_device_handle *m_handle; }; struct DeviceListImpl { libusb_device** m_list; ssize_t m_listcnt; std::vector m_devices; }; struct EndpointDescriptorImpl { const struct libusb_endpoint_descriptor* m_desc; }; struct InterfaceDescriptorImpl { const struct libusb_interface_descriptor* m_desc; }; struct ConfigDescriptorImpl { struct libusb_config_descriptor* m_desc; }; struct DeviceDescriptorImpl { struct libusb_device_descriptor m_desc; DeviceID m_devid; }; }; // namespace Usb #endif // __SB_USBWRAP_LIBUSB_1_0_H__ barry-0.18.5/src/m_mode_base.h0000644001161500056700000000306712242254476015454 0ustar cdfreycdfrey/// /// \file m_mode_base.h /// Base for mode classes /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_M_MODE_BASE_H__ #define __BARRY_M_MODE_BASE_H__ #include "dll.h" #include "controller.h" namespace Barry { namespace Mode { // // Mode class // /// Base class for simple mode classes. Put common code here. /// class BXEXPORT Mode { protected: Controller &m_con; Controller::ModeType m_modetype; SocketHandle m_socket; uint16_t m_ModeSocket; // socket recommended by device // when mode was selected public: Mode(Controller &con, Controller::ModeType type); virtual ~Mode(); ////////////////////////////////// // primary operations - required before anything else void Open(const char *password = 0); void Open(const char *password, const char *name); void RetryPassword(const char *password); // void Close(); protected: ////////////////////////////////// // overrides virtual void OnOpen(); }; }} // namespace Barry::Mode #endif barry-0.18.5/src/vsmartptr.h0000644001161500056700000000664612242254476015272 0ustar cdfreycdfrey/// /// \file vsmartptr.h /// Smart pointer that accepts custom 'free' functions. /// /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_VSMARTPTR_H__ #define __BARRY_VSMARTPTR_H__ namespace Barry { // // vSmartPtr // /// A special smart pointer for variables that have their own /// special 'free' functions. Behaves like std::auto_ptr<> /// in that only one object at a time owns the pointer, /// and destruction frees it by calling the given FreeFunc. /// template class vSmartPtr { mutable T *m_pt; public: vSmartPtr() : m_pt(0) {} vSmartPtr(T *pt) : m_pt(pt) {} vSmartPtr(const vSmartPtr &sp) : m_pt(sp.m_pt) { sp.m_pt = 0; } ~vSmartPtr() { reset(); } vSmartPtr& operator=(T *pt) { reset(pt); return *this; } vSmartPtr& operator=(const vSmartPtr &sp) { reset(sp.release()); return *this; } // Some non-standard APIs used by Barry T* Extract() { return this->release(); } T* Get() { return this->get(); } // std::auto_ptr<> style API T* get() { return m_pt; } T* release() { T *rp = m_pt; m_pt = 0; return rp; } void reset(T *new_obj = 0) { if( m_pt ) FreeFunc(m_pt); m_pt = new_obj; } }; // // vLateSmartPtr // /// Variation of the above smart pointer that allows the user to /// assign a free function after construction, in the case of /// dlopen()'d frees. /// template class vLateSmartPtr { mutable T *m_pt; FreeFuncPtrT m_FreeFuncPtr; public: explicit vLateSmartPtr(FreeFuncPtrT freefunc = 0) : m_pt(0) , m_FreeFuncPtr(freefunc) { } vLateSmartPtr(T *pt, FreeFuncPtrT freefunc = 0) : m_pt(pt) , m_FreeFuncPtr(freefunc) { } vLateSmartPtr(const vLateSmartPtr &sp) : m_pt(sp.m_pt) , m_FreeFuncPtr(sp.m_FreeFuncPtr) { sp.m_pt = 0; } ~vLateSmartPtr() { reset(); } void SetFreeFunc(FreeFuncPtrT freefunc) { m_FreeFuncPtr = freefunc; } vLateSmartPtr& operator=(T *pt) { reset(pt); return *this; } vLateSmartPtr& operator=(const vLateSmartPtr &sp) { reset(sp.release()); m_FreeFuncPtr = sp.m_FreeFuncPtr; return *this; } // Some non-standard APIs used by Barry T* Extract() { return this->release(); } T* Get() { return this->get(); } // std::auto_ptr<> style API T* get() { return m_pt; } T* release() { T *rp = m_pt; m_pt = 0; return rp; } void reset(T *new_obj = 0) { // don't check for null m_FreeFuncPtr, since // that should be an obvious crash and requires fixing if( m_pt ) (*m_FreeFuncPtr)(m_pt); m_pt = new_obj; } }; /* Example usage: typedef vSmartPtr vAttrPtr; typedef vSmartPtr vParamPtr; typedef vSmartPtr gStringPtr; */ } // namespace Barry #endif barry-0.18.5/src/a_osloader.cc0000644001161500056700000001072112242254476015463 0ustar cdfreycdfrey/// /// \file a_osloader.cc /// OS files parser (multi ALX files parser) /// /* Copyright (C) 2010, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include #include #include #include #include #include #include "a_osloader.h" #include "a_alxparser.h" #include "vsmartptr.h" #include "error.h" #include "ios_state.h" namespace Barry { namespace ALX { OSLoader::OSLoader(void) { } OSLoader::~OSLoader(void) { } void OSLoader::Load(const std::string& pathname) { #define ALX_FILE_EXT ".alx" int offset; struct dirent *entry; std::string alxfile; const std::string ext = ALX_FILE_EXT; // At first, we have to read platform properties... alxfile = pathname + "/Platform.alx"; LoadALXFile(alxfile, false); // Then, we can read all ALX files // Wrap it in a smart pointer so exceptions are safe vLateSmartPtr path(&closedir); path.reset( opendir(pathname.c_str()) ); if( path.get() == NULL ) throw Barry::ErrnoError(_("Could not opendir: ") + pathname, errno); while ((entry = readdir(path.get())) != NULL) { alxfile = entry->d_name; if (alxfile.length() < ext.length()) continue; offset = alxfile.length() - ext.length(); // Ignore all files except ".alx" files if (alxfile.substr(offset, ext.length()) != ALX_FILE_EXT) continue; LoadALXFile(pathname + "/" + alxfile, true); } } void OSLoader::LoadALXFile(const std::string& alxfile, const bool enable) { std::ifstream file(alxfile.c_str()); if( !file ) throw Barry::Error(_("Cannot open ALX file: ") + alxfile); ALX::ALXParser parser(*this, file); parser.Run(enable); file.close(); } void OSLoader::Dump(std::ostream &os) const { ios_format_state state(os); os << _("OS Properties :") << std::endl; { std::map::const_iterator b = properties.begin(), e = properties.end(); for (; b != e; b++) { os << " - " << (*b).first << " = " << (*b).second << std::endl; } } os << std::endl; os << _("SFI File :") << std::endl; os << " " << sfifile << std::endl; os << std::endl; os << _("Applications :") << std::endl; { CODSectionList::const_iterator b = applications.begin(), e = applications.end(); for (; b != e; b++) { os << (**b) << std::endl; } } os << _("Libraries :") << std::endl; { CODSectionList::const_iterator b = libraries.begin(), e = libraries.end(); for (; b != e; b++) { os << (**b) << std::endl; } } } void OSLoader::AddProperties(const std::string& property, const std::string& value) { properties[property] = value; if (property == "JVMLevel") properties["Java"] = value; } void OSLoader::AddProperties(const xmlpp::SaxParser::AttributeList& attrs) { for (xmlpp::SaxParser::AttributeList::const_iterator iter = attrs.begin(); iter != attrs.end(); ++iter) { std::string attribut(iter->name); std::string value(iter->value); AddProperties(attribut, value); } } void OSLoader::SetSFIFile(const std::string& name) { sfifile = name; } bool OSLoader::IsSupported(const xmlpp::SaxParser::AttributeList& attrs) { if (properties.empty()) return false; for (xmlpp::SaxParser::AttributeList::const_iterator iter = attrs.begin(); iter != attrs.end(); ++iter) { std::string attribut(iter->name); std::string value(iter->value); std::string s = properties[attribut]; std::transform(value.begin(), value.end(), value.begin(), ::tolower); std::transform(s.begin(), s.end(), s.begin(), ::tolower); if (value[0] == '~') { value = value.substr(1, value.length()-1); if (s == value) return false; } else { if (s != value) return false; } } return true; } void OSLoader::AddApplication(OSLoader::CODSectionPtr app) { applications.push_back(app); } void OSLoader::AddLibrary(OSLoader::CODSectionPtr lib) { libraries.push_back(lib); } } // namespace ALX } // namespace Barry barry-0.18.5/src/record.cc0000644001161500056700000003730012242254476014633 0ustar cdfreycdfrey/// /// \file record.cc /// Misc. Blackberry database record helper classes and functions. /// Helps translate data from data packets to useful structures, /// and back. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "record.h" #include "record-internal.h" #include "protostructs.h" #include "data.h" #include "time.h" #include "error.h" #include "endian.h" #include "trim.h" #include "ios_state.h" #include "parser.h" #include #include #include #include #include // for sscanf() #include // for DBNamedFieldCmp below #include "recordtmpl.h" #include "r_calendar.h" #include "r_calllog.h" #include "r_bookmark.h" #include "r_contact.h" #include "r_cstore.h" #include "r_memo.h" #include "r_message.h" #include "r_servicebook.h" #include "r_task.h" #include "r_pin_message.h" #include "r_saved_message.h" #include "r_sms.h" #include "r_folder.h" #include "r_timezone.h" #include "r_hhagent.h" #define __DEBUG_MODE__ #include "debug.h" using namespace std; using namespace Barry::Protocol; namespace Barry { std::ostream& operator<< (std::ostream &os, const Cr2LfWrapper &str) { for( std::string::const_iterator i = str.m_str.begin(); i != str.m_str.end() && *i; i++) { if( *i == '\r' ) os << '\n'; else os << *i; } return os; } std::ostream& operator<< (std::ostream &os, const TimeT &t) { // strip the trailing newline string output = ctime(&t.Time); while( output.size() && (output[output.size()-1] == '\n' || output[output.size()-1] == '\r') ) { output.resize(output.size() - 1); } os << output; return os; } ////////////////////////////////////////////////////////////////////////////// // Field builder helper functions void BuildField1900(Data &data, size_t &size, uint8_t type, time_t t) { size_t timesize = COMMON_FIELD_MIN1900_SIZE; size_t fieldsize = COMMON_FIELD_HEADER_SIZE + timesize; unsigned char *pd = data.GetBuffer(size + fieldsize) + size; CommonField *field = (CommonField *) pd; field->size = htobs(timesize); field->type = type; field->u.min1900 = time2min(t); size += fieldsize; } void BuildField(Data &data, size_t &size, uint8_t type, char c) { BuildField(data, size, type, (uint8_t)c); } void BuildField(Data &data, size_t &size, uint8_t type, uint8_t c) { size_t strsize = 1; size_t fieldsize = COMMON_FIELD_HEADER_SIZE + strsize; unsigned char *pd = data.GetBuffer(size + fieldsize) + size; CommonField *field = (CommonField *) pd; field->size = htobs(strsize); field->type = type; memcpy(field->u.raw, &c, strsize); size += fieldsize; } void BuildField(Data &data, size_t &size, uint8_t type, uint16_t value) { size_t strsize = 2; size_t fieldsize = COMMON_FIELD_HEADER_SIZE + strsize; unsigned char *pd = data.GetBuffer(size + fieldsize) + size; CommonField *field = (CommonField *) pd; field->size = htobs(strsize); field->type = type; uint16_t store = htobs(value); memcpy(field->u.raw, &store, strsize); size += fieldsize; } void BuildField(Data &data, size_t &size, uint8_t type, uint32_t value) { size_t strsize = 4; size_t fieldsize = COMMON_FIELD_HEADER_SIZE + strsize; unsigned char *pd = data.GetBuffer(size + fieldsize) + size; CommonField *field = (CommonField *) pd; field->size = htobl(strsize); field->type = type; uint32_t store = htobl(value); memcpy(field->u.raw, &store, strsize); size += fieldsize; } void BuildField(Data &data, size_t &size, uint8_t type, uint64_t value) { size_t strsize = 8; size_t fieldsize = COMMON_FIELD_HEADER_SIZE + strsize; unsigned char *pd = data.GetBuffer(size + fieldsize) + size; CommonField *field = (CommonField *) pd; field->size = htobl(strsize); field->type = type; uint64_t store = htobll(value); memcpy(field->u.raw, &store, strsize); size += fieldsize; } void BuildField(Data &data, size_t &size, uint8_t type, const std::string &str) { // include null terminator BuildField(data, size, type, str.c_str(), str.size() + 1); } void BuildField(Data &data, size_t &size, uint8_t type, const void *buf, size_t bufsize) { // include null terminator size_t fieldsize = COMMON_FIELD_HEADER_SIZE + bufsize; unsigned char *pd = data.GetBuffer(size + fieldsize) + size; CommonField *field = (CommonField *) pd; field->size = htobs(bufsize); field->type = type; memcpy(field->u.raw, buf, bufsize); size += fieldsize; } void BuildField(Data &data, size_t &size, const Barry::UnknownField &field) { BuildField(data, size, field.type, field.data.raw_data.data(), field.data.raw_data.size()); } void BuildField(Data &data, size_t &size, uint8_t type, const Barry::Protocol::GroupLink &link) { size_t linksize = sizeof(Barry::Protocol::GroupLink); size_t fieldsize = COMMON_FIELD_HEADER_SIZE + linksize; unsigned char *pd = data.GetBuffer(size + fieldsize) + size; CommonField *field = (CommonField *) pd; field->size = htobs(linksize); field->type = type; field->u.link = link; size += fieldsize; } std::string ParseFieldString(const Barry::Protocol::CommonField *field) { // make no assumptions here, and pass the full size in as // the maxlen, even though 99% of the time, it will be a null... // this function can be used by non-null terminated strings as well return ParseFieldString(field->u.raw, btohs(field->size)); } std::string ParseFieldString(const void *data, uint16_t maxlen) { const char *str = (const char *)data; // find last non-null character, since some fields // can have multiple null terminators while( maxlen && str[maxlen-1] == 0 ) maxlen--; return std::string(str, maxlen); } /////////////////////////////////////////////////////////////////////////////// // UnknownField std::ostream& operator<< (std::ostream &os, const std::vector &unknowns) { ios_format_state state(os); std::vector::const_iterator ub = unknowns.begin(), ue = unknowns.end(); if( ub != ue ) os << _(" Unknowns:\n"); for( ; ub != ue; ub++ ) { os << _(" Type: ") << "0x" << setbase(16) << (unsigned int) ub->type << _(" Data:\n") << Data(ub->data.data(), ub->data.size()); } return os; } /////////////////////////////////////////////////////////////////////////////// // EmailList typedef std::ostream& operator<< (std::ostream &os, const EmailList &list) { for( EmailList::const_iterator b = list.begin(), e = list.end(); b != e; ++b ) { if( b != list.begin() ) os << ", "; os << *b; } return os; } /////////////////////////////////////////////////////////////////////////////// // EmailAddress class EmailAddress::EmailAddress(const std::string &complex_address) { size_t end = complex_address.rfind('>'); size_t start = complex_address.rfind('<'); if( start == string::npos || end == string::npos || start > end ) { // simple address, add it Email = complex_address; Inplace::trim(Email); } else { Name = complex_address.substr(0, start); Inplace::trim(Name); Email = complex_address.substr(start+1, end - start - 1); Inplace::trim(Email); } } std::ostream& operator<<(std::ostream &os, const EmailAddress &msga) { if( msga.Name.size() ) os << msga.Name << " <"; os << msga.Email; if( msga.Name.size() ) os << ">"; return os; } /////////////////////////////////////////////////////////////////////////////// // EmailAddressList class std::string EmailAddressList::ToCommaSeparated() const { std::ostringstream oss; oss << *this; return oss.str(); } /// Adds every email address found in the comma separated list. /// Does not clear() first. void EmailAddressList::AddCommaSeparated(const std::string &list) { istringstream iss(list); string address; iss >> ws; while( getline(iss, address, ',') ) { // trim any trailing whitespace in the address size_t len = address.size(); while( len && ::isspace(address[len-1]) ) address.resize(len-1); // add to list if anything left if( address.size() ) { EmailAddress ea(address); push_back(ea); } } } std::ostream& operator<<(std::ostream &os, const EmailAddressList &elist) { for( EmailAddressList::const_iterator i = elist.begin(); i != elist.end(); ++i ) { if( i != elist.begin() ) os << ", "; os << *i; } return os; } /////////////////////////////////////////////////////////////////////////////// // PostalAddress class // // GetLabel // /// Format a mailing address into a single string, handling missing fields. /// std::string PostalAddress::GetLabel() const { std::string address = Address1; if( Address2.size() ) { if( address.size() ) address += "\n"; address += Address2; } if( Address3.size() ) { if( address.size() ) address += "\n"; address += Address3; } if( address.size() ) address += "\n"; if( City.size() ) address += City + " "; if( Province.size() ) address += Province + " "; if( Country.size() ) address += Country; if( address.size() ) address += "\n"; if( PostalCode.size() ) address += PostalCode; return address; } void PostalAddress::Clear() { Address1.clear(); Address2.clear(); Address3.clear(); City.clear(); Province.clear(); PostalCode.clear(); Country.clear(); } std::ostream& operator<<(std::ostream &os, const PostalAddress &post) { os << post.GetLabel(); return os; } /////////////////////////////////////////////////////////////////////////////// // Date class Date::Date(const struct tm *timep) { FromTm(timep); } void Date::Clear() { Month = Day = Year = 0; } void Date::ToTm(struct tm *timep) const { memset(timep, 0, sizeof(tm)); timep->tm_year = Year - 1900; timep->tm_mon = Month; timep->tm_mday = Day; } std::string Date::ToYYYYMMDD() const { std::ostringstream oss; // setfill and setw not sticky. oss << setw(4) << setfill('0') << dec << Year << setw(2) << setfill('0') << dec << (Month + 1) << setw(2) << setfill('0') << dec << Day; return oss.str(); } // // ToBBString // /// The Blackberry stores Birthday and Anniversary date fields /// with the format: DD/MM/YYYY /// std::string Date::ToBBString() const { std::ostringstream oss; // setw() ain't 'sticky'! oss << setw(2) << setfill('0') << dec << Day << '/' << setw(2) << setfill('0') << dec << (Month + 1) << '/' << setw(2) << setfill('0') << dec << Year; return oss.str(); } bool Date::FromTm(const struct tm *timep) { if( !timep ) throw std::logic_error(_("NULL time pointer passed to Date::FromTm")); Year = timep->tm_year + 1900; Month = timep->tm_mon; Day = timep->tm_mday; return true; } bool Date::FromBBString(const std::string &str) { int m, d, y; if( 3 == sscanf(str.c_str(), "%d/%d/%d", &d, &m, &y) ) { Year = y; Month = m - 1; Day = d; return true; } return false; } bool Date::FromYYYYMMDD(const std::string &str) { int m, d, y; if( 3 == sscanf(str.c_str(), "%4d%2d%2d", &y, &m, &d) ) { Year = y; Month = m - 1; Day = d; return true; } return false; } std::ostream& operator<<(std::ostream &os, const Date &date) { ios_format_state state(os); os.setf(ios::right); os.fill('0'); os << setw(4) << dec << date.Year << '/' << setw(2) << dec << (date.Month + 1) << '/' << setw(2) << dec << date.Day; return os; } /////////////////////////////////////////////////////////////////////////////// // CategoryList class /// Parses the given comma delimited category string into /// this CategoryList object, appending each token to the vector. /// Will clear vector beforehand. void CategoryList::CategoryStr2List(const std::string &str) { // start fresh clear(); if( !str.size() ) return; // parse the comma-delimited string to a list, stripping away // any white space around each category name string::size_type start = 0, end = 0, delim = str.find(',', start); while( start != string::npos ) { if( delim == string::npos ) end = str.size() - 1; else end = delim - 1; // strip surrounding whitespace while( str[start] == ' ' ) start++; while( end && str[end] == ' ' ) end--; if( start <= end ) { string token = str.substr(start, end-start+1); push_back(token); } // next start = delim; if( start != string::npos ) start++; delim = str.find(',', start); } } /// Turns the current vectory into a comma delimited category /// string suitable for use in Calendar, Task, and Memo protocol values. void CategoryList::CategoryList2Str(std::string &str) const { str.clear(); Barry::CategoryList::const_iterator i = begin(); for( ; i != end(); ++i ) { if( str.size() ) str += ", "; str += *i; } } std::ostream& operator<<(std::ostream &os, const CategoryList &cl) { string buf; cl.CategoryList2Str(buf); os << buf; return os; } /////////////////////////////////////////////////////////////////////////////// // EnumConstants class void EnumConstants::AddConstant(const char *name, const std::string &display, int val) { m_constants.push_back(EnumConstant(name, display, val)); } const EnumConstants::EnumConstant& EnumConstants::GetConstant(int value) const { for( EnumConstantList::const_iterator b = m_constants.begin(), e = m_constants.end(); b != e; ++b ) { if( b->Value == value ) return *b; } // not found in list throw std::logic_error(_("Enum value not found in constant list")); } const char* EnumConstants::GetName(int value) const { return GetConstant(value).Name; } const std::string& EnumConstants::GetDisplayName(int value) const { return GetConstant(value).DisplayName; } bool EnumConstants::IsConstantValid(int value) const { for( EnumConstantList::const_iterator b = m_constants.begin(), e = m_constants.end(); b != e; ++b ) { if( b->Value == value ) return true; } // not found in list, so not a valid constant return false; } ////////////////////////////////////////////////////////////////////////////// // DBNamedFieldCmp class DBNamedFieldCmp::DBNamedFieldCmp(const std::string &field_name, const Barry::IConverter *ic) : m_name(field_name) , m_ic(ic) { } bool DBNamedFieldCmp::operator() (const Barry::DBData &a, const Barry::DBData &b) const { #undef HANDLE_PARSER #define HANDLE_PARSER(tname) \ else if( tname::GetDBName() == a.GetDBName() ) { \ tname rec1, rec2; \ ParseDBData(a, rec1, m_ic); \ ParseDBData(b, rec2, m_ic); \ return NamedFieldCmp(m_name).operator()(rec1, rec2); \ } if( a.GetDBName() != b.GetDBName() ) { throw logic_error(_("Different database types in DBNamedFieldCmp")); } // fall through and use else's ALL_KNOWN_PARSER_TYPES throw logic_error(_("Unknown database in DBNamedFieldCmp::operator()")); } } // namespace Barry #ifdef __TEST_MODE__ #include int main(int argc, char *argv[]) { if( argc < 2 ) { cerr << "Usage: test " << endl; return 1; } std::vector array; if( !LoadDataArray(argv[1], array) ) { cerr << "Unable to load file: " << argv[1] << endl; return 1; } cout << "Loaded " << array.size() << " items" << endl; for( std::vector::iterator b = array.begin(), e = array.end(); b != e; b++ ) { Data &d = *b; // cout << d << endl; if( d.GetSize() > 13 && d.GetData()[6] == 0x4f ) { Barry::Contact contact; size_t size = 13; contact.ParseFields(d, size); cout << contact << endl; contact.DumpLdif(cout, "ou=People,dc=example,dc=com"); } else if( d.GetSize() > 13 && d.GetData()[6] == 0x44 ) { Barry::Calendar cal; size_t size = 13; cal.ParseFields(d, size); cout << cal << endl; } } } #endif barry-0.18.5/src/tarfile.cc0000644001161500056700000002004412242254476015000 0ustar cdfreycdfrey/// /// \file tarfile.cc /// API for reading and writing sequentially from compressed /// tar files. /* Copyright (C) 2007-2013, Chris Frey 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "tarfile.h" #include "data.h" #include #include #include #include namespace reuse { TarFile::TarFile(const char *filename, bool create, tartype_t *compress_ops, bool always_throw) : m_tar(0), m_throw(always_throw), m_writemode(create) { // figure out how to handle the file flags/modes int flags = 0; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; if( m_writemode ) { flags = O_WRONLY | O_CREAT | O_EXCL; } else { flags = O_RDONLY; } // open... throw on error, as we are in the constructor if( tar_open(&m_tar, const_cast(filename), compress_ops, flags, mode, TAR_VERBOSE | TAR_GNU) == -1 ) { throw TarError(std::string(_("Unable to open tar file: ")) + strerror(errno)); } } TarFile::~TarFile() { try { Close(); } catch( TarError &te ) {} } bool TarFile::False(const char *msg) { m_last_error = msg; if( m_throw ) throw TarError(msg); else return false; } bool TarFile::False(const std::string &msg, int err) { std::string str = msg; str += ": "; str += strerror(err); return False(str); } bool TarFile::Close() { if( m_tar ) { if( m_writemode ) { if( tar_append_eof(m_tar) != 0 ) return False(_("Unable to write eof"), errno); } if( tar_close(m_tar) != 0 ) { return False(_("Unable to close file"), errno); } m_tar = 0; } return true; } /// Appends a new file to the current tarfile, using tarpath as /// its internal filename, and data as the complete file contents. /// Uses current date and time as file mtime. bool TarFile::AppendFile(const char *tarpath, const std::string &data) { // write standard file header th_set_type(m_tar, REGTYPE); th_set_mode(m_tar, 0644); th_set_path(m_tar, const_cast(tarpath)); th_set_user(m_tar, 0); th_set_group(m_tar, 0); th_set_size(m_tar, data.size()); th_set_mtime(m_tar, time(NULL)); if( th_write(m_tar) != 0 ) { return False(_("Unable to write tar header"), errno); } // write the data in blocks until finished char block[T_BLOCKSIZE]; for( size_t pos = 0; pos < data.size(); pos += T_BLOCKSIZE ) { memset(block, 0, T_BLOCKSIZE); size_t size = T_BLOCKSIZE; if( data.size() - pos < T_BLOCKSIZE ) size = data.size() - pos; memcpy(block, data.data() + pos, size); if( tar_block_write(m_tar, block) != T_BLOCKSIZE ) { return False(_("Unable to write block"), errno); } } return true; } /// Reads next available file into data, filling tarpath with /// internal filename from tarball. bool TarFile::ReadNextFile(std::string &tarpath, std::string &data) { // start fresh tarpath.clear(); data.clear(); // read next tar file header... skip all directories do { if( th_read(m_tar) != 0 ) { // this is not necessarily an error, as it could just // be the end of file, so a simple false is good here, // don't throw an exception m_last_error = ""; return false; } } while( TH_ISDIR(m_tar) ); // write standard file header if( !TH_ISREG(m_tar) ) { return False(_("Only regular files are supported inside a tarball.")); } char *pathname = th_get_pathname(m_tar); tarpath = pathname; // // FIXME (leak) - someday, when all distros use a patched version of // libtar, we may be able to avoid this memory leak, but // th_get_pathname() does not consistently return a user-freeable // string on all distros. // // See the following links for more information: // https://bugs.launchpad.net/ubuntu/+source/libtar/+bug/41804 // https://lists.feep.net:8080/pipermail/libtar/2006-April/000222.html // // free(pathname); size_t size = th_get_size(m_tar); // read the data in blocks until finished char block[T_BLOCKSIZE]; for( size_t pos = 0; pos < size; pos += T_BLOCKSIZE ) { memset(block, 0, T_BLOCKSIZE); size_t readsize = T_BLOCKSIZE; if( size - pos < T_BLOCKSIZE ) readsize = size - pos; if( tar_block_read(m_tar, block) != T_BLOCKSIZE ) { return False(_("Unable to read block"), errno); } data.append(block, readsize); } return true; } // FIXME - yes, this is blatant copying of code, but this is // specific to Barry, to use a Barry::Data object instead of std::string // in order to reduce copies. bool TarFile::ReadNextFile(std::string &tarpath, Barry::Data &data) { // start fresh tarpath.clear(); data.QuickZap(); // read next tar file header... skip all directories do { if( th_read(m_tar) != 0 ) { // this is not necessarily an error, as it could just // be the end of file, so a simple false is good here, // don't throw an exception m_last_error = ""; return false; } } while( TH_ISDIR(m_tar) ); // write standard file header if( !TH_ISREG(m_tar) ) { return False(_("Only regular files are supported inside a tarball.")); } char *pathname = th_get_pathname(m_tar); tarpath = pathname; // // FIXME (leak) - someday, when all distros use a patched version of // libtar, we may be able to avoid this memory leak, but // th_get_pathname() does not consistently return a user-freeable // string on all distros. // // See the following links for more information: // https://bugs.launchpad.net/ubuntu/+source/libtar/+bug/41804 // https://lists.feep.net:8080/pipermail/libtar/2006-April/000222.html // // free(pathname); size_t size = th_get_size(m_tar); // read the data in blocks until finished char block[T_BLOCKSIZE]; for( size_t pos = 0; pos < size; pos += T_BLOCKSIZE ) { memset(block, 0, T_BLOCKSIZE); size_t readsize = T_BLOCKSIZE; if( size - pos < T_BLOCKSIZE ) readsize = size - pos; if( tar_block_read(m_tar, block) != T_BLOCKSIZE ) { return False(_("Unable to read block"), errno); } data.Append(block, readsize); } return true; } /// Read next available filename, skipping the data if it is /// a regular file bool TarFile::ReadNextFilenameOnly(std::string &tarpath) { // start fresh tarpath.clear(); // read next tar file header... skip all directories do { if( th_read(m_tar) != 0 ) { // this is not necessarily an error, as it could just // be the end of file, so a simple false is good here, // don't throw an exception m_last_error = ""; return false; } } while( TH_ISDIR(m_tar) ); // write standard file header if( !TH_ISREG(m_tar) ) { return False(_("Only regular files are supported inside a tarball.")); } char *pathname = th_get_pathname(m_tar); tarpath = pathname; // See above FIXME (leak) comment // free(pathname); if( tar_skip_regfile(m_tar) != 0 ) { return False(_("Unable to skip tar file"), errno); } return true; } } // namespace reuse #ifdef __TEST_MODE__ #include #include using namespace std; int main() { try { cout << "Writing test file..." << endl; reuse::TarFile output("tartest.tar.gz", true, true, true); std::string data; for( int i = 0; i < 60; i++ ) { data.append("0123456789", 10); } output.AppendFile("path1/test1.txt", data); output.AppendFile("path2/test2.txt", data); output.Close(); cout << "Reading test file..." << endl; reuse::TarFile input("tartest.tar.gz", false, true, true); std::string path, incoming; while( input.ReadNextFile(path, incoming) ) { cout << "Read: " << path << " Data: " << (( data == incoming ) ? "equal" : "different") << endl; } input.Close(); unlink("tartest.tar.gz"); } catch( reuse::TarFile::TarError &te ) { cerr << te.what() << endl; return 1; } } #endif barry-0.18.5/src/legal.txt0000644001161500056700000000121112242254476014663 0ustar cdfreycdfrey/* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ barry-0.18.5/src/gettext.h0000644001161500056700000002242112242254476014701 0ustar cdfreycdfrey/* Convenience header for conditional use of GNU . Copyright (C) 1995-1998, 2000-2002, 2004-2006 Free Software Foundation, Inc. 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, 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 Library 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. */ #ifndef _LIBGETTEXT_H #define _LIBGETTEXT_H 1 /* NLS can be disabled through the configure --disable-nls option. */ #if ENABLE_NLS /* Get declarations of GNU message catalog functions. */ # include /* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by the gettext() and ngettext() macros. This is an alternative to calling textdomain(), and is useful for libraries. */ # ifdef DEFAULT_TEXT_DOMAIN # undef gettext # define gettext(Msgid) \ dgettext (DEFAULT_TEXT_DOMAIN, Msgid) # undef ngettext # define ngettext(Msgid1, Msgid2, N) \ dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) # endif #else /* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which chokes if dcgettext is defined as a macro. So include it now, to make later inclusions of a NOP. We don't include as well because people using "gettext.h" will not include , and also including would fail on SunOS 4, whereas is OK. */ #if defined(__sun) # include #endif /* Many header files from the libstdc++ coming with g++ 3.3 or newer include , which chokes if dcgettext is defined as a macro. So include it now, to make later inclusions of a NOP. */ #if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) # include # if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H # include # endif #endif /* Disabled NLS. The casts to 'const char *' serve the purpose of producing warnings for invalid uses of the value returned from these functions. On pre-ANSI systems without 'const', the config.h file is supposed to contain "#define const". */ # define gettext(Msgid) ((const char *) (Msgid)) # define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) # define dcgettext(Domainname, Msgid, Category) \ ((void) (Category), dgettext (Domainname, Msgid)) # define ngettext(Msgid1, Msgid2, N) \ ((N) == 1 \ ? ((void) (Msgid2), (const char *) (Msgid1)) \ : ((void) (Msgid1), (const char *) (Msgid2))) # define dngettext(Domainname, Msgid1, Msgid2, N) \ ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ ((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N)) # define textdomain(Domainname) ((const char *) (Domainname)) # define bindtextdomain(Domainname, Dirname) \ ((void) (Domainname), (const char *) (Dirname)) # define bind_textdomain_codeset(Domainname, Codeset) \ ((void) (Domainname), (const char *) (Codeset)) #endif /* A pseudo function call that serves as a marker for the automated extraction of messages, but does not call gettext(). The run-time translation is done at a different place in the code. The argument, String, should be a literal string. Concatenated strings and other string expressions won't work. The macro's expansion is not parenthesized, so that it is suitable as initializer for static 'char[]' or 'const char[]' variables. */ #define gettext_noop(String) String /* The separator between msgctxt and msgid in a .mo file. */ #define GETTEXT_CONTEXT_GLUE "\004" /* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be short and rarely need to change. The letter 'p' stands for 'particular' or 'special'. */ #ifdef DEFAULT_TEXT_DOMAIN # define pgettext(Msgctxt, Msgid) \ pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) #else # define pgettext(Msgctxt, Msgid) \ pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) #endif #define dpgettext(Domainname, Msgctxt, Msgid) \ pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) #define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) #ifdef DEFAULT_TEXT_DOMAIN # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) #else # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) #endif #define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) #define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category) #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * pgettext_aux (const char *domain, const char *msg_ctxt_id, const char *msgid, int category) { const char *translation = dcgettext (domain, msg_ctxt_id, category); if (translation == msg_ctxt_id) return msgid; else return translation; } #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * npgettext_aux (const char *domain, const char *msg_ctxt_id, const char *msgid, const char *msgid_plural, unsigned long int n, int category) { const char *translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); if (translation == msg_ctxt_id || translation == msgid_plural) return (n == 1 ? msgid : msgid_plural); else return translation; } /* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID can be arbitrary expressions. But for string literals these macros are less efficient than those above. */ #include #define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \ (((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \ /* || __STDC_VERSION__ >= 199901L */ ) #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS #include #endif #define pgettext_expr(Msgctxt, Msgid) \ dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) #define dpgettext_expr(Domainname, Msgctxt, Msgid) \ dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * dcpgettext_expr (const char *domain, const char *msgctxt, const char *msgid, int category) { size_t msgctxt_len = strlen (msgctxt) + 1; size_t msgid_len = strlen (msgid) + 1; const char *translation; #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS char msg_ctxt_id[msgctxt_len + msgid_len]; #else char buf[1024]; char *msg_ctxt_id = (msgctxt_len + msgid_len <= sizeof (buf) ? buf : (char *) malloc (msgctxt_len + msgid_len)); if (msg_ctxt_id != NULL) #endif { memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); msg_ctxt_id[msgctxt_len - 1] = '\004'; memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); translation = dcgettext (domain, msg_ctxt_id, category); #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS if (msg_ctxt_id != buf) free (msg_ctxt_id); #endif if (translation != msg_ctxt_id) return translation; } return msgid; } #define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) #define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * dcnpgettext_expr (const char *domain, const char *msgctxt, const char *msgid, const char *msgid_plural, unsigned long int n, int category) { size_t msgctxt_len = strlen (msgctxt) + 1; size_t msgid_len = strlen (msgid) + 1; const char *translation; #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS char msg_ctxt_id[msgctxt_len + msgid_len]; #else char buf[1024]; char *msg_ctxt_id = (msgctxt_len + msgid_len <= sizeof (buf) ? buf : (char *) malloc (msgctxt_len + msgid_len)); if (msg_ctxt_id != NULL) #endif { memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); msg_ctxt_id[msgctxt_len - 1] = '\004'; memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS if (msg_ctxt_id != buf) free (msg_ctxt_id); #endif if (!(translation == msg_ctxt_id || translation == msgid_plural)) return translation; } return (n == 1 ? msgid : msgid_plural); } #endif /* _LIBGETTEXT_H */ barry-0.18.5/src/bmp.cc0000644001161500056700000001672712242254476014145 0ustar cdfreycdfrey/// /// \file bmp.cc /// BMP conversion routines /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2008-2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "bmp.h" #include "bmp-internal.h" #include "error.h" #include "endian.h" #include "data.h" #include "m_javaloader.h" namespace Barry { // // GetBitmapHeadersSize // /// Returns the size of the bitmap headers (both file and info headers). /// You can use this as an offset into the bitmap produced by /// ScreenshotToBitmap to get just the 4-byte RGB data. /// size_t GetBitmapHeadersSize() { return sizeof(bmp_file_header_t) + sizeof(bmp_info_header_t); } // // GetTotalBitmapSize // /// Returns the total number of bytes needed to convert a /// screenshot of the given dimensions into a bitmap, /// using the ScreenshotToBitmap() function. /// size_t GetTotalBitmapSize(const JLScreenInfo &info) { return sizeof(bmp_file_header_t) + sizeof(bmp_info_header_t) + (info.width * info.height * 4); // 4 byte RGB per pixel } // // ScreenshotToRGB // /// Converts screenshot data obtained via JavaLoader::GetScreenshot() /// into uncompressed RGB bitmap format. The results will not have /// a bitmap BMP header. Data will be written to buffer, starting /// at offset. The depth variable can be 24 or 32. If invert is /// true, the result will be inverted, just like a BMP file; otherwise not. /// void ScreenshotToRGB(const JLScreenInfo &info, const Data &screenshot, Data &buffer, size_t offset, int depth, bool invert, bool overwrite_alpha, uint8_t alpha) { if( depth != 24 && depth != 32 ) throw Barry::Error(_("ScreenshotToRGB: depth must be 24 or 32")); // if user doesn't want to overwrite alpha channel, then use // the value for our own default if( !overwrite_alpha ) alpha = 0xFF; size_t width = info.width; size_t height = info.height; size_t bytes_per_pixel = (depth == 24) ? 3 : 4; size_t pixel_count = width * height; size_t total_bitmap_size = pixel_count * bytes_per_pixel; size_t total_buffer_size = total_bitmap_size + offset; // using pixel_count (width*height), determine the size used // per pixel size_t data_size; for( data_size = 2; screenshot.GetSize() > (data_size * pixel_count); data_size++ ) ; if( screenshot.GetSize() < (pixel_count * data_size) ) throw Error(_("ScreenshotToRGB: Screenshot data size is too small for given width+height")); if( data_size != 2 && data_size != 4 ) throw Error(_("ScreenshotToRGB: Screenshot depth is not supported (Barry supports 2 byte or 4 byte pixels in device screenshots)")); // setup write pointer unsigned char *write = buffer.GetBuffer(total_buffer_size) + offset; // pointer into screenshot data (grabbing pixel bytes per data_size) const uint8_t *data = (const uint8_t*) screenshot.GetData(); // For each pixel... (note BMP format is up and backwards, hence // offset calculation for each pixel in for loop) for( size_t j = 0; j < height; j++ ) { for( size_t i = 0; i < width; i++ ) { // Read one pixel in the picture // offset is in pixels... so multiply it by data_size // to read out of data int get_offset = 0; if( invert ) get_offset = (pixel_count - 1) - ((width-1 - i) + (width * j)); else get_offset = (j * width) + i; // extract the pixel data, using data_size bytes uint32_t value; switch( data_size ) { case 2: value = ((const uint16_t *)data)[get_offset]; // 16bit pixel format used by the handheld is: // MSB < .... .... .... .... > LSB // ^^^^^^ : Blue (between 0x00 and 0x1F) // ^^^^^^^ : Green (between 0x00 and 0x3F) // ^^^^^^ : Red (between 0x00 and 0x1F) if( bytes_per_pixel == 4 ) write[3] = alpha; write[2] = (((value >> 11) & 0x1F) * 0xFF) / 0x1F; // red write[1] = (((value >> 5) & 0x3F) * 0xFF) / 0x3F; // green write[0] = ((value & 0x1F) * 0xFF) / 0x1F; // blue break; case 4: value = ((const uint32_t *)data)[get_offset]; // 32bit pixel format used by the handheld is // assumed to be RGBA if( bytes_per_pixel == 4 ) { if( overwrite_alpha ) write[3] = alpha; else write[3] = (value >> 24) & 0xFF;// alpha } write[2] = (value >> 16) & 0xFF; // red write[1] = (value >> 8) & 0xFF; // green write[0] = value & 0xFF; // blue break; default: throw Error(_("ScreenshotToRGB: bad switch value, should never happen. Double check the data_size check.")); } write += bytes_per_pixel; } } buffer.ReleaseBuffer(total_buffer_size); } // // ScreenshotToBitmap // /// Converts screenshot data obtained via JavaLoader::GetScreenshot() /// into uncompressed bitmap format, suitable for writing BMP files. /// Arguments info and screenshot come from GetScreenshot() and the /// converted data is stored in bitmap. /// // // This function assumes that the btoh() converter functions match // the needs of the bitmap file format. Namely: little endian. // void ScreenshotToBitmap(const JLScreenInfo &info, const Data &screenshot, Data &bitmap) { // Read screen info size_t width = info.width; size_t height = info.height; size_t total_bitmap_size = GetTotalBitmapSize(info); // make sure there is enough screeshot pixel data for the // given width and height if( screenshot.GetSize() < (width * height * 2) ) // 2 byte screenshot pixel data throw Error(_("Screenshot data size is too small for given width+height")); // setup write pointer unsigned char *bitbuf = bitmap.GetBuffer(total_bitmap_size); unsigned char *write = bitbuf; // // Build header BMP file // bmp_file_header_t *fileheader = (bmp_file_header_t*) write; write += sizeof(bmp_file_header_t); // BMP fileheader->bfType[0] = 'B'; fileheader->bfType[1] = 'M'; // Size of file fileheader->bfSize = btohl(total_bitmap_size); // Always 0x00 fileheader->bfReserved1 = 0; fileheader->bfReserved2 = 0; // Offset to find the data fileheader->bfOffBits = btohl(sizeof(bmp_file_header_t) + sizeof(bmp_info_header_t)); // // Build info BMP file // bmp_info_header_t *infoheader = (bmp_info_header_t*) write; write += sizeof(bmp_info_header_t); // Size of info section infoheader->biSize = btohl(sizeof(bmp_info_header_t)); // Width x Height infoheader->biWidth = btohl(width); infoheader->biHeight = btohl(height); // Planes number infoheader->biPlanes = btohs(0x01); // Bit count infoheader->biBitCount = btohs(0x20); // Compression : No infoheader->biCompression = 0; // Size of image infoheader->biSizeImage = btohl(4 * width * height); // Pels Per Meter infoheader->biXPelsPerMeter = 0; infoheader->biYPelsPerMeter = 0; // Color palette used : None infoheader->biClrUsed = 0; // Color palette important : None infoheader->biClrImportant = 0; // Fill in the RGB data ScreenshotToRGB(info, screenshot, bitmap, write - bitbuf, 32, true); bitmap.ReleaseBuffer(total_bitmap_size); } } // namespace Barry barry-0.18.5/src/configfile.h0000644001161500056700000001444312242254476015327 0ustar cdfreycdfrey/// /// \file configfile.h /// Barry configuraion class, for one device PIN /// /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_CONFIGFILE_H__ #define __BARRY_CONFIGFILE_H__ #include "dll.h" #include "record.h" #include "pin.h" #include #include namespace Barry { /// Creates a tar.gz filename using PIN + date + time + label. /// Does not include any path, just returns a new filename. BXEXPORT std::string MakeBackupFilename(const Barry::Pin &pin, const std::string &label); class BXEXPORT ConfigFile { public: class BXEXPORT DBListType : public std::vector { public: bool IsSelected(const std::string &dbname) const; DBListType& operator=(const DatabaseDatabase &dbdb); DBListType() {} DBListType(const DatabaseDatabase &dbdb) { operator=(dbdb); } }; private: // meta data Barry::Pin m_pin; std::string m_path; // /path/to/config/dir without trailing slash std::string m_filename; // /path/to/config/dir/filename bool m_loaded; std::string m_last_error; // configuration data DBListType m_backupList; DBListType m_restoreList; std::string m_deviceName; bool m_promptBackupLabel; // if true, prompt the user on every // backup for a string to label the // backup file with bool m_autoSelectAll; // if true, automatically select all // databases on every backup protected: void BuildFilename(); void BuildDefaultPath(); void Clear(); void Load(); public: /// Loads config file for the given pin, and ends up in an /// unenlightened state. Throws ConfigFileError on error, /// but it is not an error if the config does not exist. /// Never use this if you have a DatabaseDatabase object! /// This ctor is only for temporary loading of config data. explicit ConfigFile(Barry::Pin pin); /// Opens and loads config file for given pin, and calls Enlighten /// Throws ConfigFileError on error. Should never fail unless /// passed a bad pin, or if unable to get current user info. ConfigFile(Barry::Pin pin, const Barry::DatabaseDatabase &db); ~ConfigFile(); // // data access // const std::string& get_last_error() const { return m_last_error; } bool IsConfigLoaded() const { return m_loaded; } const std::string& GetPath() const { return m_path; } // const std::string& GetDeviceConfigFilename() const { return m_device_filename; } // // per-Device Configuration // const DBListType& GetBackupList() const { return m_backupList; } const DBListType& GetRestoreList() const { return m_restoreList; } const std::string& GetDeviceName() const { return m_deviceName; } bool HasDeviceName() const { return m_deviceName.size() != 0; } bool PromptBackupLabel() const { return m_promptBackupLabel; } bool AutoSelectAll() const { return m_autoSelectAll; } // // operations // /// Saves current device's config, overwriting or creating a /// config file bool Save(); /// Compares a given databasedatabase from a real device with the /// current config. If not yet configured, initialize with valid /// defaults. void Enlighten(const Barry::DatabaseDatabase &db); // // per-Device Configuration setting // /// Sets list with new config void SetBackupList(const DBListType &list); void SetRestoreList(const DBListType &list); void SetDeviceName(const std::string &name); void SetBackupPath(const std::string &path); void SetPromptBackupLabel(bool prompt = true); void SetAutoSelectAll(bool asa = true); // // Utility functions // /// Checks that the path in path exists, and if not, creates it. /// Returns false if unable to create path, true if ok. static bool CheckPath(const std::string &path, std::string *perr = 0); }; class BXEXPORT GlobalConfigFile { private: typedef std::map keymap_type; // meta data std::string m_path; // /path/to/.barry without trailing slash std::string m_filename; // /path/to/.barry/config bool m_loaded; std::string m_last_error; std::string m_appname; // global configuration data Barry::Pin m_lastDevice; // the last selected device in a GUI bool m_verboseLogging; // set/get key data keymap_type m_keymap; protected: void BuildFilename(); void Clear(); void Load(); public: /// Loads the global config file. /// Throws ConfigFileError on error, but it is not an error /// if the config does not exist. GlobalConfigFile(); /// Loads the global config file, as well as any application-specific /// keywords and variables. Use this if you wish to make use of /// SetKey() and GetKey(), otherwise these functions will throw /// and exception since they don't have an application name. GlobalConfigFile(const std::string &appname); ~GlobalConfigFile(); // // data access // const std::string& get_last_error() const { return m_last_error; } bool IsConfigLoaded() const { return m_loaded; } const std::string& GetPath() const { return m_path; } // // Global Configuration data access // Barry::Pin GetLastDevice() const { return m_lastDevice; } bool VerboseLogging() const { return m_verboseLogging; } // // operations // /// Save the current global config, overwriting or creating as needed bool Save(); /// Throws std::logic_error if not constructed with an appname void SetKey(const std::string &key, const std::string &value); /// Returns value for key, and returns default_value if key does not /// exist in the config file. /// Throws std::logic_error if not constructed with an appname std::string GetKey(const std::string &key, const std::string &default_value = "") const; // // Global Configuration setting // void SetLastDevice(const Barry::Pin &pin); void SetVerboseLogging(bool verbose = true); }; BXEXPORT std::ostream& operator<< (std::ostream &os, const ConfigFile::DBListType &list); } // namespace Barry #endif barry-0.18.5/src/error.h0000644001161500056700000001705312242254476014353 0ustar cdfreycdfrey/// /// \file error.h /// Common exception classes for the Barry library /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_ERROR_H__ #define __BARRY_ERROR_H__ #include "dll.h" #include "pin.h" #include #include namespace Barry { /// \addtogroup exceptions /// @{ // // Error class // /// The base class for any future derived exceptions. /// Can be thrown on any protocol error. /// class BXEXPORT Error : public std::runtime_error { public: Error(const std::string &str) : std::runtime_error(str) {} }; // // BadPassword // /// A bad or unknown password when talking to the device. /// Can be thrown in the following instances: /// /// - no password provided and the device requests one /// - device rejected the available password /// - too few remaining tries left... Barry will refuse to keep /// trying passwords if there are fewer than /// BARRY_MIN_PASSWORD_TRIES tries remaining. In this case, /// out_of_tries() will return true. /// /// class BXEXPORT BadPassword : public Barry::Error { int m_remaining_tries; bool m_out_of_tries; public: BadPassword(const std::string &str, int remaining_tries, bool out_of_tries) : Barry::Error(str), m_remaining_tries(remaining_tries), m_out_of_tries(out_of_tries) {} int remaining_tries() const { return m_remaining_tries; } bool out_of_tries() const { return m_out_of_tries; } }; // // SocketCloseOnOpen // /// Thrown by the Socket class if it receives a CLOSE message in /// response to an OPEN command. This can mean a number of things: /// /// - device is password protected, and the wrong password was given /// - device thinks that the socket is already open /// /// This special exception thrown so the application can try again /// with a fresh Socket::Open() call. /// class BXEXPORT SocketCloseOnOpen : public Barry::Error { public: SocketCloseOnOpen(const std::string &str) : Barry::Error(str) {} }; // // PinNotFound // /// Thrown by the Connector class when unable to find the requested Pin /// If the attached pin is not Valid(), then unable to autodetect device. /// If pin is Valid(), then the specified pin number was not available. /// probe_count is the number of devices found during the probe. /// class BXEXPORT PinNotFound : public Barry::Error { Barry::Pin m_pin; int m_probe_count; public: PinNotFound(Barry::Pin pin, int probe_count) : Barry::Error("PIN not found: " + pin.Str()) , m_pin(pin) , m_probe_count(probe_count) {} const Barry::Pin& pin() const { return m_pin; } int probe_count() const { return m_probe_count; } }; // // BadData // /// Thrown by record classes if their data is invalid and cannot be /// uploaded to the Blackberry. /// class BXEXPORT BadData : public Barry::Error { public: BadData(const std::string &str) : Barry::Error(str) {} }; // // BadSize // /// Unexpected packet size, or not enough data. /// class BXEXPORT BadSize : public Barry::Error { unsigned int m_packet_size, m_data_buf_size, m_required_size; BXLOCAL static std::string GetMsg(const char *msg, unsigned int d, unsigned int r); BXLOCAL static std::string GetMsg(unsigned int p, unsigned int d, unsigned int r); public: BadSize(const char *msg, unsigned int data_size, unsigned int required_size); BadSize(unsigned int packet_size, unsigned int data_buf_size, unsigned int required_size); unsigned int packet_size() const { return m_packet_size; } unsigned int data_buf_size() const { return m_data_buf_size; } unsigned int required_size() const { return m_required_size; } }; // // ErrnoError // /// System error that provides an errno error code. /// class BXEXPORT ErrnoError : public Barry::Error { int m_errno; BXLOCAL static std::string GetMsg(const std::string &msg, int err); protected: ErrnoError(const std::string &msg); // for derived classes public: ErrnoError(const std::string &msg, int err); int error_code() const { return m_errno; } }; // // ConfigFileError // /// Thrown by the ConfigFile class when encountering a serious system /// error while loading the global config file for a given PIN. /// class BXEXPORT ConfigFileError : public Barry::ErrnoError { public: ConfigFileError(const char *msg) : Barry::ErrnoError(msg) {} ConfigFileError(const char *msg, int err) : Barry::ErrnoError(msg, err) {} }; // // BadPackedFormat // /// Thrown by record classes that don't recognize a given packed format code. /// This exception is mostly handled internally, but is published here /// just in case it escapes. /// class BXEXPORT BadPackedFormat : public Barry::Error { uint8_t m_format; public: BadPackedFormat(uint8_t format) : Barry::Error("Bad packed format - internal exception") , m_format(format) {} uint8_t format() const { return m_format; } }; // // BadPacket // /// Thrown by the socket class if a packet command's response indicates /// an error. Some commands may be able to recover inside the library, /// so a special exception is used, that includes the response code. /// class BXEXPORT BadPacket : public Barry::Error { uint8_t m_response; public: BadPacket(uint8_t response, const std::string &msg) : Barry::Error(msg) , m_response(response) {} uint8_t response() const { return m_response; } }; // // ConvertError // /// Thrown by the vformat related barrysync library classes. /// class BXEXPORT ConvertError : public Barry::Error { public: ConvertError(const std::string &msg) : Barry::Error(msg) {} }; // // BackupError // /// Thrown by the Backup parser class when there is a problem with the /// low level file operation. /// class BXEXPORT BackupError : public Barry::Error { public: BackupError(const std::string &str) : Error(str) {} }; // // RestoreError // /// Thrown by the Restore builder class when there is a problem with the /// low level file operation. /// class BXEXPORT RestoreError : public Barry::Error { public: RestoreError(const std::string &str) : Error(str) {} }; // // ReturnCodeError // /// Thrown by the Mode::Desktop class when a database command returns /// a non-zero error code. Can happen when writing or clearing a database. /// The packet command and return code are passed along, for examination /// by application code. Note that return code 0x02 usually means /// you're trying to clear or write to a read-only database, like Time Zones. /// class BXEXPORT ReturnCodeError : public Barry::Error { unsigned int m_command, m_return_code; public: ReturnCodeError(const std::string &str, unsigned int command, unsigned int return_code) : Error(str) , m_command(command) , m_return_code(return_code) { } unsigned int command() const { return m_command; } unsigned int return_code() const { return m_return_code; } bool IsReadOnly() const { return return_code() == 0x02; } }; // // ValidationError // /// Thrown by one of the record classes' Validate() function. Contains /// and error message describing the deficiency. /// class BXEXPORT ValidationError : public Barry::Error { public: explicit ValidationError(const std::string &str) : Error(str) { } }; /// @} } // namespace Barry #endif barry-0.18.5/src/protostructs.h0000644001161500056700000007262612242254476016024 0ustar cdfreycdfrey/// /// \file protostructs.h /// USB Blackberry bulk protocol API. This is split out from /// protocol.h so that low level, packed structs can be /// compiled separately from the application. This prevents /// aliasing problems in the application, or using /// -fno-strict-aliasing, which the library only needs. /// /// Do not include this in any Barry library header. /// This may only be included from .cc files, in order /// to hide aliasing concernes from the application. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_PROTOSTRUCTS_H__ #define __BARRY_PROTOSTRUCTS_H__ #include #include #include "platform.h" // safe to include platform.h here, since // protostructs.h is not installed either #if USE_PACK_PRAGMA #pragma pack(push, 1) #endif // forward declarations namespace Barry { class Data; } namespace Barry { namespace Protocol { /////////////////////////////////////////////////////////////////////////////// union SizePacket { uint16_t size; char buffer[4]; } ATTRIBUTE_PACKED; /////////////////////////////////////////////////////////////////////////////// // Record sub-field structs struct GroupLink // used for Contacts records { uint32_t uniqueId; uint16_t unknown; } ATTRIBUTE_PACKED; struct MessageAddress // used for Message records { uint8_t unknown[8]; uint8_t addr[1]; // 2 null terminated strings: first // contains full name, second contains // the email address } ATTRIBUTE_PACKED; /////////////////////////////////////////////////////////////////////////////// // SMS Message field and record structures struct SMSMetaData { uint8_t recv; // if received, this is set to 1; otherwise 0 uint8_t flags; #define SMS_FLG_NEW_CONVERSATION 0x20 #define SMS_FLG_SAVED 0x10 #define SMS_FLG_DELETED 0x08 #define SMS_FLG_OPENED 0x01 uint8_t new_flag; uint16_t zero; // constantly 0 uint32_t status; #define SMS_STA_RECEIVED 0x000007ff #define SMS_STA_DRAFT 0x7fffffff uint32_t error_id; uint64_t timestamp; uint64_t service_center_timestamp; uint8_t dcs; #define SMS_DCS_7BIT 0x00 #define SMS_DCS_8BIT 0x01 #define SMS_DCS_UCS2 0x02 } ATTRIBUTE_PACKED; #define SMS_METADATA_SIZE (sizeof(::Barry::Protocol::SMSMetaData)) /////////////////////////////////////////////////////////////////////////////// // Record Field Formats struct CommonField { uint16_t size; // including null terminator uint8_t type; union CommonFieldData { GroupLink link; MessageAddress addr; SMSMetaData sms_metadata; uint64_t timestamp; uint64_t uint64; uint32_t uint32; int32_t min1900; uint16_t code; uint8_t raw[1]; int16_t int16; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define COMMON_FIELD_HEADER_SIZE (sizeof(::Barry::Protocol::CommonField) - sizeof(::Barry::Protocol::CommonField::CommonFieldData)) #define COMMON_FIELD_MIN1900_SIZE (sizeof(int32_t)) struct CommandTableField { uint8_t size; // no null terminator uint8_t code; uint8_t name[1]; } ATTRIBUTE_PACKED; #define COMMAND_FIELD_HEADER_SIZE (sizeof(::Barry::Protocol::CommandTableField) - 1) struct OldDBDBField { uint16_t dbNumber; uint8_t unknown1; uint32_t dbSize; // assumed from Cassis docs... // always 0 in USB uint16_t dbRecordCount; uint16_t unknown2; uint16_t nameSize; // includes null terminator uint8_t name[1]; } ATTRIBUTE_PACKED; #define OLD_DBDB_FIELD_HEADER_SIZE (sizeof(::Barry::Protocol::OldDBDBField) - 1) struct DBDBField { uint16_t dbNumber; uint8_t unknown1; uint32_t dbSize; // assumed from Cassis docs... // always 0 in USB uint32_t dbRecordCount; uint16_t unknown2; uint16_t nameSize; // includes null terminator uint8_t unknown3; uint8_t name[1]; // followed by 2 zeros! uint16_t unknown; // this comes after the // null terminated name, but // is here for size calcs } ATTRIBUTE_PACKED; #define DBDB_FIELD_HEADER_SIZE (sizeof(::Barry::Protocol::DBDBField) - 1) struct RecordStateTableField { uint8_t rectype; // it is unknown exactly what // this field does, but it // shows up here and in the // tagged record header, and // for some of the records // they must match when writing uint16_t index; uint32_t uniqueId; // matches the uniqueId of say, // address book records uint8_t flags; // bit 0x01 is the dirty flag // don't know if any other bits // are used #define BARRY_RSTF_DIRTY 0x01 uint8_t unknown2[4]; } ATTRIBUTE_PACKED; struct CalendarRecurrenceDataField // as documented in the Cassis project spec { uint8_t type; #define CRDF_TYPE_DAY 0x01 #define CRDF_TYPE_MONTH_BY_DATE 0x03 #define CRDF_TYPE_MONTH_BY_DAY 0x04 #define CRDF_TYPE_YEAR_BY_DATE 0x05 #define CRDF_TYPE_YEAR_BY_DAY 0x06 #define CRDF_TYPE_WEEK 0x0c uint8_t unknown; // always 0x01 uint16_t interval; uint32_t startTime; uint32_t endTime; // 0xFFFFFFFF for never union Additional { // Note: blank fields should be set to 0 struct Day { uint8_t day[6]; // always zeros! } ATTRIBUTE_PACKED day; struct MonthByDate { uint8_t monthDay; // day of month to recur on // (1-31) uint8_t blank[5]; } ATTRIBUTE_PACKED month_by_date; struct MonthByDay { uint8_t weekDay; // day of week to recur on (0-6) uint8_t week; // week of month to recur on // (1 to 5, first week, second // week, etc) uint8_t blank[4]; } ATTRIBUTE_PACKED month_by_day; struct YearByDate { uint8_t monthDay; // day of month to recur on // (1-31) uint8_t blank; uint8_t month; // month to recur on (1-12) uint8_t blank_[3]; } ATTRIBUTE_PACKED year_by_date; struct YearByDay { uint8_t weekDay; // day of week to recur on (0-6) uint8_t week; // week of month (1 to 5) uint8_t month; // (1-12) uint8_t blank[3]; } ATTRIBUTE_PACKED year_by_day; struct Week { uint8_t days; // bitmask #define CRDF_WD_SUN 0x01 #define CRDF_WD_MON 0x02 #define CRDF_WD_TUE 0x04 #define CRDF_WD_WED 0x08 #define CRDF_WD_THU 0x10 #define CRDF_WD_FRI 0x20 #define CRDF_WD_SAT 0x40 uint8_t blank[5]; } ATTRIBUTE_PACKED week; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define CALENDAR_RECURRENCE_DATA_FIELD_SIZE sizeof(::Barry::Protocol::CalendarRecurrenceDataField) // // Calendar record: field constants // #define CR_FREEBUSY_FREE 0 #define CR_FREEBUSY_TENTATIVE 1 #define CR_FREEBUSY_BUSY 2 #define CR_FREEBUSY_OUT_OF_OFFICE 3 #define CR_FREEBUSY_RANGE_LOW 0 #define CR_FREEBUSY_RANGE_HIGH 3 #define CR_CLASS_PUBLIC 0 #define CR_CLASS_CONFIDENTIAL 1 #define CR_CLASS_PRIVATE 2 #define CR_CLASS_RANGE_LOW 0 #define CR_CLASS_RANGE_HIGH 2 // // Task record: field constants // #define TR_ALARM_DATE 1 #define TR_ALARM_RELATIVE 2 #define TR_ALARM_RANGE_LOW 1 #define TR_ALARM_RANGE_HIGH 2 #define TR_PRIORITY_HIGH 0 #define TR_PRIORITY_NORMAL 1 #define TR_PRIORITY_LOW 2 #define TR_PRIORITY_RANGE_LOW 0 #define TR_PRIORITY_RANGE_HIGH 2 #define TR_STATUS_NOT_STARTED 0 #define TR_STATUS_IN_PROGRESS 1 #define TR_STATUS_COMPLETED 2 #define TR_STATUS_WAITING 3 #define TR_STATUS_DEFERRED 4 #define TR_STATUS_RANGE_LOW 0 #define TR_STATUS_RANGE_HIGH 4 // // Phone Call Logs record: field constants // // #define CLL_DIRECTION_RECEIVER 0 #define CLL_DIRECTION_EMITTER 1 #define CLL_DIRECTION_FAILED 2 #define CLL_DIRECTION_MISSING 3 #define CLL_DIRECTION_RANGE_LOW 0 #define CLL_DIRECTION_RANGE_HIGH 3 #define CLL_PHONETYPE_UNDEFINED 0 #define CLL_PHONETYPE_OFFICE 1 #define CLL_PHONETYPE_HOME 2 #define CLL_PHONETYPE_MOBILE 3 #define CLL_PHONETYPE_RANGE_LOW 0 #define CLL_PHONETYPE_RANGE_HIGH 3 // // Browser Bookmarks record: field constants // // #define BMK_BROWSER_AUTO 0 #define BMK_BROWSER_BLACKBERRY 1 #define BMK_BROWSER_FIREFOX 2 #define BMK_BROWSER_INTERNET_EXPLORER 3 #define BMK_DISPLAY_AUTO 0 #define BMK_DISPLAY_COLOMN 1 #define BMK_DISPLAY_PAGE 2 #define BMK_JAVASCRIPT_AUTO 0 #define BMK_JAVASCRIPT_ENABLED 1 #define BMK_JAVASCRIPT_DISABLED 2 struct StringField { uint16_t be_size; // may or may not have a null term. // big-endian uint8_t data[1]; } ATTRIBUTE_PACKED; #define STRING_FIELD_HEADER_SIZE (sizeof(::Barry::Protocol::StringField) - 1) struct BookmarkId { uint32_t bookmark_id; uint8_t index; } ATTRIBUTE_PACKED; #define BOOKMARK_ID_SIZE (sizeof(::Barry::Protocol::BookmarkId)) struct VarStringField { uint8_t present; uint16_t be_size; // big-endian uint8_t data[1]; } ATTRIBUTE_PACKED; #define VARSTRING_FIELD_HEADER_SIZE (sizeof(::Barry::Protocol::VarStringField) - 1) struct BookmarkFolders { uint32_t id1; // these two fields contain uint32_t id2; // b9 fc f8 f6 c2 e3 a4 d5 // whenever there is a record in // the Blackberry Bookmarks folder, // even across multiple devices! // this was true for the 9550 and // the oooold 7750, and the 8700 uint8_t unknown; // may be a section code? seems to // always be 0x08 uint8_t flag; // unknown flag } ATTRIBUTE_PACKED; #define BOOKMARK_FOLDERS_HEADER_SIZE (sizeof(::Barry::Protocol::BookmarkFolders)) // // Folder record: field constants // #define FR_TYPE_SUBTREE 0x00 #define FR_TYPE_DELETED 0x01 #define FR_TYPE_INBOX 0x02 #define FR_TYPE_OUTBOX 0x03 #define FR_TYPE_SENT 0x04 #define FR_TYPE_OTHER 0x05 #define FR_TYPE_DRAFT 0x0a #define FR_STATUS_ORPHAN 0x50 #define FR_STATUS_UNFILED 0x51 #define FR_STATUS_FILED 0x52 /////////////////////////////////////////////////////////////////////////////// // Packed field structures - odd format used with Service Book records struct PackedField_02 { uint8_t code; uint8_t size; uint8_t type; uint8_t raw[1]; } ATTRIBUTE_PACKED; #define PACKED_FIELD_02_HEADER_SIZE (sizeof(::Barry::Protocol::PackedField_02) - 1) struct PackedField_10 { uint8_t type; uint8_t size; uint8_t raw[1]; } ATTRIBUTE_PACKED; #define PACKED_FIELD_10_HEADER_SIZE (sizeof(::Barry::Protocol::PackedField_10) - 1) /////////////////////////////////////////////////////////////////////////////// // Service Book field and record structures struct ServiceBookConfigField { uint8_t format; uint8_t fields[1]; } ATTRIBUTE_PACKED; #define SERVICE_BOOK_CONFIG_FIELD_HEADER_SIZE (sizeof(::Barry::Protocol::ServiceBookConfigField) - 1) /////////////////////////////////////////////////////////////////////////////// // DB Command Parameter structures struct DBC_Record { uint16_t recordIndex; // index comes from RecordStateTable uint8_t data[1]; } ATTRIBUTE_PACKED; #define DBC_RECORD_HEADER_SIZE (sizeof(::Barry::Protocol::DBC_Record) - 1) struct DBC_RecordFlags { uint8_t unknown; uint16_t index; uint8_t unknown2[5]; } ATTRIBUTE_PACKED; #define DBC_RECORD_FLAGS_SIZE (sizeof(::Barry::Protocol::DBC_RecordFlags)) struct DBC_TaggedUpload { uint8_t rectype; // it is unknown exactly what // this field does, but it // shows up here and in the // RecordStateTable, and // for some of the records // they must match when writing uint32_t uniqueId; uint8_t unknown2; uint8_t data[1]; } ATTRIBUTE_PACKED; #define DBC_TAGGED_UPLOAD_HEADER_SIZE (sizeof(::Barry::Protocol::DBC_TaggedUpload) - 1) struct DBC_IndexedUpload { uint8_t unknown; // observed: 00 or 05 uint16_t index; uint8_t data[1]; } ATTRIBUTE_PACKED; #define DBC_INDEXED_UPLOAD_HEADER_SIZE (sizeof(::Barry::Protocol::DBC_IndexedUpload) - 1) struct PasswordChallenge { uint8_t remaining_tries; // number of password attempts // the device will accept before // committing suicide... // starts at 10 and counts down // on each bad password uint8_t unknown; // observed as 0... probably just // the top byte of a uint16 // remaining_tries, but I don't // want to take that chance uint16_t param; // seems to be a secondary command // of some kind, observed as 0x14 // or 0x04, but purpose unknown // possibly a send/receive flag // bit (0x10/0x00) union Hash { uint32_t seed; uint8_t hash[20]; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define PASSWORD_CHALLENGE_HEADER_SIZE (sizeof(::Barry::Protocol::PasswordChallenge) - sizeof(::Barry::Protocol::PasswordChallenge::Hash)) #define PASSWORD_CHALLENGE_SEED_SIZE (PASSWORD_CHALLENGE_HEADER_SIZE + sizeof(uint32_t)) #define PASSWORD_CHALLENGE_SIZE (sizeof(::Barry::Protocol::PasswordChallenge)) struct AttributeFetch { uint16_t object; uint16_t attribute; uint8_t raw[1]; // used only in response } ATTRIBUTE_PACKED; #define ATTRIBUTE_FETCH_COMMAND_SIZE (sizeof(::Barry::Protocol::AttributeFetch) - 1) struct ModeSelect { uint8_t name[16]; struct ResponseBlock { uint8_t unknown[20]; } ATTRIBUTE_PACKED response; } ATTRIBUTE_PACKED; struct Echo { uint64_t ticks; // number of microseconds since // host system startup } ATTRIBUTE_PACKED; #define ECHO_COMMAND_SIZE (sizeof(::Barry::Protocol::Echo)) /////////////////////////////////////////////////////////////////////////////// // Protocol command structures struct SocketCommand { uint16_t socket; uint8_t sequence; // incremented on each socket 0 // communication, replies return // the same number from command union PacketData { PasswordChallenge password; AttributeFetch fetch; ModeSelect mode; uint8_t raw[1]; Echo echo; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define SOCKET_COMMAND_HEADER_SIZE (sizeof(::Barry::Protocol::SocketCommand) - sizeof(::Barry::Protocol::SocketCommand::PacketData)) struct SequenceCommand { uint8_t socket; // socket number, single byte uint8_t unknown2; uint8_t unknown3; uint32_t sequenceId; } ATTRIBUTE_PACKED; struct DBCommand { uint8_t operation; // see below uint16_t databaseId; // value from the Database Database union Parameters { DBC_Record record; DBC_RecordFlags flags; DBC_TaggedUpload tag_upload; DBC_IndexedUpload index_upload; uint8_t raw[1]; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define DB_COMMAND_HEADER_SIZE (sizeof(::Barry::Protocol::DBCommand) - sizeof(::Barry::Protocol::DBCommand::Parameters)) /////////////////////////////////////////////////////////////////////////////// // Protocol response parameter structures struct DBR_OldDBDBRecord { uint16_t count; // number of fields in record OldDBDBField field[1]; } ATTRIBUTE_PACKED; #define OLD_DBDB_RECORD_HEADER_SIZE (sizeof(::Barry::Protocol::DBR_OldDBDBRecord) - sizeof(::Barry::Protocol::OldDBDBField)) struct DBR_DBDBRecord { uint16_t count; uint8_t unknown[3]; DBDBField field[1]; } ATTRIBUTE_PACKED; #define DBDB_RECORD_HEADER_SIZE (sizeof(::Barry::Protocol::DBR_DBDBRecord) - sizeof(::Barry::Protocol::DBDBField)) // Records with a uniqueId. This covers the following records: // // Old Contact records // Old Service Book records // Old Calendar records // struct DBR_OldTaggedRecord { uint8_t rectype; uint16_t index; uint32_t uniqueId; uint8_t unknown2; union TaggedData { CommonField field[1]; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define DBR_OLD_TAGGED_RECORD_HEADER_SIZE (sizeof(::Barry::Protocol::DBR_OldTaggedRecord) - sizeof(::Barry::Protocol::DBR_OldTaggedRecord::TaggedData)) struct MessageRecord { uint8_t field1; // always 'j' uint32_t field2; // always 0x00000000 uint32_t flags; // flags uint32_t field4; // normal email and pin recv this is 0x7ff // changes on sent and reply to 0x01ffffff // and 0x003fffff on pin send uint32_t field5; // always 0x00000000 uint32_t field6; // always 0x00000000 uint32_t field7; // always 0x00000000 uint32_t field8; // always 0x00000000 uint16_t field9; // always 0x0000 uint16_t dateReceived; // the first two of these time fields are always the same uint16_t timeReceived; // uint16_t dateDuplicate; // On mail sent from the BB all three fields are identical uint16_t timeDuplicate; // (time sent) uint16_t dateSent; uint16_t timeSent; uint16_t priority; // priority field uint32_t field14; // always 0x00000000 uint32_t field15; // always 0x00000000 uint16_t field16; // always 0x0000 uint32_t field13; // PIN reply 0x00000000 other time 0xffffffff or 0xfffffffe uint16_t messageSize; // Message size, 0x0000 if Reply or Saved, 0xffff if below ???? uint32_t field18; // 0x0's and 0xF'x uint32_t field19; // 0x0's and 0xF's uint16_t field20; // always 0x0000 uint16_t field21; // 0x01 unless PIN reply then 0x00 uint32_t inReplyTo; // reply to message? uint32_t field22; // always 0x00000000 uint16_t field23; // FIXME uint32_t folderOne; // these are the 'folders' the message is in uint32_t folderTwo; // uint16_t replyMessageFlags; // 0xfffe on recvd messages // 0x001b on reply // 0x0015 on send // 0x3 pin send // 0x2 on pin recv uint16_t field27; // set to 0x00000004 on PIN reply, 0x00000005 otherwise uint32_t headerUID; // yet another copy of the UID (RecId) uint32_t field29; // always 0x00000000 uint16_t field30; // always 0x0002 uint16_t field31; // always 0x00000000 uint16_t field32; // always 0x0004 uint16_t field34; // always 0x0000 uint8_t field33; // always 'd' uint32_t timeBlock; // FIXME CommonField field[1]; } ATTRIBUTE_PACKED; #define MESSAGE_RECORD_HEADER_SIZE (sizeof(::Barry::Protocol::MessageRecord) - sizeof(::Barry::Protocol::CommonField)) /////////////////////////////////////////////////////////////////////////////// // Protocol response structures struct DBResponse { uint8_t operation; union Parameters { DBR_OldTaggedRecord tagged; DBR_OldDBDBRecord old_dbdb; DBR_DBDBRecord dbdb; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define DB_RESPONSE_HEADER_SIZE (sizeof(::Barry::Protocol::DBResponse) - sizeof(::Barry::Protocol::DBResponse::Parameters)) /////////////////////////////////////////////////////////////////////////////// // Database access command structure // even fragmented packets have a tableCmd struct DBAccess { uint8_t tableCmd; union DBData { DBCommand command; DBResponse response; CommandTableField table[1]; uint8_t return_code; uint8_t fragment[1]; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define SB_DBACCESS_HEADER_SIZE (sizeof(::Barry::Protocol::DBAccess) - sizeof(::Barry::Protocol::DBAccess::DBData)) #define SB_DBACCESS_RETURN_CODE_SIZE (1) /////////////////////////////////////////////////////////////////////////////// // Javaloader protocol structure struct JLDirEntry { uint16_t unknown; uint32_t timestamp; uint16_t filename_size; uint8_t filename[1]; // the rest of the packet is variable length // another string for version, then: // uint32_t cod_size; } ATTRIBUTE_PACKED; #define SB_JLDIRENTRY_HEADER_SIZE (sizeof(::Barry::Protocol::JLDirEntry) - 1) struct JLCommand { uint8_t command; uint8_t unknown; // nearly always 0, might be top half of command uint16_t size; } ATTRIBUTE_PACKED; #define SB_JLCOMMAND_HEADER_SIZE (sizeof(::Barry::Protocol::JLCommand)) struct JLResponse { uint8_t command; uint8_t unknown; uint16_t expect; } ATTRIBUTE_PACKED; #define SB_JLRESPONSE_HEADER_SIZE (sizeof(::Barry::Protocol::JLResponse)) struct JLScreenInfo { uint16_t unknown1; uint16_t unknown2; uint16_t unknown3; uint16_t width; uint16_t height; uint16_t unknown4; uint16_t unknown5; uint16_t unknown6; } ATTRIBUTE_PACKED; #define SB_JLSCREENINFO_SIZE (sizeof(::Barry::Protocol::JLScreenInfo)) struct JLEventlogEntry { uint16_t size; // remainder of packet is variable // it contains the log data as an ASCII (UTF-8?) string } ATTRIBUTE_PACKED; #define SB_JLEVENTLOG_ENTRY_HEADER_SIZE (sizeof(::Barry::Protocol::JLEventlogEntry)) struct JLDeviceInfo { uint32_t hardware_id; uint32_t pin; uint32_t os_version; uint32_t vm_version; uint32_t radio_id; uint32_t vendor_id; uint32_t active_wafs; // older devices (such as 7130) don't this extra data in the // device info packet and will therefore fail the size check //uint8_t raw[4]; } ATTRIBUTE_PACKED; #define SB_JLDEVICEINFO_SIZE (sizeof(::Barry::Protocol::JLDeviceInfo)) struct JLPacket { uint16_t socket; uint16_t size; // total size of data packet union PacketData { JLCommand command; JLResponse response; JLScreenInfo screeninfo; JLEventlogEntry logentry; JLDeviceInfo devinfo; uint8_t raw[1]; char filename[1]; uint32_t cod_size; uint32_t timestamp; uint16_t id; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define SB_JLPACKET_HEADER_SIZE (sizeof(::Barry::Protocol::JLPacket) - sizeof(::Barry::Protocol::JLPacket::PacketData)) /////////////////////////////////////////////////////////////////////////////// // JavaDebug protocol structures namespace JDWP { // Packet command //---------------- struct PacketEventRequestSet { uint8_t eventKind; uint8_t suspendPolicy; uint32_t modifiers; } ATTRIBUTE_PACKED; struct PacketEventRequest { union PacketEventRequestData { PacketEventRequestSet set; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; struct PacketCommand { uint8_t commandset; uint8_t command; union PacketCommandData { PacketEventRequest eventRequest; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define JDWP_COMMAND_HEADER_SIZE (sizeof(::Barry::Protocol::JDWP::PacketCommand)) // Packet response //----------------- struct PacketVirtualMachineIDSizes { uint32_t fieldIDSize; uint32_t methodIDSize; uint32_t objectIDSize; uint32_t referenceTypeIDSize; uint32_t frameIDSize; } ATTRIBUTE_PACKED; #define JDWP_PACKETVIRTUALMACHINEIDSIZES_DATA_SIZE sizeof(::Barry::Protocol::JDWP::PacketVirtualMachineIDSizes) struct PacketVirtualMachine { union PacketVirtualMachineData { PacketVirtualMachineIDSizes IDSizes; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; struct PacketResponse { uint16_t errorcode; union PacketResponseData { PacketVirtualMachine virtualMachine; uint32_t value; uint8_t raw[1]; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define JDWP_RESPONSE_HEADER_SIZE (sizeof(::Barry::Protocol::JDWP::PacketResponse) - sizeof(::Barry::Protocol::JDWP::PacketResponse::PacketResponseData)) // Generic packet //---------------- struct Packet { uint32_t length; uint32_t id; uint8_t flags; union PacketType { PacketCommand command; PacketResponse response; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define JDWP_PACKET_HEADER_SIZE (sizeof(::Barry::Protocol::JDWP::Packet) - sizeof(::Barry::Protocol::JDWP::Packet::PacketType)) #define MAKE_JDWPPACKET(var, data) const ::Barry::Protocol::JDWP::Packet *var = (const ::Barry::Protocol::JDWP::Packet *) (data).GetData() #define MAKE_JDWPPACKETPTR_BUF(var, ptr) ::Barry::Protocol::JDWP::Packet *var = (::Barry::Protocol::JDWP::Packet *)ptr } // namespace JDWP struct JDWField { uint32_t size; union JDWFieldData { uint8_t raw[1]; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define JDWP_FIELD_HEADER_SIZE (sizeof(::Barry::Protocol::JDWField) - sizeof(::Barry::Protocol::JDWField::JDWFieldData)) struct JVMCommand { uint16_t size; uint8_t command; uint8_t raw[1]; } ATTRIBUTE_PACKED; #define SB_JVMCOMMAND_HEADER_SIZE (sizeof(::Barry::Protocol::JVMCommand)) struct JVMResponse { uint8_t command; uint8_t unknown; uint16_t expect; } ATTRIBUTE_PACKED; #define SB_JVMRESPONSE_HEADER_SIZE (sizeof(::Barry::Protocol::JVMResponse)) struct JVMModulesList { uint32_t nbr; // remainder of packet is variable // it contains the modules list } ATTRIBUTE_PACKED; #define SB_JVMMODULES_LIST_HEADER_SIZE (sizeof(::Barry::Protocol::JVMModulesList)) struct JVMModulesEntry { uint32_t id; uint32_t uniqueId; uint16_t sizename; // remainder of packet is variable // it contains the module name } ATTRIBUTE_PACKED; #define SB_JVMMODULES_ENTRY_HEADER_SIZE (sizeof(::Barry::Protocol::JVMModulesEntry)) struct JVMThreadsList { uint32_t nbr; // remainder of packet is variable // it contains the threads list } ATTRIBUTE_PACKED; #define SB_JVMTHREADS_LIST_HEADER_SIZE (sizeof(::Barry::Protocol::JVMThreadsList)) struct JVMUnknown01 { uint8_t byte; uint32_t address; } ATTRIBUTE_PACKED; #define SB_JVMUNKNOWN01_HEADER_SIZE (sizeof(::Barry::Protocol::JVMUnknown01)) struct JVMUnknown02 { uint32_t address1; uint32_t address2; } ATTRIBUTE_PACKED; #define SB_JVMUNKNOWN02_HEADER_SIZE (sizeof(::Barry::Protocol::JVMUnknown02)) struct JVMPacket { uint16_t socket; uint16_t size; // total size of data packet union PacketData { JVMCommand command; JVMResponse response; JVMModulesList moduleslist; JVMThreadsList threadslist; JVMUnknown01 unknown01; JVMUnknown02 unknown02; uint32_t address; uint16_t expect; uint16_t msglength; uint16_t value; uint8_t status; uint8_t raw[1]; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define SB_JVMPACKET_HEADER_SIZE (sizeof(::Barry::Protocol::JVMPacket) - sizeof(::Barry::Protocol::JVMPacket::PacketData)) ///////////////////////////////////////////////////////////////////////////// // Raw channel packet structure struct ChannelPacket { uint16_t socket; // socket ID... 0 exists by default uint16_t size; // total size of data packet union PacketData { uint8_t data[1]; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define SB_CHANNELPACKET_HEADER_SIZE (sizeof(::Barry::Protocol::ChannelPacket) - sizeof(::Barry::Protocol::ChannelPacket::PacketData)) #define SB_CHANNELPACKET_MAX_DATA_SIZE 0x3FFC /////////////////////////////////////////////////////////////////////////////// // Main packet struct struct Packet { uint16_t socket; // socket ID... 0 exists by default uint16_t size; // total size of data packet uint8_t command; union PacketData { SocketCommand socket; SequenceCommand sequence; DBAccess db; uint8_t raw[1]; } ATTRIBUTE_PACKED u; } ATTRIBUTE_PACKED; #define SB_PACKET_SOCKET_SIZE (sizeof(uint16_t)) // size needed to read the socket in a packet #define SB_PACKET_HEADER_SIZE (sizeof(::Barry::Protocol::Packet) - sizeof(::Barry::Protocol::Packet::PacketData)) // WARNING : For JavaLoader we have some packet with 5 size ! #define MIN_PACKET_SIZE 5 #define MIN_PACKET_DATA_SIZE 4 // maximum sizes #define MAX_PACKET_SIZE 0x400 // anything beyond this needs to be fragmented #define MAX_PACKET_DATA_SIZE 0x7FC // for data packet (JavaLoader) ///////////////////////////////////////////////////////////////////////////// // // various useful sizes // #define SB_PACKET_DBACCESS_HEADER_SIZE (SB_PACKET_HEADER_SIZE + SB_DBACCESS_HEADER_SIZE) #define SB_FRAG_HEADER_SIZE SB_PACKET_DBACCESS_HEADER_SIZE #define SB_PACKET_COMMAND_HEADER_SIZE (SB_PACKET_DBACCESS_HEADER_SIZE + DB_COMMAND_HEADER_SIZE) #define SB_PACKET_RESPONSE_HEADER_SIZE (SB_PACKET_DBACCESS_HEADER_SIZE + DB_RESPONSE_HEADER_SIZE) #define SB_PACKET_DBDB_HEADER_SIZE (SB_PACKET_RESPONSE_HEADER_SIZE + DBDB_RECORD_HEADER_SIZE) #define SB_PACKET_OLD_DBDB_HEADER_SIZE (SB_PACKET_RESPONSE_HEADER_SIZE + OLD_DBDB_RECORD_HEADER_SIZE) #define SB_PACKET_UPLOAD_HEADER_SIZE (SB_PACKET_DBACCESS_HEADER_SIZE + UPLOAD_HEADER_SIZE) #define SB_SEQUENCE_PACKET_SIZE (SB_PACKET_HEADER_SIZE + sizeof(::Barry::Protocol::SequenceCommand)) #define SB_SOCKET_PACKET_HEADER_SIZE (SB_PACKET_HEADER_SIZE + SOCKET_COMMAND_HEADER_SIZE) #define SB_MODE_PACKET_COMMAND_SIZE (SB_SOCKET_PACKET_HEADER_SIZE + sizeof(::Barry::Protocol::ModeSelect) - sizeof(::Barry::Protocol::ModeSelect::ResponseBlock)) #define SB_MODE_PACKET_RESPONSE_SIZE (SB_SOCKET_PACKET_HEADER_SIZE + sizeof(::Barry::Protocol::ModeSelect)) // Macros #define COMMAND(data) (((const ::Barry::Protocol::Packet *)data.GetData())->command) #define IS_COMMAND(data, cmd) (COMMAND(data) == cmd) #define MAKE_PACKET(var, data) const ::Barry::Protocol::Packet *var = (const ::Barry::Protocol::Packet *) (data).GetData() #define MAKE_JLPACKET(var, data) const ::Barry::Protocol::JLPacket *var = (const ::Barry::Protocol::JLPacket *) (data).GetData() #define MAKE_JVMPACKET(var, data) const ::Barry::Protocol::JVMPacket *var = (const ::Barry::Protocol::JVMPacket *) (data).GetData() #define MAKE_CHANNELPACKET(var, data) const ::Barry::Protocol::ChannelPacket *var = (const ::Barry::Protocol::ChannelPacket *) (data).GetData() #define MAKE_PACKETPTR_BUF(var, ptr) ::Barry::Protocol::Packet *var = (::Barry::Protocol::Packet *)ptr #define MAKE_JLPACKETPTR_BUF(var, ptr) ::Barry::Protocol::JLPacket *var = (::Barry::Protocol::JLPacket *)ptr #define MAKE_JVMPACKETPTR_BUF(var, ptr) ::Barry::Protocol::JVMPacket *var = (::Barry::Protocol::JVMPacket *)ptr #define MAKE_CHANNELPACKETPTR_BUF(var, ptr) ::Barry::Protocol::ChannelPacket *var = (::Barry::Protocol::ChannelPacket *)ptr #define MAKE_RECORD(type,var,data,off) type *var = (type *) ((data).GetData() + (off)) #define MAKE_RECORD_PTR(type,var,data,off) type *var = (type *) ((data) + (off)) // fragmentation protocol // send DATA first, then keep sending DATA packets, FRAGMENTing // as required until finished, then send DONE. Both sides behave // this way, so different sized data can be sent in both // directions // // the fragmented piece only has a the param header, and then continues // right on with the data // checks packet size and throws BError if not right void CheckSize(const Barry::Data &packet, size_t requiredsize); unsigned int GetSize(const Barry::Data &packet); bool IsSequencePacket(const Barry::Data &data); }} // namespace Barry::Protocol #if USE_PACK_PRAGMA #pragma pack(pop) #endif #endif barry-0.18.5/src/controller.h0000644001161500056700000000734512242254476015410 0ustar cdfreycdfrey/// /// \file controller.h /// High level BlackBerry API class /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_CONTROLLER_H__ #define __BARRY_CONTROLLER_H__ #include "dll.h" #include "socket.h" /// Project namespace, containing all related functions and classes. /// This is the only namespace applications should be concerned with, /// for now. namespace Barry { // forward declarations class SocketRoutingQueue; struct ProbeResult; class PrivateControllerData; namespace Mode { class Mode; class IpModem; class Serial; class JavaLoader; class JVMDebug; class RawChannel; } // // Controller class // /// The main interface class. This class coordinates the communication to /// a single handheld. This class also owns the only Usb::Device object /// the handheld. All other classes reference this one for the low level /// device object. This class owns the only SocketZero object as well, /// which is the object that any SocketRoutingQueue is plugged into /// if constructed that way. /// /// To use this class, use the following steps: /// /// - Probe the USB bus for matching devices with the Probe class /// - Create an optional SocketRoutingQueue object and create a /// read thread for it, or use its default read thread. /// - Pass one of the probe results into the Controller constructor /// to connect to the USB device. Pass the routing queue /// to the Controller constructor here too, if needed. /// - Create the Mode object of your choice. See m_desktop.h /// and m_serial.h for these mode classes. You pass /// your controller object into these mode constructors /// to create the mode. /// class BXEXPORT Controller { friend class Barry::Mode::Mode; friend class Barry::Mode::IpModem; friend class Barry::Mode::Serial; friend class Barry::Mode::JavaLoader; friend class Barry::Mode::JVMDebug; friend class Barry::Mode::RawChannel; public: /// Handheld mode type enum ModeType { Unspecified, //< default on start up (unused) Bypass, //< unsupported, unknown Desktop, //< desktop mode required for database //< operation JavaLoader, //< experimental JVMDebug, //< experimental UsbSerData, //< GPRS modem support over USB UsbSerCtrl, //< internally used behind the scenes RawChannel //< raw channel }; private: const std::auto_ptr m_priv; private: Controller(const Controller& rhs); // prevent copying void SetupUsb(const ProbeResult &device); protected: uint16_t SelectMode(ModeType mode); // returns mode socket uint16_t SelectMode(ModeType mode, const char *explicitModeName); // returns mode socket SocketHandle OpenSocket(uint16_t socket, const char *password = 0); PrivateControllerData* GetPrivate() { return m_priv.get(); } public: explicit Controller(const ProbeResult &device, int default_timeout = USBWRAP_DEFAULT_TIMEOUT); Controller(const ProbeResult &device, SocketRoutingQueue &queue, int default_timeout = USBWRAP_DEFAULT_TIMEOUT); ~Controller(); bool HasQueue() const; SocketRoutingQueue* GetQueue(); // FIXME - not really ideal to have // this exposed, but oh well const ProbeResult& GetProbeResult() const; }; } // namespace Barry #endif barry-0.18.5/src/r_command.cc0000644001161500056700000000517612242254476015322 0ustar cdfreycdfrey/// /// \file r_command.cc /// Internal implementation of CommandTable parser class /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "record.h" #include "record-internal.h" #include "data.h" #include #include using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // CommandTable class CommandTable::CommandTable() { } CommandTable::~CommandTable() { } const unsigned char* CommandTable::ParseField(const unsigned char *begin, const unsigned char *end) { // check if there is enough data for a header const unsigned char *headend = begin + sizeof(CommandTableField); if( headend > end ) return headend; const CommandTableField *field = (const CommandTableField *) begin; // advance and check size begin += COMMAND_FIELD_HEADER_SIZE + field->size; // size is byte if( begin > end ) // if begin==end, we are ok return begin; if( !field->size ) // if field has no size, something's up return begin; Command command; command.Code = field->code; command.Name.assign((const char *)field->name, field->size); Commands.push_back(command); return begin; } void CommandTable::Parse(const Data &data, size_t offset) { if( offset >= data.GetSize() ) return; const unsigned char *begin = data.GetData() + offset; const unsigned char *end = data.GetData() + data.GetSize(); while( begin < end ) begin = ParseField(begin, end); } void CommandTable::Clear() { Commands.clear(); } unsigned int CommandTable::GetCommand(const std::string &name) const { CommandArrayType::const_iterator b = Commands.begin(); for( ; b != Commands.end(); b++ ) if( b->Name == name ) return b->Code; return 0; } void CommandTable::Dump(std::ostream &os) const { CommandArrayType::const_iterator b = Commands.begin(); os << _("Command table:\n"); for( ; b != Commands.end(); b++ ) { os << _(" Command: ") << "0x" << setbase(16) << b->Code << " '" << b->Name << "'\n"; } } } // namespace Barry barry-0.18.5/src/packet.h0000644001161500056700000002242712242254476014472 0ustar cdfreycdfrey/// /// \file packet.h /// Low level protocol packet builder class. /// Has knowledge of specific protocol commands in order /// to hide protocol details behind an API. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_PACKET_H__ #define __BARRY_PACKET_H__ #include #include #include #include "protocol.h" #include "data.h" namespace Barry { class Data; } namespace Barry { // forward declarations class Parser; class Builder; class SocketZero; class Socket; class IConverter; namespace Mode { class Desktop; class JavaLoader; } class Packet { friend class SocketZero; friend class SocketBase; protected: Data &m_send; Data *m_receive; Data& GetSend() { return m_send; } Data& GetReceive() { return *m_receive; } public: Packet(Data &send, Data &receive) : m_send(send), m_receive(&receive) {} virtual ~Packet() {} // allow user to override the receive buffer for // optimization purposes, to reduce copies... be // careful with this, since this new Data object // must outlive any usage of it via this Packet class void SetNewReceive(Data &receive) { m_receive = &receive; } ////////////////////////////////// // common response analysis unsigned int Command() const; // throws Error if receive isn't big enough }; // // ZeroPacket class // /// Provides an API for building and analyzing socket-0 protocol packets. /// This class relies on 2 external objects: a send and receive Data buffer. /// /// Note that the receive buffer may be modified /// during a packet send, and this class provides API helpers /// to analyze the results. /// class ZeroPacket : public Packet { friend class Socket; public: ZeroPacket(Data &send, Data &receive); ~ZeroPacket(); ////////////////////////////////// // meta access ////////////////////////////////// // packet building void GetAttribute(unsigned int object, unsigned int attribute); void Echo(uint64_t us_ticks); void Reset(); ////////////////////////////////// // response analysis unsigned int ObjectID() const; unsigned int AttributeID() const; uint32_t ChallengeSeed() const; unsigned int RemainingTries() const; unsigned int SocketResponse() const; unsigned char SocketSequence() const; uint8_t CommandResponse() const; }; // // DBPacket class // /// Provides an API for building and analyzing raw DB protocol packets. /// This class relies on 3 external objects: a Mode::Desktop object, /// a send Data buffer, and a receive data buffer. Socket and /// connection details are retrieved on a readonly basis from the /// Mode::Desktop object, but both send and receive buffers can be /// modified. /// /// Note that the receive buffer may be modified /// during a packet send, and this DBPacket class provides API helpers /// to analyze the results. /// class DBPacket : public Packet { friend class Socket; private: Mode::Desktop &m_con; unsigned int m_last_dbop; // last database operation protected: public: DBPacket(Mode::Desktop &con, Data &send, Data &receive); ~DBPacket(); ////////////////////////////////// // meta access ////////////////////////////////// // packet building // commands that correspond to the DB operation // constants in protocol.h void ClearDatabase(unsigned int dbId); void GetDBDB(); void GetRecordStateTable(unsigned int dbId); void SetRecordFlags(unsigned int dbId, unsigned int stateTableIndex, uint8_t flag1); void DeleteRecordByIndex(unsigned int dbId, unsigned int stateTableIndex); void GetRecordByIndex(unsigned int dbId, unsigned int stateTableIndex); bool SetRecordByIndex(unsigned int dbId, unsigned int stateTableIndex, Builder &build, const IConverter *ic); void GetRecords(unsigned int dbId); bool AddRecord(unsigned int dbId, Builder &build, const IConverter *ic); ////////////////////////////////// // response analysis // DB command response functions unsigned int ReturnCode() const; // throws FIXME if packet doesn't support it unsigned int DBOperation() const; // throws Error on size trouble bool Parse(Parser &parser, const std::string &dbname, const IConverter *ic); // switches based on last m_send command bool ParseMeta(DBData &data); // response parsers }; // // JLPacket class // /// Provides an API for building and analyzing raw Javaloader protocol packets. /// This class relies on 3 external objects: /// a command send Data buffer (which can be fairly small), a data /// or argument send Data buffer, and a receive data buffer. Socket and /// connection details are retrieved on a readonly basis from the /// Mode::JavaLoader object, but all buffers can be modified. /// /// Note that the receive buffer may be modified /// during a packet send, and this JLPacket class provides API helpers /// to analyze the results. /// class JLPacket : public Packet { friend class SocketBase; private: Data &m_cmd, &m_data; int m_last_set_size; public: JLPacket(Data &cmd, Data &send, Data &receive); ~JLPacket(); ////////////////////////////////// // meta access bool HasData() const { return m_last_set_size == 2; } Data& GetReceive() { return *m_receive; } ////////////////////////////////// // packet building // commands that correspond to the operation // constants in protocol.h // returns 1 or 2 depending on whether cmd or cmd+send are available int SimpleCmd(uint8_t cmd, uint8_t unknown = 0, uint16_t size = 0); int SimpleData(const void *data, uint16_t size); int BigEndianData(uint16_t value); int BigEndianData(uint32_t value); int Hello() { return SimpleCmd(SB_COMMAND_JL_HELLO); } int Goodbye() { return SimpleCmd(SB_COMMAND_JL_GOODBYE); } int SetUnknown1(); int SetCodFilename(const std::string &filename); int SetCodSize(off_t size); int SetTime(time_t when); int GetScreenshot(); int GetData() { return SimpleCmd(SB_COMMAND_JL_SEND_DATA); } int DeviceInfo() { return SimpleCmd(SB_COMMAND_JL_DEVICE_INFO); } int OsMetrics() { return SimpleCmd(SB_COMMAND_JL_OS_METRICS); } int BootromMetrics() { return SimpleCmd(SB_COMMAND_JL_BOOTROM_METRICS); } int GetDirectory() { return SimpleCmd(SB_COMMAND_JL_GET_DIRECTORY); } int GetSubDir(uint16_t id); int GetDirEntry(uint8_t entry_cmd, uint16_t id); int Erase(uint16_t cmd, uint16_t id); int GetEventlog() { return SimpleCmd(SB_COMMAND_JL_GET_LOG); } int GetEventlogEntry(uint16_t entry_num); int ClearEventlog() { return SimpleCmd(SB_COMMAND_JL_CLEAR_LOG); } int SaveModule(uint16_t id); int PutData(const void *data, uint16_t size); int WipeApps() { return SimpleCmd(SB_COMMAND_JL_WIPE_APPS); } int WipeFs() { return SimpleCmd(SB_COMMAND_JL_WIPE_FS); } int LogStackTraces() { return SimpleCmd(SB_COMMAND_JL_LOG_STRACES); } int ResetToFactory() { return SimpleCmd(SB_COMMAND_JL_RESET_FACTORY); } ////////////////////////////////// // response analysis unsigned int Size(); }; // // JVMPacket class // /// Provides an API for building and analyzing raw JavaDebug protocol packets. /// This class relies on 3 external objects: /// a command send Data buffer (which can be fairly small), a data /// or argument send Data buffer, and a receive data buffer. Socket and /// connection details are retrieved on a readonly basis from the /// Mode::JavaDebug object, but all buffers can be modified. /// /// Note that the receive buffer may be modified /// during a packet send, and this JVMPacket class provides API helpers /// to analyze the results. /// class JVMPacket : public Packet { friend class SocketBase; private: Data &m_cmd; public: JVMPacket(Data &cmd, Data &receive); ~JVMPacket(); ////////////////////////////////// // meta access Data& GetReceive() { return *m_receive; } ////////////////////////////////// // packet building // commands that correspond to the operation // constants in protocol.h // returns 1 or 2 depending on whether cmd or cmd+send are available void SimpleCmd(uint8_t cmd); void ComplexCmd(uint8_t cmd, const void *param, uint16_t size = 0); void Unknown01(); // Command 0x53 void Unknown02(); // Command 0x01 void Unknown03(); // Command 0x6f void Unknown04(); // Command 0x8a void Unknown05(); // Command 0x90 void Unknown06(); // Command 0x44 void Unknown07(); // Command 0x45 void Unknown08(); // Command 0x54 void Unknown09(); // Command 0x33 void Unknown10(); // Command 0x46 void Unknown11(uint32_t id); // Command 0x0e void Unknown12(uint32_t id); // Command 0x50 void Unknown13(uint32_t id); // Command 0x0d void Unknown14(uint32_t id); // Command 0x85 void Unknown15(uint32_t id); // Command 0x84 void GetModulesList(uint32_t id); // Command 0x8d void GetThreadsList(); // Command 0x08 void GetConsoleMessage(); void Go(); // Command mal formed :) void Stop(); // Command 0x02 void GetStatus(); // Command 0x06 ////////////////////////////////// // response analysis unsigned int Size(); }; } // namespace Barry #endif barry-0.18.5/src/m_raw_channel.h0000644001161500056700000001163212242254476016014 0ustar cdfreycdfrey/// /// \file m_raw_channel.h /// Mode class for a raw channel /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Portions Copyright (C) 2010 RealVNC Ltd. 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_M_RAW_CHANNEL_H__ #define __BARRY_M_RAW_CHANNEL_H__ #include "dll.h" #include "m_mode_base.h" #include "socket.h" #include "data.h" #include #include namespace Barry { class semaphore; namespace Mode { // Forward declaration of internal classes class RawChannelSocketHandler; class RawChannelZeroSocketHandler; // Callback from the raw channel. class BXEXPORT RawChannelDataCallback { public: virtual ~RawChannelDataCallback() {} // Called when data has been received on the channel virtual void DataReceived(Data &data) = 0; // Called when the channel has an error virtual void ChannelError(std::string msg) = 0; // Called when the channel has been asked to close by the other side virtual void ChannelClose() = 0; }; // // Raw channel class // /// The main class for creating a raw channel session. /// /// To use this class, use the following steps: /// /// - Implement RawChannelDataCallback /// - Create a Controller object (see Controller class for more details) /// - Create this Mode::RawChannel object, passing in the Controller /// object during construction /// - Call Open() to open the channel and finish constructing. /// - Call GetData() to fetch data /// - Call SendData() to send data /// class BXEXPORT RawChannel : public Mode { friend class RawChannelSocketHandler; friend class RawChannelZeroSocketHandler; RawChannelDataCallback *m_callback; unsigned char *m_send_buffer; bool m_zero_registered; std::string *m_pending_error; Data m_receive_data; protected: void CheckQueueAvailable(); void InitBuffer(); void SetPendingError(const char *msg); void UnregisterZeroSocketInterest(); // Used to validate a packet is a valid channel data packet void ValidateDataPacket(Data &data); // Not intended for use by users of this class. // Used for handling zero-socket packets. void HandleReceivedZeroPacket(Data &data); // Not intended for use by users of this class. // Instead data received will come in via the // RawChannelDataCallback::DataReceived callback // or using Receive(). void HandleReceivedData(Data &data); // Not intended for use by users of this class. void HandleError(Barry::Error &data); // Not intended for use by users of this class. // This method is called by the internals of // Barry when setting up a connection. void OnOpen(); public: // Creates a raw channel in non-callback mode. // This requires all data to be sent and received // via calls to Send and Receive. // As there are no notifications of data being // available to send or receive, this is only recommended // for use with synchronous protocols over the channel. // // Will throw a Barry::Error if the provided controller // doesn't have a routing queue set. RawChannel(Controller &con); // Creates a raw channel in callback mode. // This requires all data to be sent via calls to Send, but // the Receive method must never be called. // Instead the DataReceive // // Will throw a Barry::Error if the provided controller // doesn't have a routing queue set. RawChannel(Controller &con, RawChannelDataCallback &callback); virtual ~RawChannel(); ////////////////////////////////// // Raw channel mode specific methods // Send some data on the raw channel. // Will throw a Barry::Error if data is longer than // MaximumPacketContentsSize or a Usb::Error if there // is an underlying USB error. // // If using a raw channel in callback mode then care must be // taken to ensure another thread is running during any calls // to Send. See the comment in the constructor of RawChannel // for further information. void Send(Data &data, int timeout = -1); // Receive some data on the raw channel. // Will throw a Barry::Error if a disconnect occurs // or a Usb::Error if there is an underlying USB error // or a Usb::Timeout if the receive times out. // // Only valid to call this if the raw channel was created in non-callback // mode. If this is called when the raw channel was created with a // callback then a std::logic_error will be thrown. void Receive(Data &data, int timeout = -1); // Returns the maximum quantity of data which // can be sent size_t MaximumSendSize(); }; }} // namespace Barry::Mode #endif barry-0.18.5/src/r_folder.cc0000644001161500056700000001452212242254476015152 0ustar cdfreycdfrey/// /// \file r_folder.cc /// Record parsing class for the folders database. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2007, Brian Edginton 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "r_folder.h" #include "record-internal.h" #include "protostructs.h" #include "data.h" #include "time.h" #include "debug.h" #include "iconv.h" #include #include #include #include "ios_state.h" using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // Folder Class, static members // // Note! These functions currently only pass the same values through. // In actuality, these are technically two different values: // one on the raw protocol side, and the other part of the // guaranteed Barry API. If the Blackberry ever changes the // meanings for these codes, do the translation here. // Folder::FolderType Folder::TypeProto2Rec(uint8_t t) { return (FolderType)t; } uint8_t Folder::TypeRec2Proto(FolderType t) { return t; } /////////////////////////////////////////////////////////////////////////////// // Folder Class // Folder Field Codes #define FFC_NUMBER 0x0a #define FFC_LEVEL 0x0b #define FFC_NAME 0x0c #define FFC_ADDRESS1 0x0d #define FFC_ADDRESS2 0x0e #define FFC_TYPE 0x0f #define FFC_END 0xffff #define INVALID -1 #define SEPARATOR 0x2f #define ROOT_SEPARATOR 0x3a static FieldLink FolderFieldLinks[] = { { FFC_NAME, N_("FolderName"), 0, 0, &Folder::Name, 0, 0, 0, 0, true }, { FFC_END, N_("End of List"), 0, 0, 0, 0, 0, 0, 0, false }, }; Folder::Folder() { Clear(); } Folder::~Folder() { } const unsigned char* Folder::ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { const CommonField *field = (const CommonField *) begin; // advance and check size begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size); if( begin > end ) // if begin==end, we are ok return begin; if( !btohs(field->size) ) // if field has no size, something's up return begin; // cycle through the type table for( FieldLink *b = FolderFieldLinks; b->type != FFC_END; b++ ) { if( b->type == field->type ) { if( b->strMember ) { std::string &s = this->*(b->strMember); s = ParseFieldString(field); if( b->iconvNeeded && ic ) s = ic->FromBB(s); return begin; // done! } else if( b->timeMember && btohs(field->size) == 4 ) { TimeT &t = this->*(b->timeMember); t.Time= min2time(field->u.min1900); return begin; } } } // handle special cases switch( field->type ) { case FFC_TYPE: Type = TypeProto2Rec(field->u.raw[0]); return begin; case FFC_NUMBER: Number = field->u.raw[0]; // two's complement return begin; case FFC_LEVEL: Level = field->u.raw[0]; return begin; } // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; uf.data.assign((const char*)field->u.raw, btohs(field->size)); Unknowns.push_back(uf); // return new pointer for next field return begin; } void Folder::ParseHeader(const Data &data, size_t &offset) { // no header in Folder records } void Folder::ParseFields(const Data &data, size_t &offset, const IConverter *ic) { const unsigned char *finish = ParseCommonFields(*this, data.GetData() + offset, data.GetData() + data.GetSize(), ic); offset += finish - (data.GetData() + offset); } void Folder::Validate() const { } void Folder::BuildHeader(Data &data, size_t &offset) const { // not yet implemented } void Folder::BuildFields(Data &data, size_t &offset, const IConverter *ic) const { // not yet implemented } void Folder::Clear() { RecType = GetDefaultRecType(); RecordId = 0; Name.clear(); Number = 0; Level = 0; Type = FolderSubtree; Unknowns.clear(); } const FieldHandle::ListT& Folder::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; #undef CONTAINER_OBJECT_NAME #define CONTAINER_OBJECT_NAME fhv #undef RECORD_CLASS_NAME #define RECORD_CLASS_NAME Folder FHP(RecType, _("Record Type Code")); FHP(RecordId, _("Unique Record ID")); FHD(Name, _("Folder Name"), FFC_NAME, true); FHD(Number, _("Order Number"), FFC_NUMBER, false); FHD(Level, _("Folder Level"), FFC_LEVEL, false); FHE(ft, FolderType, Type, _("Folder Type")); FHE_CONST(ft, FolderSubtree, _("Subtree")); FHE_CONST(ft, FolderDeleted, _("Deleted")); FHE_CONST(ft, FolderInbox, _("Inbox")); FHE_CONST(ft, FolderOutbox, _("Outbox")); FHE_CONST(ft, FolderSent, _("Sent")); FHE_CONST(ft, FolderOther, _("Other")); FHE_CONST(ft, FolderDraft, _("Draft")); // Not yet implemented // FHE(fst, FolderStatusType, ..., _("Folder Status")); // FHE_CONST(fst, FolderOrphan, _("Orphan")); // FHE_CONST(fst, FolderUnfiled, _("Unfiled")); // FHE_CONST(fst, FolderFiled, _("Filed")); FHP(Unknowns, _("Unknown Fields")); return fhv; } std::string Folder::GetDescription() const { ostringstream oss; oss << Name << " (" << Level << ")"; return oss.str(); } void Folder::Dump(std::ostream &os) const { ios_format_state state(os); static const char *FolderTypeString[] = { N_("Subtree"), N_("Deleted"), N_("Inbox"), N_("Outbox"), N_("Sent"), N_("Other") }; // static const char *FolderStatusString[] = { "Orphan", "Unfiled", "Filed" }; os << _("Folder Records\n\n"); os << _("Folder Name: ") << Name << "\n"; os << _("Folder Type: "); if( Type < FolderDraft ) os << gettext( FolderTypeString[Type] ) << "\n"; else if( Type == FolderDraft ) os << _("Draft\n"); else os << _("Unknown") << " (" << std::hex << Type << ")\n"; os << _("Folder Number: ") << std::dec << Number << "\n"; os << _("Folder Level: ") << std::dec << Level << "\n"; os << "\n"; os << Unknowns; os << "\n\n"; } } // namespace Barry barry-0.18.5/src/r_recur_base.h0000644001161500056700000000660012242254476015651 0ustar cdfreycdfrey/// /// \file r_recur_base.h /// Base class for recurring calendar event data. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_RECUR_BASE_H__ #define __BARRY_RECORD_RECUR_BASE_H__ #include "dll.h" #include "record.h" #include #include #include #include #include namespace Barry { // forward declarations class IConverter; // // NOTE: All classes here must be container-safe! Perhaps add sorting // operators in the future. // class BXEXPORT RecurBase { public: /// /// Recurring data /// /// Note: interval can be used on all of these recurring types to /// make it happen "every other time" or more, etc. /// enum RecurringCodeType { Day = 1, //< eg. every day //< set: nothing MonthByDate = 3, //< eg. every month on the 12th //< set: DayOfMonth MonthByDay = 4, //< eg. every month on 3rd Wed //< set: DayOfWeek and WeekOfMonth YearByDate = 5, //< eg. every year on March 5 //< set: DayOfMonth and MonthOfYear YearByDay = 6, //< eg. every year on 3rd Wed of Jan //< set: DayOfWeek, WeekOfMonth, and //< MonthOfYear Week = 12 //< eg. every week on Mon and Fri //< set: WeekDays }; bool Recurring; RecurringCodeType RecurringType; uint16_t Interval; // must be >= 1 Barry::TimeT RecurringEndTime; // only pertains if Recurring is true // sets the date and time when // recurrence of this appointment // should no longer occur // If a perpetual appointment, this // is 0xFFFFFFFF in the low level data // Instead, set the following flag. bool Perpetual; // if true, this will always recur uint16_t // recurring details, depending on type DayOfWeek, // 0-6 WeekOfMonth, // 1-5 DayOfMonth, // 1-31 MonthOfYear; // 1-12 uint8_t WeekDays; // bitmask, bit 0 = sunday // FIXME - put these somewhere usable by both C and C++ #define CAL_WD_SUN 0x01 #define CAL_WD_MON 0x02 #define CAL_WD_TUE 0x04 #define CAL_WD_WED 0x08 #define CAL_WD_THU 0x10 #define CAL_WD_FRI 0x20 #define CAL_WD_SAT 0x40 protected: void ParseRecurrenceData(const void *data); static unsigned char WeekDayProto2Rec(uint8_t raw_field); static uint8_t WeekDayRec2Proto(unsigned char weekdays); protected: RecurBase(); virtual ~RecurBase(); public: void Validate() const; // return true if parse, false if not (for example, if type not // recognized) bool ParseField(uint8_t type, const unsigned char *data, size_t size, const IConverter *ic = 0); void BuildRecurrenceData(time_t StartTime, void *data) const; uint8_t RecurringFieldType() const; void Clear(); void Dump(std::ostream &os) const; }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const RecurBase &msg) { msg.Dump(os); return os; } } // namespace Barry #endif barry-0.18.5/src/j_manager.h0000644001161500056700000000245212242254476015142 0ustar cdfreycdfrey/// /// \file j_manager.h /// Application management classes /// /* Copyright (C) 2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYJDWP_MANAGER_H__ #define __BARRYJDWP_MANAGER_H__ #include "dll.h" #include "dp_codinfo.h" #include #include #include namespace Barry { namespace JDWP { class BXEXPORT JDWAppInfo { private: protected: public: uint32_t uniqueId; std::string appName; Barry::JDG::ClassList classList; void Load(Barry::JDG::CodInfo &info); }; class BXEXPORT JDWAppList : public std::map { public: typedef std::map base_type; typedef base_type::iterator iterator; typedef base_type::const_iterator const_iterator; }; }} // namespace Barry::JDWP #endif barry-0.18.5/src/pppfilter.cc0000644001161500056700000000675512242254476015374 0ustar cdfreycdfrey/// /// \file pppfilter.cc /// Data filter class, to morph PPP data into something that /// the Blackberry / Rogers / ISP can handle. /// This logic is based partly on XmBlackBerry's /// gprs_protocol_fix.c program. /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "pppfilter.h" #include namespace Barry { ////////////////////////////////////////////////////////////////////////////// // PppFilter class PppFilter::PppFilter() : m_ppp_mode(false) , m_last(0x7e) { } // // Filter // /// Copy PPP data from src to dest, creating needed space in dest, /// and inserting missing 0x7e characters wherever they are detected. /// Starts writing at the start of the dest buffer + destoffset. /// void PppFilter::Filter(Data &dest, const Data &src, unsigned int destoffset) { const unsigned char *b = src.GetData(), *e = src.GetData() + src.GetSize(); size_t needed = src.GetSize() / 2 * 3 + 4 + destoffset; // worst case unsigned char *buf = dest.GetBuffer(needed) + destoffset; unsigned char *put = buf; while( b != e ) { // if last character was 0x7e, then next one must be, // or else we insert it ourselves if( m_last == 0x7e ) { m_last = 0; if( *b != 0x7e ) *put++ = 0x7e; else *put++ = *b++; } // copy all non-0x7e chars verbatim while( b != e && *b != 0x7e ) { *put++ = *b++; } if( b != e ) { // if b!=e then *b == 0x7e and must keep going *put++ = *b++; m_last = 0x7e; } } dest.ReleaseBuffer(put - buf + destoffset); } // // Write // /// If PPP mode has not been detected, just return the data buffer. /// If in PPP mode, then filter data into internal write buffer, /// inserting any missing 0x7e characters and return reference /// to internal write buffer. /// const Data& PppFilter::Write(const Data &data) { if( data.GetSize() == 0 ) return data; // nothing to do const unsigned char *b = data.GetData(); if( !m_ppp_mode ) { if( *b == 0x7e ) { m_ppp_mode = true; // fall through } else { // not in ppp mode yet, so just pass the buffer // straight back to the caller return data; } } Filter(m_writeBuf, data, 0); return m_writeBuf; } // // Write (with prepend) // /// Same as Write(data), but makes sure that prepend bytes are available /// at the beginning of the returned buffer. /// If not in PPP mode, the extra bytes are still provided. /// Data& PppFilter::Write(const Data &data, unsigned int prepend) { const unsigned char *b = data.GetData(), *e = data.GetData() + data.GetSize(); if( !m_ppp_mode ) { if( b != e && *b == 0x7e ) { m_ppp_mode = true; // fall through } else { // make space, copy, return unsigned int size = data.GetSize() + prepend; unsigned char *buf = m_writeBuf.GetBuffer(size); memcpy(&buf[prepend], data.GetData(), data.GetSize()); m_writeBuf.ReleaseBuffer(size); return m_writeBuf; } } Filter(m_writeBuf, data, prepend); return m_writeBuf; } } // namespace Barry barry-0.18.5/src/j_server.cc0000644001161500056700000004021612242254476015174 0ustar cdfreycdfrey/// /// \file j_server.cc /// Server protocol implementation /// /* Copyright (C) 2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "j_server.h" #include "protocol.h" #include "data.h" #include "endian.h" #include "debug.h" #include "j_message.h" #include "protostructs.h" #include "record-internal.h" #include "error.h" #include #include #include #include #include #include #include #include #include #include #include using namespace std; namespace Barry { namespace JDWP { static void * acceptThread(Barry::Thread::CallbackData *data); JDWServer::JDWServer(Barry::Mode::JVMDebug &device, const char *address, int port) : jvmdebug(&device) , acceptfd(-1) , sockfd(-1) , address(address) , port(port) , loop(false) , targetrunning(false) , printConsoleMessage(0) { SearchDebugFile(debugFileList); } JDWServer::~JDWServer() { Stop(); } void JDWServer::SetPasswordDevice(string password) { this->password = password; } void JDWServer::SetConsoleCallback(ConsoleCallbackType callback) { printConsoleMessage = callback; } static const char* h_strerror(int code) { // Codes and messages taken from the Linux gethostbyname(3) manpage switch( code ) { case HOST_NOT_FOUND: return _("HOST_NOT_FOUND: The specified host is unknown"); case NO_ADDRESS: return _("NO_ADDRESS: The requested name is valid but does not have an IP address"); case NO_RECOVERY: return _("NO_RECOVERY: A non-recoverable name server error occurred"); case TRY_AGAIN: return _("TRY_AGAIN: A temporary error occurred on an authoritative name server. Try again later."); default: return _("Unknown network error code"); } } bool JDWServer::Start() { int rc; struct hostent *hp; struct sockaddr_in sad; memset((char *) &sad, '\0', sizeof(struct sockaddr_in)); if (!address.size()) sad.sin_addr.s_addr = INADDR_ANY; else { sad.sin_addr.s_addr = inet_addr(address.c_str()); if (sad.sin_addr.s_addr == INADDR_NONE) { hp = gethostbyname(address.c_str()); if (hp == NULL) { std::ostringstream oss; oss << "JDWServer::Start: " << h_errno << h_strerror(h_errno); throw Barry::Error(oss.str()); } memcpy((char*) &sad.sin_addr, (char*) hp->h_addr, (size_t) hp->h_length); } } sad.sin_family = AF_INET; sad.sin_port = htons((short) (port & 0xFFFF)); // Open socket sockfd = socket(sad.sin_family, SOCK_STREAM, 0); if (sockfd < 0) { throw Barry::ErrnoError(_("JDWServer::Start: Cannot open socket."), errno); } // Bind rc = bind(sockfd, (struct sockaddr *) &sad, sizeof(sad)); if (rc < 0) { int code = errno; close(sockfd); sockfd = -1; throw Barry::ErrnoError(_("JDWServer::Start: Cannot bind socket"), code); } // Listen if (listen(sockfd, SOMAXCONN) < 0) { int code = errno; close(sockfd); sockfd = -1; throw Barry::ErrnoError(_("JDWServer::Start: Cannot listen on socket"), code); } handler.reset(new Thread(sockfd, acceptThread, (void*) this)); return true; } static void * acceptThread(Barry::Thread::CallbackData *data) { JDWServer *s = (JDWServer *) data->userdata; while( !data->stopflag ) { if( s->AcceptConnection() && s->AttachToDevice() && s->InitVisibleClassList() && s->Hello() ) { s->Run(data->stopflag); s->DetachFromDevice(); } } return NULL; } // Returns true if a new connection was accepted and established bool JDWServer::AcceptConnection() { struct sockaddr_in addr; struct sockaddr *sa = (struct sockaddr*) &addr; socklen_t addrlen = sizeof(addr); acceptfd = accept(sockfd, sa, &addrlen); if( acceptfd < 0 ) return false; fcntl(acceptfd, F_SETFL, O_NONBLOCK); return true; } bool JDWServer::AttachToDevice() { targetrunning = false; jvmdebug->Open(password.c_str()); jvmdebug->Attach(); jvmdebug->Unknown01(); jvmdebug->Unknown02(); jvmdebug->Unknown03(); jvmdebug->Unknown04(); jvmdebug->Unknown05(); jvmdebug->GetModulesList(modulesList); dout(modulesList); // Check debug info for each modules JVMModulesList::const_iterator b = modulesList.begin(); for ( ; b != modulesList.end(); b++) { JDG::CodInfo codInfo; const JVMModulesEntry &entry = *b; bool ret = LoadDebugInfo(debugFileList, entry.UniqueID, entry.Name, codInfo); if (ret == true) { appList[entry.UniqueID].Load(codInfo); } else { dout(_("No debug information found for: ") << entry.Name); dout("' (" << hex << setfill('0') << setw(8) << entry.UniqueID << ")." << endl) } } return true; } void JDWServer::DetachFromDevice() { jvmdebug->Detach(); jvmdebug->Close(); } #define JDWP_HELLO_STRING "JDWP-Handshake" bool JDWServer::Hello() { bool ret; Barry::Data response; const size_t len = strlen(JDWP_HELLO_STRING); JDWMessage msg(acceptfd); do { ret = msg.Receive(response); } while (!ret); size_t size = response.GetSize(); char *str = (char *) response.GetBuffer(); if (size != len) return false; if (!strncmp(str, JDWP_HELLO_STRING, len)) { Data command(JDWP_HELLO_STRING, len); msg.Send(command); return true; } return false; } void JDWServer::Run(volatile bool &stopflag) { string str; JDWMessage msg(acceptfd); Barry::Data command; MAKE_JDWPPACKET(rpack, command); loop = true; while( loop && !stopflag ) { if (targetrunning) { // Read JDWP message from device int value = jvmdebug->GetConsoleMessage(str); if (value < 0) { bool ret; int status; ret = jvmdebug->GetStatus(status); while (!ret) { // Read JDB message from host msg.Receive(command); if (command.GetSize() > 0) { // Convert to packet rpack = (const Barry::Protocol::JDWP::Packet *) command.GetData(); if (command.GetSize() != be_btohl(rpack->length)) { dout(_("Packet size error !!!") << endl); // TODO : add throw exception continue; } CommandsetProcess(command); break; } else ret = jvmdebug->WaitStatus(status); } } else { if (printConsoleMessage != NULL) printConsoleMessage(str); } } else { // Read JDB message from host msg.Receive(command); if (command.GetSize() > 0) { // Convert to packet rpack = (const Barry::Protocol::JDWP::Packet *) command.GetData(); if (command.GetSize() != be_btohl(rpack->length)) { dout(_("Packet size error !!!") << endl); // TODO : add throw exception continue; } CommandsetProcess(command); } usleep(50); } } } bool JDWServer::Stop() { if( handler.get() ) { handler->StopFlag(); handler.reset(); } if( sockfd >= 0 ) { close(sockfd); sockfd = -1; } if( acceptfd >= 0 ) { close(acceptfd); acceptfd = -1; } return true; } bool JDWServer::InitVisibleClassList() { int index; // Skip the cell '0' // it's very ugly, but I want use an index started at '1' inside of '0' // JDB works from '1' :( JDG::ClassEntry e; visibleClassList.push_back(e); // Count and index the class (start to '1') index = 1; JDWAppList::iterator it; for (it = appList.begin(); it != appList.end(); it++) { JDWAppInfo &appInfo = it->second; JDG::ClassList &list = appInfo.classList; JDG::ClassList::iterator b; for (b = list.begin(); b != list.end(); b++) { // FIXME // I don't from class field, we have to filter the class view by JDB // if ((b->type != 0x824) && (b->type != 0x64)) { if (b->id == 0xffffffff) { b->index = -1; continue; } b->index = index; visibleClassList.push_back(*b); index++; } } visibleClassList.CreateDefaultEntries(); return true; } void JDWServer::CommandsetProcess(Data &cmd) { MAKE_JDWPPACKET(rpack, cmd); switch (rpack->u.command.commandset) { case JDWP_CMDSET_VIRTUALMACHINE: CommandsetVirtualMachineProcess(cmd); break; case JDWP_CMDSET_REFERECENTYPE: break; case JDWP_CMDSET_CLASSTYPE: break; case JDWP_CMDSET_ARRAYTYPE: break; case JDWP_CMDSET_INTERFACETYPE: break; case JDWP_CMDSET_METHOD: break; case JDWP_CMDSET_FIELD: break; case JDWP_CMDSET_OBJECTREFERENCE: break; case JDWP_CMDSET_STRINGREFERENCE: break; case JDWP_CMDSET_THREADREFERENCE: break; case JDWP_CMDSET_THREADGROUPREFERENCE: break; case JDWP_CMDSET_ARRAYREFERENCE: break; case JDWP_CMDSET_CLASSLOADERREFERENCE: break; case JDWP_CMDSET_EVENTREQUEST: CommandsetEventRequestProcess(cmd); break; case JDWP_CMDSET_STACKFRAME: break; case JDWP_CMDSET_CLASSOBJECTREFERENCE: break; case JDWP_CMDSET_EVENT: break; default: // TODO : add exception (or alert) dout(_("Commandset unknown !!!") << endl); } } void JDWServer::CommandsetVirtualMachineProcess(Data &cmd) { MAKE_JDWPPACKET(rpack, cmd); switch (rpack->u.command.command) { case JDWP_CMD_VERSION: CommandVersion(cmd); break; case JDWP_CMD_ALLCLASSES: CommandAllClasses(cmd); break; case JDWP_CMD_ALLTHREADS: CommandAllThreads(cmd); break; case JDWP_CMD_DISPOSE: loop = false; targetrunning = false; close(acceptfd); acceptfd = -1; break; case JDWP_CMD_IDSIZES: CommandIdSizes(cmd); break; case JDWP_CMD_SUSPEND: CommandSuspend(cmd); targetrunning = false; break; case JDWP_CMD_RESUME: CommandResume(cmd); targetrunning = true; break; case JDWP_CMD_CLASSPATHS: CommandClassPaths(cmd); break; } } void JDWServer::CommandsetEventRequestProcess(Data &cmd) { MAKE_JDWPPACKET(rpack, cmd); switch (rpack->u.command.command) { case JDWP_CMD_SET: CommandSet(cmd); break; } } void JDWServer::CommandVersion(Data &cmd) { JDWMessage msg(acceptfd); // Build packet data Data response; size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE; AddJDWString(response, offset, string("RIM JVM")); AddJDWInt(response, offset, be_htobl(1)); AddJDWInt(response, offset, be_htobl(4)); AddJDWString(response, offset, string("1.4")); AddJDWString(response, offset, string("RIM JVM")); response.ReleaseBuffer(offset); size_t total_size = response.GetSize(); // Fill in the header values MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size)); Barry::Protocol::JDWP::Packet &packet = *cpack; MAKE_JDWPPACKET(rpack, cmd); packet.length = be_htobl(total_size); packet.id = rpack->id; packet.flags = 0x80; packet.u.response.errorcode = be_htobs(0); response.ReleaseBuffer(total_size); msg.Send(response); } void JDWServer::CommandAllClasses(Data &cmd) { size_t i; int size; JDWMessage msg(acceptfd); // Build packet data Data response; size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE; // Size of known class list size = visibleClassList.size() - 1; AddJDWInt(response, offset, be_htobl(size)); // Then, write the list of known class for (i=1; i(),'.'), '/'); AddJDWByte(response, offset, 0x01); AddJDWInt(response, offset, i); // Should be equal to visibleClassList[i].index AddJDWString(response, offset, str); AddJDWInt(response, offset, be_htobl(0x04)); } response.ReleaseBuffer(offset); size_t total_size = response.GetSize(); // Fill in the header values MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size)); Barry::Protocol::JDWP::Packet &packet = *cpack; MAKE_JDWPPACKET(rpack, cmd); packet.length = be_htobl(total_size); packet.id = rpack->id; packet.flags = 0x80; packet.u.response.errorcode = be_htobs(0); response.ReleaseBuffer(total_size); msg.Send(response); } void JDWServer::CommandAllThreads(Data &cmd) { JDWMessage msg(acceptfd); // Get threads list from device JVMThreadsList list; jvmdebug->GetThreadsList(list); dout(list); // Build packet data Data response; size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE; // Indicate the number of element AddJDWInt(response, offset, be_htobl(list.size())); // Send all threads ID JVMThreadsList::const_iterator b = list.begin(); for( ; b != list.end(); b++ ) { const JVMThreadsEntry &entry = *b; AddJDWInt(response, offset, be_htobl(entry.Id)); } response.ReleaseBuffer(offset); size_t total_size = response.GetSize(); // Fill in the header values MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size)); Barry::Protocol::JDWP::Packet &packet = *cpack; MAKE_JDWPPACKET(rpack, cmd); packet.length = be_htobl(total_size); packet.id = rpack->id; packet.flags = 0x80; packet.u.response.errorcode = be_htobs(0); response.ReleaseBuffer(total_size); msg.Send(response); } void JDWServer::CommandIdSizes(Data &cmd) { JDWMessage msg(acceptfd); MAKE_JDWPPACKET(rpack, cmd); size_t size; Barry::Protocol::JDWP::Packet packet; size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE + JDWP_PACKETVIRTUALMACHINEIDSIZES_DATA_SIZE; packet.length = be_htobl(size); packet.id = rpack->id; packet.flags = 0x80; packet.u.response.errorcode = be_htobs(0); packet.u.response.u.virtualMachine.u.IDSizes.fieldIDSize = be_htobl(0x04); packet.u.response.u.virtualMachine.u.IDSizes.methodIDSize = be_htobl(0x04); packet.u.response.u.virtualMachine.u.IDSizes.objectIDSize = be_htobl(0x04); packet.u.response.u.virtualMachine.u.IDSizes.referenceTypeIDSize = be_htobl(0x04); packet.u.response.u.virtualMachine.u.IDSizes.frameIDSize = be_htobl(0x04); Data response(&packet, size); msg.Send(response); } void JDWServer::CommandSuspend(Data &cmd) { JDWMessage msg(acceptfd); // Suspend device jvmdebug->Stop(); // Notify debugger MAKE_JDWPPACKET(rpack, cmd); size_t size; Barry::Protocol::JDWP::Packet packet; size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE; packet.length = be_htobl(size); packet.id = rpack->id; packet.flags = 0x80; packet.u.response.errorcode = be_htobs(0); Data response(&packet, size); msg.Send(response); } void JDWServer::CommandResume(Data &cmd) { JDWMessage msg(acceptfd); // Resume device jvmdebug->Unknown06(); jvmdebug->Unknown07(); jvmdebug->Unknown08(); jvmdebug->Unknown09(); jvmdebug->Unknown10(); jvmdebug->Go(); // Notify debugger MAKE_JDWPPACKET(rpack, cmd); size_t size; Barry::Protocol::JDWP::Packet packet; size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE; packet.length = be_htobl(size); packet.id = rpack->id; packet.flags = 0x80; packet.u.response.errorcode = be_htobs(0); Data response(&packet, size); msg.Send(response); } void JDWServer::CommandClassPaths(Data &cmd) { JDWMessage msg(acceptfd); // Build packet data Data response; size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE; AddJDWString(response, offset, string("")); AddJDWInt(response, offset, be_htobl(0)); AddJDWInt(response, offset, be_htobl(0)); response.ReleaseBuffer(offset); size_t total_size = response.GetSize(); // Fill in the header values MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size)); Barry::Protocol::JDWP::Packet &packet = *cpack; MAKE_JDWPPACKET(rpack, cmd); packet.length = be_htobl(total_size); packet.id = rpack->id; packet.flags = 0x80; packet.u.response.errorcode = be_htobs(0); response.ReleaseBuffer(total_size); msg.Send(response); } void JDWServer::CommandSet(Data &cmd) { static int value = 2; JDWMessage msg(acceptfd); MAKE_JDWPPACKET(rpack, cmd); size_t size; Barry::Protocol::JDWP::Packet packet; size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE + sizeof(uint32_t); packet.length = be_htobl(size); packet.id = rpack->id; packet.flags = 0x80; packet.u.response.errorcode = be_htobs(0); packet.u.response.u.value = be_htobl(value); Data response(&packet, size); msg.Send(response); value++; } }} // namespace Barry::JDWP barry-0.18.5/src/debug.h0000644001161500056700000000442212242254476014304 0ustar cdfreycdfrey/* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include // debugging only #include #include "common.h" #include "log.h" #ifndef __BARRY_DEBUG_H__ // only protect the non-macro portion, in order #define __BARRY_DEBUG_H__ // to allow re-inclusion of debug.h with // different __DEBUG_MODE__ settings namespace Barry { extern bool __data_dump_mode__; extern std::ostream *LogStream; } #endif // __BARRY_DEBUG_H__ // data dump output - controlled by command line -v switch #define ddout(x) if(::Barry::__data_dump_mode__) { ::Barry::LogLock lock; (*::Barry::LogStream) << x << std::endl; } #ifdef __DEBUG_MODE__ // debugging on #undef dout #undef eout #undef DEBUG_ONLY // low level debug output #define dout(x) if(::Barry::__data_dump_mode__) { ::Barry::LogLock lock; (*::Barry::LogStream) << x << std::endl; } // #define dout(x) // exception output #define eout(x) { ::Barry::LogLock lock; (*::Barry::LogStream) << x << std::endl; } // easy exception output #define eeout(c, r) { ::Barry::LogLock lock; (*::Barry::LogStream) << "Sent packet:\n" << c << "\n" << "Response packet:\n" << r << "\n"; } // For debug only variables and parameters #define DEBUG_ONLY(x) x // handle assert() #undef NDEBUG #else // debugging off #undef dout #undef eout #undef DEBUG_ONLY #define dout(x) #define eout(x) { ::Barry::LogLock lock; (*::Barry::LogStream) << x << std::endl; } #define eeout(c, r) { ::Barry::LogLock lock; (*::Barry::LogStream) << "Sent packet:\n" << c << "\n" << "Response packet:\n" << r << "\n"; } // For debug only variables and parameters #define DEBUG_ONLY(x) // handle assert() as well #undef NDEBUG #define NDEBUG #endif #include barry-0.18.5/src/r_servicebook.cc0000644001161500056700000003176212242254476016217 0ustar cdfreycdfrey/// /// \file r_servicebook.cc /// Blackberry database record parser class for /// Service Book records. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "r_servicebook.h" #include "record-internal.h" #include "protocol.h" #include "protostructs.h" #include "data.h" #include "time.h" #include "error.h" #include "endian.h" #include "iconv.h" #include #include #include #include #include "ios_state.h" #define __DEBUG_MODE__ #include "debug.h" using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // ServiceBookConfig class // service book packed field codes #define SBFCC_END 0xffff static FieldLink ServiceBookConfigFieldLinks[] = { // { SBFC_DSID, "DSID", 0, 0, &ServiceBook::DSID, 0, 0 }, { SBFCC_END, N_("End of List"),0, 0, 0, 0, 0 } }; ServiceBookConfig::ServiceBookConfig() : Format(0) { Clear(); } ServiceBookConfig::~ServiceBookConfig() { } const unsigned char* ServiceBookConfig::ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { const void *raw; uint16_t size, type; switch( Format ) { case 0x01: case 0x02: { const PackedField_02 *field = (const PackedField_02 *) begin; raw = field->raw; size = field->size; type = field->type; begin += PACKED_FIELD_02_HEADER_SIZE + size; } break; case 0x10: { const PackedField_10 *field = (const PackedField_10 *) begin; raw = field->raw; size = field->size; type = field->type; begin += PACKED_FIELD_10_HEADER_SIZE + size; } break; default: dout("------> Unknown packed field format: 0x" << std::hex << (unsigned int) Format); throw BadPackedFormat(Format); return begin + 1; } // check size if( begin > end ) // if begin==end, we are ok return begin; if( !size ) // if field has no size, something's up return begin; // cycle through the type table for( FieldLink *b = ServiceBookConfigFieldLinks; b->type != SBFCC_END; b++ ) { if( b->type == type ) { if( b->strMember ) { std::string &s = this->*(b->strMember); s = ParseFieldString(raw, size-1); return begin; // done! } } } /* // handle special cases switch( type ) { } */ // if still not handled, add to the Unknowns list UnknownField uf; uf.type = (uint8_t)type; uf.data.assign((const char*)raw, size); Unknowns.push_back(uf); // return new pointer for next field return begin; } void ServiceBookConfig::ParseHeader(const Data &data, size_t &offset) { MAKE_RECORD(const Barry::Protocol::ServiceBookConfigField, sbc, data, offset); offset += SERVICE_BOOK_CONFIG_FIELD_HEADER_SIZE; if( data.GetSize() >= offset ) { // size check! Format = sbc->format; } } void ServiceBookConfig::ParseFields(const Data &data, size_t &offset, const IConverter *ic) { const unsigned char *finish = ParseCommonFields(*this, data.GetData() + offset, data.GetData() + data.GetSize(), ic); offset += finish - (data.GetData() + offset); } void ServiceBookConfig::Validate() const { } void ServiceBookConfig::BuildHeader(Data &data, size_t &offset) const { // make sure there is enough space data.GetBuffer(offset + SERVICE_BOOK_CONFIG_FIELD_HEADER_SIZE); MAKE_RECORD(Barry::Protocol::ServiceBookConfigField, sbc, data, offset); sbc->format = Format; offset += SERVICE_BOOK_CONFIG_FIELD_HEADER_SIZE; } // // BuildFields // /// Build fields part of record /// void ServiceBookConfig::BuildFields(Data &data, size_t &offset, const IConverter *ic) const { throw std::logic_error(_("ServiceBookConfig::Build not yet implemented")); } void ServiceBookConfig::Clear() { Format = 0; Unknowns.clear(); } void ServiceBookConfig::Dump(std::ostream &os) const { ios_format_state state(os); os << _(" ServiceBookConfig Format: ") << setbase(16) << (uint16_t)Format << "\n"; // cycle through the type table for( const FieldLink *b = ServiceBookConfigFieldLinks; b->type != SBFCC_END; b++ ) { if( b->strMember ) { const std::string &s = this->*(b->strMember); if( s.size() ) os << " " << gettext(b->name) << ": " << s << "\n"; } else if( b->timeMember ) { TimeT t = this->*(b->timeMember); if( t.Time> 0 ) os << " " << gettext(b->name) << ": " << t << "\n"; } } // print any unknowns os << Unknowns; os << _(" ------------------- End of Config Field\n"); } /////////////////////////////////////////////////////////////////////////////// // ServiceBook class // service book field codes #define SBFC_OLD_NAME 0x01 #define SBFC_HIDDEN_NAME 0x02 #define SBFC_NAME 0x03 #define SBFC_OLD_UNIQUE_ID 0x06 #define SBFC_UNIQUE_ID 0x07 #define SBFC_CONTENT_ID 0x08 #define SBFC_CONFIG 0x09 #define SBFC_OLD_DESC 0x32 #define SBFC_DESCRIPTION 0x0f #define SBFC_DSID 0xa1 #define SBFC_BES_DOMAIN 0xa2 #define SBFC_USER_ID 0xa3 #define SBFC_END 0xffff // private data class, containing internal structures class ServiceBookData { public: FieldLink *m_typeSet; ServiceBookData(FieldLink *typeSet) : m_typeSet(typeSet) {} }; // The Old/New tables contain the same fields, but use different // type codes. Keeping them separate yet linked makes it possible // to convert between old and new type codes, while hopefully keeping // things generic. static FieldLink ServiceBookOldFieldLinks[] = { { SBFC_OLD_NAME, N_("Old Name"), 0, 0, &ServiceBook::Name, 0, 0, 0, 0, true }, { SBFC_OLD_DESC, N_("Old Desc"), 0, 0, &ServiceBook::Description, 0, 0, 0, 0, true }, { SBFC_OLD_UNIQUE_ID, N_("Old UniqueId"), 0, 0, &ServiceBook::UniqueId, 0, 0, 0, 0, false }, { SBFC_END, N_("End of List"), 0, 0, 0, 0, 0, 0, 0, false } }; static FieldLink ServiceBookNewFieldLinks[] = { { SBFC_NAME, N_("Name"), 0, 0, &ServiceBook::Name, 0, 0, 0, 0, true }, { SBFC_DESCRIPTION, N_("Description"), 0, 0, &ServiceBook::Description, 0, 0, 0, 0, true }, { SBFC_UNIQUE_ID, N_("UniqueId"), 0, 0, &ServiceBook::UniqueId, 0, 0, 0, 0, false }, { SBFC_END, N_("End of List"), 0, 0, 0, 0, 0, 0, 0, false } }; // This table holds all static FieldLink ServiceBookFieldLinks[] = { { SBFC_HIDDEN_NAME, N_("Hidden Name"),0, 0, &ServiceBook::HiddenName, 0, 0, 0, 0, true }, { SBFC_DSID, N_("DSID"), 0, 0, &ServiceBook::DSID, 0, 0, 0, 0, false }, { SBFC_CONTENT_ID, N_("ContentId"), 0, 0, &ServiceBook::ContentId, 0, 0, 0, 0, false }, { SBFC_BES_DOMAIN, N_("BES Domain"), 0, 0, &ServiceBook::BesDomain, 0, 0, 0, 0, false }, { SBFC_END, N_("End of List"),0, 0, 0, 0, 0, 0, 0, false } }; // Array of conflicting tables only static FieldLink *ServiceBookLinkTable[] = { ServiceBookOldFieldLinks, ServiceBookNewFieldLinks, 0 }; #define FIELDLINK_END 0xffff template FieldLink* ParseFieldByTable(RecordT *rec, const CommonField *field, const IConverter *ic, FieldLink *links) { // cycle through the type table for( FieldLink *b = links; b->type != FIELDLINK_END; b++ ) { if( b->type == field->type ) { if( b->strMember ) { std::string &s = rec->*(b->strMember); if( s.size() ) { dout(RecordT::GetDBName() << ": field '" << b->name << "' already has data (" << s << "). Overwriting."); } s = ParseFieldString(field); if( b->iconvNeeded && ic ) s = ic->FromBB(s); return links; } else if( b->timeMember && btohs(field->size) == 4 ) { TimeT &t = rec->*(b->timeMember); t.Time = min2time(field->u.min1900); return links; } } } return 0; } template FieldLink* ParseFieldByTable(RecordT *rec, const CommonField *field, const IConverter *ic, FieldLink **b) { for( ; *b; b++ ) { FieldLink *link = ParseFieldByTable(rec, field, ic, *b); if( link ) return link; } return 0; } ServiceBook::ServiceBook() : m_data( new ServiceBookData(ServiceBookOldFieldLinks) ) , RecordId(0) { Clear(); } ServiceBook::~ServiceBook() { } const unsigned char* ServiceBook::ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { const CommonField *field = (const CommonField *) begin; // advance and check size begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size); if( begin > end ) // if begin==end, we are ok return begin; if( !btohs(field->size) ) // if field has no size, something's up return begin; // cycle through the type tables FieldLink *typeSet = ParseFieldByTable(this, field, ic, ServiceBookLinkTable); if( typeSet ) { if( m_data->m_typeSet && m_data->m_typeSet != typeSet ) { dout("ServiceBook record has a mix of old and new field types."); } m_data->m_typeSet = typeSet; return begin; } else { if( ParseFieldByTable(this, field, ic, ServiceBookFieldLinks) ) return begin; // done! } // handle special cases switch( field->type ) { case SBFC_CONFIG: try { Data config((const void *)field->u.raw, btohs(field->size)); size_t offset = 0; Config.ParseHeader(config, offset); Config.ParseFields(config, offset); return begin; // success } catch( BadPackedFormat & ) { // break here so unprocessed raw packet is still // visible in dump break; } } // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; uf.data.assign((const char*)field->u.raw, btohs(field->size)); Unknowns.push_back(uf); // return new pointer for next field return begin; } void ServiceBook::ParseHeader(const Data &data, size_t &offset) { // no header in this record (?) } void ServiceBook::ParseFields(const Data &data, size_t &offset, const IConverter *ic) { const unsigned char *finish = ParseCommonFields(*this, data.GetData() + offset, data.GetData() + data.GetSize(), ic); offset += finish - (data.GetData() + offset); } void ServiceBook::Validate() const { Config.Validate(); } void ServiceBook::BuildHeader(Data &data, size_t &offset) const { // no header in this record (?) } // // BuildFields // /// Build fields part of record /// void ServiceBook::BuildFields(Data &data, size_t &offset, const IConverter *ic) const { throw std::logic_error(_("ServiceBook::BuildFields not yet implemented")); } void ServiceBook::Clear() { m_data->m_typeSet = ServiceBookOldFieldLinks; Unknowns.clear(); Config.Clear(); } const FieldHandle::ListT& ServiceBook::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; #undef CONTAINER_OBJECT_NAME #define CONTAINER_OBJECT_NAME fhv #undef RECORD_CLASS_NAME #define RECORD_CLASS_NAME ServiceBook FHP(RecType, _("Record Type Code")); FHP(RecordId, _("Unique Record ID")); FHP(Name, _("Name")); FHP(HiddenName, _("Hidden Name")); FHP(Description, _("Description")); FHP(DSID, _("DSID")); FHP(BesDomain, _("BES Domain")); FHP(UniqueId, _("Unique ID")); FHP(ContentId, _("Content ID")); // FIXME - this config is not yet implmented fully... when it is, // will need to add this as a field to FieldHandle<>, and maybe // implement a ServiceBookConfig::GetFieldHandles() //ServiceBookConfig Config; FHP(Unknowns, _("Unknown Fields")); return fhv; } std::string ServiceBook::GetDescription() const { return Name; } inline void FormatStr(std::ostream &os, const char *name, const std::string &str) { ios_format_state state(os); if( str.size() ) { os << " " << setw(20) << name; os << ": " << str << "\n"; } } void ServiceBook::Dump(std::ostream &os) const { ios_format_state state(os); os.setf(ios::left); os.fill(' '); os << _("ServiceBook entry: ") << "0x" << setbase(16) << RecordId << " (" << (unsigned int)RecType << ")\n"; FormatStr(os, _("Name"), Name); FormatStr(os, _("Hidden Name"), HiddenName); FormatStr(os, _("Description"), Description); FormatStr(os, _("DSID"), DSID); FormatStr(os, _("Unique ID"), UniqueId); FormatStr(os, _("Content ID"), ContentId); FormatStr(os, _("(BES) Domain"), BesDomain); os << Config; // print any unknowns os << Unknowns; } bool ServiceBook::operator<(const ServiceBook &other) const { int cmp = BesDomain.compare(other.BesDomain); if( cmp == 0 ) cmp = DSID.compare(other.DSID); if( cmp == 0 ) cmp = Name.compare(other.Name); if( cmp == 0 ) cmp = UniqueId.compare(other.UniqueId); return cmp < 0; } } // namespace Barry barry-0.18.5/src/base64.cc0000644001161500056700000001170712242254476014444 0ustar cdfreycdfrey/* * Encode or decode file as MIME base64 (RFC 1341) * Public domain by John Walker, August 11 1997 * http://www.fourmilab.ch/ * Modified slightly for the Citadel/UX system, June 1999 * * Taken from the Citadel/UX GPL source tree, at version 6.01 * Modified into a C++ API by Chris Frey for Net Direct Inc., November 2005 * http://www.netdirect.ca/ * */ #include "base64.h" #include #include #include #define TRUE 1 #define FALSE 0 #define LINELEN 72 /* Encoded line length (max 76) */ typedef unsigned char byte; /* Byte type */ static byte dtable[256]; /* Encode / decode table */ //static char eol[] = "\r\n"; /* End of line sequence */ static int errcheck = TRUE; /* Check decode input for errors ? */ /* INCHAR -- Return next character from input */ class base64_input { std::string::const_iterator begin, end; public: base64_input(const std::string &input) : begin(input.begin()), end(input.end()) {} int operator()() { if (begin == end) { return EOF; } return (int)((unsigned int)(unsigned char) *begin++); } }; /* OCHAR -- Output an encoded character, inserting line breaks where required. */ class base64_output { std::back_insert_iterator insert; int linelength; /* Length of encoded output line */ public: base64_output(std::string &output) : insert(back_inserter(output)), linelength(0) {} void operator()(int c) { if (linelength >= LINELEN) { *insert++ = '\n'; *insert++ = ' '; linelength = 0; } *insert++ = (unsigned char) c; linelength++; } }; /* ENCODE -- Encode binary file into base64. */ static bool encode(base64_input &inchar, base64_output &ochar) { int i, hiteof = FALSE; /* Fill dtable with character encodings. */ for (i = 0; i < 26; i++) { dtable[i] = 'A' + i; dtable[26 + i] = 'a' + i; } for (i = 0; i < 10; i++) { dtable[52 + i] = '0' + i; } dtable[62] = '+'; dtable[63] = '/'; while (!hiteof) { byte igroup[3], ogroup[4]; int c, n; igroup[0] = igroup[1] = igroup[2] = 0; for (n = 0; n < 3; n++) { c = inchar(); if (c == EOF) { hiteof = TRUE; break; } igroup[n] = (byte) c; } if (n > 0) { ogroup[0] = dtable[igroup[0] >> 2]; ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)]; ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)]; ogroup[3] = dtable[igroup[2] & 0x3F]; /* Replace characters in output stream with "=" pad characters if fewer than three characters were read from the end of the input stream. */ if (n < 3) { ogroup[3] = '='; if (n < 2) { ogroup[2] = '='; } } for (i = 0; i < 4; i++) { ochar(ogroup[i]); } } } return true; } /* INSIG -- Return next significant input */ static int insig(base64_input &inchar) { int c; /*CONSTANTCONDITION*/ while (TRUE) { c = inchar(); if (c == EOF || (c > ' ')) { return c; } } /*NOTREACHED*/ } /* DECODE -- Decode base64. */ static bool decode(base64_input &inchar, base64_output &ochar) { int i; for (i = 0; i < 255; i++) { dtable[i] = 0x80; } for (i = 'A'; i <= 'Z'; i++) { dtable[i] = 0 + (i - 'A'); } for (i = 'a'; i <= 'z'; i++) { dtable[i] = 26 + (i - 'a'); } for (i = '0'; i <= '9'; i++) { dtable[i] = 52 + (i - '0'); } dtable[(int)'+'] = 62; dtable[(int)'/'] = 63; dtable[(int)'='] = 0; /*CONSTANTCONDITION*/ while (TRUE) { byte a[4], b[4], o[3]; for (i = 0; i < 4; i++) { int c = insig(inchar); if (c == EOF) { // fprintf(stderr, "Input file incomplete.\n"); return false; } if (dtable[c] & 0x80) { if (errcheck) { //fprintf(stderr, "Illegal character '%c' in input file.\n", c); return false; } /* Ignoring errors: discard invalid character. */ i--; continue; } a[i] = (byte) c; b[i] = (byte) dtable[c]; } o[0] = (b[0] << 2) | (b[1] >> 4); o[1] = (b[1] << 4) | (b[2] >> 2); o[2] = (b[2] << 6) | b[3]; i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3); for (int w = 0; w < i; w++ ) ochar(o[w]); if (i < 3) { return true; } } } // in-memory encode / decode API bool base64_encode(const std::string &in, std::string &out) { out.clear(); base64_input input(in); base64_output output(out); return encode(input, output); } bool base64_decode(const std::string &in, std::string &out) { out.clear(); base64_input input(in); base64_output output(out); return decode(input, output); } #ifdef __TEST_MODE__ #include using namespace std; /* Main program */ int main() { string test = "This is a test.", encoded, decoded; base64_encode(test, encoded); base64_decode(encoded, decoded); if( test != decoded ) cerr << "Test failed" << endl; else cerr << "Success" << endl; } #endif barry-0.18.5/src/r_pin_message.h0000644001161500056700000000336112242254476016032 0ustar cdfreycdfrey/// /// \file r_pin_message.h /// Blackberry database record parser class for pin message records. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2007, Brian Edginton (edge@edginton.net) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_PIN_MESSAGE_H__ #define __BARRY_RECORD_PIN_MESSAGE_H__ #include "dll.h" #include "r_message_base.h" namespace Barry { // // NOTE: All classes here must be container-safe! Perhaps add sorting // operators in the future. // /// \addtogroup RecordParserClasses /// @{ class BXEXPORT PINMessage : public MessageBase { public: PINMessage() { // must call this again, since base class can't call ours Clear(); } void Clear() { MessageBase::Clear(); RecType = GetDefaultRecType(); RecordId = 0; } // database name static const char * GetDBName() { return "PIN Messages"; } static uint8_t GetDefaultRecType() { return 0; } // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const PINMessage &msg) { msg.Dump(os); return os; } /// @} } // namespace Barry #endif // __BARRY_RECORD_PIN_MESSAGE_H__ barry-0.18.5/src/r_message_base.h0000644001161500056700000000672212242254476016162 0ustar cdfreycdfrey/// /// \file r_message_base.h /// Base class for email-oriented Blackberry database records /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2007, Brian Edginton (edge@edginton.net) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_MESSAGE_BASE_H__ #define __BARRY_RECORD_MESSAGE_BASE_H__ #include "dll.h" #include "record.h" #include #include #include #include #include namespace Barry { // forward declarations class IConverter; // // NOTE: All classes here must be container-safe! Perhaps add sorting // operators in the future. // class BXEXPORT MessageBase { public: typedef Barry::UnknownsType UnknownsType; uint8_t RecType; uint32_t RecordId; EmailAddressList From; EmailAddressList To; EmailAddressList Cc; EmailAddressList Bcc; EmailAddressList Sender; //< not available for PINMessage? EmailAddressList ReplyTo; //< not available for PINMessage? std::string Subject; std::string Body; std::string Attachment; //< not available for PINMessage? uint32_t MessageRecordId; // in PINMessage, this happens to be // the same as RecordId in my (CDF) // testing, but interestingly, it is // stored as a field *inside* the // record, and not as part of the // header... in effect, this record ID // occurs twice in the protocol uint32_t MessageReplyTo; Barry::TimeT MessageDateSent; Barry::TimeT MessageDateReceived; // Message Flags bool MessageTruncated; bool MessageRead; bool MessageReply; bool MessageSaved; bool MessageSavedDeleted; enum PriorityType { LowPriority = 0, NormalPriority, HighPriority, UnknownPriority }; PriorityType Priority; enum SensitivityType { NormalSensitivity = 0, Personal, Private, Confidential, UnknownSensitivity }; SensitivityType Sensitivity; UnknownsType Unknowns; protected: std::string SimpleFromAddress() const; public: const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); protected: MessageBase(); ~MessageBase(); public: // Parser / Builder API (see parser.h / builder.h) void Validate() const; uint8_t GetRecType() const { return RecType; } uint32_t GetUniqueId() const { return RecordId; } void SetIds(uint8_t Type, uint32_t Id){ RecType = Type; RecordId = Id; } void ParseHeader(const Data &data, size_t &offset); void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); void BuildHeader(Data &data, size_t &offset) const; void BuildFields(Data &data, size_t &offset, const IConverter *ic = 0) const; // operations (common among record classes) void Clear(); void Dump(std::ostream &os) const; std::string GetDescription() const; // sorting bool operator<(const MessageBase &other) const; }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const MessageBase &msg) { msg.Dump(os); return os; } } // namespace Barry #endif barry-0.18.5/src/log.cc0000644001161500056700000000355612242254476014144 0ustar cdfreycdfrey/// /// \file log.cc /// General Barry interface routines /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "log.h" #include "clog.h" #include "platform.h" #include #include #include #include #include namespace Barry { extern bool __data_dump_mode__; extern std::ostream *LogStream; extern pthread_mutex_t LogStreamMutex; LogLock::LogLock() { while( pthread_mutex_lock(&LogStreamMutex) != 0 ) ; } LogLock::~LogLock() { pthread_mutex_unlock(&LogStreamMutex); } bool LogVerbose() { return __data_dump_mode__; } std::ostream* GetLogStream() { return LogStream; } } // namespace Barry // Callable from C: void BarryLogf(int verbose, const char *msg, ...) { va_list vl; va_start(vl, msg); char buffer[2048]; char *output = buffer; int buflen = sizeof(buffer); int n = vsnprintf(buffer, buflen, msg, vl); if( n < 0 || n >= buflen ) { buflen = n + 100; output = new char [buflen]; n = vsnprintf(output, buflen, msg, vl); if( n < 0 || n >= buflen ) { delete [] output; output = buffer; strcpy(buffer, "BarryLog: (trace error, output too long for buffer)"); } } va_end(vl); if( verbose ) { barryverbose(output); } else { barrylog(output); } if( output != buffer ) delete [] output; } barry-0.18.5/src/configfileunix.cc0000644001161500056700000000775012242254476016374 0ustar cdfreycdfrey/// /// \file configfileunix.cc /// Barry configuration class, for one device PIN, using Unix APIs /// /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) Portions Copyright (C) 2012, RealVNC Ltd. 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "configfile.h" #include "error.h" #include "r_message.h" #include "getpwuid.h" #include #include #include #include #include #include #include #include #include namespace Barry { /// Creates a tar.gz filename using PIN + date + time + label. /// Does not include any path, just returns a new filename. std::string MakeBackupFilename(const Barry::Pin &pin, const std::string &label) { using namespace std; time_t t = time(NULL); struct tm *lt = localtime(&t); std::string fileLabel = label; if( fileLabel.size() ) { // prepend a hyphen fileLabel.insert(fileLabel.begin(), '-'); // translate all spaces and slashes for( size_t i = 0; i < fileLabel.size(); i++ ) { if( fileLabel[i] == ' ' ) fileLabel[i] = '_'; else if( fileLabel[i] == '/' ) fileLabel[i] = '-'; else if( fileLabel[i] == '\\' ) fileLabel[i] = '-'; } } ostringstream tarfilename; tarfilename << pin.Str() << "-" << setw(4) << setfill('0') << (lt->tm_year + 1900) << setw(2) << setfill('0') << (lt->tm_mon + 1) << setw(2) << setfill('0') << lt->tm_mday << "-" << setw(2) << setfill('0') << lt->tm_hour << setw(2) << setfill('0') << lt->tm_min << setw(2) << setfill('0') << lt->tm_sec << fileLabel << ".tar.gz"; return tarfilename.str(); } void ConfigFile::BuildFilename() { size_t strsize = 255 * 5; char *strbuf = new char[strsize]; struct passwd pwbuf; struct passwd *pw; getpwuid_r(getuid(), &pwbuf, strbuf, strsize, &pw); if( !pw ) { delete [] strbuf; throw ConfigFileError(_("BuildFilename: getpwuid failed"), errno); } m_filename = pw->pw_dir; m_filename += "/.barry/backup/"; m_filename += m_pin.Str(); m_filename += "/config"; delete [] strbuf; } void ConfigFile::BuildDefaultPath() { struct passwd *pw = getpwuid(getuid()); m_path = pw->pw_dir; m_path += "/.barry/backup/"; m_path += m_pin.Str(); } /// Checks that the path in path exists, and if not, creates it. /// Returns false if unable to create path, true if ok. bool ConfigFile::CheckPath(const std::string &path, std::string *perr) { if( path.size() == 0 ) { if( perr ) *perr = _("ConfigFile::CheckPath(): path is empty!"); return false; } if( access(path.c_str(), F_OK) == 0 ) return true; std::string base; std::string::size_type slash = 0; while( (slash = path.find('/', slash + 1)) != std::string::npos ) { base = path.substr(0, slash); if( access(base.c_str(), F_OK) != 0 ) { if( mkdir(base.c_str(), 0755) == -1 ) { if( perr ) { *perr = _("mkdir() failed to create: ") + base + ": "; *perr += strerror(errno); } return false; } } } if( mkdir(path.c_str(), 0755) == -1 ) { if( perr ) { *perr = _("last mkdir() failed to create: ") + path + ": "; *perr += strerror(errno); } return false; } return true; } void GlobalConfigFile::BuildFilename() { struct passwd *pw = getpwuid(getuid()); if( !pw ) throw ConfigFileError(_("BuildFilename: getpwuid failed"), errno); m_filename = pw->pw_dir; m_filename += "/.barry/config"; // build the global path too, since this never changes m_path = pw->pw_dir; m_path += "/.barry"; } } // namespace Barry barry-0.18.5/src/j_jdwp.h0000644001161500056700000000315412242254476014474 0ustar cdfreycdfrey/// /// \file j_jdwp.h /// JDWP classes /// /* Copyright (C) 2009, Nicolas VIVIEN 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYJDWP_JDWP_H__ #define __BARRYJDWP_JDWP_H__ #include "error.h" namespace Barry { // forward declarations class Data; namespace JDWP { /// \addtogroup exceptions /// @{ /// Thrown on low level JDWP errors. class BXEXPORT Error : public Barry::Error { int m_errcode; public: Error(const std::string &str); Error(int errcode, const std::string &str); // can return 0 in some case, if unknown error code int errcode() const { return m_errcode; } }; class BXEXPORT Timeout : public Error { public: Timeout(const std::string &str) : Error(str) {} Timeout(int errcode, const std::string &str) : Error(errcode, str) {} }; /// @} class JDWP { private: int m_lasterror; protected: public: JDWP(); ~JDWP(); bool Read(int socket, Barry::Data &data, int timeout = -1); bool Write(int socket, const Barry::Data &data, int timeout = -1); bool Write(int socket, const void *data, size_t size, int timeout = -1); }; }} // namespace Barry::JDWP #endif barry-0.18.5/src/endian.h0000644001161500056700000000570012242254476014454 0ustar cdfreycdfrey/// /// \file endian.h /// Endian conversion macros /// /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_ENDIAN_H__ #define __BARRY_ENDIAN_H__ // The Blackberry is little endian in its USB data. Fortunately, // this makes conversion easy on the x86... #include "config.h" // endian.h is not installed, so this is safe #include //#include // The following is a byteswap.h replacement, for systems like Mac OS X. // It was taken from a patch to the GPL software cowpatty, patch // by user gm2net. // http://www.netstumbler.org/showpost.php?s=79764fd1526e4653d5cb4432225da6ee&p=190494&postcount=29 //#warning "byteswap.h is an unportable GNU extension! Don't use!" static inline uint16_t bbswap_16(uint16_t x) { return (x>>8) | (x<<8); } static inline uint32_t bbswap_32(uint32_t x) { return (bbswap_16(x&0xffff)<<16) | (bbswap_16(x>>16)); } static inline uint64_t bbswap_64(uint64_t x) { return (((uint64_t)bbswap_32((uint32_t)(x&0xffffffffull)))<<32) | (bbswap_32((uint32_t)(x>>32))); } #ifndef WORDS_BIGENDIAN // For when Blackberry needs little endian (most of the time) #define btohs(x) x // for uint16_t #define btohl(x) x // for uint32_t #define btohll(x) x // for uint64_t #define htobs(x) x // for uint16_t #define htobl(x) x // for uint32_t #define htobll(x) x // for uint64_t // For when Blackberry needs big endian (often in JavaLoader protocol) #define be_btohs(x) bbswap_16(x) // for uint16_t #define be_btohl(x) bbswap_32(x) // for uint32_t #define be_btohll(x) bbswap_64(x) // for uint64_t #define be_htobs(x) bbswap_16(x) // for uint16_t #define be_htobl(x) bbswap_32(x) // for uint32_t #define be_htobll(x) bbswap_64(x) // for uint64_t #else // For when Blackberry needs little endian (most of the time) #define btohs(x) bbswap_16(x) // for uint16_t #define btohl(x) bbswap_32(x) // for uint32_t #define btohll(x) bbswap_64(x) // for uint64_t #define htobs(x) bbswap_16(x) // for uint16_t #define htobl(x) bbswap_32(x) // for uint32_t #define htobll(x) bbswap_64(x) // for uint64_t // For when Blackberry needs big endian (often in JavaLoader protocol) #define be_btohs(x) x // for uint16_t #define be_btohl(x) x // for uint32_t #define be_btohll(x) x // for uint64_t #define be_htobs(x) x // for uint16_t #define be_htobl(x) x // for uint32_t #define be_htobll(x) x // for uint64_t #endif #endif barry-0.18.5/src/m_javaloader.cc0000644001161500056700000006665412242254476016017 0ustar cdfreycdfrey/// /// \file m_javaloader.cc /// Mode class for the JavaLoader mode /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2008-2009, Nicolas VIVIEN Some parts are inspired from m_desktop.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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "m_javaloader.h" #include "data.h" #include "protocol.h" #include "protostructs.h" #include "packet.h" #include "endian.h" #include "error.h" #include "usbwrap.h" #include "controller.h" #include "cod.h" #include #include #include #include #include #include #include #include #include "ios_state.h" #include "debug.h" using namespace std; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // JLScreenInfo class JLScreenInfo::JLScreenInfo() { } JLScreenInfo::~JLScreenInfo() { } /////////////////////////////////////////////////////////////////////////////// // JLDirectory class JLDirectory::JLDirectory(int level) : m_level(level) { } JLDirectory::~JLDirectory() { } void JLDirectory::ParseTable(const Data &table_packet) { m_idTable.clear(); size_t count = table_packet.GetSize() / 2; uint16_t *item = (uint16_t*) table_packet.GetData(); for( size_t i = 0; i < count; i++, item++ ) { m_idTable.push_back( be_btohs(*item) ); } } void JLDirectory::Dump(std::ostream &os) const { ios_format_state state(os); int indent = m_level * 2; os << setfill(' ') << setw(indent) << ""; os << "Directory: " << m_idTable.size() << "/" << size() << " entries\n"; const_iterator i = begin(), e = end(); for( ; i != e; ++i ) { os << setfill(' ') << setw(indent + 2) << ""; os << *i << "\n"; } } /////////////////////////////////////////////////////////////////////////////// // JLDirectoryEntry class JLDirectoryEntry::JLDirectoryEntry() : m_level(0) , SubDir(1) { } JLDirectoryEntry::JLDirectoryEntry(int level) : m_level(level) , SubDir(level + 1) { } void JLDirectoryEntry::Parse(uint16_t id, const Data &entry_packet) { size_t needed = SB_JLDIRENTRY_HEADER_SIZE; size_t have = entry_packet.GetSize(); if( have < needed ) throw BadSize("JLDE:Parse(1)", have, needed); const unsigned char *ptr = entry_packet.GetData(); Protocol::JLDirEntry *entry = (Protocol::JLDirEntry*) ptr; Id = id; Timestamp = be_btohl(entry->timestamp); uint16_t len = be_btohs(entry->filename_size); needed += len; if( have < needed ) throw BadSize("JLDE:Parse(2)", have, needed); Name.assign((char *)entry->filename, len); // need parsed data + string size ptr += needed; needed += 2; if( have < needed ) throw BadSize("JLDE:Parse(3)", have, needed); len = be_btohs( *((uint16_t*)(ptr)) ); ptr += sizeof(uint16_t); needed += len; if( have < needed ) throw BadSize("JLDE:Parse(4)", have, needed); Version.assign((char*)ptr, len); // need parsed data + string size ptr += len; needed += sizeof(uint32_t); if( have < needed ) throw BadSize("JLDE:Parse(5)", have, needed); CodSize = be_btohl( *((uint32_t*)(ptr)) ); } void JLDirectoryEntry::Dump(std::ostream &os) const { ios_format_state state(os); os << left << setfill(' ') << setw(50) << Name; os << "\n"; os << left << setw(28) << " "; os << "0x" << setfill('0') << setw(4) << hex << Id; os << " " << setw(10) << Version; os << " " << setw(7) << std::dec << CodSize; std::string ts = ctime(&Timestamp); ts.erase(ts.size() - 1); os << " " << ts; if( SubDir.size() ) os << "\n" << SubDir; } /////////////////////////////////////////////////////////////////////////////// // JLEventlog class void JLEventlog::Dump(std::ostream &os) const { const_iterator i = begin(), e = end(); for( ; i != e; ++i ) { (*i).Dump(os); } } /////////////////////////////////////////////////////////////////////////////// // JLEventlogEntry class, static members // // Note! These functions currently only pass the same values through. // In actuality, these are technically two different values: // one on the raw protocol side, and the other part of the // guaranteed Barry API. If the Blackberry ever changes the // meanings for these codes, do the translation here. // JLEventlogEntry::Severity_t JLEventlogEntry::SeverityProto2Rec(unsigned int s) { return (Severity_t)s; } unsigned int JLEventlogEntry::SeverityRec2Proto(Severity_t s) { return s; } JLEventlogEntry::ViewerType_t JLEventlogEntry::ViewerTypeProto2Rec(unsigned int v) { return (ViewerType_t)v; } unsigned int JLEventlogEntry::ViewerTypeRec2Proto(ViewerType_t v) { return v; } /////////////////////////////////////////////////////////////////////////////// // JLEventlogEntry class void JLEventlogEntry::Parse(uint16_t size, const char* buf) { // example of a single log entry //guid:92E11214401C3 time:0x11F133E6470 severity:0 type:2 app:UI data:GS-D 2c89868b std::string src = std::string(buf, size); std::istringstream ss(src); ss.ignore(5); // skip "guid:" ss >> Guid; if( ss.fail() ) throw BadData(_("JLEventlogEntry:Parse bad guid field")); ss.ignore(6); // skip " time:" ss >> hex >> MSTimestamp; if( ss.fail() ) throw BadData(_("JLEventlogEntry:Parse bad time field")); ss.ignore(10); // skip " severity:" unsigned int severity; ss >> severity; Severity = SeverityProto2Rec(severity); if( ss.fail() ) throw BadData(_("JLEventlogEntry:Parse bad severity field")); ss.ignore(6); // skip " type:" unsigned int type; ss >> type; Type = ViewerTypeProto2Rec(type); if( ss.fail() ) throw BadData(_("JLEventlogEntry:Parse bad type field")); ss.ignore(5); // skip " app:" ss >> App; if( ss.fail() ) throw BadData(_("JLEventlogEntry:Parse bad app field")); ss.ignore(6); // skip " data:" // use stringbuf to extract rest of data from stream stringbuf databuf; ss >> &databuf; if( ss.fail() ) throw BadData(_("JLEventlogEntry:Parse bad data field")); Data = databuf.str(); } std::string JLEventlogEntry::GetFormattedTimestamp() const { char buf[21]; struct tm split; time_t timestamp = (time_t) (MSTimestamp / 1000); if( localtime_r(×tamp, &split) == NULL ) return ""; if( strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S.", &split) == 0 ) return ""; std::ostringstream oss; oss << buf << (MSTimestamp % 1000); return oss.str(); } void JLEventlogEntry::Dump(std::ostream &os) const { ios_format_state state(os); static const char *SeverityNames[] = { N_("Always Log"), N_("Severe Error"), N_("Error"), N_("Warning"), N_("Information"), N_("Debug Info") }; static const char *ViewerTypes[] = { "", N_("Number"), N_("String"), N_("Exception") }; os << _("guid:") << Guid; os << _(" time:") << GetFormattedTimestamp(); os << _(" severity:") << gettext( SeverityNames[Severity] ); os << _(" type:") << gettext( ViewerTypes[Type] ); os << _(" app:") << App; os << _(" data:") << Data << endl; } /////////////////////////////////////////////////////////////////////////////// // JLDeviceInfo class void JLDeviceInfo::Dump(std::ostream &os) const { ios_format_state state(os); os << left << setfill(' ') << setw(17) << _("Hardware Id:"); os << "0x" << hex << HardwareId << endl; os << left << setfill(' ') << setw(17) << _("PIN:"); os << "0x" << Pin.Str() << endl; os << left << setfill(' ') << setw(17) << _("OS Version:"); os << dec << OsVersion.Major << '.' << OsVersion.Minor << '.' << OsVersion.SubMinor << '.' << OsVersion.Build << endl; os << left << setfill(' ') << setw(17) << _("VM Version:"); os << dec << VmVersion.Major << '.' << VmVersion.Minor << '.' << VmVersion.SubMinor << '.' << VmVersion.Build << endl; os << left << setfill(' ') << setw(17) << _("Radio ID:"); os << "0x" << hex << RadioId << endl; os << left << setfill(' ') << setw(17) << _("Vendor ID:"); os << dec << VendorId << endl; // WAF = Wireless Access Families os << left << setfill(' ') << setw(17) << _("Active Wireless Access Families:"); os << "0x" << hex << ActiveWafs << endl; os << left << setfill(' ') << setw(17) << _("OS Metrics:") << endl; os << OsMetrics; os << left << setfill(' ') << setw(17) << _("Bootrom Metrics:") << endl; os << BootromMetrics; } namespace Mode { /////////////////////////////////////////////////////////////////////////////// // JavaLoader Mode class JavaLoader::JavaLoader(Controller &con) : Mode(con, Controller::JavaLoader) , m_StreamStarted(false) { } JavaLoader::~JavaLoader() { try { if( m_StreamStarted ) StopStream(); } catch( std::exception &DEBUG_ONLY(e) ) { dout("Exception ignored in ~JavaLoader(): " << e.what()); } catch( ... ) { dout("Unknown exception in ~JavaLoader()"); } } /////////////////////////////////////////////////////////////////////////////// // protected members /////////////////////////////////////////////////////////////////////////////// // public API void JavaLoader::OnOpen() { Data response; m_socket->Receive(response, -1); } // These commands are sent to prepare the data stream void JavaLoader::StartStream() { Data cmd(-1, 8), data(-1, 8), response; JLPacket packet(cmd, data, response); packet.Hello(); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_HELLO_ACK ) { ThrowJLError(_("JavaLoader::StartStream Hello"), packet.Command()); } packet.SetUnknown1(); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError(_("JavaLoader::StartStream Unknown1"), packet.Command()); } m_StreamStarted = true; } // This function permits to send a COD application // WARNING : Before, you have to call the "Start" function, // After, you have to call the "Stop" function. // // From the USB traces, the max size of packet is : 0x07FC // Packet header : // 04 00 08 00 68 00 F8 07 // ^^^^^ : about size // ^^ : command // ^^ : size of packet header // ^^^^^ : socket // Response : // 00 00 0C 00 13 04 01 00 0A 00 00 00 // Packet format : // 04 00 FC 07 DB 9D 95 2B 57 .... E6 FD // ^^^^^ ............. ^^^^^ : data (the file content) // ^^^^^ : packet size // ^^^^^ : socket // // // WARNING : A COD file starts with the integer 0xDEC0FFFF (FIXME) // An application can contain several COD parts. In this case we can read a header (start with PK) // In this sample, we have to skip the file header : // 00000000 50 4B 03 04 0A 00 00 00 00 00 A0 00 51 35 BA 9F 99 5D 30 CE PK..........Q5...]0. // 00000014 00 00 30 CE 00 00 15 00 04 00 4D 65 74 72 6F 56 69 65 77 65 ..0.......MetroViewe // 00000028 72 2E 50 61 72 69 73 2E 63 6F 64 FE CA 00 00 DE C0 FF FF 00 r.Paris.cod......... // ^^ Start of data sent ! // 0000003C 00 00 00 00 00 00 00 0F 10 34 45 00 00 00 00 00 00 00 00 21 .........4E........! // 00000050 00 FF FF FF FF FF FF FF FF FF FF 4E 00 9C 08 68 C5 00 00 F0 ...........N...h.... // 00000064 B8 BC C0 A1 C0 14 00 81 00 00 01 01 04 0E 3F 6D 00 02 00 6D ..............?m...m void JavaLoader::SendStream(std::istream &input, size_t module_size) { char buffer[MAX_PACKET_DATA_SIZE - SB_JLPACKET_HEADER_SIZE]; size_t max_data_size = sizeof(buffer); size_t remaining = module_size; Data cmd(-1, 8), data(-1, 8), response; JLPacket packet(cmd, data, response); packet.SetCodSize(module_size); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError(_("JavaLoader::SendStream: set code size first"), packet.Command()); } while( remaining > 0 ) { size_t size = min(remaining, max_data_size); input.read(buffer, size); if( input.fail() || (size_t)input.gcount() != size ) { throw Error(_("JavaLoader::SendStream: input stream read failed")); } packet.PutData(buffer, size); m_socket->Packet(packet); if( packet.Command() == SB_COMMAND_JL_NOT_ENOUGH_MEMORY ) { throw Error(_("JavaLoader::SendStream: not enough memory to install the application")); } if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError(_("JavaLoader::SendStream: send data"), packet.Command()); } remaining -= size; } } void JavaLoader::LoadApp(std::istream &input) { uint32_t module_size; while( (module_size = SeekNextCod(input)) != 0 ) { SendStream(input, module_size); } } // // StopStream // /// Must be called at the end of a JavaLoader session. The JL_GOODBYE /// command is sent to the device. When the device responds with /// RESET_REQUIRED the device reset command will be sent when the /// socket is closed. /// /// \return true when a device reset was required /// bool JavaLoader::StopStream() { Data cmd(-1, 8), data(-1, 8), response; JLPacket packet(cmd, data, response); packet.Goodbye(); try { m_socket->Packet(packet); } catch( BadPacket &bp ) { // on some devices, such as the 7750 and the 7130, // the Goodbye command receives NOT_SUPPORTED // instead of the usual ACK... this is not an // error, so catch that case here and ignore it. // otherwise, throw it to higher levels if( bp.response() != SB_COMMAND_JL_NOT_SUPPORTED ) throw; } m_StreamStarted = false; if( packet.Command() == SB_COMMAND_JL_RESET_REQUIRED ) { m_socket->ResetOnClose(true); return true; } else if( packet.Command() != SB_COMMAND_JL_ACK && packet.Command() != SB_COMMAND_JL_NOT_SUPPORTED ) { ThrowJLError(_("JavaLoader::StopStream error"), packet.Command()); } return false; } void JavaLoader::SetTime(time_t when) { Data cmd(-1, 8), data(-1, 8), response; JLPacket packet(cmd, data, response); packet.SetTime(when); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError(_("JavaLoader::SetTime error"), packet.Command()); } } void JavaLoader::ThrowJLError(const std::string &msg, uint8_t cmd) { std::ostringstream oss; oss << msg << ": " << _("unexpected packet command code: ") << "0x" << std::hex << (unsigned int) cmd; throw Error(oss.str()); } void JavaLoader::GetDirectoryEntries(JLPacket &packet, uint8_t entry_cmd, JLDirectory &dir, bool include_subdirs) { JLDirectory::TableIterator i = dir.TableBegin(), e = dir.TableEnd(); for( ; i != e; ++i ) { packet.GetDirEntry(entry_cmd, *i); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::GetDirectoryEntries", packet.Command()); } Data &response = packet.GetReceive(); m_socket->Receive(response); JLDirectoryEntry entry(dir.Level()); Protocol::CheckSize(response, 4); entry.Parse(*i, Data(response.GetData() + 4, response.GetSize() - 4)); if( include_subdirs ) { packet.GetSubDir(*i); GetDir(packet, SB_COMMAND_JL_GET_SUBDIR_ENTRY, entry.SubDir, false); } // add to list dir.push_back(entry); } } void JavaLoader::GetDir(JLPacket &packet, uint8_t entry_cmd, JLDirectory &dir, bool include_subdirs) { m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::GetDir", packet.Command()); } // ack response will contain length of module ID array in next packet unsigned int expect = packet.Size(); if( expect > 0 ) { Data &response = packet.GetReceive(); m_socket->Receive(response); Protocol::CheckSize(response, 4); dir.ParseTable(Data(response.GetData() + 4, response.GetSize() - 4)); GetDirectoryEntries(packet, entry_cmd, dir, include_subdirs); } } void JavaLoader::GetDirectory(JLDirectory &dir, bool include_subdirs) { Data cmd(-1, 8), data(-1, 8), response; JLPacket packet(cmd, data, response); packet.GetDirectory(); GetDir(packet, SB_COMMAND_JL_GET_DATA_ENTRY, dir, include_subdirs); } // This function permits to receive a ScreenShot (maybe other...) // WARNING : Before, you have to call the "Start" function, // After, you have to call the "Stop" function. // // From the USB traces, the max size of packet is : 0x07FC // When you are ready, we send the packet : // 04 00 08 00 68 00 00 00 // Then, we receive an acknoledge and the data. // The data is composed of two packets : header and content. // Packet header : // 04 00 08 00 6E 00 F8 07 // ^^^^^ : size + 4 bytes // ^^ : command // ^^^^^ : size of packet header // ^^^^^ : socket // Packet content : // 04 00 FC 07 DB 9D 95 2B 57 .... E6 FD // ^^^^^ ............. ^^^^^ : data (the file content) // ^^^^^ : packet size (0x07FC = 0x7F8 + 4) // ^^^^^ : socket // // // GetScreenshot // /// Downloads screenshot from device, and fills info with size data /// and the given Data buffer image with the bitmap. /// void JavaLoader::GetScreenshot(JLScreenInfo &info, Data &image) { // start fresh image.Zap(); Data cmd(-1, 8), data(-1, 8), response; JLPacket packet(cmd, data, response); // Send the screenshot command : // 00000000: 04 00 08 00 87 00 04 00 packet.GetScreenshot(); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::GetScreenshot", packet.Command()); } // Get Info : // 00000000: 04 00 14 00 00 05 46 00 40 03 01 68 01 e0 00 10 ......F.@..h.... // ^^^^^x^^^^^ : width x height // ^^^^^ : packet size // ^^^^^ : socket ID // 00000010: 00 00 00 00 .... m_socket->Receive(response); // Parse response... Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE + SB_JLSCREENINFO_SIZE); MAKE_JLPACKET(rpack, response); info.width = be_btohs(rpack->u.screeninfo.width); info.height = be_btohs(rpack->u.screeninfo.height); // Read stream for (;;) { // Send the packet : // 04 00 08 00 68 00 00 00 packet.GetData(); m_socket->Packet(packet); // Read and parse the response // 04 00 08 00 64 00 00 00 // or // 04 00 08 00 6e 00 f8 07 if( packet.Command() == SB_COMMAND_JL_ACK ) return; if( packet.Command() != SB_COMMAND_JL_GET_DATA_ENTRY ) { ThrowJLError("JavaLoader::GetScreenShot ", packet.Command()); } // Read the size of next packet size_t expect = packet.Size(); // Read the stream m_socket->Receive(response); // Save data in buffer Protocol::CheckSize(response, 4); const unsigned char *pd = response.GetData(); size_t bytereceived = response.GetSize() - 4; // Check the size read into the previous packet if( expect != bytereceived ) { ThrowJLError(_("JavaLoader::GetScreenShot expect"), expect); } // Copy data unsigned char *buffer = image.GetBuffer(image.GetSize() + bytereceived); memcpy(buffer + image.GetSize(), pd + 4, bytereceived); // New size image.ReleaseBuffer(image.GetSize() + bytereceived); } } void JavaLoader::DoErase(uint8_t cmd, const std::string &cod_name) { Data command(-1, 8), data(-1, 8), response; JLPacket packet(command, data, response); // set filename, device responds with an ID packet.SetCodFilename(cod_name); m_socket->Packet(packet); if( packet.Command() == SB_COMMAND_JL_COD_NOT_FOUND ) { throw Error(string(_("JavaLoader::DoErase: module not found: ")) + cod_name); } if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::DoErase", packet.Command()); } // make sure there is an ID coming if( packet.Size() != 2 ) throw Error(_("JavaLoader::DoErase: expected code ID not available")); // get ID m_socket->Receive(response); Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE + sizeof(uint16_t)); MAKE_JLPACKET(jpack, response); uint16_t id = be_btohs(jpack->u.id); // send erase command, with application ID packet.Erase(cmd, id); m_socket->Packet(packet); if( packet.Command() == SB_COMMAND_JL_COD_IN_USE ) { throw Error(_("JavaLoader::DoErase: COD file in use.")); } if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::DoErase", packet.Command()); } } void JavaLoader::Erase(const std::string &cod_name) { DoErase(SB_COMMAND_JL_ERASE, cod_name); } void JavaLoader::ForceErase(const std::string &cod_name) { DoErase(SB_COMMAND_JL_FORCE_ERASE, cod_name); } void JavaLoader::GetEventlog(JLEventlog &log) { Data command(-1, 8), data(-1, 8), response; JLPacket packet(command, data, response); packet.GetEventlog(); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::GetEventlog", packet.Command()); } m_socket->Receive(response); Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE + sizeof(uint16_t)); // number of eventlog entries MAKE_JLPACKET(jpack, response); uint16_t count = be_btohs(jpack->u.response.expect); for( uint16_t i = 0; i < count; ++ i ) { packet.GetEventlogEntry(i); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::GetEventlog", packet.Command()); } m_socket->Receive(response); Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE + SB_JLEVENTLOG_ENTRY_HEADER_SIZE); MAKE_JLPACKET(jpack, response); uint16_t size = be_btohs(jpack->u.logentry.size); JLEventlogEntry entry; entry.Parse(size, (const char *)(response.GetData() + SB_JLPACKET_HEADER_SIZE + SB_JLEVENTLOG_ENTRY_HEADER_SIZE)); log.push_back(entry); } } void JavaLoader::ClearEventlog() { Data command(-1, 8), data(-1, 8), response; JLPacket packet(command, data, response); packet.ClearEventlog(); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::ClearEventlog", packet.Command()); } } void JavaLoader::SaveData(JLPacket &packet, uint16_t id, CodFileBuilder &builder, std::ostream &output) { packet.SaveModule(id); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::SaveData", packet.Command()); } // get total size of cod file or this sibling cod file Data &response = packet.GetReceive(); m_socket->Receive(response); Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE + sizeof(uint32_t)); MAKE_JLPACKET(jpack, response); uint32_t total_size = be_btohl(jpack->u.cod_size); // allocate buffer to hold data for this sibling Data buffer(-1, total_size); uint32_t offset = 0; for( ;; ) { packet.GetData(); m_socket->Packet(packet); if( packet.Command() == SB_COMMAND_JL_ACK ) break; if( packet.Command() != SB_COMMAND_JL_GET_DATA_ENTRY ) { ThrowJLError("JavaLoader::SaveData", packet.Command()); } // expected size of data in response packet unsigned int expect = packet.Size(); m_socket->Receive(response); Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE + expect); memcpy(buffer.GetBuffer(offset + expect) + offset, response.GetData() + SB_JLPACKET_HEADER_SIZE, expect); offset += expect; buffer.ReleaseBuffer(offset); } builder.WriteNextHeader(output, buffer.GetData(), buffer.GetSize()); output.write((const char *)buffer.GetData(), buffer.GetSize()); } void JavaLoader::Save(const std::string &cod_name, std::ostream &output) { Data command(-1, 8), data(-1, 8), response; JLPacket packet(command, data, response); // set filename, device responds with an ID packet.SetCodFilename(cod_name); m_socket->Packet(packet); if( packet.Command() == SB_COMMAND_JL_COD_NOT_FOUND ) { throw Error(string(_("JavaLoader::Save: module not found: ")) + cod_name); } if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::Save", packet.Command()); } // make sure there is an ID coming if( packet.Size() != 2 ) throw Error(_("JavaLoader::Save: expected module ID, but not available")); // get ID m_socket->Receive(response); Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE + sizeof(uint16_t)); MAKE_JLPACKET(jpack, response); uint16_t id = be_btohs(jpack->u.id); // get list of sibling modules packet.GetSubDir(id); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::Save", packet.Command()); } // expected number of module ID's unsigned int expect = packet.Size(); // get list of sibling module ID's m_socket->Receive(response); Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE + expect); // copy array of module ID's since we reuse the response packet buffer size_t count = expect / 2; const uint16_t *begin = (const uint16_t*) (response.GetData() + SB_JLPACKET_HEADER_SIZE); const uint16_t *end = begin + count; vector ids(begin, end); CodFileBuilder builder(cod_name, count); // save each block of data for( size_t i = 0; i < count; i++ ) { SaveData(packet, be_btohs(ids[i]), builder, output); } builder.WriteFooter(output); } void JavaLoader::DeviceInfo(JLDeviceInfo &info) { Data command(-1, 8), data(-1, 8), response; JLPacket packet(command, data, response); packet.DeviceInfo(); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::DeviceInfo", packet.Command()); } m_socket->Receive(response); Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE + SB_JLDEVICEINFO_SIZE); MAKE_JLPACKET(rpack, response); info.HardwareId = be_btohl(rpack->u.devinfo.hardware_id); info.Pin = be_btohl(rpack->u.devinfo.pin); info.OsVersion = be_btohl(rpack->u.devinfo.os_version); info.VmVersion = be_btohl(rpack->u.devinfo.vm_version); info.RadioId = be_btohl(rpack->u.devinfo.radio_id); info.VendorId = be_btohl(rpack->u.devinfo.vendor_id); info.ActiveWafs = be_btohl(rpack->u.devinfo.active_wafs); packet.OsMetrics(); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::DeviceInfo", packet.Command()); } m_socket->Receive(response); Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE); size_t offset = SB_JLPACKET_HEADER_SIZE; size_t size = response.GetSize()-offset; unsigned char* buf = info.OsMetrics.GetBuffer(size); memcpy(buf, response.GetData()+offset, size); info.OsMetrics.ReleaseBuffer(size); packet.BootromMetrics(); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::DeviceInfo", packet.Command()); } m_socket->Receive(response); Protocol::CheckSize(response, SB_JLPACKET_HEADER_SIZE); offset = SB_JLPACKET_HEADER_SIZE; size = response.GetSize()-offset; buf = info.BootromMetrics.GetBuffer(size); memcpy(buf, response.GetData()+offset, size); info.BootromMetrics.ReleaseBuffer(size); } void JavaLoader::Wipe(bool apps, bool fs) { Data command(-1, 8), data(-1, 8), response; JLPacket packet(command, data, response); if( apps ) { packet.WipeApps(); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::WipeApps", packet.Command()); } } if( fs ) { packet.WipeFs(); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::WipeFs", packet.Command()); } } } void JavaLoader::LogStackTraces() { Data command(-1, 8), data(-1, 8), response; JLPacket packet(command, data, response); packet.LogStackTraces(); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::LogStackTraces", packet.Command()); } } void JavaLoader::ResetToFactory() { Data command(-1, 8), data(-1, 8), response; JLPacket packet(command, data, response); packet.ResetToFactory(); m_socket->Packet(packet); if( packet.Command() != SB_COMMAND_JL_ACK ) { ThrowJLError("JavaLoader::ResetToFactory", packet.Command()); } } }} // namespace Barry::Mode barry-0.18.5/src/README0000644001161500056700000000047312242254476013727 0ustar cdfreycdfreyThis directory has source code to 6 libraries. Take a look at the Makefile.am file to see which files belong to which library. The file prefixes j_* and dp_* have some connection to this split. The prefixes r_* and m_* do not: they mark files related to database record parsing and protocol modes respectively. barry-0.18.5/src/vevent.h0000644001161500056700000000506512242254476014531 0ustar cdfreycdfrey/// /// \file vevent.h /// Conversion routines for vevents (VCALENDAR, etc) /// /* Copyright (C) 2006-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_SYNC_VEVENT_H__ #define __BARRY_SYNC_VEVENT_H__ #include "dll.h" #include "vbase.h" #include "vformat.h" #include "r_calendar.h" #include #include #include namespace Barry { namespace Sync { // // vCalendar // /// Class for converting between RFC 2445 iCalendar data format, /// and the Barry::Calendar class. /// class BXEXPORT vCalendar : public vBase { typedef std::map ArgMapType; // external reference vTimeConverter &m_vtc; // data to pass to external requests char *m_gCalData; // dynamic memory returned by vformat()... can // be used directly by the plugin, without // overmuch allocation and freeing (see Extract()) std::string m_vCalData; // copy of m_gCalData, for C++ use Barry::Calendar m_BarryCal; static const char *WeekDays[7]; void CheckUnsupportedArg(const ArgMapType &args, const std::string &name); std::vector SplitBYDAY(const std::string &ByDay); uint16_t GetMonthWeekNumFromBYDAY(const std::string& ByDay); uint16_t GetWeekDayIndexFromBYDAY(const std::string& ByDay); uint16_t GetDayOfMonthFromBYMONTHDAY(const ArgMapType &args, int month_override = -1); protected: void RecurToVCal(); void RecurToBarryCal(vAttr& rrule, time_t starttime); static uint16_t GetWeekDayIndex(const char *dayname); bool HasMultipleVEvents() const; public: explicit vCalendar(vTimeConverter &vtc); ~vCalendar(); const std::string& ToVCal(const Barry::Calendar &cal); const Barry::Calendar& ToBarry(const char *vcal, uint32_t RecordId); const std::string& GetVCal() const { return m_vCalData; } const Barry::Calendar& GetBarryCal() const { return m_BarryCal; } char* ExtractVCal(); void Clear(); // This is the v-name of the innermost BEGIN/END block static const char* GetVName() { return "VEVENT"; } }; }} // namespace Barry::Sync #endif barry-0.18.5/src/m_javaloader.h0000644001161500056700000001347512242254476015652 0ustar cdfreycdfrey/// /// \file m_javaloader.h /// Mode class for the JavaLoader mode /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2008-2009, Nicolas VIVIEN Some parts are inspired from m_desktop.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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_M_JAVALOADER_H__ #define __BARRY_M_JAVALOADER_H__ #include "dll.h" #include "m_mode_base.h" #include "data.h" #include "pin.h" namespace Barry { // forward declarations class Parser; class Builder; class Controller; class CodFileBuilder; class JLDirectoryEntry; class JLEventlogEntry; class BXEXPORT JLDirectory : public std::vector { public: typedef std::vector BaseType; typedef BaseType::iterator BaseIterator; typedef std::vector TableType; typedef TableType::iterator TableIterator; private: TableType m_idTable; int m_level; public: JLDirectory(int level = 0); ~JLDirectory(); int Level() const { return m_level; } TableIterator TableBegin() { return m_idTable.begin(); } TableIterator TableEnd() { return m_idTable.end(); } void ParseTable(const Data &table_packet); void Dump(std::ostream &os) const; }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const JLDirectory &d) { d.Dump(os); return os; } class BXEXPORT JLDirectoryEntry { private: int m_level; public: uint16_t Id; std::string Name; std::string Version; uint32_t CodSize; time_t Timestamp; JLDirectory SubDir; public: JLDirectoryEntry(); explicit JLDirectoryEntry(int level); void Parse(uint16_t id, const Data &entry_packet); void Dump(std::ostream &os) const; }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const JLDirectoryEntry &e) { e.Dump(os); return os; } class BXEXPORT JLScreenInfo { public: uint16_t width; uint16_t height; public: JLScreenInfo(); ~JLScreenInfo(); }; class BXEXPORT JLEventlog : public std::vector { public: void Dump(std::ostream &os) const; }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const JLEventlog &log) { log.Dump(os); return os; } class BXEXPORT JLEventlogEntry { public: typedef enum { JES_ALWAYS_LOG, JES_SEVERE_ERROR, JES_ERROR, JES_WARNING, JES_INFORMATION, JES_DEBUG_INFO } Severity_t; typedef enum { JEVT_NUMBER = 1, JEVT_STRING, JEVT_EXCEPTION } ViewerType_t; std::string Guid; uint64_t MSTimestamp; // time_t in milliseconds Severity_t Severity; ViewerType_t Type; std::string App; std::string Data; protected: static Severity_t SeverityProto2Rec(unsigned int s); static unsigned int SeverityRec2Proto(Severity_t s); static ViewerType_t ViewerTypeProto2Rec(unsigned int v); static unsigned int ViewerTypeRec2Proto(ViewerType_t v); public: void Parse(uint16_t size, const char* str); std::string GetFormattedTimestamp() const; void Dump(std::ostream &os) const; }; class BXEXPORT JLDeviceInfo { public: struct VersionQuad { VersionQuad() { } VersionQuad(uint32_t v) { Major = (v & 0xff000000) >> 24; Minor = (v & 0xff0000) >> 16; SubMinor = (v & 0xff00) >> 8; Build = (v & 0xff); } unsigned int Major; unsigned int Minor; unsigned int SubMinor; unsigned int Build; }; public: uint32_t HardwareId; class Pin Pin; VersionQuad OsVersion; VersionQuad VmVersion; uint32_t RadioId; uint32_t VendorId; uint32_t ActiveWafs; Data OsMetrics; Data BootromMetrics; public: void Dump(std::ostream &os) const; }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const JLDeviceInfo &info) { info.Dump(os); return os; } namespace Mode { // // JavaLoader class // /// The main interface class to the java program loader protocol /// /// To use this class, use the following steps: /// /// - Create a Controller object (see Controller class for more details) /// - Create this Mode::JavaLoader object, passing in the Controller /// object during construction /// - Call Open() to open database socket and finish constructing. /// - Call LoadDatabase() to retrieve and store a database /// class BXEXPORT JavaLoader : public Mode { private: bool m_StreamStarted; protected: void GetDirectoryEntries(JLPacket &packet, uint8_t entry_cmd, JLDirectory &dir, bool include_subdirs); void GetDir(JLPacket &packet, uint8_t entry_cmd, JLDirectory &dir, bool include_subdirs); void ThrowJLError(const std::string &msg, uint8_t cmd); void DoErase(uint8_t cmd, const std::string &cod_name); void SaveData(JLPacket &packet, uint16_t, CodFileBuilder &builder, std::ostream &output); ////////////////////////////////// // overrides virtual void OnOpen(); public: JavaLoader(Controller &con); ~JavaLoader(); ////////////////////////////////// // API void StartStream(); bool StopStream(); // mid-stream operations void SendStream(std::istream &input, size_t module_size); void LoadApp(std::istream &input); void SetTime(time_t when); void GetDirectory(JLDirectory &dir, bool include_subdirs); void GetScreenshot(JLScreenInfo &info, Data &image); void Erase(const std::string &cod_name); void ForceErase(const std::string &cod_name); void GetEventlog(JLEventlog &log); void ClearEventlog(); void Save(const std::string &cod_name, std::ostream &output); void DeviceInfo(JLDeviceInfo &info); void Wipe(bool apps = true, bool fs = true); void LogStackTraces(); void ResetToFactory(); }; }} // namespace Barry::Mode #endif barry-0.18.5/src/m_desktop.h0000644001161500056700000002073712242254476015212 0ustar cdfreycdfrey/// /// \file m_desktop.h /// Mode class for the Desktop mode /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_M_DESKTOP_H__ #define __BARRY_M_DESKTOP_H__ #include "dll.h" #include "m_mode_base.h" #include "data.h" #include "socket.h" #include "record.h" #include "parser.h" #include "builder.h" namespace Barry { // forward declarations class Parser; class IConverter; namespace Mode { class DBLoader; // // Desktop class // /// The main interface class to the device databases. /// /// To use this class, use the following steps: /// /// - Create a Controller object (see Controller class for more details) /// - Create this Mode::Desktop object, passing in the Controller /// object during construction /// - Call Open() to open database socket and finish constructing. /// - Call GetDBDB() to get the device's database database /// - Call GetDBID() to get a database ID by name /// - Call LoadDatabase() to retrieve and store a database /// class BXEXPORT Desktop : public Mode { friend class DBLoader; public: enum CommandType { Unknown, DatabaseAccess }; private: // packet data Data m_command, m_response; CommandTable m_commandTable; DatabaseDatabase m_dbdb; // external objects (optional, can be null) const IConverter *m_ic; protected: void LoadCommandTable(); void LoadDBDB(); ////////////////////////////////// // overrides virtual void OnOpen(); public: Desktop(Controller &con); Desktop(Controller &con, const IConverter &ic); ~Desktop(); ////////////////////////////////// // meta access /// Returns DatabaseDatabase object for this connection. /// Must call Open() first, which loads the DBDB. const DatabaseDatabase& GetDBDB() const { return m_dbdb; } unsigned int GetDBID(const std::string &name) const; unsigned int GetDBCommand(CommandType ct); void SetIConverter(const IConverter &ic); ////////////////////////////////// // Desktop mode - database specific // dirty flag related functions, for sync operations void GetRecordStateTable(unsigned int dbId, RecordStateTable &result); void AddRecord(unsigned int dbId, Builder &build); // RecordId is // retrieved from build, and duplicate IDs are allowed, // but *not* recommended! void GetRecord(unsigned int dbId, unsigned int stateTableIndex, Parser &parser); void SetRecord(unsigned int dbId, unsigned int stateTableIndex, Builder &build); void ClearDirty(unsigned int dbId, unsigned int stateTableIndex); void DeleteRecord(unsigned int dbId, unsigned int stateTableIndex); // pure load/save operations void LoadDatabase(unsigned int dbId, Parser &parser); void ClearDatabase(unsigned int dbId); void SaveDatabase(unsigned int dbId, Builder &builder); template void LoadDatabaseByType(StorageT &store); template void SaveDatabaseByType(StorageT &store); template void LoadDatabaseByName(const std::string &name, StorageT &store); template void SaveDatabaseByName(const std::string &name, StorageT &store); template void AddRecordByType(uint32_t recordId, const RecordT &rec); }; // used to hold internal-only state struct DBLoaderData; // // DBLoader // /// Database Loader operation class. Encapsulates the load / save /// logic of Desktop::LoadDatabase() and someday Desktop::SaveDatabase() /// in such a way that the loading of individual records is /// controllable by the user, instead of using the parser callback mechanism. /// /// This class can be reused to load / save multiple databases, but /// do not call Desktop members while a load operation is in progress. /// class BXEXPORT DBLoader { Desktop &m_desktop; Data m_send; bool m_loading; std::string m_dbName; DBLoaderData *m_loader; public: explicit DBLoader(Desktop &desktop); ~DBLoader(); /// Do not call Desktop members if this is true. bool IsBusy() const { return m_loading; } // caller-controllable load/save operations... if // these functions return true, then new data has // just been loaded into the data object passed to // the constructor // // Both of these functions use a DBData object in order // to pass buffers from application code all the way down // to the socket level, to avoid copies wherever possible. bool StartDBLoad(unsigned int dbId, DBData &data); bool GetNextRecord(DBData &data); }; } // namespace Barry::Mode // // DeviceBuilder // /// Takes a list of database dbId's and behaves like a Builder, /// trying to avoid copies where possible on the device loading end. /// class BXEXPORT DeviceBuilder : public Builder { typedef unsigned int dbid_type; struct DBLabel { dbid_type id; std::string name; DBLabel(dbid_type id, const std::string &name) : id(id) , name(name) { } }; typedef std::vector list_type; // list of databases to fetch during build list_type m_dbIds; list_type::iterator m_current; bool m_started; Mode::Desktop &m_desktop; // loader object to use optimized batch loading while // giving per-record control Mode::DBLoader m_loader; public: explicit DeviceBuilder(Mode::Desktop &desktop); // searches the dbdb from the desktop to find the dbId, // returns false if not found, and adds it to the list of // databases to retrieve if found bool Add(const std::string &dbname); // adds all databases found in the given dbdb void Add(const Barry::DatabaseDatabase &dbdb); /// sets the internal iterator to the start of the list /// in order to perform a fresh run void Restart() { m_current = m_dbIds.begin(); m_started = false; } // // Builder overrides // // has both BuildRecord() and Retrieve() functionality, // and uses data all the way down to the socket level copy virtual bool BuildRecord(DBData &data, size_t &offset, const IConverter *ic); virtual bool FetchRecord(DBData &data, const IConverter *ic); virtual bool EndOfFile() const; }; // // DeviceParser // /// A parser class that "parses" raw data into a device. Basically this /// is a pipe-oriented way to call SaveDatabase(). /// /// Note that this is a multi-record parser. For each incoming DBData /// that has a new DBName, a new save will be started. There is no /// way to filter out records, except via the callback, so the easiest /// way to filter out records by database name is on the Builder side. /// class BXEXPORT DeviceParser : public Barry::Parser { public: enum WriteMode { /// Similar to SaveDatabase(). Erases all records from /// the existing database and then uploads all new records. ERASE_ALL_WRITE_ALL, /// Adds any new records, and for records with Unique IDs /// that already exist, overwrite them. INDIVIDUAL_OVERWRITE, /// Adds any new records, but if a record exists with the /// current Unique ID, skip that record and don't write it /// to the device. ADD_BUT_NO_OVERWRITE, /// Adds all incoming records as brand new records, generating /// a new Unique ID for each one, and leaving any existing /// records intact. ADD_WITH_NEW_ID, /// Calls the virtual function DecideWrite(...) for each /// record, passing in the data. DecideWrite() returns one /// of these WriteMode values. DECIDE_BY_CALLBACK, /// Primarily used by DecideWrite(), and causes the current /// record to not be written. DROP_RECORD }; private: Mode::Desktop &m_desktop; WriteMode m_mode; std::string m_current_db; unsigned int m_current_dbid; RecordStateTable m_rstate; protected: void StartDB(const DBData &data, const IConverter *ic); void WriteNext(const DBData &data, const IConverter *ic); public: DeviceParser(Mode::Desktop &desktop, WriteMode mode); virtual ~DeviceParser(); /// Callback... you must derive and override this if you use /// the DECIDE_BY_CALLBACK mode. /// May be called multiple times per record. virtual WriteMode DecideWrite(const DBData &record) const { return DROP_RECORD; } /// Parser overrides virtual void ParseRecord(const DBData &data, const IConverter *ic); }; } // namespace Barry #endif barry-0.18.5/src/getpwuid.h0000644001161500056700000000356012242254476015050 0ustar cdfreycdfrey/// /// \file getpwuid.h /// Header for getpwduid*() calls, for systems that don't have an equivalent. /// /* Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/) Portions Copyright (C) 2011, RealVNC Ltd. 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_GETPWUID_H__ #define __BARRY_GETPWUID_H__ #include "config.h" // getpwuid.h is not installed, so this is safe #include #ifdef HAVE_GETPWUID // System supports pwd so just include the system headers #include #else // so define our own version... #ifdef __cplusplus extern "C" { #endif struct barry_passwd { char *pw_name; /* username */ char *pw_passwd; /* user password */ uid_t pw_uid; /* user ID */ gid_t pw_gid; /* group ID */ char *pw_gecos; /* real name */ char *pw_dir; /* home directory */ char *pw_shell; /* shell program */ }; struct barry_passwd *barry_getpwuid(uid_t uid); int barry_getpwuid_r(uid_t uid, struct barry_passwd *pwd, char *buf, size_t buflen, struct barry_passwd **result); #ifdef __cplusplus } #endif // and override the system's names so we call our own #define passwd barry_passwd #define getpwuid(u) barry_getpwuid(u) #define getpwuid_r(u, p, b, l, r) barry_getpwuid_r(u, p, b, l, r) #endif // !HAVE_GETPWDUID #endif // __BARRY_GETPWUID_H__ barry-0.18.5/src/parser.cc0000644001161500056700000001601512242254476014651 0ustar cdfreycdfrey/// /// \file parser.cc /// Virtual parser wrapper /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "parser.h" #include "r_calendar.h" #include "r_calllog.h" #include "r_bookmark.h" #include "r_contact.h" #include "r_memo.h" #include "r_message.h" #include "r_servicebook.h" #include "r_task.h" #include "r_pin_message.h" #include "r_saved_message.h" #include "r_sms.h" #include "r_folder.h" #include "r_timezone.h" #include "r_cstore.h" #include "r_hhagent.h" #include "ios_state.h" #include #include using namespace std; namespace Barry { ////////////////////////////////////////////////////////////////////////////// // HexDumpParser class HexDumpParser::HexDumpParser(std::ostream &os) : m_os(os) { } void HexDumpParser::ParseRecord(const Barry::DBData &data, const IConverter *ic) { ios_format_state state(m_os); if( m_last_dbname != data.GetDBName() ) { m_os << _("Records for database: ") << data.GetDBName() << endl; m_last_dbname = data.GetDBName(); } m_os << _("Raw record dump for record: ") << "0x" << hex << data.GetUniqueId() << ", " << _("type: ") << "0x" << hex << (unsigned int) data.GetRecType() << ", " << _("offset: ") << "0x" << hex << data.GetOffset() << endl; m_os << data.GetData() << endl; } ////////////////////////////////////////////////////////////////////////////// // DBNamesOnlyParser class DBNamesOnlyParser::DBNamesOnlyParser(std::ostream &os) : m_os(os) { } void DBNamesOnlyParser::ParseRecord(const Barry::DBData &data, const IConverter *ic) { ios_format_state state(m_os); if( m_last_dbname != data.GetDBName() ) { m_os << data.GetDBName() << endl; m_last_dbname = data.GetDBName(); } } ////////////////////////////////////////////////////////////////////////////// // MultiRecordParser class // takes ownership of default_parser! MultiRecordParser::MultiRecordParser(Parser *default_parser) : m_delete_default(default_parser) // takes ownership , m_default(default_parser) { } // does not take ownership of the default_parser MultiRecordParser::MultiRecordParser(Parser &default_parser) : m_delete_default(0) // no ownership of reference , m_default(&default_parser) { } MultiRecordParser::~MultiRecordParser() { map_type::iterator i = m_parsers.begin(); for( ; i != m_parsers.end(); ++i ) { delete i->second; } // and the default parser delete m_delete_default; } void MultiRecordParser::Add(const std::string &dbname, Parser *parser) { std::auto_ptr p(parser); map_type::iterator i = m_parsers.find(dbname); if( i != m_parsers.end() ) { // found existing parser, so delete it first delete i->second; // assign it i->second = p.release(); } else { m_parsers[dbname] = p.get(); p.release(); } } // takes ownership of parser! void MultiRecordParser::Add(RecordParserBase *parser) { std::auto_ptr p(parser); std::string name = parser->GetDBName(); Add(name, p.release()); } bool MultiRecordParser::Add(const std::string &dbname, std::ostream &os) { std::auto_ptr p; #undef HANDLE_PARSER #define HANDLE_PARSER(tname) if( dbname == tname::GetDBName() ) { p.reset( new RecordParser > (new DumpStore(os)) ); } // check for recognized database names ALL_KNOWN_PARSER_TYPES if( !p.get() ) { // name not known return false; } Add(dbname, p.release()); return true; } bool MultiRecordParser::Add(const std::string &dbname, AllRecordStore &store) { #undef HANDLE_PARSER #define HANDLE_PARSER(tname) \ if( dbname == tname::GetDBName() ) { \ Add(dbname, new RecordParser(store)); \ return true; \ } // check for recognized database names ALL_KNOWN_PARSER_TYPES // if we get here, record was not found return false; } // Parser overrides void MultiRecordParser::ParseRecord(const DBData &data, const IConverter *ic) { // search for a named parser map_type::iterator i = m_parsers.find(data.GetDBName()); if( i != m_parsers.end() ) { // found one, use it i->second->ParseRecord(data, ic); } else if( m_default ) { // use default parser m_default->ParseRecord(data, ic); } } ////////////////////////////////////////////////////////////////////////////// // AllRecordDumpStore class // Use the macro here to implement the overrides, so that // the compiler will catch if we are missing any. #undef HANDLE_PARSER #define HANDLE_PARSER(tname) \ void AllRecordDumpStore::operator() (const Barry::tname &r) \ { \ m_os << r << std::endl; \ } ALL_KNOWN_PARSER_TYPES ////////////////////////////////////////////////////////////////////////////// // AllRecordDumpParser class AllRecordParser::AllRecordParser(std::ostream &os, Parser *default_parser, AllRecordStore *store) : MultiRecordParser(default_parser) , m_store(store) // takes ownership here { AddRecords(&os, store); } // does not take ownership of default_parser or store AllRecordParser::AllRecordParser(Parser &default_parser, AllRecordStore &store) : MultiRecordParser(default_parser) , m_store(0) { AddRecords(0, &store); } AllRecordParser::~AllRecordParser() { delete m_store; } void AllRecordParser::AddRecords(std::ostream *os, AllRecordStore *store) { // Does not allow RecordParser<> to own store, since we're using // it multiple times as the same store for each record type. #undef HANDLE_PARSER #define HANDLE_PARSER(tname) \ if( store ) { \ Add( new RecordParser(*store)); \ } else if( os ) { \ Add(tname::GetDBName(), *os); \ } ALL_KNOWN_PARSER_TYPES; } ////////////////////////////////////////////////////////////////////////////// // TeeParser class TeeParser::TeeParser() { } TeeParser::~TeeParser() { // free all the owned parser pointers for( parser_list_type::iterator i = m_owned_parsers.begin(); i != m_owned_parsers.end(); ++i ) { delete *i; } } // takes ownership of the pointer! void TeeParser::Add(Parser *p) { std::auto_ptr ap(p); m_owned_parsers.push_back(ap.get()); ap.release(); } // does NOT take ownership void TeeParser::Add(Parser &p) { m_external_parsers.push_back(&p); } void TeeParser::ParseRecord(const DBData &data, const IConverter *ic) { // call all owned parsers for( parser_list_type::iterator i = m_owned_parsers.begin(); i != m_owned_parsers.end(); ++i ) { (*i)->ParseRecord(data, ic); } // call all external parsers for( parser_list_type::iterator i = m_external_parsers.begin(); i != m_external_parsers.end(); ++i ) { (*i)->ParseRecord(data, ic); } } } // namespace Barry barry-0.18.5/src/probe.cc0000644001161500056700000003703412242254476014470 0ustar cdfreycdfrey/// /// \file probe.cc /// USB Blackberry detection routines /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "common.h" #include "probe.h" #include "usbwrap.h" #include "data.h" #include "endian.h" #include "error.h" #include "debug.h" #include "packet.h" #include "socket.h" #include "protocol.h" #include "protostructs.h" #include "record-internal.h" #include "strnlen.h" #include "configfile.h" #include "platform.h" #include #include #include #include #include "ios_state.h" using namespace Usb; namespace Barry { unsigned char Intro_Sends[][32] = { // packet #1 { 0x00, 0x00, 0x10, 0x00, 0x01, 0xff, 0x00, 0x00, 0xa8, 0x18, 0xda, 0x8d, 0x6c, 0x02, 0x00, 0x00 } }; unsigned char Intro_Receives[][32] = { // response to packet #1 { 0x00, 0x00, 0x10, 0x00, 0x02, 0xff, 0x00, 0x00, 0xa8, 0x18, 0xda, 0x8d, 0x6c, 0x02, 0x00, 0x00 } }; namespace { unsigned int GetSize(const unsigned char *packet) { const Protocol::Packet *pack = (const Protocol::Packet*) packet; return btohs(pack->size); } bool Intro(int IntroIndex, const EndpointPair &ep, Device &dev, Data &response) { dev.BulkWrite(ep.write, Intro_Sends[IntroIndex], GetSize(Intro_Sends[IntroIndex])); try { dev.BulkRead(ep.read, response, 500); } catch( Usb::Timeout &to ) { ddout("BulkRead: " << to.what()); return false; } ddout("BulkRead (" << (unsigned int)ep.read << "):\n" << response); return true; } } // anonymous namespace bool Probe::CheckSize(const Data &data, unsigned int required) { const unsigned char *pd = data.GetData(); if( GetSize(pd) != (unsigned int) data.GetSize() || data.GetSize() < required || pd[4] != SB_COMMAND_FETCHED_ATTRIBUTE ) { dout(_("Probe: Parse data failure: ") << "GetSize(pd): " << GetSize(pd) << ", data.GetSize(): " << data.GetSize() << ", pd[4]: " << (unsigned int) pd[4]); return false; } return true; } bool Probe::ParsePIN(const Data &data, uint32_t &pin) { // validate response data const unsigned char *pd = data.GetData(); if( !CheckSize(data, 0x14) ) return false; // capture the PIN memcpy(&pin, &pd[16], sizeof(pin)); pin = btohl(pin); return true; } bool Probe::ParseDesc(const Data &data, std::string &desc) { if( !CheckSize(data, 29) ) return false; // capture the description const char *d = (const char*) &data.GetData()[28]; int maxlen = data.GetSize() - 28; desc.assign(d, strnlen(d, maxlen)); return true; } Probe::Probe(const char *busname, const char *devname, const Usb::EndpointPair *epp, unsigned int log_exceptions, bool auto_dump_log) : m_log_exceptions(log_exceptions) , m_fail_count(0) , m_epp_override(epp != NULL) { if( m_epp_override ) { m_epp = *epp; } // let the programmer pass in "" as well as 0 if( busname && !strlen(busname) ) busname = 0; if( devname && !strlen(devname) ) devname = 0; // Search for standard product ID first ProbeMatching(VENDOR_RIM, PRODUCT_RIM_BLACKBERRY, busname, devname); // Search for Pearl devices second // // productID 6 devices (PRODUCT_RIM_PEARL) do not expose // the USB class 255 interface we need, but only the // Mass Storage one. Here we search for PRODUCT_RIM_PEARL_DUAL, // (ID 4) which has both enabled. ProbeMatching(VENDOR_RIM, PRODUCT_RIM_PEARL_DUAL, busname, devname); // And a special case, which behaves similar to the PEARL_DUAL, // but with a unique Product ID. ProbeMatching(VENDOR_RIM, PRODUCT_RIM_PEARL_8120, busname, devname); // And one more! The Pearl Flip ProbeMatching(VENDOR_RIM, PRODUCT_RIM_PEARL_FLIP, busname, devname); // And one more time, for the Blackberry Storm ProbeMatching(VENDOR_RIM, PRODUCT_RIM_STORM, busname, devname); // now dump all logged error messages if( auto_dump_log && m_fail_msgs.size() ) { eout(string_vprintf(_("Probe logged %u exception messages:"), m_fail_msgs.size())); for( std::vector::const_iterator b = m_fail_msgs.begin(); b != m_fail_msgs.end(); ++b ) { eout(*b); } } } void Probe::ProbeMatching(int vendor, int product, const char *busname, const char *devname) { Usb::DeviceID devid; Match match(m_devices, vendor, product, busname, devname); while( match.next_device(devid) ) try { ProbeDevice(devid); } catch( Usb::Error &e ) { using namespace std; dout(_("Usb::Error exception caught: ") << e.what()); if( ((m_log_exceptions & LOG_BUSY) && e.system_errcode() == -EBUSY) || ((m_log_exceptions & LOG_ACCESS) && e.system_errcode() == -EACCES) || ((m_log_exceptions & LOG_PERM) && e.system_errcode() == -EPERM) ) { m_fail_count++; string msg = "Device " + devid.GetUsbName() + ": "; if( e.system_errcode() == -EBUSY ) msg += "(EBUSY) "; else if( e.system_errcode() == -EACCES ) msg += "(EACCES) "; else if( e.system_errcode() == -EPERM ) msg += "(EPERM) "; msg += e.what(); m_fail_msgs.push_back(msg); } else { throw; } } } void Probe::ProbeDevice(Usb::DeviceID& devid) { // skip if we can't properly discover device config DeviceDescriptor desc(devid); ConfigDescriptor* config = desc[BLACKBERRY_CONFIGURATION]; if( !config ) { dout(_("Probe: No device descriptor for BlackBerry config (config id: ") << BLACKBERRY_CONFIGURATION << ")"); return; // not found } // search for interface class ConfigDescriptor::base_type::iterator idi = config->begin(); for( ; idi != config->end(); idi++ ) { if( idi->second->GetClass() == BLACKBERRY_DB_CLASS ) break; } if( idi == config->end() ) { dout(string_vprintf(_("Probe: Interface with BLACKBERRY_DB_CLASS (%u) not found."), BLACKBERRY_DB_CLASS)); return; // not found } unsigned char InterfaceNumber = idi->second->GetNumber(); unsigned char InterfaceAltSetting = idi->second->GetAltSetting(); dout("Probe: using InterfaceNumber: " << (unsigned int) InterfaceNumber << " AltSetting: " << (unsigned int) InterfaceAltSetting); // check endpoint validity EndpointPairings ep(*(*config)[InterfaceNumber]); if( !ep.IsValid() || ep.size() == 0 ) { dout(_("Probe: endpoint invalid.") << " ep.IsValid() == " << (ep.IsValid() ? _("true") : _("false")) << ", ep.size() == " << ep.size()); return; } ProbeResult result; result.m_dev = devid; result.m_interface = InterfaceNumber; result.m_altsetting = InterfaceAltSetting; result.m_zeroSocketSequence = 0; // open device Device dev(devid); // dev.Reset(); // sleep(5); // make sure we're talking to the right config unsigned char cfg; if( !dev.GetConfiguration(cfg) ) throw Usb::Error(dev.GetLastError(), _("Probe: GetConfiguration failed")); if( cfg != BLACKBERRY_CONFIGURATION || MUST_SET_CONFIGURATION ) { if( !dev.SetConfiguration(BLACKBERRY_CONFIGURATION) ) throw Usb::Error(dev.GetLastError(), _("Probe: SetConfiguration failed")); } // open interface Interface iface(dev, InterfaceNumber); // Try the initial probing of endpoints ProbeDeviceEndpoints(dev, ep, result); if( !result.m_ep.IsComplete() ) { // Probing of end-points failed, so try reprobing // after calling usb_set_altinterface(). // // Calling usb_set_altinterface() should be harmless // and can help the host and device to synchronize the // USB state, especially on FreeBSD and Mac OS X. // However it can cause usb-storage URBs to be lost // on some devices, so is only used if necessary. dout(_("Probe: probing endpoints failed, retrying after setting alternate interface")); iface.SetAltInterface(InterfaceAltSetting); result.m_needSetAltInterface = true; ProbeDeviceEndpoints(dev, ep, result); } // add to list if( result.m_ep.IsComplete() ) { // before adding to list, try to load the device's // friendly name from the configfile... but don't // fail if we can't do it try { ConfigFile cfg(result.m_pin); result.m_cfgDeviceName = cfg.GetDeviceName(); } catch( Barry::ConfigFileError & ) { // ignore... } m_results.push_back(result); ddout("Using ReadEndpoint: " << (unsigned int)result.m_ep.read); ddout(" WriteEndpoint: " << (unsigned int)result.m_ep.write); } else { ddout(_("Unable to discover endpoint pair for one device.")); } } void Probe::ProbeDeviceEndpoints(Device &dev, EndpointPairings &ed, ProbeResult &result) { if( m_epp_override ) { // user has given us endpoints to try... so try them uint32_t pin; uint8_t zeroSocketSequence; std::string desc; bool needClearHalt; if( ProbePair(dev, m_epp, pin, desc, zeroSocketSequence, needClearHalt) ) { // looks good, finish filling out the result result.m_ep = m_epp; result.m_pin = pin; result.m_description = desc; result.m_zeroSocketSequence = zeroSocketSequence; result.m_needClearHalt = needClearHalt; } } else { // find the first bulk read/write endpoint pair that answers // to our probe commands // Start with second pair, since evidence indicates the later pairs // are the ones we need. size_t i; for(i = ed.size() > 1 ? 1 : 0; i < ed.size(); i++ ) { const EndpointPair &ep = ed[i]; if( ep.type == Usb::EndpointDescriptor::BulkType ) { uint32_t pin; uint8_t zeroSocketSequence; std::string desc; bool needClearHalt; if( ProbePair(dev, ep, pin, desc, zeroSocketSequence, needClearHalt) ) { result.m_ep = ep; result.m_pin = pin; result.m_description = desc; result.m_zeroSocketSequence = zeroSocketSequence; result.m_needClearHalt = needClearHalt; break; } } else { dout(_("Probe: Skipping non-bulk endpoint pair (offset: ") << i-1 << ") "); } } // check for ip modem endpoints i++; if( i < ed.size() ) { const EndpointPair &ep = ed[i]; if( ProbeModem(dev, ep) ) { result.m_epModem = ep; } } } } bool Probe::ProbePair(Usb::Device &dev, const Usb::EndpointPair &ep, uint32_t &pin, std::string &desc, uint8_t &zeroSocketSequence, bool &needClearHalt) { // Initially assume that clear halt isn't needed as it causes some // devices to drop packets. The suspicion is that the toggle bits // get out of sync, but this hasn't been confirmed with hardware // tracing. // // It is possible to always use clear halt, as long as SET // INTERFACE has been sent before, via usb_set_altinterface(). // However this has the side affect that any outstanding URBs // on other interfaces (i.e. usb-storage) timeout and lose // their data. This is not a good thing as it can corrupt the // file system exposed over usb-storage. This also has the // side-affect that usb-storage issues a port reset after the // 30 second timeout, which kills any current Barry // connection. // // To further complicate matters some devices, such as the // 8830, always need clear halt before they will respond to // probes. // // So to work with all these device quirks the probe is first // attempted without calling clear halt. If that probe fails // then a clear halt is issued followed by a retry on the // probing. needClearHalt = false; Data data; dev.BulkDrain(ep.read); if( !Intro(0, ep, dev, data) ) { // Try clearing halt and then reprobing dout(_("Probe: Intro(0) failed, retrying after clearing halt")); dev.ClearHalt(ep.read); dev.ClearHalt(ep.write); needClearHalt = true; // Retry dev.BulkDrain(ep.read); if( !Intro(0, ep, dev, data) ) { // Still no response so fail the probe dout(_("Probe: Intro(0) still failed after clearing halt")); return false; } } SocketZero socket(dev, ep.write, ep.read); Data send, receive; ZeroPacket packet(send, receive); // unknown attribute: 0x14 / 0x01 packet.GetAttribute(SB_OBJECT_INITIAL_UNKNOWN, SB_ATTR_INITIAL_UNKNOWN); socket.Send(packet); // fetch PIN packet.GetAttribute(SB_OBJECT_PROFILE, SB_ATTR_PROFILE_PIN); socket.Send(packet); if( packet.ObjectID() != SB_OBJECT_PROFILE || packet.AttributeID() != SB_ATTR_PROFILE_PIN || !ParsePIN(receive, pin) ) { dout(_("Probe: unable to fetch PIN")); return false; } // fetch Description packet.GetAttribute(SB_OBJECT_PROFILE, SB_ATTR_PROFILE_DESC); socket.Send(packet); // response ObjectID does not match request... :-/ if( // packet.ObjectID() != SB_OBJECT_PROFILE || packet.AttributeID() != SB_ATTR_PROFILE_DESC || !ParseDesc(receive, desc) ) { dout(_("Probe: unable to fetch description")); } // more unknowns: for( uint16_t attr = 5; attr < 9; attr++ ) { packet.GetAttribute(SB_OBJECT_SOCKET_UNKNOWN, attr); socket.Send(packet); // FIXME parse these responses, if they turn // out to be important } // all info obtained! zeroSocketSequence = socket.GetZeroSocketSequence(); return true; } bool Probe::ProbeModem(Usb::Device &dev, const Usb::EndpointPair &ep) { // // This check is not needed for all devices. Some devices, // like the 8700 have both the RIM_UsbSerData mode and IpModem mode. // // If this function is called, then we have extra endpoints, // so might as well try them. // // FIXME - someday, we might wish to confirm that the endpoints // work as a modem, and return true/false based on that test. // return true; // Thanks to Rick Scott (XmBlackBerry:bb_usb.c) for reverse engineering this // int num_read; // char data[255]; // int local_errno; // // num_read = usb_control_msg(dev.GetHandle(), // /* bmRequestType */ USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, // /* bRequest */ 0xa5, // /* wValue */ 0, // /* wIndex */ 1, // /* data */ data, // /* wLength */ sizeof(data), // /* timeout */ 2000); // local_errno = errno; // if( num_read > 1 ) { // if( data[0] == 0x02 ) { // return true; // } // } // return false; } int Probe::FindActive(Barry::Pin pin) const { return FindActive(m_results, pin); } int Probe::FindActive(const Barry::Probe::Results &results, Barry::Pin pin) { int i = Find(results, pin); if( i == -1 && pin == 0 ) { // can we default to a single device? if( results.size() == 1 ) return 0; // yes! } return i; } int Probe::Find(const Results &results, Barry::Pin pin) { Barry::Probe::Results::const_iterator ci = results.begin(); for( int i = 0; ci != results.end(); i++, ++ci ) { if( ci->m_pin == pin ) return i; } // PIN not found return -1; } void ProbeResult::DumpAll(std::ostream &os) const { ios_format_state state(os); os << *this << ", Interface: 0x" << std::hex << (unsigned int) m_interface << ", Endpoints: (read: 0x" << std::hex << (unsigned int) m_ep.read << ", write: 0x" << std::hex << (unsigned int) m_ep.write << ", type: 0x" << std::hex << (unsigned int) m_ep.type << ", ZeroSocketSequence: 0x" << std::hex << (unsigned int) m_zeroSocketSequence; } std::string ProbeResult::GetDisplayName() const { std::ostringstream oss; oss << m_pin.Str(); if( m_cfgDeviceName.size() ) oss << " (" << m_cfgDeviceName << ")"; return oss.str(); } std::ostream& operator<< (std::ostream &os, const ProbeResult &pr) { ios_format_state state(os); os << _("Device ID: ") << pr.m_dev.m_impl.get() << ". " << _("PIN: ") << pr.m_pin.Str() << ", " << _("Description: ") << pr.m_description; if( pr.m_cfgDeviceName.size() ) os << ", " << _("Name: ") << pr.m_cfgDeviceName; return os; } } // namespace Barry barry-0.18.5/src/dataqueue.cc0000644001161500056700000001302512242254476015331 0ustar cdfreycdfrey/// /// \file dataqueue.cc /// FIFO queue of Data objects /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "dataqueue.h" #include "scoped_lock.h" #include "data.h" #include "time.h" #include using namespace std; namespace Barry { ////////////////////////////////////////////////////////////////////////////// // DataQueue class DataQueue::DataQueue() { pthread_mutex_init(&m_waitMutex, NULL); pthread_cond_init(&m_waitCond, NULL); pthread_mutex_init(&m_accessMutex, NULL); } DataQueue::~DataQueue() { scoped_lock lock(m_accessMutex); // FIXME - is this sane? while( m_queue.size() ) { delete raw_pop(); } } // a push without locking - adds to the back void DataQueue::raw_push(Data *data) { try { m_queue.push_back(data); } catch(...) { delete data; throw; } } // a pop without locking - removes from the front, and returns it Data* DataQueue::raw_pop() { if( m_queue.size() == 0 ) return 0; Data *ret = m_queue.front(); m_queue.pop_front(); return ret; } // // push // /// Pushes data into the end of the queue. /// /// The queue owns this pointer as soon as the function is /// called. In the case of an exception, it will be freed. /// Performs a thread broadcast once new data has been added. /// void DataQueue::push(Data *data) { { scoped_lock lock(m_accessMutex); raw_push(data); } // on success, signal scoped_lock wait(m_waitMutex); pthread_cond_broadcast(&m_waitCond); } // // pop // /// Pops the next element off the front of the queue. /// /// Returns 0 if empty. /// The queue no longer owns this pointer upon return. /// Data* DataQueue::pop() { scoped_lock lock(m_accessMutex); return raw_pop(); } // // wait_pop // /// Pops the next element off the front of the queue, and /// waits until one exists if empty. If still no data /// on timeout, returns null. /// (unlock the access mutex while waiting!) /// /// Timeout specified in milliseconds. Default is wait forever. /// Data* DataQueue::wait_pop(int timeout) { // check if something's there already { scoped_lock access(m_accessMutex); if( m_queue.size() ) { return raw_pop(); } } // nothing there, so wait... if( timeout == -1 ) { // no timeout int size = 0; do { { scoped_lock wait(m_waitMutex); pthread_cond_wait(&m_waitCond, &m_waitMutex); } // anything there? scoped_lock access(m_accessMutex); size = m_queue.size(); if( size != 0 ) { // already have the lock, return now return raw_pop(); } } while( size == 0 ); } else { // timeout in conditional wait struct timespec to; scoped_lock wait(m_waitMutex); pthread_cond_timedwait(&m_waitCond, &m_waitMutex, ThreadTimeout(timeout, &to)); } scoped_lock access(m_accessMutex); return raw_pop(); } // // append_from // /// Pops all data from other and appends it to this. /// /// After calling this function, other will be empty, and /// this will contain all its data. /// /// In the case of an exception, any uncopied data will /// remain in other. /// /// This is a locking optimization, so all copying can happen /// inside one lock, instead of locking for each copy. /// void DataQueue::append_from(DataQueue &other) { scoped_lock us(m_accessMutex); scoped_lock them(other.m_accessMutex); while( other.m_queue.size() ) { raw_push( other.m_queue.front() ); // only pop after the copy, since in the // case of an exception we want to leave other intact other.raw_pop(); } } // // empty // /// Returns true if the queue is empty. /// bool DataQueue::empty() const { scoped_lock access(m_accessMutex); return m_queue.size() == 0; } // // size // /// Returns number of items in the queue. /// size_t DataQueue::size() const { scoped_lock access(m_accessMutex); return m_queue.size(); } void DataQueue::DumpAll(std::ostream &os) const { // queue is pushed to the back, and popped from the front // (see raw_() functions) so this iterator direction will // print the packets in the order they arrived scoped_lock access(m_accessMutex); queue_type::const_iterator b = m_queue.begin(), e = m_queue.end(); for( ; b != e; ++b ) { os << **b << endl; } } } // namespace Barry #ifdef __DQ_TEST_MODE__ #include using namespace std; using namespace Barry; void *WriteThread(void *userdata) { DataQueue *dq = (DataQueue*) userdata; dq->push( new Data ); dq->push( new Data ); sleep(5); dq->push( new Data ); return 0; } void *ReadThread(void *userdata) { DataQueue *dq = (DataQueue*) userdata; sleep(1); if( Data *d = dq->pop() ) { cout << "Received via pop: " << d << endl; delete d; } else { cout << "No data in the queue yet." << endl; } while( Data *d = dq->wait_pop(5010) ) { cout << "Received: " << d << endl; delete d; } return 0; } int main() { DataQueue from; from.push( new Data ); DataQueue dq; dq.append_from(from); pthread_t t1, t2; pthread_create(&t1, NULL, &ReadThread, &dq); pthread_create(&t2, NULL, &WriteThread, &dq); pthread_join(t2, NULL); pthread_join(t1, NULL); } #endif barry-0.18.5/src/barrybackup.h0000644001161500056700000000161312242254476015522 0ustar cdfreycdfrey/// /// \file barrybackup.h /// Main header file for libbarrybackup /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_BARRYBACKUP_H__ #define __BARRY_BARRYBACKUP_H__ // Include only the public backup / restore headers // (not tarfile) #include "backup.h" #include "restore.h" #endif barry-0.18.5/src/cod.cc0000644001161500056700000001410512242254476014120 0ustar cdfreycdfrey/// /// \file cod.cc /// COD file API /// /* Copyright (C) 2009-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2008-2009, Nicolas VIVIEN Copyright (C) 2009, Josh Kropf 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "cod.h" #include "cod-internal.h" #include "error.h" #include "endian.h" #include #include #include #include #include #include #ifdef HAVE_ZLIB #include #endif using namespace std; namespace Barry { size_t SeekNextCod(std::istream &input) { unsigned char codtype_simple[] = CODFILE_TYPE_SIMPLE; char codtype_pkzip[] = CODFILE_TYPE_PKZIP; char local_file_sig[] = PKZIP_LOCAL_FILE_SIG; char directory_sig[] = PKZIP_DIRECTORY_SIG; char signature[4]; // finished reading stream containing single cod file input.peek(); if( input.eof() ) { return 0; } if( input.read(signature, sizeof(signature)).eof() ) { throw Error(_("SeekNextCod: EOF while reading file signature")); } if( memcmp(signature, codtype_pkzip, sizeof(codtype_pkzip)) == 0 ) { if( memcmp(signature, local_file_sig, sizeof(signature)) == 0 ) { pkzip_local_header_t header; if( input.read((char *)&header, sizeof(pkzip_local_header_t)).eof() ) { throw Error(_("SeekNextCod: EOF while reading PKZIP header")); } // skip cod file name and extra field, we don't need them size_t skip_len = header.file_name_length + header.extra_field_length; if( input.ignore(skip_len).eof() ) { throw Error(_("SeekNextCod: EOF while skipping unused fields")); } return btohl(header.compressed_size); } else if( memcmp(signature, directory_sig, sizeof(signature)) == 0 ) { // done reading when central directory is reached return 0; } } else if( memcmp(signature, codtype_simple, sizeof(codtype_simple)) == 0 ) { // find and return size of cod file if( input.seekg(0, ios::end).fail() ) { throw Error(_("SeekNextCod: seek to end failed")); } uint32_t size = input.tellg(); if( input.seekg(0, ios::beg).fail() ) { throw Error(_("SeekNextCod: seek to start failed")); } return size; } else { throw Error(_("SeekNextCod: unknown COD file signature")); } return 0; } CodFileBuilder::CodFileBuilder(const std::string &module_name, size_t module_count) : m_module_name(module_name) , m_module_count(module_count) , m_current_module(0) { } CodFileBuilder::~CodFileBuilder() { } void CodFileBuilder::WriteNextHeader(std::ostream &output, const uint8_t* module_buffer, uint32_t module_size) { // ignored for single module .cod files (simple .cod file) if( m_module_count == 1 ) { return; } // 32bit CRC of module in file header and directory entry // using zero for CRC will result in warnings when inflating .cod file uint32_t crc = 0; #ifdef HAVE_ZLIB crc = crc32(0, NULL, module_size); crc = crc32(crc, module_buffer, module_size); #endif // .cod file name for siblings have hyphenated index number, name-1.cod std::ostringstream file_name(m_module_name, ios::app); if( m_current_module == 0 ) file_name << ".cod"; else file_name << "-" << m_current_module << ".cod"; // current stream pointer is relative offset to start of file entry uint32_t entry_offset = output.tellp(); // structures for the local file entry and central directory entry pkzip_local_header_t header; pkzip_directory_t entry; // zero both structs, most fields are zero memset(&header, 0, sizeof(pkzip_local_header_t)); memset(&entry, 0, sizeof(pkzip_directory_t)); char header_sig[] = PKZIP_LOCAL_FILE_SIG; output.write(header_sig, sizeof(header_sig)); // version is always 0x00A0 = 'Windows NTFS' header.version_needed = htobs(10); // time and date fields seem to randomly have invalid or fixed values // just leave them as zero //header.last_mod_time //header.last_mod_date header.crc_32 = htobl(crc); header.compressed_size = htobl(module_size); header.uncompressed_size = htobl(module_size); header.file_name_length = htobs(file_name.str().length()); // the very first cod sibling to be written has an extra field // length equal to 4, with all zeros in the field itself // all subsequent siblings have a zero length extra field //header.extra_field_length = htobs(4); output.write((char *)&header, sizeof(pkzip_local_header_t)); output << file_name.str(); char footer_sig[] = PKZIP_DIRECTORY_SIG; // version is always 0x00A0 = 'Windows NTFS' entry.version_madeby = htobs(10); entry.version_needed = htobs(10); entry.crc_32 = htobl(crc); entry.compressed_size = htobl(module_size); entry.uncompressed_size = htobl(module_size); entry.file_name_length = htobs(file_name.str().length()); entry.relative_offset = htobl(entry_offset); m_directory.write(footer_sig, sizeof(footer_sig)); m_directory.write((char*)&entry, sizeof(pkzip_directory_t)); m_directory << file_name.str(); m_current_module ++; } void CodFileBuilder::WriteFooter(std::ostream &output) { // ignored for single module .cod files (simple .cod file) if( m_module_count == 1 ) { return; } pkzip_end_directory_t end; memset(&end, 0, sizeof(pkzip_end_directory_t)); end.this_disk_entry_count = htobs(m_current_module); end.total_entry_count = htobs(m_current_module); end.directory_length = htobl(m_directory.str().length()); // current stream pointer is relative offset to start of directory end.directory_offset = output.tellp(); char sig[] = PKZIP_END_DIRECTORY_SIG; output.write(m_directory.str().data(), m_directory.str().length()); output.write(sig, sizeof(sig)); output.write((char *)&end, sizeof(pkzip_end_directory_t)); } } // namespace Barry barry-0.18.5/src/vformat.c0000644001161500056700000015340612242254476014676 0ustar cdfreycdfrey/* * Copyright (C) 2003 Ximian, Inc. * * 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. * * Author: Chris Toshok (toshok@ximian.com) * Author: Armin Bauer (armin.bauer@opensync.org) * */ #include "i18n.h" #include "vformat.h" #include "clog.h" //#ifdef HAVE_CONFIG_H //#include "config.h" //#endif #include #include #include #include #include //#include #define TRACE_INTERNAL 1 #define TRACE_ENTRY 1 #define TRACE_EXIT 1 #define TRACE_ERROR 0 static size_t base64_encode_step(const unsigned char *in, size_t len, gboolean break_lines, unsigned char *out, int *state, int *save); static size_t base64_decode_step(const unsigned char *in, size_t len, unsigned char *out, int *state, unsigned int *save); static size_t base64_decode_simple (char *data, size_t len); static char *base64_encode_simple (const char *data, size_t len); static size_t quoted_decode_simple (char *data, size_t len); static char *quoted_encode_simple (const unsigned char *string, int len); /** * _helper_is_base64 is helper function to check i a string is "b" or "base64" * @param check_string string that should be compared with "b" or "base64" * @return 0 if check_string is not base64 and 1 if it is */ static int _helper_is_base64(const char *check_string) { if(!g_ascii_strcasecmp ((char *) check_string, "BASE64") || !g_ascii_strcasecmp ((char *) check_string, "b") ) return (1); return (0); } time_t b_vformat_time_to_unix(const char *inptime) { char *date = NULL; char *time = NULL; char *ftime = NULL; if ((ftime = g_strrstr(inptime, "T"))) { date = g_strndup(inptime, ftime - inptime); if (ftime[3] == ':') time = g_strndup(ftime + 1, 8); else time = g_strndup(ftime + 1, 6); } else { date = g_strdup(inptime); } struct tm btime; memset(&btime, 0, sizeof(struct tm)); btime.tm_isdst = -1; if (strlen(date) == 10) { btime.tm_year = date[0] * 1000 + date[1] * 100 + date[2] * 10 + date[3] - '0' * 1111 - 1900; btime.tm_mon = date[5] * 10 + date[6] - '0' * 11 - 1; btime.tm_mday = date[8] * 10 + date[9] - '0' * 11; } else { btime.tm_year = date[0] * 1000 + date[1] * 100 + date[2] * 10 + date[3] - '0' * 1111- 1900; btime.tm_mon = date[4] * 10 + date[5] - '0' * 11 - 1; btime.tm_mday = date[6] * 10 + date[7] - '0' * 11; } if (time && strlen(time) == 8) { //Time btime.tm_hour = time[0] * 10 + time[1] - '0' * 11; btime.tm_min = time[3] * 10 + time[4] - '0' * 11; btime.tm_sec = time[6] * 10 + time[7] - '0' * 11; } else if (time && strlen(time) == 6) { btime.tm_hour = time[0] * 10 + time[1] - '0' * 11; btime.tm_min = time[2] * 10 + time[3] - '0' * 11; btime.tm_sec = time[4] * 10 + time[5] - '0' * 11; } time_t utime = mktime(&btime); return utime; } static char *_unfold_lines (char *buf) { GString *str = g_string_new (""); GString *line = g_string_new (""); char *p = buf; char *next, *next2, *q; gboolean newline = TRUE; gboolean quotedprintable = FALSE; /* * We're pretty liberal with line folding here. We handle * lines folded with \r\n, \n\r, \n, =\r\n and =\n\r. * We also turn single \r's and \n's not followed by into \r\n's. */ while (*p) { /* search new lines for quoted printable encoding */ if (newline) { for (q=p; *q != '\n' && *q != '\0'; q++) line = g_string_append_unichar (line, g_utf8_get_char (q)); if (strstr(line->str, "ENCODING=QUOTED-PRINTABLE")) quotedprintable = TRUE; g_string_free(line, TRUE); line = g_string_new (""); newline = FALSE; } if ((quotedprintable && *p == '=') || *p == '\r' || *p == '\n') { next = g_utf8_next_char (p); if (*next == '\n' || *next == '\r') { next2 = g_utf8_next_char (next); if (*next2 == '\n' || *next2 == '\r' || *next2 == ' ' || *next2 == '\t') { p = g_utf8_next_char (next2); } else if(quotedprintable && (*p == '=')) { p = g_utf8_next_char (next); } else { str = g_string_append (str, CRLF); p = g_utf8_next_char (next); newline = TRUE; quotedprintable = FALSE; } } else if (*p == '=') { str = g_string_append_unichar (str, g_utf8_get_char (p)); p = g_utf8_next_char (p); } else if (*next == ' ' || *next == '\t') { p = g_utf8_next_char (next); } else { str = g_string_append (str, CRLF); p = g_utf8_next_char (p); newline = TRUE; quotedprintable = FALSE; } } else { str = g_string_append_unichar (str, g_utf8_get_char (p)); p = g_utf8_next_char (p); } } g_free (buf); g_string_free(line, TRUE); return g_string_free (str, FALSE); } /* skip forward until we hit the CRLF, or \0 */ static void _skip_to_next_line (char **p) { char *lp; lp = *p; while (*lp != '\r' && *lp != '\0') lp = g_utf8_next_char (lp); if (*lp == '\r') { lp = g_utf8_next_char (lp); /* \n */ lp = g_utf8_next_char (lp); /* start of the next line */ } *p = lp; } /* skip forward until we hit a character in @s, CRLF, or \0. leave *p pointing at the character that causes us to stop */ static void _skip_until (char **p, char *s) { char *lp; lp = *p; while (*lp != '\r' && *lp != '\0') { gboolean s_matches = FALSE; char *ls; for (ls = s; *ls; ls = g_utf8_next_char (ls)) { if (g_utf8_get_char (ls) == g_utf8_get_char (lp)) { s_matches = TRUE; break; } } if (s_matches) break; lp++; } *p = lp; } static void _read_attribute_value_add (b_VFormatAttribute *attr, GString *str, GString *charset) { /* don't convert empty strings */ if (str->len == 0) { b_vformat_attribute_add_value(attr, str->str); return; } char *inbuf, *outbuf, *p; size_t inbytesleft, outbytesleft; inbuf = str->str; p = outbuf = malloc(str->len*2); inbytesleft = str->len; outbytesleft = str->len*2; iconv_t cd; /* if a CHARSET was given, let's try to convert inbuf to UTF-8 */ if (charset) { cd = iconv_open("UTF-8", charset->str); #ifdef SOLARIS if (iconv(cd, (const char**)&inbuf, &inbytesleft, &p, &outbytesleft) != (size_t)(-1)) { #else if (iconv(cd, &inbuf, &inbytesleft, &p, &outbytesleft) != (size_t)(-1)) { #endif *p = 0; b_vformat_attribute_add_value(attr, outbuf); } else { /* hmm, should not happen */ b_vformat_attribute_add_value(attr, str->str); } iconv_close(cd); } else { /* no CHARSET was given, if inbuf is already UTF-8 we add str->str */ if (g_utf8_validate (inbuf, -1, NULL)) { b_vformat_attribute_add_value (attr, str->str); } else { /* because inbuf is not UTF-8, we think it is ISO-8859-1 */ cd = iconv_open("UTF-8", "ISO-8859-1"); #ifdef SOLARIS if (iconv(cd, (const char**)&inbuf, &inbytesleft, &p, &outbytesleft) != (size_t)(-1)) { #else if (iconv(cd, &inbuf, &inbytesleft, &p, &outbytesleft) != (size_t)(-1)) { #endif *p = 0; b_vformat_attribute_add_value (attr, outbuf); } else { b_vformat_attribute_add_value (attr, str->str); } iconv_close(cd); } } free(outbuf); } static void _read_attribute_value (b_VFormatAttribute *attr, char **p, int format_encoding, GString *charset) { char *lp = *p; GString *str; /* read in the value */ str = g_string_new (""); while (*lp != '\r' && *lp != '\0') { if (*lp == '=' && format_encoding == VF_ENCODING_QP) { char a, b, x1=0, x2=0; if ((a = *(++lp)) == '\0') break; if ((b = *(++lp)) == '\0') break; if (isalnum(a)) { if (isalnum(b)) { /* e.g. ...N=C3=BCrnberg\r\n * ^^^ */ x1=a; x2=b; } else if (b == '=') { /* e.g. ...N=C=\r\n * ^^^ * 3=BCrnberg... * ^ */ char *tmplp = lp; if (*(++tmplp) == '\r' && *(++tmplp) == '\n' && isalnum(*(++tmplp))) { x1 = a; x2 = *tmplp; lp = tmplp; } } else { /* append malformed input, and continue parsing */ str = g_string_append_c(str, a); str = g_string_append_c(str, b); } } else if (a == '=') { char *tmplp = lp; char c, d, e; c = *(++tmplp); d = *(++tmplp); e = *(++tmplp); if (b == '\r' && c == '\n' && isalnum(d) && isalnum(e)) { x1 = d; x2 = e; lp = tmplp; } else { /* append malformed input, and continue parsing */ str = g_string_append_c(str, a); str = g_string_append_c(str, b); } } else { /* append malformed input, and continue parsing */ str = g_string_append_c(str, a); str = g_string_append_c(str, b); } if (x1 && x2) { char c; a = tolower (x1); b = tolower (x2); c = (((a>='a'?a-'a'+10:a-'0')&0x0f) << 4) | ((b>='a'?b-'a'+10:b-'0')&0x0f); str = g_string_append_c (str, c); } lp++; x1 = x2 = 0; } else if (format_encoding == VF_ENCODING_BASE64) { if((*lp != ' ') && (*lp != '\t') ) str = g_string_append_unichar (str, g_utf8_get_char (lp)); lp = g_utf8_next_char(lp); } else if (*lp == '\\') { /* convert back to the non-escaped version of the characters */ lp = g_utf8_next_char(lp); if (*lp == '\0') { str = g_string_append_c (str, '\\'); break; } switch (*lp) { case 'n': str = g_string_append_c (str, '\n'); break; case 'r': str = g_string_append_c (str, '\r'); break; case ';': str = g_string_append_c (str, ';'); break; case ',': if (!g_ascii_strcasecmp (attr->name, "CATEGORIES")) { //We need to handle categories here to work //aroung a bug in evo2 _read_attribute_value_add (attr, str, charset); g_string_assign (str, ""); } else str = g_string_append_c (str, ','); break; case '\\': str = g_string_append_c (str, '\\'); break; case '"': str = g_string_append_c (str, '"'); break; /* \t is (incorrectly) used by kOrganizer, so handle it here */ case 't': str = g_string_append_c (str, '\t'); break; default: BarryLogf(TRACE_INTERNAL, _("invalid escape, passing it through. escaped char was %u"), (unsigned int)*lp); str = g_string_append_c (str, '\\'); str = g_string_append_unichar (str, g_utf8_get_char(lp)); break; } lp = g_utf8_next_char(lp); } else if ((*lp == ';') || (*lp == ',' && !g_ascii_strcasecmp (attr->name, "CATEGORIES"))) { _read_attribute_value_add (attr, str, charset); g_string_assign (str, ""); lp = g_utf8_next_char(lp); } else { str = g_string_append_unichar (str, g_utf8_get_char (lp)); lp = g_utf8_next_char(lp); } } if (str) { _read_attribute_value_add (attr, str, charset); g_string_free (str, TRUE); } if (*lp == '\r') { lp = g_utf8_next_char (lp); /* \n */ lp = g_utf8_next_char (lp); /* start of the next line */ } *p = lp; } static void _read_attribute_params(b_VFormatAttribute *attr, char **p, int *format_encoding, GString **charset) { char *lp = *p; GString *str; b_VFormatParam *param = NULL; gboolean in_quote = FALSE; str = g_string_new (""); while (*lp != '\0') { if (*lp == '"') { in_quote = !in_quote; lp = g_utf8_next_char (lp); } else if (in_quote || g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_' || *lp == '/' || *lp == '.' || *lp == ' ') { str = g_string_append_unichar (str, g_utf8_get_char (lp)); lp = g_utf8_next_char (lp); } /* accumulate until we hit the '=' or ';'. If we hit * a '=' the string contains the parameter name. if * we hit a ';' the string contains the parameter * value and the name is either ENCODING (if value == * QUOTED-PRINTABLE) or TYPE (in any other case.) */ else if (*lp == '=') { if (str->len > 0) { param = b_vformat_attribute_param_new (str->str); g_string_assign (str, ""); lp = g_utf8_next_char (lp); } else { _skip_until (&lp, ":;"); if (*lp == '\r') { lp = g_utf8_next_char (lp); /* \n */ lp = g_utf8_next_char (lp); /* start of the next line */ break; } else if (*lp == ';') lp = g_utf8_next_char (lp); } } else if (*lp == ';' || *lp == ':' || *lp == ',') { gboolean colon = (*lp == ':'); gboolean comma = (*lp == ','); if (param) { if (str->len > 0) { b_vformat_attribute_param_add_value (param, str->str); g_string_assign (str, ""); if (!colon) lp = g_utf8_next_char (lp); } else { /* we've got a parameter of the form: * PARAM=(.*,)?[:;] * so what we do depends on if there are already values * for the parameter. If there are, we just finish * this parameter and skip past the offending character * (unless it's the ':'). If there aren't values, we free * the parameter then skip past the character. */ if (!param->values) { b_vformat_attribute_param_free (param); param = NULL; if (!colon) lp = g_utf8_next_char (lp); } } if (param && !g_ascii_strcasecmp (param->name, "encoding")) { if (!g_ascii_strcasecmp (param->values->data, "quoted-printable")) { *format_encoding = VF_ENCODING_QP; b_vformat_attribute_param_free (param); param = NULL; } else if ( _helper_is_base64(param->values->data)) { *format_encoding = VF_ENCODING_BASE64; // b_vformat_attribute_param_free (param); // param = NULL; } } else if (param && !g_ascii_strcasecmp(param->name, "charset")) { *charset = g_string_new(param->values->data); b_vformat_attribute_param_free (param); param = NULL; } } else { if (str->len > 0) { char *param_name; if (!g_ascii_strcasecmp (str->str, "quoted-printable")) { param_name = "ENCODING"; *format_encoding = VF_ENCODING_QP; } /* apple's broken addressbook app outputs naked BASE64 parameters, which aren't even vcard 3.0 compliant. */ else if (!g_ascii_strcasecmp (str->str, "base64")) { param_name = "ENCODING"; g_string_assign (str, "b"); *format_encoding = VF_ENCODING_BASE64; } else { param_name = "TYPE"; } if (param_name) { param = b_vformat_attribute_param_new (param_name); b_vformat_attribute_param_add_value (param, str->str); } g_string_assign (str, ""); if (!colon) lp = g_utf8_next_char (lp); } else { /* we've got an attribute with a truly empty attribute parameter. So it's of the form: ATTR;[PARAM=value;]*;[PARAM=value;]*: (note the extra ';') the only thing to do here is, well.. nothing. we skip over the character if it's not a colon, and the rest is handled for us: We'll either continue through the loop again if we hit a ';', or we'll break out correct below if it was a ':' */ if (!colon) lp = g_utf8_next_char (lp); } } if (param && !comma) { b_vformat_attribute_add_param (attr, param); param = NULL; } if (colon) break; } else { BarryLogf(TRACE_INTERNAL, _("invalid character found in parameter spec: \"%i\" String so far: %s"), lp[0], str->str); g_string_assign (str, ""); _skip_until (&lp, ":;"); } } if (str) g_string_free (str, TRUE); *p = lp; } /* reads an entire attribute from the input buffer, leaving p pointing at the start of the next line (past the \r\n) */ static b_VFormatAttribute *_read_attribute (char **p) { char *attr_group = NULL; char *attr_name = NULL; b_VFormatAttribute *attr = NULL; GString *str, *charset = NULL; char *lp = *p; gboolean is_qp = FALSE; /* first read in the group/name */ str = g_string_new (""); while (*lp != '\r' && *lp != '\0') { if (*lp == ':' || *lp == ';') { if (str->len != 0) { /* we've got a name, break out to the value/attribute parsing */ attr_name = g_string_free (str, FALSE); break; } else { /* a line of the form: * (group.)?[:;] * * since we don't have an attribute * name, skip to the end of the line * and try again. */ g_string_free (str, TRUE); *p = lp; _skip_to_next_line(p); goto lose; } } else if (*lp == '.') { if (attr_group) { BarryLogf(TRACE_INTERNAL, _("extra `.' in attribute specification. ignoring extra group `%s'"), str->str); g_string_free (str, TRUE); str = g_string_new (""); } if (str->len != 0) { attr_group = g_string_free (str, FALSE); str = g_string_new (""); } } else if (g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_' || *lp == '/') { str = g_string_append_unichar (str, g_utf8_get_char (lp)); } else { BarryLogf(TRACE_INTERNAL, _("invalid character found in attribute group/name: \"%i\" String so far: %s"), lp[0], str->str); g_string_free (str, TRUE); *p = lp; _skip_to_next_line(p); goto lose; } lp = g_utf8_next_char(lp); } if (!attr_name) { _skip_to_next_line (p); goto lose; } attr = b_vformat_attribute_new (attr_group, attr_name); g_free (attr_group); g_free (attr_name); if (*lp == ';') { /* skip past the ';' */ lp = g_utf8_next_char(lp); _read_attribute_params (attr, &lp, &is_qp, &charset); } if (*lp == ':') { /* skip past the ':' */ lp = g_utf8_next_char(lp); _read_attribute_value (attr, &lp, is_qp, charset); } if (charset) g_string_free(charset, TRUE); *p = lp; if (!attr->values) goto lose; return attr; lose: if (attr) b_vformat_attribute_free (attr); return NULL; } static void open_block(char **block, const char *block_name) { char *start = *block ? *block : ""; char *result = NULL; result = g_strconcat(start, "/", block_name, NULL); if( *block ) g_free(*block); *block = result; } static void close_block(char **block, const char *block_name) { int name_len = strlen(block_name); int block_len = *block ? strlen(*block) : 0; char *cmp_start = NULL; if( block_len < name_len + 1 ) return; cmp_start = *block + (block_len - name_len - 1); if( cmp_start[0] == '/' && g_ascii_strcasecmp(cmp_start+1, block_name) == 0 ) { // end of block hierarchy contains block name, // so safe to remove // cut off the end of the string... no need to free/realloc *cmp_start = '\0'; } } /* we try to be as forgiving as we possibly can here - this isn't a * validator. Almost nothing is considered a fatal error. We always * try to return *something*. */ static void _parse(b_VFormat *evc, const char *str) { char *buf = g_strdup (str); char *p, *end; b_VFormatAttribute *attr; /* first validate the string is valid utf8 */ if (!g_utf8_validate (buf, -1, (const char **)&end)) { /* if the string isn't valid, we parse as much as we can from it */ BarryLogf(TRACE_INTERNAL, _("invalid utf8 passed to b_VFormat. Limping along.")); *end = '\0'; } buf = _unfold_lines (buf); p = buf; attr = _read_attribute (&p); if (!attr) attr = _read_attribute (&p); if (!attr || attr->group || g_ascii_strcasecmp (attr->name, "begin")) { BarryLogf(TRACE_INTERNAL, _("vformat began without a BEGIN\n")); } if (attr && !g_ascii_strcasecmp (attr->name, "begin")) b_vformat_attribute_free (attr); else if (attr) b_vformat_add_attribute (evc, attr); char *block = NULL; while (*p) { b_VFormatAttribute *next_attr = _read_attribute (&p); if (next_attr) { if( g_ascii_strcasecmp(next_attr->name, "begin") == 0 ) { // add to block hierarchy string char *value = b_vformat_attribute_get_value(next_attr); open_block(&block, value); //BarryLogf(TRACE_INTERNAL, "open block: %s", block); g_free(value); } else if( g_ascii_strcasecmp(next_attr->name, "end") == 0 ) { // close off the block char *value = b_vformat_attribute_get_value(next_attr); close_block(&block, value); //BarryLogf(TRACE_INTERNAL, "close block: %s", block); g_free(value); } // apply the block to the attr next_attr->block = g_strdup(block); // add! b_vformat_add_attribute (evc, next_attr); attr = next_attr; } } if (!attr || attr->group || g_ascii_strcasecmp (attr->name, "end")) { BarryLogf(TRACE_INTERNAL, _("vformat ended without END")); } g_free (buf); g_free (block); } char *b_vformat_escape_string (const char *s, b_VFormatType type) { GString *str; const char *p; str = g_string_new (""); /* Escape a string as described in RFC2426, section 5 */ for (p = s; p && *p; p++) { switch (*p) { case '\n': str = g_string_append (str, "\\n"); break; case '\r': if (*(p+1) == '\n') p++; str = g_string_append (str, "\\n"); break; case ';': str = g_string_append (str, "\\;"); break; case ',': if (type == VFORMAT_CARD_30 || type == VFORMAT_EVENT_20 || type == VFORMAT_TODO_20) str = g_string_append (str, "\\,"); else str = g_string_append_c (str, *p); break; case '\\': /** * We won't escape backslashes * on vcard 2.1, unless it is in the end of a value. * See comments above for a better explanation **/ if (*p != '\0' && type == VFORMAT_CARD_21) { BarryLogf(TRACE_INTERNAL, _("[%s]We won't escape backslashes"), __func__); str = g_string_append_c(str, *p); } else { BarryLogf(TRACE_INTERNAL, _("[%s] escape backslashes!!"), __func__); str = g_string_append (str, "\\\\"); } break; default: str = g_string_append_c (str, *p); break; } } return g_string_free (str, FALSE); } char* b_vformat_unescape_string (const char *s) { GString *str; const char *p; g_return_val_if_fail (s != NULL, NULL); str = g_string_new (""); /* Unescape a string as described in RFC2426, section 4 (Formal Grammar) */ for (p = s; *p; p++) { if (*p == '\\') { p++; if (*p == '\0') { str = g_string_append_c (str, '\\'); break; } switch (*p) { case 'n': str = g_string_append_c (str, '\n'); break; case 'r': str = g_string_append_c (str, '\r'); break; case ';': str = g_string_append_c (str, ';'); break; case ',': str = g_string_append_c (str, ','); break; case '\\': str = g_string_append_c (str, '\\'); break; case '"': str = g_string_append_c (str, '"'); break; /* \t is (incorrectly) used by kOrganizer, so handle it here */ case 't': str = g_string_append_c (str, '\t'); break; default: BarryLogf(TRACE_INTERNAL, _("invalid escape, passing it through. escaped char was %u"), (unsigned int)*p); str = g_string_append_c (str, '\\'); str = g_string_append_unichar (str, g_utf8_get_char(p)); break; } } } return g_string_free (str, FALSE); } void b_vformat_construct (b_VFormat *evc, const char *str) { g_return_if_fail (str != NULL); if (*str) _parse (evc, str); } void b_vformat_free(b_VFormat *format) { g_list_foreach (format->attributes, (GFunc)b_vformat_attribute_free, NULL); g_list_free (format->attributes); g_free(format); } b_VFormat *b_vformat_new_from_string (const char *str) { g_return_val_if_fail (str != NULL, NULL); b_VFormat *evc = g_malloc0(sizeof(b_VFormat)); b_vformat_construct (evc, str); return evc; } b_VFormat *b_vformat_new(void) { return b_vformat_new_from_string (""); } static int _block_match(b_VFormatAttribute *attr, const char *block) { // a block matches if the end of the attribute's block // string matches a case insensitive compare with block // // for example, a calendar may or may not start with a // BEGIN: VCALENDAR, so DTSTART's block string could be // "/vcalendar/vevent" or just "/vevent". By passing // "/vevent" or even "vevent" as the block argument above, // we should get a match for any of the above. int attr_len = attr->block ? strlen(attr->block) : 0; int block_len = block ? strlen(block) : 0; if( block == NULL ) return 1; // if block is null, match everything if( attr_len < block_len ) return 0; // not enough string to compare if( attr_len == 0 && block_len == 0 ) return 1; // empty and null strings match if( attr->block == NULL ) return 0; // don't compare if one side is null return g_ascii_strcasecmp(&attr->block[attr_len - block_len], block) == 0; } b_VFormatAttribute *b_vformat_find_attribute(b_VFormat *vcard, const char *name, int nth, const char *block) { GList *attributes = b_vformat_get_attributes(vcard); GList *a = NULL; int i = 0; for (a = attributes; a; a = a->next) { b_VFormatAttribute *attr = a->data; if (!g_ascii_strcasecmp(b_vformat_attribute_get_name(attr), name)) { if( block == NULL || _block_match(attr, block) ) { if( i == nth ) return attr; i++; } } } return NULL; } /* b_VFormatAttribute *b_vformat_find_attribute_next(b_VFormatAttribute *last, const char *name, int nth) { GList *attributes = last ? last->next : 0; GList *a = NULL; int i = 0; for (a = attributes; a; a = a->next) { b_VFormatAttribute *attr = a->data; if (!g_ascii_strcasecmp(b_vformat_attribute_get_name(attr), name)) { if( i == nth ) return attr; i++; } } return NULL; } */ char *b_vformat_to_string (b_VFormat *evc, b_VFormatType type) { BarryLogf(TRACE_ENTRY, "%s(%p, %i)", __func__, evc, type); GList *l; GList *v; GString *str = g_string_new (""); switch (type) { case VFORMAT_CARD_21: str = g_string_append (str, "BEGIN:VCARD\r\nVERSION:2.1\r\n"); break; case VFORMAT_CARD_30: str = g_string_append (str, "BEGIN:VCARD\r\nVERSION:3.0\r\n"); break; case VFORMAT_TODO_10: case VFORMAT_EVENT_10: str = g_string_append (str, "BEGIN:VCALENDAR\r\nVERSION:1.0\r\n"); break; case VFORMAT_TODO_20: case VFORMAT_EVENT_20: case VFORMAT_JOURNAL: str = g_string_append (str, "BEGIN:VCALENDAR\r\nVERSION:2.0\r\n"); break; case VFORMAT_NOTE: str = g_string_append (str, "BEGIN:VNOTE\r\nVERSION:1.1\r\n"); break; } for (l = evc->attributes; l; l = l->next) { GList *p; b_VFormatAttribute *attr = l->data; GString *attr_str; int l; int format_encoding = VF_ENCODING_RAW; attr_str = g_string_new (""); /* From rfc2425, 5.8.2 * * contentline = [group "."] name *(";" param) ":" value CRLF */ if (attr->group) { attr_str = g_string_append (attr_str, attr->group); attr_str = g_string_append_c (attr_str, '.'); } attr_str = g_string_append (attr_str, attr->name); /* handle the parameters */ for (p = attr->params; p; p = p->next) { b_VFormatParam *param = p->data; /* 5.8.2: * param = param-name "=" param-value *("," param-value) */ if( type == VFORMAT_CARD_30 || type == VFORMAT_TODO_20 || type == VFORMAT_EVENT_20 || type == VFORMAT_JOURNAL) { /** * Character set can only be specified on the CHARSET * parameter on the Content-Type MIME header field. **/ if (!g_ascii_strcasecmp (param->name, "CHARSET")) continue; attr_str = g_string_append_c (attr_str, ';'); attr_str = g_string_append (attr_str, param->name); if (param->values) { attr_str = g_string_append_c (attr_str, '='); } for (v = param->values; v; v = v->next) { if (_helper_is_base64((const char *) v->data)) { format_encoding = VF_ENCODING_BASE64; /*Only the "B" encoding of [RFC 2047] is an allowed*/ v->data=g_strdup("B"); } /** * QUOTED-PRINTABLE inline encoding has been * eliminated. **/ if (!g_ascii_strcasecmp (param->name, "ENCODING") && !g_ascii_strcasecmp ((char *) v->data, "QUOTED-PRINTABLE")) { BarryLogf(TRACE_ERROR, _("%s false encoding QUOTED-PRINTABLE is not allowed"), __func__); format_encoding = VF_ENCODING_QP; } attr_str = g_string_append (attr_str, v->data); if (v->next) attr_str = g_string_append_c (attr_str, ','); } } else { attr_str = g_string_append_c (attr_str, ';'); /** * The "TYPE=" is optional skip it. * LOGO, PHOTO and SOUND multimedia formats MUST * have a "TYPE=" parameter **/ gboolean must_have_type = FALSE; if (!g_ascii_strcasecmp (attr->name, "PHOTO") || !g_ascii_strcasecmp (attr->name, "LOGO") || !g_ascii_strcasecmp (attr->name, "SOUND") ) must_have_type = TRUE; if ( must_have_type || g_ascii_strcasecmp (param->name, "TYPE") ) attr_str = g_string_append (attr_str, param->name); if ( param->values && (must_have_type || g_ascii_strcasecmp (param->name, "TYPE")) ) attr_str = g_string_append_c (attr_str, '='); for (v = param->values; v; v = v->next) { // check for quoted-printable encoding if (!g_ascii_strcasecmp (param->name, "ENCODING") && !g_ascii_strcasecmp ((char *) v->data, "QUOTED-PRINTABLE")) format_encoding = VF_ENCODING_QP; // check for base64 encoding if (_helper_is_base64((const char *) v->data)) { format_encoding = VF_ENCODING_BASE64; v->data=g_strdup("BASE64"); } attr_str = g_string_append (attr_str, v->data); if (v->next) attr_str = g_string_append_c (attr_str, ','); } } } attr_str = g_string_append_c (attr_str, ':'); for (v = attr->values; v; v = v->next) { char *value = v->data; char *escaped_value = NULL; if (!g_ascii_strcasecmp (attr->name, "RRULE") && strstr (value, "BYDAY") == v->data) { attr_str = g_string_append (attr_str, value); } else { escaped_value = b_vformat_escape_string (value, type); attr_str = g_string_append (attr_str, escaped_value); } if (v->next) { /* XXX toshok - i hate you, rfc 2426. why doesn't CATEGORIES use a ; like a normal list attribute? */ if (!g_ascii_strcasecmp (attr->name, "CATEGORIES")) attr_str = g_string_append_c (attr_str, ','); else attr_str = g_string_append_c (attr_str, ';'); } g_free (escaped_value); } /* Folding lines: * ^^^^^^^^^^^^^^ * * rfc 2426 (vCard), 2.6 Line Delimiting and Folding: * After generating a content line, * lines longer than 75 characters SHOULD be folded according to the * folding procedure described in [MIME-DIR]. * * rfc 2445 (iCalendar), 4.1 Content Lines: * Lines of text SHOULD NOT be longer than 75 octets, excluding the line * break. Long content lines SHOULD be split into a multiple line * representations using a line "folding" technique. That is, a long * line can be split between any two characters by inserting a CRLF * immediately followed by a single linear white space character (i.e., * SPACE, US-ASCII decimal 32 or HTAB, US-ASCII decimal 9). Any sequence * of CRLF followed immediately by a single linear white space character * is ignored (i.e., removed) when processing the content type. * * SUMMARY: When generating a content line, lines longer then 75 characters SHOULD be folded! * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * * Differences between encodings: * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * * rfc 2425 [MIME-DIR], 5.8.1: * A logical line MAY be continued on the next physical line anywhere * between two characters by inserting a CRLF immediately followed by a * single (white space) character. * * rfc 2045, 6.7, chapter 5: * The quoted-printable specs says that softbreaks should be generated by inserting a =\r\n * without follwing * * UTF-8 * ^^^^^ * * Note that all the line folding above is described in terms of characters * not bytes. In particular, it would be an error to put a line break * within a UTF-8 character. */ l = 0; do { if (g_utf8_strlen(attr_str->str, attr_str->len) - l > 75) { l += 75; /* If using QP, must be sure that we do not fold within a quote sequence */ if (format_encoding == VF_ENCODING_QP) { if (g_utf8_get_char(g_utf8_offset_to_pointer(attr_str->str, l-1)) == '=') l--; else if (g_utf8_get_char(g_utf8_offset_to_pointer(attr_str->str, l-2)) == '=') l -= 2; } char *p = g_utf8_offset_to_pointer(attr_str->str, l); if (format_encoding == VF_ENCODING_QP) attr_str = g_string_insert_len (attr_str, p - attr_str->str, "=" CRLF "", sizeof ("=" CRLF "") - 1); else attr_str = g_string_insert_len (attr_str, p - attr_str->str, CRLF " ", sizeof (CRLF " ") - 1); } else break; } while (l < g_utf8_strlen(attr_str->str, attr_str->len)); attr_str = g_string_append (attr_str, CRLF); /** * base64= * the end of the text is marked with two CRLF sequences * this results in one blank line before the start of the * next property **/ if( format_encoding == VF_ENCODING_BASE64 && (type == VFORMAT_CARD_21)) attr_str = g_string_append (attr_str, CRLF); str = g_string_append (str, attr_str->str); g_string_free (attr_str, TRUE); } switch (type) { case VFORMAT_CARD_21: str = g_string_append (str, "END:VCARD\r\n"); break; case VFORMAT_CARD_30: str = g_string_append (str, "END:VCARD\r\n"); break; case VFORMAT_TODO_10: case VFORMAT_EVENT_10: str = g_string_append (str, "END:VCALENDAR\r\n"); break; case VFORMAT_TODO_20: case VFORMAT_EVENT_20: case VFORMAT_JOURNAL: str = g_string_append (str, "END:VCALENDAR\r\n"); break; case VFORMAT_NOTE: str = g_string_append (str, "END:VNOTE\r\n"); break; } BarryLogf(TRACE_EXIT, "%s", __func__); return g_string_free (str, FALSE); } void b_vformat_dump_structure (b_VFormat *evc) { GList *a; GList *v; int i; printf ("b_VFormat\n"); for (a = evc->attributes; a; a = a->next) { GList *p; b_VFormatAttribute *attr = a->data; printf ("+-- %s\n", attr->name); if (attr->params) { printf (" +- params=\n"); for (p = attr->params, i = 0; p; p = p->next, i++) { b_VFormatParam *param = p->data; printf (" | [%d] = %s", i,param->name); printf ("("); for (v = param->values; v; v = v->next) { char *value = b_vformat_escape_string ((char*)v->data, VFORMAT_CARD_21); printf ("%s", value); if (v->next) printf (","); g_free (value); } printf (")\n"); } } printf (" +- values=\n"); for (v = attr->values, i = 0; v; v = v->next, i++) { printf (" [%d] = `%s'\n", i, (char*)v->data); } } } b_VFormatAttribute *b_vformat_attribute_new (const char *attr_group, const char *attr_name) { b_VFormatAttribute *attr; attr = g_new0 (b_VFormatAttribute, 1); attr->group = g_strdup (attr_group); attr->name = g_strdup (attr_name); return attr; } void b_vformat_attribute_free (b_VFormatAttribute *attr) { g_return_if_fail (attr != NULL); g_free (attr->block); g_free (attr->group); g_free (attr->name); b_vformat_attribute_remove_values (attr); b_vformat_attribute_remove_params (attr); g_free (attr); } b_VFormatAttribute* b_vformat_attribute_copy (b_VFormatAttribute *attr) { b_VFormatAttribute *a; GList *p; g_return_val_if_fail (attr != NULL, NULL); a = b_vformat_attribute_new (b_vformat_attribute_get_group (attr), b_vformat_attribute_get_name (attr)); for (p = attr->values; p; p = p->next) b_vformat_attribute_add_value (a, p->data); for (p = attr->params; p; p = p->next) b_vformat_attribute_add_param (a, b_vformat_attribute_param_copy (p->data)); return a; } void b_vformat_remove_attributes (b_VFormat *evc, const char *attr_group, const char *attr_name) { GList *attr; g_return_if_fail (attr_name != NULL); attr = evc->attributes; while (attr) { GList *next_attr; b_VFormatAttribute *a = attr->data; next_attr = attr->next; if (((!attr_group && !a->group) || (attr_group && !g_ascii_strcasecmp (attr_group, a->group))) && ((!attr_name && !a->name) || !g_ascii_strcasecmp (attr_name, a->name))) { /* matches, remove/delete the attribute */ evc->attributes = g_list_remove_link (evc->attributes, attr); b_vformat_attribute_free (a); } attr = next_attr; } } void b_vformat_remove_attribute (b_VFormat *evc, b_VFormatAttribute *attr) { g_return_if_fail (attr != NULL); evc->attributes = g_list_remove (evc->attributes, attr); b_vformat_attribute_free (attr); } void b_vformat_add_attribute (b_VFormat *evc, b_VFormatAttribute *attr) { g_return_if_fail (attr != NULL); evc->attributes = g_list_append (evc->attributes, attr); } void b_vformat_add_attribute_with_value (b_VFormat *b_VFormat, b_VFormatAttribute *attr, const char *value) { g_return_if_fail (attr != NULL); b_vformat_attribute_add_value (attr, value); b_vformat_add_attribute (b_VFormat, attr); } void b_vformat_add_attribute_with_values (b_VFormat *b_VFormat, b_VFormatAttribute *attr, ...) { va_list ap; char *v; g_return_if_fail (attr != NULL); va_start (ap, attr); while ((v = va_arg (ap, char*))) { b_vformat_attribute_add_value (attr, v); } va_end (ap); b_vformat_add_attribute (b_VFormat, attr); } void b_vformat_attribute_add_value (b_VFormatAttribute *attr, const char *value) { g_return_if_fail (attr != NULL); attr->values = g_list_append (attr->values, g_strdup (value)); } void b_vformat_attribute_add_value_decoded (b_VFormatAttribute *attr, const char *value, int len) { g_return_if_fail (attr != NULL); switch (attr->encoding) { case VF_ENCODING_RAW: BarryLogf(TRACE_INTERNAL, _("can't add_value_decoded with an attribute using RAW encoding. you must set the ENCODING parameter first")); break; case VF_ENCODING_BASE64: { char *b64_data = base64_encode_simple (value, len); GString *decoded = g_string_new_len (value, len); /* make sure the decoded list is up to date */ b_vformat_attribute_get_values_decoded (attr); attr->values = g_list_append (attr->values, b64_data); attr->decoded_values = g_list_append (attr->decoded_values, decoded); break; } case VF_ENCODING_QP: { char *qp_data = quoted_encode_simple ((unsigned char*)value, len); GString *decoded = g_string_new (value); /* make sure the decoded list is up to date */ b_vformat_attribute_get_values_decoded (attr); attr->values = g_list_append (attr->values, qp_data); attr->decoded_values = g_list_append (attr->decoded_values, decoded); break; } case VF_ENCODING_8BIT: { char *data = g_strdup(value); GString *decoded = g_string_new (value); /* make sure the decoded list is up to date */ b_vformat_attribute_get_values_decoded (attr); attr->values = g_list_append (attr->values, data); attr->decoded_values = g_list_append (attr->decoded_values, decoded); break; } } } void b_vformat_attribute_add_values (b_VFormatAttribute *attr, ...) { va_list ap; char *v; g_return_if_fail (attr != NULL); va_start (ap, attr); while ((v = va_arg (ap, char*))) { b_vformat_attribute_add_value (attr, v); } va_end (ap); } static void free_gstring (GString *str) { g_string_free (str, TRUE); } void b_vformat_attribute_remove_values (b_VFormatAttribute *attr) { g_return_if_fail (attr != NULL); g_list_foreach (attr->values, (GFunc)g_free, NULL); g_list_free (attr->values); attr->values = NULL; g_list_foreach (attr->decoded_values, (GFunc)free_gstring, NULL); g_list_free (attr->decoded_values); attr->decoded_values = NULL; } void b_vformat_attribute_remove_params (b_VFormatAttribute *attr) { g_return_if_fail (attr != NULL); g_list_foreach (attr->params, (GFunc)b_vformat_attribute_param_free, NULL); g_list_free (attr->params); attr->params = NULL; /* also remove the cached encoding on this attribute */ attr->encoding_set = FALSE; attr->encoding = VF_ENCODING_RAW; } b_VFormatParam* b_vformat_attribute_param_new (const char *name) { b_VFormatParam *param = g_new0 (b_VFormatParam, 1); param->name = g_strdup (name); return param; } void b_vformat_attribute_param_free (b_VFormatParam *param) { g_return_if_fail (param != NULL); g_free (param->name); b_vformat_attribute_param_remove_values (param); g_free (param); } b_VFormatParam* b_vformat_attribute_param_copy (b_VFormatParam *param) { b_VFormatParam *p; GList *l; g_return_val_if_fail (param != NULL, NULL); p = b_vformat_attribute_param_new (b_vformat_attribute_param_get_name (param)); for (l = param->values; l; l = l->next) { b_vformat_attribute_param_add_value (p, l->data); } return p; } void b_vformat_attribute_add_param (b_VFormatAttribute *attr, b_VFormatParam *param) { g_return_if_fail (attr != NULL); g_return_if_fail (param != NULL); attr->params = g_list_append (attr->params, param); /* we handle our special encoding stuff here */ if (!g_ascii_strcasecmp (param->name, "ENCODING")) { if (attr->encoding_set) { BarryLogf(TRACE_INTERNAL, _("ENCODING specified twice")); return; } if (param->values && param->values->data) { if (_helper_is_base64((const char*)param->values->data)) attr->encoding = VF_ENCODING_BASE64; else if (!g_ascii_strcasecmp ((char*)param->values->data, "QUOTED-PRINTABLE")) attr->encoding = VF_ENCODING_QP; else if (!g_ascii_strcasecmp ((char *)param->values->data, "8BIT")) attr->encoding = VF_ENCODING_8BIT; else { BarryLogf(TRACE_INTERNAL, _("Unknown value `%s' for ENCODING parameter. values will be treated as raw"), (char*)param->values->data); } attr->encoding_set = TRUE; } else { BarryLogf(TRACE_INTERNAL, _("ENCODING parameter added with no value")); } } } b_VFormatParam *b_vformat_attribute_find_param(b_VFormatAttribute *attr, const char *name, int level) { g_return_val_if_fail (attr != NULL, NULL); GList *p = NULL; for (p = attr->params; p; p = p->next) { b_VFormatParam *param = p->data; if (!g_ascii_strcasecmp (param->name, name)) { if( level == 0 ) return param; else level--; } } return NULL; } void b_vformat_attribute_set_value (b_VFormatAttribute *attr, int nth, const char *value) { GList *param = g_list_nth(attr->values, nth); g_free(param->data); param->data = g_strdup(value); } void b_vformat_attribute_param_add_value (b_VFormatParam *param, const char *value) { g_return_if_fail (param != NULL); param->values = g_list_append (param->values, g_strdup (value)); } void b_vformat_attribute_param_add_values (b_VFormatParam *param, ...) { va_list ap; char *v; g_return_if_fail (param != NULL); va_start (ap, param); while ((v = va_arg (ap, char*))) { b_vformat_attribute_param_add_value (param, v); } va_end (ap); } void b_vformat_attribute_add_param_with_value (b_VFormatAttribute *attr, const char *name, const char *value) { g_return_if_fail (attr != NULL); g_return_if_fail (name != NULL); if (!value) return; b_VFormatParam *param = b_vformat_attribute_param_new(name); b_vformat_attribute_param_add_value (param, value); b_vformat_attribute_add_param (attr, param); } void b_vformat_attribute_add_param_with_values (b_VFormatAttribute *attr, b_VFormatParam *param, ...) { va_list ap; char *v; g_return_if_fail (attr != NULL); g_return_if_fail (param != NULL); va_start (ap, param); while ((v = va_arg (ap, char*))) { b_vformat_attribute_param_add_value (param, v); } va_end (ap); b_vformat_attribute_add_param (attr, param); } void b_vformat_attribute_param_remove_values (b_VFormatParam *param) { g_return_if_fail (param != NULL); g_list_foreach (param->values, (GFunc)g_free, NULL); g_list_free (param->values); param->values = NULL; } GList* b_vformat_get_attributes (b_VFormat *format) { return format->attributes; } const char* b_vformat_attribute_get_group (b_VFormatAttribute *attr) { g_return_val_if_fail (attr != NULL, NULL); return attr->group; } const char* b_vformat_attribute_get_name (b_VFormatAttribute *attr) { g_return_val_if_fail (attr != NULL, NULL); return attr->name; } const char* b_vformat_attribute_get_block (b_VFormatAttribute *attr) { g_return_val_if_fail (attr != NULL, NULL); return attr->block; } GList* b_vformat_attribute_get_values (b_VFormatAttribute *attr) { g_return_val_if_fail (attr != NULL, NULL); return attr->values; } GList* b_vformat_attribute_get_values_decoded (b_VFormatAttribute *attr) { g_return_val_if_fail (attr != NULL, NULL); if (!attr->decoded_values) { GList *l; switch (attr->encoding) { case VF_ENCODING_RAW: case VF_ENCODING_8BIT: for (l = attr->values; l; l = l->next) attr->decoded_values = g_list_append (attr->decoded_values, g_string_new ((char*)l->data)); break; case VF_ENCODING_BASE64: for (l = attr->values; l; l = l->next) { char *decoded = g_strdup ((char*)l->data); int len = base64_decode_simple (decoded, strlen (decoded)); attr->decoded_values = g_list_append (attr->decoded_values, g_string_new_len (decoded, len)); g_free (decoded); } break; case VF_ENCODING_QP: for (l = attr->values; l; l = l->next) { if (!(l->data)) continue; char *decoded = g_strdup ((char*)l->data); int len = quoted_decode_simple (decoded, strlen (decoded)); attr->decoded_values = g_list_append (attr->decoded_values, g_string_new_len (decoded, len)); g_free (decoded); } break; } } return attr->decoded_values; } gboolean b_vformat_attribute_is_single_valued (b_VFormatAttribute *attr) { g_return_val_if_fail (attr != NULL, FALSE); if (attr->values == NULL || attr->values->next != NULL) return FALSE; return TRUE; } char* b_vformat_attribute_get_value (b_VFormatAttribute *attr) { GList *values; g_return_val_if_fail (attr != NULL, NULL); values = b_vformat_attribute_get_values (attr); if (!b_vformat_attribute_is_single_valued (attr)) BarryLogf(TRACE_INTERNAL, _("b_vformat_attribute_get_value called on multivalued attribute")); return values ? g_strdup ((char*)values->data) : NULL; } GString* b_vformat_attribute_get_value_decoded (b_VFormatAttribute *attr) { GList *values; GString *str = NULL; g_return_val_if_fail (attr != NULL, NULL); values = b_vformat_attribute_get_values_decoded (attr); if (!b_vformat_attribute_is_single_valued (attr)) BarryLogf(TRACE_INTERNAL, _("b_vformat_attribute_get_value_decoded called on multivalued attribute")); if (values) str = values->data; return str ? g_string_new_len (str->str, str->len) : NULL; } const char *b_vformat_attribute_get_nth_value(b_VFormatAttribute *attr, int nth) { GList *values = b_vformat_attribute_get_values_decoded(attr); if (!values) return NULL; GString *retstr = (GString *)g_list_nth_data(values, nth); if (!retstr) return NULL; if (!g_utf8_validate(retstr->str, -1, NULL)) { values = b_vformat_attribute_get_values(attr); if (!values) return NULL; return g_list_nth_data(values, nth); } return retstr->str; } gboolean b_vformat_attribute_has_type (b_VFormatAttribute *attr, const char *typestr) { GList *params; GList *p; g_return_val_if_fail (attr != NULL, FALSE); g_return_val_if_fail (typestr != NULL, FALSE); params = b_vformat_attribute_get_params (attr); for (p = params; p; p = p->next) { b_VFormatParam *param = p->data; if (!strcasecmp (b_vformat_attribute_param_get_name (param), "TYPE")) { GList *values = b_vformat_attribute_param_get_values (param); GList *v; for (v = values; v; v = v->next) { if (!strcasecmp ((char*)v->data, typestr)) return TRUE; } } } return FALSE; } gboolean b_vformat_attribute_has_param(b_VFormatAttribute *attr, const char *name) { g_return_val_if_fail (attr != NULL, FALSE); g_return_val_if_fail (name != NULL, FALSE); GList *params = b_vformat_attribute_get_params(attr); GList *p; for (p = params; p; p = p->next) { b_VFormatParam *param = p->data; if (!strcasecmp(name, b_vformat_attribute_param_get_name(param))) return TRUE; } return FALSE; } GList* b_vformat_attribute_get_params (b_VFormatAttribute *attr) { g_return_val_if_fail (attr != NULL, NULL); return attr->params; } const char* b_vformat_attribute_param_get_name (b_VFormatParam *param) { g_return_val_if_fail (param != NULL, NULL); return param->name; } GList* b_vformat_attribute_param_get_values (b_VFormatParam *param) { g_return_val_if_fail (param != NULL, NULL); return param->values; } const char *b_vformat_attribute_param_get_nth_value(b_VFormatParam *param, int nth) { const char *ret = NULL; GList *values = b_vformat_attribute_param_get_values(param); if (!values) return NULL; ret = g_list_nth_data(values, nth); return ret; } static const char *base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; //static unsigned char _evc_base64_rank[256]; static void base64_init(char *rank) { int i; memset(rank, 0xff, sizeof(rank)); for (i=0;i<64;i++) { rank[(unsigned int)base64_alphabet[i]] = i; } rank['='] = 0; } /* call this when finished encoding everything, to flush off the last little bit */ static size_t base64_encode_close(const unsigned char *in, size_t inlen, gboolean break_lines, unsigned char *out, int *state, int *save) { int c1, c2; unsigned char *outptr = out; if (inlen>0) outptr += base64_encode_step(in, inlen, break_lines, outptr, state, save); c1 = ((unsigned char *)save)[1]; c2 = ((unsigned char *)save)[2]; switch (((char *)save)[0]) { case 2: outptr[2] = base64_alphabet[ ( (c2 &0x0f) << 2 ) ]; g_assert(outptr[2] != 0); goto skip; case 1: outptr[2] = '='; skip: outptr[0] = base64_alphabet[ c1 >> 2 ]; outptr[1] = base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 )]; outptr[3] = '='; outptr += 4; break; } if (break_lines) *outptr++ = '\n'; *save = 0; *state = 0; return outptr-out; } /* performs an 'encode step', only encodes blocks of 3 characters to the output at a time, saves left-over state in state and save (initialise to 0 on first invocation). */ static size_t base64_encode_step(const unsigned char *in, size_t len, gboolean break_lines, unsigned char *out, int *state, int *save) { register const unsigned char *inptr; register unsigned char *outptr; if (len<=0) return 0; inptr = in; outptr = out; if (len + ((char *)save)[0] > 2) { const unsigned char *inend = in+len-2; register int c1, c2, c3; register int already; already = *state; switch (((char *)save)[0]) { case 1: c1 = ((unsigned char *)save)[1]; goto skip1; case 2: c1 = ((unsigned char *)save)[1]; c2 = ((unsigned char *)save)[2]; goto skip2; } /* yes, we jump into the loop, no i'm not going to change it, it's beautiful! */ while (inptr < inend) { c1 = *inptr++; skip1: c2 = *inptr++; skip2: c3 = *inptr++; *outptr++ = base64_alphabet[ c1 >> 2 ]; *outptr++ = base64_alphabet[ c2 >> 4 | ( (c1&0x3) << 4 ) ]; *outptr++ = base64_alphabet[ ( (c2 &0x0f) << 2 ) | (c3 >> 6) ]; *outptr++ = base64_alphabet[ c3 & 0x3f ]; /* this is a bit ugly ... */ if (break_lines && (++already)>=19) { *outptr++='\n'; already = 0; } } ((char *)save)[0] = 0; len = 2-(inptr-inend); *state = already; } if (len>0) { register char *saveout; /* points to the slot for the next char to save */ saveout = & (((char *)save)[1]) + ((char *)save)[0]; /* len can only be 0 1 or 2 */ switch(len) { case 2: *saveout++ = *inptr++; case 1: *saveout++ = *inptr++; } ((char *)save)[0]+=len; } return outptr-out; } /** * base64_decode_step: decode a chunk of base64 encoded data * @in: input stream * @len: max length of data to decode * @out: output stream * @state: holds the number of bits that are stored in @save * @save: leftover bits that have not yet been decoded * * Decodes a chunk of base64 encoded data **/ static size_t base64_decode_step(const unsigned char *in, size_t len, unsigned char *out, int *state, unsigned int *save) { unsigned char base64_rank[256]; base64_init((char*)base64_rank); register const unsigned char *inptr; register unsigned char *outptr; const unsigned char *inend; unsigned char c; register unsigned int v; int i; inend = in+len; outptr = out; /* convert 4 base64 bytes to 3 normal bytes */ v=*save; i=*state; inptr = in; while (inptr>16; *outptr++ = v>>8; *outptr++ = v; i=0; } } } *save = v; *state = i; /* quick scan back for '=' on the end somewhere */ /* fortunately we can drop 1 output char for each trailing = (upto 2) */ i=2; while (inptr>in && i) { inptr--; if (base64_rank[*inptr] != 0xff) { if (*inptr == '=' && outptr>out) outptr--; i--; } } /* if i!= 0 then there is a truncation error! */ return outptr-out; } static char *base64_encode_simple (const char *data, size_t len) { unsigned char *out; int state = 0, outlen; unsigned int save = 0; g_return_val_if_fail (data != NULL, NULL); out = g_malloc (len * 4 / 3 + 5); outlen = base64_encode_close ((unsigned char *)data, len, FALSE, out, &state, (int*)&save); out[outlen] = '\0'; return (char *)out; } static size_t base64_decode_simple (char *data, size_t len) { int state = 0; unsigned int save = 0; g_return_val_if_fail (data != NULL, 0); return base64_decode_step ((unsigned char *)data, len, (unsigned char *)data, &state, &save); } static char *quoted_encode_simple(const unsigned char *string, int len) { GString *tmp = g_string_new(""); int i = 0; while(string[i] != 0) { if (string[i] > 127 || string[i] == 13 || string[i] == 10 || string[i] == '=') { g_string_append_printf(tmp, "=%02X", string[i]); } else { g_string_append_c(tmp, string[i]); } i++; } char *ret = tmp->str; g_string_free(tmp, FALSE); return ret; } static size_t quoted_decode_simple (char *data, size_t len) { g_return_val_if_fail (data != NULL, 0); GString *string = g_string_new(data); if (!string) return 0; char hex[5]; hex[4] = 0; while (1) { //Get the index of the next encoded char int i = strcspn(string->str, "="); if (i >= strlen(string->str)) break; strcpy(hex, "0x"); strncat(hex, &string->str[i + 1], 2); char rep = ((int)(strtod(hex, NULL))); g_string_erase(string, i, 2); g_string_insert_c(string, i, rep); } memset(data, 0, strlen(data)); strcpy(data, string->str); g_string_free(string, 1); return strlen(data); } barry-0.18.5/src/common.cc0000644001161500056700000000752112242254476014647 0ustar cdfreycdfrey/// /// \file common.cc /// General Barry interface routines /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "common.h" #include #include "debug.h" #include "config.h" #include #include #include #ifdef USE_BARRY_SOCKETS #include "usbwrap.h" #endif namespace Barry { bool __data_dump_mode__; std::ostream *LogStream = &std::cout; pthread_mutex_t LogStreamMutex; // // Init // /// Barry library initializer. Call this before anything else. /// This takes care of initializing the lower level libusb. /// /// This function is safe to be called multiple times. The /// data_dump_mode and the log stream will be updated each time /// it is called, but the USB library will not be re-initialized. /// /// \param[in] data_dump_mode If set to true, the protocol conversation /// will be sent to the logStream specified /// in the second argument. /// \param[in] LogStream Pointer to std::ostream object to use for /// debug output and logging. Defaults to /// std::cout. /// void Init(bool data_dump_mode, std::ostream *logStream) { static bool initialized = false; #ifdef USE_BARRY_SOCKETS Usb::LibraryInterface::SetDataDump(data_dump_mode); #endif // perform one-time initalization if( !initialized ) { // initialize i18n gettext directory // the rest is done in i18n.h bindtextdomain(PACKAGE, LOCALEDIR); #ifdef USE_BARRY_SOCKETS // Should call Usb::Uninit at some point, // but there isn't currently a deinit call. int err = 0; if( !Usb::LibraryInterface::Init(&err) ) { eout(_("USB library failed to initialise with libusb error: ") << err); throw Error(_("Failed to initialise USB")); return; } #endif // only need to initialize this once pthread_mutex_init(&LogStreamMutex, NULL); // done initialized = true; } __data_dump_mode__ = data_dump_mode; LogStream = logStream; } // // Verbose // /// This API call lets the application enable / disable verbose debug /// output on the fly. /// /// \param[in] data_dump_mode If set to true, the protocol conversation /// will be sent to the logStream specified /// in the Barry::Init() call. /// void Verbose(bool data_dump_mode) { __data_dump_mode__ = data_dump_mode; #ifdef USE_BARRY_SOCKETS Usb::LibraryInterface::SetDataDump(data_dump_mode); #endif } // // IsVerbose // /// Returns true if data dump mode is enabled. /// bool IsVerbose() { return __data_dump_mode__; } // The following code is based on the example from the vsnprintf(3) manpage std::string string_vprintf(const char *fmt, ...) { // Guess we need no more than 200 bytes. int n, size = 200; char *p, *np; std::string result; va_list ap; if ((p = (char*)malloc(size)) == NULL) return NULL; for (;;) { // Try to print in the allocated space. va_start(ap, fmt); n = vsnprintf(p, size, fmt, ap); va_end(ap); // If that worked, return the string. if (n > -1 && n < size) { result = p; free(p); return result; } // Else try again with more space. if (n > -1) // glibc 2.1 size = n+1; // precisely what is needed else // glibc 2.0 size *= 2; // twice the old size if ((np = (char*)realloc (p, size)) == NULL) { free(p); return result; } else { p = np; } } } } // namespace Barry barry-0.18.5/src/log.h0000644001161500056700000000273712242254476014006 0ustar cdfreycdfrey/// /// \file log.h /// General header for the Barry library /// /* Copyright (C) 2008-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_LOG_H__ #define __BARRY_LOG_H__ #include "dll.h" #include namespace Barry { // // LogLock // /// RAII locking class used to protect the logStream passed into /// Barry::Init() (common.h). If the application uses the same stream for /// its own logging, it should use this lock class, or use the macros /// in log.h. /// class BXEXPORT LogLock { public: LogLock(); ~LogLock(); }; BXEXPORT bool LogVerbose(); BXEXPORT std::ostream* GetLogStream(); } // namespace Barry #define barrylog(x) { ::Barry::LogLock lock; (*::Barry::GetLogStream()) << x << std::endl; } // controlled by command line -v switch #define barryverbose(x) if(::Barry::LogVerbose()) { ::Barry::LogLock lock; (*::Barry::GetLogStream()) << x << std::endl; } #endif // __BARRY_LOG_H__ barry-0.18.5/src/packet.cc0000644001161500056700000005470312242254476014632 0ustar cdfreycdfrey/// /// \file packet.cc /// Low level protocol packet builder class. /// Has knowledge of specific protocol commands in order /// to hide protocol details behind an API. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "packet.h" #include "m_desktop.h" #include "protocol.h" #include "protostructs.h" #include "data.h" #include "endian.h" #include "parser.h" #include "builder.h" #include "error.h" #include #define __DEBUG_MODE__ #include "debug.h" namespace Barry { ////////////////////////////////////////////////////////////////////////////// // Packet base class // // Command // /// Returns the command value of the receive packet. If receive isn't /// large enough, throws Error. /// unsigned int Packet::Command() const { Protocol::CheckSize(*m_receive, SB_PACKET_HEADER_SIZE); MAKE_PACKET(rpack, *m_receive); return rpack->command; } ////////////////////////////////////////////////////////////////////////////// // ZeroPacket class ZeroPacket::ZeroPacket(Data &send, Data &receive) : Packet(send, receive) { } ZeroPacket::~ZeroPacket() { } // // GetAttribute // /// Builds a command packet for the initial socket-0 handshakes /// that fetch certain (some unknown) attributes. The attributes /// appear to exist in an object/attribute sequence, so that's /// how we address them here. /// void ZeroPacket::GetAttribute(unsigned int object, unsigned int attribute) { size_t size = SB_SOCKET_PACKET_HEADER_SIZE + ATTRIBUTE_FETCH_COMMAND_SIZE; MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size)); Protocol::Packet &packet = *cpack; // socket class sets socket for us packet.size = htobs(size); packet.command = SB_COMMAND_FETCH_ATTRIBUTE; packet.u.socket.socket = htobs(0x00ff); // default non-socket request packet.u.socket.sequence = 0; // filled in by Socket class packet.u.socket.u.fetch.object = htobs(object); packet.u.socket.u.fetch.attribute = htobs(attribute); m_send.ReleaseBuffer(size); } // // Echo // /// Builds command packet for sending echo request. The parameter /// to this command is the number of microseconds elapsed since host /// computer startup. /// void ZeroPacket::Echo(uint64_t us_ticks) { size_t size = SB_SOCKET_PACKET_HEADER_SIZE + ECHO_COMMAND_SIZE; MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size)); Protocol::Packet &packet = *cpack; packet.size = htobs(size); packet.command = SB_COMMAND_ECHO; packet.u.socket.socket = htobs(0x00ff); // default non-socket request packet.u.socket.sequence = 0; // filled in by Socket class packet.u.socket.u.echo.ticks = htobl(us_ticks); m_send.ReleaseBuffer(size); } void ZeroPacket::Reset() { size_t size = SB_SOCKET_PACKET_HEADER_SIZE; MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size)); Protocol::Packet &packet = *cpack; packet.size = htobs(size); packet.command = SB_COMMAND_RESET; packet.u.socket.socket = htobs(0x00ff); // default non-socket request packet.u.socket.sequence = 0; // filled in by Socket class m_send.ReleaseBuffer(size); } unsigned int ZeroPacket::ObjectID() const { Protocol::CheckSize(*m_receive, SB_SOCKET_PACKET_HEADER_SIZE); MAKE_PACKET(rpack, *m_receive); return btohs(rpack->u.socket.u.fetch.object); } unsigned int ZeroPacket::AttributeID() const { Protocol::CheckSize(*m_receive, SB_SOCKET_PACKET_HEADER_SIZE); MAKE_PACKET(rpack, *m_receive); return btohs(rpack->u.socket.u.fetch.attribute); } uint32_t ZeroPacket::ChallengeSeed() const { Protocol::CheckSize(*m_receive, SB_SOCKET_PACKET_HEADER_SIZE + PASSWORD_CHALLENGE_SEED_SIZE); MAKE_PACKET(rpack, *m_receive); return btohl(rpack->u.socket.u.password.u.seed); } unsigned int ZeroPacket::RemainingTries() const { Protocol::CheckSize(*m_receive, SB_SOCKET_PACKET_HEADER_SIZE + PASSWORD_CHALLENGE_HEADER_SIZE); MAKE_PACKET(rpack, *m_receive); // this is a byte, so no byte swapping needed return rpack->u.socket.u.password.remaining_tries; } unsigned int ZeroPacket::SocketResponse() const { Protocol::CheckSize(*m_receive, SB_SOCKET_PACKET_HEADER_SIZE); MAKE_PACKET(rpack, *m_receive); return btohs(rpack->u.socket.socket); } unsigned char ZeroPacket::SocketSequence() const { Protocol::CheckSize(*m_receive, SB_SOCKET_PACKET_HEADER_SIZE); MAKE_PACKET(rpack, *m_receive); return rpack->u.socket.sequence; // sequence is a byte } uint8_t ZeroPacket::CommandResponse() const { Protocol::CheckSize(*m_receive, SB_SOCKET_PACKET_HEADER_SIZE); MAKE_PACKET(rpack, *m_receive); return rpack->command; } ////////////////////////////////////////////////////////////////////////////// // DBPacket class DBPacket::DBPacket(Mode::Desktop &con, Data &send, Data &receive) : Packet(send, receive) , m_con(con) , m_last_dbop(0) { } DBPacket::~DBPacket() { } // // ClearDatabase // /// Builds a command packet for the CLEAR_DATABASE command code, placing /// the data in the send buffer. /// void DBPacket::ClearDatabase(unsigned int dbId) { MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(9)); Protocol::Packet &packet = *cpack; // socket class sets socket for us packet.size = htobs(9); packet.command = SB_COMMAND_DB_DATA; packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess); packet.u.db.u.command.operation = SB_DBOP_CLEAR_DATABASE; packet.u.db.u.command.databaseId = htobs(dbId); m_send.ReleaseBuffer(9); m_last_dbop = SB_DBOP_CLEAR_DATABASE; } // // GetDBDB // /// Builds a command packet for the GET_DBDB command code, placing the /// data in m_send. /// void DBPacket::GetDBDB() { MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(7)); Protocol::Packet &packet = *cpack; // socket class sets socket for us packet.size = htobs(7); packet.command = SB_COMMAND_DB_DATA; packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess); // packet.u.db.u.command.operation = SB_DBOP_GET_DBDB; packet.u.db.u.command.operation = SB_DBOP_OLD_GET_DBDB; m_send.ReleaseBuffer(7); m_last_dbop = SB_DBOP_OLD_GET_DBDB; } // // GetRecordStateTable // /// Builds a command packet in the send buffer for the /// GET_RECORD_STATE_TABLE command. /// void DBPacket::GetRecordStateTable(unsigned int dbId) { MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(9)); Protocol::Packet &packet = *cpack; // socket class sets socket for us packet.size = htobs(9); packet.command = SB_COMMAND_DB_DATA; packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess); packet.u.db.u.command.operation = SB_DBOP_GET_RECORD_STATE_TABLE; packet.u.db.u.command.databaseId = htobs(dbId); m_send.ReleaseBuffer(9); m_last_dbop = SB_DBOP_GET_RECORD_STATE_TABLE; } // // SetRecordFlags // /// Builds a command packet in the send buffer for the SET_RECORD_FLAGS /// command code. /// /// FIXME - this API call is incomplete, since there are unknown flags /// in the SetRecordFlags protocol packet. Currently it is only /// used to set all flags to zero. /// void DBPacket::SetRecordFlags(unsigned int dbId, unsigned int stateTableIndex, uint8_t flag1) { size_t size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_RECORD_FLAGS_SIZE; MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size)); Protocol::Packet &packet = *cpack; // socket class sets socket for us packet.size = htobs(size); packet.command = SB_COMMAND_DB_DATA; packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess); packet.u.db.u.command.operation = SB_DBOP_SET_RECORD_FLAGS; packet.u.db.u.command.databaseId = htobs(dbId); packet.u.db.u.command.u.flags.unknown = flag1; packet.u.db.u.command.u.flags.index = htobs(stateTableIndex); memset(packet.u.db.u.command.u.flags.unknown2, 0, sizeof(packet.u.db.u.command.u.flags.unknown2)); m_send.ReleaseBuffer(size); m_last_dbop = SB_DBOP_SET_RECORD_FLAGS; } // // DeleteRecordByIndex // /// Builds a command packet in the send buffer for the DELETE_RECORD_BY_INDEX /// command code. /// void DBPacket::DeleteRecordByIndex(unsigned int dbId, unsigned int stateTableIndex) { size_t size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_RECORD_HEADER_SIZE; MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size)); Protocol::Packet &packet = *cpack; // socket class sets socket for us packet.size = htobs(size); packet.command = SB_COMMAND_DB_DATA; packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess); packet.u.db.u.command.operation = SB_DBOP_DELETE_RECORD_BY_INDEX; packet.u.db.u.command.databaseId = htobs(dbId); packet.u.db.u.command.u.record.recordIndex = htobs(stateTableIndex); m_send.ReleaseBuffer(size); m_last_dbop = SB_DBOP_DELETE_RECORD_BY_INDEX; } // // GetRecordByIndex // /// Builds a command packet in the send buffer for the GET_RECORD_BY_INDEX /// command code. /// void DBPacket::GetRecordByIndex(unsigned int dbId, unsigned int stateTableIndex) { MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(11)); Protocol::Packet &packet = *cpack; // socket class sets socket for us packet.size = htobs(11); packet.command = SB_COMMAND_DB_DATA; packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess); packet.u.db.u.command.operation = SB_DBOP_GET_RECORD_BY_INDEX; packet.u.db.u.command.databaseId = htobs(dbId); packet.u.db.u.command.u.record.recordIndex = htobs(stateTableIndex); m_send.ReleaseBuffer(11); m_last_dbop = SB_DBOP_GET_RECORD_BY_INDEX; } // // SetRecordByIndex // /// Builds a command packet in the m_send buffer for the SET_RECORD_BY_INDEX /// command code. /// /// \return bool /// - true means success /// - false means no data available from Builder object /// bool DBPacket::SetRecordByIndex(unsigned int dbId, unsigned int stateTableIndex, Builder &build, const IConverter *ic) { // build packet data DBData send(m_send, false); // send is just a reference to m_send, // so it is safe to use m_send later size_t header_size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_INDEXED_UPLOAD_HEADER_SIZE; if( !build.BuildRecord(send, header_size, ic) ) return false; // no data available size_t total_size = m_send.GetSize(); // fill in the header values MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(total_size)); Protocol::Packet &packet = *cpack; // socket class sets socket for us packet.size = htobs(total_size); packet.command = SB_COMMAND_DB_DATA; packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess); packet.u.db.u.command.operation = SB_DBOP_SET_RECORD_BY_INDEX; packet.u.db.u.command.databaseId = htobs(dbId); packet.u.db.u.command.u.index_upload.unknown = 0; packet.u.db.u.command.u.index_upload.index = htobs(stateTableIndex); m_send.ReleaseBuffer(total_size); m_last_dbop = SB_DBOP_SET_RECORD_BY_INDEX; return true; } // // GetRecords // /// Builds a command packet in the send buffer for the GET_RECORDS /// command code. /// void DBPacket::GetRecords(unsigned int dbId) { MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(9)); Protocol::Packet &packet = *cpack; // socket class sets socket for us packet.size = htobs(9); packet.command = SB_COMMAND_DB_DATA; packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess); packet.u.db.u.command.operation = SB_DBOP_OLD_GET_RECORDS; packet.u.db.u.command.databaseId = htobs(dbId); m_send.ReleaseBuffer(9); m_last_dbop = SB_DBOP_OLD_GET_RECORDS; } // // AddRecord // /// Builds a command packet in the m_send buffer for the ADD_RECORD command /// code. /// /// \return bool /// - true means success /// - false means no data available from Builder object /// bool DBPacket::AddRecord(unsigned int dbId, Builder &build, const IConverter *ic) { // build packet data DBData send(m_send, false); // send is just a reference to m_send, // so it is safe to use m_send later size_t header_size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_TAGGED_UPLOAD_HEADER_SIZE; if( !build.BuildRecord(send, header_size, ic) ) return false; // no data available size_t total_size = m_send.GetSize(); // fill in the header values MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(total_size)); Protocol::Packet &packet = *cpack; // socket class sets socket for us packet.size = htobs(total_size); packet.command = SB_COMMAND_DB_DATA; packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess); packet.u.db.u.command.operation = SB_DBOP_ADD_RECORD; packet.u.db.u.command.databaseId = htobs(dbId); packet.u.db.u.command.u.tag_upload.rectype = send.GetRecType(); packet.u.db.u.command.u.tag_upload.uniqueId = htobl(send.GetUniqueId()); packet.u.db.u.command.u.tag_upload.unknown2 = 1; // unknown observed value m_send.ReleaseBuffer(total_size); m_last_dbop = SB_DBOP_ADD_RECORD; return true; } // throws FIXME if packet doesn't support it unsigned int DBPacket::ReturnCode() const { if( Command() == SB_COMMAND_DB_DONE ) { Protocol::CheckSize(*m_receive, SB_PACKET_DBACCESS_HEADER_SIZE + SB_DBACCESS_RETURN_CODE_SIZE); MAKE_PACKET(rpack, *m_receive); return rpack->u.db.u.return_code; } else { throw Error(_("Attempting to extract a return code from the wrong response packet type")); } } // // DBOperation // /// Returns the database operation code from the receive packet, assuming /// that receive contains a response packet. If receive isn't large /// enough, throws Error. /// unsigned int DBPacket::DBOperation() const { Protocol::CheckSize(*m_receive, SB_PACKET_RESPONSE_HEADER_SIZE); MAKE_PACKET(rpack, *m_receive); return rpack->u.db.u.response.operation; } // // Parse // /// Parses the data in the receive buffer, and attempts to be smart about it, /// using the last send command as guidance for what to expect in the /// response. /// /// \returns bool true - packet was recognized and parse was attempted /// false - packet was not recognized /// bool DBPacket::Parse(Parser &parser, const std::string &dbname, const IConverter *ic) { size_t offset = 0; MAKE_PACKET(rpack, *m_receive); switch( m_last_dbop ) { case SB_DBOP_OLD_GET_RECORDS: case SB_DBOP_GET_RECORD_BY_INDEX: offset = SB_PACKET_RESPONSE_HEADER_SIZE + DBR_OLD_TAGGED_RECORD_HEADER_SIZE; Protocol::CheckSize(*m_receive, offset); // FIXME - this may need adjustment for email records... they // don't seem to have uniqueID's { DBData block(DBData::REC_VERSION_1, dbname, rpack->u.db.u.response.u.tagged.rectype, btohl(rpack->u.db.u.response.u.tagged.uniqueId), offset, *m_receive, false); parser.ParseRecord(block, ic); } return true; default: // unknown command return false; } } // // ParseMeta // /// Fills DBData's meta data based on its data block, and the last dbop. /// bool DBPacket::ParseMeta(DBData &data) { size_t offset = 0; MAKE_PACKET(rpack, data.GetData()); switch( m_last_dbop ) { case SB_DBOP_OLD_GET_RECORDS: case SB_DBOP_GET_RECORD_BY_INDEX: data.SetVersion(DBData::REC_VERSION_1); offset = SB_PACKET_RESPONSE_HEADER_SIZE + DBR_OLD_TAGGED_RECORD_HEADER_SIZE; Protocol::CheckSize(data.GetData(), offset); data.SetOffset(offset); // FIXME - this may need adjustment for email records... they // don't seem to have uniqueID's data.SetIds(rpack->u.db.u.response.u.tagged.rectype, btohl(rpack->u.db.u.response.u.tagged.uniqueId)); return true; default: // unknown command return false; } } ////////////////////////////////////////////////////////////////////////////// // JLPacket class JLPacket::JLPacket(Data &cmd, Data &send, Data &receive) : Packet(send, receive) , m_cmd(cmd) , m_data(send) , m_last_set_size(0) { } JLPacket::~JLPacket() { } unsigned int JLPacket::Size() { Protocol::CheckSize(*m_receive, SB_JLPACKET_HEADER_SIZE + SB_JLRESPONSE_HEADER_SIZE); MAKE_JLPACKET(rpack, *m_receive); return btohs(rpack->u.response.expect); } // returns 1 or 2 depending on whether cmd or cmd+send are available int JLPacket::SimpleCmd(uint8_t cmd, uint8_t unknown, uint16_t size) { MAKE_JLPACKETPTR_BUF(cpack, m_cmd.GetBuffer(8)); Protocol::JLPacket &packet = *cpack; // socket class sets socket for us packet.size = htobs(8); packet.u.command.command = cmd; packet.u.command.unknown = unknown; packet.u.command.size = htobs(size); m_cmd.ReleaseBuffer(8); return m_last_set_size = 1; } int JLPacket::SimpleData(const void *data, uint16_t size) { uint16_t total = size + 4; MAKE_JLPACKETPTR_BUF(dpack, m_data.GetBuffer(total)); // socket class sets socket for us dpack->size = htobs(total); memcpy(dpack->u.raw, data, size); m_data.ReleaseBuffer(total); return m_last_set_size = 2; } int JLPacket::BigEndianData(uint16_t value) { value = be_htobs(value); return SimpleData(&value, sizeof(value)); } int JLPacket::BigEndianData(uint32_t value) { value = be_htobl(value); return SimpleData(&value, sizeof(value)); } int JLPacket::SetUnknown1() { SimpleCmd(SB_COMMAND_JL_SET_UNKNOWN1, 0, 1); uint8_t arg = 0; return SimpleData(&arg, 1); } int JLPacket::SetCodFilename(const std::string &filename) { SimpleCmd(SB_COMMAND_JL_SET_COD_FILENAME, 0, filename.size()); return SimpleData(filename.data(), filename.size()); } int JLPacket::SetCodSize(off_t size) { SimpleCmd(SB_COMMAND_JL_SET_COD_SIZE, 1, 4); return BigEndianData((uint32_t)size); } int JLPacket::SetTime(time_t when) { SimpleCmd(SB_COMMAND_JL_SET_TIME, 0, 4); return BigEndianData((uint32_t)when); } int JLPacket::GetSubDir(uint16_t id) { SimpleCmd(SB_COMMAND_JL_GET_SUBDIR, 0, 2); return BigEndianData(id); } int JLPacket::GetDirEntry(uint8_t entry_cmd, uint16_t id) { SimpleCmd(entry_cmd, 0, 2); return BigEndianData(id); } int JLPacket::GetScreenshot() { SimpleCmd(SB_COMMAND_JL_GET_SCREENSHOT, 0, 4); return BigEndianData((uint32_t) 0); } int JLPacket::Erase(uint16_t cmd, uint16_t id) { SimpleCmd((uint8_t)cmd, 0, 2); return BigEndianData(id); } int JLPacket::GetEventlogEntry(uint16_t entry_num) { SimpleCmd(SB_COMMAND_JL_GET_LOG_ENTRY, 0, 2); return BigEndianData(entry_num); } int JLPacket::SaveModule(uint16_t id) { SimpleCmd(SB_COMMAND_JL_SAVE_MODULE, 0, 2); return BigEndianData(id); } int JLPacket::PutData(const void *data, uint16_t size) { SimpleCmd(SB_COMMAND_JL_SEND_DATA, 0, size); return SimpleData(data, size); } ////////////////////////////////////////////////////////////////////////////// // JVMPacket class JVMPacket::JVMPacket(Data &send, Data &receive) : Packet(send, receive) , m_cmd(send) { } JVMPacket::~JVMPacket() { } unsigned int JVMPacket::Size() { MAKE_JVMPACKET(rpack, *m_receive); Protocol::CheckSize(*m_receive, SB_JVMPACKET_HEADER_SIZE + sizeof(rpack->u.expect)); return be_btohs(rpack->u.expect); } // Command format (param is optionnal) : // 00000000: 05 00 07 00 00 01 8a // ^^ : command // ^^^^^ : size of commd + param // ^^^^^ : packet size // ^^^^^ : socket ID void JVMPacket::SimpleCmd(uint8_t cmd) { // 4 : socket id field + packet size field // 2 : size field // 1 : command field const uint16_t total = 4 + 2 + 1; MAKE_JVMPACKETPTR_BUF(cpack, m_cmd.GetBuffer(total)); Protocol::JVMPacket &packet = *cpack; // socket class sets socket for us packet.size = htobs(total); packet.u.command.size = be_htobs(1); packet.u.command.command = cmd; m_cmd.ReleaseBuffer(total); } // Command with parameter format : // 00000000: 05 00 0b 00 00 05 8d 00 00 00 00 // ^^^^^^^^^^^ : param // ^^ : command // ^^^^^ : size of commd + param // ^^^^^ : packet size // ^^^^^ : socket ID void JVMPacket::ComplexCmd(uint8_t cmd, const void *param, uint16_t size) { // 4 : socket id field + packet size field // 2 : size field // 1 : command field uint16_t total = 4 + 2 + 1 + size; MAKE_JVMPACKETPTR_BUF(cpack, m_cmd.GetBuffer(total)); Protocol::JVMPacket &packet = *cpack; // socket class sets socket for us packet.size = htobs(total); packet.u.command.size = be_htobs(1 + size); packet.u.command.command = cmd; if ((size > 0) && (param != NULL)) memcpy(cpack->u.command.raw, param, size); m_cmd.ReleaseBuffer(total); } void JVMPacket::Unknown01() { SimpleCmd(SB_COMMAND_JVM_UNKNOWN01); } void JVMPacket::Unknown02() { SimpleCmd(SB_COMMAND_JVM_UNKNOWN02); } void JVMPacket::Unknown03() { SimpleCmd(SB_COMMAND_JVM_UNKNOWN03); } void JVMPacket::Unknown04() { SimpleCmd(SB_COMMAND_JVM_UNKNOWN04); } void JVMPacket::Unknown05() { SimpleCmd(SB_COMMAND_JVM_UNKNOWN05); } void JVMPacket::Unknown06() { uint32_t param = 0; ComplexCmd(SB_COMMAND_JVM_UNKNOWN06, ¶m, sizeof(param)); } void JVMPacket::Unknown07() { uint32_t param = 0; ComplexCmd(SB_COMMAND_JVM_UNKNOWN07, ¶m, sizeof(param)); } void JVMPacket::Unknown08() { uint32_t param = 0; ComplexCmd(SB_COMMAND_JVM_UNKNOWN08, ¶m, sizeof(param)); } void JVMPacket::Unknown09() { uint32_t param = be_htobl(0x09); ComplexCmd(SB_COMMAND_JVM_UNKNOWN09, ¶m, sizeof(param)); } void JVMPacket::Unknown10() { uint32_t param = be_htobl(0x01); ComplexCmd(SB_COMMAND_JVM_UNKNOWN10, ¶m, sizeof(param)); } void JVMPacket::Unknown11(uint32_t id) { id = be_htobl(id); ComplexCmd(SB_COMMAND_JVM_UNKNOWN11, &id, sizeof(id)); } void JVMPacket::Unknown12(uint32_t id) { id = be_htobl(id); ComplexCmd(SB_COMMAND_JVM_UNKNOWN12, &id, sizeof(id)); } void JVMPacket::Unknown13(uint32_t id) { id = be_htobl(id); ComplexCmd(SB_COMMAND_JVM_UNKNOWN13, &id, sizeof(id)); } void JVMPacket::Unknown14(uint32_t id) { id = be_htobl(id); ComplexCmd(SB_COMMAND_JVM_UNKNOWN14, &id, sizeof(id)); } void JVMPacket::Unknown15(uint32_t id) { id = be_htobl(id); ComplexCmd(SB_COMMAND_JVM_UNKNOWN15, &id, sizeof(id)); } void JVMPacket::GetModulesList(uint32_t id) { id = be_htobl(id); ComplexCmd(SB_COMMAND_JVM_GET_MODULES_LIST, &id, sizeof(id)); } void JVMPacket::GetThreadsList() { SimpleCmd(SB_COMMAND_JVM_GET_THREADS_LIST); } void JVMPacket::GetConsoleMessage() { SimpleCmd(SB_COMMAND_JVM_GET_CONSOLE_MSG); } void JVMPacket::Go() { SimpleCmd(SB_COMMAND_JVM_GO); } void JVMPacket::Stop() { // 4 : socket id field + packet size field // 2 : value field const uint16_t total = 4 + 2; MAKE_JVMPACKETPTR_BUF(cpack, m_cmd.GetBuffer(total)); Protocol::JVMPacket &packet = *cpack; // socket class sets socket for us packet.size = htobs(total); packet.u.value = be_htobs(SB_COMMAND_JVM_STOP); m_cmd.ReleaseBuffer(total); } void JVMPacket::GetStatus() { SimpleCmd(SB_COMMAND_JVM_GET_STATUS); } } // namespace Barry barry-0.18.5/src/r_timezone.h0000644001161500056700000001537312242254476015400 0ustar cdfreycdfrey/// /// \file r_timezone.h /// Record parsing class for the timezone database. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2008, Brian Edginton 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_TIMEZONE_H__ #define __BARRY_RECORD_TIMEZONE_H__ #include "dll.h" #include "record.h" #include #include #include namespace Barry { // forward declarations class IConverter; class BXEXPORT TimeZone { public: typedef Barry::UnknownsType UnknownsType; uint8_t RecType; uint32_t RecordId; std::string Name; //< name of time zone int32_t Index; //< index of entry in time zone table... //< matches Code in hard coded TimeZone //< table in Barry int32_t UTCOffset; //< Timezone offset from UTC in minutes. //< Will be a negative value for west //< of UTC (North America, etc), and //< a positive value for east (Europe). //< i.e. -210 for St. John's, which is //< -3.5 hours from UTC. bool UseDST; //< true this timezone uses DST uint32_t DSTOffset; //< minutes of DST, if UseDST is true. //< This value will almost always be 60. uint32_t StartMonth; //< index, 0-11, of month to start DST uint32_t EndMonth; //< index, 0-11, of month to end DST uint8_t TZType; //< unknown UnknownsType Unknowns; public: TimeZone(); /// Creates a new timezone based on utc_offset minutes. /// Use same semantics as UTCOffset. For example, a -3.5 hour /// timezone (which is west of UTC) would be constructed /// as: TimeZone(-210) explicit TimeZone(int utc_offset); /// Creates a new timezone based on negative/positive hours, /// and positive minutes. For example, a -3.5 hour timezone /// (which is west of UTC) would be constructed as: TimeZone(-3, 30) /// Note that minutes can be negative, and it will be handled /// correctly. i.e. TimeZone(-3, 30) == TimeZone(-3, -30) TimeZone(int hours, int minutes); virtual ~TimeZone(); // // TimeZone related utility functions // bool IsWest() const { return UTCOffset < 0; } /// Splits UTCOffset minutes into hours and minutes. hours can be /// negative. minutes is always positive. void Split(int *hours, int *minutes) const; /// Splits UTCOffset minutes into absolute values of hours and minutes, /// and sets the west flag appropriately. This is to mimic the /// old behaviour of the Left, Offset and OffsetFraction member /// variables. void SplitAbsolute(bool *west, unsigned int *hours, unsigned int *minutes) const; /// Creates a timezone string suitable for a Unix / POSIX TZ /// environment variable. Expects a time zone prefix. /// For example, New Zealand Standard/Daylight Time is NZST/NZDT, so /// the prefix would be "NZ". Eastern Standard/Daylight Time /// is EST/EDT, so the prefix would be "E". /// /// Should be able to use this string to achieve time zone conversions /// using the TzWrapper class. std::string GetTz(const std::string &prefix) const; // common Barry record functions void Validate() const; const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); void ParseRecurrenceData(const void *data); void BuildRecurrenceData(void *data); uint8_t GetRecType() const { return RecType; } uint32_t GetUniqueId() const { return RecordId; } void SetIds(uint8_t Type, uint32_t Id) { RecType = Type; RecordId = Id; } void ParseHeader(const Data &data, size_t &offset); void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); void BuildHeader(Data &data, size_t &offset) const; void BuildFields(Data &data, size_t &offset, const IConverter *ic = 0) const; // operations (common among record classes) void Clear(); void Dump(std::ostream &os) const; std::string GetDescription() const; bool operator<(const TimeZone &other) const { return SortByName(*this, other); } // sort options - suitable for use in std::sort() static bool SortByName(const TimeZone &a, const TimeZone &b) { return a.Name < b.Name; } static bool SortByZone(const TimeZone &a, const TimeZone &b) { return a.UTCOffset < b.UTCOffset; } // database name static const char * GetDBName() { return "Time Zones"; } static uint8_t GetDefaultRecType() { return 2; } // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const TimeZone &msg) { msg.Dump(os); return os; } // forward declarations namespace Mode { class Desktop; } // // TimeZones // /// Creates a vector of TimeZone objects either based on the library's /// hard coded StaticTimeZone list, or by extracting the time zone database /// from a given device. /// /// After construction, the vector will be sorted according to time zone, /// with west-most first. /// class BXEXPORT TimeZones { public: typedef std::vector ListType; typedef ListType::iterator iterator; typedef ListType::const_iterator const_iterator; private: ListType m_list; public: /// Creates the list based on the library's hard coded StaticTimeZone /// list. TimeZones(); /// Extracts the time zone database from the given device. /// Throws an exception if the device does not have a time zones /// database. explicit TimeZones(Barry::Mode::Desktop &desktop); /// Static helper function that returns true if the device /// referenced by desktop has a time zone database static bool IsLoadable(Barry::Mode::Desktop &desktop); ListType& GetList() { return m_list; } const ListType& GetList() const { return m_list; } iterator begin() { return m_list.begin(); } const_iterator begin() const { return m_list.begin(); } iterator end() { return m_list.end(); } const_iterator end() const { return m_list.end(); } TimeZone& operator[](int i) { return m_list[i]; } const TimeZone& operator[](int i) const { return m_list[i]; } // utility functions - return end() if not found iterator Find(int index); const_iterator Find(int index) const; iterator FindByOffset(int utc_offset); const_iterator FindByOffset(int utc_offset) const; void Dump(std::ostream &os) const; }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const TimeZones &l) { l.Dump(os); return os; } } // namespace Barry #endif /* __BARRY_RECORD_TIMEZONE_H__*/ barry-0.18.5/src/mimeio.cc0000644001161500056700000000743412242254476014641 0ustar cdfreycdfrey/// /// \file mimeio.cc /// Storage, parser, builder classes for MIME objects /// (vcard, vevent, vtodo, vjournal) /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "mimeio.h" #include "vcard.h" #include "vevent.h" #include "vtodo.h" #include "vjournal.h" #include #include #include using namespace std; namespace Barry { MimeBuilder::MimeBuilder(const std::string &filename) : m_ifs( new std::ifstream(filename.c_str()) ) , m_is(*m_ifs) { } MimeBuilder::MimeBuilder(std::istream &is) : m_is(is) { } bool MimeBuilder::BuildRecord(DBData &data, size_t &offset, const IConverter *ic) { string vrec; vector types; while( ReadMimeRecord(m_is, vrec, types) ) { if( !vrec.size() ) { // end of file return false; } else if( IsMember(Sync::vCard::GetVName(), types) ) { Sync::vCard vcard; SetDBData(vcard.ToBarry(vrec.c_str(), 0), data, offset, ic); return true; } else if( IsMember(Sync::vCalendar::GetVName(), types) ) { Sync::vTimeConverter vtc; Sync::vCalendar vcal(vtc); SetDBData(vcal.ToBarry(vrec.c_str(), 0), data, offset, ic); return true; } else if( IsMember(Sync::vTodo::GetVName(), types) ) { Sync::vTimeConverter vtc; Sync::vTodo vtodo(vtc); SetDBData(vtodo.ToBarry(vrec.c_str(), 0), data, offset, ic); return true; } else if( IsMember(Sync::vJournal::GetVName(), types) ) { Sync::vTimeConverter vtc; Sync::vJournal vjournal(vtc); SetDBData(vjournal.ToBarry(vrec.c_str(), 0), data, offset, ic); return true; } else { // read the next one } } // end of file return false; } bool MimeBuilder::FetchRecord(DBData &data, const IConverter *ic) { size_t offset = 0; return BuildRecord(data, offset, ic); } bool MimeBuilder::EndOfFile() const { return !m_is; } // return false at end of file, true if a record was read bool MimeBuilder::ReadMimeRecord(std::istream &is, std::string &vrec, std::vector &types) { vrec.clear(); types.clear(); string line; // ignore whitespace while( getline(is, line) ) { if( strcasecmp(line.substr(0, 6).c_str(), "BEGIN:") == 0 ) { vrec += line; vrec += "\n"; types.push_back(line.substr(6)); break; } } if( !vrec.size() ) return false; // load until end int count = 0; while( getline(is, line) ) { // end on blank lines if( !line.size() ) return true; vrec += line; vrec += "\n"; // pick up innermost BEGIN line if( strcasecmp(line.substr(0, 6).c_str(), "BEGIN:") == 0 ) { string type = line.substr(6); while( type.size() && type[type.size()-1] == '\r' ) { type = type.substr(0, type.size()-1); } types.push_back(type); } // place an upper limit on the number of lines... // since a MIME data block shouldn't be more than // a few pages of lines! count++; if( count > 200 ) return false; } // assume that end of file is the same as "blank line" return true; } bool MimeBuilder::IsMember(const std::string &item, const std::vector &types) { std::vector::const_iterator i = types.begin(); for( ; i != types.end(); ++i ) { if( strcasecmp(i->c_str(), item.c_str()) == 0 ) return true; } return false; } } // namespace Barry barry-0.18.5/src/a_alxparser.h0000644001161500056700000000462012242254476015517 0ustar cdfreycdfrey/// /// \file a_alxparser.h /// ALX file parser (for one file) /// /* Copyright (C) 2010, Nicolas VIVIEN Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_A_ALX_PARSER_H__ #define __BARRY_A_ALX_PARSER_H__ #include #include "dll.h" #include "xmlparser.h" #include "a_codsection.h" #include "a_library.h" #include "a_application.h" #include "a_osloader.h" #include namespace Barry { namespace ALX { class BXEXPORT ALXParser : public XML::XMLParser { public: enum MainNodeType { MAIN_NONE, IN_LOADER, IN_SYSTEM, IN_SYSTEM_APPLICATION, IN_SYSTEM_LIBRARY, IN_APPLICATION, IN_APPLICATION_APPLICATION, IN_LIBRARY }; enum SubNodeType { SUB_NONE, IN_DIRECTORY, IN_OSFILES, IN_NAME, IN_DESCRIPTION, IN_VERSION, IN_VENDOR, IN_COPYRIGHT, IN_LANGUAGE, IN_LANGUAGE_SUPPORTED, IN_REQUIRED, IN_FILESET }; private: bool m_register; OSLoader& osloader; MainNodeType node; SubNodeType subnode; std::string buffdata; std::tr1::shared_ptr m_codsection; std::tr1::shared_ptr m_savecodsection; public: ALXParser(OSLoader& osloader, std::istream& input); virtual ~ALXParser(void); virtual bool Run(const bool enable); protected: // SaxParser overrides, also overridden in XMLParser virtual void on_start_document(); virtual void on_end_document(); virtual void on_start_element(const Glib::ustring& name, const xmlpp::SaxParser::AttributeList& attrs); virtual void on_end_element(const Glib::ustring& name); virtual void on_characters(const Glib::ustring& data); virtual void on_comment(const Glib::ustring& text); virtual void on_warning(const Glib::ustring& text); virtual void on_error(const Glib::ustring& text); virtual void on_fatal_error(const Glib::ustring& text); }; } // namespace ALX } // namespace Barry #endif barry-0.18.5/src/semaphore.h0000644001161500056700000000407012242254476015200 0ustar cdfreycdfrey/// /// \file semaphore.h /// Simple class implementing a semaphore using pthreads mutex and condvar. /// /* Copyright (C) 2010, RealVNC Ltd. 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_SEMAPHORE_H__ #define __BARRY_SEMAPHORE_H__ #include "scoped_lock.h" #include namespace Barry { class semaphore { pthread_mutex_t *m_mutex; pthread_cond_t *m_cv; int m_value; public: semaphore(pthread_mutex_t &mutex, pthread_cond_t &cv, int value = 0) : m_mutex(&mutex) , m_cv(&cv) , m_value(value) { } // Waits for the value of this semaphore to be greater than 0 and then // decrements it by one before returning. void WaitForSignal() { scoped_lock lock(*m_mutex); while( m_value <= 0 ) { int ret = pthread_cond_wait(m_cv, m_mutex); if( ret != 0 ) { throw Barry::Error("semaphore: failed to wait on condvar"); } } --m_value; lock.unlock(); } // Checks for a semaphore signal without blocking. Returns true and decrements // the semaphore if the value is greater than 0, otherwise returns false. bool ReceiveSignal() { bool ret = false; scoped_lock lock(*m_mutex); if( m_value > 0 ) { --m_value; ret = true; } lock.unlock(); return ret; } // Increments the value of this semaphore by 1, waking any sleeping threads waiting // on this semaphore. void Signal() { scoped_lock lock(*m_mutex); ++m_value; int ret = pthread_cond_signal(m_cv); if( ret != 0 ) { throw Barry::Error("Condvar: failed to signal condvar"); } lock.unlock(); } }; } // namespace Barry #endif barry-0.18.5/src/m_desktop.cc0000644001161500056700000004426712242254476015354 0ustar cdfreycdfrey/// /// \file m_desktop.cc /// Mode class for the Desktop mode /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "m_desktop.h" #include "data.h" #include "protocol.h" #include "protostructs.h" #include "packet.h" #include "endian.h" #include "error.h" #include "usbwrap.h" #include "controller.h" #include "parser.h" #include #include #include "debug.h" namespace Barry { namespace Mode { /////////////////////////////////////////////////////////////////////////////// // Desktop Mode class Desktop::Desktop(Controller &con) : Mode(con, Controller::Desktop) , m_ic(0) { } Desktop::Desktop(Controller &con, const IConverter &ic) : Mode(con, Controller::Desktop) , m_ic(&ic) { } Desktop::~Desktop() { } /////////////////////////////////////////////////////////////////////////////// // protected members void Desktop::LoadCommandTable() { char rawCommand[] = { 6, 0, 0x0a, 0, 0x40, 0, 0, 1, 0, 0 }; Data command(rawCommand, sizeof(rawCommand)); try { m_socket->Packet(command, m_response); MAKE_PACKET(rpack, m_response); while( rpack->command != SB_COMMAND_DB_DONE ) { m_socket->NextRecord(m_response); rpack = (const Protocol::Packet *) m_response.GetData(); if( rpack->command == SB_COMMAND_DB_DATA && btohs(rpack->size) > 10 ) { // second packet is generally large, and contains // the command table m_commandTable.Clear(); m_commandTable.Parse(m_response, 6); } } ddout(m_commandTable); } catch( Usb::Error & ) { eout(_("Desktop: error getting command table")); eeout(command, m_response); throw; } } void Desktop::LoadDBDB() { DBPacket packet(*this, m_command, m_response); packet.GetDBDB(); m_socket->Packet(packet); while( packet.Command() != SB_COMMAND_DB_DONE ) { if( packet.Command() == SB_COMMAND_DB_DATA ) { m_dbdb.Clear(); m_dbdb.Parse(m_response); } // advance! m_socket->NextRecord(m_response); } } void Desktop::OnOpen() { // get command table and database database LoadCommandTable(); LoadDBDB(); } /////////////////////////////////////////////////////////////////////////////// // public API // // GetDBID // /// Get numeric database ID by name. /// /// \param[in] name Name of database, which matches one of the /// names listed in GetDBDB() /// /// \exception Barry::Error /// Thrown if name not found. /// unsigned int Desktop::GetDBID(const std::string &name) const { unsigned int ID = 0; // FIXME - this needs a better error handler... if( !m_dbdb.GetDBNumber(name, ID) ) { throw Error(_("Desktop: database name not found: ") + name); } return ID; } // // GetDBCommand // /// Get database command from command table. Must call Open() /// before this. /// unsigned int Desktop::GetDBCommand(CommandType ct) { unsigned int cmd = 0; const char *cmdName = "Unknown"; switch( ct ) { case DatabaseAccess: cmdName = "Database Access"; cmd = m_commandTable.GetCommand(cmdName); break; default: throw std::logic_error(_("Desktop: unknown command type")); } if( cmd == 0 ) { std::ostringstream oss; oss << _("Desktop: unable to get command code: ") << cmdName; throw Error(oss.str()); } return cmd; } void Desktop::SetIConverter(const IConverter &ic) { m_ic = ⁣ } // // GetRecordStateTable // /// Retrieve the record state table from the handheld device, using the given /// database ID. Results will be stored in result, which will be cleared /// before adding. /// void Desktop::GetRecordStateTable(unsigned int dbId, RecordStateTable &result) { dout(_("Database ID: ") << dbId); // start fresh result.Clear(); DBPacket packet(*this, m_command, m_response); packet.GetRecordStateTable(dbId); m_socket->Packet(packet); result.Parse(m_response); // flush the command sequence while( packet.Command() != SB_COMMAND_DB_DONE ) m_socket->NextRecord(m_response); } // // AddRecord // /// Adds a record to the specified database. RecordId is /// retrieved from build, and duplicate IDs are allowed by the device /// (i.e. you can have two records with the same ID) /// but *not* recommended! // void Desktop::AddRecord(unsigned int dbId, Builder &build) { dout(_("Database ID: ") << dbId); DBPacket packet(*this, m_command, m_response); if( packet.AddRecord(dbId, build, m_ic) ) { std::ostringstream oss; m_socket->Packet(packet); // successful packet transfer, so check the network return code if( packet.Command() != SB_COMMAND_DB_DONE ) { oss << _("Desktop: device responded with unexpected packet command code: ") << "0x" << std::hex << packet.Command(); throw Error(oss.str()); } if( packet.ReturnCode() != 0 ) { oss << _("Desktop: device responded with error code (command: ") << packet.Command() << ", " << _("code: ") << packet.ReturnCode() << ")"; throw ReturnCodeError(oss.str(), packet.Command(), packet.ReturnCode()); } } } // // GetRecord // /// Retrieves a specific record from the specified database. /// The stateTableIndex comes from the GetRecordStateTable() /// function. GetRecord() does not clear the dirty flag. /// void Desktop::GetRecord(unsigned int dbId, unsigned int stateTableIndex, Parser &parser) { dout(_("Database ID: ") << dbId); std::string dbName; m_dbdb.GetDBName(dbId, dbName); DBPacket packet(*this, m_command, m_response); packet.GetRecordByIndex(dbId, stateTableIndex); m_socket->Packet(packet); // perform copious packet checks if( m_response.GetSize() < SB_PACKET_RESPONSE_HEADER_SIZE ) { eeout(m_command, m_response); std::ostringstream oss; oss << _("Desktop: invalid response packet size of: ") << std::dec << m_response.GetSize(); eout(oss.str()); throw Error(oss.str()); } if( packet.Command() != SB_COMMAND_DB_DATA ) { eeout(m_command, m_response); std::ostringstream oss; oss << _("Desktop: unexpected command of ") << "0x" << std::setbase(16) << packet.Command() << _(" instead of expected ") << "0x" << std::setbase(16) << (unsigned int)SB_COMMAND_DB_DATA; eout(oss.str()); throw Error(oss.str()); } // grab that data packet.Parse(parser, dbName, m_ic); // flush the command sequence while( packet.Command() != SB_COMMAND_DB_DONE ) m_socket->NextRecord(m_response); } // // SetRecord // /// Overwrites a specific record in the device as identified by the /// stateTableIndex. /// void Desktop::SetRecord(unsigned int dbId, unsigned int stateTableIndex, Builder &build) { dout(_("Database ID: ") << dbId << " " << _("Index: ") << stateTableIndex); DBPacket packet(*this, m_command, m_response); // write only if builder object has data if( !packet.SetRecordByIndex(dbId, stateTableIndex, build, m_ic) ) { throw std::logic_error(_("Desktop: no data available in SetRecord")); } m_socket->Packet(packet); std::ostringstream oss; // successful packet transfer, so check the network return code if( packet.Command() != SB_COMMAND_DB_DONE ) { oss << _("Desktop: device responded with unexpected packet command code: ") << "0x" << std::hex << packet.Command(); throw Error(oss.str()); } if( packet.ReturnCode() != 0 ) { oss << _("Desktop: device responded with error code (command: ") << packet.Command() << ", " << _("code: ") << packet.ReturnCode() << ")"; throw ReturnCodeError(oss.str(), packet.Command(), packet.ReturnCode()); } } // // ClearDirty // /// Clears the dirty flag on the specified record in the specified database. /// void Desktop::ClearDirty(unsigned int dbId, unsigned int stateTableIndex) { dout(_("Database ID: ") << dbId); DBPacket packet(*this, m_command, m_response); packet.SetRecordFlags(dbId, stateTableIndex, 0); m_socket->Packet(packet); // flush the command sequence while( packet.Command() != SB_COMMAND_DB_DONE ) m_socket->NextRecord(m_response); } // // DeleteRecord // /// Deletes the specified record in the specified database. /// void Desktop::DeleteRecord(unsigned int dbId, unsigned int stateTableIndex) { dout(_("Database ID: ") << dbId); DBPacket packet(*this, m_command, m_response); packet.DeleteRecordByIndex(dbId, stateTableIndex); m_socket->Packet(packet); // flush the command sequence while( packet.Command() != SB_COMMAND_DB_DONE ) m_socket->NextRecord(m_response); } // // LoadDatabase // /// Retrieve a database from the handheld device, using the given parser /// to parse the resulting data, and optionally store it. /// /// See the RecordParser<> template to create a parser object. The /// RecordParser<> template allows custom storage based on the type of /// database record retrieved. The database ID and the parser Record /// type must match. /// /// \param[in] dbId Database Database ID - use GetDBID() /// \param[out] parser Parser object which parses the resulting /// protocol data, and optionally stores it in /// a custom fashion. See the RecordParser<> /// template. /// /// \exception Barry::Error /// Thrown on protocol error. /// /// \exception std::logic_error /// Thrown if not in Desktop mode. /// void Desktop::LoadDatabase(unsigned int dbId, Parser &parser) { DBData data; DBLoader loader(*this); bool loading = loader.StartDBLoad(dbId, data); while( loading ) { // manual parser call parser.ParseRecord(data, m_ic); // advance! loading = loader.GetNextRecord(data); } } void Desktop::ClearDatabase(unsigned int dbId) { dout(_("Database ID: ") << dbId); DBPacket packet(*this, m_command, m_response); packet.ClearDatabase(dbId); // wait up to a minute here for old, slower devices with lots of data m_socket->Packet(packet, 60000); if( packet.ReturnCode() != 0 ) { std::ostringstream oss; oss << _("Desktop: could not clear database: (command: ") << "0x" << std::hex << packet.Command() << ", " << _("code: ") << "0x" << std::hex << packet.ReturnCode() << ")"; throw ReturnCodeError(oss.str(), packet.Command(), packet.ReturnCode()); } // check response to clear command was successful if( packet.Command() != SB_COMMAND_DB_DONE ) { eeout(m_command, m_response); throw Error(_("Desktop: error clearing database, bad response")); } } void Desktop::SaveDatabase(unsigned int dbId, Builder &builder) { dout(_("Database ID: ") << dbId); ClearDatabase(dbId); DBPacket packet(*this, m_command, m_response); // loop until builder object has no more data bool first = true; while( packet.AddRecord(dbId, builder, m_ic) ) { dout(_("Database ID: ") << dbId); m_socket->Packet(packet, first ? 60000 : -1); first = false; std::ostringstream oss; // successful packet transfer, so check the network return code if( packet.Command() != SB_COMMAND_DB_DONE ) { oss << _("Desktop: device responded with unexpected packet command code: ") << "0x" << std::hex << packet.Command(); throw Error(oss.str()); } if( packet.ReturnCode() != 0 ) { oss << _("Desktop: device responded with error code (command: ") << packet.Command() << ", " << _("code: ") << packet.ReturnCode() << ")"; throw ReturnCodeError(oss.str(), packet.Command(), packet.ReturnCode()); } } } ////////////////////////////////////////////////////////////////////////////// // DBLoader class struct DBLoaderData { DBPacket m_packet; DBLoaderData(Desktop &desktop, Data &command, Data &response) : m_packet(desktop, command, response) { } }; DBLoader::DBLoader(Desktop &desktop) : m_desktop(desktop) , m_loading(false) , m_loader(new DBLoaderData(desktop, m_send, m_send)) { } DBLoader::~DBLoader() { delete m_loader; } bool DBLoader::StartDBLoad(unsigned int dbId, DBData &data) { dout(_("Database ID: ") << dbId); m_loading = true; m_desktop.m_dbdb.GetDBName(dbId, m_dbName); DBPacket &packet = m_loader->m_packet; packet.SetNewReceive(data.UseData()); packet.GetRecords(dbId); m_desktop.m_socket->Packet(packet); while( packet.Command() != SB_COMMAND_DB_DONE ) { if( packet.Command() == SB_COMMAND_DB_DATA ) { packet.ParseMeta(data); data.SetDBName(m_dbName); return true; } // advance! (use the same data block as in packet) m_desktop.m_socket->NextRecord(data.UseData()); } m_loading = false; return false; } bool DBLoader::GetNextRecord(DBData &data) { if( !m_loading ) return false; DBPacket &packet = m_loader->m_packet; packet.SetNewReceive(data.UseData()); do { // advance! (use same data as in packet) m_desktop.m_socket->NextRecord(data.UseData()); if( packet.Command() == SB_COMMAND_DB_DATA ) { packet.ParseMeta(data); return true; } } while( m_loader->m_packet.Command() != SB_COMMAND_DB_DONE ); m_loading = false; return false; } } // namespace Barry::Mode ////////////////////////////////////////////////////////////////////////////// // DeviceBuilder class DeviceBuilder::DeviceBuilder(Mode::Desktop &desktop) : m_started(false) , m_desktop(desktop) , m_loader(desktop) { Restart(); } // searches the dbdb from the desktop to find the dbId, // returns false if not found, and adds it to the list of // databases to retrieve if found bool DeviceBuilder::Add(const std::string &dbname) { try { DBLabel id(m_desktop.GetDBID(dbname), dbname); m_dbIds.push_back(id); return true; } catch( Barry::Error & ) { // GetDBID() throws on error... return false; } } void DeviceBuilder::Add(const Barry::DatabaseDatabase &dbdb) { DatabaseDatabase::DatabaseArrayType::const_iterator b = dbdb.Databases.begin(), e = dbdb.Databases.end(); for( ; b != e; ++b ) { // hmmm, could optimize this and only add ids // with RecordCount > 0, but let's stick with this // for now... it might flush bugs out of the system DBLabel id(b->Number, b->Name); m_dbIds.push_back(id); } } bool DeviceBuilder::BuildRecord(DBData &data, size_t &offset, const IConverter *ic) { DBData temp; if( !FetchRecord(temp, ic) ) return false; // copy the metadata data.SetVersion(temp.GetVersion()); data.SetDBName(temp.GetDBName()); data.SetIds(temp.GetRecType(), temp.GetUniqueId()); data.SetOffset(offset); // copy data from temp into the given offset size_t tempsize = temp.GetData().GetSize() - temp.GetOffset(); data.UseData().MemCpy(offset, temp.GetData().GetData() + temp.GetOffset(), tempsize); data.UseData().ReleaseBuffer(offset + tempsize); return true; } bool DeviceBuilder::FetchRecord(DBData &data, const IConverter *ic) { bool ret; if( !m_dbIds.size() ) return false; // nothing to do if( !m_started ) { m_current = m_dbIds.begin(); ret = m_loader.StartDBLoad(m_current->id, data); m_started = true; } else if( m_loader.IsBusy() ) { ret = m_loader.GetNextRecord(data); } else { // don't do anything if we're at the end of our rope if( EndOfFile() ) return false; // advance and check again... m_current always points // to our current DB ++m_current; if( EndOfFile() ) return false; ret = m_loader.StartDBLoad(m_current->id, data); } // fill in the DBname if successful if( ret ) { data.SetDBName(m_current->name); } return ret; } bool DeviceBuilder::EndOfFile() const { return m_current == m_dbIds.end(); } ////////////////////////////////////////////////////////////////////////////// // DeviceParser class DeviceParser::DeviceParser(Mode::Desktop &desktop, WriteMode mode) : m_desktop(desktop) , m_mode(mode) { } DeviceParser::~DeviceParser() { } void DeviceParser::StartDB(const DBData &data, const IConverter *ic) { // start fresh m_rstate.Clear(); m_current_db = data.GetDBName(); if( !m_desktop.GetDBDB().GetDBNumber(m_current_db, m_current_dbid) ) { // doh! This database does not exist in this device dout(_("This database does not exist in device: ") << m_current_db << ". " << _("Dropping record.")); m_current_db.clear(); m_current_dbid = 0; return; } // determine mode WriteMode mode = m_mode; if( mode == DECIDE_BY_CALLBACK ) mode = DecideWrite(data); switch( mode ) { case ERASE_ALL_WRITE_ALL: m_desktop.ClearDatabase(m_current_dbid); WriteNext(data, ic); break; case INDIVIDUAL_OVERWRITE: case ADD_BUT_NO_OVERWRITE: case ADD_WITH_NEW_ID: m_desktop.GetRecordStateTable(m_current_dbid, m_rstate); WriteNext(data, ic); break; case DROP_RECORD: break; case DECIDE_BY_CALLBACK: default: throw std::logic_error(_("DeviceParser: unknown mode")); } } void DeviceParser::WriteNext(const DBData &data, const IConverter *ic) { // determine mode WriteMode mode = m_mode; if( mode == DECIDE_BY_CALLBACK ) mode = DecideWrite(data); // create fast copy with our own metadata DBData local(data.GetVersion(), data.GetDBName(), data.GetRecType(), data.GetUniqueId(), data.GetOffset(), data.GetData().GetData(), data.GetData().GetSize()); DBDataBuilder dbuild(local); RecordStateTable::IndexType index; switch( mode ) { case ERASE_ALL_WRITE_ALL: // just do an AddRecord() m_desktop.AddRecord(m_current_dbid, dbuild); break; case INDIVIDUAL_OVERWRITE: // search the state table, overwrite existing, and add new if( m_rstate.GetIndex(local.GetUniqueId(), &index) ) { // found this record ID, use the index m_desktop.SetRecord(m_current_dbid, index, dbuild); } else { // new record m_desktop.AddRecord(m_current_dbid, dbuild); } break; case ADD_BUT_NO_OVERWRITE: if( !m_rstate.GetIndex(local.GetUniqueId()) ) { // no such record ID, so safe to add as new m_desktop.AddRecord(m_current_dbid, dbuild); } // else, drop record break; case ADD_WITH_NEW_ID: // use state table to create new id, and add as new local.SetIds(local.GetRecType(), m_rstate.MakeNewRecordId()); m_desktop.AddRecord(m_current_dbid, dbuild); break; case DROP_RECORD: break; case DECIDE_BY_CALLBACK: default: throw std::logic_error(_("DeviceParser: unknown mode")); } } void DeviceParser::ParseRecord(const DBData &data, const IConverter *ic) { if( data.GetDBName() == m_current_db ) { WriteNext(data, ic); } else { StartDB(data, ic); } } } // namespace Barry barry-0.18.5/src/tarfile.h0000644001161500056700000000454112242254476014646 0ustar cdfreycdfrey/// /// \file tarfile.h /// API for reading and writing sequentially from compressed /// tar files. /* Copyright (C) 2007-2013, Chris Frey 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __REUSE_TARFILE_H__ #define __REUSE_TARFILE_H__ #include "dll.h" #include #include #include namespace Barry { class Data; } namespace reuse { // // Compression options... more op sets can be added based on // threading needs, or threading library support. // /// Compression op set for zlib, non-threadsafe. extern tartype_t gztar_ops_nonthread; class BXLOCAL TarFile { TAR *m_tar; bool m_throw; bool m_writemode; std::string m_last_error; private: bool False(const char *msg); bool False(const std::string &str) { return False(str.c_str()); } bool False(const std::string &msg, int err); public: class TarError : public std::runtime_error { public: TarError(const std::string &msg) : std::runtime_error(msg) {} }; public: explicit TarFile(const char *filename, bool write = false, tartype_t *compress_ops = 0, bool always_throw = false); ~TarFile(); const std::string& get_last_error() const { return m_last_error; } bool Close(); /// Appends a new file to the current tarfile, using tarpath as /// its internal filename, and data as the complete file contents. /// Uses current date and time as file mtime. bool AppendFile(const char *tarpath, const std::string &data); /// Reads next available file into data, filling tarpath with /// internal filename from tarball. /// Returns false on end of archive. bool ReadNextFile(std::string &tarpath, std::string &data); bool ReadNextFile(std::string &tarpath, Barry::Data &data); /// Read next available filename, skipping the data if it is /// a regular file bool ReadNextFilenameOnly(std::string &tarpath); }; } #endif barry-0.18.5/src/restore.h0000644001161500056700000001237112242254476014703 0ustar cdfreycdfrey/// /// \file restore.h /// Builder class for restoring from Barry Backup files /// /* Copyright (C) 2010-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRYBACKUP_RESTORE_H__ #define __BARRYBACKUP_RESTORE_H__ #include "dll.h" #include "builder.h" #include "configfile.h" #include #include #include // forward declarations namespace reuse { class TarFile; } namespace Barry { // // Restore // /// Barry Backup Restore builder class. This class is suitable /// to be used as a builder object anywhere a builder object is /// accepted. It reads from a Barry Backup tar.gz backup file, /// and builds records in a staged manner. /// /// If a backup file contains more than one database (for example /// both Address Book and Calendar), then it will build one database /// first, return false on Retrieve(), and then build the next. /// If Retrieve() returns false, but EndOfFile() also returns false, /// then more databases are available. /// /// The idea is that you can call Desktop::SaveDatabase() multiple /// times with this same Restore object, for all the databases in /// the backup file. /// /// It is safe to call Retrieve() multiple times, so when first /// starting a restore: /// - call the constructor /// - call AddDB() with any filters /// - then call Retrieve(), which will grab the first record, /// and make GetDBName() valid. /// class BXEXPORT Restore : public Barry::Builder { public: typedef Barry::ConfigFile::DBListType DBListType; private: enum RetrievalState { RS_EMPTY, // no record loaded RS_UNKNOWN, // record data loaded, but not yet checked // whether this is part of current database RS_NEXT, // record loaded, part of current database RS_DBEND, // next record loaded, but end-of-database // not yet processed by Builder API RS_EOF // no recrd loaded, end of tar file }; DBListType m_dbList; DBListType m_dbSkipList; std::string m_tarpath; std::auto_ptr m_tar; bool m_default_all_db; RetrievalState m_tar_record_state; uint8_t m_rec_type; uint32_t m_unique_id; std::string m_current_dbname; Barry::Data m_record_data; std::string m_tar_id_text; protected: static bool SplitTarPath(const std::string &tarpath, std::string &dbname, std::string &dbid_text, uint8_t &dbrectype, uint32_t &dbid); bool IsSelected(const std::string &dbName) const; RetrievalState Retrieve(Data &record_data); public: /// If default_all_db is true, and none of the Add*() functions /// are called (meaning that Restore has an empty database list), /// then all records are restored. If false in this situation, /// nothing is restored. /// /// If any of the Add*() functions are called, then the database /// list takes precedence, and default_all_db has no effect. /// explicit Restore(const std::string &tarpath, bool default_all_db = true); ~Restore(); /// Add database name to the read filter. void AddDB(const std::string &dbName); /// Add all database names in dblist to the read filter void Add(const DBListType &dbList); /// Add all database names in the DBDB to the read filter void Add(const DatabaseDatabase &dbdb); /// Add database name to the skip list. The skip list prevents /// any matching database from appearing in the restore process. /// It is the converse of AddDB() in ultimate behaviour. void AddSkipDB(const std::string &dbName); // Skip the current DB, in case of error, or preference void SkipCurrentDB(); /// Loads the given file, and counts all records according /// to the current read filter. Does not use the main /// Restore file, but opens the file separately. /// It is safe to call this function as often as needed. unsigned int GetRecordTotal() const; /// Static version of above call static unsigned int GetRecordTotal(const std::string &tarpath, const DBListType &dbList, bool default_all_db); /// Loads the given file, and creates a DBListType list of /// all database names available in the tarball, using no filters. /// Does not use the main Restore file, but opens the file separately. /// It is safe to call this function as often as needed. DBListType GetDBList() const; /// Static version of GetDBList() static DBListType GetDBList(const std::string &tarpath); /// If this function returns true, it fills data with the /// meta data that the next call to BuildRecord() will retrieve. /// This is useful for applications that need to setup a manual /// call to Desktop::SaveDatabase(). bool GetNextMeta(DBData &data); // Barry::Builder overrides bool BuildRecord(Barry::DBData &data, size_t &offset, const Barry::IConverter *ic); bool FetchRecord(Barry::DBData &data, const Barry::IConverter *ic); bool EndOfFile() const; }; } // namespace Barry #endif barry-0.18.5/src/barry.h0000644001161500056700000000533712242254476014343 0ustar cdfreycdfrey/// /// \file barry.h /// Main header file for applications /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_BARRY_H__ #define __BARRY_BARRY_H__ /** \mainpage Barry Reference Manual \section getting_started Getting Started Welcome to the Barry reference manual. This entire manual was generated via Doxygen from comments in the code. You can view the code here as well, in the Files section. The best place to get started at the moment is to examine the source code to the Barry command line tool: btool.cc \section classes Major Classes To get started with the API, see the Barry::Controller class. */ // This lists all the headers that the application needs. // Only these headers get installed. #include "data.h" #include "usbwrap.h" // to be moved to libusb someday #include "common.h" // Init() #include "error.h" // exceptions #include "configfile.h" #include "probe.h" // device prober class #include "dataqueue.h" #include "socket.h" #include "router.h" #include "protocol.h" // application-safe header #include "parser.h" #include "builder.h" #include "ldif.h" #include "ldifio.h" #include "controller.h" #include "m_desktop.h" #include "m_ipmodem.h" #include "m_serial.h" #include "m_javaloader.h" #include "m_raw_channel.h" #include "m_jvmdebug.h" #include "version.h" #include "log.h" #include "sha1.h" #include "iconv.h" #include "bmp.h" #include "cod.h" #include "record.h" #include "threadwrap.h" #include "vsmartptr.h" #include "pipe.h" #include "connector.h" #include "fifoargs.h" // Include the JDW Debug Parser classes #include "dp_codinfo.h" // Include the JDWP Server classes #include "j_manager.h" #include "j_server.h" // Include the template helpers after the record classes #include "m_desktoptmpl.h" #include "recordtmpl.h" #ifdef __BARRY_BOOST_MODE__ // Boost serialization seems to be picky about header order, do them all here #include #include #include #include #include #include #include #include #include "s11n-boost.h" #endif #endif barry-0.18.5/src/r_recur_base.cc0000644001161500056700000002022612242254476016007 0ustar cdfreycdfrey/// /// \file r_recur_base.cc /// Base class for recurring calendar event data. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "r_recur_base.h" #include "protostructs.h" #include "error.h" #include "endian.h" #include "time.h" #include "ios_state.h" #include #include #define __DEBUG_MODE__ #include "debug.h" using namespace std; using namespace Barry::Protocol; #define FIELDCODE_RECURRENCE_DATA 0x0c namespace Barry { /////////////////////////////////////////////////////////////////////////////// // RecurBase class, static members unsigned char RecurBase::WeekDayProto2Rec(uint8_t raw_field) { // Note: this simple copy is only possible since // the CAL_WD_* constants are the same as CRDF_WD_* constants. // If this ever changes, this code will need to change. return raw_field; } uint8_t RecurBase::WeekDayRec2Proto(unsigned char weekdays) { // Note: this simple copy is only possible since // the CAL_WD_* constants are the same as CRDF_WD_* constants. // If this ever changes, this code will need to change. return weekdays; } /////////////////////////////////////////////////////////////////////////////// // RecurBase class RecurBase::RecurBase() { Clear(); } RecurBase::~RecurBase() { } bool RecurBase::ParseField(uint8_t type, const unsigned char *data, size_t size, const IConverter *ic) { // handle special cases switch( type ) { case FIELDCODE_RECURRENCE_DATA: if( size >= CALENDAR_RECURRENCE_DATA_FIELD_SIZE ) { // good data ParseRecurrenceData(data); } else { // not enough data! throw Error(_("RecurBase::ParseField: not enough data in recurrence data field")); } return true; } // unknown field return false; } // this function assumes the size has already been checked void RecurBase::ParseRecurrenceData(const void *data) { const CalendarRecurrenceDataField *rec = (const CalendarRecurrenceDataField*) data; Interval = btohs(rec->interval); if( Interval < 1 ) Interval = 1; // must always be >= 1 if( rec->endTime == 0xffffffff ) { Perpetual = true; } else { RecurringEndTime.Time = min2time(rec->endTime); Perpetual = false; } switch( rec->type ) { case CRDF_TYPE_DAY: RecurringType = Day; // no extra data break; case CRDF_TYPE_MONTH_BY_DATE: RecurringType = MonthByDate; DayOfMonth = rec->u.month_by_date.monthDay; break; case CRDF_TYPE_MONTH_BY_DAY: RecurringType = MonthByDay; DayOfWeek = rec->u.month_by_day.weekDay; WeekOfMonth = rec->u.month_by_day.week; break; case CRDF_TYPE_YEAR_BY_DATE: RecurringType = YearByDate; DayOfMonth = rec->u.year_by_date.monthDay; MonthOfYear = rec->u.year_by_date.month; break; case CRDF_TYPE_YEAR_BY_DAY: RecurringType = YearByDay; DayOfWeek = rec->u.year_by_day.weekDay; WeekOfMonth = rec->u.year_by_day.week; MonthOfYear = rec->u.year_by_day.month; break; case CRDF_TYPE_WEEK: RecurringType = Week; WeekDays = WeekDayProto2Rec(rec->u.week.days); break; default: eout("Unknown recurrence data type: 0x" << setbase(16) << (unsigned int) rec->type); throw Error(_("Unknown recurrence data type")); } Recurring = true; } void RecurBase::Validate() const { } // this function assumes there is CALENDAR_RECURRENCE_DATA_FIELD_SIZE bytes // available in data void RecurBase::BuildRecurrenceData(time_t StartTime, void *data) const { if( !Recurring ) throw Error(_("RecurBase::BuildRecurrenceData: Attempting to build recurrence data on non-recurring record.")); CalendarRecurrenceDataField *rec = (CalendarRecurrenceDataField*) data; // set all to zero memset(data, 0, CALENDAR_RECURRENCE_DATA_FIELD_SIZE); rec->interval = htobs(Interval); rec->startTime = time2min(StartTime); if( Perpetual ) rec->endTime = 0xffffffff; else rec->endTime = time2min(RecurringEndTime.Time); switch( RecurringType ) { case Day: rec->type = CRDF_TYPE_DAY; // no extra data break; case MonthByDate: rec->type = CRDF_TYPE_MONTH_BY_DATE; rec->u.month_by_date.monthDay = (uint8_t)DayOfMonth; break; case MonthByDay: rec->type = CRDF_TYPE_MONTH_BY_DAY; rec->u.month_by_day.weekDay = (uint8_t)DayOfWeek; rec->u.month_by_day.week = (uint8_t)WeekOfMonth; break; case YearByDate: rec->type = CRDF_TYPE_YEAR_BY_DATE; rec->u.year_by_date.monthDay = (uint8_t)DayOfMonth; rec->u.year_by_date.month = (uint8_t)MonthOfYear; break; case YearByDay: rec->type = CRDF_TYPE_YEAR_BY_DAY; rec->u.year_by_day.weekDay = (uint8_t)DayOfWeek; rec->u.year_by_day.week = (uint8_t)WeekOfMonth; rec->u.year_by_day.month = (uint8_t)MonthOfYear; break; case Week: rec->type = CRDF_TYPE_WEEK; rec->u.week.days = WeekDayRec2Proto(WeekDays); break; default: eout("RecurBase::BuildRecurrenceData: " "Unknown recurrence data type: 0x" << setbase(16) << (unsigned int) rec->type); throw Error(_("RecurBase::BuildRecurrenceData: Unknown recurrence data type")); } } uint8_t RecurBase::RecurringFieldType() const { return FIELDCODE_RECURRENCE_DATA; } void RecurBase::Clear() { Recurring = false; RecurringType = RecurBase::Week; Interval = 1; RecurringEndTime.clear(); Perpetual = false; DayOfWeek = WeekOfMonth = DayOfMonth = MonthOfYear = 0; WeekDays = 0; } void RecurBase::Dump(std::ostream &os) const { ios_format_state state(os); static const char *DayNames[] = { N_("Sun"), N_("Mon"), N_("Tue"), N_("Wed"), N_("Thu"), N_("Fri"), N_("Sat") }; static const char *MonthNames[] = { N_("Jan"), N_("Feb"), N_("Mar"), N_("Apr"), N_("May"), N_("Jun"), N_("Jul"), N_("Aug"), N_("Sep"), N_("Oct"), N_("Nov"), N_("Dec") }; // FIXME - need a "check all data" function that make sure that all // recurrence data is within range. Then call that before using // the data, such as in Build and in Dump. // print recurrence data if available os << _(" Recurring: ") << (Recurring ? _("yes") : _("no")) << "\n"; if( Recurring ) { switch( RecurringType ) { case Day: os << _(" Every day.\n"); break; case MonthByDate: // TRANSLATORS: to remove the 'th' ending on numbers, // just replace the %s with %.0s in this string. os << string_vprintf(_(" Every month on the %u%s"), DayOfMonth, (DayOfMonth == 1 ? "st" : (DayOfMonth == 2 ? "nd" : (DayOfMonth == 3 ? "rd" : (DayOfMonth > 3 ? "th" : ""))))) << "\n"; break; case MonthByDay: os << string_vprintf(_(" Every month on the %s of week %u"), gettext( DayNames[DayOfWeek] ), WeekOfMonth) << "\n"; break; case YearByDate: os << string_vprintf(_(" Every year on %s %u"), gettext( MonthNames[MonthOfYear-1] ), DayOfMonth) << "\n"; break; case YearByDay: os << string_vprintf(_(" Every year in %s on %s of week %u"), gettext( MonthNames[MonthOfYear-1] ), gettext( DayNames[DayOfWeek] ), WeekOfMonth) << "\n"; break; case Week: os << _(" Every week on: "); if( WeekDays & CAL_WD_SUN ) os << gettext("Sun") << " "; if( WeekDays & CAL_WD_MON ) os << gettext("Mon") << " "; if( WeekDays & CAL_WD_TUE ) os << gettext("Tue") << " "; if( WeekDays & CAL_WD_WED ) os << gettext("Wed") << " "; if( WeekDays & CAL_WD_THU ) os << gettext("Thu") << " "; if( WeekDays & CAL_WD_FRI ) os << gettext("Fri") << " "; if( WeekDays & CAL_WD_SAT ) os << gettext("Sat") << " "; os << "\n"; break; default: os << _(" Unknown recurrence type\n"); break; } os << dec << _(" Interval: ") << Interval << "\n"; if( Perpetual ) os << _(" Ends: never\n"); else os << _(" Ends: ") << RecurringEndTime << "\n"; } } } // namespace Barry barry-0.18.5/src/r_sms.h0000644001161500056700000000640412242254476014343 0ustar cdfreycdfrey/// /// \file r_sms.h /// Record parsing class for SMS messages. /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2009, Ryan Li(ryan@ryanium.com) 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_RECORD_SMS_H__ #define __BARRY_RECORD_SMS_H__ #include "dll.h" #include "record.h" #include #include #include namespace Barry { // forward declarations class IConverter; class BXEXPORT Sms { public: typedef Barry::UnknownsType UnknownsType; uint8_t RecType; uint32_t RecordId; enum MessageType { Unknown = 0, Received, Sent, Draft }; MessageType MessageStatus; enum DeliveryType { NoReport = 0, Failed, Succeeded }; DeliveryType DeliveryStatus; // not implemented yet bool IsNew; bool NewConversation; bool Saved; bool Deleted; bool Opened; uint64_t Timestamp; // milliseconds from Jan 1, 1970 uint64_t ServiceCenterTimestamp; // not applicable for non-incoming messages enum DataCodingSchemeType { SevenBit = 0, EightBit, UCS2 }; DataCodingSchemeType DataCodingScheme; uint32_t ErrorId; EmailList Addresses; //< not strictly email, but just a list //< strings, used for phone numbers std::string Body; UnknownsType Unknowns; public: Sms(); ~Sms(); time_t GetTime() const; time_t GetServiceCenterTime() const; void SetTime(const time_t timestamp, unsigned int milliseconds = 0); void SetServiceCenterTime(const time_t timestamp, unsigned int milliseconds = 0); // Parser / Builder API (see parser.h / builder.h) void Validate() const; const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); uint8_t GetRecType() const { return RecType; } uint32_t GetUniqueId() const { return RecordId; } void SetIds(uint8_t Type, uint32_t Id) { RecType = Type; RecordId = Id; } void ParseHeader(const Data &data, size_t &offset); void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); void BuildHeader(Data &data, size_t &offset) const; void BuildFields(Data &data, size_t &offset, const IConverter *ic = 0) const; // operations (common among record classes) void Clear(); void Dump(std::ostream &os) const; std::string GetDescription() const; static std::string ConvertGsmToUtf8(const std::string &); // sorting bool operator<(const Sms &other) const { return Timestamp < other.Timestamp; } // database name static const char * GetDBName() { return "SMS Messages"; } static uint8_t GetDefaultRecType() { return 5; } // Generic Field Handle support static const FieldHandle::ListT& GetFieldHandles(); }; BXEXPORT inline std::ostream& operator<<(std::ostream &os, const Sms &msg) { msg.Dump(os); return os; } } // namespace Barry #endif barry-0.18.5/src/bmp-internal.h0000644001161500056700000000340512242254476015606 0ustar cdfreycdfrey/// /// \file bmp-internal.h /// BMP structures /// /* Copyright (C) 2008-2009, Nicolas VIVIEN See also: http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html 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 in the COPYING file at the root directory of this project for more details. */ #ifndef __BARRY_BMP_INTERNAL_H__ #define __BARRY_BMP_INTERNAL_H__ #include "dll.h" #include #include #include "platform.h" // safe to include platform.h here, since // bmp-internal.h is not installed either #if USE_PACK_PRAGMA #pragma pack(push, 1) #endif typedef struct BXLOCAL { char bfType[2]; // Contains always 'BM' uint32_t bfSize; // Size of file uint16_t bfReserved1; // 0x00 uint16_t bfReserved2; // 0x00 uint32_t bfOffBits; // Offset to find the raw data } ATTRIBUTE_PACKED bmp_file_header_t; typedef struct BXLOCAL { uint32_t biSize; // Size of struct itself uint32_t biWidth; // Width of image uint32_t biHeight; // Height of image uint16_t biPlanes; // uint16_t biBitCount; // uint32_t biCompression; // uint32_t biSizeImage; // Size of raw data uint32_t biXPelsPerMeter; // uint32_t biYPelsPerMeter; // uint32_t biClrUsed; // uint32_t biClrImportant; // } ATTRIBUTE_PACKED bmp_info_header_t; #if USE_PACK_PRAGMA #pragma pack(pop) #endif #endif barry-0.18.5/src/r_message_base.cc0000644001161500056700000003405312242254476016316 0ustar cdfreycdfrey/// /// \file r_message_base.cc /// Base class for email-oriented Blackberry database records /// /* Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/) Copyright (C) 2007, Brian Edginton (edge@edginton.net) 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 in the COPYING file at the root directory of this project for more details. */ #include "i18n.h" #include "r_message_base.h" #include "record-internal.h" #include "protostructs.h" #include "data.h" #include "time.h" #include "endian.h" #include "iconv.h" #include #include #include #include "ios_state.h" #define __DEBUG_MODE__ #include "debug.h" using namespace std; using namespace Barry::Protocol; namespace Barry { /////////////////////////////////////////////////////////////////////////////// // Message class // Email / message field codes #define MBFC_TO 0x01 // can occur multiple times #define MBFC_CC 0x02 // ditto #define MBFC_BCC 0x03 // ditto #define MBFC_SENDER 0x04 #define MBFC_FROM 0x05 #define MBFC_REPLY_TO 0x06 #define MBFC_SUBJECT 0x0b #define MBFC_BODY 0x0c #define MBFC_REPLY_UNKNOWN 0x12 // This shows up as 0x00 on replies // but we don't do much with it now #define MBFC_ATTACHMENT 0x16 #define MBFC_RECORDID 0x4b // Internal Message ID, mimics header RecNumber #define MBFC_END 0xffff #define PRIORITY_MASK 0x003f #define PRIORITY_HIGH 0x0008 #define PRIORITY_LOW 0x0002 #define SENSITIVE_MASK 0xff80 #define SENSITIVE_CONFIDENTIAL 0x0100 #define SENSITIVE_PERSONAL 0x0080 #define SENSITIVE_PRIVATE 0x0040 // actual pattern is 0x00C0 #define MESSAGE_READ 0x0800 #define MESSAGE_REPLY 0x0001 #define MESSAGE_SAVED 0x0002 #define MESSAGE_FORWARD 0x0008 #define MESSAGE_TRUNCATED 0x0020 #define MESSAGE_SAVED_DELETED 0x0080 static FieldLink MessageBaseFieldLinks[] = { { MBFC_TO, N_("To"), 0, 0, 0, &MessageBase::To, 0, 0, 0, true }, { MBFC_CC, N_("Cc"), 0, 0, 0, &MessageBase::Cc, 0, 0, 0, true }, { MBFC_BCC, N_("Bcc"), 0, 0, 0, &MessageBase::Bcc, 0, 0, 0, true }, { MBFC_SENDER, N_("Sender"), 0, 0, 0, &MessageBase::Sender, 0, 0, 0, true }, { MBFC_FROM, N_("From"), 0, 0, 0, &MessageBase::From, 0, 0, 0, true }, { MBFC_REPLY_TO, N_("ReplyTo"), 0, 0, 0, &MessageBase::ReplyTo, 0, 0, 0, true }, { MBFC_SUBJECT, N_("Subject"), 0, 0, &MessageBase::Subject, 0, 0, 0, 0, true }, { MBFC_BODY, N_("Body"), 0, 0, &MessageBase::Body, 0, 0, 0, 0, true }, { MBFC_ATTACHMENT,N_("Attachment"), 0, 0, &MessageBase::Attachment, 0, 0, 0, 0, false }, { MBFC_END, N_("End of List"), 0, 0, 0, 0, 0, 0, 0, false } }; MessageBase::MessageBase() { Clear(); } MessageBase::~MessageBase() { } const unsigned char* MessageBase::ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic) { const CommonField *field = (const CommonField *) begin; // advance and check size begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size); if( begin > end ) // if begin==end, we are ok return begin; if( !btohs(field->size) ) // if field has no size, something's up return begin; // cycle through the type table for( FieldLink *b = MessageBaseFieldLinks; b->type != MBFC_END; b++ ) { if( b->type == field->type ) { if( b->strMember ) { // parse regular string std::string &s = this->*(b->strMember); s = ParseFieldString(field); if( b->iconvNeeded && ic ) s = ic->FromBB(s); return begin; // done! } else if( b->addrMember ) { // parse email address // get dual name+addr string first const char *fa = (const char*)field->u.addr.addr; std::string dual(fa, btohs(field->size) - sizeof(field->u.addr.unknown)); // assign first string, using null terminator // letting std::string add it for us if it // doesn't exist EmailAddress a; a.Name = dual.c_str(); // assign second string, using first size // as starting point a.Email = dual.c_str() + a.Name.size() + 1; // if the address is non-empty, add to list if( a.size() ) { // i18n convert if needed if( b->iconvNeeded && ic ) { a.Name = ic->FromBB(a.Name); a.Email = ic->FromBB(a.Email); } EmailAddressList &al = this->*(b->addrMember); al.push_back(a); } return begin; } } } // handle special cases switch( field->type ) { case MBFC_RECORDID: MessageRecordId = btohl(field->u.uint32); return begin; case MBFC_REPLY_UNKNOWN: // FIXME - not available in SavedMessage? //char swallow = field->u.raw[0]; return begin; } // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; uf.data.assign((const char*)field->u.raw, btohs(field->size)); Unknowns.push_back(uf); return begin; } void MessageBase::ParseHeader(const Data &data, size_t &offset) { const unsigned char *begin = data.GetData(); const unsigned char *end = data.GetData() + data.GetSize(); begin += offset + MESSAGE_RECORD_HEADER_SIZE; if( begin > end ) return; MAKE_RECORD(const Barry::Protocol::MessageRecord, mr, data, offset); // Priority Priority = NormalPriority; uint16_t priority = btohs(mr->priority); // deal with endian swap once if( priority & PRIORITY_MASK ) { if( priority & PRIORITY_HIGH ) { Priority = HighPriority; } else if( priority & PRIORITY_LOW ) { Priority = LowPriority; } else Priority = UnknownPriority; } // Sensitivity Sensitivity = NormalSensitivity; if( priority & SENSITIVE_MASK ) { if(( priority & SENSITIVE_CONFIDENTIAL ) == SENSITIVE_CONFIDENTIAL ) { Sensitivity = Confidential; } else if(( priority & SENSITIVE_PRIVATE ) == SENSITIVE_PRIVATE ) { Sensitivity = Private; } else if(( priority & SENSITIVE_PERSONAL ) == SENSITIVE_PERSONAL ) { Sensitivity = Personal; } else Sensitivity = UnknownSensitivity; } // X-rim-org-message-ref-id // NOTE: I'm cheating a bit here and using this as a reply-to // It's actually sent by BB with the actual UID in every message if( mr->inReplyTo ) MessageReplyTo = btohl(mr->inReplyTo); // Status Flags uint32_t flags = btohl(mr->flags); // NOTE: A lot of these flags are 'backwards' but this seemed // like the most logical way to interpret them for now if( !( flags & MESSAGE_READ )) MessageRead = true; // NOTE: This is a reply, the original message's flags are not changed // the inReplyTo field is updated with the original messages's UID if(( flags & MESSAGE_REPLY ) == MESSAGE_REPLY ) MessageReply = true; // NOTE: This bit is unset on truncation, around 4096 on my 7100g // NOTE: bit 0x400 is set on REALLY huge messages, haven't tested // the exact size yet if( !( flags & MESSAGE_TRUNCATED )) MessageTruncated = true; // NOTE: Saved to 'saved' folder if( !( flags & MESSAGE_SAVED )) MessageSaved = true; // NOTE: Saved to 'saved' folder and then deleted from inbox if( !( flags & MESSAGE_SAVED_DELETED )) MessageSavedDeleted = true; MessageDateSent.Time = Message2Time(mr->dateSent, mr->timeSent); MessageDateReceived.Time = Message2Time(mr->dateReceived, mr->timeReceived); offset += MESSAGE_RECORD_HEADER_SIZE; } void MessageBase::ParseFields(const Data &data, size_t &offset, const IConverter *ic) { const unsigned char *finish = ParseCommonFields(*this, data.GetData() + offset, data.GetData() + data.GetSize(), ic); offset += finish - (data.GetData() + offset); } void MessageBase::Validate() const { } void MessageBase::BuildHeader(Data &data, size_t &offset) const { throw std::logic_error(_("MessageBase::BuildHeader not yet implemented")); } void MessageBase::BuildFields(Data &data, size_t &offset, const IConverter *ic) const { throw std::logic_error(_("MessageBase::BuildFields not yet implemented")); } void MessageBase::Clear() { // these must be overwritten by any derived classes RecType = 0; RecordId = 0; // clear base class variables From.clear(); To.clear(); Cc.clear(); Bcc.clear(); Sender.clear(); ReplyTo.clear(); Subject.clear(); Body.clear(); Attachment.clear(); MessageRecordId = 0; MessageReplyTo = 0; MessageDateSent.clear(); MessageDateReceived.clear(); MessageTruncated = false; MessageRead = false; MessageReply = false; MessageSaved = false; MessageSavedDeleted = false; Priority = NormalPriority; Sensitivity = NormalSensitivity; Unknowns.clear(); } template void DoFillHandles(typename FieldHandle::ListT &handles) { // start fresh handles.clear(); #undef CONTAINER_OBJECT_NAME #define CONTAINER_OBJECT_NAME handles #undef RECORD_CLASS_NAME #define RECORD_CLASS_NAME RecordT FHP(RecType, _("Record Type Code")); FHP(RecordId, _("Unique Record ID")); FHD(From, _("From"), MBFC_FROM, true); FHD(To, _("To"), MBFC_TO, true); FHD(Cc, _("CC"), MBFC_CC, true); FHD(Bcc, _("BCC"), MBFC_BCC, true); FHD(Sender, _("Sender"), MBFC_SENDER, true); FHD(ReplyTo, _("Reply To"), MBFC_REPLY_TO, true); FHD(Subject, _("Subject"), MBFC_SUBJECT, true); FHD(Body, _("Body"), MBFC_BODY, true); FHD(Attachment, _("Attachment"), MBFC_ATTACHMENT, false); FHD(MessageRecordId, _("Message Record ID"), MBFC_RECORDID, false); FHP(MessageReplyTo, _("Message Reply To")); FHP(MessageDateSent, _("Date Sent")); FHP(MessageDateReceived, _("Date Received")); FHP(MessageTruncated, _("Truncated")); FHP(MessageRead, _("Read")); FHP(MessageReply, _("Reply")); FHP(MessageSaved, _("Saved")); FHP(MessageSavedDeleted, _("Saved Deleted")); FHET(pt, PriorityType, Priority, _("Priority")); FHE_CONST(pt, LowPriority, _("Low")); FHE_CONST(pt, NormalPriority, _("Normal")); FHE_CONST(pt, HighPriority, _("High")); FHE_CONST(pt, UnknownPriority, _("Unknown")); FHET(st, SensitivityType, Sensitivity, _("Sensitivity")); FHE_CONST(st, NormalSensitivity, _("Normal")); FHE_CONST(st, Personal, _("Personal")); FHE_CONST(st, Private, _("Private")); FHE_CONST(st, Confidential, _("Confidential")); FHE_CONST(st, UnknownSensitivity, _("Unknown")); FHP(Unknowns, _("Unknown Fields")); } std::string MessageBase::GetDescription() const { // FIXME - ponder a better description... return Subject; } std::string MessageBase::SimpleFromAddress() const { if( From.size() ) { // remove all spaces from the email std::string ret; for( size_t i = 0; i < From[0].Email.size(); i++ ) if( From[0].Email[i] != ' ' ) ret += From[0].Email[i]; return ret; } else { return _("unknown"); } } // dump message in mbox format void MessageBase::Dump(std::ostream &os) const { ios_format_state state(os); static const char *Importance[] = { "Low", "Normal", "High", "Unknown Priority" }; static const char *SensitivityString[] = { "Normal", "Personal", "Private", "Confidential", "Unknown Sensivity" }; os << "From " << SimpleFromAddress() << " " << MessageDateReceived << "\n"; /* FIXME // savedmessage prints like this: os << "From " << SimpleFromAddress() << " " << ctime( &MessageDateSent ); // pinmessage prints like this: os << "From " << SimpleFromAddress() << " " << ctime( &MessageDateSent ); */ os << "X-Record-ID: (" << setw(8) << std::hex << MessageRecordId << ")\n"; if( MessageReplyTo ) os << "X-rim-org-msg-ref-id: " << std::dec << MessageReplyTo << "\n"; if( MessageSaved ) os << "X-Message-Status: Saved\n"; else if( MessageRead ) os << "Message Status: Opened\n"; if( Priority != NormalPriority ) os << "Importance: " << Importance[Priority] << "\n"; if( Sensitivity != NormalSensitivity ) os << "Sensitivity: " << SensitivityString[Sensitivity] << "\n"; os << "Date: " << MessageDateSent << "\n"; if( From.size() ) os << "From: " << From[0] << "\n"; if( To.size() ) os << "To: " << To << "\n"; if( Cc.size() ) os << "Cc: " << Cc << "\n"; if( Bcc.size() ) os << "Bcc: " << Bcc << "\n"; if( Sender.size() ) os << "Sender: " << Sender << "\n"; if( ReplyTo.size()) os << "Reply To: " << ReplyTo << "\n"; if( Subject.size() ) os << "Subject: " << Subject << "\n"; os << "\n"; os << Cr2LfWrapper(Body); os << "\n"; if( Attachment.size() ) os << "Attachments: " << Data(Attachment.data(), Attachment.size()) << "\n"; os << Unknowns; os << "\n\n"; } bool MessageBase::operator<(const MessageBase &other) const { // just in case either of these are set to '0', use the // one with the max value... this uses the latest date, which // is likely the most accurate time_t date = std::max(MessageDateSent.Time, MessageDateReceived.Time); time_t odate = std::max(other.MessageDateSent.Time, other.MessageDateReceived.Time); if( date != odate ) return date < odate; return Subject < other.Subject; } } // namespace Barry ////////////////////////////////////////////////////////////////////////////// // Generic Field Handle support #include "r_message.h" #include "r_pin_message.h" #include "r_saved_message.h" namespace Barry { ////////////////////////////////////////////////////////////////////////////// // Message class - statics const FieldHandle::ListT& Message::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; DoFillHandles(fhv); return fhv; } ////////////////////////////////////////////////////////////////////////////// // PINMessage class - statics const FieldHandle::ListT& PINMessage::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; DoFillHandles(fhv); return fhv; } ////////////////////////////////////////////////////////////////////////////// // SavedMessage class - statics const FieldHandle::ListT& SavedMessage::GetFieldHandles() { static FieldHandle::ListT fhv; if( fhv.size() ) return fhv; DoFillHandles(fhv); return fhv; } } // namespace Barry barry-0.18.5/bash/0000755001161500056700000000000012242254476013171 5ustar cdfreycdfreybarry-0.18.5/bash/btool0000755001161500056700000000141212242254476014234 0ustar cdfreycdfrey# -*- mode: shell-script; sh-basic-offset: 8; indent-tabs-mode: t -*- # ex: ts=8 sw=8 noet filetype=sh # # btool(1) completion by Ryan Li have btool && _btool() { local cur prev COMPREPLY=() cur=`_get_cword` if [[ COMP_CWORD -eq 1 || "$cur" == -* ]]; then COMPREPLY=( $( compgen -W '-B -N -a -c -C -d -e -h -i -l -L -m -M -n -p -P -s -S -t -T -v -X -z -Z' -- "$cur" ) ) else prev=${COMP_WORDS[COMP_CWORD-1]} case "$prev" in -f) _filedir return 0 ;; -i) COMPREPLY=( $( compgen -W \ '$( iconv --list | sed -e "s@//@@;" )' -- "$cur" ) ) return 0 ;; -p) COMPREPLY=( $( compgen -W \ '$( bidentify | sed -e "s/,.*$//" )' \ -- "$cur" ) ) return 0 ;; *) ;; esac fi } && complete -F _btool btool barry-0.18.5/bash/bjavaloader0000755001161500056700000000252112242254476015371 0ustar cdfreycdfrey# -*- mode: shell-script; sh-basic-offset: 8; indent-tabs-mode: t -*- # ex: ts=8 sw=8 noet filetype=sh # # bjavaloader(1) completion by Ryan Li have bjavaloader && _bjavaloader() { local cur prev local cmd declare -i cmd COMREPLY=() cur=`_get_cword` prev=${COMP_WORDS[COMP_CWORD-1]} cmd=0 for (( i = 0; i < COMP_CWORD; ++i )); do case ${COMP_WORDS[$i]} in @(dir|deviceinfo|load|wipe|save|erase| \ eventlog|cleareventlog|logstacktraces|screenshot|settime)) cmd=1 ;; esac done if [[ "$cur" == -* ]]; then if [[ $cmd -eq 0 ]]; then COMPREPLY=( $( compgen -W '-h -p -P -v' -- "$cur" ) ) else case "$prev" in dir) COMPREPLY=( $( compgen -W '-s' -- "$cur" ) ) return 0 ;; wipe) COMPREPLY=( $( compgen -W '-a -i' -- "$cur" ) ) return 0 ;; erase) COMPREPLY=( $( compgen -W '-f' -- "$cur" ) ) return 0 ;; *) ;; esac fi elif [[ $cmd -eq 0 ]]; then COMPREPLY=( $( compgen -W 'dir deviceinfo \ load wipe save erase eventlog cleareventlog \ logstacktraces screenshot settime' -- "$cur" ) ) fi case "$prev" in -p) COMPREPLY=( $( compgen -W \ '$( bidentify 2>&- | sed -e "s/,.*$//" )' \ -- "$cur" ) ) return 0 ;; load) _filedir cod return 0 ;; screenshot) _filedir bmp return 0 ;; *) ;; esac } && complete -F _bjavaloader bjavaloader barry-0.18.5/bash/README0000644001161500056700000000064212242254476014053 0ustar cdfreycdfreyBarry bash autocompletion ======================== The scripts in this directory are programmable completion functions for barry utils used in bash. To use them, simply copy the files in this directory except this README file to: /etc/bash_completion.d/ And to load manually, run the following command: $ . /etc/bash_completion Programmable completion is for bash 3+ but is backwards compatiable with bash 2.05b. barry-0.18.5/configure.ac0000644001161500056700000003757512242254476014563 0ustar cdfreycdfrey# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) AC_INIT([barry], [0.18.5], [barry-devel@lists.sourceforge.net]) #AM_CONFIG_HEADER(config.h) AC_CONFIG_SRCDIR([src/barry.h]) AC_CONFIG_HEADERS([config.h:config.h.in]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([dist-bzip2]) AC_USE_SYSTEM_EXTENSIONS AM_GNU_GETTEXT([external]) # this is the version of gettext, not barry AM_GNU_GETTEXT_VERSION([0.18.1]) # # Barry Version Numbers # BARRY_LOGICAL=0 BARRY_MAJOR=18 BARRY_MINOR=5 AC_DEFINE_UNQUOTED([BARRY_LOGICAL], [$BARRY_LOGICAL], [Logical version number]) AC_DEFINE_UNQUOTED([BARRY_MAJOR], [$BARRY_MAJOR], [Major library version number]) AC_DEFINE_UNQUOTED([BARRY_MINOR], [$BARRY_MINOR], [Minor library version number]) AC_DEFINE_UNQUOTED([BARRY_VER_STRING], ["${BARRY_LOGICAL}.${BARRY_MAJOR}.${BARRY_MINOR}"], [Full Barry version in string form]) AC_SUBST([BARRY_LOGICAL]) AC_SUBST([BARRY_MAJOR]) AC_SUBST([BARRY_MINOR]) # # Checks for programs. # AC_PROG_CC AC_PROG_CXX AC_PROG_MAKE_SET AC_PROG_LIBTOOL AX_C_CHECK_FLAG([-fvisibility=hidden], [], [], [HAVE_C_GCCVISIBILITY=1], [HAVE_C_GCCVISIBILITY=0]) AX_CXX_CHECK_FLAG([-fvisibility=hidden], [], [], [HAVE_CXX_GCCVISIBILITY=1], [HAVE_CXX_GCCVISIBILITY=0]) AM_CONDITIONAL([WITH_GCCVISIBILITY], [test "$HAVE_C_GCCVISIBILITY" = "1" -a "$HAVE_CXX_GCCVISIBILITY" = "1"]) AC_LANG([C++]) # # Checks for libraries. # # libtar and libz don't have pkg-config files on many systems. # libz we can assume, but libtar we need to test for AC_ARG_WITH(libtar, [ --with-libtar= root path of libtar install], [LIBTAR_CFLAGS="-I$with_libtar/include" LIBTAR_LIBS="-L$with_libtar/lib -ltar"], [echo "Guessing libtar location... may not compile..."; LIBTAR_CFLAGS="" LIBTAR_LIBS="-ltar"]) AC_SUBST(LIBTAR_CFLAGS) AC_SUBST(LIBTAR_LIBS) AC_CHECK_LIB([tar], [tar_open], [LIBTAR_FOUND=1 AC_MSG_NOTICE([Found libtar, enabling libbarrybackup]) ], [LIBTAR_FOUND=0 AC_MSG_NOTICE([Libtar NOT found, disabling libbarrybackup])], [$LIBTAR_CFLAGS $LIBTAR_LIBS]) AC_ARG_WITH(libz, [ --with-zlib= root path of zlib install], [LIBZ_CFLAGS="-I$with_libtar/include" LIBZ_LIBS="-L$with_libtar/lib -ltar"], [echo "Guessing zlib location... may not compile..."; LIBZ_CFLAGS="" LIBZ_LIBS="-lz"]) AC_SUBST(LIBZ_CFLAGS) AC_SUBST(LIBZ_LIBS) AM_CONDITIONAL([WITH_BACKUP], [test "$LIBTAR_FOUND" = "1"]) # Always use Barry sockets and low level USB access, rather than # attempting to use third party socket APIs. # # Currently compiling without this flag won't work, but # it exists to allow areas of code which are only needed # when using Barry sockets to be easily marked # # The idea is that this is always set on Linux, but could be # disabled when building on Windows to allow a different # socket API to be used. AC_DEFINE([USE_BARRY_SOCKETS], [], [Define to use the low-level socket and USB code built into Barry.]) USE_BARRY_SOCKETS=1 AC_SUBST([USE_BARRY_SOCKETS]) AM_CONDITIONAL([USE_BARRY_SOCKETS], [test "$USE_BARRY_SOCKETS" = "1"]) # Work out which USB library to use. # Ultimately this is all to set a few variables: # USB_LIBRARY_CFLAGS - Compiler flags for chosen USB library # USB_LIBRARY_LIBS - Linker flags for chosen USB library # And one of the following defines: # USE_LIBUSB_0_1 # USE_LIBUSB_1_0 # Check what USB libraries are available PKG_CHECK_MODULES([LIBUSB_0_1], [libusb], [HAVE_LIBUSB_0_1=1], [HAVE_LIBUSB_0_1=0]) PKG_CHECK_MODULES([LIBUSB_1_0], [libusb-1.0], [HAVE_LIBUSB_1_0=1], [HAVE_LIBUSB_1_0=0]) # Process any user provided 'with' arguments AC_ARG_WITH(libusb, AS_HELP_STRING([--with-libusb@<:@=@:>@], [use libusb 0.1 as the USB library, optionally providing the root path of libusb 0.1 installation]), [ case x"$with_libusb" in xyes) USE_LIBUSB_0_1=1 ;; xno) USE_LIBUSB_0_1=0 ;; x*) LIBUSB_0_1_CFLAGS="-I$with_libusb/include" LIBUSB_0_1_LIBS="-L$with_libusb/lib -lusb" USE_LIBUSB_0_1=1 ;; esac ], []) AC_ARG_WITH(libusb1_0, AS_HELP_STRING([--with-libusb1_0@<:@=@:>@], [use libusb 1.0 as the USB library, optionally providing the root path of libusb 1.0 installation]), [ case x"$with_libusb1_0" in xyes) USE_LIBUSB_1_0=1 ;; xno) USE_LIBUSB_1_0=0 ;; x*) LIBUSB_1_0_CFLAGS="-I$with_libusb1_0/include/libusb-1.0" LIBUSB_1_0_LIBS="-L$with_libusb1_0/lib -lusb-1.0" USE_LIBUSB_1_0=1 ;; esac ], []) # Work out which USB library should be used. # Count how many libraries have been chosen USB_CHOSEN_COUNT=0 if test x"$USE_LIBUSB_1_0" == x1 ; then USB_CHOSEN_COUNT=$(($USB_CHOSEN_COUNT + 1)) fi if test x"$USE_LIBUSB_0_1" == x1 ; then USB_CHOSEN_COUNT=$(($USB_CHOSEN_COUNT + 1)) fi case $USB_CHOSEN_COUNT in 0) # User didn't ask for a specific library, so pick one if test -n "${LIBUSB_1_0_CFLAGS+x}" -a -n "${LIBUSB_1_0_LIBS+x}" -a x"$USE_LIBUSB_1_0" != x0 ; then USE_LIBUSB_1_0=1 elif test -n "${LIBUSB_0_1_CFLAGS+x}" -a -n "${LIBUSB_0_1_LIBS+x}" -a x"$USE_LIBUSB_0_1" != x0 ; then USE_LIBUSB_0_1=1 fi ;; 1) # User explicitly asked for a library, the code below will pick this. ;; *) AC_MSG_ERROR([Multiple USB libraries specified, please only specify one --with- option to the configure script.]) ;; esac AC_MSG_CHECKING([for which USB library to use]) if test x"$USE_LIBUSB_1_0" = x1 ; then # User explicitly asked for libusb 1.0 USB_LIBRARY_CFLAGS="$LIBUSB_1_0_CFLAGS" USB_LIBRARY_LIBS="$LIBUSB_1_0_LIBS" USE_LIBUSB_1_0=1 AC_SUBST([USE_LIBUSB_1_0]) AC_DEFINE([USE_LIBUSB_1_0], [], [Define if libusb 1.0 interface should be used]) AC_MSG_RESULT([libusb-1.0]) elif test x"$USE_LIBUSB_0_1" = x1 ; then # User explicitly asked for libusb 0.1 USB_LIBRARY_CFLAGS="$LIBUSB_0_1_CFLAGS" USB_LIBRARY_LIBS="$LIBUSB_0_1_LIBS" USE_LIBUSB_0_1=1 AC_SUBST([USE_LIBUSB_0_1]) AC_DEFINE([USE_LIBUSB_0_1], [], [Define if libusb 0.1 interface should be used]) AC_MSG_RESULT([libusb-0.1]) else AC_MSG_RESULT([unknown]) AC_MSG_WARN("ERROR: No USB library found automatically... build may fail if you don't specify --with-libusb or --with-libusb-1.0") fi AC_SUBST([USB_LIBRARY_CFLAGS]) AC_SUBST([USB_LIBRARY_LIBS]) AM_CONDITIONAL([USE_LIBUSB_0_1], [test "$USE_LIBUSB_0_1" = "1"]) AM_CONDITIONAL([USE_LIBUSB_1_0], [test "$USE_LIBUSB_1_0" = "1"]) # # Allow user to disable libbarrysync, since it depends on glib-2.0 which # may not be possible to cross-compile. # AC_ARG_ENABLE([sync], AC_HELP_STRING([--disable-sync], [disable Barry sync library]), [ if test x"$enableval" = "xno" ; then SYNC_ENABLED=no else SYNC_ENABLED=yes fi ], [SYNC_ENABLED=yes]) # # Boost library configuration # # Ok, the requirements: # # - let the user enable/disable Boost support from configure # - default to disabled # - if enabled, and not available, error # # - let user specify include path, and lib path, separately, # since some Boost installations have an additional boost-1.34.1 # style directory in them # - default to using no path overrides, assuming everything # that is needed is in default distro locations # # - let user specify the name of the serialization library, since # the name of the library can change whether you're building # from source or not # - default to searching for boost_serialization or # boost_serialization-mt, and error if not found # # Therefore: # # --enable-boost Handles enable/disable # --with-boost-include=path Override the include path # --with-boost-lib=path Override the lib path # --with-boost-serialization=name Override the name of serialization # library to link with # AC_ARG_ENABLE([boost], AC_HELP_STRING([--enable-boost], [enable Boost support]), [ if test x"$enableval" = "xno" ; then BOOST_ENABLED=no else BOOST_ENABLED=yes fi ], [BOOST_ENABLED=no]) AC_ARG_WITH([boost-include], AC_HELP_STRING(--with-boost-include=path, [path to Boost include directory in order to make include valid (defaults to system paths)]), BOOST_INC_PATH="-I$withval", BOOST_INC_PATH="" ) AC_ARG_WITH([boost-lib], AC_HELP_STRING(--with-boost-lib=path, [path to Boost library directory (defaults to system paths)]), BOOST_LIB_PATH="-L$withval", BOOST_LIB_PATH="" ) AC_ARG_WITH(boost-serialization, AC_HELP_STRING(--with-boost-serialization=name, [name of serialization library to use with compiler's -l option (defaults to boost_serialization or boost_serialization-mt.)]), boost_serialization_name=$withval, boost_serialization_name="boost_serialization") AC_MSG_NOTICE([using BOOST library... $BOOST_ENABLED]) if test x"$BOOST_INC_PATH$BOOST_LIB_PATH" != x ; then AC_MSG_NOTICE([BOOST include options: $BOOST_INC_PATH]) AC_MSG_NOTICE([BOOST library options: $BOOST_LIB_PATH]) fi if test x"$BOOST_ENABLED" = "xyes" ; then # Only $BOOST_LIB_PATH is given for this check, since no # headers are included in the autoconf main() test snippet. AC_CHECK_LIB($boost_serialization_name, main, [BOOST_LDADD="-l$boost_serialization_name"], [ AC_CHECK_LIB(boost_serialization-mt, main, [BOOST_LDADD="-lboost_serialization-mt"], [AC_MSG_ERROR(boost_serialization not found)], [$BOOST_LIB_PATH] ) ], [$BOOST_LIB_PATH]) if test x"$BOOST_LDADD" != x ; then AC_MSG_NOTICE([BOOST library name: $BOOST_LDADD]) else AC_MSG_ERROR([boost_serialization library not found]) fi fi AC_SUBST(BOOST_LIB_PATH) AC_SUBST(BOOST_INC_PATH) AC_SUBST(BOOST_LDADD) AM_CONDITIONAL([WITH_BOOST], [test "$BOOST_ENABLED" = "yes"]) #PKG_CHECK_MODULES([OPENSSL], [openssl]) PKG_CHECK_MODULES([FUSE], [fuse >= 2.5], [FUSE_FOUND=1], [echo "FUSE library not found, skipping fuse module."; FUSE_FOUND=0] ) PKG_CHECK_MODULES([SDL], [sdl >= 1.2], [SDL_FOUND=1], [echo "SDL library not found, skipping bwatch tool."; SDL_FOUND=0] ) PKG_CHECK_MODULES([GLIB2], [glib-2.0], [GLIB2_FOUND=1], [echo "GLIB 2.0 not found, skipping sync library."; GLIB2_FOUND=0] ) pkgconfigdir=${libdir}/pkgconfig AC_SUBST(pkgconfigdir) AC_SUBST(LIBUSB_CFLAGS) AC_SUBST(LIBUSB_LIBS) AM_CONDITIONAL([WITH_FUSE], [test "$FUSE_FOUND" = "1"]) AM_CONDITIONAL([WITH_SDL], [test "$SDL_FOUND" = "1"]) AM_CONDITIONAL([WITH_SYNC], [test "$GLIB2_FOUND" = "1" -a "$SYNC_ENABLED" = "yes"]) # Do not define the success case here, since we rely on -lpthread to be # automatically added to LIBS (the default macro behaviour) AC_CHECK_LIB([pthread], [pthread_create], [], [NEED_PTHREAD_CHECK2=1]) if test "$NEED_PTHREAD_CHECK2" = "1"; then # See if pthreads is part of the core library or user provided # LDFLAGS anyway... this is needed for systems like QNX AC_MSG_CHECKING([for pthread_create in standard linker options]) AC_CHECK_FUNC([pthread_create], [ AC_MSG_RESULT([ok]) ], [ AC_MSG_ERROR([failed]) ]) fi AC_CHECK_FUNC([getpwuid], [AC_DEFINE([HAVE_GETPWUID], [], [Defined if getpwuid is available])], []) NETWORK_LIBRARY_LIBS= AC_CHECK_FUNC([bind], [], [ AC_CHECK_LIB([socket], [bind], [ NETWORK_LIBRARY_LIBS="-lsocket" ] , [ echo "**************************************************" echo "WARNING: No networking library found, build errors" echo " will probably occur. " echo "**************************************************" ]) ]) AC_SUBST([NETWORK_LIBRARY_LIBS]) AC_ARG_WITH(zlib, AC_HELP_STRING(--with-zlib, [force usage of zlib, and halt if not available]), force_zlib=$withval, force_zlib=no ) AC_CHECK_LIB([z], [crc32], [ AC_DEFINE([HAVE_ZLIB], [1], [Use crc32 when generating packed .cod files]) AC_ARG_VAR([ZLIB_LIBS], [Linker options for zlib]) ZLIB_LIBS="-lz" ], [ echo "*****************************************************************" echo "WARNING: zlib not found... packed .cod files will fail crc checks" echo "*****************************************************************" AC_ARG_VAR([ZLIB_LIBS], [Linker options for zlib]) ZLIB_LIBS="" if test "x$force_zlib" != xno ; then AC_MSG_FAILURE([--with-zlib specified, but zlib not found]) fi ] ) PKG_CHECK_MODULES([LIBXMLXX], [libxml++-2.6], [LIBXMLXX_FOUND=1], [ echo "*****************************************************************" echo "WARNING: libxml++ not found... ALX parser not included" echo "*****************************************************************" LIBXMLXX_FOUND=0 ] ) AM_CONDITIONAL([WITH_ALX], [test "$LIBXMLXX_FOUND" = "1"]) AM_ICONV # # Checks for header files. # AC_HEADER_DIRENT AC_HEADER_STDC AC_CHECK_HEADERS([assert.h stdint.h time.h]) # # Checks for typedefs, structures, and compiler characteristics. # #AC_TYPE_SIZE_T AC_HEADER_TIME AC_STRUCT_TM # # Checks for library functions. # # checks that are buggy and need a C compiler only AC_LANG([C]) # AC_FUNC_STRNLEN changes linker options for us, and depends on a src/strnlen.c HAVE_WORKING_STRNLEN=0 AC_FUNC_STRNLEN if test "$ac_cv_func_strnlen_working" = "yes" ; then # If cross compiling for anything other than AIX then AC_FUNC_STRNLEN # will end up saying it's working. Before we trust it, check if the # function exists at all: AC_CHECK_FUNC([strnlen], [HAVE_WORKING_STRNLEN=1], [ HAVE_WORKING_STRNLEN=0 # Need to also add strnlen to AC_LIBOBJ as the # AC_FUNC_STRNLEN macro won't have done that as it # has guessed at everything being ok. AC_LIBOBJ([strnlen]) ]) fi if test "$ac_cv_func_strnlen_working" = "no" ; then HAVE_WORKING_STRNLEN=0 fi AC_DEFINE_UNQUOTED(HAVE_WORKING_STRNLEN, $HAVE_WORKING_STRNLEN, [Define to 1 if a working strnlen exists, 0 if not.]) # checks that work with C++ AC_LANG([C++]) AC_FUNC_CLOSEDIR_VOID AC_PROG_GCC_TRADITIONAL #AC_FUNC_MALLOC #AC_FUNC_MKTIME #AC_FUNC_REALLOC AC_FUNC_SELECT_ARGTYPES #AC_FUNC_STAT AC_CHECK_FUNCS([bzero gettimeofday memset select strcasecmp strchr strerror strtol strtoul]) AC_C_BIGENDIAN AC_CONFIG_FILES([Makefile po/Makefile.in src/Makefile tools/Makefile examples/Makefile man/Makefile test/Makefile libbarry-18.pc libbarrydp-18.pc libbarryjdwp-18.pc libbarrysync-18.pc libbarrybackup-18.pc libbarryalx-18.pc]) # # nested packages # AC_ARG_ENABLE([gui], [AC_HELP_STRING([--enable-gui], [build the gui])]) AC_ARG_ENABLE([opensync-plugin], [AC_HELP_STRING([--enable-opensync-plugin], [build the opensync plugin])]) AC_ARG_ENABLE([opensync-plugin-4x], [AC_HELP_STRING([--enable-opensync-plugin-4x], [build the opensync 0.4x plugin])]) AC_ARG_ENABLE([desktop], [AC_HELP_STRING([--enable-desktop], [build the desktop control panel])]) # make sure that the environment is setup before anything else if test "$enable_gui" = yes || test "$enable_opensync_plugin" = yes || test "$enable_opensync_plugin_4x" = yes || test "$enable_desktop" = yes; then export TREE_BUILD_CXXFLAGS="-I`pwd`" export TREE_BUILD_LDFLAGS="-L`pwd`/src" export PKG_CONFIG_PATH="`pwd`:$PKG_CONFIG_PATH" fi # conditionally enable the subdirectory packages if test "$enable_gui" = yes; then AC_CONFIG_SUBDIRS([gui]) fi if test "$enable_opensync_plugin" = yes; then AC_CONFIG_SUBDIRS([opensync-plugin]) fi if test "$enable_opensync_plugin_4x" = yes; then AC_CONFIG_SUBDIRS([opensync-plugin-0.4x]) fi if test "$enable_desktop" = yes; then AC_CONFIG_SUBDIRS([desktop]) fi # # Generate the scripts! # AC_OUTPUT # # Add a special hack at the end, to let the user disable RPATH if he wants. # # http://wiki.debian.org/RpathIssue # http://lists.debian.org/debian-devel/2003/debian-devel-200306/msg00569.html # http://fedoraproject.org/wiki/Packaging:Guidelines#Removing_Rpath # AC_ARG_ENABLE([rpathhack], [AC_HELP_STRING([--enable-rpathhack], [patch libtool to remove RPATH])], [ AC_MSG_RESULT([patching libtool to fix HIDEOUS BREAKAGE]) sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool ], []) barry-0.18.5/modprobe/0000755001161500056700000000000012242254476014063 5ustar cdfreycdfreybarry-0.18.5/modprobe/blacklist-berry_charge.conf0000644001161500056700000000010112242254476021324 0ustar cdfreycdfrey# conflicts with Barry's bcharge utility blacklist berry_charge barry-0.18.5/contrib/0000755001161500056700000000000012242254476013714 5ustar cdfreycdfreybarry-0.18.5/contrib/modemtest.rb0000755001161500056700000000526512242254476016255 0ustar cdfreycdfrey#!/usr/bin/env ruby # # Copyright (C) 2008, Andy Herkey # # 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 in the COPYING file at the # root directory of this project for more details. # # # # The purpose of this script is to try a large batch of known AT # commands, and report which ones work with your Blackberry # modem / provider. There will be output written to stdout # as well as a file created in /tmp/modemtest.log which holds # the raw pppob traffic log. # #Change the $PPP variable to point to where pppob is installed. $PPP="/usr/local/sbin/pppob -vP xxxxx -l /tmp/modemtest.log" class IPmodem def initialize @connecting = true @connectionHandle = IO.popen( $PPP,"w+" ) sleep 2 authAtempts = 0 timeout = 0 end def write( data ) @connectionHandle.write( data ) end def read() timeout = 0 return nil if @connectionHandle.closed? @ioBuffer = "" while input = IO.select([@connectionHandle],nil,nil,1) c = @connectionHandle.getc @ioBuffer << c if c != nil return if ! @connecting if c == nil timeout+=1 break if timeout >= 9000 else timeout = 0 end end return @ioBuffer end end # # Note: AT+CLAC should list all available commands # commands = [ "+++AT", "AT", "AT&F", "ATZ", "ATS0=0", "ATE0", "ATE0V1", "ATE0V1Q0X4", "AT+CRC=1", "AT+SPSERVICE", "AT+SPSERVICE", "AT$QCMIPP?", "AT$QCMIPP=?", "AT+CSQ", "AT+CSQ?", "AT+CSQ=?", "AT+CSS", "AT+CSS?", "AT+CSS=?", "ATI1", "ATI2", "ATI3", "AT+CAD?", "AT+CIMI", "AT+CGMI", "AT+CGMR", "AT+CGDCONT?", "AT+GMI", "AT+GMM", "AT+GMR", "AT+GSN", "AT+CBC", "AT+CBIP", "AT+CCED?", "AT+ESR", "AT+CIND=?", "AT+FCLASS=?", "AT+GCAP=?", "AT$SPMDN?", "AT$QCMIPGETP=1", "AT&V", "ATH" ] modem = IPmodem.new puts("Testing the Blackberry Modem by sending AT commands through pppob.") printf("Starting %s: %s",$PPP,modem.read()) puts("--------------------------------------------") commands.each {|c| modem.write(c+"\r") printf("Command: %s \nResult: %s",c,modem.read()) puts("--------------------------------------------") } barry-0.18.5/contrib/perlbarry/0000755001161500056700000000000012242254476015716 5ustar cdfreycdfreybarry-0.18.5/contrib/perlbarry/misc/0000755001161500056700000000000012242254476016651 5ustar cdfreycdfreybarry-0.18.5/contrib/perlbarry/misc/reipd0000755001161500056700000001650312242254476017707 0ustar cdfreycdfrey#!/usr/bin/perl # reipd version 0.1 # Copyright (C) 2008, ashley willis # # 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 in the COPYING file at the # root directory of this project for more details. # reconstructs an .ipd file to .ipd2. Argument to reipd is the # directory containing the .deipd files, or the .info file. No # argument needed if in the directory containing these files. This will # recreate the original .ipd file byte-for-byte if the data was unchanged. # Alternatively, .deipd files can be given on the command line, with output # to "new.ipd2". use Cwd; if (@ARGV) { if (($count == 1) and !($ARGV[0] =~ /\.deipd2?$/) ) { $arg = $ARGV[0]; if ($arg =~ /\.info$/) { open(DBNAMES,"$arg") || die; $basename = $arg; $basename =~ s/\.info$//; $basename =~ s/^(.*)\///g; $dir = $1; } else { $arg =~ s/\/$//; $basename = $arg; $basename =~ s/^(.*)\///g; open(DBNAMES,"$arg/$basename.info") || die; $dir = $arg; } ($dir) or $dir = "."; print STDERR "dir=\"$dir\"\n"; print STDERR "base=\"$basename\"\n"; while() { chomp $_; (/^$/) or $dbname[$i++] = $_; } } else { $dir = "."; $basename = "new"; foreach (@ARGV) { s/\.deipd2?$// || die; $dbname[$i++] = $_; } } } else { $dir = cwd(); #chomp $dir; $basename = $dir; $basename =~ s/^(.*)\///g; print STDERR "dir=\"$dir\"\n"; print STDERR "base=\"$basename\"\n"; open(DBNAMES,"$basename.info") || die "$basename.info not found!\n"; while() { chomp $_; (/^$/) or $dbname[$i++] = $_; } } $numOfDB = @dbname; $numOfDBBIN = reverse(dec2Bin($numOfDB,2)); open(OUT, ">$basename.ipd2") || die; print OUT "Inter\@ctive Pager Backup/Restore File\n" . $numOfDBBIN . ""; for ($dbnum = 0; $dbnum < @dbname; $dbnum++) { $db = $dbname[$dbnum] . ""; $nameLength = split(//,$db); print OUT dec2Bin($nameLength,2) . $db; } for ($dbnum = 0; $dbnum < @dbname; $dbnum++) { $db = $dbname[$dbnum]; open(IN, "$dir/$db.deipd") || die "$dir/$db.deipd"; @dbLine = ; close(IN); $dbName = $dbLine[0]; $dbName =~ s/"\n// or die; $dbName =~ s/^dbName = "// || die; ($dbName eq $db) || die; if ($dbLine[1] =~ /^\n/) { for ($c = 2; $c < @dbLine; $c++) { $current = $dbLine[$c]; if ($current =~ s/^dbID *= //) { chomp $current; $dbID = $current; $dbIDBIN = dec2Bin($dbID,2); $found = 1; } elsif($current =~ s/^dbRecordLength *= //) { chomp $current; $dbRecordLength = $current; $dbRecordLengthBIN = dec2Bin($dbRecordLength,4); ($VERBOSE) and print STDERR "dbRecordLength = $dbRecordLength = \"$dbRecordLengthBIN\"\n"; $found = 1; } elsif($current =~ s/^dbVersion *= //) { chomp $current; $dbVersion = $current; $dbVersionBIN = reverse(dec2Bin($dbVersion)); $found = 1; } elsif($current =~ s/^dbRecordHandler *= //) { chomp $current; $dbRecordHandler = $current; $dbRecordHandlerBIN = dec2Bin($dbRecordHandler,2); $found = 1; } elsif($current =~ s/^recordID *= //) { chomp $current; $recordID = $current; $recordIDBIN = reverse(pack("H*", $recordID)); $found = 1; } elsif($current =~ s/^field *= //) { ($fieldType, $fieldData) = split(/' -> "/, $current); $fieldType =~ s/^'// || die; if ($fieldType eq "\\n") { $fieldType = "\n"; } ### fieldData do { if ($fieldData =~ /"\n$/) { # maybe end? if ($dbLine[$c+1] =~ /^field length = \d+$/ or $dbLine[$c+1] =~ /^field = / or $c+1 >= @dbLine) { $fieldData =~ s/"\n$//; $cont = 0; # done } elsif ($dbLine[$c+1] =~ /^\n$/) { if ($dbLine[$c+2] =~ /^dbID = \d+$/ or $dbLine[$c+2] =~ /^dbRecordLength = \d+$/ or $dbLine[$c+2] =~ /^dbVersion = \d+$/) { $fieldData =~ s/"\n$//; $cont = 0; # done } elsif ($c+2 >= @dbLine) { # EOF $fieldData =~ s/"\n$//; $cont = 0; # done } else { $c++; $fieldData .= $dbLine[$c]; $cont = 1; } } else { # next line !/^field/ and !/^$/ $c++; $fieldData .= $dbLine[$c]; $cont = ($c < @dbLine) ? 1 : 0; } } else { # $fieldData does not end with /"/ # add next line and repeat $c++; $fieldData .= $dbLine[$c]; $cont = ($c < @dbLine) ? 1 : 0; } } while ($cont); ### END fieldData $fieldLength = split(//, $fieldData); $fieldLengthBIN = dec2Bin($fieldLength,2); $fieldTypeBIN = $fieldType; $fieldDataBIN = $fieldData; $field[$fieldCount++] = $fieldLengthBIN . $fieldTypeBIN . $fieldDataBIN; ($VERBOSE) and print STDERR "$fieldLength: \'$fieldTypeBIN\' \"$fieldDataBIN\"\n"; $found = 1; } elsif($current =~ /^$/) { # clear ($found) or die; $database = $dbVersionBIN . $dbRecordHandlerBIN . $recordIDBIN; foreach $item (@field) { $database .= $item; } unless ($dbRecordLength) { $dbRecordLength = split(//, $database); $dbRecordLengthBIN = dec2Bin($dbRecordLength,4); } $database = $dbIDBIN . $dbRecordLengthBIN . $database; print OUT $database; undef $dbID, $dbRecordLength, $dbRecordHandler, $recordID, $fieldType, $fieldData; undef @field; $fieldCount = 0; undef $found; } } if ($found) { $database = $dbVersionBIN . $dbRecordHandlerBIN . $recordIDBIN; foreach $item (@field) { $database .= $item; } unless ($dbRecordLength) { $dbRecordLength = split(//, $database); $dbRecordLengthBIN = dec2Bin($dbRecordLength,4); } $database = $dbIDBIN . $dbRecordLengthBIN . $database; print OUT $database; undef $dbID, $dbRecordLength, $dbRecordHandler, $recordID, $fieldType, $fieldData; undef @field; $fieldCount = 0; undef $found; } } else { # Database is empty. } } ####################### sub dec2Bin() { return pack("h*", dec2Hex(@_)); } sub dec2Hex() { my $dec = $_[0]; my $size = ($_[1] ? $_[1] : 1) * 2; my $hex = ''; my $tmp = ''; while ($dec > 0) { $tmp = $dec % 16; if ($tmp >= 10) { $tmp -= 10; $tmp =~ tr/0-5/a-f/; } $dec = int($dec / 16); $hex .= $tmp; } while (split(//,$hex) < $size) { $hex .= '0'; } return $hex; } barry-0.18.5/contrib/perlbarry/misc/backup0000755001161500056700000000352712242254476020053 0ustar cdfreycdfrey#!/usr/bin/perl # backup version 0.1 # Copyright (C) 2008, ashley willis # # 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 in the COPYING file at the # root directory of this project for more details. # backs up each DB in phone, or each DB given on command line, to file # / (in binary format). data is same as barrybackup data, but # with a 15 byte header (and not tar-gzipped). `bcharge`; # inits phone if (@ARGV) { @list = @ARGV; $arg = 1; } else { @list = `btool -t`; # gets list of databases } $i = 0; #print "@list\n"; foreach (@list) { if ($arg) { $found = 1; $db[$i] = $_; } elsif (s/ Database: 0x[\da-f][\da-f]? '//) { $found = 1; ($db[$i], $records[$i]) = split(/' \(records: /); $records[$i] =~ s/\)$//; } else { $found = 0; } if ($found) { print "### $i $db[$i] ###\n"; $hex = `btool -n -d "$db[$i]"`; #print "### CONVERTING ###\n"; convert($hex); #print "### DONE ###\n"; $i++; } } print "count=$i\n"; sub convert() { $file = $db[$i]; mkdir($file); $record = 0; @hex = split(/\n/, $_[0]); foreach (@hex) { if (s/^Raw record dump for record: //) { chomp; ($record) and close (OUT); $record++; open(OUT, ">$file/$record"); } if (/^ 0/) { s/^ 0[\da-f]{7}: //; s/ .*$//; s/ //g; $out = pack("H*", $_); print OUT $out; } } close(OUT); } barry-0.18.5/contrib/perlbarry/misc/dump-simple0000755001161500056700000000203012242254476021026 0ustar cdfreycdfrey#!/usr/bin/perl # dump-simple version 0.1 # Copyright (C) 2008, ashley willis # # 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 in the COPYING file at the # root directory of this project for more details. # backs up each DB in phone to file .dump `bcharge`; # inits phone @list = `btool -t`; # gets list of databases $i = 0; foreach (@list) { if (s/ Database: 0x[\da-f][\da-f]? //) { ($db[$i], $records[$i]) = split(/ \(records: /); $records[$i] =~ s/\)$//; print "### $i $db[$i] ###\n"; print `btool -n -d $db[$i] > $db[$i].dump`; $i++; } } print "count=$i\n"; barry-0.18.5/contrib/perlbarry/misc/split-jpeg0000755001161500056700000000467212242254476020666 0ustar cdfreycdfrey#!/usr/bin/perl # split-jpeg version 0.1 # Copyright (C) 2008, ashley willis # # 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 in the COPYING file at the # root directory of this project for more details. # takes resulting files of "./convert-dumps Content_Store" and outputs any # jpeg files into current directory, as well as header into a separate file. # the file "Content_Store" is created by # "btool -d 'Content Store' > Content_Store". $HEAD = 0; foreach $file (@ARGV) { open(IN, "$file"); $jpeg = 0; read(IN, $head, 3); if ($head =~ /^!$/) { # barrybackup data, ipd2tgz $header = $head; } else { read(IN, $header, 15); $header = $head . $header; } ($name, $remainder) = split(//, , 2); ($name =~ /\.jpg$/) or next; $remainder = "$remainder"; print "NAME=$name\n"; if ($remainder =~ //) { ($remainder, $jpeg) = split(//, $remainder, 2); $head = $header . $name . $remainder; if ($HEAD) { open(OUT, ">$file.head") or die "Cannot create header file: $file.head\n"; print OUT $head; close(OUT); } open(OUT, ">$file.jpg") or die "Cannot create jpeg file: $file.jpg\n"; print OUT "$jpeg"; } $head = $header . $name . $remainder; while () { if (!$jpeg and //) { ($remainder, $jpeg) = split(//); $head .= $remainder; if ($HEAD) { open(OUT, ">$file.head") or die "Cannot create header file: $file.head\n"; print OUT $head; close(OUT); } open(OUT, ">$file.jpg") or die "Cannot create jpeg file: $file.jpg\n"; print OUT "$jpeg"; } elsif (!$jpeg) { $head .= $_; } else { print OUT; } } close(OUT); close(IN); open(IN, "$file.jpg"); $name =~ s/^.*\///; open(OUT, ">$name") or die "Cannot create jpeg file: $name\n"; do { $count = read(IN, $jpg, 65535); # print "$name: COUNT=$count\n"; print OUT $jpg; read(IN, $head, 3); } while ($count == 65535); close(OUT); close(IN); unlink("$file.jpg"); } barry-0.18.5/contrib/perlbarry/misc/deipd0000755001161500056700000001441512242254476017671 0ustar cdfreycdfrey#!/usr/bin/perl # deipd version 0.1 # Copyright (C) 2008, ashley willis # # 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 in the COPYING file at the # root directory of this project for more details. # deconstructs an .ipd file into individual database files of # format /.deipd, with file /.info # containing a list of the databases. # NOTES: # dbID == 0 if first db in IPD, 1 if second, ... # dbRecordHandler: sequential in overall file, but sometimes skips $BINARY = 0; # must be 0 $SCREEN = 0; # optional $OPENING = 0; # optional $VERBOSE = 0; # optional $DBID = 1; # must be 1 $DBRECORDLENGTH = 1; # must be 1 $DBRECORDHANDLER = 1; # must be 1 $FIELDLENGTH = 0; # optional if ($VERBOSE) { $DBID = 1; $DBRECORDLENGTH = 1; $DBRECORDHANDLER = 1; $FIELDLENGTH = 1; } foreach $file (@ARGV) { $file =~ /\.ipd2?$/ or die; ($OPENING) and print "\nAttempting to open $file...\n"; open(IN, "$file"); $basename = $file; $basename =~ s/\.ipd2?$// or die; mkdir("$basename") or die; # overall header = 42 bytes read(IN, $header, 38); unless ($header =~ /^Inter\@ctive Pager Backup\/Restore File\n$/) { print STDERR "Not a valid IPD file: $file\n"; next; } read(IN, $ipdVersion, 1); unless ($ipdVersion =~ //) { print STDERR"Unknown IPD version: " . Bin2dec($ipdVersion) . "\n"; next; } read(IN, $numberOfDBs, 2); read(IN, $separator, 1); # == unless ($separator =~ //) { print STDERR "Unknown error 1: Invalid separator\n"; next; } $ipdVersionTXT = Bin2dec($ipdVersion); $numberOfDBsTXT = bin2dec($numberOfDBs); ($VERBOSE and $SCREEN) and print "header = \"$header\"\n"; ($VERBOSE and $SCREEN) and print "ipdVersion = \'$ipdVersionTXT\'" . ($BINARY ? "\t\"$ipdVersion\"" : "") . "\n"; ($VERBOSE and $SCREEN) and print "number of DBs = $numberOfDBsTXT" . ($BINARY ? "\t\"$numberOfDBs\"" : "") . "\n"; # get database names undef @dbnames; for ($db = 1; $db <= $numberOfDBsTXT; $db++) { read(IN, $dbNameLength, 2); $dbNameLengthTXT = Bin2dec($dbNameLength); ($VERBOSE and $SCREEN) and print "dbNameLength = $dbNameLengthTXT" . ($BINARY ? "\t\"$dbNameLength\"" : "") . "\n"; read(IN, $dbName, $dbNameLengthTXT); unless ($dbName =~ s/$//) { print STDERR "Unknown error 2: Invalid dbName end\n"; next; } ($SCREEN) and print "dbName = \"$dbName\"\n"; $dbNames[$db-1] = $dbName; if ($file =~ /2$/) { open(OUT,">$basename/$dbName.deipd2"); } else { open(OUT,">$basename/$dbName.deipd"); } print OUT "dbName = \"$dbName\"\n"; close(OUT); } open(OUT,">$basename/$basename.info"); foreach $name (@dbNames) { print OUT "$name\n"; } # parse the database entries while(read(IN, $dbID, 2)) { undef $dbIDTXT, $dbRecordLength, $dbRecordLengthTXT, $dbVersion, $dbRecordHandler, $recordID, $fieldLength, $fieldLengthTXT, $fieldType, $fieldData; ($SCREEN) and print "\n"; #read(IN, $dbID, 2) || die "out of data"; $dbIDTXT = Bin2dec(reverse($dbID)); ($SCREEN) and print "dbID = $dbIDTXT" . ($BINARY ? "\t\"$dbID\"" : "") . "\n"; read(IN, $dbRecordLength, 4); $dbRecordLengthTXT = Bin2dec($dbRecordLength); ($VERBOSE and $SCREEN) and print "dbRecordLength = $dbRecordLengthTXT" . ($BINARY ? "\t\"$dbRecordLength\"" : "") . "\n"; read(IN, $dbVersion, 1); ($SCREEN) and print "dbVersion = " . Bin2dec($dbVersion) . "\n"; read(IN, $dbRecordHandler, 2); ($SCREEN) and print "dbRecordHandler = " . Bin2dec($dbRecordHandler) . ($BINARY ? "\t\"$dbRecordHandler\"" : "") . "\n"; read(IN, $recordID, 4); ($SCREEN) and print "recordID = " . reverse(unpack ("h*", $recordID)) . ($BINARY ? "\t\"$recordID\"" : "") . "\n"; #open(OUT,">>$dbNames[$dbIDTXT].deipd"); if ($file =~ /2$/) { open(OUT,">>$basename/$dbNames[$dbIDTXT].deipd2"); } else { open(OUT,">>$basename/$dbNames[$dbIDTXT].deipd"); } print OUT "\n"; ($DBID) and print OUT "dbID = $dbIDTXT" . ($BINARY ? "\t\"$dbID\"" : "") . "\n"; ($DBRECORDLENGTH) and print OUT "dbRecordLength = $dbRecordLengthTXT" . ($BINARY ? "\t\"$dbRecordLength\"" : "") . "\n"; print OUT "dbVersion = " . Bin2dec($dbVersion) . "\n"; ($DBRECORDHANDLER) and print OUT "dbRecordHandler = " . Bin2dec($dbRecordHandler) . ($BINARY ? "\t\"$dbRecordHandler\"" : "") . "\n"; $recordIDTXT = unpack ("H*", reverse($recordID)); print OUT "recordID = " . $recordIDTXT . ($BINARY ? "\t\"$recordID\"" : "") . "\n"; $c = 7; while($c < $dbRecordLengthTXT) { read(IN, $fieldLength, 2); $fieldLengthTXT = Bin2dec($fieldLength); ($VERBOSE and $SCREEN) and print "field length = $fieldLengthTXT" . ($BINARY ? "\t\"$fieldLength\"" : "") . "\n"; read(IN, $fieldType, 1); if ($fieldType eq "\n") { $fieldType = "\\n"; } read(IN, $fieldData, $fieldLengthTXT); #unless ($fieldType =~ /M/) { # unless ($fieldData =~ s/$//) { # #die("field data error"); # } #} #print "field type = \'$fieldType\'\n"; #print "field data = \"$fieldData\"\n"; ($SCREEN) and print "field = \'$fieldType\' -> \"$fieldData\"\n"; $c += 3 + $fieldLengthTXT; ($FIELDLENGTH) and print OUT "field length = $fieldLengthTXT" . ($BINARY ? "\t\"$fieldLength\"" : "") . "\n"; #print OUT "field type = \'$fieldType\'\n"; #print OUT "field data = \"$fieldData\"\n"; print OUT "field = \'$fieldType\' -> \"$fieldData\"\n"; } # print OUT "\n"; # close(OUT); } print OUT "\n"; close(OUT); ($OPENING) and print "out of data for $file\n"; } sub bin2dec() { return hex(unpack ("H*", $_[0])); } sub Bin2dec() { return hex(unpack ("H*", reverse($_[0]))); } barry-0.18.5/contrib/perlbarry/misc/README0000644001161500056700000000264712242254476017542 0ustar cdfreycdfreydeipd: deconstructs an .ipd file into individual database files of format /.deipd, with file /.info containing a list of the databases. reipd: reconstructs an .ipd file to .ipd2. Argument to reipd is the directory containing the .deipd files, or the .info file. No argument needed if in the directory containing these files. This will recreate the original .ipd file byte-for-byte if the data was unchanged. Alternatively, .deipd files can be given on the command line, with output to "new.ipd2". backup: backs up each DB in phone, or each DB given on command line, to file / (in binary format). data is same as barrybackup data, but with a 15 byte header (and not tar-gzipped). convert-dumps: converts "btool -n -d " output, or .dump files from "dump-simple", into individual binary files. dump-simple: backs up each DB in phone to file .dump split-jpeg: takes resulting files of "convert-dumps Content_Store" and outputs any jpeg files into current directory, as well as header into a separate file. the file "Content_Store" is created by "btool -d 'Content Store' > Content_Store". barry-0.18.5/contrib/perlbarry/misc/convert-dumps0000755001161500056700000000224012242254476021403 0ustar cdfreycdfrey#!/usr/bin/perl # convert-dumps version 0.1 # Copyright (C) 2008, ashley willis # # 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 in the COPYING file at the # root directory of this project for more details. # converts "btool -n -d " output, or .dump files from "./dump-simple", # into individual binary files. # ($_ = pack "H*", "414243") foreach $file (@ARGV) { open(IN, "$file"); $record = 0; while () { if (/^Raw record dump for record: /) { ($record) and close (OUT); $record++; open(OUT, ">$file-$record"); } if (/^ 0/) { s/^ 0[\da-f]{7}: //; s/ .*\n//; s/ //g; $out = pack("H*", $_); print OUT $out; } } close(OUT); close(IN); } barry-0.18.5/contrib/perlbarry/ipd2tgz0000755001161500056700000000727712242254476017244 0ustar cdfreycdfrey#!/usr/bin/perl # ipd2tgz version 0.1 # Copyright (C) 2008, ashley willis # # 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 in the COPYING file at the # root directory of this project for more details. # converts file .ipd to .tar.gz, in the format of # barrybackup. # NOTES for yet-to-be tgz2ipd: # dbRecordLength = computed # dbVersion = second part of name # dbRecordHandler = (last dbRecordHandler) + (# of records in last db) + 1 # recordID = first part of name $BINARY = 0; # must be 0 $VERBOSE = 0; # optional $DBID = 1; # must be 1 $DBRECORDLENGTH = 1; # must be 1 $DBRECORDHANDLER = 1; # must be 1 $FIELDLENGTH = 0; # optional if ($VERBOSE) { $DBID = 1; $DBRECORDLENGTH = 1; $DBRECORDHANDLER = 1; $FIELDLENGTH = 1; } foreach $file (@ARGV) { open(IN, "$file"); $tmpdir = "$0-$$"; $tmpdir =~ s/^.*\//\/tmp\//; print "$tmpdir\n"; mkdir($tmpdir); # overall header = 42 bytes read(IN, $header, 38); unless ($header =~ /^Inter\@ctive Pager Backup\/Restore File\n$/) { print STDERR "Not a valid IPD file: $file\n"; next; } read(IN, $ipdVersion, 1); unless ($ipdVersion =~ //) { print STDERR"Unknown IPD version: " . Bin2dec($ipdVersion) . "\n"; next; } read(IN, $numberOfDBs, 2); read(IN, $separator, 1); # == unless ($separator =~ //) { print STDERR "Unknown error 1: Invalid separator\n"; next; } $numberOfDBsTXT = bin2dec($numberOfDBs); # get database names undef @dbnames; for ($db = 1; $db <= $numberOfDBsTXT; $db++) { read(IN, $dbNameLength, 2); $dbNameLengthTXT = Bin2dec($dbNameLength); read(IN, $dbName, $dbNameLengthTXT); unless ($dbName =~ s/$//) { print STDERR "Unknown error 2: Invalid dbName end\n"; next; } $dbNames[$db-1] = $dbName; } # parse the database entries while(read(IN, $dbID, 2)) { undef $dbIDTXT, $dbRecordLength, $dbRecordLengthTXT, $dbVersion, $dbRecordHandler, $recordID, $fieldLength, $fieldLengthTXT, $fieldType, $fieldData; $dbIDTXT = Bin2dec(reverse($dbID)); read(IN, $dbRecordLength, 4); $dbRecordLengthTXT = Bin2dec($dbRecordLength); read(IN, $dbVersion, 1); read(IN, $dbRecordHandler, 2); read(IN, $recordID, 4); $recordIDTXT = unpack ("H*", reverse($recordID)); $recordIDTXT =~ s/^0+//; (!$recordIDTXT) and $recordIDTXT = "0"; $dbVersionTXT = unpack ("H*", reverse($dbVersion)); $dbVersionTXT =~ s/^0+//; (!$dbVersionTXT) and $dbVersionTXT = "0"; $newfile = "$recordIDTXT $dbVersionTXT"; mkdir("$tmpdir/$dbNames[$dbIDTXT]"); ($dirs =~ /\"$dbNames[$dbIDTXT]\" /) or $dirs .= "\"$dbNames[$dbIDTXT]\" "; open(OUT,">>$tmpdir/$dbNames[$dbIDTXT]/$newfile"); $c = 7; while($c < $dbRecordLengthTXT) { read(IN, $fieldLength, 2); $fieldLengthTXT = Bin2dec($fieldLength); read(IN, $fieldType, 1); read(IN, $fieldData, $fieldLengthTXT); $c += 3 + $fieldLengthTXT; print OUT "$fieldLength$fieldType$fieldData"; } close(OUT); } $tgz = $file; $tgz =~ s/\.ipd$/\.tar.gz/; `tar zcf "$tgz" -C $tmpdir $dirs`; `rm -rf $tmpdir`; } sub bin2dec() { return hex(unpack ("H*", $_[0])); } sub Bin2dec() { return hex(unpack ("H*", reverse($_[0]))); } barry-0.18.5/contrib/perlbarry/barrybkup0000755001161500056700000000633712242254476017656 0ustar cdfreycdfrey#!/usr/bin/perl # barrybkup version 0.1 # Copyright (C) 2008, ashley willis # # 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 in the COPYING file at the # root directory of this project for more details. # backs up each DB in phone, or each DB given on command line, # to file ~/.barry/backup//--