diff options
Diffstat (limited to 'debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock')
44 files changed, 30303 insertions, 0 deletions
diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/Makefile.am b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/Makefile.am new file mode 100644 index 00000000..e5b11162 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/Makefile.am @@ -0,0 +1,91 @@ +INCLUDES = \ + -I../include \ + -I$(top_srcdir)/include + +bluetooth_FILES = \ + bluetooth.c + +serial_FILES = \ + unixserial.c +serial_SOURCE = unixserial.c + +usb_FILES = \ + usb.c \ + libusb.c \ + linuxusb.c \ + freebsdusb.c \ + darwinusb.c + +if WITH_LIBUSB +usb_SOURCE = usb.c libusb.c +endif + +if WITH_LINUXUSB +usb_SOURCE = usb.c linuxusb.c +endif + +if WITH_FREEBSDUSB +usb_SOURCE = usb.c freebsdusb.c +endif + +if WITH_DARWINUSB +usb_SOURCE = usb.c darwinusb.c +endif + +if WITH_BLUEZ +bluetooth_SOURCE = bluetooth.c +endif + +lib_LTLIBRARIES = libpisock.la + +# All new sources MUST be added here, or anything +# building against libpisock will fail! +libpisock_la_SOURCES = \ + $(bluetooth_SOURCE) \ + $(serial_SOURCE) \ + $(usb_SOURCE) \ + address.c \ + appinfo.c \ + connect.c \ + contact.c \ + cmp.c \ + datebook.c \ + debug.c \ + dlp.c \ + expense.c \ + hinote.c \ + inet.c \ + location.c \ + blob.c \ + calendar.c \ + mail.c \ + md5.c \ + memo.c \ + money.c \ + net.c \ + notepad.c \ + padp.c \ + palmpix.c \ + pi-buffer.c \ + pi-file.c \ + pi-header.c \ + serial.c \ + slp.c \ + sys.c \ + socket.c \ + syspkt.c \ + threadsafe.c \ + todo.c \ + utils.c \ + veo.c \ + versamail.c + +# Including PTHREAD_CFLAGS here is a dirty ugly kluge. It works. +libpisock_la_LIBADD = \ + @usb_libs@ @PTHREAD_LIBS@ @PTHREAD_CFLAGS@ @BLUEZ_LIBS@ + +libpisock_la_LDFLAGS = \ + -export-dynamic -version-info $(PISOCK_CURRENT):$(PISOCK_REVISION):$(PISOCK_AGE) +libpisock_la_CFLAGS = $(PIC_LIBS) @PTHREAD_CFLAGS@ @BLUEZ_CFLAGS@ + +EXTRA_DIST = $(bluetooth_FILES) $(serial_FILES) $(usb_FILES) diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/Makefile.in b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/Makefile.in new file mode 100644 index 00000000..d7a3c539 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/Makefile.in @@ -0,0 +1,1037 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in 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. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = libpisock +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/bluez.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/python.m4 \ + $(top_srcdir)/m4/socklen.m4 $(top_srcdir)/m4/tcl.m4 \ + $(top_srcdir)/m4/threads.m4 \ + $(top_srcdir)/m4/vl_lib_readline.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h \ + $(top_builddir)/include/pi-md5.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libpisock_la_DEPENDENCIES = +am__libpisock_la_SOURCES_DIST = bluetooth.c unixserial.c usb.c \ + darwinusb.c freebsdusb.c libusb.c linuxusb.c address.c \ + appinfo.c connect.c contact.c cmp.c datebook.c debug.c dlp.c \ + expense.c hinote.c inet.c location.c blob.c calendar.c mail.c \ + md5.c memo.c money.c net.c notepad.c padp.c palmpix.c \ + pi-buffer.c pi-file.c pi-header.c serial.c slp.c sys.c \ + socket.c syspkt.c threadsafe.c todo.c utils.c veo.c \ + versamail.c +@WITH_BLUEZ_TRUE@am__objects_1 = libpisock_la-bluetooth.lo +am__objects_2 = libpisock_la-unixserial.lo +@WITH_DARWINUSB_FALSE@@WITH_FREEBSDUSB_FALSE@@WITH_LIBUSB_FALSE@@WITH_LINUXUSB_TRUE@am__objects_3 = libpisock_la-usb.lo \ +@WITH_DARWINUSB_FALSE@@WITH_FREEBSDUSB_FALSE@@WITH_LIBUSB_FALSE@@WITH_LINUXUSB_TRUE@ libpisock_la-linuxusb.lo +@WITH_DARWINUSB_FALSE@@WITH_FREEBSDUSB_FALSE@@WITH_LIBUSB_TRUE@am__objects_3 = libpisock_la-usb.lo \ +@WITH_DARWINUSB_FALSE@@WITH_FREEBSDUSB_FALSE@@WITH_LIBUSB_TRUE@ libpisock_la-libusb.lo +@WITH_DARWINUSB_FALSE@@WITH_FREEBSDUSB_TRUE@am__objects_3 = libpisock_la-usb.lo \ +@WITH_DARWINUSB_FALSE@@WITH_FREEBSDUSB_TRUE@ libpisock_la-freebsdusb.lo +@WITH_DARWINUSB_TRUE@am__objects_3 = libpisock_la-usb.lo \ +@WITH_DARWINUSB_TRUE@ libpisock_la-darwinusb.lo +am_libpisock_la_OBJECTS = $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) libpisock_la-address.lo \ + libpisock_la-appinfo.lo libpisock_la-connect.lo \ + libpisock_la-contact.lo libpisock_la-cmp.lo \ + libpisock_la-datebook.lo libpisock_la-debug.lo \ + libpisock_la-dlp.lo libpisock_la-expense.lo \ + libpisock_la-hinote.lo libpisock_la-inet.lo \ + libpisock_la-location.lo libpisock_la-blob.lo \ + libpisock_la-calendar.lo libpisock_la-mail.lo \ + libpisock_la-md5.lo libpisock_la-memo.lo libpisock_la-money.lo \ + libpisock_la-net.lo libpisock_la-notepad.lo \ + libpisock_la-padp.lo libpisock_la-palmpix.lo \ + libpisock_la-pi-buffer.lo libpisock_la-pi-file.lo \ + libpisock_la-pi-header.lo libpisock_la-serial.lo \ + libpisock_la-slp.lo libpisock_la-sys.lo libpisock_la-socket.lo \ + libpisock_la-syspkt.lo libpisock_la-threadsafe.lo \ + libpisock_la-todo.lo libpisock_la-utils.lo libpisock_la-veo.lo \ + libpisock_la-versamail.lo +libpisock_la_OBJECTS = $(am_libpisock_la_OBJECTS) +libpisock_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libpisock_la_CFLAGS) \ + $(CFLAGS) $(libpisock_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libpisock_la_SOURCES) +DIST_SOURCES = $(am__libpisock_la_SOURCES_DIST) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLUEZ_CFLAGS = @BLUEZ_CFLAGS@ +BLUEZ_LIBS = @BLUEZ_LIBS@ +CAT_ENTRY_END = @CAT_ENTRY_END@ +CAT_ENTRY_START = @CAT_ENTRY_START@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DOCBOOK_ROOT = @DOCBOOK_ROOT@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +ICONV_CFLAGS = @ICONV_CFLAGS@ +ICONV_LIBS = @ICONV_LIBS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAR = @JAR@ +JAVA = @JAVA@ +JAVABASE = @JAVABASE@ +JAVAC = @JAVAC@ +JAVA_VERSION = @JAVA_VERSION@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PIC_LIBS = @PIC_LIBS@ +PILOT_LINK_MAJOR = @PILOT_LINK_MAJOR@ +PILOT_LINK_MINOR = @PILOT_LINK_MINOR@ +PILOT_LINK_PATCH = @PILOT_LINK_PATCH@ +PILOT_LINK_VERS = @PILOT_LINK_VERS@ +PISOCK_AGE = @PISOCK_AGE@ +PISOCK_CURRENT = @PISOCK_CURRENT@ +PISOCK_REVISION = @PISOCK_REVISION@ +PISYNC_AGE = @PISYNC_AGE@ +PISYNC_CURRENT = @PISYNC_CURRENT@ +PISYNC_REVISION = @PISYNC_REVISION@ +PKG_CONFIG = @PKG_CONFIG@ +PNG_CFLAGS = @PNG_CFLAGS@ +PNG_LIBS = @PNG_LIBS@ +POPT_INCLUDES = @POPT_INCLUDES@ +POPT_LIBS = @POPT_LIBS@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +PYTHON = @PYTHON@ +PYTHON_CFLAGS = @PYTHON_CFLAGS@ +PYTHON_H = @PYTHON_H@ +PYTHON_LIBS = @PYTHON_LIBS@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +RL_LIBS = @RL_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCLSH_PROG = @TCLSH_PROG@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_DEFS = @TCL_DEFS@ +TCL_EXTRA_CFLAGS = @TCL_EXTRA_CFLAGS@ +TCL_INCLUDES = @TCL_INCLUDES@ +TCL_LD_FLAGS = @TCL_LD_FLAGS@ +TCL_LIBS = @TCL_LIBS@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_SHLIB_LD_LIBS = @TCL_SHLIB_LD_LIBS@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +VERSION = @VERSION@ +WISH_PROG = @WISH_PROG@ +XML_CATALOG = @XML_CATALOG@ +XSLTPROC = @XSLTPROC@ +XSLTPROC_FLAGS = @XSLTPROC_FLAGS@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_F77 = @ac_ct_F77@ +acx_pthread_config = @acx_pthread_config@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +usb_libs = @usb_libs@ +INCLUDES = \ + -I../include \ + -I$(top_srcdir)/include + +bluetooth_FILES = \ + bluetooth.c + +serial_FILES = \ + unixserial.c + +serial_SOURCE = unixserial.c +usb_FILES = \ + usb.c \ + libusb.c \ + linuxusb.c \ + freebsdusb.c \ + darwinusb.c + +@WITH_DARWINUSB_TRUE@usb_SOURCE = usb.c darwinusb.c +@WITH_FREEBSDUSB_TRUE@usb_SOURCE = usb.c freebsdusb.c +@WITH_LIBUSB_TRUE@usb_SOURCE = usb.c libusb.c +@WITH_LINUXUSB_TRUE@usb_SOURCE = usb.c linuxusb.c +@WITH_BLUEZ_TRUE@bluetooth_SOURCE = bluetooth.c +lib_LTLIBRARIES = libpisock.la + +# All new sources MUST be added here, or anything +# building against libpisock will fail! +libpisock_la_SOURCES = \ + $(bluetooth_SOURCE) \ + $(serial_SOURCE) \ + $(usb_SOURCE) \ + address.c \ + appinfo.c \ + connect.c \ + contact.c \ + cmp.c \ + datebook.c \ + debug.c \ + dlp.c \ + expense.c \ + hinote.c \ + inet.c \ + location.c \ + blob.c \ + calendar.c \ + mail.c \ + md5.c \ + memo.c \ + money.c \ + net.c \ + notepad.c \ + padp.c \ + palmpix.c \ + pi-buffer.c \ + pi-file.c \ + pi-header.c \ + serial.c \ + slp.c \ + sys.c \ + socket.c \ + syspkt.c \ + threadsafe.c \ + todo.c \ + utils.c \ + veo.c \ + versamail.c + + +# Including PTHREAD_CFLAGS here is a dirty ugly kluge. It works. +libpisock_la_LIBADD = \ + @usb_libs@ @PTHREAD_LIBS@ @PTHREAD_CFLAGS@ @BLUEZ_LIBS@ + +libpisock_la_LDFLAGS = \ + -export-dynamic -version-info $(PISOCK_CURRENT):$(PISOCK_REVISION):$(PISOCK_AGE) + +libpisock_la_CFLAGS = $(PIC_LIBS) @PTHREAD_CFLAGS@ @BLUEZ_CFLAGS@ +EXTRA_DIST = $(bluetooth_FILES) $(serial_FILES) $(usb_FILES) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libpisock/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu libpisock/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libpisock.la: $(libpisock_la_OBJECTS) $(libpisock_la_DEPENDENCIES) + $(libpisock_la_LINK) -rpath $(libdir) $(libpisock_la_OBJECTS) $(libpisock_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-address.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-appinfo.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-blob.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-bluetooth.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-calendar.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-cmp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-connect.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-contact.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-darwinusb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-datebook.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-debug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-dlp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-expense.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-freebsdusb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-hinote.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-inet.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-libusb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-linuxusb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-location.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-mail.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-md5.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-memo.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-money.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-net.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-notepad.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-padp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-palmpix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-pi-buffer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-pi-file.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-pi-header.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-serial.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-slp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-socket.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-sys.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-syspkt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-threadsafe.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-todo.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-unixserial.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-usb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-utils.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-veo.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpisock_la-versamail.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libpisock_la-bluetooth.lo: bluetooth.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-bluetooth.lo -MD -MP -MF $(DEPDIR)/libpisock_la-bluetooth.Tpo -c -o libpisock_la-bluetooth.lo `test -f 'bluetooth.c' || echo '$(srcdir)/'`bluetooth.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-bluetooth.Tpo $(DEPDIR)/libpisock_la-bluetooth.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bluetooth.c' object='libpisock_la-bluetooth.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-bluetooth.lo `test -f 'bluetooth.c' || echo '$(srcdir)/'`bluetooth.c + +libpisock_la-unixserial.lo: unixserial.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-unixserial.lo -MD -MP -MF $(DEPDIR)/libpisock_la-unixserial.Tpo -c -o libpisock_la-unixserial.lo `test -f 'unixserial.c' || echo '$(srcdir)/'`unixserial.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-unixserial.Tpo $(DEPDIR)/libpisock_la-unixserial.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='unixserial.c' object='libpisock_la-unixserial.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-unixserial.lo `test -f 'unixserial.c' || echo '$(srcdir)/'`unixserial.c + +libpisock_la-usb.lo: usb.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-usb.lo -MD -MP -MF $(DEPDIR)/libpisock_la-usb.Tpo -c -o libpisock_la-usb.lo `test -f 'usb.c' || echo '$(srcdir)/'`usb.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-usb.Tpo $(DEPDIR)/libpisock_la-usb.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='usb.c' object='libpisock_la-usb.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-usb.lo `test -f 'usb.c' || echo '$(srcdir)/'`usb.c + +libpisock_la-darwinusb.lo: darwinusb.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-darwinusb.lo -MD -MP -MF $(DEPDIR)/libpisock_la-darwinusb.Tpo -c -o libpisock_la-darwinusb.lo `test -f 'darwinusb.c' || echo '$(srcdir)/'`darwinusb.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-darwinusb.Tpo $(DEPDIR)/libpisock_la-darwinusb.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='darwinusb.c' object='libpisock_la-darwinusb.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-darwinusb.lo `test -f 'darwinusb.c' || echo '$(srcdir)/'`darwinusb.c + +libpisock_la-freebsdusb.lo: freebsdusb.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-freebsdusb.lo -MD -MP -MF $(DEPDIR)/libpisock_la-freebsdusb.Tpo -c -o libpisock_la-freebsdusb.lo `test -f 'freebsdusb.c' || echo '$(srcdir)/'`freebsdusb.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-freebsdusb.Tpo $(DEPDIR)/libpisock_la-freebsdusb.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='freebsdusb.c' object='libpisock_la-freebsdusb.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-freebsdusb.lo `test -f 'freebsdusb.c' || echo '$(srcdir)/'`freebsdusb.c + +libpisock_la-libusb.lo: libusb.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-libusb.lo -MD -MP -MF $(DEPDIR)/libpisock_la-libusb.Tpo -c -o libpisock_la-libusb.lo `test -f 'libusb.c' || echo '$(srcdir)/'`libusb.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-libusb.Tpo $(DEPDIR)/libpisock_la-libusb.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libusb.c' object='libpisock_la-libusb.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-libusb.lo `test -f 'libusb.c' || echo '$(srcdir)/'`libusb.c + +libpisock_la-linuxusb.lo: linuxusb.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-linuxusb.lo -MD -MP -MF $(DEPDIR)/libpisock_la-linuxusb.Tpo -c -o libpisock_la-linuxusb.lo `test -f 'linuxusb.c' || echo '$(srcdir)/'`linuxusb.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-linuxusb.Tpo $(DEPDIR)/libpisock_la-linuxusb.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='linuxusb.c' object='libpisock_la-linuxusb.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-linuxusb.lo `test -f 'linuxusb.c' || echo '$(srcdir)/'`linuxusb.c + +libpisock_la-address.lo: address.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-address.lo -MD -MP -MF $(DEPDIR)/libpisock_la-address.Tpo -c -o libpisock_la-address.lo `test -f 'address.c' || echo '$(srcdir)/'`address.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-address.Tpo $(DEPDIR)/libpisock_la-address.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='address.c' object='libpisock_la-address.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-address.lo `test -f 'address.c' || echo '$(srcdir)/'`address.c + +libpisock_la-appinfo.lo: appinfo.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-appinfo.lo -MD -MP -MF $(DEPDIR)/libpisock_la-appinfo.Tpo -c -o libpisock_la-appinfo.lo `test -f 'appinfo.c' || echo '$(srcdir)/'`appinfo.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-appinfo.Tpo $(DEPDIR)/libpisock_la-appinfo.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='appinfo.c' object='libpisock_la-appinfo.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-appinfo.lo `test -f 'appinfo.c' || echo '$(srcdir)/'`appinfo.c + +libpisock_la-connect.lo: connect.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-connect.lo -MD -MP -MF $(DEPDIR)/libpisock_la-connect.Tpo -c -o libpisock_la-connect.lo `test -f 'connect.c' || echo '$(srcdir)/'`connect.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-connect.Tpo $(DEPDIR)/libpisock_la-connect.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='connect.c' object='libpisock_la-connect.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-connect.lo `test -f 'connect.c' || echo '$(srcdir)/'`connect.c + +libpisock_la-contact.lo: contact.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-contact.lo -MD -MP -MF $(DEPDIR)/libpisock_la-contact.Tpo -c -o libpisock_la-contact.lo `test -f 'contact.c' || echo '$(srcdir)/'`contact.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-contact.Tpo $(DEPDIR)/libpisock_la-contact.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='contact.c' object='libpisock_la-contact.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-contact.lo `test -f 'contact.c' || echo '$(srcdir)/'`contact.c + +libpisock_la-cmp.lo: cmp.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-cmp.lo -MD -MP -MF $(DEPDIR)/libpisock_la-cmp.Tpo -c -o libpisock_la-cmp.lo `test -f 'cmp.c' || echo '$(srcdir)/'`cmp.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-cmp.Tpo $(DEPDIR)/libpisock_la-cmp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cmp.c' object='libpisock_la-cmp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-cmp.lo `test -f 'cmp.c' || echo '$(srcdir)/'`cmp.c + +libpisock_la-datebook.lo: datebook.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-datebook.lo -MD -MP -MF $(DEPDIR)/libpisock_la-datebook.Tpo -c -o libpisock_la-datebook.lo `test -f 'datebook.c' || echo '$(srcdir)/'`datebook.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-datebook.Tpo $(DEPDIR)/libpisock_la-datebook.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='datebook.c' object='libpisock_la-datebook.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-datebook.lo `test -f 'datebook.c' || echo '$(srcdir)/'`datebook.c + +libpisock_la-debug.lo: debug.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-debug.lo -MD -MP -MF $(DEPDIR)/libpisock_la-debug.Tpo -c -o libpisock_la-debug.lo `test -f 'debug.c' || echo '$(srcdir)/'`debug.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-debug.Tpo $(DEPDIR)/libpisock_la-debug.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='debug.c' object='libpisock_la-debug.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-debug.lo `test -f 'debug.c' || echo '$(srcdir)/'`debug.c + +libpisock_la-dlp.lo: dlp.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-dlp.lo -MD -MP -MF $(DEPDIR)/libpisock_la-dlp.Tpo -c -o libpisock_la-dlp.lo `test -f 'dlp.c' || echo '$(srcdir)/'`dlp.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-dlp.Tpo $(DEPDIR)/libpisock_la-dlp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dlp.c' object='libpisock_la-dlp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-dlp.lo `test -f 'dlp.c' || echo '$(srcdir)/'`dlp.c + +libpisock_la-expense.lo: expense.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-expense.lo -MD -MP -MF $(DEPDIR)/libpisock_la-expense.Tpo -c -o libpisock_la-expense.lo `test -f 'expense.c' || echo '$(srcdir)/'`expense.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-expense.Tpo $(DEPDIR)/libpisock_la-expense.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='expense.c' object='libpisock_la-expense.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-expense.lo `test -f 'expense.c' || echo '$(srcdir)/'`expense.c + +libpisock_la-hinote.lo: hinote.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-hinote.lo -MD -MP -MF $(DEPDIR)/libpisock_la-hinote.Tpo -c -o libpisock_la-hinote.lo `test -f 'hinote.c' || echo '$(srcdir)/'`hinote.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-hinote.Tpo $(DEPDIR)/libpisock_la-hinote.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hinote.c' object='libpisock_la-hinote.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-hinote.lo `test -f 'hinote.c' || echo '$(srcdir)/'`hinote.c + +libpisock_la-inet.lo: inet.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-inet.lo -MD -MP -MF $(DEPDIR)/libpisock_la-inet.Tpo -c -o libpisock_la-inet.lo `test -f 'inet.c' || echo '$(srcdir)/'`inet.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-inet.Tpo $(DEPDIR)/libpisock_la-inet.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='inet.c' object='libpisock_la-inet.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-inet.lo `test -f 'inet.c' || echo '$(srcdir)/'`inet.c + +libpisock_la-location.lo: location.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-location.lo -MD -MP -MF $(DEPDIR)/libpisock_la-location.Tpo -c -o libpisock_la-location.lo `test -f 'location.c' || echo '$(srcdir)/'`location.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-location.Tpo $(DEPDIR)/libpisock_la-location.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='location.c' object='libpisock_la-location.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-location.lo `test -f 'location.c' || echo '$(srcdir)/'`location.c + +libpisock_la-blob.lo: blob.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-blob.lo -MD -MP -MF $(DEPDIR)/libpisock_la-blob.Tpo -c -o libpisock_la-blob.lo `test -f 'blob.c' || echo '$(srcdir)/'`blob.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-blob.Tpo $(DEPDIR)/libpisock_la-blob.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='blob.c' object='libpisock_la-blob.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-blob.lo `test -f 'blob.c' || echo '$(srcdir)/'`blob.c + +libpisock_la-calendar.lo: calendar.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-calendar.lo -MD -MP -MF $(DEPDIR)/libpisock_la-calendar.Tpo -c -o libpisock_la-calendar.lo `test -f 'calendar.c' || echo '$(srcdir)/'`calendar.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-calendar.Tpo $(DEPDIR)/libpisock_la-calendar.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='calendar.c' object='libpisock_la-calendar.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-calendar.lo `test -f 'calendar.c' || echo '$(srcdir)/'`calendar.c + +libpisock_la-mail.lo: mail.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-mail.lo -MD -MP -MF $(DEPDIR)/libpisock_la-mail.Tpo -c -o libpisock_la-mail.lo `test -f 'mail.c' || echo '$(srcdir)/'`mail.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-mail.Tpo $(DEPDIR)/libpisock_la-mail.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mail.c' object='libpisock_la-mail.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-mail.lo `test -f 'mail.c' || echo '$(srcdir)/'`mail.c + +libpisock_la-md5.lo: md5.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-md5.lo -MD -MP -MF $(DEPDIR)/libpisock_la-md5.Tpo -c -o libpisock_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-md5.Tpo $(DEPDIR)/libpisock_la-md5.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='md5.c' object='libpisock_la-md5.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c + +libpisock_la-memo.lo: memo.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-memo.lo -MD -MP -MF $(DEPDIR)/libpisock_la-memo.Tpo -c -o libpisock_la-memo.lo `test -f 'memo.c' || echo '$(srcdir)/'`memo.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-memo.Tpo $(DEPDIR)/libpisock_la-memo.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='memo.c' object='libpisock_la-memo.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-memo.lo `test -f 'memo.c' || echo '$(srcdir)/'`memo.c + +libpisock_la-money.lo: money.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-money.lo -MD -MP -MF $(DEPDIR)/libpisock_la-money.Tpo -c -o libpisock_la-money.lo `test -f 'money.c' || echo '$(srcdir)/'`money.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-money.Tpo $(DEPDIR)/libpisock_la-money.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='money.c' object='libpisock_la-money.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-money.lo `test -f 'money.c' || echo '$(srcdir)/'`money.c + +libpisock_la-net.lo: net.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-net.lo -MD -MP -MF $(DEPDIR)/libpisock_la-net.Tpo -c -o libpisock_la-net.lo `test -f 'net.c' || echo '$(srcdir)/'`net.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-net.Tpo $(DEPDIR)/libpisock_la-net.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='net.c' object='libpisock_la-net.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-net.lo `test -f 'net.c' || echo '$(srcdir)/'`net.c + +libpisock_la-notepad.lo: notepad.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-notepad.lo -MD -MP -MF $(DEPDIR)/libpisock_la-notepad.Tpo -c -o libpisock_la-notepad.lo `test -f 'notepad.c' || echo '$(srcdir)/'`notepad.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-notepad.Tpo $(DEPDIR)/libpisock_la-notepad.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='notepad.c' object='libpisock_la-notepad.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-notepad.lo `test -f 'notepad.c' || echo '$(srcdir)/'`notepad.c + +libpisock_la-padp.lo: padp.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-padp.lo -MD -MP -MF $(DEPDIR)/libpisock_la-padp.Tpo -c -o libpisock_la-padp.lo `test -f 'padp.c' || echo '$(srcdir)/'`padp.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-padp.Tpo $(DEPDIR)/libpisock_la-padp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='padp.c' object='libpisock_la-padp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-padp.lo `test -f 'padp.c' || echo '$(srcdir)/'`padp.c + +libpisock_la-palmpix.lo: palmpix.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-palmpix.lo -MD -MP -MF $(DEPDIR)/libpisock_la-palmpix.Tpo -c -o libpisock_la-palmpix.lo `test -f 'palmpix.c' || echo '$(srcdir)/'`palmpix.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-palmpix.Tpo $(DEPDIR)/libpisock_la-palmpix.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='palmpix.c' object='libpisock_la-palmpix.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-palmpix.lo `test -f 'palmpix.c' || echo '$(srcdir)/'`palmpix.c + +libpisock_la-pi-buffer.lo: pi-buffer.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-pi-buffer.lo -MD -MP -MF $(DEPDIR)/libpisock_la-pi-buffer.Tpo -c -o libpisock_la-pi-buffer.lo `test -f 'pi-buffer.c' || echo '$(srcdir)/'`pi-buffer.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-pi-buffer.Tpo $(DEPDIR)/libpisock_la-pi-buffer.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pi-buffer.c' object='libpisock_la-pi-buffer.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-pi-buffer.lo `test -f 'pi-buffer.c' || echo '$(srcdir)/'`pi-buffer.c + +libpisock_la-pi-file.lo: pi-file.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-pi-file.lo -MD -MP -MF $(DEPDIR)/libpisock_la-pi-file.Tpo -c -o libpisock_la-pi-file.lo `test -f 'pi-file.c' || echo '$(srcdir)/'`pi-file.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-pi-file.Tpo $(DEPDIR)/libpisock_la-pi-file.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pi-file.c' object='libpisock_la-pi-file.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-pi-file.lo `test -f 'pi-file.c' || echo '$(srcdir)/'`pi-file.c + +libpisock_la-pi-header.lo: pi-header.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-pi-header.lo -MD -MP -MF $(DEPDIR)/libpisock_la-pi-header.Tpo -c -o libpisock_la-pi-header.lo `test -f 'pi-header.c' || echo '$(srcdir)/'`pi-header.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-pi-header.Tpo $(DEPDIR)/libpisock_la-pi-header.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pi-header.c' object='libpisock_la-pi-header.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-pi-header.lo `test -f 'pi-header.c' || echo '$(srcdir)/'`pi-header.c + +libpisock_la-serial.lo: serial.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-serial.lo -MD -MP -MF $(DEPDIR)/libpisock_la-serial.Tpo -c -o libpisock_la-serial.lo `test -f 'serial.c' || echo '$(srcdir)/'`serial.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-serial.Tpo $(DEPDIR)/libpisock_la-serial.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='serial.c' object='libpisock_la-serial.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-serial.lo `test -f 'serial.c' || echo '$(srcdir)/'`serial.c + +libpisock_la-slp.lo: slp.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-slp.lo -MD -MP -MF $(DEPDIR)/libpisock_la-slp.Tpo -c -o libpisock_la-slp.lo `test -f 'slp.c' || echo '$(srcdir)/'`slp.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-slp.Tpo $(DEPDIR)/libpisock_la-slp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='slp.c' object='libpisock_la-slp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-slp.lo `test -f 'slp.c' || echo '$(srcdir)/'`slp.c + +libpisock_la-sys.lo: sys.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-sys.lo -MD -MP -MF $(DEPDIR)/libpisock_la-sys.Tpo -c -o libpisock_la-sys.lo `test -f 'sys.c' || echo '$(srcdir)/'`sys.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-sys.Tpo $(DEPDIR)/libpisock_la-sys.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sys.c' object='libpisock_la-sys.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-sys.lo `test -f 'sys.c' || echo '$(srcdir)/'`sys.c + +libpisock_la-socket.lo: socket.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-socket.lo -MD -MP -MF $(DEPDIR)/libpisock_la-socket.Tpo -c -o libpisock_la-socket.lo `test -f 'socket.c' || echo '$(srcdir)/'`socket.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-socket.Tpo $(DEPDIR)/libpisock_la-socket.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='socket.c' object='libpisock_la-socket.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-socket.lo `test -f 'socket.c' || echo '$(srcdir)/'`socket.c + +libpisock_la-syspkt.lo: syspkt.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-syspkt.lo -MD -MP -MF $(DEPDIR)/libpisock_la-syspkt.Tpo -c -o libpisock_la-syspkt.lo `test -f 'syspkt.c' || echo '$(srcdir)/'`syspkt.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-syspkt.Tpo $(DEPDIR)/libpisock_la-syspkt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='syspkt.c' object='libpisock_la-syspkt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-syspkt.lo `test -f 'syspkt.c' || echo '$(srcdir)/'`syspkt.c + +libpisock_la-threadsafe.lo: threadsafe.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-threadsafe.lo -MD -MP -MF $(DEPDIR)/libpisock_la-threadsafe.Tpo -c -o libpisock_la-threadsafe.lo `test -f 'threadsafe.c' || echo '$(srcdir)/'`threadsafe.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-threadsafe.Tpo $(DEPDIR)/libpisock_la-threadsafe.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threadsafe.c' object='libpisock_la-threadsafe.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-threadsafe.lo `test -f 'threadsafe.c' || echo '$(srcdir)/'`threadsafe.c + +libpisock_la-todo.lo: todo.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-todo.lo -MD -MP -MF $(DEPDIR)/libpisock_la-todo.Tpo -c -o libpisock_la-todo.lo `test -f 'todo.c' || echo '$(srcdir)/'`todo.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-todo.Tpo $(DEPDIR)/libpisock_la-todo.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='todo.c' object='libpisock_la-todo.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-todo.lo `test -f 'todo.c' || echo '$(srcdir)/'`todo.c + +libpisock_la-utils.lo: utils.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-utils.lo -MD -MP -MF $(DEPDIR)/libpisock_la-utils.Tpo -c -o libpisock_la-utils.lo `test -f 'utils.c' || echo '$(srcdir)/'`utils.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-utils.Tpo $(DEPDIR)/libpisock_la-utils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils.c' object='libpisock_la-utils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-utils.lo `test -f 'utils.c' || echo '$(srcdir)/'`utils.c + +libpisock_la-veo.lo: veo.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-veo.lo -MD -MP -MF $(DEPDIR)/libpisock_la-veo.Tpo -c -o libpisock_la-veo.lo `test -f 'veo.c' || echo '$(srcdir)/'`veo.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-veo.Tpo $(DEPDIR)/libpisock_la-veo.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='veo.c' object='libpisock_la-veo.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-veo.lo `test -f 'veo.c' || echo '$(srcdir)/'`veo.c + +libpisock_la-versamail.lo: versamail.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -MT libpisock_la-versamail.lo -MD -MP -MF $(DEPDIR)/libpisock_la-versamail.Tpo -c -o libpisock_la-versamail.lo `test -f 'versamail.c' || echo '$(srcdir)/'`versamail.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libpisock_la-versamail.Tpo $(DEPDIR)/libpisock_la-versamail.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='versamail.c' object='libpisock_la-versamail.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpisock_la_CFLAGS) $(CFLAGS) -c -o libpisock_la-versamail.lo `test -f 'versamail.c' || echo '$(srcdir)/'`versamail.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-libLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/address.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/address.c new file mode 100644 index 00000000..46ae49a3 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/address.c @@ -0,0 +1,313 @@ +/* + * $Id: address.c,v 1.30 2006/11/22 22:52:25 adridg Exp $ + * + * address.c: Translate Pilot address book data formats + * (c) 1996, Kenneth Albanowski + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pi-macros.h" +#include "pi-address.h" + +#define hi(x) (((x) >> 4) & 0x0f) +#define lo(x) ((x) & 0x0f) +#define pair(x,y) (((x) << 4) | (y)) + +/*********************************************************************** + * + * Function: free_Address + * + * Summary: Free the members of an address structure + * + * Parameters: Address_t* + * + * Returns: void + * + ***********************************************************************/ +void +free_Address(Address_t *addr) +{ + int i; + + for (i = 0; i < 19; i++) + if (addr->entry[i]) { + free(addr->entry[i]); + addr->entry[i] = NULL; + } +} + + +/*********************************************************************** + * + * Function: unpack_Address + * + * Summary: Fill in the address structure based on the raw record + * data + * + * Parameters: Address_t*, pi_buffer_t *buf + * + * Returns: -1 on error, 0 on success + * + ***********************************************************************/ +int +unpack_Address(Address_t *addr, const pi_buffer_t *buf, addressType type) +{ + unsigned long contents, + v; + size_t ofs; + + if (type != address_v1) + /* Don't support anything else yet */ + return -1; + + if (buf == NULL || buf->data == NULL || buf->used < 9) + return -1; + + /* get_byte(buffer); gapfill */ + addr->showPhone = hi(get_byte(buf->data + 1)); + addr->phoneLabel[4] = lo(get_byte(buf->data + 1)); + addr->phoneLabel[3] = hi(get_byte(buf->data + 2)); + addr->phoneLabel[2] = lo(get_byte(buf->data + 2)); + addr->phoneLabel[1] = hi(get_byte(buf->data + 3)); + addr->phoneLabel[0] = lo(get_byte(buf->data + 3)); + + contents = get_long(buf->data + 4); + + /* get_byte(buf->data+8) offset */ + + ofs = 9; + + /* if(flag & 0x1) { + addr->lastname = strdup((buf->data + ofs); + ofs += strlen((buf->data + ofs)) + 1; + } else { + addr->lastname = 0; + } */ + + for (v = 0; v < 19; v++) { + if (contents & (1 << v)) { + if ((buf->used - ofs) < 1) + return 0; + addr->entry[v] = strdup((char *) (buf->data + ofs)); + ofs += strlen(addr->entry[v]) + 1; + } else { + addr->entry[v] = 0; + } + } + + return 0; +} + + +/*********************************************************************** + * + * Function: pack_Address + * + * Summary: Fill in the raw address record data based on the + * address structure + * + * Parameters: Address_t*, pi_buffer_t *buf of record, record type + * + * Returns: -1 on error, 0 on success. + * + ***********************************************************************/ +int +pack_Address(const Address_t *addr, pi_buffer_t *buf, addressType type) +{ + unsigned int l, + destlen = 9; + + unsigned char *buffer; + unsigned long contents, + v, + phoneflag; + + unsigned char offset; + + if (addr == NULL || buf == NULL) + return -1; + + if (type != address_v1) + /* Don't support anything else yet */ + return -1; + + for (v = 0; v < 19; v++) + if (addr->entry[v] && strlen(addr->entry[v])) + destlen += strlen(addr->entry[v]) + 1; + + pi_buffer_expect (buf, destlen); + buf->used = destlen; + + buffer = buf->data + 9; + phoneflag = 0; + contents = 0; + offset = 0; + + for (v = 0; v < 19; v++) { + if (addr->entry[v] && strlen(addr->entry[v])) { + if (v == entryCompany) + offset = + (unsigned char) (buffer - buf->data) - 8; + contents |= (1 << v); + l = strlen(addr->entry[v]) + 1; + memcpy(buffer, addr->entry[v], l); + buffer += l; + } + } + + phoneflag = ((unsigned long) addr->phoneLabel[0]) << 0; + phoneflag |= ((unsigned long) addr->phoneLabel[1]) << 4; + phoneflag |= ((unsigned long) addr->phoneLabel[2]) << 8; + phoneflag |= ((unsigned long) addr->phoneLabel[3]) << 12; + phoneflag |= ((unsigned long) addr->phoneLabel[4]) << 16; + phoneflag |= ((unsigned long) addr->showPhone) << 20; + + set_long(buf->data, phoneflag); + set_long(buf->data + 4, contents); + set_byte(buf->data + 8, offset); + + return 0; +} + + +/*********************************************************************** + * + * Function: unpack_AddressAppInfo + * + * Summary: Fill in the app info structure based on the raw app + * info data + * + * Parameters: AddressAppInfo_t*, char * to record, record length + * + * Returns: The necessary length of the buffer if record is NULL, + * or 0 on error, the length of the data used from the + * buffer otherwise + * + ***********************************************************************/ +int +unpack_AddressAppInfo(AddressAppInfo_t *ai, const unsigned char *record, size_t len) +{ + size_t i, + destlen = 4 + 16 * 22 + 2 + 2; + + unsigned char *start = record; + unsigned long r; + + ai->type = address_v1; + + i = unpack_CategoryAppInfo(&ai->category, record, len); + if (!record) + return i + destlen; + if (!i) + return i; + record += i; + len -= i; + + if (len < destlen) + return 0; + + r = get_long(record); + for (i = 0; i < 22; i++) + ai->labelRenamed[i] = !!(r & (1 << i)); + + record += 4; + memcpy(ai->labels, record, 16 * 22); + record += 16 * 22; + ai->country = get_short(record); + record += 2; + ai->sortByCompany = get_byte(record); + record += 2; + + for (i = 3; i < 8; i++) + strcpy(ai->phoneLabels[i - 3], ai->labels[i]); + for (i = 19; i < 22; i++) + strcpy(ai->phoneLabels[i - 19 + 5], ai->labels[i]); + + return (record - start); +} + +/*********************************************************************** + * + * Function: pack_AddressAppInfo + * + * Summary: Fill in the raw app info record data based on the app + * info structure + * + * Parameters: AddressAppInfo_t*, char * to record, record length + * + * Returns: The length of the buffer required if record is NULL, + * or 0 on error, the length of the data used from the + * buffer otherwise + * + ***********************************************************************/ +int +pack_AddressAppInfo(const AddressAppInfo_t *ai, unsigned char *record, size_t len) +{ + int i; + size_t destlen = 4 + 16 * 22 + 2 + 2; + unsigned char *pos = record; + unsigned long r; + + i = pack_CategoryAppInfo(&ai->category, record, len); + if (!record) + return destlen + i; + if (!i) + return i; + + pos += i; + len -= i; + + for (i = 3; i < 8; i++) + strcpy(ai->phoneLabels[i - 3], ai->labels[i]); + for (i = 19; i < 22; i++) + strcpy(ai->phoneLabels[i - 19 + 5], ai->labels[i]); + + memset(pos, 0, destlen); + + r = 0; + for (i = 0; i < 22; i++) + if (ai->labelRenamed[i]) + r |= (1 << i); + set_long(pos, r); + pos += 4; + + memcpy(pos, ai->labels, 16 * 22); + pos += 16 * 22; + set_short(pos, ai->country); + pos += 2; + set_byte(pos, ai->sortByCompany); + pos += 2; + + for (i = 3; i < 8; i++) + strcpy(ai->phoneLabels[i - 3], ai->labels[i]); + for (i = 19; i < 22; i++) + strcpy(ai->phoneLabels[i - 19 + 5], ai->labels[i]); + + return (pos - record); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/appinfo.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/appinfo.c new file mode 100644 index 00000000..b89d9604 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/appinfo.c @@ -0,0 +1,119 @@ +/* + * $Id: appinfo.c,v 1.19 2006/11/22 22:52:25 adridg Exp $ + * + * appinfo.c: Translate Pilot category info + * + * Copyright (c) 1996, 1997, Kenneth Albanowski + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pi-macros.h" +#include "pi-appinfo.h" + +/*********************************************************************** + * + * Function: unpack_CategoryAppInfo + * + * Summary: Unpack the AppInfo block from record into the structure + * + * Parameters: CategoryAppInfo_t*, char* to record, record length + * + * Returns: Nothing + * + ***********************************************************************/ +int +unpack_CategoryAppInfo(CategoryAppInfo_t *ai, const unsigned char *record, size_t len) +{ + int i, + rec; + + if (len < 2 + 16 * 16 + 16 + 4) + return 0; + rec = get_short(record); + for (i = 0; i < 16; i++) { + if (rec & (1 << i)) + ai->renamed[i] = 1; + else + ai->renamed[i] = 0; + } + record += 2; + for (i = 0; i < 16; i++) { + memcpy(ai->name[i], record, 16); + record += 16; + } + memcpy(ai->ID, record, 16); + record += 16; + ai->lastUniqueID = get_byte(record); + record += 4; + return 2 + 16 * 16 + 16 + 4; +} + +/*********************************************************************** + * + * Function: pack_CategoryAppInfo + * + * Summary: Pack the AppInfo structure + * + * Parameters: CategoryAppInfo_t*, char* to record, record length + * + * Returns: Nothing + * + ***********************************************************************/ +int +pack_CategoryAppInfo(const CategoryAppInfo_t *ai, unsigned char *record, size_t len) +{ + int i, + rec; + + unsigned char *start = record; + + if (!record) { + return 2 + 16 * 16 + 16 + 4; + } + if (len < (2 + 16 * 16 + 16 + 4)) + return 0; /* not enough room */ + rec = 0; + for (i = 0; i < 16; i++) { + if (ai->renamed[i]) + rec |= (1 << i); + } + set_short(record, rec); + record += 2; + for (i = 0; i < 16; i++) { + memcpy(record, ai->name[i], 16); + record += 16; + } + memcpy(record, ai->ID, 16); + record += 16; + set_byte(record, ai->lastUniqueID); + record++; + set_byte(record, 0); /* gapfill */ + set_short(record + 1, 0); /* gapfill */ + record += 3; + + return (record - start); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/blob.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/blob.c new file mode 100644 index 00000000..af8fc93b --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/blob.c @@ -0,0 +1,173 @@ +/* + * $Id: blob.c,v 1.1 2009/02/22 08:09:00 nicholas Exp $ + * + * pi-blob.h - Support for blobs that appear in some palm databases. + * + * (c) 2008, Jon Schewe & Judd Montgomery + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include "pi-macros.h" +#include "pi-blob.h" + +/*********************************************************************** + * + * Function: free_Blob + * + * Summary: Frees members of the blob structure + * + * Parameters: Blob_t* + * + * Returns: void + * + ***********************************************************************/ +void +free_Blob(Blob_t *blob) +{ + if(NULL != blob->data) { + free(blob->data); + blob->data = NULL; + } +} + +/*********************************************************************** + * + * Function: dup_Blob + * + * Summary: Allocate memory for a new blob that is a duplicate of this one and copy the data into it + * + * Parameters: Blob_t* + * + * Returns: Blob_t* or NULL if there isn't enough memory and errno is set to ENOMEM + * + ***********************************************************************/ +Blob_t* +dup_Blob(const Blob_t *blob) +{ + if(NULL == blob) { + return NULL; + } + + Blob_t *retval = (Blob_t*)malloc(sizeof(Blob_t)); + if(NULL == retval) { + errno = ENOMEM; + return NULL; + } + memcpy(retval->type, blob->type, 4); + retval->length = blob->length; + if(blob->length > 0) { + retval->data = (uint8_t *)malloc(blob->length); + if(NULL == retval->data) { + errno = ENOMEM; + return NULL; + } else { + memcpy(retval->data, blob->data, blob->length); + } + } else { + retval->data = NULL; + } + return retval; +} + + +/*********************************************************************** + * + * Function: unpack_Blob + * + * Summary: Unpack a blob starting at position in data + * + * Parameters: Blob_t*, unsigned char*, size_t + * + * Returns: the number of bytes read or -1 on error + * + ***********************************************************************/ +int +unpack_Blob_p(Blob_t *blob, const unsigned char *data, const size_t position) { + size_t localPosition = position; + + memcpy(blob->type, (char *)data+localPosition, 4); + localPosition += 4; + //printf("blob->type = %c %c %c %c\n", blob->type[0], blob->type[1], blob->type[2], blob->type[3]); + blob->length = get_short(data+localPosition); + localPosition += 2; + if(blob->length > 0) { + //printf("blob->length = %d\n", blob->length); + blob->data = (uint8_t *)malloc(blob->length); + if(NULL == blob->data) { + printf("Malloc failed!\n"); + return -1; + } else { + memcpy(blob->data, data+localPosition, blob->length); + } + localPosition += blob->length; + } + + return localPosition - position; +} + +/*********************************************************************** + * + * Function: pack_Blob + * + * Summary: Pack a blob into the specified buffer + * + * Parameters: Blob_t*, pi_buffer_t* + * + * Returns: 0 on success, -1 on failure + * + ***********************************************************************/ +int +pack_Blob(const Blob_t *blob, pi_buffer_t *buf) { + size_t offset; + + offset = buf->used; + pi_buffer_expect(buf, buf->used + 6 + blob->length); + buf->used = buf->used + 6 + blob->length; + + memcpy(buf->data+offset, blob->type, 4); + offset += 4; + + set_short(buf->data+offset, blob->length); + offset += 2; + + memcpy(buf->data+offset, blob->data, blob->length); + offset += blob->length; + + return 0; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/bluetooth.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/bluetooth.c new file mode 100644 index 00000000..1da4d821 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/bluetooth.c @@ -0,0 +1,830 @@ +/* + * bluetooth.c: Interface layer to bluetooth HotSync connections + * using the Bluez stack (http://www.bluez.org/) + * + * Copyright (c) 1996, 1997, D. Jeff Dionne & Kenneth Albanowski + * Copyright (c) 1999, Tilo Christ + * Copyright (c) 2005, Florent Pillet + * Copyright (c) 2004, Paul Evans <leonerd@leonerd.org.uk> + * Copyright (c) 2005, Bastien Nocera <hadess@hadess.net> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <fcntl.h> +#include <string.h> + +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> /* Needed for Redhat 6.x machines */ + +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/rfcomm.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-socket.h" +#include "pi-bluetooth.h" +#include "pi-cmp.h" +#include "pi-net.h" +#include "pi-error.h" +#include "pi-serial.h" +#include "pi-util.h" + +#ifdef OS2 +#include <sys/select.h> +#endif + +/* Declare prototypes */ +static int pi_bluetooth_open(struct pi_socket *ps, struct pi_sockaddr *addr, + int addrlen); +static int pi_bluetooth_connect(pi_socket_t *ps, struct sockaddr *addr, + size_t addrlen); +static int pi_bluetooth_bind(pi_socket_t *ps, struct sockaddr *addr, + size_t addrlen); +static int pi_bluetooth_listen(pi_socket_t *ps, int backlog); +static int pi_bluetooth_accept(pi_socket_t *ps, struct sockaddr *addr, + size_t *addrlen); +static int pi_bluetooth_getsockopt(pi_socket_t *ps, int level, + int option_name, void *option_value, + size_t *option_len); +static int pi_bluetooth_setsockopt(pi_socket_t *ps, int level, + int option_name, const void *option_value, + size_t *option_len); +static int pi_bluetooth_close(pi_socket_t *ps); +static int pi_bluetooth_flush(pi_socket_t *ps, int flags); +static ssize_t pi_bluetooth_write(struct pi_socket *ps, + const unsigned char *buf, size_t len, int flags); +static ssize_t pi_bluetooth_read(struct pi_socket *ps, + pi_buffer_t *buf, size_t len, int flags); + +extern int pi_socket_init(pi_socket_t *ps); + +/* SDP Helper functions */ +/* + * Copyright (C) 2004 Edd Dumbill <edd@usefulinc.com> + * Copyright (C) 2005 Bastien Nocera <hadess@hadess.net> + * Mostly borrowed from BlueZ + * + * Copyright (C) 2001-2002 Nokia Corporation + * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> + * Copyright (C) 2002-2005 Marcel Holtmann <marcel@holtmann.org> + * Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com> + * Copyright (C) 2002-2003 Jean Tourrilhes <jt@hpl.hp.com> + * + */ +#include <bluetooth/sdp.h> +#include <bluetooth/sdp_lib.h> + +typedef struct { + char *name; + char *provider; + char *desc; + + unsigned int class; + unsigned int profile; + unsigned int channel; +} svc_info_t; + +#define HOTSYNC_CHANNEL 22 + +static unsigned char hotsync_uuid[] = { + 0xD8, 0x0C, 0xF9, 0xEA, 0x13, 0x4C, 0x11, 0xD5, + 0x83, 0xCE, 0x00, 0x30, 0x65, 0x7C, 0x54, 0x3C +}; + +static int +add_hotsync(sdp_session_t *session, + sdp_record_t *rec, + bdaddr_t *interface, + svc_info_t *si, + uint32_t *handle, + int *channel_ret) +{ + sdp_record_t record; + sdp_list_t *root, *svclass, *proto; + uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid; + uint8_t channel = HOTSYNC_CHANNEL; + + memset(&record, 0, sizeof(record)); + record.handle = 0xffffffff; + + sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); + root = sdp_list_append(NULL, &root_uuid); + sdp_set_browse_groups(&record, root); + + sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); + proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid)); + + sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); + proto = sdp_list_append(proto, sdp_list_append( + sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel))); + + sdp_set_access_protos(&record, sdp_list_append(NULL, proto)); + + sdp_uuid128_create(&svclass_uuid, (void *) hotsync_uuid); + svclass = sdp_list_append(NULL, &svclass_uuid); + sdp_set_service_classes(&record, svclass); + + sdp_set_info_attr(&record, "PalmOS HotSync", NULL, NULL); + + if (sdp_device_record_register(session, interface, &record, 0) < 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + "bluetooth: service record registration failed\n")); + return -1; + } + + *handle = record.handle; + *channel_ret = HOTSYNC_CHANNEL; + return 0; +} + +static int +register_sdp (uint32_t *handle, int *channel, sdp_session_t **sess) +{ + svc_info_t si; + bdaddr_t interface; + + bacpy (&interface, BDADDR_ANY); + *sess = sdp_connect (&interface, BDADDR_LOCAL, 0); + + if (*sess == NULL) + return -1; + memset (&si, 0, sizeof(si)); + si.name = "HOTSYNC"; + return add_hotsync (*sess, 0, &interface, &si, handle, channel); +} + +static int +deregister_sdp(uint32_t handle, sdp_session_t *sess) +{ + uint32_t range = 0x0000ffff; + sdp_list_t *attr; + sdp_record_t *rec; + bdaddr_t interface; + + if (!sess) + return 0; + + bacpy(&interface, BDADDR_ANY); + + attr = sdp_list_append(0, &range); + rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attr); + sdp_list_free(attr, 0); + if (!rec) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + "bluetooth: service record not found\n")); + sdp_close(sess); + return -1; + } + if (sdp_record_unregister(sess, rec)) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + "bluetooth: failed to unregister service record: %s\n", + strerror(errno))); + sdp_close(sess); + return -1; + } + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, "bluetooth: service record deleted\n")); + sdp_close(sess); + return 0; +} + +/* Protocol Functions */ +/*********************************************************************** + * + * Function: pi_bluetooth_protocol_dup + * + * Summary: clones an existing pi_protocol struct + * + * Parameters: pi_protocol* + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +static pi_protocol_t* +pi_bluetooth_protocol_dup (pi_protocol_t *prot) +{ + pi_protocol_t *new_prot; + + ASSERT (prot != NULL); + + new_prot = (pi_protocol_t *) malloc(sizeof (pi_protocol_t)); + + if (new_prot != NULL) { + new_prot->level = prot->level; + new_prot->dup = prot->dup; + new_prot->free = prot->free; + new_prot->read = prot->read; + new_prot->write = prot->write; + new_prot->flush = prot->flush; + new_prot->getsockopt = prot->getsockopt; + new_prot->setsockopt = prot->setsockopt; + new_prot->data = NULL; + } + + return new_prot; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_protocol_free + * + * Summary: frees an existing pi_protocol struct + * + * Parameters: pi_protocol* + * + * Returns: void + * + ***********************************************************************/ +static void +pi_bluetooth_protocol_free (pi_protocol_t *prot) +{ + ASSERT (prot != NULL); + if (prot != NULL) + free(prot); +} + +/*********************************************************************** + * + * Function: pi_bluetooth_protocol + * + * Summary: creates and inits pi_protocol struct instance + * + * Parameters: pi_device_t* + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +static pi_protocol_t* +pi_bluetooth_protocol (pi_device_t *dev) +{ + pi_protocol_t *prot; + struct pi_bluetooth_data *data; + + ASSERT (dev != NULL); + + prot = (pi_protocol_t *) malloc(sizeof (pi_protocol_t)); + + data = (struct pi_bluetooth_data *)(dev->data); + + if (prot != NULL) { + prot->level = PI_LEVEL_DEV; + prot->dup = pi_bluetooth_protocol_dup; + prot->free = pi_bluetooth_protocol_free; + prot->read = pi_bluetooth_read; + prot->write = pi_bluetooth_write; + prot->flush = pi_bluetooth_flush; + prot->getsockopt = pi_bluetooth_getsockopt; + prot->setsockopt = pi_bluetooth_setsockopt; + prot->data = NULL; + } + + return prot; +} + +/* Device Functions */ +/*********************************************************************** + * + * Function: pi_bluetooth_register_hotsync_sdp + * + * Summary: Gets on which channel the HOTSYNC service is, and + * registers it if necessary + * + * Parameters: None + * + * Returns: Nothing + * + **********************************************************************/ +static void +pi_bluetooth_register_hotsync_sdp (struct pi_bluetooth_data *data) +{ + if (register_sdp (&data->handle, &data->channel, &data->sess) < 0) { + data->channel = -1; + data->handle = 0; + data->sess = NULL; + } +} + +/*********************************************************************** + * + * Function: pi_bluetooth_unregister_hotsync_sdp + * + * Summary: Removes the HOTSYNC service + * + * Parameters: None + * + * Returns: Nothing + * + **********************************************************************/ +static void +pi_bluetooth_unregister_hotsync_sdp (struct pi_bluetooth_data *data) +{ + if (data->handle != 0) + deregister_sdp (data->handle, data->sess); +} + +/*********************************************************************** + * + * Function: pi_bluetooth_device_free + * + * Summary: frees an existing pi_device struct + * + * Parameters: pi_device_t* + * + * Returns: void + * + ***********************************************************************/ +static void +pi_bluetooth_device_free (pi_device_t *dev) +{ + struct pi_bluetooth_data *data; + + ASSERT (dev != NULL); + + if (dev->data) { + data = dev->data; + pi_bluetooth_unregister_hotsync_sdp (data); + if (data->device) + free (data->device); + free(dev->data); + } + free(dev); +} + +/*********************************************************************** + * + * Function: pi_bluetooth_open + * + * Summary: Open a new BlueTooth RFCOMM socket + * + * Parameters: None + * + * Returns: A negative number on error, 0 otherwise + * + **********************************************************************/ +static int +pi_bluetooth_open(struct pi_socket *ps, struct pi_sockaddr *addr, int addrlen) +{ + int fd, flags; + struct pi_bluetooth_data *data = ps->device->data; + + pi_bluetooth_register_hotsync_sdp (data); + /* If we didn't manage to create an SDP record, force channel 22 and try + * again */ + if (data->channel < 0) { + fprintf (stderr, "didn't manage to get a channel\n"); + data->channel = 22; + } + + if ((fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) + return -1; + + if ((flags = fcntl(fd, F_GETFL, 0)) != -1) { + flags &= ~O_NONBLOCK; + fcntl(fd, F_SETFL, flags); + } + + if (pi_socket_setsd(ps, fd) < 0) + return -1; + return 0; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_device + * + * Summary: creates and inits pi_device struct instance + * + * Parameters: device type + * + * Returns: pi_device_t* or NULL if operation failed + * + ***********************************************************************/ +pi_device_t* +pi_bluetooth_device (int type) +{ + pi_device_t *dev; + struct pi_bluetooth_data *data; + + dev = (pi_device_t *) malloc(sizeof (pi_device_t)); + if (dev == NULL) + return NULL; + + data = (struct pi_bluetooth_data *) malloc(sizeof (struct pi_bluetooth_data)); + if (data == NULL) { + free(dev); + return NULL; + } + + dev->free = pi_bluetooth_device_free; + dev->protocol = pi_bluetooth_protocol; + dev->bind = pi_bluetooth_bind; + dev->listen = pi_bluetooth_listen; + dev->accept = pi_bluetooth_accept; + dev->connect = pi_bluetooth_connect; + dev->close = pi_bluetooth_close; + + data->timeout = 0; + dev->data = data; + + return dev; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_connect + * + * Summary: Connect socket to a given address + * + * Parameters: pi_socket*, sockaddr*, size_t + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +static int +pi_bluetooth_connect(pi_socket_t *ps, struct sockaddr *addr, + size_t addrlen) +{ + ps->raddr = malloc(addrlen); + memcpy(ps->raddr, addr, addrlen); + ps->raddrlen = addrlen; + + ps->laddr = malloc(addrlen); + memcpy(ps->laddr, addr, addrlen); + ps->laddrlen = addrlen; + + if (( ps->type == PI_SOCK_STREAM && + ps->cmd == PI_CMD_CMP) && + cmp_tx_handshake(ps) < 0) + { + pi_close(ps->sd); + return -1; + } + ps->state = PI_SOCK_CONN_INIT; + ps->command = 0; + return 0; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_bind + * + * Summary: Bind address to a local socket + * + * Parameters: pi_socket*, sockaddr*, size_t + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +static int +pi_bluetooth_bind(pi_socket_t *ps, struct sockaddr *addr, size_t addrlen) +{ + struct pi_sockaddr *pa = (struct pi_sockaddr *) addr; + struct pi_bluetooth_data *data = + (struct pi_bluetooth_data *)ps->device->data; + char *device = pa->pi_device; + struct sockaddr_rc bindaddr; + + if (pi_bluetooth_open(ps, pa, addrlen) == -1) + return -1; /* errno already set */ + + data->device = strdup (device); + + bindaddr.rc_family = AF_BLUETOOTH; + bacpy(&bindaddr.rc_bdaddr, BDADDR_ANY); + bindaddr.rc_channel = data->channel; + + if (bind(ps->sd, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) { + pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + return -1; + } + + ps->laddr = malloc(addrlen); + memcpy(ps->laddr, addr, addrlen); + ps->laddrlen = addrlen; + + return 0; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_listen + * + * Summary: Prepare for incoming connections + * + * Parameters: pi_socket*, backlog + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int pi_bluetooth_listen(pi_socket_t *ps, int backlog) +{ + // FIXME: no result is actually being taken into account + listen(ps->sd, 10); + ps->state = PI_SOCK_LISTEN; + return 0; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_accept_rfcomm + * + * Summary: Accept an incoming connection and associate it with an + * RFCOMM serial device + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +static int +pi_bluetooth_accept_rfcomm(struct pi_socket *ps, const char *device, struct sockaddr_rc *peeraddr, unsigned int *peeraddrlen) +{ + int rfcommfd; + + rfcommfd = accept(ps->sd, (struct sockaddr *)peeraddr, peeraddrlen); + if (rfcommfd < 0) { + pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + return -1; + } + + /* Check whether we need to really accept this connection */ + if (device[0] != '\0' && strcmp (device, "any") != 0) { + bdaddr_t tmp; + if (str2ba (device, &tmp) < 0) { + close (rfcommfd); + return -1; + } + if (bacmp (&tmp, &(peeraddr->rc_bdaddr)) != 0) { + close (rfcommfd); + return -1; + } + } + + return rfcommfd; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_accept + * + * Summary: Accept an incoming connection + * + * Parameters: pi_socket*, sockaddr* + * + * Returns: Nothing + * + ***********************************************************************/ +static int +pi_bluetooth_accept(pi_socket_t *ps, struct sockaddr *addr, + size_t *addrlen) +{ + struct pi_bluetooth_data *data = + (struct pi_bluetooth_data *)ps->device->data; + struct sockaddr_rc peeraddr; + unsigned int peeraddrlen = sizeof(peeraddr); + int sd; + + /* Wait for data */ + sd = pi_bluetooth_accept_rfcomm(ps, data->device, &peeraddr, &peeraddrlen); + if (sd < 0) { + pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + return -1; + } + + if (pi_socket_setsd(ps, sd) < 0) + return -1; + pi_socket_init(ps); + + if (ps->type == PI_SOCK_STREAM) { + switch (ps->cmd) { + case PI_CMD_CMP: + if (cmp_rx_handshake(ps, 0, 0) < 0) + return -1; + break; + case PI_CMD_NET: + if (net_rx_handshake(ps) < 0) + return -1; + break; + } + + ps->dlprecord = 0; + } + + data->timeout = 0; + ps->command = 0; + ps->state = PI_SOCK_CONN_ACCEPT; + + return ps->sd; +} + +static int +pi_bluetooth_flush(pi_socket_t *ps, int flags) +{ + char buf[256]; + int fl; + + if (flags & PI_FLUSH_INPUT) { + if ((fl = fcntl(ps->sd, F_GETFL, 0)) != -1) { + fcntl(ps->sd, F_SETFL, fl | O_NONBLOCK); + while (read(ps->sd, buf, sizeof(buf)) > 0) + ; + fcntl(ps->sd, F_SETFL, fl); + } + } + return 0; +} + +static ssize_t +pi_bluetooth_read(struct pi_socket *ps, pi_buffer_t *buf, size_t len, int flags) +{ + int rbuf; + struct pi_bluetooth_data *data = (struct pi_bluetooth_data *)ps->device->data; + struct timeval t; + fd_set ready; + + if (pi_buffer_expect (buf, len) == NULL) + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + + /* If timeout == 0, wait forever for packet, otherwise wait till + timeout milliseconds */ + if (data->timeout == 0) + select(ps->sd + 1, &ready, 0, 0, 0); + else { + t.tv_sec = data->timeout / 1000; + t.tv_usec = (data->timeout % 1000) * 1000; + select(ps->sd + 1, &ready, 0, 0, &t); + } + + /* If data is available in time, read it */ + if (FD_ISSET(ps->sd, &ready)) { + if (flags == PI_MSG_PEEK && len > 256) + len = 256; + rbuf = read(ps->sd, buf->data + buf->used, len); + } else { + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, "DEV RX BlueTooth timeout\n")); + pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + return -1; + } + buf->used += rbuf; + + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, "DEV RX bluetooth %d bytes\n", rbuf)); + + return rbuf; +} + +static ssize_t +pi_bluetooth_write(struct pi_socket *ps, const unsigned char *buf, size_t len, int flags) +{ + int total, + nwrote; + struct pi_bluetooth_data *data = (struct pi_bluetooth_data *)ps->device->data; + struct timeval t; + fd_set ready; + + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + + total = len; + while (total > 0) { + if (data->timeout == 0) + select(ps->sd + 1, 0, &ready, 0, 0); + else { + t.tv_sec = data->timeout / 1000; + t.tv_usec = (data->timeout % 1000) * 1000; + select(ps->sd + 1, 0, &ready, 0, &t); + } + if (!FD_ISSET(ps->sd, &ready)) { + pi_set_error(ps->sd, PI_ERR_SOCK_IO); + return -1; + } + nwrote = write(ps->sd, buf, len); + if (nwrote < 0) { + pi_set_error(ps->sd, PI_ERR_SOCK_IO); + return -1; + } + total -= nwrote; + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, "DEV TX bluetooth %d bytes\n", len)); + return len; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_getsockopt + * + * Summary: get options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +pi_bluetooth_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len) +{ + struct pi_bluetooth_data *data = + (struct pi_bluetooth_data *)ps->device->data; + + if (option_name == PI_DEV_TIMEOUT) { + if (*option_len < sizeof (data->timeout)) { + pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); + return -1; + } + memcpy (option_value, &data->timeout, sizeof (data->timeout)); + *option_len = sizeof (data->timeout); + } + + return 0; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_setsockopt + * + * Summary: set options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +pi_bluetooth_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len) +{ + struct pi_bluetooth_data *data = + (struct pi_bluetooth_data *)ps->device->data; + + if (option_name == PI_DEV_TIMEOUT) { + if (*option_len != sizeof (data->timeout)) { + pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); + return -1; + } + memcpy (&data->timeout, option_value, sizeof (data->timeout)); + } + return 0; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_close + * + * Summary: Close a connection, destroy the socket + * + * Parameters: pi_socket* + * + * Returns: always 0 for success + * + ***********************************************************************/ +static int pi_bluetooth_close(pi_socket_t *ps) +{ + if (ps->laddr) { + free(ps->laddr); + ps->laddr = NULL; + } + + if (ps->raddr) { + free(ps->raddr); + ps->raddr = NULL; + } + return 0; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/calendar.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/calendar.c new file mode 100644 index 00000000..404f1054 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/calendar.c @@ -0,0 +1,737 @@ +/* + * $Id: calendar.c,v 1.4 2010-01-17 00:38:47 judd Exp $ + * + * calendar.c - Support for PalmOne Calendar application (CalendarDB-PDat), + * this is a copy of datebook.c with the calendar fields added. + * + * (c) 2008, Jon Schewe + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include "pi-macros.h" +#include "pi-calendar.h" + +#define alarmFlag 64 +#define repeatFlag 32 +#define noteFlag 16 +#define exceptFlag 8 +#define descFlag 4 +#define locFlag 2 + +/*********************************************************************** + * + * Function: new_CalendarEvent + * + * Summary: Create empty calendar event + * + * Parameters: CalendarEvent_t* + * + * Returns: void + * + ***********************************************************************/ +void +new_CalendarEvent(CalendarEvent_t *a) +{ + int i = 0; + + a->event = 0; + a->begin.tm_hour = 0; + a->begin.tm_min = 0; + a->begin.tm_sec = 0; + a->begin.tm_year = 2000; + a->begin.tm_mon = 0; + a->begin.tm_mday = 0; + a->begin.tm_isdst = -1; + a->end.tm_hour = 0; + a->end.tm_min = 0; + a->end.tm_sec = 0; + a->end.tm_year = 2000; + a->end.tm_mon = 0; + a->end.tm_mday = 0; + a->end.tm_isdst = -1; + a->alarm = 0; + a->advance = 0; + a->advanceUnits = 0; + a->repeatType = 0; + a->repeatForever = 0; + a->repeatEnd.tm_hour = 0; + a->repeatEnd.tm_min = 0; + a->repeatEnd.tm_sec = 0; + a->repeatEnd.tm_year = 2000; + a->repeatEnd.tm_mon = 0; + a->repeatEnd.tm_mday = 0; + a->repeatEnd.tm_isdst = -1; + + a->repeatFrequency = 0; + a->repeatDay = 0; + for (i = 0; i < 7; i++) { + a->repeatDays[i] = 0; + } + a->repeatWeekstart = 0; + a->exceptions = 0; + a->exception = NULL; + a->description = NULL; + a->note = NULL; + a->location = NULL; + a->tz = NULL; + + /* initialize the blobs to NULL */ + for (i=0; i<MAX_BLOBS; i++) { + a->blob[i]=NULL; + } +} + +/*********************************************************************** + * + * Function: copy_CalendarEvent + * + * Summary: Copy the data from one calendar event to another. The destination + * calendar event must already be cleared, either by creating new or by + * calling free_CalendarEvent on it first. + * + * Parameters: CalendarEvent_t*, CalendarEvent_t* + * + * Returns: int -1 on failure (errno will be set), 0 on success + * + ***********************************************************************/ +int +copy_CalendarEvent(const CalendarEvent_t *source, CalendarEvent_t *dest) +{ + int i = 0; + + dest->event = source->event; + memcpy(&(dest->begin), &(source->begin), sizeof(struct tm)); + memcpy(&(dest->end), &(source->end), sizeof(struct tm)); + dest->alarm = source->alarm; + dest->advance = source->advance; + dest->advanceUnits = source->advanceUnits; + dest->repeatType = source->repeatType; + dest->repeatForever = source->repeatForever; + memcpy(&(dest->repeatEnd), &(source->repeatEnd), sizeof(struct tm)); + + dest->repeatFrequency = source->repeatFrequency; + dest->repeatDay = source->repeatDay; + for (i = 0; i < 7; i++) { + dest->repeatDays[i] = source->repeatDays[i]; + } + dest->repeatWeekstart = source->repeatWeekstart; + dest->exceptions = source->exceptions; + if(source->exceptions > 0) { + dest->exception = (struct tm*)malloc(source->exceptions * sizeof(struct tm)); + if(NULL == dest->exception) { + errno = ENOMEM; + return -1; + } + for(i=0; i<source->exceptions; i++) { + memcpy(&(dest->exception[i]), &(source->exception[i]), sizeof(struct tm)); + } + } + if(NULL != source->description) { + dest->description = strdup(source->description); + } else { + dest->description = NULL; + } + if(NULL != source->note) { + dest->note = strdup(source->note); + } else { + dest->note = NULL; + } + if(NULL != source->location) { + dest->location = strdup(source->location); + } else { + dest->location = NULL; + } + + /* copy the blobs */ + for (i=0; i<MAX_BLOBS; i++) { + if(source->blob[i] != NULL) { + dest->blob[i] = dup_Blob(source->blob[i]); + if(NULL == dest->blob[i]) { + return -1; + } + } else { + dest->blob[i] = NULL; + } + } + + if(source->tz != NULL) { + dest->tz = dup_Timezone(source->tz); + if(NULL == dest->tz) { + return -1; + } + } else { + dest->tz = NULL; + } + + return 0; +} + +/*********************************************************************** + * + * Function: free_CalendarEvent + * + * Summary: Frees members of the calendar event structure + * + * Parameters: CalendarEvent_t* + * + * Returns: void + * + ***********************************************************************/ +void +free_CalendarEvent(CalendarEvent_t *a) +{ + int i; + + if (a->exception != NULL) { + free(a->exception); + a->exception = NULL; + } + + if (a->description != NULL) { + free(a->description); + a->description = NULL; + } + + if (a->note != NULL) { + free(a->note); + a->note = NULL; + } + + if(a->location != NULL) { + free(a->location); + a->location = NULL; + } + + if(NULL != a->tz) { + free_Timezone(a->tz); + free(a->tz); + } + + for(i=0; i<MAX_BLOBS; ++i) { + if(NULL != a->blob[i]) { + free_Blob(a->blob[i]); + + free(a->blob[i]); + a->blob[i] = NULL; + } + } +} + +/*********************************************************************** + * + * Function: unpack_CalendarEvent + * + * Summary: Fill in the calendar event structure based on the raw + * record data + * + * Parameters: CalendarEvent_t*, pi_buffer_t * of buffer, calendarType + * + * Returns: -1 on fail, 0 on success + * + ***********************************************************************/ +int +unpack_CalendarEvent(CalendarEvent_t *a, const pi_buffer_t *buf, calendarType type) +{ + int iflags, + j, + destlen, + i, + result; + unsigned char *p2; + unsigned long d; + + destlen = 8; + + if (type != calendar_v1) + return -1; + + if (buf == NULL || buf->data == NULL || buf->used < destlen) { + return -1; + } + + a->begin.tm_hour = get_byte(buf->data); + a->begin.tm_min = get_byte(buf->data + 1); + a->begin.tm_sec = 0; + d = (unsigned short int) get_short(buf->data + 4); + a->begin.tm_year = (d >> 9) + 4; + a->begin.tm_mon = ((d >> 5) & 15) - 1; + a->begin.tm_mday = d & 31; + a->begin.tm_isdst = -1; + a->end = a->begin; + + a->end.tm_hour = get_byte(buf->data + 2); + a->end.tm_min = get_byte(buf->data + 3); + + if (get_short(buf->data) == 0xffff) { + a->event = 1; + a->begin.tm_hour = 0; + a->begin.tm_min = 0; + a->end.tm_hour = 0; + a->end.tm_min = 0; + } else { + a->event = 0; + } + + mktime(&a->begin); + mktime(&a->end); + + iflags = get_byte(buf->data + 6); + + /* buf->data+7 is gapfill */ + + p2 = (unsigned char *) buf->data + 8; + + if (iflags & alarmFlag) { + a->alarm = 1; + a->advance = get_byte(p2); + p2 += 1; + a->advanceUnits = get_byte(p2); + p2 += 1; + + } else { + a->alarm = 0; + a->advance = 0; + a->advanceUnits = 0; + } + + if (iflags & repeatFlag) { + int i, + on; + + a->repeatType = (enum calendarRepeatType) get_byte(p2); + p2 += 2; + d = (unsigned short int) get_short(p2); + p2 += 2; + if (d == 0xffff) + a->repeatForever = 1; /* repeatEnd is invalid */ + else { + a->repeatEnd.tm_year = (d >> 9) + 4; + a->repeatEnd.tm_mon = ((d >> 5) & 15) - 1; + a->repeatEnd.tm_mday = d & 31; + a->repeatEnd.tm_min = 0; + a->repeatEnd.tm_hour = 0; + a->repeatEnd.tm_sec = 0; + a->repeatEnd.tm_isdst = -1; + mktime(&a->repeatEnd); + a->repeatForever = 0; + } + a->repeatFrequency = get_byte(p2); + p2++; + on = get_byte(p2); + p2++; + a->repeatDay = (enum calendarDayOfMonthType) 0; + for (i = 0; i < 7; i++) + a->repeatDays[i] = 0; + + if (a->repeatType == calendarRepeatMonthlyByDay) + a->repeatDay = (enum calendarDayOfMonthType) on; + else if (a->repeatType == calendarRepeatWeekly) + for (i = 0; i < 7; i++) + a->repeatDays[i] = !!(on & (1 << i)); + a->repeatWeekstart = get_byte(p2); + p2++; + p2++; + } else { + int i; + + a->repeatType = (enum calendarRepeatType) 0; + a->repeatForever = 1; /* repeatEnd is invalid */ + a->repeatFrequency = 0; + a->repeatDay = (enum calendarDayOfMonthType) 0; + for (i = 0; i < 7; i++) + a->repeatDays[i] = 0; + a->repeatWeekstart = 0; + } + + if (iflags & exceptFlag) { + a->exceptions = get_short(p2); + p2 += 2; + a->exception = malloc(sizeof(struct tm) * a->exceptions); + + for (j = 0; j < a->exceptions; j++, p2 += 2) { + d = (unsigned short int) get_short(p2); + a->exception[j].tm_year = (d >> 9) + 4; + a->exception[j].tm_mon = ((d >> 5) & 15) - 1; + a->exception[j].tm_mday = d & 31; + a->exception[j].tm_hour = 0; + a->exception[j].tm_min = 0; + a->exception[j].tm_sec = 0; + a->exception[j].tm_isdst = -1; + mktime(&a->exception[j]); + } + + } else { + a->exceptions = 0; + a->exception = 0; + } + + if (iflags & descFlag) { + a->description = strdup((char *)p2); + p2 += strlen((char *)p2) + 1; + } else + a->description = 0; + + if (iflags & noteFlag) { + a->note = strdup((char *)p2); + p2 += strlen((char *)p2) + 1; + } else { + a->note = 0; + } + + if (iflags & locFlag) { + a->location = strdup((char *)p2); + p2 += strlen((char *)p2) + 1; + } else { + a->location = 0; + } + + /* initialize the blobs to NULL */ + for (i=0; i<MAX_BLOBS; ++i) { + a->blob[i]=NULL; + } + + if(p2 - buf->data < buf->used) { + uint8_t blob_count; + + /* read the blobs */ + a->tz = NULL; + for(blob_count = 0; buf->used - (p2 - buf->data) > 6; ++blob_count) { + if(blob_count >= MAX_BLOBS) { + /* too many blobs were found */ + printf("Error, found more than %d blobs: %d\n", MAX_BLOBS, blob_count); + return -1; + } + + a->blob[blob_count] = (Blob_t *)malloc(sizeof(Blob_t)); + result = unpack_Blob_p(a->blob[blob_count], p2, 0); + if(-1 == result) { + return -1; + } else { + p2 += result; + } + //printf("DEBUG: record %s read in blob[%d] of size %d\n", a->description, blob_count, a->blob[blob_count]->length); + + /* if it's a timezone blob store it */ + if (0 == memcmp(a->blob[blob_count]->type, BLOB_TYPE_CALENDAR_TIMEZONE_ID, 4)) { + int result; + if(NULL != a->tz) { + printf("Warning: Found more than one timezone blob! Freeing the previous one and starting again\n"); + free_Timezone(a->tz); + free(a->tz); + } + a->tz = (Timezone_t *)malloc(sizeof(Timezone_t)); + result = unpack_Timezone_p(a->tz, a->blob[blob_count]->data, 0); + if(-1 == result) { + printf("Error unpacking timezone blob\n"); + return -1; + } else if(result != a->blob[blob_count]->length) { + printf("Read the wrong number of bytes for a timezone expected %d but was %d\n", a->blob[blob_count]->length, result); + return -1; + } + + } + } + if(p2 - buf->data < buf->used) { + printf("Extra data found %ld bytes\n", (buf->used - (p2 - buf->data))); + return -1; + } + } else { + a->tz = NULL; + } + + return 0; +} + +/*********************************************************************** + * + * Function: pack_CalendarEvent + * + * Summary: Fill in the raw calendar event record data based on the + * calendar event structure. + * + * Parameters: CalendarEvent_t*, pi_buffer_t*, calendarType + * + * Returns: -1 on error (bad arguments, mostyle) or 0 on success. + * The buffer is sized to accomodate the required data. + * + ***********************************************************************/ +int +pack_CalendarEvent(const CalendarEvent_t *a, pi_buffer_t *buf, calendarType type) +{ + int iflags, + destlen = 8; + char *pos; + + if (type != calendar_v1) + return -1; + + if (a == NULL || buf == NULL) + return -1; + + if (a->alarm) + destlen += 2; + if (a->repeatType) + destlen += 8; + if (a->exceptions) + destlen += 2 + 2 * a->exceptions; + if (a->note) + destlen += strlen(a->note) + 1; + if (a->description) + destlen += strlen(a->description) + 1; + if (a->location) + destlen += strlen(a->location) + 1; + + pi_buffer_expect (buf, destlen); + buf->used = destlen; + + set_byte(buf->data, a->begin.tm_hour); + set_byte(buf->data + 1, a->begin.tm_min); + set_byte(buf->data + 2, a->end.tm_hour); + set_byte(buf->data + 3, a->end.tm_min); + set_short(buf->data + 4, + ((a-> + begin.tm_year - 4) << 9) | ((a->begin.tm_mon + + 1) << 5) | a->begin. + tm_mday); + + if (a->event) { + set_long(buf->data, 0xffffffff); + } + + iflags = 0; + + pos = (char *) buf->data + 8; + + if (a->alarm) { + iflags |= alarmFlag; + + set_byte(pos, a->advance); + set_byte(pos + 1, a->advanceUnits); + pos += 2; + } + + if (a->repeatType) { + int i, + on; + + iflags |= repeatFlag; + + if (a->repeatType == calendarRepeatMonthlyByDay) + on = a->repeatDay; + else if (a->repeatType == calendarRepeatWeekly) { + on = 0; + for (i = 0; i < 7; i++) + if (a->repeatDays[i]) + on |= 1 << i; + } else + on = 0; + + set_byte(pos, a->repeatType); + set_byte(pos + 1, 0); + pos += 2; + + if (a->repeatForever) + set_short(pos, 0xffff); + else + set_short(pos, + ((a-> + repeatEnd.tm_year - + 4) << 9) | ((a->repeatEnd.tm_mon + + 1) << 5) | a->repeatEnd. + tm_mday); + + pos += 2; + + set_byte(pos, a->repeatFrequency); + pos++; + set_byte(pos, on); + pos++; + set_byte(pos, a->repeatWeekstart); + pos++; + set_byte(pos, 0); + pos++; + } + + if (a->exceptions) { + int i; + + iflags |= exceptFlag; + + set_short(pos, a->exceptions); + pos += 2; + + for (i = 0; i < a->exceptions; i++, pos += 2) + set_short(pos, + ((a-> + exception[i].tm_year - + 4) << 9) | ((a->exception[i].tm_mon + + 1) << 5) | a-> + exception[i].tm_mday); + } + + if (a->description != NULL) { + iflags |= descFlag; + + strcpy(pos, a->description); + pos += strlen(pos) + 1; + } + + if (a->note != NULL) { + iflags |= noteFlag; + + strcpy(pos, a->note); + pos += strlen(pos) + 1; + } + + if (a->location != NULL) { + iflags |= locFlag; + + strcpy(pos, a->location); + pos += strlen(pos) + 1; + } + + set_byte(buf->data + 6, iflags); + set_byte(buf->data + 7, 0); /* gapfill */ + + /* Calendar stuff */ + uint8_t blob_index; + + //write out the blobs + for(blob_index = 0; blob_index < MAX_BLOBS; ++blob_index) { + if(NULL != a->blob[blob_index]) { + pack_Blob(a->blob[blob_index], buf); + } + } + + return 0; +} + +/*********************************************************************** + * + * Function: unpack_CalendarAppInfo + * + * Summary: Fill in the app info structure based on the raw app + * info data + * + * Parameters: CalendarAppInfo_t*, char* to record, record length + * + * Returns: 0 on error, the length of the data used from the + * buffer otherwise + * + ***********************************************************************/ +int +unpack_CalendarAppInfo(CalendarAppInfo_t *ai, pi_buffer_t *buf) +{ + int i; + int len; + unsigned char *record; + int used; + + len = buf->used; + record = buf->data; + used = unpack_CategoryAppInfo(&ai->category, record, len); + if (!used) + return 0; + record += used; + len -= used; + if (len < 2) + return 0; + ai->startOfWeek = get_byte(record); + // alignment byte + record += 2; + used += 2; + + for(i=0; i<18; ++i) { + ai->internal[i] = get_byte(record); + record++; + used++; + } + ai->type = calendar_v1; + + return used; +} + +/*********************************************************************** + * + * Function: pack_CalendarAppInfo + * + * Summary: Fill in the raw app info record data based on the app + * info structure + * + * Parameters: AppointmentAppInfo*, char* to buffer, buffer length + * + * Returns: The length of the buffer required if record is NULL, + * or 0 on error, the length of the data used from the + * buffer otherwise + * + ***********************************************************************/ +int +pack_CalendarAppInfo(const CalendarAppInfo_t *ai, pi_buffer_t *buf) +{ + int i; + int len; + unsigned char *record; + + if (!buf) { + return 298; + } + + /* AppInfo size should be 298, 300 will do */ + len = 300; + pi_buffer_expect(buf, 300); + buf->used = pack_CategoryAppInfo(&ai->category, buf->data, buf->allocated); + if (!buf->used) + return 0; + record = buf->data + buf->used; + len -= buf->used; + if (len < 2) + return 0; + set_short(record, 0); + set_byte(record, ai->startOfWeek); + record += 2; + buf->used += 2; + + for(i=0; i<18; ++i) { + set_byte(record, ai->internal[i]); + record ++; + buf->used ++; + } + + return (record - buf->data); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/cmp.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/cmp.c new file mode 100644 index 00000000..e2f5f357 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/cmp.c @@ -0,0 +1,655 @@ +/* + * $Id: cmp.c,v 1.41 2006/11/07 21:13:24 adridg Exp $ + * + * cmp.c: Pilot Connection Management Protocol + * + * Copyright (c) 1996, Kenneth Albanowski. + * Copyright (c) 1999, Tilo Christ + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + * + * -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-socket.h" +#include "pi-padp.h" +#include "pi-cmp.h" +#include "pi-error.h" + +/* Declare prototypes */ +static int cmp_flush(pi_socket_t *ps, int flags); +static int cmp_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len); +static int cmp_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len); + +static pi_protocol_t *cmp_protocol_dup (pi_protocol_t *prot); +static void cmp_protocol_free (pi_protocol_t *prot); + +/* Protocol Functions */ +/*********************************************************************** + * + * Function: cmp_protocol_dup + * + * Summary: clones an existing pi_protocol struct + * + * Parameters: pi_protocol_t* + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +static pi_protocol_t* +cmp_protocol_dup (pi_protocol_t *prot) +{ + pi_protocol_t *new_prot; + + struct pi_cmp_data *data, + *new_data; + + new_prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t)); + new_data = (struct pi_cmp_data *)malloc (sizeof (struct pi_cmp_data)); + + if ( (new_prot != NULL) && (new_data != NULL) ) { + new_prot->level = prot->level; + new_prot->dup = prot->dup; + new_prot->free = prot->free; + new_prot->read = prot->read; + new_prot->write = prot->write; + new_prot->flush = prot->flush; + new_prot->getsockopt = prot->getsockopt; + new_prot->setsockopt = prot->setsockopt; + + data = (struct pi_cmp_data *)prot->data; + new_data->type = data->type; + new_data->flags = data->flags; + new_data->version = data->version; + new_data->baudrate = data->baudrate; + + new_prot->data = new_data; + + } else if (new_prot != NULL) { + free(new_prot); + new_prot = NULL; + } else if (new_data != NULL) { + free(new_data); + new_data = NULL; + } + + return new_prot; +} + + +/*********************************************************************** + * + * Function: cmp_protocol_free + * + * Summary: frees an existing pi_protocol struct + * + * Parameters: pi_protocol_t* + * + * Returns: void + * + ***********************************************************************/ +static void +cmp_protocol_free (pi_protocol_t *prot) +{ + if (prot != NULL) { + if (prot->data != NULL) + free(prot->data); + free(prot); + } +} + + +/*********************************************************************** + * + * Function: cmp_protocol + * + * Summary: creates and inits pi_protocol struct instance + * + * Parameters: void + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +pi_protocol_t* +cmp_protocol (void) +{ + pi_protocol_t *prot; + struct pi_cmp_data *data; + + prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t)); + data = (struct pi_cmp_data *)malloc (sizeof (struct pi_cmp_data)); + + if (prot != NULL && data != NULL) { + prot->level = PI_LEVEL_CMP; + prot->dup = cmp_protocol_dup; + prot->free = cmp_protocol_free; + prot->read = cmp_rx; + prot->write = cmp_tx; + prot->flush = cmp_flush; + prot->getsockopt = cmp_getsockopt; + prot->setsockopt = cmp_setsockopt; + + data->type = 0; + data->flags = 0; + data->version = 0; + data->baudrate = 0; + + prot->data = data; + + } else if (prot != NULL) { + free(prot); + prot = NULL; + } else if (data != NULL) { + free(data); + data = NULL; + } + + return prot; +} + + +/*********************************************************************** + * + * Function: cmp_rx_handshake + * + * Summary: establishes RX handshake + * + * Parameters: pi_socket_t*, baudrate, hirate enable + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +int +cmp_rx_handshake(pi_socket_t *ps, int establishrate, + int establishhighrate) +{ + pi_protocol_t *prot; + struct pi_cmp_data *data; + pi_buffer_t *buf; + int bytes; + + prot = pi_protocol(ps->sd, PI_LEVEL_CMP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (struct pi_cmp_data *)prot->data; + + /* Read the cmp packet */ + buf = pi_buffer_new (PI_CMP_HEADER_LEN); + if (buf == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + bytes = cmp_rx(ps, buf, PI_CMP_HEADER_LEN, 0); + + pi_buffer_free (buf); + if (bytes < 0) + return bytes; + + if ((data->version & 0xFF00) == 0x0100) { + if (establishrate != -1) { + if (establishrate > data->baudrate) { + if (establishhighrate) { + LOG((PI_DBG_CMP, PI_DBG_LVL_INFO, + "CMP Establishing higher rate %ul (%ul)\n", + establishrate, data->baudrate)); + data->baudrate = establishrate; + } + } else { + data->baudrate = establishrate; + } + } + + if ((bytes = cmp_init(ps, data->baudrate)) < 0) + return bytes; + } else { + /* 0x80 means the comm version wasn't compatible */ + LOG((PI_DBG_CMP, PI_DBG_LVL_ERR, "CMP Incompatible Version\n")); + cmp_abort(ps, 0x80); + errno = ECONNREFUSED; + return pi_set_error(ps->sd, PI_ERR_PROT_INCOMPATIBLE); + } + + return 0; +} + + +/*********************************************************************** + * + * Function: cmp_tx_handshake + * + * Summary: establishes TX handshake + * + * Parameters: pi_socket_t* + * + * Returns: >= 0 for success, negative otherwise + * + ***********************************************************************/ +int +cmp_tx_handshake(pi_socket_t *ps) +{ + pi_protocol_t *prot; + struct pi_cmp_data *data; + int result; + + prot = pi_protocol(ps->sd, PI_LEVEL_CMP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (struct pi_cmp_data *)prot->data; + + if ((result = cmp_wakeup(ps, 38400)) < 0) /* Assume box can't go over 38400 */ + return result; + + if ((result = cmp_rx(ps, NULL, 0, 0)) < 0) + return result; /* failed to read, errno already set */ + + switch (data->type) { + case PI_CMP_TYPE_INIT: + return 0; + case PI_CMP_TYPE_ABRT: + LOG((PI_DBG_CMP, PI_DBG_LVL_NONE, + "CMP Aborted by other end\n")); + errno = -EIO; + return pi_set_error(ps->sd, PI_ERR_PROT_ABORTED); + } + + return PI_ERR_PROT_INCOMPATIBLE; + +} + + +/*********************************************************************** + * + * Function: cmp_tx + * + * Summary: Transmit CMP Packets + * + * Parameters: pi_socket_t*, char* to buf, buf length, flags + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +ssize_t +cmp_tx(pi_socket_t *ps, const unsigned char *buf, size_t len, int flags) +{ + int bytes, + type; + size_t size; + pi_protocol_t *prot, + *next; + struct pi_cmp_data *data; + unsigned char cmp_buf[PI_CMP_HEADER_LEN]; + + prot = pi_protocol(ps->sd, PI_LEVEL_CMP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (struct pi_cmp_data *)prot->data; + next = pi_protocol_next(ps->sd, PI_LEVEL_CMP); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + type = padData; + size = sizeof(type); + pi_setsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_TYPE, &type, &size); + + set_byte(&cmp_buf[PI_CMP_OFFSET_TYPE], data->type); + set_byte(&cmp_buf[PI_CMP_OFFSET_FLGS], data->flags); + set_short(&cmp_buf[PI_CMP_OFFSET_VERS], data->version > PI_CMP_VERSION ? PI_CMP_VERSION : data->version); + set_short(&cmp_buf[PI_CMP_OFFSET_RESV], 0); + set_long(&cmp_buf[PI_CMP_OFFSET_BAUD], data->baudrate); + + CHECK(PI_DBG_CMP, PI_DBG_LVL_INFO, cmp_dump(cmp_buf, 1)); + + bytes = next->write(ps, cmp_buf, PI_CMP_HEADER_LEN, flags); + if (bytes < 10) + return (bytes < 0) ? bytes : pi_set_error(ps->sd, PI_ERR_PROT_ABORTED); + + return 0; +} + +/*********************************************************************** + * + * Function: cmp_rx + * + * Summary: Receive CMP packets + * + * Parameters: None + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +ssize_t +cmp_rx(pi_socket_t *ps, pi_buffer_t *msg, size_t len, int flags) +{ + int bytes; + pi_protocol_t *prot, + *next; + struct pi_cmp_data *data; + + LOG((PI_DBG_CMP, PI_DBG_LVL_DEBUG, "CMP RX len=%d flags=0x%02x\n", + len, flags)); + + prot = pi_protocol(ps->sd, PI_LEVEL_CMP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (struct pi_cmp_data *)prot->data; + next = pi_protocol_next(ps->sd, PI_LEVEL_CMP); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + bytes = next->read(ps, msg, len, flags); + if (bytes < 10) + return pi_set_error(ps->sd, (bytes < 0) ? bytes : PI_ERR_PROT_ABORTED); + + CHECK(PI_DBG_CMP, PI_DBG_LVL_INFO, cmp_dump(msg->data, 0)); + + data->type = get_byte(&msg->data[PI_CMP_OFFSET_TYPE]); + data->flags = get_byte(&msg->data[PI_CMP_OFFSET_FLGS]); + data->version = get_short(&msg->data[PI_CMP_OFFSET_VERS]); + data->baudrate = get_long(&msg->data[PI_CMP_OFFSET_BAUD]); + + return 0; +} + +/*********************************************************************** + * + * Function: cmp_flush + * + * Summary: Flush input and output buffers + * + * Parameters: pi_socket_t*, flags + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +static int +cmp_flush(pi_socket_t *ps, int flags) +{ + pi_protocol_t *prot, + *next; + + prot = pi_protocol(ps->sd, PI_LEVEL_CMP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + next = pi_protocol_next(ps->sd, PI_LEVEL_CMP); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + return next->flush(ps, flags); +} + +/*********************************************************************** + * + * Function: cmp_init + * + * Summary: Initialize the socket for CMP transmission + * + * Parameters: pi_socket_t*, baudrate + * + * Returns: Number of packets transmitted + * + ***********************************************************************/ +int +cmp_init(pi_socket_t *ps, int baudrate) +{ + pi_protocol_t *prot; + struct pi_cmp_data *data; + + prot = pi_protocol(ps->sd, PI_LEVEL_CMP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + data = (struct pi_cmp_data *)prot->data; + + data->type = PI_CMP_TYPE_INIT; + data->flags = CMP_FL_LONG_PACKET_SUPPORT; + if (baudrate != 9600) + data->flags = CMP_FL_CHANGE_BAUD_RATE; + data->baudrate = baudrate; + + return cmp_tx(ps, NULL, 0, 0); +} + +/*********************************************************************** + * + * Function: cmp_abort + * + * Summary: Abort a CMP session in progress + * + * Parameters: pi_socket_t* + * + * Returns: Number of PADP packets transmitted or negative on error + * + ***********************************************************************/ +int +cmp_abort(pi_socket_t *ps, int reason) +{ + pi_protocol_t *prot; + struct pi_cmp_data *data; + + prot = pi_protocol(ps->sd, PI_LEVEL_CMP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (struct pi_cmp_data *)prot->data; + data->type = PI_CMP_TYPE_ABRT; + data->flags = reason; + + LOG((PI_DBG_CMP, PI_DBG_LVL_NONE, "CMP ABORT\n")); + + return cmp_tx (ps, NULL, 0, 0); +} + +/*********************************************************************** + * + * Function: cmp_wakeup + * + * Summary: Wakeup the CMP listener process + * + * Parameters: pi_socket_t* + * + * Returns: Number of PADP packets transmitted or negative on error + * + ***********************************************************************/ +int +cmp_wakeup(pi_socket_t *ps, int maxbaud) +{ + pi_protocol_t *prot; + struct pi_cmp_data *data; + + prot = pi_protocol(ps->sd, PI_LEVEL_CMP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (struct pi_cmp_data *)prot->data; + data->type = PI_CMP_TYPE_WAKE; + data->flags = 0; + data->version = PI_CMP_VERSION; + data->baudrate = maxbaud; + + return cmp_tx(ps, NULL, 0, 0); +} + + +/*********************************************************************** + * + * Function: cmp_getsockopt + * + * Summary: get options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +cmp_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len) +{ + pi_protocol_t *prot; + struct pi_cmp_data *data; + + (void) level; + + prot = pi_protocol(ps->sd, PI_LEVEL_CMP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + data = (struct pi_cmp_data *)prot->data; + + switch (option_name) { + case PI_CMP_TYPE: + if (*option_len != sizeof (data->type)) + goto error; + memcpy (option_value, &data->type, + sizeof (data->type)); + *option_len = sizeof (data->type); + break; + + case PI_CMP_FLAGS: + if (*option_len != sizeof (data->flags)) + goto error; + memcpy (option_value, &data->flags, + sizeof (data->flags)); + *option_len = sizeof (data->flags); + break; + + case PI_CMP_VERS: + if (*option_len != sizeof (data->version)) + goto error; + memcpy (option_value, &data->version, + sizeof (data->version)); + *option_len = sizeof (data->version); + break; + + case PI_CMP_BAUD: + if (*option_len != sizeof (data->baudrate)) + goto error; + memcpy (option_value, &data->baudrate, + sizeof (data->baudrate)); + *option_len = sizeof (data->baudrate); + break; + } + + return 0; + + error: + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); +} + + +/*********************************************************************** + * + * Function: cmp_setsockopt + * + * Summary: set options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +cmp_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len) +{ + pi_protocol_t *prot; + struct pi_padp_data *data; + + (void) level; + + prot = pi_protocol(ps->sd, PI_LEVEL_PADP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + data = (struct pi_padp_data *)prot->data; + + if (option_name == PI_PADP_TYPE) { + if (*option_len != sizeof (data->type)) + goto error; + memcpy (&data->type, option_value, + sizeof (data->type)); + *option_len = sizeof (data->type); + } + + return 0; + + error: + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); +} + + +/*********************************************************************** + * + * Function: cmp_dump + * + * Summary: Dump the CMP packet frames + * + * Parameters: char* to cmp packet, TX boolean + * + * Returns: void + * + ***********************************************************************/ +void +cmp_dump(const unsigned char *cmp, int rxtx) +{ + char *type; + + (void) rxtx; + + switch (get_byte(&cmp[PI_CMP_OFFSET_TYPE])) { + case PI_CMP_TYPE_WAKE: + type = "WAKE"; + break; + case PI_CMP_TYPE_INIT: + type = "INIT"; + break; + case PI_CMP_TYPE_ABRT: + type = "ABRT"; + break; + default: + type = "UNK"; + break; + } + + LOG((PI_DBG_CMP, PI_DBG_LVL_NONE, + "CMP %s %s Type: 0x%02x Flags: 0x%02x Version: 0x%04x Baud: %d\n", + rxtx ? "TX" : "RX", type, + get_byte(&cmp[PI_CMP_OFFSET_TYPE]), + get_byte(&cmp[PI_CMP_OFFSET_FLGS]), + get_long(&cmp[PI_CMP_OFFSET_VERS]), + get_long(&cmp[PI_CMP_OFFSET_BAUD]))); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/connect.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/connect.c new file mode 100644 index 00000000..711c3d4e --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/connect.c @@ -0,0 +1,126 @@ +/* + * $Id: connect.c,v 1.60 2006/10/12 14:21:22 desrod Exp $ + * + * connect.c: Palm Serial, USB, IR connection routines + * + * Copyright (c) 2001, David A. Desrosiers + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#ifdef HAVE_IFADDRS_H +#include <ifaddrs.h> +#endif +#include <unistd.h> +#include <sys/stat.h> + +#include "pi-socket.h" +#include "pi-dlp.h" +#include "pi-header.h" + +/*********************************************************************** + * + * Function: pilot_connect [DEPRECATED] + * + * Summary: Connect to a Palm device. + * + * Parameters: port. Communications port through which the Palm device is + * connected. + * + * Returns: Socket descriptor of type 'client_sd', if successful. + * Returns 1, if the connection can not be established. + * + * 'port' is allowed to be NULL for the pi_bind call because pi_bind will + * check your PILOTPORT environment variable. If port is NULL and the + * attempt to connect fails for any reason, we simply assume the user didn't + * provide one, because pilot_connect doesn't have a way of knowing, for the + * time being. + * + * This function is deprecated because it doesn't really belong in libpisock. + * It will remain at least until it has been properly replaced. + * + ***********************************************************************/ +int +pilot_connect(const char *port) +{ + int sd = -1, /* Socket, formerly parent/client_socket */ + result; + + struct SysInfo sys_info; + + fprintf(stderr, "\n"); + fprintf(stderr," DEPRECATED: The application is calling pilot_connect()\n"); + if ((sd = pi_socket(PI_AF_PILOT, + PI_SOCK_STREAM, PI_PF_DLP)) < 0) { + fprintf(stderr, "\n Unable to create socket '%s'\n", port); + return -1; + } + + result = pi_bind(sd, port); + + if (result < 0) { + if (port == NULL) + fprintf(stderr, " No port specified\n"); + else + fprintf(stderr, " Unable to bind to port: %s\n", port); + + fprintf(stderr, " Please use --help for more information\n\n"); + return result; + } + + if (isatty(fileno(stdout))) { + printf("\n Listening for incoming connection on %s... ", + port); + fflush(stdout); + } + + if (pi_listen(sd, 1) < 0) { + fprintf(stderr, "\n Error listening on %s\n", port); + pi_close(sd); + return -1; + } + + sd = pi_accept(sd, 0, 0); + if (sd < 0) { + fprintf(stderr, "\n Error accepting data on %s\n", port); + pi_close(sd); + return -1; + } + + if (isatty(fileno(stdout))) { + printf("connected!\n\n"); + } + + if (dlp_ReadSysInfo(sd, &sys_info) < 0) { + fprintf(stderr, "\n Error read system info on %s\n", port); + pi_close(sd); + return -1; + } + + dlp_OpenConduit(sd); + return sd; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/contact.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/contact.c new file mode 100644 index 00000000..7748fe01 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/contact.c @@ -0,0 +1,586 @@ +/* $Id: contact.c,v 1.20 2009/02/23 11:59:16 nicholas Exp $ */ + +/******************************************************************************* + * contact.c: Translate Palm contact data formats + * Derived from a module of J-Pilot http://jpilot.org (jp-contact.c 1.10) + * + * Rewrite Copyright 2006, 2007 Judd Montgomery + * Rewrite Copyright 2004, 2005 Joseph Carter + * Copyright 2003, 2004 Judd Montgomery + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + ******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pi-macros.h" +#include "pi-contact.h" + + +/*********************************************************************** + * + * Function: free_Contact + * + * Summary: Free the members of a contact structure + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +void free_Contact(struct Contact *c) +{ + int i; + + for (i = 0; i < NUM_CONTACT_ENTRIES; i++) + if (c->entry[i]) + free(c->entry[i]); + for (i = 0; i < MAX_CONTACT_BLOBS; i++) { + if (c->blob[i]) { + if (c->blob[i]->data) + free(c->blob[i]->data); + + free(c->blob[i]); + } + } + + if (c->picture) free(c->picture); +} + +#define hi(x) (((x) >> 4) & 0x0f) +#define lo(x) ((x) & 0x0f) +#define pair(x,y) (((x) << 4) | (y)) + +/*********************************************************************** + * + * Function: unpack_Contact + * + * Summary: Fill in the contact structure based on the raw record + * data + * + * Parameters: None + * + * Returns: -1 on error, + * The length of the data used from the buffer on success + * + ***********************************************************************/ +int unpack_Contact(struct Contact *c, pi_buffer_t *buf, contactsType type) +{ + unsigned long contents1; + unsigned long contents2; + unsigned char *Pbuf, *record; + int i, field_num, len; + unsigned int packed_date; + unsigned int blob_count; + + if (buf == NULL || buf->data == NULL || buf->used < 17) + return -1; + + if (type != contacts_v10 && type != contacts_v11) { + /* Don't support anything else yet */ + return -1; + } + + record = Pbuf = buf->data; + len = buf->used; + + for (i=0; i<MAX_CONTACT_BLOBS; i++) { + c->blob[i]=NULL; + } + c->picture=NULL; + + c->showPhone = hi(get_byte(Pbuf)); + c->phoneLabel[6] = lo(get_byte(Pbuf)); + c->phoneLabel[5] = hi(get_byte(Pbuf + 1)); + c->phoneLabel[4] = lo(get_byte(Pbuf + 1)); + c->phoneLabel[3] = hi(get_byte(Pbuf + 2)); + c->phoneLabel[2] = lo(get_byte(Pbuf + 2)); + c->phoneLabel[1] = hi(get_byte(Pbuf + 3)); + c->phoneLabel[0] = lo(get_byte(Pbuf + 3)); + + c->addressLabel[2] = lo(get_byte(Pbuf + 4)); + c->addressLabel[1] = hi(get_byte(Pbuf + 5)); + c->addressLabel[0] = lo(get_byte(Pbuf + 5)); + + c->IMLabel[1] = hi(get_byte(Pbuf + 7)); + c->IMLabel[0] = lo(get_byte(Pbuf + 7)); + + contents1 = get_long(record + 8); + contents2 = get_long(record + 12); + + /* c->companyOffset = get_byte(record + 16); */ + + Pbuf += 17; + len -= 17; + + field_num=0; + + for (i = 0; i < 28; i++, field_num++) { + if (contents1 & (1 << i)) { + if (len < 1) + return 0; + c->entry[field_num] = strdup((char *) Pbuf); + Pbuf += strlen((char *) Pbuf) + 1; + len -= strlen(c->entry[field_num]) + 1; + } else { + c->entry[field_num] = 0; + } + } + for (i = 0; i < 11; i++, field_num++) { + if (contents2 & (1 << i)) { + if (len < 1) + return 0; + c->entry[field_num] = strdup((char *) Pbuf); + Pbuf += strlen((char *) Pbuf) + 1; + len -= strlen(c->entry[field_num]) + 1; + } else { + c->entry[field_num] = 0; + } + } + + /* I think one of these is a birthday flag and one is an alarm flag. + * Since both are always set there is no way to know which is which. + * It could be something like a flag for advanceUnits also. */ + if ((contents2 & 0x0800) || (contents2 & 0x1000)) { + c->birthdayFlag = 1; + if (len < 1) + return 0; + packed_date = get_short(Pbuf); + c->birthday.tm_year = ((packed_date & 0xFE00) >> 9) + 4; + c->birthday.tm_mon = ((packed_date & 0x01E0) >> 5) - 1; + c->birthday.tm_mday = (packed_date & 0x001F); + c->birthday.tm_hour = 0; + c->birthday.tm_min = 0; + c->birthday.tm_sec = 0; + c->birthday.tm_isdst= -1; + mktime(&c->birthday); + /* 2 bytes and a zero padding byte */ + len -= 3; + Pbuf += 3; + c->advanceUnits = get_byte(Pbuf); + len--; + Pbuf++; + } else { + c->birthdayFlag = 0; + } + + if (contents2 & 0x2000) { + c->reminder = 1; + if (len < 1) + return 0; + c->advance = get_byte(Pbuf); + len -= 1; + Pbuf += 1; + } else { + c->reminder = 0; + c->advance = 0; + } + + /* A blob of size zero would take 6 bytes */ + blob_count=0; + while (len >= 6) { + if (blob_count >= MAX_CONTACT_BLOBS) { + /* Too many blobs were found. */ + return (Pbuf - record); + } + c->blob[blob_count] = malloc(sizeof(struct ContactBlob)); + strncpy(c->blob[blob_count]->type, (char *)Pbuf, 4); + c->blob[blob_count]->length = get_short(Pbuf+4); + c->blob[blob_count]->data = malloc(c->blob[blob_count]->length); + if (c->blob[blob_count]->data) { + memcpy(c->blob[blob_count]->data, Pbuf+6, c->blob[blob_count]->length); + } + if (! strncmp(c->blob[blob_count]->type, BLOB_TYPE_PICTURE_ID, 4)) { + if (!(c->picture)) { + c->picture = malloc(sizeof(struct ContactPicture)); + } + c->picture->dirty = get_short(c->blob[blob_count]->data); + c->picture->length = c->blob[blob_count]->length - 2; + c->picture->data = c->blob[blob_count]->data + 2; + } + + Pbuf += 6; + len -= 6; + Pbuf += c->blob[blob_count]->length; + len -= c->blob[blob_count]->length; + blob_count++; + } + + return (Pbuf - record); +} + + +/*********************************************************************** + * + * Function: pack_Contact + * + * Summary: Fill in the raw contact record data based on the + * contact structure + * + * Parameters: None + * + * Returns: -1 on error + * The length of the buffer used on success + * + ***********************************************************************/ +int pack_Contact(struct Contact *c, pi_buffer_t *buf, contactsType type) +{ + int l, destlen = 17; + + unsigned char *Pbuf, *record; + unsigned long contents1, contents2; + int i; + unsigned int field_i; + unsigned long phoneflag; + unsigned long typesflag; + unsigned short packed_date; + int companyOffset = 0; + + if (c == NULL || buf == NULL) + return -1; + + if (type != contacts_v10 && type != contacts_v11) { + /* Don't support anything else yet */ + return -1; + } + + for (i = 0; i < NUM_CONTACT_ENTRIES; i++) { + if (c->entry[i]) { + destlen += (strlen(c->entry[i]) + 1); + } + } + if (c->birthdayFlag) { + destlen += 3; + if (c->reminder) { + destlen += 2; + } else { + destlen += 1; + } + } + + /* Check for blobs */ + for (i=0; i<MAX_CONTACT_BLOBS; i++) { + if (c->blob[i]) { + destlen += c->blob[i]->length + 6; + } + } + + pi_buffer_expect(buf, destlen); + + record = buf->data; + + Pbuf = record + 17; + phoneflag = 0; + typesflag = 0; + contents1 = contents2 = 0; + + field_i = 0; + for (i = 0; i < 28; i++, field_i++) { + if (c->entry[field_i] && strlen(c->entry[field_i])) { + contents1 |= (1 << i); + l = strlen(c->entry[field_i]) + 1; + memcpy(Pbuf, c->entry[field_i], l); + Pbuf += l; + } + } + for (i = 0; i < 11; i++, field_i++) { + if (c->entry[field_i] && strlen(c->entry[field_i])) { + contents2 |= (1 << i); + l = strlen(c->entry[field_i]) + 1; + memcpy(Pbuf, c->entry[field_i], l); + Pbuf += l; + } + } + + phoneflag = (((unsigned long) c->phoneLabel[0]) & 0xF) << 0; + phoneflag |= (((unsigned long) c->phoneLabel[1]) & 0xF) << 4; + phoneflag |= (((unsigned long) c->phoneLabel[2]) & 0xF) << 8; + phoneflag |= (((unsigned long) c->phoneLabel[3]) & 0xF) << 12; + phoneflag |= (((unsigned long) c->phoneLabel[4]) & 0xF) << 16; + phoneflag |= (((unsigned long) c->phoneLabel[5]) & 0xF) << 20; + phoneflag |= (((unsigned long) c->phoneLabel[6]) & 0xF) << 24; + phoneflag |= (((unsigned long) c->showPhone) & 0xF) << 28; + + typesflag = (((unsigned long) c->IMLabel[0]) & 0xF) << 0; + typesflag |= (((unsigned long) c->IMLabel[1]) & 0xF) << 4; + typesflag |= (((unsigned long) c->addressLabel[0]) & 0xF) << 16; + typesflag |= (((unsigned long) c->addressLabel[1]) & 0xF) << 20; + typesflag |= (((unsigned long) c->addressLabel[2]) & 0xF) << 24; + + if (c->birthdayFlag) { + contents2 |= 0x1800; + packed_date = (((c->birthday.tm_year - 4) << 9) & 0xFE00) | + (((c->birthday.tm_mon+1) << 5) & 0x01E0) | + (c->birthday.tm_mday & 0x001F); + set_short(Pbuf, packed_date); + Pbuf += 2; + set_byte(Pbuf, 0); /* padding byte in birthday date */ + Pbuf += 1; + if (c->reminder) { + contents2 |= 0x2000; + set_byte(Pbuf, c->advanceUnits); + Pbuf += 1; + set_byte(Pbuf, c->advance); + Pbuf += 1; + } else { + set_byte(Pbuf, 0); + Pbuf += 1; + } + } + + set_long(record, phoneflag); + set_long(record + 4, typesflag); + set_long(record + 8, contents1); + set_long(record + 12, contents2); + /* companyOffset is the offset from itself to the company field, + * or zero if no company field. Its not useful to us at all. */ + if (c->entry[2]) { + companyOffset++; + if (c->entry[0]) companyOffset += strlen(c->entry[0]) + 1; + if (c->entry[1]) companyOffset += strlen(c->entry[1]) + 1; + } + set_byte(record + 16, companyOffset); + + /* Pack blobs */ + for (i=0; i<MAX_CONTACT_BLOBS; i++) { + if (c->blob[i]) { + memcpy(Pbuf, c->blob[i]->type, 4); + Pbuf += 4; + set_short(Pbuf, c->blob[i]->length); + Pbuf += 2; + memcpy(Pbuf, c->blob[i]->data, c->blob[i]->length); + Pbuf += c->blob[i]->length; + } + } + buf->used = Pbuf - record; + + return (buf->used); +} + + +/*********************************************************************** + * + * Function: Contact_add_blob + * + * Summary: Add a blob record to a Contact Record + * + * Parameters: None + * + * Returns: 0 on success + * 1 on other error + * + ***********************************************************************/ +int Contact_add_blob(struct Contact *c, struct ContactBlob *blob) +{ + int i; + + for (i=0; i<MAX_CONTACT_BLOBS; i++) { + if (c->blob[i]) { + continue; + } + + c->blob[i] = malloc(sizeof(struct ContactBlob)); + if (!c->blob[i]) return EXIT_FAILURE; + + c->blob[i]->data = malloc(blob->length); + strncpy(c->blob[i]->type, blob->type, 4); + c->blob[i]->length = blob->length; + strncpy((char *)c->blob[i]->data, (char *)blob->data, blob->length); + return EXIT_SUCCESS; + } + + return EXIT_FAILURE; +} + + +/*********************************************************************** + * + * Function: Contact_add_picture + * + * Summary: Add a picture blob record to a Contact Record + * This will add a blob, but not touch the picture structure + * of the contact record + * + * Parameters: None + * + * Returns: 0 on success + * 1 on other error + * + ***********************************************************************/ +int Contact_add_picture(struct Contact *c, struct ContactPicture *p) +{ + int i; + + if ((!p) || (p->length<1) || (!p->data)) { + return EXIT_FAILURE; + } + for (i=0; i<MAX_CONTACT_BLOBS; i++) { + if (c->blob[i]) { + continue; + } + + c->blob[i] = malloc(sizeof(struct ContactBlob)); + if (!c->blob[i]) return EXIT_FAILURE; + + c->blob[i]->data = malloc(p->length + 2); + strncpy(c->blob[i]->type, BLOB_TYPE_PICTURE_ID, 4); + c->blob[i]->length = p->length + 2; + set_short(c->blob[i]->data, p->dirty); + memcpy(c->blob[i]->data + 2, p->data, p->length); + return EXIT_SUCCESS; + } + + return EXIT_FAILURE; +} + + +/*********************************************************************** + * + * Function: unpack_ContactAppInfo + * + * Summary: Fill in the app info structure based on the raw app + * info data + * + * Parameters: None + * + * Returns: -1 on error + * The length of data used from the buffer on success + * + ***********************************************************************/ +int unpack_ContactAppInfo(struct ContactAppInfo *ai, pi_buffer_t *buf) +{ + int i, j, destlen; + unsigned char *start, *Pbuf; + int len; + + start = Pbuf = buf->data; + len = buf->used; + if (len == 1092) { + ai->type = contacts_v10; + ai->num_labels = NUM_CONTACT_V10_LABELS; + ai->numCustoms = 9; /* not sure - but pi-contact.h <= 1.11 had 9 all the time */ + } else if (len == 1156) { + ai->type = contacts_v11; + ai->num_labels = NUM_CONTACT_V11_LABELS; + ai->numCustoms = 9; /* not sure - but pi-contact.h <= 1.11 had 9 all the time */ + } else { + fprintf(stderr, "contact.c: unpack_ContactAppInfo: ContactAppInfo size of %d incorrect\n", len); + return -1; + } + + /* 278 app info, 26 unknown, labels, county, sortBy */ + destlen = 278 + 26 + (16 * ai->num_labels) + 2 + 2; + if (buf->used < destlen) + return -1; + + i = unpack_CategoryAppInfo(&ai->category, start, len); + if (!i) + return i; + Pbuf += i; + + memcpy(ai->internal, Pbuf, 26); + Pbuf += 26; + memcpy(ai->labels, Pbuf, 16 * ai->num_labels); + Pbuf += 16 * ai->num_labels; + ai->country = get_byte(Pbuf); + Pbuf += 2; + ai->sortByCompany = get_byte(Pbuf); + Pbuf += 2; + + /* These are the fields that go in drop down menus */ + for (i = 4, j = 0; i < 11; i++, j++) { + strcpy(ai->phoneLabels[j], ai->labels[i]); + } + strcpy(ai->phoneLabels[j], ai->labels[40]); + + for (i = 0; i < ai->numCustoms; i++) { + strcpy(ai->customLabels[i], ai->labels[14 + i]); + } + + strcpy(ai->addrLabels[0], ai->labels[23]); + strcpy(ai->addrLabels[1], ai->labels[28]); + strcpy(ai->addrLabels[2], ai->labels[33]); + + strcpy(ai->IMLabels[0], ai->labels[41]); + strcpy(ai->IMLabels[1], ai->labels[42]); + strcpy(ai->IMLabels[2], ai->labels[43]); + strcpy(ai->IMLabels[3], ai->labels[44]); + strcpy(ai->IMLabels[4], ai->labels[45]); + + return (Pbuf - start); +} + + +/*********************************************************************** + * + * Function: free_ContactAppInfo + * + * Summary: Unallocate dynamically sized parts of ContactAppInfo + * (However, there are now none - provided for source compatibility) + * + * Parameters: struct ContactAppInfo *ai + * + * Returns: None + * + ***********************************************************************/ +void free_ContactAppInfo (struct ContactAppInfo *ai) +{ +} + +/*********************************************************************** + * + * Function: pack_ContactAppInfo + * + * Summary: Fill in the raw app info record data based on the + * ContactAppInfo structure + * + * Parameters: None + * + * Returns: -1 on error + * The length of the data used from the buffer on success. + * + ***********************************************************************/ +int pack_ContactAppInfo(struct ContactAppInfo *ai, pi_buffer_t *buf) +{ + int destlen; + + if (buf == NULL || buf->data == NULL) + return -1; + + /* 278 app info, 26 unknown, labels, country, sortBy */ + destlen = 278 + 26 + (16 * ai->num_labels) + 2 + 2; + + pi_buffer_expect(buf, destlen); + + buf->used = pack_CategoryAppInfo(&ai->category, buf->data, buf->allocated); + if (buf->used != 278) + return -1; + + pi_buffer_append(buf, ai->internal, 26); + + pi_buffer_append(buf, ai->labels, 16 * ai->num_labels); + + set_byte(buf->data + buf->used++, ai->country); + /* Unknown field */ + set_byte(buf->data + buf->used++, 0x00); + + set_byte(buf->data + buf->used++, ai->sortByCompany); + /* Unknown field */ + set_byte(buf->data + buf->used++, 0x00); + + return (buf->used); +} + diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/darwinusb.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/darwinusb.c new file mode 100644 index 00000000..1cccc4ad --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/darwinusb.c @@ -0,0 +1,1968 @@ +/* + * $Id: darwinusb.c,v 1.66 2006/11/09 10:26:21 fpillet Exp $ + * + * darwinusb.c: I/O support for Darwin (Mac OS X) USB + * + * Copyright (c) 2004-2006, Florent Pillet. + * + * libpisock interface modeled after linuxusb.c by Jeff Dionne and + * Kenneth Albanowski + * Some structures & defines extracted from Linux "visor.c", + * which is Copyright (C) 1999 - 2003 Greg Kroah-Hartman (greg@kroah.com) + * KLSI adapter (PalmConnect USB) support implemented thanks for the + * Linux implementation made by Utz-Uwe Haus (haus@uuhaus.de) + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + * + */ + +/* Theory of operation + * + * Darwin IOKit is different from traditional unix i/o. It is much more + * structured, and also more complex. + * + * One of the strengths of IOKit is IOUSBLib which allows talking to USB + * devices directly from userland code, without the need to write a driver. + * This is the way we do it here. + * + * Here is what we do: + * - We start a separate thread which will handle the USB communications. The + * main (controlling) thread exposes start, stop, poll, read and write + * functions. These function take care of controlling the USB thread. + * - We register for "device added" notifications. These notifications are + * sent by the IOKit to registered clients when a new device shows up. We + * use a matching dictionary to restrict the devices we're interested in to + * USB devices (IOUSBDevice class) + * - When we get notified that a new device showed up, we check the USB vendor + * ID and product ID and only accept those that are known to be Palm OS + * devices + * - We then examine the device interfaces and select the pipes we're going to + * use for input and output. + * - We register for notifications coming from the device. When the device + * goes away, our notification callback is called and we can cleanly close + * things. + * - Once everything is initialized, we fire a first "read" from the read + * pipe. Subsequent reads are fired directly from the previous read's + * completion routine [1]. + * - In case the thread or application is aborted, the IOKit will clean things + * up for us. + * + * [1] Reading is done asynchronously and in a chained way: we fire a read + * with ReadPipeAsync(). Once the read completes (or fails), our + * completion routine is called. As long as the read is not "aborted" + * (which means the device has been disconnected), we fire another read + * from the read_completion() function. + * + * All read data fills a buffer which is independantly consumed by the + * main thread. This way, we get the maximum read throughput by making + * sure that any data received from the device is fetched as soon as + * possible and made available to the main thread. + * + * Writes, in the contrary, are synchronous for now. I can make them async + * as well, though I have not explored the implications for the libpisock + * code yet. This could speed things up a bit as well, though. + */ + +#include <mach/mach.h> +#include <stdio.h> +#include <pthread.h> + +#include <IOKit/IOKitLib.h> +#include <IOKit/IOMessage.h> +#include <IOKit/IOCFPlugIn.h> +#include <IOKit/usb/IOUSBLib.h> +#include <CoreFoundation/CFByteOrder.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-usb.h" +#include "pi-util.h" + +/* Define this to make debug logs include USB debug info */ +#ifdef PI_DEBUG + #define DEBUG_USB 1 +#endif +#undef DEBUG_USB /* comment out to leave debug enabled */ + +/* Macro to log more information when debugging USB. Note that this is for + * my own use, mostly, as the info logged is primarily being used to + * debug complex thread/usb issues + */ +#ifdef DEBUG_USB + #define ULOG(a) LOG(a) +#else + #define ULOG(a) do {} while(0) +#endif + +/* These values are somewhat tricky. Priming reads with a size of exactly one + * USB packet works best (no timeouts). Probably best to leave these as they are. + */ +#define MAX_AUTO_READ_SIZE 4096 +#define AUTO_READ_SIZE 64 + +/* Options */ +#if HAVE_PTHREAD +static int accept_multiple_simultaneous_connections = 1; /* enabled by default when compiling with --enable-threads */ +#else +static int accept_multiple_simultaneous_connections = 0; /* disabled by default, set to 1 to enable */ +#endif + +/* IOKit interface */ +static IONotificationPortRef usb_notify_port; +static io_iterator_t usb_device_added_iter; + +/* RunLoop / threading management */ +static CFRunLoopRef usb_run_loop = 0; +static pthread_mutex_t usb_run_loop_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t usb_thread_ready_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t usb_thread_ready_cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t usb_connections_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t usb_connection_added_cond = PTHREAD_COND_INITIALIZER; +static pthread_t usb_thread = 0; + +/* Device interface linked list */ +typedef struct usb_connection_t +{ + struct usb_connection_t *next; /* linked list */ + struct pi_socket *ps; /* the pilot-link socket we're associated with (if already paired) */ + + /* refcount management */ + pthread_mutex_t ref_count_mutex; + int ref_count; + + IOUSBInterfaceInterface190 **interface; /* IOUSBInterface190 is 1.9.0 available on OS X 10.2 and later */ + IOUSBDeviceInterface **device; + io_object_t device_notification; /* for device removal */ + + unsigned short vendorID; /* connected USB device vendor ID */ + unsigned short productID; /* connected USB device product ID */ + unsigned short dev_flags; /* copy of the flags from the acceptedDevices structure */ + + int opened; /* set to != 0 if the connection is opened */ + int device_present; + int read_pending; /* set to 1 when a prime_read() has been issued and the read_completion() has not been called yet */ + int in_pipe_ref; /* pipe for reads */ + int in_pipe_bulk_size; /* max packet size of bulk packets on input */ + int out_pipe_ref; /* pipe for writes */ + int out_pipe_bulk_size; /* size of bulk packets on the out pipe (used when talking with a PalmConnect USB serial adapter) */ + + /* these provide hints about the size of the next read */ + int auto_read_size; /* if != 0, prime reads to the input pipe to get data permanently */ + int read_ahead_size; /* when waiting for big chunks of data, used as a hint to make bigger read requests */ + int last_read_ahead_size; /* also need this to properly compute the size of the next read */ + + unsigned long total_bytes_read; /* total number of bytes received since connection was opened */ + unsigned long total_bytes_written; /* total number of bytes sent since connection was opened */ + + pthread_mutex_t read_queue_mutex; + pthread_cond_t read_queue_data_avail_cond; + char *read_queue; /* stores completed reads, grows by 64k chunks */ + size_t read_queue_size; + size_t read_queue_used; + + char read_buffer[MAX_AUTO_READ_SIZE]; +} usb_connection_t; + +static usb_connection_t *usb_connections = NULL; /* linked list of active connections */ + +/* USB control requests we send to the devices + * Got them from linux/drivers/usb/serial/visor.h + */ +#define GENERIC_REQUEST_BYTES_AVAILABLE 0x01 +#define GENERIC_CLOSE_NOTIFICATION 0x02 +#define VISOR_GET_CONNECTION_INFORMATION 0x03 +#define PALM_GET_EXT_CONNECTION_INFORMATION 0x04 + +/* Structures defining the info a device returns + * Got them from linux/drivers/usb/serial/visor.h + */ +typedef struct +{ + UInt16 num_ports; + struct + { + UInt8 port_function_id; + UInt8 port; + } connections[8]; +} visor_connection_info; + +/* struct visor_connection_info.connection[x].port defines: */ +#define VISOR_ENDPOINT_1 0x01 +#define VISOR_ENDPOINT_2 0x02 + +/* struct visor_connection_info.connection[x].port_function_id defines: */ +#define VISOR_FUNCTION_GENERIC 0x00 +#define VISOR_FUNCTION_DEBUGGER 0x01 +#define VISOR_FUNCTION_HOTSYNC 0x02 +#define VISOR_FUNCTION_CONSOLE 0x03 +#define VISOR_FUNCTION_REMOTE_FILE_SYS 0x04 + +typedef struct +{ + UInt8 num_ports; + UInt8 endpoint_numbers_different; + UInt16 reserved1; + struct + { + UInt32 port_function_id; + UInt8 port; + UInt8 endpoint_info; + UInt16 reserved; + } connections[8]; +} palm_ext_connection_info; + +/* PalmConnect USB specific information + * Extracted from Linux kl5kusb105 Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de> + * Using documentation Utz-Uwe provided + */ +enum { + /* Values for KLSI_GET/SET_COMM_DESCRIPTOR */ + KLSI_BAUD_115200 = 0, + KLSI_BAUD_57600 = 1, + KLSI_BAUD_38400 = 2, + KLSI_BAUD_28800 = 3, + KLSI_BAUD_19200 = 4, + KLSI_BAUD_14400 = 5, + KLSI_BAUD_9600 = 6, + KLSI_BAUD_7200 = 7, + KLSI_BAUD_4800 = 8, + KLSI_BAUD_2400 = 9, + KLSI_BAUD_1200 = 10, + KLSI_BAUD_600 = 11, + KLSI_BAUD_230400 = 12, + + KLSI_PARITY_NONE = 0, + KLSI_PARITY_ODD = 1, + KLSI_PARITY_EVEN = 2, + KLSI_PARITY_MARK = 3, + + KLSI_STOPBITS_0 = 0, + KLSI_STOPBITS_2 = 2, + + /* Handshake values for KLSI_GET_HANDSHAKE_LINES */ + KLSI_GETHS_DCD = 0x80, /* Data Carrier Detect */ + KLSI_GETHS_RI = 0x40, /* Ring Indicator */ + KLSI_GETHS_DSR = 0x20, /* Data Set Ready */ + KLSI_GETHS_CTS = 0x10, /* Clear To Send */ + + /* Handshake values for KLST_SET_HANDSHAKE_LINES */ + KLSI_SETHS_RTS = 0x02, /* Ready To Send */ + KLSI_SETHS_DTR = 0x01, /* Data Terminal Ready */ + + /* Flow control values */ + KLSI_FLOW_USE_RTS = 0x01, /* use RTS/CTS */ + KLSI_FLOW_USE_DSR = 0x02, /* use DSR/CD */ + KLSI_FLOW_USE_XON = 0x04 /* use XON/XOFF */ +}; + +#define KLSI_GET_COMM_DESCRIPTOR 0 +#define KLSI_SET_COMM_DESCRIPTOR 1 +#define KLSI_GET_HANDSHAKE_LINES 2 +#define KLSI_SET_HANDSHAKE_LINES 3 +#define KLSI_GET_FLOWCONTROL 4 +#define KLSI_SET_FLOWCONTROL 5 + +typedef struct +{ + unsigned char DCBLength __attribute__((packed)); + unsigned char BaudRateIndex __attribute__((packed)); + unsigned char DataBits __attribute__((packed)); + unsigned char Parity __attribute__((packed)); + unsigned char StopBits __attribute__((packed)); +} klsi_port_settings; + +/* Some vendor and product codes we use */ +#define VENDOR_SONY 0x054c +#define VENDOR_KEYSPAN 0x06cd +#define VENDOR_HANDSPRING 0x082d +#define VENDOR_PALMONE 0x0830 +#define VENDOR_TAPWAVE 0x12ef +#define PRODUCT_PALMCONNECT_USB 0x0080 +#define PRODUCT_HANDSPRING_VISOR 0x0100 +#define PRODUCT_SONY_CLIE_3_5 0x0038 + +/* This table helps us determine whether a connecting USB device is + * one we'd like to talk to. Don't forget to update it as new + * devices come out. To accept ALL the devices from a vendor, add + * an entry with the vendorID and 0xFFFF as productID. + */ + +#define FLAG_ANSWERS_CONN_INFO 0x0001 /* device is known to answer connection information requests */ +#define FLAG_USE_FIRST_PAIR 0x0002 /* thanks to dumb programmers at Palm, the connection information doesn't match the actual pipes being used. If this flag is set, always try to use the first endoints pair */ +#define FLAG_USE_SECOND_PAIR 0x0004 /* ditto */ +#define FLAG_ANSWERS_PALM_CONN_INFO 0x0008 /* means that if the device doesn't answer PALM_EXT_CONNECTION_INFORMATION, don't try the visor variant (for stupid PalmOne handhelds) */ +#define FLAG_REJECT 0x8000 /* device is known but not supported yet */ + +static struct { + unsigned short vendorID; + unsigned short productID; + unsigned short flags; +} +acceptedDevices[] = { + /* Sony */ + {0x054c, 0x0038}, /* Sony Palm OS 3.5 devices, S300 */ + {0x054c, 0x0066}, /* Sony T, S320, SJ series, and other Palm OS 4.0 devices */ + {0x054c, 0x0095}, /* Sony S360 */ + {0x054c, 0x000a}, /* Sony NR and other Palm OS 4.1 devices */ + {0x054c, 0x009a}, /* Sony NR70V/U */ + {0x054c, 0x00da}, /* Sony NX */ + {0x054c, 0x00e9}, /* Sony NZ */ + {0x054c, 0x0144}, /* Sony UX */ + {0x054c, 0x0169}, /* Sony TJ */ + + /* Keyspan serial-to-USB PDA adapter */ + {0x06cd, 0x0103, FLAG_REJECT}, /* ID sent by an adapter which firmware has not been uploaded yet */ + {0x06cd, 0x0104, FLAG_REJECT}, /* ID sent by an adapter with proper firmware uploaded */ + + /* AlphaSmart */ + {0x081e, 0xdf00}, /* Dana */ + + /* HANDSPRING (vendor 0x082d) */ + {0x082d, 0x0100}, /* Visor */ + {0x082d, 0x0200}, /* Treo */ + {0x082d, 0x0300, FLAG_ANSWERS_CONN_INFO}, /* Treo 600 */ + + /* PalmOne, Palm Inc */ + {0x0830, 0x0001, FLAG_ANSWERS_CONN_INFO}, /* m500 */ + {0x0830, 0x0002, FLAG_ANSWERS_CONN_INFO}, /* m505 */ + {0x0830, 0x0003, FLAG_ANSWERS_CONN_INFO}, /* m515 */ + {0x0830, 0x0010}, + {0x0830, 0x0011}, + {0x0830, 0x0020}, /* i705 */ + {0x0830, 0x0030}, + {0x0830, 0x0031}, /* Tungsten|W */ + {0x0830, 0x0040}, /* m125 */ + {0x0830, 0x0050}, /* m130 */ + {0x0830, 0x0051}, + {0x0830, 0x0052}, + {0x0830, 0x0053}, + {0x0830, 0x0060, FLAG_ANSWERS_CONN_INFO}, /* Tungsten series, Zire 71 */ + {0x0830, 0x0061, FLAG_ANSWERS_PALM_CONN_INFO | FLAG_USE_FIRST_PAIR}, /* Zire 22, 31, 72, T|5, T|X, LifeDrive, Treo 650 -- for T|X and LD, they don't answer to the PALM_EXT_CONNECTION_INFORMATION control code. In this case we revert to using the first pair of pipes */ + {0x0830, 0x0062}, + {0x0830, 0x0063}, + {0x0830, 0x0070, FLAG_ANSWERS_CONN_INFO}, /* Zire */ + {0x0830, 0x0071}, + {0x0830, 0x0080}, /* palmOne serial adapter */ + {0x0830, 0x0099}, + {0x0830, 0x0100}, + + /* GARMIN */ + {0x091e, 0x0004}, /* IQUE 3600 */ + + /* Kyocera */ + {0x0c88, 0x0021}, /* 7135 Smartphone */ + {0x0c88, 0xa226}, /* 6035 Smartphone */ + + /* Tapwave */ + {0x12ef, 0x0100, FLAG_ANSWERS_CONN_INFO}, /* Zodiac, Zodiac2 */ + + /* ACEECA */ + {0x4766, 0x0001}, /* MEZ1000 */ + + /* Fossil */ + {0x0e67, 0x0002}, /* Abacus wrist PDA */ + + /* Samsung */ + {0x04e8, 0x8001} /* I330 */ +}; + + +/* local prototypes */ +static int change_refcount(usb_connection_t *c, int increment); +static void stop_listening(usb_connection_t *c); +static IOReturn control_request (IOUSBDeviceInterface **dev, UInt8 requestType, UInt8 request, UInt16 value, UInt16 index, void *pData, UInt16 maxReplyLength); +static void device_added (void *refCon, io_iterator_t iterator); +static void device_notification (usb_connection_t *connexion, io_service_t service, natural_t messageType, void *messageArgument); +static void read_completion (usb_connection_t *connexion, IOReturn result, void *arg0); +static int accepts_device (unsigned short vendor, unsigned short product, unsigned short *flags); +static IOReturn configure_device (IOUSBDeviceInterface **dev, unsigned short vendor, unsigned short product, unsigned short flags, int *port_number, int *input_pipe_number, int *output_pipe_number, int *pipe_info_retrieved); +static IOReturn find_interfaces (usb_connection_t *usb, IOUSBDeviceInterface **dev, unsigned short vendor, unsigned short product, unsigned short accept_flags, int port_number, int input_pipe_number, int output_pipe_number, int pipe_info_retrieved); +static int prime_read (usb_connection_t *connexion); +static IOReturn read_visor_connection_information (IOUSBDeviceInterface **dev, int *port_number, int *input_pipe, int *output_pipe); +static IOReturn decode_generic_connection_information(palm_ext_connection_info *ci, int *port_number, int *input_pipe, int *output_pipe); +static IOReturn read_generic_connection_information (IOUSBDeviceInterface **dev, int *port_number, int *input_pipe_number, int *output_pipe_number); +static IOReturn klsi_set_portspeed(IOUSBDeviceInterface **dev, int speed); + + +/***************************************************************************/ +/* */ +/* GLOBAL DARWINUSB OPTIONS FOR CLIENT CODE */ +/* */ +/***************************************************************************/ +void +darwinusb_setoptions(int multiple_connections_support) +{ + accept_multiple_simultaneous_connections = multiple_connections_support; +} + + +/***************************************************************************/ +/* */ +/* CONNECTIONS LINKED LIST MANAGEMENT */ +/* */ +/***************************************************************************/ +static void +add_connection(usb_connection_t *c) +{ + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: adding connection %p to linked list\n", c)); + pthread_mutex_lock(&usb_connections_mutex); + c->next = usb_connections; + usb_connections = c; + //pthread_cond_signal(&usb_connection_added_cond); + pthread_mutex_unlock(&usb_connections_mutex); +} + +static int +remove_connection(usb_connection_t *c) +{ + /* remove the connection from the linked list if it exists + * and return != 0. Otherwise return 0. Don't free the + * connection structure or variables. + */ + usb_connection_t *previous = NULL, *elem; + pthread_mutex_lock(&usb_connections_mutex); + elem = usb_connections; + while (elem && elem != c) + { + previous = elem; + elem = elem->next; + } + if (elem) + { + if (previous) + previous->next = elem->next; + else + usb_connections = elem->next; + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: removed connection %p from linked list\n", c)); + } + pthread_mutex_unlock(&usb_connections_mutex); + return elem != NULL; +} + +static int +device_already_in_use(IOUSBDeviceInterface **device) +{ + usb_connection_t *elem; + pthread_mutex_lock(&usb_connections_mutex); + elem = usb_connections; + while (elem != NULL && elem->device != device) + elem = elem->next; + pthread_mutex_unlock(&usb_connections_mutex); + return elem != NULL; +} + +static usb_connection_t* +connection_for_socket(pi_socket_t *ps) +{ + /* if there is no active connection associated with this socket, + * try to associate the first unassociated connection + */ + usb_connection_t *c = ((pi_usb_data_t *)ps->device->data)->ref; + if (change_refcount(c, +1) > 0) + return c; + + pthread_mutex_lock(&usb_connections_mutex); + c = usb_connections; + while (c && (c->ps != NULL || c->opened == 0 || c->total_bytes_read == 0)) /* skip connections which are being disposed of (opened=0) */ + c = c->next; + if (change_refcount(c, +1) <= 0) + c = NULL; + else + { + c->ps = ps; + ((pi_usb_data_t *)ps->device->data)->ref = c; + } + pthread_mutex_unlock(&usb_connections_mutex); + return c; +} + +static int +change_refcount(usb_connection_t *c, int increment) +{ + /* update the refcount on the connection structure. If the refcount becomes + * zero, call the stop_listening() function + */ + int rc; + if (c == NULL) + return 0; + if (pthread_mutex_lock(&c->ref_count_mutex) != 0) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: connection %p, can't lock ref_count_mutex (ref_count=%d)\n",c,c->ref_count_mutex)); + return 0; + } + rc = c->ref_count = c->ref_count + increment; + if (rc < 0) + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: connection %p's refcount became < 0 (%d)\n", c, c->ref_count)); + if (rc == 0) + { + if (remove_connection(c)) + stop_listening(c); + } + else + pthread_mutex_unlock(&c->ref_count_mutex); + return rc; +} + +/***************************************************************************/ +/* */ +/* INTERNAL ROUTINES */ +/* */ +/***************************************************************************/ +static int +start_listening(void) +{ + mach_port_t masterPort; + CFMutableDictionaryRef matchingDict; + CFRunLoopSourceRef runLoopSource; + kern_return_t kr; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: start_listening for connections\n")); + + /* first create a master_port for my task */ + kr = IOMasterPort (MACH_PORT_NULL, &masterPort); + if (kr || !masterPort) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: couldn't create a master IOKit Port(%08x)\n", kr)); + return PI_ERR_GENERIC_SYSTEM; + } + + /* Set up the matching criteria for the devices we're interested in + * Interested in instances of class IOUSBDevice and its subclasses + * Since we are supporting many USB devices, we just get notifications + * for all USB devices and sort out the ones that we want later. + */ + matchingDict = IOServiceMatching (kIOUSBDeviceClassName); + if (!matchingDict) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: can't create a USB matching dictionary\n")); + mach_port_deallocate (mach_task_self(), masterPort); + return PI_ERR_GENERIC_SYSTEM; + } + + /* Create a notification port and add its run loop event source to our run loop + * This is how async notifications get set up. + */ + usb_notify_port = IONotificationPortCreate (masterPort); + runLoopSource = IONotificationPortGetRunLoopSource (usb_notify_port); + CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); + + /* Set up a notifications to be called when a raw device is first matched by I/O Kit */ + kr = IOServiceAddMatchingNotification ( + usb_notify_port, + kIOFirstMatchNotification, + matchingDict, + device_added, + NULL, + &usb_device_added_iter); + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: added service matching notification (kr=0x%08lx)\n", kr)); + + /* Iterate once to get already-present devices and arm the notification */ + device_added (NULL, usb_device_added_iter); + + /* Now done with the master_port */ + mach_port_deallocate (mach_task_self(), masterPort); + + return 0; +} + +static void +stop_listening(usb_connection_t *c) +{ + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: stop_listening for connection %p\n",c)); + + c->opened = 0; + c->in_pipe_ref = 0; + c->out_pipe_ref = 0; + + if (c->ps) + { + /* we do this because if the connection abruptly ends before pilot-link notices, + * we want to avoid pi_close() trying to do a dlp_EndOfSync() + */ + c->ps->state = PI_SOCK_CLOSE; + if (c->ps->device != NULL && c->ps->device->data != NULL) + ((pi_usb_data_t *)c->ps->device->data)->ref = NULL; + } + c->ps = NULL; + + if (c->device_notification) + { + IOObjectRelease (c->device_notification); + c->device_notification = 0; + } + + if (c->interface) + { + (*c->interface)->USBInterfaceClose (c->interface); + (*c->interface)->Release(c->interface); + c->interface = NULL; + } + + if (c->device) + { + (*c->device)->USBDeviceClose (c->device); + (*c->device)->Release(c->device); + c->device = NULL; + } + + pthread_mutex_destroy(&c->read_queue_mutex); + pthread_mutex_destroy(&c->ref_count_mutex); + free(c); +} + +static void * +usb_thread_run(void *foo) +{ + if (start_listening() == 0) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: usb_thread_run, starting...\n")); + + /* obtain the CFRunLoop for this thread */ + pthread_mutex_lock(&usb_run_loop_mutex); + usb_run_loop = CFRunLoopGetCurrent(); + pthread_mutex_unlock(&usb_run_loop_mutex); + + /* signal main thread that init was successful */ + pthread_mutex_lock(&usb_thread_ready_mutex); + pthread_cond_broadcast(&usb_thread_ready_cond); + pthread_mutex_unlock(&usb_thread_ready_mutex); + + CFRunLoopRun(); + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: usb_thread_run, done with runloop\n")); + + pthread_mutex_lock(&usb_run_loop_mutex); + usb_run_loop = 0; + pthread_mutex_unlock(&usb_run_loop_mutex); + + if (usb_device_added_iter) + { + IOObjectRelease (usb_device_added_iter); + usb_device_added_iter = 0; + } + + if (usb_notify_port) + { + IONotificationPortDestroy(usb_notify_port); + usb_notify_port = NULL; + } + + /* decrement the refcount of each structure. If there + * was a pending read, decrement once more since + * prime_read() increments the refcount + */ + usb_connection_t *elem, *next, *prev = NULL; + pthread_mutex_lock(&usb_connections_mutex); + elem = usb_connections; + while (elem != NULL) + { + next = elem->next; + pthread_mutex_lock(&elem->ref_count_mutex); + elem->ref_count--; + if (elem->read_pending) + elem->ref_count--; + if (elem < 0) + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: while stopping usb_thread, connection %p's refcount became < 0 (%d)", elem, elem->ref_count)); + if (elem == 0) + { + if (prev != NULL) + prev->next = next; + else + usb_connections = next; + stop_listening(elem); + elem = NULL; + } + else + { + pthread_mutex_unlock(&elem->ref_count_mutex); + prev = elem; + } + } + pthread_mutex_unlock(&usb_connections_mutex); + + usb_thread = 0; + usb_run_loop = NULL; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: usb_thread_run, exited.\n")); + } + else + { + /* signal main thread that init failed */ + usb_thread = 0; + usb_run_loop = NULL; + pthread_mutex_lock(&usb_thread_ready_mutex); + pthread_cond_signal(&usb_thread_ready_cond); + pthread_mutex_unlock(&usb_thread_ready_mutex); + } + return NULL; +} + +static void +device_added (void *refCon, io_iterator_t iterator) +{ + kern_return_t kr; + io_service_t ioDevice; + IOCFPlugInInterface **plugInInterface = NULL; + IOUSBDeviceInterface **dev = NULL; + HRESULT res; + SInt32 score; + UInt16 vendor, product; + unsigned short accept_flags; + int port_number = 0xff, + input_pipe_number = 0xff, + output_pipe_number = 0xff, + pipe_info_retrieved = 0; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: device_added\n")); + + while ((ioDevice = IOIteratorNext (iterator))) + { + if (usb_connections != NULL && !accept_multiple_simultaneous_connections) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: new device plugged but we already have a running connection\n")); + IOObjectRelease (ioDevice); + continue; + } + + kr = IOCreatePlugInInterfaceForService (ioDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); + if (kr != kIOReturnSuccess || !plugInInterface) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: -> unable to create a plugin (kr=0x%08x)\n", kr)); + IOObjectRelease (ioDevice); + continue; + } + + res = (*plugInInterface)->QueryInterface (plugInInterface, CFUUIDGetUUIDBytes (kIOUSBDeviceInterfaceID), (LPVOID *)&dev); + (*plugInInterface)->Release (plugInInterface); + if (res || !dev) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: couldn't create a device interface (res=0x%08x)\n", (int) res)); + IOObjectRelease (ioDevice); + continue; + } + + /* make sure this device is not already being handled (this may happen + * with some handhelds that reconnect immediately after disconnecting, like the T5) + */ + if (device_already_in_use(dev)) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: device %p already in use, skipping it\n")); + IOObjectRelease (ioDevice); + continue; + } + + kr = (*dev)->GetDeviceVendor (dev, &vendor); + kr = (*dev)->GetDeviceProduct (dev, &product); + if (accepts_device(vendor, product, &accept_flags) == 0) + { + ULOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: not accepting device (vendor=0x%04x product=0x%04x)\n", vendor, product)); + (*dev)->Release(dev); + IOObjectRelease (ioDevice); + continue; + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: Accepted USB device, vendor: 0x%04x product: 0x%04x\n", vendor, product)); + + kr = (*dev)->USBDeviceOpen (dev); + if (kr != kIOReturnSuccess) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: unable to open device (kr=0x%08x)\n", kr)); + (*dev)->Release(dev); + IOObjectRelease (ioDevice); + continue; + } + + /* configure the device and query for its preferred I/O pipes */ + kr = configure_device (dev, vendor, product, accept_flags, &port_number, &input_pipe_number, &output_pipe_number, &pipe_info_retrieved); + if (kr != kIOReturnSuccess) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, (kr == kIOReturnNotReady) + ? "darwinusb: device not ready to synchonize\n" + : "darwinusb: unable to configure device (kr=0x%08x)\n", kr)); + (*dev)->USBDeviceClose (dev); + (*dev)->Release (dev); + IOObjectRelease (ioDevice); + continue; + } + + /* allocate and initialize the USB connection structure */ + usb_connection_t *c = malloc(sizeof(usb_connection_t)); + if (c == NULL) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "out of memory")); + (*dev)->USBDeviceClose (dev); + (*dev)->Release (dev); + IOObjectRelease (ioDevice); + break; + } + + memset(c, 0, sizeof(usb_connection_t)); + c->auto_read_size = AUTO_READ_SIZE; + c->device = dev; + c->ref_count = 1; + c->opened = 1; + c->device_present = 1; + c->vendorID = vendor; + c->productID = product; + c->dev_flags = accept_flags; + + /* try to locate the pipes we need to talk to the device */ + kr = find_interfaces(c, dev, vendor, product, accept_flags, port_number, input_pipe_number, output_pipe_number, pipe_info_retrieved); + if (kr != kIOReturnSuccess) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: unable to find interfaces (kr=0x%08x)\n", kr)); + free(c); + (*dev)->USBDeviceClose (dev); + (*dev)->Release (dev); + IOObjectRelease (ioDevice); + continue; + } + + /* Just like with service matching notifications, we need to create an event source and add it + * to our run loop in order to receive async completion notifications. + */ + CFRunLoopSourceRef runLoopSource; + kr = (*c->interface)->CreateInterfaceAsyncEventSource (c->interface, &runLoopSource); + if (kr != kIOReturnSuccess) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: Unable to create async event source (%08x)\n", kr)); + free(c); + (*dev)->USBDeviceClose (dev); + (*dev)->Release (dev); + IOObjectRelease (ioDevice); + continue; + } + CFRunLoopAddSource (CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); + + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, "darwinusb: USBConnection %p OPENED c->in_pipe_ref=%d c->out_pipe_ref=%d\n",c,c->in_pipe_ref,c->out_pipe_ref)); + + /* Register for an interest notification for this device, + * so we get notified when it goes away + */ + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: registering for disconnect notification\n")); + kr = IOServiceAddInterestNotification( + usb_notify_port, + ioDevice, + kIOGeneralInterest, + (IOServiceInterestCallback)device_notification, + (void *)c, + &c->device_notification); + IOObjectRelease(ioDevice); + + /* add the device to our linked list, then only start reading data + * (order of operations matters here to avoid race conditions) + */ + pthread_mutex_init(&c->read_queue_mutex, NULL); + pthread_mutex_init(&c->ref_count_mutex, NULL); + pthread_cond_init(&c->read_queue_data_avail_cond, NULL); + + add_connection(c); + prime_read(c); + } +} + +static IOReturn +configure_device(IOUSBDeviceInterface **di, + unsigned short vendor, + unsigned short product, + unsigned short flags, + int *port_number, + int *input_pipe_number, + int *output_pipe_number, + int *pipe_info_retrieved) +{ + UInt8 numConf, conf, deviceClass; + IOReturn kr; + IOUSBConfigurationDescriptorPtr confDesc; + + /* Get the device class. Most handhelds are registered as composite devices + * and therefore already opened & configured by OS X drivers! It seems that + * reconfiguring them as we did before is what caused some Sony devices to + * refuse talking to us. + */ + kr = (*di)->GetDeviceClass (di, &deviceClass); + if (kr != kIOReturnSuccess) + return kr; + + if (deviceClass != kUSBCompositeClass) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: Not a composite device: performing confiuration\n")); + + kr = (*di)->GetNumberOfConfigurations (di, &numConf); + if (!numConf) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: device has zero configurations!\n")); + return -1; + } + + /* try all possible configurations if the first one fails + * (shouldn't happen in most cases though) + */ + for (conf=0; conf < numConf; conf++) + { + kr = (*di)->GetConfigurationDescriptorPtr(di, 0, &confDesc); + if (kr) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: unable to get config descriptor for index %d (err=%08x numConf=%d)\n", + 0, kr, (int)numConf)); + continue; + } + + kr = (*di)->SetConfiguration(di, confDesc->bConfigurationValue); + if (kr == kIOReturnSuccess) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: successfully set configuration %d\n",(int)confDesc->bConfigurationValue)); + break; + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: unable to set configuration to value %d (err=%08x numConf=%d)\n", + (int)confDesc->bConfigurationValue, kr, (int)numConf)); + } + if (conf == numConf) + return kr; + } + + if (vendor == VENDOR_PALMONE && product == PRODUCT_PALMCONNECT_USB) + { + kr = klsi_set_portspeed(di, 9600); + *input_pipe_number = 0x01; + *output_pipe_number = 0x02; + *pipe_info_retrieved = 1; + return kr; + } + + /* Try reading pipe information. Most handhelds support a control request that returns info about the ports and + * pipes. We first try the generic control code, and if it doesn't work we try the Visor one which seems to be + * supported by some devices Also, we can detect that a T5 / LifeDrive is in "wait" mode + * (device appears on USB but not synchronizing) and in this case we return a kIOReturnNotReady code. + */ + kr = read_generic_connection_information (di, port_number, input_pipe_number, output_pipe_number); + if (kr != kIOReturnSuccess && kr != kIOReturnNotReady && !(flags & FLAG_ANSWERS_PALM_CONN_INFO)) + kr = read_visor_connection_information (di, port_number, input_pipe_number, output_pipe_number); + if (kr == kIOReturnNotReady) + return kr; + + /* With some devices (Palm) we need to hardcode the location of the pipes to use + * because the Palm engineers had the good idea to mismatch the connection information data + * and the actual pipes to use + */ + if (flags & (FLAG_USE_FIRST_PAIR | FLAG_USE_SECOND_PAIR)) + { + *pipe_info_retrieved = 1; + return kIOReturnSuccess; + } + + /* For device which we know return connection information, we want it to be returned to + * consider the device alive + */ + if (kr != kIOReturnSuccess && (flags & FLAG_ANSWERS_CONN_INFO)) + return kIOReturnNotReady; + + *pipe_info_retrieved = (kr == kIOReturnSuccess); + + /* query bytes available. Not that we really care, but most devices expect to receive this + * before they agree on talking to us. + */ + if (vendor != VENDOR_TAPWAVE) + { + unsigned char ba[2]; + kr = control_request (di, 0xc2, GENERIC_REQUEST_BYTES_AVAILABLE, 0, 0, &ba[0] , 2); + if (kr != kIOReturnSuccess) + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: GENERIC_REQUEST_BYTES_AVAILABLE failed (err=%08x)\n", kr)); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "GENERIC_REQUEST_BYTES_AVAILABLE returns 0x%02x%02x\n", ba[0], ba[1])); + } + + return kIOReturnSuccess; +} + +static IOReturn +find_interfaces(usb_connection_t *c, + IOUSBDeviceInterface **di, + unsigned short vendor, + unsigned short product, + unsigned short accept_flags, + int port_number, + int input_pipe_number, + int output_pipe_number, + int pipe_info_retrieved) +{ + IOReturn kr; + io_iterator_t iterator; + io_service_t usbInterface; + HRESULT res; + SInt32 score; + UInt8 intfClass, intfSubClass, intfNumEndpoints; + int pipeRef, pass; + IOUSBFindInterfaceRequest request; + IOCFPlugInInterface **plugInInterface = NULL; + UInt8 direction, number, transferType, interval; + UInt16 maxPacketSize; + + request.bInterfaceClass = kIOUSBFindInterfaceDontCare; + request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; + request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; + request.bAlternateSetting = kIOUSBFindInterfaceDontCare; + + kr = (*di)->CreateInterfaceIterator (di, &request, &iterator); + + while ((usbInterface = IOIteratorNext (iterator))) + { + kr = IOCreatePlugInInterfaceForService (usbInterface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); + kr = IOObjectRelease (usbInterface); // done with the usbInterface object now that I have the plugin + if (kr != kIOReturnSuccess || !plugInInterface) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: unable to create a plugin (%08x)\n", kr)); + continue; + } + + /* we have the interface plugin: we now need the interface interface */ + res = (*plugInInterface)->QueryInterface (plugInInterface, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID *) &c->interface); + (*plugInInterface)->Release (plugInInterface); /* done with this */ + if (res || c->interface == NULL) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: couldn't create an IOUSBInterfaceInterface (%08x)\n", (int) res)); + continue; + } + + /* get the interface class and subclass */ + kr = (*c->interface)->GetInterfaceClass (c->interface, &intfClass); + kr = (*c->interface)->GetInterfaceSubClass (c->interface, &intfSubClass); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: interface class %d, subclass %d\n", intfClass, intfSubClass)); + + /* Now open the interface. This will cause the pipes to be instantiated that are + * associated with the endpoints defined in the interface descriptor. + */ + kr = (*c->interface)->USBInterfaceOpen (c->interface); + if (kr != kIOReturnSuccess) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: unable to open interface (%08x)\n", kr)); + (*c->interface)->Release (c->interface); + c->interface = NULL; + continue; + } + + kr = (*c->interface)->GetNumEndpoints (c->interface, &intfNumEndpoints); + if (kr != kIOReturnSuccess) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: unable to get number of endpoints (%08x)\n", kr)); + (*c->interface)->USBInterfaceClose (c->interface); + (*c->interface)->Release (c->interface); + c->interface = NULL; + continue; + } + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: interface has %d endpoints\n", intfNumEndpoints)); + + /* If device didn't answer to the connection_information request, + * try to read a preamble sent by the device. This is sent by devices which chipsets + * don't support the vendor control endpoint requests. Look for the first pipe on + * which a preamble is available. + */ + if (!pipe_info_retrieved) + { + int reqTimeout; + int preambleFound = 0; + for (reqTimeout = 100; reqTimeout <= 300 && !preambleFound; reqTimeout += 100) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: checking for pipe_info sent by device with timeout %dms\n",reqTimeout)); + for (pipeRef = 1; pipeRef <= intfNumEndpoints; pipeRef++) + { + kr = (*c->interface)->GetPipeProperties (c->interface, pipeRef, &direction, &number, + &transferType, &maxPacketSize, &interval); + if (kr != kIOReturnSuccess) + continue; + if (direction == kUSBIn) + { + UInt32 size = sizeof(c->read_buffer)-1; + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: trying pipe %d type=%d\n", pipeRef, (int)transferType)); + if (transferType == kUSBBulk) + kr = (*c->interface)->ReadPipeTO (c->interface, pipeRef, &c->read_buffer, &size, reqTimeout, 250); + else + kr = (*c->interface)->ReadPipe (c->interface, pipeRef, &c->read_buffer, &size); + + if (kr == kIOReturnSuccess && size >= 8) + { + /* got something! */ + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: got %d bytes there!\n", (int)size)); + CHECK(PI_DBG_DEV, PI_DBG_LVL_DEBUG, pi_dumpdata(c->read_buffer, size)); + if (!memcmp(c->read_buffer, "VNDR10", 6)) + { + /* VNDR version 1.0 */ + palm_ext_connection_info ci; + memcpy(&ci, &c->read_buffer[6], sizeof(ci)); + decode_generic_connection_information(&ci, &port_number, &input_pipe_number, &output_pipe_number); + preambleFound = 1; + break; + } + } + } + } + } + } + + /* Locate the pipes we're going to use for reading and writing. + * We have four chances to find the right pipes: + * 1. If we got a hint from the device with input/output pipes, we try this one first. + * 2. If we didn't get both pipes, try using the port number hint. There is at least one recent + * device (LifeDrive) on which the port_number hint is actually an endpoint pair index. + * The code below tries to cope with that. + * 3. If we're still missing one or two pipes, give a second try looking for pipes with a + * 64 bytes transfer size + * 4. Finally of this failed, forget about the transfer size and take the first ones that + * come (i.e. Tungsten W has a 64 bytes IN pipe and a 32 bytes OUT pipe). + */ + for (pass=1; pass <= 4 && (c->in_pipe_ref==0 || c->out_pipe_ref==0); pass++) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: pass %d looking for pipes, port_number=0x%02x, input_pipe_number=0x%02x, output_pipe_number=0x%02x\n", + pass, port_number, input_pipe_number, output_pipe_number)); + c->in_pipe_ref = 0; + c->out_pipe_ref = 0; + + int input_pipes_seen = 0; + int output_pipes_seen = 0; + + for (pipeRef = 1; pipeRef <= intfNumEndpoints; pipeRef++) + { + kr = (*c->interface)->GetPipeProperties (c->interface, pipeRef, &direction, &number, + &transferType, &maxPacketSize, &interval); + if (kr != kIOReturnSuccess) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: unable to get properties of pipe %d (kr=0x%08x)\n", pipeRef, kr)); + } + else + { + int pair_index = (direction == kUSBIn) ? ++input_pipes_seen : ++output_pipes_seen; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "darwinusb: pipe %d: direction=0x%02x, number=0x%02x, transferType=0x%02x, maxPacketSize=%d, interval=0x%02x, pair_index=%d\n", + pipeRef,(int)direction,(int)number,(int)transferType,(int)maxPacketSize,(int)interval,pair_index)); + if (c->in_pipe_ref == 0 && + direction == kUSBIn && + transferType == kUSBBulk) + { + if ((pass == 1 && input_pipe_number != 0xff && number == input_pipe_number) || + (pass == 1 && port_number == 0xff && input_pipe_number == 0xff && (accept_flags & FLAG_USE_FIRST_PAIR)) || + (pass == 2 && port_number != 0xff && number == port_number) || + (pass == 3 && ((port_number != 0xff && pair_index == port_number) || (port_number == 0xff && (maxPacketSize == 64 || maxPacketSize == 512)))) || + pass == 4) + c->in_pipe_ref = pipeRef; + c->in_pipe_bulk_size = maxPacketSize; + } + else if (c->out_pipe_ref == 0 && + direction == kUSBOut && + transferType == kUSBBulk) + { + if ((pass == 1 && output_pipe_number != 0xff && number == output_pipe_number) || + (pass == 1 && port_number == 0xff && input_pipe_number == 0xff && (accept_flags & FLAG_USE_FIRST_PAIR)) || + (pass == 2 && port_number != 0xff && number == port_number) || + (pass == 3 && ((port_number != 0xff && pair_index == port_number) || (port_number == 0xff && (maxPacketSize == 64 || maxPacketSize == 512)))) || + pass == 4) + { + c->out_pipe_ref = pipeRef; + c->out_pipe_bulk_size = maxPacketSize; + } + } + } + } + } + + if (c->in_pipe_ref && c->out_pipe_ref) + return kIOReturnSuccess; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: couldn't find any suitable pipes pair on this interface\n")); + (*c->interface)->USBInterfaceClose (c->interface); + (*c->interface)->Release (c->interface); + c->interface = NULL; + c->in_pipe_ref = 0; + c->out_pipe_ref = 0; + } + + return c->interface==NULL ? -1 : kIOReturnSuccess; +} + +static IOReturn +control_request(IOUSBDeviceInterface **dev, UInt8 requestType, UInt8 request, UInt16 value, UInt16 index, void *pData, UInt16 maxReplyLength) +{ + IOReturn kr; + IOUSBDevRequest req; + void *pReply = pData; + + if (!pReply && maxReplyLength) + pReply = malloc(maxReplyLength); + + req.bmRequestType = requestType; /* i.e. 0xc2=kUSBIn, kUSBVendor, kUSBEndpoint */ + req.bRequest = request; + req.wValue = value; + req.wIndex = index; + req.wLength = maxReplyLength; + req.pData = pReply; + req.wLenDone = 0; + + kr = (*dev)->DeviceRequest (dev, &req); + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: control_request(0x%02x) wLenDone=%d kr=0x%08lx\n", (int)request, req.wLenDone, kr)); + + if (pReply && !pData) + free (pReply); + + return kr; +} + +static IOReturn +read_visor_connection_information (IOUSBDeviceInterface **dev, int *port_number, int *input_pipe, int *output_pipe) +{ + int i; + kern_return_t kr; + visor_connection_info ci; + + memset(&ci, 0, sizeof(ci)); + kr = control_request (dev, 0xc2, VISOR_GET_CONNECTION_INFORMATION, 0, 0, &ci, sizeof(ci)); + if (kr != kIOReturnSuccess) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: VISOR_GET_CONNECTION_INFORMATION failed (err=%08x)\n", kr)); + } + else + { + CHECK(PI_DBG_DEV, PI_DBG_LVL_DEBUG, pi_dumpdata((const char *)&ci, sizeof(ci))); + ci.num_ports = CFSwapInt16LittleToHost(ci.num_ports); /* number of ports is little-endian */ + if (ci.num_ports > 8) + ci.num_ports = 8; + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: VISOR_GET_CONNECTION_INFORMATION, num_ports=%d\n", ci.num_ports)); + kr = kIOReturnNotReady; + for (i=0; i < ci.num_ports; i++) + { + char *function_str; + switch (ci.connections[i].port_function_id) + { + case VISOR_FUNCTION_GENERIC: + function_str = "GENERIC"; + break; + case VISOR_FUNCTION_DEBUGGER: + function_str = "DEBUGGER"; + break; + case VISOR_FUNCTION_HOTSYNC: + function_str = "HOTSYNC"; + if (port_number) + *port_number = ci.connections[i].port; + kr = kIOReturnSuccess; + break; + case VISOR_FUNCTION_CONSOLE: + function_str = "CONSOLE"; + break; + case VISOR_FUNCTION_REMOTE_FILE_SYS: + function_str = "REMOTE_FILE_SYSTEM"; + break; + default: + function_str = "UNKNOWN"; + break; + } + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "\t[%d] port_function_id=0x%02x (%s)\n", i, ci.connections[i].port_function_id, function_str)); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "\t[%d] port=%d\n", i, ci.connections[i].port)); + } + } + return kr; +} + +static IOReturn +decode_generic_connection_information(palm_ext_connection_info *ci, int *port_number, int *input_pipe, int *output_pipe) +{ + int i; + + CHECK(PI_DBG_DEV, PI_DBG_LVL_DEBUG, pi_dumpdata((const char *)ci, sizeof(palm_ext_connection_info))); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: decode_generic_connection_information num_ports=%d, endpoint_numbers_different=%d\n", ci->num_ports, ci->endpoint_numbers_different)); + + for (i=0; i < ci->num_ports; i++) + { + UInt32 port_function_id = CFSwapInt32LittleToHost(ci->connections[i].port_function_id); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "\t[%d] port_function_id=0x%08lx ('%4.4s')\n", i, port_function_id, (char*)&port_function_id)); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "\t[%d] port=%d\n", i, ci->connections[i].port)); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "\t[%d] endpoint_info=%d (0x%02x)\n", i, ci->connections[i].endpoint_info, (int)ci->connections[i].endpoint_info)); + if (port_function_id == 'rfsL') + { + /* This is a T5 in USB connected but not synchronizing: + * don't bother trying to talk to it + */ + return kIOReturnNotReady; + } + if (port_function_id == 'sync' || port_function_id == 'ppp_') + { + /* we found the port/pipes to use for synchronization + * If endpoint_numbers_different is != 0, then the number of each + * endpoint to use for IN and OUT is stored in endpoint_info. + * Otherwise, the port number (same for both endpoints) is in + * port. + */ + if (!ci->endpoint_numbers_different) + { + if (port_number) + *port_number = ci->connections[i].port; + } + else if (ci->connections[i].endpoint_info) + { + if (input_pipe) + *input_pipe = ci->connections[i].endpoint_info >> 4; + if (output_pipe) + *output_pipe = ci->connections[i].endpoint_info & 0x0f; + } + } + } + + return kIOReturnSuccess; +} + +static IOReturn +read_generic_connection_information (IOUSBDeviceInterface **dev, int *port_number, int *input_pipe, int *output_pipe) +{ + kern_return_t kr; + palm_ext_connection_info ci; + + memset(&ci, 0, sizeof(ci)); + kr = control_request (dev, 0xc2, PALM_GET_EXT_CONNECTION_INFORMATION, 0, 0, &ci, sizeof(ci)); + if (kr != kIOReturnSuccess) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: PALM_GET_EXT_CONNECTION_INFORMATION failed (err=%08x)\n", kr)); + return kr; + } + return decode_generic_connection_information(&ci, port_number, input_pipe, output_pipe); +} + +static IOReturn +klsi_set_portspeed(IOUSBDeviceInterface **dev, int speed) +{ + /* set the comms speed for a KLSI serial adapter (PalmConnect USB) */ + kern_return_t kr; + klsi_port_settings settings = {5, KLSI_BAUD_9600, 8, KLSI_PARITY_NONE, KLSI_STOPBITS_0}; + switch (speed) + { + case 230400: settings.BaudRateIndex = KLSI_BAUD_230400; break; + case 115200: settings.BaudRateIndex = KLSI_BAUD_115200; break; + case 57600: settings.BaudRateIndex = KLSI_BAUD_57600; break; + case 38400: settings.BaudRateIndex = KLSI_BAUD_38400; break; + case 28800: settings.BaudRateIndex = KLSI_BAUD_28800; break; + case 19200: settings.BaudRateIndex = KLSI_BAUD_19200; break; + case 14400: settings.BaudRateIndex = KLSI_BAUD_14400; break; + case 9600: settings.BaudRateIndex = KLSI_BAUD_9600; break; + case 7200: settings.BaudRateIndex = KLSI_BAUD_7200; break; + case 4800: settings.BaudRateIndex = KLSI_BAUD_4800; break; + case 2400: settings.BaudRateIndex = KLSI_BAUD_2400; break; + case 1200: settings.BaudRateIndex = KLSI_BAUD_1200; break; + case 600: settings.BaudRateIndex = KLSI_BAUD_600; break; + default: break; + } + + kr = control_request(dev, 0x40, KLSI_SET_COMM_DESCRIPTOR, 0, 0, &settings, 5); + if (kr == kIOReturnSuccess) + { + kr = control_request(dev, 0x40, KLSI_SET_COMM_DESCRIPTOR, 0, 0, &settings, 5); + if (kr == kIOReturnSuccess) + kr = control_request(dev, 0x40, KLSI_SET_FLOWCONTROL, (speed > 9600) ? KLSI_FLOW_USE_RTS : 0, 0, NULL, 0); + + control_request(dev, 0x40, KLSI_SET_HANDSHAKE_LINES, KLSI_SETHS_DTR | KLSI_SETHS_RTS, 0, NULL, 0); + } + return kr; +} + +static void +device_notification(usb_connection_t *c, io_service_t service, natural_t messageType, void *messageArgument) +{ + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: device_notification (c=%p messageType=0x%08lx)\n", c, messageType)); + + if (messageType == kIOMessageServiceIsTerminated && c != NULL) + { + c->device_present = 0; + c->opened = 0; /* so that stop_listening() does'nt try to send the control_request */ + if (change_refcount(c,-1) > 0) + { + /* In case the reading thread is waiting for data, + * we need to raise the usb_data_available cond once. + * since darwin_usb_read tests usb.opened, it will + * gracefully exit during a data wait. + */ + ULOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: device_notification signaling c->read_queue_data_avail_cond for c=%p\n",c)); + pthread_mutex_lock (&c->read_queue_mutex); + pthread_cond_signal (&c->read_queue_data_avail_cond); + pthread_mutex_unlock (&c->read_queue_mutex); + } + } +} + +static void +read_completion (usb_connection_t *c, IOReturn result, void *arg0) +{ + size_t bytes_read = (size_t) arg0; + + ULOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: read_completion(c=%p, result=0x%08lx, bytes_read=%d)\n", c, (long)result, bytes_read)); + + if (!c->opened) + { + change_refcount(c, -1); + return; + } + + if (result != kIOReturnSuccess) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, "darwinusb: async read completion(%p) received error code 0x%08x\n", c, result)); + } + + if (bytes_read) + { + if (c->vendorID == VENDOR_PALMONE && c->productID == PRODUCT_PALMCONNECT_USB) + { + /* decode PalmConnect USB frame */ + if (bytes_read < 2) + bytes_read = 0; + else + { + int data_size = (int)c->read_buffer[0] | ((int)c->read_buffer[1] << 8); + if ((data_size + 2) > bytes_read) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: invalid PalmConnect packet (%d bytes, says %d content bytes)\n", + bytes_read, data_size)); + bytes_read = 0; + } else { + memmove(&c->read_buffer[0], &c->read_buffer[2], data_size); + bytes_read = data_size; + } + } + } + if (bytes_read > 0) + { + pthread_mutex_lock(&c->read_queue_mutex); + if (c->read_queue == NULL) + { + c->read_queue_size = ((bytes_read + 0xfffe) & ~0xffff) - 1; /* 64k chunks */ + c->read_queue = (char *) malloc (c->read_queue_size); + c->read_queue_used = 0; + } + else if ((c->read_queue_used + bytes_read) > c->read_queue_size) + { + c->read_queue_size += ((bytes_read + 0xfffe) & ~0xffff) - 1; + c->read_queue = (char *) realloc (c->read_queue, c->read_queue_size); + } + if (c->read_queue) + { + memcpy(c->read_queue + c->read_queue_used, c->read_buffer, bytes_read); + c->read_queue_used += bytes_read; + ULOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: signaling c->read_queue_data_avail_cond for c=%p\n",c)); + pthread_cond_signal(&c->read_queue_data_avail_cond); + } + else + { + c->read_queue_used = 0; + c->read_queue_size = 0; + } + pthread_mutex_unlock(&c->read_queue_mutex); + + if (c->total_bytes_read == 0) + { + /* the connection is now considered live */ + pthread_mutex_lock(&usb_connections_mutex); + pthread_cond_signal(&usb_connection_added_cond); + pthread_mutex_unlock(&usb_connections_mutex); + } + c->total_bytes_read += (unsigned long)bytes_read; + } + } + + if (result != kIOReturnAborted && c->opened && usb_run_loop) + { + if (result != kIOReturnSuccess) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: clearing input pipe stall\n")); + (*c->interface)->ClearPipeStallBothEnds (c->interface, c->in_pipe_ref); + } + prime_read(c); + } + + change_refcount(c, -1); +} + +static int +prime_read(usb_connection_t *c) +{ + /* increment refcount */ + if (pthread_mutex_lock(&c->ref_count_mutex) != 0) + { + /* c became invalid? */ + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: prime_read(%p): can't lock c->ref_count_mutex (structure freed?)\n", c)); + return 0; + } + c->ref_count++; + pthread_mutex_unlock(&c->ref_count_mutex); + + if (c->opened) + { + /* select a correct read size (always use a multiple of the USB packet size) */ + if (c->vendorID == VENDOR_PALMONE && c->productID == PRODUCT_PALMCONNECT_USB) + { + /* with PalmConnect USB, always use 64 bytes */ + c->last_read_ahead_size = 64; + } + else + { + c->last_read_ahead_size = c->read_ahead_size & ~(c->in_pipe_bulk_size-1); + if (c->last_read_ahead_size <= 0) + c->last_read_ahead_size = c->auto_read_size; + if (c->last_read_ahead_size > MAX_AUTO_READ_SIZE) + c->last_read_ahead_size = MAX_AUTO_READ_SIZE; + else if (c->last_read_ahead_size < c->in_pipe_bulk_size) + c->last_read_ahead_size = c->in_pipe_bulk_size; // USB packet size + } + + ULOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: prime_read(%p) for %d bytes\n", c, c->last_read_ahead_size)); + + IOReturn kr = (*c->interface)->ReadPipeAsyncTO (c->interface, c->in_pipe_ref, + c->read_buffer, c->last_read_ahead_size, 5000, 5000, (IOAsyncCallback1)&read_completion, (void *)c); + + if (kr == kIOUSBPipeStalled || kr == kIOUSBTransactionTimeout || kr == kIOUSBDataToggleErr) + { + // this code may be removed later as we are now using ReadPipeAsyncTO which is not + // supposed to return them (it calls the completion callback instead) + ULOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: stalled -- clearing stall and re-priming\n")); + (*c->interface)->ClearPipeStall (c->interface, c->in_pipe_ref); + kr = (*c->interface)->ReadPipeAsyncTO (c->interface, c->in_pipe_ref, + c->read_buffer, c->last_read_ahead_size, 5000, 5000, (IOAsyncCallback1)&read_completion, (void *)c); + } + if (kr == kIOReturnSuccess) + { + c->read_pending = 1; + return 1; + } + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: prime_read(%p): ReadPipeAsync returned error 0x%08x\n", c, kr)); + } + + change_refcount(c, -1); + return 0; +} + +static int +accepts_device(unsigned short vendor, unsigned short product, unsigned short *flags) +{ + int i; + for (i=0; i < (int)(sizeof(acceptedDevices) / sizeof(acceptedDevices[0])); i++) + { + if (vendor == acceptedDevices[i].vendorID) + { + if (acceptedDevices[i].flags & FLAG_REJECT) + return 0; + if (acceptedDevices[i].productID == 0xffff || product == acceptedDevices[i].productID) + { + if (flags) + *flags = acceptedDevices[i].flags; + return 1; + } + } + } + return 0; +} + + +/***************************************************************************/ +/* */ +/* ENTRY POINTS CALLED BY LIBPISOCK */ +/* */ +/***************************************************************************/ +static int +u_flush(pi_socket_t *ps, int flags) +{ + usb_connection_t *c = ((pi_usb_data_t *)ps->device->data)->ref; + if (change_refcount(c, +1) <= 0) + return PI_ERR_SOCK_DISCONNECTED; + if (!c->opened) + { + change_refcount(c, -1); + return PI_ERR_SOCK_DISCONNECTED; + } + if (flags & PI_FLUSH_INPUT) + { + pthread_mutex_lock(&c->read_queue_mutex); + c->read_queue_used = 0; + pthread_mutex_unlock(&c->read_queue_mutex); + } + change_refcount(c, -1); + return 0; +} + +static int +u_open(struct pi_socket *ps, struct pi_sockaddr *addr, size_t addrlen) +{ + pthread_mutex_lock(&usb_thread_ready_mutex); + if (usb_thread == 0) + { + /* thread doesn't exist yet: create it and wait for + * the init phase to be either successful or failed + */ + pthread_create(&usb_thread, NULL, usb_thread_run, NULL); + pthread_cond_wait(&usb_thread_ready_cond, &usb_thread_ready_mutex); + pthread_mutex_unlock(&usb_thread_ready_mutex); + if (usb_thread != 0) + return 1; + + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + } + pthread_mutex_unlock(&usb_thread_ready_mutex); + return 1; +} + +static int +u_close(struct pi_socket *ps) +{ + usb_connection_t *c = ((pi_usb_data_t *)ps->device->data)->ref; + ULOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: u_close(ps=%p c=%p\n",ps,c)); + if (c && change_refcount(c, 1) > 0) + { + // @@@ TODO: for KLSI, we should set total_bytes_read to 0 so that next time we receive data, + // @@@ a new connection is declared `live' + //if (c->vendorID == VENDOR_PALMONE && c->productID == PRODUCT_PALMCONNECT_USB) + // control_request(c->device, 0x40, KLSI_SET_HANDSHAKE_LINES, KLSI_SETHS_RTS, 0, NULL, 0); + + c->opened = 0; /* set opened to 0 so that other threads don't try to acquire this connection, as it is on the way out */ + c->total_bytes_read = 0; + c->total_bytes_written = 0; + c->ps = NULL; + change_refcount(c, -2); /* decrement current refcount + disconnect */ + } + return close(ps->sd); +} + +static int +u_wait_for_device(struct pi_socket *ps, int *timeout) +{ + usb_connection_t *c = connection_for_socket(ps); + struct timespec to, to_expiration; + + ULOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: u_wait_for_device(ps=%p c=%p, timeout=%d)\n",ps,c,timeout ? *timeout : 0)); + + if (timeout && *timeout) + { + pi_timeout_to_timespec(*timeout, &to_expiration); + to.tv_sec = *timeout / 1000; + to.tv_nsec = (*timeout % 1000) * 1000 * 1000; + } + + if (c == NULL) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: u_wait_for_device -> waiting for a connection to come up\n")); + pthread_mutex_lock(&usb_connections_mutex); + if (timeout && *timeout) + { + if (pthread_cond_timedwait_relative_np(&usb_connection_added_cond, &usb_connections_mutex, &to) == ETIMEDOUT) +// if (pthread_cond_timedwait(&usb_connection_added_cond, &usb_connections_mutex, &when) == ETIMEDOUT) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: u_wait_for_device -> connection wait timed out\n")); + pthread_mutex_unlock(&usb_connections_mutex); + return PI_ERR_SOCK_TIMEOUT; + } + } + else + pthread_cond_wait(&usb_connection_added_cond, &usb_connections_mutex); + pthread_mutex_unlock(&usb_connections_mutex); + + c = connection_for_socket(ps); + + ULOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: u_wait_for_device -> end of wait, c=%p\n",c)); + if (c && c->vendorID==VENDOR_PALMONE && c->productID==PRODUCT_PALMCONNECT_USB) + { + /* when working with a PalmConnect USB, make sure we use the right speed + * then let the adapter send us data + */ + klsi_set_portspeed(c->device, ((pi_usb_data_t *)ps->device->data)->rate); + } + + if (timeout && *timeout) + { + /* if there was a timeout, compute the remaining timeout time */ + *timeout = pi_timespec_to_timeout(&to_expiration); + } + } + return (c != NULL); +} + +static int +u_poll(struct pi_socket *ps, int timeout) +{ + usb_connection_t *c = connection_for_socket(ps); + if (c == NULL) + return PI_ERR_SOCK_DISCONNECTED; + + struct timespec to; + + ULOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: u_poll(ps=%p c=%p, timeout=%d)\n",ps,c,timeout)); + + if (timeout) + { + to.tv_sec = timeout / 1000; + to.tv_nsec = (timeout % 1000) * 1000 * 1000; + } + + pthread_mutex_lock(&c->read_queue_mutex); + int available = c->read_queue_used; + if (!available) + { + ULOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: u_poll -> waiting data to be available for c=%p\n",c)); + if (timeout) + { + if (pthread_cond_timedwait_relative_np(&c->read_queue_data_avail_cond, &c->read_queue_mutex, &to) == ETIMEDOUT) + { + ULOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: u_poll -> data wait timed out\n")); + available = PI_ERR_SOCK_TIMEOUT; + } + else + available = c->read_queue_used; + } + else + { + /* wait forever for some data to arrive */ + pthread_cond_wait(&c->read_queue_data_avail_cond, &c->read_queue_mutex); + available = c->read_queue_used; + } + } + pthread_mutex_unlock(&c->read_queue_mutex); + change_refcount(c, -1); + + ULOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: u_poll -> end, c=%p, result=%d\n",c,available)); + + return available; +} + +static ssize_t +u_write(struct pi_socket *ps, const unsigned char *buf, size_t len, int flags) +{ + IOReturn kr; + size_t transferred_bytes = 0, + data_size; + usb_connection_t *c = ((pi_usb_data_t *)ps->device->data)->ref; + if (change_refcount(c,+1)<=0 || !c->opened) + { + /* make sure we report broken connections */ + if (ps->state == PI_SOCK_CONN_ACCEPT || ps->state == PI_SOCK_CONN_INIT) + ps->state = PI_SOCK_CONN_BREAK; + change_refcount(c, -1); + return PI_ERR_SOCK_DISCONNECTED; + } + + ULOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: u_write(ps=%p, c=%p, len=%d, flags=%d)\n",ps,c,(int)len,flags)); + + if (c->vendorID == VENDOR_PALMONE && c->productID == PRODUCT_PALMCONNECT_USB) + { + /* format packets for the PalmConnect USB adapter */ + unsigned char *packet = malloc(c->out_pipe_bulk_size); + if (packet == NULL) + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + + while (len > 0) + { + data_size = len; + if (data_size > (size_t)(c->out_pipe_bulk_size - 2)) + data_size = (size_t)(c->out_pipe_bulk_size - 2); + packet[0] = data_size; + packet[1] = data_size >> 8; + memcpy(&packet[2], &buf[transferred_bytes], data_size); + + kr = (*c->interface)->WritePipeTO(c->interface, c->out_pipe_ref, packet, c->out_pipe_bulk_size, 5000, 5000); + if (kr != kIOReturnSuccess) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: darwin_usb_write(): WritePipe returned kr=0x%08lx\n", kr)); + break; + } + + c->total_bytes_written += (unsigned long)data_size; + transferred_bytes += data_size; + len -= data_size; + } + free(packet); + } + else + { + kr = (*c->interface)->WritePipeTO(c->interface, c->out_pipe_ref, (void *)buf, len, 5000, 5000); + if (kr != kIOReturnSuccess) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "darwinusb: darwin_usb_write(): WritePipe returned kr=0x%08lx\n", kr)); + } + else + { + c->total_bytes_written += (unsigned long)len; + transferred_bytes = len; + } + } + + if (change_refcount(c, -1) <= 0) + return PI_ERR_SOCK_DISCONNECTED; + + return transferred_bytes; +} + +static ssize_t +u_read(struct pi_socket *ps, pi_buffer_t *buf, size_t len, int flags) +{ + int timeout = ((struct pi_usb_data *)ps->device->data)->timeout; + int timed_out = 0; + usb_connection_t *c = ((pi_usb_data_t *)ps->device->data)->ref; + + if (change_refcount(c,+1)<=0 || !c->opened) + { + /* make sure we report broken connections */ + if (ps->state == PI_SOCK_CONN_ACCEPT || ps->state == PI_SOCK_CONN_INIT) + ps->state = PI_SOCK_CONN_BREAK; + if (c != NULL) + change_refcount(c, -1); + return PI_ERR_SOCK_DISCONNECTED; + } + + if (pi_buffer_expect (buf, len) == NULL) + { + errno = ENOMEM; + change_refcount(c, -1); + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + +#ifdef DEBUG_USB + struct timeval startTime, endTime; + gettimeofday(&startTime, NULL); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: u_read(ps=%p, c=%p, len=%d, timeout=%d, flags=%d)\n", ps, c, (int)len, timeout, flags)); +#endif + + pthread_mutex_lock(&c->read_queue_mutex); + + if (flags == PI_MSG_PEEK && len > 256) + len = 256; + + if (c->read_queue_used < len) + { + struct timeval now; + struct timespec when; + gettimeofday(&now, NULL); + when.tv_sec = now.tv_sec + timeout / 1000; + when.tv_nsec = now.tv_usec + (timeout % 1000) * 1000 * 1000; + if (when.tv_nsec >= 1000000000) + { + when.tv_nsec -= 1000000000; + when.tv_sec++; + } + do + { + /* next prime_read() will use a bigger read request */ + c->read_ahead_size = len - c->read_queue_used - c->last_read_ahead_size; + if (timeout) + { + if (pthread_cond_timedwait(&c->read_queue_data_avail_cond, &c->read_queue_mutex, &when) == ETIMEDOUT) + { + timed_out = 1; + break; + } + } + else + pthread_cond_wait(&c->read_queue_data_avail_cond, &c->read_queue_mutex); + } + while (c->opened && (c->read_queue_used < len || (flags == PI_MSG_PEEK && c->read_queue_used >= 256))); + + c->read_ahead_size = 0; + } + + if (!c->opened) + { + /* make sure we report broken connections */ + if (ps->state == PI_SOCK_CONN_ACCEPT || ps->state == PI_SOCK_CONN_INIT) + ps->state = PI_SOCK_CONN_BREAK; + len = PI_ERR_SOCK_DISCONNECTED; + } + else + { + if (c->read_queue_used < len) + len = c->read_queue_used; + + if (len) + { + pi_buffer_append (buf, c->read_queue, len); + + if (flags != PI_MSG_PEEK) + { + c->read_queue_used -= len; + if (c->read_queue_used > 0) + memmove(c->read_queue, c->read_queue + len, c->read_queue_used); + if ((c->read_queue_size - c->read_queue_used) > (16L * 65535L)) + { + /* if we have more than 1M free in the read queue, we'd better + * shrink the buffer + */ + c->read_queue_size = ((c->read_queue_used + 0xfffe) & ~0xffff) - 1; + c->read_queue = (char *) realloc (c->read_queue, c->read_queue_size); + } + } + } + else if (timed_out) + len = PI_ERR_SOCK_TIMEOUT; + } + +#ifdef DEBUG_USB + double a,b; + gettimeofday(&endTime, NULL); + a = (double)startTime.tv_sec + (double)startTime.tv_usec / (double)1000000; + b = (double)endTime.tv_sec + (double)endTime.tv_usec / (double)1000000; + if (len >= 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: -> u_read complete (bytes_read=%d, remaining bytes in queue=%d) in %.06fs\n", + len, c->read_queue_used,b-a)); + } else { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: -> u_read end with error (err=%d) in %.06fs\n", + len,b-a)); + } +#endif + + pthread_mutex_unlock(&c->read_queue_mutex); + if (change_refcount(c, -1) <= 0) + len = PI_ERR_SOCK_DISCONNECTED; + return len; +} + +static int +u_changebaud(pi_socket_t *ps) +{ + /* Change the baud rate. This is only useful for serial-to-USB adapters, + * as these adapters need to know which rate we use to talk to the device. + * We currently only support the PalmConnect USB adapter. + */ + pi_usb_data_t *data = (pi_usb_data_t *)ps->device->data; + usb_connection_t *c = data->ref; + if (c == NULL) + return PI_ERR_SOCK_DISCONNECTED; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "darwinusb: u_changebaud(ps=%p, c=%p, rate=%d)\n", ps, c, data->rate)); + + if (c->vendorID == VENDOR_PALMONE && c->productID == PRODUCT_PALMCONNECT_USB) + return klsi_set_portspeed(c->device, data->rate); + + return 0; +} + +void +pi_usb_impl_init (struct pi_usb_impl *impl) +{ + impl->open = u_open; + impl->close = u_close; + impl->write = u_write; + impl->read = u_read; + impl->flush = u_flush; + impl->poll = u_poll; + impl->wait_for_device = u_wait_for_device; + impl->changebaud = u_changebaud; + impl->control_request = NULL; /* that is, until we factor out common code */ +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/datebook.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/datebook.c new file mode 100644 index 00000000..47b9063d --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/datebook.c @@ -0,0 +1,485 @@ +/* + * $Id: datebook.c,v 1.36 2006/11/22 22:52:25 adridg Exp $ + * + * datebook.c: Translate Pilot datebook data formats + * + * Copyright (c) 1996, Kenneth Albanowski + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include "pi-macros.h" +#include "pi-datebook.h" + +#define alarmFlag 64 +#define repeatFlag 32 +#define noteFlag 16 +#define exceptFlag 8 +#define descFlag 4 + +char *DatebookAlarmTypeNames[] = { "Minutes", "Hours", "Days", NULL }; + +char *DatebookRepeatTypeNames[] = + { "None", "Daily", "Weekly", "MonthlyByDay", "MonthlyByDate", "Yearly", + NULL +}; + +/* dom1stSun = REM Sun 1 + dom1stMon = Rem Mon 1 + dom2ndSun = REM Sun 8 + domLastSun = REM Sun 1 -7 */ + +/*********************************************************************** + * + * Function: free_Appointment + * + * Summary: Frees members of the appointment structure + * + * Parameters: Appointment_t* + * + * Returns: void + * + ***********************************************************************/ +void +free_Appointment(Appointment_t *a) +{ + if (a->exception != NULL) { + free(a->exception); + a->exception = NULL; + } + + if (a->description != NULL) { + free(a->description); + a->description = NULL; + } + + if (a->note != NULL) { + free(a->note); + a->note = NULL; + } +} + +/*********************************************************************** + * + * Function: unpack_Appointment + * + * Summary: Fill in the appointment structure based on the raw + * record data + * + * Parameters: Appointment_t*, pi_buffer_t * of buffer, datebook type + * + * Returns: -1 on fail, 0 on success + * + ***********************************************************************/ +int +unpack_Appointment(Appointment_t *a, const pi_buffer_t *buf, datebookType type) +{ + int iflags, + j, + destlen; + unsigned char *p2; + unsigned long d; + + + /* Note: There are possible timezone conversion problems related to + the use of the begin, end, repeatEnd, and exception[] members of + a struct Appointment. As they are kept in local (wall) time in + struct tm's, the timezone of the Pilot is irrelevant, _assuming_ + that any UNIX program keeping time in time_t's converts them to + the correct local time. If the Pilot is in a different timezone + than the UNIX box, it may not be simple to deduce that correct + (desired) timezone. + + The easiest solution is to keep apointments in struct tm's, and + out of time_t's. Of course, this might not actually be a help if + you are constantly darting across timezones and trying to keep + appointments. + -- KJA */ + + destlen = 8; + + if (type != datebook_v1) + return -1; + + if (buf == NULL || buf->data == NULL || buf->used < destlen) + return -1; + + a->begin.tm_hour = get_byte(buf->data); + a->begin.tm_min = get_byte(buf->data + 1); + a->begin.tm_sec = 0; + d = (unsigned short int) get_short(buf->data + 4); + a->begin.tm_year = (d >> 9) + 4; + a->begin.tm_mon = ((d >> 5) & 15) - 1; + a->begin.tm_mday = d & 31; + a->begin.tm_isdst = -1; + a->end = a->begin; + + a->end.tm_hour = get_byte(buf->data + 2); + a->end.tm_min = get_byte(buf->data + 3); + + if (get_short(buf->data) == 0xffff) { + a->event = 1; + a->begin.tm_hour = 0; + a->begin.tm_min = 0; + a->end.tm_hour = 0; + a->end.tm_min = 0; + } else { + a->event = 0; + } + + mktime(&a->begin); + mktime(&a->end); + + iflags = get_byte(buf->data + 6); + + /* buf->data+7 is gapfill */ + + p2 = (unsigned char *) buf->data + 8; + + if (iflags & alarmFlag) { + a->alarm = 1; + a->advance = get_byte(p2); + p2 += 1; + a->advanceUnits = get_byte(p2); + p2 += 1; + + } else { + a->alarm = 0; + a->advance = 0; + a->advanceUnits = 0; + } + + if (iflags & repeatFlag) { + int i, + on; + + a->repeatType = (enum repeatTypes) get_byte(p2); + p2 += 2; + d = (unsigned short int) get_short(p2); + p2 += 2; + if (d == 0xffff) + a->repeatForever = 1; /* repeatEnd is invalid */ + else { + a->repeatEnd.tm_year = (d >> 9) + 4; + a->repeatEnd.tm_mon = ((d >> 5) & 15) - 1; + a->repeatEnd.tm_mday = d & 31; + a->repeatEnd.tm_min = 0; + a->repeatEnd.tm_hour = 0; + a->repeatEnd.tm_sec = 0; + a->repeatEnd.tm_isdst = -1; + mktime(&a->repeatEnd); + a->repeatForever = 0; + } + a->repeatFrequency = get_byte(p2); + p2++; + on = get_byte(p2); + p2++; + a->repeatDay = (enum DayOfMonthType) 0; + for (i = 0; i < 7; i++) + a->repeatDays[i] = 0; + + if (a->repeatType == repeatMonthlyByDay) + a->repeatDay = (enum DayOfMonthType) on; + else if (a->repeatType == repeatWeekly) + for (i = 0; i < 7; i++) + a->repeatDays[i] = !!(on & (1 << i)); + a->repeatWeekstart = get_byte(p2); + p2++; + p2++; + } else { + int i; + + a->repeatType = (enum repeatTypes) 0; + a->repeatForever = 1; /* repeatEnd is invalid */ + a->repeatFrequency = 0; + a->repeatDay = (enum DayOfMonthType) 0; + for (i = 0; i < 7; i++) + a->repeatDays[i] = 0; + a->repeatWeekstart = 0; + } + + if (iflags & exceptFlag) { + a->exceptions = get_short(p2); + p2 += 2; + a->exception = malloc(sizeof(struct tm) * a->exceptions); + + for (j = 0; j < a->exceptions; j++, p2 += 2) { + d = (unsigned short int) get_short(p2); + a->exception[j].tm_year = (d >> 9) + 4; + a->exception[j].tm_mon = ((d >> 5) & 15) - 1; + a->exception[j].tm_mday = d & 31; + a->exception[j].tm_hour = 0; + a->exception[j].tm_min = 0; + a->exception[j].tm_sec = 0; + a->exception[j].tm_isdst = -1; + mktime(&a->exception[j]); + } + + } else { + a->exceptions = 0; + a->exception = 0; + } + + if (iflags & descFlag) { + a->description = strdup((char *)p2); + p2 += strlen((char *)p2) + 1; + } else + a->description = 0; + + if (iflags & noteFlag) { + a->note = strdup((char *)p2); + p2 += strlen((char *)p2) + 1; + } else { + a->note = 0; + } + return 0; +} + +/*********************************************************************** + * + * Function: pack_Appointment + * + * Summary: Fill in the raw appointment record data based on the + * appointment structure. + * + * Parameters: Appointment_t*, pi_buffer_t*, datebook database version + * from the datebookType enumeration -- only v1 is supported + * for now. + * + * Returns: -1 on error (bad arguments, mostyle) or 0 on success. + * The buffer is sized to accomodate the required data. + * + ***********************************************************************/ +int +pack_Appointment(const Appointment_t *a, pi_buffer_t *buf, datebookType type) +{ + int iflags, + destlen = 8; + char *pos; + + if (a == NULL || buf == NULL) + return -1; + + if (type != datebook_v1) + return -1; + + if (a->alarm) + destlen += 2; + if (a->repeatType) + destlen += 8; + if (a->exceptions) + destlen += 2 + 2 * a->exceptions; + if (a->note) + destlen += strlen(a->note) + 1; + if (a->description) + destlen += strlen(a->description) + 1; + + pi_buffer_expect (buf, destlen); + buf->used = destlen; + + set_byte(buf->data, a->begin.tm_hour); + set_byte(buf->data + 1, a->begin.tm_min); + set_byte(buf->data + 2, a->end.tm_hour); + set_byte(buf->data + 3, a->end.tm_min); + set_short(buf->data + 4, + ((a-> + begin.tm_year - 4) << 9) | ((a->begin.tm_mon + + 1) << 5) | a->begin. + tm_mday); + + if (a->event) { + set_long(buf->data, 0xffffffff); + } + + iflags = 0; + + pos = (char *) buf->data + 8; + + if (a->alarm) { + iflags |= alarmFlag; + + set_byte(pos, a->advance); + set_byte(pos + 1, a->advanceUnits); + pos += 2; + } + + if (a->repeatType) { + int i, + on; + + iflags |= repeatFlag; + + if (a->repeatType == repeatMonthlyByDay) + on = a->repeatDay; + else if (a->repeatType == repeatWeekly) { + on = 0; + for (i = 0; i < 7; i++) + if (a->repeatDays[i]) + on |= 1 << i; + } else + on = 0; + + set_byte(pos, a->repeatType); + set_byte(pos + 1, 0); + pos += 2; + + if (a->repeatForever) + set_short(pos, 0xffff); + else + set_short(pos, + ((a-> + repeatEnd.tm_year - + 4) << 9) | ((a->repeatEnd.tm_mon + + 1) << 5) | a->repeatEnd. + tm_mday); + + pos += 2; + + set_byte(pos, a->repeatFrequency); + pos++; + set_byte(pos, on); + pos++; + set_byte(pos, a->repeatWeekstart); + pos++; + set_byte(pos, 0); + pos++; + } + + if (a->exceptions) { + int i; + + iflags |= exceptFlag; + + set_short(pos, a->exceptions); + pos += 2; + + for (i = 0; i < a->exceptions; i++, pos += 2) + set_short(pos, + ((a-> + exception[i].tm_year - + 4) << 9) | ((a->exception[i].tm_mon + + 1) << 5) | a-> + exception[i].tm_mday); + } + + if (a->description != NULL) { + iflags |= descFlag; + + strcpy(pos, a->description); + pos += strlen(pos) + 1; + } + + if (a->note != NULL) { + iflags |= noteFlag; + + strcpy(pos, a->note); + pos += strlen(pos) + 1; + } + + set_byte(buf->data + 6, iflags); + set_byte(buf->data + 7, 0); /* gapfill */ + + return 0; +} + +/*********************************************************************** + * + * Function: unpack_AppointmentAppInfo + * + * Summary: Fill in the app info structure based on the raw app + * info data + * + * Parameters: AppointmentAppInfo_t*, char* to record, record length + * + * Returns: The necessary length of the buffer if record is NULL, + * or 0 on error, the length of the data used from the + * buffer otherwise + * + ***********************************************************************/ +int +unpack_AppointmentAppInfo(AppointmentAppInfo_t *ai, + const unsigned char *record, size_t len) +{ + int i; + + i = unpack_CategoryAppInfo(&ai->category, record, len); + if (!i) + return 0; + record += i; + len -= i; + if (len < 2) + return 0; + ai->startOfWeek = get_byte(record); + return i + 2; +} + +/*********************************************************************** + * + * Function: pack_AppointmentAppInfo + * + * Summary: Fill in the raw app info record data based on the app + * info structure + * + * Parameters: AppointmentAppInfo*, char* to buffer, buffer length + * + * Returns: The length of the buffer required if record is NULL, + * or 0 on error, the length of the data used from the + * buffer otherwise + * + ***********************************************************************/ +int +pack_AppointmentAppInfo(const AppointmentAppInfo_t *ai, + unsigned char *record, size_t len) +{ + int i; + unsigned char *start = record; + + i = pack_CategoryAppInfo(&ai->category, record, len); + if (!record) + return i + 2; + if (!i) + return i; + record += i; + len -= i; + if (len < 2) + return 0; + set_short(record, 0); + set_byte(record, ai->startOfWeek); + record += 2; + + return (record - start); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/debug.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/debug.c new file mode 100644 index 00000000..8f27c694 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/debug.c @@ -0,0 +1,242 @@ +/* + * $Id: debug.c,v 1.16 2006/10/12 14:21:22 desrod Exp $ + * + * debug.c: Pilot-Link debug configuration and debug logging + * + * Copyright (c) 1996, Anonymous + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> + +#include "pi-debug.h" +#include "pi-threadsafe.h" + +static int debug_types = PI_DBG_NONE; +static int debug_level = PI_DBG_LVL_NONE; +static FILE *debug_file = NULL; +static PI_MUTEX_DEFINE(logfile_mutex); + +/*********************************************************************** + * + * Function: pi_debug_get_types + * + * Summary: fetches the current debug types configuration + * + * Parameters: void + * + * Returns: debug_types + * + ***********************************************************************/ +int +pi_debug_get_types (void) +{ + return debug_types; +} + + +/*********************************************************************** + * + * Function: pi_debug_set_types + * + * Summary: sets the debug_types configuration + * + * Parameters: types + * + * Returns: void + * + ***********************************************************************/ +void +pi_debug_set_types (int types) +{ + debug_types = types; +} + + +/*********************************************************************** + * + * Function: pi_debug_get_types + * + * Summary: fetches the current debug level configuration + * + * Parameters: void + * + * Returns: debug_level + * + ***********************************************************************/ +int +pi_debug_get_level (void) +{ + return debug_level; +} + + +/*********************************************************************** + * + * Function: pi_debug_set_level + * + * Summary: sets the debug_level configuration + * + * Parameters: level + * + * Returns: void + * + ***********************************************************************/ +void +pi_debug_set_level (int level) +{ + pi_mutex_lock(&logfile_mutex); + debug_level = level; + pi_mutex_unlock(&logfile_mutex); +} + +/*********************************************************************** + * + * Function: pi_debug_set_file + * + * Summary: sets the debug log file configuration + * + * Parameters: char* to logfile name + * + * Returns: void + * + ***********************************************************************/ +void +pi_debug_set_file (const char *path) +{ + pi_mutex_lock(&logfile_mutex); + + if (debug_file != NULL && debug_file != stderr) + fclose (debug_file); + + debug_file = fopen (path, "a"); + if (debug_file == NULL) + debug_file = stderr; + + pi_mutex_unlock(&logfile_mutex); +} + + +/*********************************************************************** + * + * Function: pi_log + * + * Summary: logs a debug message + * + * Parameters: type, level, format, ... + * + * Returns: void + * + ***********************************************************************/ +void +pi_log (int type, int level, const char *format, ...) +{ + va_list ap; + + if (!(debug_types & type) && type != PI_DBG_ALL) + return; + + if (debug_level < level) + return; + + pi_mutex_lock(&logfile_mutex); + + if (debug_file == NULL) + debug_file = stderr; + +#if HAVE_PTHREAD + fprintf(debug_file, "[thread 0x%08lx] ", pi_thread_id()); +#endif + va_start(ap, format); + vfprintf(debug_file, format, ap); + va_end(ap); + + fflush(debug_file); + + pi_mutex_unlock(&logfile_mutex); +} + +void +pi_dumpline(const char *buf, size_t len, unsigned int addr) +{ + unsigned int i; + int offset; + char line[256]; + + offset = sprintf(line, " %.4x ", addr); + + for (i = 0; i < 16; i++) { + if (i < len) + offset += sprintf(line+offset, "%.2x ", + 0xff & (unsigned int) buf[i]); + else { + strcpy(line+offset, " "); + offset += 3; + } + } + + strcpy(line+offset, " "); + offset += 2; + + for (i = 0; i < len; i++) { + if (buf[i] == '%') { + /* since we're going through pi_log, we need to + * properly escape % characters + */ + line[offset++] = '%'; + line[offset++] = '%'; + } else if (isprint(buf[i]) && buf[i] >= 32 && buf[i] <= 126) + line[offset++] = buf[i]; + else + line[offset++] = '.'; + } + + strcpy(line+offset,"\n"); + LOG((PI_DBG_ALL, PI_DBG_LVL_NONE, line)); +} + +void +dumpline(const char *buf, size_t len, unsigned int addr) +{ + /* this function will be removed in 0.13. Use pi_dumpline() instead. */ + pi_dumpline(buf, len, addr); +} + +void +pi_dumpdata(const char *buf, size_t len) +{ + unsigned int i; + + for (i = 0; i < len; i += 16) + pi_dumpline(buf + i, ((len - i) > 16) ? 16 : len - i, i); +} + +void +dumpdata(const char *buf, size_t len) +{ + /* this function will be removed in 0.13. Use pi_dumpdata() instead */ + pi_dumpdata(buf, len); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/dlp.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/dlp.c new file mode 100644 index 00000000..25146052 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/dlp.c @@ -0,0 +1,4911 @@ +/* + * $Id: dlp.c,v 1.139 2006/11/07 20:42:36 adridg Exp $ + * + * dlp.c: Palm DLP protocol + * + * Copyright (c) 1996, 1997, Kenneth Albanowski + * Copyright (c) 1998-2003, David Desrosiers, JP Rosevear and others + * Copyright (c) 2004, 2005, 2006, Florent Pillet + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif +#include <stdio.h> +#include <stdarg.h> +#ifdef HAVE_ERRNO_H + #include <errno.h> + #ifndef ENOMSG + #define ENOMSG EINVAL /* For systems that don't provide ENOMSG. Use EINVAL instead. */ + #endif +#endif +#include <sys/types.h> +#include <netinet/in.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-dlp.h" +#include "pi-syspkt.h" + +#define DLP_REQUEST_DATA(req, arg, offset) &req->argv[arg]->data[offset] +#define DLP_RESPONSE_DATA(res, arg, offset) &res->argv[arg]->data[offset] + +#define get_date(ptr) (dlp_ptohdate((ptr))) +#define set_date(ptr,val) (dlp_htopdate((val),(ptr))) + +#define RequireDLPVersion(sd,major,minor) \ + if (pi_version(sd) < (((major)<<8) | (minor))) \ + return dlpErrNotSupp + +/* This constant is being used during dlp_ReadResourceByType, dlp_ReadResourceByIndex, dlp_ReadRecordById, and dlp_ReadRecordByIndex + * Scott Gruby discovered that on some devices, reading a record that has the maximum record size can lock up the device. + * We'll read large records in two steps, getting the small amount of remaining data the second time. + * Scott's tests showed that the value above (100 bytes) was enough of a safeguard to prevent device lockup + */ +#define RECORD_READ_SAFEGUARD_SIZE 100 + +/* Define prototypes */ +#ifdef PI_DEBUG +static void record_dump (unsigned long recID, unsigned int recIndex, + int flags, int catID, const char *data, int data_len); +#endif + +char *dlp_errorlist[] = { + "No error", + "General System error", + "Illegal Function", + "Out of memory", + "Invalid parameter", + "Not found", + "None Open", + "Already Open", + "Too many Open", + "Already Exists", + "Cannot Open", + "Record deleted", + "Record busy", + "Operation not supported", + "-Unused-", + "Read only", + "Not enough space", + "Limit exceeded", + "Sync cancelled", + "Bad arg wrapper", + "Argument missing", + "Bad argument size" +}; + +/* Look at "Error codes" in VFSMgr.h in the Palm SDK for their + implementation */ +char * vfs_errorlist[] = { + "No error", + "Buffer Overflow", + "Generic file error", + "File reference is invalid", + "File still open", + "Permission denied", + "File or folder already exists", + "FileEOF", + "File not found", + "volumereference is invalid", + "Volume still mounted", + "No filesystem", + "Bad data", + "Non-empty directory", + "Invalid path or filename", + "Volume full - not enough space", + "Unimplemented", + "Not a directory", + "Is a directory", + "Directory not found", + "Name truncated" +}; + +/* Look at "Error codes" in ExpansionMgr.h in the Palm SDK for their + implementation */ +char * exp_errorlist[] = { + "No error", + "Unsupported Operation", + "Not enough Power", + "Card not present", + "Invalid slotreference number", + "Slot deallocated", + "Card no sector read/write", + "Card read only", + "Card bad sector", + "Protected sector", + "Not open (slot driver)", + "still open (slot driver)", + "Unimplemented", + "Enumeration empty", + "Incompatible API version" +}; + +#ifdef DLP_TRACE +static int dlp_trace = 0; +#endif +static int dlp_version_major = PI_DLP_VERSION_MAJOR; +static int dlp_version_minor = PI_DLP_VERSION_MINOR; + +#ifdef PI_DEBUG + #define Trace(name) \ + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, "DLP sd=%d %s\n", sd, #name)); + #ifdef __GNUC__ + #define TraceX(name,format,...) \ + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, "DLP sd=%d %s " #format "\n", sd, #name, __VA_ARGS__)); + #else + #define TraceX(name,format,...) \ + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, "DLP sd=%d %s\n", sd, #name)); + #endif +#else + #define Trace(name) + #define TraceX(name,format,...) +#endif + +#ifdef PI_DEBUG +static void record_dump (unsigned long recID, unsigned int recIndex, int flags, + int catID, const char *data, int data_len) +{ + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " ID: 0x%8.8lX, Index: %u, Category: %d\n" + " Flags:%s%s%s%s%s%s (0x%2.2X), and %d bytes:\n", + (unsigned long) recID, + recIndex, + catID, + (flags & dlpRecAttrDeleted) ? " Deleted" : "", + (flags & dlpRecAttrDirty) ? " Dirty" : "", + (flags & dlpRecAttrBusy) ? " Busy" : "", + (flags & dlpRecAttrSecret) ? " Secret" : "", + (flags & dlpRecAttrArchived) ? " Archive" : "", + (!flags) ? " None" : "", + flags, data_len)); + pi_dumpdata(data, (size_t)data_len); +} +#endif + +void +dlp_set_protocol_version(int major, int minor) +{ + dlp_version_major = major; + dlp_version_minor = minor; +} + +/*************************************************************************** + * + * Function: dlp_strerror + * + * Summary: lookup text for dlp error + * + * Parameters: error number + * + * Returns: char* to error text string + * + ***************************************************************************/ +char +*dlp_strerror(int error) +{ + if (error < 0) + error = -error; + + if ((unsigned int) error >= (sizeof(dlp_errorlist)/(sizeof(char *)))) + return "Unknown error"; + + return dlp_errorlist[error]; +} + + +/*************************************************************************** + * + * Function: dlp_arg_new + * + * Summary: create a dlpArg instance + * + * Parameters: id_, length of data + * + * Returns: dlpArg* or NULL on failure + * + ***************************************************************************/ +struct dlpArg +*dlp_arg_new (int argID, size_t len) +{ + struct dlpArg *arg; + + arg = (struct dlpArg *)malloc(sizeof (struct dlpArg)); + + if (arg != NULL) { + arg->id_ = argID; + arg->len = len; + arg->data = NULL; + if (len > 0) { + arg->data = (char *)malloc (len); + if (arg->data == NULL) { + free(arg); + arg = NULL; + } + } + } + + return arg; +} + + +/*************************************************************************** + * + * Function: dlp_arg_free + * + * Summary: frees a dlpArg instance + * + * Parameters: dlpArg* + * + * Returns: void + * + ***************************************************************************/ +void +dlp_arg_free (struct dlpArg *arg) +{ + if (arg != NULL) { + if (arg->data != NULL) + free (arg->data); + free (arg); + } +} + + +/*************************************************************************** + * + * Function: dlp_arg_len + * + * Summary: computes aggregate length of data members associated with an + * array of dlpArg instances + * + * Parameters: number of dlpArg instances, dlpArg** + * + * Returns: aggregate length or -1 on error + * + ***************************************************************************/ +int +dlp_arg_len (int argc, struct dlpArg **argv) +{ + int i, len = 0; + + for (i = 0; i < argc; i++) { + struct dlpArg *arg = argv[i]; + + /* FIXME: shapiro: should these be < or <= ??? */ + if (arg->len < PI_DLP_ARG_TINY_LEN && + (arg->id_ & (PI_DLP_ARG_FLAG_SHORT | PI_DLP_ARG_FLAG_LONG)) == 0) + len += 2; + else if (arg->len < PI_DLP_ARG_SHORT_LEN && + (arg->id_ & PI_DLP_ARG_FLAG_LONG) == 0) + len += 4; + else + len += 6; + + len += arg->len; + } + + return len; +} + + +/*************************************************************************** + * + * Function: dlp_request_new + * + * Summary: creates a new dlpRequest instance + * + * Parameters: dlpFunction command, number of dlpArgs, lengths of dlpArgs + * data member + * + * Returns: dlpRequest* or NULL if failure + * + ***************************************************************************/ +struct dlpRequest* +dlp_request_new (enum dlpFunctions cmd, int argc, ...) +{ + struct dlpRequest *req; + va_list ap; + int i, + j; + + req = (struct dlpRequest *)malloc (sizeof (struct dlpRequest)); + + if (req != NULL) { + req->cmd = cmd; + req->argc = argc; + req->argv = NULL; + + if (argc) { + req->argv = (struct dlpArg **) malloc (sizeof (struct dlpArg *) * argc); + if (req->argv == NULL) { + free(req); + return NULL; + } + } + + va_start (ap, argc); + for (i = 0; i < argc; i++) { + size_t len; + + len = va_arg (ap, size_t); + req->argv[i] = dlp_arg_new (PI_DLP_ARG_FIRST_ID + i, + len); + if (req->argv[i] == NULL) { + for (j = 0; j < i; j++) + dlp_arg_free(req->argv[j]); + free(req->argv); + free(req); + req = NULL; + break; + } + } + va_end (ap); + } + + return req; +} + + +/*************************************************************************** + * + * Function: dlp_request_new_with_argid + * + * Summary: creates a new dlpRequest instance with argid + * + * Parameters: dlpFunction command, number of dlpArgs, argid, lengths of + * dlpArgs data member + * + * Returns: dlpRequest* or NULL if failure + * + ***************************************************************************/ +struct dlpRequest* +dlp_request_new_with_argid (enum dlpFunctions cmd, int argid, int argc, ...) +{ + struct dlpRequest *req; + va_list ap; + int i, + j; + + req = (struct dlpRequest *) malloc (sizeof (struct dlpRequest)); + + if (req != NULL) { + req->cmd = cmd; + req->argc = argc; + req->argv = NULL; + + if (argc) { + req->argv = (struct dlpArg **) malloc (sizeof (struct dlpArg *) * argc); + if (req->argv == NULL) { + free(req); + return NULL; + } + } + + va_start (ap, argc); + for (i = 0; i < argc; i++) { + size_t len; + + len = va_arg (ap, size_t); + req->argv[i] = dlp_arg_new (argid + i, len); + if (req->argv[i] == NULL) { + for (j = 0; j < i; j++) + dlp_arg_free(req->argv[j]); + free(req->argv); + free(req); + req = NULL; + break; + } + } + va_end (ap); + } + + return req; +} + + +/*************************************************************************** + * + * Function: dlp_response_new + * + * Summary: creates a new dlpResponse instance + * + * Parameters: dlpFunction command, number of dlpArg instances + * + * Returns: dlpResponse* or NULL if failure + * + ***************************************************************************/ +struct dlpResponse +*dlp_response_new (enum dlpFunctions cmd, int argc) +{ + struct dlpResponse *res; + + res = (struct dlpResponse *) malloc (sizeof (struct dlpResponse)); + + if (res != NULL) { + + res->cmd = cmd; + res->err = dlpErrNoError; + res->argc = argc; + res->argv = NULL; + + if (argc) { + res->argv = (struct dlpArg **) malloc (sizeof (struct dlpArg *) * argc); + if (res->argv == NULL) { + free(res); + return NULL; + } + /* zero-out argv so that in case of error during + response read, dlp_response_free() won't try to + free uninitialized ptrs */ + memset(res->argv, 0, sizeof (struct dlpArg *) * argc); + } + } + + return res; +} + + +/*************************************************************************** + * + * Function: dlp_response_read + * + * Summary: reads dlp response + * + * Parameters: dlpResonse**, sd + * + * Returns: first dlpArg response length or -1 on error + * + ***************************************************************************/ +ssize_t +dlp_response_read (struct dlpResponse **res, int sd) +{ + struct dlpResponse *response; + unsigned char *buf; + short argid; + int i; + ssize_t bytes; + size_t len; + pi_buffer_t *dlp_buf; + + dlp_buf = pi_buffer_new (DLP_BUF_SIZE); + if (dlp_buf == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + bytes = pi_read (sd, dlp_buf, dlp_buf->allocated); /* buffer will grow as needed */ + if (bytes < 0) { + pi_buffer_free (dlp_buf); + return bytes; + } + if (bytes < 4) { + /* packet is probably incomplete */ +#ifdef DEBUG + LOG((PI_DBG_DLP, PI_DBG_LVL_ERR, + "dlp_response_read: response too short (%d bytes)\n", + bytes)); + if (bytes) + pi_dumpdata(dlp_buf->data, (size_t)dlp_buf->used); +#endif + return pi_set_error(sd, PI_ERR_DLP_COMMAND); + } + + response = dlp_response_new ((enum dlpFunctions)(dlp_buf->data[0] & 0x7f), dlp_buf->data[1]); + *res = response; + + /* note that in case an error occurs, we do not deallocate the response + since callers already do it under all circumstances */ + if (response == NULL) { + pi_buffer_free (dlp_buf); + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + } + + response->err = (enum dlpErrors) get_short (&dlp_buf->data[2]); + pi_set_palmos_error(sd, (int)response->err); + + /* FIXME: add bounds checking to make sure we don't access past + * the end of the buffer in case the data is corrupt */ + buf = dlp_buf->data + 4; + for (i = 0; i < response->argc; i++) { + argid = get_byte (buf) & 0x3f; + if (get_byte(buf) & PI_DLP_ARG_FLAG_LONG) { + if (pi_version(sd) < 0x0104) { + /* we received a response from a device indicating that + it would have transmitted a >64k data block but DLP + versions prior to 1.4 don't have this capacity. In + this case (as observed on a T3), there is NO length + stored after the argid, it goes straigt to the data + contents. We need to report that the data is too large + to be transferred. + */ + pi_buffer_free (dlp_buf); + return pi_set_error(sd, PI_ERR_DLP_DATASIZE); + } + len = get_long (&buf[2]); + buf += 6; + } else if (get_byte(buf) & PI_DLP_ARG_FLAG_SHORT) { + len = get_short (&buf[2]); + buf += 4; + } else { + argid = get_byte(buf); + len = get_byte(&buf[1]); + buf += 2; + } + + response->argv[i] = dlp_arg_new (argid, len); + if (response->argv[i] == NULL) { + pi_buffer_free (dlp_buf); + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + } + memcpy (response->argv[i]->data, buf, len); + buf += len; + } + + pi_buffer_free (dlp_buf); + + return response->argc ? response->argv[0]->len : 0; +} + + +/*************************************************************************** + * + * Function: dlp_request_write + * + * Summary: writes dlp request + * + * Parameters: dlpRequest**, sd + * + * Returns: response length or -1 on error + * + ***************************************************************************/ +ssize_t +dlp_request_write (struct dlpRequest *req, int sd) +{ + unsigned char *exec_buf, *buf; + int i; + size_t len; + + len = dlp_arg_len (req->argc, req->argv) + 2; + exec_buf = (unsigned char *) malloc (sizeof (unsigned char) * len); + if (exec_buf == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte (&exec_buf[PI_DLP_OFFSET_CMD], req->cmd); + set_byte (&exec_buf[PI_DLP_OFFSET_ARGC], req->argc); + + buf = &exec_buf[PI_DLP_OFFSET_ARGV]; + for (i = 0; i < req->argc; i++) { + struct dlpArg *arg = req->argv[i]; + short argid = arg->id_; + + if (arg->len < PI_DLP_ARG_TINY_LEN && + (argid & (PI_DLP_ARG_FLAG_SHORT | PI_DLP_ARG_FLAG_LONG)) == 0) { + set_byte(&buf[0], argid | PI_DLP_ARG_FLAG_TINY); + set_byte(&buf[1], arg->len); + + memcpy(&buf[2], arg->data, arg->len); + buf += arg->len + 2; + } else if (arg->len < PI_DLP_ARG_SHORT_LEN && + (argid & PI_DLP_ARG_FLAG_LONG) == 0) { + set_byte(&buf[0], argid | PI_DLP_ARG_FLAG_SHORT); + set_byte(&buf[1], 0); + set_short(&buf[2], arg->len); + + memcpy (&buf[4], arg->data, arg->len); + buf += arg->len + 4; + } else { + set_byte (&buf[0], argid | PI_DLP_ARG_FLAG_LONG); + set_byte(&buf[1], 0); + set_long (&buf[2], arg->len); + + memcpy (&buf[6], arg->data, arg->len); + buf += arg->len + 6; + } + } + + pi_flush(sd, PI_FLUSH_INPUT); + + if ((i = pi_write(sd, exec_buf, len)) < (ssize_t)len) { + errno = -EIO; + if (i >= 0 && i < (ssize_t)len) + i = -1; + } + + free (exec_buf); + + return i; +} + + +/*************************************************************************** + * + * Function: dlp_request_free + * + * Summary: frees a dlpRequest instance + * + * Parameters: dlpRequest* + * + * Returns: void + * + ***************************************************************************/ +void +dlp_request_free (struct dlpRequest *req) +{ + int i; + + if (req == NULL) + return; + + if (req->argv != NULL) { + for (i = 0; i < req->argc; i++) { + if (req->argv[i] != NULL) + dlp_arg_free (req->argv[i]); + } + free (req->argv); + } + + free (req); +} + + +/*************************************************************************** + * + * Function: dlp_response_free + * + * Summary: frees a dlpResponse instance + * + * Parameters: dlpResponse* + * + * Returns: void + * + ***************************************************************************/ +void +dlp_response_free (struct dlpResponse *res) +{ + int i; + + if (res == NULL) + return; + + if (res->argv != NULL) { + for (i = 0; i < res->argc; i++) { + if (res->argv[i] != NULL) + dlp_arg_free (res->argv[i]); + } + free (res->argv); + } + + free (res); +} + + +/*************************************************************************** + * + * Function: dlp_exec + * + * Summary: writes a dlp request and reads the response + * + * Parameters: dlpResponse* + * + * Returns: the number of response bytes, or -1 on error + * + ***************************************************************************/ +int +dlp_exec(int sd, struct dlpRequest *req, struct dlpResponse **res) +{ + int bytes, result; + *res = NULL; + + if ((result = dlp_request_write (req, sd)) < req->argc) { + LOG((PI_DBG_DLP, PI_DBG_LVL_ERR, + "DLP sd:%i dlp_request_write returned %i\n", + sd, result)); + errno = -EIO; + return result; + } + + if ((bytes = dlp_response_read (res, sd)) < 0) { + LOG((PI_DBG_DLP, PI_DBG_LVL_ERR, + "DLP sd:%i dlp_response_read returned %i\n", + sd, bytes)); + errno = -EIO; + return bytes; + } + + /* Check to make sure the response is for this command */ + if ((*res)->cmd != req->cmd) { + /* The Palm m130 and Tungsten T return the wrong code for VFSVolumeInfo */ + /* Tungsten T5 (and maybe Treo 650) return dlpFuncEndOfSync for dlpFuncWriteResource */ + /* In some cases, the Tapwave Zodiac returns dlpFuncReadRecord instead of dlpFuncReadRecordEx */ + if ((req->cmd != dlpFuncVFSVolumeInfo || (*res)->cmd != dlpFuncVFSVolumeSize) + && req->cmd != dlpFuncWriteResource /* T5 */ + && req->cmd != dlpFuncReadRecord /* Zodiac */ + && req->cmd != dlpFuncReadRecordEx) /* Zodiac */ + { + errno = -ENOMSG; + + LOG((PI_DBG_DLP, PI_DBG_LVL_DEBUG, + "dlp_exec: result CMD 0x%02x doesn't match requested cmd 0x%02x\n", + (unsigned)((*res)->cmd), (unsigned)req->cmd)); + + return pi_set_error(sd, PI_ERR_DLP_COMMAND); + } + } + + /* Check to make sure there was no error */ + if ((*res)->err != dlpErrNoError) { + errno = -ENOMSG; + pi_set_palmos_error(sd, (int)((*res)->err)); + return pi_set_error(sd, PI_ERR_DLP_PALMOS); + } + + return bytes; +} + +/* These conversion functions are strictly for use within the DLP layer. + This particular date/time format does not occur anywhere else within the + Palm or its communications. */ + +/* Notice: + The dates in the DLP protocol are expressed as absolute dates/times, + without any time zone information. For example if a file was created + on the device at 19:32:48, the time members will be 19, 32 and 48. + This simplifies things a lot since we don't need to to time zone + conversions. The functions below convert a breakdown DLP date to and + from a time_t expressed in the machine's local timezone. + -- FP */ + +time_t +dlp_ptohdate(const unsigned char *data) +{ + struct tm t; + + /* Seems like year comes back as all zeros if the date is "empty" + (but other fields can vary). And mktime() chokes on 1900 B.C. + (result of 0 minus 1900), returning -1, which the higher level + code can't deal with (passes it straight on to utime(), which + simply leaves the file's timestamp "as-is"). + + So, since year 0 appears to mean "no date", we'll return an odd + number that works out to precisely one day before the start of + the Palm's clock (thus little chance of being run into by any + Palm-based time stamp). */ + + if (data[0] == 0 && data[1] == 0) { + + /* This original calculation was wrong, and reported one day + earlier than it was supposed to report. You can verify + this with the following: + + perl -e '$date=localtime(0x83D8FE00); print $date,"\n"' + + return (time_t) 0x83D8FE00; // Wed Dec 30 16:00:00 1903 GMT + + Here are others, depending on what your system requirements are: + + return (time_t) 0x83D96E80; // Thu Dec 31 00:00:00 1903 GMT + return (time_t) 0x00007080; // Thu Jan 1 00:00:00 1970 GMT + + Palm's own Conduit Development Kit references using 1/1/1904, + so that's what we'll use here until something else breaks + it. + */ + + return (time_t) 0x83DAC000; /* Fri Jan 1 00:00:00 1904 GMT */ + } + + memset(&t, 0, sizeof(t)); + t.tm_sec = (int) data[6]; + t.tm_min = (int) data[5]; + t.tm_hour = (int) data[4]; + t.tm_mday = (int) data[3]; + t.tm_mon = (int) data[2] - 1; + t.tm_year = (((int)data[0] << 8) | (int)data[1]) - 1900; + t.tm_isdst = -1; + + return mktime(&t); +} + +void +dlp_htopdate(time_t time_interval, unsigned char *data) +{ /* @+ptrnegate@ */ + int year; + const struct tm *t; + + /* Fri Jan 1 00:00:00 1904 GMT */ + time_t palm_epoch = 0x83DAC000; + + if (time_interval == palm_epoch) { + memset(data, 0, 8); + return; + } + + t = localtime(&time_interval); + ASSERT(t != NULL); + + year = t->tm_year + 1900; + + data[7] = (unsigned char) 0; /* packing spacer */ + data[6] = (unsigned char) t->tm_sec; + data[5] = (unsigned char) t->tm_min; + data[4] = (unsigned char) t->tm_hour; + data[3] = (unsigned char) t->tm_mday; + data[2] = (unsigned char) (t->tm_mon + 1); + data[0] = (unsigned char) (year >> 8); + data[1] = (unsigned char) year; +} + +int +dlp_GetSysDateTime(int sd, time_t *t) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_GetSysDateTime); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncGetSysDateTime, 0); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + *t = dlp_ptohdate((const unsigned char *)DLP_RESPONSE_DATA (res, 0, 0)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP GetSysDateTime %s", ctime(t))); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_SetSysDateTime(int sd, time_t t) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_SetSysDateTime,"time=0x%08lx",t); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncSetSysDateTime, 1, 8); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + dlp_htopdate(t, (unsigned char *)DLP_REQUEST_DATA(req, 0, 0)); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_ReadStorageInfo(int sd, int cardno, struct CardInfo *c) +{ + int result; + size_t len1, len2; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_ReadStorageInfo,"cardno=%d",cardno); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncReadStorageInfo, 1, 2); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), cardno); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + c->more = get_byte(DLP_RESPONSE_DATA(res, 0, 0)) + || (get_byte(DLP_RESPONSE_DATA(res, 0, 3)) > 1); + c->card = get_byte(DLP_RESPONSE_DATA(res, 0, 5)); + c->version = get_byte(DLP_RESPONSE_DATA(res, 0, 6)); + c->creation = get_date((const unsigned char *)DLP_RESPONSE_DATA(res, 0, 8)); + c->romSize = get_long(DLP_RESPONSE_DATA(res, 0, 16)); + c->ramSize = get_long(DLP_RESPONSE_DATA(res, 0, 20)); + c->ramFree = get_long(DLP_RESPONSE_DATA(res, 0, 24)); + + len1 = get_byte(DLP_RESPONSE_DATA(res, 0, 28)); + memcpy(c->name, DLP_RESPONSE_DATA(res, 0, 30), len1); + c->name[len1] = '\0'; + + len2 = get_byte(DLP_RESPONSE_DATA(res, 0, 29)); + memcpy(c->manufacturer, DLP_RESPONSE_DATA(res, 0, 30 + len1), + len2); + c->manufacturer[len2] = '\0'; + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP Read Cardno: %d, Card Version: %d, Creation time: %s", + c->card, c->version, ctime(&c->creation))); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Total ROM: %lu, Total RAM: %lu, Free RAM: %lu\n", + c->romSize, c->ramSize, c->ramFree)); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Card name: '%s'\n", c->name)); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Manufacturer name: '%s'\n", c->manufacturer)); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " More: %s\n", c->more ? "Yes" : "No")); + } + + dlp_response_free (res); + + return result; +} + +int +dlp_ReadSysInfo(int sd, struct SysInfo *s) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_ReadSysInfo); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncReadSysInfo, 1, 4); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short (DLP_REQUEST_DATA (req, 0, 0), dlp_version_major); + set_short (DLP_REQUEST_DATA (req, 0, 2), dlp_version_minor); + + result = dlp_exec(sd, req, &res); + + dlp_request_free (req); + + if (result > 0) { + s->romVersion = get_long (DLP_RESPONSE_DATA (res, 0, 0)); + s->locale = get_long (DLP_RESPONSE_DATA (res, 0, 4)); + /* The 8th byte is a filler byte */ + s->prodIDLength = get_byte (DLP_RESPONSE_DATA (res, 0, 9)); + memcpy(s->prodID, DLP_RESPONSE_DATA(res, 0, 10), + s->prodIDLength); + + if (res->argc > 1) { + /* response added in DLP 1.2 */ + pi_socket_t *ps = find_pi_socket(sd); + + s->dlpMajorVersion = + get_short (DLP_RESPONSE_DATA (res, 1, 0)); + s->dlpMinorVersion = + get_short (DLP_RESPONSE_DATA (res, 1, 2)); + s->compatMajorVersion = + get_short (DLP_RESPONSE_DATA (res, 1, 4)); + s->compatMinorVersion = + get_short (DLP_RESPONSE_DATA (res, 1, 6)); + s->maxRecSize = + get_long (DLP_RESPONSE_DATA (res, 1, 8)); + + /* update socket information */ + ps->dlpversion = (s->dlpMajorVersion << 8) | s->dlpMinorVersion; + ps->maxrecsize = s->maxRecSize; + } else { + s->dlpMajorVersion = 0; + s->dlpMinorVersion = 0; + s->compatMajorVersion = 0; + s->compatMinorVersion = 0; + s->maxRecSize = 0; + } + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadSysInfo ROM Ver=0x%8.8lX Locale=0x%8.8lX\n", + s->romVersion, s->locale)); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Product ID=0x%8.8lX\n", s->prodID)); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " DLP Major Ver=0x%4.4lX DLP Minor Ver=0x%4.4lX\n", + s->dlpMajorVersion, s->dlpMinorVersion)); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Compat Major Ver=0x%4.4lX Compat Minor Vers=0x%4.4lX\n", + s->compatMajorVersion, s->compatMinorVersion)); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Max Rec Size=%ld\n", s->maxRecSize)); + } + + dlp_response_free (res); + + return result; +} + +int +dlp_ReadDBList(int sd, int cardno, int flags, int start, pi_buffer_t *info) +{ + int result, + i, + count; + struct dlpRequest *req; + struct dlpResponse *res; + unsigned char *p; + struct DBInfo db; + + TraceX(dlp_ReadDBList,"cardno=%d flags=0x%04x start=%d",cardno,flags,start); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncReadDBList, 1, 4); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + pi_buffer_clear (info); + + /* `multiple' only supported in DLP 1.2 and above */ + if (pi_version(sd) < 0x0102) + flags &= ~dlpDBListMultiple; + + set_byte(DLP_REQUEST_DATA(req, 0, 0), (unsigned char) flags); + set_byte(DLP_REQUEST_DATA(req, 0, 1), (unsigned char) cardno); + set_short(DLP_REQUEST_DATA(req, 0, 2), start); + + result = dlp_exec (sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + p = (unsigned char *)DLP_RESPONSE_DATA(res, 0, 0); + db.more = get_byte(p + 2); + count = get_byte(p + 3); + + for (i=0; i < count; i++) { + /* PalmOS 2.0 has additional flag */ + if (pi_version(sd) > 0x0100) + db.miscFlags = get_byte(p + 5); + else + db.miscFlags = 0; + + db.flags = get_short(p + 6); + db.type = get_long(p + 8); + db.creator = get_long(p + 12); + db.version = get_short(p + 16); + db.modnum = get_long(p + 18); + db.createDate = get_date(p + 22); + db.modifyDate = get_date(p + 30); + db.backupDate = get_date(p + 38); + db.index = get_short(p + 46); + + memset(db.name, 0, sizeof(db.name)); + strncpy(db.name, (char *)(p + 48), 32); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadDBList Name: '%s', Version: %d, More: %s\n", + db.name, db.version, db.more ? "Yes" : "No")); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Creator: '%s'", printlong(db.creator))); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Type: '%s' Flags: %s%s%s%s%s%s%s%s%s%s", + printlong(db.type), + (db.flags & dlpDBFlagResource) ? "Resource " : "", + (db.flags & dlpDBFlagReadOnly) ? "ReadOnly " : "", + (db.flags & dlpDBFlagAppInfoDirty) ? + "AppInfoDirty " : "", + (db.flags & dlpDBFlagBackup) ? "Backup " : "", + (db.flags & dlpDBFlagReset) ? "Reset " : "", + (db.flags & dlpDBFlagNewer) ? "Newer " : "", + (db.flags & dlpDBFlagCopyPrevention) ? + "CopyPrevention " : "", + (db.flags & dlpDBFlagStream) ? "Stream " : "", + (db.flags & dlpDBFlagOpen) ? "Open " : "", + (!db.flags) ? "None" : "")); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, " (0x%2.2X)\n", db.flags)); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Modnum: %ld, Index: %d, Creation date: 0x%08lx, %s", + db.modnum, db.index, db.createDate, ctime(&db.createDate))); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Modification date: 0x%08lx, %s", db.modifyDate, ctime(&db.modifyDate))); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Backup date: 0x%08lx, %s", db.backupDate, ctime(&db.backupDate))); + + if (pi_buffer_append(info, &db, sizeof(db)) == NULL) { + result = pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + break; + } + + p += get_byte(p + 4); + } + } else { + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "Error in dlp_ReadDBList: %d\n", result)); + } + + dlp_response_free (res); + + return result; +} + +int +dlp_FindDBInfo(int sd, int cardno, int start, const char *dbname, + unsigned long type, unsigned long creator, + struct DBInfo *info) +{ + int i, + j; + pi_buffer_t *buf; + + TraceX(dlp_FindDBInfo,"cardno=%d start=%d",cardno,start); + pi_reset_errors(sd); + + buf = pi_buffer_new (sizeof (struct DBInfo)); + if (buf == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + if (start < 0x1000) { + i = start; + while (dlp_ReadDBList(sd, cardno, 0x80 | dlpDBListMultiple, i, buf) >= 0) { + for (j=0; j < (int)(buf->used / sizeof(struct DBInfo)); j++) { + memcpy (info, buf->data + j * sizeof(struct DBInfo), sizeof(struct DBInfo)); + if ((!dbname || strcmp(info->name, dbname) == 0) + && (!type || info->type == type) + && (!creator || info->creator == creator)) + goto found; + i = info->index + 1; + } + } + start = 0x1000; + } + + i = start & 0xFFF; + while (dlp_ReadDBList(sd, cardno, 0x40 | dlpDBListMultiple, i, buf) >= 0) { + for (j=0; j < (int)(buf->used / sizeof(struct DBInfo)); j++) { + memcpy (info, buf->data + j * sizeof(struct DBInfo), sizeof(struct DBInfo)); + if ((!dbname || strcmp(info->name, dbname) == 0) + && (!type || info->type == type) + && (!creator || info->creator == creator)) + { + info->index |= 0x1000; + goto found; + } + i = info->index + 1; + } + } + + pi_buffer_free (buf); + return -1; + +found: + pi_buffer_free (buf); + return 0; +} + +/*************************************************************************** + * + * Function: dlp_decode_finddb_response + * + * Summary: Response decoding for the three variants of dlp_FindDB + * + * Parameters: None + * + * Returns: Nothing + * + ***************************************************************************/ +static void +dlp_decode_finddb_response(struct dlpResponse *res, int *cardno, unsigned long *localid, + int *dbhandle, struct DBInfo *info, struct DBSizeInfo *size) +{ + int arg, argid; + for (arg = 0; arg < res->argc; arg++) { + argid = (res->argv[arg]->id_ & 0x7f) - PI_DLP_ARG_FIRST_ID; + if (argid == 0) { + if (cardno) + *cardno = get_byte(DLP_RESPONSE_DATA(res, arg, 0)); + if (localid) + *localid = get_long(DLP_RESPONSE_DATA(res, arg, 2)); + if (dbhandle) + *dbhandle = get_long(DLP_RESPONSE_DATA(res, arg, 6)); + + if (info) { + info->more = 0; + info->miscFlags = + get_byte(DLP_RESPONSE_DATA(res, arg, 11)); + info->flags = + get_short(DLP_RESPONSE_DATA(res, arg, 12)); + info->type = + get_long(DLP_RESPONSE_DATA(res, arg, 14)); + info->creator = + get_long(DLP_RESPONSE_DATA(res, arg, 18)); + info->version = + get_short(DLP_RESPONSE_DATA(res, arg, 22)); + info->modnum = + get_long(DLP_RESPONSE_DATA(res, arg, 24)); + info->createDate = + get_date((const unsigned char *)DLP_RESPONSE_DATA(res, arg, 28)); + info->modifyDate = + get_date((const unsigned char *)DLP_RESPONSE_DATA(res, arg, 36)); + info->backupDate = + get_date((const unsigned char *)DLP_RESPONSE_DATA(res, arg, 44)); + info->index = + get_short(DLP_RESPONSE_DATA(res, arg, 52)); + + strncpy(info->name, DLP_RESPONSE_DATA(res, arg, 54), 32); + info->name[32] = '\0'; + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP FindDB Name: '%s', " + "Version: %d, More: %s\n", + info->name, info->version, + info->more ? "Yes" : "No")); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Creator: '%s'", printlong(info->creator))); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Type: '%s' Flags: %s%s%s%s%s%s%s%s%s%s", + printlong(info->type), + (info->flags & dlpDBFlagResource) ? + "Resource " : "", + (info->flags & dlpDBFlagReadOnly) ? + "ReadOnly " : "", + (info->flags & dlpDBFlagAppInfoDirty) ? + "AppInfoDirty " : "", + (info->flags & dlpDBFlagBackup) ? + "Backup " : "", + (info->flags & dlpDBFlagReset) ? + "Reset " : "", + (info->flags & dlpDBFlagNewer) ? + "Newer " : "", + (info->flags & dlpDBFlagCopyPrevention) ? + "CopyPrevention " : "", + (info->flags & dlpDBFlagStream) ? + "Stream " : "", + (info->flags & dlpDBFlagOpen) ? + "Open " : "", + (!info->flags) ? "None" : "")); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " (0x%2.2X)\n", info->flags)); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Modnum: %ld, Index: %d, " + "Creation date: %s", + info->modnum, info->index, + ctime(&info->createDate))); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Modification date: %s", + ctime(&info->modifyDate))); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Backup date: %s", + ctime(&info->backupDate))); + } + } + else if (argid == 1) { + if (size) { + size->numRecords = + get_long(DLP_RESPONSE_DATA(res, arg, 0)); + size->totalBytes = + get_long(DLP_RESPONSE_DATA(res, arg, 4)); + size->dataBytes = + get_long(DLP_RESPONSE_DATA(res, arg, 8)); + size->appBlockSize = + get_long(DLP_RESPONSE_DATA(res, arg, 12)); + size->sortBlockSize = + get_long(DLP_RESPONSE_DATA(res, arg, 16)); + size->maxRecSize = + get_long(DLP_RESPONSE_DATA(res, arg, 20)); + } + } + } +} + +int +dlp_FindDBByName (int sd, int cardno, PI_CONST char *name, unsigned long *localid, + int *dbhandle, struct DBInfo *info, struct DBSizeInfo *size) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + int flags = 0; + + TraceX(dlp_FindDBByName,"cardno=%d name='%s'",cardno,name); + pi_reset_errors(sd); + + if (pi_version(sd) < 0x0102) + return pi_set_error(sd, PI_ERR_DLP_UNSUPPORTED); + + req = dlp_request_new(dlpFuncFindDB, 1, 2 + (strlen(name) + 1)); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + if (localid || dbhandle || info) + flags |= dlpFindDBOptFlagGetAttributes; + if (size) + flags |= dlpFindDBOptFlagGetSize; + + set_byte(DLP_REQUEST_DATA(req, 0, 0), flags); + set_byte(DLP_REQUEST_DATA(req, 0, 1), cardno); + strcpy(DLP_REQUEST_DATA(req, 0, 2), name); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) + dlp_decode_finddb_response(res, NULL, localid, dbhandle, info, size); + + dlp_response_free(res); + + return result; +} + +int +dlp_FindDBByOpenHandle (int sd, int dbhandle, int *cardno, + unsigned long *localid, struct DBInfo *info, struct DBSizeInfo *size) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + int flags = 0; + + Trace(dlp_FindDBByOpenHandle); + pi_reset_errors(sd); + + if (pi_version(sd) < 0x0102) + return pi_set_error(sd, PI_ERR_DLP_UNSUPPORTED); + + req = dlp_request_new_with_argid(dlpFuncFindDB, 0x21, 1, 2); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + /* Note: there is a bug in HotSync -- requesting the maxRecSize + * crashes the device, so we don't. This is supposed to work only + * for this variant of FindDB anyway. + */ + if (cardno || localid || info) + flags |= dlpFindDBOptFlagGetAttributes; + if (size) + flags |= dlpFindDBOptFlagGetSize; + + set_byte(DLP_REQUEST_DATA(req, 0, 0), flags); + set_byte(DLP_REQUEST_DATA(req, 0, 1), dbhandle); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) + dlp_decode_finddb_response(res, cardno, localid, NULL, info, size); + + dlp_response_free(res); + + return result; +} + +int +dlp_FindDBByTypeCreator (int sd, unsigned long type, unsigned long creator, + int start, int latest, int *cardno, unsigned long *localid, + int *dbhandle, struct DBInfo *info, struct DBSizeInfo *size) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + int flags = 0, search_flags = 0; + + TraceX(dlp_FindDBByTypeCreator,"type='%4.4s' creator='%4.4s' start=%d latest=%d", + (const char *)&type,(const char *)&creator,start,latest); + pi_reset_errors(sd); + + if (pi_version(sd) < 0x0102) + return pi_set_error(sd, PI_ERR_DLP_UNSUPPORTED); + + req = dlp_request_new_with_argid(dlpFuncFindDB, 0x22, 1, 10); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + if (cardno || localid || dbhandle || info) + flags |= dlpFindDBOptFlagGetAttributes; + if (size) + flags |= (dlpFindDBOptFlagGetSize | + dlpFindDBOptFlagMaxRecSize); + + if (start) + search_flags |= dlpFindDBSrchFlagNewSearch; + if (latest) + search_flags |= dlpFindDBSrchFlagOnlyLatest; + + + set_byte(DLP_REQUEST_DATA(req, 0, 0), flags); + set_byte(DLP_REQUEST_DATA(req, 0, 1), search_flags); + set_long(DLP_REQUEST_DATA(req, 0, 2), type); + set_long(DLP_REQUEST_DATA(req, 0, 6), creator); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) + dlp_decode_finddb_response(res, cardno, localid, dbhandle, info, size); + + dlp_response_free(res); + + return result; +} + +int +dlp_OpenDB(int sd, int cardno, int mode, PI_CONST char *name, int *dbhandle) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_OpenDB,"'%s'",name); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncOpenDB, 1, 2 + strlen(name) + 1); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), cardno); + set_byte(DLP_REQUEST_DATA(req, 0, 1), mode); + strcpy(DLP_REQUEST_DATA(req, 0, 2), name); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + *dbhandle = get_byte(DLP_RESPONSE_DATA(res, 0, 0)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "-> dlp_OpenDB dbhandle=%d\n", *dbhandle)); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_DeleteDB(int sd, int card, const char *name) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_DeleteDB,"%s",name); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncDeleteDB, 1, 2 + (strlen(name) + 1)); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), card); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + strcpy(DLP_REQUEST_DATA(req, 0, 2), name); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_CreateDB(int sd, unsigned long creator, unsigned long type, int cardno, + int flags, unsigned int version, const char *name, int *dbhandle) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_CreateDB,"'%s' type='%4.4s' creator='%4.4s' flags=0x%04x version=%d", + name,(const char *)&type,(const char *)&creator,flags,version); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncCreateDB, 1, 14 + (strlen(name) + 1)); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long(DLP_REQUEST_DATA(req, 0, 0), creator); + set_long(DLP_REQUEST_DATA(req, 0, 4), type); + set_byte(DLP_REQUEST_DATA(req, 0, 8), cardno); + set_byte(DLP_REQUEST_DATA(req, 0, 9), 0); + set_short(DLP_REQUEST_DATA(req, 0, 10), flags); + set_short(DLP_REQUEST_DATA(req, 0, 12), version); + strcpy(DLP_REQUEST_DATA(req, 0, 14), name); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0 && dbhandle) { + *dbhandle = get_byte(DLP_RESPONSE_DATA(res, 0, 0)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP CreateDB Handle=%d\n", *dbhandle)); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_CloseDB(int sd, int dbhandle) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_CloseDB); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncCloseDB, 1, 1); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), (unsigned char) dbhandle); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_CloseDB_All(int sd) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_CloseDB_All); + pi_reset_errors(sd); + + req = dlp_request_new_with_argid(dlpFuncCloseDB, 0x21, 0); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_CallApplication(int sd, unsigned long creator, unsigned long type, + int action, size_t length, const void *data, + unsigned long *retcode, pi_buffer_t *retbuf) +{ + int result, + version = pi_version(sd), + previous_honor_rx_timeout, + no_rx_timeout = 0; + size_t data_len; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_CallApplication,"type='%4.4s' creator='%4.4s' action=0x%04x dataLength=%d", + (const char *)&type,(const char *)&creator,action,(int)length); + pi_reset_errors(sd); + if (retbuf) + pi_buffer_clear(retbuf); + + /* we are going to temporarily disable PI_SOCK_HONOR_RX_TIMEOUT + * so that lengthy tasks on the device side don't cause a + * connection timeout + */ + data_len = sizeof(previous_honor_rx_timeout); + pi_getsockopt(sd, PI_LEVEL_SOCK, PI_SOCK_HONOR_RX_TIMEOUT, + &previous_honor_rx_timeout, &data_len); + + if (version >= 0x0101) { /* PalmOS 2.0 call encoding */ + + if (length + 22 > DLP_BUF_SIZE) { + LOG((PI_DBG_DLP, PI_DBG_LVL_ERR, + "DLP CallApplication: data too large (>64k)")); + pi_set_error(sd, PI_ERR_DLP_DATASIZE); + return -131; + } + + req = dlp_request_new_with_argid( + dlpFuncCallApplication, 0x21, 1, 22 + length); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long(DLP_REQUEST_DATA(req, 0, 0), creator); + set_long(DLP_REQUEST_DATA(req, 0, 4), type); + set_short(DLP_REQUEST_DATA(req, 0, 8), action); + set_long(DLP_REQUEST_DATA(req, 0, 10), length); + set_long(DLP_REQUEST_DATA(req, 0, 14), 0); + set_long(DLP_REQUEST_DATA(req, 0, 18), 0); + if (length) + memcpy(DLP_REQUEST_DATA(req, 0, 22), data, length); + + data_len = sizeof(no_rx_timeout); + pi_setsockopt(sd, PI_LEVEL_SOCK, PI_SOCK_HONOR_RX_TIMEOUT, + &no_rx_timeout, &data_len); + + result = dlp_exec(sd, req, &res); + + pi_setsockopt(sd, PI_LEVEL_SOCK, PI_SOCK_HONOR_RX_TIMEOUT, + &previous_honor_rx_timeout, &data_len); + + dlp_request_free(req); + + if (result > 0) { + data_len = res->argv[0]->len - 16; + + if (retcode) + *retcode = get_long(DLP_RESPONSE_DATA(res, 0, 0)); + if (retbuf) + pi_buffer_append(retbuf, DLP_RESPONSE_DATA(res, 0, 16), data_len); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP CallApplication Result: %lu (0x%08lx), " + "and %d bytes:\n", + get_long(DLP_RESPONSE_DATA(res, 0, 0)), + get_long(DLP_RESPONSE_DATA(res, 0, 0)), + data_len)); + CHECK(PI_DBG_DLP, PI_DBG_LVL_DEBUG, + pi_dumpdata(DLP_RESPONSE_DATA(res, 0, 16), + (size_t)data_len)); + } + + } else { /* PalmOS 1.0 call encoding */ + + if (length + 8 > DLP_BUF_SIZE) { + LOG((PI_DBG_DLP, PI_DBG_LVL_ERR, + "DLP CallApplication: data too large (>64k)")); + pi_set_error(sd, PI_ERR_DLP_DATASIZE); + return -131; + } + + req = dlp_request_new (dlpFuncCallApplication, 1, 8 + length); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long(DLP_REQUEST_DATA(req, 0, 0), creator); + set_short(DLP_REQUEST_DATA(req, 0, 4), action); + set_short(DLP_REQUEST_DATA(req, 0, 6), length); + memcpy(DLP_REQUEST_DATA(req, 0, 8), data, length); + + data_len = sizeof(no_rx_timeout); + pi_setsockopt(sd, PI_LEVEL_SOCK, PI_SOCK_HONOR_RX_TIMEOUT, + &no_rx_timeout, &data_len); + + result = dlp_exec(sd, req, &res); + + pi_setsockopt(sd, PI_LEVEL_SOCK, PI_SOCK_HONOR_RX_TIMEOUT, + &previous_honor_rx_timeout, &data_len); + + dlp_request_free(req); + + if (result > 0) { + data_len = res->argv[0]->len - 6; + if (retcode) + *retcode = get_short(DLP_RESPONSE_DATA(res, 0, 2)); + if (retbuf) + pi_buffer_append(retbuf, DLP_RESPONSE_DATA(res, 0, 6), data_len); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP CallApplication Action: %d Result:" + " %u (0x%04x), and %d bytes:\n", + (int)get_short(DLP_RESPONSE_DATA(res, 0, 0)), + (unsigned int)get_short(DLP_RESPONSE_DATA(res, 0, 2)), + (unsigned int)get_short(DLP_RESPONSE_DATA(res, 0, 2)), + data_len)); + CHECK(PI_DBG_DLP, PI_DBG_LVL_DEBUG, + pi_dumpdata(DLP_RESPONSE_DATA(res, 0, 6), + (size_t)data_len)); + } + } + + dlp_response_free(res); + return result; +} + +int +dlp_ResetSystem(int sd) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_ResetSystem); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncResetSystem, 0); + + result = dlp_exec(sd, req, &res); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_AddSyncLogEntry(int sd, char *entry) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_AddSyncLogEntry,"%s",entry); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncAddSyncLogEntry, 1, strlen(entry) + 1); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + strcpy(DLP_REQUEST_DATA(req, 0, 0), entry); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + if (result > 0) { + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP AddSyncLogEntry Entry: \n %s\n", entry)); + } + + return result; +} + +int +dlp_ReadOpenDBInfo(int sd, int dbhandle, int *records) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_ReadOpenDBInfo); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncReadOpenDBInfo, 1, 1); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + if (records) + *records = get_short(DLP_RESPONSE_DATA(res, 0, 0)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadOpenDBInfo %d records\n", + get_short(DLP_RESPONSE_DATA(res, 0, 0)))); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_SetDBInfo (int sd, int dbhandle, int flags, int clearFlags, + unsigned int version, time_t createDate, time_t modifyDate, + time_t backupDate, unsigned long type, unsigned long creator) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_SetDBInfo); + pi_reset_errors(sd); + + if (pi_version(sd) < 0x0102) + return pi_set_error(sd, PI_ERR_DLP_UNSUPPORTED); + + req = dlp_request_new(dlpFuncSetDBInfo, 1, 40); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + set_short(DLP_REQUEST_DATA(req, 0, 2), clearFlags); + set_short(DLP_REQUEST_DATA(req, 0, 4), flags); + set_short(DLP_REQUEST_DATA(req, 0, 6), version); + set_date((unsigned char *)DLP_REQUEST_DATA(req, 0, 8), createDate); + set_date((unsigned char *)DLP_REQUEST_DATA(req, 0, 16), modifyDate); + set_date((unsigned char *)DLP_REQUEST_DATA(req, 0, 24), backupDate); + set_long(DLP_REQUEST_DATA(req, 0, 32), type); + set_long(DLP_REQUEST_DATA(req, 0, 36), creator); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_MoveCategory(int sd, int handle, int fromcat, int tocat) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_MoveCategory,"from %d to %d",fromcat,tocat); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncMoveCategory, 1, 4); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), handle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), fromcat); + set_byte(DLP_REQUEST_DATA(req, 0, 2), tocat); + set_byte(DLP_REQUEST_DATA(req, 0, 3), 0); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + if (result >= 0) { + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP MoveCategory Handle: %d, From: %d, To: %d\n", + handle, fromcat, tocat)); + } + + return result; +} + +int +dlp_OpenConduit(int sd) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_OpenConduit); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncOpenConduit, 0); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + /* if this was not done yet, this will read and cache the DLP version + that the Palm is running. We need this when reading responses during + record/resource transfers */ + if (result >= 0) + pi_version(sd); + + return result; +} + +int +dlp_EndOfSync(int sd, int status) +{ + int result; + pi_socket_t *ps; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_EndOfSync); + pi_reset_errors(sd); + + ps = find_pi_socket(sd); + if (ps == NULL) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + req = dlp_request_new(dlpFuncEndOfSync, 1, 2); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short(DLP_REQUEST_DATA(req, 0, 0), status); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + /* Messy code to set end-of-sync flag on socket + so pi_close won't do it for us */ + if (result == 0) + ps->state = PI_SOCK_CONN_END; + + return result; +} + +int +dlp_AbortSync(int sd) +{ + pi_socket_t *ps; + + Trace(dlp_AbortSync); + pi_reset_errors(sd); + + /* Pretend we sent the sync end */ + if ((ps = find_pi_socket(sd)) == NULL) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + ps->state = PI_SOCK_CONN_END; + + return 0; +} + +int +dlp_WriteUserInfo(int sd, const struct PilotUser *User) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + int len; + + Trace(dlp_WriteUserInfo); + pi_reset_errors(sd); + + len = strlen (User->username) + 1; + + req = dlp_request_new (dlpFuncWriteUserInfo, 1, 22 + len); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long(DLP_REQUEST_DATA(req, 0, 0), User->userID); + set_long(DLP_REQUEST_DATA(req, 0, 4), User->viewerID); + set_long(DLP_REQUEST_DATA(req, 0, 8), User->lastSyncPC); + set_date((unsigned char *)DLP_REQUEST_DATA(req, 0, 12), User->lastSyncDate); + set_byte(DLP_REQUEST_DATA(req, 0, 20), 0xff); + set_byte(DLP_REQUEST_DATA(req, 0, 21), len); + strcpy(DLP_REQUEST_DATA(req, 0, 22), User->username); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + dlp_response_free (res); + + return result; +} + +int +dlp_ReadUserInfo(int sd, struct PilotUser *User) +{ + int result; + size_t userlen; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_ReadUserInfo); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncReadUserInfo, 0); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + + if (result > 0) { + User->userID = + get_long(DLP_RESPONSE_DATA (res, 0, 0)); + User->viewerID = + get_long(DLP_RESPONSE_DATA (res, 0, 4)); + User->lastSyncPC = + get_long(DLP_RESPONSE_DATA (res, 0, 8)); + User->successfulSyncDate = + get_date((const unsigned char *)DLP_RESPONSE_DATA (res, 0, 12)); + User->lastSyncDate = + get_date((const unsigned char *)DLP_RESPONSE_DATA (res, 0, 20)); + userlen = + get_byte(DLP_RESPONSE_DATA (res, 0, 28)); + User->passwordLength = + get_byte(DLP_RESPONSE_DATA (res, 0, 29)); + + memcpy(User->username, + DLP_RESPONSE_DATA (res, 0, 30), userlen); + memcpy(User->password, + DLP_RESPONSE_DATA (res, 0, 30 + userlen), + User->passwordLength); + + if (userlen < sizeof(User->username)) + User->username[userlen] = '\0'; + if (User->passwordLength < sizeof(User->password)) + User->password[User->passwordLength] = '\0'; + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadUserInfo UID=0x%8.8lX VID=0x%8.8lX " + "PCID=0x%8.8lX\n", + User->userID, User->viewerID, User->lastSyncPC)); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Last Sync=%s Last Successful Sync=%s", + ctime (&User->lastSyncDate), + ctime (&User->successfulSyncDate))); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " Username=%s\n", User->username)); + } + + dlp_response_free (res); + + return result; +} + +int +dlp_ReadNetSyncInfo(int sd, struct NetSyncInfo *i) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_ReadNetSyncInfo); + pi_reset_errors(sd); + + if (pi_version(sd) < 0x0101) + return pi_set_error(sd, PI_ERR_DLP_UNSUPPORTED); + + req = dlp_request_new(dlpFuncReadNetSyncInfo, 0); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + result = dlp_exec (sd, req, &res); + + dlp_request_free(req); + + if (result >= 0) { + size_t str_offset = 24; + + i->lanSync = get_byte(DLP_RESPONSE_DATA(res, 0, 0)); + + i->hostName[0] = '\0'; + memcpy(i->hostName, DLP_RESPONSE_DATA(res, 0, str_offset), + get_short(DLP_RESPONSE_DATA(res, 0, 18))); + str_offset += get_short(DLP_RESPONSE_DATA(res, 0, 18)); + + i->hostAddress[0] = '\0'; + memcpy(i->hostAddress, DLP_RESPONSE_DATA(res, 0, str_offset), + get_short(DLP_RESPONSE_DATA(res, 0, 20))); + str_offset += get_short(DLP_RESPONSE_DATA(res, 0, 20)); + + i->hostSubnetMask[0] = '\0'; + memcpy(i->hostSubnetMask, DLP_RESPONSE_DATA(res, 0, str_offset), + get_short(DLP_RESPONSE_DATA(res, 0, 22))); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadNetSyncInfo Active: %d\n", i->lanSync ? 1 : 0)); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " PC hostname: '%s', address '%s', mask '%s'\n", + i->hostName, i->hostAddress, i->hostSubnetMask)); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_WriteNetSyncInfo(int sd, const struct NetSyncInfo *i) +{ + int result, + str_offset = 24; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_WriteNetSyncInfo); + pi_reset_errors(sd); + + if (pi_version(sd) < 0x0101) + return pi_set_error(sd, PI_ERR_DLP_UNSUPPORTED); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadNetSyncInfo Active: %d\n", i->lanSync ? 1 : 0)); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " PC hostname: '%s', address '%s', mask '%s'\n", + i->hostName, i->hostAddress, i->hostSubnetMask)); + + req = dlp_request_new(dlpFuncWriteNetSyncInfo, 1, + 24 + strlen(i->hostName) + + strlen(i->hostAddress) + strlen(i->hostSubnetMask) + 3); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + /* Change all settings */ + set_byte(DLP_REQUEST_DATA(req, 0, 0), 0x80 | 0x40 | 0x20 | 0x10); + + set_byte(DLP_REQUEST_DATA(req, 0, 1), i->lanSync); + set_long(DLP_REQUEST_DATA(req, 0, 2), 0); /* Reserved1 */ + set_long(DLP_REQUEST_DATA(req, 0, 6), 0); /* Reserved2 */ + set_long(DLP_REQUEST_DATA(req, 0, 10), 0); /* Reserved3 */ + set_long(DLP_REQUEST_DATA(req, 0, 14), 0); /* Reserved4 */ + set_short(DLP_REQUEST_DATA(req, 0, 18), strlen(i->hostName) + 1); + set_short(DLP_REQUEST_DATA(req, 0, 20), strlen(i->hostAddress) + 1); + set_short(DLP_REQUEST_DATA(req, 0, 22), strlen(i->hostSubnetMask) + 1); + + strcpy(DLP_REQUEST_DATA(req, 0, str_offset), i->hostName); + str_offset += strlen(i->hostName) + 1; + strcpy(DLP_REQUEST_DATA(req, 0, str_offset), i->hostAddress); + str_offset += strlen(i->hostAddress) + 1; + strcpy(DLP_REQUEST_DATA(req, 0, str_offset), i->hostSubnetMask); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +#ifdef _PILOT_SYSPKT_H +int +dlp_RPC(int sd, struct RPC_params *p, unsigned long *result) +{ + int i, + err = 0; + long D0 = 0, + A0 = 0; + unsigned char *c; + pi_buffer_t *dlp_buf; + + Trace(dlp_RPC); + pi_reset_errors(sd); + + /* RPC through DLP breaks all the rules and isn't well documented to + boot */ + dlp_buf = pi_buffer_new (DLP_BUF_SIZE); + if (dlp_buf == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + dlp_buf->data[0] = 0x2D; + dlp_buf->data[1] = 1; + dlp_buf->data[2] = 0; /* Unknown filler */ + dlp_buf->data[3] = 0; + + InvertRPC(p); + + set_short(dlp_buf->data + 4, p->trap); + set_long(dlp_buf->data + 6, D0); + set_long(dlp_buf->data + 10, A0); + set_short(dlp_buf->data + 14, p->args); + + c = dlp_buf->data + 16; + for (i = p->args - 1; i >= 0; i--) { + set_byte(c, p->param[i].byRef); + c++; + set_byte(c, p->param[i].size); + c++; + if (p->param[i].data) + memcpy(c, p->param[i].data, p->param[i].size); + c += p->param[i].size; + if (p->param[i].size & 1) + *c++ = 0; + } + + if (pi_write(sd, dlp_buf->data, (size_t)(c - dlp_buf->data)) > 0) { + err = 0; + if (p->reply) { + int l = pi_read(sd, dlp_buf, (size_t)(c - dlp_buf->data + 2)); + + if (l < 0) + err = l; + else if (l < 6) + err = -1; + else if (dlp_buf->data[0] != 0xAD) + err = -2; + else if (get_short(dlp_buf->data + 2)) { + err = -get_short(dlp_buf->data + 2); + pi_set_palmos_error(sd, -err); + } else { + D0 = get_long(dlp_buf->data + 8); + A0 = get_long(dlp_buf->data + 12); + c = dlp_buf->data + 18; + for (i = p->args - 1; i >= 0; i--) { + if (p->param[i].byRef && p->param[i].data) + memcpy(p->param[i].data, c + 2, + p->param[i].size); + c += 2 + ((p->param[i].size + 1) & + (unsigned)~1); + } + } + } + } + + pi_buffer_free (dlp_buf); + + UninvertRPC(p); + + if (result) { + if (p->reply == RPC_PtrReply) { + *result = A0; + } else if (p->reply == RPC_IntReply) { + *result = D0; + } + } + + return err; +} + + +int +dlp_ReadFeature(int sd, unsigned long creator, int num, + unsigned long *feature) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_ReadFeature,"creator='%4.4s' num=%d",(const char *)&creator,num); + pi_reset_errors(sd); + + if (pi_version(sd) < 0x0101) { + struct RPC_params p; + int val; + unsigned long errCode; + + if (feature == NULL) + return 0; + + *feature = 0x12345678; + + PackRPC(&p, 0xA27B, RPC_IntReply, RPC_Long(creator), RPC_Short(num), RPC_LongPtr(feature), RPC_End); + + val = dlp_RPC(sd, &p, &errCode); + + if (val < 0) { + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadFeature Error: %s (%d)\n", + dlp_errorlist[-val], val)); + + return val; + } + + if (errCode) { + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadFeature FtrGet error 0x%8.8lX\n", + res)); + pi_set_palmos_error(sd, (int)errCode); + return pi_set_error(sd, PI_ERR_DLP_PALMOS); + } + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " DLP ReadFeature Feature: 0x%8.8lX\n", + (unsigned long) *feature)); + + return 0; + } + + Trace(dlp_ReadFeatureV2); + + req = dlp_request_new(dlpFuncReadFeature, 1, 6); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long(DLP_REQUEST_DATA(req, 0, 0), creator); + set_short(DLP_REQUEST_DATA(req, 0, 4), num); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + if (feature) + *feature = (unsigned long) + get_long(DLP_RESPONSE_DATA(res, 0, 0)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadFeature Feature: 0x%8.8lX\n", + (unsigned long) + get_long(DLP_RESPONSE_DATA(res, 0, 0)))); + } + + dlp_response_free(res); + + return result; +} +#endif /* IFDEF _PILOT_SYSPKT_H */ + +int +dlp_GetROMToken(int sd, unsigned long token, void *buffer, size_t *size) +{ + unsigned long result; + + struct RPC_params p; + + int val; + unsigned long buffer_ptr; + + Trace(dlp_GetROMToken); + pi_reset_errors(sd); + +#ifdef DLP_TRACE + if (dlp_trace) { + fprintf(stderr, + " Wrote: Token: '%s'\n", + printlong(token)); + } +#endif + + PackRPC(&p, 0xa340, RPC_IntReply, /* sysTrapHwrGetROMToken */ + RPC_Short(0), + RPC_Long(token), + RPC_LongPtr(&buffer_ptr), + RPC_ShortPtr(size), RPC_End); + + val = dlp_RPC(sd, &p, &result); + +#ifdef DLP_TRACE + if (dlp_trace) { + if (val < 0) + fprintf(stderr, + "Result: Error: %s (%d)\n", + dlp_errorlist[-val], val); + else if (result) + fprintf(stderr, + "FtrGet error 0x%8.8lX\n", + (unsigned long) result); + else + fprintf(stderr, + " Read: Buffer Ptr: 0x%8.8lX Size: %d\n", + (unsigned long) buffer_ptr, *size); + } +#endif + + if (buffer) { + ((unsigned char *)buffer)[*size] = 0; + + PackRPC(&p, 0xa026, RPC_IntReply, /* sysTrapMemMove */ + RPC_Ptr(buffer, *size), + RPC_Long(buffer_ptr), + RPC_Long((unsigned long) *size), + RPC_End); + + val = dlp_RPC(sd, &p, &result); + } + +#ifdef DLP_TRACE + if (dlp_trace) { + if (val < 0) + fprintf(stderr, + "Result: Error: %s (%d)\n", + dlp_errorlist[-val], val); + else if (result) + fprintf(stderr, + "FtrGet error 0x%8.8lX\n", + (unsigned long) result); + else + fprintf(stderr, + " Read: Buffer: %s\n", buffer); + } +#endif + + if (val < 0) + return val; + + if (result) + return -((int)result); + + return result; +} + +int +dlp_ResetLastSyncPC(int sd) +{ + int err; + struct PilotUser User; + + Trace(dlp_ResetLastSyncPC); + + if ((err = dlp_ReadUserInfo(sd, &User)) < 0) + return err; + + User.lastSyncPC = 0; + + return dlp_WriteUserInfo(sd, &User); +} + +int +dlp_ResetDBIndex(int sd, int dbhandle) +{ + int result; + pi_socket_t *ps; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_ResetDBIndex); + pi_reset_errors(sd); + + if ((ps = find_pi_socket(sd)) == NULL) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + ps->dlprecord = 0; + + req = dlp_request_new(dlpFuncResetRecordIndex, 1, 1); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_ReadRecordIDList(int sd, int dbhandle, int sort, int start, int max, + recordid_t * IDs, int *count) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_ReadRecordIDList,"sort=%d start=%d max=%d", + sort,start,max); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncReadRecordIDList, 1, 6); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), sort ? 0x80 : 0); + set_short(DLP_REQUEST_DATA(req, 0, 2), start); + set_short(DLP_REQUEST_DATA(req, 0, 4), max); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + int ret, i; + + ret = get_short(DLP_RESPONSE_DATA(res, 0, 0)); + for (i = 0; i < ret; i++) + IDs[i] = + get_long(DLP_RESPONSE_DATA(res, 0, 2 + (i * 4))); + + if (count) + *count = ret; + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadRecordIDList %d IDs:\n", ret)); + CHECK(PI_DBG_DLP, PI_DBG_LVL_DEBUG, + pi_dumpdata(DLP_RESPONSE_DATA(res, 0, 2), + (size_t)(ret * 4))); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_WriteRecord(int sd, int dbhandle, int flags, recordid_t recID, + int catID, const void *data, size_t length, recordid_t *pNewRecID) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_WriteRecord); + pi_reset_errors(sd); + + if (length == (size_t)-1) + length = strlen((char *) data) + 1; + + if (pi_version(sd) >= 0x0104) { + req = dlp_request_new(dlpFuncWriteRecordEx, 1, 12 + length); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0x80); /* "data included" */ + set_long(DLP_REQUEST_DATA(req, 0, 2), recID); + set_byte(DLP_REQUEST_DATA(req, 0, 6), flags); + set_byte(DLP_REQUEST_DATA(req, 0, 7), catID); + set_long(DLP_REQUEST_DATA(req, 0, 8), 0); + + memcpy(DLP_REQUEST_DATA(req, 0, 12), data, length); + } else { + if ((length + 8) > DLP_BUF_SIZE) { + LOG((PI_DBG_DLP, PI_DBG_LVL_ERR, + "DLP WriteRecord: data too large (>64k)")); + return PI_ERR_DLP_DATASIZE; + } + + req = dlp_request_new(dlpFuncWriteRecord, 1, 8 + length); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0x80); /* "data included" */ + set_long(DLP_REQUEST_DATA(req, 0, 2), recID); + set_byte(DLP_REQUEST_DATA(req, 0, 6), flags); + set_byte(DLP_REQUEST_DATA(req, 0, 7), catID); + + memcpy(DLP_REQUEST_DATA(req, 0, 8), data, length); + } + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + if (pNewRecID) + *pNewRecID = get_long(DLP_RESPONSE_DATA(res, 0, 0)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP WriteRecord Record ID: 0x%8.8lX\n", + get_long(DLP_RESPONSE_DATA(res, 0, 0)))); + + CHECK(PI_DBG_DLP, PI_DBG_LVL_DEBUG, + record_dump( + get_long(DLP_RESPONSE_DATA(res, 0, 0)), /* recID */ + 0xffff, /* index */ + flags, + catID, + (const char *)data, (int)length)); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_DeleteRecord(int sd, int dbhandle, int all, recordid_t recID) +{ + int result, + flags = all ? 0x80 : 0; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_DeleteRecord); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncDeleteRecord, 1, 6); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), flags); + set_long(DLP_REQUEST_DATA(req, 0, 2), recID); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_DeleteCategory(int sd, int dbhandle, int category) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_DeleteCategory,"category=%d",category); + pi_reset_errors(sd); + + if (pi_version(sd) < 0x0101) { + /* Emulate if not connected to PalmOS 2.0 */ + int i, cat, attr; + recordid_t id_; + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP DeleteCategory Emulating with: Handle: %d, " + "Category: %d\n", + dbhandle, category & 0xff)); + + for (i = 0; + (result = dlp_ReadRecordByIndex(sd, dbhandle, i, NULL, &id_, + &attr, &cat)) >= 0; i++) { + if (cat != category + || (attr & dlpRecAttrDeleted) + || (attr & dlpRecAttrArchived)) + continue; + result = dlp_DeleteRecord(sd, dbhandle, 0, id_); + if (result < 0) + break; + i--; /* Sigh, deleting record moves it to the end. */ + } + + return result; + } else { + int flags = 0x40; + + req = dlp_request_new(dlpFuncDeleteRecord, 1, 6); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), flags); + set_long(DLP_REQUEST_DATA(req, 0, 2), category & 0xff); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; + } +} + +int +dlp_ReadResourceByType(int sd, int dbhandle, unsigned long type, int resID, + pi_buffer_t *buffer, int *resindex) +{ + int result, + data_len; + struct dlpRequest *req; + struct dlpResponse *res; + int maxBufferSize = pi_maxrecsize(sd) - RECORD_READ_SAFEGUARD_SIZE; + + TraceX(dlp_ReadResourceByType,"type='%4.4s' resID=%d",(const char *)&type,resID); + pi_reset_errors(sd); + + req = dlp_request_new_with_argid(dlpFuncReadResource, 0x21, 1, 12); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + set_long(DLP_REQUEST_DATA(req, 0, 2), type); + set_short(DLP_REQUEST_DATA(req, 0, 6), resID); + set_short(DLP_REQUEST_DATA(req, 0, 8), 0); + set_short(DLP_REQUEST_DATA(req, 0, 10), buffer ? maxBufferSize : 0); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + data_len = res->argv[0]->len - 10; + if (resindex) + *resindex = get_short(DLP_RESPONSE_DATA(res, 0, 6)); + if (buffer) { + pi_buffer_clear (buffer); + pi_buffer_append (buffer, DLP_RESPONSE_DATA(res, 0, 10), + (size_t)data_len); + + /* Some devices such as the Tungsten TX, Treo 650 and Treo 700p lock up if you try to read the entire record if the + ** record is almost at the maximum record size. The following mitigates this and allows the record + ** to be read in two chunks. + */ + if (data_len == maxBufferSize) { + dlp_response_free(res); + req = dlp_request_new_with_argid(dlpFuncReadResource, 0x21, 1, 12); + if (req != NULL) { + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + set_long(DLP_REQUEST_DATA(req, 0, 2), type); + set_short(DLP_REQUEST_DATA(req, 0, 6), resID); + set_short(DLP_REQUEST_DATA(req, 0, 8), maxBufferSize); /* Offset in record */ + set_short(DLP_REQUEST_DATA(req, 0, 10), RECORD_READ_SAFEGUARD_SIZE); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + data_len = res->argv[0]->len - 10; /* number of bytes returned by the second read... */ + pi_buffer_append (buffer, DLP_RESPONSE_DATA(res, 0, 10), (size_t)data_len); + data_len += maxBufferSize; /* ...that add up to the bytes received in the first read */ + } + } + } + } + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadResourceByType Type: '%s', ID: %d, " + "Index: %d, and %d bytes:\n", + printlong(type), resID, + get_short(DLP_RESPONSE_DATA(res, 0, 6)),(size_t)data_len)); + CHECK(PI_DBG_DLP, PI_DBG_LVL_DEBUG, + pi_dumpdata(DLP_RESPONSE_DATA(res, 0, 10),(size_t)data_len)); + } else { + data_len = result; + } + + dlp_response_free(res); + + return data_len; +} + +int +dlp_ReadResourceByIndex(int sd, int dbhandle, unsigned int resindex, pi_buffer_t *buffer, + unsigned long *type, int *resID) +{ + int result, + data_len, + large = 0; + struct dlpRequest *req; + struct dlpResponse *res; + int maxBufferSize = pi_maxrecsize(sd) - RECORD_READ_SAFEGUARD_SIZE; + + TraceX(dlp_ReadResourceByIndex,"resindex=%d",resindex); + pi_reset_errors(sd); + + /* TapWave (DLP 1.4) implements a `large' version of dlpFuncReadResource, + * which can return resources >64k + */ + if (pi_version(sd) >= 0x0104) { + req = dlp_request_new (dlpFuncReadResourceEx, 1, 12); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + set_short(DLP_REQUEST_DATA(req, 0, 2), resindex); + set_long(DLP_REQUEST_DATA(req, 0, 4), 0); + set_long(DLP_REQUEST_DATA(req, 0, 8), pi_maxrecsize(sd)); + large = 1; + } else { + req = dlp_request_new (dlpFuncReadResource, 1, 8); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + set_short(DLP_REQUEST_DATA(req, 0, 2), resindex); + set_long(DLP_REQUEST_DATA(req, 0, 4), maxBufferSize); + } + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + data_len = res->argv[0]->len - (large ? 12 : 10); + if (type) + *type = get_long(DLP_RESPONSE_DATA(res, 0, 0)); + if (resID) + *resID = get_short(DLP_RESPONSE_DATA(res, 0, 4)); + if (buffer) { + pi_buffer_clear (buffer); + pi_buffer_append (buffer, DLP_RESPONSE_DATA(res, 0, large ? 12 : 10), + (size_t)data_len); + + /* Some devices such as the Tungsten TX, Treo 650 and Treo 700p lock up if you try to read the entire record if the + ** record is almost at the maximum record size. The following mitigates this and allows the record + ** to be read in two chunks. + */ + if (data_len == maxBufferSize && !large) { + dlp_response_free(res); + req = dlp_request_new (dlpFuncReadResource, 1, 8); + if (req != NULL) { + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + set_short(DLP_REQUEST_DATA(req, 0, 2), resindex); + set_short(DLP_REQUEST_DATA(req, 0, 4), maxBufferSize); /* Offset in record */ + set_short(DLP_REQUEST_DATA(req, 0, 6), RECORD_READ_SAFEGUARD_SIZE); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + data_len = res->argv[0]->len - (large ? 12 : 10); /* number of bytes returned by the second read... */ + pi_buffer_append (buffer, DLP_RESPONSE_DATA(res, 0, large ? 12 : 10), + (size_t)data_len); + data_len += maxBufferSize; /* ...that add up to the bytes received in the first read */ + } + } + } + } + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadResourceByIndex Type: '%s', ID: %d, " + "Index: %d, and %d bytes:\n", + printlong(get_long(DLP_RESPONSE_DATA(res, 0, 0))), + get_short(DLP_RESPONSE_DATA(res, 0, 4)), + resindex, data_len)); + CHECK(PI_DBG_DLP, PI_DBG_LVL_DEBUG, + pi_dumpdata(DLP_RESPONSE_DATA(res, 0, (large ? 12 : 10)), + (size_t)data_len)); + } else { + data_len = result; + } + + dlp_response_free(res); + + return data_len; +} + +int +dlp_WriteResource(int sd, int dbhandle, unsigned long type, int resID, + const void *data, size_t length) +{ + int result, + large = 0; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_WriteResource,"'%4.4s' #%d",(const char *)&type,resID); + pi_reset_errors(sd); + + /* TapWave (DLP 1.4) implements a `large' version of dlpFuncWriteResource, + * which can store records >64k + */ + if (pi_version(sd) >= 0x0104) { + req = dlp_request_new_with_argid(dlpFuncWriteResourceEx, + PI_DLP_ARG_FIRST_ID | PI_DLP_ARG_FLAG_LONG, 1, 12 + length); + large = 1; + } else { + if (length > 0xffff) + length = 0xffff; + req = dlp_request_new(dlpFuncWriteResource, 1, 10 + length); + } + if (req == NULL) { + LOG((PI_DBG_DLP, PI_DBG_LVL_ERR, + "DLP sd:%i large:%i dlp_request_new failed\n", + sd, large)); + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + } + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + set_long(DLP_REQUEST_DATA(req, 0, 2), type); + set_short(DLP_REQUEST_DATA(req, 0, 6), resID); + if (large) + set_long (DLP_REQUEST_DATA(req, 0, 8), 0); /* device doesn't want length here (it computes it) */ + else + set_short(DLP_REQUEST_DATA(req, 0, 8), length); + + memcpy(DLP_REQUEST_DATA(req, 0, large ? 12 : 10), data, length); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + + +int +dlp_DeleteResource(int sd, int dbhandle, int all, unsigned long restype, + int resID) +{ + int result, + flags = all ? 0x80 : 0; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_DeleteResource,"restype='%4.4s' resID=%d all=%d", + (const char *)&restype,resID,all); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncDeleteResource, 1, 8); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), flags); + set_long(DLP_REQUEST_DATA(req, 0, 2), restype); + set_short(DLP_REQUEST_DATA(req, 0, 6), resID); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_ReadAppBlock(int sd, int dbhandle, int offset, int reqbytes, pi_buffer_t *retbuf) +{ + int result, + data_len; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_ReadAppBlock,"offset=%d reqbytes=%ld",offset,reqbytes); + pi_reset_errors(sd); + + if (retbuf) + pi_buffer_clear(retbuf); + + req = dlp_request_new(dlpFuncReadAppBlock, 1, 6); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + set_short(DLP_REQUEST_DATA(req, 0, 2), offset); + set_short(DLP_REQUEST_DATA(req, 0, 4), reqbytes); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result >= 0) { + if (result < 2) + data_len = PI_ERR_DLP_COMMAND; + else { + data_len = res->argv[0]->len - 2; + if (retbuf && data_len) + pi_buffer_append(retbuf, DLP_RESPONSE_DATA(res, 0, 2), + (size_t)data_len); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadAppBlock %d bytes\n", data_len)); + CHECK(PI_DBG_DLP, PI_DBG_LVL_DEBUG, + pi_dumpdata(DLP_RESPONSE_DATA(res, 0, 2), + (size_t)data_len)); + } + } else { + data_len = result; + } + + dlp_response_free(res); + + return data_len; +} + +int +dlp_WriteAppBlock(int sd, int dbhandle, const /* @unique@ */ void *data, + size_t length) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_WriteAppBlock,"length=%ld",length); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncWriteAppBlock, 1, 4 + length); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + set_short(DLP_REQUEST_DATA(req, 0, 2), length); + + if (length + 10 > DLP_BUF_SIZE) { + LOG((PI_DBG_DLP, PI_DBG_LVL_ERR, + "DLP WriteAppBlock: data too large (>64k)")); + pi_set_error(sd, PI_ERR_DLP_DATASIZE); + return -131; + } + if (length) + memcpy(DLP_REQUEST_DATA(req, 0, 4), data, length); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_ReadSortBlock(int sd, int dbhandle, int offset, int reqbytes, pi_buffer_t *retbuf) +{ + int result, + data_len; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_ReadSortBlock,"offset=%d reqbytes=%d",offset,reqbytes); + pi_reset_errors(sd); + + if (retbuf) + pi_buffer_clear(retbuf); + + req = dlp_request_new(dlpFuncReadSortBlock, 1, 6); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + set_short(DLP_REQUEST_DATA(req, 0, 2), offset); + set_short(DLP_REQUEST_DATA(req, 0, 4), reqbytes); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result >= 0) { + if (result < 2) + data_len = PI_ERR_DLP_COMMAND; + else { + data_len = res->argv[0]->len - 2; + if (retbuf) + pi_buffer_append(retbuf, DLP_RESPONSE_DATA(res, 0, 2), + (size_t)data_len); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadSortBlock %d bytes\n", data_len)); + CHECK(PI_DBG_DLP, PI_DBG_LVL_DEBUG, + pi_dumpdata(DLP_RESPONSE_DATA(res, 0, 2), + (size_t)data_len)); + } + } else { + data_len = result; + } + + dlp_response_free(res); + + return data_len; +} + +int +dlp_WriteSortBlock(int sd, int dbhandle, const /* @unique@ */ void *data, + size_t length) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_WriteSortBlock,"length=%ld",length); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncWriteSortBlock, 1, 4 + length); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + set_short(DLP_REQUEST_DATA(req, 0, 2), length); + + if (length + 10 > DLP_BUF_SIZE) { + LOG((PI_DBG_DLP, PI_DBG_LVL_ERR, + "DLP WriteSortBlock: data too large (>64k)")); + pi_set_error(sd, PI_ERR_DLP_DATASIZE); + return -131; + } + memcpy(DLP_REQUEST_DATA(req, 0, 4), data, length); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_CleanUpDatabase(int sd, int dbhandle) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_CleanUpDatabase); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncCleanUpDatabase, 1, 1); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_ResetSyncFlags(int sd, int dbhandle) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dpl_ResetSyncFlags); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncResetSyncFlags, 1, 1); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_ReadNextRecInCategory(int sd, int dbhandle, int category, + pi_buffer_t *buffer, recordid_t *recuid, int *recindex, + int *attr) +{ + int result, + data_len, + flags; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_ReadNextRecInCategory,"category=%d",category); + pi_reset_errors(sd); + + if (pi_version(sd) < 0x0101) { + /* Emulate for PalmOS 1.0 */ + int cat, + rec; + pi_socket_t *ps; + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadNextRecInCategory Emulating with: Handle: %d, " + "Category: %d\n", + dbhandle, category)); + + if ((ps = find_pi_socket(sd)) == 0) { + errno = ESRCH; + return -130; + } + + for (;;) { + /* Fetch next modified record (in any category) */ + rec = dlp_ReadRecordByIndex(sd, dbhandle, + ps->dlprecord, 0, 0, + 0, &cat); + + if (rec < 0) + break; + + if (cat != category) { + ps->dlprecord++; + continue; + } + + rec = dlp_ReadRecordByIndex(sd, dbhandle, + ps->dlprecord, buffer, + recuid, attr, &cat); + + if (rec >= 0) { + if (recindex) + *recindex = ps->dlprecord; + ps->dlprecord++; + } else { + /* If none found, reset modified pointer so + that another search on a different (or + the same!) category will work */ + + /* Freeow! Do _not_ reset, as the Palm + itself does not! + + ps->dlprecord = 0; */ + } + + break; + } + + return rec; + } + + req = dlp_request_new(dlpFuncReadNextRecInCategory, 1, 2); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), category); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + data_len = res->argv[0]->len - 10; + if (recuid) + *recuid = get_long(DLP_RESPONSE_DATA(res, 0, 0)); + if (recindex) + *recindex = get_short(DLP_RESPONSE_DATA(res, 0, 4)); + if (attr) + *attr = get_byte(DLP_RESPONSE_DATA(res, 0, 8)); + if (buffer) { + pi_buffer_clear (buffer); + pi_buffer_append (buffer, DLP_RESPONSE_DATA(res, 0, 10), + (size_t)data_len); + } + + flags = get_byte(DLP_RESPONSE_DATA(res, 0, 8)); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadNextRecInCategory ID: 0x%8.8lX, " + "Index: %d, Category: %d\n" + " Flags: %s%s%s%s%s%s (0x%2.2X) and %d bytes:\n", + (unsigned long) get_long(DLP_RESPONSE_DATA(res, + 0, 0)), + get_short(DLP_RESPONSE_DATA(res, 0, 4)), + (int) get_byte(DLP_RESPONSE_DATA(res, 0, 9)), + (flags & dlpRecAttrDeleted) ? " Deleted" : "", + (flags & dlpRecAttrDirty) ? " Dirty" : "", + (flags & dlpRecAttrBusy) ? " Busy" : "", + (flags & dlpRecAttrSecret) ? " Secret" : "", + (flags & dlpRecAttrArchived) ? " Archive" : "", + (!flags) ? " None" : "", + flags, data_len)); + CHECK(PI_DBG_DLP, PI_DBG_LVL_DEBUG, + pi_dumpdata(DLP_RESPONSE_DATA(res, 0, 10), + (size_t)data_len)); + } else { + data_len = result; + } + + dlp_response_free(res); + + return data_len; +} + +int +dlp_ReadAppPreference(int sd, unsigned long creator, int prefID, int backup, + int maxsize, void *buffer, size_t *size, int *version) +{ + int result, + data_len; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_ReadAppPreference,"creator='%4.4s' prefID=%d backup=%d maxsize=%d", + (const char *)creator,prefID,backup,maxsize); + pi_reset_errors(sd); + + if (pi_version(sd) < 0x0101) { + /* Emulate on PalmOS 1.0 */ + int db; + pi_buffer_t *buf; + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadAppPreference Emulating with: Creator: '%s', " + "Id: %d, Size: %d, Backup: %d\n", + printlong(creator), prefID, + buffer ? maxsize : 0, backup ? 0x80 : 0)); + + result = dlp_OpenDB(sd, 0, dlpOpenRead, "System Preferences", &db); + if (result < 0) + return result; + + buf = pi_buffer_new (1024); + + result = dlp_ReadResourceByType(sd, db, creator, prefID, buf,NULL); + + if (result < 0) { + /* have to keep the previous error codes to properly return it */ + int err1 = pi_error(sd); + int err2 = pi_palmos_error(sd); + + pi_buffer_free (buf); + if (err1 != PI_ERR_SOCK_DISCONNECTED) + dlp_CloseDB(sd, db); + + pi_set_error(sd, err1); + pi_set_palmos_error(sd, err2); + return result; + } + + if (size) + *size = buf->used - 2; + + if (version) + *version = get_short(buf->data); + + if (result > 2) { + result -= 2; + memcpy(buffer, buf->data + 2, (size_t)result); + } else { + result = 0; + } + + pi_buffer_free (buf); + dlp_CloseDB(sd, db); + return result; + } + + req = dlp_request_new(dlpFuncReadAppPreference, 1, 10); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long(DLP_REQUEST_DATA(req, 0, 0), creator); + set_short(DLP_REQUEST_DATA(req, 0, 4), prefID); + set_short(DLP_REQUEST_DATA(req, 0, 6), buffer ? maxsize : 0); + set_byte(DLP_REQUEST_DATA(req, 0, 8), backup ? 0x80 : 0); + set_byte(DLP_REQUEST_DATA(req, 0, 9), 0); /* Reserved */ + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + data_len = get_short(DLP_RESPONSE_DATA(res, 0, 4)); + if (version) + *version = get_short(DLP_RESPONSE_DATA(res, 0, 0)); + if (size && !buffer) *size = + get_short(DLP_RESPONSE_DATA(res, 0, 2)); /* Total sz */ + if (size && buffer) + *size = data_len; /* Size returned */ + if (buffer) + memcpy(buffer, DLP_RESPONSE_DATA(res, 0, 6), + (size_t)data_len); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadAppPref Version: %d, " + "Total size: %d, Read %d bytes:\n", + get_short(DLP_RESPONSE_DATA(res, 0, 0)), + get_short(DLP_RESPONSE_DATA(res, 0, 2)), + get_short(DLP_RESPONSE_DATA(res, 0, 4)))); + CHECK(PI_DBG_DLP, PI_DBG_LVL_DEBUG, + pi_dumpdata(DLP_RESPONSE_DATA(res, 0, 6), + (size_t)data_len)); + } else { + data_len = result; + } + + dlp_response_free(res); + + return data_len; +} + +int +dlp_WriteAppPreference(int sd, unsigned long creator, int prefID, int backup, + int version, const void *buffer, size_t size) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_WriteAppPreference,"creator='%4.4s' prefID=%d backup=%d version=%d size=%ld", + (const char *)&creator,prefID,backup,version,size); + pi_reset_errors(sd); + + if (pi_version(sd) < 0x0101) { + /* Emulate on PalmOS 1.0 */ + int db, + err1, + err2; + + if ((result = dlp_OpenDB(sd, 0, dlpOpenWrite, "System Preferences", + &db)) < 0) + return result; + + if (buffer && size) { + unsigned char dlp_buf[DLP_BUF_SIZE]; + memcpy(dlp_buf + 2, buffer, size); + set_short(dlp_buf, version); + result = dlp_WriteResource(sd, db, creator, prefID, dlp_buf, + size); + } else { + result = dlp_WriteResource(sd, db, creator, prefID, NULL, + 0); + } + err1 = pi_error(sd); + err2 = pi_palmos_error(sd); + + if (err1 != PI_ERR_SOCK_DISCONNECTED) + dlp_CloseDB(sd, db); + + if (result < 0) { + /* restore previous error after DB close */ + pi_set_error(sd, err1); + pi_set_palmos_error(sd, err2); + } + return result; + } + + req = dlp_request_new(dlpFuncWriteAppPreference, 1, 12 + size); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long(DLP_REQUEST_DATA(req, 0, 0), creator); + set_short(DLP_REQUEST_DATA(req, 0, 4), prefID); + set_short(DLP_REQUEST_DATA(req, 0, 6), version); + set_short(DLP_REQUEST_DATA(req, 0, 8), size); + set_byte(DLP_REQUEST_DATA(req, 0, 10), backup ? 0x80 : 0); + set_byte(DLP_REQUEST_DATA(req, 0, 11), 0); /* Reserved */ + + if ((size + 12) > DLP_BUF_SIZE) { + LOG((PI_DBG_DLP, PI_DBG_LVL_ERR, + "DLP WriteAppPreferenceV2: data too large (>64k)")); + return PI_ERR_DLP_DATASIZE; + } + memcpy(DLP_REQUEST_DATA(req, 0, 12), buffer, size); + + result = dlp_exec (sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_ReadNextModifiedRecInCategory(int sd, int dbhandle, int category, + pi_buffer_t *buffer, recordid_t *recID, + int *recindex, int *attr) +{ + int result, + data_len; + struct dlpRequest *req; + struct dlpResponse *res; + + TraceX(dlp_ReadNextModifiedRecInCategory,"category=%d",category); + pi_reset_errors(sd); + + if (pi_version(sd) < 0x0101) { + /* Emulate for PalmOS 1.0 */ + int cat; + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ReadNextModifiedRecInCategory" + " Emulating with: Handle: %d, Category: %d\n", + dbhandle, category)); + + do { + /* Fetch next modified record (in any category) */ + result = dlp_ReadNextModifiedRec(sd, dbhandle, buffer, + recID, recindex, attr, &cat); + + /* If none found, reset modified pointer so that + another search on a different (or the same!) category + will start from the beginning */ + + /* Working on same assumption as ReadNextRecInCat, + elide this: + if (r < 0) + dlp_ResetDBIndex(sd, fHandle); + */ + + /* Loop until we fail to get a record or a record + is found in the proper category */ + } + while (result >= 0 && cat != category); + + return result; + } + + req = dlp_request_new(dlpFuncReadNextModifiedRecInCategory, 1, 2); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), category); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + data_len = res->argv[0]->len - 10; + + if (recID) + *recID = get_long(DLP_RESPONSE_DATA(res, 0, 0)); + if (recindex) + *recindex = get_short(DLP_RESPONSE_DATA(res, 0, 4)); + if (attr) + *attr = get_byte(DLP_RESPONSE_DATA(res, 0, 8)); + + if (buffer) { + pi_buffer_clear (buffer); + pi_buffer_append (buffer, DLP_RESPONSE_DATA(res, 0, 10), + (size_t)data_len); + } + + CHECK(PI_DBG_DLP, PI_DBG_LVL_DEBUG, + record_dump( + get_long(DLP_RESPONSE_DATA(res, 0, 0)), /* recID */ + get_short(DLP_RESPONSE_DATA(res, 0, 4)), /* index */ + get_byte(DLP_RESPONSE_DATA(res, 0, 8)), /* flags */ + get_byte(DLP_RESPONSE_DATA(res, 0, 9)), /* catID */ + DLP_RESPONSE_DATA(res, 0, 10), data_len)); + } else { + data_len = result; + } + + dlp_response_free(res); + + return data_len; +} + +int +dlp_ReadNextModifiedRec(int sd, int dbhandle, pi_buffer_t *buffer, recordid_t * recID, + int *recindex, int *attr, int *category) +{ + int result, + data_len; + struct dlpRequest *req; + struct dlpResponse *res; + + Trace(dlp_ReadNextModifiedRec); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncReadNextModifiedRec, 1, 1); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + + result = dlp_exec (sd, req, &res); + + dlp_request_free(req); + + if (result >= 0) { + data_len = res->argv[0]->len -10; + if (recID) + *recID = get_long(DLP_RESPONSE_DATA(res, 0, 0)); + if (recindex) + *recindex = get_short(DLP_RESPONSE_DATA(res, 0, 4)); + if (attr) + *attr = get_byte(DLP_RESPONSE_DATA(res, 0, 8)); + if (category) + *category = get_byte(DLP_RESPONSE_DATA(res, 0, 9)); + + if (buffer) { + pi_buffer_clear (buffer); + pi_buffer_append (buffer, DLP_RESPONSE_DATA(res, 0, 10), + (size_t)data_len); + } + + CHECK(PI_DBG_DLP, PI_DBG_LVL_DEBUG, + record_dump( + get_long(DLP_RESPONSE_DATA(res, 0, 0)), /* recID */ + get_short(DLP_RESPONSE_DATA(res, 0, 4)), /* index */ + get_byte(DLP_RESPONSE_DATA(res, 0, 8)), /* flags */ + get_byte(DLP_RESPONSE_DATA(res, 0, 9)), /* catID */ + DLP_RESPONSE_DATA(res, 0, 10), data_len)); + } else { + data_len = result; + } + + dlp_response_free(res); + + return data_len; +} + +int +dlp_ReadRecordById(int sd, int dbhandle, recordid_t recuid, pi_buffer_t *buffer, + int *recindex, int *attr, int *category) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + int maxBufferSize = pi_maxrecsize(sd) - RECORD_READ_SAFEGUARD_SIZE; + + TraceX(dlp_ReadRecordById,"recuid=0x%08lx",recuid); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncReadRecord, 1, 10); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + set_long(DLP_REQUEST_DATA(req, 0, 2), recuid); + set_short(DLP_REQUEST_DATA(req, 0, 6), 0); /* Offset into record */ + set_short(DLP_REQUEST_DATA(req, 0, 8), buffer ? maxBufferSize : 0); /* length to return */ + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + result = res->argv[0]->len - 10; + if (recindex) + *recindex = get_short(DLP_RESPONSE_DATA(res, 0, 4)); + if (attr) + *attr = get_byte(DLP_RESPONSE_DATA(res, 0, 8)); + if (category) + *category = get_byte(DLP_RESPONSE_DATA(res, 0, 9)); + if (buffer) { + pi_buffer_clear (buffer); + pi_buffer_append (buffer, DLP_RESPONSE_DATA(res, 0, 10), + (size_t)result); + + /* Some devices such as the Tungsten TX, Treo 650 and Treo 700p lock up if you try to read the entire record if the + ** record is almost at the maximum record size. The following mitigates this and allows the record + ** to be read in two chunks. + */ + if (result == maxBufferSize) { + dlp_response_free(res); + req = dlp_request_new(dlpFuncReadRecord, 1, 10); + if (req != NULL) { + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0); + set_long(DLP_REQUEST_DATA(req, 0, 2), recuid); + set_short(DLP_REQUEST_DATA(req, 0, 6), maxBufferSize); /* Offset into record */ + set_short(DLP_REQUEST_DATA(req, 0, 8), buffer ? RECORD_READ_SAFEGUARD_SIZE : 0); /* length to return */ + + result = dlp_exec(sd, req, &res); + dlp_request_free(req); + + if (result > 0) { + result = res->argv[0]->len - 10; + pi_buffer_append (buffer, DLP_RESPONSE_DATA(res, 0, 10), + (size_t)result); + result += maxBufferSize; + } + } + } + } + + CHECK(PI_DBG_DLP, PI_DBG_LVL_DEBUG, + record_dump( + get_long(DLP_RESPONSE_DATA(res, 0, 0)), /* recID */ + get_short(DLP_RESPONSE_DATA(res, 0, 4)), /* index */ + get_byte(DLP_RESPONSE_DATA(res, 0, 8)), /* flags */ + get_byte(DLP_RESPONSE_DATA(res, 0, 9)), /* catID */ + DLP_RESPONSE_DATA(res, 0, 10), result)); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_ReadRecordByIndex(int sd, int dbhandle, int recindex, pi_buffer_t *buffer, + recordid_t * recuid, int *attr, int *category) +{ + int result, + large = 0; + struct dlpRequest *req; + struct dlpResponse *res; + int maxBufferSize = pi_maxrecsize(sd) - RECORD_READ_SAFEGUARD_SIZE; + + TraceX(dlp_ReadRecordByIndex,"recindex=%d",recindex); + pi_reset_errors(sd); + + /* TapWave (DLP 1.4) implements a `large' version of dlpFuncReadRecord, + * which can return records >64k + */ + if (pi_version(sd) >= 0x0104) { + req = dlp_request_new_with_argid(dlpFuncReadRecordEx, 0x21, 1, 12); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0x00); + set_short(DLP_REQUEST_DATA(req, 0, 2), recindex); + set_long(DLP_REQUEST_DATA(req, 0, 4), 0); /* Offset into record */ + set_long(DLP_REQUEST_DATA(req, 0, 8), pi_maxrecsize(sd)); /* length to return */ + large = 1; + } else { + req = dlp_request_new_with_argid(dlpFuncReadRecord, 0x21, 1, 8); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0x00); + set_short(DLP_REQUEST_DATA(req, 0, 2), recindex); + set_short(DLP_REQUEST_DATA(req, 0, 4), 0); /* Offset into record */ + set_short(DLP_REQUEST_DATA(req, 0, 6), buffer ? maxBufferSize : 0); /* length to return */ + } + result = dlp_exec(sd, req, &res); + dlp_request_free(req); + + if (result > 0) { + result = res->argv[0]->len - (large ? 14 : 10); + if (recuid) + *recuid = get_long(DLP_RESPONSE_DATA(res, 0, 0)); + if (attr) + *attr = get_byte(DLP_RESPONSE_DATA(res, 0, large ? 12 : 8)); + if (category) + *category = get_byte(DLP_RESPONSE_DATA(res, 0, large ? 13 : 9)); + if (buffer) { + pi_buffer_clear (buffer); + pi_buffer_append (buffer, DLP_RESPONSE_DATA(res, 0, large ? 14 : 10), + (size_t)result); + + /* Some devices such as the Tungsten TX, Treo 650 and Treo 700p lock up if you try to read the entire record if the + ** record is almost at the maximum record size. The following mitigates this and allows the record + ** to be read in two chunks. + */ + if (result == maxBufferSize && !large) { + dlp_response_free(res); + req = dlp_request_new_with_argid(dlpFuncReadRecord, 0x21, 1, 8); + if (req != NULL) { + set_byte(DLP_REQUEST_DATA(req, 0, 0), dbhandle); + set_byte(DLP_REQUEST_DATA(req, 0, 1), 0x00); + set_short(DLP_REQUEST_DATA(req, 0, 2), recindex); + set_short(DLP_REQUEST_DATA(req, 0, 4), maxBufferSize); /* Offset into record */ + set_short(DLP_REQUEST_DATA(req, 0, 6), buffer ? RECORD_READ_SAFEGUARD_SIZE : 0); /* length to return */ + + result = dlp_exec(sd, req, &res); + dlp_request_free(req); + + if (result > 0) { + result = res->argv[0]->len - (large ? 14 : 10); + pi_buffer_append (buffer, DLP_RESPONSE_DATA(res, 0, large ? 14 : 10), + (size_t)result); + + result += maxBufferSize; + } + } + } + } + + CHECK(PI_DBG_DLP, PI_DBG_LVL_DEBUG, + record_dump( + get_long(DLP_RESPONSE_DATA(res, 0, 0)), /* recUID */ + get_short(DLP_RESPONSE_DATA(res, 0, 4)), /* index */ + get_byte(DLP_RESPONSE_DATA(res, 0, large ? 12 : 8)), /* flags */ + get_byte(DLP_RESPONSE_DATA(res, 0, large ? 13 : 9)), /* catID */ + DLP_RESPONSE_DATA(res, 0, large ? 14 : 10), result)); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_ExpSlotEnumerate(int sd, int *numSlots, int *slotRefs) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + Trace(dlp_ExpSlotEnumerate); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncExpSlotEnumerate, 0); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + int slots, i; + + slots = get_short(DLP_RESPONSE_DATA (res, 0, 0)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ExpSlotEnumerate %d\n", slots)); + + if (slots) { + for (i = 0; i < slots && i < *numSlots; i++) { + slotRefs[i] = + get_short(DLP_RESPONSE_DATA (res, 0, + 2 + (2 * i))); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " %d Slot-Refnum %d\n", i, slotRefs[i])); + } + } + + *numSlots = slots; + } + + dlp_response_free(res); + + return result; +} + +int +dlp_ExpCardPresent(int sd, int slotRef) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_ExpCardPresent,"slotRef=%d",slotRef); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncExpCardPresent, 1, 2); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short(DLP_REQUEST_DATA(req, 0, 0), slotRef); + + result = dlp_exec (sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_ExpCardInfo(int sd, int slotRef, unsigned long *flags, int *numStrings, + char **strings) +{ + int result; + struct dlpRequest* req; + struct dlpResponse* res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_ExpCardInfo,"slotRef=%d",slotRef); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncExpCardInfo, 1, 2); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short(DLP_REQUEST_DATA(req, 0, 0), slotRef); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + *flags = get_long(DLP_RESPONSE_DATA (res, 0, 0)); + *numStrings = get_byte(DLP_RESPONSE_DATA (res, 0, 4)); + + if (strings && *numStrings) { + int i, len, sz = 0; + char *p = DLP_RESPONSE_DATA (res, 0, 8); + + for (i=0; i < *numStrings; i++, sz+=len, p+=len) + len = strlen (p) + 1; + + *strings = (char *) malloc ((size_t)sz); + if (*strings) + memcpy (*strings, DLP_RESPONSE_DATA (res, 0, 8), (size_t)sz); + else + result = pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + } + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP ExpCardInfo flags: 0x%08lx numStrings: %d\n", + *flags, *numStrings)); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_VFSGetDefaultDir(int sd, int volRefNum, const char *type, char *dir, + int *len) +{ + int result, buflen; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSGetDefaultDir,"volRefNum=%d",volRefNum); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncVFSGetDefaultDir, + 1, 2 + (strlen(type) + 1)); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short(DLP_REQUEST_DATA(req, 0, 0), volRefNum); + strcpy(DLP_REQUEST_DATA(req, 0, 2), type); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + buflen = get_short(DLP_RESPONSE_DATA (res, 0, 0)); + + if (*len < buflen + 1) + result = pi_set_error(sd, PI_ERR_DLP_BUFSIZE); + else { + if (buflen) + strncpy(dir, DLP_RESPONSE_DATA (res, 0, 2), + (size_t)buflen); + else + dir[0] = '\0'; + + *len = buflen; + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "Default dir is %s\n", dir)); + } + } + + dlp_response_free(res); + + return result; +} + +int +dlp_VFSImportDatabaseFromFile(int sd, int volRefNum, const char *path, + int *cardno, unsigned long *localid) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSImportDatabaseFromFile,"volRefNum=%d path='%s'",volRefNum,path); + pi_reset_errors(sd); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "Import file <%s>%d\n", path)); + + req = dlp_request_new(dlpFuncVFSImportDatabaseFromFile, + 1, 2 + (strlen(path) + 1)); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short(DLP_REQUEST_DATA(req, 0, 0), volRefNum); + strcpy(DLP_REQUEST_DATA(req, 0, 2), path); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + + if (result > 0) { + if (cardno) + *cardno = get_short(DLP_RESPONSE_DATA (res, 0, 0)); + if (localid) + *localid = get_short(DLP_RESPONSE_DATA (res, 0, 2)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "Database imported as: cardNo:%d dbID:%d\n", + get_short(DLP_RESPONSE_DATA (res, 0, 0)), + get_short(DLP_RESPONSE_DATA (res, 0, 2)))); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_VFSExportDatabaseToFile(int sd, int volRefNum, const char *path, + int cardno, unsigned int localid) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSExportDatabaseToFile,"cardno=%d localid=0x%08lx volRefNum=%d path='%s'", + cardno,(long)localid,volRefNum,path); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncVFSExportDatabaseToFile, + 1, 8 + (strlen(path) + 1)); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short(DLP_REQUEST_DATA(req, 0, 0), volRefNum); + set_short(DLP_REQUEST_DATA(req, 0, 2), cardno); + set_long(DLP_REQUEST_DATA(req, 0, 4), localid); + strcpy(DLP_REQUEST_DATA(req, 0, 8), path); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_VFSFileCreate(int sd, int volRefNum, const char *name) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileCreate,"volRefNum=%d name='%s'",volRefNum,name); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSFileCreate, 1, 2 + (strlen(name) + 1)); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short (DLP_REQUEST_DATA (req, 0, 0), volRefNum); + strcpy (DLP_REQUEST_DATA (req, 0, 2), name); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + dlp_response_free (res); + + return result; +} + +int +dlp_VFSFileOpen(int sd, int volRefNum, const char *path, int openMode, + FileRef *fileRef) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileOpen,"volRefNum=%d mode=0x%04x path='%s'", + volRefNum,openMode,path); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSFileOpen, 1, 4 + (strlen (path) + 1)); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short (DLP_REQUEST_DATA (req, 0, 0), volRefNum); + set_short (DLP_REQUEST_DATA (req, 0, 2), openMode); + strcpy (DLP_REQUEST_DATA (req, 0, 4), path); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + + if (result > 0) { + *fileRef = get_long(DLP_RESPONSE_DATA (res, 0, 0)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "OpenFileRef: 0x%x\n", *fileRef)); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_VFSFileClose(int sd, FileRef fileRef) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileClose,"fileRef=%ld",fileRef); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSFileClose, 1, 4); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long (DLP_REQUEST_DATA (req, 0, 0), fileRef); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + dlp_response_free (res); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "Closed FileRef: %x\n", fileRef)); + + return result; +} + +int +dlp_VFSFileWrite(int sd, FileRef fileRef, const void *data, size_t len) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res = NULL; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileWrite,"fileRef=%ld len=%ld",(long)fileRef,(long)len); + pi_reset_errors(sd); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "Write to FileRef: %x bytes %d\n", fileRef, len)); + + req = dlp_request_new (dlpFuncVFSFileWrite, 1, 8); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long (DLP_REQUEST_DATA (req, 0, 0), fileRef); + set_long (DLP_REQUEST_DATA (req, 0, 4), len); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + + if (result >= 0) { + int bytes = pi_write (sd, data, len); + result = bytes; + if (result < (int)len) { + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "send failed %d\n", result)); + } else { + dlp_response_free (res); + res = NULL; + + result = dlp_response_read (&res, sd); + + if (result > 0) { + pi_set_palmos_error(sd, get_short(DLP_RESPONSE_DATA (res, 0, 2))); + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "send success (%d) res 0x%04x!\n", len, pi_palmos_error(sd))); + result = bytes; + } + } + } + + dlp_response_free (res); + + return result; +} + +int +dlp_VFSFileRead(int sd, FileRef fileRef, pi_buffer_t *data, size_t len) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + size_t bytes = 0; + int freeze_txid = 1; + size_t opt_size = sizeof(int); + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileRead,"fileRef=%ld len=%ld",(long)fileRef,(long)len); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSFileRead, 1, 8); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long (DLP_REQUEST_DATA (req, 0, 0), fileRef); + set_long (DLP_REQUEST_DATA (req, 0, 4), len); + + /* if we're using PADP, this socket option is required so that + * the transfer can complete without error + */ + pi_setsockopt(sd, PI_LEVEL_PADP, PI_PADP_FREEZE_TXID, &freeze_txid, &opt_size); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + + pi_buffer_clear (data); + + if (result >= 0) { + + do { + result = pi_read(sd, data, len); + if (result > 0) { + len -= result; + bytes += result; + } + } while (result > 0 && len > 0); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "dlp_VFSFileRead: read %u bytes (last pi_read was %d)\n", + (unsigned)bytes, result)); + + if (result >= 0) + result = bytes; + } + + dlp_response_free(res); + + freeze_txid = 0; + pi_setsockopt(sd, PI_LEVEL_PADP, PI_PADP_FREEZE_TXID, &freeze_txid, &opt_size); + + return result; +} + +int +dlp_VFSFileDelete(int sd, int volRefNum, const char *path) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileDelete,"volRefNum=%d path='%s'",volRefNum,path); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSFileDelete, 1, 2 + (strlen (path) + 1)); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short (DLP_REQUEST_DATA (req, 0, 0), volRefNum); + strcpy (DLP_REQUEST_DATA (req, 0, 2), path); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + dlp_response_free (res); + + return result; +} + +int +dlp_VFSFileRename(int sd, int volRefNum, const char *path, + const char *newname) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileRename,"volRefNum=%d file '%s' renamed '%s'", + volRefNum,path,rename); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSFileRename, + 1, 4 + (strlen (path) + 1) + (strlen (newname) + 1)); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short (DLP_REQUEST_DATA (req, 0, 0), volRefNum); + set_short (DLP_REQUEST_DATA (req, 0, 2), 2); + strcpy (DLP_REQUEST_DATA (req, 0, 4), path); + strcpy (DLP_REQUEST_DATA (req, 0, 4 + (strlen(path) + 1)), newname); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + dlp_response_free (res); + + return result; +} + +int +dlp_VFSFileEOF(int sd, FileRef fileRef) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileEOF,"fileRef=%ld",fileRef); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSFileEOF, 1, 4); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long (DLP_REQUEST_DATA (req, 0, 0), fileRef); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + dlp_response_free (res); + + return result; +} + +int +dlp_VFSFileTell(int sd, FileRef fileRef,int *position) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileTell,"fileRef=%ld",fileRef); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncVFSFileTell, 1, 4); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long (DLP_REQUEST_DATA (req, 0, 0), fileRef); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + + if (result > 0) { + *position = get_long (DLP_RESPONSE_DATA (res, 0, 0)); + } + + dlp_response_free (res); + + return result; +} + +int +dlp_VFSFileGetAttributes (int sd, FileRef fileRef, unsigned long *attributes) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileGetAttributes,"fileRef=%ld",fileRef); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSFileGetAttributes, 1, 4); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long (DLP_REQUEST_DATA (req, 0, 0), fileRef); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + + if (result > 0) { + *attributes = get_long (DLP_RESPONSE_DATA (res, 0, 0)); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_VFSFileSetAttributes(int sd, FileRef fileRef, unsigned long attributes) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileSetAttributes,"fileRef=%ld attributes=0x%08lx", + fileRef,attributes); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSFileSetAttributes, 1, 8); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long (DLP_REQUEST_DATA (req, 0, 0), fileRef); + set_long (DLP_REQUEST_DATA (req, 0, 4), attributes); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + dlp_response_free (res); + + return result; +} + +int +dlp_VFSFileGetDate(int sd, FileRef fileRef, int which, time_t *date) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileGetDate,"fileRef=%ld which=%d",fileRef,which); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSFileGetDate, 1, 6); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long (DLP_REQUEST_DATA (req, 0, 0), fileRef); + set_short (DLP_REQUEST_DATA (req, 0, 4), which); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + + if (result > 0) { + *date = get_long (DLP_RESPONSE_DATA (res, 0, 0)) - 2082852000; + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "Requested date(%d): %d / %x calc %d / %x\n",which, + get_long(DLP_RESPONSE_DATA (res, 0, 0)), + get_long(DLP_RESPONSE_DATA (res, 0, 0)), + *date,*date)); + } + + dlp_response_free (res); + + return result; +} + +int +dlp_VFSFileSetDate(int sd, FileRef fileRef, int which, time_t date) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileSetDate,"fileRef=%ld which=%d date=0x%08lx", + (long)fileRef,which,(long)date); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncVFSFileSetDate, 1, 10); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long (DLP_REQUEST_DATA(req, 0, 0), fileRef); + set_short (DLP_REQUEST_DATA(req, 0, 4), which); + set_long (DLP_REQUEST_DATA(req, 0, 6), date + 2082852000); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + dlp_response_free (res); + + return result; +} + +int +dlp_VFSDirCreate(int sd, int volRefNum, const char *path) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSDirCreate,"volRefNum=%d path='%s'",volRefNum,path); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSDirCreate, 1, 2 + (strlen(path) + 1)); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short (DLP_REQUEST_DATA (req, 0, 0), volRefNum); + strcpy (DLP_REQUEST_DATA (req, 0, 2), path); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + dlp_response_free (res); + + return result; +} + +int +dlp_VFSDirEntryEnumerate(int sd, FileRef dirRefNum, + unsigned long *dirIterator, int *maxDirItems, struct VFSDirInfo *data) +{ + unsigned int result, + entries, + from, + at, + slen, + count; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSDirEntryEnumerate,"dirRef=%ld",dirRefNum); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSDirEntryEnumerate, 1, 12); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long (DLP_REQUEST_DATA (req, 0, 0), dirRefNum); + set_long (DLP_REQUEST_DATA (req, 0, 4), *dirIterator); + set_long (DLP_REQUEST_DATA (req, 0, 8), 8 + *maxDirItems * (4 + vfsMAXFILENAME)); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + + if (result > 0) { + if (result) { + *dirIterator = get_long (DLP_RESPONSE_DATA (res, 0, 0)); + entries = get_long (DLP_RESPONSE_DATA (res, 0, 4)); + } else { + *dirIterator = vfsIteratorStop; + entries = 0; + } + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "%d results returnd (ilterator: %d)\n", entries, + *dirIterator)); + + from = 8; + count = 0; + + for (at = 0; at < entries; at++) { + if (*maxDirItems > at) { + data[at].attr = + get_long(DLP_RESPONSE_DATA (res, 0, from)); + + /* fix for Sony sims (and probably devices too): they return + the attributes in the high word of attr instead of the low + word. We can safely shift it since the high 16 bits are not + used for VFS flags */ + if ((data[at].attr & 0x0000FFFF) == 0 && + (data[at].attr & 0xFFFF0000) != 0) + data[at].attr >>= 16; + + strncpy (data[at].name, + DLP_RESPONSE_DATA(res, 0, from + 4), + vfsMAXFILENAME); + data[at].name[vfsMAXFILENAME-1] = 0; + count++; + } + + /* Zero terminated string. Strings that have an + even length will be null terminated and have a + pad byte. */ + slen = strlen (DLP_RESPONSE_DATA(res, 0, from + 4)) + 1; + if (slen & 1) + slen++; /* make even stringlen + NULL */ + + /* 6 = 4 (attr) + 1 (NULL) -+ 1 (PADDING) */ + from += slen + 4; + } + *maxDirItems = count; + } + + dlp_response_free (res); + + return result; +} + +int +dlp_VFSVolumeFormat(int sd, unsigned char flags, + int fsLibRef, struct VFSSlotMountParam *param) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + Trace(dlp_VFSVolumeFormat); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncVFSVolumeFormat, 1, 4); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + +/* FIXME check sizes, list the mount params properly */ + set_short(DLP_REQUEST_DATA(req, 0, 0), fsLibRef); + set_short(DLP_REQUEST_DATA(req, 0, 2), + sizeof(struct VFSSlotMountParam)); + set_byte(DLP_REQUEST_DATA(req, 0, 4), flags); + set_byte(DLP_REQUEST_DATA(req, 0, 4), 0); /* unused */ + + set_short(DLP_REQUEST_DATA(req, 0, 6), param->vfsMountParam.volRefNum); + set_short(DLP_REQUEST_DATA(req, 0, 8), param->vfsMountParam.reserved); + set_long(DLP_REQUEST_DATA(req, 0, 10), param->vfsMountParam.mountClass); + set_short(DLP_REQUEST_DATA(req, 0, 14), param->slotLibRefNum); + set_short(DLP_REQUEST_DATA(req, 0, 16), param->slotRefNum); + + result = dlp_exec(sd, req, &res); + + dlp_request_free(req); + dlp_response_free(res); + + return result; +} + +int +dlp_VFSVolumeEnumerate(int sd, int *numVols, int *volRefs) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + Trace(dlp_VFSVolumeEnumerate); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSVolumeEnumerate, 0); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + + if (result > 0) { + int vols, i; + + vols = get_short (DLP_RESPONSE_DATA (res, 0, 0)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP VFSVolumeEnumerate %d\n", vols)); + + if (vols) { + for (i = 0; i < vols && i < *numVols; i++) { + volRefs[i] = + get_short (DLP_RESPONSE_DATA (res, + 0, 2 + (2 * i))); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + " %d Volume-Refnum %d\n", i, volRefs[i])); + } + } + *numVols = vols; + } + else + *numVols = 0; + + dlp_response_free (res); + + return result; +} + +int +dlp_VFSVolumeInfo(int sd, int volRefNum, struct VFSInfo *volInfo) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSVolumeInfo,"volRefNum=%d",volRefNum); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSVolumeInfo, 1, 2); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short (DLP_REQUEST_DATA(req, 0, 0), volRefNum); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + + if (result > 0) { + volInfo->attributes = get_long (DLP_RESPONSE_DATA (res, 0, 0)); + volInfo->fsType = get_long (DLP_RESPONSE_DATA (res, 0, 4)); + volInfo->fsCreator = get_long (DLP_RESPONSE_DATA (res, 0, 8)); + volInfo->mountClass = get_long (DLP_RESPONSE_DATA (res, 0, 12)); + volInfo->slotLibRefNum = get_short (DLP_RESPONSE_DATA (res, 0, 16)); + volInfo->slotRefNum = get_short (DLP_RESPONSE_DATA (res, 0, 18)); + volInfo->mediaType = get_long (DLP_RESPONSE_DATA (res, 0, 20)); + volInfo->reserved = get_long (DLP_RESPONSE_DATA (res, 0, 24)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "VFSVolumeInfo: fstype '%s' ", printlong(volInfo->fsType))); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "fscreator: '%s'\nSlotlibref %d Slotref %d\n", + printlong(volInfo->fsCreator), + volInfo->slotLibRefNum, + volInfo->slotRefNum)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "Media: '%s'\n", printlong(volInfo->mediaType))); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_VFSVolumeGetLabel(int sd, int volRefNum, int *len, char *name) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSVolumeGetLabel,"volRefNum=%d",volRefNum); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSVolumeGetLabel, 1, 2); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short (DLP_REQUEST_DATA (req, 0, 0), volRefNum); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + + if (result > 0) { + strncpy(name, DLP_RESPONSE_DATA(res, 0, 0), + (size_t)(*len - 1)); + *len = strlen(name); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP VFSVolumeGetLabel %s\n", name)); + } + + dlp_response_free(res); + + return result; +} + +int +dlp_VFSVolumeSetLabel(int sd, int volRefNum, const char *name) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSVolumeSetLabel,"volRefNum=%d name='%s'",volRefNum,name); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSVolumeSetLabel, 1, + 2 + (strlen(name) + 1)); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short (DLP_REQUEST_DATA (req, 0, 0), volRefNum); + strcpy (DLP_REQUEST_DATA (req, 0, 2), name); + + result = dlp_exec (sd, req, &res); + + dlp_response_free (res); + dlp_request_free (req); + + return result; +} + +int +dlp_VFSVolumeSize(int sd, int volRefNum, long *volSizeUsed, + long *volSizeTotal) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSVolumeSize,"volRefNum=%d",volRefNum); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSVolumeSize, 1, 2); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short (DLP_REQUEST_DATA (req, 0, 0), volRefNum); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + + if (result > 0) { + *volSizeUsed = get_long (DLP_RESPONSE_DATA (res, 0, 0)); + *volSizeTotal = get_long (DLP_RESPONSE_DATA (res, 0, 4)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP VFS Volume Size total: %d used: %d\n", + *volSizeTotal, *volSizeUsed)); + } + + dlp_response_free (res); + + return result; +} + +int +dlp_VFSFileSeek(int sd, FileRef fileRef, int origin, int offset) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileSeek,"fileRef=%ld origin=%d offset=%d", + fileRef,origin,offset); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSFileSeek, 1, 10); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long (DLP_REQUEST_DATA (req, 0, 0), fileRef); + set_short (DLP_REQUEST_DATA (req, 0, 4), origin); + set_long (DLP_REQUEST_DATA (req, 0, 6), offset); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + dlp_response_free (res); + + return result; +} + +int +dlp_VFSFileResize(int sd, FileRef fileRef, int newSize) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileResize,"fileRef=%ld newSize=%d",fileRef,newSize); + pi_reset_errors(sd); + + req = dlp_request_new(dlpFuncVFSFileResize, 1, 8); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long(DLP_REQUEST_DATA(req, 0, 0), fileRef); + set_long(DLP_REQUEST_DATA(req, 0, 4), newSize); + + result = dlp_exec(sd, req, &res); + + dlp_request_free (req); + dlp_response_free (res); + + return result; +} + +int +dlp_VFSFileSize(int sd, FileRef fileRef, int *size) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1,2); + TraceX(dlp_VFSFileSize,"fileRef=%ld",fileRef); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncVFSFileSize, 1, 4); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_long (DLP_REQUEST_DATA (req, 0, 0), fileRef); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + + if (result > 0) { + *size = get_long (DLP_RESPONSE_DATA (res, 0, 0)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP VFS File Size: %d\n", *size)); + } + + dlp_response_free (res); + + return result; +} + +int +dlp_ExpSlotMediaType(int sd, int slotNum, unsigned long *mediaType) +{ + int result; + struct dlpRequest *req; + struct dlpResponse *res; + + RequireDLPVersion(sd,1, 4); + TraceX(dlp_ExpSlotMediaType,"slotNum=%d",slotNum); + pi_reset_errors(sd); + + req = dlp_request_new (dlpFuncExpSlotMediaType, 1, 2); + if (req == NULL) + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + + set_short (DLP_REQUEST_DATA (req, 0, 0), slotNum); + + result = dlp_exec (sd, req, &res); + + dlp_request_free (req); + + if (result > 0) { + *mediaType = get_long (DLP_RESPONSE_DATA (res, 0, 0)); + + LOG((PI_DBG_DLP, PI_DBG_LVL_INFO, + "DLP Media Type for slot %d: %4.4s\n", + slotNum, mediaType)); + } + + dlp_response_free (res); + + return result; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/expense.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/expense.c new file mode 100644 index 00000000..bbd06a6d --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/expense.c @@ -0,0 +1,481 @@ +/* + * $Id: expense.c,v 1.29 2006/11/07 21:13:24 adridg Exp $ + * + * expense.c: Translate Pilot expense tracker data formats + * + * Copyright (c) 1997, Kenneth Albanowski + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include "pi-macros.h" +#include "pi-expense.h" + +char *ExpenseSortNames[] = { "Date", "Type", NULL }; +char *ExpenseDistanceNames[] = { "Miles", "Kilometers", NULL }; +char *ExpensePaymentNames[] = + { "AmEx", "Cash", "Check", "CreditCard", "MasterCard", "Prepaid", + "VISA", "Unfiled" +}; + +char *ExpenseTypeNames[] = + { "Airfare", "Breakfast", "Bus", "Business Meals", "Car Rental", + "Dinner", "Entertainment", "Fax", "Gas", "Gifts", "Hotel", + "Incidentals", "Laundry", "Limo", "Lodging", "Lunch", "Mileage", + "Other", "Parking", "Postage", "Snack", "Subway", "Supplies", + "Taxi", "Telephone", "Tips", "Tolls", "Train" +}; + + +/*********************************************************************** + * + * Function: free_Expense + * + * Summary: frees members of the Expense structure + * + * Parameters: Expense_t* + * + * Returns: void + * + ***********************************************************************/ +void +free_Expense(Expense_t *expense) +{ + if (expense->note != NULL) { + free(expense->note); + expense->note = NULL; + } + + if (expense->amount != NULL) { + free(expense->amount); + expense->amount = NULL; + } + + if (expense->city != NULL) { + free(expense->city); + expense->city = NULL; + } + + if (expense->vendor != NULL) { + free(expense->vendor); + expense->vendor = NULL; + } + + if (expense->attendees != NULL) { + free(expense->attendees); + expense->attendees = NULL; + } +} + + +/*********************************************************************** + * + * Function: unpack_Expense + * + * Summary: unpack Expense records + * + * Parameters: Expense_t*, char* to buffer, length of buffer + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +unpack_Expense(Expense_t *expense, unsigned char *buffer, int len) +{ + unsigned long d; + unsigned char *start = buffer; + + if (len < 6) + return 0; + + d = (unsigned short int) get_short(buffer); + expense->date.tm_year = (d >> 9) + 4; + expense->date.tm_mon = ((d >> 5) & 15) - 1; + expense->date.tm_mday = d & 31; + expense->date.tm_hour = 0; + expense->date.tm_min = 0; + expense->date.tm_sec = 0; + expense->date.tm_isdst = -1; + mktime(&expense->date); + + expense->type = (enum ExpenseType) get_byte(buffer + 2); + expense->payment = (enum ExpensePayment) get_byte(buffer + 3); + expense->currency = get_byte(buffer + 4); + + buffer += 6; + len -= 6; + + if (len < 1) + return 0; + + if (*buffer) { + expense->amount = strdup((char *)buffer); + buffer += strlen(expense->amount); + len -= strlen(expense->amount); + } else { + expense->amount = 0; + } + buffer++; + len--; + + if (len < 1) + return 0; + + if (*buffer) { + expense->vendor = strdup((char *)buffer); + buffer += strlen(expense->vendor); + len -= strlen(expense->vendor); + } else { + expense->vendor = 0; + } + buffer++; + len--; + + if (len < 1) + return 0; + + if (*buffer) { + expense->city = strdup((char *)buffer); + buffer += strlen(expense->city); + len -= strlen(expense->city); + } else { + expense->city = 0; + } + buffer++; + len--; + + if (len < 1) + return 0; + + if (*buffer) { + expense->attendees = strdup((char *)buffer); + buffer += strlen(expense->attendees); + len -= strlen(expense->attendees); + } else { + expense->attendees = 0; + } + buffer++; + len--; + + if (len < 1) + return 0; + + if (*buffer) { + expense->note = strdup((char *)buffer); + buffer += strlen(expense->note); + len -= strlen(expense->note); + } else { + expense->note = 0; + } + + buffer++; + len--; + + return (buffer - start); +} + + +/*********************************************************************** + * + * Function: pack_Expense + * + * Summary: pack Expense records + * + * Parameters: Expense_t*, char* to buffer, buffer length + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +pack_Expense(Expense_t *expense, unsigned char *record, int len) +{ + int destlen = 6 + 1 + 1 + 1 + 1 + 1; + unsigned char *buf = record; + + if (expense->amount) + destlen += strlen(expense->amount); + if (expense->vendor) + destlen += strlen(expense->vendor); + if (expense->city) + destlen += strlen(expense->city); + if (expense->attendees) + destlen += strlen(expense->attendees); + if (expense->note) + destlen += strlen(expense->note); + + if (!record) + return destlen; + if (len < destlen) + return 0; + + set_short(buf, + ((expense->date.tm_year - 4) << 9) | ((expense->date.tm_mon + + 1) << 5) | expense->date. + tm_mday); + buf += 2; + set_byte(buf, expense->type); + set_byte(buf + 1, expense->payment); + set_byte(buf + 2, expense->currency); + set_byte(buf + 3, 0); /* gapfill */ + buf += 4; + + if (expense->amount) { + strcpy((char *)buf, expense->amount); + buf += strlen((char *)buf); + } else { + set_byte(buf, 0); + } + buf++; + + if (expense->vendor) { + strcpy((char *)buf, expense->vendor); + buf += strlen((char *)buf); + } else { + set_byte(buf, 0); + } + buf++; + + if (expense->city) { + strcpy((char *)buf, expense->city); + buf += strlen((char *)buf); + } else { + set_byte(buf, 0); + } + buf++; + + if (expense->attendees) { + strcpy((char *)buf, expense->attendees); + buf += strlen((char *)buf); + } else { + set_byte(buf, 0); + } + buf++; + + if (expense->note) { + strcpy((char *)buf, expense->note); + buf += strlen((char *)buf); + } else { + set_byte(buf, 0); + } + buf++; + + return (buf - record); +} + + +/*********************************************************************** + * + * Function: unpack_ExpenseAppInfo + * + * Summary: unpacks ExpenseAppInfo record + * + * Parameters: ExpenseAppInfo_t*, char* to record, record length + * + * Returns: effective record length + * + ***********************************************************************/ +int +unpack_ExpenseAppInfo(ExpenseAppInfo_t *appinfo, unsigned char *record, + size_t len) +{ + int i; + unsigned char *start = record; + + i = unpack_CategoryAppInfo(&appinfo->category, record, len); + if (!i) + return 0; + record += i; + len -= i; + + appinfo->sortOrder = (enum ExpenseSort) get_byte(record); + record += 2; + for (i = 0; i < 4; i++) { + memcpy(appinfo->currencies[i].name, record, 16); + record += 16; + memcpy(appinfo->currencies[i].symbol, record, 4); + record += 4; + memcpy(appinfo->currencies[i].rate, record, 8); + record += 8; + } + return (record - start); +} + +/*********************************************************************** + * + * Function: pack_ExpenseAppInfo + * + * Summary: packs ExpenseAppInfo record + * + * Parameters: ExpenseAppInfo_t*, char* to record, record length + * + * Returns: effective record length + * + ***********************************************************************/ +int +pack_ExpenseAppInfo(ExpenseAppInfo_t *appinfo, unsigned char *record, + size_t len) +{ + int i, + destlen = 2 + (16 + 4 + 8) * 4; + unsigned char *start = record; + + i = pack_CategoryAppInfo(&appinfo->category, record, len); + if (!record) + return i + destlen; + if (!i) + return i; + record += i; + len -= i; + if (len < destlen) + return 0; + set_byte(record, appinfo->sortOrder); + set_byte(record + 1, 0); /* gapfill */ + record += 2; + for (i = 0; i < 4; i++) { + memcpy(record, appinfo->currencies[i].name, 16); + record += 16; + memcpy(record, appinfo->currencies[i].symbol, 4); + record += 4; + memcpy(record, appinfo->currencies[i].rate, 8); + record += 8; + } + + return (record - start); +} + +/*********************************************************************** + * + * Function: unpack_ExpensePref + * + * Summary: unpacks ExpensePref record + * + * Parameters: ExpensePref_t*, char* to record, record length + * + * Returns: effective record length + * + ***********************************************************************/ +int +unpack_ExpensePref(ExpensePref_t *pref, unsigned char *record, int len) +{ + int i; + unsigned char *start = record; + + (void) len; + + pref->currentCategory = get_short(record); + record += 2; + pref->defaultCurrency = get_short(record); + record += 2; + pref->attendeeFont = get_byte(record); + record++; + pref->showAllCategories = get_byte(record); + record++; + pref->showCurrency = get_byte(record); + record++; + pref->saveBackup = get_byte(record); + record++; + pref->allowQuickFill = get_byte(record); + record++; + pref->unitOfDistance = (enum ExpenseDistance) get_byte(record); + record++; + + for (i = 0; i < 5; i++) { + pref->currencies[i] = get_byte(record); + record++; + } + + for (i = 0; i < 2; i++) { + pref->unknown[i] = get_byte(record); + record++; + } + + pref->noteFont = get_byte(record); + record++; + + return (record - start); +} + +/*********************************************************************** + * + * Function: pack_ExpensePref + * + * Summary: packs ExpensePref record + * + * Parameters: ExpensePref_t*, char* to record, record length + * + * Returns: Nothing + * + ***********************************************************************/ +int pack_ExpensePref(ExpensePref_t *p, unsigned char *record, int len) +{ + int i; + unsigned char *start = record; + + (void) len; + + set_short(record, p->currentCategory); + record += 2; + set_short(record, p->defaultCurrency); + record += 2; + set_byte(record, p->attendeeFont); + record++; + set_byte(record, p->showAllCategories); + record++; + set_byte(record, p->showCurrency); + record++; + set_byte(record, p->saveBackup); + record++; + set_byte(record, p->allowQuickFill); + record++; + set_byte(record, p->unitOfDistance); + record++; + for (i = 0; i < 5; i++) { + set_byte(record, p->currencies[i]); + record++; + } + /* Unknown values */ + set_byte(record, 0xff); + record++; + set_byte(record, 0xff); + record++; + + set_byte(record, p->noteFont); + record++; + + return record - start; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ + diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/freebsdusb.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/freebsdusb.c new file mode 100644 index 00000000..5ec1682e --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/freebsdusb.c @@ -0,0 +1,460 @@ +/* + * $Id: freebsdusb.c,v 1.28 2006/10/12 14:21:22 desrod Exp $ + * + * freebsdusb.c: device IO for FreeBSD usb devices + * + * Copyright (c) 1996, 1997, D. Jeff Dionne & Kenneth Albanowski. + * 2002, Anish Mistry + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-usb.h" + +#ifdef HAVE_SYS_IOCTL_COMPAT_H +#include <sys/ioctl_compat.h> +#endif + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#ifndef O_NONBLOCK +# define O_NONBLOCK 0 +#endif + +#if defined(__FreeBSD__) +/* freebsd usb header */ +#include <dev/usb/usb.h> +#define MAX_BUF 256 +#endif + +/* Declare prototypes */ +static int u_open(pi_socket_t *ps, struct pi_sockaddr *addr, size_t addrlen); +static int u_close(pi_socket_t *ps); +static ssize_t u_write(pi_socket_t *ps, const unsigned char *buf, size_t len, int flags); +static ssize_t u_read(pi_socket_t *ps, pi_buffer_t *buf, size_t len, int flags); +static int u_poll(pi_socket_t *ps, int timeout); +static int u_flush(pi_socket_t *ps, int flags); + +void pi_usb_impl_init (struct pi_usb_impl *impl) +{ + impl->open = u_open; + impl->close = u_close; + impl->write = u_write; + impl->read = u_read; + impl->flush = u_flush; + impl->poll = u_poll; +} + + +/*********************************************************************** + * + * Function: u_open + * + * Summary: Open the usb port and establish a connection for + * communicating over the usb port. + * + * Parameters: ps is of type pi_socket_t which will given a copy of the + * valid file descriptor that is returned by the function. + * + * addr of type pi_socketaddr contains the member pi_device + * which is a character string of the usb device. + * + * XXX addrlen is of type int contain the size of addr? I'm + * not using this, should I? Possible buffer overflow because + * I'm not checking something? + * + * Returns: The file descriptor + * + ***********************************************************************/ +static int +u_open(pi_socket_t *ps, struct pi_sockaddr *addr, size_t addrlen) +{ + int fd, + i, + endpoint_fd; + + struct usb_device_info udi; + /* struct usb_ctl_request ur; */ + /* unsigned char usbresponse[50]; */ + + char *tty = addr->pi_device; + char *pEndPoint = NULL; + + /* open the usb device */ + if ((fd = open(tty, O_RDWR, 0)) < 0) { + ps->last_error = PI_ERR_GENERIC_SYSTEM; + return PI_ERR_GENERIC_SYSTEM; + } + + /* check for a valid file descriptor */ + if (fd < 0) { + ps->last_error = PI_ERR_GENERIC_SYSTEM; + return PI_ERR_GENERIC_SYSTEM; + } + + /* fill the udi structure with information about the handheld, after + this is where you will probably want to do device specific stuff + */ + + if (ioctl(fd, USB_GET_DEVICEINFO, &udi)) { + close(fd); + ps->last_error = PI_ERR_GENERIC_SYSTEM; + return PI_ERR_GENERIC_SYSTEM; + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, + "DEV USB_GET_DEVICE_INFO USB FreeBSD fd: %d\n", fd)); + + /* set the configuration */ + i = 1; + if (ioctl(fd, USB_SET_CONFIG, &i) < 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + "DEV USB_SET_CONFIG USB FreeBSD fd: %d failed\n", fd)); + + close(fd); + ps->last_error = PI_ERR_GENERIC_SYSTEM; + return PI_ERR_GENERIC_SYSTEM; + } + + /* close the main communication pipe since we have initilized + everything we needed to + NOTE: we HAVE to do all this stuff to the main pipe or we will + cause a kernel panic when data is sent over the endpoint */ + close(fd); + + /* open endpoint */ + /* allocate data for the usb endpoint string */ + pEndPoint = malloc(strlen(tty)+20); + if(!pEndPoint) + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + + /* create device endpoint name string */ + sprintf(pEndPoint, "%s.%d", tty, 2); + + /* open the endpoint with read write access */ + endpoint_fd = open(pEndPoint, O_RDWR, 0); + if(endpoint_fd < 0) { + /* we failed to open the endpoint */ + free(pEndPoint); + return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + } + + if ((i = fcntl(endpoint_fd, F_GETFL, 0)) != -1) { + i &= ~O_NONBLOCK; + fcntl(endpoint_fd, F_SETFL, i); + } + + /* set short transfer so that we can allow "short" reads since we + will don't know exactly + what is coming so we can't specify exact byte amounts */ + i = 1; + if (ioctl(endpoint_fd, USB_SET_SHORT_XFER, &i) < 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, + "DEV USB_SET_SHORT_XFER USB FreeBSD fd: %d failed\n", + endpoint_fd)); + } + + /* 0 timeout value will cause us the wait until the device has data + available or is disconnected */ + i = 0; + if (ioctl(endpoint_fd, USB_SET_TIMEOUT, &i) < 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, + "DEV USB_SET_TIMEOUT USB FreeBSD fd: %d failed\n", + endpoint_fd)); + } + + /* save our file descriptor in the pi_socket structure */ + if ((i = pi_socket_setsd(ps, endpoint_fd)) < 0) { + free(pEndPoint); + return i; + } + + /* free endpoint string memory */ + free(pEndPoint); + + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, + "DEV OPEN USB FreeBSD fd: %d\n", endpoint_fd)); + + /* return our endpoint file descriptor since this is where the + reading and writing will be done */ + return endpoint_fd; + +} + +/*********************************************************************** + * + * Function: u_close + * + * Summary: Close the open socket/file descriptor + * + * Parameters: ps is of type pi_socket that contains the member sd which is + * the file descriptor that is to be closed. + * + * Returns: 0 if sucessful or -1 if it failed and errno set to the error + * + ***********************************************************************/ +static int +u_close(pi_socket_t *ps) +{ + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, + "DEV CLOSE USB FreeBSD fd: %d\n", ps->sd)); + + return close(ps->sd); +} + +/*********************************************************************** + * + * Function: u_poll + * + * Summary: Poll the open socket/file descriptor + * + * Parameters: None + * + * Returns: 1 always since we buffer our own data and you can't poll() + * FreeBSD USB devices? + * + ***********************************************************************/ +static int +u_poll(pi_socket_t *ps, int timeout) +{ + /* stub this function and log an error that this should never needed + to be called */ + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, + "DEV POLL USB FreeBSD Timeout: %d\npoll()" + " should not be called for FreeBSD USB\n", timeout)); + + return 1; +} + +/*********************************************************************** + * + * Function: u_write + * + * Parameters: ps is of type pi_socket that contains the sd member which is + * the file descriptor that the data in buf will be written to. + * + * buf is a unsigned char pointer that points to the data that + * is to be written to ps->sd. + * + * len is of type int and indicated the number of bytes to + * write to ps->sd. + * + * flags is of type int and contains various write flags. What + * flags and should I respect them, since I am currently not + * checking this variable? + * + * Parameters: None + * + * Returns: The number of bytes written from buf or negative to indicate an + * error + * + ***********************************************************************/ +static ssize_t +u_write(pi_socket_t *ps, const unsigned char *buf, size_t len, int flags) +{ + int nwrote, + total, + write_len; + fd_set ready; + + total = len; + write_len = len; + + /* FIXME: there is no timeout handling in the original freebsdusb code! */ + + while (total > 0) { + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + + if (!FD_ISSET(ps->sd, &ready)) { + ps->state = PI_SOCK_CONN_BREAK; + return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED); + } + + nwrote = write(ps->sd, buf, write_len); + if (nwrote < 0) { + ps->state = PI_SOCK_CONN_BREAK; + return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED); + } + + write_len -= nwrote; + buf += nwrote; + total -= nwrote; + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, + "DEV TX USB FreeBSD Bytes: %d\n", len)); + + return len; +} + +/*********************************************************************** + * + * Function: u_read + * + * Summary: Read incoming data from the socket/file descriptor and + * buffer any extra data that is read in the process of + * receiving data from the device. + * + * Parameters: ps is of type pi_socket that contains the sd member which is + * the file descriptor that the data in buf will be read. It + * also contains the read buffer. + * + * buf is a pointer to an unsigned character string that will + * receive the data the is read from the device. + * + * len is of type int that is the the number of bytes to read + * from the device/buffer into buf. + * + * flags is of type in that currently only indicated if you + * want to peek data from the device/buffer . + * + * Returns: The number of bytes that was read from the device or from + * the buffer and copied to buf. + * + ***********************************************************************/ +static ssize_t +u_read(pi_socket_t *ps, pi_buffer_t *buf, size_t len, int flags) +{ + struct pi_usb_data *data = (struct pi_usb_data *) ps->device->data; + ssize_t rlen; + int bytes_read = 0; + fd_set ready; + struct timeval t; + + if (flags == PI_MSG_PEEK && len > 256) + len = 256; + + if (pi_buffer_expect (buf, len) == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + /* first extract anything we had in the "peek" buffer */ + if (data->buf_size > 0) { + bytes_read = len > data->buf_size ? data->buf_size : len; + len -= bytes_read; + pi_buffer_append(buf, data->buf, bytes_read); + if (flags != PI_MSG_PEEK) { + data->buf_size -= bytes_read; + if (data->buf_size > 0) + memmove(data->buf, data->buf + bytes_read, data->buf_size); + } + if (!len) + return bytes_read; + } + + /* check to see if device is ready for read */ + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + + /* If timeout == 0, wait forever for packet, otherwise wait till + timeout milliseconds */ + if (data->timeout == 0) + select(ps->sd + 1, &ready, 0, 0, 0); + else { + t.tv_sec = data->timeout / 1000; + t.tv_usec = (data->timeout % 1000) * 1000; + if (select(ps->sd + 1, &ready, 0, 0, &t) == 0) + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + + /* If data is available in time, read it */ + if (!FD_ISSET(ps->sd, &ready)) { + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, + "DEV RX USB FreeBSD timeout\n")); + errno = ETIMEDOUT; + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + + /* read data to pre-sized buffer */ + rlen = read(ps->sd, &buf->data[buf->used], len); + if (rlen > 0) { + if (flags == PI_MSG_PEEK) { + memcpy(data->buf, buf->data + buf->used, rlen); + data->buf_size = rlen; + } + buf->used += rlen; + bytes_read += rlen; + + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, + "DEV RX USB FreeBSD Bytes: %d:%d\n", bytes_read, + bytes_read + data->buf_size)); + + } + else + bytes_read = PI_ERR_SOCK_IO; + + return bytes_read; +} + +/*********************************************************************** + * + * Function: u_flush + * + * Summary: Flush incoming and/or outgoing data from the socket/file + * descriptor + * + * Parameters: ps is of type pi_socket that contains the sd member which is + * the file descriptor that the data in buf will be read. It + * also contains the read buffer. + * + * flags is of type int and can be a combination of + * PI_FLUSH_INPUT and PI_FLUSH_OUTPUT + * + * Returns: 0 + * + ***********************************************************************/ +static int +u_flush(pi_socket_t *ps, int flags) +{ + char buf[256]; + int fl; + struct pi_usb_data *data = (struct pi_usb_data *) ps->device->data; + + if (flags & PI_FLUSH_INPUT) { + /* clear internal buffer */ + data->buf_size = 0; + + /* flush pending data */ + if ((fl = fcntl(ps->sd, F_GETFL, 0)) != -1) { + fcntl(ps->sd, F_SETFL, fl | O_NONBLOCK); + while (read(ps->sd, buf, sizeof(buf)) > 0) + ; + fcntl(ps->sd, F_SETFL, fl); + } + } + return 0; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/hinote.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/hinote.c new file mode 100644 index 00000000..e315e3cf --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/hinote.c @@ -0,0 +1,180 @@ +/* + * $Id: hinote.c,v 1.22 2006/10/12 14:21:22 desrod Exp $ + * + * hinote.c: Translate Hi-Note data formats + * + * Copyright 1997 Bill Goodman + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pi-hinote.h" + +/*********************************************************************** + * + * Function: free_HiNoteNote + * + * Summary: frees HiNoteNote_t members + * + * Parameters: HiNoteNote_t* + * + * Returns: void + * + ***********************************************************************/ +void +free_HiNoteNote(HiNoteNote_t *hinote) +{ + if (hinote->text != NULL) { + free(hinote->text); + hinote->text = NULL; + } +} + +/*********************************************************************** + * + * Function: unpack_HiNoteNote + * + * Summary: Unpack a HiNote record + * + * Parameters: HiNoteNote_t*, char* to buffer, buffer length + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +unpack_HiNoteNote(HiNoteNote_t *hinote, unsigned char *buffer, int len) +{ + if (len < 3) + return 0; + + hinote->flags = buffer[0]; + hinote->level = buffer[1]; + hinote->text = strdup((char *) &buffer[2]); + + return strlen((char *) &buffer[2]) + 3; +} + +/*********************************************************************** + * + * Function: pack_HiNoteNote + * + * Summary: Pack a HiNote record + * + * Parameters: HiNoteNote_t* + * + * Returns: Nothing + * + ***********************************************************************/ +int +pack_HiNoteNote(HiNoteNote_t *hinote, unsigned char *buffer, int len) +{ + int destlen; + + destlen = 3; + if (hinote->text) + destlen += strlen(hinote->text); + + if (!buffer) + return destlen; + if (len < destlen) + return 0; + + buffer[0] = hinote->flags; + buffer[1] = hinote->level; + + if (hinote->text) + strcpy((char *) &buffer[2], hinote->text); + else { + buffer[2] = 0; + } + return destlen; +} + + +/*********************************************************************** + * + * Function: unpack_HiNoteAppInfo + * + * Summary: Unpack the HiNote AppInfo block + * + * Parameters: HiNoteAppInfo_t*, char* to record, record length + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +unpack_HiNoteAppInfo(HiNoteAppInfo_t *appinfo, unsigned char *record, size_t len) +{ + int i, + idx; + unsigned char *start; + + start = record; + i = unpack_CategoryAppInfo(&appinfo->category, record, len); + if (!i) + return i; + record += i; + len -= i; + if (len < 48) + return 0; + for (idx = 0; i < 48; i++) + appinfo->reserved[i] = *record++; + return (record - start); +} + + +/*********************************************************************** + * + * Function: pack_HiNoteAppInfo + * + * Summary: Pack the HiNote AppInfo block + * + * Parameters: HiNoteAppInfo_t*, char* record, length of record + * + * Returns: effective record length + * + ***********************************************************************/ +int +pack_HiNoteAppInfo(HiNoteAppInfo_t *appinfo, unsigned char *record, size_t len) +{ + int i, + idx; + unsigned char *start = record; + + i = pack_CategoryAppInfo(&appinfo->category, record, len); + if (i == 0) /* category pack failed */ + return 0; + if (!record) + return i + 48; + record += i; + len -= i; + if (len < 48) + return (record - start); + for (idx = 0; i < 48; i++) + *record++ = appinfo->reserved[i]; + + return (record - start); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/inet.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/inet.c new file mode 100644 index 00000000..9906bdde --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/inet.c @@ -0,0 +1,595 @@ +/* + * $Id: inet.c,v 1.61 2006/10/12 14:21:22 desrod Exp $ + * + * inet.c: Interface layer to TCP/IP NetSync connections + * + * Copyright (c) 1997, Kenneth Albanowski + * Copyright (c) 1999, Tilo Christ + * Copyright (c) 1999, John Franks + * Copyright (c) 2004, 2005 Florent Pillet + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + * + * -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/tcp.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-inet.h" +#include "pi-cmp.h" +#include "pi-net.h" + +/* Declare prototypes */ +static void pi_inet_device_free (pi_device_t *dev); +static pi_protocol_t* pi_inet_protocol (pi_device_t *dev); +static pi_protocol_t* pi_inet_protocol_dup (pi_protocol_t *prot); +static void pi_inet_protocol_free (pi_protocol_t *prot); +static int pi_inet_close(pi_socket_t *ps); +static int pi_inet_connect(pi_socket_t *ps, struct sockaddr *addr, size_t addrlen); +static int pi_inet_bind(pi_socket_t *ps, struct sockaddr *addr, size_t addrlen); +static int pi_inet_listen(pi_socket_t *ps, int backlog); +static int pi_inet_accept(pi_socket_t *ps, struct sockaddr *addr, size_t *addrlen); +static ssize_t pi_inet_read(pi_socket_t *ps, pi_buffer_t *msg, size_t len, int flags); +static ssize_t pi_inet_write(pi_socket_t *ps, const unsigned char *msg, size_t len, int flags); +static int pi_inet_getsockopt(pi_socket_t *ps, int level, int option_name, void *option_value, size_t *option_len); +static int pi_inet_setsockopt(pi_socket_t *ps, int level, int option_name, const void *option_value, size_t *option_len); +static int pi_inet_flush(pi_socket_t *ps, int flags); + +extern int pi_socket_init(pi_socket_t *ps); + +pi_device_t* +pi_inet_device (int type) +{ + pi_device_t *dev = NULL; + pi_inet_data_t *data = NULL; + + dev = (pi_device_t *)malloc (sizeof (pi_device_t)); + if (dev != NULL) { + data = (pi_inet_data_t *)malloc (sizeof (pi_inet_data_t)); + if (data == NULL) { + free(dev); + dev = NULL; + } + } + + if (dev != NULL && data != NULL) { + dev->free = pi_inet_device_free; + dev->protocol = pi_inet_protocol; + dev->bind = pi_inet_bind; + dev->listen = pi_inet_listen; + dev->accept = pi_inet_accept; + dev->connect = pi_inet_connect; + dev->close = pi_inet_close; + + data->timeout = 0; + data->rx_bytes = 0; + data->rx_errors = 0; + data->tx_bytes = 0; + data->tx_errors = 0; + dev->data = data; + } + + return dev; +} + +static void +pi_inet_device_free (pi_device_t *dev) +{ + ASSERT (dev != NULL); + if (dev != NULL) { + if (dev->data != NULL) + free(dev->data); + free(dev); + } +} + +static pi_protocol_t* +pi_inet_protocol (pi_device_t *dev) +{ + pi_protocol_t *prot; + pi_inet_data_t *data; + + ASSERT (dev != NULL); + + data = dev->data; + + prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t)); + + if (prot != NULL) { + prot->level = PI_LEVEL_DEV; + prot->dup = pi_inet_protocol_dup; + prot->free = pi_inet_protocol_free; + prot->read = pi_inet_read; + prot->write = pi_inet_write; + prot->flush = pi_inet_flush; + prot->getsockopt = pi_inet_getsockopt; + prot->setsockopt = pi_inet_setsockopt; + prot->data = NULL; + } + + return prot; +} + +static pi_protocol_t* +pi_inet_protocol_dup (pi_protocol_t *prot) +{ + pi_protocol_t *new_prot; + + ASSERT (prot != NULL); + + new_prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t)); + + if (new_prot != NULL) { + new_prot->level = prot->level; + new_prot->dup = prot->dup; + new_prot->free = prot->free; + new_prot->read = prot->read; + new_prot->write = prot->write; + new_prot->flush = prot->flush; + new_prot->getsockopt = prot->getsockopt; + new_prot->setsockopt = prot->setsockopt; + new_prot->data = NULL; + } + + return new_prot; +} + +static void +pi_inet_protocol_free (pi_protocol_t *prot) +{ + ASSERT (prot != NULL); + if (prot != NULL) + free(prot); +} + +static int +pi_inet_bind(pi_socket_t *ps, struct sockaddr *addr, size_t addrlen) +{ + int opt, + sd, + err; + size_t optlen; + struct pi_sockaddr *paddr = (struct pi_sockaddr *) addr; + struct sockaddr_in serv_addr; + char *device = paddr->pi_device, + *port = NULL; + + /* Figure out the addresses to allow */ + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + if (strlen(device) > 1 && strncmp(device, "any", 3)) { + serv_addr.sin_addr.s_addr = inet_addr(device); + if (serv_addr.sin_addr.s_addr == (in_addr_t)-1) { + struct hostent *hostent = gethostbyname(device); + + if (!hostent) + return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + + memcpy((char *) &serv_addr.sin_addr.s_addr, + hostent->h_addr, (size_t)hostent->h_length); + } + } else { + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + } + if ((port = strchr(device, ':')) != NULL) { + serv_addr.sin_port = htons(atoi(++port)); + } else { + serv_addr.sin_port = htons(14238); + } + + sd = socket(AF_INET, SOCK_STREAM, 0); + if (sd < 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + "DEV BIND Inet: Unable to create socket\n")); + return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + } + if ((err = pi_socket_setsd (ps, sd)) < 0) + return err; + + opt = 1; + optlen = sizeof(opt); + + if (setsockopt(ps->sd, SOL_SOCKET, SO_REUSEADDR, (void *) &opt, + (int)optlen) < 0) { + return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + } + + if (bind(ps->sd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, + "DEV BIND Inet Bound to %s\n", device)); + + ps->raddr = malloc(addrlen); + memcpy(ps->raddr, addr, addrlen); + ps->raddrlen = addrlen; + ps->laddr = malloc(addrlen); + memcpy(ps->laddr, addr, addrlen); + ps->laddrlen = addrlen; + + return 0; +} + +static int +pi_inet_connect(pi_socket_t *ps, struct sockaddr *addr, size_t addrlen) +{ + int sd, + err; + + struct pi_sockaddr *paddr = (struct pi_sockaddr *) addr; + struct sockaddr_in serv_addr; + char *device = paddr->pi_device; + + /* Figure out the addresses to allow */ + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + if (strlen(device) > 1) { + serv_addr.sin_addr.s_addr = inet_addr(device); + if (serv_addr.sin_addr.s_addr == (in_addr_t)-1) { + struct hostent *hostent = gethostbyname(device); + + if (!hostent) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + "DEV CONNECT Inet: Unable" + " to determine host\n")); + return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + } + + memcpy((char *) &serv_addr.sin_addr.s_addr, + hostent->h_addr, (size_t)hostent->h_length); + } + } else { + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + } + serv_addr.sin_port = htons(14238); + + sd = socket(AF_INET, SOCK_STREAM, 0); + + if (sd < 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + "DEV CONNECT Inet: Unable to create socket\n")); + return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + } + + if ((err = pi_socket_setsd (ps, sd)) < 0) + return err; + + if (connect (ps->sd, (struct sockaddr *) &serv_addr, + sizeof(serv_addr)) < 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + "DEV CONNECT Inet: Unable to connect\n")); + return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + } + + ps->raddr = malloc(addrlen); + memcpy(ps->raddr, addr, addrlen); + ps->raddrlen = addrlen; + ps->laddr = malloc(addrlen); + memcpy(ps->laddr, addr, addrlen); + ps->laddrlen = addrlen; + + switch (ps->cmd) { + case PI_CMD_CMP: + if ((err = cmp_tx_handshake(ps)) < 0) + goto fail; + break; + case PI_CMD_NET: + if ((err = net_tx_handshake(ps)) < 0) + goto fail; + break; + } + ps->state = PI_SOCK_CONN_INIT; + ps->command = 0; + + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, "DEV CONNECT Inet: Connected\n")); + return 0; + +fail: + return err; +} + +static int +pi_inet_listen(pi_socket_t *ps, int backlog) +{ + int result; + + result = listen(ps->sd, backlog); + if (result == 0) + ps->state = PI_SOCK_LISTEN; + + return result; +} + +static int +pi_inet_accept(pi_socket_t *ps, struct sockaddr *addr, size_t *addrlen) +{ + int sd, + err, + split = 0, + chunksize = 0; + size_t len, + size; + pl_socklen_t l = 0; + unsigned char cmp_flags; + + if (addrlen) + l = *addrlen; + sd = accept(ps->sd, addr, &l); + if (addrlen) + *addrlen = l; + if (sd < 0) { + pi_set_error(ps->sd, sd); + err = PI_ERR_GENERIC_SYSTEM; + goto fail; + } + + pi_socket_setsd(ps, sd); + pi_socket_init(ps); + + switch (ps->cmd) { + case PI_CMD_CMP: + if ((err = cmp_rx_handshake(ps, 57600, 0)) < 0) + goto fail; + + /* propagate the long packet format flag to both command and non-command stacks */ + size = sizeof(cmp_flags); + pi_getsockopt(ps->sd, PI_LEVEL_CMP, PI_CMP_FLAGS, &cmp_flags, &size); + if (cmp_flags & CMP_FL_LONG_PACKET_SUPPORT) { + int use_long_format = 1; + size = sizeof(int); + pi_setsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_USE_LONG_FORMAT, + &use_long_format, &size); + ps->command ^= 1; + pi_setsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_USE_LONG_FORMAT, + &use_long_format, &size); + ps->command ^= 1; + } + + break; + case PI_CMD_NET: + /* network: make sure we don't split writes. set socket option + * on both the command and non-command instances of the protocol + */ + len = sizeof (split); + pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_SPLIT_WRITES, + &split, &len); + len = sizeof (chunksize); + pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_WRITE_CHUNKSIZE, + &chunksize, &len); + + ps->command ^= 1; + len = sizeof (split); + pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_SPLIT_WRITES, + &split, &len); + len = sizeof (chunksize); + pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_WRITE_CHUNKSIZE, + &chunksize, &len); + ps->command ^= 1; + + if ((err = net_rx_handshake(ps)) < 0) + goto fail; + break; + } + + ps->state = PI_SOCK_CONN_ACCEPT; + ps->command = 0; + ps->dlprecord = 0; + + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, "DEV INET ACCEPT accepted\n")); + + return ps->sd; + + fail: + return err; +} + +static int +pi_inet_close(pi_socket_t *ps) +{ + if (ps->sd) { + close(ps->sd); + ps->sd = 0; + } + if (ps->laddr) { + free(ps->laddr); + ps->laddr = NULL; + } + if (ps->raddr) { + free(ps->raddr); + ps->raddr = NULL; + } + return 0; +} + +static int +pi_inet_flush(pi_socket_t *ps, int flags) +{ + char buf[256]; + int fl; + + if (flags & PI_FLUSH_INPUT) { + if ((fl = fcntl(ps->sd, F_GETFL, 0)) != -1) { + fcntl(ps->sd, F_SETFL, fl | O_NONBLOCK); + while (recv(ps->sd, buf, sizeof(buf), 0) > 0) + ; + fcntl(ps->sd, F_SETFL, fl); + } + } + return 0; +} + +static ssize_t +pi_inet_write(pi_socket_t *ps, const unsigned char *msg, size_t len, int flags) +{ + int total, + nwrote; + pi_inet_data_t *data = (pi_inet_data_t *)ps->device->data; + struct timeval t; + fd_set ready; + + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + + total = len; + while (total > 0) { + if (data->timeout == 0) { + if (select(ps->sd + 1, 0, &ready, 0, 0) < 0 + && errno == EINTR) + continue; + } else { + t.tv_sec = data->timeout / 1000; + t.tv_usec = (data->timeout % 1000) * 1000; + if (select(ps->sd + 1, 0, &ready, 0, &t) == 0) + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + if (!FD_ISSET(ps->sd, &ready)) { + ps->state = PI_SOCK_CONN_BREAK; + return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED); + } + + nwrote = write(ps->sd, msg, len); + if (nwrote < 0) { + /* test errno to properly set the socket error */ + if (errno == EPIPE || errno == EBADF) { + ps->state = PI_SOCK_CONN_BREAK; + return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED); + } + return pi_set_error(ps->sd, PI_ERR_SOCK_IO); + } + + total -= nwrote; + } + data->tx_bytes += len; + + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, "DEV TX Inet Bytes: %d\n", len)); + + return len; +} + +static ssize_t +pi_inet_read(pi_socket_t *ps, pi_buffer_t *msg, size_t len, int flags) +{ + int r, + fl = 0; + pi_inet_data_t *data = (pi_inet_data_t *)ps->device->data; + fd_set ready; + struct timeval t; + + if (pi_buffer_expect (msg, len) == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + if (flags == PI_MSG_PEEK) + fl = MSG_PEEK; + + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + + /* If timeout == 0, wait forever for packet, otherwise wait till + timeout milliseconds */ + if (data->timeout == 0) + select(ps->sd + 1, &ready, 0, 0, 0); + else { + t.tv_sec = data->timeout / 1000; + t.tv_usec = (data->timeout % 1000) * 1000; + if (select(ps->sd + 1, &ready, 0, 0, &t) == 0) + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + + /* If data is available in time, read it */ + if (FD_ISSET(ps->sd, &ready)) { + r = recv(ps->sd, msg->data + msg->used, len, fl); + if (r < 0) { + if (errno == EPIPE || errno == EBADF) { + ps->state = PI_SOCK_CONN_BREAK; + return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED); + } + return pi_set_error(ps->sd, PI_ERR_SOCK_IO); + } + + data->rx_bytes += r; + msg->used += r; + + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, "DEV RX Inet Bytes: %d\n", r)); + return r; + } + + /* otherwise throw out any current packet and return */ + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, "DEV RX Inet timeout\n")); + data->rx_errors++; + return 0; +} + +static int +pi_inet_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len) +{ + pi_inet_data_t *data = (pi_inet_data_t *)ps->device->data; + + switch (option_name) { + case PI_DEV_TIMEOUT: + if (*option_len != sizeof (data->timeout)) { + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); + } + memcpy (option_value, &data->timeout, + sizeof (data->timeout)); + *option_len = sizeof (data->timeout); + break; + } + + return 0; +} + +static int +pi_inet_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len) +{ + pi_inet_data_t *data = (pi_inet_data_t *)ps->device->data; + + switch (option_name) { + case PI_DEV_TIMEOUT: + if (*option_len != sizeof (data->timeout)) { + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); + } + memcpy (&data->timeout, option_value, + sizeof (data->timeout)); + break; + } + + return 0; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/libusb.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/libusb.c new file mode 100644 index 00000000..e571aeaf --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/libusb.c @@ -0,0 +1,605 @@ +/* + * $Id: libusb.c,v 1.33 2007/02/09 16:06:22 desrod Exp $ + * + * libusb.c: device i/o for libusb + * + * Copyright (c) 2004 Zephaniah E. Hull & Florent Pillet. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <pthread.h> +#include <signal.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-usb.h" +#include "pi-util.h" + +#ifdef HAVE_SYS_IOCTL_COMPAT_H +#include <sys/ioctl_compat.h> +#endif + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#include <usb.h> + +#if defined(sun) && defined(__SVR4) +#define __FUNCTION__ __func__ +#endif + +static int u_open(struct pi_socket *ps, struct pi_sockaddr *addr, size_t addrlen); +static int u_close(struct pi_socket *ps); +static ssize_t u_write(struct pi_socket *ps, const unsigned char *buf, size_t len, + int flags); +static ssize_t u_read(struct pi_socket *ps, pi_buffer_t *buf, size_t len, + int flags); +static int u_read_i(struct pi_socket *ps, pi_buffer_t *buf, size_t len, int flags, + int timeout); +static int u_poll(struct pi_socket *ps, int timeout); +static int u_wait_for_device(struct pi_socket *ps, int *timeout); +static int u_flush(pi_socket_t *ps, int flags); +static int u_control_request (pi_usb_data_t *usb_data, int request_type, + int request, int value, int control_index, void *data, int size, int timeout); + +void pi_usb_impl_init (struct pi_usb_impl *impl) +{ + impl->open = u_open; + impl->close = u_close; + impl->write = u_write; + impl->read = u_read; + impl->flush = u_flush; + impl->poll = u_poll; + impl->wait_for_device = u_wait_for_device; + impl->changebaud = NULL; /* we don't need this one for libusb (yet) */ + impl->control_request = u_control_request; +} + + +/*********************************************************************** + * + * Start of the device identification code. + * + ***********************************************************************/ + +static usb_dev_handle *USB_handle; +static int USB_interface; +static int USB_in_endpoint; +static int USB_out_endpoint; + +static int +USB_open (pi_usb_data_t *data) +{ + usb_init (); + + return 1; +} + +static int +USB_poll (pi_usb_data_t *data) +{ + struct usb_bus *bus; + struct usb_device *dev; + int ret; + u_int8_t input_endpoint = 0xFF, output_endpoint = 0xFF; +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP + int first; +#endif + + usb_find_busses (); + usb_find_devices (); + CHECK (PI_DBG_DEV, PI_DBG_LVL_DEBUG, usb_set_debug (2)); + + for (bus = usb_busses; bus; bus = bus->next) { + for (dev = bus->devices; dev; dev = dev->next) { + int i; + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s: checking device %p\n", + __FILE__, dev)); + + if (dev->descriptor.bNumConfigurations < 1) + continue; + if (!dev->config) + continue; + if (dev->config[0].bNumInterfaces < 1) + continue; + if (dev->config[0].interface[0].num_altsetting < 1) + continue; + if (dev->config[0].interface[0].altsetting[0].bNumEndpoints < 2) + continue; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s: %d, 0x%04x 0x%04x.\n", + __FILE__, __LINE__, dev->descriptor.idVendor, dev->descriptor.idProduct)); + + if (USB_check_device (data, dev->descriptor.idVendor, dev->descriptor.idProduct)) + continue; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s: trying to open device %p\n", + __FILE__, dev)); + + USB_handle = usb_open(dev); + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s: USB_handle=%p\n", + __FILE__, USB_handle)); + + data->ref = USB_handle; + + input_endpoint = output_endpoint = 0xFF; + USB_in_endpoint = USB_out_endpoint = 0xFF; + + ret = USB_configure_device (data, &input_endpoint, &output_endpoint); + if (ret < 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "%s: USB configure failed for familar device: 0x%04x 0x%04x. (LifeDrive issue?)\n", + __FILE__, dev->descriptor.idVendor, dev->descriptor.idProduct)); + + usb_close(USB_handle); + continue; + } + + for (i = 0; i < dev->config[0].interface[0].altsetting[0].bNumEndpoints; i++) { + struct usb_endpoint_descriptor *endpoint; + u_int8_t address; + + endpoint = &dev->config[0].interface[0].altsetting[0].endpoint[i]; + + if (endpoint->wMaxPacketSize != 0x40) + continue; + if ((endpoint->bmAttributes & USB_ENDPOINT_TYPE_MASK) != USB_ENDPOINT_TYPE_BULK) + continue; + address = endpoint->bEndpointAddress; + if ((address & USB_ENDPOINT_DIR_MASK)) { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "In: 0x%x 0x%x.\n", address, input_endpoint)); + if (input_endpoint == 0xFF) + USB_in_endpoint = address; + else if ((address & USB_ENDPOINT_ADDRESS_MASK) == input_endpoint) + USB_in_endpoint = address; + } else { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "Out: 0x%x 0x%x.\n", address, output_endpoint)); + if (output_endpoint == 0xFF) + USB_out_endpoint = address; + else if ((address & USB_ENDPOINT_ADDRESS_MASK) == output_endpoint) + USB_out_endpoint = address; + } + } + + if (USB_in_endpoint == 0xFF || USB_out_endpoint == 0xFF) { + usb_close (USB_handle); + continue; + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "Config: %d, 0x%x 0x%x | 0x%x 0x%x.\n", + ret, input_endpoint, output_endpoint, USB_in_endpoint, USB_out_endpoint)); + + USB_interface = dev->config[0].interface[0].altsetting[0].bInterfaceNumber; +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP + first = 1; +claim: +#endif + i = usb_claim_interface (USB_handle, USB_interface); + if (i < 0) { + if (i == -EBUSY) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "Unable to claim device: Busy.\n")); +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP + if (first) { + usb_detach_kernel_driver_np (USB_handle, USB_interface); + first = 0; + goto claim; + } +#endif + } else if (i == -ENOMEM) + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "Unable to claim device: No memory.\n")); + else + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "Unable to claim device: %d.\n", i)); + usb_close (USB_handle); + + errno = -i; + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s: %d.\n", + __FILE__, __LINE__)); + + return 0; + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s: %d.\n", + __FILE__, __LINE__)); + return 1; + } + } + + errno = ENODEV; + CHECK (PI_DBG_DEV, PI_DBG_LVL_DEBUG, usb_set_debug (0)); + return 0; +} + +static int +USB_close (void) +{ + if (!USB_handle) + return 0; + + usb_release_interface (USB_handle, USB_interface); + usb_close (USB_handle); + USB_handle = NULL; + return 1; +} + + +/*********************************************************************** + * + * Start of the read thread code, please note that all of this runs + * in a separate thread. + * + ***********************************************************************/ + +#define MAX_READ_SIZE 16384 +#define AUTO_READ_SIZE 64 +static char *RD_buffer = NULL; +static size_t RD_buffer_size; +static size_t RD_buffer_used; +static pthread_mutex_t RD_buffer_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t RD_buffer_available_cond = PTHREAD_COND_INITIALIZER; +static int RD_wanted; +static int RD_running = 0; +static char RD_usb_buffer[MAX_READ_SIZE]; +static pthread_t RD_thread = 0; + +static void +RD_do_read (int timeout) +{ + int bytes_read, read_size; + + read_size = RD_wanted - RD_buffer_used; + if (read_size < AUTO_READ_SIZE) + read_size = AUTO_READ_SIZE; + else if (read_size > MAX_READ_SIZE) + read_size = MAX_READ_SIZE; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "Reading: len: %d, timeout: %d.\n", read_size, timeout)); + bytes_read = usb_bulk_read (USB_handle, USB_in_endpoint, RD_usb_buffer, read_size, timeout); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s): %d\n", + __FILE__, __LINE__, __FUNCTION__, bytes_read)); + if (bytes_read < 0) { + if (bytes_read == -ENODEV) { + LOG((PI_DBG_DEV, PI_DBG_LVL_NONE, "Device went byebye!\n")); + RD_running = 0; + return; +#ifdef ELAST + } else if (bytes_read == -(ELAST + 1)) { + usb_clear_halt (USB_handle, USB_in_endpoint); + return; +#endif + } else if (bytes_read == -ETIMEDOUT) + return; + + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "libusb: USB bulk read returned error code %d\n", bytes_read)); + return; + } + if (!bytes_read) + return; + + + pthread_mutex_lock (&RD_buffer_mutex); + if ((RD_buffer_used + bytes_read) > RD_buffer_size) { + RD_buffer_size = ((RD_buffer_used + bytes_read + 0xfffe) & ~0xffff) - 1; /* 64k chunks. */ + RD_buffer = realloc (RD_buffer, RD_buffer_size); + } + + memcpy (RD_buffer + RD_buffer_used, RD_usb_buffer, bytes_read); + RD_buffer_used += bytes_read; + pthread_cond_broadcast (&RD_buffer_available_cond); + pthread_mutex_unlock (&RD_buffer_mutex); +} + +static void * +RD_main (void *foo) +{ + RD_buffer_used = 0; + RD_buffer = NULL; + RD_buffer_size = 0; + + pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + while (RD_running == 1) { + RD_do_read (0); + } + + RD_running = 0; + + return NULL; +} + + +static int +RD_start (void) +{ + if (RD_thread || RD_running) + return 0; + + RD_running = 1; + pthread_create (&RD_thread, NULL, RD_main, NULL); + + return 1; +} + +static int +RD_stop (void) +{ + if (!RD_thread && !RD_running) + return 0; + + if (RD_running) + RD_running = 0; + + if (RD_thread) { + pthread_cancel(RD_thread); + RD_thread = 0; + } + + if (RD_thread || RD_running) + return 0; + + return 1; +} + + +/*********************************************************************** + * + * Start of the glue code which makes this whole mess WORK. + * + ***********************************************************************/ + + +static int +u_open(struct pi_socket *ps, struct pi_sockaddr *addr, size_t addrlen) +{ + pi_usb_data_t *data = (pi_usb_data_t *)ps->device->data; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s).\n", + __FILE__, __LINE__, __FUNCTION__)); + + if (RD_running) + return -1; + if (!USB_open (data)) + return -1; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s).\n", + __FILE__, __LINE__, __FUNCTION__)); + + return 1; +} + +static int +u_close(struct pi_socket *ps) +{ + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s).\n", + __FILE__, __LINE__, __FUNCTION__)); + + RD_stop (); + USB_close (); + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s).\n", + __FILE__, __LINE__, __FUNCTION__)); + + return close (ps->sd); +} + +static int +u_wait_for_device(struct pi_socket *ps, int *timeout) +{ + pi_usb_data_t *data = (pi_usb_data_t *)ps->device->data; + struct timespec when; + int ret = 0; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s).\n", + __FILE__, __LINE__, __FUNCTION__)); + + if (*timeout) + pi_timeout_to_timespec (*timeout, &when); + + while (1) { + ret = USB_poll (data); + if (ret > 0) { + /* Evil, calculate how much longer the timeout is. */ + if (*timeout) { + *timeout = pi_timespec_to_timeout (&when); + if (*timeout <= 0) + *timeout = 1; + } + if (!RD_start ()) { + USB_close (); + return -1; + } + return ret; + + } + + if (*timeout) { + if (pi_timeout_expired(&when)) { + *timeout = 1; + return 0; + } + } + usleep (500000); + } + + return 0; +} + +static int +u_poll(struct pi_socket *ps, int timeout) +{ + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s).\n", + __FILE__, __LINE__, __FUNCTION__)); + + return u_read_i (ps, NULL, 1, PI_MSG_PEEK, timeout); +} + +static ssize_t +u_write(struct pi_socket *ps, const unsigned char *buf, size_t len, int flags) +{ + int timeout = ((struct pi_usb_data *)ps->device->data)->timeout; + int ret; + + if (!RD_running) + return -1; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "Writing: len: %d, flags: %d, timeout: %d.\n", len, flags, timeout)); + if (len <= 0) + return 0; + + ret = usb_bulk_write (USB_handle, USB_out_endpoint, buf, len, timeout); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "Wrote: %d.\n", ret)); + if (ret > 0) + CHECK (PI_DBG_DEV, PI_DBG_LVL_DEBUG, pi_dumpdata (buf, ret)); + + return (ssize_t)ret; +} + +static ssize_t +u_read(struct pi_socket *ps, pi_buffer_t *buf, size_t len, int flags) +{ + int ret; + + ret = u_read_i (ps, buf, len, flags, ((struct pi_usb_data *)ps->device->data)->timeout); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "Read: %d (%d).\n", ret, len)); + if (ret > 0) + CHECK (PI_DBG_DEV, PI_DBG_LVL_DEBUG, pi_dumpdata (buf->data, ret)); + + return (ssize_t)ret; +} + +static int +u_read_i(struct pi_socket *ps, pi_buffer_t *buf, size_t len, int flags, int timeout) +{ + if (!RD_running) + return PI_ERR_SOCK_DISCONNECTED; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s): %d %d %d\n", + __FILE__, __LINE__, __FUNCTION__, len, flags, timeout)); + + pthread_mutex_lock (&RD_buffer_mutex); + if (flags & PI_MSG_PEEK && len > 256) + len = 256; + + if (RD_buffer_used < len) { + struct timeval now; + struct timespec when, nownow; + int last_used; + gettimeofday(&now, NULL); + when.tv_sec = now.tv_sec + timeout / 1000; + when.tv_nsec = (now.tv_usec + (timeout % 1000) * 1000) * 1000; + if (when.tv_nsec >= 1000000000) { + when.tv_nsec -= 1000000000; + when.tv_sec++; + } + + RD_wanted = len; + do { + last_used = RD_buffer_used; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s): %d %d.\n", + __FILE__, __LINE__, __FUNCTION__, len, RD_buffer_used)); + + if (timeout) { + gettimeofday(&now, NULL); + nownow.tv_sec = now.tv_sec; + nownow.tv_nsec = now.tv_usec * 1000; + if ((nownow.tv_sec == when.tv_sec ? (nownow.tv_nsec > when.tv_nsec) : (nownow.tv_sec > when.tv_sec))) { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s): %d %d.\n", + __FILE__, __LINE__, __FUNCTION__, len, RD_buffer_used)); + break; + } + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s): %d %d.\n", + __FILE__, __LINE__, __FUNCTION__, len, RD_buffer_used)); + if (pthread_cond_timedwait (&RD_buffer_available_cond, &RD_buffer_mutex, &when) == ETIMEDOUT) { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s): %d %d.\n", + __FILE__, __LINE__, __FUNCTION__, len, RD_buffer_used)); + break; + } + } else + pthread_cond_wait (&RD_buffer_available_cond, &RD_buffer_mutex); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s): %d %d.\n", + __FILE__, __LINE__, __FUNCTION__, len, RD_buffer_used)); + } while (RD_buffer_used < len); + + RD_wanted = 0; + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s): %d %d.\n", + __FILE__, __LINE__, __FUNCTION__, len, RD_buffer_used)); + + if (!RD_running) { + pthread_mutex_unlock (&RD_buffer_mutex); + return PI_ERR_SOCK_DISCONNECTED; + } + + if (RD_buffer_used < len) + len = RD_buffer_used; + + if (len && buf) { + pi_buffer_append (buf, RD_buffer, len); + if (!(flags & PI_MSG_PEEK)) { + RD_buffer_used -= len; + if (RD_buffer_used) + memmove (RD_buffer, RD_buffer + len, RD_buffer_used); + + if ((RD_buffer_size - RD_buffer_used) > (1024 * 1024)) { + /* If we have more then 1M free in the buffer, shrink it. */ + RD_buffer_size = ((RD_buffer_used + 0xfffe) & ~0xffff) - 1; + RD_buffer = realloc (RD_buffer, RD_buffer_size); + } + } + } + + pthread_mutex_unlock (&RD_buffer_mutex); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s %d (%s).\n", + __FILE__, __LINE__, __FUNCTION__)); + return len; +} + +static int +u_flush(pi_socket_t *ps, int flags) +{ + if (flags & PI_FLUSH_INPUT) { + /* clear internal buffer */ + pthread_mutex_lock (&RD_buffer_mutex); + RD_buffer_used = 0; + pthread_mutex_unlock (&RD_buffer_mutex); + } + return 0; +} + +static int +u_control_request (pi_usb_data_t *usb_data, int request_type, int request, + int value, int control_index, void *data, int size, int timeout) +{ + return usb_control_msg (usb_data->ref, request_type, request, value, control_index, data, size, timeout); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/linuxusb.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/linuxusb.c new file mode 100644 index 00000000..a662a01f --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/linuxusb.c @@ -0,0 +1,400 @@ +/* + * $Id: linuxusb.c,v 1.24 2006/10/12 14:21:22 desrod Exp $ + * + * linuxusb.c: device i/o for linux usb + * + * Copyright (c) 1996, 1997, D. Jeff Dionne & Kenneth Albanowski. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-usb.h" +#include "pi-error.h" + +#ifdef HAVE_SYS_IOCTL_COMPAT_H +#include <sys/ioctl_compat.h> +#endif + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#ifndef O_NONBLOCK +# define O_NONBLOCK 0 +#endif + + +static int u_open(pi_socket_t *ps, struct pi_sockaddr *addr, size_t addrlen); +static int u_close(pi_socket_t *ps); +static int u_write(pi_socket_t *ps, unsigned char *buf, size_t len, int flags); +static int u_read(pi_socket_t *ps, pi_buffer_t *buf, size_t len, int flags); +static int u_poll(pi_socket_t *ps, int timeout); +static int u_flush(pi_socket_t *ps, int flags); + +void pi_usb_impl_init (struct pi_usb_impl *impl) +{ + impl->open = u_open; + impl->close = u_close; + impl->write = u_write; + impl->read = u_read; + impl->flush = u_flush; + impl->poll = u_poll; + impl->wait_for_device = NULL; /* not implemented in linuxusb yet */ + impl->changebaud = NULL; /* we don't need this one on linuxusb + * as USB serial adapters redirect to serial ports + */ + impl->control_request = NULL; +} + + +/*********************************************************************** + * + * Function: u_open + * + * Summary: Open the usb port and establish a connection for + * + * Parameters: None + * + * Returns: The file descriptor + * + ***********************************************************************/ +static int +u_open(pi_socket_t *ps, struct pi_sockaddr *addr, size_t addrlen) +{ + int fd, + i; + char *tty = addr->pi_device; + + if ((fd = open(tty, O_RDWR | O_NONBLOCK)) < 0) { + ps->last_error = PI_ERR_GENERIC_SYSTEM; + return PI_ERR_GENERIC_SYSTEM; /* errno already set */ + } + + if (!isatty(fd)) { + close(fd); + errno = EINVAL; + ps->last_error = PI_ERR_GENERIC_SYSTEM; + return PI_ERR_GENERIC_SYSTEM; + } + + if ((i = fcntl(fd, F_GETFL, 0)) != -1) { + i &= ~O_NONBLOCK; + fcntl(fd, F_SETFL, i); + } + + if ((i = pi_socket_setsd(ps, fd)) < 0) + return i; + + return fd; +} + + +/*********************************************************************** + * + * Function: u_close + * + * Summary: Close the open socket/file descriptor + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +static int +u_close(pi_socket_t *ps) +{ + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, + "DEV CLOSE linuxusb fd: %d\n", ps->sd)); + + return close(ps->sd); +} + + +/*********************************************************************** + * + * Function: u_poll + * + * Summary: Poll the open socket/file descriptor + * + * Parameters: None + * + * Returns: 1 on success, PI_ERR_SOCK_TIMEOUT on timeout + * + ***********************************************************************/ +static int +u_poll(pi_socket_t *ps, int timeout) +{ + struct timeval t; + fd_set ready; + + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + + /* If timeout == 0, wait forever for packet, otherwise wait till + timeout milliseconds */ + if (timeout == 0) + select(ps->sd + 1, &ready, 0, 0, 0); + else { + t.tv_sec = timeout / 1000; + t.tv_usec = (timeout % 1000) * 1000; + select(ps->sd + 1, &ready, 0, 0, &t); + } + + if (!FD_ISSET(ps->sd, &ready)) { + /* otherwise throw out any current packet and return */ + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, + "DEV POLL linuxusb timeout\n")); + errno = ETIMEDOUT; + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV POLL linuxusb found data on fd: %d\n", ps->sd)); + + return 1; +} + + +/*********************************************************************** + * + * Function: u_write + * + * Summary: Write to the open socket/file descriptor + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +static int +u_write(pi_socket_t *ps, unsigned char *buf, size_t len, int flags) +{ + int total, + nwrote; + struct pi_usb_data *data = (struct pi_usb_data *)ps->device->data; + struct timeval t; + fd_set ready; + + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + + total = len; + while (total > 0) { + if (data->timeout == 0) + select(ps->sd + 1, 0, &ready, 0, 0); + else { + t.tv_sec = data->timeout / 1000; + t.tv_usec = (data->timeout % 1000) * 1000; + if (select(ps->sd + 1, 0, &ready, 0, &t)) + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + + if (!FD_ISSET(ps->sd, &ready)) { + ps->state = PI_SOCK_CONN_BREAK; + return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED); + } + + nwrote = write(ps->sd, buf, len); + if (nwrote < 0) { + ps->state = PI_SOCK_CONN_BREAK; + return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED); + } + + total -= nwrote; + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV TX linuxusb wrote %d bytes\n", len)); + + return len; +} + + +/*********************************************************************** + * + * Function: u_read_buf + * + * Summary: read buffer + * + * Parameters: pi_socket_t*, char* to buffer, length of buffer + * + * Returns: number of bytes read + * + ***********************************************************************/ +static int +u_read_buf (pi_socket_t *ps, pi_buffer_t *buf, size_t len, int flags) +{ + struct pi_usb_data *data = (struct pi_usb_data *)ps->device->data; + size_t rbuf = data->buf_size; + + if (rbuf > len) + rbuf = len; + + if (pi_buffer_append (buf, data->buf, rbuf) == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + if (flags != PI_MSG_PEEK) { + data->buf_size -= rbuf; + if (data->buf_size > 0) + memmove(data->buf, &data->buf[rbuf], data->buf_size); + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV RX linuxusb read %d bytes from read-ahead buffer\n", rbuf)); + + return rbuf; +} + + +/*********************************************************************** + * + * Function: u_read + * + * Summary: Read incoming data from the socket/file descriptor + * + * Parameters: pi_socket_t*, char* to buffer, buffer length, flags + * + * Returns: number of bytes read or negative otherwise + * + ***********************************************************************/ +static int +u_read(pi_socket_t *ps, pi_buffer_t *buf, size_t len, int flags) +{ + ssize_t rbuf = 0, + bytes; + struct pi_usb_data *data = (struct pi_usb_data *)ps->device->data; + struct timeval t; + fd_set ready; + + /* check whether we have at least partial data in store */ + if (data->buf_size) { + rbuf = u_read_buf(ps, buf, len, flags); + if (rbuf < 0) + return rbuf; + len -= rbuf; + if (len == 0) + return rbuf; + } + + /* If timeout == 0, wait forever for packet, otherwise wait till + timeout milliseconds */ + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + if (data->timeout == 0) + select(ps->sd + 1, &ready, 0, 0, 0); + else { + t.tv_sec = data->timeout / 1000; + t.tv_usec = (data->timeout % 1000) * 1000; + if (select(ps->sd + 1, &ready, 0, 0, &t) == 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, + "DEV RX linuxusb timeout\n")); + errno = ETIMEDOUT; + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + } + + /* If data is available in time, read it */ + if (FD_ISSET(ps->sd, &ready)) { + if (flags == PI_MSG_PEEK && len > 256) + len = 256; + + if (pi_buffer_expect (buf, len) == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + bytes = read(ps->sd, buf->data + buf->used, len); + + if (bytes > 0) { + if (flags == PI_MSG_PEEK) { + memcpy(data->buf + data->buf_size, buf->data + buf->used, bytes); + data->buf_size += bytes; + } + buf->used += bytes; + rbuf += bytes; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV RX linuxusb read %d bytes\n", bytes)); + } + } else { + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, + "DEV RX linuxusb timeout\n")); + errno = ETIMEDOUT; + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + + return rbuf; +} + +/*********************************************************************** + * + * Function: u_flush + * + * Summary: Flush incoming and/or outgoing data from the socket/file + * descriptor + * + * Parameters: ps is of type pi_socket that contains the sd member which is + * the file descriptor that the data in buf will be read. It + * also contains the read buffer. + * + * flags is of type int and can be a combination of + * PI_FLUSH_INPUT and PI_FLUSH_OUTPUT + * + * Returns: 0 + * + ***********************************************************************/ +static int +u_flush(pi_socket_t *ps, int flags) +{ + char buf[256]; + int fl; + struct pi_usb_data *data = (struct pi_usb_data *) ps->device->data; + + if (flags & PI_FLUSH_INPUT) { + /* clear internal buffer */ + data->buf_size = 0; + + /* flush pending data */ + if ((fl = fcntl(ps->sd, F_GETFL, 0)) != -1) { + fcntl(ps->sd, F_SETFL, fl | O_NONBLOCK); + while (recv(ps->sd, buf, sizeof(buf), 0) > 0) + ; + fcntl(ps->sd, F_SETFL, 0); + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV FLUSH linuxusb flushed input buffer\n")); + } + return 0; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/location.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/location.c new file mode 100644 index 00000000..537c7f2e --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/location.c @@ -0,0 +1,805 @@ +/* + * $Id: location.c,v 1.1 2009/02/22 08:09:01 nicholas Exp $ + * + * location.c: Translate Pilot location data formats + * (c) 2008, Jon Schewe + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "pi-macros.h" +#include "pi-location.h" + +/*********************************************************************** + * + * Function: new_Timezone + * + * Summary: Create empty timzone + * + * Parameters: Timezone_t* + * + * Returns: void + * + ***********************************************************************/ +void +new_Timezone(Timezone_t *a) +{ + a->offset = 0; + a->t2 = 0; + a->dstStart.dayOfWeek = 0; + a->dstStart.weekOfMonth = 0; + a->dstStart.month = 0; + a->dstStart.unknown = 0; + a->dstEnd.dayOfWeek = 0; + a->dstEnd.weekOfMonth = 0; + a->dstEnd.month = 0; + a->dstEnd.unknown = 0; + a->dstObserved = 0; + a->t4 = 0; + a->unknown = 0; + a->name = NULL; +} + +/*********************************************************************** + * + * Function: new_Locatio + * + * Summary: Create empty location + * + * Parameters: Location_t* + * + * Returns: void + * + ***********************************************************************/ +void +new_Location(Location_t *a) +{ + new_Timezone(&(a->tz)); + a->unknownExists = 0; + a->unknown = 0; + a->latitude.degrees = 0; + a->latitude.minutes = 0; + a->latitude.direction = 0; + a->longitude.degrees = 0; + a->longitude.minutes = 0; + a->longitude.direction = 0; + a->note = NULL; +} + +/*********************************************************************** + * + * Function: copy_Timezone + * + * Summary: Copy the data from one timezone to another. The destination + * timezone event must already be cleared, either by creating new or by + * calling free_Timezone on it first. + * + * Parameters: Timezone_t*, Timezone_t* + * + * Returns: int -1 on failure (errno will be set), 0 on success + * + ***********************************************************************/ +int +copy_Timezone(const Timezone_t *source, Timezone_t *dest) +{ + + dest->offset = source->offset; + dest->t2 = source->t2; + dest->dstStart.dayOfWeek = source->dstStart.dayOfWeek; + dest->dstStart.weekOfMonth = source->dstStart.weekOfMonth; + dest->dstStart.month = source->dstStart.month; + dest->dstStart.unknown = source->dstStart.unknown; + dest->dstEnd.dayOfWeek = source->dstEnd.dayOfWeek; + dest->dstEnd.weekOfMonth = source->dstEnd.weekOfMonth; + dest->dstEnd.month = source->dstEnd.month; + dest->dstEnd.unknown = source->dstEnd.unknown; + dest->dstObserved = source->dstObserved; + dest->t4 = source->t4; + dest->unknown = source->unknown; + if(NULL != source->name) { + dest->name = strdup(source->name); + } else { + dest->name = NULL; + } + + return 0; +} + +/*********************************************************************** + * + * Function: copy_Location + * + * Summary: Copy the data from one location to another. The destination + * location event must already be cleared, either by creating new or by + * calling free_Location on it first. + * + * Parameters: Location_t*, Location_t* + * + * Returns: int -1 on failure (errno will be set), 0 on success + * + ***********************************************************************/ +int +copy_Location(const Location_t *source, Location_t *dest) +{ + int retval; + retval = copy_Timezone(&(source->tz), &(dest->tz)); + if(0 != retval) { + return retval; + } + dest->unknownExists = source->unknownExists; + dest->unknown = source->unknown; + dest->latitude.degrees = source->latitude.degrees; + dest->latitude.minutes = source->latitude.minutes; + dest->latitude.direction = source->latitude.direction; + dest->longitude.degrees = source->longitude.degrees; + dest->longitude.minutes = source->longitude.minutes; + dest->longitude.direction = source->longitude.direction; + if(NULL != source->note) { + dest->note = strdup(source->note); + } else { + dest->note = NULL; + } + + return 0; +} + +/*********************************************************************** + * + * Function: free_Location + * + * Summary: Free the members of a location structure + * + * Parameters: Location_t* + * + * Returns: void + * + ***********************************************************************/ +void +free_Location(Location_t *loc) +{ + free_Timezone(&(loc->tz)); + + if(loc->note != NULL) { + free(loc->note); + loc->note = NULL; + } + +} + +/*********************************************************************** + * + * Function: dup_Timezone + * + * Summary: Allocate memory for a new timezone that is a duplicate of this one and copy the data into it + * + * Parameters: Timezone_t* + * + * Returns: Timezone_t* or NULL if there isn't enough memory and errno is set to ENOMEM + * + ***********************************************************************/ +Timezone_t* +dup_Timezone(const Timezone_t *tz) +{ + Timezone_t *retval = (Timezone_t*)malloc(sizeof(Timezone_t)); + if(NULL == retval) { + errno = ENOMEM; + return NULL; + } + retval->offset = tz->offset; + retval->t2 = tz->t2; + memcpy(&(retval->dstStart), &(tz->dstStart), sizeof(DST_t)); + memcpy(&(retval->dstEnd), &(tz->dstEnd), sizeof(DST_t)); + retval->dstObserved = tz->dstObserved; + retval->t4 = tz->t4; + retval->unknown = tz->unknown; + if(NULL != tz->name) { + retval->name = strdup(tz->name); + } else { + retval->name = NULL; + } + + return retval; +} + +/*********************************************************************** + * + * Function: free_Timezone + * + * Summary: Free the members of a timezone structure + * + * Parameters: Timezone_t* + * + * Returns: void + * + ***********************************************************************/ +void +free_Timezone(Timezone_t *tz) { + if(tz->name != NULL) { + free(tz->name); + tz->name = NULL; + } +} + +/*********************************************************************** + * + * Function: unpack_DST + * + * Summary: Fill in the daylight savings time structure based on the raw record + * data + * + * Parameters: DST_t*, pi_buffer_t *buf + * + * Returns: -1 on error, 0 on success + * + ***********************************************************************/ +int +unpack_DST(DST_t *dst, const pi_buffer_t *buf) { + return unpack_DST_p(dst, buf->data, 0); +} +/** + Does the work for unpack_DST given a position in buf +*/ +int +unpack_DST_p(DST_t *dst, const unsigned char *data, const size_t position) { + uint8_t byte; + + byte = get_byte(data+position); + switch(byte) { + case 0x00: + dst->dayOfWeek = sunday; + break; + case 0x01: + dst->dayOfWeek = monday; + break; + case 0x02: + dst->dayOfWeek = tuesday; + break; + case 0x03: + dst->dayOfWeek = wednesday; + break; + case 0x04: + dst->dayOfWeek = thursday; + break; + case 0x05: + dst->dayOfWeek = friday; + break; + case 0x06: + dst->dayOfWeek = saturday; + break; + default: + printf("Illegal value found in day of week: 0x%02X\n", byte); + return -1; + } + + byte = get_byte(data+position+1); + switch(byte) { + case 0x00: + dst->weekOfMonth = first; + break; + case 0x01: + dst->weekOfMonth = second; + break; + case 0x02: + dst->weekOfMonth = third; + break; + case 0x03: + dst->weekOfMonth = fourth; + break; + case 0x04: + dst->weekOfMonth = last; + break; + default: + printf("Illegal value found in week: 0x%02Xd\n", byte); + return -1; + } + + byte = get_byte(data+position+2); + switch(byte) { + case 0x00: + dst->month = none; + break; + case 0x01: + dst->month = january; + break; + case 0x02: + dst->month = february; + break; + case 0x03: + dst->month = march; + break; + case 0x04: + dst->month = april; + break; + case 0x05: + dst->month = may; + break; + case 0x06: + dst->month = june; + break; + case 0x07: + dst->month = july; + break; + case 0x08: + dst->month = august; + break; + case 0x09: + dst->month = september; + break; + case 0x0a: + dst->month = october; + break; + case 0x0b: + dst->month = november; + break; + case 0x0c: + dst->month = december; + break; + default: + printf("Illegal value found in month: 0x%02Xd\n", byte); + return -1; + } + + dst->unknown = get_byte(data+position+3); + switch(dst->unknown) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + /*case 0x04:*/ + break; + default: + printf("Bad value for DST.unknown: 0x%02x\n", dst->unknown); + return -1; + } + + return 0; +} + +/*********************************************************************** + * + * Function: unpack_timezone + * + * Summary: Fill in the timezone structure based on the raw record + * data + * + * Parameters: Timezone_t*, pi_buffer_t *buf, optional position in buf + * + * Returns: -1 on error, number of bytes read on success + * + ***********************************************************************/ +int +unpack_Timezone(Timezone_t *tz, const pi_buffer_t *buf) { + return unpack_Timezone_p(tz, buf->data, 0); +} +/** + * Does the work of unpack_Timezone given a position in buf. + * + * Returns: -1 on error, number of bytes read on success + */ +int +unpack_Timezone_p(Timezone_t *tz, const unsigned char *data, const size_t position) { + uint8_t byte; + size_t localPosition = position; + + tz->offset = get_short(data+localPosition); + localPosition += 2; + /*printf("Offset is %d\n", tz->offset);*/ + + tz->t2 = get_byte(data + localPosition); + ++localPosition; + switch(tz->t2) { + case 0x00: + break; + case 0x01: + break; + case 0x02: + break; + case 0x03: + break; + default: + /*printf("Bad value for t2 0x%02X\n", tz->t2);*/ + return -1; + } + + if(unpack_DST_p(&(tz->dstStart), data, localPosition) != 0) { + return -1; + } + localPosition += 4; + + if(unpack_DST_p(&(tz->dstEnd), data, localPosition) != 0) { + return -1; + } + localPosition += 4; + + byte = get_byte(data+localPosition); + ++localPosition; + switch(byte) { + case 0x3c: + /* dst observed */ + tz->dstObserved = 1; + break; + case 0x00: + /* dst not observed */ + tz->dstObserved = 0; + break; + default: + printf("Illegal value in dst_observed 0x%02X\n", byte); + return -1; + } + + tz->t4 = get_byte(data+localPosition); + ++localPosition; + + tz->unknown = get_byte(data+localPosition); + ++localPosition; + switch(tz->unknown) { + case 0x80: + case 0x00: + break; + default: + printf("Bad value for unknown 0x%02X\n", tz->unknown); + return -1; + } + + if(0x00 == data+localPosition) { + tz->name = NULL; + ++localPosition; + } else { + tz->name = strdup((char *)(data+localPosition)); + localPosition += strlen(tz->name) + 1; + } + + return localPosition; +} + +/*********************************************************************** + * + * Function: unpack_Location + * + * Summary: Fill in the location structure based on the raw record + * data + * + * Parameters: Location_t*, pi_buffer_t *buf + * + * Returns: -1 on error, 0 on success + * + ***********************************************************************/ +int +unpack_Location(Location_t *loc, const pi_buffer_t *buf) +{ + size_t localPosition = 0; + + localPosition = unpack_Timezone_p(&(loc->tz), buf->data, localPosition); + if(localPosition < 0) { + return -1; + } + + loc->unknownExists = 0; + + /* unpack latitude */ + loc->latitude.degrees = get_short(buf->data+localPosition); + loc->latitude.minutes = get_short(buf->data+localPosition+2); + if(loc->latitude.degrees > 90 || loc->latitude.degrees < -90 + || loc->latitude.minutes > 60 || loc->latitude.minutes < -60) { + /* + printf("latitude degrees out of range: %d or\n", loc->latitude.degrees); + printf("latitude minutes out of range: %d\n", loc->latitude.minutes); + */ + + loc->unknownExists = 1; + loc->unknown = get_byte(buf->data+localPosition); + ++localPosition; + + /*printf("Found unknown: 0x%02X\n", loc->unknown); */ + + loc->latitude.degrees = get_short(buf->data+localPosition); + localPosition += 2; + loc->latitude.minutes = get_short(buf->data+localPosition); + localPosition += 2; + } else { + localPosition += 4; + } + + loc->longitude.degrees = get_short(buf->data+localPosition); + localPosition += 2; + loc->longitude.minutes = get_short(buf->data+localPosition); + localPosition += 2; + + /* now make latitude and longitude easy to read */ + loc->latitude.direction = south; + loc->longitude.direction = west; + if(loc->latitude.minutes < 0) { + loc->latitude.direction = north; + loc->latitude.minutes = -1 * loc->latitude.minutes; + } + if(loc->latitude.degrees < 0) { + loc->latitude.direction = north; + loc->latitude.degrees = -1 * loc->latitude.degrees; + } + if(loc->longitude.minutes < 0) { + loc->longitude.direction = east; + loc->longitude.minutes = -1 * loc->longitude.minutes; + } + if(loc->longitude.degrees < 0) { + loc->longitude.direction = east; + loc->longitude.degrees = -1 * loc->longitude.degrees; + } + + + if(0x00 == buf->data[localPosition]) { + loc->note = NULL; + ++localPosition; + } else { + loc->note = strdup((char *)(buf->data+localPosition)); + localPosition += strlen(loc->note) + 1; + } + + return 0; +} + + +/*********************************************************************** + * + * Function: pack_DST + * + * Summary: append raw DST record data to buf based on the + * DST structure + * + * Parameters: DST_t*, pi_buffer_t *buf of record, record type + * + * Returns: -1 on error, 0 on success. + * + ***********************************************************************/ +int +pack_DST(const DST_t *dst, pi_buffer_t *buf) +{ + size_t offset; + + if (dst == NULL || buf == NULL) + return -1; + + offset = buf->used; + + pi_buffer_expect(buf, buf->used + 4); + buf->used = buf->used + 4; + + switch(dst->dayOfWeek) { + case sunday: + set_byte(buf->data+offset, 0x00); + break; + case monday: + set_byte(buf->data+offset, 0x01); + break; + case tuesday: + set_byte(buf->data+offset, 0x02); + break; + case wednesday: + set_byte(buf->data+offset, 0x03); + break; + case thursday: + set_byte(buf->data+offset, 0x04); + break; + case friday: + set_byte(buf->data+offset, 0x05); + break; + case saturday: + set_byte(buf->data+offset, 0x06); + break; + default: + return -1; + + } + + switch(dst->weekOfMonth) { + case first: + set_byte(buf->data+offset+1, 0x00); + break; + case second: + set_byte(buf->data+offset+1, 0x01); + break; + case third: + set_byte(buf->data+offset+1, 0x02); + break; + case fourth: + set_byte(buf->data+offset+1, 0x03); + break; + case last: + set_byte(buf->data+offset+1, 0x04); + break; + default: + return -1; + + } + + switch(dst->month) { + case none: + set_byte(buf->data+offset+2, 0x00); + break; + case january: + set_byte(buf->data+offset+2, 0x01); + break; + case february: + set_byte(buf->data+offset+2, 0x02); + break; + case march: + set_byte(buf->data+offset+2, 0x03); + break; + case april: + set_byte(buf->data+offset+2, 0x04); + break; + case may: + set_byte(buf->data+offset+2, 0x05); + break; + case june: + set_byte(buf->data+offset+2, 0x06); + break; + case july: + set_byte(buf->data+offset+2, 0x07); + break; + case august: + set_byte(buf->data+offset+2, 0x08); + break; + case september: + set_byte(buf->data+offset+2, 0x09); + break; + case october: + set_byte(buf->data+offset+2, 0x0a); + break; + case november: + set_byte(buf->data+offset+2, 0x0b); + break; + case december: + set_byte(buf->data+offset+2, 0x0c); + break; + default: + return -1; + } + + set_byte(buf->data+offset+3, dst->unknown); + + return 0; +} + +/*********************************************************************** + * + * Function: pack_Timezone + * + * Summary: Append the raw Timezone record to buf based on the + * Timezone structure + * + * Parameters: Timezone_t*, pi_buffer_t *buf of record, record type + * + * Returns: -1 on error, 0 on success. + * + ***********************************************************************/ +int +pack_Timezone(const Timezone_t *tz, pi_buffer_t *buf) +{ + + size_t offset; + + if (tz == NULL || buf == NULL) + return -1; + + offset = buf->used; + pi_buffer_expect(buf, buf->used + 3); + buf->used = buf->used + 3; + + set_short(buf->data+offset, tz->offset); + set_byte(buf->data+offset+2, tz->t2); + + pack_DST(&(tz->dstStart), buf); + pack_DST(&(tz->dstEnd), buf); + + offset = buf->used; + pi_buffer_expect(buf, buf->used + 3); + buf->used = buf->used + 3; + + if(tz->dstObserved) { + set_byte(buf->data+offset, 0x3c); + } else { + set_byte(buf->data+offset, 0x00); + } + set_byte(buf->data+offset, tz->t4); + + if(NULL != tz->name) { + offset = buf->used; + pi_buffer_expect(buf, buf->used + strlen(tz->name)+1); + buf->used = buf->used + strlen(tz->name)+1; + + strcpy((char *)(buf->data+offset), tz->name); + } + + return 0; +} + +/*********************************************************************** + * + * Function: pack_Location + * + * Summary: Append the raw Location record to buf based on the + * Location structure + * + * Parameters: Location_t*, pi_buffer_t *buf of record, record type + * + * Returns: -1 on error, 0 on success. + * + ***********************************************************************/ +int +pack_Location(const Location_t *loc, pi_buffer_t *buf) +{ + size_t offset; + + if (loc == NULL || buf == NULL) + return -1; + + pack_Timezone(&(loc->tz), buf); + + if(loc->unknownExists) { + offset = buf->used; + pi_buffer_expect(buf, buf->used + 1); + buf->used = buf->used+1; + set_byte(buf->data+offset, loc->unknown); + } + + offset = buf->used; + pi_buffer_expect(buf, buf->used+8); + buf->used = buf->used+8; + + if(loc->latitude.direction == north) { + set_short(buf->data+offset, -1 * loc->latitude.degrees); + set_short(buf->data+offset+2, -1 * loc->latitude.minutes); + } else { + set_short(buf->data+offset, loc->latitude.degrees); + set_short(buf->data+offset+2, loc->latitude.minutes); + } + if(loc->longitude.direction == east) { + set_short(buf->data+offset+4, -1 * loc->longitude.degrees); + set_short(buf->data+offset+6, -1 * loc->longitude.minutes); + } else { + set_short(buf->data+offset+4, loc->longitude.degrees); + set_short(buf->data+offset+6, loc->longitude.minutes); + } + + if(NULL != loc->note) { + offset = buf->used; + pi_buffer_expect(buf, buf->used + strlen(loc->note)+1); + buf->used = buf->used + strlen(loc->note)+1; + + strcpy((char *)(buf->data+offset), loc->note); + } else { + offset = buf->used; + pi_buffer_expect(buf, buf->used + 1); + set_byte(buf->data+offset, 0); + buf->used = buf->used + 1; + } + + + return 0; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/mail.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/mail.c new file mode 100644 index 00000000..f4c97bc9 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/mail.c @@ -0,0 +1,683 @@ +/* + * $Id: mail.c,v 1.25 2006/10/12 14:21:22 desrod Exp $ + * + * mail.c: Translate Pilot mail data formats + * + * Copyright (c) 1997, Kenneth Albanowski + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include "pi-macros.h" +#include "pi-mail.h" + +char *MailSortTypeNames[] = { "Date", "Type", NULL }; +char *MailSyncTypeNames[] = { "All", "Send", "Filter", NULL }; + +/*********************************************************************** + * + * Function: free_Mail + * + * Summary: frees all the Mail_t structure members + * + * Parameters: Mail_t* + * + * Returns: void + * + ***********************************************************************/ +void +free_Mail(Mail_t *mail) +{ + if (mail->from != NULL) { + free(mail->from); + mail->from = NULL; + } + + if (mail->to != NULL) { + free(mail->to); + mail->to = NULL; + } + + if (mail->subject != NULL) { + free(mail->subject); + mail->to = NULL; + } + + if (mail->cc != NULL) { + free(mail->cc); + mail->cc = NULL; + } + + if (mail->bcc != NULL) { + free(mail->bcc); + mail->bcc = NULL; + } + + if (mail->replyTo) { + free(mail->replyTo); + mail->replyTo = NULL; + } + + if (mail->sentTo) { + free(mail->sentTo); + mail->sentTo = NULL; + } + + if (mail->body != NULL) { + free(mail->body); + mail->body = NULL; + } +} + + +/*********************************************************************** + * + * Function: free_MailAppInfo + * + * Summary: frees all MailAppInfo_t structure members + * + * Parameters: MailAppInfo_t* + * + * Returns: void + * + ***********************************************************************/ +void +free_MailAppInfo(MailAppInfo_t *appinfo) +{ + /* if (appinfo->signature) + free(appinfo->signature); */ +} + + +/*********************************************************************** + * + * Function: free_MailSyncPref + * + * Summary: frees all MailSyncPref_t structure members + * + * Parameters: MailSyncPref_t* + * + * Returns: void + * + ***********************************************************************/ +void +free_MailSyncPref(MailSyncPref_t *pref) +{ + if (pref->filterTo != NULL) { + free(pref->filterTo); + pref->filterTo = NULL; + } + + if (pref->filterFrom != NULL) { + free(pref->filterFrom); + pref->filterFrom = NULL; + } + + if (pref->filterSubject != NULL) { + free(pref->filterSubject); + pref->filterSubject = NULL; + } +} + + +/*********************************************************************** + * + * Function: free_MailSignaturePref + * + * Summary: frees all MailSignaturePref_t structure members + * + * Parameters: MailSignaturePref_t* + * + * Returns: void + * + ***********************************************************************/ +void +free_MailSignaturePref(MailSignaturePref_t *pref) +{ + if (pref->signature != NULL) { + free(pref->signature); + pref->signature = NULL; + } +} + + +/*********************************************************************** + * + * Function: unpack_Mail + * + * Summary: unpacks Mail + * + * Parameters: Mail_t*, char* to buffer, buffer length + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +unpack_Mail(Mail_t *mail, unsigned char *buffer, size_t len) +{ + int flags; + unsigned long d; + unsigned char *start = buffer; + + if (len < 6) + return 0; + + d = (unsigned short int) get_short(buffer); + mail->date.tm_year = (d >> 9) + 4; + mail->date.tm_mon = ((d >> 5) & 15) - 1; + mail->date.tm_mday = d & 31; + mail->date.tm_hour = get_byte(buffer + 2); + mail->date.tm_min = get_byte(buffer + 3); + mail->date.tm_sec = 0; + mail->date.tm_isdst = -1; + mktime(&mail->date); + + if (d) + mail->dated = 1; + else + mail->dated = 0; + + flags = get_byte(buffer + 4); + + mail->read = (flags & (1 << 7)) ? 1 : 0; + mail->signature = (flags & (1 << 6)) ? 1 : 0; + mail->confirmRead = (flags & (1 << 5)) ? 1 : 0; + mail->confirmDelivery = (flags & (1 << 4)) ? 1 : 0; + mail->priority = (flags & (3 << 2)) >> 2; + mail->addressing = (flags & 3); + + buffer += 6; + len -= 6; + + if (len < 1) + return 0; + if (get_byte(buffer)) { + mail->subject = strdup((char *)buffer); + buffer += strlen((char *)buffer); + len -= strlen((char *)buffer); + } else + mail->subject = 0; + buffer++; + len--; + if (len < 1) + return 0; + if (get_byte(buffer)) { + mail->from = strdup((char *)buffer); + buffer += strlen((char *)buffer); + len -= strlen((char *)buffer); + } else + mail->from = 0; + buffer++; + len--; + if (len < 1) + return 0; + if (get_byte(buffer)) { + mail->to = strdup((char *)buffer); + buffer += strlen((char *)buffer); + len -= strlen((char *)buffer); + } else + mail->to = 0; + buffer++; + len--; + if (len < 1) + return 0; + if (get_byte(buffer)) { + mail->cc = strdup((char *)buffer); + buffer += strlen((char *)buffer); + len -= strlen((char *)buffer); + } else + mail->cc = 0; + buffer++; + len--; + if (len < 1) + return 0; + if (get_byte(buffer)) { + mail->bcc = strdup((char *)buffer); + buffer += strlen((char *)buffer); + len -= strlen((char *)buffer); + } else + mail->bcc = 0; + buffer++; + len--; + if (len < 1) + return 0; + if (get_byte(buffer)) { + mail->replyTo = strdup((char *)buffer); + buffer += strlen((char *)buffer); + len -= strlen((char *)buffer); + } else + mail->replyTo = 0; + buffer++; + len--; + if (len < 1) + return 0; + if (get_byte(buffer)) { + mail->sentTo = strdup((char *)buffer); + buffer += strlen((char *)buffer); + len -= strlen((char *)buffer); + } else + mail->sentTo = 0; + buffer++; + len--; + if (len < 1) + return 0; + if (get_byte(buffer)) { + mail->body = strdup((char *)buffer); + buffer += strlen((char *)buffer); + len -= strlen((char *)buffer); + } else + mail->body = 0; + buffer++; + len--; + + return (buffer - start); +} + + +/*********************************************************************** + * + * Function: pack_Mail + * + * Summary: packs Mail + * + * Parameters: Mail_t*, char* to buffer, buffer length + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +pack_Mail(struct Mail *mail, unsigned char *buffer, size_t len) +{ + size_t destlen = 6 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; + unsigned char *start = buffer; + + if (mail->subject) + destlen += strlen(mail->subject); + if (mail->from) + destlen += strlen(mail->from); + if (mail->to) + destlen += strlen(mail->to); + if (mail->cc) + destlen += strlen(mail->cc); + if (mail->bcc) + destlen += strlen(mail->bcc); + if (mail->replyTo) + destlen += strlen(mail->replyTo); + if (mail->sentTo) + destlen += strlen(mail->sentTo); + if (mail->body) + destlen += strlen(mail->body); + + if (!buffer) + return destlen; + if (len < destlen) + return 0; + + set_short(buffer, + ((mail->date.tm_year - 4) << 9) | ((mail->date.tm_mon + + 1) << 5) | mail->date. + tm_mday); + set_byte(buffer + 2, mail->date.tm_hour); + set_byte(buffer + 3, mail->date.tm_min); + + if (!mail->dated) + set_long(buffer, 0); + + set_byte(buffer + 4, (mail->read ? (1 << 7) : 0) | + (mail->signature ? (1 << 6) : 0) | (mail-> + confirmRead ? (1 << 5) : + 0) | (mail-> + confirmDelivery + ? (1 << 4) : 0) | + ((mail->priority & 3) << 2) | (mail->addressing & 3)); + set_byte(buffer + 5, 0); + + buffer += 6; + + if (mail->subject) { + strcpy((char *)buffer, mail->subject); + buffer += strlen((char *)buffer); + } else + set_byte(buffer, 0); + buffer++; + if (mail->from) { + strcpy((char *)buffer, mail->from); + buffer += strlen((char *)buffer); + } else + set_byte(buffer, 0); + buffer++; + if (mail->to) { + strcpy((char *)buffer, mail->to); + buffer += strlen((char *)buffer); + } else + set_byte(buffer, 0); + buffer++; + if (mail->cc) { + strcpy((char *)buffer, mail->cc); + buffer += strlen((char *)buffer); + } else + set_byte(buffer, 0); + buffer++; + if (mail->bcc) { + strcpy((char *)buffer, mail->bcc); + buffer += strlen((char *)buffer); + } else + set_byte(buffer, 0); + buffer++; + if (mail->replyTo) { + strcpy((char *)buffer, mail->replyTo); + buffer += strlen((char *)buffer); + } else + set_byte(buffer, 0); + buffer++; + if (mail->sentTo) { + strcpy((char *)buffer, mail->sentTo); + buffer += strlen((char *)buffer); + } else + set_byte(buffer, 0); + buffer++; + if (mail->body) { + strcpy((char *)buffer, mail->body); + buffer += strlen((char *)buffer); + } else + set_byte(buffer, 0); + buffer++; + + return (buffer - start); +} + + +/*********************************************************************** + * + * Function: unpack_MailAppInfo + * + * Summary: unpacks MailAppInfo + * + * Parameters: MailAppInfo_t*, char* to buffer, buffer length + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +unpack_MailAppInfo(MailAppInfo_t *appinfo, unsigned char *record, size_t len) +{ + int i; + unsigned char *start = record; + + i = unpack_CategoryAppInfo(&appinfo->category, record, len); + if (!i) + return i; + record += i; + len -= i; + if (len < 11) + return 0; + appinfo->dirty = get_short(record); + record += 2; + appinfo->sortOrder = get_byte(record); + record += 2; + appinfo->unsentMessage = get_long(record); + record += 4; + +/* ai->signature = 0; */ +/* strdup(start + get_short(record)); */ + record += 3; + + return (record - start); +} + + +/*********************************************************************** + * + * Function: pack_MailAppInfo + * + * Summary: packs MailAppInfo + * + * Parameters: MailAppInfo_t*, char* to buffer, buffer length + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +pack_MailAppInfo(struct MailAppInfo *appinfo, unsigned char *record, size_t len) +{ + int i; + unsigned char *start = record; + + i = pack_CategoryAppInfo(&appinfo->category, record, len); + if (!record) + return i + 11; + if (!i) + return i; + record += i; + len -= i; + if (len < 8) + return 0; + set_short(record, appinfo->dirty); + record += 2; + set_short(record, 0); /* gapfill */ + set_byte(record, appinfo->sortOrder); + record += 2; + set_long(record, appinfo->unsentMessage); + record += 4; + + set_short(record, (record - start + 2)); + record += 2; + + /* if (appinfo->signature) + strcpy(record, appinfo->signature); + else + set_byte(record, 0); + record += strlen(record); */ + set_byte(record, 0); + record++; + + return (record - start); +} + + +/*********************************************************************** + * + * Function: unpack_MailSyncPref + * + * Summary: unpacks Mail + * + * Parameters: MailSyncPref_t*, char* to buffer, buffer length + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +unpack_MailSyncPref(MailSyncPref_t *pref, unsigned char *record, size_t len) +{ + unsigned char *start = record; + + pref->syncType = get_byte(record); + record += 1; + pref->getHigh = get_byte(record); + record += 1; + pref->getContaining = get_byte(record); + record += 2; + pref->truncate = get_short(record); + record += 2; + + if (get_byte(record)) { + pref->filterTo = strdup((char *)record); + record += strlen((char *)record); + } else + pref->filterTo = 0; + record++; + if (get_byte(record)) { + pref->filterFrom = strdup((char *)record); + record += strlen((char *)record); + } else + pref->filterFrom = 0; + record++; + if (get_byte(record)) { + pref->filterSubject = strdup((char *)record); + record += strlen((char *)record); + } else + pref->filterSubject = 0; + record++; + + return (record - start); +} + + +/*********************************************************************** + * + * Function: pack_MailSyncPref + * + * Summary: packs Mail + * + * Parameters: MailSyncPref_t*, char* to buffer, buffer length + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +pack_MailSyncPref(MailSyncPref_t *pref, unsigned char *record, size_t len) +{ + size_t destlen = 6 + 1 + 1 + 1; + unsigned char *start = record; + + if (pref->filterTo) + destlen += strlen(pref->filterTo); + if (pref->filterSubject) + destlen += strlen(pref->filterSubject); + if (pref->filterFrom) + destlen += strlen(pref->filterFrom); + + if (!record) + return destlen; + if (len < destlen) + return 0; + + set_byte(record, pref->syncType); + record++; + set_byte(record, pref->getHigh); + record++; + set_byte(record, pref->getContaining); + record++; + set_byte(record, 0); + record++; /* gapfill */ + set_short(record, pref->truncate); + record += 2; + + if (pref->filterTo) { + strcpy((char *)record, pref->filterTo); + record += strlen(pref->filterTo); + } + *record++ = 0; + + if (pref->filterFrom) { + strcpy((char *)record, pref->filterFrom); + record += strlen(pref->filterFrom); + } + *record++ = 0; + + if (pref->filterSubject) { + strcpy((char *)record, pref->filterSubject); + record += strlen(pref->filterSubject); + } + *record++ = 0; + + return (record - start); +} + + +/*********************************************************************** + * + * Function: unpack_MailSignaturePref + * + * Summary: unpacks MailSignaturePref + * + * Parameters: MailSignaturePref_t*, char* to buffer, buffer length + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +unpack_MailSignaturePref(MailSignaturePref_t *pref, + unsigned char *record, size_t len) +{ + unsigned char *start = record; + + if (len < 1) + return 0; + + pref->signature = strdup((char *)record); + + record += strlen(pref->signature) + 1; + + return (record - start); +} + + +/*********************************************************************** + * + * Function: pack_MailSignaturePref + * + * Summary: packs MailSignaturePref + * + * Parameters: MailSignaturePref_t*, char* to buffer, buffer length + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +pack_MailSignaturePref(struct MailSignaturePref *pref, unsigned char *record, + size_t len) +{ + size_t destlen = 1; + unsigned char *start = record; + + if (pref->signature) + destlen += strlen(pref->signature); + + if (!record) + return destlen; + if (len < destlen) + return 0; + if (pref->signature) { + strcpy((char *)record, pref->signature); + record += strlen(pref->signature); + } + *record = 0; + record++; + + return (record - start); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/md5.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/md5.c new file mode 100644 index 00000000..cc8213b0 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/md5.c @@ -0,0 +1,240 @@ +/* + * $Id: md5.c,v 1.9 2006/10/12 14:21:22 desrod Exp $ + * + * LICENSE: Public Domain + * + * This code implements the MD5 message-digest algorithm. The algorithm is + * due to Ron Rivest. This code was written by Colin Plumb in 1993, no + * copyright is claimed. This code is in the public domain; do with it what + * you wish. + * + * Equivalent code is available from RSA Data Security, Inc. This code has + * been tested against that, and is equivalent, except that you don't need + * to include two pages of legalese with every copy. + * + * To compute the message digest of a chunk of bytes, declare an MD5Context + * structure, pass it to MD5Init, call MD5Update as needed on buffers full + * of bytes, and then call MD5Final, which will fill a supplied 16-byte + * array with the digest. + * + * Modified by Ian Jackson in 1995 so as not to use Colin Plumb's + * 'usuals.h'. Arranged for byteSwap to be compiled and called even on + * little-endian machines, as performance isn't critical here. + * + */ + +#include <string.h> /* for memcpy() */ +#include "pi-md5.h" + +/* + * Note: this code is harmless but does nothing on little-endian machines. + */ +void byteSwap(UINT32 * buf, unsigned words) +{ + UINT8 *p = (UINT8 *) buf; + + do { + *buf++ = (UINT32) ((unsigned) p[3] << 8 | p[2]) << 16 | + ((unsigned) p[1] << 8 | p[0]); + p += 4; + } while (--words); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, UINT8 const *buf, unsigned len) +{ + UINT32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((UINT8 *) ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((UINT8 *) ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(UINT8 digest[16], struct MD5Context *ctx) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + UINT8 *p = (UINT8 *) ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, (size_t)(count + 8)); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (UINT8 *) ctx->in; + count = 56; + } + memset(p, 0, (size_t)count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(UINT32 buf[4], UINT32 const in[16]) +{ + register UINT32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/memo.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/memo.c new file mode 100644 index 00000000..aab418f8 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/memo.c @@ -0,0 +1,186 @@ +/* + * $Id: memo.c,v 1.27 2006/11/22 22:52:25 adridg Exp $ + * + * memo.c: Translate Pilot memopad data formats + * + * Copyright (c) 1996, Kenneth Albanowski + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pi-macros.h" +#include "pi-memo.h" + +/*********************************************************************** + * + * Function: free_Memo + * + * Summary: Frees all record data associated with the Memo database + * + * Parameters: Memo_t* + * + * Returns: void + * + ***********************************************************************/ +void +free_Memo(Memo_t *memo) +{ + if (memo->text != NULL) { + free(memo->text); + memo->text = NULL; + } +} + + +/*********************************************************************** + * + * Function: unpack_Memo + * + * Summary: Unpack the memo structure from the buffer + * + * Parameters: Memo_t*, char* to buffer, length + * + * Returns: Length in bytes of the buffer allocated + * + ***********************************************************************/ +int +unpack_Memo(Memo_t *memo, const pi_buffer_t *record, memoType type) +{ + if (type != memo_v1) + /* Don't support anything else yet */ + return -1; + if (record == NULL || record->data == NULL || record->used < 1) + return -1; + memo->text = strdup((char *) record->data); + return 0; +} + + +/*********************************************************************** + * + * Function: pack_Memo + * + * Summary: Pack the memo structure into the buffer allocated + * + * Parameters: Memo_t*, char* to buffer, length of buffer + * + * Returns: buffer length + * + ***********************************************************************/ +int +pack_Memo(const Memo_t *memo, pi_buffer_t *record, memoType type) +{ + size_t destlen = (memo->text ? strlen(memo->text) : 0) + 1; + + if (type != memo_v1) + /* Don't support anything else yet */ + return -1; + if (record == NULL) + return -1; + + pi_buffer_expect(record, destlen); + record->used = destlen; + + if (memo->text) + strcpy((char *) record->data, memo->text); + else + record->data[0] = 0; + + return 0; +} + + +/*********************************************************************** + * + * Function: unpack_MemoAppInfo + * + * Summary: Unpack the memo AppInfo block structure + * + * Parameters: MemoAppInfo_t*, char* to record, record length + * + * Returns: effective record length + * + ***********************************************************************/ +int +unpack_MemoAppInfo(struct MemoAppInfo *appinfo, const unsigned char *record, + size_t len) +{ + int i = unpack_CategoryAppInfo(&appinfo->category, record, len); + unsigned char *start = record; + + appinfo->type = memo_v1; + + if (!i) + return i; + record += i; + len -= i; + if (len >= 4) { + record += 2; + appinfo->sortByAlpha = get_byte(record); + record += 2; + } else { + appinfo->sortByAlpha = 0; + } + return (record - start); +} + + +/*********************************************************************** + * + * Function: pack_MemoAppInfo + * + * Summary: Pack the memo AppInfo block structure + * + * Parameters: MemoAppInfo_t*, char* to record, record length + * + * Returns: effective record length + * + ***********************************************************************/ +int +pack_MemoAppInfo(const MemoAppInfo_t *appinfo, unsigned char *record, size_t len) +{ + int i; + unsigned char *start = record; + + i = pack_CategoryAppInfo(&appinfo->category, record, len); + if (!record) + return i + 4; + if (i == 0) /* category pack failed */ + return 0; + record += i; + len -= i; + if (len < 4) + return (record - start); + set_short(record, 0); /* gapfill new for 2.0 */ + record += 2; + set_byte(record, appinfo->sortByAlpha); /* new for 2.0 */ + record++; + set_byte(record, 0); /* gapfill new for 2.0 */ + record++; + + return (record - start); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ + diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/money.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/money.c new file mode 100644 index 00000000..3173cae9 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/money.c @@ -0,0 +1,268 @@ +/* + * $Id: money.c,v 1.16 2006/10/12 14:21:22 desrod Exp $ + * + * money.c: Translate Pilot MoneyManager data formats + * + * Copyright (c) 1998, Rui Oliveira + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pi-macros.h" +#include "pi-money.h" + +/*********************************************************************** + * + * Function: unpack_Transaction + * + * Summary: unpacks Transaction_t data + * + * Parameters: Transaction_t*, char* to buffer, length of buffer + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +unpack_Transaction(Transaction_t *trans, unsigned char *buffer, size_t len) +{ + + unsigned char *p; + + if (len < 46) + return 0; + + p = buffer; + trans->flags = get_byte(p); + p += 2; /* gap */ + trans->checknum = get_short(p); + p += 2; + trans->amount = get_slong(p); + p += 4; + trans->total = get_slong(p); + p += 4; + trans->amountc = get_sshort(p); + p += 2; + trans->totalc = get_sshort(p); + p += 2; + + trans->second = get_sshort(p); + p += 2; + trans->minute = get_sshort(p); + p += 2; + trans->hour = get_sshort(p); + p += 2; + trans->day = get_sshort(p); + p += 2; + trans->month = get_sshort(p); + p += 2; + trans->year = get_sshort(p); + p += 2; + trans->wday = get_sshort(p); + p += 2; + + trans->repeat = get_byte(p); + p += 1; + trans->flags2 = get_byte(p); + p += 1; + trans->type = get_byte(p); + p += 1; + + memcpy(trans->reserved, p, 2); + p += 2; + + trans->xfer = get_byte(p); + p += 1; + + strcpy(trans->description, (char *)p); + p += 19; + strcpy(trans->note, (char *)p); + p += strlen((char *)p) + 1; + + return (p - buffer); +} + + +/*********************************************************************** + * + * Function: pack_Transaction + * + * Summary: unpacks Transaction_t data + * + * Parameters: Transaction_t*, char* to buffer, length of buffer + * + * Returns: effective buffer length + * + ***********************************************************************/ +int pack_Transaction(struct Transaction *trans, unsigned char *buffer, + size_t len) +{ + size_t destlen = 46 + strlen(trans->note) + 1; + unsigned char *p; + + if (!buffer) + return destlen; + if (len < destlen) + return 0; + + p = buffer; + set_byte(p, trans->flags); + p += 1; + set_byte(p, 0); + p += 1; /* gap fill */ + set_short(p, trans->checknum); + p += 2; + set_slong(p, trans->amount); + p += 4; + set_slong(p, trans->total); + p += 4; + set_sshort(p, trans->amountc); + p += 2; + set_sshort(p, trans->totalc); + p += 2; + + set_sshort(p, trans->second); + p += 2; + set_sshort(p, trans->minute); + p += 2; + set_sshort(p, trans->hour); + p += 2; + set_sshort(p, trans->day); + p += 2; + set_sshort(p, trans->month); + p += 2; + set_sshort(p, trans->year); + p += 2; + set_sshort(p, trans->wday); + p += 2; + + set_byte(p, trans->repeat); + p += 1; + set_byte(p, trans->flags2); + p += 1; + set_byte(p, trans->type); + p += 1; + + /* gap fill */ + set_short(p, 0); + p += 2; + + set_byte(p, trans->xfer); + p += 1; + + strcpy((char *)p, trans->description); + p += 19; + strcpy((char *)p, trans->note); + p += strlen((char *)p) + 1; + + return (p - buffer); +} + + +/*********************************************************************** + * + * Function: unpack_MoneyAppInfo + * + * Summary: unpacks MoneyAppInfo_t data + * + * Parameters: MoneyAppInfo_t*, char* to buffer, length of buffer + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +unpack_MoneyAppInfo(MoneyAppInfo_t *appinfo, unsigned char *buffer, size_t len) +{ + int i, + j; + + unsigned char *p; + + i = unpack_CategoryAppInfo(&appinfo->category, buffer, len); + if (!i) + return 0; + + p = (unsigned char *) (buffer + i); + + len -= i; + if (len < 603) + return 0; + + for (j = 0; j < 20; j++) { + memcpy(appinfo->typeLabels[j], p, 10); + p += 10; + } + + for (j = 0; j < 20; j++) { + memcpy(appinfo->tranLabels[j], p, 20); + p += 20; + } + + return i + 603; +} + + +/*********************************************************************** + * + * Function: pack_MoneyAppInfo + * + * Summary: packs MoneyAppInfo_t data + * + * Parameters: MoneyAppInfo_t*, char* to buffer, length of buffer + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +pack_MoneyAppInfo(MoneyAppInfo_t *appinfo, unsigned char *buffer, size_t len) +{ + int i, + j; + unsigned char *p; + + i = pack_CategoryAppInfo(&appinfo->category, buffer, len); + + if (!buffer) + return i + 603; + if (!i) + return i; + + p = (unsigned char *) (buffer + i); + len -= i; + if (i < 603) + return 0; + + for (j = 0; j < 20; j++) { + memcpy(p, appinfo->typeLabels[j], 10); + p += 10; + } + + for (j = 0; j < 20; j++) { + memcpy(p, appinfo->tranLabels[j], 20); + p += 20; + } + + return (i + 603); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/net.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/net.c new file mode 100644 index 00000000..27946982 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/net.c @@ -0,0 +1,715 @@ +/* + * $Id: net.c,v 1.45 2006/10/12 14:21:22 desrod Exp $ + * + * net.c: Protocol for NetSync connections + * + * Copyright (c) 1997, Kenneth Albanowski + * Copyright (c) 1999, Tilo Christ + * Copyright (c) 1999, John Franks + * Copyright (c) 2004, 2005 Florent Pillet + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-net.h" +#include "pi-error.h" + +#define PI_NET_TIMEOUT 30*1000 + +static int net_flush(pi_socket_t *ps, int flags); +static int net_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len); +static int net_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len); + +/*********************************************************************** + * + * Function: net_protocol_dup + * + * Summary: clones an existing pi_protocol struct + * + * Parameters: pi_protocol_t* + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +static pi_protocol_t +*net_protocol_dup (pi_protocol_t *prot) +{ + pi_protocol_t *new_prot = NULL; + pi_net_data_t *data = NULL, + *new_data = NULL; + + ASSERT(prot != NULL); + + new_prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t)); + if (new_prot != NULL) { + new_data = (pi_net_data_t *)malloc (sizeof (pi_net_data_t)); + if (new_data == NULL) { + free(new_prot); + new_prot = NULL; + } + } + + if (new_prot != NULL && new_data != NULL) { + new_prot->level = prot->level; + new_prot->dup = prot->dup; + new_prot->free = prot->free; + new_prot->read = prot->read; + new_prot->write = prot->write; + new_prot->flush = prot->flush; + new_prot->getsockopt = prot->getsockopt; + new_prot->setsockopt = prot->setsockopt; + + data = (pi_net_data_t *)prot->data; + new_data->type = data->type; + new_data->split_writes = data->split_writes; + new_data->write_chunksize = data->write_chunksize; + new_data->txid = data->txid; + new_prot->data = new_data; + } + + return new_prot; +} + + +/*********************************************************************** + * + * Function: net_protocol_free + * + * Summary: frees an existing pi_protocol struct + * + * Parameters: pi_protocol* + * + * Returns: void + * + ***********************************************************************/ +static +void net_protocol_free (pi_protocol_t *prot) +{ + ASSERT (prot != NULL); + + if (prot != NULL) { + if (prot->data != NULL) + free(prot->data); + free(prot); + } +} + + +/*********************************************************************** + * + * Function: net_protocol + * + * Summary: creates and inits pi_protocol struct instance + * + * Parameters: void + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +pi_protocol_t +*net_protocol (void) +{ + pi_protocol_t *prot = NULL; + pi_net_data_t *data = NULL; + + prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t)); + if (prot != NULL) { + data = (pi_net_data_t *)malloc (sizeof (pi_net_data_t)); + if (data == NULL) { + free(prot); + prot = NULL; + } + } + + if (prot != NULL && data != NULL) { + prot->level = PI_LEVEL_NET; + prot->dup = net_protocol_dup; + prot->free = net_protocol_free; + prot->read = net_rx; + prot->write = net_tx; + prot->flush = net_flush; + prot->getsockopt = net_getsockopt; + prot->setsockopt = net_setsockopt; + + data->type = PI_NET_TYPE_DATA; + data->split_writes = 1; /* write packet header and data separately */ + data->write_chunksize = 4096; /* and push data in 4k chunks. Required for some USB devices */ + data->txid = 0x00; + prot->data = data; + } + + return prot; +} + + +/*********************************************************************** + * + * Function: net_rx_handshake + * + * Summary: RX handshake + * + * Parameters: pi_socket_t* + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +int +net_rx_handshake(pi_socket_t *ps) +{ + static const unsigned char msg1[] = /* 50 bytes */ + "\x12\x01\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00" + "\x24\xff\xff\xff\xff\x3c\x00\x3c\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\xc0\xa8\xa5\x1f\x04\x27\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + static const unsigned char msg2[] = /* 46 bytes */ + "\x13\x01\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00" + "\x20\xff\xff\xff\xff\x00\x3c\x00\x3c\x00\x00\x00\x00" + "\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00"; + pi_buffer_t *buffer; + int err; + + buffer = pi_buffer_new (256); + if (buffer == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + if ((err = net_rx(ps, buffer, 256, 0)) >= 0 && + (err = net_tx(ps, msg1, 50, 0)) >= 0 && + (err = net_rx(ps, buffer, 50, 0)) >= 0 && + (err = net_tx(ps, msg2, 46, 0)) >= 0 && + (err = net_rx(ps, buffer, 8, 0)) >= 0) + { + pi_buffer_free (buffer); + return 0; + } + + pi_buffer_free (buffer); + return err; +} + + +/*********************************************************************** + * + * Function: net_tx_handshake + * + * Summary: TX handshake + * + * Parameters: pi_socket_t* + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +int +net_tx_handshake(pi_socket_t *ps) +{ + static const unsigned char msg1[] = /* 22 bytes */ + "\x90\x01\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00" + "\x08\x01\x00\x00\x00\x00\x00\x00\x00"; + static const unsigned char msg2[] = /* 50 bytes */ + "\x92\x01\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00" + "\x24\xff\xff\xff\xff\x00\x3c\x00\x3c\x40\x00\x00\x00" + "\x01\x00\x00\x00\xc0\xa8\xa5\x1e\x04\x01\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + static const unsigned char msg3[] = /* 8 bytes */ + "\x93\x00\x00\x00\x00\x00\x00\x00"; + pi_buffer_t *buffer; + int err; + + buffer = pi_buffer_new (256); + if (buffer == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + if ((err = net_tx(ps, msg1, 22, 0)) >= 0 && + (err = net_rx(ps, buffer, 256, 0)) >= 0 && + (err = net_tx(ps, msg2, 50, 0)) >= 0 && + (err = net_rx(ps, buffer, 256, 0)) >= 0 && + (err = net_tx(ps, msg3, 8, 0)) >= 0) + { + pi_buffer_free (buffer); + return 0; + } + + pi_buffer_free (buffer); + return err; +} + +/*********************************************************************** + * + * Function: net_flush + * + * Summary: Flush input and output buffers + * + * Parameters: pi_socket_t*, flags + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +int +net_flush(pi_socket_t *ps, int flags) +{ + pi_protocol_t *prot, + *next; + + prot = pi_protocol(ps->sd, PI_LEVEL_NET); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + next = pi_protocol_next(ps->sd, PI_LEVEL_NET); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + return next->flush(ps, flags); +} + +/*********************************************************************** + * + * Function: net_tx + * + * Summary: Transmit NET Packets + * + * Parameters: pi_socket_t*, char* to buf, buf length, flags + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +ssize_t +net_tx(pi_socket_t *ps, const unsigned char *msg, size_t len, int flags) +{ + int bytes, + offset, + remain, + tosend; + pi_protocol_t *prot, + *next; + pi_net_data_t *data; + unsigned char *buf; + + prot = pi_protocol(ps->sd, PI_LEVEL_NET); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + data = (pi_net_data_t *)prot->data; + + next = pi_protocol_next(ps->sd, PI_LEVEL_NET); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + /* Create the header */ + buf = (unsigned char *) malloc(PI_NET_HEADER_LEN + len); + if (buf == NULL) + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + buf[PI_NET_OFFSET_TYPE] = data->type; + if (data->type == PI_NET_TYPE_TCKL) + buf[PI_NET_OFFSET_TXID] = 0xff; + else + buf[PI_NET_OFFSET_TXID] = data->txid; + set_long(&buf[PI_NET_OFFSET_SIZE], len); + memcpy(&buf[PI_NET_HEADER_LEN], msg, len); + + /* Write the header and body, possibly in one write, or in two, + * or in more, depending on the current options. Crucial options + * here are `split_writes' and `write_chunksize' in this protocol's + * data (use net_setsockopt() to set them). + */ + if (data->split_writes) + { + /* Bugfix for USB send problems. If connected over + * USB, do the following: + * - send the 6 bytes of header first + * - split the rest of data into chunks if the write_chunksize opt is set + * This is what Palm Desktop does on Windows for the Zire 72 + * (uses split writes and 4k chunks) + * -- FP + */ + bytes = next->write(ps, buf, PI_NET_HEADER_LEN, flags); + if (bytes < PI_NET_HEADER_LEN) + { + free(buf); + return bytes; + } + offset = PI_NET_HEADER_LEN; + remain = len; + } + else + { + offset = 0; + remain = PI_NET_HEADER_LEN + len; + } + + while (remain > 0) + { + if (data->write_chunksize) + tosend = (remain > data->write_chunksize) ? data->write_chunksize : remain; + else + tosend = remain; + + bytes = next->write(ps, &buf[offset], tosend, flags); + if (bytes < tosend) + { + free(buf); + return bytes; + } + remain -= bytes; + offset += bytes; + } + + CHECK(PI_DBG_NET, PI_DBG_LVL_INFO, net_dump_header(buf, 1, ps->sd)); + CHECK(PI_DBG_NET, PI_DBG_LVL_DEBUG, pi_dumpdata((char *)msg, len)); + + free(buf); + return len; +} + +/*********************************************************************** + * + * Function: net_rx + * + * Summary: Receive NET Packets + * + * Parameters: ps --> socket to read from + * msg <-- malloc()ed buffer containing the data + * len --> unused + * flags --> unused + * + * Returns: A negative number on error, 0 on timeout, otherwise the + * length of the received packet. + * + ***********************************************************************/ +ssize_t +net_rx(pi_socket_t *ps, pi_buffer_t *msg, size_t len, int flags) +{ + int bytes, + total_bytes, + packet_len, + timeout, + honor_rx_timeout; + size_t size; + pi_protocol_t *prot, + *next; + pi_buffer_t *header; + pi_net_data_t *data; + + prot = pi_protocol(ps->sd, PI_LEVEL_NET); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (pi_net_data_t *)prot->data; + next = pi_protocol_next(ps->sd, PI_LEVEL_NET); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + size = sizeof(honor_rx_timeout); + pi_getsockopt(ps->sd, PI_LEVEL_SOCK, PI_SOCK_HONOR_RX_TIMEOUT, + &honor_rx_timeout, &size); + + timeout = honor_rx_timeout ? PI_NET_TIMEOUT : 0; + size = sizeof(timeout); + pi_setsockopt(ps->sd, PI_LEVEL_DEV, PI_DEV_TIMEOUT, + &timeout, &size); + + header = pi_buffer_new (PI_NET_HEADER_LEN); + if (header == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + /* loop until we find a non-tickle packet (if the other end + sends us a tickle, we would receive it prior to getting + the expected reply to one of our commands, so we need + to make sure tickle packets don't get in the way) */ + total_bytes = 0; + while (!total_bytes) { + if (data->txid == 0) { + /* Peek to see if it is a headerless packet */ + bytes = next->read(ps, header, 1, flags); + if (bytes <= 0) { + pi_buffer_free (header); + return bytes; + } + + LOG ((PI_DBG_NET, PI_DBG_LVL_INFO, + "NET RX (%i): Checking for headerless packet %d\n", + ps->sd, header->data[0])); + + if (header->data[0] == 0x90) { + /* Cause the header bytes to be skipped */ + LOG ((PI_DBG_NET, PI_DBG_LVL_INFO, + "NET RX (%i): Headerless packet\n", + ps->sd)); + total_bytes = PI_NET_HEADER_LEN; + header->data[PI_NET_OFFSET_TYPE] = PI_NET_TYPE_DATA; + header->data[PI_NET_OFFSET_TXID] = 0x01; + set_long (&header->data[PI_NET_OFFSET_SIZE], 21); + break; + } else { + total_bytes += bytes; + } + } + + /* bytes in what's left of the header */ + while (total_bytes < PI_NET_HEADER_LEN) { + bytes = next->read(ps, header, + (size_t)(PI_NET_HEADER_LEN - total_bytes), flags); + if (bytes <= 0) { + pi_buffer_free (header); + return bytes; + } + total_bytes += bytes; + } + + packet_len = get_long(&header->data[PI_NET_OFFSET_SIZE]); + data->type = header->data[PI_NET_OFFSET_TYPE]; + + switch (data->type) { + case PI_NET_TYPE_TCKL: + if (packet_len != 0) { + LOG ((PI_DBG_NET, PI_DBG_LVL_ERR, + "NET RX (%i): tickle packet with non-zero length\n", + ps->sd)); + pi_buffer_free(header); + return pi_set_error(ps->sd, PI_ERR_PROT_BADPACKET); + } + /* valid tickle packet; continue reading. */ + LOG((PI_DBG_NET, PI_DBG_LVL_DEBUG, + "NET RX (%i): received tickle packet\n", + ps->sd)); + total_bytes = 0; + header->used = 0; + break; + + case PI_NET_TYPE_DATA: + /* move on to reading the rest of the packet */ + break; + + default: + LOG ((PI_DBG_NET, PI_DBG_LVL_ERR, + "NET RX (%i): Unknown packet type\n", + ps->sd)); + CHECK(PI_DBG_NET, PI_DBG_LVL_INFO, pi_dumpdata((char *)header->data, PI_NET_HEADER_LEN)); + pi_buffer_free(header); + return pi_set_error(ps->sd, PI_ERR_PROT_BADPACKET); + } + } + + total_bytes = 0; + packet_len = get_long(&header->data[PI_NET_OFFSET_SIZE]); + + /* shield against absurd packet lengths */ + if (packet_len < 0 || packet_len > 0x100000L) { + /* we see an invalid packet */ + next->flush(ps, PI_FLUSH_INPUT); + LOG ((PI_DBG_NET, PI_DBG_LVL_ERR, "NET RX (%i): Invalid packet length (%ld)\n", ps->sd, packet_len)); + pi_buffer_free(header); + return pi_set_error(ps->sd, PI_ERR_PROT_BADPACKET); + } + + /* read the actual packet data */ + while (total_bytes < packet_len) { + bytes = next->read(ps, msg, + (size_t)(packet_len - total_bytes), flags); + if (bytes < 0) { + pi_buffer_free (header); + return bytes; + } + total_bytes += bytes; + } + + CHECK(PI_DBG_NET, PI_DBG_LVL_INFO, net_dump_header(header->data, 0, ps->sd)); + CHECK(PI_DBG_NET, PI_DBG_LVL_DEBUG, net_dump(header->data, msg->data)); + + /* Update the transaction id */ + if (ps->state == PI_SOCK_CONN_INIT || ps->command == 1) + data->txid = header->data[PI_NET_OFFSET_TXID]; + else { + data->txid++; + if (data->txid == 0xff) + data->txid = 1; + } + + pi_buffer_free (header); + return packet_len; +} + +/*********************************************************************** + * + * Function: net_getsockopt + * + * Summary: get options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +net_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len) +{ + pi_protocol_t *prot; + pi_net_data_t *data; + + prot = pi_protocol(ps->sd, PI_LEVEL_NET); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (pi_net_data_t *)prot->data; + + switch (option_name) { + case PI_NET_TYPE: + if (*option_len != sizeof (data->type)) { + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); + } + memcpy (option_value, &data->type, + sizeof (data->type)); + *option_len = sizeof (data->type); + break; + } + + return 0; +} + + +/*********************************************************************** + * + * Function: net_setsockopt + * + * Summary: set options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +net_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len) +{ + pi_protocol_t *prot; + pi_net_data_t *data; + + prot = pi_protocol(ps->sd, PI_LEVEL_NET); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (pi_net_data_t *)prot->data; + + switch (option_name) { + case PI_NET_TYPE: + if (*option_len != sizeof (data->type)) { + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); + } + memcpy (&data->type, option_value, + sizeof (data->type)); + break; + + /* this option, when set to != 0, instructs NET to separately + * write the NET header and the data block. Data can be further + * sent in chunks by also setting PI_NET_WRITE_CHUNKSIZE below. + */ + case PI_NET_SPLIT_WRITES: + if (*option_len != sizeof (data->split_writes)) { + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); + } + memcpy (&data->split_writes, option_value, + sizeof(data->split_writes)); + break; + + /* this option, when set to != 0, instructs NET to write the + * packet data in chunks of the given maximum size. If + * PI_NET_SPLIT_WRITES is not set, and this option is set, we + * chunk the whole write (including the NET header) + */ + case PI_NET_WRITE_CHUNKSIZE: + if (*option_len != sizeof (data->write_chunksize)) { + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); + } + memcpy (&data->write_chunksize, option_value, + sizeof(data->write_chunksize)); + break; + } + + return 0; +} + +/*********************************************************************** + * + * Function: net_dump_header + * + * Summary: Dump the NET packet header + * + * Parameters: char* to net packet, TX boolean + * + * Returns: void + * + ***********************************************************************/ +void +net_dump_header(unsigned char *data, int rxtx, int sd) +{ + LOG((PI_DBG_NET, PI_DBG_LVL_NONE, + "NET %s sd=%i type=%d txid=0x%.2x len=0x%.4x\n", + rxtx ? "TX" : "RX", + sd, + get_byte(&data[PI_NET_OFFSET_TYPE]), + get_byte(&data[PI_NET_OFFSET_TXID]), + get_long(&data[PI_NET_OFFSET_SIZE]))); +} + + +/*********************************************************************** + * + * Function: net_dump + * + * Summary: Dump the NET packet + * + * Parameters: char* to net packet + * + * Returns: void + * + ***********************************************************************/ +void +net_dump(unsigned char *header, unsigned char *data) +{ + size_t size; + + size = get_long(&header[PI_NET_OFFSET_SIZE]); + pi_dumpdata((char *)data, size); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/notepad.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/notepad.c new file mode 100644 index 00000000..aca64ed9 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/notepad.c @@ -0,0 +1,265 @@ +/* + * $Id: notepad.c,v 1.14 2006/10/12 14:21:22 desrod Exp $ + * + * notepad.c: Translate Palm NotePad application data formats + * + * Copyright (c) 2002, Angus Ainslie + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include "pi-macros.h" +#include "pi-notepad.h" + + +/*********************************************************************** + * + * Function: free_NotePad + * + * Summary: Free the memory and filehandle from the record alloc. + * + ***********************************************************************/ +void free_NotePad( NotePad_t *a ) +{ + if( a->flags & NOTEPAD_FLAG_NAME ) + { +/* fprintf( stderr, "Freeing name: %s\n", a->name ); */ + free(a->name); + } + + if( a->flags & NOTEPAD_FLAG_BODY ) + { +/* fprintf( stderr, "Freeing data\n" ); */ + free(a->data); + } + +} + + +/*********************************************************************** + * + * Function: unpack_NotePad + * + * Summary: Unpack the NotePad structure into records we can chew on + * + ***********************************************************************/ +int unpack_NotePad(NotePad_t *notepad, unsigned char *buffer, size_t len) +{ + unsigned char *start = buffer; + + notepad->createDate.sec = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->createDate.min = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->createDate.hour = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->createDate.day = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->createDate.month = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->createDate.year = (unsigned short int) get_short(buffer); + buffer += 2; + + notepad->createDate.s = (unsigned short int) get_short(buffer); + buffer += 2; + + notepad->changeDate.sec = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->changeDate.min = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->changeDate.hour = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->changeDate.day = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->changeDate.month = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->changeDate.year = (unsigned short int) get_short(buffer); + buffer += 2; + + notepad->changeDate.s = (unsigned short int) get_short(buffer); + buffer += 2; + + notepad->flags = (unsigned short int) get_short(buffer); + buffer += 2; + +/* fprintf( stderr, "flags: 0x%x\n", notepad->flags ); */ + + if( notepad->flags & NOTEPAD_FLAG_ALARM ) + { +/* fprintf( stderr, "Getting Alarm\n" ); */ + notepad->alarmDate.sec = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->alarmDate.min = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->alarmDate.hour = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->alarmDate.day = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->alarmDate.month = (unsigned short int) get_short(buffer); + buffer += 2; + notepad->alarmDate.year = (unsigned short int) get_short(buffer); + buffer += 2; + + notepad->alarmDate.s = (unsigned short int) get_short(buffer); + buffer += 2; + } + + if( notepad->flags & NOTEPAD_FLAG_NAME ) + { +/* fprintf( stderr, "Getting Name\n" ); */ + notepad->name = strdup((char *) buffer); + + buffer += strlen( notepad->name ) + 1; + + if( (strlen( notepad->name ) + 1)%2 == 1) + buffer++; + + } + else + { + notepad->name = NULL; + } + + + if( notepad->flags & NOTEPAD_FLAG_BODY ) + { +/* fprintf( stderr, "Getting Body\n" ); */ + notepad->body.bodyLen = get_long( buffer ); + buffer += 4; + + notepad->body.width = get_long( buffer ); + buffer += 4; + + notepad->body.height = get_long( buffer ); + buffer += 4; + + notepad->body.l1 = get_long( buffer ); + buffer += 4; + + notepad->body.dataType = get_long( buffer ); + buffer += 4; + + notepad->body.dataLen = get_long( buffer ); + buffer += 4; + + notepad->data = malloc( notepad->body.dataLen ); + + if( notepad->data == NULL ) + { + fprintf( stderr, "Body data alloc failed\n" ); + return( 0 ); + } + + memcpy( notepad->data, buffer, notepad->body.dataLen ); + + } + + return ( buffer - start ); /* FIXME: return real length */ +} + + +/*********************************************************************** + * + * Function: pack_NotePad + * + * Summary: Pack the NotePad records into a structure + * + ***********************************************************************/ +int pack_NotePad(NotePad_t *notepad, unsigned char *buf, size_t len) +{ + return( 0 ); +} + + +/*********************************************************************** + * + * Function: unpack_NotePadAppInfo + * + * Summary: Unpack the NotePad AppInfo block from the structure + * + ***********************************************************************/ +int unpack_NotePadAppInfo(NotePadAppInfo_t *appinfo, unsigned char *record, + size_t len) +{ + int i; + unsigned char *start = record; + + i = unpack_CategoryAppInfo( &appinfo->category, record, len ); + if (!i) + return 0; + record += i; + len -= i; + if (len < 4) + return 0; + appinfo->dirty = get_short(record); + record += 2; + appinfo->sortByPriority = get_byte(record); + record += 2; + return (record - start); +} + +/*********************************************************************** + * + * Function: pack_NotePadAppInfo + * + * Summary: Pack the AppInfo block/record back into the structure + * + ***********************************************************************/ +int +pack_NotePadAppInfo(NotePadAppInfo_t *appinfo, unsigned char *record, + size_t len) +{ + int i; + unsigned char *start = record; + + i = pack_CategoryAppInfo(&appinfo->category, record, len); + if (!record) + return i + 4; + if (!i) + return 0; + record += i; + len -= i; + if (len < 4) + return 0; + set_short(record, appinfo->dirty); + set_byte(record + 2, appinfo->sortByPriority); + set_byte(record + 3, 0); /* gapfill */ + record += 4; + + return (record - start); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ + diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/padp.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/padp.c new file mode 100644 index 00000000..ec364398 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/padp.c @@ -0,0 +1,971 @@ +/* + * $Id: padp.c,v 1.59 2006/10/13 09:52:13 fpillet Exp $ + * + * padp.c: Pilot PADP protocol + * + * (c) 1996, D. Jeff Dionne. + * Much of this code adapted from Brian J. Swetland <swetland@uiuc.edu> + * Mostly rewritten by Kenneth Albanowski. Adjusted timeout values and + * better error handling by Tilo Christ. + * (c) 2005, Florent Pillet + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-padp.h" +#include "pi-slp.h" +#include "pi-error.h" + +#define PI_PADP_TX_TIMEOUT 2*1000 +#define PI_PADP_TX_RETRIES 10 +#define PI_PADP_RX_BLOCK_TO 30*1000 +#define PI_PADP_RX_SEGMENT_TO 30*1000 + +/* Declare function prototypes */ +static int padp_flush(pi_socket_t *ps, int flags); +static int padp_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len); +static int padp_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len); +static int padp_sendack(struct pi_socket *ps, struct pi_padp_data *data, + unsigned char txid, struct padp *padp, int flags); + + +/*********************************************************************** + * + * Function: padp_protocol_dup + * + * Summary: clones an existing pi_protocol struct + * + * Parameters: pi_protocol* + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +static pi_protocol_t* +padp_protocol_dup (pi_protocol_t *prot) +{ + pi_protocol_t *new_prot = NULL; + pi_padp_data_t *data = NULL, + *new_data = NULL; + + new_prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t)); + if (new_prot != NULL) { + new_data = (pi_padp_data_t *)malloc (sizeof (pi_padp_data_t)); + if (new_data == NULL) { + free(new_prot); + new_prot = NULL; + } else { + new_prot->level = prot->level; + new_prot->dup = prot->dup; + new_prot->free = prot->free; + new_prot->read = prot->read; + new_prot->write = prot->write; + new_prot->flush = prot->flush; + new_prot->getsockopt = prot->getsockopt; + new_prot->setsockopt = prot->setsockopt; + + data = (pi_padp_data_t *)prot->data; + memcpy(new_data, data, sizeof(pi_padp_data_t)); + new_prot->data = new_data; + } + } + + return new_prot; +} + + +/*********************************************************************** + * + * Function: padp_protocol_free + * + * Summary: frees an existing pi_protocol struct + * + * Parameters: pi_protocol* + * + * Returns: void + * + ***********************************************************************/ +static +void padp_protocol_free (pi_protocol_t *prot) +{ + ASSERT (prot != NULL); + + if (prot != NULL) { + if (prot->data != NULL) + free(prot->data); + free(prot); + } +} + + +/*********************************************************************** + * + * Function: padp_protocol + * + * Summary: creates and inits pi_protocol struct instance + * + * Parameters: void + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +pi_protocol_t +*padp_protocol (void) +{ + pi_protocol_t *prot = NULL; + pi_padp_data_t *data = NULL; + + prot = (pi_protocol_t *) malloc (sizeof (pi_protocol_t)); + if (prot != NULL) { + data = (pi_padp_data_t *) malloc (sizeof (pi_padp_data_t)); + if (data == NULL) { + free(prot); + prot = NULL; + } else { + prot->level = PI_LEVEL_PADP; + prot->dup = padp_protocol_dup; + prot->free = padp_protocol_free; + prot->read = padp_rx; + prot->write = padp_tx; + prot->flush = padp_flush; + prot->getsockopt = padp_getsockopt; + prot->setsockopt = padp_setsockopt; + + data->type = padData; + data->last_type = -1; + data->txid = 0xff; + data->next_txid = 0xff; + data->freeze_txid = 0; + data->use_long_format = 0; + prot->data = data; + } + } + + return prot; +} + +/*********************************************************************** + * + * Function: padp_tx + * + * Summary: Transmit PADP packets + * + * Parameters: pi_socket_t*, char* to buffer, buffer length, flags + * + * Returns: Number of packets transmitted + * + ***********************************************************************/ +ssize_t +padp_tx(pi_socket_t *ps, const unsigned char *buf, size_t len, int flags) +{ + int fl = PADP_FL_FIRST, + count = 0, + retries, + result, + type, + socket, + timeout, + header_size; + size_t size, + tlen; + unsigned char txid; + pi_protocol_t *prot, *next; + pi_padp_data_t *data; + pi_buffer_t *padp_buf; + struct padp padp; + + prot = pi_protocol(ps->sd, PI_LEVEL_PADP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (pi_padp_data_t *)prot->data; + next = pi_protocol_next(ps->sd, PI_LEVEL_PADP); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + if (data->type == padWake) + data->txid = 0xff; + + if (!data->freeze_txid) { + if (data->txid == 0) + data->txid = 0x10; /* some random # */ + else if (data->txid >= 0xfe) + data->next_txid = 1; /* wrap */ + else + data->next_txid = data->txid + 1; + } + + if (data->type != padAck && ps->state == PI_SOCK_CONN_ACCEPT) + data->txid = data->next_txid; + + padp_buf = pi_buffer_new (PI_PADP_HEADER_LEN + 2 + PI_PADP_MTU); + if (padp_buf == NULL) + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + + pi_flush(ps->sd, PI_FLUSH_INPUT); + + do { + retries = PI_PADP_TX_RETRIES; + do { + padp_buf->used = 0; + + type = PI_SLP_TYPE_PADP; + socket = PI_SLP_SOCK_DLP; + timeout = PI_PADP_TX_TIMEOUT; + + size = sizeof(type); + pi_setsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_TYPE, &type, &size); + pi_setsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_DEST, &socket, &size); + pi_setsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_SRC, &socket, &size); + size = sizeof(timeout); + pi_setsockopt(ps->sd, PI_LEVEL_DEV, PI_DEV_TIMEOUT, &timeout, &size); + size = sizeof(data->txid); + pi_setsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_TXID, &data->txid, &size); + + tlen = (len > PI_PADP_MTU) ? PI_PADP_MTU : len; + header_size = data->use_long_format ? PI_PADP_HEADER_LEN+2 : PI_PADP_HEADER_LEN; + + /* build the packet */ + set_byte(&padp_buf->data[PI_PADP_OFFSET_TYPE], data->type); + set_byte(&padp_buf->data[PI_PADP_OFFSET_FLGS], fl | + (len == tlen ? PADP_FL_LAST : 0) | + (data->use_long_format ? PADP_FL_LONG : 0)); + if (data->use_long_format) + set_long(&padp_buf->data[PI_PADP_OFFSET_SIZE], (fl ? len : (size_t)count)); + else + set_short(&padp_buf->data[PI_PADP_OFFSET_SIZE], (fl ? len : (size_t)count)); + memcpy(padp_buf->data + header_size, buf, tlen); + + CHECK(PI_DBG_PADP, PI_DBG_LVL_INFO, padp_dump_header(padp_buf->data, 1)); + CHECK(PI_DBG_PADP, PI_DBG_LVL_DEBUG, padp_dump(padp_buf->data)); + + /* send the packet, check for disconnection (i.e. when running over USB) */ + result = next->write(ps, padp_buf->data, header_size + tlen, flags); + if (result < 0) { + if (result == PI_ERR_SOCK_DISCONNECTED) + goto disconnected; + } + + /* Tickles don't get acks */ + if (data->type == padTickle) + break; + +keepwaiting: + LOG((PI_DBG_PADP, PI_DBG_LVL_DEBUG, "PADP TX waiting for ACK\n")); + result = next->read(ps, padp_buf, PI_PADP_HEADER_LEN + 2 + PI_PADP_MTU, flags); + if (result > 0) { + padp.type = get_byte(&padp_buf->data[PI_PADP_OFFSET_TYPE]); + padp.flags = get_byte(&padp_buf->data[PI_PADP_OFFSET_FLGS]); + if (padp.flags & PADP_FL_LONG) { + header_size = PI_PADP_HEADER_LEN + 2; + padp.size = get_long(&padp_buf->data[PI_PADP_OFFSET_SIZE]); + } else { + header_size = PI_PADP_HEADER_LEN; + padp.size = get_short(&padp_buf->data[PI_PADP_OFFSET_SIZE]); + } + + CHECK(PI_DBG_PADP, PI_DBG_LVL_INFO, padp_dump_header(padp_buf->data, 0)); + CHECK(PI_DBG_PADP, PI_DBG_LVL_DEBUG, padp_dump(padp_buf->data)); + + size = sizeof(type); + pi_getsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_LASTTYPE, &type, &size); + size = sizeof(txid); + pi_getsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_LASTTXID, &txid, &size); + + if (type == PI_SLP_TYPE_PADP + && padp.type == (unsigned char)padData + && txid == data->txid + && len == tlen) { + /* We didn't receive the ack for the + last packet, but the incomding data + is the response to this transmission. + The ack was lost. + */ + LOG((PI_DBG_PADP, PI_DBG_LVL_WARN, + "PADP TX Missing Ack\n")); + count += tlen; + goto done; + } else if (padp.type == (unsigned char)padTickle) { + /* Tickle to avoid timeout */ + goto keepwaiting; + } else if (type == PI_SLP_TYPE_PADP && + padp.type == (unsigned char)padAck && + txid == data->txid) { + if (padp.flags & PADP_FL_MEMERROR) { + /* OS 2.x enjoys sending erroneous memory errors */ + LOG((PI_DBG_PADP, PI_DBG_LVL_WARN, + "PADP TX Memory Error\n")); + + /* Mimimum failure: transmission failed due to + * lack of memory in reciever link layer, but + * connection is still active. This transmission + * was lost, but other transmissions will be + * received. + */ + errno = EMSGSIZE; + count = -1; + goto done; + } + + /* Successful Ack */ + buf = buf + tlen; + len -= tlen; + count += tlen; + fl = 0; + LOG((PI_DBG_PADP, PI_DBG_LVL_DEBUG, "PADP TX got ACK\n")); + break; + } else if (type == PI_SLP_TYPE_PADP && + padp.type == data->last_ack_padp.type && + padp.flags == data->last_ack_padp.flags && + padp.size == data->last_ack_padp.size && + txid == data->last_ack_txid) { + /* A repeat of a packet we already received. The + ack got lost, so resend it. */ + LOG((PI_DBG_PADP, PI_DBG_LVL_WARN, + "PADP TX resending lost ACK\n")); + padp_sendack(ps, data, txid, &padp, flags); + continue; + } else { + LOG((PI_DBG_PADP, PI_DBG_LVL_ERR, + "PADP TX Unexpected packet " + "(possible port speed problem? " + "out of sync packet?)\n")); + padp_dump_header (buf, 1); + /* Got unknown packet */ + errno = EIO; + count = -1; + goto done; + } + + } else if (result == PI_ERR_SOCK_DISCONNECTED) + goto disconnected; + + } while (--retries > 0); + + if (retries == 0) { + /* Maximum failure: transmission + failed, and the connection must be presumed dead */ + LOG((PI_DBG_PADP, PI_DBG_LVL_ERR, "PADP TX too many retries")); + errno = ETIMEDOUT; + pi_buffer_free (padp_buf); + ps->state = PI_SOCK_CONN_BREAK; + return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED); + } + } while (len); + +done: + if (data->type != padAck && ps->state == PI_SOCK_CONN_INIT) + data->txid = data->next_txid; + pi_buffer_free (padp_buf); + return count; + +disconnected: + LOG((PI_DBG_PADP, PI_DBG_LVL_ERR, "PADP TX disconnected")); + pi_buffer_free(padp_buf); + ps->state = PI_SOCK_CONN_BREAK; + return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED); +} + + +/*********************************************************************** + * + * Function: padp_rx + * + * Summary: Receive PADP packets + * + * Parameters: pi_socket_t*, char* to buffer, expected length, flags + * + * Returns: number of bytes received or negative on error + * + ***********************************************************************/ +ssize_t +padp_rx(pi_socket_t *ps, pi_buffer_t *buf, size_t expect, int flags) +{ + int bytes, + offset = 0, + ouroffset = 0, + honor_rx_timeout, + type, + timeout, + header_size; + unsigned char txid; + size_t total_bytes, + size; + pi_protocol_t *next, *prot; + pi_padp_data_t *data; + struct padp padp; + pi_buffer_t *padp_buf; + time_t endtime; + + LOG((PI_DBG_PADP, PI_DBG_LVL_DEBUG, "PADP RX expect=%d flags=0x%04x\n", + expect, flags)); + + prot = pi_protocol(ps->sd, PI_LEVEL_PADP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (pi_padp_data_t *)prot->data; + next = pi_protocol_next(ps->sd, PI_LEVEL_PADP); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + size = sizeof(honor_rx_timeout); + pi_getsockopt(ps->sd, PI_LEVEL_SOCK, PI_SOCK_HONOR_RX_TIMEOUT, + &honor_rx_timeout, &size); + + padp_buf = pi_buffer_new (PI_PADP_HEADER_LEN + PI_PADP_MTU); + if (padp_buf == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + /* the txid may be "frozen" if we're in the process of doing a large read + * over VFS. In this case, all packets have the same txid + */ + if (!data->freeze_txid) { + if (ps->state == PI_SOCK_CONN_ACCEPT) { + if (data->txid >= 0xfe) + data->next_txid = 1; /* wrap */ + else + data->next_txid = data->txid + 1; + } else + data->next_txid = data->txid; + } + + endtime = time(NULL) + PI_PADP_RX_BLOCK_TO / 1000; + + for (;;) { + if (honor_rx_timeout && time(NULL) > endtime) { + LOG((PI_DBG_PADP, PI_DBG_LVL_ERR, + "PADP RX Timed out")); + /* Bad timeout breaks connection */ + errno = ETIMEDOUT; + ps->state = PI_SOCK_CONN_BREAK; + pi_buffer_free (padp_buf); + return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED); + } + + timeout = honor_rx_timeout ? PI_PADP_RX_BLOCK_TO + 2000 : 0; + size = sizeof(timeout); + pi_setsockopt(ps->sd, PI_LEVEL_DEV, PI_DEV_TIMEOUT, + &timeout, &size); + + total_bytes = 0; + padp_buf->used = 0; + header_size = PI_PADP_HEADER_LEN; + while (total_bytes < header_size) { + bytes = next->read(ps, padp_buf, + (size_t)header_size + PI_PADP_MTU - total_bytes, flags); + if (bytes < 0) { + LOG((PI_DBG_PADP, PI_DBG_LVL_ERR, "PADP RX Read Error\n")); + pi_buffer_free (padp_buf); + return bytes; + } + total_bytes += bytes; + + /* check for the long packet format flag and adjust header size */ + if (header_size==PI_PADP_HEADER_LEN && + total_bytes >= PI_PADP_HEADER_LEN && + (padp_buf->data[PI_PADP_OFFSET_FLGS] & PADP_FL_LONG)) { + header_size += 2; + } + } + + padp.type = padp_buf->data[PI_PADP_OFFSET_TYPE]; + padp.flags = padp_buf->data[PI_PADP_OFFSET_FLGS]; + if (padp.flags & PADP_FL_LONG) + padp.size = get_long(&padp_buf->data[PI_PADP_OFFSET_SIZE]); + else + padp.size = get_short(&padp_buf->data[PI_PADP_OFFSET_SIZE]); + + size = sizeof(type); + pi_getsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_LASTTYPE, &type, &size); + size = sizeof(txid); + pi_getsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_LASTTXID, &txid, &size); + + if (padp.flags & PADP_FL_MEMERROR) { + if (txid == data->txid) { + LOG((PI_DBG_PADP, PI_DBG_LVL_WARN, + "PADP RX Memory Error\n")); + errno = EMSGSIZE; + ouroffset = -1; + goto done; /* Mimimum failure: + transmission failed due to + lack of memory in reciever + link layer, but connection is + still active. This + transmission was lost, but + other transmissions will be + received. */ + } + continue; + } else if (padp.type == padTickle) { + /* Tickle to avoid timeout */ + LOG((PI_DBG_PADP, PI_DBG_LVL_WARN, + "PADP RX Got Tickled\n")); + endtime = time(NULL) + PI_PADP_RX_BLOCK_TO / 1000; + continue; + } else if (type != PI_SLP_TYPE_PADP || + padp.type != padData || + txid != data->txid || + !(padp.flags & PADP_FL_FIRST)) { + LOG((PI_DBG_PADP, PI_DBG_LVL_ERR, + "PADP RX Wrong packet type on queue" + "(possible port speed problem? (loc1))\n")); + continue; + } + break; + } + + /* OK, we got the expected begin-of-data packet */ + endtime = time(NULL) + PI_PADP_RX_SEGMENT_TO / 1000; + + for (;;) { + CHECK(PI_DBG_PADP, PI_DBG_LVL_INFO, padp_dump_header(padp_buf->data, 0)); + CHECK(PI_DBG_PADP, PI_DBG_LVL_DEBUG, padp_dump(padp_buf->data)); + + /* Ack the packet */ + padp_sendack(ps, data, data->txid, &padp, flags); + + /* calculate length and offset - remove */ + offset = ((padp.flags & PADP_FL_FIRST) ? 0 : padp.size); + total_bytes -= PI_PADP_HEADER_LEN; + + /* If packet was out of order, ignore it */ + if (offset == ouroffset) { + if (pi_buffer_append (buf, &padp_buf->data[header_size], total_bytes) == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + ouroffset += total_bytes; + } + + if (padp.flags & PADP_FL_LAST) + break; + + endtime = time(NULL) + PI_PADP_RX_SEGMENT_TO / 1000; + + for (;;) { + if (honor_rx_timeout && time(NULL) > endtime) { + LOG((PI_DBG_PADP, PI_DBG_LVL_ERR, + "PADP RX Segment Timeout")); + + /* Segment timeout, return error */ + errno = ETIMEDOUT; + ouroffset = -1; + /* Bad timeout breaks connection */ + ps->state = PI_SOCK_CONN_BREAK; + pi_buffer_free (padp_buf); + return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED); + } + + timeout = honor_rx_timeout ? (PI_PADP_RX_SEGMENT_TO + 2000) : 0; + size = sizeof(timeout); + pi_setsockopt(ps->sd, PI_LEVEL_DEV, PI_DEV_TIMEOUT, &timeout, &size); + + total_bytes = 0; + padp_buf->used = 0; + header_size = PI_PADP_HEADER_LEN; + + while (total_bytes < header_size) { + bytes = next->read(ps, padp_buf, + header_size + PI_PADP_MTU - total_bytes, flags); + if (bytes < 0) { + LOG((PI_DBG_PADP, PI_DBG_LVL_ERR, "PADP RX Read Error")); + pi_buffer_free (padp_buf); + return pi_set_error(ps->sd, bytes); + } + total_bytes += bytes; + + /* check for the long packet format flag and adjust header size */ + if (header_size==PI_PADP_HEADER_LEN && + total_bytes >= PI_PADP_HEADER_LEN && + (padp_buf->data[PI_PADP_OFFSET_FLGS] & PADP_FL_LONG)) { + header_size += 2; + } + } + + padp.type = padp_buf->data[PI_PADP_OFFSET_TYPE]; + padp.flags = padp_buf->data[PI_PADP_OFFSET_FLGS]; + if (padp.flags & PADP_FL_LONG) + padp.size = get_long(&padp_buf->data[PI_PADP_OFFSET_SIZE]); + else + padp.size = get_short(&padp_buf->data[PI_PADP_OFFSET_SIZE]); + + CHECK(PI_DBG_PADP, PI_DBG_LVL_INFO, padp_dump_header(padp_buf->data, 0)); + CHECK(PI_DBG_PADP, PI_DBG_LVL_DEBUG, padp_dump(padp_buf->data)); + + size = sizeof(type); + pi_getsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_LASTTYPE, &type, &size); + size = sizeof(txid); + pi_getsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_LASTTXID, &txid, &size); + + if (padp.flags & PADP_FL_MEMERROR) { + if (txid == data->txid) { + /* Mimimum failure: transmission failed due + to lack of memory in receiver link layer, + but connection is still active. This + transmission was lost, but other transmissions + will be received. */ + LOG((PI_DBG_PADP, PI_DBG_LVL_WARN, + "PADP RX Memory Error")); + errno = EMSGSIZE; + ouroffset = -1; + goto done; + } + continue; + } + + if (padp.type == (unsigned char) 4) { + /* Tickle to avoid timeout */ + endtime = time(NULL) + + PI_PADP_RX_BLOCK_TO / 1000; + LOG((PI_DBG_PADP, PI_DBG_LVL_WARN, + "PADP RX Got Tickled")); + continue; + } + + if (type != PI_SLP_TYPE_PADP || + padp.type != padData || + txid != data->txid || + (padp.flags & PADP_FL_FIRST)) { + LOG((PI_DBG_PADP, PI_DBG_LVL_ERR, + "PADP RX Wrong packet type on queue" + "(possible port speed problem? (loc2))\n")); + continue; + } + break; + } + } + +done: + data->txid = data->next_txid; + + pi_buffer_free (padp_buf); + + return ouroffset; +} + +/*********************************************************************** + * + * Function: padp_flush + * + * Summary: Flush input and output buffers + * + * Parameters: pi_socket_t*, flags + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +static int +padp_flush(pi_socket_t *ps, int flags) +{ + pi_protocol_t *prot, + *next; + + prot = pi_protocol(ps->sd, PI_LEVEL_PADP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + next = pi_protocol_next(ps->sd, PI_LEVEL_PADP); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + return next->flush(ps, flags); +} + +/*********************************************************************** + * + * Function: padp_getsockopt + * + * Summary: get options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +padp_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len) +{ + pi_protocol_t *prot; + pi_padp_data_t *data; + + prot = pi_protocol(ps->sd, PI_LEVEL_PADP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + data = (pi_padp_data_t *)prot->data; + + switch (option_name) { + case PI_PADP_TYPE: + if (*option_len != sizeof (data->type)) + goto error; + memcpy (option_value, &data->type, sizeof (data->type)); + break; + + case PI_PADP_LASTTYPE: + if (*option_len != sizeof (data->last_type)) + goto error; + memcpy (option_value, &data->last_type, sizeof (data->last_type)); + break; + + case PI_PADP_FREEZE_TXID: + if (*option_len != sizeof (data->freeze_txid)) + goto error; + memcpy (option_value, &data->freeze_txid, sizeof(data->freeze_txid)); + break; + + case PI_PADP_USE_LONG_FORMAT: + if (*option_len != sizeof (data->use_long_format)) + goto error; + memcpy (option_value, &data->use_long_format, sizeof(data->use_long_format)); + break; + } + + return 0; + + error: + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); +} + + +/*********************************************************************** + * + * Function: padp_setsockopt + * + * Summary: get options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +padp_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len) +{ + pi_protocol_t *prot; + pi_padp_data_t *data; + int was_frozen; + + prot = pi_protocol(ps->sd, PI_LEVEL_PADP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + data = (pi_padp_data_t *)prot->data; + + switch (option_name) { + case PI_PADP_TYPE: + if (*option_len != sizeof (data->type)) + goto error; + memcpy (&data->type, option_value, sizeof (data->type)); + break; + + case PI_PADP_FREEZE_TXID: + if (*option_len != sizeof (data->freeze_txid)) + goto error; + was_frozen = data->freeze_txid; + memcpy (&data->freeze_txid, option_value, sizeof (data->freeze_txid)); + if (was_frozen && !data->freeze_txid) { + data->next_txid++; + if (data->next_txid >= 0xfe) + data->next_txid = 1; + } + break; + + case PI_PADP_USE_LONG_FORMAT: + if (*option_len != sizeof (data->use_long_format)) + goto error; + memcpy (&data->use_long_format, option_value, sizeof(data->use_long_format)); + break; + } + + return 0; + + error: + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); +} + +/*********************************************************************** +* +* Function: padp_sendack +* +* Summary: Acknowledge receipt of a packet +* +* Parameters: +* +* Returns: +* +***********************************************************************/ +static int +padp_sendack(struct pi_socket *ps, + struct pi_padp_data *data, /* padp state, will be modified */ + unsigned char txid, /* txid of the packet being acked */ + struct padp *padp, /* padp header of the packet being acked */ + int flags) +{ + int type, + socket, + result, + header_size; + size_t size; + unsigned char + npadp_buf[PI_PADP_HEADER_LEN+2]; + struct pi_protocol + *next; + + next = pi_protocol_next(ps->sd, PI_LEVEL_PADP); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + type = 2; + socket = PI_SLP_SOCK_DLP; + size = sizeof(type); + pi_setsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_TYPE, &type, &size); + pi_setsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_DEST, &socket, &size); + pi_setsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_SRC, &socket, &size); + size = sizeof(txid); + pi_setsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_TXID, &txid, &size); + + header_size = PI_PADP_HEADER_LEN; + set_byte(&npadp_buf[PI_PADP_OFFSET_TYPE], padAck); + set_byte(&npadp_buf[PI_PADP_OFFSET_FLGS], padp->flags); + if (padp->flags & PADP_FL_LONG) { + header_size += 2; + set_long(&npadp_buf[PI_PADP_OFFSET_SIZE], padp->size); + } else { + set_short(&npadp_buf[PI_PADP_OFFSET_SIZE], padp->size); + } + + CHECK(PI_DBG_PADP, PI_DBG_LVL_INFO, padp_dump_header(npadp_buf, 1)); + CHECK(PI_DBG_PADP, PI_DBG_LVL_DEBUG, padp_dump(npadp_buf)); + + result = next->write(ps, npadp_buf, header_size, flags); + + if (result >= 0) { + data->last_ack_txid = txid; + data->last_ack_padp.type = padp->type; + data->last_ack_padp.flags = padp->flags; + data->last_ack_padp.size = padp->size; + } + + return result; +} + +/*********************************************************************** + * + * Function: padp_dump_header + * + * Summary: Dump PADP packet header + * + * Parameters: char* to data, RXTX boolean + * + * Returns: void + * + ***********************************************************************/ +void +padp_dump_header(const unsigned char *data, int rxtx) +{ + long s; + char *stype; + unsigned char type, flags; + + type = get_byte (&data[PI_PADP_OFFSET_TYPE]); + switch (type) { + case padData: + stype = "DATA"; + break; + case padAck: + stype = "ACK"; + break; + case padTickle: + stype = "TICKLE"; + break; + case padAbort: + stype = "ABORT"; + break; + default: + stype = "UNK"; + break; + } + + flags = get_byte(&data[PI_PADP_OFFSET_FLGS]); + if (flags & PADP_FL_LONG) + s = get_long(&data[PI_PADP_OFFSET_SIZE]); + else + s = get_short(&data[PI_PADP_OFFSET_SIZE]); + + LOG((PI_DBG_PADP, PI_DBG_LVL_NONE, + "PADP %s %c%c%c type=%s len=%ld\n", + rxtx ? "TX" : "RX", + (flags & PADP_FL_FIRST) ? 'F' : ' ', + (flags & PADP_FL_LAST) ? 'L' : ' ', + (flags & PADP_FL_MEMERROR) ? 'M' : ' ', + stype, s)); +} + + +/*********************************************************************** + * + * Function: padp_dump + * + * Summary: Dump PADP packets + * + * Parameters: char* to data + * + * Returns: void + * + ***********************************************************************/ +void +padp_dump(const unsigned char *data) +{ + size_t size; + unsigned char + type, + flags; + int header_size = PI_PADP_HEADER_LEN; + + type = get_byte (&data[PI_PADP_OFFSET_TYPE]); + flags = get_byte (&data[PI_PADP_OFFSET_FLGS]); + if (flags & PADP_FL_LONG) { + header_size += 2; + size = get_long(&data[PI_PADP_OFFSET_SIZE]); + } else + size = get_short(&data[PI_PADP_OFFSET_SIZE]); + + if (size > PI_PADP_MTU) + size = PI_PADP_MTU; + if (type != padAck) + pi_dumpdata((char *)&data[header_size], size); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ + diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/palmpix.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/palmpix.c new file mode 100644 index 00000000..5a4c3cc4 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/palmpix.c @@ -0,0 +1,1815 @@ +/* + * $Id: palmpix.c,v 1.17 2006/10/12 14:21:22 desrod Exp $ + * + * palmpix.c: Translate PalmPix image format + * + * Copyright 2001 Angus Ainslie <angusa@deltatee.com> + * Copyright 2001 John Marshall <jmarshall@acm.org> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#if HAVE_STDINT_H +# include <stdint.h> +#else +# if HAVE_INTTYPES_H +# include <inttypes.h> +# else + +# ifndef uint8_t +# define uint8_t unsigned char +# endif + +# ifndef uint16_t +# define uint16_t unsigned short +# endif + +# ifndef uint32_t +# define uint32_t unsigned long +# endif + +# ifndef int8_t +# define int8_t char +# endif + +# ifndef int16_t +# define int16_t short +# endif + +# ifndef int32_t +# define int32_t long +# endif + +# endif /* HAVE_INTTYPES_H */ +#endif /* HAVE_STDINT_H */ + +#include "pi-macros.h" +#include "pi-palmpix.h" + +#define max(a,b) (( a > b ) ? a : b ) +#define min(a,b) (( a < b ) ? a : b ) + +int ColourCorrect (const struct PalmPixHeader *picHdr, uint8_t *r, uint8_t *gr, uint8_t *gb, + uint8_t *b); + +int Histogram(const struct PalmPixHeader *picHdr, uint8_t *r, uint8_t *gr, uint8_t *gb, + uint8_t *b); + +void DecodeRow(uint8_t *compData, uint8_t *lastRow, uint8_t *unCompData, + uint32_t *offset, int32_t *firstWord, uint16_t *PPLutsW, + uint8_t *PPLuts, uint16_t halfWidth); + +uint8_t huffWidth[] = { + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, + 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, + 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, + 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, + 0x0c,0x0c,0x0b,0x0b,0x0a,0x0a,0x0a,0x0a, + 0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, + 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, + 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, + 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, + 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09, + 0x0a,0x0a,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c +}; + +uint16_t huffTable[] = +{ + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd,0xfffd, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7,0xfff7, + 0xffe8,0xffe8,0xffe8,0xffe8,0xffe8,0xffe8,0xffe8,0xffe8, + 0xffe8,0xffe8,0xffe8,0xffe8,0xffe8,0xffe8,0xffe8,0xffe8, + 0xffe8,0xffe8,0xffe8,0xffe8,0xffe8,0xffe8,0xffe8,0xffe8, + 0xffe8,0xffe8,0xffe8,0xffe8,0xffe8,0xffe8,0xffe8,0xffe8, + 0xff60,0xff7b,0xffa5,0xffa5,0xffbd,0xffbd,0xffbd,0xffbd, + 0xffd0,0xffd0,0xffd0,0xffd0,0xffd0,0xffd0,0xffd0,0xffd0, + 0xffdc,0xffdc,0xffdc,0xffdc,0xffdc,0xffdc,0xffdc,0xffdc, + 0xffdc,0xffdc,0xffdc,0xffdc,0xffdc,0xffdc,0xffdc,0xffdc, + 0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef, + 0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef, + 0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef, + 0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef, + 0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef, + 0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef, + 0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef, + 0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef,0xffef, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3,0xfff3, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa,0xfffa, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d,0x000d, + 0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011, + 0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011, + 0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011, + 0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011, + 0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011, + 0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011, + 0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011, + 0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011,0x0011, + 0x0018,0x0018,0x0018,0x0018,0x0018,0x0018,0x0018,0x0018, + 0x0018,0x0018,0x0018,0x0018,0x0018,0x0018,0x0018,0x0018, + 0x0018,0x0018,0x0018,0x0018,0x0018,0x0018,0x0018,0x0018, + 0x0018,0x0018,0x0018,0x0018,0x0018,0x0018,0x0018,0x0018, + 0x0024,0x0024,0x0024,0x0024,0x0024,0x0024,0x0024,0x0024, + 0x0024,0x0024,0x0024,0x0024,0x0024,0x0024,0x0024,0x0024, + 0x0030,0x0030,0x0030,0x0030,0x0030,0x0030,0x0030,0x0030, + 0x0043,0x0043,0x0043,0x0043,0x005b,0x005b,0x0085,0x00a0 +}; + +/**************************************************************** + * Bias + * + * Bias is based on the Fast Alternative to Perlin's Bias algorithm + * in Graphics Gems IV by + * Christophe Schlick schlick@labri.u-bordeuax.fr + *****************************************************************/ + +static void Bias( double bias, int width, int height, uint8_t *data ) +{ + int i; + double num, denom, t; + + fprintf( stderr, "Bias factor : %lf\n", bias ); + + for( i=0; i<width*height; i++ ) + { + t = (double)data[i]/256.0; + num = t; + denom = (1.0/bias - 2) * (1.0 - t) + 1; + data[i] = num/denom * 256.0; + } +} + +/*********************************************************************** + * Odd green rows and even green rows have a different histogram + ***********************************************************************/ +int ColourCorrect (const struct PalmPixHeader *picHdr, uint8_t *r, uint8_t *gr, uint8_t *gb, uint8_t *b) +{ + /* uint8_t *tmpRow; */ + uint8_t gbMin, gbMax, grMin, grMax, rMin, rMax, bMin, bMax; + float grInc, gbInc, rInc, bInc, grCur, gbCur, rCur, bCur; + float rMean = 0, grMean = 0, gbMean = 0, bMean = 0, maxMean; + uint16_t width = picHdr->w/2; + uint16_t height = picHdr->h/2; + int i; + uint8_t red[256], greenB[256], greenR[256], blue[256]; + + memset( red, 0, 256 * sizeof( uint8_t )); + memset( greenR, 0, 256 * sizeof( uint8_t )); + memset( greenB, 0, 256 * sizeof( uint8_t )); + memset( blue, 0, 256 * sizeof( uint8_t )); + + gbMin = grMin = rMin = bMin = 255; + gbMax = grMax = rMax = bMax = 0; + + for( i=0; i<width*height; i ++ ) + { + gbMin = min( gbMin, gb[i] ); + grMin = min( grMin, gr[i] ); + rMin = min( rMin, r[i] ); + bMin = min( bMin, b[i] ); + + gbMax = max( gbMax, gb[i] ); + grMax = max( grMax, gr[i] ); + rMax = max( rMax, r[i] ); + bMax = max( bMax, b[i] ); + + rMean += r[i]; + gbMean += gb[i]; + grMean += gr[i]; + bMean += b[i]; + } + + rMean = rMean / ( width * height ); + gbMean = gbMean / ( width * height ); + grMean = grMean / ( width * height ); + bMean = bMean / ( width * height ); + + maxMean = max( max( gbMean-gbMin, grMean-grMin ), max( bMean-bMin, rMean-rMin )); + + rInc = maxMean / (rMean-rMin); + grInc = maxMean / (grMean-grMin); + gbInc = maxMean / (gbMean-gbMin); + bInc = maxMean / (bMean-bMin); + + rCur = 0; + grCur = 0; + gbCur = 0; + bCur = 0; + + for (i = 0; i<256; i++) + { + if( i < rMin ) + red[i] = 0; + else + { + if( rCur < 255 ) + red[i] = rCur; + else + red[i] = 255; + + rCur += rInc; + } + + if( i < grMin ) + greenR[i] = 0; + else + { + if( grCur < 255 ) + greenR[i] = grCur; + else + greenR[i] = 255; + + grCur += grInc; + } + + if( i < gbMin ) + greenB[i] = 0; + else + { + if( gbCur < 255 ) + greenB[i] = gbCur; + else + greenB[i] = 255; + + gbCur += gbInc; + } + + if( i < bMin ) + blue[i] = 0; + else + { + if( bCur < 255 ) + blue[i] = bCur; + else + blue[i] = 255; + + bCur += bInc; + } + } + + for( i=0; i<width*height; i ++ ) + { + gb[i] = greenB[gb[i]]; + gr[i] = greenR[gr[i]]; + b[i] = blue[b[i]]; + r[i] = red[r[i]]; + } + + return( 1 ); +} + +int Histogram( const struct PalmPixHeader *picHdr, uint8_t *r, uint8_t *gr, uint8_t *gb, uint8_t *b ) +{ + /* uint8_t *tmpRow; */ + uint8_t gbMin, gbMax, grMin, grMax, rMin, rMax, bMin, bMax; + uint32_t rCum, grCum, gbCum, bCum; + uint32_t grC[256], gbC[256], rC[256], bC[256]; + float grInc, gbInc, rInc, bInc, grCur, gbCur, rCur, bCur; + uint16_t width = picHdr->w/2; + uint16_t height = picHdr->h/2; + int i; + float clip; + uint8_t red[256], greenB[256], greenR[256], blue[256]; + float redCeiling = 254; + float greenCeiling = 252; + float blueCeiling = 255; + + memset( red, 0, 256 * sizeof( uint8_t )); + memset( greenR, 0, 256 * sizeof( uint8_t )); + memset( greenB, 0, 256 * sizeof( uint8_t )); + memset( blue, 0, 256 * sizeof( uint8_t )); + + memset( rC, 0, 256 * sizeof( uint32_t )); + memset( grC, 0, 256 * sizeof( uint32_t )); + memset( gbC, 0, 256 * sizeof( uint32_t )); + memset( bC, 0, 256 * sizeof( uint32_t )); + + gbMin = grMin = rMin = bMin = 255; + gbMax = grMax = rMax = bMax = 0; + + for( i=0; i<width*height; i ++ ) + { + rC[r[i]]++; + grC[gr[i]]++; + gbC[gb[i]]++; + bC[b[i]]++; + } + + rCum = grCum = gbCum = bCum = 0; + + clip = 0.05 * width * height; + + for( i=0; i<256; i++ ) + { + rCum += rC[i]; + + if( rMin == 255 && rCum > clip ) + rMin = i; + + grCum += grC[i]; + + if( grMin == 255 && grCum > clip ) + grMin = i; + + gbCum += gbC[i]; + + if( gbMin == 255 && gbCum > clip ) + gbMin = i; + + bCum += bC[i]; + + if( bMin == 255 && bCum > clip ) + bMin = i; + + if( rMin != 255 && grMin != 255 && gbMin != 255 && bMin != 255 ) + break; + } + + rCum = grCum = gbCum = bCum = 0; + + for( i=255; i > 0; i-- ) + { + rCum += rC[i]; + + if( rMax == 0 && rCum > clip ) + rMax = i; + + grCum += grC[i]; + + if( grMax == 0 && grCum > clip ) + grMax = i; + + gbCum += gbC[i]; + + if( gbMax == 0 && gbCum > clip ) + gbMax = i; + + bCum += bC[i]; + + if( bMax == 0 && bCum > clip ) + bMax = i; + + if( rMax != 0 && grMax != 0 && gbMax != 0 && bMax != 0 ) + break; + } + + rInc = redCeiling / (rMax-rMin); + grInc = greenCeiling / (grMax-grMin); + gbInc = greenCeiling / (gbMax-gbMin); + bInc = blueCeiling / (bMax-bMin); + + rCur = 0; + grCur = 0; + gbCur = 0; + bCur = 0; + + for (i = 0; i<256; i++) + { + if( i < rMin ) + red[i] = 0; + else + { + if( rCur < redCeiling ) + red[i] = rCur; + else + red[i] = greenCeiling; + + rCur += rInc; + } + + if( i < grMin ) + greenR[i] = 0; + else + { + if( grCur < greenCeiling ) + greenR[i] = grCur; + else + greenR[i] = greenCeiling; + + grCur += grInc; + } + + if( i < gbMin ) + greenB[i] = 0; + else + { + if( gbCur < greenCeiling ) + greenB[i] = gbCur; + else + greenB[i] = blueCeiling; + + gbCur += gbInc; + } + + if( i < bMin ) + blue[i] = 0; + else + { + if( bCur < blueCeiling ) + blue[i] = bCur; + else + blue[i] = blueCeiling; + + bCur += bInc; + } + } + + for( i=0; i<width*height; i ++ ) + { + gb[i] = greenB[gb[i]]; + gr[i] = greenR[gr[i]]; + b[i] = blue[b[i]]; + r[i] = red[r[i]]; + } + + return( 1 ); +} + +/***************************************************************************** + * The interpolation function looks a litte strange in that it uses 4 * the + * green component when the green component is centered. This is to compensate + * for a different intensity on odd and even green rows. All green + * interpolations have an equal number of pixels from a red row and blue row. + *****************************************************************************/ +static void Interpolate( const struct PalmPixHeader *pixHdr, uint8_t *red, uint8_t *greenR, uint8_t *greenB, uint8_t *blue, uint8_t *pp, int offset_r, int offset_g, int offset_b ) +{ + int idx, offset, ppOff; + int x, y, rowOff; + uint8_t r, g, b; + int rawWidth = pixHdr->w/2; + + for( y=1; y<pixHdr->h-1; y++ ) + { + + idx = y/2; + offset = idx * rawWidth; + ppOff = y * pixHdr->w; + + if( y%2 == 1 ) + { + for( x=1; x<rawWidth-1; x++ ) + { + + rowOff = x*2; + + r = (red[offset+x-1] + red[offset + x] + red[offset + rawWidth + x -1] + red[offset + rawWidth + x])>>2; + g = (greenR[offset+x] + greenR[offset+x+rawWidth] + greenB[offset + x - 1] + greenB[offset + x])>>2; + b = blue[offset + x]; + pp[3 * (ppOff + rowOff) + offset_r] = r; + pp[3 * (ppOff + rowOff) + offset_g] = g; + pp[3 * (ppOff + rowOff) + offset_b] = b; + + r = (red[offset + x] + red[offset + rawWidth + x])>>1; + g = (( greenB[offset + x] << 2 ) + greenR[offset+x] + greenR[offset+x+1] + greenR[offset+x+rawWidth] + greenR[offset+x+rawWidth+1] )>>3; + b = (blue[offset + x] + blue[offset + x + 1])>>1; + pp[3 * (ppOff + rowOff + 1) + offset_r] = r; + pp[3 * (ppOff + rowOff + 1) + offset_g] = g; + pp[3 * (ppOff + rowOff + 1) + offset_b] = b; + + } + } + else + { + for( x=1; x<rawWidth-1; x++ ) + { + rowOff = x*2; + + r = (red[offset + x - 1] + red[offset + x])>>1; + g = (( greenR[offset + x] << 2 ) + greenB[offset-rawWidth+x-1] + greenB[offset-rawWidth+x] + greenB[offset+x-1] + greenB[offset+x] )>>3; + b = (blue[offset-rawWidth+x] + blue[offset+x])>>1; + pp[3 * (ppOff + rowOff) + offset_r] = r; + pp[3 * (ppOff + rowOff) + offset_g] = g; + pp[3 * (ppOff + rowOff) + offset_b] = b; + + r = red[offset+x]; + g = (greenR[offset+x] + greenR[offset+x+1] + greenB[offset-rawWidth+x] + greenB[offset + x])>>2; + b = (blue[offset+x-rawWidth] + blue[offset+x-rawWidth-1] + blue[offset+x] + blue[offset+x+1])>>2; + pp[3 * (ppOff + rowOff + 1) + offset_r] = r; + pp[3 * (ppOff + rowOff + 1) + offset_g] = g; + pp[3 * (ppOff + rowOff + 1) + offset_b] = b; + + } + } + } + +} + +void DecodeRow( uint8_t *compData, uint8_t *lastRow, uint8_t *unCompData, uint32_t *offset, int32_t *firstWord, uint16_t *PPLutsW, uint8_t *PPLuts, uint16_t halfWidth ) +{ + uint8_t *saveStartP, shiftOut; + int16_t tmpW3, tmpResult, tmpW0, idx, resultW; + uint32_t lutIdx, tmpL0, tmpL2, tmpL5; + + saveStartP = compData; + + tmpW3 = 32 - *firstWord; + + tmpResult = 32 - tmpW3; + + tmpL5 = compData[0]<<24 | compData[1]<<16 | compData[2]<<8 | compData[3] ; + tmpL5 = tmpL5<<tmpResult; + tmpL0 = tmpL5; + + compData += 4; + + tmpL0 = tmpL0 >> 24; + + unCompData[0] = (uint8_t)tmpL0; + + tmpL5 = tmpL5 << 8; + tmpW3 = tmpW3 - 8; + idx = 1; + + while( idx < halfWidth ) + { + if( tmpW3 < 12 ) + { + tmpW0 = 16 - tmpW3; + tmpL2 = ( compData[0]<<8 | compData[1] ) << tmpW0; + tmpL5 = tmpL5 | tmpL2; + tmpW3 += 16; + compData += 2; + } + + lutIdx = tmpL5 >> 20; + + shiftOut = PPLuts[lutIdx]; + + tmpL5 = tmpL5 << shiftOut; + + tmpW3 = tmpW3 - shiftOut; + + resultW = ( unCompData[idx-1] + lastRow[idx] ) >> 1; + + resultW = resultW + PPLutsW[lutIdx]; + + if( resultW > 255 ) + resultW = 255; + + if( resultW < 0 ) + resultW = 0; + + unCompData[idx++] = (uint8_t)resultW; + + } + + while( tmpW3 > 0 ) + { + compData--; + tmpW3 -= 8; + } + + *offset = compData - saveStartP; + *firstWord = -tmpW3; + +} + +/* A binary PalmPixHeader is a record of length 196 in the following format. + Note that multibyte integers are in little endian byte order -- they are + NOT in m68k byte order. + + 0UInt8 numRec; + 1UInt8 s0; // Always zero + 2UInt8 month; + 3UInt8 day; + 4UInt8 cent; + 5UInt8 year; + 6UInt8 hour; + 7UInt8 min; + 8UInt8 sec; + 9UInt8 resolution; // 640x480 = 1, 320x240 = 2, 400x300 = 3, 800x600 = 4 + 10UInt16 w; + 12UInt16 h; + 14UInt16 thumbLen; // Size of the thumbnail following the name + 16UInt16 GRsize; + 18UInt8 sep0; + 19UInt16 Rsize; + 21UInt8 sep1; + 22UInt16 Bsize; + 24UInt8 sep2; + 25UInt16 GBsize; + 27UInt16 pad1; + 29UInt16 num; // hires 1200, lowres 300 + 31UInt8 resA[14]; + 45UInt8 zoom; + 46UInt8 softMajor; // Always 0x0102 [see below] + 47UInt8 softMinor; // Always 0x0102 [see below] + 48UInt8 resB[34]; + 82UInt16 dir[57]; + + */ + + + /* The remainder is due to John Marshall. It is pretty trivial compared to + the analysis above. */ + +static int + get_le_short (const unsigned char *p) +{ + + return p[0] | (p[1] << 8); + +} + +int + unpack_PalmPixHeader (struct PalmPixHeader *h, const unsigned char *p, int len) +{ + int magic1, magic2; + + if (len != 196) + return 0; + + magic1 = p[1]; + magic2 = get_le_short (&p[46]); + + /* FIXME For now, don't check the magic. I've seen 0x0002 and 0x0201. + I'm not sure that the endianness is right on this one. Possibly it + should be interpreted as two bytes instead (major and minor?). */ + #if 0 + if (magic1 != 0 || (magic2 != 0x0102 && magic2 != 0x0002)) + return 0; + #endif + + h->numRec= p[0]; + h->month= p[2]; + h->day= p[3]; + h->year= p[4] * 100 + p[5]; + h->hour= p[6]; + h->min= p[7]; + h->sec= p[8]; + h->resolution= p[9]; + h->w= get_le_short (&p[10]); + h->h= get_le_short (&p[12]); + h->thumbLen= get_le_short (&p[14]); + h->chansize[pixChannelGR] = get_le_short (&p[16]); + h->chansize[pixChannelR] = get_le_short (&p[19]); + h->chansize[pixChannelB] = get_le_short (&p[22]); + h->chansize[pixChannelGB] = get_le_short (&p[25]); + h->num= get_le_short (&p[29]); + h->zoom= p[45]; + + return 196; + +} + +int unpack_PalmPix (struct PalmPixState *s, + const struct PalmPixHeader *h, int header_recno, int wanted) +{ + int retcode = 1; + + if (wanted & pixName) + { + + void *buffer; + size_t bufsize; + if (s->getrecord (s, header_recno + 1, &buffer, &bufsize) == 0 + && bufsize == 32) + { + + memcpy (s->pixname, buffer, 32); + s->pixname[32] = '\0'; + + } + else + retcode = 0; + + } + + if (wanted & pixThumbnail) + { + + /* FIXME */ + retcode = 0; + fprintf (stderr, + "palmpix.c: thumbnail reader not implemented\n"); + + } + + if (wanted & pixPixmap) + { + + int rawWidth = h->w / 2; + int rawHeight = h->h / 2; + unsigned char *raw; + unsigned char *chan[4]; /* red/greenR/greenB/blue channels */ + int chansize_max = 0; + int recno = header_recno; + int failed = 1; + int k; + + for (k = 0; k < 4; k++) + chan[k] = NULL; + raw = NULL; + s->pixmap = NULL; + + for (k = 0; k < 4; k++) + { + + chan[k] = malloc ((size_t)(rawWidth * rawHeight)); + if (chan[k] == NULL) + goto failed; + memset (chan[k], 0, (size_t)(rawWidth * rawHeight)); + if (chansize_max < h->chansize[k]) + chansize_max = h->chansize[k]; + + } + + + raw = malloc ((size_t)chansize_max); + if (raw == NULL) + goto failed; + + s->pixmap = malloc ((size_t)(h->w * h->h * 3)); + if (s->pixmap == NULL) + goto failed; + + recno += 4; /* Skip to the first channel record. */ + + for (k = 0; k < 4; k++) + { + long num_bytes, offset; + int32_t lastWord = 0; + int j; + + for (num_bytes = 0; num_bytes < h->chansize[k]; recno++) + { + void *buffer; + size_t bufsize; + if (s->getrecord (s, recno, &buffer, &bufsize) == 0) { + if (bufsize > h->chansize[k] - num_bytes) + bufsize = h->chansize[k] - num_bytes; + memcpy (&raw[num_bytes], buffer, (size_t)bufsize); + num_bytes += bufsize; + + } + else + goto failed; + + } + + offset = 0; + memcpy (chan[k], &raw[offset], (size_t)rawWidth); + offset += rawWidth; + + for (j = 1; j < rawHeight; j++) + { + uint32_t eaten; + DecodeRow (&raw[offset], + &chan[k][rawWidth * (j - 1)], + &chan[k][rawWidth * j], + &eaten, &lastWord, + huffTable, huffWidth, rawWidth); + offset += eaten; + + } + + } + + if( s->flags & PALMPIX_COLOUR_CORRECTION ) + ColourCorrect ( h, chan[pixChannelR], chan[pixChannelGR], + chan[pixChannelGB], chan[pixChannelB] ); + + if( s->bias != 50 ) + { + Bias ( (double)s->bias / 100.0, rawWidth, rawHeight, chan[pixChannelR]); + Bias ( (double)s->bias / 100.0, rawWidth, rawHeight, chan[pixChannelGR]); + Bias ( (double)s->bias / 100.0, rawWidth, rawHeight, chan[pixChannelGB]); + Bias ( (double)s->bias / 100.0, rawWidth, rawHeight, chan[pixChannelB]); + } + + if( s->flags & PALMPIX_HISTOGRAM_STRETCH ) + Histogram ( h, chan[pixChannelR], chan[pixChannelGR], + chan[pixChannelGB], chan[pixChannelB] ); + + Interpolate (h, + chan[pixChannelR], chan[pixChannelGR], + chan[pixChannelGB], chan[pixChannelB], + s->pixmap, s->offset_r, s->offset_g, s->offset_b); + + failed = 0; + +failed: + for (k = 0; k < 4; k++) + free (chan[k]); + free (raw); + if (failed) + { + free (s->pixmap); + retcode = 0; + } + } + + s->highest_recno = header_recno + 3 + h->numRec; + + return retcode; +} + +int + free_PalmPix_data (struct PalmPixState *s) +{ + free (s->pixmap); + + return 1; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/pi-buffer.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/pi-buffer.c new file mode 100644 index 00000000..8064f316 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/pi-buffer.c @@ -0,0 +1,117 @@ +/* + * $Id: pi-buffer.c,v 1.10 2006/10/12 14:21:22 desrod Exp $ + * + * pi-buffer.c: simple data block management for variable data storage + * + * Copyright (c) 2004-2005, Florent Pillet. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + * + * -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pi-buffer.h" + +pi_buffer_t* +pi_buffer_new (size_t capacity) +{ + pi_buffer_t* buf; + buf = (struct pi_buffer_t *) malloc (sizeof (struct pi_buffer_t)); + if (buf == NULL) + return NULL; + + if (capacity <= 0) + capacity = 16; /* allocating 0 byte is illegal - use a small value instead */ + + buf->data = (unsigned char *) malloc (capacity); + if (buf->data == NULL) { + free (buf); + return NULL; + } + + buf->allocated = capacity; + buf->used = 0; + return buf; +} + +pi_buffer_t* +pi_buffer_expect (pi_buffer_t *buf, size_t expect) +{ + if ((buf->allocated - buf->used) >= expect) + return buf; + + if (buf->data) + buf->data = (unsigned char *) realloc (buf->data, buf->used + expect); + else + buf->data = (unsigned char *) malloc (expect); + + if (buf->data == NULL) { + buf->allocated = 0; + buf->used = 0; + return NULL; + } + + buf->allocated = buf->used + expect; + return buf; +} + +pi_buffer_t* +pi_buffer_append (pi_buffer_t *buf, const void *data, size_t len) +{ + if (pi_buffer_expect (buf, len) == NULL) + return NULL; + + memcpy (buf->data + buf->used, data, len); + buf->used += len; + + return buf; +} + +pi_buffer_t * +pi_buffer_append_buffer (pi_buffer_t *dest, const pi_buffer_t *src) +{ + return pi_buffer_append (dest, src->data, src->used); +} + +void +pi_buffer_clear (pi_buffer_t *buf) +{ + buf->used = 0; + if (buf->allocated > (size_t)65535) + { + buf->data = (unsigned char *) realloc (buf->data, 65535); + buf->allocated = (buf->data == NULL) ? 0 : 65535; + } +} + +void +pi_buffer_free (pi_buffer_t* buf) +{ + if (buf) { + if (buf->data) + free (buf->data); + free (buf); + } +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/pi-file.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/pi-file.c new file mode 100644 index 00000000..e507bb32 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/pi-file.c @@ -0,0 +1,1531 @@ +/* + * $Id: pi-file.c,v 1.72 2006/10/12 14:21:22 desrod Exp $ + * + * Pilot File Interface Library + * Pace Willisson <pace@blitz.com> December 1996 + * Additions by Kenneth Albanowski + * Additions by Florent Pillet + * + * This is free software, licensed under the GNU Library Public License V2. + * See the file COPYING.LIB for details. + * + * the following is extracted from the combined wisdom of + * PDB by Kevin L. Flynn + * install-prc by Brian J. Swetland, D. Jeff Dionne and Kenneth Albanowski + * makedoc7 by Pat Beirne, <patb@corel.com> + * and the include files from the pilot SDK + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-file.h" +#include "pi-error.h" + +#undef FILEDEBUG +#define pi_mktag(c1,c2,c3,c4) (((c1)<<24)|((c2)<<16)|((c3)<<8)|(c4)) + +/* + header: + 32 name + 2 flags + 2 version + 4 creation time + 4 modification time + 4 backup time + 4 modification number + 4 app info offset + 4 sort info offset + 4 type + 4 creator + 4 uniq id seed (I think it is just garbage) + 4 next record list id (normally 0, or ptr to extended hdr) + 2 num records for this header + + Hypothetically plus 2 more bytes if an extended or perhaps secondary + header (not supported) (In practice, this value is never set, instead it + usually indicates a damaged file.) + + if the low bit of attr is on, then next thing is a list of resource entry + descriptors: + + resource entry header + 4 type + 2 id + 4 offset + + otherwise, if the low bit of attr is off, the next thing is a list of + record entry decriptors: + + record entry header + 4 offset + 1 record attributes + 3 unique id + + then two bytes of unknown purpose, \0\0 seems safe + + next, the app_info, if any, then the sort_info, if any + + then the space used the data. Every offset is an offset from the + beginning of the file, and will point until this area. Each block starts + at the given offset and ends at the beginning of the next block. The last + block ends at the end of the file. + */ + +#define PI_HDR_SIZE 78 +#define PI_RESOURCE_ENT_SIZE 10 +#define PI_RECORD_ENT_SIZE 8 + +/* Local prototypes */ +static int pi_file_close_for_write(pi_file_t *pf); +static void pi_file_free(pi_file_t *pf); +static int pi_file_find_resource_by_type_id(const pi_file_t *pf, unsigned long restype, int resid, int *resindex); +static pi_file_entry_t *pi_file_append_entry(pi_file_t *pf); +static int pi_file_set_rbuf_size(pi_file_t *pf, size_t size); + +/* this seems to work, but what about leap years? */ +/*#define PILOT_TIME_DELTA (((unsigned)(1970 - 1904) * 365 * 24 * 60 * 60) + 1450800)*/ + +/* Exact value of "Jan 1, 1970 0:00:00 GMT" - "Jan 1, 1904 0:00:00 GMT" */ +#define PILOT_TIME_DELTA (unsigned)(2082844800) + + +/* FIXME: These conversion functions apply no timezone correction. UNIX uses + UTC for time_t's, while the Pilot uses local time for database backup + time and appointments, etc. It is not particularly simple to convert + between these in UNIX, especially since the Pilot's local time is + unknown, and if syncing over political boundries, could easily be + different then the local time on the UNIX box. Since the Pilot does not + know what timezone it is in, there is no unambiguous way to correct for + this. + + Worse, the creation date for a program is stored in the local time _of + the computer which did the final linking of that program_. Again, the + Pilot does not store the timezone information needed to reconstruct + where/when this was. + + A better immediate tack would be to dissect these into struct tm's, and + return those. + --KJA + */ +time_t +pilot_time_to_unix_time(unsigned long raw_time) +{ + return (time_t) (raw_time - PILOT_TIME_DELTA); +} + +unsigned long +unix_time_to_pilot_time(time_t t) +{ + return (unsigned long) ((unsigned long) t + PILOT_TIME_DELTA); +} + +pi_file_t +*pi_file_open(const char *name) +{ + int i, + file_size; + + pi_file_t *pf; + struct DBInfo *ip; + pi_file_entry_t *entp; + + unsigned char buf[PI_HDR_SIZE]; + unsigned char *p; + off_t offset, app_info_offset = 0, sort_info_offset = 0; + + if ((pf = calloc(1, sizeof (pi_file_t))) == NULL) + return NULL; + + if ((pf->f = fopen(name, "rb")) == NULL) + goto bad; + + fseek(pf->f, 0, SEEK_END); + file_size = ftell(pf->f); + fseek(pf->f, 0, SEEK_SET); + + if (fread(buf, PI_HDR_SIZE, 1, pf->f) != (size_t) 1) { + LOG ((PI_DBG_API, PI_DBG_LVL_ERR, + "FILE OPEN %s: can't read header\n", name)); + goto bad; + } + + p = buf; + ip = &pf->info; + + memcpy(ip->name, p, 32); + ip->flags = get_short(p + 32); + ip->miscFlags = dlpDBMiscFlagRamBased; + ip->version = get_short(p + 34); + ip->createDate = pilot_time_to_unix_time(get_long(p + 36)); + ip->modifyDate = pilot_time_to_unix_time(get_long(p + 40)); + ip->backupDate = pilot_time_to_unix_time(get_long(p + 44)); + ip->modnum = get_long(p + 48); + app_info_offset = get_long(p + 52); + sort_info_offset = get_long(p + 56); + ip->type = get_long(p + 60); + ip->creator = get_long(p + 64); + pf->unique_id_seed = get_long(p + 68); + + /* record list header */ + pf->next_record_list_id = get_long(p + 72); + pf->num_entries = get_short(p + 76); + + LOG ((PI_DBG_API, PI_DBG_LVL_INFO, + "FILE OPEN Name: '%s' Flags: 0x%4.4X Version: %d\n", + ip->name, ip->flags, ip->version)); + LOG ((PI_DBG_API, PI_DBG_LVL_DEBUG, + " Creation date: %s", ctime(&ip->createDate))); + LOG ((PI_DBG_API, PI_DBG_LVL_DEBUG, + " Modification date: %s", ctime(&ip->modifyDate))); + LOG ((PI_DBG_API, PI_DBG_LVL_DEBUG, + " Backup date: %s", ctime(&ip->backupDate))); + LOG ((PI_DBG_API, PI_DBG_LVL_DEBUG, + " Appinfo Size: %d Sortinfo Size: %d\n", + pf->app_info_size, pf->sort_info_size)); + LOG ((PI_DBG_API, PI_DBG_LVL_DEBUG, + " Type: '%s'", printlong(ip->type))); + LOG ((PI_DBG_API, PI_DBG_LVL_DEBUG, + " Creator: '%s' Seed: 0x%8.8lX\n", printlong(ip->creator), + pf->unique_id_seed)); + + if (pf->next_record_list_id != 0) { + LOG ((PI_DBG_API, PI_DBG_LVL_ERR, + "FILE OPEN %s: this file is probably damaged\n", name)); + goto bad; + } + + if (ip->flags & dlpDBFlagResource) { + pf->resource_flag = 1; + pf->ent_hdr_size = PI_RESOURCE_ENT_SIZE; + } else { + pf->resource_flag = 0; + pf->ent_hdr_size = PI_RECORD_ENT_SIZE; + } + + if (pf->num_entries < 0) { + LOG ((PI_DBG_API, PI_DBG_LVL_ERR, + "FILE OPEN %s: bad header\n", name)); + goto bad; + } + + offset = file_size; + + if (pf->num_entries) { + if ((pf->entries = + calloc((size_t)pf->num_entries, + sizeof *pf->entries)) == NULL) + goto bad; + + for (i = 0, entp = pf->entries; i < pf->num_entries; + i++, entp++) { + if (fread(buf, (size_t) pf->ent_hdr_size, 1, pf->f) + != (size_t) 1) + goto bad; + + p = buf; + if (pf->resource_flag) { + entp->type = get_long(p); + entp->resource_id = get_short(p + 4); + entp->offset = get_long(p + 6); + + LOG ((PI_DBG_API, PI_DBG_LVL_DEBUG, + "FILE OPEN Entry %d '%s' #%d @%X\n", i, + printlong(entp->type), entp->resource_id, + entp->offset)); + } else { + entp->offset = get_long(p); + entp->attrs = get_byte(p + 4); + entp->uid = get_treble(p + 5); + + LOG ((PI_DBG_API, PI_DBG_LVL_DEBUG, + "FILE OPEN Entry %d UID: " + "0x%8.8X Attrs: %2.2X Offset: @%X\n", i, + (int) entp->uid, entp->attrs, + entp->offset)); + } + } + + for (i = 0, entp = pf->entries + pf->num_entries - 1; + i < pf->num_entries; i++, entp--) { + entp->size = offset - entp->offset; + offset = entp->offset; + + LOG ((PI_DBG_API, PI_DBG_LVL_DEBUG, + "FILE OPEN Entry: %d Size: %d\n", + pf->num_entries - i - 1, entp->size)); + + if (entp->size < 0 || + (entp->offset + entp->size) > file_size) { + LOG ((PI_DBG_API, PI_DBG_LVL_DEBUG, + "FILE OPEN %s: Entry %d corrupt," + " giving up\n", + name, pf->num_entries - i - 1)); + goto bad; + } + } + } + + if (sort_info_offset) { + pf->sort_info_size = offset - sort_info_offset; + offset = sort_info_offset; + } + + if (app_info_offset) { + pf->app_info_size = offset - app_info_offset; + offset = app_info_offset; + } + + if (pf->app_info_size < 0 || + (sort_info_offset + pf->sort_info_size) > file_size || + pf->sort_info_size < 0 || + (app_info_offset + pf->app_info_size) > file_size) { + LOG ((PI_DBG_API, PI_DBG_LVL_ERR, + "FILE OPEN %s: bad header " + "(app_info @ %d size %d, " + "sort_info @ %d size %d)\n", name, + app_info_offset, pf->app_info_size, + sort_info_offset, pf->sort_info_size)); + goto bad; + } + + if (pf->app_info_size == 0) + pf->app_info = NULL; + else { + if ((pf->app_info = + malloc((size_t) pf->app_info_size)) == NULL) + goto bad; + fseek(pf->f, (long)app_info_offset, SEEK_SET); + if (fread(pf->app_info, 1, (size_t) pf->app_info_size, pf->f) + != (size_t) pf->app_info_size) + goto bad; + } + + if (pf->sort_info_size == 0) + pf->sort_info = NULL; + else { + if ((pf->sort_info = malloc((size_t)pf->sort_info_size)) + == NULL) + goto bad; + fseek(pf->f, (long)sort_info_offset, SEEK_SET); + if (fread(pf->sort_info, 1, (size_t) pf->sort_info_size, + pf->f) != (size_t) pf->sort_info_size) + goto bad; + } + + return pf; + +bad: + pi_file_close(pf); + return NULL; +} + +int +pi_file_close(pi_file_t *pf) +{ + int err; + + if (!pf) + return PI_ERR_FILE_INVALID; + + if (pf->for_writing) + pf->err = pi_file_close_for_write(pf); + + err = pf->err; + + pi_file_free(pf); + + return err; +} + +void +pi_file_get_info(const pi_file_t *pf, struct DBInfo *infop) +{ + *infop = pf->info; +} + +void +pi_file_get_app_info(pi_file_t *pf, void **datap, size_t *sizep) +{ + *datap = pf->app_info; + *sizep = pf->app_info_size; +} + +void +pi_file_get_sort_info(pi_file_t *pf, void **datap, size_t *sizep) +{ + *datap = pf->sort_info; + *sizep = pf->sort_info_size; +} + +int +pi_file_read_resource_by_type_id(pi_file_t *pf, unsigned long restype, + int resid, void **bufp, size_t *sizep, + int *resindex) +{ + int i, + result; + + result = pi_file_find_resource_by_type_id(pf, restype, resid, &i); + if (!result) + return PI_ERR_FILE_NOT_FOUND; + if (resindex) + *resindex = i; + return pi_file_read_resource(pf, i, bufp, sizep, NULL, NULL); +} + +int +pi_file_type_id_used(const pi_file_t *pf, unsigned long restype, int resid) +{ + return pi_file_find_resource_by_type_id(pf, restype, resid, NULL); +} + +int +pi_file_read_resource(pi_file_t *pf, int i, + void **bufp, size_t *sizep, unsigned long *type, + int *idp) +{ + pi_file_entry_t *entp; + int result; + + if (pf->for_writing || !pf->resource_flag) + return PI_ERR_FILE_INVALID; + + if (i < 0 || i >= pf->num_entries) + return PI_ERR_GENERIC_ARGUMENT; + + entp = &pf->entries[i]; + + if (bufp) { + if ((result = pi_file_set_rbuf_size(pf, (size_t) entp->size)) < 0) + return result; + fseek(pf->f, pf->entries[i].offset, SEEK_SET); + if (fread(pf->rbuf, 1, (size_t) entp->size, pf->f) != + (size_t) entp->size) + return PI_ERR_FILE_ERROR; + *bufp = pf->rbuf; + } + + if (sizep) + *sizep = entp->size; + if (type) + *type = entp->type; + if (idp) + *idp = entp->resource_id; + + return 0; +} + +int +pi_file_read_record(pi_file_t *pf, int recindex, + void **bufp, size_t *sizep, int *recattrs, int *category, + recordid_t * recuid) +{ + int result; + pi_file_entry_t *entp; + + if (pf->for_writing || pf->resource_flag) + return PI_ERR_FILE_INVALID; + + if (recindex < 0 || recindex >= pf->num_entries) + return PI_ERR_GENERIC_ARGUMENT; + + entp = &pf->entries[recindex]; + + if (bufp) { + if ((result = pi_file_set_rbuf_size(pf, (size_t) entp->size)) < 0) { + LOG((PI_DBG_API, PI_DBG_LVL_ERR, + "FILE READ_RECORD Unable to set buffer size!\n")); + return result; + } + + fseek(pf->f, pf->entries[recindex].offset, SEEK_SET); + + if (fread(pf->rbuf, 1, (size_t) entp->size, pf->f) != + (size_t) entp->size) { + LOG((PI_DBG_API, PI_DBG_LVL_ERR, + "FILE READ_RECORD Unable to read record!\n")); + return PI_ERR_FILE_ERROR; + } + + *bufp = pf->rbuf; + } + + LOG ((PI_DBG_API, PI_DBG_LVL_INFO, + "FILE READ_RECORD Record: %d Bytes: %d\n", recindex, entp->size)); + + if (sizep) + *sizep = entp->size; + if (recattrs) + *recattrs = entp->attrs & 0xf0; + if (category) + *category = entp->attrs & 0xf; + if (recuid) + *recuid = entp->uid; + + return 0; +} + +int +pi_file_read_record_by_id(pi_file_t *pf, recordid_t uid, + void **bufp, size_t *sizep, int *idxp, int *attrp, + int *catp) +{ + int i; + struct pi_file_entry *entp; + + for (i = 0, entp = pf->entries; i < pf->num_entries; + i++, entp++) { + if (entp->uid == uid) { + if (idxp) + *idxp = i; + return (pi_file_read_record + (pf, i, bufp, sizep, attrp, catp, &uid)); + } + } + + return PI_ERR_FILE_NOT_FOUND; +} + +int +pi_file_id_used(const pi_file_t *pf, recordid_t uid) +{ + int i; + struct pi_file_entry *entp; + + for (i = 0, entp = pf->entries; i < pf->num_entries; i++, entp++) { + if (entp->uid == uid) + return 1; + } + return 0; +} + +pi_file_t * +pi_file_create(const char *name, const struct DBInfo *info) +{ + pi_file_t *pf = calloc(1, sizeof(pi_file_t)); + + if (pf == NULL) + return NULL; + + if ((pf->file_name = strdup(name)) == NULL) + goto bad; + + pf->for_writing = 1; + pf->info = *info; + + if (info->flags & dlpDBFlagResource) { + pf->resource_flag = 1; + pf->ent_hdr_size = PI_RESOURCE_ENT_SIZE; + } else { + pf->resource_flag = 0; + pf->ent_hdr_size = PI_RECORD_ENT_SIZE; + } + + pf->tmpbuf = pi_buffer_new(2048); + if (pf->tmpbuf == NULL) + goto bad; + + return (pf); + +bad: + pi_file_free(pf); + return NULL; +} + +int +pi_file_set_info(pi_file_t *pf, const struct DBInfo *ip) +{ + if (!pf->for_writing) + return PI_ERR_FILE_INVALID; + + if ((ip->flags & dlpDBFlagResource) != + (pf->info.flags & dlpDBFlagResource)) + return PI_ERR_FILE_INVALID; + + pf->info = *ip; + + return 0; +} + +int +pi_file_set_app_info(pi_file_t *pf, void *data, size_t size) +{ + void *p; + + if (!size) { + if (pf->app_info) + free(pf->app_info); + pf->app_info_size = 0; + return 0; + } + + if ((p = malloc(size)) == NULL) + return PI_ERR_GENERIC_MEMORY; + + memcpy(p, data, size); + + if (pf->app_info) + free(pf->app_info); + + pf->app_info = p; + pf->app_info_size = size; + + return 0; +} + +int +pi_file_set_sort_info(pi_file_t *pf, void *data, size_t size) +{ + void *p; + + if (!size) { + if (pf->sort_info) + free(pf->sort_info); + pf->sort_info_size = 0; + return 0; + } + + if ((p = malloc(size)) == NULL) + return PI_ERR_GENERIC_MEMORY; + + memcpy(p, data, size); + + if (pf->sort_info) + free(pf->sort_info); + + pf->sort_info = p; + pf->sort_info_size = size; + + return 0; +} + +int +pi_file_append_resource(pi_file_t *pf, void *data, size_t size, + unsigned long restype, int resid) +{ + pi_file_entry_t *entp; + + if (!pf->for_writing || !pf->resource_flag) + return PI_ERR_FILE_INVALID; + if (pi_file_type_id_used(pf, restype, resid)) + return PI_ERR_FILE_ALREADY_EXISTS; + + entp = pi_file_append_entry(pf); + if (entp == NULL) + return PI_ERR_GENERIC_MEMORY; + + if (size && pi_buffer_append(pf->tmpbuf, data, size) == NULL) { + pf->err = 1; + return PI_ERR_GENERIC_MEMORY; + } + + entp->size = size; + entp->type = restype; + entp->resource_id = resid; + + return size; +} + +int +pi_file_append_record(pi_file_t *pf, void *data, size_t size, + int recattrs, int category, recordid_t recuid) +{ + pi_file_entry_t *entp; + + if (!pf->for_writing || pf->resource_flag) + return PI_ERR_FILE_INVALID; + if (recuid && pi_file_id_used(pf, recuid)) + return PI_ERR_FILE_ALREADY_EXISTS; + + entp = pi_file_append_entry(pf); + if (entp == NULL) + return PI_ERR_GENERIC_MEMORY; + + if (size && pi_buffer_append(pf->tmpbuf, data, size) == NULL) { + pf->err = 1; + return PI_ERR_GENERIC_MEMORY; + } + + entp->size = size; + entp->attrs = (recattrs & 0xf0) | (category & 0xf); + entp->uid = recuid; + + return size; +} + +void +pi_file_get_entries(pi_file_t *pf, int *entries) +{ + *entries = pf->num_entries; +} + +int +pi_file_retrieve(pi_file_t *pf, int socket, int cardno, + progress_func report_progress) +{ + int db = -1, + result, + old_device = 0; + + unsigned int j; + + struct DBInfo dbi; + struct DBSizeInfo size_info; + + pi_buffer_t *buffer = NULL; + pi_progress_t progress; + + pi_reset_errors(socket); + memset(&size_info, 0, sizeof(size_info)); + memset(&dbi, 0, sizeof(dbi)); + + /* Try to get more info on the database to retrieve. Note that + * with some devices like the Tungsten T3 and shadowed databases + * like AddressDB, the size_info is -wrong-. It doesn't reflect + * the actual contents of the database except for the number of + * records. Also, this call doesn't work pre-OS 3. + */ + if ((result = dlp_FindDBByName(socket, cardno, pf->info.name, + NULL, NULL, &dbi, &size_info)) < 0) + { + if (result != PI_ERR_DLP_UNSUPPORTED) + goto fail; + old_device = 1; + } + + if ((result = dlp_OpenDB (socket, cardno, dlpOpenRead | dlpOpenSecret, + pf->info.name, &db)) < 0) + goto fail; + + buffer = pi_buffer_new (DLP_BUF_SIZE); + if (buffer == NULL) { + result = pi_set_error(socket, PI_ERR_GENERIC_MEMORY); + goto fail; + } + + if (old_device) { + int num_records; + if ((result = dlp_ReadOpenDBInfo(socket, db, &num_records)) < 0) + goto fail; + size_info.numRecords = num_records; + } + + memset(&progress, 0, sizeof(progress)); + progress.type = PI_PROGRESS_RECEIVE_DB; + progress.data.db.pf = pf; + progress.data.db.size = size_info; + + if (size_info.appBlockSize + || (dbi.miscFlags & dlpDBMiscFlagRamBased) + || old_device) { + /* what we're trying to do here is avoid trying to read an appBlock + * from a ROM file, because this crashes on several devices. + * Also, on several palmOne devices, the size info returned by the OS + * is absolutely incorrect. This happens with some system shadow files + * like AddressDB on T3, which actually do contain data and an appInfo + * block but the system tells us there's no appInfo and nearly no data, + * but still gives the accurate number of records. Seems to be bad + * structure shadows in PACE. + * In any case, the ultimate result is that: + * 1. On devices pre-OS 3, we do always try to read the appInfo block + * because dlp_FindDBByName() is unsupported so we can't find out if + * there's an appInfo block + * 2. On OS5+ devices, we're not sure that the appInfo size we have is + * accurate. But if we try reading an appInfo block in ROM it may + * crash the device + * 3. Therefore, we only try to read the appInfo block if we are + * working on a RAM file or we are sure that a ROM file has appInfo. + */ + result = dlp_ReadAppBlock(socket, db, 0, DLP_BUF_SIZE, buffer); + if (result > 0) { + pi_file_set_app_info(pf, buffer->data, (size_t)result); + progress.transferred_bytes += result; + if (report_progress && report_progress(socket, + &progress) == PI_TRANSFER_STOP) { + result = PI_ERR_FILE_ABORTED; + goto fail; + } + } + } + + if (pf->info.flags & dlpDBFlagResource) { + for (j = 0; j < size_info.numRecords; j++) { + int resource_id; + unsigned long type; + + if ((result = dlp_ReadResourceByIndex(socket, db, j, buffer, + &type, &resource_id)) < 0) + goto fail; + + if ((result = pi_file_append_resource (pf, buffer->data, buffer->used, + type, resource_id)) < 0) { + pi_set_error(socket, result); + goto fail; + } + + progress.transferred_bytes += buffer->used; + progress.data.db.transferred_records++; + + if (report_progress && report_progress(socket, + &progress) == PI_TRANSFER_STOP) { + result = pi_set_error(socket, PI_ERR_FILE_ABORTED); + goto fail; + } + } + } else for (j = 0; j < size_info.numRecords; j++) { + int attr, + category; + unsigned long resource_id; + + if ((result = dlp_ReadRecordByIndex(socket, db, j, buffer, &resource_id, &attr, + &category)) < 0) + goto fail; + + progress.transferred_bytes += buffer->used; + progress.data.db.transferred_records++; + + if (report_progress + && report_progress(socket, + &progress) == PI_TRANSFER_STOP) { + result = pi_set_error(socket, PI_ERR_FILE_ABORTED); + goto fail; + } + + /* There is no way to restore records with these + attributes, so there is no use in backing them up + */ + if (attr & + (dlpRecAttrArchived | dlpRecAttrDeleted)) + continue; + if ((result = pi_file_append_record(pf, buffer->data, buffer->used, + attr, category, resource_id)) < 0) { + pi_set_error(socket, result); + goto fail; + } + } + + pi_buffer_free(buffer); + + return dlp_CloseDB(socket, db); + +fail: + if (db != -1 && pi_socket_connected(socket)) { + int err = pi_error(socket); /* make sure we keep last error code */ + int palmoserr = pi_palmos_error(socket); + + dlp_CloseDB(socket, db); + + pi_set_error(socket, err); /* then restore it afterwards */ + pi_set_palmos_error(socket, palmoserr); + } + + if (buffer != NULL) + pi_buffer_free (buffer); + + if (result >= 0) { + /* one of our pi_file* calls failed */ + result = pi_set_error(socket, PI_ERR_FILE_ERROR); + } + return result; +} + +int +pi_file_install(pi_file_t *pf, int socket, int cardno, + progress_func report_progress) +{ + int db = -1, + j, + reset = 0, + flags, + version, + freeai = 0, + result, + err1, + err2; + size_t l, + size = 0; + void *buffer; + pi_progress_t progress; + + version = pi_version(socket); + + memset(&progress, 0, sizeof(progress)); + progress.type = PI_PROGRESS_SEND_DB; + progress.data.db.pf = pf; + progress.data.db.size.numRecords = pf->num_entries; + progress.data.db.size.dataBytes = pf->app_info_size; + progress.data.db.size.appBlockSize = pf->app_info_size; + progress.data.db.size.maxRecSize = pi_maxrecsize(socket); + + /* compute total size for progress reporting, and check that + either records are 64k or less, or the handheld can accept + large records. we do this prior to starting the install, + to avoid messing the device up if we have to fail. */ + for (j = 0; j < pf->num_entries; j++) { + result = (pf->info.flags & dlpDBFlagResource) ? + pi_file_read_resource(pf, j, 0, &size, 0, 0) : + pi_file_read_record(pf, j, 0, &size, 0, 0, 0); + if (result < 0) { + LOG((PI_DBG_API, PI_DBG_LVL_ERR, + "FILE INSTALL can't read all records/resources\n")); + goto fail; + } + if (size > 65536 && version < 0x0104) { + LOG((PI_DBG_API, PI_DBG_LVL_ERR, + "FILE INSTALL Database contains" + " record/resource over 64K!\n")); + goto fail; + } + progress.data.db.size.dataBytes += size; + } + + progress.data.db.size.totalBytes = + progress.data.db.size.dataBytes + + pf->ent_hdr_size * pf->num_entries + + PI_HDR_SIZE + 2; + + /* Delete DB if it already exists */ + dlp_DeleteDB(socket, cardno, pf->info.name); + + /* Set up DB flags */ + flags = pf->info.flags; + + /* Judd - 25Nov99 - Graffiti hack We want to make sure that these 2 + flags get set for this one */ + if (pf->info.creator == pi_mktag('g', 'r', 'a', 'f')) { + flags |= dlpDBFlagNewer; + flags |= dlpDBFlagReset; + } + + if (strcmp(pf->info.name, "Graffiti ShortCuts ") == 0) { + flags |= 0x8000; /* Rewrite an open DB */ + reset = 1; /* To be on the safe side */ + } + LOG((PI_DBG_API, PI_DBG_LVL_INFO, + "FILE INSTALL Name: %s Flags: %8.8X\n", pf->info.name, flags)); + + /* Create DB */ + if ((result = dlp_CreateDB + (socket, pf->info.creator, pf->info.type, cardno, flags, + pf->info.version, pf->info.name, &db)) < 0) { + int retry = 0; + + /* Judd - 25Nov99 - Graffiti hack + + The dlpDBFlagNewer specifies that if a DB is open and + cannot be deleted then it can be overwritten by a DB with + a different name. The creator ID of "graf" is what + really identifies a DB, not the name. We could call it + JimBob and the palm would still find it and use it. */ + + if (strcmp(pf->info.name, "Graffiti ShortCuts ") == 0) { + strcpy(pf->info.name, "Graffiti ShortCuts"); + retry = 1; + } else if (strcmp(pf->info.name, "Graffiti ShortCuts") == + 0) { + strcpy(pf->info.name, "Graffiti ShortCuts "); + retry = 1; + } else if (pf->info.creator == + pi_mktag('g', 'r', 'a', 'f')) { + /* Yep, someone has named it JimBob */ + strcpy(pf->info.name, "Graffiti ShortCuts"); + retry = 1; + } + + if (retry) { + /* Judd - 25Nov99 - Graffiti hack + We changed the name, now we can try to write it + again */ + if ((result = dlp_CreateDB + (socket, pf->info.creator, pf->info.type, + cardno, flags, pf->info.version, + pf->info.name, &db)) < 0) { + return result; + } + } else { + return result; + } + } + + pi_file_get_app_info(pf, &buffer, &l); + + /* Compensate for bug in OS 2.x Memo */ + if (version > 0x0100 + && strcmp(pf->info.name, "MemoDB") == 0 + && l > 0 + && l < 282) { + /* Justification: The appInfo structure was accidentally + lengthend in OS 2.0, but the Memo application does not + check that it is long enough, hence the shorter block + from OS 1.x will cause the 2.0 Memo application to lock + up if the sort preferences are modified. This code + detects the installation of a short app info block on a + 2.0 machine, and lengthens it. This transformation will + never lose information. */ + void *b2 = calloc(1, 282); + memcpy(b2, buffer, (size_t)l); + buffer = b2; + progress.data.db.size.appBlockSize = 282; + l = 282; + freeai = 1; + } + + /* All system updates seen to have the 'ptch' type, so trigger a + reboot on those */ + if (pf->info.creator == pi_mktag('p', 't', 'c', 'h')) + reset = 1; + + if (pf->info.flags & dlpDBFlagReset) + reset = 1; + + /* Upload appInfo block */ + if (l > 0) { + if ((result = dlp_WriteAppBlock(socket, db, buffer, l)) < 0) { + if (freeai) + free(buffer); + goto fail; + } + if (freeai) + free(buffer); + progress.transferred_bytes = l; + if (report_progress && report_progress(socket, + &progress) == PI_TRANSFER_STOP) { + result = pi_set_error(socket, PI_ERR_FILE_ABORTED); + goto fail; + } + } + + /* Upload resources / records */ + if (pf->info.flags & dlpDBFlagResource) { + for (j = 0; j < pf->num_entries; j++) { + int resource_id; + unsigned long type; + + if ((result = pi_file_read_resource(pf, j, &buffer, &size, + &type, &resource_id)) < 0) + goto fail; + + /* Skip empty resource, it cannot be installed */ + if (size == 0) + continue; + + if ((result = dlp_WriteResource(socket, db, type, resource_id, buffer, + size)) < 0) + goto fail; + + progress.transferred_bytes += size; + progress.data.db.transferred_records++; + + if (report_progress && report_progress(socket, + &progress) == PI_TRANSFER_STOP) { + result = pi_set_error(socket, PI_ERR_FILE_ABORTED); + goto fail; + } + + /* If we see a 'boot' section, regardless of file + type, require reset */ + if (type == pi_mktag('b', 'o', 'o', 't')) + reset = 1; + } + } else { + for (j = 0; j < pf->num_entries; j++) { + int attr, + category; + unsigned long resource_id; + + if ((result = pi_file_read_record(pf, j, &buffer, &size, &attr, + &category, &resource_id)) < 0) + goto fail; + + /* Old OS version cannot install deleted records, so + don't even try */ + if ((attr & (dlpRecAttrArchived | dlpRecAttrDeleted)) + && version < 0x0101) + continue; + + if ((result = dlp_WriteRecord(socket, db, attr, resource_id, category, + buffer, size, 0)) < 0) + goto fail; + + progress.transferred_bytes += size; + progress.data.db.transferred_records++; + + if (report_progress + && report_progress(socket, + &progress) == PI_TRANSFER_STOP) { + result = pi_set_error(socket, PI_ERR_FILE_ABORTED); + goto fail; + } + } + } + + if (reset) + dlp_ResetSystem(socket); + + return dlp_CloseDB(socket, db); + +fail: + /* save error codes then restore them after + closing/deleting the DB */ + err1 = pi_error(socket); + err2 = pi_palmos_error(socket); + + LOG((PI_DBG_API, PI_DBG_LVL_ERR, "FILE INSTALL error: pilot-link " + "0x%04x, PalmOS 0x%04x\n", err1, err2)); + if (db != -1 && pi_socket_connected(socket)) + dlp_CloseDB(socket, db); + if (pi_socket_connected(socket)) + dlp_DeleteDB(socket, cardno, pf->info.name); + + pi_set_error(socket, err1); + pi_set_palmos_error(socket, err2); + + if (result >= 0) + result = pi_set_error(socket, PI_ERR_FILE_ERROR); + return result; +} + +int +pi_file_merge(pi_file_t *pf, int socket, int cardno, + progress_func report_progress) +{ + int db = -1, + j, + reset = 0, + version, + result; + void *buffer; + size_t size; + pi_progress_t progress; + + version = pi_version(socket); + + memset(&progress, 0, sizeof(progress)); + progress.type = PI_PROGRESS_SEND_DB; + progress.data.db.pf = pf; + progress.data.db.size.numRecords = pf->num_entries; + progress.data.db.size.dataBytes = pf->app_info_size; + progress.data.db.size.appBlockSize = pf->app_info_size; + progress.data.db.size.maxRecSize = pi_maxrecsize(socket); + + if (dlp_OpenDB(socket, cardno, dlpOpenReadWrite | dlpOpenSecret, + pf->info.name, &db) < 0) + return pi_file_install(pf, socket, cardno, report_progress); + + /* compute total size for progress reporting, and check that + either records are 64k or less, or the handheld can accept + large records. we do this prior to starting the install, + to avoid messing the device up if we have to fail. */ + for (j = 0; j < pf->num_entries; j++) { + result = (pf->info.flags & dlpDBFlagResource) ? + pi_file_read_resource(pf, j, 0, &size, 0, 0) : + pi_file_read_record(pf, j, 0, &size, 0, 0, 0); + if (result < 0) { + LOG((PI_DBG_API, PI_DBG_LVL_ERR, + "FILE INSTALL can't read all records/resources\n")); + goto fail; + } + if (size > 65536 && version < 0x0104) { + LOG((PI_DBG_API, PI_DBG_LVL_ERR, + "FILE INSTALL Database contains" + " record/resource over 64K!\n")); + result = pi_set_error(socket, PI_ERR_DLP_DATASIZE); + goto fail; + } + progress.data.db.size.dataBytes += size; + } + + progress.data.db.size.totalBytes = + progress.data.db.size.dataBytes + + pf->ent_hdr_size * pf->num_entries + + PI_HDR_SIZE + 2; + + /* All system updates seen to have the 'ptch' type, so trigger a + reboot on those */ + if (pf->info.creator == pi_mktag('p', 't', 'c', 'h')) + reset = 1; + + if (pf->info.flags & dlpDBFlagReset) + reset = 1; + + /* Upload resources / records */ + if (pf->info.flags & dlpDBFlagResource) { + for (j = 0; j < pf->num_entries; j++) { + int resource_id; + unsigned long type; + + if ((result = pi_file_read_resource + (pf, j, &buffer, &size, &type, &resource_id)) < 0) + goto fail; + + if (size == 0) + continue; + + if ((result = dlp_WriteResource + (socket, db, type, resource_id, buffer, size)) < 0) + goto fail; + + progress.transferred_bytes += size; + progress.data.db.transferred_records++; + + if (report_progress && report_progress(socket, + &progress) == PI_TRANSFER_STOP) { + result = pi_set_error(socket, PI_ERR_FILE_ABORTED); + goto fail; + } + + /* If we see a 'boot' section, regardless of file + type, require reset */ + if (type == pi_mktag('b', 'o', 'o', 't')) + reset = 1; + } + } else { + for (j = 0; j < pf->num_entries; j++) { + int attr, + category; + unsigned long resource_id; + + if ((result = pi_file_read_record(pf, j, &buffer, &size, + &attr, &category, &resource_id)) < 0) + goto fail; + + /* Old OS version cannot install deleted records, so + don't even try */ + if ((attr & (dlpRecAttrArchived | dlpRecAttrDeleted)) + && version < 0x0101) + continue; + + if ((result = dlp_WriteRecord(socket, db, attr, 0, category, + buffer, size, 0)) < 0) + goto fail; + + progress.transferred_bytes += size; + progress.data.db.transferred_records++; + + if (report_progress && report_progress(socket, + &progress) == PI_TRANSFER_STOP) { + result = PI_ERR_FILE_ABORTED; + goto fail; + } + } + } + + if (reset) + dlp_ResetSystem(socket); + + return dlp_CloseDB(socket, db); + +fail: + if (db != -1 && pi_socket_connected(socket)) { + int err1 = pi_error(socket); + int err2 = pi_palmos_error(socket); + + dlp_CloseDB(socket, db); + + pi_set_error(socket, err1); + pi_set_palmos_error(socket, err2); + } + if (result >= 0) + result = pi_set_error(socket, PI_ERR_FILE_ERROR); + return result; +} + +/*********************************************************************************/ +/* */ +/* INTERNAL FUNCTIONS */ +/* */ +/*********************************************************************************/ + +/*********************************************************************** + * + * Function: pi_file_close_for_write + * + * Summary: Writes a file to disk + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +static int +pi_file_close_for_write(pi_file_t *pf) +{ + int i, + offset; + FILE *f; + + struct DBInfo *ip; + struct pi_file_entry *entp; + struct stat sbuf; + + unsigned char buf[512]; + unsigned char *p; + + ip = &pf->info; + if (pf->num_entries >= 64 * 1024) { + LOG((PI_DBG_API, PI_DBG_LVL_ERR, + "pi_file_close_for_write: too many entries " + "for this implentation of pi-file: %d\n", + pf->num_entries)); + return PI_ERR_FILE_INVALID; + } + + /* + * Unlink instead of overwriting. + * For the case of something along the lines of: + * cp -lav backup_2005_05_27 backup_2005_05_28 + * Then updating the new copy. + * -- Warp. + */ + + if (!stat (pf->file_name, &sbuf)) + if (S_ISREG(sbuf.st_mode)) + unlink (pf->file_name); + + if ((f = fopen(pf->file_name, "wb")) == NULL) + return PI_ERR_FILE_ERROR; + + ip = &pf->info; + + offset = PI_HDR_SIZE + pf->num_entries * pf->ent_hdr_size + 2; + + p = buf; + memcpy(p, ip->name, 32); + set_short(p + 32, ip->flags); + set_short(p + 34, ip->version); + set_long(p + 36, unix_time_to_pilot_time(ip->createDate)); + set_long(p + 40, unix_time_to_pilot_time(ip->modifyDate)); + set_long(p + 44, unix_time_to_pilot_time(ip->backupDate)); + set_long(p + 48, ip->modnum); + set_long(p + 52, pf->app_info_size ? offset : 0); + offset += pf->app_info_size; + set_long(p + 56, pf->sort_info_size ? offset : 0); + offset += pf->sort_info_size; + set_long(p + 60, ip->type); + set_long(p + 64, ip->creator); + set_long(p + 68, pf->unique_id_seed); + set_long(p + 72, pf->next_record_list_id); + set_short(p + 76, pf->num_entries); + + if (fwrite(buf, PI_HDR_SIZE, 1, f) != 1) + goto bad; + + for (i = 0, entp = pf->entries; i < pf->num_entries; i++, entp++) { + entp->offset = offset; + + p = buf; + if (pf->resource_flag) { + set_long(p, entp->type); + set_short(p + 4, entp->resource_id); + set_long(p + 6, entp->offset); + } else { + set_long(p, entp->offset); + set_byte(p + 4, entp->attrs); + set_treble(p + 5, entp->uid); + } + + if (fwrite(buf, (size_t) pf->ent_hdr_size, 1, f) != 1) + goto bad; + + offset += entp->size; + } + + /* This may just be packing */ + fwrite("\0\0", 1, 2, f); + + if (pf->app_info + && (fwrite(pf->app_info, 1,(size_t) pf->app_info_size, f) != + (size_t) pf->app_info_size)) + goto bad; + + if (pf->sort_info + && (fwrite(pf->sort_info, 1, (size_t) pf->sort_info_size, f) != + (size_t) pf->sort_info_size)) + goto bad; + + + fwrite(pf->tmpbuf->data, pf->tmpbuf->used, 1, f); + fflush(f); + + if (ferror(f) || feof(f)) + goto bad; + + fclose(f); + return 0; + +bad: + fclose(f); + return PI_ERR_FILE_ERROR; +} + +/*********************************************************************** + * + * Function: pi_file_free + * + * Summary: Flush and clean the file handles used + * + * Parameters: file handle pi_file_t* + * + * Returns: void + * + ***********************************************************************/ +static +void pi_file_free(pi_file_t *pf) +{ + ASSERT (pf != NULL); + + if (pf->f != 0) + fclose(pf->f); + + if (pf->app_info != NULL) + free(pf->app_info); + + if (pf->sort_info != NULL) + free(pf->sort_info); + + if (pf->entries != NULL) + free(pf->entries); + + if (pf->file_name != NULL) + free(pf->file_name); + + if (pf->rbuf != NULL) + free(pf->rbuf); + + if (pf->tmpbuf != NULL) + pi_buffer_free(pf->tmpbuf); + + /* in case caller forgets the struct has been freed... */ + memset(pf, 0, sizeof(pi_file_t)); + + free(pf); +} + +/*********************************************************************** + * + * Function: pi_file_set_rbuf_size + * + * Summary: set pi_file rbuf size + * + * Parameters: file handle pi_file_t*, rbuf size + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +pi_file_set_rbuf_size(pi_file_t *pf, size_t size) +{ + size_t new_size; + void *rbuf; + + if (size > (size_t)pf->rbuf_size) { + if (pf->rbuf_size == 0) { + new_size = size + 2048; + rbuf = malloc(new_size); + } else { + new_size = size + 2048; + rbuf = realloc(pf->rbuf, new_size); + } + + if (rbuf == NULL) + return PI_ERR_GENERIC_MEMORY; + + pf->rbuf_size = new_size; + pf->rbuf = rbuf; + } + + return 0; +} + +/*********************************************************************** + * + * Function: pi_file_append_entry + * + * Summary: Internal function to extend entry list if necessary, + * and return a pointer to the next available slot + * + * Parameters: None + * + * Returns: NULL on allocation error + * + ***********************************************************************/ +static pi_file_entry_t +*pi_file_append_entry(pi_file_t *pf) +{ + int new_count; + size_t new_size; + struct pi_file_entry *new_entries; + struct pi_file_entry *entp; + + if (pf->num_entries >= pf->num_entries_allocated) { + if (pf->num_entries_allocated == 0) + new_count = 100; + else + new_count = pf->num_entries_allocated * 3 / 2; + new_size = new_count * sizeof *pf->entries; + + if (pf->entries == NULL) + new_entries = malloc(new_size); + else + new_entries = realloc(pf->entries, new_size); + + if (new_entries == NULL) + return NULL; + + pf->num_entries_allocated = new_count; + pf->entries = new_entries; + } + + entp = &pf->entries[pf->num_entries++]; + memset(entp, 0, sizeof *entp); + return entp; +} + +static int +pi_file_find_resource_by_type_id(const pi_file_t *pf, + unsigned long restype, int resid, int *resindex) +{ + int i; + struct pi_file_entry *entp; + + if (!pf->resource_flag) + return PI_ERR_FILE_INVALID; + + for (i = 0, entp = pf->entries; i < pf->num_entries; i++, entp++) { + if (entp->type == restype && entp->resource_id == resid) { + if (resindex) + *resindex = i; + return 1; + } + } + return 0; +} + + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ + diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/pi-header.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/pi-header.c new file mode 100644 index 00000000..a4d19404 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/pi-header.c @@ -0,0 +1,63 @@ +/* + * $Id: pi-header.c,v 1.25 2006/10/12 14:21:22 desrod Exp $ + * + * pi-header.c: Splash for the version/etc. + * + * Copyright (c) 2000, David A. Desrosiers + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include "pi-version.h" +#include "pi-header.h" + +void print_splash(const char *progname) +{ + char *patchlevel = ""; + + fprintf(stderr," DEPRECATED: The application is calling print_splash()\n"); +#ifdef PILOT_LINK_PATCH + patchlevel = PILOT_LINK_PATCH; +#endif + printf(" .--------------------------------------------.\n" + " | (c) Copyright 1996-2006, pilot-link team |\n" + " | Join the pilot-link lists to help out. |\n" + " `--------------------------------------------'\n" + " This is %s, from pilot-link version %d.%d.%d%s\n\n" + " Build target..: %s\n" + " Build date....: %s %s\n\n", progname, + PILOT_LINK_VERSION, PILOT_LINK_MAJOR, PILOT_LINK_MINOR, + patchlevel, HOST_OS, __DATE__, __TIME__); + + printf(" pilot-link %d.%d.%d%s is covered under the GPL/LGPL\n", + PILOT_LINK_VERSION, PILOT_LINK_MAJOR, PILOT_LINK_MINOR, + patchlevel); + + printf(" See the file COPYING under docs for more info.\n\n" + " Please use --help for more detailed options.\n"); + +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/serial.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/serial.c new file mode 100644 index 00000000..37d292a2 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/serial.c @@ -0,0 +1,717 @@ +/* + * $Id: serial.c,v 1.72 2006/10/12 14:21:22 desrod Exp $ + * + * serial.c: Interface layer to serial HotSync connections + * + * Copyright (c) 1996, 1997, D. Jeff Dionne & Kenneth Albanowski + * Copyright (c) 1999, Tilo Christ + * Copyright (c) 2005, Florent Pillet + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + * + * -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> /* Needed for Redhat 6.x machines */ +#include <unistd.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-socket.h" +#include "pi-serial.h" +#include "pi-net.h" +#include "pi-cmp.h" +#include "pi-error.h" +#include "pi-util.h" + +#ifdef OS2 +#include <sys/select.h> +#endif + +/* Declare prototypes */ +static int pi_serial_connect(pi_socket_t *ps, struct sockaddr *addr, + size_t addrlen); +static int pi_serial_bind(pi_socket_t *ps, struct sockaddr *addr, + size_t addrlen); +static int pi_serial_listen(pi_socket_t *ps, int backlog); +static int pi_serial_accept(pi_socket_t *ps, struct sockaddr *addr, + size_t *addrlen); +static int pi_serial_getsockopt(pi_socket_t *ps, int level, + int option_name, void *option_value, + size_t *option_len); +static int pi_serial_setsockopt(pi_socket_t *ps, int level, + int option_name, const void *option_value, + size_t *option_len); +static int pi_serial_close(pi_socket_t *ps); + +extern int pi_socket_init(pi_socket_t *ps); + + +/* Protocol Functions */ +/*********************************************************************** + * + * Function: pi_serial_protocol_dup + * + * Summary: clones an existing pi_protocol struct + * + * Parameters: pi_protocol* + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +static pi_protocol_t* +pi_serial_protocol_dup (pi_protocol_t *prot) +{ + pi_protocol_t *new_prot; + + ASSERT (prot != NULL); + + new_prot = (pi_protocol_t *) malloc(sizeof (pi_protocol_t)); + + if (new_prot != NULL) { + new_prot->level = prot->level; + new_prot->dup = prot->dup; + new_prot->free = prot->free; + new_prot->read = prot->read; + new_prot->write = prot->write; + new_prot->flush = prot->flush; + new_prot->getsockopt = prot->getsockopt; + new_prot->setsockopt = prot->setsockopt; + new_prot->data = NULL; + } + + return new_prot; +} + + +/*********************************************************************** + * + * Function: pi_serial_protocol_free + * + * Summary: frees an existing pi_protocol struct + * + * Parameters: pi_protocol* + * + * Returns: void + * + ***********************************************************************/ +static void +pi_serial_protocol_free (pi_protocol_t *prot) +{ + ASSERT (prot != NULL); + + if (prot != NULL) + free(prot); +} + + +/*********************************************************************** + * + * Function: pi_serial_protocol + * + * Summary: creates and inits pi_protocol struct instance + * + * Parameters: pi_device_t* + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +static pi_protocol_t* +pi_serial_protocol (pi_device_t *dev) +{ + pi_protocol_t *prot; + struct pi_serial_data *data; + + ASSERT (dev != NULL); + + prot = (pi_protocol_t *) malloc(sizeof (pi_protocol_t)); + + data = (struct pi_serial_data *)(dev->data); + + if (prot != NULL) { + prot->level = PI_LEVEL_DEV; + prot->dup = pi_serial_protocol_dup; + prot->free = pi_serial_protocol_free; + prot->read = data->impl.read; + prot->write = data->impl.write; + prot->flush = data->impl.flush; + prot->getsockopt = pi_serial_getsockopt; + prot->setsockopt = pi_serial_setsockopt; + prot->data = NULL; + } + + return prot; +} + + +/* Device Functions */ +/*********************************************************************** + * + * Function: pi_serial_device_free + * + * Summary: frees an existing pi_device struct + * + * Parameters: pi_device_t* + * + * Returns: void + * + ***********************************************************************/ +static void +pi_serial_device_free (pi_device_t *dev) +{ + ASSERT (dev != NULL); + + free(dev->data); + free(dev); +} + + +/*********************************************************************** + * + * Function: pi_serial_device + * + * Summary: creates and inits pi_device struct instance + * + * Parameters: device type + * + * Returns: pi_device_t* or NULL if operation failed + * + ***********************************************************************/ +pi_device_t* +pi_serial_device (int type) +{ + pi_device_t *dev; + struct pi_serial_data *data; + + dev = (pi_device_t *) malloc(sizeof (pi_device_t)); + if (dev == NULL) + return NULL; + + data = (struct pi_serial_data *) malloc(sizeof (struct pi_serial_data)); + if (data == NULL) { + free(dev); + return NULL; + } + + dev->free = pi_serial_device_free; + dev->protocol = pi_serial_protocol; + dev->bind = pi_serial_bind; + dev->listen = pi_serial_listen; + dev->accept = pi_serial_accept; + dev->connect = pi_serial_connect; + dev->close = pi_serial_close; + + switch (type) { + case PI_SERIAL_DEV: + pi_serial_impl_init (&data->impl); + break; + default: + pi_serial_impl_init (&data->impl); + break; + } + + data->buf_size = 0; + data->rate = -1; + data->establishrate = -1; + data->establishhighrate = -1; + data->timeout = 0; + data->rx_bytes = 0; + data->rx_errors = 0; + data->tx_bytes = 0; + data->tx_errors = 0; + + dev->data = data; + + return dev; +} + + +/*********************************************************************** + * + * Function: pi_serial_connect + * + * Summary: Connect socket to a given address + * + * Parameters: pi_socket*, sockaddr*, size_t + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +static int +pi_serial_connect(pi_socket_t *ps, struct sockaddr *addr, + size_t addrlen) +{ + struct pi_serial_data *data = + (struct pi_serial_data *)ps->device->data; + struct pi_sockaddr *pa = (struct pi_sockaddr *) addr; + int err; + + if (ps->type == PI_SOCK_STREAM) { + if (ps->protocol == PI_PF_SYS) { + data->establishrate = data->rate = 57600; + } else { + if (data->establishrate == -1) + get_pilot_rate(&data->establishrate, &data->establishhighrate); + + /* Mandatory CMP connection rate */ + data->rate = 9600; + } + } else if (ps->type == PI_SOCK_RAW) { + /* Mandatory SysPkt connection rate */ + data->establishrate = data->rate = 57600; + } + + if ((err = data->impl.open(ps, pa, addrlen)) < 0) + return err; /* errno already set */ + + ps->raddr = malloc(addrlen); + memcpy(ps->raddr, addr, addrlen); + ps->raddrlen = addrlen; + ps->laddr = malloc(addrlen); + memcpy(ps->laddr, addr, addrlen); + ps->laddrlen = addrlen; + + if (ps->type == PI_SOCK_STREAM) { + size_t size; + switch (ps->cmd) { + case PI_CMD_CMP: + if (cmp_tx_handshake(ps) < 0) + goto fail; + + size = sizeof(data->rate); + pi_getsockopt(ps->sd, PI_LEVEL_CMP, PI_CMP_BAUD, + &data->rate, &size); + + if ((err = data->impl.changebaud(ps)) < 0) + goto fail; + break; + + case PI_CMD_NET: + if ((err = data->impl.changebaud(ps)) < 0) + goto fail; + break; + + case PI_CMD_SYS: + if ((err = data->impl.changebaud(ps)) < 0) + goto fail; + break; + } + } + ps->state = PI_SOCK_CONN_INIT; + ps->command = 0; + return 0; + +fail: + return err; +} + + +/*********************************************************************** + * + * Function: pi_serial_bind + * + * Summary: Bind address to a local socket + * + * Parameters: pi_socket*, sockaddr*, size_t + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +static int +pi_serial_bind(pi_socket_t *ps, struct sockaddr *addr, size_t addrlen) +{ + struct pi_serial_data *data = + (struct pi_serial_data *)ps->device->data; + struct pi_sockaddr *pa = (struct pi_sockaddr *) addr; + int err, count = 0; + + if (ps->type == PI_SOCK_STREAM) { + if (data->establishrate == -1) + get_pilot_rate(&data->establishrate, &data->establishhighrate); + + /* Mandatory CMP connection rate */ + data->rate = 9600; + } else if (ps->type == PI_SOCK_RAW) { + /* Mandatory SysPkt connection rate */ + data->establishrate = data->rate = 57600; + } + +begin: + if ((err = data->impl.open(ps, pa, addrlen)) < 0) { + int save_errno = errno; +#ifdef MAXPATHLEN + char realport[MAXPATHLEN]; +#else + # ifdef PATH_MAX + char realport[PATH_MAX]; + # else + char realport[4096]; + # endif /* PATH_MAX */ +#endif /* MAXPATHLEN */ + + realpath(pa->pi_device, realport); + errno = save_errno; + + if (errno == ENOENT) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + " The device %s does not exist..\n", + pa->pi_device)); + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + " Possible solution:\n\n\tmknod %s c " + "<major> <minor>\n\n", pa->pi_device)); + } else if (errno == EACCES) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + " Please check the " + "permissions on %s..\n", realport)); + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + " Possible solution:\n\n\tchmod 0666 " + "%s\n\n", realport)); + } else if (errno == ENODEV) { + while (count <= 5) { + if (isatty(fileno(stdout))) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + "\r Port not connected," + " sleeping for 2 seconds, ")); + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + "%d retries..", + 5-count)); + } + sleep(2); + count++; + goto begin; + } + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + "\n\n Device not found on %s, \ + Did you hit HotSync?\n\n", realport)); + } else if (errno == EISDIR) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + " The port specified must" + " contain a device name, and %s was" + " a directory.\n" + " Please change that to reference a" + " real device, and try" + " again\n\n", pa->pi_device)); + } + return err; + } + ps->raddr = malloc(addrlen); + memcpy(ps->raddr, addr, addrlen); + ps->raddrlen = addrlen; + ps->laddr = malloc(addrlen); + memcpy(ps->laddr, addr, addrlen); + ps->laddrlen = addrlen; + + return 0; +} + +/*********************************************************************** + * + * Function: pi_serial_listen + * + * Summary: Prepare for incoming connections + * + * Parameters: pi_socket*, backlog + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int pi_serial_listen(pi_socket_t *ps, int backlog) +{ + int result; + struct pi_serial_data *data = + (struct pi_serial_data *)ps->device->data; + + /* ps->rate has been set by bind */ + result = data->impl.changebaud(ps); + if (result == 0) + ps->state = PI_SOCK_LISTEN; + + return result; +} + +/*********************************************************************** + * + * Function: pi_serial_accept + * + * Summary: Accept an incoming connection + * + * Parameters: pi_socket*, sockaddr* + * + * Returns: Nothing + * + ***********************************************************************/ +static int +pi_serial_accept(pi_socket_t *ps, struct sockaddr *addr, + size_t *addrlen) +{ + struct pi_serial_data *data = + (struct pi_serial_data *)ps->device->data; + size_t size; + int err; + + /* Wait for data */ +#ifdef linux + if (ps->accept_to) { + /* shield against losing the first packet */ + int result = data->impl.poll(ps, 1000); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s: %d, poll result: %d.\n", __FILE__, __LINE__, result)); + + if (result < 0) { + char buf[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; + data->impl.write(ps, buf, sizeof (buf), 1000); + } + } +#endif + if ((err = data->impl.poll(ps, ps->accept_to * 1000)) < 0) + goto fail; + + data->timeout = ps->accept_to * 1000; + + pi_socket_init(ps); + if (ps->type == PI_SOCK_STREAM) { + struct timeval tv; + unsigned char cmp_flags; + + switch (ps->cmd) { + case PI_CMD_CMP: + if ((err = cmp_rx_handshake(ps, data->establishrate, data->establishhighrate)) < 0) + goto fail; + + /* propagate the long packet format flag to both command and non-command stacks */ + size = sizeof(cmp_flags); + pi_getsockopt(ps->sd, PI_LEVEL_CMP, PI_CMP_FLAGS, &cmp_flags, &size); + if (cmp_flags & CMP_FL_LONG_PACKET_SUPPORT) { + int use_long_format = 1; + size = sizeof(int); + pi_setsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_USE_LONG_FORMAT, + &use_long_format, &size); + ps->command ^= 1; + pi_setsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_USE_LONG_FORMAT, + &use_long_format, &size); + ps->command ^= 1; + } + + /* We always reconfigure our port, no matter what */ + size = sizeof(data->rate); + pi_getsockopt(ps->sd, PI_LEVEL_CMP, PI_CMP_BAUD, &data->rate, &size); + if ((err = data->impl.changebaud(ps)) < 0) + goto fail; + + /* Palm device needs some time to reconfigure its port */ + tv.tv_sec = 0; + tv.tv_usec = 50000; + select(0, 0, 0, 0, &tv); + break; + + case PI_CMD_NET: + /* serial/network: make sure we don't split writes. set socket option + * on both the command and non-command instances of the protocol + */ +#ifdef MACOSX + /* We need to turn fragmentation OFF to improve Bluetooth performance + * but this code is also used by USB on Linux and Freebsd + * therefore, only compile it when running OS X + */ + { + int split = 0; + size_t chunksize = 0; + + size = sizeof (split); + pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_SPLIT_WRITES, + &split, &size); + size = sizeof (chunksize); + pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_WRITE_CHUNKSIZE, + &chunksize, &size); + + ps->command ^= 1; + size = sizeof (split); + pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_SPLIT_WRITES, + &split, &size); + size = sizeof (chunksize); + pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_WRITE_CHUNKSIZE, + &chunksize, &size); + ps->command ^= 1; + } +#endif + if ((err = net_rx_handshake(ps)) < 0) + goto fail; + break; + } + ps->dlprecord = 0; + } + + data->timeout = 0; + ps->command = 0; + ps->state = PI_SOCK_CONN_ACCEPT; + + return ps->sd; + +fail: + return err; +} + + +/*********************************************************************** + * + * Function: pi_serial_getsockopt + * + * Summary: get options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +pi_serial_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len) +{ + struct pi_serial_data *data = + (struct pi_serial_data *)ps->device->data; + + switch (option_name) { + case PI_DEV_RATE: + if (*option_len != sizeof (data->rate)) + goto error; + memcpy (option_value, &data->rate, sizeof (data->rate)); + break; + + case PI_DEV_ESTRATE: + if (*option_len != sizeof (data->establishrate)) + goto error; + memcpy (option_value, &data->establishrate, sizeof (data->establishrate)); + break; + + case PI_DEV_HIGHRATE: + if (*option_len != sizeof (data->establishhighrate)) + goto error; + memcpy (option_value, &data->establishhighrate, sizeof (data->establishhighrate)); + break; + + case PI_DEV_TIMEOUT: + if (*option_len != sizeof (data->timeout)) + goto error; + memcpy (option_value, &data->timeout, sizeof (data->timeout)); + break; + } + + return 0; + +error: + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); +} + + +/*********************************************************************** + * + * Function: pi_serial_setsockopt + * + * Summary: set options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +pi_serial_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len) +{ + struct pi_serial_data *data = + (struct pi_serial_data *)ps->device->data; + + /* FIXME: can't change stuff if already connected */ + switch (option_name) { + case PI_DEV_ESTRATE: + if (*option_len != sizeof (data->establishrate)) + goto error; + memcpy (&data->establishrate, option_value, sizeof (data->establishrate)); + break; + + case PI_DEV_HIGHRATE: + if (*option_len != sizeof (data->establishhighrate)) + goto error; + memcpy (&data->establishhighrate, option_value, sizeof (data->establishhighrate)); + break; + + case PI_DEV_TIMEOUT: + if (*option_len != sizeof (data->timeout)) + goto error; + memcpy (&data->timeout, option_value, sizeof (data->timeout)); + break; + } + + return 0; + + error: + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); +} + + +/*********************************************************************** + * + * Function: pi_serial_close + * + * Summary: Close a connection, destroy the socket + * + * Parameters: pi_socket* + * + * Returns: always 0 for success + * + ***********************************************************************/ +static int pi_serial_close(pi_socket_t *ps) +{ + struct pi_serial_data *data = + (struct pi_serial_data *)ps->device->data; + + if (ps->sd) { + data->impl.close (ps); + ps->sd = 0; + } + + if (ps->laddr) { + free(ps->laddr); + ps->laddr = NULL; + } + + if (ps->raddr) { + free(ps->raddr); + ps->raddr = NULL; + } + + return 0; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/slp.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/slp.c new file mode 100644 index 00000000..c3063a3c --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/slp.c @@ -0,0 +1,657 @@ +/* + * $Id: slp.c,v 1.56 2006/10/13 09:52:13 fpillet Exp $ + * + * slp.c: Pilot SLP protocol + * + * (c) 1996, D. Jeff Dionne. + * Much of this code adapted from Brian J. Swetland <swetland@uiuc.edu> + * Additional work Copyright (c) 2005, Florent Pillet + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + * + * -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <netinet/in.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-serial.h" +#include "pi-slp.h" +#include "pi-error.h" + +/* Declare function prototypes */ +static int slp_flush(pi_socket_t *ps, int flags); +static int slp_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len); +static int slp_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len); + + +/*********************************************************************** + * + * Function: slp_protocol_dup + * + * Summary: clones an existing pi_protocol struct + * + * Parameters: pi_protocol_t* + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +static pi_protocol_t* +slp_protocol_dup (pi_protocol_t *prot) +{ + pi_protocol_t *new_prot; + + struct pi_slp_data *data, + *new_data; + + new_prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t)); + new_data = (struct pi_slp_data *)malloc (sizeof (struct pi_slp_data)); + + if (new_prot != NULL && new_data != NULL) { + new_prot->level = prot->level; + new_prot->dup = prot->dup; + new_prot->free = prot->free; + new_prot->read = prot->read; + new_prot->write = prot->write; + new_prot->flush = prot->flush; + new_prot->getsockopt = prot->getsockopt; + new_prot->setsockopt = prot->setsockopt; + + data = (struct pi_slp_data *)prot->data; + + new_data->dest = data->dest; + new_data->last_dest = data->last_dest; + new_data->src = data->src; + new_data->last_src = data->last_src; + new_data->type = data->type; + new_data->last_type = data->last_type; + new_data->txid = data->txid; + new_data->last_txid = data->last_txid; + + new_prot->data = new_data; + + } else if (new_prot != NULL) { + free(new_prot); + new_prot = NULL; + } else if (new_data != NULL) { + free(new_data); + new_data = NULL; + } + + return new_prot; +} + + +/*********************************************************************** + * + * Function: slp_protocol_free + * + * Summary: frees an existing pi_protocol struct + * + * Parameters: pi_protocol_t* + * + * Returns: void + * + ***********************************************************************/ +static void +slp_protocol_free (pi_protocol_t *prot) +{ + if (prot != NULL) { + if (prot->data != NULL) + free(prot->data); + free(prot); + } +} + + +/*********************************************************************** + * + * Function: slp_protocol + * + * Summary: creates a pi_protocol struct instance + * + * Parameters: pi_protocol_t* + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +pi_protocol_t* +slp_protocol (void) +{ + pi_protocol_t *prot; + struct pi_slp_data *data; + + prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t)); + data = (struct pi_slp_data *)malloc (sizeof (struct pi_slp_data)); + + if (prot != NULL && data != NULL) { + prot->level = PI_LEVEL_SLP; + prot->dup = slp_protocol_dup; + prot->free = slp_protocol_free; + prot->read = slp_rx; + prot->write = slp_tx; + prot->flush = slp_flush; + prot->getsockopt = slp_getsockopt; + prot->setsockopt = slp_setsockopt; + + data->dest = PI_SLP_SOCK_DLP; + data->last_dest = -1; + data->src = PI_SLP_SOCK_DLP; + data->last_src = -1; + data->type = PI_SLP_TYPE_PADP; + data->last_type = -1; + data->txid = 0xfe; + data->last_txid = 0xff; + prot->data = data; + + } else if (prot != NULL) { + free(prot); + prot = NULL; + } else if (data != NULL) { + free(data); + data = NULL; + } + + return prot; +} + + +/*********************************************************************** + * + * Function: slp_tx + * + * Summary: Build and queue up an SLP packet to be transmitted + * + * Parameters: None + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +ssize_t +slp_tx(pi_socket_t *ps, const unsigned char *buf, size_t len, int flags) +{ + int bytes; + pi_protocol_t *prot, + *next; + struct pi_slp_data *data; + struct slp *slp; + unsigned char *slp_buf; + unsigned int i, + n; + + prot = pi_protocol(ps->sd, PI_LEVEL_SLP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (struct pi_slp_data *)prot->data; + next = pi_protocol_next(ps->sd, PI_LEVEL_SLP); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + slp_buf = (unsigned char *) malloc (PI_SLP_HEADER_LEN + + PI_SLP_MTU + PI_SLP_FOOTER_LEN); + if (slp_buf == NULL) + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + + slp = (struct slp *) slp_buf; + + /* Header values */ + slp->_be = 0xbe; + slp->_ef = 0xef; + slp->_ed = 0xed; + slp->dest = data->dest; + slp->src = data->src; + slp->type = data->type; + set_short(&slp->dlen, len); + slp->id_ = data->txid; + + for (n = i = 0; i < 9; i++) + n += slp_buf[i]; + slp->csum = 0xff & n; + + /* Copy in the packet data */ + memcpy (slp_buf + PI_SLP_HEADER_LEN, buf, len); + + /* CRC value */ + set_short(&slp_buf[PI_SLP_HEADER_LEN + len], + crc16(slp_buf, (int)(PI_SLP_HEADER_LEN + len))); + + /* Write out the data */ + bytes = next->write(ps, slp_buf, + PI_SLP_HEADER_LEN + len + PI_SLP_FOOTER_LEN, flags); + + if (bytes >= 0) { + CHECK(PI_DBG_SLP, PI_DBG_LVL_INFO, slp_dump_header(slp_buf, 1)); + CHECK(PI_DBG_SLP, PI_DBG_LVL_DEBUG, slp_dump(slp_buf)); + } + + free (slp_buf); + + return bytes; +} + +/* Sigh. SLP is a really broken protocol. It has no proper framing, so it + makes a proper "device driver" layer impossible. There ought to be a + layer below SLP that reads frames off the wire and passes them up. + Instead, all we can do is have the device driver give us bytes and SLP has + to keep a pile of status info while it builds frames for itself. So + here's the code that does that. */ + +/*********************************************************************** + * + * Function: slp_rx + * + * Summary: Accept SLP packets on the wire + * + * Parameters: None + * + * Returns: packet length or negative on error + * + ***********************************************************************/ +ssize_t +slp_rx(pi_socket_t *ps, pi_buffer_t *buf, size_t len, int flags) +{ + int i, + computed_crc, + received_crc, + b1, + b2, + b3, + state, + expect = 0, + packet_len, + bytes; + unsigned char + header_checksum; + pi_protocol_t *prot, + *next; + pi_buffer_t *slp_buf; + struct pi_slp_data *data; + + LOG((PI_DBG_SLP, PI_DBG_LVL_DEBUG, "SLP RX len=%d flags=0x%04x\n", + len, flags)); + + prot = pi_protocol(ps->sd, PI_LEVEL_SLP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (struct pi_slp_data *)prot->data; + next = pi_protocol_next(ps->sd, PI_LEVEL_SLP); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + slp_buf = pi_buffer_new (PI_SLP_HEADER_LEN + PI_SLP_MTU + PI_SLP_FOOTER_LEN); + if (slp_buf == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + state = 0; + packet_len = 0; + + for (;;) { + switch (state) { + case 0: + expect = 3; + state++; + break; + + case 1: + b1 = slp_buf->data[PI_SLP_OFFSET_SIG1]; + b2 = slp_buf->data[PI_SLP_OFFSET_SIG2]; + b3 = slp_buf->data[PI_SLP_OFFSET_SIG3]; + if (b1 == PI_SLP_SIG_BYTE1 && + b2 == PI_SLP_SIG_BYTE2 && + b3 == PI_SLP_SIG_BYTE3) { + state++; + expect = PI_SLP_HEADER_LEN - 3; + } else { + slp_buf->data[PI_SLP_OFFSET_SIG1] = slp_buf->data[PI_SLP_OFFSET_SIG2]; + slp_buf->data[PI_SLP_OFFSET_SIG2] = slp_buf->data[PI_SLP_OFFSET_SIG3]; + expect = 1; + slp_buf->used = 2; + LOG((PI_DBG_SLP, PI_DBG_LVL_WARN, + "SLP RX Unexpected signature" + " 0x%.2x 0x%.2x 0x%.2x\n", + b1, b2, b3)); + } + break; + + case 2: + /* Addition check sum for header */ + for (header_checksum = i = 0; i < 9; i++) + header_checksum += slp_buf->data[i]; + + /* read in the whole SLP header. */ + if (header_checksum == slp_buf->data[PI_SLP_OFFSET_SUM]) { + state++; + packet_len = get_short(&slp_buf->data[PI_SLP_OFFSET_SIZE]); + if (packet_len > (int)len) { + LOG((PI_DBG_SLP, PI_DBG_LVL_ERR, + "SLP RX Packet size exceed buffer\n")); + pi_buffer_free (slp_buf); + return pi_set_error(ps->sd, PI_ERR_PROT_BADPACKET); + } + expect = packet_len; + } else { + LOG((PI_DBG_SLP, PI_DBG_LVL_WARN, + "SLP RX Header checksum failed for header:\n")); + pi_dumpdata((const char *)slp_buf->data, PI_SLP_HEADER_LEN); + pi_buffer_free (slp_buf); + return 0; + } + break; + + case 3: + state++; + expect = PI_SLP_FOOTER_LEN; + break; + + case 4: + /* that should be the whole packet. */ + computed_crc = crc16(slp_buf->data, PI_SLP_HEADER_LEN + packet_len); + received_crc = get_short(&slp_buf->data[PI_SLP_HEADER_LEN + packet_len]); + if (get_byte(&slp_buf->data[PI_SLP_OFFSET_TYPE]) == PI_SLP_TYPE_LOOP) { + /* Adjust because every tenth loopback + * packet has a bogus check sum */ + if (computed_crc != received_crc) + computed_crc |= 0x00e0; + } + if (computed_crc != received_crc) { + LOG((PI_DBG_SLP, PI_DBG_LVL_ERR, + "SLP RX packet crc failed: " + "computed=0x%.4x received=0x%.4x\n", + computed_crc, received_crc)); + pi_buffer_free (slp_buf); + return 0; + } + + /* Track the info so getsockopt will work */ + data->last_dest = get_byte(&slp_buf->data[PI_SLP_OFFSET_DEST]); + data->last_src = get_byte(&slp_buf->data[PI_SLP_OFFSET_SRC]); + data->last_type = get_byte(&slp_buf->data[PI_SLP_OFFSET_TYPE]); + data->last_txid = get_byte(&slp_buf->data[PI_SLP_OFFSET_TXID]); + + CHECK(PI_DBG_SLP, PI_DBG_LVL_INFO, slp_dump_header(slp_buf->data, 0)); + CHECK(PI_DBG_SLP, PI_DBG_LVL_DEBUG, slp_dump(slp_buf->data)); + + if (pi_buffer_append (buf, &slp_buf->data[PI_SLP_HEADER_LEN], packet_len) == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + pi_buffer_free (slp_buf); + return packet_len; + + default: + break; + } + + do { + bytes = next->read(ps, slp_buf, (size_t)expect, flags); + if (bytes < 0) { + LOG((PI_DBG_SLP, PI_DBG_LVL_ERR, + "SLP RX Read Error %d\n", + bytes)); + pi_buffer_free (slp_buf); + return bytes; + } + expect -= bytes; + } while (expect > 0); + } +} + +/*********************************************************************** + * + * Function: slp_flush + * + * Summary: Flush input and output buffers + * + * Parameters: pi_socket_t*, flags + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +static int +slp_flush(pi_socket_t *ps, int flags) +{ + pi_protocol_t *prot, + *next; + + prot = pi_protocol(ps->sd, PI_LEVEL_SLP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + next = pi_protocol_next(ps->sd, PI_LEVEL_SLP); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + return next->flush(ps, flags); +} + +/*********************************************************************** + * + * Function: slp_getsockopt + * + * Summary: get options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +slp_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len) +{ + pi_protocol_t *prot; + struct pi_slp_data *data; + + prot = pi_protocol(ps->sd, PI_LEVEL_SLP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (struct pi_slp_data *)prot->data; + + switch (option_name) { + case PI_SLP_DEST: + if (*option_len < sizeof (data->dest)) + goto error; + memcpy (option_value, &data->dest, sizeof (data->dest)); + *option_len = sizeof (data->dest); + break; + case PI_SLP_LASTDEST: + if (*option_len < sizeof (data->dest)) + goto error; + memcpy (option_value, &data->last_dest, + sizeof (data->last_dest)); + *option_len = sizeof (data->last_dest); + break; + case PI_SLP_SRC: + if (*option_len < sizeof (data->src)) + goto error; + memcpy (option_value, &data->src, + sizeof (data->src)); + *option_len = sizeof (data->src); + break; + case PI_SLP_LASTSRC: + if (*option_len < sizeof (data->last_src)) + goto error; + memcpy (option_value, &data->last_src, + sizeof (data->last_src)); + *option_len = sizeof (data->last_src); + break; + case PI_SLP_TYPE: + if (*option_len < sizeof (data->type)) + goto error; + memcpy (option_value, &data->type, + sizeof (data->type)); + *option_len = sizeof (data->type); + break; + case PI_SLP_LASTTYPE: + if (*option_len < sizeof (data->last_type)) + goto error; + memcpy (option_value, &data->last_type, + sizeof (data->last_type)); + *option_len = sizeof (data->last_type); + break; + case PI_SLP_TXID: + if (*option_len < sizeof (data->txid)) + goto error; + memcpy (option_value, &data->txid, + sizeof (data->txid)); + *option_len = sizeof (data->txid); + break; + case PI_SLP_LASTTXID: + if (*option_len < sizeof (data->last_txid)) + goto error; + memcpy (option_value, &data->last_txid, + sizeof (data->last_txid)); + *option_len = sizeof (data->last_txid); + break; + } + + return 0; + + error: + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); +} + + +/*********************************************************************** + * + * Function: slp_setsockopt + * + * Summary: set options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +slp_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len) +{ + pi_protocol_t *prot; + struct pi_slp_data *data; + + prot = pi_protocol(ps->sd, PI_LEVEL_SLP); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + data = (struct pi_slp_data *)prot->data; + + switch (option_name) { + case PI_SLP_DEST: + if (*option_len != sizeof (data->dest)) + goto error; + memcpy (&data->dest, option_value, + sizeof (data->dest)); + *option_len = sizeof (data->dest); + break; + case PI_SLP_SRC: + if (*option_len != sizeof (data->src)) + goto error; + memcpy (&data->src, option_value, + sizeof (data->src)); + *option_len = sizeof (data->src); + break; + case PI_SLP_TYPE: + if (*option_len != sizeof (data->type)) + goto error; + memcpy (&data->type, option_value, + sizeof (data->type)); + *option_len = sizeof (data->type); + break; + case PI_SLP_TXID: + if (*option_len != sizeof (data->txid)) + goto error; + memcpy (&data->txid, option_value, + sizeof (data->txid)); + *option_len = sizeof (data->txid); + break; + } + + return 0; + + error: + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); +} + + +/*********************************************************************** + * + * Function: slp_dump_header + * + * Summary: Dump the contents of the SPL frame header + * + * Parameters: char* to data buffer, RXTX flag + * + * Returns: void + * + ***********************************************************************/ +void +slp_dump_header(const unsigned char *data, int rxtx) +{ + LOG((PI_DBG_SLP, PI_DBG_LVL_NONE, + "SLP %s %d->%d type=%d txid=0x%.2x len=0x%.4x checksum=0x%.2x\n", + rxtx ? "TX" : "RX", + get_byte(&data[PI_SLP_OFFSET_DEST]), + get_byte(&data[PI_SLP_OFFSET_SRC]), + get_byte(&data[PI_SLP_OFFSET_TYPE]), + get_byte(&data[PI_SLP_OFFSET_TXID]), + get_short(&data[PI_SLP_OFFSET_SIZE]), + get_byte(&data[PI_SLP_OFFSET_SUM]))); +} + + +/*********************************************************************** + * + * Function: slp_dump + * + * Summary: Dump the contents of the SPL frame + * + * Parameters: char* to data buffer + * + * Returns: void + * + ***********************************************************************/ +void +slp_dump(const unsigned char *data) +{ + pi_dumpdata((char *)&data[PI_SLP_HEADER_LEN], get_short(&data[PI_SLP_OFFSET_SIZE])); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/socket.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/socket.c new file mode 100644 index 00000000..2f877448 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/socket.c @@ -0,0 +1,1694 @@ +/* + * $Id: socket.c,v 1.118 2006/11/07 21:13:24 adridg Exp $ + * + * socket.c: Berkeley sockets style interface to Pilot + * + * Copyright (c) 1996, D. Jeff Dionne. + * Copyright (c) 1997-1999, Kenneth Albanowski + * Copyright (c) 1999, Tilo Christ + * Copyright (c) 2000-2001, JP Rosevear + * Copyright (c) 2004-2005, Florent Pillet + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + * + * -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <fcntl.h> +#include <string.h> + +#include "pi-source.h" +#include "pi-serial.h" +#ifdef HAVE_USB +#include "pi-usb.h" +#endif +#include "pi-bluetooth.h" +#include "pi-inet.h" +#include "pi-slp.h" +#include "pi-sys.h" +#include "pi-padp.h" +#include "pi-cmp.h" +#include "pi-net.h" +#include "pi-dlp.h" +#include "pi-syspkt.h" +#include "pi-debug.h" +#include "pi-error.h" +#include "pi-threadsafe.h" + +/* Declare function prototypes */ +static pi_socket_list_t *ps_list_append (pi_socket_list_t *list, + pi_socket_t *ps); +static pi_socket_t *ps_list_find (pi_socket_list_t *list, + int pi_sd); +static pi_socket_list_t *ps_list_remove (pi_socket_list_t *list, + int pi_sd); +static pi_socket_list_t *ps_list_copy (pi_socket_list_t *list); +static void ps_list_free (pi_socket_list_t *list); + +static void protocol_queue_add (pi_socket_t *ps, pi_protocol_t *prot); +static void protocol_cmd_queue_add (pi_socket_t *ps, pi_protocol_t *prot); +static pi_protocol_t *protocol_queue_find (pi_socket_t *ps, int level); +static pi_protocol_t *protocol_queue_find_next (pi_socket_t *ps, int level); + +int pi_socket_init(pi_socket_t *ps); + +static int is_connected (pi_socket_t *ps); +static int is_listener (pi_socket_t *ps); + +/* GLOBALS */ +static PI_MUTEX_DEFINE(psl_mutex); +static pi_socket_list_t *psl = NULL; + +static PI_MUTEX_DEFINE(watch_list_mutex); +static pi_socket_list_t *watch_list = NULL; + +/* Automated tickling interval */ +static unsigned int interval = 0; + +/* Indicates that the exit function has already been installed. Made non-static + * so that library users can choose to not have an exit function installed */ +int pi_sock_installedexit = 0; + +/* Linked List Code */ +/*********************************************************************** + * + * Function: ps_list_dump + * + * Summary: internal debugging function + * + * Parameters: pi_socket_list_t * + * + * Returns: void + * + ***********************************************************************/ +#if 0 +static void +ps_list_dump (pi_socket_list_t *list) +{ + fprintf(stderr, "* Dumping pi_socket_list @ %p:\n",(void*)list); + while (list != NULL) { + fprintf(stderr," %p: ps=%p, pi_sd=%d\n", (void*)list, (void*)list->ps, list->ps->sd); + list = list->next; + } +} +#endif + +/*********************************************************************** + * + * Function: ps_list_append + * + * Summary: creates and appends a new pi_socket_list element to + * the (possibly empty) pi_socket_list and fills in the + * pi_socket_t* member to point to the given pi_socket. + * + * Parameters: pi_socket_list_t*, pi_socket_t* + * + * Returns: pi_socket_list_t*, or NULL if operation failed + * + ***********************************************************************/ +static pi_socket_list_t * +ps_list_append (pi_socket_list_t *list, pi_socket_t *ps) +{ + pi_socket_list_t *elem, *new_elem; + + ASSERT (ps != NULL); + + new_elem = (pi_socket_list_t *) malloc (sizeof(pi_socket_list_t)); + if (new_elem == NULL) + return list; + + new_elem->ps = ps; + new_elem->next = NULL; + + if (list == NULL) + return new_elem; + + elem = list; + while (elem->next != NULL) + elem = elem->next; + elem->next = new_elem; + + return list; +} + + +/*********************************************************************** + * + * Function: ps_list_find + * + * Summary: traverse a (possibly empty) pi_socket_list and find + * the first list element whose pi_socket_t* member points + * to a pi_socket matching the given socket descriptor + * + * Parameters: pi_socket_list_t *, socket descriptor + * + * Returns: pi_socket_t *, or NULL if no match + * + * NOTE: ps_list_find returns a pointer which points directly to + * the socket (pi_socket_t *) whereas ps_find_elem returns a + * pointer to the list element (pi_socket_list_t *) which + * _contains_ a pointer to the socket + * + ***********************************************************************/ +static pi_socket_t * +ps_list_find (pi_socket_list_t *list, int pi_sd) +{ + pi_socket_list_t *elem; + + for (elem = list; elem != NULL; elem = elem->next) + if (elem->ps != NULL && elem->ps->sd == pi_sd) + return elem->ps; + + return NULL; +} + + +/*********************************************************************** + * + * Function: ps_list_remove + * + * Summary: remove first pi_socket_list element pointing to a pi_socket + * member matching socket descriptor + * + * Parameters: pi_socket_list_t *, socket descriptor + * + * Returns: the (possibly NULL) head pi_socket_list_t * + * + * NOTE: only the pi_socket_list element is freed, + * _not_ the pi_socket. Consequently, this function + * makes the (risky) assumption that the pi_socket will + * be freed elsewhere. + * + ***********************************************************************/ +static pi_socket_list_t * +ps_list_remove (pi_socket_list_t *list, int pi_sd) +{ + pi_socket_list_t *elem, + *new_list = list, + *prev_elem = NULL; + + for (elem = list; elem != NULL; elem = elem->next) { + if (elem->ps == NULL) + continue; + else if (elem->ps->sd == pi_sd) { + if (prev_elem == NULL) + new_list = elem->next; + else + prev_elem->next = elem->next; + free(elem); + break; + } + prev_elem = elem; + } + + return new_list; +} + + +/*********************************************************************** + * + * Function: ps_list_copy + * + * Summary: copy pi_socket_list + * + * Parameters: pi_socket_list_t * + * + * Returns: pi_socket_list_t* (new list head) + * + * NOTE: pi_list_copy does _not_ copy the pi_socket member, it + * copies only the list elements + * + ***********************************************************************/ +static pi_socket_list_t * +ps_list_copy (pi_socket_list_t *list) +{ + pi_socket_list_t *l, *new_list = NULL; + + for (l = list; l != NULL; l = l->next) + new_list = ps_list_append (new_list, l->ps); + + return new_list; +} + + +/*********************************************************************** + * + * Function: ps_list_free + * + * Summary: free pi_socket_list elements + * + * Parameters: pi_socket_list_t * + * + * Returns: void + * + * NOTE: only the pi_socket_list elements are freed, + * _not_ the pi_sockets. Consequently, this function + * makes the (risky) assumption that the pi_sockets will + * be freed elsewhere. + * + ***********************************************************************/ +static void +ps_list_free (pi_socket_list_t *list) +{ + pi_socket_list_t *l, *next; + + if (list == NULL) + return; + + l = list; + do { + next = l->next; + free(l); + l = next; + } while (l != NULL); +} + +/* Protocol Queue */ +/*********************************************************************** + * + * Function: protocol_queue_add + * + * Summary: adds protocol queue to pi_socket + * + * Parameters: pi_socket_t*, pi_protocol_t* + * + * Returns: void + * + ***********************************************************************/ +static void +protocol_queue_add (pi_socket_t *ps, pi_protocol_t *prot) +{ + ps->protocol_queue = realloc(ps->protocol_queue, + (sizeof(pi_protocol_t *)) * (ps->queue_len + 1)); + if (ps->protocol_queue != NULL) { + ps->protocol_queue[ps->queue_len] = prot; + ps->queue_len++; + } else { + errno = ENOMEM; + ps->queue_len = 0; + } +} + + +/*********************************************************************** + * + * Function: cmd_queue_add + * + * Summary: adds command queue to pi_socket + * + * Parameters: pi_socket_t*, pi_protocol* + * + * Returns: void + * + ***********************************************************************/ +static void +protocol_cmd_queue_add (pi_socket_t *ps, pi_protocol_t *prot) +{ + ps->cmd_queue = realloc(ps->cmd_queue, + (sizeof(pi_protocol_t *)) * (ps->cmd_len + 1)); + if (ps->cmd_queue != NULL) { + ps->cmd_queue[ps->cmd_len] = prot; + ps->cmd_len++; + } else { + errno = ENOMEM; + ps->cmd_len = 0; + } +} + + +/*********************************************************************** + * + * Function: protocol_queue_find + * + * Summary: find queue entry + * + * Parameters: pi_socket_t*, level + * + * Returns: pi_protocol*, or NULL if queue entry not found + * + ***********************************************************************/ +static pi_protocol_t* +protocol_queue_find (pi_socket_t *ps, int level) +{ + int i; + + if (ps->command) { + for (i = 0; i < ps->cmd_len; i++) { + if (ps->cmd_queue[i]->level == level) + return ps->cmd_queue[i]; + } + } else { + for (i = 0; i < ps->queue_len; i++) { + if (ps->protocol_queue[i]->level == level) + return ps->protocol_queue[i]; + } + } + + return NULL; +} + + +/*********************************************************************** + * + * Function: protocol_queue_find_next + * + * Summary: find next queue entry + * + * Parameters: pi_socket*, level + * + * Returns: pi_protocol_t* or NULL if next queue entry not found + * + ***********************************************************************/ +static pi_protocol_t* +protocol_queue_find_next (pi_socket_t *ps, int level) +{ + int i; + + if (ps->command && ps->cmd_len == 0) + return NULL; + + if (!ps->command && ps->queue_len == 0) + return NULL; + + if (ps->command && level == 0) + return ps->cmd_queue[0]; + + if (!ps->command && level == 0) + return ps->protocol_queue[0]; + + if (ps->command) { + for (i = 0; i < ps->cmd_len - 1; i++) { + if (ps->cmd_queue[i]->level == level) + return ps->cmd_queue[i + 1]; + } + } else { + for (i = 0; i < ps->queue_len - 1; i++) { + if (ps->protocol_queue[i]->level == level) + return ps->protocol_queue[i + 1]; + } + } + + return NULL; +} + + +/*********************************************************************** + * + * Function: protocol_queue_build + * + * Summary: build protocol queue + * + * Parameters: pi_socket_t*, autodetect + * + * Returns: void + * + ***********************************************************************/ +static void +protocol_queue_build (pi_socket_t *ps, int autodetect) +{ + int protocol, + result; + pi_protocol_t + *dev_prot, + *dev_cmd_prot; + + LOG((PI_DBG_SOCK,PI_DBG_LVL_DEBUG, "SOCK fd=%d auto=%d\n",ps->sd,autodetect)); + + /* The device protocol */ + dev_prot = ps->device->protocol (ps->device); + dev_cmd_prot = ps->device->protocol (ps->device); + + /* When opening the device in RAW mode, we stay low-level */ + if (ps->type == PI_SOCK_RAW) { + LOG((PI_DBG_SOCK,PI_DBG_LVL_DEBUG, "RAW mode, no protocol\n",ps->sd,autodetect)); + protocol_queue_add (ps, dev_prot); + protocol_cmd_queue_add (ps, dev_cmd_prot); + return; + } + + protocol = ps->protocol; + + LOG((PI_DBG_SOCK,PI_DBG_LVL_DEBUG, "SOCK proto=%s (%d)\n", + protocol == PI_PF_DEV ? "DEV" : + protocol == PI_PF_SLP ? "SLP" : + protocol == PI_PF_SYS ? "SYS" : + protocol == PI_PF_PADP? "PADP" : + protocol == PI_PF_NET ? "NET" : + protocol == PI_PF_DLP ? "DLP" : + "unknown", protocol)); + + if (protocol == PI_PF_DLP && autodetect) { + int skipped_bytes = 0, + bytes_to_skip; + pi_buffer_t + *detect_buf = pi_buffer_new(64); + + for (;;) { + /* try to peek a header start from the input sent by the device */ + result = dev_prot->read (ps, detect_buf, 10, PI_MSG_PEEK); + if (result < 0) + break; + if (result != 10) { + pi_buffer_clear(detect_buf); + continue; + } + + bytes_to_skip = 1; + + /* detect a valid PADP header packet */ + if (detect_buf->data[0] == PI_SLP_SIG_BYTE1 && + detect_buf->data[1] == PI_SLP_SIG_BYTE2 && + detect_buf->data[2] == PI_SLP_SIG_BYTE3) + { + /* compute the checksum */ + int i; + unsigned char header_checksum; + for (header_checksum = i = 0; i < 9; i++) + header_checksum += detect_buf->data[i]; + + if (header_checksum == detect_buf->data[9]) { /* sum */ + if (detect_buf->data[3] == PI_SLP_SOCK_DLP && /* src */ + detect_buf->data[4] == PI_SLP_SOCK_DLP && /* dest */ + detect_buf->data[5] == PI_SLP_TYPE_PADP && /* type */ + detect_buf->data[8] == 0xff) /* txid */ + { + protocol = PI_PF_PADP; + LOG((PI_DBG_SOCK, PI_DBG_LVL_INFO, + "\nusing PADP/SLP protocol (skipped %d bytes)\n", + skipped_bytes)); + break; + } + else { + /* valid but not what we're looking for, skip it altogether */ + bytes_to_skip = 10; + } + } else { + /* skip the SLP SIG bytes */ + bytes_to_skip = 3; + } + } + + /* detect NET header packets */ + else if (detect_buf->data[0] == 0x01 && /* NET packet */ + detect_buf->data[2] == 0x00 && /* length byte 0 */ + detect_buf->data[3] == 0x00 && /* length byte 1 */ + detect_buf->data[4] == 0x00 && /* length byte 2 */ + detect_buf->data[5] > 0 && /* length byte 3 */ + detect_buf->data[6] == 0x90) /* PI_NET_SIG_BYTE1 */ + { + protocol = PI_PF_NET; + LOG((PI_DBG_SOCK, PI_DBG_LVL_INFO, + "\nusing NET protocol (skipped %d bytes)\n", + skipped_bytes)); + break; + } + + /* detect NET packet for cases where we lost the first 6 bytes + * (this unfortunately happens on Linux with unixserial, and the + * correct way to cope with this is to recognize the second + * part of the NET handshake packet) + */ + else if (detect_buf->data[0] == 0x90 && /* PI_NET_SIG_BYTE1 */ + detect_buf->data[1] == 0x01 && + detect_buf->data[2] == 0x00 && + detect_buf->data[3] == 0x00 && + detect_buf->data[4] == 0x00 && + detect_buf->data[5] == 0x00 && + detect_buf->data[6] == 0x00 && + detect_buf->data[7] == 0x00 && + detect_buf->data[8] == 0x00 && + detect_buf->data[9] == 0x20) + { + protocol = PI_PF_NET; + LOG((PI_DBG_SOCK, PI_DBG_LVL_INFO, + "\nusing NET protocol (skipped %d bytes)\n", + skipped_bytes)); + break; + } + + /* eliminate one byte from the input, trying to frame a proper header */ + result = dev_prot->read (ps, detect_buf, bytes_to_skip, 0); + if (result < 0) + break; + skipped_bytes += bytes_to_skip; + pi_buffer_clear(detect_buf); + } + + pi_buffer_free(detect_buf); + + if (result < 0) { + /* if there was an error (i.e. disconnect), temporarily fallback + * on PADP protocol. In further releases, we should really make + * this function return an error if there was a problem. -- fpillet + */ + LOG((PI_DBG_SOCK, PI_DBG_LVL_DEBUG, + "Error: last read returned %d; switching to PADP by default\n", + result)); + protocol = PI_PF_PADP; + } + + } else if (protocol == PI_PF_DLP) { + protocol = PI_PF_PADP; + } + + /* The connected protocol queue */ + switch (protocol) { + case PI_PF_PADP: + protocol_queue_add (ps, padp_protocol ()); + case PI_PF_SLP: + protocol_queue_add (ps, slp_protocol ()); + break; + case PI_PF_NET: + protocol_queue_add (ps, net_protocol ()); + break; + case PI_PF_SYS: + protocol_queue_add (ps, sys_protocol ()); + protocol_queue_add (ps, slp_protocol ()); + break; + } + + /* The command protocol queue */ + switch (protocol) { + case PI_PF_PADP: + case PI_PF_SLP: + protocol_cmd_queue_add (ps, cmp_protocol ()); + protocol_cmd_queue_add (ps, padp_protocol ()); + protocol_cmd_queue_add (ps, slp_protocol ()); + ps->cmd = PI_CMD_CMP; + break; + case PI_PF_NET: + protocol_cmd_queue_add (ps, net_protocol ()); + ps->cmd = PI_CMD_NET; + break; + case PI_PF_SYS: + ps->cmd = PI_CMD_SYS; + break; + default: + LOG((PI_DBG_SOCK, PI_DBG_LVL_ERR, "invalid protocol (%d)", protocol)); + break; + } + + protocol_queue_add (ps, dev_prot); + protocol_cmd_queue_add (ps, dev_cmd_prot); +} + + +/*********************************************************************** + * + * Function: protocol_queue_destroy + * + * Summary: destroy protocol queue + * + * Parameters: pi_socket_t * + * + * Returns: void + * + ***********************************************************************/ +static void +protocol_queue_destroy (pi_socket_t *ps) +{ + int i; + for (i = 0; i < ps->queue_len; i++) + ps->protocol_queue[i]->free(ps->protocol_queue[i]); + for (i = 0; i < ps->cmd_len; i++) + ps->cmd_queue[i]->free(ps->cmd_queue[i]); + + if (ps->queue_len > 0) + free(ps->protocol_queue); + if (ps->cmd_len > 0) + free(ps->cmd_queue); +} + + +/*********************************************************************** + * + * Function: pi_protocol + * + * Summary: destroy protocol queue + * + * Parameters: socket descriptor, level + * + * Returns: pi_protocol_t* + * + ***********************************************************************/ +pi_protocol_t * +pi_protocol (int pi_sd, int level) +{ + pi_socket_t *ps; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return NULL; + } + + return protocol_queue_find(ps, level); +} + +pi_protocol_t * +pi_protocol_next (int pi_sd, int level) +{ + pi_socket_t *ps; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return NULL; + } + + return protocol_queue_find_next(ps, level); +} + + +/* Environment Code */ +/*********************************************************************** + * + * Function: env_check + * + * Summary: configures Pilot-Link debug environment + * + * Parameters: void + * + * Returns: void + * + ***********************************************************************/ +static void +env_dbgcheck (void) +{ + if (getenv("PILOT_DEBUG")) { + int types = 0, + done; + char *debug, + *b, + *e; + + debug = strdup(getenv("PILOT_DEBUG")); + + b = debug; + done = 0; + while (!done) { + e = strchr(b, ' '); + if (e) + *e = '\0'; + else + done = 1; + + if (!strcmp(b, "SYS")) + types |= PI_DBG_SYS; + else if (!strcmp(b, "DEV")) + types |= PI_DBG_DEV; + else if (!strcmp(b, "SLP")) + types |= PI_DBG_SLP; + else if (!strcmp(b, "PADP")) + types |= PI_DBG_PADP; + else if (!strcmp(b, "DLP")) + types |= PI_DBG_DLP; + else if (!strcmp(b, "NET")) + types |= PI_DBG_NET; + else if (!strcmp(b, "CMP")) + types |= PI_DBG_CMP; + else if (!strcmp(b, "SOCK")) + types |= PI_DBG_SOCK; + else if (!strcmp(b, "API")) + types |= PI_DBG_API; + else if (!strcmp(b, "USER")) + types |= PI_DBG_USER; + else if (!strcmp(b, "ALL")) + types |= PI_DBG_ALL; + e++; + b = e; + } + pi_debug_set_types(types); + + free(debug); + } + + /* PILOT Debug Level */ + if (getenv("PILOT_DEBUG_LEVEL")) { + int level = 0; + const char *debug; + + + debug = getenv("PILOT_DEBUG_LEVEL"); + if (!strcmp(debug, "NONE")) + level |= PI_DBG_LVL_NONE; + else if (!strcmp(debug, "ERR")) + level |= PI_DBG_LVL_ERR; + else if (!strcmp(debug, "WARN")) + level |= PI_DBG_LVL_WARN; + else if (!strcmp(debug, "INFO")) + level |= PI_DBG_LVL_INFO; + else if (!strcmp(debug, "DEBUG")) + level |= PI_DBG_LVL_DEBUG; + + pi_debug_set_level (level); + } + + /* log file name */ + if (getenv("PILOT_LOG") && atoi(getenv("PILOT_LOG"))) { + const char *logfile; + + logfile = getenv("PILOT_LOGFILE"); + if (logfile == NULL) + pi_debug_set_file("pilot-link.debug"); + else + pi_debug_set_file(logfile); + } +} + +/* Util functions */ +/*********************************************************************** + * + * Function: is_connected + * + * Summary: interrogate socket connection state + * + * Parameters: pi_socket* + * + * Returns: 1 if socket is connected, 0 otherwise + * + ***********************************************************************/ +static int +is_connected (pi_socket_t *ps) +{ + return (ps->state == PI_SOCK_CONN_INIT || ps->state == PI_SOCK_CONN_ACCEPT) ? 1 : 0; +} + +/*********************************************************************** + * + * Function: is_listener + * + * Summary: interrogate socket listener state + * + * Parameters: pi_socket* + * + * Returns: 1 if socket is listener, 0 otherwise + * + ***********************************************************************/ +static int +is_listener (pi_socket_t *ps) +{ + return (ps->state == PI_SOCK_LISTEN) ? 1 : 0; +} + +/* Alarm Handling Code */ +static RETSIGTYPE +onalarm(int signo) +{ + pi_socket_list_t *l; + + signal(signo, onalarm); + + pi_mutex_lock(&watch_list_mutex); + + for (l = watch_list; l != NULL; l = l->next) { + pi_socket_t *ps = l->ps; + + if (!is_connected(ps)) + continue; + + if (pi_tickle(ps->sd) < 0) { + LOG((PI_DBG_SOCK, PI_DBG_LVL_INFO, + "SOCKET Socket %d is busy during tickle\n", + ps->sd)); + alarm(1); + } else { + LOG((PI_DBG_SOCK, PI_DBG_LVL_INFO, + "SOCKET Tickling socket %d\n", ps->sd)); + alarm(interval); + } + } + + pi_mutex_unlock(&watch_list_mutex); +} + +/* Exit Handling Code */ +/*********************************************************************** + * + * Function: onexit + * + * Summary: this function closes and destroys all pi_sockets and + * frees the global pi_socket_list + * + * Parameters: void + * + * Returns: void + * + ***********************************************************************/ +static void +onexit(void) +{ + pi_socket_list_t *l, + *list; + + pi_mutex_lock(&psl_mutex); + list = ps_list_copy (psl); + pi_mutex_unlock(&psl_mutex); + + for (l = list; l != NULL; l = l->next) + pi_close(l->ps->sd); + + ps_list_free (list); +} + + +/*********************************************************************** + * + * Function: installexit + * + * Summary: install exit function using atexit() + * + * Parameters: void + * + * Returns: void + * + ***********************************************************************/ +static void +installexit(void) +{ + if (!pi_sock_installedexit) { + atexit(onexit); + pi_sock_installedexit = 1; + } +} + +int +pi_socket(int domain, int type, int protocol) +{ + pi_socket_t *ps; + pi_socket_list_t *list; + + env_dbgcheck (); + + if (protocol == 0) { + if (type == PI_SOCK_STREAM) + protocol = PI_PF_DLP; + else if (type == PI_SOCK_RAW) + protocol = PI_PF_DEV; + } + + ps = calloc(1, sizeof(pi_socket_t)); + if (ps == NULL) { + errno = ENOMEM; + return -1; + } + + /* Create unique socket descriptor */ + if ((ps->sd = open(NULL_DEVICE, O_RDWR)) == -1) { + int err = errno; /* Save errno of open */ + + free(ps); + errno = err; + return -1; + } + + /* Initialize the rest of the fields (calloc zeroes out + all the fields we don't touch) */ + ps->type = type; + ps->protocol = protocol; + ps->state = PI_SOCK_CLOSE; + ps->honor_rx_to = 1; + ps->command = 1; + + /* post the new socket to the list */ + list = pi_socket_recognize(ps); + if (list == NULL) { + close (ps->sd); + free(ps); + errno = ENOMEM; + return -1; + } + + installexit(); + return ps->sd; +} + +int +pi_socket_setsd(pi_socket_t *ps, int pi_sd) +{ +#ifdef HAVE_DUP2 + ps->sd = dup2(pi_sd, ps->sd); +#else + close(ps->sd); + #ifdef F_DUPFD + ps->sd = fcntl(pi_sd, F_DUPFD, ps->sd); + #else + ps->sd = dup(pi_sd); + #endif +#endif + if (ps->sd == -1) + return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + if (ps->sd != pi_sd) + close(pi_sd); + return 0; +} + + +/*********************************************************************** + * + * Function: pi_socket_init + * + * Summary: inits the pi_socket + * + * Parameters: pi_socket_t* + * + * Returns: 0 + * + ***********************************************************************/ +int +pi_socket_init(pi_socket_t *ps) +{ + protocol_queue_build (ps, 1); + return 0; +} + + +/*********************************************************************** + * + * Function: pi_socket_recognize + * + * Summary: appends the pi_socket to global list + * + * Parameters: pi_socket* + * + * Returns: pi_socket_list_t * + * + ***********************************************************************/ +pi_socket_list_t * +pi_socket_recognize(pi_socket_t *ps) +{ + pi_mutex_lock(&psl_mutex); + psl = ps_list_append(psl, ps); + pi_mutex_unlock(&psl_mutex); + return psl; +} + +/*********************************************************************** + * + * Function: pi_devsocket (static) + * + * Summary: Looks up a socket and creates a new device + * FIXME: Decide whether or not to create the socket here + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +static pi_socket_t * +pi_devsocket(int pi_sd, const char *port, struct pi_sockaddr *addr) +{ + pi_socket_t *ps; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return NULL; + } + + if (port == NULL && (port = getenv("PILOTPORT")) == NULL) { + errno = ENXIO; + return NULL; + } + + /* Create the device and sockaddr */ + addr->pi_family = PI_AF_PILOT; + if (!strncmp (port, "serial:", 7)) { + strncpy(addr->pi_device, port + 7, sizeof(addr->pi_device)); + ps->device = pi_serial_device (PI_SERIAL_DEV); +#ifdef HAVE_USB + } else if (!strncmp (port, "usb:", 4)) { + strncpy(addr->pi_device, port + 4, sizeof(addr->pi_device)); + ps->device = pi_usb_device (PI_USB_DEV); +#endif + } else if (!strncmp (port, "net:", 4)) { + strncpy(addr->pi_device, port + 4, sizeof(addr->pi_device)); + ps->device = pi_inet_device (PI_NET_DEV); +#ifdef HAVE_BLUEZ + } else if (!strncmp (port, "bluetooth:", 10) || !strncmp (port, "bt:", 3)) { + strncpy(addr->pi_device, strchr(port, ':') + 1, sizeof(addr->pi_device)); + ps->device = pi_bluetooth_device (PI_BLUETOOTH_DEV); +#endif + } else { + /* No prefix assumed to be serial: (for compatibility) */ + strncpy(addr->pi_device, port, sizeof(addr->pi_device)); + ps->device = pi_serial_device (PI_SERIAL_DEV); + } + + return ps; +} + +int +pi_connect(int pi_sd, const char *port) +{ + pi_socket_t *ps; + struct pi_sockaddr addr; + int result; + + ps = pi_devsocket(pi_sd, port, &addr); + if (!ps) + return PI_ERR_SOCK_INVALID; + + /* Build the protocol queue */ + protocol_queue_build (ps, 0); + + result = ps->device->connect (ps, (struct sockaddr *)&addr, sizeof(addr)); + if (result < 0) + pi_close(pi_sd); + + return result; +} + +int +pi_bind(int pi_sd, const char *port) +{ + int bind_return; + pi_socket_t *ps; + struct pi_sockaddr addr; + + ps = pi_devsocket(pi_sd, port, &addr); + if (!ps) + return PI_ERR_SOCK_INVALID; + + bind_return = + ps->device->bind (ps, (struct sockaddr *)&addr, sizeof(addr)); + if (bind_return < 0) { + ps->device->free (ps->device); + ps->device = NULL; + + } + return bind_return; +} + +int +pi_listen(int pi_sd, int backlog) +{ + pi_socket_t *ps; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + return ps->device->listen (ps, backlog); +} + +int +pi_accept(int pi_sd, struct sockaddr *addr, size_t *addrlen) +{ + return pi_accept_to(pi_sd, addr, addrlen, 0); +} + +int +pi_accept_to(int pi_sd, struct sockaddr *addr, size_t *addrlen, int timeout) +{ + pi_socket_t *ps; + int result; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + if (!is_listener (ps)) + return PI_ERR_SOCK_LISTENER; + + ps->accept_to = timeout; + + result = ps->device->accept(ps, addr, addrlen); + if (result < 0) { + LOG((PI_DBG_SOCK, PI_DBG_LVL_DEBUG, + "pi_accept_to: ps->device->accept returned %d, calling pi_close()\n", + result)); + pi_close(pi_sd); + } + + return result; +} + +int +pi_getsockopt(int pi_sd, int level, int option_name, + void *option_value, size_t *option_len) +{ + pi_socket_t *ps; + pi_protocol_t *prot; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + /* handle getsockopt at socket level */ + if (level == PI_LEVEL_SOCK) { + switch (option_name) { + case PI_SOCK_STATE: + if (*option_len != sizeof (ps->state)) + goto argerr; + memcpy (option_value, &ps->state, sizeof (ps->state)); + break; + + case PI_SOCK_HONOR_RX_TIMEOUT: + if (*option_len != sizeof (ps->honor_rx_to)) + goto argerr; + memcpy (option_value, &ps->honor_rx_to, sizeof (ps->honor_rx_to)); + break; + + default: + goto argerr; + } + return 0; + } + + /* find the protocol at the requested level and forward it the getsockopt request */ + prot = protocol_queue_find (ps, level); + + if (prot == NULL || prot->level != level) { + errno = EINVAL; + return pi_set_error(pi_sd, PI_ERR_SOCK_INVALID); + } + + return prot->getsockopt (ps, level, option_name, option_value, option_len); + +argerr: + errno = EINVAL; + return pi_set_error(pi_sd, PI_ERR_GENERIC_ARGUMENT); +} + +int +pi_setsockopt(int pi_sd, int level, int option_name, + const void *option_value, size_t *option_len) +{ + pi_socket_t *ps; + pi_protocol_t *prot; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + /* handle setsockopt at socket level */ + if (level == PI_LEVEL_SOCK) { + switch (option_name) { + case PI_SOCK_STATE: + if (*option_len != sizeof (ps->state)) + goto argerr; + memcpy (&ps->state, option_value, sizeof (ps->state)); + break; + + case PI_SOCK_HONOR_RX_TIMEOUT: + if (*option_len != sizeof (ps->honor_rx_to)) + goto argerr; + memcpy (&ps->honor_rx_to, option_value, sizeof (ps->honor_rx_to)); + break; + + default: + goto argerr; + } + return 0; + } + + /* find the protocol at the requested level and forward it the setsockopt request */ + prot = protocol_queue_find (ps, level); + + if (prot == NULL || prot->level != level) { + errno = EINVAL; + return PI_ERR_SOCK_INVALID; + } + + return prot->setsockopt (ps, level, option_name, option_value, option_len); + +argerr: + errno = EINVAL; + return pi_set_error(pi_sd, PI_ERR_GENERIC_ARGUMENT); +} + +/*********************************************************************** + * + * Function: pi_send + * + * Summary: Send message on a connected socket + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +pi_send(int pi_sd, const void *msg, size_t len, int flags) +{ + pi_socket_t *ps; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + if (!is_connected (ps)) + return PI_ERR_SOCK_DISCONNECTED; + + if (interval) + alarm(interval); + + return ps->protocol_queue[0]->write (ps, (void *)msg, len, flags); +} + +/*********************************************************************** + * + * Function: pi_recv + * + * Summary: Receive msg on a connected socket + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +ssize_t +pi_recv(int pi_sd, pi_buffer_t *msg, size_t len, int flags) +{ + pi_socket_t *ps; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + if (!is_connected (ps)) + return PI_ERR_SOCK_DISCONNECTED; + + return ps->protocol_queue[0]->read (ps, msg, len, flags); +} + +/*********************************************************************** + * + * Function: pi_read + * + * Summary: Wrapper for receive + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +ssize_t +pi_read(int pi_sd, pi_buffer_t *msg, size_t len) +{ + return pi_recv(pi_sd, msg, len, 0); +} + +/*********************************************************************** + * + * Function: pi_write + * + * Summary: Wrapper for send + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +ssize_t +pi_write(int pi_sd, const void *msg, size_t len) +{ + return pi_send(pi_sd, msg, len, 0); +} + +void +pi_flush(int pi_sd, int flags) +{ + pi_socket_t *ps; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return; + } + + if (!is_connected (ps)) + return; + + ps->protocol_queue[0]->flush (ps, flags); +} + +int +pi_tickle(int pi_sd) +{ + int result=0, + type, + oldtype; + size_t len = 0, + size; + unsigned char msg[1]; + pi_socket_t *ps; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + if (!is_connected (ps)) + return PI_ERR_SOCK_DISCONNECTED; + + LOG((PI_DBG_SOCK, PI_DBG_LVL_INFO, + "SOCKET Tickling socket %d\n", pi_sd)); + + switch (ps->cmd) { + case PI_CMD_CMP: + /* save previous packet type */ + size = sizeof(type); + pi_getsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_TYPE, &oldtype, &size); + + /* set packet type to "tickle" */ + type = padTickle; + size = sizeof(type); + pi_setsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_TYPE, &type, &size); + + /* send packet */ + result = ps->protocol_queue[0]->write (ps, msg, len, 0); + + /* restore previous packet type */ + size = sizeof(type); + pi_setsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_TYPE, &oldtype, &size); + break; + + case PI_CMD_NET: + /* Enter command state */ + ps->command = 1; + + /* Set the type to "tickle" */ + type = PI_NET_TYPE_TCKL; + size = sizeof(type); + pi_setsockopt(ps->sd, PI_LEVEL_NET, PI_NET_TYPE, &type, &size); + + /* send packet */ + result = ps->cmd_queue[0]->write (ps, msg, len, 0); + + /* Exit command state */ + ps->command = 0; + break; + } + + return result; +} + +int +pi_close(int pi_sd) +{ + int result = 0; + pi_socket_t *ps; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + if (ps->type == PI_SOCK_STREAM && ps->cmd != PI_CMD_SYS) { + if (is_connected (ps)) { + ps->command = 1; + + /* then end sync, with clean status */ + result = dlp_EndOfSync(ps->sd, 0); + + ps->command = 0; + } + } + + if (result == 0) { + /* we need to remove the entry from the list prior to + * closing it, because closing it will reset the pi_sd */ + pi_mutex_lock(&psl_mutex); + psl = ps_list_remove (psl, pi_sd); + pi_mutex_unlock(&psl_mutex); + + pi_mutex_lock(&watch_list_mutex); + watch_list = ps_list_remove (watch_list, pi_sd); + pi_mutex_unlock(&watch_list_mutex); + + if (ps->device != NULL) + result = ps->device->close (ps); + + protocol_queue_destroy(ps); + + if (ps->device != NULL) + ps->device->free(ps->device); + + if (ps->sd > 0) + close(ps->sd); + free(ps); + } + + return result; +} + + +/*********************************************************************** + * + * Function: pi_getsockname + * + * Summary: Get the local address for a socket + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +pi_getsockname(int pi_sd, struct sockaddr *addr, size_t *namelen) +{ + pi_socket_t *ps; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + if (*namelen > ps->laddrlen) + *namelen = ps->laddrlen; + memcpy(addr, &ps->laddr, *namelen); + + return 0; +} + + +/*********************************************************************** + * + * Function: pi_getsockpeer + * + * Summary: Get the remote address for a socket + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +pi_getsockpeer(int pi_sd, struct sockaddr *addr, size_t *namelen) +{ + pi_socket_t *ps; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + if (*namelen > ps->raddrlen) + *namelen = ps->raddrlen; + memcpy(addr, &ps->raddr, *namelen); + + return 0; +} + +int +pi_version(int pi_sd) +{ + size_t size; + pi_socket_t *ps; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + if (ps->dlpversion) + return ps->dlpversion; + + if (ps->cmd == PI_CMD_CMP) { + /* Enter command state */ + ps->command = 1; + + /* Get the version */ + size = sizeof(ps->dlpversion); + pi_getsockopt(ps->sd, PI_LEVEL_CMP, PI_CMP_VERS, &ps->dlpversion, &size); + ps->maxrecsize = DLP_BUF_SIZE; + + /* Exit command state */ + ps->command = 0; + } + + return ps->dlpversion; +} + +unsigned long +pi_maxrecsize(int pi_sd) +{ + pi_socket_t *ps; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return 0; + } + + /* pi_version will read necessary info from device */ + if (pi_version(pi_sd) == 0) + return DLP_BUF_SIZE; + + return ps->maxrecsize; +} + +/*********************************************************************** + * + * Function: find_pi_socket + * + * Summary: Thread-safe wrapper for ps_list_find + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +pi_socket_t * +find_pi_socket(int pi_sd) +{ + pi_socket_t *result; + + pi_mutex_lock(&psl_mutex); + result = ps_list_find (psl, pi_sd); + pi_mutex_unlock(&psl_mutex); + + return result; +} + +int +pi_watchdog(int pi_sd, int newinterval) +{ + pi_socket_t *ps; + + if (!(ps = find_pi_socket(pi_sd))) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + + pi_mutex_lock(&watch_list_mutex); + watch_list = ps_list_append (watch_list, ps); + pi_mutex_unlock(&watch_list_mutex); + + signal(SIGALRM, onalarm); + interval = newinterval; + alarm(interval); + + return 0; +} + +int +pi_error(int pi_sd) +{ + pi_socket_t *ps; + + if ((ps = find_pi_socket(pi_sd)) == NULL) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + return ps->last_error; +} + +int +pi_set_error(int pi_sd, int error_code) +{ + pi_socket_t *ps; + + if ((ps = find_pi_socket(pi_sd))) + ps->last_error = error_code; + else + errno = ESRCH; + + /* also update errno if makes sense */ + if (error_code == PI_ERR_GENERIC_MEMORY) + errno = ENOMEM; + + return error_code; +} + +int +pi_palmos_error(int pi_sd) +{ + pi_socket_t *ps; + + if ((ps = find_pi_socket(pi_sd)) == NULL) { + errno = ESRCH; + return PI_ERR_SOCK_INVALID; + } + return ps->palmos_error; +} + +int +pi_set_palmos_error(int pi_sd, int error_code) +{ + pi_socket_t *ps; + + if ((ps = find_pi_socket(pi_sd))) + ps->palmos_error = error_code; + else + errno = ESRCH; + return error_code; +} + +void +pi_reset_errors(int pi_sd) +{ + pi_socket_t *ps; + + if ((ps = find_pi_socket(pi_sd))) { + ps->last_error = 0; + ps->palmos_error = 0; + } else + errno = ESRCH; +} + +int +pi_socket_connected(int pi_sd) +{ + pi_socket_t *ps; + + if ((ps = find_pi_socket(pi_sd))) + return is_connected(ps); + errno = ESRCH; + return 0; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ + diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/sys.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/sys.c new file mode 100644 index 00000000..8555cdd7 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/sys.c @@ -0,0 +1,372 @@ +/* + * $Id: sys.c,v 1.17 2006/10/12 14:21:22 desrod Exp $ + * + * sys.c: Pilot System Protocol + * + * (c) 1996, Kenneth Albanowski. + * Derived from padp.c. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-slp.h" +#include "pi-sys.h" +#include "pi-error.h" + +/* Declare function prototypes */ +static int sys_flush(pi_socket_t *ps, int flags); +static int sys_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len); +static int sys_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len); + + +/*********************************************************************** + * + * Function: sys_protocol_dup + * + * Summary: clones an existing pi_protocol struct + * + * Parameters: pi_protocol* + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +static pi_protocol_t * +sys_protocol_dup (pi_protocol_t *prot) +{ + pi_protocol_t *new_prot = NULL; + pi_sys_data_t *data = NULL, + *new_data = NULL; + + new_prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t)); + if (new_prot != NULL) { + new_data = (pi_sys_data_t *)malloc (sizeof (pi_sys_data_t)); + if (new_data == NULL) { + free(new_prot); + new_prot = NULL; + } + } + + if (new_prot != NULL && new_data != NULL) { + new_prot->level = prot->level; + new_prot->dup = prot->dup; + new_prot->free = prot->free; + new_prot->read = prot->read; + new_prot->write = prot->write; + new_prot->flush = prot->flush; + new_prot->getsockopt = prot->getsockopt; + new_prot->setsockopt = prot->setsockopt; + + data = (pi_sys_data_t *)prot->data; + new_data->txid = data->txid; + new_prot->data = new_data; + } + + return new_prot; +} + + +/*********************************************************************** + * + * Function: sys_protocol_free + * + * Summary: frees an existing pi_protocol struct + * + * Parameters: pi_protocol* + * + * Returns: void + * + ***********************************************************************/ +static void +sys_protocol_free (pi_protocol_t *prot) +{ + + ASSERT (prot != NULL); + if (prot != NULL) { + if (prot->data != NULL) + free(prot->data); + free(prot); + } +} + + +/*********************************************************************** + * + * Function: sys_protocol + * + * Summary: creates and inits pi_protocol struct instance + * + * Parameters: void + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +pi_protocol_t * +sys_protocol (void) +{ + pi_protocol_t *prot = NULL; + pi_sys_data_t *data = NULL; + + prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t)); + if (prot != NULL) { + data = (pi_sys_data_t *)malloc (sizeof (pi_sys_data_t)); + if (data == NULL) { + free(prot); + prot = NULL; + } + } + + if (prot != NULL && data != NULL) { + prot->level = PI_LEVEL_SYS; + prot->dup = sys_protocol_dup; + prot->free = sys_protocol_free; + prot->read = sys_rx; + prot->write = sys_tx; + prot->flush = sys_flush; + prot->getsockopt = sys_getsockopt; + prot->setsockopt = sys_setsockopt; + + data->txid = 0x00; + prot->data = data; + } + + return prot; +} + + +/*********************************************************************** + * + * Function: sys_tx + * + * Summary: Send a system message + * + * Parameters: pi_socket_t*, char* to buffer, buffer length, flags + * + * Returns: 0 if success, nonzero otherwise + * + ***********************************************************************/ +ssize_t +sys_tx(pi_socket_t *ps, const unsigned char *buf, size_t len, int flags) +{ + pi_protocol_t *prot, + *next; + + pi_sys_data_t *data; + + int type, + socket; + + size_t size; + + prot = pi_protocol(ps->sd, PI_LEVEL_SYS); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (pi_sys_data_t *)prot->data; + + next = pi_protocol_next(ps->sd, PI_LEVEL_SYS); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + if (!data->txid || data->txid == 0xff) + data->txid = 0x11; /* some random # */ + data->txid++; + if (!data->txid || data->txid == 0xff) + data->txid = 0x11; /* some random # */ + + type = PI_SLP_TYPE_RDCP; + + /* Fix me, allow socket type */ + socket = PI_SLP_SOCK_CON; + size = sizeof(type); + pi_setsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_TYPE, + &type, &size); + pi_setsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_DEST, + &socket, &size); + pi_setsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_SRC, + &socket, &size); + size = sizeof(data->txid); + pi_setsockopt(ps->sd, PI_LEVEL_SLP, PI_SLP_TXID, + &data->txid, &size); + + len = next->write(ps, buf, len, flags); + if (len >= 0) { + CHECK(PI_DBG_SYS, PI_DBG_LVL_INFO, sys_dump_header(buf, 1)); + CHECK(PI_DBG_SYS, PI_DBG_LVL_DEBUG, sys_dump(buf, len)); + } + + return len; +} + + +/*********************************************************************** + * + * Function: sys_rx + * + * Summary: Receive system message + * + * Parameters: pi_socket_t*, char* to buffer, buffer length, flags + * + * Returns: Length of read or negative on error + * + ***********************************************************************/ +ssize_t +sys_rx(pi_socket_t *ps, pi_buffer_t *buf, size_t len, int flags) +{ + pi_protocol_t *next, + *prot; + + pi_sys_data_t *data; + size_t data_len; + + prot = pi_protocol(ps->sd, PI_LEVEL_SYS); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data = (pi_sys_data_t *)prot->data; + next = pi_protocol_next(ps->sd, PI_LEVEL_SYS); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + data_len = next->read(ps, buf, len, flags); + + CHECK(PI_DBG_SYS, PI_DBG_LVL_INFO, sys_dump_header(buf->data, 0)); + CHECK(PI_DBG_SYS, PI_DBG_LVL_DEBUG, sys_dump(buf->data, data_len)); + + return data_len; +} + +/*********************************************************************** + * + * Function: sys_flush + * + * Summary: Flush input and output buffers + * + * Parameters: pi_socket_t*, flags + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +static int +sys_flush(pi_socket_t *ps, int flags) +{ + pi_protocol_t *prot, + *next; + + prot = pi_protocol(ps->sd, PI_LEVEL_SYS); + if (prot == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + next = pi_protocol_next(ps->sd, PI_LEVEL_SYS); + if (next == NULL) + return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID); + + return next->flush(ps, flags); +} + +/*********************************************************************** + * + * Function: sys_getsockopt + * + * Summary: get options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success + * + ***********************************************************************/ +static int +sys_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len) +{ + return 0; +} + + +/*********************************************************************** + * + * Function: sys_setsockopt + * + * Summary: get options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success + * + ***********************************************************************/ +static int +sys_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len) +{ + return 0; +} + + +/*********************************************************************** + * + * Function: sys_dump_header + * + * Summary: Dump SYS packet header + * + * Parameters: char* to data, RXTX boolean + * + * Returns: void + * + ***********************************************************************/ +void +sys_dump_header(const unsigned char *data, int rxtx) +{ + LOG((PI_DBG_SYS, PI_DBG_LVL_NONE, + "SYS %s\n", rxtx ? "TX" : "RX")); +} + + +/*********************************************************************** + * + * Function: sys_dump + * + * Summary: Dump SYS packet + * + * Parameters: char* to data, length + * + * Returns: void + * + ***********************************************************************/ +void +sys_dump(const unsigned char *data, size_t len) +{ + pi_dumpdata((char *)&data[PI_SYS_HEADER_LEN], len); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ + diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/syspkt.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/syspkt.c new file mode 100644 index 00000000..8cafb839 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/syspkt.c @@ -0,0 +1,1031 @@ +/* + * $Id: syspkt.c,v 1.41 2006/10/12 14:21:23 desrod Exp $ + * + * syspkt.c: Pilot SysPkt manager + * + * (c) 1996, Kenneth Albanowski. + * Derived from padp.c. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +#include "pi-source.h" +#include "pi-syspkt.h" +#include "pi-slp.h" +#include "pi-serial.h" +#include "pi-error.h" + +/* Declare prototypes */ +static int sys_PackRegisters(void *data, struct Pilot_registers *r); + + +/*********************************************************************** + * + * Function: sys_UnpackState + * + * Summary: Get the state command + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +sys_UnpackState(void *buffer, struct Pilot_state *s) +{ + int idx; + unsigned char *data = buffer; + + s->reset = get_short(data); + s->exception = get_short(data + 2); + memcpy(s->func_name, data + 152, 32); + memcpy(s->instructions, data + 78, 30); + s->func_name[32 - 1] = 0; + s->func_start = get_long(data + 144); + s->func_end = get_long(data + 148); + sys_UnpackRegisters(data + 4, &s->regs); + + for (idx = 0; idx < 6; idx++) { + s->breakpoint[idx].address = get_long(data + 108 + idx * 6); + s->breakpoint[idx].enabled = get_byte(data + 112 + idx * 6); + } + + s->trap_rev = get_short(data + 184); + + return 0; +} + + +/*********************************************************************** + * + * Function: sys_UnpackRegisters + * + * Summary: Read the register commands + * + * Parameters: None + * + * Returns: 0 + * + ***********************************************************************/ +int +sys_UnpackRegisters(void *data, struct Pilot_registers *r) +{ + unsigned char *buffer = data; + + r->D[0] = get_long(buffer + 0); + r->D[1] = get_long(buffer + 4); + r->D[2] = get_long(buffer + 8); + r->D[3] = get_long(buffer + 12); + r->D[4] = get_long(buffer + 16); + r->D[5] = get_long(buffer + 20); + r->D[6] = get_long(buffer + 24); + r->D[7] = get_long(buffer + 28); + r->A[0] = get_long(buffer + 32); + r->A[1] = get_long(buffer + 36); + r->A[2] = get_long(buffer + 40); + r->A[3] = get_long(buffer + 44); + r->A[4] = get_long(buffer + 48); + r->A[5] = get_long(buffer + 52); + r->A[6] = get_long(buffer + 56); + r->USP = get_long(buffer + 60); + r->SSP = get_long(buffer + 64); + r->PC = get_long(buffer + 68); + + r->SR = get_short(buffer + 72); + + return 0; +} + + +/*********************************************************************** + * + * Function: sys_PackRegisters + * + * Summary: Pack the register commands + * + * Parameters: None + * + * Returns: 0 + * + ***********************************************************************/ +static int +sys_PackRegisters(void *data, struct Pilot_registers *r) +{ + int idx; + unsigned char *buffer = data; + + for (idx = 0; idx < 8; idx++) + set_long(buffer + idx * 4, r->D[idx]); + for (idx = 0; idx < 7; idx++) + set_long(buffer + 32 + idx * 4, r->A[idx]); + set_long(buffer + 60, r->USP); + set_long(buffer + 64, r->SSP); + set_long(buffer + 68, r->PC); + + set_short(buffer + 72, r->SR); + + return 0; +} + +/*********************************************************************** + * + * Function: sys_Continue + * + * Summary: Define the Continue command + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +sys_Continue(int sd, struct Pilot_registers *r, struct Pilot_watch *w) +{ + char buf[94]; + + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + buf[4] = 0x07; + buf[5] = 0; /* gapfill */ + + if (!r) + return pi_write(sd, buf, 6); + + sys_PackRegisters(buf + 6, r); + set_byte(buf + 80, (w != 0) ? 1 : 0); + set_byte(buf + 81, 0); + set_long(buf + 82, w ? w->address : 0); + set_long(buf + 86, w ? w->length : 0); + set_long(buf + 90, w ? w->checksum : 0); + + return pi_write(sd, buf, 94); +} + +/*********************************************************************** + * + * Function: sys_Step + * + * Summary: Single-step command + * + * Parameters: None + * + * Returns: Socket, command, 6 bytes + * + ***********************************************************************/ +int +sys_Step(int sd) +{ + char buf[94]; + + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + buf[4] = 0x03; + buf[5] = 0; /* gapfill */ + + return pi_write(sd, buf, 6); +} + +/*********************************************************************** + * + * Function: sys_SetBreakpoints + * + * Summary: Set the breakpoints (0x0C, 0x8C) + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +sys_SetBreakpoints(int sd, struct Pilot_breakpoint *b) +{ + int idx; + pi_buffer_t *buf; + + buf = pi_buffer_new (94); + if (buf == NULL) { + errno = ENOMEM; + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + } + + buf->data[0] = 0; + buf->data[1] = 0; + buf->data[2] = 0; + buf->data[3] = 0; + buf->data[4] = 0x0c; + buf->data[5] = 0; /* gapfill */ + + for (idx = 0; idx < 6; idx++) { + set_long(buf->data + 6 + idx * 6, b[idx].address); + set_byte(buf->data + 10 + idx * 6, b[idx].enabled); + set_byte(buf->data + 11 + idx * 6, 0); + } + + pi_write(sd, buf->data, 42); + + idx = pi_read(sd, buf, 6); + + if (idx <= 0 || buf->data[4] != (unsigned char) 0x8c) { + pi_buffer_free (buf); + return 0; + } + + pi_buffer_free (buf); + return 1; +} + +/*********************************************************************** + * + * Function: sys_SetTrapBreaks + * + * Summary: Set the Trap Breaks (0x11, 0x91) + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +sys_SetTrapBreaks(int sd, int *traps) +{ + int idx; + pi_buffer_t *buf; + + buf = pi_buffer_new (32); + if (buf == NULL) { + errno = ENOMEM; + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + } + + buf->data[0] = 0; + buf->data[1] = 0; + buf->data[2] = 0; + buf->data[3] = 0; + buf->data[4] = 0x11; + buf->data[5] = 0; /* gapfill */ + + for (idx = 0; idx < 5; idx++) { + set_short(buf->data + 6 + idx * 2, traps[idx]); + } + + pi_write(sd, buf->data, 16); + + idx = pi_read(sd, buf, 6); + + if ((idx <= 0) || (buf->data[4] != (unsigned char) 0x91)) { + pi_buffer_free (buf); + return 0; + } + + pi_buffer_free (buf); + return 1; +} + +/*********************************************************************** + * + * Function: sys_GetTrapBreaks + * + * Summary: Get the Trap Breaks (0x10, 0x90) + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +sys_GetTrapBreaks(int sd, int *traps) +{ + int idx; + pi_buffer_t *buf; + + buf = pi_buffer_new (32); + if (buf == NULL) { + errno = ENOMEM; + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + } + + buf->data[0] = 0; + buf->data[1] = 0; + buf->data[2] = 0; + buf->data[3] = 0; + buf->data[4] = 0x10; + buf->data[5] = 0; /* gapfill */ + + pi_write(sd, buf->data, 6); + + idx = pi_read(sd, buf, 16); + + if ((idx < 16) || (buf->data[4] != (unsigned char) 0x90)) { + pi_buffer_free (buf); + return 0; + } + + for (idx = 0; idx < 5; idx++) { + traps[idx] = get_short(buf->data + 6 + idx * 2); + } + + pi_buffer_free (buf); + return 1; +} + + +/*********************************************************************** + * + * Function: sys_ToggleDbgBreaks + * + * Summary: Enable the DbgBreaks command (0x0D, 0x8D) + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +sys_ToggleDbgBreaks(int sd) +{ + int idx; + pi_buffer_t *buf; + unsigned char byte; + + buf = pi_buffer_new (32); + if (buf == NULL) { + errno = ENOMEM; + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + } + + buf->data[0] = 0; + buf->data[1] = 0; + buf->data[2] = 0; + buf->data[3] = 0; + buf->data[4] = 0x0d; + buf->data[5] = 0; /* gapfill */ + + pi_write(sd, buf->data, 6); + + idx = pi_read(sd, buf, 7); + + if ((idx < 7) || (buf->data[4] != (unsigned char) 0x8d)) { + pi_buffer_free (buf); + return 0; + } + + byte = get_byte(buf->data + 6); + + pi_buffer_free (buf); + + return byte; +} + + +/*********************************************************************** + * + * Function: sys_QueryState + * + * Summary: Query the state (uh) + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +sys_QueryState(int sd) +{ + char buf[6]; + + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; /* gapfill */ + + return pi_write(sd, buf, 2); +} + +/*********************************************************************** + * + * Function: sys_ReadMemory + * + * Summary: Read memory (0x01, 0x81) + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +sys_ReadMemory(int sd, unsigned long addr, unsigned long len, void *dest) +{ + int result; + unsigned long todo, done; + pi_buffer_t *buf; + + buf = pi_buffer_new (0xFFFF); + if (buf == NULL) { + errno = ENOMEM; + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + } + + done = 0; + do { + todo = len; + if (todo > 256) + todo = 256; + + buf->data[0] = 0; + buf->data[1] = 0; + buf->data[2] = 0; + buf->data[3] = 0; + buf->data[4] = 0x01; + buf->data[5] = 0; /* gapfill */ + + set_long(buf->data + 6, addr + done); + set_short(buf->data + 10, todo); + + pi_write(sd, buf->data, 12); + + result = pi_read(sd, buf, todo + 6); + + if (result < 0) { + pi_buffer_free (buf); + return done; + } + + if ((buf->data[4] == 0x81) + && ((unsigned int) result == todo + 6)) { + memcpy(((char *) dest) + done, buf->data + 6, todo); + done += todo; + } else { + pi_buffer_free (buf); + return done; + } + } while (done < len); + + pi_buffer_free (buf); + return done; +} + + +/*********************************************************************** + * + * Function: sys_WriteMemory + * + * Summary: Write memory (0x02, 0x82) + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +sys_WriteMemory(int sd, unsigned long addr, unsigned long len, void *src) +{ + int result; + unsigned long todo, done; + pi_buffer_t *buf; + + buf = pi_buffer_new (0xFFFF); + if (buf == NULL) { + errno = ENOMEM; + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + } + + done = 0; + do { + todo = len; + if (todo > 256) + todo = 256; + + buf->data[0] = 0; + buf->data[1] = 0; + buf->data[2] = 0; + buf->data[3] = 0; + buf->data[4] = 0x02; + buf->data[5] = 0; /* gapfill */ + + set_long(buf->data + 6, addr); + set_short(buf->data + 10, len); + memcpy(buf->data + 12, (char *)src + done, todo); + + pi_write(sd, buf->data, len + 12); + + result = pi_read(sd, buf, 6); + + if (result < 0) { + pi_buffer_free (buf); + return done; + } + + if ((buf->data[4] == (unsigned char)0x82) + && ((unsigned long) result == todo + 6)) { + ; + } else { + pi_buffer_free (buf); + return done; + } + } while (done < len); + + pi_buffer_free (buf); + return done; +} + + +/*********************************************************************** + * + * Function: sys_Find + * + * Summary: Searches a range of addresses for data (0x13, 0x80) + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +sys_Find(int sd, unsigned long startaddr, unsigned long stopaddr, size_t len, + int caseinsensitive, void *data, unsigned long *found) +{ + int result; + unsigned char byte; + pi_buffer_t *buf; + + buf = pi_buffer_new (len + 17); + if (buf == NULL) { + errno = ENOMEM; + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + } + + buf->data[0] = 0; + buf->data[1] = 0; + buf->data[2] = 0; + buf->data[3] = 0; + buf->data[4] = 0x11; + buf->data[5] = 0; /* gapfill */ + + set_long(buf->data + 6, startaddr); + set_long(buf->data + 10, stopaddr); + set_short(buf->data + 14, len); + set_byte(buf->data + 16, caseinsensitive); + memcpy(buf->data + 17, data, len); + + pi_write(sd, buf->data, len + 17); + + result = pi_read(sd, buf, 12); + + if (result < 0) { + pi_buffer_free (buf); + return result; + } + + if (found) + *found = get_long(buf->data + 6); + + byte = get_byte(buf->data + 10); + + pi_buffer_free (buf); + + return byte; +} + + +/*********************************************************************** + * + * Function: sys_RemoteEvent + * + * Summary: Parameters sent from host to target to feed pen and + * keyboard events. They do not require a response. + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +sys_RemoteEvent(int sd, int penDown, int x, int y, int keypressed, + int keymod, int keyasc, int keycode) +{ + char buf[16]; + + /* Offset 1, 3 and 9 are padding */ + set_byte(&buf[0], 0x0D); /* RemoteEvtCommand */ + set_byte(&buf[1], 0); + set_byte(&buf[2], penDown); + set_byte(&buf[3], 0); + set_short(&buf[4], x); + set_short(&buf[6], y); + set_byte(&buf[8], keypressed); + set_byte(&buf[9], 0); + set_short(&buf[10], keymod); + set_short(&buf[12], keyasc); + set_short(&buf[14], keycode); + + return pi_write(sd, buf, 16); +} + + +/*********************************************************************** + * + * Function: sys_RPC + * + * Summary: Remote Procedure calls (0x0A, 0x8A) + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +sys_RPC(int sd, int sockaddr, int trap, long *D0, long *A0, int params, + struct RPC_param *param, int reply) +{ + int idx; + unsigned char *c; + pi_buffer_t *buf; + + buf = pi_buffer_new (4096); + if (buf == NULL) { + errno = ENOMEM; + return pi_set_error(sd, PI_ERR_GENERIC_MEMORY); + } + + buf->data[0] = sockaddr; /* 0 for debug, 1 for console */ + buf->data[1] = sockaddr; + buf->data[2] = 0; + buf->data[4] = 0x0a; + buf->data[5] = 0; + + set_short(buf->data + 6, trap); + set_long(buf->data + 8, *D0); + set_long(buf->data + 12, *A0); + set_short(buf->data + 16, params); + + c = buf->data + 18; + for (idx = params - 1; idx >= 0; idx--) { + set_byte(c, param[idx].byRef); + c++; + set_byte(c, param[idx].size); + c++; + if (param[idx].data) + memcpy(c, param[idx].data, param[idx].size); + c += param[idx].size; + if (param[idx].size & 1) + *c++ = 0; + } + + if (sockaddr == 3) + set_short(buf->data + 4, c - buf->data - 6); + + pi_write(sd, buf->data + 4,(size_t)(c - buf->data - 4)); + + if (reply) { + int l = pi_read(sd, buf, 4096); + + if (l < 0) { + pi_buffer_free (buf); + return l; + } + + if (buf->data[0] != (unsigned char)0x8a) { + pi_buffer_free (buf); + return pi_set_error(sd, -2); + } + + *D0 = get_long(buf->data + 4); + *A0 = get_long(buf->data + 8); + c = buf->data + 14; + for (idx = params - 1; idx >= 0; idx--) { + if (param[idx].byRef && param[idx].data) + memcpy(param[idx].data, c + 2, + param[idx].size); + c += 2 + ((get_byte(c + 1) + 1) & ~1); + } + } + + pi_buffer_free (buf); + return 0; +} + + +/*********************************************************************** + * + * Function: RPC + * + * Summary: Deprecated + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +RPC(int sd, int sockaddr, int trap, int reply, ...) +{ + int idx = 0, + j, + RPC_arg[20]; + va_list ap; + struct RPC_param p[20]; + long D0 = 0, + A0 = 0; + + va_start(ap, reply); + for (;;) { + int type = va_arg(ap, int); + + if (type == 0) + break; + if (type < 0) { + p[idx].byRef = 0; + p[idx].size = -type; + RPC_arg[idx] = va_arg(ap, int); + + p[idx].data = &RPC_arg[idx]; + p[idx].invert = 0; + } else { + void *c = va_arg(ap, void *); + + p[idx].byRef = 1; + p[idx].size = type; + p[idx].data = c; + p[idx].invert = va_arg(ap, int); + + if (p[idx].invert) { + if (p[idx].size == 2) { + int *s = c; + + *s = htons(*s); + } else { + int *l = c; + + *l = htonl(*l); + } + } + } + idx++; + } + va_end(ap); + + if (sys_RPC(sd, sockaddr, trap, &D0, &A0, idx, p, reply != 2) < 0) + return pi_error(sd); + + for (j = 0; j < idx; j++) { + if (p[j].invert) { + void *c = p[j].data; + + if (p[j].size == 2) { + int *s = c; + + *s = htons(*s); + } else { + int *l = c; + + *l = htonl(*l); + } + } + } + + if (reply) + return A0; + return D0; +} + + +/*********************************************************************** + * + * Function: PackRPC + * + * Summary: Pack the RPC structure for transmission + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +PackRPC(struct RPC_params *p, int trap, int reply, ...) +{ + int idx = 0; + va_list ap; + + p->trap = trap; + p->reply = reply; + + va_start(ap, reply); + for (;;) { + int type = (int) va_arg(ap, int); + + if (type == 0) + break; + if (type < 0) { + p->param[idx].byRef = 0; + p->param[idx].size = -type; + p->param[idx].arg = (int) va_arg(ap, int); + + p->param[idx].data = &p->param[idx].arg; + p->param[idx].invert = 0; + } else { + void *c = (void *) va_arg(ap, void *); + + p->param[idx].byRef = 1; + p->param[idx].size = type; + p->param[idx].data = c; + p->param[idx].invert = (int) va_arg(ap, int); + } + idx++; + } + p->args = idx; + va_end(ap); + + return 0; +} + + +/*********************************************************************** + * + * Function: UninvertRPC + * + * Summary: + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +void +UninvertRPC(struct RPC_params *p) +{ + int j; + + for (j = 0; j < p->args; j++) { + if (p->param[j].invert) { + void *c = p->param[j].data; + + if ((p->param[j].invert == 2) + && (p->param[j].size == 2)) { + int *s = c; + + *s = htons(*s) >> 8; + } else if (p->param[j].size == 2) { + int *s = c; + + *s = htons(*s); + } else { + long *l = c; + + *l = htonl(*l); + } + } + } +} + + +/*********************************************************************** + * + * Function: InvertRPC + * + * Summary: + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +void +InvertRPC(struct RPC_params *p) +{ + int j; + + for (j = 0; j < p->args; j++) { + if (p->param[j].invert) { + void *c = p->param[j].data; + + if ((p->param[j].invert == 2) + && (p->param[j].size == 2)) { + int *s = c; + + *s = ntohs(*s) >> 8; + } else if (p->param[j].size == 2) { + int *s = c; + + *s = ntohs(*s); + } else { + long *l = c; + + *l = ntohl((unsigned) *l); + } + } + } +} + + +/*********************************************************************** + * + * Function: DoRPC + * + * Summary: Actually execute the RPC query/response + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +unsigned long +DoRPC(int sd, int sockaddr, struct RPC_params *p, int *error) +{ + int err; + long D0 = 0, + A0 = 0; + + InvertRPC(p); + + err = + sys_RPC(sd, sockaddr, p->trap, &D0, &A0, p->args, &p->param[0], + p->reply); + + UninvertRPC(p); + + if (error) + *error = err; + + if (p->reply == RPC_PtrReply) + return A0; + else if (p->reply == RPC_IntReply) + return D0; + else + return err; +} + + +/*********************************************************************** + * + * Function: RPC_Int_Void + * + * Summary: + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +RPC_Int_Void(int sd, int trap) +{ + return RPC(sd, 1, trap, 0, RPC_End); +} + + +/*********************************************************************** + * + * Function: RPC_Ptr_Void + * + * Summary: + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int +RPC_Ptr_Void(int sd, int trap) +{ + return RPC(sd, 1, trap, 1, RPC_End); +} + + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ + diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/threadsafe.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/threadsafe.c new file mode 100644 index 00000000..4b4b69dc --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/threadsafe.c @@ -0,0 +1,70 @@ +/* + * $Id: threadsafe.c,v 1.5 2006/10/12 14:21:23 desrod Exp $ + * + * threadsafe.c: utilities for thread-safe behavior + * + * Copyright (c) 2005, Florent Pillet. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + * + * -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + */ + +#include "pi-threadsafe.h" + +int pi_mutex_lock(pi_mutex_t *mutex) +{ +#if HAVE_PTHREAD + return pthread_mutex_lock(mutex); +#else + return 0; +#endif +} + +int pi_mutex_trylock(pi_mutex_t *mutex) +{ +#if HAVE_PTHREAD + return pthread_mutex_trylock(mutex); +#else + return 0; +#endif +} + +int pi_mutex_unlock(pi_mutex_t *mutex) +{ +#if HAVE_PTHREAD + return pthread_mutex_unlock(mutex); +#else + return 0; +#endif +} + +unsigned long pi_thread_id() +{ +#if HAVE_PTHREAD + return (unsigned long)pthread_self(); +#else + return 0; +#endif +} + +#include "pi-threadsafe.h" + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/todo.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/todo.c new file mode 100644 index 00000000..c74c3738 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/todo.c @@ -0,0 +1,293 @@ +/* + * $Id: todo.c,v 1.28 2006/11/22 22:52:25 adridg Exp $ + * + * todo.c: Translate Palm ToDo application data formats + * + * Copyright (c) 1996, Kenneth Albanowski + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include "pi-macros.h" +#include "pi-todo.h" + +/* Maximum length of Description and Note fields */ +#define DescMaxLength 256 +#define NoteMaxLength 4096 + + +/*********************************************************************** + * + * Function: free_ToDo + * + * Summary: Free the memory and filehandle from the record alloc. + * + * Parameters: ToDo_t* + * + * Returns: void + * + ***********************************************************************/ +void +free_ToDo(ToDo_t *todo) +{ + + if (todo->description != NULL) { + free(todo->description); + todo->description = NULL; + } + + if (todo->note != NULL) { + free(todo->note); + todo->note = NULL; + } +} + + +/*********************************************************************** + * + * Function: unpack_ToDo + * + * Summary: Unpack the ToDo structure from buffer into records + * we can chew on. + * + * Parameters: ToDo_t*, pi_buffer_t * of buffer, todo type + * + * Returns: -1 on fail, 0 on success + * + ***********************************************************************/ +int +unpack_ToDo(ToDo_t *todo, const pi_buffer_t *buf, todoType type) +{ + unsigned long d; + int ofs; + + /* Note: There are possible timezone conversion problems related to + the use of the due member of a struct ToDo. As it is kept in + local (wall) time in struct tm's, the timezone of the Palm is + irrelevant, _assuming_ that any UNIX program keeping time in + time_t's converts them to the correct local time. If the Palm is + in a different timezone than the UNIX box, it may not be simple + to deduce that correct (desired) timezone. + + The easiest solution is to keep apointments in struct tm's, and + out of time_t's. Of course, this might not actually be a help if + you are constantly darting across timezones and trying to keep + appointments. + -- KJA */ + + if (type != todo_v1) + return -1; + + if (buf == NULL || buf->data == NULL || buf->used < 3) + return -1; + + d = (unsigned short int) get_short(buf->data); + if (d != 0xffff) { + todo->due.tm_year = (d >> 9) + 4; + todo->due.tm_mon = ((d >> 5) & 15) - 1; + todo->due.tm_mday = d & 31; + todo->due.tm_hour = 0; + todo->due.tm_min = 0; + todo->due.tm_sec = 0; + todo->due.tm_isdst = -1; + mktime(&todo->due); + todo->indefinite = 0; + } else { + todo->indefinite = 1; /* todo->due is invalid */ + } + + todo->priority = get_byte(buf->data + 2); + if (todo->priority & 0x80) { + todo->complete = 1; + todo->priority &= 0x7f; + } else { + todo->complete = 0; + } + + ofs = 3; + + if (buf->used - ofs < 1) + return -1; + + todo->description = strdup((char *) buf->data + ofs); + + ofs += strlen(todo->description) + 1; + + if (buf->used - ofs < 1) { + free(todo->description); + todo->description = 0; + return -1; + } + todo->note = strdup((char *) buf->data + ofs); + + return 0; +} + + +/*********************************************************************** + * + * Function: pack_ToDo + * + * Summary: Pack the ToDo records into a structure + * + * Parameters: ToDo_t*, pi_buffer_t *buf of record, record type + * + * Returns: -1 on error, 0 on success. + * + ***********************************************************************/ +int +pack_ToDo(const ToDo_t *todo, pi_buffer_t *buf, todoType type) +{ + int pos; + size_t destlen = 3; + + if (todo == NULL || buf == NULL) + return -1; + + if (type != todo_v1) + return -1; + + if (todo->description) + destlen += strlen(todo->description); + destlen++; + if (todo->note) + destlen += strlen(todo->note); + destlen++; + + pi_buffer_expect (buf, destlen); + buf->used = destlen; + + if (todo->indefinite) { + buf->data[0] = 0xff; + buf->data[1] = 0xff; + } else { + set_short(buf->data, + ((todo->due.tm_year - 4) << 9) | ((todo->due.tm_mon + + 1) << 5) | todo-> + due.tm_mday); + } + buf->data[2] = todo->priority; + if (todo->complete) { + buf->data[2] |= 0x80; + } + + pos = 3; + if (todo->description) { + strcpy((char *) buf->data + pos, todo->description); + pos += strlen(todo->description) + 1; + } else { + buf->data[pos++] = 0; + } + + if (todo->note) { + strcpy((char *) buf->data + pos, todo->note); + pos += strlen(todo->note) + 1; + } else { + buf->data[pos++] = 0; + } + + return 0; +} + + +/*********************************************************************** + * + * Function: unpack_ToDoAppInfo + * + * Summary: Unpack the ToDo AppInfo block from the structure + * + * Parameters: ToDoAppInfo_t*, char* to record, record length + * + * Returns: effective record length + * + ***********************************************************************/ +int +unpack_ToDoAppInfo(ToDoAppInfo_t *appinfo, const unsigned char *record, size_t len) +{ + int i; + unsigned char *start = record; + + appinfo->type = todo_v1; + + i = unpack_CategoryAppInfo(&appinfo->category, record, len); + if (!i) + return 0; + record += i; + len -= i; + if (len < 4) + return 0; + appinfo->dirty = get_short(record); + record += 2; + appinfo->sortByPriority = get_byte(record); + record += 2; + return (record - start); +} + + +/*********************************************************************** + * + * Function: pack_ToDoAppInfo + * + * Summary: Pack the AppInfo block/record back into the structure + * + * Parameters: ToDoAppInfo_t*, char* to record, record length + * + * Returns: effective buffer length + * + ***********************************************************************/ +int +pack_ToDoAppInfo(const ToDoAppInfo_t *appinfo, unsigned char *record, size_t len) +{ + int i; + unsigned char *start = record; + + i = pack_CategoryAppInfo(&appinfo->category, record, len); + if (!record) + return i + 4; + if (!i) + return 0; + record += i; + len -= i; + if (len < 4) + return 0; + set_short(record, appinfo->dirty); + set_byte(record + 2, appinfo->sortByPriority); + set_byte(record + 3, 0); /* gapfill */ + record += 4; + + return (record - start); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/unixserial.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/unixserial.c new file mode 100644 index 00000000..4cf48db9 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/unixserial.c @@ -0,0 +1,745 @@ +/* + * $Id: unixserial.c,v 1.53 2006/10/12 14:21:23 desrod Exp $ + * + * unixserial.c: tty line interface code for Pilot serial comms under UNIX + * + * Copyright (c) 1996, 1997, D. Jeff Dionne & Kenneth Albanowski. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> /* Needed for Redhat 6.x machines */ +#include <fcntl.h> +#include <string.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-serial.h" +#include "pi-error.h" + +/* if this is running on a NeXT system... */ +#ifdef NeXT +#include <sys/uio.h> +#include <sys/time.h> +#include <sys/file.h> +#endif + +#ifdef HAVE_SYS_IOCTL_COMPAT_H +#include <sys/ioctl_compat.h> +#endif + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#ifndef SGTTY + +#ifndef HAVE_CFMAKERAW +#define cfmakeraw(ptr) (ptr)->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR\ + |IGNCR|ICRNL|IXON);\ + (ptr)->c_oflag &= ~OPOST;\ + (ptr)->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);\ + (ptr)->c_cflag &= ~(CSIZE|PARENB);\ + (ptr)->c_cflag |= CS8 +#endif + +#ifndef HAVE_CFSETSPEED +#if defined(HAVE_CFSETISPEED) && defined(HAVE_CFSETOSPEED) +#define cfsetspeed(t,speed) \ + (cfsetispeed(t,speed) || cfsetospeed(t,speed)) +#else +static int cfsetspeed(struct termios *t, int speed) +{ +#ifdef HAVE_TERMIOS_CSPEED + t->c_ispeed = speed; + t->c_ospeed = speed; +#else + t->c_cflag |= speed; +#endif + return 0; +} +#endif +#endif + +#endif /* SGTTY */ + +#ifndef O_NONBLOCK +# define O_NONBLOCK 0 +#endif + +/* Linux versions "before 2.1.8 or so" fail to flush hardware FIFO on port + close */ +#ifdef linux +# ifndef LINUX_VERSION_CODE +# include <linux/version.h> +# endif +# ifndef LINUX_VERSION_CODE +# define sleeping_beauty +# else +# if (LINUX_VERSION_CODE < 0x020108) +# define sleeping_beauty +# endif +# endif +#endif + +/* Unspecified NetBSD versions fail to flush hardware FIFO on port close */ +#if defined(__NetBSD__) || defined (__OpenBSD__) +# define sleeping_beauty +#endif + +/* Unspecified BSD/OS versions fail to flush hardware FIFO on port close */ +#ifdef __bsdi__ +# define sleeping_beauty +#endif + +/* SGI IRIX fails to flush hardware FIFO on port close */ +#ifdef __sgi +# define sleeping_beauty +#endif + +/* Declare prototypes */ +static int s_open(pi_socket_t *ps, struct pi_sockaddr *addr, + size_t addrlen); +static int s_close(pi_socket_t *ps); +static int s_changebaud(pi_socket_t *ps); +static ssize_t s_write(pi_socket_t *ps, const unsigned char *buf, + size_t len, int flags); +static ssize_t s_read(pi_socket_t *ps, pi_buffer_t *buf, size_t len, + int flags); +static int s_poll(pi_socket_t *ps, int timeout); + +static speed_t calcrate(int baudrate); +void pi_serial_impl_init (struct pi_serial_impl *impl); +static int s_flush(pi_socket_t *ps, int flags); + +#ifdef sleeping_beauty +static void s_delay(time_t sec, suseconds_t usec); +#endif + + +/*********************************************************************** + * + * Function: s_open + * + * Summary: Open the serial port and establish a connection for + * unix + * + * Parameters: pi_socket_t*, pi_socket_taddr*, size_t + * + * Returns: The file descriptor or negative on error + * + ***********************************************************************/ +int +s_open(pi_socket_t *ps, struct pi_sockaddr *addr, size_t addrlen) +{ + int fd, + i; + char *tty = addr->pi_device; + + struct pi_serial_data *data = + (struct pi_serial_data *)ps->device->data; + +#ifndef SGTTY + struct termios tcn; +#else + struct sgttyb tcn; +#endif + if ((fd = open(tty, O_RDWR | O_NONBLOCK)) < 0) { + ps->last_error = PI_ERR_GENERIC_SYSTEM; + return PI_ERR_GENERIC_SYSTEM; /* errno already set */ + } + + if (!isatty(fd)) { + close(fd); + errno = EINVAL; + ps->last_error = PI_ERR_GENERIC_SYSTEM; + return PI_ERR_GENERIC_SYSTEM; + } + +#ifndef SGTTY + /* Set the tty to raw and to the correct speed */ + tcgetattr(fd, &tcn); + + data->tco = tcn; + tcn.c_oflag = 0; + tcn.c_iflag = IGNBRK | IGNPAR; + tcn.c_cflag = CREAD | CLOCAL | CS8; + + cfsetspeed(&tcn, calcrate(data->rate)); + + tcn.c_lflag = NOFLSH; + + cfmakeraw(&tcn); + + for (i = 0; i < 16; i++) + tcn.c_cc[i] = 0; + + tcn.c_cc[VMIN] = 1; + tcn.c_cc[VTIME] = 0; + + tcsetattr(fd, TCSANOW, &tcn); +#else + /* Set the tty to raw and to the correct speed */ + ioctl(fd, TIOCGETP, &tcn); + + data->tco = tcn; + + tcn.sg_flags = RAW; + tcn.sg_ispeed = calcrate(data->rate); + tcn.sg_ospeed = calcrate(data->rate); + + ioctl(fd, TIOCSETN, &tcn); +#endif + + if ((i = fcntl(fd, F_GETFL, 0)) != -1) { + i &= ~O_NONBLOCK; + fcntl(fd, F_SETFL, i); + } + + if ((i = pi_socket_setsd(ps, fd)) < 0) + return i; + + return fd; +} + + +/*********************************************************************** + * + * Function: s_close + * + * Summary: Close the open socket/file descriptor + * + * Parameters: pi_socket_t* + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +s_close(pi_socket_t *ps) +{ +#ifdef sleeping_beauty + s_delay(2, 0); +#endif + +#if 0 /* previous test would never allow this code to execute */ + #ifndef SGTTY + tcsetattr(ps->sd, TCSADRAIN, &data->tco); + #else + ioctl(ps->sd, TIOCSETP, &data->tco); + #endif +#endif + + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, + "DEV CLOSE unixserial fd: %d\n", ps->sd)); + + return close(ps->sd); +} + + +/*********************************************************************** + * + * Function: s_poll + * + * Summary: poll the open socket/file descriptor + * + * Parameters: pi_socket_t*, timeout in milliseconds + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +s_poll(pi_socket_t *ps, int timeout) +{ + struct pi_serial_data *data = + (struct pi_serial_data *)ps->device->data; + struct timeval t; + fd_set ready; + + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + + /* If timeout == 0, wait forever for packet, otherwise wait till + timeout milliseconds */ + if (timeout == 0) + select(ps->sd + 1, &ready, 0, 0, 0); + else { + t.tv_sec = timeout / 1000; + t.tv_usec = (timeout % 1000) * 1000; + if (select(ps->sd + 1, &ready, 0, 0, &t) == 0) + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + + if (!FD_ISSET(ps->sd, &ready)) { + /* otherwise throw out any current packet and return */ + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, + "DEV POLL unixserial timeout\n")); + data->rx_errors++; + errno = ETIMEDOUT; + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV POLL unixserial found data on fd: %d\n", ps->sd)); + + return 0; +} + + +/*********************************************************************** + * + * Function: s_write + * + * Summary: Write to the open socket/file descriptor + * + * Parameters: pi_socket_t*, unsigned char* to buf, buf length + * + * Returns: number of bytes written or negative on error + * + ***********************************************************************/ +static ssize_t +s_write(pi_socket_t *ps, const unsigned char *buf, size_t len, + int flags) +{ + ssize_t total, + nwrote; + struct pi_serial_data *data = + (struct pi_serial_data *)ps->device->data; + struct timeval t; + fd_set ready; + + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + + total = len; + while (total > 0) { + if (data->timeout == 0) + select(ps->sd + 1, 0, &ready, 0, 0); + else { + t.tv_sec = data->timeout / 1000; + t.tv_usec = (data->timeout % 1000) * 1000; + if (select(ps->sd + 1, 0, &ready, 0, &t) == 0) + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + + if (!FD_ISSET(ps->sd, &ready)) + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + + nwrote = write(ps->sd, buf, len); + if (nwrote < 0) { + if (errno == EPIPE || errno == EBADF) { + ps->state = PI_SOCK_CONN_BREAK; + return pi_set_error(ps->sd, PI_ERR_SOCK_DISCONNECTED); + } + return pi_set_error(ps->sd, PI_ERR_SOCK_IO); + } + total -= nwrote; + } + data->tx_bytes += len; + + /* hack to slow things down so that the Visor will work */ + usleep(10 + len); + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV TX unixserial wrote %d bytes\n", len)); + + return len; +} + + +/*********************************************************************** + * + * Function: s_read_buf + * + * Summary: read from data buffer + * + * Parameters: pi_socket_t*, pi_buffer_t* to buf, length to get + * + * Returns: number of bytes read + * + ***********************************************************************/ +static size_t +s_read_buf (pi_socket_t *ps, pi_buffer_t *buf, size_t len, int flags) +{ + struct pi_serial_data *data = + (struct pi_serial_data *)ps->device->data; + size_t rbuf = data->buf_size; + + if (rbuf > len) + rbuf = len; + + if (pi_buffer_append (buf, data->buf, rbuf) == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + if (flags != PI_MSG_PEEK) { + data->buf_size -= rbuf; + if (data->buf_size > 0) + memmove(data->buf, &data->buf[rbuf], data->buf_size); + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV RX unixserial read %d bytes from read-ahead buffer\n", rbuf)); + + return rbuf; +} + +/*********************************************************************** + * + * Function: s_read + * + * Summary: Read incoming data from the socket/file descriptor + * + * Parameters: pi_socket_t*, pi_buffer_t* to buf, expect length, flags + * + * Returns: number of bytes read or negative on error + * + ***********************************************************************/ +static ssize_t +s_read(pi_socket_t *ps, pi_buffer_t *buf, size_t len, int flags) +{ + ssize_t rbuf = 0, + bytes; + struct pi_serial_data *data = + (struct pi_serial_data *)ps->device->data; + struct timeval t; + fd_set ready; + + /* check whether we have at least partial data in store */ + if (data->buf_size) { + rbuf = s_read_buf(ps, buf, len, flags); + if (rbuf < 0) + return rbuf; + len -= rbuf; + if (len == 0) + return rbuf; + } + + /* If timeout == 0, wait forever for packet, otherwise wait till + timeout milliseconds */ + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + if (data->timeout == 0) + select(ps->sd + 1, &ready, 0, 0, 0); + else { + t.tv_sec = data->timeout / 1000; + t.tv_usec = (data->timeout % 1000) * 1000; + if (select(ps->sd + 1, &ready, 0, 0, &t) == 0) + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + + /* If data is available in time, read it */ + if (FD_ISSET(ps->sd, &ready)) { + if (flags == PI_MSG_PEEK && len > 256) + len = 256; + + if (pi_buffer_expect (buf, len) == NULL) { + errno = ENOMEM; + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + bytes = read(ps->sd, &buf->data[buf->used], len); + + if (bytes > 0) { + if (flags == PI_MSG_PEEK) { + memcpy(data->buf + data->buf_size, buf->data + buf->used, bytes); + data->buf_size += bytes; + } + buf->used += bytes; + data->rx_bytes += bytes; + rbuf += bytes; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV RX unixserial read %d bytes\n", bytes)); + } else if (bytes < 0) { + rbuf = bytes; + } + } else { + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, + "DEV RX unixserial timeout\n")); + data->rx_errors++; + errno = ETIMEDOUT; + return pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + } + + return rbuf; +} + +/*********************************************************************** + * + * Function: s_flush + * + * Summary: Flush incoming and/or outgoing data from the socket/file + * descriptor + * + * Parameters: ps is of type pi_socket that contains the sd member which is + * the file descriptor that the data in buf will be read. It + * also contains the read buffer. + * + * flags is of type int and can be a combination of + * PI_FLUSH_INPUT and PI_FLUSH_OUTPUT + * + * Returns: 0 + * + ***********************************************************************/ +static int +s_flush(pi_socket_t *ps, int flags) +{ + int fl; + char buf[256]; + struct pi_serial_data *data = (struct pi_serial_data *) ps->device->data; + + if (flags & PI_FLUSH_INPUT) { + /* clear internal buffer */ + data->buf_size = 0; + + /* flush pending data (we assume the socket is in blocking mode) */ + if ((fl = fcntl(ps->sd, F_GETFL, 0)) != -1) + { + fcntl(ps->sd, F_SETFL, fl | O_NONBLOCK); + while (recv(ps->sd, buf, sizeof(buf), 0) > 0) + ; + fcntl(ps->sd, F_SETFL, fl); + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV FLUSH unixserial flushed input buffer\n")); + } + return 0; +} + +#ifdef sleeping_beauty +/*********************************************************************** + * + * Function: s_delay + * + * Summary: Delay for a given period of time + * + * Parameters: seconds, microseconds + * + * Returns: Nothing + * + ***********************************************************************/ +static void +s_delay(time_t sec, suseconds_t usec) +{ + struct timeval tv; + + tv.tv_sec = sec; + tv.tv_usec = usec; + + select(0, 0, 0, 0, &tv); +} +#endif + + +/*********************************************************************** + * + * Function: s_changebaud + * + * Summary: Change the speed of the socket + * + * Parameters: pi_socket_t* + * + * Returns: 0 on success, negative otherwise + * + ***********************************************************************/ +static int +s_changebaud(pi_socket_t *ps) +{ + struct pi_serial_data *data = + (struct pi_serial_data *)ps->device->data; +#ifndef SGTTY + struct termios tcn; + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, + "DEV SPEED unixserial switch to %d bps\n", (int)data->rate)); + +#ifdef sleeping_beauty + s_delay(0, 200000); +#endif + /* Set the tty to the new speed */ + if (tcgetattr(ps->sd, &tcn)) + return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + + tcn.c_cflag = CREAD | CLOCAL | CS8; + cfsetspeed(&tcn, calcrate(data->rate)); + + if (tcsetattr(ps->sd, TCSADRAIN, &tcn)) + return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + +#else + struct sgttyb tcn; + + if (ioctl(ps->sd, TIOCGETP, &tcn)) + return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + + tcn.sg_ispeed = calcrate(data->rate); + tcn.sg_ospeed = calcrate(data->rate); + + if (ioctl(ps->sd, TIOCSETN, &tcn)) + return pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); +#endif + +#ifdef sleeping_beauty + s_delay(0, 200000); +#endif + return 0; +} + + +/*********************************************************************** + * + * Function: pi_serial_impl_init + * + * Summary: initialize function pointers for serial I/O operations + * + * Parameters: struct pi_serial_impl* + * + * Returns: void + * + ***********************************************************************/ +void +pi_serial_impl_init (struct pi_serial_impl *impl) +{ + impl->open = s_open; + impl->close = s_close; + impl->changebaud = s_changebaud; + impl->write = s_write; + impl->read = s_read; + impl->flush = s_flush; + impl->poll = s_poll; +} + + +/*********************************************************************** + * + * Function: calcrate + * + * Summary: validates the selected baudrate + * + * Paramters: buadrate + * + * Returns: POSIX defined baudrate constant or terminates the process + * if the requested baudrate is not supported. + * + ***********************************************************************/ +static speed_t +calcrate(int baudrate) +{ +#ifdef B50 + if (baudrate == 50) + return B50; +#endif +#ifdef B75 + if (baudrate == 75) + return B75; +#endif +#ifdef B110 + if (baudrate == 110) + return B110; +#endif +#ifdef B134 + if (baudrate == 134) + return B134; +#endif +#ifdef B150 + if (baudrate == 150) + return B150; +#endif +#ifdef B200 + if (baudrate == 200) + return B200; +#endif +#ifdef B300 + if (baudrate == 300) + return B300; +#endif +#ifdef B600 + if (baudrate == 600) + return B600; +#endif +#ifdef B1200 + if (baudrate == 1200) + return B1200; +#endif +#ifdef B1800 + if (baudrate == 1800) + return B1800; +#endif +#ifdef B2400 + if (baudrate == 2400) + return B2400; +#endif +#ifdef B4800 + if (baudrate == 4800) + return B4800; +#endif +#ifdef B9600 + if (baudrate == 9600) + return B9600; +#endif +#ifdef B19200 + else if (baudrate == 19200) + return B19200; +#endif +#ifdef B38400 + else if (baudrate == 38400) + return B38400; +#endif +#ifdef B57600 + else if (baudrate == 57600) + return B57600; +#endif +#ifdef B76800 + else if (baudrate == 76800) + return B76800; +#endif +#ifdef B115200 + else if (baudrate == 115200) + return B115200; +#endif +#ifdef B230400 + else if (baudrate == 230400) + return B230400; +#endif +#ifdef B460800 + else if (baudrate == 460800) + return B460800; +#endif + + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, + "DEV Serial CHANGEBAUD Unable to set baud rate %d\n", + baudrate)); + abort(); /* invalid baud rate */ + return 0; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/usb.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/usb.c new file mode 100644 index 00000000..050e52f5 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/usb.c @@ -0,0 +1,1099 @@ +/* + * $Id: usb.c,v 1.57 2009/05/25 04:19:46 desrod Exp $ + * + * usb.c: Interface layer to serial HotSync connections + * + * Copyright (c) 1996, 1997, D. Jeff Dionne & Kenneth Albanowski + * Copyright (c) 1999, Tilo Christ + * Copyright (c) 2005, Florent Pillet + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + * + * -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-usb.h" +#include "pi-net.h" +#include "pi-cmp.h" +#include "pi-error.h" +#include "pi-util.h" + +pi_protocol_t *pi_usb_protocol_dup (pi_protocol_t *prot); + +static int pi_usb_connect(pi_socket_t *ps, struct sockaddr *addr, + size_t addrlen); +static int pi_usb_bind(pi_socket_t *ps, struct sockaddr *addr, + size_t addrlen); +static int pi_usb_listen(pi_socket_t *ps, int backlog); +static int pi_usb_accept(pi_socket_t *ps, struct sockaddr *addr, + size_t *addrlen); +static int pi_usb_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len); +static int pi_usb_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len); +static int pi_usb_close(pi_socket_t *ps); + +static int USB_configure_visor (pi_usb_data_t *dev, u_int8_t *input_pipe, u_int8_t *output_pipe); +static int USB_configure_generic (pi_usb_data_t *dev, u_int8_t *input_pipe, u_int8_t *output_pipe); + +int pi_socket_init(pi_socket_t *ps); + +/* Protocol Functions */ +/*********************************************************************** + * + * Function: pi_usb_protocol_dup + * + * Summary: creates a new copy of a USB pi_protocol instance + * + * Parameters: pi_protocol_t* + * + * Returns: new pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +pi_protocol_t * +pi_usb_protocol_dup (pi_protocol_t *prot) +{ + pi_protocol_t *new_prot; + + ASSERT(prot != NULL); + + new_prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t)); + + if (new_prot != NULL) { + new_prot->level = prot->level; + new_prot->dup = prot->dup; + new_prot->free = prot->free; + new_prot->read = prot->read; + new_prot->write = prot->write; + new_prot->flush = prot->flush; + new_prot->getsockopt = prot->getsockopt; + new_prot->setsockopt = prot->setsockopt; + new_prot->data = NULL; + } + + return new_prot; +} + + +/*********************************************************************** + * + * Function: pi_usb_protocol_free + * + * Summary: frees USB pi_protocol instance + * + * Parameters: pi_protocol_t* + * + * Returns: void + * + ***********************************************************************/ +static void +pi_usb_protocol_free (pi_protocol_t *prot) +{ + ASSERT(prot != NULL); + + if (prot != NULL) + free(prot); +} + + +/*********************************************************************** + * + * Function: pi_usb_protocol + * + * Summary: creates a new USB pi_protocol instance + * + * Parameters: pi_device_t* + * + * Returns: new pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +static pi_protocol_t * +pi_usb_protocol (pi_device_t *dev) +{ + pi_protocol_t *prot; + pi_usb_data_t *data; + + ASSERT(dev != NULL); + + data = dev->data; + + prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t)); + + if (prot != NULL) { + prot->level = PI_LEVEL_DEV; + prot->dup = pi_usb_protocol_dup; + prot->free = pi_usb_protocol_free; + prot->read = data->impl.read; + prot->write = data->impl.write; + prot->flush = data->impl.flush; + prot->getsockopt = pi_usb_getsockopt; + prot->setsockopt = pi_usb_setsockopt; + prot->data = NULL; + } + + return prot; +} + +/*********************************************************************** + * + * Function: pi_usb_device_free + * + * Summary: frees USB pi_device instance + * + * Parameters: pi_device_t* + * + * Returns: void + * + ***********************************************************************/ +static void +pi_usb_device_free (pi_device_t *dev) +{ + pi_usb_data_t *data = (pi_usb_data_t *)dev->data; + + ASSERT(dev != NULL); + + if (data != NULL) + free(data); + if (dev != NULL) + free(dev); +} + + +/*********************************************************************** + * + * Function: pi_usb_device + * + * Summary: creates a new USB pi_device instance + * + * Parameters: pi_device_t* + * + * Returns: new pi_device_t* or NULL if operation failed + * + ***********************************************************************/ +pi_device_t * +pi_usb_device (int type) +{ + pi_device_t *dev; + pi_usb_data_t *data; + + dev = (pi_device_t *)malloc (sizeof (pi_device_t)); + if (dev != NULL) { + data = (pi_usb_data_t *)malloc (sizeof (struct pi_usb_data)); + if (data == NULL) { + free(dev); + dev = NULL; + } else { + dev->free = pi_usb_device_free; + dev->protocol = pi_usb_protocol; + dev->bind = pi_usb_bind; + dev->listen = pi_usb_listen; + dev->accept = pi_usb_accept; + dev->connect = pi_usb_connect; + dev->close = pi_usb_close; + + memset(data, 0, sizeof(struct pi_usb_data)); + data->rate = -1; + data->establishrate = -1; + data->establishhighrate = 0; + pi_usb_impl_init (&data->impl); + + dev->data = data; + } + } + + return dev; +} + +/*********************************************************************** + * + * Function: pi_usb_connect + * + * Summary: Connect socket to a given address + * + * Parameters: pi_socket_t*, sockaddr*, socket length + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +static int +pi_usb_connect(pi_socket_t *ps, struct sockaddr *addr, size_t addrlen) +{ + struct pi_usb_data *data = (pi_usb_data_t *)ps->device->data; + struct pi_sockaddr *pa = (struct pi_sockaddr *) addr; + int result, timeout; + size_t size; + + if (ps->type == PI_SOCK_STREAM) { + if (ps->protocol == PI_PF_SYS) { + data->establishrate = data->rate = 57600; + } else { + if (data->establishrate == -1) + get_pilot_rate(&data->establishrate, &data->establishhighrate); + + /* Mandatory CMP connection rate */ + data->rate = 9600; + } + } else if (ps->type == PI_SOCK_RAW) { + /* Mandatory SysPkt connection rate */ + data->establishrate = data->rate = 57600; + } + + result = data->impl.open(ps, pa, addrlen); + if (result < 0) + goto fail; + + data->timeout = timeout = ps->accept_to * 1000; + + if (data->impl.wait_for_device) { + result = data->impl.wait_for_device (ps, &timeout); + if (result <= 0) + goto fail; + } + + ps->raddr = malloc(addrlen); + memcpy(ps->raddr, addr, addrlen); + ps->raddrlen = addrlen; + ps->laddr = malloc(addrlen); + memcpy(ps->laddr, addr, addrlen); + ps->laddrlen = addrlen; + + if (ps->type == PI_SOCK_STREAM) { + switch (ps->cmd) { + case PI_CMD_CMP: + if ((result = cmp_tx_handshake(ps)) < 0) + goto fail; + size = sizeof(data->rate); + pi_getsockopt(ps->sd, PI_LEVEL_CMP, PI_CMP_BAUD, + &data->rate, &size); + if ((result = data->impl.changebaud(ps)) < 0) + goto fail; + break; + + case PI_CMD_NET: + if ((result = net_tx_handshake(ps)) < 0) + goto fail; + break; + } + } + ps->state = PI_SOCK_CONN_INIT; + ps->command = 0; + +fail: + return (result < 0) ? result : 0; +} + +/*********************************************************************** + * + * Function: pi_usb_bind + * + * Summary: Bind address to a local socket + * + * Parameters: pi_socket_t*, sockaddr*, socket length + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +static int +pi_usb_bind(pi_socket_t *ps, struct sockaddr *addr, size_t addrlen) +{ + struct pi_usb_data *data = (pi_usb_data_t *)ps->device->data; + struct pi_sockaddr *pa = (struct pi_sockaddr *) addr; + int result; + + /* this rate stuff is only useful on platforms where USB-serial adapters + * connect through the USB layer, not through a serial tty + */ + if (ps->type == PI_SOCK_STREAM) { + if (data->establishrate == -1) + get_pilot_rate(&data->establishrate, &data->establishhighrate); + + /* Mandatory CMP connection rate */ + data->rate = 9600; + } else if (ps->type == PI_SOCK_RAW) { + /* Mandatory SysPkt connection rate */ + data->establishrate = data->rate = 57600; + } + + result = data->impl.open(ps, pa, addrlen); + if (result < 0) + return result; + + ps->raddr = malloc(addrlen); + memcpy(ps->raddr, addr, addrlen); + ps->raddrlen = addrlen; + ps->laddr = malloc(addrlen); + memcpy(ps->laddr, addr, addrlen); + ps->laddrlen = addrlen; + + return 0; +} + +/*********************************************************************** + * + * Function: pi_usb_listen + * + * Summary: Prepare for incoming connections + * + * Parameters: pi_socket_t*, backlog + * + * Returns: 0 + * + ***********************************************************************/ +static int +pi_usb_listen(pi_socket_t *ps, int backlog) +{ + ps->state = PI_SOCK_LISTEN; + return 0; +} + +/*********************************************************************** + * + * Function: pi_usb_accept + * + * Summary: Accept an incoming connection + * + * Parameters: pi_socket_t*, sockaddr*, socket length + * + * Returns: pi_socket descriptor or negative on error + * + ***********************************************************************/ +static int +pi_usb_accept(pi_socket_t *ps, struct sockaddr *addr, size_t *addrlen) +{ + struct pi_usb_data *data = (pi_usb_data_t *)ps->device->data; + int result, + timeout; + size_t size; + + data->timeout = timeout = ps->accept_to * 1000; + + if (data->impl.wait_for_device) { + result = data->impl.wait_for_device (ps, &timeout); + if (result <= 0) + return result; + } + + /* Wait for data */ +#ifdef LINUX + /* + * Evilish kluge, some palm devices won't send the initial + * packets if we don't try and get them fairly quickly. + * + * Sending a 0 byte NET packet can get them talking again + * in some cases though. + */ + result = data->impl.poll(ps, 1000); + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s: %d, poll result: %d.\n", __FILE__, __LINE__, result)); + + if (result <= 0) { + char buf[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; + data->impl.write(ps, buf, sizeof (buf), 1000); + } +#endif + + result = data->impl.poll(ps, timeout); + if (result <= 0) { + if (result == 0) { + return(PI_ERR_SOCK_LISTENER); + } else { + return result; + } + } + + pi_socket_init(ps); + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s: %d, prot: 0x%x, type: 0x%x, cmd: 0x%x.\n", __FILE__, __LINE__, ps->protocol, ps->type, ps->cmd)); + if (ps->type == PI_SOCK_STREAM) { + struct timeval tv; + unsigned char cmp_flags; + + switch (ps->cmd) { + case PI_CMD_CMP: + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s: %d, cmp rx.\n", __FILE__, __LINE__)); + if ((result = cmp_rx_handshake(ps, data->establishrate, data->establishhighrate)) < 0) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "usb.c: cmp_rx_handshake returned %d\n", result)); + return result; + } + + /* propagate the long packet format flag to both command and non-command stacks */ + size = sizeof(cmp_flags); + pi_getsockopt(ps->sd, PI_LEVEL_CMP, PI_CMP_FLAGS, &cmp_flags, &size); + if (cmp_flags & CMP_FL_LONG_PACKET_SUPPORT) { + int use_long_format = 1; + size = sizeof(int); + pi_setsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_USE_LONG_FORMAT, + &use_long_format, &size); + ps->command ^= 1; + pi_setsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_USE_LONG_FORMAT, + &use_long_format, &size); + ps->command ^= 1; + } + + /* reconfigure the port to match the negotiated speed */ + size = sizeof(data->rate); + pi_getsockopt(ps->sd, PI_LEVEL_CMP, PI_CMP_BAUD, &data->rate, &size); + if (data->impl.changebaud != NULL) { + if ((result = data->impl.changebaud(ps)) < 0) + return result; + + /* handheld needs some time to reconfigure its port */ + tv.tv_sec = 0; + tv.tv_usec = 50000; + select(0, 0, 0, 0, &tv); + } + break; + + case PI_CMD_NET: + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "%s: %d, net rx.\n", __FILE__, __LINE__)); + if ((result = net_rx_handshake(ps)) < 0) + { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "usb.c: cmp_rx_handshake returned %d\n", result)); + return result; + } + break; + + default: + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "%s: %d, unknown rx %x.\n", __FILE__, __LINE__,ps->cmd)); + break; + } + ps->dlprecord = 0; + } + + data->timeout = 0; + ps->command = 0; + ps->state = PI_SOCK_CONN_ACCEPT; + return ps->sd; +} + +/*********************************************************************** + * + * Function: pi_usb_getsockopt + * + * Summary: get options on USB socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +pi_usb_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len) +{ + pi_usb_data_t *data = (pi_usb_data_t *)ps->device->data; + + switch (option_name) { + case PI_DEV_RATE: + if (*option_len != sizeof (data->rate)) + goto fail; + memcpy (option_value, &data->rate, sizeof (data->rate)); + break; + + case PI_DEV_ESTRATE: + if (*option_len != sizeof (data->establishrate)) + goto fail; + memcpy (option_value, &data->establishrate, + sizeof (data->establishrate)); + break; + + case PI_DEV_HIGHRATE: + if (*option_len != sizeof (data->establishhighrate)) + goto fail; + memcpy (option_value, &data->establishhighrate, + sizeof (data->establishhighrate)); + break; + + case PI_DEV_TIMEOUT: + if (*option_len != sizeof (data->timeout)) + goto fail; + memcpy (option_value, &data->timeout, + sizeof (data->timeout)); + break; + } + + return 0; + +fail: + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); +} + +/*********************************************************************** + * + * Function: pi_usb_setsockopt + * + * Summary: set options on USB socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +pi_usb_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len) +{ + pi_usb_data_t *data = (pi_usb_data_t *)ps->device->data; + + switch (option_name) { + case PI_DEV_ESTRATE: + if (*option_len != sizeof (data->establishrate)) + goto fail; + memcpy (&data->establishrate, option_value, + sizeof (data->establishrate)); + break; + + case PI_DEV_HIGHRATE: + if (*option_len != sizeof (data->establishhighrate)) + goto fail; + memcpy (&data->establishhighrate, option_value, + sizeof (data->establishhighrate)); + break; + + case PI_DEV_TIMEOUT: + if (*option_len != sizeof (data->timeout)) + goto fail; + memcpy (&data->timeout, option_value, + sizeof (data->timeout)); + break; + } + + return 0; + +fail: + errno = EINVAL; + return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); +} + + +/*********************************************************************** + * + * Function: pi_usb_close + * + * Summary: Close a connection, destroy the socket + * + * Parameters: pi_socket_t* + * + * Returns: 0 + * + ***********************************************************************/ +static int +pi_usb_close(pi_socket_t *ps) +{ + pi_usb_data_t *data = (pi_usb_data_t *)ps->device->data; + + if (ps->sd != 0) { + data->impl.close (ps); + ps->sd = 0; + } + + if (ps->laddr != NULL) { + free(ps->laddr); + ps->laddr = NULL; + } + if (ps->raddr != NULL) { + free(ps->raddr); + ps->raddr = NULL; + } + + return 0; +} + + +/* + * Start of the identification and init code. + */ + +/* + * This is the table of USB devices that we know about, what they are, and + * some flags. + * + * This table helps us determine whether a connecting USB device is one we'd + * like to talk to. + * + */ +pi_usb_dev_t known_devices[] = { + /* Sony */ + { + .vendor = 0x054c, + .product = 0x0038, + .idstr = "Sony S S320 and other Palm OS 3.5 devices", + .flags = USB_INIT_SONY_CLIE, + }, + + { + .vendor = 0x054c, + .product = 0x0066, + .idstr = "Sony T, SJ series, and other Palm OS 4.0 devices", + }, + + { + .vendor = 0x054c, + .product = 0x0095, + .idstr = "Sony S360", + }, + + { + .vendor = 0x054c, + .product = 0x000a, + .idstr = "Sony NR and other Palm OS 4.1 devices", + }, + + { + .vendor = 0x054c, + .product = 0x009a, + .idstr = "Sony NR70V/U", + .flags = USB_INIT_SONY_CLIE, + }, + + { + .vendor = 0x054c, + .product = 0x00da, + .idstr = "Sony NX", + }, + + { + .vendor = 0x054c, + .product = 0x00e9, + .idstr = "Sony NZ", + }, + + { + .vendor = 0x054c, + .product = 0x0144, + .idstr = "Sony UX", + }, + + { + .vendor = 0x054c, + .product = 0x0169, + .idstr = "Sony TJ", + .flags = USB_INIT_SONY_CLIE, + }, + + /* AlphaSmart */ + { + .vendor = 0x081e, + .product = 0xdf00, + .idstr = "Alphasmart Dana", + }, + + /* HANDSPRING (vendor 0x082d) */ + { + .vendor = 0x082d, + .product = 0x0100, + .idstr = "Visor, Treo 300", + .flags = USB_INIT_VISOR, + }, + + { + .vendor = 0x082d, + .product = 0x0200, + .idstr = "Treo", + }, + + { + .vendor = 0x082d, + .product = 0x0300, + .idstr = "Treo 600", + }, + + /* PalmOne, Palm Inc */ + { + .vendor = 0x0830, + .product = 0x0001, + .idstr = "m500", + }, + + { + .vendor = 0x0830, + .product = 0x0002, + .idstr = "m505", + }, + + { + .vendor = 0x0830, + .product = 0x0003, + .idstr = "m515", + }, + + { + .vendor = 0x0830, + .product = 0x0010, + }, + + { + .vendor = 0x0830, + .product = 0x0011, + }, + + { + .vendor = 0x0830, + .product = 0x0020, + .idstr = "i705", + }, + + { + .vendor = 0x0830, + .product = 0x0030, + .idstr = "Tungsten|Z", + }, + + { + .vendor = 0x0830, + .product = 0x0031, + .idstr = "Tungsten|W", + }, + + { + .vendor = 0x0830, + .product = 0x0040, + .idstr = "m125", + }, + + { + .vendor = 0x0830, + .product = 0x0050, + .idstr = "m130", + }, + + { + .vendor = 0x0830, + .product = 0x0051, + }, + + { + .vendor = 0x0830, + .product = 0x0052, + }, + + { + .vendor = 0x0830, + .product = 0x0053, + }, + + { + .vendor = 0x0830, + .product = 0x0060, + .idstr = "Tungsten series, Zire 71", + }, + + { + .vendor = 0x0830, + .product = 0x0061, + .idstr = "Zire 31, 72, Z22", + .flags = USB_INIT_TAPWAVE, + }, + + { + .vendor = 0x0830, + .product = 0x0062, + }, + + { + .vendor = 0x0830, + .product = 0x0063, + }, + + { + .vendor = 0x0830, + .product = 0x0070, + .idstr = "Zire", + }, + + { + .vendor = 0x0830, + .product = 0x0071, + }, + + { + .vendor = 0x0830, + .product = 0x0080, + .idstr = "m100", + .flags = USB_INIT_NONE, + }, + + { + .vendor = 0x0830, + .product = 0x0099, + }, + + { + .vendor = 0x0830, + .product = 0x0100, + }, + + /* GARMIN */ + { + .vendor = 0x091e, + .product = 0x0004, + .idstr = "IQUE 3600", + }, + + /* Kyocera */ + { + .vendor = 0x0c88, + .product = 0x0021, + .idstr = "7135 Smartphone", + }, + + { + .vendor = 0x0c88, + .product = 0xa226, + .idstr = "6035 Smartphone", + }, + + /* Tapwave */ + { + .vendor = 0x12ef, + .product = 0x0100, + .idstr = "Zodiac, Zodiac2", + .flags = USB_INIT_TAPWAVE, + }, + + /* ACEECA */ + { + .vendor = 0x4766, + .product = 0x0001, + .idstr = "MEZ1000", + }, + + /* Samsung */ + { + .vendor = 0x04e8, + .product = 0x8001, + .idstr = "i330", + }, +}; + +int +USB_check_device (pi_usb_data_t *dev, u_int16_t vendor, u_int16_t product) +{ + unsigned int i; + + for (i = 0; i < (sizeof (known_devices) / sizeof (known_devices[0])); i++) { + if (known_devices[i].vendor == vendor) { + if (!known_devices[i].product || + known_devices[i].product == product) { + dev->dev.flags |= known_devices[i].flags; + return 0; + } + } + } + + return -1; +} + + +/* + * Device configuration, ugh. + */ + +int +USB_configure_device (pi_usb_data_t *dev, u_int8_t *input_pipe, u_int8_t *output_pipe) +{ + int ret; + u_int32_t flags = dev->dev.flags; + + *input_pipe = 0xff; + *output_pipe = 0xff; + + /* + * Device specific magic incantations + * + * Many devices agree on talking only if you say the "magic" incantation first. + * Usually, it's a control request or a sequence of control requests + * + */ + + if (flags & USB_INIT_NONE) + return 0; + if (flags & USB_INIT_VISOR) + ret = USB_configure_visor (dev, input_pipe, output_pipe); + else if (flags & USB_INIT_SONY_CLIE) { + /* according to linux code, PEG S-300 awaits these two requests */ + /* USB_REQ_GET_CONFIGURATION */ + ret = dev->impl.control_request (dev, 0x80, 0x08, 0, 0, NULL, 1, 0); + if (ret < 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "usb: Sony USB_REQ_GET_CONFIGURATION failed (err=%08x)\n", ret)); + } + /* USB_REQ_GET_INTERFACE */ + ret = dev->impl.control_request (dev, 0x80, 0x0A, 0, 0, NULL, 1, 0); + if (ret < 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "usb: Sony USB_REQ_GET_INTERFACE failed (err=%08x)\n", ret)); + } + } else { + /* other devices will either accept or deny this generic call */ + ret = USB_configure_generic (dev, input_pipe, output_pipe); + if (ret < 0) { + return -1; + } + } + + /* query bytes available. Not that we really care, + but most devices expect to receive this before + they agree on talking to us. */ + if (!(flags & USB_INIT_TAPWAVE)) { + unsigned char ba[2] = { 0 }; + + ret = dev->impl.control_request (dev, 0xc2, GENERIC_REQUEST_BYTES_AVAILABLE, 0, 0, &ba[0], 2, 0); + if (ret < 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "usb: GENERIC_REQUEST_BYTES_AVAILABLE failed (err=%08x)\n", ret)); + /* configuration have to fail to skip this device - or LifeDrive(?) devices will hang */ + return -1; + } + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "GENERIC_REQUEST_BYTES_AVAILABLE returns 0x%02x%02x\n", ba[0], ba[1])); + } + + return 0; +} + +static int +USB_configure_visor (pi_usb_data_t *dev, u_int8_t *input_pipe, u_int8_t *output_pipe) +{ + int i, ret; + visor_connection_info_t ci; + + ret = dev->impl.control_request (dev, 0xc2, VISOR_GET_CONNECTION_INFORMATION, 0, 0, &ci, sizeof (ci), 0); + if (ret < 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "usb: VISOR_GET_CONNECTION_INFORMATION failed (err=%08x)\n", ret)); + } else { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "usb: VISOR_GET_CONNECTION_INFORMATION, num_ports=%d\n", ci.num_ports)); + if (ci.num_ports > 2) + ci.num_ports = 2; + for (i=0; i < ci.num_ports; i++) + { + char *function_str; + switch (ci.connections[i].port_function_id) + { + case VISOR_FUNCTION_GENERIC: + function_str="GENERIC"; + break; + case VISOR_FUNCTION_DEBUGGER: + function_str="DEBUGGER"; + break; + case VISOR_FUNCTION_HOTSYNC: + function_str="HOTSYNC"; + break; + case VISOR_FUNCTION_CONSOLE: + function_str="CONSOLE"; + break; + case VISOR_FUNCTION_REMOTE_FILE_SYS: + function_str="REMOTE_FILE_SYSTEM"; + break; + default: + function_str="UNKNOWN"; + break; + } + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "\t[%d] port_function_id=0x%02x (%s)\n", i, + ci.connections[i].port_function_id, + function_str)); + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "\t[%d] port=%d\n", i, + ci.connections[i].port)); + } + } + return ret; +} + +static int +USB_configure_generic (pi_usb_data_t *dev, u_int8_t *input_pipe, u_int8_t *output_pipe) +{ + int i, ret; + int hotsync = 0; + palm_ext_connection_info_t ci; + u_int32_t flags = dev->dev.flags; + + ret = dev->impl.control_request (dev, 0xc2, PALM_GET_EXT_CONNECTION_INFORMATION, 0, 0, &ci, sizeof (ci), 0); + if (ret < 0) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "usb: PALM_GET_EXT_CONNECTION_INFORMATION failed (err=%08x)\n", ret)); + } else { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "usb: PALM_GET_EXT_CONNECTION_INFORMATION, num_ports=%d, endpoint_numbers_different=%d\n", + ci.num_ports, + ci.endpoint_numbers_different)); + for (i=0; i < ci.num_ports; i++) { + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "\t[%d] port_function_id='%c%c%c%c'\n", i, + ci.connections[i].port_function_id[0], + ci.connections[i].port_function_id[1], + ci.connections[i].port_function_id[2], + ci.connections[i].port_function_id[3])); + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "\t[%d] port=%d\n", i, + ci.connections[i].port)); + + LOG((PI_DBG_DEV, PI_DBG_LVL_DEBUG, "\t[%d] endpoint_info=%d\n", i, + ci.connections[i].endpoint_info)); + if (!memcmp(ci.connections[i].port_function_id, "cnys", 4)) { + + /* found hotsync port */ + hotsync = 1; + + /* 'sync': we found the pipes to use for synchronization force + find_interfaces to select this one rather than another one */ + if (ci.endpoint_numbers_different) { + if (input_pipe) + *input_pipe = ci.connections[i].endpoint_info >> 4; + if (output_pipe) + *output_pipe = ci.connections[i].endpoint_info & 0x0f; + } else { + if (input_pipe) + *input_pipe = ci.connections[i].port; + if (output_pipe) + *output_pipe = ci.connections[i].port; + } + } + } + + if (!hotsync) { + LOG((PI_DBG_DEV, PI_DBG_LVL_ERR, "usb: PALM_GET_EXT_CONNECTION_INFORMATION - no hotsync port found.\n", ret)); + return -1; + } + } + + if (flags & USB_INIT_TAPWAVE) { + /* + * Tapwave: for Zodiac, the TwUSBD.sys driver on Windows sends + * the ext-connection-info packet two additional times. + */ + ret = dev->impl.control_request (dev, 0xc2, PALM_GET_EXT_CONNECTION_INFORMATION, 0, 0, &ci, sizeof (ci), 0); + ret = dev->impl.control_request (dev, 0xc2, PALM_GET_EXT_CONNECTION_INFORMATION, 0, 0, &ci, sizeof (ci), 0); + } + return ret; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/utils.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/utils.c new file mode 100644 index 00000000..eb2cc1c9 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/utils.c @@ -0,0 +1,413 @@ +/* + * $Id: utils.c,v 1.47 2006/10/12 14:21:23 desrod Exp $ + * + * utils.c: misc. stuff for dealing with packets. + * + * Portions Copyright (c) 1996, D. Jeff Dionne. + * Portions Copyright (c) 1996, Kenneth Albanowski + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <math.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ctype.h> +#include <string.h> + +#include "pi-debug.h" +#include "pi-source.h" + +void pi_timeout_to_timespec(int timeout, struct timespec *ts); +void get_pilot_rate(int *establishrate, int *establishhighrate); +int pi_timespec_to_timeout(const struct timespec *ts); +int pi_timeout_expired(const struct timespec *ts); +size_t palm_strftime(char *s, size_t max, const char *fmt, + const struct tm *tm); + +/* this routine ruthlessly stolen verbatim from Brian J. Swetland */ + +/*********************************************************************** + * + * Function: crc16 + * + * Summary: Implementation of the CRC16 Cyclic Redundancy Check + * + * Parameters: None + * + * Returns: CRC + NULL + * + ***********************************************************************/ +int crc16(unsigned char *ptr, int count) +{ + int crc, + i; + + crc = 0; + while (--count >= 0) { + crc = crc ^ (int) *ptr++ << 8; + for (i = 0; i < 8; ++i) + if (crc & 0x8000) + crc = crc << 1 ^ 0x1021; + else + crc = crc << 1; + } + return (crc & 0xFFFF); +} + +void get_pilot_rate(int *establishrate, int *establishhighrate) +{ + /* Default PADP connection rate */ + char *rate_env = getenv("PILOTRATE"); + if (rate_env) { + /* Establish high rate */ + if (rate_env[0] == 'H') { + *establishrate = atoi(rate_env + 1); + *establishhighrate = 1; + } else { + *establishrate = atoi(rate_env); + *establishhighrate = 0; + } + } + else { + *establishrate = -1; + } +} + +#ifndef HAVE_STRDUP +char *strdup(const char *s) +{ + char *result; + size_t size = strlen(s) + 1; + + if (!(result = malloc(size))) { + return NULL; + } + + memcpy(result, s, size); + + return result; +} +#endif + +/* Borrowed from GNU sh-utils, and then probably from GNU libc */ +#ifndef HAVE_PUTENV +#if HAVE_GNU_LD + # define environ __environ +#else + extern char **environ; +#endif + +/* Put STRING, which is of the form "NAME=VALUE", in the environment */ +int putenv(const char *string) +{ + const char *const name_end = strchr(string, '='); + register size_t size; + register char **ep; + + if (name_end == NULL) { + /* Remove the variable from the environment. */ + size = strlen(string); + for (ep = environ; *ep != NULL; ++ep) + if (!strncmp(*ep, string, size) + && (*ep)[size] == '=') { + while (ep[1] != NULL) { + ep[0] = ep[1]; + ++ep; + } + *ep = NULL; + return 0; + } + } + + size = 0; + for (ep = environ; *ep != NULL; ++ep) + if (!strncmp(*ep, string, name_end - string) + && (*ep)[name_end - string] == '=') + break; + else + ++size; + + if (*ep == NULL) { + static char **last_environ = NULL; + char **new_environ = + (char **) malloc((size + 2) * sizeof(char *)); + + if (new_environ == NULL) + return -1; + (void) memcpy((void *) new_environ, (void *) environ, + size * sizeof(char *)); + + new_environ[size] = (char *) string; + new_environ[size + 1] = NULL; + if (last_environ != NULL) + free((void *) last_environ); + last_environ = new_environ; + environ = new_environ; + } else + *ep = (char *) string; + + return 0; +} +#endif + +#ifdef OS2 +/* Replacement version of getenv(), because the one in the EMX 0.9c, fix03 + dist appears to be busted when called from inside a DLL. (MJJ) */ +char *getenv(const char *envar) +{ + APIRET rc; + unsigned char *envstring; + + /* just call the OS/2 function directly */ + rc = DosScanEnv(envar, &envstring); + if (rc) + return NULL; + else + return envstring; +} +#endif + + + +#ifndef HAVE_INET_ATON +/*********************************************************************** + * + * Function: inet_aton + * + * Summary: Manipulate our network address information + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +int inet_aton(const char *cp, struct in_addr *addr) +{ + register u_long val; + register int base; + register int n; + register char c; + u_int parts[4]; + register u_int *pp = parts; + + for (;;) { + /* Collect number up to ``.''. Values are specified as for + C: 0x=hex, 0=octal, other=decimal. */ + val = 0; + base = 10; + if (*cp == '0') { + if (*++cp == 'x' || *cp == 'X') + base = 16, cp++; + else + base = 8; + } + while ((c = *cp) != '\0') { + if (isascii(c) && isdigit(c)) { + val = (val * base) + (c - '0'); + cp++; + continue; + } + if (base == 16 && isascii(c) && isxdigit(c)) { + val = + (val << 4) + (c + 10 - + (islower(c) ? 'a' : + 'A')); + cp++; + continue; + } + break; + } + if (*cp == '.') { + /* Internet format: + a.b.c.d + a.b.c (with c treated as 16-bits) + a.b (with b treated as 24 bits) */ + + if (pp >= parts + 3 || val > 0xff) + return (0); + *pp++ = val, cp++; + } else + break; + } + /* Check for trailing characters. */ + if (*cp && (!isascii(*cp) || !isspace(*cp))) + return (0); + + /* Concoct the address according to the number of parts specified. */ + n = pp - parts + 1; + switch (n) { + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffff) + return (0); + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) + return (0); + val |= + (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (addr) + addr->s_addr = htonl(val); + return (1); +} +#endif + +char *printlong(unsigned long val) +{ + static char buf[5]; + + set_long(buf, val); + buf[4] = 0; + return buf; +} + +unsigned long makelong(char *c) +{ + int l = strlen(c); + char c2[4]; + + if (l >= 4) + return get_long(c); + memset(c2, ' ', 4); + memcpy(c2, c, (size_t)l); + return get_long(c2); +} + +double get_float(void *buffer) +{ + unsigned char *buf = buffer; + unsigned long frac = get_long(buf); + + int expr = get_sshort(buf + 4), + sign = get_byte(buf + 6); + + /* if (sign) f = frac; else f = -frac; return ldexp(f, exp); */ + return ldexp(sign ? (double) frac : -(double) frac, expr); +} + +void set_float(void *buffer, double value) +{ + int expr, + sign; + unsigned char *buf = buffer; + unsigned long frac; + double r; + + /* Take absolute */ + if (value < 0) { + sign = 0; + value = -value; + } else + sign = 0xFF; + + /* Convert mantissa to 32-bit integer, and take exponent */ + r = ldexp(frexp(value, &expr), 32); + frac = (unsigned long)r; + expr -= 32; + + /* Store values in buffer */ + set_long(buf, frac); + set_sshort(buf + 4, expr); + set_byte(buf + 6, sign); + set_byte(buf + 7, 0); +} + +int compareTm(struct tm *a, struct tm *b) +{ + int date; + + date = a->tm_year - b->tm_year; + if (date) + return date; + date = a->tm_mon - b->tm_mon; + if (date) + return date; + date = a->tm_mday - b->tm_mday; + if (date) + return date; + date = a->tm_hour - b->tm_hour; + if (date) + return date; + date = a->tm_min - b->tm_min; + if (date) + return date; + date = a->tm_sec - b->tm_sec; + return date; +} + +void pi_timeout_to_timespec(int timeout, struct timespec *ts) +{ + /* convert a timeout value (in milliseconds) to an absolute timespec */ + struct timeval now; + gettimeofday(&now, NULL); + ts->tv_sec = now.tv_sec + (long)(timeout / 1000); + ts->tv_nsec = (now.tv_usec + ((long)timeout % 1000) * 1000) * 1000; + if (ts->tv_nsec >= 1000000000) { + ts->tv_nsec -= 1000000000; + ts->tv_sec++; + } +} + +int pi_timespec_to_timeout(const struct timespec *ts) +{ + /* convert an absolute timespec to a timeout value (in milliseconds) from now + * returns a negative if the timeout expired already + */ + struct timeval now; + gettimeofday(&now, NULL); + return (int)(((double)ts->tv_sec * 1000.0 + (double)ts->tv_nsec / 1000000.0) - + ((double)now.tv_sec * 1000.0 + (double)now.tv_usec / 1000.0)); +} + +int pi_timeout_expired(const struct timespec *ts) +{ + return pi_timespec_to_timeout(ts) <= 0; +} + +/* Fix some issues with some locales reporting 2 or 4 digit years */ +size_t palm_strftime(char *s, size_t max, const char *fmt, + const struct tm *tm) { + + return strftime(s, max, fmt, tm); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/veo.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/veo.c new file mode 100644 index 00000000..3a8489df --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/veo.c @@ -0,0 +1,165 @@ +/* + * $Id: veo.c,v 1.7 2006/10/12 14:21:23 desrod Exp $ + * + * veo.c: Translate veo traveler data formats + * + * Copyright (c) 2002, Angus Ainslie + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pi-macros.h" +#include "pi-veo.h" + +/*********************************************************************** + * + * Function: free_Veo + * + * Summary: Free the memory and filehandle from the record alloc. + * + ***********************************************************************/ +void +free_Veo( Veo_t *veo ) +{ +} + +/*********************************************************************** + * + * Function: unpack_Veo + * + * Summary: Unpack the Veo structure into records we can chew on + * + ***********************************************************************/ +int +unpack_Veo(Veo_t *veo, unsigned char *buffer, size_t len) +{ + unsigned char *start = buffer; + + /* consume unknown */ + buffer += 1; + veo->quality = (unsigned char) get_byte(buffer); + buffer += 1; + veo->resolution = (unsigned char) get_byte(buffer); + buffer += 1; + /* consume 12 more unknowns */ + buffer += 12; + veo->picnum = (unsigned long int) get_long(buffer); + buffer += 4; + veo->day = (unsigned short int) get_short(buffer); + buffer += 2; + veo->month = (unsigned short int) get_short(buffer); + buffer += 2; + veo->year = (unsigned short int) get_short(buffer); + buffer += 2; + + if( veo->resolution == 0 ) + { + veo->width = 640; + veo->height = 480; + } + else if( veo->resolution == 1 ) + { + veo->width = 320; + veo->height = 240; + } + else + fprintf( stderr, "unknown resolution\n" ); + + return ( buffer - start ); /* FIXME: return real length */ +} + + +/*********************************************************************** + * + * Function: pack_Veo + * + * Summary: Pack the Veo records into a structure + * + ***********************************************************************/ +int pack_Veo(Veo_t *veo, unsigned char *buf, size_t len) +{ + return( 0 ); +} + + +/*********************************************************************** + * + * Function: unpack_VeoAppInfo + * + * Summary: Unpack the Veo AppInfo block from the structure + * + ***********************************************************************/ +int unpack_VeoAppInfo(struct VeoAppInfo *appinfo, unsigned char *record, + size_t len) +{ + int i; + unsigned char *start = record; + + i = unpack_CategoryAppInfo( &appinfo->category, record, len ); + if (!i) + return 0; + record += i; + len -= i; + if (len < 4) + return 0; + appinfo->dirty = get_short(record); + record += 2; + appinfo->sortByPriority = get_byte(record); + record += 2; + return (record - start); +} + + +/*********************************************************************** + * + * Function: pack_VeoAppInfo + * + * Summary: Pack the AppInfo block/record back into the structure + * + ***********************************************************************/ +int +pack_VeoAppInfo(struct VeoAppInfo *appinfo, unsigned char *record, size_t len) +{ + int i; + unsigned char *start = record; + + i = pack_CategoryAppInfo(&appinfo->category, record, len); + if (!record) + return i + 4; + if (!i) + return 0; + record += i; + len -= i; + if (len < 4) + return 0; + set_short(record, appinfo->dirty); + set_byte(record + 2, appinfo->sortByPriority); + set_byte(record + 3, 0); /* gapfill */ + record += 4; + + return (record - start); +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ + diff --git a/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/versamail.c b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/versamail.c new file mode 100644 index 00000000..3ceb6686 --- /dev/null +++ b/debian/pilot-link/pilot-link-0.12.5-dfsg/libpisock/versamail.c @@ -0,0 +1,394 @@ +/* + * $Id: versamail.c,v 1.11 2006/10/12 14:21:23 desrod Exp $ + * + * versamail.c: Translate VersaMail data formats + * + * Copyright (c) 2004, Nick Piper + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include "pi-macros.h" +#include "pi-versamail.h" + + +/* + +Todo: What is unknown1 and 2? + What is reserved 1 and 2? + What is download ? (It's non zero, when there is more to d/l, + and appears to be an ID, allocated + by VersaMail. Maybe an index into another db?) + How do we do attachments ? They are not kept in-line, but in another db. + Attachments are related to unknown3. + Why is mark = 2, when there is no mark set, and 3 when it is? + +*/ + +void free_VersaMail(struct VersaMail *a) +{ + if (a->messageUID) + free(a->messageUID); + if (a->to) + free(a->to); + if (a->from) + free(a->from); + if (a->cc) + free(a->cc); + if (a->bcc) + free(a->bcc); + if (a->subject) + free(a->subject); + if (a->dateString) + free(a->dateString); + if (a->body) + free(a->body); + if (a->replyTo) + free(a->replyTo); + if (a->unknown3) + free(a->unknown3); +} + + + +#define SHUFFLE_BUFFER(shuffle_distance) { \ + len -= shuffle_distance; \ + buffer += shuffle_distance; \ + } + +#define GET_BYTE_INTO(attrib) { \ + attrib = get_byte(buffer); \ + SHUFFLE_BUFFER(1); \ + } + +#define GET_SHORT_INTO(attrib) { \ + attrib = (unsigned int) get_short(buffer); \ + SHUFFLE_BUFFER(2); \ + } + +#define GET_STR_INTO(attrib) { \ + if (get_byte(buffer)) { \ + attrib = strdup(buffer); \ + SHUFFLE_BUFFER(strlen(buffer)); \ + } else { \ + attrib = NULL; \ + }; \ + buffer++; \ + len--; \ + } + +#define PUT_STR_FROM(attrib) { \ + if (attrib) { \ + strcpy(buffer, attrib); \ + SHUFFLE_BUFFER(strlen(buffer)); \ + } else \ + set_byte(buffer, 0); \ + buffer++; \ + len--; \ + } + + +#define ADD_LENGTH(str, destlen) { \ + if (str) { \ + destlen += 1+strlen(str); \ + } else { \ + destlen++; \ + }; \ + } \ + +#define CONVERT_TIME_T_PALM_TO_UNIX(t) (t=t-2082844800) +#define CONVERT_TIME_T_UNIX_TO_PALM(t) (t=t+2082844800) + +int unpack_VersaMail(struct VersaMail *a, char *buffer, size_t len) +{ + time_t date_t; + struct tm *date_tm; + char *start = buffer; + + /* 000000 - 000003 */ + a->imapuid = (unsigned long) get_long(buffer); + SHUFFLE_BUFFER(4); + + + /* This is different to the other databases, because Palm didn't + write VersaMail :-) */ + /* 000004 - 000007 */ + date_t = (time_t) get_long(buffer); + CONVERT_TIME_T_PALM_TO_UNIX(date_t); + date_tm = localtime(&date_t); + memcpy(&(a->date), date_tm, sizeof(struct tm)); + SHUFFLE_BUFFER(4); + + /* 000008 - 000009 */ + GET_SHORT_INTO(a->category); + + /* 00000A - 00000B */ + GET_SHORT_INTO(a->accountNo); + + /* 00000C - 00000D */ + GET_SHORT_INTO(a->unknown1); + /* 00000E - 00000E */ + GET_BYTE_INTO(a->download); + /* 00000F - 00000F */ + GET_BYTE_INTO(a->mark); + /* of the above, bit 0 is mark, apparently bit 4 is header-only flag, + and it looks like bit 1 is always set, which gives a normal + value of 2 */ + + /* 000010 - 000011 */ + GET_SHORT_INTO(a->unknown2); + + /* 000012 - 000013 */ + a->reserved1 = (get_byte(buffer)); + a->reserved2 = (get_byte(buffer + 1) >> 1); + a->read = (get_byte(buffer + 1) && 1); + SHUFFLE_BUFFER(2); + + /* This is the size, as provided by the imap server: + * 1 FETCH (UID 12779 BODY[] {3377} .... ) + Size==3377 + I guess VersaMail uses it to determine how much + more there might be to download. I don't think it uses it + to know there IS more to download though, because + the palm doesn't track most of the headers, so it'll never + be able to calculate if there is more or not, exactly. + */ + + /* 000014 - 000017 */ + a->msgSize = get_long(buffer); + SHUFFLE_BUFFER(4); + + GET_STR_INTO(a->messageUID); + GET_STR_INTO(a->to); + GET_STR_INTO(a->from); + GET_STR_INTO(a->cc); + GET_STR_INTO(a->bcc); + GET_STR_INTO(a->subject); + GET_STR_INTO(a->dateString); + GET_STR_INTO(a->body); + GET_STR_INTO(a->replyTo); + + a->unknown3length = 0; + a->unknown3 = NULL; + a->attachmentCount = 0; + if (len > 0) { + a->unknown3 = (void *) malloc(len); + + /* + printf("Msg has extra %d bytes. That's 4*%d + %d\n", + len, len / 4, len % 4); + */ + + + /* + Example: + + Byte 0: 0x 43 | C | 67 / Variable amount of 'rubbish' + Byte 1: 0x 50 | P | 80 \ NOT neccessary !NULL + Byte 2: 0x 0 | . | 0 / + Byte 3: 0x 68 | h | 104 | Each attachment adds four bytes, + Byte 4: 0x ffffffc0 | . | -64 | NULL, an int, then two signed ints + Byte 5: 0x ffffff90 | . | -112 \ + Byte 6: 0x 0 | . | 0 / + Byte 7: 0x 68 | h | 104 | + Byte 8: 0x ffffffc0 | . | -64 | + Byte 9: 0x ffffff92 | . | -110 \ + Byte 10: 0x 0 | . | 0 / + Byte 11: 0x 68 | h | 104 | + Byte 12: 0x ffffffc0 | . | -64 | + Byte 13: 0x ffffff94 | . | -108 \ + Byte 14: 0x 0 | . | 0 / + Byte 15: 0x 0 | . | 0 | Then we end with a block of + Byte 16: 0x 0 | . | 0 | four NULLs + Byte 17: 0x 0 | . | 0 \ + + The 'rubbish' doesn't seem to be for alignment within the pdb, AFAIKS. + */ + + a->attachmentCount = (len / 4) - 1; + if (a->unknown3) { + a->unknown3length = len; + memcpy(a->unknown3, buffer, len); + SHUFFLE_BUFFER(len); + } + } + + return (buffer - start); +} + +int pack_VersaMail(struct VersaMail *a, char *buffer, size_t len) +{ + time_t date_t; + unsigned int destlen; + char *start = buffer; + + destlen = 4 + 4 + 2 + 2 + 2 + 2 + 2 + 2 + 4 + a->unknown3length; + + ADD_LENGTH(a->messageUID, destlen); + ADD_LENGTH(a->to, destlen); + ADD_LENGTH(a->from, destlen); + ADD_LENGTH(a->cc, destlen); + ADD_LENGTH(a->bcc, destlen); + ADD_LENGTH(a->subject, destlen); + ADD_LENGTH(a->dateString, destlen); + ADD_LENGTH(a->body, destlen); + ADD_LENGTH(a->replyTo, destlen); + + if (!buffer) + return destlen; + + if (len < destlen) + return 0; + + set_long(buffer, a->imapuid); + SHUFFLE_BUFFER(4); + + date_t = mktime(&(a->date)); + CONVERT_TIME_T_UNIX_TO_PALM(date_t); + set_long(buffer, (unsigned long) date_t); + SHUFFLE_BUFFER(4); + + set_short(buffer, a->category); + SHUFFLE_BUFFER(2); + set_short(buffer, a->accountNo); + SHUFFLE_BUFFER(2); + set_short(buffer, a->unknown1); + SHUFFLE_BUFFER(2); + set_byte(buffer, a->download); + SHUFFLE_BUFFER(1); + set_byte(buffer, a->mark); + SHUFFLE_BUFFER(1); + set_short(buffer, a->unknown2); + SHUFFLE_BUFFER(2); + + set_byte(buffer, a->reserved1); + set_byte(buffer + 1, ((a->reserved2 << 1) || a->read)); + SHUFFLE_BUFFER(2); + + set_long(buffer, a->msgSize); + SHUFFLE_BUFFER(4); + + PUT_STR_FROM(a->messageUID); + PUT_STR_FROM(a->to); + PUT_STR_FROM(a->from); + PUT_STR_FROM(a->cc); + PUT_STR_FROM(a->bcc); + PUT_STR_FROM(a->subject); + PUT_STR_FROM(a->dateString); + PUT_STR_FROM(a->body); + PUT_STR_FROM(a->replyTo); + + if (a->unknown3length > 0) { + memcpy(buffer, a->unknown3, a->unknown3length); + } + + return (buffer - start); +} + +int unpack_VersaMailAppInfo(struct VersaMailAppInfo *ai, + unsigned char *record, size_t len) +{ + int i; + unsigned char *start = record; + + i = unpack_CategoryAppInfo(&ai->category, record, len); + if (!i) + return i; + record += i; + len -= i; + + return (record - start); +} + +/* + +Message provided to the maintainer of pilot-mailsync: +(the above implementation does not fully agree, BTW) + +-------- Original Message -------- +Subject: Re: QueueSync2.0 +Date: Sat, 31 Jan 2004 03:19:28 +0900 +From: Masaru matsumoto <matumoto@queuesoft.jp> +To: Jochen Garcke <jochen@garcke.de> +References: <401A7AE7.5090109@garcke.de> + +Hi, + +The definition of the database is to refer to the following. +But, because I analyzed it, it has the possibility to be wrong. +Write only information on VersaMail. Because there are many problems in +ClieMail. + + +typedef struct +{ + UInt16 mu_reserved1 : 8; + UInt16 mu_reserved2 : 7; + UInt16 mu_read : 1; +} mu_MailFlagsType; + +typedef struct { + UInt32 mu_version; + UInt32 mu_datetime; + UInt16 mu_category; + UInt16 mu_account_no; + UInt16 mu_rfu1; + UInt16 mu_mark; + UInt16 mu_rfu2; + mu_MailFlagsType mu_flags; + UInt32 mu_msgSize; + char mu_firstField; +} mu_MailPackedDBRecordType; + +typedef mu_MailPackedDBRecordType * mu_MailPackedDBRecordPtr; + + +mu_msgSize = +strlen(subject)+strlen(contents)+strlen(dateString)+strlen(replyto)+4; + +Field sequence : +messageUID +to +from +cc +bcc +subject +dateString +body +replayTo + +*/ + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* ex: set tabstop=4 expandtab: */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ |