Initial commit

This commit is contained in:
crt0mega 2020-09-15 21:16:28 +02:00
commit 8c52e5dba8
76 changed files with 24269 additions and 0 deletions

21
.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
Makefile.in
Makefile
aclocal.m4
configure
config.h.in
config.h
config.log
config.cache
config.status
install-sh
missing
mkinstalldirs
stamp-h.in
stamp-h
autom4te.cache
debian/autoreconf.after
debian/autoreconf.before
debian/debhelper-build-stamp
debian/*.ex
debian/ic35link
debian/.debhelper

5
AUTHORS Normal file
View File

@ -0,0 +1,5 @@
IC35Link was written by Thomas Schulz,
see the file THANKS about contributions.
Thomas Schulz <t.schulz@d2mail.de>

340
COPYING Normal file
View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

683
ChangeLog Normal file
View File

@ -0,0 +1,683 @@
$Id: ChangeLog,v 1.26 2001/11/20 23:26:42 thosch Exp $
ChangeLog for IC35 communication
================================
2001-11-10 version 1.18.1 (CVS only)
* ic35mgr.c,mgrtrans.c,mgrtrans.h,mgrproto.h,mgrproto.c: new ic35mgr
commands "mmcgettree","mmcputtree" for transfer whole directory tree
contributed by Hans-Michael Stahl <hm.stahl@berlin.de>
2001-08-12 version 1.18 IC35LINK-1-18
long pending release with several improvements and corrections
according to suggestions and bug reports by users.
improvements:
- improved README: table of contents, restrictions, more explanations
- ic35mgr restore and MMC write 30% faster (proposal by Harald Becker)
- ic35sync, ic35mgr, vcaconv now support long options, e.g. "--help"
info enquiry with "--help" or "--version" now returns exitcode 0
- new autogen.sh script for generate configure etc. after CVS checkout
(thanks Konrad Mader for report about missing configure in CVS)
- new configure option "--disable-logandcomsim" for conditional compile
without logging and com-simulation (proposal by Harald Becker)
- new configure options "--enable-ansi" and "--enable-pedantic"
bugfixes:
- fixed problem where ic35sync with many (ca. 860) addresses failed
(thanks Konrad Mader for bug report "get_mod_flen failed")
- ic35sync now accepts also empty PIMfile(s), e.g. empty ic35.memo
(thanks Malte Schmidt for bug report "ic35.memo: parse error")
- ic35mgr MMCard functions now check ic35path before accessing IC35
e.g. warn if shell eat backslash (\) in unquoted MMCard1\test.txt
(thanks Thomas Lichtenberg for bug report)
- restricted ic35mgr to max.blocksize 16350 found by experiments
- ic35sync, ic35mgr now abort on open failure of logfile or simfile
- fixed com-simulation for adjacent "RD nn" lines and non-logged bytes
- fixed compile problem util.c with Linux Mandrake-8.0 and SuSE-7.2
(thanks Christian Theile, Karl Stroetmann for bug reports)
- corrected warnings from "--enable-ansi" and "--missing-prototypes"
- fixed all Makefile.am: maintainer-clean keeps only sources in CVS,
install also README and COPYING, clean dependencies and versinfo.c
2001-08-12_05
* Makefile.am: maintainer-clean delete also INSTALL, as not in CVS
* autogen.sh: clearified CONFIGURE_FLAGS and NOCONFIGURE
* README: didactic reordering, explain autogen.sh maintainer-mode,
initial test with 'ic35sync status', tested some more platforms
2001-08-02_22
* autogen.sh: new script for generating configure and Makefile.in etc.
thanks Konrad Mader <konrad.mader@gmx.de> for problem report about
configure missing in CVS
* README: explain when and how to use autogen.sh
2001-06-18_01 version 1.17.6 (CVS only)
* synproto.c: timeout 2.0 sec for L1-ack1 response on L1-command
thanks Konrad Mader <konrad.mader@gmx.de> for bug report where
sync of ca. 860 addresses caused "get_mod_flen failed"
2001-06-09_11
* util.c: explicitely #include <time.h>, as using localtime() etc.
thanks Christian Theile <ch_theile@gmx.de> for bug report with
Mandrake 8.0 gcc 2.96
2001-03-03_04
* ic35mgr.c,comio.c,comio.h: new option "--nice=NICEVAL" to lower
process priority with restore,mmcput, default "--nice=2", works
like builtin 'nice -n 2 ic35mgr mmcput ..", see nice(1).
(proposal from Harald Becker)
2001-03-02_02 version 1.17.5 (CVS only)
* configure.in,README: new configure option "--disable-logandcomsim"
(proposal from Harald Becker)
* ic35sync.c,dataio.c,databin.c,datavca.c,ic35frec.c,syntrans.c,
ic35mgr.c,mgrtrans.c,mgrproto.c,comio.{c,h},util.{c,h}:
conditional compile for logging and com-simulation (default enabled)
* ic35sync.c,ic35mgr.c,comio.c,util.c:
log_init(),com_siminit() abort program on failure opening file
* util.{c,h}: new fatal() reports error message and aborts program
2001-02-22_05
* datavca.c bugfix: accept also empty PIMfile(s), e.g. empty ic35.memo
ic35sync creates empty ic35.memo if IC35 has no memo records, and
next call ic35sync complained "vCard/vCal "ic35.memo": parse error"
(thanks Malte Schmidt for bug report)
* README: explain 1..3 PIMfiles, more details about export,import,sync
2001-02-19_19
* comio.c: com_sendw() delay with busy wait instead of interval timer
increased write MMCard file throughput to 1740 b/s (with 2kB blocks)
(thanks Harald Becker)
* ic35mgr.c: max.blocksize 16350 for MMC read/write found by experiments
* mgrproto.c: timeout 5.0 sec for response length needed with big blocks
2001-02-19_02 version 1.17.4 (CVS only)
* ic35mgr.c: MMCard functions now check ic35path before accessing IC35
(thanks Thomas Lichtenberg for bug report)
* comio.c: fixed com_simrecv() adjacent "RD nn" lines, non-logged bytes
* README: remarks about install-strip and uninstall
* all Makefile.am: maintainer-clean keeps only sources under CVS
* .cvsignore,src/.cvsignore: added missing config.log, programs, .deps
2001-02-17_21 version 1.17.3 (CVS only)
* ic35sync.c,ic35mgr.c,vcaconv.c: support long options, e.g. "--help"
info enquiry with "--help" or "--version" now returns exitcode 0
* ic35sync.c,ic35mgr.c,comio.h,comio.c,util.h,util.c:
error exit on open failure of logfile or simfile
* README: 'configure --enable-ansi' is ok, warning '--enable-pedantic'
successful tests on some more platforms (thanks Thomas Lichtenberg)
restrictions of ic35sync and ic35mgr
* configure.in: pass revision info to configure
* Makefile.am: install also README and COPYING
* src/Makefile.am: clean dependencies and versinfo.c
2001-02-10_04 version 1.17.1 (CVS only)
* configure.in: separate "ansi" and "pedantic" gcc compile options
* ic35sync.c,ic35mgr.c,datavca.c,port.h,vcc.y,comio.c:
corrected warnings from "-ansi" compile
* util.c,util.h,comio.c,comio.h:
local substitutes for functions missing with "-ansi" compile
2001-02-07_04
* configure.in: more compile warnings with "--missing-prototypes"
* databin.c,mgrtrans.c,vcc.y,vobject.c:
corrected warnings from "--missing-prototypes"
* README: table of contents, warning about 'configure --enable-ansi'
2001-02-05_03 IC35LINK-1-17
package renamed to "ic35link" and automake/autoconf/CVS reorganization.
no changes in sources, programs are unchanged except for version (and
except for compile with -O2 instead of -O due to automake/autoconf).
new files:
NEWS release information
AUTHORS authors
THANKS contributors
configure.in input for autoconf to create configure
Makefile.am input for automake to create Makefile.in
.cvsignore topdir CVS ignore patterns
doc/ subdirectory with documentation
doc/Makefile.am input for automake to create doc/Makefile.in
doc/.cvsignore CVS ignore patterns
src/ subdirectory with sources
src/Makefile.am input for automake to create doc/Makefile.in
src/.cvsignore CVS ignore patterns
2001-02-04_02 IC35SYNC-1-16
this is a bugfix and redesign release and is the last named "ic35sync".
(the package will be renamed to "ic35link" in the next release, when
the reorganizations for automake/autoconf and public CVS are done.)
improvements and redesign:
- ic35sync,ic35mgr,vcaconv now report package version and build info
- distribution includes vcc.c to handle missing/bad 'bison' or 'yacc'
(e.g. SuSE-7.0's yacc produced bad vcc.o, thanks Michael Bruennert)
- reworked and clearified the IC35 manager protocol documentation and
implementation (see ic35mgr.txt, mgrtrans.*, mgrproto.*), refer to
the IC35 SoftwareDevelopmentKit API MMCard functions in mgrproto.c
bugfixes in ic35mgr and ic35sync:
- fixed compile error RedHat-7.0 gcc-2.96 (thanks Dieter Schultschik)
- corrections for 'ic35mgr status' (thanks Michael Bruennert):
mgrtrans.c:status() tries to get IC35 response instead of only wait
mgrproto.c:MMCsend() sends blocklength with initial wait
corrected output of MMCard2 label
- ic35mgr commands backup and restore show error messages on new line
- avoid failing 'ic35mgr restore ..' at "disconnect" by delay 3.25 sec
after writedatabase() done
- avoid failure of 'ic35mgr mmcput file' with occasional slow IC35
MMCard write with 3.5 sec timeout for length of response block
- corrected MMC closedir,closefile response PDUs having no status-word
- corrected to make 'ic35sync status' work also with simulation file
2001-02-04_01
* ic35sync.c,ic35mgr.c,vcaconv.c,Makefile:
import version info from auto-generated "versinfo.c"
all programs now report the common package version
* util.{c,h}: new log_proginfo(),log_argsinfo() used
by ic35sync.c,ic35mgr.c for initial info in logfile
* ic35sync.c: corrected com_siminit() before status command
* Makefile: include vcc.c in distribution to avoid bison/yacc problems
2001-02-03_20
* mgrproto.h,mgrtrans.h: moved MMC file attributes and open modes
from mgrtrans.h to mgrproto.h as needed for MMCxxxx() functions
* mgrproto.c,mgrtrans.c: common conversions functions for FILE_INFO
import FIDENSZ for accurate size of FILE_IDEN from IC35 SDK Mmc.h
* ic35mgr.txt: incorporated protocol corrections due to experience
2001-01-30_01
* mgrproto.c: need 3.5 sec timeout for length of response block
2001-01-29_13
* fixed compile error gcc-2.96 RedHat-7.0 (thanks Dieter Schultschik):
synproto.c now passes 'int' instead of 'ushort to 'va_arg', because
`short unsigned int' is promoted to `int' when passed through `...'
* mgrproto.h,mgrproto.c,mgrtrans.c:
new MMCard command functions MMCxxxx() replace sendmcmd(),recvmcmd()
for better prototype check and avoid the gcc-2.96 RedHat-7.0 problem
refer to IC35 SoftwareDevelopmentKit API MMCard functions
* synproto.c,mgrproto.c,ic35frec.c offsetof,alenof macros now in util.h
2001-01-27_05
* bugfix "ic35mgr status" (thanks to Michael Bruennert):
mgrtrans.c:status() tries to get IC35 response instead of only wait
mgrproto.c:MMCsend() sends blocklength with initial wait
ic35mgr.c: corrected MMCard2 label output
* ic35mgr.c,util.{c,h}: extracted _not_impl() to util.{c,h}
2001-01-25_05
* mgrtrans.c,mgrproto.c,ic35mgr.txt:
corrected: closedir,closefile response PDUs do not have status-word
* mgrtrans.c: backup,restore show error messages on new line
writedatabase() delays 3.25 sec to avoid failure in mdisconnect()
* mgrtrans.c,mgrproto.c,mgrproto.h,genproto.h:
reorganized manager protocol, new Mcmdrsp(),Msendblk(),Mrecvblk()
* ic35mgr.txt: described and incorporated basic protocol operations
2001-01-21_21
* genproto.c,genproto.h,Makefile,README:
new module genproto.{c,h} - general IC35 protocol support
* synproto.c,mgrproto.c: import PDU encode/decode with genproto.h
* syntrans.c,mgrtrans.c: import general welcome() with genproto.h
2001-01-20_03 IC35SYNC-1-15
new IC35 manager 'ic35mgr' supports access of IC35 MMCard(s)
- command "mmcdir" lists contents of MMCard(s)
- commands "mmcget","mmcput","mmcdel" read,write,delete MMCard file
- commands "backup","restore" IC35 organizer database
- ic35mgr.txt now really describes the IC35 manager protocol
(previously it was just extracts of Windows 'portmon' logfiles)
bugfixes in ic35sync and vcaconv:
- "ic35sync sync" now updates record if on IC35, else writes new record
- "vcaconv sortvca ic35.vcal" did produce empty output, fixed vobject.c
- fixed vcc.y compile warnings
- "vcaconv sortvca .." improved: shows properties in sort order sequence
todo:
- ic35mgr install application on IC35
- ic35sync initial sync does not yet write all records to IC35
workaround: do "ic35sync import .." before first "ic35sync sync .."
* ic35mgr.c: fixed compile warning with unused _not_impl()
2001-01-18_02
* comio.{c,h},mgrproto.c,mgrtrans.c:
new com_sendw() - send datablock with waiting (for slow MMCard ops)
com_send() does send without delays at full speed
* mgrtrans.c: status() needs 10 msec delay to let IC35 get ready
2001-01-17_05
* ic35mgr.c,mgrtrans.c:
implemented "restore" IC35 organizer database from file, tested OK
2001-01-16_05
* ic35mgr.c,mgrtrans.h,mgrtrans.c:
implemented "backup" IC35 organizer database to file, tested OK
* ic35mgr.txt: corrected details IC35 backup: head retry, last ack resp
2001-01-14_23
* README: IC35 manager modules and usage, short section "programs"
2001-01-14_22
* comio.c: com_send() using interval timer for delay increased
write MMCard file throughput to 1350 b/s (with 2kB blocks)
2001-01-14_01
* ic35log.sh: new option "-s n" - prepend output with 1:line 2:time
CAVEAT: "-s n" does not work for "-lsyn2", "-lsyn4"
* Makefile: added missing ic35log,ic35mgr to "all" target
2001-01-13_04
* comio.c: made "mmcput" faster with 2 stopbits and delay every 29 bytes
improved write MMCard to 890 b/s default 2kB blocks (930 b/s with 5kB)
err.corr com_recv,comsend: handle un-opened com_fd to avoid segfault
RCS branch 1.4.1 with experiments for throughput
RCS branch 1.3.1 with com_simrecv() non-logged bytes (yet erroneous)
2001-01-12_22
ic35mgr "mmcget", "mmcput", "mmcdel" commands tested OK with IC35
* ic35mgr.c,mgrtrans.h,mgrtrans.c,mgrproto.h,mgrproto.c:
implemented "mmcput" - write file to IC35 MMCard, tested OK (but slow)
implemented "mmcdel" - delete file on IC35 MMCard, tested OK (fast ;-)
additional 'mode' parameter for mmc_openfile(),sendmcmd(MCMDopenfile,)
* ic35mgr.c: new option "-b size" - read/write blocksize (for tests)
corrected mmcget,mmcput show progress: space to separate errormessage
* mgrproto.c: log checksum error in MPDUsend(),MPDUrecv() for diagnostic
* ic35mgr.txt: MMCard operations for write file, delete file
table of contents, table of MMCard operation functions and codes
moved logfile reference to end, removed hacked log extracts
read MMCard file throughput 2250 b/s with default 5kB blocksize
write MMCard file throughput 590 b/s default 2kB (610 b/s with 5kB)
2001-01-10_02
* ic35mgr.c: mmcget,mmcput without 'file' arg derive it from ic35path
mmcget converts ic35path lowercase to uppercase, translate '/' to '\'
mmcget shows file transfer progress every 5kB read data
2001-01-09_05
* ic35mgr.c,mgrtrans.h,mgrtrans.c,mgrproto.h,mgrproto.c:
implemented "mmcget" - read file from IC35 MMCard, tested OK
* mgrproto.c: MPDUrecv() needs receive timeout increased to 2.0 sec
2001-01-08_03
ic35mgr "mmcdir" corrected and tested OK with IC35
* ic35mgr.c: mmcdir output to stdout for simpler redirect to file
mmcdir output also MMC file attribute, do not read IC35 status data
* mgrtrans.c: status() must always send '\x50' to init IC35,
status() optionally reads status data, fixed typo mmctstampstr()
* mgrproto.c: reduced MAXRETRY to 5 for MPDUsend(),MPDUrecv()
corrected retry protocol MPDUsend(), 10 sec timeout nn_nn response
err.corr sendmcmd(): puttxt0() append trailing '\0' to dirpath in pdu
* comio.c: delays 100 usec before send every 16th byte (slow MMCard ops)
* comio.c,comio.h: com_settimeout() return previous timeout
* ic35mgr.txt: details about MMCard ops filestatus block from IC35 SDK
read status data from IC35 is optional, initial send 50 is mandatory
negative acknowledge in MMCard operations protocol
2001-01-07_06
* ic35mgr.c,mgrtrans.h,mgrtrans.c,mgrproto.h,mgrproto.c:
implemented directory listing of MMCard(s), tested OK with simulation
corrected max.length of MMC label to 11 chars (IC35 SDK API Ref.Guide)
* mgrtrans.c: corrected mdisconnect(): send 09 recv 90, send 01 recv 90
mconnect() reads IC35 status only if statfname specified, log mconnect
problem: MMCard(s) directory listing does not work with IC35,
checksum error / timeout on send command get directory length
uncertain if read IC35 status data needed in ic35mgr.c:ic35mmcdir()
2001-01-04_07
* ic35mgr.txt: description of MMCard operations and backup,restore
* ic35mgr.c,mgrtrans.h,mgrtrans.c,mgrproto.h,mgrproto.c,Makefile
first version of IC35 Manager, "status" command working with IC35
* syntrans.c: removed not needed headers <time.h>,"dataio.h"
2001-01-01_20
* ic35mgr.c: framework for (yet non-functional) IC35 Manager commands
2000-12-31_18
* vcc.y: corrected compile warnings about unused functions
fixed yacc/bison warning: %expect 2 shift/reduce conflicts for "items"
use YYERROR_VERBOSE for parse error reports, disabled useless YYDEBUG
* vobject.c: correct delList(): return removed vobj even if first
* vcaconv.c: improved "sortvca": show properties in sort order sequence
sort todo by due-time,summary, memo by summary,modify-time
compare date+time independant of encoding
* ic35sync.c: corrected "sync": update record if on IC35, else write new
2000-12-28_04 IC35SYNC-1-14
ic35sync import,sync step-5 done: "sync" command, misc. improvements
- sync command for synchronize vCard,vCalendar format PIMdata with IC35
- corrected convert of PIM BDAY birthday to IC35 for yyyy-mm-dd format
- PIM multiple CATEGORIES now preserved by prepend category from IC35,
single or standard of multiple CATEGORIES are replaced
- PIM fullname FN now preserved, IC35 updates first,last name into it
- put first 2 EMAIL entries from vCard into IC35 address Email1,Email2
- put unspecific telno to IC35 TelWork for "Business", else to TelHome
- map IC35 address "(def.)"s in VCARD.NOTE marked "(def1):","(def2):"
- conversion IC35 to/from PIM record does now yet delete record fields
- extracted data formats from dataio.c into separate modules:
datatxt.c text format (output only)
databin.c binary IC35 record format
datavca.c vCard,vCalendar format
vcutil.c vCard,vCalendar utilities
vcutil.h header for vCard,vCalendar utilities
fixes for gnomecard from gnome-pim_1.2.0:
- compare VCARD.REV against old reference date+time from IC35, because
gnomecard does not maintain X-PILOTSTAT.
- write VCARD.REV:yyyy-mm-ddThh:mm:ss, because yyyymmddThhmmss was
ignored by gnomecard.
fixes for gnomecal from gnome-pim_1.2.0:
- first line of VEVENT.SUMMARY to/from IC35 Summary, remaining lines
to/from Notes, because gnomecal does not support VEVENT.DESCRIPTION
- keep unsupported property VTODO.DTSTART marked in VTODO.DESCRIPTION
- add VEVENT,VTODO.CLASS:PUBLIC, else gnomecal would crash on edit
fixes for korganizer v1.1.1:
- put UID:IC35id-xxxxxxxx to vCard,vCalender record if no UID there.
- produce output vCard,vCal in same CRLF/NL-mode as found on input,
as korganizer has NL-terminated lines in vCalendar.
- translate IC35 CRLF to/from PIM NL in NOTE and DESCRIPTION fields.
- keep unsupported properties VTODO.DTSTART,DUE,CATEGORIES as marked
lines in VTODO.DESCRIPTION
- korganizer supports only DALARM, map IC35 LED and Beep to/from it
vcaconv extensions:
- command "prvca" reports vCard/vCalendar parse error.
- command "sortvca" outputs sorted vCard,vCalendar to standard output.
- command "imphandy" appends vCards with category HANDY from vCard file
to standard output, after import the result back into IC35 they are
for upload to a mobile phone from IC35 addresses in category HANDY.
CAVEAT:
- no options for sync conflict resolve, PIMfile always overrides IC35!
- IC35 has no different times for LED,Beep alarm, DALARM takes priority
- vcaconv conversions do not transfer clean/modified record status
- memory leak in vobject.c: all setVObject_*_Value() do not free the
previously attached dupStr()-allocated string value
* datavca.c,vcutil.{c,h}: support delete empty fields IC35 to/from PIM
* vobject.c: correct delList(), delete (only) first in property list
2000-12-27_21
* comio.c: for simulate do not set DTR, allow "RDx" in simulation file
* datavca.c,vcutil.c,vcutil.h:
extracted vCard,vCal utilities from datavca.c to vcutil.c,vcutil.h
new clr_vobjdirty(),SetModtimeIfdirty() for vCard,vCal modified time
* vcaconv.c: use vCard,vCal utilities vcutil.c
2000-12-27_01
* datavca.c: correct vca_set_recid(): update UID if "IC35id-xxxxxxxx"
2000-12-26_04
* datavca.c: fixes for gnomecal,korganizer
gnomecal does not support VTODO.DTSTART, keep in VTODO.DESCRIPTION
avoid gnomecal crash on edit by add VTODO,VEVENT.CLASS:PUBLIC
add VTODO,VEVENT.CLASS:PUBLIC, else gnomecal crashes on edit
korganizer supports only DALARM, map IC35 LED and Beep to/from it
* dataio.c,dataio.h,databin.c,datatxt.c,datavca.c:
fix open,close logic: new argument mode=r/w/r+ for xxx_open()
* dataio.c: no need to keep filenames
2000-12-25_17
* ic35sync.c: initial "sync" with empty PIM must export all IC35 recs
* datavca.c: fixes for korganizer and gnomecal
korganizer does not support VTODO.DTSTART,DUE,CATEGORIES, keep them
as marked lines in VTODO.DESCRIPTION
gnomecal does not support VEVENT.DESCRIPTION, keep the first line
of VEVENT.SUMMARY in IC35 S_Summary, more lines in S_Notes
* IC35 address fields with marks "(def1):","(def2):" to/from VCARD.NOTE
* README: added installation, usage, disclaimer sections
* Makefile: added COPYING (GPL) to distribution
2000-12-23_19
* datavca.c: default CLRF mode for output CRLF-terminated vCard,vCal
unspecific telno to IC35 TelWork for "Business", else to TelHome
replace single or standard of multiple categories, else prepend
new _vca_type() centralizes/simplifies vCard,vCal record type detect
* vcaconv.c: corrected "imphandy" to skip non-digit telno separators
2000-12-23_15
* dataio.{c,h},Makefile: extracted data formats into separate modules
datatxt.c text format (output only)
databin.c binary IC35 record format
datavca.c vCard,vCalendar format
* fixed problem with korganizer: translate IC35 CRLF to PIM NL in NOTEs
* fixed SIGSEGV in SetCategory()
2000-12-22_01
* dataio.c,vcc.y,vobject.c,vobject.h:
fixed problem with korganizer, has NL-terminated lines in vCalendar
produce output vCard,vCal in same CRLF/NL-mode as found on input
2000-12-21_22
* dataio.c: corrected some conversions IC35 to/from PIM
conversion to IC35 of PIM BDAY birthday failed with yyyy-mm-dd format
PIM multiple CATEGORIES now preserved by prepend category from IC35
PIM fullname FN now preserved, IC35 updated first,last name into it
* vcaconv.c: "sortvca" now sorts VObject property lists to ease tests
corrected "imphandy": created vCards lacked REV revised time
2000-12-21_15
improved reference date+time from IC35:
* syntrans.{c,h},ic35sync.c: ReadSysInfo() and WriteSysInfo() replace
old get_date_time(),set_date_time(), names like IC35Comm.dll
* dataio.{c,h},ic35sync.c: new set_oldic35dt() and get_newic35dt()
to convert IC35 old/new reference date+time to/from internal
fixes for gnomecard from gnome-pim_1.2.0:
* dataio.c: compare VCARD.REV against old reference date+time from IC35
because gnomecard does not maintain X-PILOTSTAT
write VCARD.REV:yyyy-mm-ddThh:mm:ss, because yyyymmddThhmmss was
ignored by gnomecard
2000-12-21_03
* vobject.{c,h},dataio.c: delList(),delProp() do not cleanVObject()
* fixed SEGV: dataio.c:_backup_and_openwr, ic35frec.c:_del_ic35recbuffs
* dataio.c: correct vcard_to_ic35addr(): 1st/2nd EMAIL to A_Email1/2
* vcaconv.c: new command "sortvca" - sort vCard,vCal file to stdout
new command "imphandy" - import vCards for upload to handy telbook
2000-12-19_02
* syntrans.c: set_date_time() reports set sysinfo
* ic35frec.c: set_ic35recdata(NULL,0) clears record-,field-buffers
* ic35frec.h: added IC35 record change flag definitions
* dataio.c: use IC35 record change flag definitions
correct vca_open(): handle empty vCal file, report parse error
(e.g. empty vCal file makes "sync" delete all IC35 records!)
ic35xxx_to_vyyy(): put UID to record if not there, korganizer needs
support pim_delrec(), vca_delrec() uses new delProp(),delList()
* vobject.{c,h}: support delete property from vobj, vobj from list
* vcaconv.c: command "prvca" reports vCard/vCal parse error
(cannot use pim_openinp() like other commands, as pim_getrec()
skips the VCALENDER property from vcafile with vCalender only.)
* ic35sync.c: implemented "sync" command as ic35sync(),syncfile()
importfile() collects IC35 actions, report num.of write/update/commit
CAVEAT: no conflict resolve options, PIMfile always overrides IC35!
2000-12-17_21 IC35SYNC-1-13 not released to public
ic35sync import,sync step-4 done: "import" command, misc. improvements
- algorithm details described in ic35sync.c:ic35import(),ic35export()
- import command for vCard,vCalendar or binary format PIMdata into IC35
- status command (new) shows IC35 version, sysinfo, total,mod records
- export command improved:
export into existing PIMfile(s), backup e.g. ic35vcal to ic35.vcal~
map IC35 address fields "(def.)" to/from VCARD:NOTE marked lines
change vCard,vCalendar record modified time only if record changed
support DCREATED in vCalendar: creation time of VEVENT,VTODO record
corrected VEVENT:AALARM,DLARM, were sometimes wrongly created
- support X-PILOTSTAT in vCard,vCal: 0=same, other=changed vs. IC35
- default format changed to "vca" for primary use vCard,vCalendar
- vcaconv may be used as filter with input/output from stdin/stdout
- fixed QUOTED-PRINTABLE problem with multi-field properties (like
VCARD:N, VCARD:ADR): due to problem with parser vcc.y and for
compatibility with other programs using the vCard,vCal output
QUOTED-PRINTABLE is not used on multi-field properties.
(otherwise the split into field sub-properties fails and the
first field (e.g. VCARD:ADR:STREET) gets the string of ALL the
fields (e.g. STREET,CITY,etc.) with ";" within it.)
todo: sync command, fix memory leak in vobject.c
conversion IC35 to/from PIM record does not yet delete record fields,
i.e. record on destination may differ and have fields not in source.
may be delete field needed only for sync, because import/export are
specified to not delete on destination.
* ic35sync.c,syntrans.c,synproto.c: support new "status" command
2000-12-17_08
* dataio.c: attach CHARSET to toplevel prop (e.g. VCARD:N, VCARD:ADR)
do not use QUOTED-PRINTABLE on e.g. VCARD:ADR due to parser problem
move IC35 address "(def.)" fields with markers to/from VCARD:NOTE
corrected for "vcaconv bin2txt .." conversion to standard output
corrected StringValue(): handle C and Unicode string values
ignore harmless LED,Beep, Start,EndTime differences (xxx_cmpic35rec)
log pimfile open,close operations
* ic35sync.c: default format now "vca", log ic35sync command line
corrected importfile(): commit was too often (vca) or not done (bin)
CAVEAT: delete field in convert vCard,vcal to/from IC35 not supported,
i.e. record on destination may differ and have fields not in source
2000-12-15_23
* ic35sync.c: re-designed import, commented import,export algorithms
compare all PIMrecs with IC35 and do commit/update/write to IC35
do not set sysinfo (date+time) if any IC35 record not in PIMfile
do not commit record on IC35 if not in PIMfile
use new _xxx_ic35recs() for records from IC35
* vcaconv.c,dataio.c: optionally use stdin/stdout to act as filter
* dataio.c: set vCard,vCal record modified-time only if record changed
added bin_cmpic35rec() - compare record from IC35 with binary record
corrected _ChangeString(): handle C and Unicode string values
fixed memory leak: pim_close() calls inpfmt close to free record list
2000-12-14_23
* dataio.c:
ignore categoryIDs, repeat fields if no repeat (vca_cmpic35rec)
corrected bin_open(): start with binlist after bin_rewind()
corrected vca_open(): must add all memo records separately to vcalist
corrected VCARD:FN space in fullname only if FirstName AND LastName
new bin_updic35rec() for pim_putrec() with e.g. "vcaconv bin2txt .."
* vcaconv.c: re-designed for generic PIM operations in dataio.c
2000-12-14_00
* ic35sync.c: corrections and improvements in importfile():
must always update_frec() owner address data with recid=05000001,
otherwise on IC35 in category "Address", but not as owner data
write back recordID and CLEAN status to PIM only if write to IC35 OK
fix memory leak: release newly created ic35rec
shorten progress,error messages of import and export commands
pim_cmpic35rec() params were swapped, close IC35 file after error
* dataio.{c,h}: prepare for vcaconv with generic operations pim_xxx()
pim_getrec() with fileid FILE_ANY=0 to get next record from any file
pim_putrec() converts inpfmt record to pimfmt and writes to outfile
pim_openinp() opens file for input and sets new inpfmt
pim_openout() opens file for output and sets pimfmt
removed old put_record(),_get_binrec(),_get_vcarec()
CAVEAT memory leak: record list from pim_openinp() not freed
2000-12-12_06
* dataio.{c,h}: support DCREATED creation time of VEVENT,VTODO record
support X-PILOTSTAT in vCard,vCal: 0=same, other=changed vs. IC35
generic operations pim_xxx(), use function tables per format
ic35xxx_to_vyyy() update existing instead of create vCard,vCal record
read from existing pimfile(s), so that "ic35sync export" preserves
corrected ic35sched_to_vevent(): create VEVENT:AALARM,DALARM only
if S_AlarmBefore is non-zero, S_Alarm_Repeat may be absent and thus
AlarmNoLED,AlarmNoBeep misleading
* syntrans.{c,h}: readfile() extracted to ic35sync.c:exportfile()
* ic35sync.c: implemented "import" command as ic35import(),importfile()
stub for "sync" command ic35sync(),syncfile(), yet non-functional
CAVEAT: memory leak in vobject.c: all setVObject_*_Value() do not free
previously attached dupStr()-allocated string value
dataio.c lacks some bin_xxx operations for import from binary format
delete PIM-record not supported yet, missing support in vobject.c
2000-12-07_04 IC35SYNC-1-12 not released to public
ic35sync import,sync step-3 done: convert vCard,vCal to IC35 record
* dataio.c: convert vCard,vCal to IC35 record vxxxx_to_ic35yyyy()
correct ic35addr_to_vcard(): set VCAdrProp if have any address field
* dataio.{c,h}: export vCard,vCal to IC35 conversion as _get_vcarec()
* ic35frec.c: corrected errors found with vCard,vCal to IC35 conversion
* vcaconv.c: support "vca2bin", new "bin2txt" conversions
* ic35sync.c: renamed ic35sync() to ic35export(), as that's what it does
stubs ic35import(), ic35sync() for un-implemented functions
connect() argument rdtime to retrieve value from IC35
2000-12-03_23
* ic35sync.txt: marked uncertain topics with "???"
experiments found new commands: read record by record-ID (01 05)
and write record data update (01 09), keeps recID on IC35 unchanged
* syntrans.{c,h},synproto.{c,h}: implemented new commands
read record by record-ID and write updated record data
* ic35log.sh: support new commands readrecrid,updatrec
2000-12-02_07
ic35sync import,sync step-2 done:
- new protocol functions for import,sync tested OK
- new knowledge about import,sync from experiments
todo: vCard,vCal to IC35 record, commands import,sync
* synproto.c: corrected CMDfgetmlen, CMDcategory, CMDsetdtime
* syntrans.{c,h}: connect() argument rdtime to retrieve value from IC35
* vcaconv.c,dataio.c: handle binfile records without data
* ic35log.sh: process ic35sync logfiles, fragmented response readmodrec
* ic35sync.txt: new knowledge about open file, changeflag, write record
first all read then write,del,commit, "date+time" may be any string
2000-12-01_20 IC35SYNC-1-11 not released to public
intermediate freeze after ic35sync import,sync step-1 done:
- new functions: set_date_time, category, get_mod_flen, read_mod_frec,
write_frec, delete_frec, commit_frec
- IC35 record access functions ic35frec.{c,h}
- 4byte record-ID combined from file-id (MSB) and record-id (LSW)
- support last-modified-time for vCard,vCalendar
- protocol-analyser ic35log.sh replaces and extends ic35prot.awk
todo: test new funcs, vCard,vCal to IC35 record, commands import,sync
* dataio.c: use 4byte record-ID in binary format
* ic35sync.c: IC35 file descriptions now from "ic35frec.h"
2000-12-01_19
* ic35sync.txt,ic35frec.h: comment max.lengths of record fields
* dataio.c,syntrans.c,ic35frec.{c,h}:
hide ic35 file description internals, use acces functions
* ic35frec.c: truncate to max.field-length, set nflds from recID
added missing 1byte-fields T_Completed,T_Priority
* vcaconv.c: usage on "-h", report unknown conversion
2000-12-01_02
* ic35frec.{c,h}: IC35 record access and file descriptions
* dataio.{c,h},syntrans.{c,h},vcaconv.c:
adapted for IC35 record access functions and 4byte record-ID
* synproto.c: adapted for 4byte record-ID combined of fileid,recid
* Makefile: new module ic35frec.{c,h}, ic35log replaces ic35prot.awk
target "clean" also removes .depend file
2000-11-29_21
* syntrans.{c,h}: missed commit_frec() for import,sync (yet untested)
2000-11-28_04
* dataio.c: support last-modified-time for vCard,vCalendar
concatenate IC35 file-id and record-id for XPilotIdProp
export ic35_dtime() for use in syntrans.c:set_date_time()
* syntrans.c: do disconnect on welcome() error to avoid hang IC35
* syntrans.{c,h}: functions for import,sync (untested): set_date_time,
category, get_mod_flen, read_mod_frec, write_frec, delete_frec
* synproto.{c,h}: import,sync commands: CMD{fdelrec,fgetmlen,fgetmrec}
2000-11-27_15
* ic35sync.txt: record-id, file-id, get number of modified records
new commands: read next modified record, delete record
updated correspondance with IC35Comm.dll to current knowledge
comment logs Delete.tar.gz:*.log, how M.Bruennert made them
* ic35log.sh: replaces ic35prot.awk, ic35prot2.awk
ic35prot.awk,ic35prot2.awk: moved to Attic/
2000-11-27_01
* ic35prot.awk: err.corr prxdata(), _plen was undefined if skip < 3
2000-11-25_18
* ic35prot2.awk: cosmetics, comment IC35Comm.dll functions
2000-11-25_03
* ic35prot2.awk: decode record field contents, comment variables
2000-11-24_04
* ic35prot.awk: prepend data with WRx,RDx (hex) WRa,RDa (ASCII)
skip also checksum if Level-1 headers are skipped with "-vskip=3"
* ic35prot2.awk: decode IC35sync PDUs from WRx,RDx transmission logs
from 'portmon' processed with 'awk -f ic35prot.awk -vskip=3'
2000-11-22_08 IC35SYNC-1-10
* ic35sync supports output IC35 PIM data in vCard,vCalendar format
new option "-f format" and command,pimfile args replace "-o outfile"
write date+time to logfile
* restrictions of implemented vCard,vCalendar output:
- strings with non-printable chars get "QUOTED-PRINTABLE" property
uncertain if it should be "ENCODING=QUOTED-PRINTABLE"
- strings with 8bit-chars also get "CHARSET=ISO-8859-1" property
uncertain if this is compliant to standard, because vobject.h
does not contain "CHARSET", but both "vCard Version 2.1" and
"vCalendar Version 1.0" explicitely allow "Character Set"
- IC35 "Memo" has no standard vCard,vCalendar format representation
using proprietary extension of VMEMO records
* vcc.y,vobject.{c,h}: extended by non-standard "VMEMO" records
for IC35 "Memo" representation
* dataio.c: VEVENT recurrence rules and alarms
* ic35sync.txt: corrected LED-,Beep-alarmflags
2000-11-21_04
* moved IC35 file descriptions from syntrans.* to dataio.*
to avoid vcaconv link needing syntrans.o,synproto.o etc.
* dataio.c: put_record() supports output vCard,vCalendar output
2000-11-20_02
* added vCard,vCalendar API: vcc.h vcc.y vobject.h vobject.c port.h
from gnome-pim-1.2.0.tar.gz:gnome-pim-1.2.0/libversit/
see ftp://ftp.gnome.org/pub/GNOME/stable/sources/gnome-pim/
other sources for vCard,vCalendar API:
- kpilot_3.1.10-1.0.tar.gz (based on KPilot 3.1b9)
from ftp://kde.tdyc.com/pub/kde/debian/dists/potato/contrib/source/
see also http://www.slac.com/pilone/kpilot_home/index.html
- versit consortium' SDK for Windows DLLs
from http://www.imc.org/pdi/sdkdllsr.zip
* new vcaconv.c vCard,vCalendar conversions, e.g. for offline tests
with IC35 binary data
* restrictions of implemented vCard,vCalendar output:
- sometimes non-7bit-ASCII chars lack QuotedPrintable and CharSet
- VEVENT recurrence rules not implemented
- VEVENT alarms AALARM,DALARM not implemented
- IC35 "Memo" has no standard vCard,vCalendar format representation
2000-11-19_07
* Makefile: ask before overwrite distribution tar.gz
* ic35sync.c: write date+time to logfile; replaced "-o outfile"
with new option "-f format" and command,pimfile arguments
* syntrans.c: reset serial device on abort with Ctrl-C
* comio.c: correct comrecv(): fdsets undefined if select() returns -1
* avoid gcc warnings about rcsid[]s not used
2000-11-19_00 IC35SYNC-1-9
added README, ic35sync.txt,ic35mgr.txt, ic35prot.awk
* Makefile: integrated help, target for tar.gz distribution
* syntrans.{c,h},ic35sync.c: export connect(), details internal
abort on bad power and wrong password responses
check for ready-reponse '\x80' from IC35
* ic35sync.c: write ic35sync version/rcsid to logfile
* util.{c,h}: log_init() interface changed (loglevel argument)
* ic35sync.txt: mention logfiles used for protocol analysis
2000-11-07_03 IC35SYNC-1-8
ic35sync.c split into modules
2000-11-05_05 IC35SYNC-1-7
version 1.7 released to Michael Bruennert
read PIM data from IC35 tested OK
CAVEAT:
- PIM data export in "home grown" format not compatible to anything
- cannot write PIM data to IC35, neither synchronize
- unsupported commands "set date+time", "category", "reset chgflag"
- ugly one-module-source
2000-11-04_19 ic35sync.c 1.1
hacking finished, now for compile and tests ..
2000-10-31
start hacking code

368
INSTALL Normal file
View File

@ -0,0 +1,368 @@
Installation Instructions
*************************
Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software
Foundation, Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without warranty of any kind.
Basic Installation
==================
Briefly, the shell command './configure && make && make install'
should configure, build, and install this package. The following
more-detailed instructions are generic; see the 'README' file for
instructions specific to this package. Some packages provide this
'INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions.
The 'configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a 'Makefile' in each directory of the package.
It may also create one or more '.h' files containing system-dependent
definitions. Finally, it creates a shell script 'config.status' that
you can run in the future to recreate the current configuration, and a
file 'config.log' containing compiler output (useful mainly for
debugging 'configure').
It can also use an optional file (typically called 'config.cache' and
enabled with '--cache-file=config.cache' or simply '-C') that saves the
results of its tests to speed up reconfiguring. Caching is disabled by
default to prevent problems with accidental use of stale cache files.
If you need to do unusual things to compile the package, please try
to figure out how 'configure' could check whether to do them, and mail
diffs or instructions to the address given in the 'README' so they can
be considered for the next release. If you are using the cache, and at
some point 'config.cache' contains results you don't want to keep, you
may remove or edit it.
The file 'configure.ac' (or 'configure.in') is used to create
'configure' by a program called 'autoconf'. You need 'configure.ac' if
you want to change it or regenerate 'configure' using a newer version of
'autoconf'.
The simplest way to compile this package is:
1. 'cd' to the directory containing the package's source code and type
'./configure' to configure the package for your system.
Running 'configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type 'make' to compile the package.
3. Optionally, type 'make check' to run any self-tests that come with
the package, generally using the just-built uninstalled binaries.
4. Type 'make install' to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular
user, and only the 'make install' phase executed with root
privileges.
5. Optionally, type 'make installcheck' to repeat any self-tests, but
this time using the binaries in their final installed location.
This target does not install anything. Running this target as a
regular user, particularly if the prior 'make install' required
root privileges, verifies that the installation completed
correctly.
6. You can remove the program binaries and object files from the
source code directory by typing 'make clean'. To also remove the
files that 'configure' created (so you can compile the package for
a different kind of computer), type 'make distclean'. There is
also a 'make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
7. Often, you can also type 'make uninstall' to remove the installed
files again. In practice, not all packages have tested that
uninstallation works correctly, even though it is required by the
GNU Coding Standards.
8. Some packages, particularly those that use Automake, provide 'make
distcheck', which can by used by developers to test that all other
targets like 'make install' and 'make uninstall' work correctly.
This target is generally not run by end users.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the 'configure' script does not know about. Run './configure --help'
for details on some of the pertinent environment variables.
You can give 'configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here is
an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU 'make'. 'cd' to the
directory where you want the object files and executables to go and run
the 'configure' script. 'configure' automatically checks for the source
code in the directory that 'configure' is in and in '..'. This is known
as a "VPATH" build.
With a non-GNU 'make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use 'make distclean' before
reconfiguring for another architecture.
On MacOS X 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple '-arch' options to the
compiler but only a single '-arch' option to the preprocessor. Like
this:
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CPP="gcc -E" CXXCPP="g++ -E"
This is not guaranteed to produce working output in all cases, you
may have to build one architecture at a time and combine the results
using the 'lipo' tool if you have problems.
Installation Names
==================
By default, 'make install' installs the package's commands under
'/usr/local/bin', include files under '/usr/local/include', etc. You
can specify an installation prefix other than '/usr/local' by giving
'configure' the option '--prefix=PREFIX', where PREFIX must be an
absolute file name.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option '--exec-prefix=PREFIX' to 'configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like '--bindir=DIR' to specify different values for particular
kinds of files. Run 'configure --help' for a list of the directories
you can set and what kinds of files go in them. In general, the default
for these options is expressed in terms of '${prefix}', so that
specifying just '--prefix' will affect all of the other directory
specifications that were not explicitly provided.
The most portable way to affect installation locations is to pass the
correct locations to 'configure'; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the
'make install' command line to change installation locations without
having to reconfigure or recompile.
The first method involves providing an override variable for each
affected directory. For example, 'make install
prefix=/alternate/directory' will choose an alternate location for all
directory configuration variables that were expressed in terms of
'${prefix}'. Any directories that were specified during 'configure',
but not in terms of '${prefix}', must each be overridden at install time
for the entire installation to be relocated. The approach of makefile
variable overrides for each directory variable is required by the GNU
Coding Standards, and ideally causes no recompilation. However, some
platforms have known limitations with the semantics of shared libraries
that end up requiring recompilation when using this method, particularly
noticeable in packages that use GNU Libtool.
The second method involves providing the 'DESTDIR' variable. For
example, 'make install DESTDIR=/alternate/directory' will prepend
'/alternate/directory' before all installation names. The approach of
'DESTDIR' overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of '${prefix}'
at 'configure' time.
Optional Features
=================
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving 'configure' the
option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'.
Some packages pay attention to '--enable-FEATURE' options to
'configure', where FEATURE indicates an optional part of the package.
They may also pay attention to '--with-PACKAGE' options, where PACKAGE
is something like 'gnu-as' or 'x' (for the X Window System). The
'README' should mention any '--enable-' and '--with-' options that the
package recognizes.
For packages that use the X Window System, 'configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the 'configure' options '--x-includes=DIR' and
'--x-libraries=DIR' to specify their locations.
Some packages offer the ability to configure how verbose the
execution of 'make' will be. For these packages, running './configure
--enable-silent-rules' sets the default to minimal output, which can be
overridden with 'make V=1'; while running './configure
--disable-silent-rules' sets the default to verbose, which can be
overridden with 'make V=0'.
Particular systems
==================
On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC
is not installed, it is recommended to use the following options in
order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
HP-UX 'make' updates targets which have the same time stamps as their
prerequisites, which makes it generally unusable when shipped generated
files such as 'configure' are involved. Use GNU 'make' instead.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its '<wchar.h>' header file. The option '-nodtk' can be used as a
workaround. If GNU CC is not installed, it is therefore recommended to
try
./configure CC="cc"
and if that doesn't work, try
./configure CC="cc -nodtk"
On Solaris, don't put '/usr/ucb' early in your 'PATH'. This
directory contains several dysfunctional programs; working variants of
these programs are available in '/usr/bin'. So, if you need '/usr/ucb'
in your 'PATH', put it _after_ '/usr/bin'.
On Haiku, software installed for all users goes in '/boot/common',
not '/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common
Specifying the System Type
==========================
There may be some features 'configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, 'configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
'--build=TYPE' option. TYPE can either be a short name for the system
type, such as 'sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS
KERNEL-OS
See the file 'config.sub' for the possible values of each field. If
'config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option '--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with '--host=TYPE'.
Sharing Defaults
================
If you want to set default values for 'configure' scripts to share,
you can create a site shell script called 'config.site' that gives
default values for variables like 'CC', 'cache_file', and 'prefix'.
'configure' looks for 'PREFIX/share/config.site' if it exists, then
'PREFIX/etc/config.site' if it exists. Or, you can set the
'CONFIG_SITE' environment variable to the location of the site script.
A warning: not all 'configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to 'configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the 'configure' command line, using 'VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified 'gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an
Autoconf limitation. Until the limitation is lifted, you can use this
workaround:
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
'configure' Invocation
======================
'configure' recognizes the following options to control how it
operates.
'--help'
'-h'
Print a summary of all of the options to 'configure', and exit.
'--help=short'
'--help=recursive'
Print a summary of the options unique to this package's
'configure', and exit. The 'short' variant lists options used only
in the top level, while the 'recursive' variant lists options also
present in any nested packages.
'--version'
'-V'
Print the version of Autoconf used to generate the 'configure'
script, and exit.
'--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally 'config.cache'. FILE defaults to '/dev/null' to
disable caching.
'--config-cache'
'-C'
Alias for '--cache-file=config.cache'.
'--quiet'
'--silent'
'-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to '/dev/null' (any error
messages will still be shown).
'--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
'configure' can determine that directory automatically.
'--prefix=DIR'
Use DIR as the installation prefix. *note Installation Names:: for
more details, including other options available for fine-tuning the
installation locations.
'--no-create'
'-n'
Run the configure checks, but stop before creating any output
files.
'configure' also accepts some other, not widely useful, options. Run
'configure --help' for more details.

21
Makefile.am Normal file
View File

@ -0,0 +1,21 @@
## Process this file with automake to produce Makefile.in
## $Id: Makefile.am,v 1.4 2001/08/12 03:29:57 thosch Rel $
## Copyright (C) 2001 Thomas Schulz
##
## automakefile for ic35link
pkgdata_DATA = \
README \
COPYING
EXTRA_DIST = $(pkgdata_DATA)
SUBDIRS = doc src
if MAINTAINER_MODE
MAINTAINERCLEANFILES = \
aclocal.m4 install-sh missing mkinstalldirs INSTALL \
Makefile.in stamp-h.in config.h.in configure
else
MAINTAINERCLEANFILES =
endif

248
NEWS Normal file
View File

@ -0,0 +1,248 @@
$Id: NEWS,v 1.18 2001/08/12 03:39:35 thosch Rel $
NEWS: release info about IC35Link
=================================
2001-08-12 version 1.18 IC35LINK-1-18
long pending release with several improvements and corrections
according to suggestions and bug reports by users.
improvements:
- improved README: table of contents, restrictions, more explanations
- ic35mgr restore and MMC write 30% faster (proposal by Harald Becker)
- ic35sync, ic35mgr, vcaconv now support long options, e.g. "--help"
info enquiry with "--help" or "--version" now returns exitcode 0
- new autogen.sh script for generate configure etc. after CVS checkout
(thanks Konrad Mader for report about missing configure in CVS)
- new configure option "--disable-logandcomsim" for conditional compile
without logging and com-simulation (proposal by Harald Becker)
- new configure options "--enable-ansi" and "--enable-pedantic"
bugfixes:
- fixed problem where ic35sync with many (ca. 860) addresses failed
(thanks Konrad Mader for bug report "get_mod_flen failed")
- ic35sync now accepts also empty PIMfile(s), e.g. empty ic35.memo
(thanks Malte Schmidt for bug report "ic35.memo: parse error")
- ic35mgr MMCard functions now check ic35path before accessing IC35
e.g. warn if shell eat backslash (\) in unquoted MMCard1\test.txt
(thanks Thomas Lichtenberg for bug report)
- restricted ic35mgr to max.blocksize 16350 found by experiments
- ic35sync, ic35mgr now abort on open failure of logfile or simfile
- fixed com-simulation for adjacent "RD nn" lines and non-logged bytes
- fixed compile problem util.c with Linux Mandrake-8.0 and SuSE-7.2
(thanks Christian Theile, Karl Stroetmann for bug reports)
- corrected warnings from "--enable-ansi" and "--missing-prototypes"
- fixed all Makefile.am: maintainer-clean keeps only sources in CVS,
install also README and COPYING, clean dependencies and versinfo.c
2001-02-05 version 1.17 IC35LINK-1-17
package renamed to "ic35link" and automake/autoconf/CVS reorganization.
no changes in sources, programs are unchanged except for version.
sources,documents now reside in src,doc subdirectories respectively.
2001-02-04 version 1.16 IC35SYNC-1-16
this is a bugfix and redesign release and is the last named "ic35sync".
(the package will be renamed to "ic35link" in the next release, when
the reorganizations for automake/autoconf and public CVS are done.)
improvements and redesign:
- ic35sync,ic35mgr,vcaconv now report package version and build info
- distribution includes vcc.c to handle missing/bad 'bison' or 'yacc'
(e.g. SuSE-7.0's yacc produced bad vcc.o, thanks Michael Bruennert)
- reworked and clearified the IC35 manager protocol documentation and
implementation (see ic35mgr.txt, mgrtrans.*, mgrproto.*), refer to
the IC35 SoftwareDevelopmentKit API MMCard functions in mgrproto.c
bugfixes in ic35mgr and ic35sync:
- fixed compile error RedHat-7.0 gcc-2.96 (thanks Dieter Schultschik)
- corrections for 'ic35mgr status' (thanks Michael Bruennert):
mgrtrans.c:status() tries to get IC35 response instead of only wait
mgrproto.c:MMCsend() sends blocklength with initial wait
corrected output of MMCard2 label
- ic35mgr commands backup and restore show error messages on new line
- avoid failing 'ic35mgr restore ..' at "disconnect" by delay 3.25 sec
after writedatabase() done
- avoid failure of 'ic35mgr mmcput file' with occasional slow IC35
MMCard write with 3.5 sec timeout for length of response block
- corrected MMC closedir,closefile response PDUs having no status-word
- corrected to make 'ic35sync status' work also with simulation file
2001-01-20 version 1.15 IC35SYNC-1-15
new IC35 manager 'ic35mgr' supports access of IC35 MMCard(s)
- command "mmcdir" lists contents of MMCard(s)
- commands "mmcget","mmcput","mmcdel" read,write,delete MMCard file
- commands "backup","restore" IC35 organizer database
- ic35mgr.txt now really describes the IC35 manager protocol
(previously it was just extracts of Windows 'portmon' logfiles)
bugfixes in ic35sync and vcaconv:
- "ic35sync sync" now updates record if on IC35, else writes new record
- "vcaconv sortvca ic35.vcal" did produce empty output, fixed vobject.c
- fixed vcc.y compile warnings
- "vcaconv sortvca .." improved: shows properties in sort order sequence
todo:
- ic35mgr install application on IC35
- ic35sync initial sync does not yet write all records to IC35
workaround: do "ic35sync import .." before first "ic35sync sync .."
2000-12-28 version 1.14 IC35SYNC-1-14
ic35sync import,sync step-5 done: "sync" command, misc. improvements
- sync command for synchronize vCard,vCalendar format PIMdata with IC35
- corrected convert of PIM BDAY birthday to IC35 for yyyy-mm-dd format
- PIM multiple CATEGORIES now preserved by prepend category from IC35,
single or standard of multiple CATEGORIES are replaced
- PIM fullname FN now preserved, IC35 updates first,last name into it
- put first 2 EMAIL entries from vCard into IC35 address Email1,Email2
- put unspecific telno to IC35 TelWork for "Business", else to TelHome
- map IC35 address "(def.)"s in VCARD.NOTE marked "(def1):","(def2):"
- conversion IC35 to/from PIM record does now yet delete record fields
- extracted data formats from dataio.c into separate modules:
datatxt.c text format (output only)
databin.c binary IC35 record format
datavca.c vCard,vCalendar format
vcutil.c vCard,vCalendar utilities
vcutil.h header for vCard,vCalendar utilities
fixes for gnomecard from gnome-pim_1.2.0:
- compare VCARD.REV against old reference date+time from IC35, because
gnomecard does not maintain X-PILOTSTAT.
- write VCARD.REV:yyyy-mm-ddThh:mm:ss, because yyyymmddThhmmss was
ignored by gnomecard.
fixes for gnomecal from gnome-pim_1.2.0:
- first line of VEVENT.SUMMARY to/from IC35 Summary, remaining lines
to/from Notes, because gnomecal does not support VEVENT.DESCRIPTION
- keep unsupported property VTODO.DSTART marked in VTODO.DESCRIPTION
- add VEVENT,VTODO.CLASS:PUBLIC, else gnomecal would crash on edit
fixes for korganizer v1.1.1:
- put UID:IC35id-xxxxxxxx to vCard,vCalender record if no UID there.
- produce output vCard,vCal in same CRLF/NL-mode as found on input,
as korganizer has NL-terminated lines in vCalendar.
- translate IC35 CRLF to/from PIM NL in NOTE and DESCRIPTION fields.
- keep unsupported properties VTODO.DSTART,DUE,CATEGORIES as marked
lines in VTODO.DESCRIPTION
- korganizer supports only DALARM, map IC35 LED and Beep to/from it
vcaconv extensions:
- command "prvca" reports vCard/vCalendar parse error.
- command "sortvca" outputs sorted vCard,vCalendar to standard output.
- command "imphandy" appends vCards with category HANDY from vCard file
to standard output, after import the result back into IC35 they are
for upload to a mobile phone from IC35 addresses in category HANDY.
CAVEAT:
- no options for sync conflict resolve, PIMfile always overrides IC35!
- IC35 has no different times for LED,Beep alarm, DALARM takes priority
- vcaconv conversions do not transfer clean/modified record status
- memory leak in vobject.c: all setVObject_*_Value() do not free the
previously attached dupStr()-allocated string value
2000-12-17 version 1.13 IC35SYNC-1-13 (not released to public)
ic35sync import,sync step-4 done: "import" command, misc. improvements
- algorithm details described in ic35sync.c:ic35import(),ic35export()
- import command for vCard,vCalendar or binary format PIMdata into IC35
- status command (new) shows IC35 version, sysinfo, total,mod records
- export command improved:
export into existing PIMfile(s), backup e.g. ic35vcal to ic35.vcal~
map IC35 address fields "(def.)" to/from VCARD:NOTE marked lines
change vCard,vCalendar record modified time only if record changed
support DCREATED in vCalendar: creation time of VEVENT,VTODO record
corrected VEVENT:AALARM,DLARM, were sometimes wrongly created
- support X-PILOTSTAT in vCard,vCal: 0=same, other=changed vs. IC35
- default format changed to "vca" for primary use vCard,vCalendar
- vcaconv may be used as filter with input/output from stdin/stdout
- fixed QUOTED-PRINTABLE problem with multi-field properties (like
VCARD:N, VCARD:ADR): due to problem with parser vcc.y and for
compatibility with other programs using the vCard,vCal output
QUOTED-PRINTABLE is not used on multi-field properties.
(otherwise the split into field sub-properties fails and the
first field (e.g. VCARD:ADR:STREET) gets the string of ALL the
fields (e.g. STREET,CITY,etc.) with ";" within it.)
todo: sync command, fix memory leak in vobject.c
conversion IC35 to/from PIM record does not yet delete record fields,
i.e. record on destination may differ and have fields not in source.
may be delete field needed only for sync, because import/export are
specified to not delete on destination.
2000-12-07 version 1.12 IC35SYNC-1-12 (not released to public)
ic35sync import,sync step-3 done:
convert vCard,vCalendar format to IC35 record
ic35sync import,sync step-2 done:
new protocol functions for import,sync tested OK
new knowledge about import,sync from experiments
new features:
- vcaconv supports "vca2bin", new "bin2txt" conversions
- ic35log.sh supports new commands readrecrid,updatrec
processes ic35sync logfiles, fragmented response readmodrec
- syntrans.{c,h}: connect() argument rdtime to retrieve value from IC35
corrections:
- corrected ic35addr_to_vcard(): set VCAdrProp if have any address field
- vcaconv.c,dataio.c: handle binfile records without data
- synproto.c: corrected CMDfgetmlen, CMDcategory, CMDsetdtime
documentation ic35sync.txt:
- marked uncertain topics with "???"
- experiments found new commands: read record by record-ID (01 05) and
write record data update (01 09), keeps recID on IC35 unchanged
- new knowledge about open file, changeflag, write record
first all read then write,del,commit, "date+time" may be any string
todo: ic35sync commands import,sync
2000-12-01 version 1.11 IC35SYNC-1-11 (not released to public)
intermediate freeze after ic35sync import,sync step-1 done:
- new functions: set_date_time, category, get_mod_flen, read_mod_frec,
write_frec, delete_frec, commit_frec
- IC35 record access functions ic35frec.{c,h}
- 4byte record-ID combined from file-id (MSB) and record-id (LSW)
- support last-modified-time for vCard,vCalendar
- protocol-analyser ic35log.sh replaces and extends ic35prot.awk
todo: test new funcs, vCard,vCal to IC35 record, commands import,sync
2000-11-22 version 1.10 IC35SYNC-1-10
- ic35sync supports output IC35 PIM data in vCard,vCalendar format
new option "-f format" and command,pimfile args replace "-o outfile"
write date+time to logfile
- added vCard,vCalendar API: vcc.h vcc.y vobject.h vobject.c port.h
from gnome-pim-1.2.0.tar.gz:gnome-pim-1.2.0/libversit/
see ftp://ftp.gnome.org/pub/GNOME/stable/sources/gnome-pim/
other sources for vCard,vCalendar API:
- kpilot_3.1.10-1.0.tar.gz (based on KPilot 3.1b9)
from ftp://kde.tdyc.com/pub/kde/debian/dists/potato/contrib/source/
see also http://www.slac.com/pilone/kpilot_home/index.html
- versit consortium' SDK for Windows DLLs
from http://www.imc.org/pdi/sdkdllsr.zip
- restrictions of implemented vCard,vCalendar output:
- strings with non-printable chars get "QUOTED-PRINTABLE" property
uncertain if it should be "ENCODING=QUOTED-PRINTABLE"
- strings with 8bit-chars also get "CHARSET=ISO-8859-1" property
uncertain if this is compliant to standard, because vobject.h
does not contain "CHARSET", but both "vCard Version 2.1" and
"vCalendar Version 1.0" explicitely allow "Character Set"
- IC35 "Memo" has no standard vCard,vCalendar format representation
using proprietary extension of VMEMO records
- new vcaconv: vCard,vCalendar conversions, e.g. for offline tests
with IC35 binary data
moved IC35 file descriptions from syntrans.* to dataio.*
to avoid vcaconv link needing syntrans.o,synproto.o etc.
- ic35sync.txt: corrected LED-,Beep-alarmflags
- Makefile: ask before overwrite distribution tar.gz
- syntrans.c: reset serial device on abort with Ctrl-C
- comio.c: correct comrecv(): fdsets undefined if select() returns -1
- avoid gcc warnings about rcsid[]s not used
2000-11-19 version 1.9 IC35SYNC-1-9 (not released to public)
- added README, ic35sync.txt,ic35mgr.txt, ic35prot.awk
- Makefile: integrated help, target for tar.gz distribution
- syntrans.{c,h},ic35sync.c: export connect(), details internal
abort on bad power and wrong password responses
check for ready-reponse '\x80' from IC35
- ic35sync.c: write ic35sync version/rcsid to logfile
- util.{c,h}: log_init() interface changed (loglevel argument)
- ic35sync.txt: mention logfiles used for protocol analysis
2000-11-07 version 1.8 IC35SYNC-1-8 (not released to public)
ic35sync.c split into modules
2000-11-05 version 1.7 IC35SYNC-1-7
first usable version, read PIM data from IC35 tested OK.
CAVEAT:
- PIM data export in "home grown" format not compatible to anything
- cannot write PIM data to IC35, neither synchronize
- unsupported commands "set date+time", "category", "reset chgflag"
- ugly one-module-source
2000-11-04 version 1.1
hacking finished, now for compile and tests ..
2000-10-31
start hacking code

417
README Normal file
View File

@ -0,0 +1,417 @@
$Id: README,v 1.19 2001/08/12 03:36:44 thosch Rel $
IC35Link for Linux
==================
IC35Link provides tools to communicate with the Siemens IC35
over a serial port.
Contents
Abstract
Installation
configure, make, install
create configure script
Usage of ic35sync
Examples
Restrictions
Usage of ic35mgr
Restrictions
Files in the distribution
Documents
Miscellaneous
Tools
Sources in the src directory
References
Standard Disclaimer, Warnings, Copyright
Abstract
--------
The tools included in the IC35Link package are:
- ic35sync
synchronizes IC35 address, schedule, todo and memo data with
Personal Information Management databases (PIMfiles).
- ic35mgr
The IC35 manager is for accessing IC35 MMCard(s), backup,restore
the IC35 PIM-database and install applications on the IC35.
CAVEAT: install applications on the IC35 is (as of version 1.17)
not yet implemented.
- vcaconv
is a converter for PIMfiles in vCard,vCalendar and binary formats.
it was mainly used during development. For non-developers the
"imphandy" conversion might be useful to manage the phonebook of
a mobile phone with the IC35: it converts vCards into the "HANDY"
category for uploading them from this category on the IC35 to the
phonebook of the mobile phone (after import or sync with IC35).
- ic35log
is for pretty-printing ic35sync, ic35mgr (and 'portmon') logfiles
and useful mainly for developers.
- ic35sync.txt
describes the IC35 synchronization protocol (in german).
- ic35mgr.txt
describes the IC35 manager protocols (in german).
All programs give help about usage if called with the short "-h" or
the long "--help" option.
Starting with version 1.17 the package is named "ic35link", because
it provides more than just IC35 synchronization under GNU/Linux.
Up to version 1.16 the package name was "ic35sync".
Installation
------------
Unpack the archive ic35link-*.tar.gz (you appeareantly did that ;-).
configure, make, install
Do the usual
./configure
make
su # superuser login for install
make install-strip # strip symbols and debugging info
exit # superuser logout
Installation is done to /usr/local/bin and /usr/local/share/ic35link
by default, change that with 'configure --prefix=/some/other/path'.
For details run 'configure --help' and see the file INSTALL.
The 'configure' options of major interest are:
--prefix=/opt
install to /opt/bin/ instead of default /usr/local/bin/
--disable-logandcomsim
compile without logging and simulated communication support
--disable-warnings
disable compile warnings
--enable-ansi
enable strict ANSI-C compilation
--enable-pedantic
enable pedantic compile warnings
be warned to get several compile errors and/or warnings
feel free to fix them (and send me the patches :-)
* The programs are compiled with debugging info. Should you want
to install them with that, use 'make install' instead of the
'make install-strip' above.
* The programs and documents can be uninstalled with 'make uninstall'.
* If you modify the vCard/vCalendar parser source vcc.y, you will
need 'bison' version 1.25 or newer. Compilation with 'yacc' will
not work and/or create a vcc.c producing 'parser stack overflow'
errors.
create configure script
If you use an archive ic35link-*.tar.gz you should not need this.
If you obtained ic35link from the public CVS repository you have
to generate the configure script and Makefile.in with
sh autogen.sh
It will check for autoconf and automake, you'll have to install
these packages if some of the checks fail.
If all goes well it will automatically run './configure' with the
options passed to autogen.sh and "--enable-maintainer-mode". The
latter enables 'make maintainer-clean', which deletes everything
not in the CVS repository, e.g. also the configure script.
Setting the environment variable NOCONFIGURE to some non-empty
value will prevent autogen.sh from running configure.
Usage of ic35sync
-----------------
ic35sync synchronizes IC35 address, schedule, todo and memo data
with Personal Information Management databases (PIMfiles) mainly
in vCard,vCalendar format. Get information about usage with:
ic35sync --help
ic35sync supports 4 modes of operation, given as command argument:
- status
reports IC35 status: firmware version, timestamp of last sync
operation and total and modified number of records per IC35 file.
No PIMfiles are accessed, contents of IC35 are not changed, thus
good for an initial test.
- export
does export IC35 data to PIMfile(s), data in IC35 is not changed
and no IC35 or PIM records will be deleted. The sychronisation
stamp will not be written to IC35 and any changemarks on records
in the IC35 remain intact.
This is the initial operation to start using IC35 data also with
Linux Personal Information Managers. It is also usable to backup
all the IC35 data.
Records from existing PIMfile(s) can afterwards be propagated to
IC35 with an 'import' or 'sync' operation.
- import
does import data from PIMfile(s) into IC35, changes in PIMfile(s)
reflect only the IC35 record numbers and status, no IC35 or PIM
records will be deleted. The synchronisation stamp (current date
and time) will be written to IC35 only if all IC35 records match
with PIMfile, e.g. if the IC35 was empty before the import.
This is the initial operation to start using Linux PIM databases
also on IC35. it can be used also to restore data into IC35.
Any records previously existing in IC35 can then be propagated
into PIMfile(s) with an 'export' or 'sync' operation.
- sync
synchronizes changes in IC35 and PIMfile(s): records modified in
IC35 will be updated to PIMfile(s), records deleted in IC35 will
be deleted from PIMfile(s) and vice versa.
If changes to the same record were made in both the IC35 and the
PIMfile, the latter takes precedence, i.e. PIM overrides IC35.
All record changemarks on IC35 will be cleared and the current
date and time will be written to IC35 as synchronisation stamp,
because after sync all IC35 records match with PIMfile(s).
With the vCard/vCalendar format (default or option "--format vca")
up to 3 PIMfile(s) can be specified on the ic35sync commandline:
If 3 PIMfiles are specified, the first file is for Addresses, the
second file is for Schedule and ToDo, the third file is for Memo.
If 2 PIMfiles are specified, the first file is for Adresses and the
second file for Schedule, ToDo and Memo. Korganizer and gnomecal
will work with the second file only if there are not VMEMO-records
in it, i.e. only if there is not any Memo note on the IC35!
If 1 PIMfile is specified, this single file is used for all data
from Adresses, Schedule, ToDo and Memo. Korganizer, gnomecal and
and gnomecard cannot work with that single file!
If no PIMfiles are specified, the default filenames are used, which
are ic35.vcard for Adresses, ic35.vcal for Schedule and ToDo, and
ic35.memo for Memo, the files are assumed in the current directory.
Examples
* GNOME addressbook and calendar
IC35 syncstation connected at /dev/ttyS1, IC35 password is "secret"
initial export from IC35:
ic35sync -d /dev/ttyS1 -p secret export \
~/.gnome/GnomeCard.gcrd ~/.gnome/user-cal.vcf ic35.memo
synchronize changes in IC35 and addressbook,calendar:
ic35sync -d /dev/ttyS1 -p secret sync \
~/.gnome/GnomeCard.gcrd ~/.gnome/user-cal.vcf ic35.memo
* KDE KOrganizer and GNOME addressbook
initial import into IC35 at /dev/ic35, no IC35 password:
ic35sync import ~/.gnome/GnomeCard.gcrd \
~/.kde/share/apps/korganizer/calendar.vcs ic35.memo
synchronize changes in IC35 and addressbook,KOrganizer:
ic35sync sync ~/.gnome/GnomeCard.gcrd \
~/.kde/share/apps/korganizer/calendar.vcs ic35.memo
Restrictions
* ic35sync yet has no options for resolving synchronize conflicts.
If the same record is modified on both sides, the modification in
the PIMfile takes precedence and overrides the changes on IC35.
* ic35sync yet has a proprietary VMEMO format for memo records.
The VMEMO format was invented by me following the vCard/vCalendar
standard. Unfortunately there is no GUI software supporting it.
Suggestions for the memo records are welcome.
* ic35sync should be used with _existing_ vCalendar files, because
Korganizer and gnomecal rely on their own file formats and do not
work properly with vCalendar files _created_ by ic35sync.
Korganizer uses newline characters as line separators and wants
its own PRODID.
gnomecal uses carriagereturn linefeed sequences as line separators
and wants its own PRODID and VERSION.
ic35sync does respect and not change the format of an existing
vCalendar file to avoid confusing Korganizer/gnomecal.
* ic35sync's sync operation is rather slow, because always all IC35
records are read to find the records, which were deleted from the
PIMfile(s). This is needed, as Korganizer, gnomecal and gnomecard
leave no traces (e.g. delete-flags) from deleted records.
* gnomecal does not support VEVENT.DESCRIPTION but multiple lines
in VEVENT.SUMMARY.
ic35sync maps the first line of VEVENT.SUMMARY to/from the IC35
"Summary" field and all remaining lines to/from the IC35 "Notes"
field.
* gnomecal does not support VTODO.DTSTART.
ic35sync maps the IC35 "Start" field to/from a line marked with
"DTSTART:" in VTODO.DESCRIPTION.
* gnomecard does not support the X-PILOTSTAT change mark.
ic35sync regards VCARD records as changed if their with revised
time VCARD.REV is newer than the date and time of the last sync.
* korganizer does not support VTODO.CATEGORIES, VTODO.DTSTART and
VTODO.DUE
ic35sync maps the IC35 Category and the "Start" and "Due" fields
to/from lines marked "CATEGORIES:", "DTSTART:" and "DUE:" in the
VTODO.DESCRIPTION.
* korganozer supports only VEVENT.DALARM, but not VEVENT.AALARM
ic35sync maps IC35 "LED" and "Beep" alarms to/from VEVENT.DALARM.
* the IC35 address fields "(Def.)" have no VCARD counterparts.
ic35sync maps them to/from lines marked "(def1):" and "(def2):"
in VCARD.NOTE.
Usage of ic35mgr
----------------
The IC35 manager currently supports access of the IC35 MMCard(s)
and backup,restore the IC35 internal PIM-database to/from a file.
Get help about usage with
ic35mgr --help
and experiment (and please tell me about problems, suggestions and
wanted features, e-mail address below).
Restrictions
* The ic35mgr MMCard access commands mmcget,mmcput,mmcdel accept the
filepath in the IC35 native form (e.g. MMcard1\IC35\APP\REVERSI.APP)
or more convenient with lowercase characters and slash separators
(e.g. mmcard1/ic35/app/reversi.app).
The filepath argument in the IC35 native form must be enclosed in
single (') or double (") quotes to prevent the shell from eating
the backslash (\) characters.
* Reading a MMCard file with mmcget will set the timestamp of the
local file to that of the MMCard file.
Even when only reading a MMCard file, the IC35 will set the MMCard
file's timestamp to the current date and time.
* Installing application programs on the IC35 is planned, but not yet
implemented. If someone (from Siemens) would provide me with the
specification of the installation protocol would ease this a lot.
Files in the Distribution
-------------------------
Documents
README
sic! you're reading this
NEWS
release information about IC35Link
ChangeLog
sic! details about what was changed
TODO
sic! what remains to be done and whish list
COPYING
GNU GENERAL PUBLIC LICENSE
AUTHORS
who has written IC35Link
THANKS
who has contributed to IC35Link
doc/ic35sync.txt
description of IC35sync protocol, yet only (?) german
doc/ic35mgr.txt
description of IC35manager protocol, yet only (?) german
Miscellaneous
INSTALL
generic installation instructions for 'configure'
autogen.sh
generates configure and Makefile.in etc.
config.h
configuration header created by configure
config.h.in
input for configure to create config.h, created by autoheader
configure
configuration script, created by autoconf
configure.in
input for autoconf to create configure
Makefile
makes 'make' make it ;-) created by configure
Makefile.in
input for configure to create Makefile, created by automake
Makefile.am
input for automake to create Makefile.in
Tools
src/ic35log.sh
make logfiles of IC35 communications more readable. supported are
logfiles created by "portmon" (from www.sysinternals.com) and the
logfiles from ic35sync and ic35mgr (of course ;-).
Sources in the src directory
ic35sync.c
IC35 synchronize PersonalInformationManagement (PIM) data
ic35mgr.c
IC35 manager: access MMCard, backup,restore database
dataio.c
dataio.h
PIM data import to / export from IC35 database records
datatxt.c
support for text output IC35 record
databin.c
support for binary IC35 record format (PIM)files
datavca.c
support for vCard,vCalendar format PIMfiles
vcutil.h
vcutil.c
utilities for vCard,vCalendar
ic35frec.h
ic35frec.c
IC35 record access and file descriptions
syntrans.c
syntrans.h
IC35 synchronize transactions:
connect, disconnect
open, close, read, write IC35 database file
synproto.c
synproto.h
IC35 synchronize protocol
mgrtrans.c
mgrtrans.h
IC35 manager transactions:
connect, disconnect
MMCard status, directory, file access
mgrproto.c
mgrproto.h
IC35 manager protocol
genproto.c
genproto.h
general IC35 protocol support
comio.c
comio.h
basic serial communication with IC35
util.c
util.h
utilities: logging, errors, messages
vcc.h
export header for vCard,vCalendar API
vcc.y
parser for vCard-,vCalendar-files
vobject.h
vobject.c
API for vCard,vCalendar VObject
port.h
compilation environment for vCard,vCalendar API
vcaconv.c
vCard,vCalendar conversion, e.g. to/from binary IC35 data
References
----------
The vCard,vCalendar API sources were taken from gnome-pim-1.2.0,
and fixed a bit to reduce compile warnings.
Sources for vCard,vCalendar API:
- Gnome-PIM gnome-pim-1.2.0.tar.gz
from ftp://ftp.gnome.org/pub/GNOME/stable/sources/gnome-pim/
- KPilot kpilot_3.1.10-1.0.tar.gz (based on KPilot 3.1b9)
from ftp://kde.tdyc.com/pub/kde/debian/dists/potato/contrib/source/
see also http://www.slac.com/pilone/kpilot_home/index.html
- versit consortium's SDK for Windows DLLs
from http://www.imc.org/pdi/sdkdllsr.zip
The autogen.sh script was taken from gnome-pim-1.3.2 and fixed
a bit to fit the needs of ic35link.
Standard Disclaimer, Warnings, Copyright
----------------------------------------
THIS SOFTWARE HAS BUGS (as any software has ;-). Use it at your
own risk. I take no responsibility for any data loss or damage,
etc. done by this software, i.e. should your IC35 crash or explode
while using ic35sync or ic35mgr, sorry.
Besides my home machine this software was successfully used with:
- KDE-1.1.2 Korganizer v1.1.1
- Gnome-1.2 gnomecard,gnomecal from gnome-pim-1.2.0
- IC35 Firmware V1.28
- IC35 Firmware V1.38 (thanks Thomas Lichtenberg)
- Debian-2.2r2 kernel 2.0.36 gcc-2.95.2 Pentium-I/133MHz /dev/ttyS3
- Debian-2.2r2 kernel-2.2.13 gcc-2.95.2 Pentium-III/400MHz /dev/ttyS1
- SuSE-7.2 (thanks Karl Stroetmann)
- SuSE-7.0 kernel-2.2.16 gcc-2.95.2-98 AMD-K5/100MHz /dev/ttyS1
- SuSE-7.0 kernel-2.2.16 gcc-2.95.2-98 Pentium-III/450MHz /dev/ttyS0
- SuSE-6.0 kernel-2.0.36 gcc-2.7.2.3-5 BAYCOM Notebook Pentium-I/166MHz
- Mandrake-7.2 AMD-Duron/750MHz /dev/ttyS1 (thanks Malte Schmidt)
- Mandrake-8.0 gcc-2.96 (thanks Christian Theile)
That being said, I _really_ want comments regarding this software
as well as suggestions and bug reports.
t.schulz@d2mail.de Thomas Schulz 2000-12-25
Geibelstrasse 57
D-22303 Hamburg
Germany
Copyright (C) 2000,2001 Thomas Schulz
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program in the file COPYING; if not, write to the
Free Software Foundation, Inc.
59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA

62
THANKS Normal file
View File

@ -0,0 +1,62 @@
People who contributed to IC35Link, in almost chronological order:
- Thomas Schulz <t.schulz@d2mail.de>
the initial author (myself :-), needed it for lack of a Windows-System
- Michael Bruennert <michael.bruennert@eikon.tum.de>
was the first one (besides me) interested in IC35sync/Linux,
supplied lots of 'portmon' logs from IC35sync under Windows/NT,
which made protocol analysis and implementation possible, and
gave feedback about bugs under SuSE-7.0
- "Logbuch IC35" <Logbuch-IC35@exmail.de>
supplied webspace for ic35sync_1.14.tar.gz and ic35sync_1.15.tar.gz
- Uwe Stobinski <uwe.stobinski@addcom.de>
made an excellent IC35 website, hosted an "IC35 Wettbewerb" and
supplied webspace for ic35sync_1.14.tar.gz and ic35sync_1.15.tar.gz
- Norbert Kolb <Norbert.Kolb@htl.de>
offered means for publishing IC35sync/Linux
and made many proposals for improving it
- Dieter Schultschik <schultschik@chello.at>
alias <tscherno.bill@gmx.net>
gave feedback about bugs under RedHat-7.0
- Harald Becker <harald@kristall.de>
contributed ideas for faster write MMCard files and
suggested compile without logging and com-simulation
- Oliver Zechlin <Oliver.Zechlin@mch.siemens.de>
promised to supply me with the IC35 communication protocol specs
and gave me "Goodies" for my "IC35 Wettbewerb" contribution
- Thomas Lichtenberg <thomas@ThomasLichtenberg.de>
reported some bugs and did tests with IC35 firmware V1.38
and under SuSE-7.0 and SuSE-6.0
- Malte Schmidt <malte.schmidt@gmx.de>
reported some bugs and did tests with Mandrake-7.2
- Konrad Mader <konrad.mader@gmx.de>
reported bug with ic35sync many addresses and some more
inspired autogen.sh due to configure missing in CVS
- Christian Theile <ch_theile@gmx.de>
reported compile problem with Mandrake-8.0
- Karl Stroetmann <Karl.Stroetmann@mchp.siemens.de>
reported compile problem with SuSE-7.2
- Hans-Michael Stahl <hm.stahl@berlin.de>
contributed ic35mgr "mmcgettree","mmcputtree" commands for whole dirtree
organizations whose work helped me:
- Debian http://www.debian.org
for the best (in my opinion) FreeSoftware GNU/Linux System
- IMC consortium http://www.imc.org
for the vCard,vCalendar standards and API
- SourceForge http://sourceforge.net
for hosting IC35Link and its CVS Repository

741
TODO Normal file
View File

@ -0,0 +1,741 @@
$Id: TODO,v 1.21 2001/08/09 23:59:22 thosch Rel $
TODO for IC35 communication
===========================
legend
------
F task to do
yyyy-mm-dd_hh WHAT
details ..
F sub-tasks ..
F is current state from:
- todo
= work
+ done
x canc cancelled as no more need/want
WHAT is task change from:
todo task invented
+nn% task nn% done
done task done
canc task cancelled
- documentation for newbies
2001-08-03_13 todo Klaus Krenz <Klaus.Krenz@t-online.de> had problems
- explain COM?-ports are /dev/ttyS?, symlink /dev/ic35, access rights
- initial test with 'ic35sync status' and/or 'ic35mgr mmcdir'
- for 'mmc*' commands put backslashed path in quotes
- segfault empty fields in gcrd-file 'TITLE:' or 'BDAY:'
2001-06-17_21 todo bug report by Konrad Mader <konrad.mader@gmx.de>
empty 'BDAY:' does not segfault, but put 'BDAY' (no colon) into PIMfile
and next ic35sync complains "parse error"
seem like output error, i.e. shall output 'BDAY:' not 'BDAY'
- report protocol error reasons (e.g. get_modflen timeout)
2001-06-17_21 todo bug report by Konrad Mader <konrad.mader@gmx.de>
should do better error reports for easier finding protocol problems
get_modflen timeout failure for 860 addresses fixed 2001-06-17_23
- combine ic35sync,ic35mgr into one program ic35link
2001-02-25_20 todo proposed by Harald Becker
- backward compatible: symlink ic35sync -> ic35link and ic35mgr -> ic35link
behave like before if argv[0] is "ic35sync" or "ic35mgr"
- partial help like CVS
--help
--help-options
--help-commands
-H <command> or --help <command>
- fixes suggested by GNU Coding Standards and automake/autoconf
2001-02-03_15 todo
+ configure.in: use AC_REVISION
+ fix warnings from -Wmissing-prototypes
+ fix warnings from -ansi
- fix warnings from -pedantic
+ long options --version --help etc. --info shows build-info
+ info enquiry with --version --help --info shall exit(0) !
- use config.h in sources where needed (e.g. VERSION), see gnotepad+
+ open device with O_NOCTTY
- test on okosuse (yacc/bison), test on tls
- misc: scripts for sync with gnome, korganizer
- bugs to <email> at end of --help message
- use 'autogen' for options and usage, see /usr/doc/autogen/autogen.ps
- update copyright 2001, add license notice
- ic35mgr.txt extensions
2001-01-31_02 todo
- new command 05 - retry read statusblock 16400-16 bytes
in WinNT logs from Michael Logs270101.tar.gz
- reponse 91 from IC35 for powerfail ? (see ic35mmcput52rcv91.log)
- analyse & describe contents of IC35 statusblock, logo-bitmap
see ic35mgr.txt 1.8.1
- ic35mgr communication improves
2001-01-30_01 todo
- use #define for busywait delaytime and blocksize
PIII/500MHz 16/3212 1/187
- measure and improve timeouts in mgrproto.c
? handle backup problem (Michael Bruennert): recv 90 instead of datablock
- handle mgrproto problem: abort on recv 90 instead A0 after send ack/nak
- mgrtrans.c: more disconn retry to catch >8.5 sec tmo on lost char
maybe do twice Mcmdrsp(MCMDreset,MRSPgotcmd)
- ic35sync syn{trans,proto}.* re-organize like mgr{trans,proto}.*
2001-01-29_12 todo
- ic35sync local database
2001-01-26_01 todo
to avoid read all IC35 records to check for deleted in PIMfiles
and for store "sysinfo" date+time to check match with IC35
may also need sync local databases between e.g. work-,home-system
use XML-format for local database ?!
- ic35mgr handle Ctl-C user interrupt
2001-01-12_21 todo
for mmcput,mmcget do mmc_close on SIGINT, for other ignore SIG_INT
e.g. mmc_readfile,mmc_writefile return ERRor on SIG_INT
- ic35mgr get/put multiple file, sync dirtree
2001-01-12_19 todo
- get multiple files:
mmcget MMCard1/dir/* get all files from dir
mmcget MMCard1/*.I35 get multiple files
mmcget MMCard1/dir/ get recursively all files in dir and below
mmcget MMCard1/ get recursively all files from MMCard
recursive get creates local directory tree like to MMCard subtree
additional localdir/ arg puts files below localdir/
put multiple files with same logic
problem: make dir on IC35 MMCard, use mmc_opendir(,MMCcreatrunc) ?
- synchronize MMCard with local dirtree
option "-n" to test what would be sync'd
- interactive transfer multiple files and walk dirs (like ftp)
2001-05-30_22 todo request guenther dreher-esders <guenther@esders-web.de>
- guenther wants to 'ic35mgr mmcput MMCard1/x*.txt' for reading big text
on IC35 split into many smaller files
- ic35sync support XML format
2001-01-09_17 todo proposed by Norbert Kolb
see xmlFiles.pdf.gz from Harald Becker
2001-02-25_20 work Harald Becker
- ic35sync sync/import/export e.g. ToDoList alone
2001-01-09_17 todo proposed by Norbert Kolb
- analyse and implement IC35 manager install application,bitmap,midi
2000-12-31 todo
- send application
- send IC35 start graphic bitmap
- send MIDI file
? remove application
? remove bitmap, MIDI file
- problem IC35 does not alarm
2000-12-30_20 todo
problem after: restore cfgmsg27.i35, set date+time, import 20001230.*
reason: old repeated events "ww" 20001023,20001027 with endrepeat before today
2000-12-31_17 50% reason found
ic35sync do not write events with endrepeat before today ?
- ic35sync corrections
2000-12-30_19 todo
+ on read_id_frec from IC35 fail do writerec instead of updaterec
2000-12-31_18 +30%
- write to IC35 all Sched,ToDo,Memo which not on IC35 (for initial sync)
- sync overwrites IC35 changes after: reset,delall,restore IC35
because IC35 appearently does not restore sysinfo date+time ?!
- shared library e.g. for perl module ic35-communications
2000-12-29_02 todo proposed by Norbert Kolb
- vcaconv vca2bin,bin2vca,bin2txt transfer recstat
design-problem ? updic35rec() and putic35rec() to not transfer recstat
see experimental dataio.c 1.32.2
2000-12-26_03 todo
- ic35sync conflict resolve options
2000-12-25_06 todo
- PIM override IC35 (default)
- IC35 overrides PIM
- duplicate conflict records
- inspect for sync,import/export: gnome-pilot,-conduits, pilot-link
- search sourceforge etc. for other PIM-programs
- reduce ic35sync log volume
2000-12-14_21 todo
option for loglevel, buffer higher level log lines in FIFO
flush buffered log to file on error, discard if buffer gets full
- ic35sync minor improvements
2000-12-17_17 todo
+ fix vcc.y compile warnings
x extract rcskvf() from ic35sync.c,ic35mgr.c to util.c
no more need with VERSION from configure.in
- pimfile(s) writable not pre-checked, pim_close() does not return write-error
- write and backup pimfile(s) only if really changed: global dirty-flag
- pim_open(),pim_close() are misleading names
xxx_open(),xxx_close re-design: who/where store filenames ?
see experimental dataio.c 1.32.1 and datavca.c 1.38.1
- dataio.c: use field map tables for vCard,vCal to/from IC35
- syntrans.c: internal fd, no need for fd-argument
implicit close on next open_file() and disconnect()
- synproto.c: finer checks in recvrsp()
- malloc/error traps with setjmp(),longjmp()
- improve gnomecard
2000-12-17_21 todo
- does not change X-PILOTSTAT !
fix: set X-PILOTSTAT:1 when VCARD changed
- changes VCARD.REV to UTC not local time !
- does update *ALL* VCARD.REV times on exit
reason: gnomecard wants yyyy-mm-ddThh:mm:ss, drops yyyymmddThhmmss
fix: accept also yyyymmddThhmmss
- default e-mail type is AOL, better change to INTERNET
- default birthday 1970-01-01 is bad, should be empty
- improve gnomecal
2000-12-25_19 todo
- extra field for VTODO.DTSTART
- extra field for VEVENT.DESCRIPTION
- do not crash if VEVENT,VTODO.CLASS:PUBLIC missing
- do not update *ALL* LAST-MODIFIED and DCREATED on exit
- add missing standard categories Personal,Business(,Unfiled)
- show/edit VTODO.STATUS
? output correct VCAL.VERSION:1.0 instead of 1.2.0
? seems to mis-behave with X-PILOTSTAT,X-PILOTID
- improve korganizer
2000-12-25_19 todo
- support VTODO.DTSTART,DUE
- support VTODO.CATEGORIES
- support also AALARM, distinguish from DALARM
? korganizer prios are 1,2,3,4 ? prios are duplicate ?
- problem: memory leak in vobject.c setVObjectStringZValue()
2000-12-12_02 todo
setVObjectStringZValue() and relatives discard previous string
although it may be malloc()ated'd and free() should be done.
* vobject.c has 'strTbl[]' possibly usable to fix memory leak
but strcasecmp prohibits use for any string
strTbl[] used in lookupStr unUseStr cleanStrTbl
lookupStr called by newVObject lookupProp
unUseStr called by deleteVObject
hashStr called by lookupStr unUseStr
- solution-1:
extend above vobject.c utilities with strcmp() instead of strcasecmp()
- solution-2:
always create new VObject instead of changing string values
re-create vobj-list and/or vprop-list, then use cleanVObject()
- solution-3:
deleteStr() previous string value before set new string value
- test-data for vCard,vCal to/from IC35 record conversion
2000-12-11_12 todo
- max.fieldlengths for each record
- Addresses
- name only
- no, one, two, three email-addrs
- telnos home,work,cell,fax
- non-ASCII in Name,ADR,ORG,..
- IC35 "(def.)" fields
- Schedule
- no alarm, LED-alarm, beep-alarm, LED+beep-alarm
- alarm 0,1,5,10,30 mins, 1,2,10 hours, 1,2 days before
- no repeat, repeat every d days, w weeks, m monwday, n monmday, y years
- ToDoList
- prio normal,high,low
- completed no,yes, other status
- Memo
- ic35sync tests for export
2000-12-15_12 todo
restore IC35 from MMC, export from IC35 as reference PIMfile
run tests: save PIMfile-1, export to PIMfile-2, compare PIMfile-1,-2
= export to new PIMfile
= export to existing same PIMfile
no changes in PIMfile
- add IC35 records, export
only added PIMrecords shall be affected (modified+created time, recID)
- change IC35 records, export
only changed PIMrecords shall be affected (modified time)
- add records to PIMfile, export
added records in PIMfile shall be unaffected
- change PIMrecords, export
changed PIMrecords shall be overwritten from IC35
- ic35sync tests for import
2000-12-15_12 todo
restore IC35 from MMC, export from IC35 as reference
run tests: export-1,import,export-2, compare export-1,-2
= import reference to IC35, i.e. re-import same data
changeflags on IC35 shall be reset, PIMfile unaffected
no write/update to IC35
= reset IC35, import reference into empty IC35
write all PIMrecords, new IC35-recIDs in PIMfile
owner addr shall appear as such
= add records to PIMfile, import
added PIMrecords on IC35, IC35-recIDs in added PIMrecords
- small PIMfile with all new records, import
all PIMrecords on IC35, IC35-recIDs in PIMrecords
= add records to IC35, import reference
added IC35 records shall have changeflag, no set_date+time
= change records in IC35, import reference
changed IC35 records shall be overwritten from PIMfile
- ic35sync tests for sync
2000-12-19_02 todo
= some test data in testdelfld{1,2,3}.vca
sync testdelfld1.vca
import testdelfld2.vca
export testout2.vca
copy testdelfld2.vca to testdelfld3t.vca, del fields,recs, set X-PILOTSTAT:1
sync testdelfld3t.vca
export testout3.vca should be same as testdelfld3t.vca
IC35: mark all records edited
copy testout2.vca to testdelfld4.vca
sync testdelfld4.vca should be same as testdelfld3t.vca
- specify more tests
- ic35sync interactive ?
2000-11-06_23 todo
- implicit connect, on exit disconnect
- set date, category
- open file, close file
- read file record
- write file record
- delete file record
- reset file record changeflag
- improve source comments
2000-12-01_17 todo
- ic35frec.c: IC35REC access logic
- synproto.c: PDU parameters
- ic35log.sh improvements and tests
2000-12-01_14 todo
- test with WindowsNT-2line logs: see below
- test with WindowsNT-1line logs: see below
- test with Windows98 logs: see below
- improve ic35prot() structure to make it more clear / readable
DONE
+ split ic35sync.c into modules:
2000-11-06_23 todo
+ util.c logging, error,message
+ comio.c serial communication
+ synproto.c L1,L2,L3 protocols
+ syntrans.c L4 protocol: IC35sync transactions
+ dataio.c import/export Addresses,Memo,Schedule,ToDoList as vCard,vCal
+ ic35sync.c main, IC35sync session
+ Makefile
2000-11-07_03 done
+ ic35sync minor improves
2000-11-07_01 todo
+ util.c
+ log_init() set also loglevel, default logtag=NULL ?
+ log ic35sync version/rcsid to logfile
+ syntrans.c
+ combined connect = welcome,identify,power,authenticate,getdtime ?
+ welcome: "WELCOME\x80" no need send "A" ?
+ stop on wrong password: response != 0101
+ Makefile
+ targets dist,dist_co for ic35sync_<vers>.tar.gz
+ integrated help
2000-11-15_04 +70% todo: Makefile
2000-11-18_23 done
+ ic35 record access
2000-11-15_02 todo
+ access record-field
+ num.of record-fields to struct ic35file
+ output binary record-data for offline vCard,vCal develop
2000-11-19_01 done
+ ic35sync export in vCard, vCalendar format
2000-11-06_23 todo
sources:
* /local/pkg/ic35/sdkdllsr.zip
vcc.h vcc.y vobject.h vobject.c
* kpilot_3.1.10-1.0.tar.gz
kpilot-3.1.10/conduits/vcalconduit/ vcal-conduit.h vcal-conduit.cc
kpilot-3.1.10/conduits/vcalconduit/versit/ vcc.h vcc.y vobject.h vobject.c
* gnome-pim_1.2.0.orig.tar.gz
gnome-pim-1.2.0/libversit/ vcc.h vcc.y vobject.h vobject.c
* gnome-pilot-conduits_0.4
* gnome-pilot_0.1.55-0pre
* jpilot_0.97
* pilot-manager_1.107
* pilot-link_0.9.3
2000-11-19_20 work
+ vcaconv:
+ IC35 raw data -> vCard,vCal
+ pretty-print vCard,vCal
+ move ic35file definitions to dataio.c to vcaconv link syntrans etc.
+ design output from IC35 to vCard,vCal file, maybe same file
+ XPilotId instead of UID
+ output text fields quoted printable if non-7bitASCII
use CHARSET=ISO-8859-1;QUOTED-PRINTABLE
+ Schedule: repeated events, recurrence rule
+ Schedule: DALARM = LED, AALARM = beep
+ whattodo with Memo in vCal format ?
use VMEMO record VCMemoProp, extend vcc.*,vobject.*
2000-11-20_05 +50%
2000-11-21_06 +70%
2000-11-22_08 done
x ic35sync export in vCard, vCalendar format: canceled tasks
2000-11-22_08 todo
x vcaconv: vCard,vCal -> IC35 raw data
x what is XPilotStatus for ? ICAL_PILOT_SYNC_{NONE,MOD,DEL}
2000-12-01_15 canc replaced by ic35sync import,sync step-2,-3
+ improve ic35prot.awk
2000-11-07_23 todo
+ test with WindowsNT-2line:
+ Simple_hex.log
+ Portmon_export.log
+ Import1.log
+ Import.tar.gz:Import.log
+ test with Windows98:
+ mgr_conn_disc.log
+ mgr_conn_disc_mmc.log.gz
+ sync_missoutlook.log
+ mgr_rwdfile_20001107.tar.gz:*.log
2000-11-15_01 +90% usable, todo: missing tests & improve structure
2000-11-27_13 canc ic35prot.awk replaced by ic35log.sh
x improve ic35prot.awk: canceled tasks
2000-11-07_23 todo
x test with WindowsNT-1line:
x Manager.tar.gz:*.LOG
x BackupRestore.tar.gz:*.log
x improve structure to make it more clear / readable
2000-11-27_13 canc ic35prot.awk replaced by ic35log.sh
+ improve ic35-prot-analyzer
20001124_20 todo
+ print 2nd ff. recdata fragments, 'currfid' less hacked
+ integrate in one script
+ ic35prot.awk faster and more clear
no need to support ASCII input
move ASCII output to separate pass
20001127_13 done
+ analyse Delete.tar.gz delete record etc.
2000-11-18_01 todo
+ meaning of new commands 01 02, 01 07
01 07 = read next modified record
01 02 = delete record
x meaning of category response 01 01, 00 01
moved to "ic35sync experiments"
2000-11-24_01 done
+ ic35sync.txt: document readrecmod, deleterec
20001124_20 todo
20001127_15 done
+ ic35sync import,sync step-1
20001124_20 todo
+ dataio.c: use rec-id AND file-id as UID/X-PILOTID
+ dataio.c: implement REV, LAST-MODIFIED
+ get_mod_flen
+ read_mod_frec
+ delete_frec
+ write_frec
+ set_date_time
+ category
20001128_04 done
+ ic35 record access
2000-11-21_02 todo
+ use ulong frid instead of uchar fid, ushort rid
+ internal IC35 record structure for easier access
+ break into fields, _get_recfld()'s static buffer is bad!
2000-12-01_02 +90% todo: opaque IC35FILE
+ hide ic35 file description internals, use acces functions
+ use 4byte record-ID in binary format
2000-12-01_19 done
+ ic35log.sh process ic35sync logfiles, create simulation files from them
2000-12-01_14 todo
2000-12-02_02 done
+ ic35sync experiments:
2000-11-06_23 todo
tests for category,filename in ic35sync.c 1.11.1 branch
+ check wrong password:
complains with 0100 (not 0101) only if password on power-on enabled
+ check category response
+ unknown category
+ category with no records, e.g. "Unfiled"
+ category with modified record(s)
+ category with new record(s)
+ new category with new record(s)
+ new category without records
+ set category influence on read_mod_frec ? NO!
mostly response for existing category is 01 01, for non-exist 00 01
but not always, still unclear what the category sematics are
+ test bad filename or other files, e.g. Messages ?
open compares only first any-case letter, unmatched opens "Schedule
2000-12-02_05 done
+ ic35sync import,sync step-2
20001124_20 todo
tests in ic35sync.c 1.11.1 branch
+ commit_frec
+ test functions for import,sync:
+ category
+ set_date_time
allows setting any text, tested up to 14 chars, maybe up to 16 chars
+ get_mod_flen, read_mod_frec
+ write_frec
+ delete_frec
+ commit_frec
+ field modified on PC: only write_frec or also del old frec ?
must delete_frec old, as write_frec gets new rec-ID (does NOT overwrite)
20001202_07 done
+ ic35sync experiments for new commands
20001201_20 todo
+ 00 01 ? file command ? ic35r{66,68}.log
IC35 accepts 1st command, response: E3,49 CD 0F
then IC35 hangs no more accepting commands
? 01 01 ? del all? NO! ic35r{62,63,65}.log
IC35 returns "done" response A0 03 00, record unchanged
* 01 02 fd_-- ri_--_-- fi delete_frec
* 01 03 fd_-- 00 00 00 00 get_flen
* 01 04 fd_-- 00 00 00 00 get_mod_flen
+ 01 05 fd_-- ri_--_-- fi read by recID ic35r{60,69,6A}.log
response non-exist Memo recID: A0,49 3E 81 D3 0D 60 xx xx xx 07
i.e. recID=0DD3813E, ch=60, 4 flens for Memo record
response non-exist Schedule recID: A0,49 FE AA 20 0E 00 xx xx xx ..
i.e. recID=0E20AAFE, ch=00, 10 flens for Schedule record
* 01 06 fd_-- 00 00 00 00 read_frec
* 01 07 fd_-- 00 00 00 00 read_mod_frec
* 01 08 fd_-- 00 00 00 00 write_frec
+ 01 09 fd_-- ri_--_-- fi ... update_frec ic35r{61,6B,6C}.log
re-writes record keeping same recID
* 01 0A fd_-- ri_--_-- fi commit_frec
2000-12-03_09 done
+ ic35sync import,sync step-3
20001124_20 todo
vCard,vCal to IC35 record, test with vcaconv
+ CategoryID cannot be mapped, use 0x00 and assume IC35 to create it
+ Category: assume IC35 auto-creates new category
+ vcard_to_ic35addr
+ vevent_to_ic35sched
+ vtodo_to_ic35todo
+ vmemo_to_ic35memo
20001207_04 done
+ problem: QUOTED-PRINTABLE fails with multi-field props like ADR,N,ORG,..
2000-12-16_15 todo
with QUOTED-PRINTABLE e.g. ADR fields are not separated, but
first field gets value of all fields with ';' embedded.
known but unfixed problem, see: http://www.imc.org/imc-vcard/mail-archive/
+ solution-1
do not use QUOTED-PRINTABLE on multi-field props, but only CHARSET
x solution-2
further debug problem to find real cause and fix
2000-12-16_21 done
+ ic35sync import,sync step-4 (import)
2000-11-24_20 todo
import,sync do both use set_date_time
+ what is XPilotStatus for ? ICAL_PILOT_SYNC_{NONE,MOD,DEL}
+ need update vCard,vCal from IC35rec to avoid destroy unmapped fields
+ import vCard,vCal or binary into IC35
2000-12-17_08 done
+ vcaconv optionally sort output needed for test
2000-12-17_06 todo
sort vCard,vCal to stdout
2000-12-20_16 done
+ problems with gnomecard
2000-12-17_21 todo
+ does not change X-PILOTSTAT, cannot not rely on X-PILOTSTAT alone
fix: detect change with create/modify-time VCARD.REV > last-sync-time
+ does update *ALL* VCARD.REV times on exit
reason: gnomecard wants yyyy-mm-ddThh:mm:ss, drops yyyymmddThhmmss
fix: produce VCARD.REV:yyyy-mm-ddThh:mm:ss
2000-12-21_15 done
+ problems with korganizer
2000-12-17_21 todo
+ wants VCAL PRODID:-//K Desktop Environment//NONSGML KOrganizer//EN
fixed ic35sync: do not change found VCAL:PRODID
must manually edit vCal output before load new into korganizer
+ complains if VEVENT,VTODO lack UID and does not load those without
fixed ic35sync: also put UID to VCAL:VEVENT,VTODO (and VCARD, VMEMO)
+ expects and produces NL-terminated lines, misbehaves on CRLF-terminated
fix ic35sync: auto-detect CRLF or NL and produce same output
+ output causes parse-error if CR in NOTE,DESC,..
need translate NOTE,DESC: PIM NL <-> IC35 CRLF
+ does not support VTODO.DTSTART,DUE
fix ic35sync: map to marked lines in VTODO
+ does not support VTODO.CATEGORIES, keep IC35 on PIM->IC35 update
x has VEVENT.CATEGORIES, but IC35 has not
2000-12-24_20 done
+ problems with gnomecal
2000-12-17_21 todo
+ does not support VTODO.DTSTART, but keeps in vCal on exit
fix ic35sync: keep marked line in VTODO.DESCRIPTION
+ crashes if VTODO,VEVENT.CLASS:PUBLIC is missing
fix ic35sync: put CLASS:PUBLIC to VTODO,VEVENT if missing
+ does not support VEVENT.DESCRIPTION, removes it from vCal on exit
vevent_to_ic35sched: 1st line to S_Subject, more lines to S_Notes
ic35sched_to_vevent: for gnomecal append S_Notes to VEVENT.SUMMARY
x outputs bad VCAL.VERSION:1.2.0, ic35sync keeps found version
2000-12-25_19 done
+ ic35sync import,sync step-5 (sync)
2000-12-15_12 todo
+ sync vCard,vCal with IC35
+ conflict resolve: initial sync empty PIM must not delete all IC35!
+ inspect for sync,import: gnome-pim, kpilot
2000-12-25_06 done
+ ic35sync some improvements
2000-12-17_17 todo
+ comio.c: for simulate do not set DTR neither open comport
+ comio.c: log input V.24 signals on change
+ comio.c: allow also WRx and RDx in simulation file
+ dataio.c: remove unused _get_vcarec()
+ dataio.c big, split: dataio.c 341 datatxt.c 92 databin.c 385 datavca.c 1528
+ dataio.c: translate CRLF<->NL in NOTES,DESCRIPTION
+ dataio.c utils, special conversions depend on PRODID Gnome,KOrganizer
put/get IC35 fields unsupported by PIM with mark in NOTE/DESCRIPTION
+ KOrganizer: VTODO.CATEGORIES,DTSTART,DUE to/from VTODO.DESCRIPTION
+ gnomecal: VTODO.DTSTART to/from VTODO.DESCRIPTION
+ gnomecal: VEVENT.DESCRIPTION 1st line S_Subject, more S_Notes
+ all: "(def1):","(def2):" to/from VCARD.NOTE
+ cmp_ic35rec() from dataio.c to ic35frec.c:cmp_ic35rec ?
2000-12-25_23 done
+ ic35sync delete fields
currently IC35 to/from PIM record conversions do not delete fields
2000-12-27_19 todo
2000-12-29_04 done
+ correct vcaconv
produces empty output on 'vcaconv sortvca ic35.vcal'
2000-12-31_01 todo
fix: correct error in vobject.c
2000-12-31_18 done
+ analyse IC35 manager protocol
2000-11-06_23 todo
+ init, exit
+ backup database.org
+ restore database.org
+ read MMCard directories
+ read file from MMCard
2001-01-04_06 +70%
+ write file to MMCard
+ delete file on MMCard
2001-01-10_03 done
+ implement IC35 manager MMCard operations
2000-12-31_18 todo
+ init, exit
+ read MMCard directories
+ read file from MMCard
2001-01-10_02 +60%
+ write file to MMCard
+ delete file on MMCard
2001-01-12_22 done
+ implement IC35 manager backup,restore operations
2000-12-31_18 todo
+ backup database.org
+ restore database.org
2001-01-17_06 done
+ improve ic35mgr throughput
2001-01-12_20 todo
ic35mgr-1.17.4, busy wait 3.25ms every 16 byte block, 2 stopbits
backup 426128 read 16384 117.3248 3632 b/s
block recv 16384 3.3211 4924 b/s
restore 426128 write 16384 140.4816 3033 b/s
block send 16384 3.5056 4674 b/s
ic35mgr-1.12a, with com_sendw(), itimer pause every 29 chars, 2 stopbits
reversi.app 16452 read 5120 6.5236 2522 b/s
reversi.app 16452 write 2048 11.9835 1373 b/s
+ comio.c,comio.h: separate com_sendw() with wait
+ mgrproto.c: use com_sendw() with wait only for big blocks
measurements:
install MMCard:browser.app 376900 117.69 3202 b/s
install MMCard:sc_info.app 16452 10.07 1634 b/s
install MMCard:convert.app 49220 15.22 3234 b/s
restore MMCard1\20010124.I35 52222 25.962 2011 b/s
backup MMCard1\20010121.I35 50701 20.625 2458 b/s
ic35mgr-1.10a, with com_sendw(), itimer pause every 29 chars, 2 stopbits
reversi.app 16452 read 5120 6.5678 2505 b/s
reversi.app 16452 write 2048 12.0640 1364 b/s
backup 426128 read 16384 117.4514 3628 b/s
block recv 16384 3.3287 4922 b/s
restore 426128 write 16384 203.6398 2093 b/s
block send 16384 6.0531 2707 b/s
status 16400 recv 16384 1.8257 8983 b/s
itimer, pause every 29 chars, 2 stopbits
reversi.app 16452 write 5120 11.8633 1387 b/s
2048 12.3224 1335 b/s rewrite 13.8034 1192 b/s
mgrep.app 32836 write 2048 24.6884 1330 b/s
domind.app 49220 write 2048 37.1055 1326 b/s
domind.app 49220 read 5120 20.0052 2460 b/s
usleep(29*400) every 29 bytes, 2 stopbits
reversi.app 16452 write 5120 17.69 929 b/s
2048 18.42 893 b/s
usleep(100) every 16 bytes
reversi.app 16452 write 5120 26.965 610 b/s
2048 27.764 593 b/s rewrite 29.094 565 b/s
1024 29.465 558 b/s
reversi.app 16452 read 10240 6.825 2410 b/s
5120 7.284 2259 b/s 7.385 2228 b/s
2048 8.485 1939 b/s
1024 10.204 1612 b/s
256 20.396 807 b/s
15 243.773 67 b/s
2001-01-18_02 done
+ fix compile errors with gcc-2.96 under RedHat-7.0
2001-01-19_17 todo reported by Dieter Schultschik
+ synproto.c:sendcmd() line-531,537,542,548,549,554,567,594
531:fd, 537:fd, 542:fd, 548:fd, 549:index, 554:fd, 567:fd, 594:fd
`short unsigned int' is promoted to `int' when passed through `...'
(so you should pass `int' not `short unsigned int' to `va_arg')
+ mgrproto.c similar problem
+ generally avoid va_arg with sendcmd() etc, replace sendcmd(CMDfclosem,fd)
with e.g. sendCMDfclose(fd) would yield compile-time prototype checking
2001-01-29_13 done
+ improve ic35mgr
2001-01-12_20 todo
+ mgrproto.c: recvmrsp() / MPDUrecv() discard checksum
+ mgrtrans.c: protocol comments, identify,disconn,.. belong to mgrproto.c
+ move backup protocol from mgrtrans.c to mgrproto.{c,h}
concentrate log,progress,errmsg separate from communication protocol
+ move putxxx(),getxxx(),chksum() from mgrtrans.c,xxxproto.{c,h}
and also welcome() etc. to genproto.{c,h}
2001-01-24_03 +50%
+ move _not_impl() from ic35mgr.c to util.{c,h}
+ recvmrsp() always return mstate, not pdulen
+ mgrproto.c: common structs for same PDUs
2001-01-29_12 +70%
+ mgrproto.c: common convert direntry and FILE_INFO
+ mgrproto.c: define iden/FILE_IDEN details, export size, how mismatch?
+ mgrproto.h: move attribs,modes from mgrtrans.h (else mgrproto.c unusable)
for backward compatible #include mgrproto.h in mgrtrans.c
x mgrtrans.c: common struct for MMCDIR MMCFILE
x extract rcskvf() from ic35sync.c,ic35mgr.c to util.c
with VERSION imported rcskvf() is obsolete
2001-02-03_18 done
+ supply also vcc.c problem found by Harald Becker, Michael Bruennert
2001-01-19_09 todo
supply also vcc.c for systems without or with bad bison/yacc
SuSE-7.0 yacc-91.7.30-220 is bad, need bison >= 1.25
2001-02-04_01 done
+ automake/autoconf
2000-12-29_02 todo proposed by Norbert Kolb
* see Software-Release-Practice-HOWTO, GNU Coding Standards
* must unset CDPATH, else re-automake fails!
+ configure.in Makefile.am, then run:
aclocal; autoheader; automake --add-missing --gnu; autoconf; ./configure
+ re-org into dirs src/ docs/
+ make CVS-tree, use .cvsignore
+ AUTHORS
+ THANKS or CREDITS
+ NEWS: compact version info
+ README: re-org like Software-Release-Practice-HOWTO suggests
x acconfig.h: ISODATE NOT NEEDED
+ program-versions from VERSION,ISODATE, remove rcskvf
+ step-1: do it with current Makefile
+ build-info like gnotepad+
+ fix also top-entry in logfiles
2001-02-05_03 done
+ README / more docs, e.g. restrictions & workarounds
2001-01-26_03 todo
+ Korganizer: PRODID, workaround missing vCal properties (...)
+ GnomeCal: PRODID, workaround missing vCal properties (...)
+ GnomeCard: missiong X-PILOT-STAT support and workaround
+ problem with bash eating backslash of ic35path
+ errors/warnings with 'configure --enable-pedantic'
+ compile problem with yacc (if vcc.y changed)
+ no sync conflict resolve yet
+ proprietary VMEMO format
2001-02-17_21 done
+ ic35mgr mmcget/mmcput check ic35path before connect
bug-report from Thomas Lichtenberg
2001-02-06_00 todo
valid ic35path:
+ auto-translate leading anycase mmcard[12], lower to upper, '/' to '\'
+ leading "MMCard[12]/"
+ adjacent / or \ not allowed
+ max 1 dot between '/' and '/' or end
+ max 8 chars before dot
+ max 3 chars after dot
tests (mail from Thomas Lichtenberg):
+ ic35mgr mmcdel MMCard1\IC35\BITMAP\INDIANER.BMP
+ ic35mgr mmcput MMCard1\TEST\TEST1.TXT test.txt
2001-02-18_07 done
+ correct com_simrecv(): dummy for non-logged receive bytes, adjacent "RD nn"
2001-01-04_05 todo
+ err.corr: fill block from adjacent "RD nn" lines, dummy non-logged
x handle checksum problem due to dummy bytes
cannot, must patch simfile with expected checksum(s)
2001-02-18_23 done
+ configure --disable-logandcomsim
2001-02-25_20 todo proposed by Harald Becker
+ configure option for disable logging and simulation for production version
default enabled
+ use macros LPRINTF(()), LOG_INIT(()), etc. to reduce codesize
2001-03-02_02 done
+ reduce priority when using busywait
2001-02-25_20 todo proposed by Harald Becker
+ use for restore,mmcput only, nice(+2), man 2 nice
+ option "-n niceval" or "--nice niceval", default niceval 2
allowed for users 0..19 for root -20..19, 0 is normal prio
2001-03-03_04 done
+ autogen.sh script for generating configure, Makefile.in, etc.
2001-05-30_11 todo problem report by Konrad Mader <konrad.mader@gmx.de>
2001-08-02_22 done

230
autogen.sh Normal file
View File

@ -0,0 +1,230 @@
#!/bin/sh
# $Id: autogen.sh,v 1.4 2001/08/12 03:34:50 thosch Rel $
# Copyright (C) 2001 Thomas Schulz
#
# Run this to generate configure and all the initial makefiles, etc.
# This is the long version with lots of checks instead of the short version
# aclocal && autoheader && automake --add-missing --gnu && autoconf
# It will automagically run './configure $CONFIGURE_FLAGS', prevent that
# by setting the environment variable NOCONFIGURE to a non-empty value.
# NOCONFIGURE=true # would disable auto-configure
CONFIGURE_FLAGS="--enable-maintainer-mode" # default flags for configure
# ACLOCAL_FLAGS= # additional flags for aclocal
DIE=0
srcdir=`dirname $0`
eval `grep '^PACKAGE=' $srcdir/configure.in`
if [ -n "$GNOME2_PATH" ]; then
ACLOCAL_FLAGS="-I $GNOME2_PATH/share/aclocal $ACLOCAL_FLAGS"
PATH="$GNOME2_PATH/bin:$PATH"
export PATH
fi
#
# check for autoconf
#
(autoconf --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have \`autoconf' installed to compile $PACKAGE"
echo "Download the appropriate package for your distribution,"
echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
DIE=1
}
#
# check for xml-i18n-toolize if needed
#
(grep "^AM_PROG_XML_I18N_TOOLS" $srcdir/configure.in >/dev/null) && {
(xml-i18n-toolize --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have \`xml-i18n-toolize' installed to compile $PACKAGE"
echo "Get ftp://ftp.gnome.org/pub/GNOME/stable/sources/xml-i18n-tools/xml-i18n-tools-0.6.tar.gz"
echo "(or a newer version if it is available)"
DIE=1
}
}
#
# check for libtool if needed
#
(grep "^AM_PROG_LIBTOOL" $srcdir/configure.in >/dev/null) && {
(libtool --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have \`libtool' installed to compile $PACKAGE"
echo "Get ftp://ftp.gnu.org/pub/gnu/libtool-1.2d.tar.gz"
echo "(or a newer version if it is available)"
DIE=1
}
}
#
# check for gettext if needed
#
#grep "^AM_GNU_GETTEXT" $srcdir/configure.in >/dev/null && {
# grep "sed.*POTFILES" $srcdir/configure.in >/dev/null || \
# (gettext --version) < /dev/null > /dev/null 2>&1 || {
# echo
# echo "**Error**: You must have \`gettext' installed to compile $PACKAGE"
# echo "Get ftp://alpha.gnu.org/gnu/gettext-0.10.35.tar.gz"
# echo "(or a newer version if it is available)"
# DIE=1
# }
#}
#grep "^AM_GNOME_GETTEXT" $srcdir/configure.in >/dev/null && {
# grep "sed.*POTFILES" $srcdir/configure.in >/dev/null || \
# (gettext --version) < /dev/null > /dev/null 2>&1 || {
# echo
# echo "**Error**: You must have \`gettext' installed to compile $PACKAGE"
# echo "Get ftp://alpha.gnu.org/gnu/gettext-0.10.35.tar.gz"
# echo "(or a newer version if it is available)"
# DIE=1
# }
#}
#
# check for automake
#
(automake --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have \`automake' installed to compile $PACKAGE"
echo "Download the appropriate package for your distribution,"
echo "or get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz"
echo "(or a newer version if it is available)"
DIE=1
NO_AUTOMAKE=yes
}
#
# check for aclocal
#
# if no automake, don't bother testing for aclocal
test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: Missing \`aclocal'. The version of \`automake'"
echo "installed doesn't appear recent enough."
echo "Download the appropriate package for your distribution,"
echo "or get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz"
echo "(or a newer version if it is available)"
DIE=1
}
if test "$DIE" -eq 1; then # some tools are missing
exit 1
fi
if test -z "$*" -a -z "$NOCONFIGURE"; then
echo "**Warning**: I am going to run \`configure $CONFIGURE_FLAGS'"
echo "If you wish to pass additional flags to it, please specify them on"
echo "the \`$0' command line."
echo
fi
case $CC in
xlc )
am_opt=--include-deps;;
esac
for coin in `find $srcdir -name configure.in -print`
do
dr=`dirname $coin`
if test -f $dr/NO-AUTO-GEN; then
echo skipping $dr -- flagged as no auto-gen
else
echo processing $dr
macrodirs=`sed -n -e 's,AM_ACLOCAL_INCLUDE(\(.*\)),\1,gp' < $coin`
( cd $dr
macrosdir=`find . -name macros -print`
for i in $macrodirs; do
if test -f $i/gnome-gettext.m4; then
DELETEFILES="$DELETEFILES $i/gnome-gettext.m4"
fi
done
echo "deletefiles is $DELETEFILES"
aclocalinclude="$ACLOCAL_FLAGS"
for k in $aclocalinclude; do
if test -d $k; then
if [ -f $k/gnome.m4 -a "$GNOME_INTERFACE_VERSION" = "1" ]; then
rm -f $DELETEFILES
fi
fi
done
for k in $macrodirs; do
if test -d $k; then
aclocalinclude="$aclocalinclude -I $k"
if [ -f $k/gnome.m4 -a "$GNOME_INTERFACE_VERSION" = "1" ]; then
rm -f $DELETEFILES
fi
fi
done
if grep "^AM_GNU_GETTEXT" configure.in >/dev/null; then
if grep "sed.*POTFILES" configure.in >/dev/null; then
: do nothing -- we still have an old unmodified configure.in
else
echo "Creating $dr/aclocal.m4 ..."
test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
echo "Running gettextize... Ignore non-fatal messages."
echo "no" | gettextize --force --copy
echo "Making $dr/aclocal.m4 writable ..."
test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
fi
fi
if grep "^AM_GNOME_GETTEXT" configure.in >/dev/null; then
echo "Creating $dr/aclocal.m4 ..."
test -r $dr/aclocal.m4 || touch $dr/aclocal.m4
echo "Running gettextize... Ignore non-fatal messages."
echo "no" | gettextize --force --copy
echo "Making $dr/aclocal.m4 writable ..."
test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4
fi
if grep "^AM_PROG_XML_I18N_TOOLS" configure.in >/dev/null; then
echo "Running xml-i18n-toolize... Ignore non-fatal messages."
xml-i18n-toolize --copy --force --automake
fi
if grep "^AM_PROG_LIBTOOL" configure.in >/dev/null; then
if test -z "$NO_LIBTOOLIZE" ; then
echo "Running libtoolize..."
libtoolize --force --copy
fi
fi
echo "Running aclocal $aclocalinclude ..."
aclocal $aclocalinclude || {
echo
echo "**Error**: aclocal failed. This may mean that you have not"
echo "installed all of the packages you need, or you may need to"
echo "set ACLOCAL_FLAGS to include \"-I \$prefix/share/aclocal\""
echo "for the prefix where you installed the packages whose"
echo "macros were not found"
exit 1
}
if grep "^AM_CONFIG_HEADER" configure.in >/dev/null; then
echo "Running autoheader..."
autoheader || { echo "**Error**: autoheader failed."; exit 1; }
fi
echo "Running automake --gnu $am_opt ..."
automake --add-missing --gnu $am_opt ||
{ echo "**Error**: automake failed."; exit 1; }
echo "Running autoconf ..."
autoconf || { echo "**Error**: autoconf failed."; exit 1; }
) || exit 1
fi
done
if test x$NOCONFIGURE = x; then
echo
echo Running $srcdir/configure $CONFIGURE_FLAGS "$@" ...
$srcdir/configure $CONFIGURE_FLAGS "$@" \
&& echo Now type \`make\' to compile $PACKAGE || exit 1
else
echo
echo Skipping configure process.
echo "Now type \`./configure $CONFIGURE_FLAGS'"
echo "and then \`make' to compile $PACKAGE"
echo " or type \`./configure --help' and see README for configure options."
fi

348
compile Executable file
View File

@ -0,0 +1,348 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2018-03-07.03; # UTC
# Copyright (C) 1999-2020 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be 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, see <https://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
nl='
'
# We need space, tab and new line, in precisely that order. Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" "" $nl"
file_conv=
# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN* | MSYS*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv/,$2, in
*,$file_conv,*)
;;
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/* | msys/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_cl_dashL linkdir
# Make cl look for libraries in LINKDIR
func_cl_dashL ()
{
func_file_conv "$1"
if test -z "$lib_path"; then
lib_path=$file
else
lib_path="$lib_path;$file"
fi
linker_opts="$linker_opts -LIBPATH:$file"
}
# func_cl_dashl library
# Do a library search-path lookup for cl
func_cl_dashl ()
{
lib=$1
found=no
save_IFS=$IFS
IFS=';'
for dir in $lib_path $LIB
do
IFS=$save_IFS
if $shared && test -f "$dir/$lib.dll.lib"; then
found=yes
lib=$dir/$lib.dll.lib
break
fi
if test -f "$dir/$lib.lib"; then
found=yes
lib=$dir/$lib.lib
break
fi
if test -f "$dir/lib$lib.a"; then
found=yes
lib=$dir/lib$lib.a
break
fi
done
IFS=$save_IFS
if test "$found" != yes; then
lib=$lib.lib
fi
}
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
# Assume a capable shell
lib_path=
shared=:
linker_opts=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
eat=1
case $2 in
*.o | *.[oO][bB][jJ])
func_file_conv "$2"
set x "$@" -Fo"$file"
shift
;;
*)
func_file_conv "$2"
set x "$@" -Fe"$file"
shift
;;
esac
;;
-I)
eat=1
func_file_conv "$2" mingw
set x "$@" -I"$file"
shift
;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
-l)
eat=1
func_cl_dashl "$2"
set x "$@" "$lib"
shift
;;
-l*)
func_cl_dashl "${1#-l}"
set x "$@" "$lib"
shift
;;
-L)
eat=1
func_cl_dashL "$2"
;;
-L*)
func_cl_dashL "${1#-L}"
;;
-static)
shared=false
;;
-Wl,*)
arg=${1#-Wl,}
save_ifs="$IFS"; IFS=','
for flag in $arg; do
IFS="$save_ifs"
linker_opts="$linker_opts $flag"
done
IFS="$save_ifs"
;;
-Xlinker)
eat=1
linker_opts="$linker_opts $2"
;;
-*)
set x "$@" "$1"
shift
;;
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
func_file_conv "$1"
set x "$@" -Tp"$file"
shift
;;
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
func_file_conv "$1" mingw
set x "$@" "$file"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -n "$linker_opts"; then
linker_opts="-link$linker_opts"
fi
exec "$@" $linker_opts
exit 1
}
eat=
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "compile $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
ofile=
cfile=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
# So we strip '-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no '-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# '.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:

201
configure.in Normal file
View File

@ -0,0 +1,201 @@
dnl ---------------------------------------------------------------------------
dnl Process this file with autoconf to produce a configure script.
dnl $Id: configure.in,v 1.9 2001/11/20 23:28:10 thosch Exp $
dnl Copyright (C) 2001 Thomas Schulz
dnl ---------------------------------------------------------------------------
AC_INIT(src/ic35sync.c)
AC_REVISION($Revision: 1.9 $ $Date: 2001/11/20 23:28:10 $)
dnl ---------------------------------------------------------------------------
dnl This is the only place where the package version appears
dnl ---------------------------------------------------------------------------
PACKAGE=ic35link
VERSION=1.18.1
ISODATE=2001-11-10
AC_SUBST(ISODATE)
AC_DEFINE_UNQUOTED(ISODATE, "$ISODATE", release date)
dnl ---------------------------------------------------------------------------
dnl Initialize automake
dnl ---------------------------------------------------------------------------
dnl ??? AUTOMAKE_OPTIONS=no-dependencies
AM_INIT_AUTOMAKE($PACKAGE, $VERSION)
AC_PREFIX_DEFAULT(/usr/local)
AM_MAINTAINER_MODE
dnl ---------------------------------------------------------------------------
dnl checks for needed compilers
dnl ---------------------------------------------------------------------------
AC_PROG_CC
dnl ---------------------------------------------------------------------------
dnl option: disable logging and com-simulation
dnl ---------------------------------------------------------------------------
logandcomsim=yes
AC_MSG_CHECKING(if we want logging and com-simulation)
AC_ARG_ENABLE(
logandcomsim,
[ --enable-logandcomsim [default=yes] enable logging and com-simulation],
logandcomsim="$enableval", logandcomsim="yes"
)
AC_MSG_RESULT($logandcomsim)
if test "$logandcomsim" != "yes"; then
AC_DEFINE_UNQUOTED(NO_LOGSIM, 1, disable log and com-simulation)
fi
dnl ---------------------------------------------------------------------------
dnl option: disable clean compiles
dnl ---------------------------------------------------------------------------
compiler_warnings=yes
AC_MSG_CHECKING(if we want compiler warnings)
AC_ARG_ENABLE(
warnings,
[ --enable-warnings [default=yes] enable gcc compiler warnings],
compiler_warnings="$enableval", compiler_warnings="yes"
)
AC_MSG_RESULT($compiler_warnings)
dnl ---------------------------------------------------------------------------
dnl option: ansi warnings
dnl ---------------------------------------------------------------------------
AC_MSG_CHECKING(whether to compile with strict ANSI)
AC_ARG_ENABLE(
ansi,
[ --enable-ansi [default=no] enable gcc strict ansi checking],
,
[enable_ansi="no"])
AC_MSG_RESULT($enable_ansi)
dnl ---------------------------------------------------------------------------
dnl option: pedantic warnings
dnl ---------------------------------------------------------------------------
AC_MSG_CHECKING(whether to compile with pedantic warnings)
AC_ARG_ENABLE(
pedantic,
[ --enable-pedantic [default=no] enable gcc pedantic checking],
,
[enable_pedantic="no"])
AC_MSG_RESULT($enable_pedantic)
if test "$ac_cv_prog_CC" = gcc -o "$ac_cv_prog_CC" = g++; then
if test $compiler_warnings = yes; then
if echo "$CFLAGS" | grep "\-Wall" > /dev/null 2> /dev/null; then
CFLAGS="$CFLAGS"
else
echo "updating CFLAGS with extra '-Wall' option"
CFLAGS="$CFLAGS -Wall"
fi
if echo "$CFLAGS" | grep "\-Wmissing-prototypes" > /dev/null 2> /dev/null; then
CFLAGS="$CFLAGS"
else
echo "updating CFLAGS with extra '-Wmissing-prototypes' option"
CFLAGS="$CFLAGS -Wmissing-prototypes"
fi
fi
if test "$enable_ansi" = "yes"; then
if echo "$CFLAGS" | grep "\-ansi" > /dev/null 2> /dev/null; then
CFLAGS="$CFLAGS"
else
CFLAGS="$CFLAGS -ansi"
echo "updating CFLAGS with extra '-ansi' option"
fi
fi
if test "$enable_pedantic" = "yes"; then
if echo "$CFLAGS" | grep "\-pedantic" > /dev/null 2> /dev/null; then
CFLAGS="$CFLAGS"
else
CFLAGS="$CFLAGS -pedantic"
echo "updating CFLAGS with extra '-pedantic' option"
fi
fi
fi
dnl ---------------------------------------------------------------------------
dnl generate the config header
dnl ---------------------------------------------------------------------------
AM_CONFIG_HEADER(config.h)
dnl ---------------------------------------------------------------------------
dnl Checks for programs.
dnl ---------------------------------------------------------------------------
AC_PROG_INSTALL
dnl AC_PROG_CC was checked above already
AC_PROG_YACC
AC_PROG_AWK
AC_PROG_LN_S
dnl ---------------------------------------------------------------------------
dnl Checks for header files.
dnl ---------------------------------------------------------------------------
AC_HEADER_STDC
AC_CHECK_HEADERS(fcntl.h malloc.h sys/ioctl.h unistd.h)
AC_HEADER_TIME
dnl ---------------------------------------------------------------------------
dnl Checks for typedefs, structures, and compiler characteristics.
dnl ---------------------------------------------------------------------------
AC_C_CONST
AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_STRUCT_TM
dnl ---------------------------------------------------------------------------
dnl Checks for library functions.
dnl ---------------------------------------------------------------------------
AC_PROG_GCC_TRADITIONAL
AC_FUNC_MEMCMP
AC_TYPE_SIGNAL
AC_FUNC_STRFTIME
dnl ??? AC_CHECK_USLEEP
dnl ??? AC_CHECK_ITIMER
AC_FUNC_UTIME_NULL
AC_FUNC_VPRINTF
AC_CHECK_FUNCS(gettimeofday mktime select strdup strerror strspn strstr)
dnl ---------------------------------------------------------------------------
dnl Makefiles to create:
dnl ---------------------------------------------------------------------------
AC_OUTPUT(Makefile src/Makefile doc/Makefile)
dnl ---------------------------------------------------------------------------
dnl output our configuration
dnl ---------------------------------------------------------------------------
echo
echo these are the options selected:
echo
if test "$USE_MAINTAINER_MODE" = "yes"; then
echo " maintainer mode : YES"
else
echo " maintainer mode : NO"
fi
if test "$logandcomsim" = "yes"; then
echo " log and com-simulation : YES"
else
echo " log and com-simulation : NO"
fi
if test "$compiler_warnings" = "yes"; then
echo " gcc compiler warnings : YES"
else
echo " gcc compiler warnings : NO"
fi
if test "$enable_ansi" = "yes"; then
echo " gcc compile with strict ansi : YES"
else
echo " gcc compile with strict ansi : NO"
fi
if test "$enable_pedantic" = "yes"; then
echo " gcc compiler pedantic checking: YES"
else
echo " gcc compiler pedantic checking: NO"
fi
echo

6
debian/README.Debian vendored Normal file
View File

@ -0,0 +1,6 @@
ic35link for Debian
------------------
This package currently "builds" on debian unstable but I won't recommend it at the current state.
-- crt0mega <crt0mega@c-r-t.tk> Tue, 15 Sep 2020 20:13:25 +0200

8
debian/README.source vendored Normal file
View File

@ -0,0 +1,8 @@
ic35link for Debian
------------------
Currently, every modifications to convince gcc of building this package are managed with quilt.
-- crt0mega <crt0mega@c-r-t.tk> Tue, 15 Sep 2020 20:13:25 +0200

5
debian/changelog vendored Normal file
View File

@ -0,0 +1,5 @@
ic35link (1.18.1-1) unstable; urgency=medium
* Initial release after adding compiler-workarounds and fixing some minor errors
-- crt0mega <crt0mega@c-r-t.tk> Tue, 15 Sep 2020 20:13:25 +0200

16
debian/control vendored Normal file
View File

@ -0,0 +1,16 @@
Source: ic35link
Section: unknown
Priority: optional
Maintainer: crt0mega <crt0mega@c-r-t.tk>
Build-Depends: debhelper-compat (= 12)
Standards-Version: 4.5.0
#Homepage: <insert the upstream URL, if relevant>
#Vcs-Browser: https://salsa.debian.org/debian/ic35link
#Vcs-Git: https://salsa.debian.org/debian/ic35link.git
Package: ic35link
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Revived managing and syncing software for IC35
This is a revival of the old ic35link software by Thomas Schulz.

1
debian/copyright vendored Symbolic link
View File

@ -0,0 +1 @@
COPYING

3
debian/files vendored Normal file
View File

@ -0,0 +1,3 @@
ic35link-dbgsym_1.18.1-1_amd64.deb debug optional automatic=yes
ic35link_1.18.1-1_amd64.buildinfo unknown optional
ic35link_1.18.1-1_amd64.deb unknown optional

2
debian/ic35link-docs.docs vendored Normal file
View File

@ -0,0 +1,2 @@
README.Debian
README.source

20
debian/ic35link.doc-base.EX vendored Normal file
View File

@ -0,0 +1,20 @@
Document: ic35link
Title: Debian ic35link Manual
Author: <insert document author here>
Abstract: This manual describes what ic35link is
and how it can be used to
manage online manuals on Debian systems.
Section: unknown
Format: debiandoc-sgml
Files: /usr/share/doc/ic35link/ic35link.sgml.gz
Format: postscript
Files: /usr/share/doc/ic35link/ic35link.ps.gz
Format: text
Files: /usr/share/doc/ic35link/ic35link.text.gz
Format: HTML
Index: /usr/share/doc/ic35link/html/index.html
Files: /usr/share/doc/ic35link/html/*.html

3
debian/ic35link.substvars vendored Normal file
View File

@ -0,0 +1,3 @@
shlibs:Depends=libc6 (>= 2.15)
misc:Depends=
misc:Pre-Depends=

16
debian/patches/fix-formats vendored Normal file
View File

@ -0,0 +1,16 @@
--- a/src/datatxt.c
+++ b/src/datatxt.c
@@ -67,11 +67,11 @@
++idx; /* increment rec.index */
}
get_ic35recdata( rec, NULL, &len );
- fprintf(outfp,"File \"%s\" Record %3d IC35id=%08lX cflag=%02X length=%d\n",
+ fprintf(outfp,"File \"%s\" Record %3d IC35id=%08lX cflag=%02X length=%ld\n",
ic35fname(fileid), idx, ic35recid(rec), ic35recchg(rec), len);
for ( fi = 0; fi < ic35fnflds( fileid ); ++fi ) {
get_ic35recfld( rec, FILEfld(fileid,fi), &fld, &len );
- fprintf( outfp, "f%d(%d)\t", fi, len );
+ fprintf( outfp, "f%d(%ld)\t", fi, len );
if ( len != 0 ) {
fprintf( outfp, "\"" );
for ( i = 0; i < len; ++i ) {

11
debian/patches/fix-label vendored Normal file
View File

@ -0,0 +1,11 @@
--- a/src/ic35mgr.c
+++ b/src/ic35mgr.c
@@ -519,7 +519,7 @@
mmcget(ic35path, NULL);
free(ic35path);
break;
- default:
+ default:;
}
}
rc = mmc_closedir( dirp );

14
debian/patches/gcc-build-workaround vendored Normal file
View File

@ -0,0 +1,14 @@
Adding several $CFLAGs as a workaround for building this currently broken package with current gcc versions
--- a/configure.in
+++ b/configure.in
@@ -116,6 +116,10 @@
fi
fi
+dnl ---------------------------------------------------------------------------
+dnl Add several cflags as a workaround
+dnl ---------------------------------------------------------------------------
+CFLAGS="$CFLAGS -Wno-format-overflow -Wno-stringop-overflow -Wno-builtin-declaration-mismatch -Wno-aggressive-loop-optimizations -Wno-unused-result -Wno-pointer-to-int-cast"
dnl ---------------------------------------------------------------------------
dnl generate the config header

3
debian/patches/series vendored Normal file
View File

@ -0,0 +1,3 @@
gcc-build-workaround
fix-formats
fix-label

25
debian/rules vendored Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/make -f
# See debhelper(7) (uncomment to enable)
# output every command that modifies files on the build system.
#export DH_VERBOSE = 1
# see FEATURE AREAS in dpkg-buildflags(1)
#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
# see ENVIRONMENT in dpkg-buildflags(1)
# package maintainers to append CFLAGS
#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic
# package maintainers to append LDFLAGS
#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
%:
dh $@ --with autoreconf
# dh_make generated override targets
# This is example for Cmake (See https://bugs.debian.org/641051 )
#override_dh_auto_configure:
# dh_auto_configure -- # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH)

1
debian/source/format vendored Normal file
View File

@ -0,0 +1 @@
3.0 (quilt)

791
depcomp Executable file
View File

@ -0,0 +1,791 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2018-03-07.03; # UTC
# Copyright (C) 1999-2020 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
# Get the directory component of the given path, and save it in the
# global variables '$dir'. Note that this directory component will
# be either empty or ending with a '/' character. This is deliberate.
set_dir_from ()
{
case $1 in
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
*) dir=;;
esac
}
# Get the suffix-stripped basename of the given path, and save it the
# global variable '$base'.
set_base_from ()
{
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
}
# If no dependency file was actually created by the compiler invocation,
# we still have to create a dummy depfile, to avoid errors with the
# Makefile "include basename.Plo" scheme.
make_dummy_depfile ()
{
echo "#dummy" > "$depfile"
}
# Factor out some common post-processing of the generated depfile.
# Requires the auxiliary global variable '$tmpdepfile' to be set.
aix_post_process_depfile ()
{
# If the compiler actually managed to produce a dependency file,
# post-process it.
if test -f "$tmpdepfile"; then
# Each line is of the form 'foo.o: dependency.h'.
# Do two passes, one to just change these to
# $object: dependency.h
# and one to simply output
# dependency.h:
# which is needed to avoid the deleted-header problem.
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
} > "$depfile"
rm -f "$tmpdepfile"
else
make_dummy_depfile
fi
}
# A tabulation character.
tab=' '
# A newline character.
nl='
'
# Character ranges might be problematic outside the C locale.
# These definitions help.
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lower=abcdefghijklmnopqrstuvwxyz
digits=0123456789
alpha=${upper}${lower}
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Avoid interferences from the environment.
gccflag= dashmflag=
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
## (see the conditional assignment to $gccflag above).
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say). Also, it might not be
## supported by the other compilers which use the 'gcc' depmode.
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The second -e expression handles DOS-style file names with drive
# letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
| tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
aix_post_process_depfile
;;
tcc)
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
# FIXME: That version still under development at the moment of writing.
# Make that this statement remains true also for stable, released
# versions.
# It will wrap lines (doesn't matter whether long or short) with a
# trailing '\', as in:
#
# foo.o : \
# foo.c \
# foo.h \
#
# It will put a trailing '\' even on the last line, and will use leading
# spaces rather than leading tabs (at least since its commit 0394caf7
# "Emit spaces for -MD").
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
# We have to change lines of the first kind to '$object: \'.
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
# And for each line of the second kind, we have to emit a 'dep.h:'
# dummy dependency, to avoid the deleted-header problem.
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
## The order of this option in the case statement is important, since the
## shell code in configure will try each of these formats in the order
## listed in this file. A plain '-MD' option would be understood by many
## compilers, so we must ensure this comes after the gcc and icc options.
pgcc)
# Portland's C compiler understands '-MD'.
# Will always output deps to 'file.d' where file is the root name of the
# source file under compilation, even if file resides in a subdirectory.
# The object file name does not affect the name of the '.d' file.
# pgcc 10.2 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using '\' :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
set_dir_from "$object"
# Use the source, not the object, to determine the base name, since
# that's sadly what pgcc will do too.
set_base_from "$source"
tmpdepfile=$base.d
# For projects that build the same source file twice into different object
# files, the pgcc approach of using the *source* file root name can cause
# problems in parallel builds. Use a locking strategy to avoid stomping on
# the same $tmpdepfile.
lockdir=$base.d-lock
trap "
echo '$0: caught signal, cleaning up...' >&2
rmdir '$lockdir'
exit 1
" 1 2 13 15
numtries=100
i=$numtries
while test $i -gt 0; do
# mkdir is a portable test-and-set.
if mkdir "$lockdir" 2>/dev/null; then
# This process acquired the lock.
"$@" -MD
stat=$?
# Release the lock.
rmdir "$lockdir"
break
else
# If the lock is being held by a different process, wait
# until the winning process is done or we timeout.
while test -d "$lockdir" && test $i -gt 0; do
sleep 1
i=`expr $i - 1`
done
fi
i=`expr $i - 1`
done
trap - 1 2 13 15
if test $i -le 0; then
echo "$0: failed to acquire lock after $numtries attempts" >&2
echo "$0: check lockdir '$lockdir'" >&2
exit 1
fi
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
# Libtool generates 2 separate objects for the 2 libraries. These
# two compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir$base.o.d # libtool 1.5
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
# Same post-processing that is required for AIX mode.
aix_post_process_depfile
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this sed invocation
# correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process the last invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed '1,2d' "$tmpdepfile" \
| tr ' ' "$nl" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E \
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
| sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:

2
doc/.cvsignore Normal file
View File

@ -0,0 +1,2 @@
Makefile
Makefile.in

5
doc/CVS/Entries Normal file
View File

@ -0,0 +1,5 @@
/.cvsignore/1.1/Sun Feb 4 22:55:23 2001//
/Makefile.am/1.2/Mon Feb 19 01:10:46 2001//
/ic35mgr.txt/1.10/Sat Feb 3 18:39:07 2001//
/ic35sync.txt/1.10/Sun Dec 3 21:10:00 2000//
D

1
doc/CVS/Repository Normal file
View File

@ -0,0 +1 @@
ic35link/doc

1
doc/CVS/Root Normal file
View File

@ -0,0 +1 @@
:pserver:anonymous@ic35link.cvs.sourceforge.net:/cvsroot/ic35link

17
doc/Makefile.am Normal file
View File

@ -0,0 +1,17 @@
## Process this file with automake to produce Makefile.in
## $Id: Makefile.am,v 1.2 2001/02/19 01:10:46 tsch Rel $
## Copyright (C) 2001 Thomas Schulz
##
## automakefile for ic35link/doc
pkgdata_DATA = \
ic35sync.txt \
ic35mgr.txt
EXTRA_DIST = $(pkgdata_DATA)
if MAINTAINER_MODE
MAINTAINERCLEANFILES = Makefile.in
else
MAINTAINERCLEANFILES =
endif

783
doc/ic35mgr.txt Normal file
View File

@ -0,0 +1,783 @@
$Id: ic35mgr.txt,v 1.10 2001/02/03 18:39:07 tsch Rel $
IC35 Manager Protokoll
======================
Inhalt
------
IC35-Manager Operationen
IC35-Manager Protokoll
Basiskommandos
Datenblock senden PC->IC35
Datenblock empfangen PC<-IC35
Verbindungsaufbau
Verbindungsabbau
IC35 Datensicherung
IC35 Datenwiederherstellung
Protokoll MMCard-Operationen
MMCard Operationen
MMCard Status
MMCard Label
MMCard Directory Operationen
MMCard Directory Open
MMCard Directory Length
MMCard Directory Entry
MMCard Directory Close
MMCard File Operationen
MMCard File Open
MMCard File Status
MMCard File Read
MMCard File Write
MMCard File Close
MMCard File Delete
Anhang: Logfiles der Protokoll-Analyse
??? Unklarheiten ueber das IC35 Manager Protokoll sind wie hier mit ???
??? am Zeilenanfang markiert.
IC35-Manager Operationen
------------------------
- Verbindungsaufbau mit IC35
- Welcome
- Identifikation und Status IC35
- Verbindung zum IC35 trennen
- Sichern, Wiederherstellen
- IC35 Datensicherung nach database.org
- IC35 Datenwiederhestellung aus database.org
- MMCard Operationen
- Status, Inhalt IC35 MMCard
- Datei Transfer nach IC35 MMCard
- Datei Transfer von IC35 MMCard
- Datei loeschen in IC35 MMCard
(noch) nicht analysiert wurden:
??? - Transfer Applikationsprogramm ins IC35
??? - Applikationsprogramm im IC35 loeschen
??? - Transfer einer Grafik-Bitmapdatei ins IC35
??? - Transfer einer MIDI-Datei ins IC35
Fortschrittsanzeigen des IC35 Manager unter Windows:
- Zugriff auf IC35 Info ..
- Zugriff erfolgreich
- MMCard1 wird getestet
- ..\IC35
- ..\APP
- ..\<*.APP ..>
- ..\<2000 ..>
- MMCard2 wird getested
- keine MMCard2 vorhanden
Standardablauf IC35 Manager unter Windows
- Verbindungsaufbau mit IC35
ausgeloest durch MouseClick "connect" am IC35 Manager
fordert Knopfdruck an SyncStation
- Status, Inhalt IC35 MMCard
- Verbindung zum IC35 trennen
ausgeloest durch MouseClick "disconnect" am IC35 Manager
IC35-Manager Protokoll
----------------------
Die Leitungsparameter fuer die Kommunikation zwischen PC und
IC35 sind Baudrate 115200, No parity, 8 databits, 2 stopbits.
Die Basisoperationen des IC35-Manager Protokolls sind
- Basiskommando mit Bestaetigung
- Datenblock senden und Verifikation mit Pruefsumme
- Datenblock emfangen und Verifikation mit Pruefsumme
Basiskommandos
Einige Basiskommandos des IC35-Manager Protokolls bestehen
jeweils aus einem 1byte-Kommando vom PC an den IC35, gefolgt
von einer 1byte-Antwort vom IC35 an den PC. Wenn die Antwort
vom IC35 ausbleibt, wird das Kommando wiederholt.
Kommunikation PC -> IC35, PC <- IC35:
-> command
timeout 0.5 sec
-> command
<- response
Die beobachteten Basiskommandos sind:
Verbindungsabbau
-> 01
<- 90
Reset Manager-Protokoll
-> 09
<- 90
Identifikation
-> 10
<- 90
<- "DCS_SDK" 00
IC35 Datensicherung
-> 13
<- 90
IC35 Datenwiederherstellung
-> 14
<- 90
-> 70
<- C0
Einleitung MMCard-Operation
-> 15
<- 90
Info Datensicherung
-> 18
<- 90
<- 30 31 32 38
Start des Verbindungsaufbaus
-> 40
<- 80
Positive Quittung
-> 60
<- A0
Negative Quittung
-> 62
<- A0
Dieser Protokollablauf der Basiskommandos ist mit Mcmdrsp()
in mgrproto.c implementiert.
Datenblock senden PC->IC35
Bei IC35-Datenwiederherstellung und MMCard-Operationen werden
Datenbloecke vom PC an den IC35 gesendet und die Uebertragung
mit einer Pruefsumme verifiziert und ggf. wiederholt.
Bei den MMCard-Operationen wird die Laenge des Datenblocks an
den IC35 gesendet und vom IC35 bestaetigt. Vor dem Senden der
Laenge muss 10 Millisekunden gewartet werden.
Bei IC35-Datenwiederherstellung unterbleibt dies, weil die
Laenge (136 oder 16384 Bytes) a priori feststeht.
Beim Senden des Datenblocks muss erfahrungsgemaess mindestens
alle 29 Bytes jeweils 10 Millisekunden gewartet werden. Offenbar
ist der IC35 nicht faehig, den Datenblock bei 115200 Baud ohne
diese Verzoegerungen korrekt zu empfangen.
Auf die Pruefsumme muss bis zu 10.0 Sekunden gewartet werden.
Kommunikation PC -> IC35, PC <- IC35:
-> nn_nn Laenge des Datenblocks, niederwertiges Byte zuerst
<- E0 Empgangsbestaetigung der Laenge
-> (Datenblock von nn_nn Bytes)
<- cc_cc Pruefsumme des Datenblocks, niederwertiges Byte zuerst
Die Pruefsumme ist die arithmetische Summe aller Bytes des
Datenblocks abgeschnitten auf 16 Bit. Wenn Datenblock-Bytes
verloren gehen (Overrun error im IC35) oder verfaelscht werden,
trifft die Pruefsumme vom IC35 erst ca. 8.2 Sekunden nach dem
Versand des Datenblocks ein.
Bei unstimmiger Pruefsumme 'cc_cc' wird negativ quittiert:
-> 62 negative Quittung
<- A0 Empfangsbestaetigung der Quittung
und der Datenblock erneut an IC35 gesendet.
Bei uebereinstimmender Pruefsumme 'cc_cc' wird positiv quittiert:
-> 60 positive Quittung
<- A0 Empfangsbestaetigung der Quittung
Wenn die Empfangsbestaetigung der Quittung vom IC35 ausbleibt, wird
die positive oder negative Quittung wiederholt.
Dieser Protokollablauf ist mit Msendblk() in mgrproto.c implementiert.
Datenblock empfangen PC<-IC35
Bei IC35-Datensicherung und MMCard-Operationen werden Datenbloecke
vom IC35 am PC empfangen und die Uebertragung mit einer Pruefsumme
verifiziert und ggf. wiederholt.
Bei den MMCard-Operationen wird die Laenge des Datenblocks vom
IC35 empfangen und bestaetigt. Auf die Laenge muss 3.5 Sekunden
gewartet werden.
Bei IC35-Datensicherung unterbleibt dies, weil die Laenge (136 oder
16384 Bytes) a priori feststeht.
Kommunikation PC -> IC35, PC <- IC35:
<- nn_nn Laenge des Datenblocks, niederwertiges Byte zuerst
-> E0 Empgangsbestaetigung der Laenge
<- (Datenblock von nn_nn Bytes)
<- cc_cc Pruefsumme des Datenblocks, niederwertiges Byte zuerst
Bei unstimmiger Pruefsumme 'cc_cc' oder kuerzerer Laenge als
angekuendigt wird negativ quittiert:
-> 62 negative Quittung
<- A0 Empfangsbestaetigung der Quittung
und der Datenblock wird erneut vom IC35 empfangen.
Bei uebereinstimmender Pruefsumme 'cc_cc' wird positiv quittiert:
-> 60 positive Quittung
<- A0 Empfangsbestaetigung der Quittung
Wenn die Empfangsbestaetigung der Quittung vom IC35 ausbleibt,
wird die positive oder negative Quittung wiederholt.
Dieser Protokollablauf ist mit Mrecvblk() in mgrproto.c implementiert.
Verbindungsaufbau
-----------------
1. Welcome Phase
- Der PC sendet wiederholt einzelne Zeichen "@" (hex 40) bis vom
IC35 "WELCOME" (hex 57 45 4C 43 4F 4D 45) empfangen wird.
Dies passiert durch Druecken des Sync-Station Knopfs.
- Der PC sendet noch einmal ein Zeichen "@" (hex 40), der IC35
antwortet mit einem Byte hex 80.
Kommunikation PC -> IC35, PC <- IC35
-> 40
timeout 1.15 sec
-> 40
sync-station button
<- 57 45 4C 43 4F 4D 45
W E L C O M E
2. Basiskommando "Start Verbindungsaufbau"
-> 40
<- 80
3. Basiskommando "Reset"
-> 09
<- 90
4. Basiskommando "Identifikation"
-> 10
<- 90
<- 44 43 53 5F 53 44 4B 00
D C S _ S D K .
5. optional Empfang des Statusblocks vom IC35
-> FF
<- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...
... FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
Block von 16400 Bytes
enthaelt u.a. Applikationsnamen, Email,SMS config, ..
6. Initialisierung
-> 50
<- 90 or timeout 0.1 sec
??? Beim Initialisierunskommando wurde keine Antwort beobachtet.
??? Es wird 100 Millisekunden auf etwaige Antwort vom IC35 gewartet
??? und diese verworfen, um sie nicht irrtuemlich fuer eine Antwort
??? auf ein nachfolgendes Basiskommando zu halten.
Der IC35 braucht mindestens 10 Millisekunden Ruhe, bis er zu
weiteren Aktionen bereit ist. (Ansonsten muss das nachfolgende
erste Basiskommando wiederholt werden.)
Verbindungsabbau
----------------
1. Basiskommando "Reset"
-> 09
timeout 1.0 sec
-> 09
<- 90
2. Basiskommando "Verbindungsabbau"
-> 01
timeout 1.0 sec
-> 01
<- 90
IC35 Datensicherung
-------------------
Der Ablauf der Datensicherung mit den Protokoll-Basisoperationen
(s.o "IC35-Manager Protokoll") ist:
1. Basiskommmando "IC35 Datensicherung"
-> 13
<- 90
2. Empfang des Kopfblocks (136 Bytes) vom IC35
<- B5 03 00 A2 01 00 F1 .. headblock 136 bytes
<- 98 0D checksum
-> 60 positive acknowledge
<- A0 got ack
Hier und unten ist jeweils nur die positive Quittung erwaehnt,
bei falscher Pruefsumme oder Blocklaenge wird jeweils negativ
quittiert und der Kopf- oder Daten-Block wiederholt.
3. Empfang von 26 Datenblocks (je 16384 Bytes) vom IC35
<- A0 09 00 40 01 00 00 .. datablock 16384 bytes
<- C0 4C checksum
-> 60 positive acknowledge
<- A0 got ack
4. Zweimal Basiskommando "Info Datensicherung"
-> 18 command info-1
timeout 1.0 sec
-> 18 command info-1
<- 90 response got command
<- 30 31 32 38 info-1
-> 18 command info-2
timeout 0.5 sec
-> 18 command info-2
<- 90 response got command
<- 30 31 32 38 info-1
??? Der Inhalt der info response 30 31 32 38 = "0128" aehnelt sehr
??? der Firmware-Version "1.28" des IC35, es ist jedoch noch unklar,
??? ob diese Aehnlichkeit realen Gehalt hat.
Alle Empfangsdaten der Datensicherung werden gespeichert in der
Datei 'database.org', dies sind 426128 = 136 + 26*16384 + 4 +4
Bytes insgesamt (headblock, 26 datablocks, 2 infoblocks).
IC35 Datenwiederherstellung
---------------------------
Der Ablauf der Datenwiederherstellung mit den Protokoll-Basis-
operationen (s.o "IC35-Manager Protokoll") ist:
1. Zweimal Basiskommando "Info Datensicherung"
-> 18 command info-1
timeout 1.0 sec
-> 18 command info-1
<- 90 response got command
<- 30 31 32 38 info-1
-> 18 command info-2
timeout 0.5 sec
-> 18 command info-2
<- 90 response got command
<- 30 31 32 38 info-1
Die beiden Antworten 30 31 32 38 werden mit den Eintraegen am
Ende der Datei 'database.org' verglichen. Bei Uebereinstimmung
wird die Datenwiederherstellung fortgesetzt, andernfalls wird
sie abgebrochen.
2. Basiskommmandos "IC35 Datenwiederherstellung"
-> 14 command restore-1
timeout 1.0 sec
-> 14 command restore-1
<- 90 response got command
-> 70 command restore-2
<- C0 response got restore-2
3. Senden des Kopfblocks (136 Bytes) an IC35
-> AD 03 00 9A 01 00 2B .. headblock 136 bytes
<- 5B 0D checksum
-> 60 positive acknowledge
<- A0 response got ack
4. Senden von 26 Datenblocks (je 16384 Bytes) vom IC35
Auf die Pruefsumme muss bis zu 10.0 sec gewartet werden.
-> A0 09 92 50 01 00 00 .. datablock 16384 bytes
<- 4D F3 checksum
-> 60 positive acknowledge
<- A0 response got ack
5. Basiskommando "Reset Manager-Protokoll"
-> 09 command reset
timeout 1.0 sec
-> 09 command reset
timeout 1.0 sec
-> 09 command reset
timeout 1.0 sec
-> 09 command reset
timeout 0.5 sec
-> 09 command reset
<- 90 response got command
Wie oben sind die Inhalte von Kopf- und Daten-Blocks Beispiele
und es ist jeweils nur die positive Quittung aufgefuehrt, bei
falscher Pruefsumme wird jeweils negativ quittiert und der Kopf-
oder Daten-Block wiederholt.
Insgesamt werden 426120 = 136 + 26*16384 Bytes uebertragen, d.h.
ein Kopfblock von 136 Bytes und 26 Datenblocks mit 16384 Bytes.
Die 2 bei der Datensicherung empfangenen 'infoblocks' von je 4
Bytes werden nicht an IC35 gesendet.
??? Bei der Datenwiederherstellung werden Datum und Uhrzeit sowie
??? Telefontyp auf Defaultwerte zurueckgesetzt! Sie muessen manuell
??? korrigiert werden!
Protokoll MMCard-Operationen
----------------------------
Der allgemeine Ablauf der MMCard-Operationen mit den Protokoll
Basisoperationen (s.o "IC35-Manager Protokoll") ist:
1. Basiskommando "MMCard-Operation"
-> 15 command mmcard
<- 90 got command
Vor dem Senden der Blocklaenge des Kommandoblocks muss 10 msec
gewartet werden.
2. Senden des MMCard Kommandoblocks
-> nn_nn block length
<- E0 got length
-> (cmdblock of nn_nn bytes)
<- cc_cc got cmdblock, checksum is cc_cc (arithmetic, LSB first)
Bei unstimmiger Pruefsumme 'cc_cc' wird negativ quittiert:
-> 62 neg.ack
<- A0 got neg.ack, send block again
und der cmdblock erneut an IC35 gesendet.
Bei uebereinstimmender Pruefsumme 'cc_cc' wird positiv quittiert:
-> 60 pos.ack
<- A0 got pos.ack
3. Empfang des MMCard Antwortblocks
<- nn_nn block length
-> E0 got length
<- (rspblock of nn_nn bytes)
<- cc_cc checksum of rspblock is cc_cc (arithmetic, LSB first)
Bei unstimmiger Pruefsumme 'cc_cc' wird negativ quittiert:
-> 62 neg.ack
<- A0 got neg.ack
und der rspblock wird erneut vom IC35 empfangen.
Bei uebereinstimmender Pruefsumme 'cc_cc' wird positiv quittiert:
-> 60 pos.ack
<- A0 got pos.ack
MMCard Operationen
------------------
Im "IC35 Software Development Kit API Reference Guide" (ic35_api.pdf
aus ic35_prog.zip) sind unter "13. Multi Media Card File Operations"
beschrieben. Sie entsprechen weitgehend den MMCard PDUs der Protokoll
Analyse. Zu den mit "???" markierten Funktionen wurden keine PDUs
beobachtet, die PDU command codes sind reine Vermutung.
IC35 SDK API Funktion mgrtrans.c PDU command code
+-----------------------+---------------------------------------------
minitialCard mmc_status 20 "MMCard1" 00
??? mFormat - 32 ???
??? mSetCardLabel - 33 ???
mGetCardLabel mmc_label 34 "MMCard1" 00
??? mGetCardInfo - 35 ???
mOpenFile mmc_openfile 22 mm mm "MMCard1\FILE.EXT" 00
??? mSetFilePointer - 25 ???
mWriteToFile mmc_writefile 23 ...
mReadFromFile mmc_readfile 24 ...
mGetFileInfo mmc_statfile 26 ...
mCloseFile mmc_closefile 27 ...
??? mRenFile - 21 ???
mDeleteFile mmc_delfile 28 "MMCard1\FILE.EXT" 00
mOpenDirectory mmc_opendir 2A mm mm "MMCard1\IC35" 00
mGetDirectorySubItemNum mmc_opendir 2B ...
mGetDirectorySubItem mmc_readdir 2C ...
??? mGetDirectoryInfo - 2D ???
mCloseDirectory mmc_closedir 2E ...
??? mRenDirectory - 29 ???
??? mDeleteDirectory - 2F ???
MMCard Status
-> command status "MMCard1"
20 4D 4D 43 61 72 64 31 00
cmd M M C a r d 1 nul
<- response MMCard OK
01 00
<- response MMCard not present
FF FF
MMCard Label
-> command label "MMCard1"
34 4D 4D 43 61 72 64 31 00
. M M C a r d 1 .
cmd mcard-id____________ nul
<- reponse MMCard label
01 00 00 4D 4D 43 61 72 64 31 00 20 20 20 00 00 00 00 00 00 00 00 48
. . . M M C a r d 1 . . . . . . . . . . . . H
ok label___________________________ ??
MMCard Directory Operationen
MMCard Directory Open empfaengt vom IC35 einen 'dirstat' Block,
welcher in allen folgenden Operationen jeweils an den IC35
gesendet und vom IC35 aktualisert wieder empfangen wird. Die
Details ueber den 'dirstat' Block wurden "Mmc.h" aus dem IC35
SoftwareDevelopmentKit entnommen, offenbar entsprechen sie
dem uebertragenen 'dirstat' Block. Beispiele:
Beispiel-1 "MMCard1" rootdir:
5F 00 00 00 00 00 00 00 00 00 01 00 00 00
sect_ clust sec_o dir_o sclst fileptr____
00 00 00 00 FF 00 00 00 00 20 00 FE 01
filesize___ cn cclst cclsn csecn rsrvd
Beispiel-2 "MMCard1\IC35\APP"
00 00 02 00 00 00 40 00 15 00 01 00 00 00
sect_ clust sec_o dir_o sclst fileptr____
00 00 00 00 FF 15 00 00 00 20 00 FE 01
filesize___ cn cclst cclsn csecn rsrvd
MMCard Directory Open
Beispiel-1 "MMCard1" rootdir
-> command opendir "MMCard1"
2A 01 00 4D 4D 43 61 72 64 31 00
. . . M M C a r d 1 .
cmd dirpath="MMCard1"___ nul
<- response
01 00
ok
5F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
dirstat________________________________________
00 00 00 00 00 00 00 00 00 FE 01
_________________________dirstat
Beispiel-2 "MMCard1\IC35\APP"
-> command opendir "MMCard1
2A 01 00 4D 4D 43 61 72 64 31 5C 49 43 33 35 5C 41 50 50 00
. . . M M C a r d 1 \ I C 3 5 \ A P P .
cmd dirpath="MMCard1\IC35\APP"_____________________ nul
<- response
01 00
ok
00 00 02 00 00 00 40 00 15 00 00 00 00 00 00 00
dirstat________________________________________
00 00 00 15 00 00 00 00 00 FE 01
_________________________dirstat
MMCard Directory Length
Beispiel-1 "MMCard1" rootdir
-> command dirlen
2B
cmd
5F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
dirstat_from_opendir___________________________
00 00 00 00 00 00 00 00 00 FE 01 00
_________________________dirstat nul
<- response dirlen
5F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
dirstat________________________________________
00 00 00 00 00 00 00 00 00 FE 01 01 00 04 00
_________________________dirstat ? ? ndent
Beispiel-2 "MMCard1\IC35\APP"
-> command dirlen
2B
cmd
00 00 02 00 00 00 40 00 15 00 00 00 00 00 00 00
dirstat_from_opendir___________________________
00 00 00 15 00 00 00 00 00 FE 01 00
_________________________dirstat nul
<- response dirlen
00 00 02 00 00 00 40 00 15 00 00 00 00 00 00 00
dirstat________________________________________
00 00 00 15 00 00 00 00 00 FE 01 01 00 07 00
_________________________dirstat ? ? ndent
MMCard Directory Entry
Beispiel-1 "MMCard1" rootdir
-> command readdir index=0000
2C
cmd
5F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
dirstat_from_opendir_or_previous_readdir_______
00 00 00 00 00 00 00 00 00 FE 01 01 00 00
_________________________dirstat idx+1 nul
<- respnse readdir
5F 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00
dirstat______________________ nxidx ___________
00 00 FF 00 00 00 00 20 00 FE 01 01 00
_________________________dirstat ? ?
49 43 33 35 00 20 20 20 00 00 20 20 00 10
filename="IC35"___________ ext=""_____ ty
2E B3 5E 29 00 00 00 00 00 00
timestamp__ ? ? size_______
-> command readdir index=0001
2C
cmd
5F 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00
dirstat_from_opendir_or_previous_readdir_______
00 00 FF 00 00 00 00 20 00 FE 01 02 00 00
_________________________dirstat idx+1 nul
<- reponse readdir
5F 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00
dirstat______________________ nxidx ___________
00 00 FF 00 00 00 00 40 00 FE 01 01 00
_________________________dirstat ? ?
32 30 30 30 31 31 30 34 00 49 33 35 00 20
filename="20001104"_______ ext="I35"__ ty
C1 14 65 29 00 00 FE 89 00 00
timestamp__ ? ? size_______
Beispiel-2 "MMCard1\IC35\APP"
-> command readdir index=0000
2C
cmd
00 00 02 00 00 00 40 00 15 00 00 00 00 00 00 00
dirstat________________________________________
00 00 00 15 00 00 00 00 00 FE 01 01 00 00
_________________________dirstat idx+1 nul
<- response readdir
00 00 02 00 00 00 40 00 15 00 01 00 00 00 00 00
dirstat______________________ nxidx ___________
00 00 FF 15 00 00 00 20 00 FE 01 01 00
_________________________dirstat ? ?
2E 2E 00 20 20 20 20 20 00 00 20 20 00 10
filename=".."_____________ ext=""_____ ty
A1 B5 61 29 00 00 00 00 00 00
timestamp__ ? ? size_______
-> command readdir index=0001
2C
cmd
00 00 02 00 00 00 40 00 15 00 01 00 00 00 00 00
dirstat______________________ index ___________
00 00 FF 15 00 00 00 20 00 FE 01 02 00 00
_________________________dirstat idx+1 nul
<- response readdir
00 00 02 00 00 00 40 00 15 00 02 00 00 00 00 00
dirstat______________________ nxidx ___________
00 00 FF 15 00 00 00 40 00 FE 01 01 00
_________________________dirstat ? ?
42 52 4F 57 53 45 52 00 00 41 50 50 00 20
filename="BROWSER"________ ext="APP"__ ty
89 B6 61 29 00 00 44 C0 05 00
timestamp__ ? ? size_______
Fuer das Typfeld 'ty' wurden beobachtet
10 Subdirectory
20 File
Die Kodierung des Zeitstempels 'timestamp' ist wie bei DOS.
Die hoeherwertigen 16 Bits kodieren Jahr, Monat und Tag:
yyyyyyy mmmm ddddd
yyyyyyy Jahre seit 1980
mmmm Monat 1-12
ddddd Tag 1-31
Die niederwertigen 16 Bits kodieren Stunde, Minute, Sekunde:
hhhhh mmmmmm sssss
hhhhh Stunde
mmmmmm Minute
sssss Sekunde / 2
MMCard Directory Close
Beispiel-1 "MMCard1" rootdir
-> command closedir
2E
cmd
5F 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00
dirstat______________________ index ___________
00 00 FF 00 00 00 00 80 00 FE 01 00
_________________________dirstat nul
<- response closedir
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00
Beispiel-2 "MMCard1\IC35\APP"
-> command closedir
2E
cmd
00 00 02 00 00 00 40 00 15 00 07 00 00 00 00 00
dirstat______________________ index ___________
00 00 FF 15 00 00 00 E0 00 FE 01 00
_________________________dirstat nul
<- response closedir
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00
MMCard File Operationen
MMCard File Open
-> command openfile
22 01 00 4D 4D 43 61 72 64 31 5C 49 43 33 35 5C 41 50 50
mo_de filepath="MMCard1\IC35\APP\REVERSI.APP"________
5C 52 45 56 45 52 53 49 2E 41 50 50 00
___________________________filepath nul
Der mo_de Parameter ist 01 00 (IC35 SDK: OPEN_EXISTING) zum Oeffnen
einer existierended MMCard Datei (im Lesemodus).
Der mo_de Parameter ist 00 00 (IC35 SDK: CREATE_ALWAYS) zum Erzeugen
einer neuen MMCard Datei, eine existierende Datei wird auf Laenge 0
gekuerzt.
<- response openfile
01 00
ok
00 00 15 00 00 00 C0 00 F9 00 00 00 00 00
filestatus_______________________________
44 40 00 00 00 F9 00 00 00 00 00 FE 01
size=16452_ filestatus________________
MMCard File Status
-> command filestat
26
00 00 15 00 00 00 C0 00 F9 00 00 00 00 00
filestatus_______________________________
44 40 00 00 00 F9 00 00 00 00 00 FE 01 00
size=16452_ filestatus________________ nul
<- response filestat
00 00 15 00 00 00 C0 00 F9 00 00 00 00 00
44 40 00 00 00 F9 00 00 00 00 00 FE 01 01 00
52 45 56 45 52 53 49 00 00 41 50 50 00 20
filename="REVERSI"________ ext="APP"__ ty
DD B6 61 29 00 00 44 40 00 00
timestamp__ ? ? size_______
MMCard File Read
-> command fileread
24
cmd
00 00 15 00 00 00 C0 00 F9 00 00 00 00 00
filestatus_______________________________
44 40 00 00 00 F9 00 00 00 00 00 FE 01 01 18 00
size=16452_ filestatus________________ rdlen nul
<- response fileread
00 00 15 00 00 00 C0 00 F9 00 01 18 00 00
filestatus_______________________________
44 40 00 00 00 FC 00 03 00 00 00 FE 01 01 00 01 18
size=16452_ filestatus________________ ? ? rdlen
80 F6 00 40 00 00 00 40 00 00 FF FF 1E 00 52 ..
filedata_____________________________________..
-> command fileread
24
cmd
00 00 15 00 00 00 C0 00 F9 00 01 18 00 00
filestatus_______________________________
44 40 00 00 00 FC 00 03 00 00 00 FE 01 01 18 00
size=16452_ filestatus________________ rdlen nul
<- response fileread
00 00 15 00 00 00 C0 00 F9 00 02 30 00 00
filestatus___________________ noffs _____
44 40 00 00 00 FF 00 06 00 00 00 FE 01 01 00 01 18
size=16452_ filestatus________________ ? ? rdlen
36 01 23 36 00 21 0E 00 39 5E 23 56 EB 29 29 ..
filedata_____________________________________..
-> command fileread
24
cmd
00 00 15 00 00 00 C0 00 F9 00 02 30 00 00
filestatus_______________________________
44 40 00 00 00 FF 00 06 00 00 00 FE 01 42 10 00
size=16452_ filestatus________________ rdlen nul
<- response fileread
00 00 15 00 00 00 C0 00 F9 00 44 40 00 00
filestatus___________________ noffs _____
44 40 00 00 00 01 01 08 00 00 00 FE 01 01 00 42 10
size=16452_ filestatus________________ ? ? rdlen
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..
filedata_____________________________________..
MMCard File Write
-> command filewrite
23
cmd
00 00 15 00 00 00 00 01 2F 01 00 00 00 00
filestatus_______________________________
00 00 00 00 00 2F 01 00 00 00 00 FE 01 01 18
size=0_____ filestatus________________ wrlen
80 F6 00 40 00 00 00 40 00 00 FF FF 1E 00 52 ..
filedata_____________________________________..
<- response filewrite
00 00 15 00 00 00 00 01 2F 01 01 18 00 00
filestatus___________________ noffs______
01 18 00 00 00 32 01 03 00 00 00 FE 01 01 00
size=6145__ filestatus________________ ok___
-> command filewrite
23
cmd
00 00 15 00 00 00 00 01 2F 01 01 18 00 00
filestatus___________________ noffs______
01 18 00 00 00 32 01 03 00 00 00 FE 01 01 18
size=6145__ filestatus________________ wrlen
36 01 23 36 00 21 0E 00 39 5E 23 56 EB 29 29 ..
filedata_____________________________________..
<- response filewrite
00 00 15 00 00 00 00 01 2F 01 02 30 00 00
filestatus___________________ noffs______
02 30 00 00 00 35 01 06 00 00 00 FE 01 01 00
size=12290_ filestatus________________ ok___
MMCard File Close
-> command fileclose
27
cmd
00 00 15 00 00 00 C0 00 F9 00 44 40 00 00
filestatus___________________ noffs _____
44 40 00 00 00 01 01 08 00 00 00 FE 01 00
size=16452_ filestatus________________ nul
<- response fileclose
00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00
MMCard File Delete
-> command filedel
28 4D 4D 43 61 72 64 31 5C 49 43 33 35 5C 41 50 50
cmd filepath="MMCard1\IC35\APP\REVERSI2.APP"_______
5C 52 45 56 45 52 53 49 32 2E 41 50 50 00
______________________________filepath nul
<- response filedel
01 00
ok___
Anhang: Logfiles der Protokoll-Analyse
--------------------------------------
- Manager.tar.gz 2000-10-26 Michael Bruennert
Windows-NT einzeiliges Format, keine MMCard
- Manager_Login.LOG
connect mit IC35mgr
- Manager_Backup.LOG
IC35 Datensicherung nach database.org
- database.org
die Daten vom IC35 backup
the data backuped from IC35
- Manager_Logout.LOG
disconnect vom IC35mgr
- Manager_Reversi.LOG
Uebertragung des Reversi.app Programms ins IC35
- Reversi.app
das uebertragene Programm
- BackupRestore.tar.gz 2000-10-30 Michael Bruennert
Windows-NT einzeiliges Format, keine MMCard
- Manager_Backup1.log
IC35 Datensicherung nach database.org
- Manager_Logout1.log
disconnect vom IC35mgr
- Manager_Restore1.log
IC35 Daten-Wiederherstellung von database.org
- mgr_conn_disc.log.gz 2000-10-26 Thomas Schulz
Windows-98, keine MMCard
connect, disconnect
- mgr_conn_disc_mmc.log.gz 2000-10-30 Thomas Schulz
Windows-98, mit MMCard1
connect, disconnect
- mgr_rwd-file_20001107.tar.gz Thomas Schulz
Windows-98, mit MMCard1
- mgr_rd-reversi_20001107.log
connect, Lesen von MMCard1\IC35\APP\REVERSI.APP, disconnect
- mgr_wr-reversi2_20001107.log
connect, Schreiben von MMCard1\IC35\APP\REVERSI2.APP, disconnect
connect, Schreiben von
- mgr_del-reversi2_20001107.log
connect, Loeschen von MMCard1\IC35\APP\REVERSI2.APP, disconnect
- REVERSI.APP
das Reversi Programm, REVERSI2.APP ist Kopie davon

846
doc/ic35sync.txt Normal file
View File

@ -0,0 +1,846 @@
$Id: ic35sync.txt,v 1.10 2000/12/03 21:10:00 tsch Rel $
IC35-sync Protokoll
===================
Inhalt
------
Ueberblick
Level-1 Protokoll
Level-2 Protokoll
Level-3 Protokoll
Kommunikations-Ablauf
identification
power
authentication
date+time
category
read,write file
disconnect
Zusammenfassung der PDUs
IC35 Record Felder
IC35Comm.dll Export Funktionen
Anhang: Logfiles der Protokoll-Analyse
Ueberblick
----------
??? Unklarheiten ueber das IC35-sync Protokoll sind wie hier mit ???
??? am Zeilenanfang markiert.
Die IC35-sync Protokoll-"Suite" folgt offenbar dem ISO Schichten-
modell: Untere Protokoll-"Level" kapseln Daten hoeherer Protokoll-
Level ein und transportieren sie.
Generell werden in allen Protokoll-Schichten Datenbloecke (oft,
aber nicht immer) kodiert nach dem Schema:
ii ll ll <data>
Dabei bedeuten
ii Identifikations des Datenblocks
ll ll Laenge: Anzahl Bytes ueber alles, d.h. incl. ii ll ll
Kodierung mit niederwertigem Byte zuerst, gefolgt vom
hoeherwertigen Byte.
<data> Datenblock Inhalt
Level-1 Protokoll
-----------------
Level-1 PDU Kodierung allgemein:
- ii ll ll <L2data> cc cc
ii Identifikations der PDU
ll ll Laenge: Anzahl der Bytes in der PDU, LSB zuerst MSB zuletzt
L2data transportierte Level-2 PDU Daten
cc cc Checksum: 16bit arithmetische Summe der PDU Bytes, LSB,MSB
- ii
kurze PDUs (nur Id) erscheinen nur von IC35 an PC.
Level-1 PDUs PC an IC35:
01 03 00 init initiate data exchange
02 ll ll <L2data> cc cc datasel select which data to send
04 03 00 datareq request to send selected data
05 03 00 exit terminate data exchange
Level-1 PDUs IC35 an PC:
F0 ack0 acknowledge to init PDU
F1 ack1 acknowledge to datasel,exit PDUs
F2 ll ll <L2data> cc cc datarsp response to datareq PDU
Level-1 Kommunikation PC->IC35, PC<-IC35:
-> command init
01 03 00
<- response ack0
F0
-> command select data
02 ll ll <L2data> cc cc
<- reponse ack1
F1
-> command request data
04 03 00
<- reponse data
F2 ll ll <L2data> cc cc
-> command exit
05 03 00
<- reponse ack1
F1
Dieses Schema wird generell fuer den Transport der Level-2 Daten
benutzt.
Level-2 Protokoll
-----------------
ll ll Laenge: Anzahl der Bytes in der Level-2 PDU (LSB,MSB)
L3data transportierte Level-3 PDU Daten
Level-2 PDUs PC an IC35:
80 ll ll <L3data> identify
02 ll ll <L3data> command write (more)
82 ll ll <L3data> command write (last)
83 ll ll <L3data> command read
81 03 00 disconnect
Level-2 PDUs IC35 an PC:
20 ll ll <L3data> response (more)
A0 ll ll <L3data> response (last)
A0 03 00 response done
90 03 00 response write more
Transaktionen in hoeheren Schichten brauchen ggf. mehrere Blocks.
Soweit noch ein Block folgt werden die "(more)" PDUs benutzt,
fuer den letzten (oder einzigen) Block die "(last)" PDUs.
Level-3 Protokoll
-----------------
ll ll Laenge: Anzahl der Bytes in der Level-2 PDU (LSB,MSB)
L3data transportierte Level-3 PDU Daten
Level-3 PDUs PC an IC35:
10 00 64 00 4A ll ll <L4data> identify request
48 ll ll <L4data> command1 (more)
49 ll ll <L4data> command2 (last)
Level-3 PDUs IC35 an PC:
10 00 D0 07 4A ll ll <L4data> identify response
48 ll ll <L4data> response1 (more)
49 ll ll <L4data> response2 (last)
Transaktionen in hoeheren Schichten brauchen ggf. mehrere Blocks.
Soweit noch ein Block folgt werden die "(more)" PDUs benutzt,
fuer den letzten (oder einzigen) Block die "(last)" PDUs.
Kommunikations-Ablauf
---------------------
Die Kommunikation zwischen PC und IC35 geschieht in zwei Phasen:
- Welcome
- Die Leitungsparameter fuer die Kommunikation zwischen PC und
IC35 sind Baudrate 115200, No parity, 8 databits, 2 stopbits.
- Der PC sendet wiederholt einzelne Zeichen "A" (hex 41) bis vom
IC35 "WELCOME" (hex 57 45 4C 43 4F 4D 45) empfangen wird.
- Der PC sendet noch einmal ein Zeichen "A", der IC35 antwortet
mit einem Byte hex 80.
- Unter Windows-98/-NT setzt der PC das DTR-Signal auf "AUS"
und schliesst den COM-Port. Nach ca. 0.015 sec oeffnet der
PC den COM-Port erneut mit Baudrate 115200, setzt das RTS-
Signal auf "AUS" und DTR-Signal auf "EIN", und stellt die
Leitungsparameter: No parity, 8 databits, 2 stopbits.
Dieses Verhalten scheint unnoetig, unter Linux ist es fuer
die Kommunikation nicht notwendig.
- PC setzt Timeouts: RC:500 und WC:500, vermutlich bedeutet das
Read Character und Write Character Timeout jeweils 500 ms.
Kommunikation der Welcome Phase:
-> 41
timeout 1.15 sec
-> 41
<- "WELCOME"
-> 41
<- 80
- Datenaustausch
In dieser Phase geschieht der Datenaustausch generell gemaess
dem Level-1 Protokoll.
Die Datenaustausch-Phase besteht aus folgenden Abschnitten:
- identification
- power
- authentication
- date+time
- category
- read,write "Addresses", "Memo", "Schedule", "To Do List"
- disconnect
Im Folgenden ist nur die Level-2 Kommunikation notiert, die Uebertragung
der Level-2 Daten geschieht wie oben beschrieben mit dem Level-1 Protokoll.
Soweit die Level-2,-3 Header der generellen Form entsprechen, sind sie
in Kurzform L2id,L3id notiert, andernfalls explizit
identification
--------------
Kommunikation PC->IC35, PC<-IC35:
-> identify request
80 26 00 # L2-header
10 00 64 00 4A 1F 00 # L3-header
"INVENTEC CORPORATION PRODUCT" # L4-data
<- identify response
A0 29 00 # L2-header
10 00 D0 07 4A 22 00 # L3-header
"INVENTEC CORPORATION DCS15 1.28" # L4-data
Der L2-header entspricht der generellen Form (80 ll ll).
??? Dem L3-header der "identify" PDUs in der generellen Form (4A ll ll)
??? gehen jeweils 4 Bytes Daten mit unklarer Bedeutung voraus.
power
-----
Kommunikation PC->IC35, PC<-IC35:
-> power request
82,49 03 01 "Power" 00 00 00
<- power response
A0,49 03 01
authentication
--------------
Kommunikation PC->IC35, PC<-IC35:
-> authenticate request
82,49 03 00 [password]
<- authenticate response right password
A0,49 01 01
oder
<- authenticate response wrong password
A0,49 00 01
[password] ist das IC35 Kennwort als ASCII Klartext.
IC35 sendet "response wrong password" nur dann, wenn auf dem IC35
die Kennwort-Abfrage beim Einschalten aktiviert ist.
date+time
---------
Kommunikation PC->IC35, PC<-IC35:
-> command get date+time
83,49 02 00 00
<- response date+time
A0,49 [mmddyyyyhhmmss] 00 00
-> command set date+time
82,49 02 01 00 [mmddyyyyhhmmss] 00 00
<- response done
A0
[mmddyyyyhhmmss] sind Monat(mm), Tag(dd), Jahr(yyyy), Stunde(hh),
Minute(mm), Sekunde(ss) jeweils in ASCII Ziffern (hex 30..39).
"set date+time" passiert offenbar nicht immer, es taucht nur auf
in Simple_hex.log, Portmon_export.log, Portmon_neukat2.log, aber
nicht in Import1.log.
??? Wenn "set date+time" passiert, dann nach "open file Addresses"
??? vor "get filelength Addresses". Ob das so noetig ist, ist unklar,
??? einfacher zu implementieren ist es vor der "read,write file"
??? Phase.
"get date+time" liefert 00-Bytes fuer [mmddyyyyhhmmss], wenn noch
nie ein "set date+time" zum IC35 geschehen ist.
Laut Experimenten laesst IC35 beliebigen Text bis 16 Zeichen zu.
Vermutlich sind die "get,set date+time" Kommandos gedacht fuer
die Hinterlegung eines Sync/Import Stempels vom PC im IC35 (auch
die Namen "AdsReadSysInfo" und "AdsWriteSysInfo" der IC35Comm.dll
Funktionen stuetzen diese Vermutung), IC35sync/Windows benutzt
dafuer offenbar einen Zeitstempel.
category
--------
Kommunikation PC->IC35, PC<-IC35:
-> command set category
82,49 03 02 [category]
[category] wird mit 00 Bytes bis zur Laenge 8 Bytes aufgefuellt.
??? <- response category ok
??? A0,49 xx 01
??? Die Bedeutung des Feldes xx ist unklar, es nimmt die Werte 01
??? (Portmon_export.log) und 00 (Import.log aus Import.tar.gz) an.
Wenn die "category" Phase vorkommt, findet sie nach "set date+time"
statt, d.h. auch innerhalb des Filezugriffs auf Addresses.
??? Die Semantik der "category" Phase unklar.
read,write file
---------------
Der Zugriff auf die Files "Addresses", "Memo", "Schedule" und
"To Do List" ist beispielhaft fuer "Addresses" notiert.
Der Filezugriff besteht aus den Phasen:
- open file
liefert filedescriptor, der fuer die uebrigen Phasen benutzt wird
- get filelength (2 Varianten)
liefert die Anzahl der zu lesenden records
- read file record(s)
liefert record daten, ggf. in mehreren Bloecken
- write file record(s)
optional, ggf. in mehreren Bloecken
- optional delete file record(s)
- optional reset change flag(s)
- close file
open file
-> command open file
82,49 00 02 00 00 00 00 00 00 00 0B 00 00 00 09 "Addresses" 02
cmd__ l1 l2 filename_
l2 ist Laenge des filename, l1 = l2 + 2
<- response fd=0001
A0,49 01 00
fd___
Der filedescriptor fd wird anschliessend fuer den Zugriff benutzt.
Der Filename ist ziemlich egal, es wird nur der erste Buchstabe
unabhaengig von Gross- oder Kleinschreibung verglichen, d.h. es
wird fuer 'A','a' "Addresses", 'M','m' "Memo", 'T','t' "To Do List"
und fuer alle anderen Zeichen das File "Schedule" geoeffnet.
get filelength 03: total number of records
Variante-1 aus Import1.log (command 01 03)
-> command get filelength fd=0001
83,49 01 03 01 00 00 00 00 00
cmd__ fd___
<- response filelength n=000B records
A0,49 0B 00
n____
Diese Variante wird bei "import" und "export" benutzt.
get filelength 04: number of modified records
-> command get filelength fd=0001
83,49 01 04 01 00 00 00 00 00
cmd__ fd___
<- response n=0000 records
A0,49 00 00
n____
Diese Variante wird bei "sync" benutzt. Sie liefert die Anzahl
der manuell auf dem IC35 modifizierten Records, d.h. veraenderte,
neu hinzugefuegte und insbesondere auch geloeschte.
read file record by index
-> command read record fd=0001 idx=0000
83,49 01 06 01 00 00 00 00 00
cmd__ fd___ idx__
<- response record data (more)
20,48 01 00 00 05 80 <flengths> <fdata>
ri___ fi ch
-> command read more
83
<- response record data (more)
20,48 <fdata>
-> command read more
83
<- response record data (last)
A0,49 <fdata>
Die Records werden index-orientiert gelesen, der Index idx nimmt
Werte 0 bis n - 1 (filelength n).
read next modified record
(Beispiele aus Delete.tar.gz:NeueDatenSync_171100.log File "Memo")
-> command read next modified record
83,49 01 07 03 00 00 00 00 00
cmd__ fd___
<- response record data (last) Beispiel geloeschter Record
A0,49 03 00 00 06 20
ri___ fi ch
-> command read next modified record
83,49 01 07 03 00 00 00 00 00
cmd__ fd___
<- response record data (last) Beispiel veraenderter Record
A0,49 05 00 00 06 80 <flengths> <fdata>
ri___ fi ch
read file record by record-ID
(Beispiele aus Experimenten mit File "Memo")
-> command read record by record-ID
83,49 01 05 03 00 05 00 00 06
cmd__ fd___ ri___ fi
<- response record data (last) Beispiel vorhandener Record
A0,49 05 00 00 06 80 <flengths> <fdata>
ri___ fi ch
Im Erfolgsfall enthaelt die Antwort die angeforderte RecordId
und gueltige Feldlaengen und Daten.
-> command read record by record-ID
83,49 01 05 03 00 EE 78 00 06
cmd__ fd___ ri___ fi
<- response record data (last) Bsp. nicht vorhandener Record
A0,49 3E 81 D3 0D 60 <flengths>
ri___ fi ch
Ist der Record mit der spezifizierten RecordId im IC35 nicht
vorhanden, so enthaelt die Antwort eine ungueltige RecordId,
ungueltige Feldlaengen und keine Felddaten.
Im "response record data" ist fi die FileId und ri die RecordId
auf dem IC35. Beide zusammen ergeben identifizieren den Record
im IC35 global eindeutig.
??? Ob die RecordId ri sich auf 3 Bytes erstreckt wurde mangels
??? Geduld (es waeren >65536 Records zu erzeugen) nicht geklaert,
??? die Implementation unter Linux nimmt dies an.
Das Feld ch ist ein Aenderungskennzeichen (CHangeflag):
80 Record im IC35 neu erzeugt oder von anderem kopiert
40 Record im IC35 veraendert
20 Record im IC35 geloescht (ohne <flengths>,<fdata>)
00 keine Aenderung in diesem Record
Das Aenderungskennzeichen wird nur durch manuelle Aenderungen
im IC35 auf ch!=00 gesetzt, mit "write file record" neu erzeugte
haben ch=00, mit "delete file record" geloeschte verschwinden
vollstaendig.
Nur von "read next modified record" werden Records mit ch=20
geliefert, bei "read record by index" tauchen sie nicht auf.
Der gelesene Record wird falls noetig in mehreren Bloecken
uebertragen, vom IC35 haben alle Bloecke bis auf den letzten
L2id=20 und L3id=48, der letzte Block hat L2id=A0 und L3id=49.
Ein Record besteht aus einer Tabelle <flengths> von Feldlaengen
(Bytes) gefolgt von den Felddaten <fdata>. Die Inhalte der Felder
ergeben sich entsprechend den Feldlaengen aus den Felddaten.
Filename Feldanzahl fi
Addresses 21 05
Memo 4 06
Schedule 10 08
To Do List 8 07
Zumindest fuer "read next modified record" muessen erst soviel
Leseoperationen, wie "get number of modified record" lieferte,
durchgefuehrt werden, bevor "write record", "delete record" oder
"reset change flag" ausgefuehrt wird. Andernfalls geschieht
Undefiniertes, z.B. wurde ein read response ohne Record-Daten
mit ri=01 07 03 fi=00 ch=00 beobachtet.
write file record
-> command write record (more) fd=0001
02,48 01 08 01 00 00 00 00 00 51 00 00 00 00 96 00 00 00 <flengths> <fdata>
cmd__ fd___ w1 w2 w3 lr
01 08 01 00 00 00 00 00 51 00 00 00 00 96 00 00 00 Addresses
01 08 03 00 00 00 00 00 58 48 99 00 00 16 00 00 00 Memo
01 08 03 00 00 00 00 00 60 16 99 00 00 16 00 00 00 Memo
01 08 00 00 00 00 00 00 10 00 00 00 00 32 00 00 00 Schedule
01 08 02 00 00 00 00 00 10 00 00 00 00 46 00 00 00 To Do List
lr ist Gesamtlaenge des Record, d.h. Anzahl der Feldlaengen
(Bytes in <flengths>) plus Summe der Feldlaengen (Bytes in
<fdata>).
??? Die Bedeutung der "write record" PDU-Felder w1, w2, w3 ist unklar.
<- reponse write more
90
-> command write record (last)
82,49 <fdata>
<- response write ok
A0,49 12 00 00 05
ri___ fi
12 00 00 05 Addresses
03 00 00 06 Memo
1B 00 00 08 Schedule
02 00 00 07 To Do List
Im "response write ok" sind fi die FileId und ri die RecordId,
die der neue Record im IC35 erhalten hat. Es wird dabei immer ein
neuer Record mit neuer RecordId erzeugt. Das Modifizieren unter
Beibehaltung der RecordId ist mit "update file record" moeglich.
Der neu erzeugte Record erhaelt Aenderungskennzeichen ch=00 (s.o.).
Der geschriebene Record wird falls noetig in mehreren Bloecken
uebertragen, alle bis auf den letzten Block habe L2id=02 und
und L3id=48, der letzte Block hat L2id=82 und L3id=49.
update file record
-> command update record (last) fd=0003 recid=06000005
82,49 01 09 03 00 05 00 00 06 60 19 99 00 00 46 00 00 00 <flengths> <fdata>
cmd__ fd___ ri___ fi w1 w2 w3 lr
ri ist die RecordId und fi die FileId auf dem IC35.
??? w1,w2,w3 sind in der "update record" PDU die gleichen Felder
??? wie in der "write record" PDU mit ebenso unklarer Bedeutung.
lr ist Gesamtlaenge des Record, d.h. Anzahl der Feldlaengen
(Bytes in <flengths>) plus Summe der Feldlaengen (Bytes in
<fdata>).
<- response write ok
A0,49 05 00 00 06
ri___ fi
Im Unterschied zu "write record" wird die RecordId auf dem IC35
hier beibehalten. Ansonsten verhaelt sich "update record" genauso
wie "write record" (Fragmentierung, Aenderungskennzeichen etc.).
delete record
(Beispiele aus Delete.tar.gz:NeueDatenSync_171100.log File "Memo")
-> command delete record
83,49 01 02 03 00 05 00 00 06
cmd__ fd___ ri___ fi
<- response done
A0
Der Record wird im IC35 direkt geloescht, d.h. er wird nicht mit
Aenderungskennzeichen ch=20 (s.o.) auftauchen. Im Gegensatz dazu
bleiben im IC35 manuell geloeschte Records mit ch=20 erhalten,
bis sie mit "reset record change flag" bestaetigt werden und dann
tatsaechlich verschwinden.
reset record change flag
-> command reset record change flag
82,49 01 0A 01 00 11 00 00 05
cmd__ fd___ ri___ fi
<- response done
A0
Das Aenderungskennzeichen des Record wird im IC35 zurueckgesetzt
auf ch=00, d.h. Record unveraendert.
Records mit ch=20 (ohne Daten, Reste von manuellem Loeschen auf
dem IC35) werden endgueltig entfernt.
close file
-> command close file fd=0001
82,49 00 03 01 00 00 00 00 00
cmd__ fd___
<- response done
A0
disconnect
----------
Kommunikation PC->IC35, PC<-IC35:
-> command disconnect
81 03 00 # L2-header
<- response done
A0 03 00 # L2-header
Beim Verbindungsabbau werden nur Level-2 Header ohne Daten
uebertragen, d.h. Level-3 wird nicht benutzt.
Zusammenfassung der PDUs
------------------------
Level-4 commands
00 file commands
00 02 open file
00 03 close file
01 record commands
01 02 delete record
01 03 get filelength: total number of records
01 04 get filelength: number of modified records
01 05 read file record by record-ID
01 06 read file record by index
01 07 read next modified record
01 08 write file record
01 09 update file record
01 0A reset file record change-flag
02 date+time
02 00 get date+time
02 01 set date+time
03 power,passwd,category
03 00 passwd
03 01 power
03 02 category
commands
- identify
80, 10 00 64 00 ,4A "INVENTEC CORPORATION PRODUCT"
- disconnect
81
- power
82,49 03 01 "Power" 00 00 00
- authenticate
82,49 03 00 [password]
- get date+time
83,49 02 00 00
- set date+time
82,49 02 01 00 [mmddyyyyhhmmss] 00 00
- category
82,49 03 02 [category] 00
- open file
82,49 00 02 00 00 00 00 00 00 00 lf+2 00 00 00 lf [filename] 02
- close file
82,49 00 03 fd_.. 00 00 00 00
- get filelength: total number of records
83,49 01 03 fd_.. 00 00 00 00
- get filelength: number of modified records
83,49 01 04 fd_.. 00 00 00 00
- read filerecord by record-ID
83,49 01 05 fd_.. ri_.. 00 fi
- read filerecord by index
83,49 01 06 fd_.. in_dx 00 00
- read next modified filerecord
83,49 01 07 fd_.. 00 00 00 00
- read more
83
- write filerecord (more)
02,48 01 08 fd_.. 00 00 00 00 w1 w2 w3 00 00 lr 00 00 00 <flens> <fdata>
- update filerecord (more)
02,48 01 09 fd_.. ri_.. 00 fi w1 w2 w3 00 00 lr 00 00 00 <flens> <fdata>
write filerecord (last)
82,49 <fdata>
- delete record
83,49 01 02 fd_.. ri_.. 00 fi
- reset filerecord change-flag
82,49 01 0A fd_.. ri_.. 00 fi
responses
- identify
A0, 10 00 D0 07 ,4A "INVENTEC CORPORATION DCS15 1.28"
- disconnect
A0
- power
A0,49 03 01
- authenticate ok
A0,49 01 01
- get date+time
A0,49 [mmddyyyyhhmmss] 00 00
- set date+time
A0
- category
A0,49 xx 01
record fields:
- xx unknown meaning, values: 00, 01
- open file
A0,49 fd_..
- close file
A0
- get filelength
A0,49 n._..
- read filerecord (more)
20,48 ri_.. 00 fi ch <flens> <fdata>
read filerecord (last)
A0,49 <fdata>
record fields:
- ri_.. record-id on IC35
- fi file-id on IC35
- ch change-flag: 00, 80, 40 or 20
- write/update filerecord
A0,49 ri_.. 00 fi
- write more
90
- delete record
A0
- reset record changeflag
A0
IC35 Record Felder
-----------------
Die nachfolgenden Tabellen zu den IC35 Files (Addresses, Memo,
Schedule, ToDoList) enthalten jeweils den 0-relativen Feld-
Index, die Feld-Bedeutung, die maximale Feld-Laenge und ggf.
Erlaeuterung zum Format.
Die maximalen Feld-Laengen sind dokumentiert bei Siemens unter
http://www.ic.siemens.com/mySiemens/lowres/content/
ap_content_moreinfocontainer_lr/1,1908,2_IC35_4_0_61_0_2183,00.html
??? Der Zweck der "category-id"s ist unklar, jede neu angelegte
??? Kategorie erhaelt eine neue "category-id".
Addresses (21 Felder)
0 Vorname 50
1 Nachname 50
2 Firma 128
3 Tel.Privat 48
4 Tel.Buero 48
5 Handy 48
6 Fax 48
7 Strasse 128
8 Ort 60
9 PLZ 10
10 Bundesland 40
11 Land 15
12 E-Mail1 80
13 E-Mail2 80
14 URL 128
15 Geburtstag 10
16 Notizen 255
17 category-id 1 bin
18 (def.)1 128
19 (def.)2 128
20 category 8
category-id, -name
02 Address (owner data)
06 Business
0B Personal
0C Unfiled
13 S35telb
14 S35SIM.1
15 S35SIM.2
16 newcateg
Memo (4 Felder)
0 Betreff 60
1 Notizen 255
2 category-id 1 bin
3 category 8
category-id, -name
0D Business
0E Personal
0F Unfiled
17 n.memcat
Schedule (10 Felder)
Schedule Records enthalten weder category-id noch category Text.
0 Betreff 60
1 Start(Datum) 8 ? [yyyymmdd]
2 Start(Zeit) 6 ? [hhmm]":1"
3 Ende(Zeit) 6 ? [hhmm]"<1"
4 AlrmBef 1 bin
00=no 01=now 02=1min 03=5min 04=10min 05=30min
06=1hour 07=2hour 08=10hour 09=1day 0A=2day
5 Notizen 255
6 AlrmRep(Byte) 1 bin lb00-0iii
l: 0=LED 1=noLED, b: 0=beep 1=nobeep
iii: 0=norepeat 1=day 2=week 3=monwday 4=year 5=monmday
7 Ende(Datum) 8 ? [yyyymmdd]
8 EndRepeat 8 ? [yyyymmdd]
9 RepAlln(Byte) 1 bin nn
repeat all nn days/weeks/mwdays/years/mmdays
Alarm/Repeat-Flags
f4 f6 f9 repeat alarm bef LED beep
0A C0 01 no 2 day no no
07 C0 01 no 2 hour no no
06 C4 01 1 year 1 hour no no
05 C5 02 2 mon md 30 min no no
04 C3 01 1 mon wd 10 min no no
03 82 03 3 week 5 min no yes
02 41 02 2 day 1 min yes no
01 01 01 1 day now yes yes
00 C2 01 1 week none no no
ToDoList (8 Felder)
0 Start 8 ? [yyyymmdd]
1 Ende 8 ? [yyyymmdd]
2 Erledigt 1 bin 00=N 01=J
3 Prioritaet 1 bin 00=low 01=normal 02=high
4 Betreff 60
5 Notizen 255
6 category-id 1 bin
7 category 8
category-id, -name
10 Business
11 Personal
12 Unfiled
category-ids
02 Address Address (owner data)
06 Business Address
0B Personal Address
0C Unfiled Address
0D Business Memo
0E Personal Memo
0F Unfiled Memo
10 Business ToDoList
11 Personal ToDoList
12 Unfiled ToDoList
13 S35telb Address
14 S35SIM.1 Address
15 S35SIM.2 Address
16 newcateg Address
17 n.memcat Memo
IC35Comm.dll Export Funktionen
------------------------------
Addr IC35Comm.dll Export Funktion Aequivalent in ic35sync/Linux
+-------+-------------------------------+----------------------------
3859 AdsBeginSession welcome
3BEB AdsCancelEndSession
11AE AdsCloseDatabase close_file ?
3FAD AdsCloseHandle close_file ?
1B87 AdsCommitRecord commit_frec
1341 AdsDeleteAllRecords
14CE AdsDeleteRecord delete_frec
3B89 AdsEndSession disconnect
1629 AdsGetModifiedRecordCount get_mod_flen
1585 AdsGetRecordCount get_flen
1D84 AdsLocalDeleteRecord
1D00 AdsLocalModifyRecord
1C3E AdsLocalNewRecord
1000 AdsOpenDatabase open_file ?
13FA AdsPurgeDeleteRecords
126D AdsReadCatagoryData category ?
189B AdsReadNextModifiedRecord read_mod_frec
16CD AdsReadRecordByID read_id_frec
1701 AdsReadRecordByIndex read_frec
1E3B AdsReadSysInfo get_date_time
1F7F AdsSendCommand sendcmd,recvrsp
37D0 AdsSetCancelHandle
1B03 AdsUpdateRecord update_frec
1A0C AdsWriteRecord write_frec
1ED5 AdsWriteSysInfo set_date_time ?
37EB AdsDeviceVersion identify
3804 AdsOpenComPort com_open
Anhang: Logfiles der Protokoll-Analyse
--------------------------------------
- Simple_hex.log +setdt -cat modrec -write -del -res
get date+time 2000-08-20 21:28:10
set date+time 2000-08-20 21:31:49
no category
get modified record count (01 04), all files return 0 records
no writerec
no reset changeflag
- Portmon_export.log +setdt +cat allrec -write -del -res
get date+time 2000-09-10 18:28:42
set date+time 2000-09-10 18:30:35
category Addresses (rsp 01 01)
get record count (01 03)
no writerec
no reset changeflag
- Import.tar.gz:Import1.log -setdt -cat allrec +write -del -res
get date+time 2000-10-24 21:44:48
no set date+time
get record count (01 03)
no category
no reset changeflag
writerec Addresses(1x),Memo(1x),Schedule(1x),ToDoList(1x)
- Import.tar.gz:Import.log +setdt +cat allrec +write -del +res
get date+time 2000-10-30 20:32:31
set date+time 2000-10-30 20:59:13
category Addresses(rsp 00 01), Memo(rsp 01 01), ToDoList(rsp 01 01)
get record count (01 03)
reset changeflag Addresses, Memo, Schedule, ToDoList
writerec Addresses(1x), Schedule(2x)
- Delete.tar.gz:Export_171100.log -setdt -cat allrec -write -del -res
Ich habe in Outlook die Daten komplett geloescht und die
IC35-Sync-Software zurueckgesetzt.
Dann habe ich die Daten des IC35 nach Outlook importiert.
get date+time 2000-11-01 17:42:13
no set date+time
no category
get record count (01 03)
no writerec
no reset changeflag
- Delete.tar.gz:InitSync_171100.log +setdt +cat allrec -write -del +res
[Dann habe die Daten des IC35 nach Outlook importiert] und
anschliessend noch einmal einen normalen Sync durchgefuehrt.
get date+time 2000-11-01 17:42:13
set date+time 2000-11-17 23:10:51
category Addressses(rsp 00 01, 01 01), Memo(rsp 01 01), ToDoList(rsp 01 01)
get record count (01 03)
no writerec
reset changeflag Memo,Schedule,ToDoList
- Delete.tar.gz:NeueDatenSync_171100.log +setdt +cat modrec +write +del +res
Anschliessendhabe ich fuer jede Kategorie je 4 Testdatensaetze
angelegt: Je zwei in Outlook und je zwei im IC35.
Im Betreff des Datensatzes steht dieser Erzeugungsort an erster Stelle
(z.B Testadresse Outlook-IC35).
An zweiter Stelle steht das Teil, mit dem der Datensatz geloescht wird.
Anschliessend habe ich einen Sync durchgefuehrt, damit hatten der
IC35 und Outlook jeweils alle 4 Datensaetze.
addr 0018 IC35-IC35
addr 0017 IC35-Outl
addr 0019 Outl-Outl
addr 001A Outl-IC35
memo 0005 IC35-IC35
memo 0004 IC35-Outl
memo 0006 Outl-IC35
memo 0007 Outl-Outl
sched 0025 IC35-IC35
sched 0024 IC35-Outl
sched 0026 Outl-Outl
sched 0027 Outl-IC35
todo 000E IC35-IC35
todo 000D IC35-Outl
todo 000F Outl-Outl
todo 0010 Outl-IC35
get date+time 2000-11-17 23:22:45
set date+time 2000-11-17 23:23:34
category Addressses, Memo, ToDoList
get record count Addresses(01 03) Memo(01 04) Schedule(01 04) ToDoList(01 04)
reset changeflag Addresses, Memo, Schedule, ToDoList
writerec Addresses(3x), Memo(2x), Schedule(2x), ToDoList(2x)
readrec Addresses, readrecmod Memo, Schedule, ToDoList
deleterec Memo, Schedule
- Delete.tar.gz:DeleteSync_171100.log +setdt +cat modrec -write +del +res
Anschliessend habe ich auf jedem Teil pro Kategorie wieder je zwei
Datensaetze geloescht und zwar die, die durch den hinteren Namensteil
gekennzeichnet waren (Nur bei Testadresse IC35-* ist mir ein Fehler
passiert, dort ist es genau umgekehrt -Outlook wurde auf dem IC35
geloescht und umgekehrt). Dann folgt wieder ein Sync (DeleteSync), bei
dem tatsaechlich aus beiden Teilen alle Datensaetze verschwunden sind.
addr 0018 IC35-IC35 0102-1
addr 0017 IC35-Outl 0107-1 0102-3
addr 0019 Outl-Outl 0102-2
addr 001A Outl-IC35 0107-2 0102-4
0002 0107-3 0102-5 Verwenden Sie ...
0012 0107-4 0102-6 Testnachname, Testvorname
0011 0107-5 0102-7 Haid, Beppo
memo 0005 IC35-IC35 0107-2 0102-4
memo 0004 IC35-Outl 0102-1
memo 0006 Outl-IC35 0107-1 0102-3
memo 0007 Outl-Outl 0102-2
sched 0025 IC35-IC35 0107-2 0102-4
sched 0024 IC35-Outl 0102-2
sched 0026 Outl-Outl 0102-1
sched 0027 Outl-IC35 0107-1 0102-3
todo 000E IC35-IC35 0107-1 0102-3
todo 000D IC35-Outl 0102-1
todo 000F Outl-Outl 0102-2
todo 0010 Outl-IC35 0107-2 0102-4
get date+time 2000-11-17 23:23:34
set date+time 2000-11-17 23:30:28
category Addresses, Memo, ToDoList
get modified record count (01 04)
readrecmod
deleterec Addresses, Memo, Schedule, ToDoList
no writerec
reset changeflag
- Delete.tar.gz:Import_171100.log +setdt +cat allrec -write -del +res
Anschliessend habe ich wie gewuenscht noch einen Export der
Outlook-Daten in den IC35 durchgefuehrt.
get date+time 2000-11-17 23:30:28
set date+time 2000-11-17 23:48:36
category
reset changeflag
no writerec

9
src/.cvsignore Normal file
View File

@ -0,0 +1,9 @@
Makefile
Makefile.in
vcc.c
versinfo.c
ic35sync
ic35mgr
ic35log
vcaconv
.deps

35
src/CVS/Entries Normal file
View File

@ -0,0 +1,35 @@
/.cvsignore/1.2/Mon Feb 19 01:09:14 2001//
/Makefile.am/1.3/Mon Feb 19 01:09:43 2001//
/comio.c/1.13/Sat Mar 3 16:30:45 2001//
/comio.h/1.7/Sat Mar 3 16:30:45 2001//
/databin.c/1.35/Fri Mar 2 02:09:59 2001//
/dataio.c/1.33/Fri Mar 2 02:09:59 2001//
/dataio.h/1.12/Tue Dec 26 01:25:22 2000//
/datatxt.c/1.32/Tue Dec 26 01:36:32 2000//
/datavca.c/1.46/Fri Mar 2 02:09:59 2001//
/genproto.c/1.2/Sun Jan 21 19:54:52 2001//
/genproto.h/1.2/Sun Jan 21 23:38:37 2001//
/ic35frec.c/1.8/Fri Mar 2 02:09:59 2001//
/ic35frec.h/1.5/Sat Dec 23 01:09:26 2000//
/ic35log.sh/1.6/Sun Jan 14 00:09:46 2001//
/ic35mgr.c/1.20/Tue Nov 20 23:08:35 2001//
/ic35sync.c/1.19/Fri Mar 2 02:10:42 2001//
/mgrproto.c/1.17/Tue Nov 20 23:08:35 2001//
/mgrproto.h/1.8/Tue Nov 20 23:08:35 2001//
/mgrtrans.c/1.17/Tue Nov 20 23:08:35 2001//
/mgrtrans.h/1.7/Tue Nov 20 23:08:35 2001//
/port.h/1.3/Sat Feb 10 03:08:41 2001//
/synproto.c/1.11/Sun Jun 17 23:37:36 2001//
/synproto.h/1.3/Sun Dec 3 07:50:44 2000//
/syntrans.c/1.19/Fri Mar 2 02:09:59 2001//
/syntrans.h/1.10/Thu Dec 21 11:05:52 2000//
/util.c/1.9/Mon Jun 11 09:14:59 2001//
/util.h/1.9/Fri Mar 2 02:08:32 2001//
/vcaconv.c/1.17/Sat Feb 17 20:56:49 2001//
/vcc.h/1.2/Sun Nov 19 18:14:45 2000//
/vcc.y/1.7/Sat Feb 10 03:09:24 2001//
/vcutil.c/1.44/Thu Dec 28 02:26:31 2000//
/vcutil.h/1.44/Wed Dec 27 22:26:52 2000//
/vobject.c/1.9/Wed Feb 7 01:44:42 2001//
/vobject.h/1.6/Thu Dec 21 23:01:45 2000//
D

1
src/CVS/Repository Normal file
View File

@ -0,0 +1 @@
ic35link/src

1
src/CVS/Root Normal file
View File

@ -0,0 +1 @@
:pserver:anonymous@ic35link.cvs.sourceforge.net:/cvsroot/ic35link

64
src/Makefile.am Normal file
View File

@ -0,0 +1,64 @@
## Process this file with automake to produce Makefile.in
## $Id: Makefile.am,v 1.3 2001/02/19 01:09:43 tsch Rel $
## Copyright (C) 2001 Thomas Schulz
##
## automakefile for ic35link/src
versinfo.c: Makefile
-@echo "Creating versinfo.c"
-@rm -f versinfo.c
-@echo '/* versinfo.c */' > versinfo.c
-@echo '/* automatically made by Makefile */' >> versinfo.c
-@echo '/* DO NOT EDIT! */' >> versinfo.c
-@echo '#include "../config.h"' >> versinfo.c
-@echo 'char * pkgvers = VERSION;' >> versinfo.c
-@echo 'char * pkgdate = ISODATE;' >> versinfo.c
-@echo 'char * bldinfo = "compiled '`date '+%Y-%m-%d %T'` \
'by '`whoami`'@'`hostname`'";' >> versinfo.c
bin_PROGRAMS = ic35sync ic35mgr vcaconv
ic35sync_SOURCES = \
ic35sync.c \
syntrans.c syntrans.h \
synproto.c synproto.h \
genproto.c genproto.h \
dataio.c dataio.h datatxt.c databin.c datavca.c \
ic35frec.c ic35frec.h \
vcutil.c vcutil.h \
vcc.y vcc.h vobject.c vobject.h port.h \
comio.c comio.h \
util.c util.h \
versinfo.c
ic35mgr_SOURCES = \
ic35mgr.c \
mgrtrans.c mgrtrans.h \
mgrproto.c mgrproto.h \
genproto.c genproto.h \
comio.c comio.h \
util.c util.h \
versinfo.c
vcaconv_SOURCES = \
vcaconv.c \
dataio.c dataio.h datatxt.c databin.c datavca.c \
ic35frec.c ic35frec.h \
vcutil.c vcutil.h \
vcc.y vcc.h vobject.c vobject.h port.h \
util.c util.h \
versinfo.c
bin_SCRIPTS = ic35log
ic35log:
cat $@.sh >$@
chmod a+x $@
EXTRA_DIST = ic35log.sh
# tell automake to not strip scripts:
INSTALL_SCRIPT = $(INSTALL)
CLEANFILES = ic35log .deps/* versinfo.c
if MAINTAINER_MODE
MAINTAINERCLEANFILES = vcc.c Makefile.in
else
MAINTAINERCLEANFILES =
endif

484
src/comio.c Normal file
View File

@ -0,0 +1,484 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* */
static char rcsid[] =
"$Id: comio.c,v 1.13 2001/03/03 16:30:45 tsch Rel $"; /*
* *
* IC35 serial communication
* *
*************************************************************************
* *
* conditional compile on NO_LOGSIM: if #defined, the simulated *
* communication is NOT supported, default WITH com-simulation. *
* conditional compile on __STRICT_ANSI__: if #defined, substitute *
* functions, which are not available with the ANSI C standard. *
* (compilation with 'gcc -ansi ..' does #define __STRICT_ANSI__) *
* *
* simulated communication #ifndef NO_LOGSIM *
* com_siminit initialize communications with simulation file *
* com_simexit local: leave simulated communication *
* com_simul local: report if simulation active *
* com_simrecv local: simulate receive from simulation file *
* real communication
* com_setsigs local: set RS232 output signals *
* com_settimeout set receive timeout, return previous *
* com_init initialize serial communication device *
* com_waitnice lower process priority when using com_sendw() *
* com_sendw send datablock to comm.device with waiting *
* com_send send datablock to comm.device *
* com_recv receive datablock from comm.device *
* com_exit close serial communication device *
* *
************************************************************************/
#include <stdio.h> /* FILE*, fopen(), .. */
#include <string.h> /* strncmp(), .. */
#include <unistd.h> /* read(), write(), .. */
#include <termios.h> /* tcgetattr(), .. */
#include <fcntl.h> /* F_GETFL, .. */
#include <sys/ioctl.h> /* ioctl(), .. */
#include <sys/types.h> /* size_t, .. */
#include <sys/time.h> /* struct timeval */
#include <signal.h> /* sigaction(), .. */
#include "util.h" /* LPRINTF(), .. */
#include "comio.h"
NOTUSED(rcsid)
/* ==================================== */
/* simulated communication */
/* ==================================== */
/*
* uses post-processed log of real communication with IC35:
* WR nn xx xx xx ...
* RD nn xx xx xx ...
* and "receives" data using the "RD nn" lines.
*/
#ifndef NO_LOGSIM
static FILE * simfp = NULL;
static int
_com_siminit( char * s_fname ) /* init simulated comm */
{
if ( s_fname && *s_fname ) {
simfp = fopen( s_fname, "r" );
if ( simfp == NULL )
return ERR;
}
return OK;
}
void
com_siminit( char * s_fname )
{
if ( _com_siminit( s_fname ) != OK )
fatal( "cannot open simulation file: %s", s_fname );
}
static void
com_simexit( void ) /* leave simulated comm */
{
if ( simfp ) {
fclose( simfp );
simfp = NULL;
}
}
static bool
com_simul( void ) /* report if simul active */
{
return (bool)( simfp != NULL );
}
static int
com_simrecv( uchar * buff, size_t blen ) /* receive from simul.file */
{
static int simrlen = 0;
static int simridx = 0;
bool do_check;
uchar * bptr;
int chr, n, rbyte;
char xdir[8];
if ( buff == NULL || blen == 0 ) /* sanity */
return 0;
memset( buff, 0, blen); /* clear buffer sets dummy bytes */
bptr = buff; do_check = FALSE;
while ( bptr < buff + blen ) {
/* forward to or check next "RD nn" line */
if ( simridx >= simrlen ) {
for ( ; ; ) {
while ( (chr = fgetc( simfp )) != '\n' )
if ( chr < 0 )
return ERR;
if ( fscanf( simfp, "%s %d", xdir, &simrlen ) == 2
&& strncmp( xdir, "RD", 2 ) == 0 )
break;
if ( do_check )
return bptr - buff;
}
do_check = TRUE;
simridx = 0;
}
/* read bytes from "RD nn" line */
for ( ; simridx < simrlen; ++simridx ) {
if ( bptr >= buff + blen )
return blen;
ungetc( chr = fgetc( simfp ), simfp ); /* avoid fscanf() eat \n */
if ( chr == '\n'
|| fscanf( simfp, "%x", &rbyte ) != 1 )
break;
*bptr++ = (uchar)rbyte;
}
/* dummy non-logged recv bytes */
n = min( blen - (bptr - buff), simrlen - simridx);
simridx += n;
bptr += n;
}
return bptr - buff;
}
#endif /*NO_LOGSIM*/
/* ==================================== */
/* real communication */
/* ==================================== */
static int com_fd = -1;
static int com_tmo = 500; /* timeout 500 ms */
/* local: set RS232 output signals
* -------------------------------
*/
static void
com_setsigs( int sigs )
{
int flags;
if ( com_fd >= 0
&& ioctl( com_fd, TIOCMGET, &flags ) == 0 ) {
flags &= ~(TIOCM_DTR|TIOCM_RTS);
flags |= (TIOCM_DTR|TIOCM_RTS) & sigs;
ioctl( com_fd, TIOCMSET, &flags );
LPRINTF(( L_NOISE, "com_setsigs(%08X) DTR %s RTS %s",
sigs, sigs & TIOCM_DTR ? "ON " : "off",
sigs & TIOCM_RTS ? "ON " : "off" ));
}
}
/* local: log state of RS232 signals
* ---------------------------------
*/
static void
_com_sigchg( void )
{
static int oflags = -1;
static struct {
char * name;
int sig;
} sigtab[] = {
{ "CTS", TIOCM_CTS },
{ "DCD", TIOCM_CAR },
{ "DSR", TIOCM_DSR },
{ "RI", TIOCM_RNG },
{ NULL, 0 }
}, *psig;
int flags;
char sigtext[48];
if ( com_fd >= 0
&& ioctl( com_fd, TIOCMGET, &flags ) == 0
&& ( ((oflags ^ flags) & (TIOCM_CTS|TIOCM_CAR|TIOCM_DSR|TIOCM_RNG)) != 0
|| oflags == -1 ) ) {
strcpy( sigtext, "" );
for ( psig = sigtab; psig->name; ++psig )
sprintf( sigtext+strlen(sigtext), " %s %s%s",
psig->name,
flags & psig->sig ? "ON" : "off",
((oflags ^ flags) & psig->sig) && oflags != -1 ? "*" : "" );
LPRINTF(( L_NOISE, "com signals:%s", sigtext ));
oflags = flags;
}
}
/* set,get receive timeout
* -----------------------
* return previous timeout. zero or negative timeout argument 'msec'
* will not be set and can be used to enquire current timeout.
*/
int
com_settimeout( int msec )
{
int old_tmo = com_tmo;
old_tmo = com_tmo;
if ( msec > 0 )
com_tmo = msec;
if ( old_tmo != com_tmo )
LPRINTF(( L_NOISE, "com_settimeout %d -> %d", old_tmo, com_tmo ));
return old_tmo;
}
/* initialize comm.device
* ----------------------
* open in O_NONBLOCK mode to avoid hanging on inactice DCD signal,
* finally set back to blocking mode.
* set line parameters to 115200,N,8,2 and raw mode, 2 stopbits are
* needed to avoid IC35 receive errors with MMCard operations.
* raise DTR and RTS signals.
*/
#ifdef __STRICT_ANSI__
#define cfmakeraw(tiop) \
(tiop)->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); \
(tiop)->c_oflag &= ~(OPOST); \
(tiop)->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); \
(tiop)->c_cflag &= ~(CSIZE|PARENB); \
(tiop)->c_cflag |= CS8;
#endif
int
com_init( char * devname )
{
int i, flags;
struct termios tio;
#ifndef NO_LOGSIM
if ( com_simul() ) {
com_fd = -1;
return OK;
}
#endif
/* open serial communication device */
if ( (com_fd = open( devname, O_RDWR|O_NONBLOCK|O_NOCTTY )) == -1 ) {
return ERR;
}
if ( !isatty( com_fd ) ) {
close( com_fd );
com_fd = -1;
return ERR;
}
/* set linepars 11500,N,8,2 and raw mode */
/* HUPCL to clear DTR,RTS on last close */
tcgetattr( com_fd, &tio );
tio.c_oflag = 0;
tio.c_iflag = IGNBRK | IGNPAR;
tio.c_cflag = CREAD | CLOCAL | CS8 | HUPCL | CSTOPB;
cfsetispeed( &tio, B115200 );
cfsetospeed( &tio, B115200 );
tio.c_lflag = NOFLSH;
cfmakeraw( &tio );
for ( i = 0; i <= NCCS; ++i ) tio.c_cc[i] = 0;
tio.c_cc[VMIN] = 1;
tio.c_cc[VTIME] = 0;
tcsetattr( com_fd, TCSANOW, &tio );
/* set line signals DTR on, RTS off */
com_setsigs( TIOCM_DTR|TIOCM_RTS );
/* back to blocking mode for timeout */
if ( (flags = fcntl( com_fd, F_GETFL, 0 )) != -1 ) {
flags &= ~O_NONBLOCK;
fcntl( com_fd, F_SETFL, flags );
}
_com_sigchg();
return OK;
}
/* send datablock with waiting
* ---------------------------
* IC35 gets receive receive errors if datablocks of more than 16 bytes
* are sent at full speed of 115200 baud, using 2 stopbits increases
* this size limit to 29 bytes.
* the problem occurred only with IC35 MMCard operations, import and
* synchronize PIM-data don't suffer this limitation.
* as a workaround do delay some time after sent every couple of bytes.
* the delay is done with busy waiting using gettimeofday(), because
* interrupt controlled delays are either too long (at least 10 msec
* with an "itimer" at Linux-2.x timer interrupt frequency of 100 Hz)
* or require root privilege (nanosleep() or fast RTC interrupts).
* other methods like usleep(), nanosleep(), select() yielded delays
* of ca. 20..30 msec and were therefore also not chosen.
* (see getitimer(2), sigaction(2), nanosleep(2), usleep(3), select(2)
* for reference).
* to avoid too much CPU hogging during busywait delays, the process
* scheduling priority may be lowered using nice(2) when comsendw()
* is called with a block of more than NICE_MINBLEN bytes.
* com_waitnice() is used to enable the priority lowering: each call
* of com_waitnice() causes one nice() systemcall.
* the maximum throughput measured with write file to IC35 MMCard was
* ca. 1740 b/s with 2kB buffersize (with "itimer" it was ca. 1350 b/s,
* with usleep() delay it was only ca. 600 b/s).
* measurements on a Pentium-I/133MHz showed that
* for blocks of 1 8 16 24 28 bytes
* the delay of 165 1570 3180 4795 5620 usec was needed at least.
* measurements on a Pentium-III/500MHz (by Harald Becker) showed that
* for blocks of 1 16 bytes
* the delay of 187 3212 usec was needed at least.
*/
#define NICE_MINBLEN 32 /* min. block length for nice() */
#define WAIT_BLKSIZE 16 /* number of bytes per write() */
#define WAIT_USDELAY 3250 /* usec to wait before write() */
static int _waitnice_inc; /* increment to use for nice(2) */
static void /* busy wait some microseconds */
_wait_usec( long usec ) /* contributed by Harald Becker */
{
long elapsed; /* elapsed delay in usec */
struct timeval tbeg, tnow; /* start time and current time */
gettimeofday( &tbeg, NULL ); /* get start time of delay loop */
do { /* loop .. */
gettimeofday( &tnow, NULL ); /* get current time */
if ( (elapsed = tnow.tv_sec - tbeg.tv_sec) ) /* seconds diff */
elapsed *= 1000000; /* to usec if nonzero */
elapsed += tnow.tv_usec - tbeg.tv_usec; /* add microsecs diff */
} while( elapsed < usec ); /* .. until specified usec over */
}
void /* export interface to store increment */
com_waitnice( int inc ) /* 'inc' for lowering process priority */
{
_waitnice_inc = inc;
}
int /* send data to communication device */
com_sendw( uchar * data, size_t dlen ) /* with busywait delays */
{
uchar * dptr;
int slen;
#ifndef NO_LOGSIM
if ( com_simul() )
slen = dlen;
else
#endif
{
if ( com_fd < 0 )
return ERR;
LPRINTF(( L_DEBUG, "com_sendw(%p,%u) ..", data, dlen ));
if ( dlen >= NICE_MINBLEN && _waitnice_inc != 0 ) {
nice( _waitnice_inc ); /* lower own process priority */
_waitnice_inc = 0; /* no more nice() before next */
} /* com_waitnice() tells again */
dptr = data;
while ( (slen = data+dlen - dptr) > 0 ) {
if ( slen > WAIT_BLKSIZE ) slen = WAIT_BLKSIZE;
_wait_usec( WAIT_USDELAY );
if ( write( com_fd, dptr, slen ) != slen )
break;
dptr += slen;
}
slen = dptr - data;
}
LDUMP(( L_NOISE, data, dlen,
"com_sendw(%p,%u) = %d", data, dlen, slen ));
return slen;
}
/* send datablock to comm.device
* -----------------------------
*/
int
com_send( uchar * data, size_t dlen )
{
int slen;
#ifndef NO_LOGSIM
if ( com_simul() )
slen = dlen;
else
#endif
{
if ( com_fd < 0 )
return ERR;
LPRINTF(( L_DEBUG, "com_send(%p,%u) ..", data, dlen ));
slen = write( com_fd, data, dlen );
}
LDUMP(( L_NOISE, data, dlen,
"com_send(%p,%u) = %d", data, dlen, slen ));
return slen;
}
/* receive datablock from comm.device
* ----------------------------------
* use select() to wait for data, accumulate data with read()
* until buffer 'buff' gets full or receive timeout occurs.
*/
int
com_recv( uchar * buff, size_t blen )
{
fd_set rfds;
struct timeval tmo;
uchar *rptr, *rend;
int rlen;
#ifndef NO_LOGSIM
if ( com_simul() )
rlen = com_simrecv( buff, blen );
else
#endif
{
if ( com_fd < 0 )
return ERR;
rend = (rptr = buff) + blen;
do {
FD_ZERO( &rfds );
FD_SET( com_fd, &rfds );
tmo.tv_sec = com_tmo / 1000;
tmo.tv_usec = (com_tmo % 1000) * 1000;
if ( select( com_fd+1, &rfds, NULL, NULL, &tmo ) > 0
&& FD_ISSET( com_fd, &rfds ) ) {
_com_sigchg();
rlen = read( com_fd, rptr, rend - rptr );
LPRINTF(( L_DEBUG, "com_recv: read(com,rptr,%d) = %d",
rend-rptr, rlen ));
if ( rlen > 0 )
rptr += rlen;
} else {
rlen = 0;
}
} while ( rlen > 0 && rptr < rend );
rlen = rptr - buff;
}
if ( rlen > 0 )
LDUMP(( L_NOISE, buff, rlen,
"com_recv(%p,%u) = %d", buff, blen, rlen ));
else
LPRINTF(( L_NOISE, "com_recv(%p,%u) = %d", buff, blen, rlen ));
return rlen;
}
/* close comm.device
* -----------------
* leave simulated communication if active.
* clear RS232 signals DTR and RTS and close comm.device.
*/
void
com_exit( void )
{
#ifndef NO_LOGSIM
com_simexit();
#endif
if ( com_fd < 0 )
return;
com_setsigs( 0 ); /* DTR off, RTS off */
_com_sigchg();
close( com_fd );
com_fd = -1;
}
/* substitute for usleep()
* -----------------------
* the usleep() function is unavailable on compilation with "-ansi",
* which #defines __STRICT_ANSI__
*/
#ifdef __STRICT_ANSI__
void
usleep( unsigned long usec )
{
struct timeval tmo;
tmo.tv_sec = usec / 1000000;
tmo.tv_usec = usec % 1000000;
select( 0, NULL, NULL, NULL, &tmo );
}
#endif /*__STRICT_ANSI__*/

37
src/comio.h Normal file
View File

@ -0,0 +1,37 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* *
* $Id: comio.h,v 1.7 2001/03/03 16:30:45 tsch Rel $ *
* *
* header for IC35 serial communication *
* *
************************************************************************/
#ifndef _COMIO_H
#define _COMIO_H 1
#include <sys/types.h> /* size_t */
#include "util.h" /* uchar, NO_LOGSIM */
#ifdef NO_LOGSIM
#define COM_SIMINIT(arg)
#else
#define COM_SIMINIT(arg) com_siminit arg
#endif
void com_siminit( char * s_fname ); /* init comm.simulation */
int com_settimeout( int msec ); /* set timeout [msec] */
int com_init( char * devname ); /* initialize comm.device */
void com_waitnice( int inc ); /* for nice() in com_sendw*/
int com_sendw( uchar * data, size_t dlen ); /* send data with waiting */
int com_send( uchar * data, size_t dlen ); /* send data to comm.dev */
int com_recv( uchar * buff, size_t blen ); /* receive from comm.dev */
void com_exit( void ); /* close comm.device */
#ifdef __STRICT_ANSI__
void usleep( unsigned long usec );
#endif
#endif /*_COMIO_H*/

362
src/databin.c Normal file
View File

@ -0,0 +1,362 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* */
static char rcsid[] =
"$Id: databin.c,v 1.35 2001/03/02 02:09:59 tsch Rel $"; /*
* *
* IC35 synchronize data import/export: binary IC35 record format *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
************************************************************************/
#include <stdio.h> /* fprintf(), .. */
#include <string.h> /* strcpy(), .. */
#include <ctype.h> /* isprint(), .. */
#include <unistd.h> /* access() */
#include <sys/types.h> /* size_t, .. */
#include <time.h> /* struct tm, time() .. */
#include "vcc.h" /* VObject, .. */
#include "util.h" /* ERR, uchar, .. */
#include "ic35frec.h" /* IC35 record fields.. */
#include "dataio.h"
NOTUSED(rcsid);
#pragma pack(1)
struct binrec { /* IC35 binary record data */
size_t len; /* length of this record */
ulong rid; /* record id on IC35 */
uchar chg; /* changeflag on IC35 */
}; /* flengths,fdata (dyn.length) */
#pragma pack()
struct binelmt { /* IC35 binrec list element */
struct binelmt * next; /* next element in list */
IC35REC * rec; /* IC35 record */
};
static struct binelmt * binlist;
static struct binelmt * binget;
/* internal: write IC35 binary record to file
* ------------------------------------------
*/
static int
_bin_writerec( FILE * outfp, IC35REC * rec )
{
uchar * recdata;
size_t reclen;
struct binrec brec;
get_ic35recdata( rec, &recdata, &reclen );
brec.len = sizeof(brec) + reclen;
brec.rid = ic35recid( rec );
brec.chg = ic35recchg( rec );
if ( fwrite( &brec, sizeof(brec), 1, outfp ) != 1
|| fwrite( recdata, reclen, 1, outfp ) != 1 )
return ERR;
return OK;
}
/* internal: read IC35 binary record from file
* -------------------------------------------
*/
static int
_bin_readrec( FILE * infp, IC35REC * rec )
{
struct binrec brec;
uchar * rbuff;
size_t rlen, i;
if ( fread( &brec, sizeof(brec), 1, infp ) != 1 )
return -1;
set_ic35recid( rec, brec.rid );
set_ic35recchg( rec, brec.chg );
rlen = brec.len - sizeof(brec);
if ( rlen > 0
&& (rbuff = malloc( rlen )) != NULL ) {
if ( fread( rbuff, rlen, 1, infp ) == 1 )
set_ic35recdata( rec, rbuff, rlen );
else
rlen = ERR;
free( rbuff );
} else {
for ( i = 0; i < rlen; ++i )
(void)fgetc( infp );
}
return rlen;
}
/* open IC35 binary record file
* ----------------------------
* read input file into internal record list
*/
static char * iomode;
static char * addr_fname;
static int
bin_open( char * mode, char * addrfname, char * vcalfname, char * memofname )
{
FILE * infp;
IC35REC * ic35rec;
struct binelmt * newelmt;
struct binelmt * pelmt;
LPRINTF(( L_INFO, "bin_open(%s,%s,%s)",
addrfname ? addrfname : "NULL",
vcalfname ? vcalfname : "NULL",
memofname ? memofname : "NULL" ));
iomode = mode; /* note input/output for close */
addr_fname = addrfname; /* note filename for close */
binlist = binget = NULL; /* reset record list */
if ( !( addrfname && *addrfname )
|| iomode[0] != 'r' ) /* open for output only */
return OK;
if ( strcmp( addrfname, "-" ) == 0 )
infp = stdin;
else if ( (infp = fopen( addrfname, "r" )) == NULL )
return access( addrfname, F_OK ) == 0 ? ERR : OK;
LPRINTF(( L_INFO, "bin_open: read %s ..", addrfname ));
pelmt = NULL;
for ( ; ; ) {
if ( (ic35rec = new_ic35rec()) == NULL
|| _bin_readrec( infp, ic35rec ) < 0 )
break;
if ( (newelmt = malloc( sizeof(*newelmt) )) != NULL ) {
newelmt->next = NULL;
newelmt->rec = ic35rec;
if ( pelmt == NULL )
binlist = pelmt = newelmt;
else
pelmt = pelmt->next = newelmt;
}
}
if ( infp != stdin )
fclose( infp );
del_ic35rec( ic35rec );
LPRINTF(( L_INFO, "bin_open: read %s done", addrfname ));
return OK;
}
/* close IC35 binary record file
* -----------------------------
* write internal record list to output file
* if closing input file only release record list
*/
static void
bin_close( void )
{
FILE * outfp = NULL;
struct binelmt * delelmt;
if ( addr_fname && *addr_fname
&& (iomode[0] == 'w' || iomode[1] == '+')
&& (outfp = backup_and_openwr( addr_fname )) == NULL )
return;
LPRINTF(( L_INFO, "bin_close: %s",
outfp && binlist ? "write .." : "no output" ));
LPRINTF(( L_INFO, "bin_close: write %s ..", addr_fname ));
while ( binlist ) {
if ( outfp )
_bin_writerec( outfp, binlist->rec );
delelmt = binlist;
binlist = binlist->next;
del_ic35rec( delelmt->rec );
free( delelmt );
}
binget = NULL; /* sanity for bin_getrec() */
if ( outfp && outfp != stdout )
fclose( outfp );
LPRINTF(( L_INFO, "bin_close: done" ));
}
/* rewind list of binary records
* -----------------------------
*/
static void
bin_rewind( void )
{
binget = NULL;
}
/* get binary record for fileid
* ----------------------------
*/
static IC35REC *
bin_getrec( int fileid )
{
if ( binget == NULL )
binget = binlist;
else
binget = binget->next;
while ( binget ) {
if ( fileid == FILE_ANY /* next record with any fileid */
|| FileId( ic35recid( binget->rec ) ) == fileid )
return binget->rec;
binget = binget->next;
}
return NULL;
}
/* get binary record by record-ID
* ------------------------------
*/
static IC35REC *
bin_getrec_byID( ulong recid )
{
struct binelmt * pelmt;
if ( RecId( recid ) == 0 )
return NULL;
for ( pelmt = binlist; pelmt; pelmt = pelmt->next )
if ( ic35recid( pelmt->rec ) == recid )
return pelmt->rec;
return NULL;
}
/* compare IC35 record with binary record
* --------------------------------------
*/
static int
bin_cmpic35rec( IC35REC * ic35rec, IC35REC * binrec )
{
return cmp_ic35rec( ic35rec, binrec );
}
/* update IC35 record with binary record
* -------------------------------------
*/
static IC35REC *
bin_updic35rec( IC35REC * ic35rec, IC35REC * rec )
{
uchar * data;
size_t dlen;
if ( ic35rec == NULL
&& (ic35rec = new_ic35rec()) == NULL )
return NULL;
set_ic35recid( ic35rec, ic35recid( rec ) );
get_ic35recdata( rec, &data, &dlen );
set_ic35recdata( ic35rec, data, dlen );
return ic35rec;
}
/* put IC35 record to (new) binary record
* --------------------------------------
*/
static IC35REC *
bin_putic35rec( IC35REC * ic35rec )
{
struct binelmt * pelmt;
struct binelmt * newelmt;
struct binelmt * lastinfile;
struct binelmt * last;
IC35REC * rec;
uchar * data;
size_t dlen;
if ( (rec = bin_getrec_byID( ic35recid( ic35rec ) )) == NULL ) {
if ( (newelmt = malloc( sizeof(*newelmt) )) == NULL
|| (rec = newelmt->rec = new_ic35rec()) == NULL ) {
free( newelmt );
return NULL;
}
last = lastinfile = NULL;
for ( pelmt = binlist; pelmt; pelmt = pelmt->next ) {
if ( FileId( ic35recid( pelmt->rec ) )
== FileId( ic35recid( ic35rec ) ) )
lastinfile = pelmt;
last = pelmt;
}
if ( lastinfile ) last = lastinfile;
if ( last == NULL ) {
binlist = newelmt;
newelmt->next = NULL;
} else {
newelmt->next = last->next;
last->next = newelmt;
}
}
set_ic35recid( rec, ic35recid( ic35rec ) );
get_ic35recdata( ic35rec, &data, &dlen );
set_ic35recdata( rec, data, dlen );
return rec;
}
/* delete binary record
* --------------------
*/
static void
bin_delrec( IC35REC * delrec )
{
struct binelmt ** pnext;
struct binelmt * pelmt;
for ( pnext = &binlist, pelmt = *pnext; pelmt != NULL;
pnext = &pelmt->next, pelmt = *pnext )
if ( pelmt->rec == delrec ) {
*pnext = pelmt->next;
del_ic35rec( pelmt->rec );
free( pelmt );
break;
}
}
/* get,set binary record-ID
* ------------------------
*/
static ulong
bin_recid( IC35REC * rec )
{
return ic35recid( rec );
}
static void
bin_set_recid( IC35REC * rec, ulong recid )
{
set_ic35recid( rec, recid );
}
/* get,set binary record status
* ----------------------------
*/
static int
bin_recstat( IC35REC * rec )
{
switch ( ic35recchg( rec ) ) {
case IC35_CLEAN: return PIM_CLEAN;
case IC35_NEW:
case IC35_MOD: return PIM_DIRTY;
case IC35_DEL: return PIM_DEL;
}
return PIM_DIRTY;
}
static void
bin_set_recstat( IC35REC * rec, int stat )
{
switch ( stat ) {
case PIM_CLEAN: set_ic35recchg( rec, IC35_CLEAN ); break;
case PIM_DIRTY: set_ic35recchg( rec, IC35_NEW ); break;
case PIM_DEL: set_ic35recchg( rec, IC35_DEL ); break;
}
}
/* binary format operations
* ------------------------
*/
struct pim_oper bin_oper = {
bin_open,
bin_close,
bin_rewind,
(void*(*)(int))bin_getrec,
(void*(*)(ulong))bin_getrec_byID,
(int(*)(IC35REC*,void*))bin_cmpic35rec,
(IC35REC*(*)(IC35REC*,void*))bin_updic35rec,
(void*(*)(IC35REC*))bin_putic35rec,
(void(*)(void*))bin_delrec,
(ulong(*)(void*))bin_recid,
(void(*)(void*,ulong))bin_set_recid,
(int(*)(void*))bin_recstat,
(void(*)(void*,int))bin_set_recstat,
};

428
src/dataio.c Normal file
View File

@ -0,0 +1,428 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* */
static char rcsid[] =
"$Id: dataio.c,v 1.33 2001/03/02 02:09:59 tsch Rel $"; /*
* *
* IC35 synchronize data import/export *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
* backup_and_openwr backup and open output file for write *
* revised date+time on IC35 *
* clr_newic35dt clear new IC35 revised to get it fresh *
* get_newic35dt new revised date+time to IC35 string *
* set_oldic35dt IC35 string to old revised date+time *
* *
* PIM format
* pimfmt2bin local: PIM format text to binary
* set_pim_format set PIM format
* pim_format report current PIM format
* pimop[] functions table of format-specific ops
* PIM file access
* pim_open open PIMfile(s) and read if present
* pim_openinp open PIMfile(s) for input and read
* pim_openout note PIMfile(s) for output
* pim_close close and flush to PIMfile(s)
* PIM record operations
* pim_rewind rewind PIM record list
* pim_getrec get next PIM record for fileid
* pim_getrec_byID get PIM record by rec-ID (and fileid)
* pim_updic35rec update IC35 record with PIM record
* pim_cmpic35rec compare IC35 record with PIM record
* pim_putic35rec put IC35 record to (new) PIM record
* pim_putrec output (new) PIM record
* pim_delrec delete PIM record
* PIM record IC35-recID and status
* pim_recid report IC35 record-ID from PIM record
* pim_set_recid set IC35 record-ID to PIM record
* pim_recstat report PIM record changeflag
* pim_set_recstat set PIM record changeflag
* *
************************************************************************/
#include <stdio.h> /* fprintf(), .. */
#include <string.h> /* strcpy(), .. */
#include <ctype.h> /* isprint(), .. */
#include <unistd.h> /* access() */
#include <sys/types.h> /* size_t, .. */
#include <time.h> /* struct tm, time() .. */
#include "vcc.h" /* VObject, .. */
#include "util.h" /* ERR, uchar, .. */
#include "ic35frec.h" /* IC35 record fields.. */
#include "dataio.h"
NOTUSED(rcsid);
/* backup and open output file for write
* -------------------------------------
*/
FILE *
backup_and_openwr( char * fname )
{
char * bkpfname;
FILE * fp;
if ( !( fname && *fname ) )
return NULL;
if ( strcmp( fname, "-" ) == 0 )
return stdout;
if ( (bkpfname = malloc( strlen( fname ) + 2 )) != NULL ) {
strcat( strcpy( bkpfname, fname ), "~" );
remove( bkpfname );
rename( fname, bkpfname );
free( bkpfname );
}
if ( (fp = fopen( fname, "w" )) == NULL )
error( "cannot open outfile: %s", fname );
return fp;
}
/* ============================================ */
/* revised date+time on IC35 */
/* ============================================ */
/*
* IC35 does not maintain last modified date+time per record
* instead there is a command to write date+time to IC35,
* which is used for synchronization.
* this timestamp is also used for "last modified" VObject property
*/
/* revised date+time for vCard,vCal records
* ----------------------------------------
*/
static time_t _new_ic35dtime; /* to vCard,vCal records and IC35 */
void
clr_newic35dt( void )
{
_new_ic35dtime = 0;
}
time_t
newic35dt( void )
{
if ( _new_ic35dtime == 0 )
_new_ic35dtime = time( NULL );
return _new_ic35dtime;
}
/* new revised date+time to string for IC35
* ----------------------------------------
*/
void
get_newic35dt( char * dtbuf )
{
time_t ic35dt;
struct tm * ptm;
ic35dt = newic35dt();
ptm = localtime( &ic35dt );
strftime( dtbuf, 2+2+4+2+2+2+1, "%m%d%Y%H%M%S", ptm );
}
/* string from IC35 to old revised date+time
* -----------------------------------------
* the ugly format [mmddyyyyhhmmss] (instead of pretty [yyyymmddhhmmss])
* is used for reasons of compatibility with IC35sync/Windows.
* if sysinfo string from IC35 lacks plausible year,month,day, assume
* sysinfo was never written to IC35 and use old reference date+time
* far in the past.
*/
static time_t _old_ic35dtime; /* from IC35, reference for vCard */
void
set_oldic35dt( char * dtime )
{
struct tm ic35tm;
if ( dtime == NULL )
return;
memset( &ic35tm, 0, sizeof(ic35tm) );
sscanf( dtime, "%2d%2d%4d%2d%2d%2d",
&ic35tm.tm_mon, &ic35tm.tm_mday, &ic35tm.tm_year,
&ic35tm.tm_hour, &ic35tm.tm_min, &ic35tm.tm_sec );
if ( 1970 <= ic35tm.tm_year
&& 1 <= ic35tm.tm_mon && ic35tm.tm_mon <= 12
&& 1 <= ic35tm.tm_mday && ic35tm.tm_mday <= 31 ) {
ic35tm.tm_year -= 1900;
ic35tm.tm_mon -= 1;
ic35tm.tm_isdst = -1;
_old_ic35dtime = mktime( &ic35tm );
} else
_old_ic35dtime = 1;
}
time_t
oldic35dt( void )
{
return _old_ic35dtime;
}
/* ============================================ */
/* generic PIM access */
/* ============================================ */
/* set, get format of input/output file(s)
* ---------------------------------------
*/
static int pimfmt;
static int inpfmt;
static int
pimfmt2bin( char * format )
{
if ( format ) {
if ( strcmp( format, "txt" ) == 0 ) return PIM_TXT;
else if ( strcmp( format, "bin" ) == 0 ) return PIM_BIN;
else if ( strcmp( format, "vca" ) == 0 ) return PIM_VCA;
}
return 0;
}
int
set_pim_format( char * format )
{
int newfmt;
if ( (newfmt = pimfmt2bin( format )) <= 0 )
return ERR; /* unknown format */
pimfmt = inpfmt = newfmt;
return OK;
}
int
pim_format( void )
{
return pimfmt;
}
/*
* pim_open()
* pim_close()
* pim_rewind()
*
* pim_getrec( int fileid ) -> void* / NULL
* pim_getrec_byID( ulong recid ) -> void* / NULL
* pim_cmpic35rec( IC35REC*, void* ) -> 0:same 1:differ
* pim_putic35rec( IC35REC* ) IC35REC to PIMrec
* pim_updic35rec( IC35REC*, void* ) PIMrec to IC35REC
* pim_delrec( void* )
*
* pim_recid( void* )
* pim_set_recid( void*, ulong )
* pim_recstat( void* )
* pim_set_recstat( void*, int )
*/
/* dummy null operations
* ---------------------
*/
static struct pim_oper nul_oper = {
NULL, /* NO open */
NULL, /* NO close */
NULL, /* NO rewind */
NULL, /* NO getrec */
NULL, /* NO getrec_byID */
NULL, /* NO cmpic35rec */
NULL, /* NO updic35rec */
NULL, /* NO putic35rec */
NULL, /* NO delrec */
NULL, /* NO recid */
NULL, /* NO set_recid */
NULL, /* NO recstat */
NULL, /* NO set_recstat */
};
/* table of supported PIM-formats
* ------------------------------
*/
extern struct pim_oper txt_oper; /* text output IC35 record */
extern struct pim_oper bin_oper; /* binary IC35 record format */
extern struct pim_oper vca_oper; /* vCard,vCalendar format */
static struct pim_oper *pimop[] = {
&nul_oper,
&txt_oper,
&bin_oper,
&vca_oper
};
/* open, close, rewind output file(s)
* ----------------------------------
*/
int
pim_open( char * addrfname, char * vcalfname, char * memofname )
{
LPRINTF(( L_INFO, "pim_open(%s,%s,%s) pimfmt=%d (%s)",
addrfname ? addrfname : "NULL",
vcalfname ? vcalfname : "NULL",
memofname ? memofname : "NULL",
pimfmt, pimfmt == PIM_TXT ? "txt" :
pimfmt == PIM_BIN ? "bin" :
pimfmt == PIM_VCA ? "vca" : "unknown" ));
/*??? check file(s) creatable in dirname(a_xxxxfname) ???*/
if ( pimop[pimfmt]->open )
return (*pimop[pimfmt]->open)( "r+", addrfname, vcalfname, memofname );
return ERR;
}
int
pim_openinp( char * format, char * fname )
{
int ifmt;
if ( (ifmt = pimfmt2bin( format )) <= 0
|| pimop[ifmt]->open == NULL )
return ERR;
inpfmt = ifmt;
return (*pimop[inpfmt]->open)( "r", fname, NULL, NULL );
}
int
pim_openout( char * format, char * fname )
{
int ofmt;
if ( (ofmt = pimfmt2bin( format )) <= 0
|| pimop[ofmt]->open == NULL
|| !( fname && *fname ) )
return ERR;
pimfmt = ofmt;
/*??? check file creatable in dirname(fname) ???*/
remove( fname );
return (*pimop[pimfmt]->open)( "w", fname, NULL, NULL );
}
void
pim_close( void )
{
LPRINTF(( L_INFO, "pim_close: pimfmt=%d (%s) inpfmt=%d (%s)",
pimfmt, pimfmt == PIM_TXT ? "txt" :
pimfmt == PIM_BIN ? "bin" :
pimfmt == PIM_VCA ? "vca" : "unknown",
inpfmt, inpfmt == PIM_TXT ? "txt" :
inpfmt == PIM_BIN ? "bin" :
inpfmt == PIM_VCA ? "vca" : "unknown" ));
if ( pimop[pimfmt]->close ) /* write output file and .. */
(*pimop[pimfmt]->close)(); /* release output record list */
if ( inpfmt != pimfmt /* input format is different .. */
&& *pimop[inpfmt]->close ) /* release input record list */
(*pimop[inpfmt]->close)();
}
void
pim_rewind( void )
{
if ( pimop[inpfmt]->rewind )
(*pimop[inpfmt]->rewind)();
}
/* get next PIM-record for fileid
* ------------------------------
*/
void *
pim_getrec( int fileid )
{
if ( pimop[inpfmt]->getrec )
return (*pimop[inpfmt]->getrec)( fileid );
return NULL;
}
/* get PIM-record by rec-ID for fileid
* -----------------------------------
*/
void *
pim_getrec_byID( ulong recid )
{
if ( pimop[inpfmt]->getrec_byID )
return (*pimop[inpfmt]->getrec_byID)( recid );
return NULL;
}
/* update IC35 record with PIM record
* ----------------------------------
*/
IC35REC *
pim_updic35rec( IC35REC * ic35rec, void * pimrec )
{
if ( pimop[inpfmt]->updic35rec )
return (*pimop[inpfmt]->updic35rec)( ic35rec, pimrec );
return NULL;
}
/* compare IC35 record with vCard,vCal record
* ------------------------------------------
*/
int
pim_cmpic35rec( IC35REC * ic35rec, void * pimrec )
{
if ( pimop[pimfmt]->cmpic35rec )
return (*pimop[pimfmt]->cmpic35rec)( ic35rec, pimrec );
return -1;
}
/* put IC35-record to (new) PIM-record
* -----------------------------------
*/
void *
pim_putic35rec( IC35REC * ic35rec )
{
if ( pimop[pimfmt]->putic35rec )
return (*pimop[pimfmt]->putic35rec)( ic35rec );
return NULL;
}
void
pim_putrec( void * pimrec )
{
IC35REC * ic35rec;
if ( pimop[inpfmt]->updic35rec != NULL
&& pimop[pimfmt]->putic35rec != NULL
&& (ic35rec = new_ic35rec()) != NULL ) {
(*pimop[inpfmt]->updic35rec)( ic35rec, pimrec );
(*pimop[pimfmt]->putic35rec)( ic35rec );
del_ic35rec( ic35rec );
}
}
/* delete PIM-record
* -----------------
*/
void
pim_delrec( void * pimrec )
{
if ( pimop[pimfmt]->delrec )
(*pimop[pimfmt]->delrec)( pimrec );
}
/* get,set IC35-record-ID
* ----------------------
*/
ulong
pim_recid( void * pimrec )
{
if ( pimop[pimfmt]->recid )
return (*pimop[pimfmt]->recid)( pimrec );
return 0;
}
void
pim_set_recid( void * pimrec, ulong recid )
{
if ( pimop[pimfmt]->set_recid )
(*pimop[pimfmt]->set_recid)( pimrec, recid );
}
/* get,set record-changeflag
* -------------------------
*/
int
pim_recstat( void * pimrec )
{
if ( pimop[pimfmt]->recstat )
return (*pimop[pimfmt]->recstat)( pimrec );
return PIM_DIRTY;
}
void
pim_set_recstat( void * pimrec, int stat )
{
if ( pimop[pimfmt]->set_recstat )
(*pimop[pimfmt]->set_recstat)( pimrec, stat );
}

77
src/dataio.h Normal file
View File

@ -0,0 +1,77 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* *
* $Id: dataio.h,v 1.12 2000/12/26 01:25:22 tsch Rel $ *
* *
* header for IC35 data import/export *
* *
************************************************************************/
#ifndef _DATAIO_H
#define _DATAIO_H 1
#include <stdio.h> /* FILE */
#include <sys/types.h> /* size_t */
#include "vcc.h" /* VObject, .. */
#include "ic35frec.h" /* IC35REC */
#include "util.h" /* uchar, .. */
/* PIM file format ids */
#define PIM_TXT 1 /* plain text */
#define PIM_BIN 2 /* raw binary data */
#define PIM_VCA 3 /* vCard,vCalendar,Memo */
/* PIM record status */
#define PIM_CLEAN 0
#define PIM_DIRTY 1
#define PIM_DEL 3
struct pim_oper { /* table of record format specific functions */
int (*open)( char *, char *, char *, char * );
void (*close)( void );
void (*rewind)( void );
void * (*getrec)( int );
void * (*getrec_byID)( ulong );
int (*cmpic35rec)( IC35REC *, void * ); /* IC35 == PIM */
IC35REC * (*updic35rec)( IC35REC *, void * ); /* IC35 <- PIM */
void * (*putic35rec)( IC35REC * ); /* IC35 -> PIM */
void (*delrec)( void * );
ulong (*recid)( void * );
void (*set_recid)( void *, ulong );
int (*recstat)( void * );
void (*set_recstat)( void *, int );
};
FILE * backup_and_openwr( char * fname );
int set_pim_format( char * format );
int pim_format( void );
void clr_newic35dt( void );
void get_newic35dt( char * dtbuf );
time_t newic35dt( void );
void set_oldic35dt( char * dtime );
time_t oldic35dt( void );
int pim_open( char * addrfname, char * vcalfname, char * memofname );
int pim_openinp( char * format, char * fname );
int pim_openout( char * format, char * fname );
void pim_close( void );
void pim_rewind( void );
void * pim_getrec( int fileid );
void * pim_getrec_byID( ulong recid );
void * pim_putic35rec( IC35REC * ic35rec );
IC35REC * pim_updic35rec( IC35REC * ic35rec, void * pimrec );
int pim_cmpic35rec( IC35REC * ic35rec, void * pimrec );
void pim_putrec( void * pimrec );
void pim_delrec( void * pimrec );
ulong pim_recid( void * pimrec );
void pim_set_recid( void * pimrec, ulong recid );
int pim_recstat( void * pimrec );
void pim_set_recstat( void * pimrec, int stat );
#endif /*_DATAIO_H*/

113
src/datatxt.c Normal file
View File

@ -0,0 +1,113 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* */
static char rcsid[] =
"$Id: datatxt.c,v 1.32 2000/12/26 01:36:32 tsch Rel $"; /*
* *
* IC35 synchronize data import/export: text format output *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
************************************************************************/
#include <stdio.h> /* fprintf(), .. */
#include <ctype.h> /* isprint(), .. */
#include <sys/types.h> /* size_t, .. */
#include "util.h" /* ERR, uchar, .. */
#include "ic35frec.h" /* IC35 record fields.. */
#include "dataio.h" /* struct pim_oper */
NOTUSED(rcsid);
/* open, close text file
* ---------------------
*/
static FILE * outfp;
static int
txt_open( char * mode, char * addrfname, char * vcalfname, char * memofname )
{
if ( !(mode[0] == 'w' || mode[1] == '+')
|| (outfp = backup_and_openwr( addrfname )) == NULL )
return ERR;
return OK;
}
static void
txt_close( void )
{
if ( outfp && outfp != stdout )
fclose( outfp );
outfp = NULL;
}
/* output IC35 record as text
* --------------------------
*/
static IC35REC *
txt_putic35rec( IC35REC * rec )
{
static int lastfileid = -1;
static int idx;
int fileid;
int fi, i;
uchar * fld;
size_t len;
fileid = FileId( ic35recid( rec ) );
if ( ic35fname( fileid ) == NULL )
return NULL; /* unknown file id */
if ( fileid != lastfileid ) { /* first/next IC35 file */
fprintf( outfp, "\nFile \"%s\"\n", ic35fname( fileid ) );
lastfileid = fileid;
idx = 0; /* reset record index */
} else { /* same IC35 file */
++idx; /* increment rec.index */
}
get_ic35recdata( rec, NULL, &len );
fprintf(outfp,"File \"%s\" Record %3d IC35id=%08lX cflag=%02X length=%d\n",
ic35fname(fileid), idx, ic35recid(rec), ic35recchg(rec), len);
for ( fi = 0; fi < ic35fnflds( fileid ); ++fi ) {
get_ic35recfld( rec, FILEfld(fileid,fi), &fld, &len );
fprintf( outfp, "f%d(%d)\t", fi, len );
if ( len != 0 ) {
fprintf( outfp, "\"" );
for ( i = 0; i < len; ++i ) {
if ( isprint( fld[i] ) )
fprintf( outfp, "%c", fld[i] );
else
fprintf( outfp, "\\x%02X", (uchar)fld[i] );
if ( 0 < i && i < len - 1
&& fld[i-1] == '\r' && fld[i] == '\n' )
fprintf( outfp, "\"\n\t\"" );
}
fprintf( outfp, "\"\n" );
} else {
fprintf( outfp, "<EMPTY>\n" );
}
}
return rec;
}
/* text format operations
* ----------------------
*/
struct pim_oper txt_oper = {
txt_open,
txt_close,
NULL, /* NO rewind */
NULL, /* NO getrec */
NULL, /* NO getrec_byID */
NULL, /* NO cmpic35rec */
NULL, /* NO updic35rec */
(void*(*)(IC35REC*))txt_putic35rec,
NULL, /* NO delrec */
NULL, /* NO recid */
NULL, /* NO set_recid */
NULL, /* NO recstat */
NULL, /* NO set_recstat */
};

1355
src/datavca.c Normal file

File diff suppressed because it is too large Load Diff

199
src/genproto.c Normal file
View File

@ -0,0 +1,199 @@
/************************************************************************
* Copyright (C) 2001 Thomas Schulz *
* */
static char rcsid[] =
"$Id: genproto.c,v 1.2 2001/01/21 19:54:52 tsch Rel $"; /*
* *
* general IC35 protocol support *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
* utilities for PDU encode/decode *
* putbyte encode one byte *
* putword encode 2byte-word *
* putdword encode 4byte-doubleword *
* putbtxt encode binary text *
* puttext encode text string *
* puttxt0 encode text string plus trailing NUL-byte *
* getbyte decode one byte *
* getword decode 2byte-word *
* getdword decode 4byte-doubleword *
* getbtxt decode binary text *
* gettext decode text string *
* chksum calculate arithmetic checksum *
* general communication *
* welcome initial welcome handshake *
* *
************************************************************************/
#include <string.h> /* memcpy(), .. */
#include <unistd.h> /* usleep() */
#include <signal.h> /* SIG_INT, signal() */
#include "util.h" /* ERR,OK, uchar, .. */
#include "comio.h" /* com_send(), .. */
#include "genproto.h"
NOTUSED(rcsid)
/* ============================================ */
/* utilities for PDU encode/decode */
/* ============================================ */
/* encode data items to PDU
* ------------------------
*/
void
putbyte( uchar * pduptr, uchar byte )
{
*pduptr = byte;
}
void
putword( uchar * pduptr, ushort word )
{
putbyte( pduptr+0, word & 0x00FF ); /* LSB first .. */
putbyte( pduptr+1, (word & 0xFF00) >> 8 ); /* .. then MSB */
}
void
putdword( uchar * pduptr, ulong dword )
{
putword( pduptr+0, dword & 0x0000FFFF );
putword( pduptr+2, (dword & 0xFFFF0000) >> 16 );
}
void
putbtxt( uchar * pduptr, uchar * text, size_t tlen )
{
memcpy( pduptr, text, tlen );
}
void
puttext( uchar * pduptr, char * text )
{
putbtxt( pduptr, text, strlen( text ) );
}
void
puttxt0( uchar * pduptr, char * text )
{
size_t len;
putbtxt( pduptr, text, len = strlen( text ) );
pduptr[len] = '\0';
}
/* decode data items from PDU
* --------------------------
*/
uchar
getbyte( uchar * pduptr )
{
return *pduptr;
}
ushort
getword( uchar * pduptr )
{
return (getbyte( pduptr+1 ) << 8) | getbyte( pduptr+0 );
}
ulong
getdword( uchar * pduptr )
{
return (getword( pduptr+2 ) << 16) | getword( pduptr+0 );
}
void
getbtxt( uchar * pduptr, uchar * text, size_t tlen )
{
memcpy( text, pduptr, tlen );
}
void
gettext( uchar * pduptr, char * text, size_t tlen )
{
getbtxt( pduptr, text, tlen );
text[tlen] = '\0';
}
/* calculate arithmetic checksum
* -----------------------------
*/
ushort
chksum( uchar * data, size_t dlen )
{
ushort checksum;
size_t i;
for ( checksum = 0x0000, i = 0; i < dlen; ++i )
checksum += data[i];
return checksum;
}
/* ==================================== */
/* general communication */
/* ==================================== */
/* welcome handshake
* -----------------
* send 'cmd' every 1.15 sec until "WELCOME" received
* send 'cmd', wait for '\x80'
* command byte 'cmd' is for:
* - synchronize protocol '\x41'='A'
* - manager protocol '\x40'='@'
*/
#define WELCOME_TIMEOUT 1150
#define WELCOME_RETRY 20
#define RSP_READY (uchar)0x80
#define GOT_NONE 0
#define GOT_WELCOME 1
#define GOT_READY 2
static int hadsignal;
static void
_sig_hdlr( int signum )
{
hadsignal = signum;
}
int
welcome( uchar cmd )
{
char * welcome = "WELCOME";
int old_tmo;
int retry, rlen;
int state;
uchar rbuff[7];
hadsignal = 0;
signal( SIGINT, _sig_hdlr );
old_tmo = com_settimeout( WELCOME_TIMEOUT );
for ( retry = 0, state = GOT_NONE;
retry < WELCOME_RETRY && state != GOT_READY && hadsignal == 0;
++retry ) {
com_send( &cmd, 1 );
switch ( state ) {
case GOT_NONE:
rlen = com_recv( rbuff, sizeof(rbuff) );
if ( rlen < strlen(welcome) /* receive error / timeout */
|| memcmp( rbuff, welcome, strlen(welcome) ) != 0 )
continue; /* not enough or miss "WELCOME" */
state = GOT_WELCOME;
continue;
case GOT_WELCOME:
rlen = com_recv( rbuff, 1 );
if ( rlen < 1 /* receive error / timeout */
|| rbuff[0] != RSP_READY )
continue; /* missing RSP_READY */
state = GOT_READY;
break;
}
break;
}
signal( SIGINT, SIG_DFL );
com_settimeout( old_tmo );
if ( hadsignal )
return ERR_intr;
if ( state != GOT_READY )
return ERR;
usleep( 50000 ); /* give IC35 50ms to get ready */
return OK;
}

39
src/genproto.h Normal file
View File

@ -0,0 +1,39 @@
/************************************************************************
* Copyright (C) 2001 Thomas Schulz *
* *
* $Id: genproto.h,v 1.2 2001/01/21 23:38:37 tsch Rel $ *
* *
* header for general IC35 protocol support *
* *
************************************************************************/
#ifndef _GENPROTO_H
#define _GENPROTO_H 1
#include "util.h" /* ushort, .. */
/* communication error codes */
#define ERR_intr -2 /* user interrupt with Ctl-C */
#define ERR_recv -3 /* receive error */
#define ERR_chksum -4 /* block checksum mismatch */
#define ERR_acknak -5 /* ack/nak handshake failed */
void putbyte( uchar * pduptr, uchar byte );
void putword( uchar * pduptr, ushort word );
void putdword( uchar * pduptr, ulong dword );
void putbtxt( uchar * pduptr, uchar * text, size_t tlen );
void puttext( uchar * pduptr, char * text );
void puttxt0( uchar * pduptr, char * text );
uchar getbyte( uchar * pduptr );
ushort getword( uchar * pduptr );
ulong getdword( uchar * pduptr );
void getbtxt( uchar * pduptr, uchar * text, size_t tlen );
void gettext( uchar * pduptr, char * text, size_t tlen );
ushort chksum( uchar * data, size_t dlen );
int welcome( uchar cmd );
#endif /*_GENPROTO_H*/

384
src/ic35frec.c Normal file
View File

@ -0,0 +1,384 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* */
static char rcsid[] =
"$Id: ic35frec.c,v 1.8 2001/03/02 02:09:59 tsch Rel $"; /*
* *
* IC35 record access *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
************************************************************************/
#include <stdlib.h> /* calloc(), .. */
#include <string.h> /* strcmp(), .. */
#include "util.h" /* ERR,OK, uchar, .. */
#include "ic35frec.h"
NOTUSED(rcsid);
struct ic35file { /* IC35 file description */
int id; /* id on IC35 */
int nfld; /* number of fields in record */
char * name; /* filename */
};
struct ic35rec { /* internal IC35 record for field access */
ulong id; /* record-id on IC35: recid[3],fileid[1]*/
uchar chg; /* change-flag on IC35 */
size_t dlen; /* length of IC35 record data buffer */
uchar * data; /* record data buffer: flens, fdata */
int nflds; /* number of fields in record */
struct {
size_t len; /* length of field */
uchar * ptr; /* pointer to field data */
} flds[MAXFLDS]; /* vector of record fields */
size_t fblen; /* length of field data buffer */
uchar * fbuff; /* field data buffer */
};
/* lookup IC35 fileid
* ------------------
*/
static struct ic35file ic35files[] = {
{ FILEADDR, 21, "Addresses" },
{ FILEMEMO, 4, "Memo" },
{ FILESCHED, 10, "Schedule" },
{ FILETODO, 8, "To Do List" },
{ 0, 0, NULL }
};
static struct ic35file *
_ic35fdesc( int fileid )
{
struct ic35file * pfile;
for ( pfile = ic35files; pfile->name != NULL; ++pfile )
if ( pfile->id == fileid )
return pfile;
return NULL;
}
/* get number of record fields acc.to file-id
* ------------------------------------------
*/
int
ic35fnflds( int fileid )
{
struct ic35file * pfile;
pfile = _ic35fdesc( fileid );
if ( pfile == NULL ) /* unknown file id */
return 0;
return pfile->nfld;
}
static int
_nrecflds( int fldid )
{
int nflds;
if ( (nflds = ic35fnflds( FldFile(fldid) )) == 0 /* unkwown file id */
|| FldIdx(fldid) >= nflds /* bad field index */
|| FldIdx(fldid) >= alenof(((IC35REC*)0)->flds) )
return 0;
return nflds;
}
/* get filename acc.to file-id
* ---------------------------
*/
char *
ic35fname( int fileid )
{
struct ic35file * pfile;
pfile = _ic35fdesc( fileid );
if ( pfile == NULL ) /* unknown file id */
return NULL;
return pfile->name;
}
/* constructur: create new IC35 record
* -----------------------------------
*/
IC35REC *
new_ic35rec( void )
{
return calloc( 1, sizeof(IC35REC) );
}
/* destructor: delete IC35 record
* ------------------------------
*/
static void
_del_ic35recbuffs( IC35REC * rec )
{
int fi;
for ( fi = 0; fi < alenof(rec->flds); ++fi ) {
if ( !( rec->fbuff <= rec->flds[fi].ptr
&& rec->flds[fi].ptr < rec->fbuff+rec->fblen ) )
free( rec->flds[fi].ptr );
rec->flds[fi].ptr = NULL;
rec->flds[fi].len = 0;
}
rec->nflds = 0;
if ( rec->fbuff != NULL ) {
free( rec->fbuff );
rec->fbuff = NULL;
rec->fblen = 0;
}
if ( rec->data != NULL ) {
free( rec->data );
rec->data = NULL;
rec->dlen = 0;
}
}
void
del_ic35rec( IC35REC * rec )
{
_del_ic35recbuffs( rec );
free( rec );
}
/* set,get special field in IC35 record
* ------------------------------------
*/
void
set_ic35recid( IC35REC * rec, ulong recid )
{
int nflds;
rec->id = recid;
if ( (nflds = ic35fnflds( FileId(recid) )) != 0 )
rec->nflds = nflds;
}
ulong
ic35recid( IC35REC * rec )
{
return rec->id;
}
void
set_ic35recchg( IC35REC * rec, uchar chgflag )
{
rec->chg = chgflag;
}
uchar
ic35recchg( IC35REC * rec )
{
return rec->chg;
}
/* set,get IC35 record raw data
* ----------------------------
*/
void
set_ic35recdata( IC35REC * rec, uchar * data, size_t dlen )
{
uchar * fptr;
uchar * fbptr;
int fi;
size_t nflds, flensum;
_del_ic35recbuffs( rec );
if ( data == NULL || dlen == 0 )
return;
if ( (rec->data = malloc( dlen )) == NULL )
return;
memcpy( rec->data, data, rec->dlen = dlen );
memset( rec->flds, 0, sizeof(rec->flds) );
for ( nflds = flensum = 0; nflds < alenof(rec->flds); ++nflds ) {
flensum += rec->data[nflds] + 1;
if ( flensum > dlen )
break;
}
if ( (rec->fbuff = malloc( dlen )) == NULL )
return;
rec->fblen = dlen;
rec->nflds = nflds;
fbptr = rec->fbuff;
fptr = rec->data + nflds;
for ( fi = 0; fi < nflds; ++fi ) {
rec->flds[fi].len = rec->data[fi];
rec->flds[fi].ptr = fbptr;
memcpy( rec->flds[fi].ptr, fptr, rec->flds[fi].len );
fbptr += rec->flds[fi].len;
*fbptr++ = '\0'; /* append end-of-string */
fptr += rec->data[fi];
}
}
void
get_ic35recdata( IC35REC * rec, uchar ** pdata, size_t * pdlen )
{
uchar * fptr;
int fi;
size_t dlen;
if ( rec->data == NULL ) { /* rebuild record data */
for ( fi = 0, dlen = 0; fi < rec->nflds; ++fi )
dlen += rec->flds[fi].len + 1;
if ( (rec->data = malloc( dlen )) != NULL ) {
rec->dlen = dlen;
fptr = rec->data + rec->nflds;
for ( fi = 0; fi < rec->nflds; ++fi ) {
if ( rec->flds[fi].ptr != NULL )
memcpy( fptr, rec->flds[fi].ptr, rec->flds[fi].len );
else
rec->flds[fi].len = 0;
fptr += (rec->data[fi] = rec->flds[fi].len);
}
}
}
if ( pdata )
*pdata = rec->data;
if ( pdlen )
*pdlen = rec->dlen;
}
/* set,get string field from IC35 record
* -------------------------------------
*/
void
set_ic35recfld( IC35REC * rec, int fldid, char * data )
{
int fi, nflds;
size_t flen;
char * fbuff;
if ( (nflds = _nrecflds( fldid )) <= 0 )
return; /* bad field id */
if ( rec->nflds == 0 )
rec->nflds = nflds;
if ( (fi = FldIdx(fldid)) >= rec->nflds )
return;
if ( data == NULL )
data = "";
switch ( fldid ) {
case A_CategoryID:
case S_AlarmBefore:
case S_Alarm_Repeat:
case S_RepCount:
case T_Completed:
case T_Priority:
case T_CategoryID:
case M_CategoryID: /* 1-byte binary fields */
flen = 1;
break;
default:
flen = strlen( data );
}
if ( flen > 255 ) flen = 255; /* truncate to max.field length */
if ( flen > rec->flds[fi].len ) { /* new field bigger old content */
if ( (fbuff = malloc( flen + 1 )) == NULL )
return; /* no memory */
if ( !( rec->fbuff <= rec->flds[fi].ptr
&& rec->flds[fi].ptr < rec->fbuff+rec->fblen ) )
free( rec->flds[fi].ptr ); /* old field outside buffer */
rec->flds[fi].ptr = fbuff;
}
if ( flen ) {
memcpy( rec->flds[fi].ptr, data, flen );
rec->flds[fi].ptr[flen] = '\0';
}
rec->flds[fi].len = flen;
if ( rec->data != NULL ) {
free( rec->data );
rec->data = NULL; /* record data must be rebuilt */
rec->dlen = 0;
}
}
void
get_ic35recfld( IC35REC * rec, int fldid, uchar ** pfld, size_t * plen )
{
if ( _nrecflds( fldid ) <= 0 /* bad field id */
|| rec->flds[FldIdx(fldid)].ptr == NULL ) { /* empty field */
if ( pfld ) *pfld = "";
if ( plen ) *plen = 0;
} else {
if ( pfld ) *pfld = rec->flds[FldIdx(fldid)].ptr;
if ( plen ) *plen = rec->flds[FldIdx(fldid)].len;
}
}
char *
ic35recfld( IC35REC * rec, int fldid )
{
uchar * fld;
get_ic35recfld( rec, fldid, &fld, NULL );
return fld;
}
/* compare 2 IC35 records
* ----------------------
* records are compared field by field, because some fields need
* special handling, i.e. difference ignored.
* returns
* 0 both IC35 records are (regarded) same
* 1 IC35 records differ
* -1 IC35 records differ strangely:
* either one is NULL or fileids mismatch
*/
int
cmp_ic35rec( IC35REC * rec1, IC35REC * rec2 )
{
int fileid;
int fi, nflds, fldid;
uchar * ic35fld;
uchar * binfld;
char ic35tfld[6+1];
if ( rec1 == NULL && rec2 == NULL )
return 0;
if ( rec1 == NULL || rec2 == NULL )
return -1;
if ( (fileid = FileId( ic35recid( rec1 ) ))
!= FileId( ic35recid( rec2 ) ) )
return -1;
nflds = ic35fnflds( fileid );
for ( fi = 0; fi < nflds; ++fi ) {
fldid = FILEfld(fileid,fi);
ic35fld = ic35recfld( rec1, fldid );
binfld = ic35recfld( rec2, fldid );
if ( strcmp( binfld, ic35fld ) == 0 )
continue;
switch ( fldid ) {
case A_CategoryID:
case M_CategoryID:
case T_CategoryID:
continue; /* ignore category-ID difference */
case S_StartTime:
case S_EndTime:
ic35fld = strncat( strcpy( ic35tfld, "" ),
ic35fld, sizeof(ic35tfld)-1 );
if ( ( fldid == S_StartTime && ic35fld[4] == ':' )
|| ( fldid == S_EndTime && ic35fld[4] == '<' ) )
ic35fld[4] = ic35fld[5] = '0';
if ( strcmp( ic35fld, binfld ) == 0 )
continue; /* ignore strange IC35 Start/EndTime */
break;
case S_RepEndDate:
case S_RepCount:
if ( (*ic35recfld( rec2, S_Alarm_Repeat ) & RepeatMASK) == 0 )
continue; /* ignore difference if not repeat */
break;
case S_Alarm_Repeat:
if ( ((*binfld ^ *ic35fld) & ~(AlarmNoLED|AlarmNoBeep)) == 0
&& *ic35recfld( rec2, S_AlarmBefore ) == AlarmBefNone )
continue; /* ignore LED,Beep diff if no alarm */
break;
}
LPRINTF(( L_DEBUG, "cmp_ic35rec: rid=%08lX fi=%d diff",
ic35recid(rec1), fi ));
LDUMP(( L_DEBUG, binfld, strlen(binfld),
"cmp_ic35rec: rec2 len=%d", strlen(binfld) ));
LDUMP(( L_DEBUG, ic35fld, strlen(ic35fld),
"cmp_ic35rec: rec1 len=%d", strlen(ic35fld) ));
return 1;
}
return 0;
}

138
src/ic35frec.h Normal file
View File

@ -0,0 +1,138 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* *
* $Id: ic35frec.h,v 1.5 2000/12/23 01:09:26 tsch Rel $ *
* *
* header for IC35 record access *
* *
************************************************************************/
#ifndef _IC35REC_H
#define _IC35REC_H 1
#include "util.h" /* uchar, .. */
/* IC35 database files */
#define FILEADDR 0x05
#define FILEMEMO 0x06
#define FILETODO 0x07
#define FILESCHED 0x08
#define FILE_ANY 0
#define MAXFLDS 21 /* max.number of fields in IC35 record */
#define MAXRLEN (MAXFLDS * (1+255)) /* #fields [Addresses] * (len + fieldlen) */
/* record-ids consist of file-id and record-id */
#define FileId(frid) ( ((ulong)(frid) & 0xFF000000) >> 24 )
#define RecId(frid) ( ((ulong)(frid) & 0x00FFFFFF) )
#define FileRecId(fid,rid) ( (((ulong)(fid) << 24) & 0xFF000000) \
| ( (ulong)(rid) & 0x00FFFFFF) )
/* field-ids consist of file-id and field-index */
#define FldFile(fldid) ( ((fldid) & 0xFF00) >> 8 )
#define FldIdx(fldid) ( (fldid) & 0x00FF )
/* IC35 record fields */
#define FILEfld(fileid,index) ( (fileid)<<8 | (index) )
/* record fields "Addresses" */
#define ADDRfld(index) FILEfld( FILEADDR, index )
#define A_LastName ADDRfld( 0 ) /* max. 50 chars */
#define A_FirstName ADDRfld( 1 ) /* max. 50 chars */
#define A_Company ADDRfld( 2 ) /* max. 128 chars */
#define A_TelHome ADDRfld( 3 ) /* max. 48 chars */
#define A_TelWork ADDRfld( 4 ) /* max. 48 chars */
#define A_TelMobile ADDRfld( 5 ) /* max. 48 chars */
#define A_TelFax ADDRfld( 6 ) /* max. 48 chars */
#define A_Street ADDRfld( 7 ) /* max. 128 chars */
#define A_City ADDRfld( 8 ) /* max. 60 chars */
#define A_ZIP ADDRfld( 9 ) /* max. 10 chars */
#define A_Region ADDRfld( 10 ) /* max. 40 chars */
#define A_Country ADDRfld( 11 ) /* max. 15 chars */
#define A_Email1 ADDRfld( 12 ) /* max. 80 chars */
#define A_Email2 ADDRfld( 13 ) /* max. 80 chars */
#define A_URL ADDRfld( 14 ) /* max. 128 chars */
#define A_BirthDate ADDRfld( 15 ) /* max. 10 chars */
#define A_Notes ADDRfld( 16 ) /* max. 255 chars */
#define A_CategoryID ADDRfld( 17 ) /* 1 Byte */
#define A_Def1 ADDRfld( 18 ) /* max. 128 chars */
#define A_Def2 ADDRfld( 19 ) /* max. 128 chars */
#define A_Category ADDRfld( 20 ) /* max. 8 chars */
/* record fields "Schedule" */
#define SCHEDfld(index) FILEfld( FILESCHED, index )
#define S_Subject SCHEDfld( 0 ) /* max. 60 chars */
#define S_StartDate SCHEDfld( 1 ) /* 8 yyyymmdd */
#define S_StartTime SCHEDfld( 2 ) /* 6 hhmmss */
#define S_EndTime SCHEDfld( 3 ) /* 6 hhmmss */
#define S_AlarmBefore SCHEDfld( 4 ) /* 1 Byte */
#define AlarmBefNone 0x00
#define AlarmBefNow 0x01
#define AlarmBef1min 0x02
#define AlarmBef5min 0x03
#define AlarmBef10min 0x04
#define AlarmBef30min 0x05
#define AlarmBef1hour 0x06
#define AlarmBef2hour 0x07
#define AlarmBef10hour 0x08
#define AlarmBef1day 0x09
#define AlarmBef2day 0x0A
#define S_Notes SCHEDfld( 5 ) /* max. 255 chars */
#define S_Alarm_Repeat SCHEDfld( 6 ) /* 1 Byte */
#define AlarmNoLED 0x80
#define AlarmNoBeep 0x40
#define RepeatMASK 0x0F
#define RepeatNone 0x00
#define RepeatDay 0x01
#define RepeatWeek 0x02
#define RepeatMonWday 0x03
#define RepeatYear 0x04
#define RepeatMonMday 0x05
#define S_EndDate SCHEDfld( 7 ) /* 8 yyyymmdd */
#define S_RepEndDate SCHEDfld( 8 ) /* 6 hhmmss */
#define S_RepCount SCHEDfld( 9 ) /* 1 Byte */
/* record fields "To Do List" */
#define TODOfld(index) FILEfld( FILETODO, index )
#define T_StartDate TODOfld( 0 ) /* 8 yyyymmdd */
#define T_EndDate TODOfld( 1 ) /* 8 yyyymmdd */
#define T_Completed TODOfld( 2 ) /* 1 Byte */
#define T_Priority TODOfld( 3 ) /* 1 Byte */
#define T_Subject TODOfld( 4 ) /* max. 60 chars */
#define T_Notes TODOfld( 5 ) /* max. 255 chars */
#define T_CategoryID TODOfld( 6 ) /* 1 Byte */
#define T_Category TODOfld( 7 ) /* max. 8 chars */
/* record fields "Memo" */
#define MEMOfld(index) FILEfld( FILEMEMO, index )
#define M_Subject MEMOfld( 0 ) /* max. 60 chars */
#define M_Notes MEMOfld( 1 ) /* max. 255 chars */
#define M_CategoryID MEMOfld( 2 ) /* 1 Byte */
#define M_Category MEMOfld( 3 ) /* max. 8 chars */
/* IC35 record change flags */
#define IC35_NEW 0x80 /* new record */
#define IC35_MOD 0x40 /* modified */
#define IC35_DEL 0x20 /* deleted (no record data) */
#define IC35_CLEAN 0x00 /* unchanged */
typedef struct ic35rec IC35REC;
char * ic35fname( int fileid );
int ic35fnflds( int fileid );
IC35REC * new_ic35rec( void );
void del_ic35rec( IC35REC * rec );
void set_ic35recid( IC35REC * rec, ulong recid );
ulong ic35recid( IC35REC * rec );
void set_ic35recchg( IC35REC * rec, uchar chgflag );
uchar ic35recchg( IC35REC * rec );
void set_ic35recdata( IC35REC * rec, uchar * data, size_t dlen );
void get_ic35recdata( IC35REC * rec, uchar ** pdata, size_t * pdlen );
void set_ic35recfld( IC35REC * rec, int fldid, char * data );
void get_ic35recfld( IC35REC * rec, int fldid, uchar** pfld, size_t * plen );
char * ic35recfld( IC35REC * rec, int fldid );
int cmp_ic35rec( IC35REC * rec1, IC35REC * rec2 );
#endif /*_IC35REC_H*/

807
src/ic35log.sh Normal file
View File

@ -0,0 +1,807 @@
#!/bin/sh
#
# $Id: ic35log.sh,v 1.6 2001/01/14 00:09:46 tsch Rel $
#
# process logs of IC35 communication
#
# setup parameters and defaults
PAGER="less -S"
PROGNAME=`basename $0`
TMPDIR=/tmp/dpkgmirr$$
usage()
{
echo "\
usage: $PROGNAME [options] [tarfile] logfile
process IC35 communication 'logfile', which may be gzip'd or contained
in optionally gzip'd 'tarfile'. options:
-l level level of output:
all show all communication (default)
syn2 suppress Level-1 of IC35sync protocol
syn4 decode Level-4 of IC35sync protocol
-s n prepend output with 1:linenumber 2:timestamp
-a show communication also as ASCII characters
-D debug/detail: output diagnostic data \
"
exit 2
}
# add ASCII chars to hex_logfile
#
showascii() # <hex_logfile >hex_ascii_logfile
{
awk '
BEGIN {
# create table chr[] for hex to char conversion
ascii = ascii " !\"#$%&\047()*+,-./"
ascii = ascii "0123456789:;<=>?"
ascii = ascii "@ABCDEFGHIJKLMNO"
ascii = ascii "PQRSTUVWXYZ[\\]^_"
ascii = ascii "`abcdefghijklmno"
ascii = ascii "pqrstuvwxyz{|}~"
for ( c = 0; c <= 255; ++c )
if ( 32 <= c && c <= 126 ) # 32=space 126=tilda
chr[ sprintf("%02X", c) ] = substr( ascii, c - 32+1, 1 )
else
chr[ sprintf("%02X", c) ] = "."
}
/WRx/ || /RDx/ {
if ( $1 == "WRx" || $1 == "RDx" ) {
if ( $1 == "WRx" ) dir = "WRa"
else dir = "RDa"
beghex = 3
} else {
if ( $2 == "WRx" ) dir = "WRa"
else dir = "RDa"
beghex = 4
}
ascblk = chr[$(beghex)]
for ( i = beghex+1; i <= NF; ++i )
ascblk = ascblk " " chr[$i]
print
if ( beghex == 3 )
printf( "%s %2d\t %s\n", dir, $2, ascblk )
else
printf( "%s %s %2d\t %s\n", $1, dir, $3, ascblk )
}' -
}
# convert 'portmon' logfile
# expects 'portmon' logfiles in Unix-format i.e. NL terminated lines
# (DOS-format CRLF terminated lines may break the awk script)
# for 'portmon' see http://www.sysinternals.com
#
ic35prot() # [-vskip=3] [-vDEBUG=1] <portmon_logfile >hex_logfile
{
awk $* '
# parameters
# skip number of leading bytes to skip from transmitted blocks
# blocks up to this much bytes are not printed, default 0
# stamp if non-zero/non-empty stamp transmit blocks with id (first
# field) from portmon log, to ease finding portmon log lines
# default: 0 / "" (disabled)
# MAXBPL maximum number of bytes to print per output line
# default: 128
# DEBUG if non-zero/non-empty print verbose debugging output
# default: 0 / "" (disabled)
# extract transmitted data bytes
# returns:
# -1 no data bytes: miss "Length" field
# 0 no data bytes: length value == 0
# > 0 length value
# xdlen number of logged bytes, maybe < length value
# xdata logged transmitted data bytes
#
function getxdata()
{
xlen = 0
xdata = ""
# search "Length" field
for ( i = 1; i <= NF; ++i )
if ( $i ~ "^Length" )
break
if ( i > NF ) { # "Length" field not found
# check if log from "ic35sync"
for ( i = 1; i <= NF; ++i )
if ( $i ~ "^[0-9A-F][0-9A-F][0-9A-F][0-9A-F]:$" )
break;
if ( i > NF )
return -1
# process log from "ic35sync"
xdata = ""
for ( i = i+1; i <= NF; ++i ) {
if ( $i !~ "^[0-9A-F][0-9A-F]$" )
break;
xdata = xdata $i " "
if ( --hadxmit == 0 )
break;
}
xdlen = length( xdata ) / 3
return xdlen
}
# get length value from next field, remove trail ":"
split( $(i+1), flds, ":" )
len = int( flds[1] )
if ( len == 0 )
return 0 # no data transmitted
# extract get data bytes after "Length" and <nn:>
lentxt = $(i) " " $(i+1)
xdata = substr( $0, index($0, lentxt) + length(lentxt)+1 )
# make string of 2dig-hex with trail " " for append
sub( "^[^0-9A-Fa-f]*", "", xdata ); # remove leading garbage
sub( "[^0-9A-Fa-f]*$", "", xdata ); # remove trailing garbage
xdata = xdata " "
xdlen = length( xdata ) / 3
# return length value, maybe not all bytes logged
return len
}
function prxdata( dir, xbuf, xlen,
_offs, _i, _hex, _pbuf, _plen )
{
if ( xlen <= skip )
return
_plen = length( xbuf )
_offs = skip * 3
if ( skip >= 3 )
_plen = length( xbuf ) - _offs - 2 * 3 # skip checksum also
printf( "%s%sx %2d\t%s\n", xstamp, dir, xlen, substr(xbuf,_offs,_plen) )
}
BEGIN {
# max.number of bytes per output line
if ( ! MAXBPL ) MAXBPL = 128
}
NF >= 2 {
if ( $2 == "ic35sync" || $2 == "ic35mgr" )
tsecs = $1
else
tsecs += $2
}
# Windows-98:
# 35 0.00034960 Ic35 syn VCOMM_ReadComm COM1 SUCCESS Length: 1: 57
/VCOMM_ReadComm/ && /SUCCESS/ {
if ( oldxdir == "WR" ) do_print = 1
xdir = "RD"
if ( DEBUG ) print "DBG: xdir=" xdir, $0
}
# 36 0.00005040 Ic35 syn VCOMM_GetCommQueueStatus COM1 SUCCESS RX: 6 TX: 0
/VCOMM_GetCommQueueStatus/ {
if ( DEBUG ) print "DBG: next ", $0
next
}
# 58 0.00063840 Ic35 syn VCOMM_WriteComm COM1 SUCCESS Length: 1: 41
/VCOMM_WriteComm/ {
if ( oldxdir == "RD" ) do_print = 1
xdir = "WR"
if ( DEBUG ) print "DBG: xdir=" xdir, $0
}
# Windows-NT:
# 22 0.00106488 IC35Mgr.exe IRP_MJ_READ Serial1 SUCCESS Length 1: 80
# 16 0.00000000 IC35 Sync.exe IRP_MJ_READ Serial0 Length 1
# 16 0.00000953 SUCCESS Length 1: 57
/IRP_MJ_READ/ {
if ( oldxdir == "WR" ) do_print = 1
if ( $0 ~ "SUCCESS" ) {
xdir = "RD"
if ( DEBUG ) print "DBG: xdir=" xdir, $0
} else if ( $0 !~ "TIMEOUT" ) {
hadread = 1
if ( DEBUG ) print "DBG: hadread", $0
} else {
do_print = 1
}
}
# 16 0.00000953 SUCCESS Length 1: 57
/SUCCESS/ && hadread {
xdir = "RD"
hadread = 0
if ( DEBUG ) print "DBG: dlyd RD", $0
}
# 15 0.07746540 TIMEOUT Length 0:
/TIMEOUT/ && hadread {
do_print = 1
}
# 419 0.00000000 IC35 Sync.exe IOCTL_SERIAL_CLR_DTR Serial0
/IOCTL_SERIAL_CLR_DTR/ {
do_print = 1
}
# 3 0.00000000 IC35 Sync.exe IRP_MJ_WRITE Serial0 Length 1: 41
/IRP_MJ_WRITE/ {
if ( oldxdir == "RD" ) do_print = 1
hadread = 0
xdir = "WR"
if ( DEBUG ) print "DBG: xdir=" xdir, $0
}
# ic35sync/Linux
# 01:11:48.3206 ic35sync 6 com_send(0x8055180,19) = 19
# 01:11:48.3206 ic35sync 6 0000: 02 13 00 83 0E 00 49 0B 00 01 07 03 00 00 00 00
# 01:11:48.3206 ic35sync 6 0010: 00 05 01
/ com_send\(/ {
if ( oldxdir == "RD" ) do_print = 1
hadxmit = $NF
xmitdir = "WR"
}
# 01:11:48.3703 ic35sync 6 com_recv(0xbffff89b,1) = 1
# 01:11:48.3703 ic35sync 6 0000: F2
# 01:11:48.3706 ic35sync 6 com_recv(0x8055181,2) = 2
# 01:11:48.3706 ic35sync 6 0000: 10 00
# 01:11:48.3800 ic35sync 6 com_recv(0x8055183,13) = 13
# 01:11:48.3800 ic35sync 6 0000: A0 0B 00 49 08 00 0A 00 00 06 20 2E 02
/ com_recv\(/ {
if ( oldxdir == "WR" ) do_print = 1
hadxmit = $NF
xmitdir = "RD"
}
/ [0-9A-F][0-9A-F][0-9A-F][0-9A-F]: / && hadxmit {
xdir = xmitdir
}
DEBUG {
print "DBG1: old,xdir=" oldxdir "," xdir, "xbuff=" xblen, "\047" xbuff "\047"
}
do_print {
prxdata( oldxdir, xbuff, xblen )
if ( txlen > xblen ) {
txdir = (oldxdir == "WR" ? "Wx " : "Rx ")
print txdir txlen
}
xbuff = ""
xblen = txlen = 0
do_print = 0
}
xdir {
if ( DEBUG ) print "DBG: do_x=" xdir, $0
xlen = getxdata() # get transmit data to xdata,xdlen
if ( xlen <= 0 )
next # no transmit / timeout
if ( xblen == 0 && stamp ) {
if ( stamp == 2 )
if ( tsecs ~ ":" )
xstamp = tsecs " "
else
xstamp = sprintf( "%010.4f ", tsecs )
else
xstamp = sprintf( "%05d\t", $1 )
}
xbuff = xbuff xdata # buffer transmit data
xblen += xlen
txlen += xlen
if ( xdlen != xlen || xblen >= MAXBPL ) { # not all logged or too much
prxdata( xdir, xbuff, xblen )
xbuff = ""
xblen = 0
}
oldxdir = xdir
xdir = ""
}
DEBUG {
print "DBG2: old,xdir=" oldxdir "," xdir, "xbuff=" xblen, "\047" xbuff "\047"
}
' -
}
# decode IC35sync Level-4 protocol
# expects output from ic35prot()
#
ic35L4prot() # [-vDEBUG=1] <hex_logfile >L4prot_logfile
{
awk $* '
# parameters
# DEBUG if non-zero/non-empty print verbose debugging output
# default: 0 / "" (disabled)
BEGIN {
# create table chr[] for hex to char conversion
ascii = ascii " !\"#$%&\047()*+,-./"
ascii = ascii "0123456789:;<=>?"
ascii = ascii "@ABCDEFGHIJKLMNO"
ascii = ascii "PQRSTUVWXYZ[\\]^_"
ascii = ascii "`abcdefghijklmno"
ascii = ascii "pqrstuvwxyz{|}~"
for ( c = 0; c <= 255; ++c ) {
xc = sprintf("%02X", c)
if ( 32 <= c && c <= 126 ) # 32=space 126=tilda
chr[ xc ] = substr( ascii, c - 32+1, 1 )
else
chr[ xc ] = "\\x" xc
}
}
# get block of bytes from hex transmit data
# convert to ASCII and enclose in " quotes
#
function ascblk( beg, len, _end, _blk, _i )
{
if ( (_end = beg + len-1) > NF )
_end = NF # truncate to end of input line
_blk = "\""
for ( _i = beg; _i <= _end; ++_i )
_blk = _blk chr[ $_i ]
_blk = _blk "\""
return _blk
}
# get byte block of bytes from hex transmit data
#
function hexblk( beg, len, _end, _blk, _i )
{
if ( (_end = beg + len-1) > NF )
_end = NF # truncate to end of input line
_blk = $beg
for ( _i = beg+1; _i <= _end; ++_i )
_blk = _blk " " $_i
return _blk
}
# convert hex strings to decimal
#
function hex2dec( hexstr, _xval, _xdig, _i )
{
if ( hexstr ~ "^0[Xx]" )
hexstr = substr(hexstr, 3)
_xval = 0
for ( _i = 1; _i <= length(hexstr); ++_i ) {
_xdig = index( "0123456789ABCDEFabcdef", substr(hexstr, _i, 1) ) - 1
if ( _xdig < 0 )
break
if ( _xdig >= 16 )
_xdig -= 16 - 10
_xval = _xval * 16 + _xdig
}
return _xval
}
# decode field data from IC35 record
function recdata( beg, fid, _i, _recblk )
{
if ( fid != "" ) { # file-id specified: this the header fragment
nflens = 0
if ( fid == "05" ) nflens = 21 # Addresses
else if ( fid == "06" ) nflens = 4 # Memo
else if ( fid == "07" ) nflens = 8 # ToDoList
else if ( fid == "08" ) nflens = 10 # Schedule
if ( nflens == 0 ) {
printf( "ERR: recdata(beg=%s,fid=%s) unkown fid\n", beg, fid )
return ""
}
delete flens
for ( _i = 1; _i <= nflens; ++_i )
flens[_i] = hex2dec( $(beg+_i-1) )
fidx = 1
fldrest = 0
}
if ( fldrest ) { # partial last field from previous fragment
_recblk = " f" fidx-1 "=" ascblk( beg, fldrest )
sub( "=\"", "=<", _recblk )
_i = beg + fldrest
fldrest = 0
} else { # record data on field boundary
_recblk = ""
if ( fid != "" ) _i = beg + nflens # header fragment
else _i = beg # 2nd ff. fragment
}
while ( _i <= NF && fidx <= nflens ) {
_recblk = _recblk " f" fidx "=" ascblk( _i, flens[fidx] )
_i += flens[fidx++]
}
if ( _i != NF+1 ) { # partial last field
fldrest = _i - (NF+1)
sub( "\"$", ">", _recblk )
}
return _recblk
}
# WRx 43 80 26 00 10 00 64 00 4A 1F 00 49 4E 56 45 4E 54 45 43 ...
# WRx 14 83 09 00 49 06 00 02 00 00
# WRx 8 83 00 03
# RDx 46 A0 29 00 10 00 D0 07 4A 22 00 49 4E 56 45 4E 54 45 43 ...
# RDx 13 A0 08 00 49 05 00 03 01
# RDx 8 A0 03 00
# variables:
# type indicates command "Cmd" "C??" or response "Rsp" "R??"
# "C??","R??" flag PDU contents not matching current knowledge
# pi parameter index: PDU paramters begin at pi-th input field
# pdu PDU identification for output, e.g. "identify", "openfile"
# pars decoded parameters from PDU for output
# l2l3 concatenation of Level-2 and Level-3 id-bytes
# l4 Level-4 command
# l2l3l4 concatenation of l2l3 and l4
# printhex flag to also output the hex input (for debugging)
# may be set by some decoder, reset on every input block
# DEBUG global debug flag to also output the hex input
#
/^WRx/ || /^RDx/ {
if ( $1 == "WRx" ) {
type = "Cmd"
pi = 2+3+3+2 + 1 # command parameter index
} else { # "RDx"
type = "Rsp"
pi = 2+3+3 + 1 # response parameter index
}
printhex = 0
pdu = pars = l2l3 = l4 = l2l3l4 = ""
if ( NF >= 2+3+3 ) { # have L2- and L3 id-bytes
l2l3 = $3 $6
if ( NF >= 2+3+3+2 ) { # have also L4 command
l4 = $9 $10
l2l3l4 = l2l3 l4
}
# identify
if ( l2l3 == "8010" ) {
# AdsGetDeviceVersion ?
pdu = "identify"
} else if ( l2l3 == "A010" ) {
pdu = "identify"
pars = ascblk(pi+25, 99) # "DCS15" version
# power, passwd
} else if ( l2l3l4 == "8249" "0301" ) {
pdu = "power"
pars = ascblk(pi, 5) # "Power"
pars = pars " " hexblk(pi+5, 99) # 00 00 00
if ( pars != "\"Power\" 00 00 00" )
type = "C??"
} else if ( l2l3 == "A049" && lastcmd == "power" ) {
pdu = "power"
pars = $(pi) $(pi+1) # 0301
if ( pars != "0301" || NF+1 - pi != 2 )
type = "R??"
} else if ( l2l3l4 == "8249" "0300" ) {
pdu = "passwd"
pars = ascblk(pi, 8) # [password]
if ( NF+1 - pi != 8 )
type = "C??"
} else if ( l2l3 == "A049" && lastcmd == "passwd" ) {
pdu = "passwd"
pars = $(pi) $(pi+1) # 0101
if ( pars != "0101" || NF+1 - pi != 2 )
type = "R??"
# getdtime, setdtime
} else if ( l2l3l4 == "8349" "0200" ) {
# AdsReadSysInfo ?
pdu = "getdtime"
pars = hexblk(pi, 99) # 00
if ( pars != "00" )
type = "C??"
} else if ( l2l3 == "A049" && lastcmd == "getdtime" ) {
pdu = "dtime"
pars = ascblk(pi, 14) # [mmddyyyyhhmmss]
tail = hexblk(pi+14, 99) # 00 00
if ( tail != "00 00" ) {
pars = pars " " tail
type = "R??"
}
} else if ( l2l3l4 == "8249" "0201" ) {
# AdsWriteSysInfo ?
pdu = "setdtime"
head = hexblk(pi, 1) # 00
pars = ascblk(pi+1, 14) # [mmddyyyyhhmmss]
tail = hexblk(pi+1+14, 99) # 00 00
if ( head != "00" && tail != "00 00" ) {
pars = head " " pars " " tail
type = "C??"
}
# response "A0"
# pdu = "done" below
# category
} else if ( l2l3l4 == "8249" "0302" ) {
# AdsReadCategoryData ?
pdu = "category"
pars = ascblk(pi, 8) # [category]
if ( NF+1 - pi != 8 )
type = "C??"
} else if ( l2l3 == "A049" && lastcmd == "category" ) {
pdu = "category"
pars = $(pi) $(pi+1)
if ( NF+1 - pi != 2 )
type = "R??"
# openfile, closefile
} else if ( l2l3l4 == "8249" "0002" ) {
# AdsOpenDataBase ?
pdu = "openfile"
head = hexblk( pi, 7 )
lf2 = hex2dec( $(pi+10) $(pi+9) $(pi+8) $(pi+7) )
lf = hex2dec( $(pi+11) )
fn = ascblk(pi+12, lf)
tail = hexblk( pi+12+lf, 99 )
if ( length( fn ) == lf + 2 \
&& lf2 == lf + 2 \
&& head == "00 00 00 00 00 00 00" \
&& tail == "02" )
pars = fn
else {
pars = head " lf2=" lf2 " lf=" lf " " fn " " tail
type = "C??"
}
# set current file-id, to determine num.of record fields
if ( fn ~ "Addresses" ) currfid = "05"
else if ( fn ~ "Memo" ) currfid = "06"
else if ( fn ~ "To Do List" ) currfid = "07"
else if ( fn ~ "Schedule" ) currfid = "08"
} else if ( l2l3 == "A049" && lastcmd == "openfile" ) {
pdu = "openfile"
pars = "fd=" $(pi+1) $(pi)
if ( NF+1 - pi != 2 )
type = "R??"
} else if ( l2l3l4 == "8249" "0003" ) {
# AdsCloseDataBase ? AdsCloseHandle ?
pdu = "closefile"
pars = "fd=" $(pi+1) $(pi)
tail = hexblk( pi+2, 99 )
if ( tail != "00 00 00 00" ) {
pars = pars " " tail
type = "C??"
}
# unset current file-id on close
currfid = ""
# response "A0"
# pdu = "done" below
# getflen
} else if ( l2l3l4 == "8349" "0103" ) {
# AdsGetRecordCount
pdu = "getflen"
pars = "fd=" $(pi+1) $(pi)
tail = hexblk( pi+2, 99 )
if ( tail != "00 00 00 00" ) {
pars = pars " " tail
type = "C??"
}
} else if ( l2l3l4 == "8349" "0104" ) {
# AdsGetModifiedRecordCount
pdu = "getflenmod"
pars = "fd=" $(pi+1) $(pi)
tail = hexblk( pi+2, 99 )
if ( tail != "00 00 00 00" ) {
pars = pars " " tail
type = "C??"
}
} else if ( l2l3 == "A049" && (lastcmd == "getflen" \
|| lastcmd == "getflenmod") ) {
pdu = lastcmd
pars = "n=" hex2dec( $(pi+1) ($pi) )
if ( NF+1 - pi != 2 )
type = "R??"
# read record
} else if ( l2l3l4 == "8349" "0105" ) {
# AdsReadRecordByID
pdu = "readrecrid"
pars = "fd=" $(pi+1) $(pi)
pars = pars " ri=" $(pi+3) $(pi+2)
pars = pars " " $(pi+4)
pars = pars " fi=" $(pi+5)
reqrid = hex2dec( $(pi+5) $(pi+4) $(pi+3) $(pi+2) )
if ( NF+1 - pi != 6 )
type = "C??"
} else if ( l2l3l4 == "8349" "0106" ) {
# AdsReadRecordByIndex
pdu = "readrec"
reqrid = ""
pars = "fd=" $(pi+1) $(pi)
pars = pars " ix=" hex2dec( $(pi+3) $(pi+2) )
tail = hexblk( pi+4, 99 )
if ( tail != "00 00" ) {
pars = pars " " tail
type = "C??"
}
} else if ( l2l3l4 == "8349" "0107" ) {
# AdsReadNextModifiedRecord
pdu = "readrecmod"
reqrid = ""
pars = "fd=" $(pi+1) $(pi)
tail = hexblk(pi+2, 99)
if ( NF+1 - pi != 6 || tail != "00 00 00 00" ) {
pars = pars " " tail
type = "C??"
}
} else if ( (l2l3 == "A049" \
|| l2l3 == "2048") && (lastcmd == "readrec" \
|| lastcmd == "readrecmod" \
|| lastcmd == "readrecrid") ) {
pdu = "rechdr" (l2l3 == "2048" ? "(more)" : "(last)")
rsprid = hex2dec( $(pi+3) $(pi+2) $(pi+1) $(pi) )
pars = "ri=" $(pi+1) $(pi)
pars = pars " " $(pi+2)
pars = pars " fi=" $(pi+3)
pars = pars " ch=" $(pi+4)
if ( NF+1 - pi == 5 )
pars = pars " (nodata)"
else if ( lastcmd == "readrecrid" && rsprid != reqrid )
pars = pars " notfound (" NF+1 - (pi+5) " bytes garbage)"
else
pars = pars " " recdata( pi+5, $(pi+3) )
reqrid = ""
} else if ( (l2l3 == "A049" \
|| l2l3 == "2048") && lastcmd == "readmore" ) {
pdu = "recdat" (l2l3 == "2048" ? "(more)" : "(last)")
pars = " "
pars = pars " " recdata( pi, "" )
# write record
} else if ( l2l3l4 == "0248" "0108" \
|| l2l3l4 == "8249" "0108" ) {
# AdsWriteRecord
pdu = "writerec" (l2l3 == "0248" ? "(more)" : "(last)")
fdesc = $(pi+1) $(pi)
zero1 = hexblk(pi+2, 4)
p678 = hexblk(pi+6, 3)
zero2 = hexblk(pi+9, 2)
lrec = hex2dec( $(pi+14) $(pi+13) $(pi+12) $(pi+11) )
if ( zero1 == "00 00 00 00" && zero2 == "00 00" ) {
pars = "fd=" fdesc " " p678 " lr=" lrec
pars = pars " " recdata( pi+15, currfid )
} else {
pars = "fd=" fdesc " " zero1 " " p678 " " zero2 " lr=" lrec
pars = pars " " recdata( pi+15, currfid )
type = "C??"
}
# update record
} else if ( l2l3l4 == "0248" "0109" \
|| l2l3l4 == "8249" "0109" ) {
# AdsUpdateRecord
pdu = "updatrec" (l2l3 == "0248" ? "(more)" : "(last)")
pars1 = "fd=" $(pi+1) $(pi)
pars1 = pars1 " ri=" $(pi+3) $(pi+2)
pars1 = pars1 " " $(pi+4)
pars1 = pars1 " fi=" $(pi+5)
pars1 = pars1 " " hexblk(pi+6, 3)
zero2 = hexblk(pi+9, 2)
pars2 = " lr=" hex2dec( $(pi+14) $(pi+13) $(pi+12) $(pi+11) )
if ( zero2 == "00 00" ) {
pars = pars1 pars2
pars = pars " " recdata( pi+15, currfid )
} else {
pars = pars1 " " zero2 pars2
pars = pars " " recdata( pi+15, currfid )
type = "C??"
}
} else if ( (l2l3 == "0248" \
|| l2l3 == "8249") && (lastcmd == "writerec(more)" \
|| lastcmd == "updatrec(more)") ) {
pdu = substr(lastcmd, 1, 8)
pdu = pdu (l2l3 == "0248" ? "(more)" : "(last)")
pars = " "
pars = pars " " recdata( pi-2, "" )
# response l2 == "90"
# pdu = "writemore" below
} else if ( l2l3 == "A049" && (lastcmd == "writerec(last)" \
|| lastcmd == "updatrec(last)") ) {
pdu = substr(lastcmd, 1, 8)
pars = "ri=" $(pi+1) $(pi)
pars = pars " " $(pi+2)
pars = pars " fi=" $(pi+3)
if ( NF+1 - pi != 4 )
type = "R??"
# delete record
} else if ( l2l3l4 == "8249" "0102" ) {
# AdsDeleteRecord
pdu = "deleterec"
pars = "fd=" $(pi+1) $(pi)
pars = pars " ri=" $(pi+3) $(pi+2)
pars = pars " " $(pi+4)
pars = pars " fi=" $(pi+5)
if ( NF+1 - pi != 6 || $(pi+4) != "00" )
type = "C??"
# response l2 == "A0"
# pdu = "done" below
# reset changeflag
} else if ( l2l3l4 == "8249" "010A" ) {
# AdsCommitRecord
pdu = "resetchg"
pars = "fd=" $(pi+1) $(pi)
pars = pars " ri=" $(pi+3) $(pi+2)
pars = pars " " $(pi+4)
pars = pars " fi=" $(pi+5)
if ( $(pi+4) != "00" || NF+1 - pi != 6 )
type = "C??"
# response l2 == "A0"
# pdu = "done" below
}
# short PDUs with Level-2 id-byte only
} else if ( NF == 2+3 ) {
if ( $3 == "83" ) {
pdu = "readmore"
} else if ( $3 == "90" ) {
pdu = "writemore"
} else if ( $3 == "81" ) {
pdu = "disconn"
} else if ( $3 == "A0" ) {
pdu = "done"
}
}
if ( $1 == "WRx" ) {
lastcmd = pdu
if ( pdu == "" ) type = "C??" # unknown command PDU
if ( type !~ "^C..$" )
print "INTERNAL ERROR"
} else { # "RDx"
lastrsp = pdu
if ( pdu == "" ) type = "R??" # unknown response PDU
if ( type !~ "^R..$" )
print "INTERNAL ERROR"
}
if ( type == "C??" || type == "R??" \
|| DEBUG || printhex )
print # show hex data for unknown PDU / params
printf( "%s %2d\t", type, $2 )
if ( pdu == "" ) {
for ( i = 3; i <= NF; ++i ) printf( " %s", $i )
printf( "\n" )
} else {
printf( " %-14s %s\n", pdu, pars )
}
}
' -
}
# process options
#
LEVEL=all
while getopts "l:s:aDh" OPT
do case $OPT in
l ) LEVEL=$OPTARG ;;# level of output
s ) STAMP="-vstamp=$OPTARG" ;;# prepend lineno/time stamp
a ) ASCII=1 ;;# also ASCII chars
D ) DEBUG="-vDEBUG=1" ; KEEPTMP=1 ;;# debug/diagnostic
h|? ) usage ;;# for other options give help and exit
esac
done
shift `expr $OPTIND - 1`
[ $# -eq 1 -o $# -eq 2 ] || usage
# the real work ..
#
case "$LEVEL" in
all)
PASS1="ic35prot $STAMP $DEBUG"
if [ -n "$ASCII" ]
then PASS2=showascii
else PASS2=cat
fi
;;
syn2)
PASS1="ic35prot -vskip=3 $DEBUG"
if [ -n "$ASCII" ]
then PASS2=showascii
else PASS2=cat
fi
;;
syn4)
PASS1="ic35prot -vskip=3"
PASS2="ic35L4prot $DEBUG"
;;
*)
echo "$PROGNAME -- unsupported output level: $LEVEL"
exit 1
esac
if [ $# -eq 2 ] ; then
if [ "$1" != "-" ] && expr "`file $1`" : '.*\<gzip.*' >/dev/null ; then
tar -xOzf $1 $2 | tr -d '\015' | $PASS1 | $PASS2 | $PAGER
else
tar -xOf $1 $2 | tr -d '\015' | $PASS1 | $PASS2 | $PAGER
fi
else
if [ "$1" != "-" ] && expr "`file $1`" : '.*\<gzip.*' >/dev/null ; then
zcat $1 | tr -d '\015' | $PASS1 | $PASS2 | $PAGER
else
cat $1 | tr -d '\015' | $PASS1 | $PASS2 | $PAGER
fi
fi

991
src/ic35mgr.c Normal file
View File

@ -0,0 +1,991 @@
/************************************************************************
* Copyright (C) 2001 Thomas Schulz *
* */
static char rcsid[] =
"$Id: ic35mgr.c,v 1.20 2001/11/20 23:08:35 thosch Exp $"; /*
* *
* IC35 manager *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
* conditional compile on NO_LOGSIM: if #defined, logging of the *
* IC35 communications as well as simulated communication are NOT *
* supported, default WITH logging and com-simulation support. *
* *
* for usage run ic35mgr -h or see function usage() below. *
* *
************************************************************************/
#include <stdio.h> /* printf(), .. */
#include <stdlib.h> /* malloc(), free() */
#include <string.h> /* memcpy(), strcpy() ..*/
#include <ctype.h> /* islower(), .. */
#include <getopt.h> /* getopt(), optarg, .. */
#include <time.h> /* struct tm, time() .. */
#include <utime.h> /* struct utimbuf, .. */
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include "util.h" /* FALSE, .. */
#include "comio.h" /* COM_SIMINIT(), .. */
#include "mgrtrans.h" /* IC35mgr transactions */
NOTUSED(rcsid)
extern char * pkgvers; /* these are all */
extern char * pkgdate; /* in versinfo.c, which is */
extern char * bldinfo; /* auto-generated by Makefile */
/* ==================================== */
/* IC35 manager commands */
/* ==================================== */
/* report IC35 status
* ------------------
*/
static int
ic35mgrstat( char * devname, char * statfname )
{
int mmcnum;
int rval;
char label[11+1];
if ( (rval = mconnect( devname, statfname )) != OK )
return rval;
for ( mmcnum = 1; mmcnum <= 2; ++mmcnum ) {
if ( (rval = mmc_status( mmcnum )) < 0 )
break;
if ( rval != 0 ) {
if ( (rval = mmc_label( mmcnum, label )) < 0 )
break;
message( "MMCard%d found, label: \"%s\"", mmcnum, label );
} else {
message( "MMCard%d not present", mmcnum );
}
}
mdisconnect();
return rval;
}
/* backup IC35 database to file
* ----------------------------
*/
static int
ic35backup( char * devname, char * fname )
{
int rval;
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
rval = readdatabase( fname );
mdisconnect();
return rval;
}
/* restore IC35 database from file
* -------------------------------
*/
static int
ic35restore( char * devname, char * fname )
{
int rval;
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
rval = writedatabase( fname );
mdisconnect();
return rval;
}
/* list IC35 MMCard(s) directories
* -------------------------------
* list looks like:
* MMCardn "Label"
* size filetimestamp attr filepath
* nnnnnnnnnn yyyy-mm-dd hh:mm:ss xxx MMCard1\subdir\filename.ext
*/
static int
mmcdirlist( char * dirpath )
{
MMCDIR * dirp;
MMCDIRENT * dirent;
size_t pfxlen;
char * subdir;
char attrtext[4+1];
int rval, rc;
if ( (dirp = mmc_opendir( dirpath )) == NULL )
return ERR;
pfxlen = strlen( dirpath ) + 1;
rval = OK;
while ( (dirent = mmc_readdir( dirp )) != NULL ) {
switch ( dirent->attr ) {
case MMCattrDirectory: strcpy( attrtext, "dir" ); break;
case MMCattrArchive: strcpy( attrtext, "arc" ); break;
default: sprintf( attrtext, "0x%02X", dirent->attr & 0xFF );
}
printf( "%10ld %s %4s %s\\%s\n",
dirent->size, mmctstampstr( dirent->tstamp ),
attrtext, dirpath, dirent->name );
fflush( stdout );
if ( dirent->attr & MMCattrDirectory
&& strcmp( dirent->name, ".." ) != 0
&& (subdir = malloc( pfxlen + strlen(dirent->name) + 1 )) != NULL ) {
sprintf( subdir, "%s\\%s", dirpath, dirent->name );
rc = mmcdirlist( subdir );
if ( rval == OK ) rval = rc;
free( subdir );
}
}
rc = mmc_closedir( dirp );
if ( rval == OK ) rval = rc;
return rval; /* errcode of first failure or success OK */
}
static int
ic35mmcdir( char * devname )
{
int mmcnum;
int rval;
char label[11+1];
char dirpath[7+1];
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
for ( mmcnum = 1; mmcnum <= 2; ++mmcnum ) {
if ( (rval = mmc_status( mmcnum )) < 0 )
break;
if ( rval == 0 ) {
message( "MMCard%d not present", mmcnum );
continue;
}
if ( (rval = mmc_label( 1, label )) < 0 )
break;
printf( "MMCard%d \"%s\"\n", mmcnum, label );
fflush( stdout );
sprintf( dirpath, "MMCard%d", mmcnum );
if ( (rval = mmcdirlist( dirpath )) < 0 )
break;
}
mdisconnect();
return rval;
}
/* ==================================== */
/* IC35 MMCard file commands */
/* ==================================== */
#define MINBLKSZ 1 /* min.blocksize */
#define MAXBLKSZ 16350 /* max.blocksize (found by experiments) */
#define ERR_mmcpfx -1
#define ERR_mmcnum -2
#define ERR_mmcslash -3
#define ERR_mmcbadpath -4
static char * MMCard = "MMCard";
static int blocksize; /* read/write buffer size mmcget/mmcput */
/* check,convert MMCard path to IC35 format & get MMCard number
* ------------------------------------------------------
* the ic35path will be checked (slash means / or \):
* - prefix must be "MMCard" in lowercase or uppercase or mixed
* - MMCard number after prefix must be '1' or '2'
* - slash after MMCard number (unless the path ends there)
* - no adjacent slashes
* - at most one dot between slashes
* - max. 8 characters after slash until dot or slash or end
* - max. 3 characters after dot until slash or end
* the ic35path will be translated to match IC35 requirements:
* translate '/' to '\' dir separators and lowercase to upper.
* the translation is done in place, i.e. the argument string
* is modified.
* returns:
* -1 ERR, missing "MMCard" prefix
* -2 ERR, bad MMCard number (not 1,2)
* -3 ERR, missing slash/backslash after "MMCard[12]"
* -4 ERR, bad path component (too long, >1 dot, adjacent slashes)
*
* parameter mode: if 1 create directories
*/
static int
_ic35mmcpath( char * ic35path , int mode)
{
MMCDIR * mdirp;
int mmcnum;
char * ptr;
char * pdot;
char * pslash;
/* check/set "MMCard" prefix in ic35fpath */
if ( strncasecmp( ic35path, MMCard, strlen(MMCard) ) != 0
|| ! isdigit( ic35path[strlen(MMCard)] ) )
return ERR_mmcpfx; /* error: missing MMCard prefix */
memcpy( ic35path, MMCard, strlen(MMCard) );
/* check MMCard number and slash/backslash after prefix */
ptr = ic35path + strlen(MMCard);
if ( *ptr != '1' && *ptr != '2' )
return ERR_mmcnum; /* error: bad MMCard number */
mmcnum = *ptr - '0';
++ptr;
if ( *ptr == 0 ) return mmcnum; /* allow just MMCard<n> */
if ( *ptr == '/' ) *ptr = '\\';
if ( *ptr != '\\' )
return ERR_mmcslash; /* error: miss slash/backslash */
/* check path components for 8+3, too many dots, etc. */
pslash = ptr++; pdot = NULL;
do {
switch ( *ptr ) {
case '/':
case '\\':
if (mode == 1) {
/* create directory if it does not yet exist */
*ptr = 0;
if ((mdirp = mmc_opendir(ic35path)) == NULL)
mdirp = mmc_createdir(ic35path);
mmc_closedir(mdirp);
}
*ptr = '\\';
/* fall through */
case '\0':
if ( ptr - (pslash+1) == 0 ) {
if (*ptr == 0) *pslash = 0; /* remove trailing slash */
else return ERR_mmcbadpath; /* error: adjacent slashes */
}
if ( (pdot != NULL && ptr - (pdot+1) > 3)
|| (pdot == NULL && ptr - (pslash+1) > 8) )
return ERR_mmcbadpath; /* error: too long since slash */
pslash = ptr; pdot = NULL;
break;
case '.':
if ( pdot != NULL )
return ERR_mmcbadpath; /* error: too many dots */
if ( ptr - (pslash+1) > 8 )
return ERR_mmcbadpath; /* error: too long before dot */
pdot = ptr;
break;
}
} while ( *ptr++ );
/* convert ic35path '/' to '\\', lowercase to uppercase */
for ( ptr = ic35path+strlen(MMCard); *ptr; ++ptr ) {
if ( islower( *ptr ) )
*ptr = (char)toupper( *ptr );
}
return mmcnum;
}
/* output MMCard path error message
* --------------------------------
*/
static void
_mmcpatherror( int errnum, char * ic35path )
{
switch ( errnum ) {
case ERR_mmcpfx:
error( "missing \"%s\" prefix in IC35 filepath: %s", MMCard, ic35path );
break;
case ERR_mmcnum:
error( "bad MMCard number in IC35 filepath: %s", ic35path );
break;
case ERR_mmcslash:
error( "missing \\ or / in IC35 filepath: %s", ic35path );
break;
case ERR_mmcbadpath:
default:
error( "bad path component in IC35 filepath: %s", ic35path );
break;
}
}
/* get filename from IC35 MMCard path
* ----------------------------------
* derive local filename from base filename in ic35path, i.e. leading
* directory components removed, and translate to lowercase.
* the buffer for the local filename is strdup()'d and shall be freed
* by caller.
*/
static char *
_dupic35fname( char * ic35path, int mode)
{
char * ptr;
char * fname;
/* create copy */
if ( (fname = strdup( ic35path )) == NULL )
return NULL;
/* convert to unix filename, creating dirs on the way */
ptr = fname;
while (*ptr) {
if (*ptr == '\\' || *ptr == '/') {
if ( mode == 1 ) {
/* create subdir */
*ptr = 0;
if (mkdir(fname, 0700) < 0
&& errno != EEXIST ) {
perror(fname);
}
}
*ptr++ = '/';
} else {
*ptr++ = tolower( *ptr );
}
}
return fname;
}
static void progress( int mode, char* ipath, char *upath, ulong curr, ulong total)
{
fprintf( stderr, "\r%s %s %s %s %ld",
mode? "read": "write", ipath,
mode? "->" : "<-", upath, (curr+511)/1024);
if (total) fprintf( stderr, "/%ldk, %ld%% ", (total+511)/1024,
curr*100/total);
else fprintf( stderr, "k ");
}
/* read file from IC35 MMCard
* --------------------------
* the ic35path will be translated to match IC35 requirements:
* translate '/' to '\' dir separators and lowercase to upper.
* on absent local filename (NULL or empty string) derive it from
* base filename in ic35path, i.e. leading directory components
* removed, translated to lowercase.
* e.g. mmcard1/Ic35\App\Reversi.APP will be translated
* to MMCard1\IC35\APP\REVERSI.APP and local file reversi.app
* the local file's timestamp will be set to the IC35 file's.
* (but IC35 seems to errorneously set the IC35 file's timestamp
* to the time of read, although the IC35 file is not modified!?)
*
*/
static int
mmcget( char * ic35path, char * a_fname )
{
int rbuffsize = 5 * 1024;
char * fname;
MMCFILE * mmcfp;
MMCDIRENT * mmcfstat;
FILE * fp;
struct utimbuf ftime;
uchar * buff;
size_t blen;
int rlen;
ulong frlen;
int rval = OK;
ulong size;
if ( MINBLKSZ <= blocksize && blocksize <= MAXBLKSZ )
rbuffsize = blocksize;
else if ( blocksize != 0 )
error( "bad buffer size %d, using default %d", blocksize, rbuffsize );
/* create fname from basename(ic35path) if absent */
if ( a_fname && *a_fname ) {
fname = a_fname;
} else
if ( (fname = _dupic35fname( ic35path, 1 )) == NULL ) {
error( "no memory for local filename from %s", ic35path );
return ERR;
}
if ( (mmcfp = mmc_openfile( ic35path, MMCopenexist )) != NULL ) {
if ( (mmcfstat = mmc_statfile( mmcfp )) != NULL ) {
size = mmcfstat->size;
if ( (buff = malloc( blen = rbuffsize )) != NULL ) {
if ( (fp = fopen( fname, "w" )) != NULL ) {
rval = OK;
frlen = 0;
progress( 1, ic35path, fname, frlen, size );
while ( (rlen = mmc_readfile( mmcfp, buff, blen )) > 0 ) {
frlen += rlen;
progress( 1, ic35path, fname, frlen, size );
if ( fwrite( buff, 1, rlen, fp ) != rlen ) {
error( "write error %s: %s (%d)",
fname, strerror(errno), errno );
rval = ERR;
break;
}
}
fclose( fp );
if ( rlen == 0 && rval == OK ) {
ftime.actime = time( NULL );
ftime.modtime = mmctstampunixtime( mmcfstat->tstamp );
utime( fname, &ftime ); /* set file modtime from IC35 */
fprintf( stderr, "\n" );
} else /* mmc_readfile() or fwrite() failed */
rval = ERR;
} else /* (fp = fopen()) == NULL */
error( "cannot open %s: %s (%d)",
fname, strerror(errno), errno );
free( buff );
} else /* (buff = malloc()) == NULL */
error( "no memory for read buffer (%d)", rbuffsize );
} else /* mmc_statfile() failed */
rval = ERR;
mmc_closefile( mmcfp );
} else /* mmc_openfile() failed */
rval = ERR;
if ( fname != a_fname )
free( fname );
return rval;
}
static int
ic35mmcget( char * devname, char * ic35path, char * a_fname )
{
int mmcnum;
int rval;
/* check ic35path, check/set "MMCard" prefix and */
/* convert '/' to '\\', lowercase to uppercase */
if ( (mmcnum = _ic35mmcpath( ic35path, 0 )) < 0 ) {
_mmcpatherror( mmcnum, ic35path );
return ERR;
}
/* connect to IC35 in SyncStation via serial device */
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
/* get MMCard status (else other MMCard ops would fail) */
if ( (rval = mmc_status( mmcnum )) <= 0 ) {
if ( rval == 0 )
message( "MMCard%d not present", mmcnum );
mdisconnect();
return ERR;
}
/* read file from IC35 MMCard */
rval = mmcget( ic35path, a_fname);
/* cleanup and disconnect from IC35 */
mdisconnect();
return rval;
}
/* get complete tree from IC35 MMCard(s)
* -------------------------------
* dirpath = subdir from which to start
*
*
*
*/
static int
mmcgettree( char * dirpath )
{
MMCDIR * dirp;
MMCDIRENT * dirent;
size_t pfxlen;
char * subdir;
char * ic35path;
int rval, rc;
if ( (dirp = mmc_opendir( dirpath )) == NULL )
return ERR;
pfxlen = strlen( dirpath ) + 1;
rval = OK;
while ( (dirent = mmc_readdir( dirp )) != NULL ) {
switch ( dirent->attr ) {
case MMCattrDirectory:
if (strcmp(dirent->name, ".." ) != 0
&& (subdir = malloc( pfxlen + strlen(dirent->name) + 1 )) != NULL ) {
sprintf(subdir, "%s\\%s", dirpath, dirent->name );
rc = mmcgettree(subdir);
if ( rval == OK ) rval = rc;
free(subdir);
}
break;
case MMCattrArchive:
ic35path = malloc(pfxlen + strlen(dirent->name) + 1 );
sprintf(ic35path, "%s\\%s", dirpath, dirent->name);
mmcget(ic35path, NULL);
free(ic35path);
break;
default:
}
}
rc = mmc_closedir( dirp );
if ( rval == OK ) rval = rc;
return rval; /* errcode of first failure or success OK */
}
static int
ic35mmcgettree( char * devname, char * ic35path)
{
int mmcnum;
int rval;
char dirpath[7+1];
if (ic35path) {
/* check ic35path, check/set "MMCard" prefix and */
/* convert '/' to '\\', lowercase to uppercase */
if ( (mmcnum = _ic35mmcpath( ic35path, 0 )) < 0 ) {
_mmcpatherror( mmcnum, ic35path );
return ERR;
}
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
if ( (rval = mmc_status( mmcnum )) == 0 ) {
message( "MMCard%d not present", mmcnum );
rval = ERR;
} else if (rval > 0)
rval = mmcgettree( ic35path );
}
else {
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
for ( mmcnum = 1; mmcnum <= 2; ++mmcnum ) {
if ( (rval = mmc_status( mmcnum )) < 0 )
break;
if ( rval == 0 ) {
message( "MMCard%d not present", mmcnum );
continue;
}
sprintf( dirpath, "MMCard%d", mmcnum );
if ( (rval = mmcgettree( dirpath )) < 0 )
break;
}
}
mdisconnect();
return rval;
}
/* write file to IC35 MMCard
* -------------------------
* see ic35mmcget() comment about ic35path conversions and deriving
* fname from it if a_fname is NULL or empty.
*/
static int
mmcput(char * ic35path, char * a_fname )
{
int wbuffsize = 2 * 1024;
MMCFILE * mmcfp;
FILE * fp;
uchar * buff;
size_t blen;
char * fname;
int rlen;
ulong fwlen;
ulong size;
int rval = OK;
struct stat statbuf;
if ( MINBLKSZ <= blocksize && blocksize <= MAXBLKSZ )
wbuffsize = blocksize;
else if ( blocksize != 0 )
error( "bad buffer size %d, using default %d", blocksize, wbuffsize );
/* create fname from basename(ic35path) if absent */
if ( a_fname && *a_fname ) {
fname = a_fname;
} else
if ( (fname = _dupic35fname( ic35path, 0 )) == NULL ) {
error( "no memory for local filename from %s", ic35path );
return ERR;
}
/* write file to IC35 MMCard */
if ( (mmcfp = mmc_openfile( ic35path, MMCcreatrunc )) != NULL ) {
if ( (buff = malloc( blen = wbuffsize )) != NULL ) {
if ( (fp = fopen( fname, "r" )) != NULL ) {
rval = OK;
fwlen = 0;
stat(fname, &statbuf);
size = statbuf.st_size;
progress( 0, ic35path, fname, fwlen, size );
while ( (rlen = fread( buff, 1, blen, fp )) > 0 ) {
if ( mmc_writefile( mmcfp, buff, rlen ) != rlen ) {
rval = ERR;
break;
}
fwlen += rlen;
progress( 0, ic35path, fname, fwlen, size );
}
if ( rlen <= 0 && feof( fp ) && rval == OK ) {
fprintf( stderr, "\n" );
} else { /* fread() or mmc_writefile() failed */
if ( rval != ERR )
error( "read error %s: %s (%d)",
fname, strerror(errno), errno );
rval = ERR;
}
fclose( fp );
} else /* (fp = fopen()) == NULL */
error( "cannot open %s: %s (%d)",
fname, strerror(errno), errno );
free( buff );
} else /* (buff = malloc()) == NULL */
error( "no memory for write buffer (%d)", wbuffsize );
mmc_closefile( mmcfp );
} else /* mmc_openfile() failed */
rval = ERR;
if ( fname != a_fname )
free( fname );
return rval;
}
static int
ic35mmcput( char * devname, char * ic35path, char * a_fname )
{
int mmcnum;
int rval;
/* check ic35path, check/set "MMCard" prefix and */
/* convert '/' to '\\', lowercase to uppercase */
if ( (mmcnum = _ic35mmcpath( ic35path, 0 )) < 0 ) {
_mmcpatherror( mmcnum, ic35path );
return ERR;
}
/* connect to IC35 in SyncStation via serial device */
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
/* get MMCard status (else other MMCard ops would fail) */
if ( (rval = mmc_status( mmcnum )) <= 0 ) {
if ( rval == 0 )
message( "MMCard%d not present", mmcnum );
mdisconnect();
return ERR;
}
rval = mmcput(ic35path, a_fname );
/* cleanup and disconnect from IC35 */
mdisconnect();
return rval;
}
/* put complete tree to IC35 MMCard(s)
* -------------------------------
* dirpath = subdir from which to start
*
*
*
*/
static int
mmcputtree( char * dirpath )
{
DIR * dirp;
struct dirent * dirent;
size_t pfxlen;
char * path;
int rval, rc;
int mmcnum;
struct stat statbuf;
if ( (dirp = opendir( dirpath )) == NULL )
return ERR;
pfxlen = strlen( dirpath ) + 1;
rval = OK;
while ( (dirent = readdir( dirp )) != NULL ) {
if (strcmp(dirent->d_name, ".." ) == 0) continue;
if (strcmp(dirent->d_name, "." ) == 0) continue;
path = malloc(pfxlen + strlen(dirent->d_name) + 1 );
if (path == NULL) {
rval = ERR;
break;
}
sprintf(path, "%s/%s", dirpath, dirent->d_name);
if (stat(path, &statbuf) == -1) {
rval = ERR;
break;
}
if (S_ISDIR(statbuf.st_mode)) {
rval = mmcputtree(path);
} else if (S_ISREG(statbuf.st_mode)) {
/* convert to IC35 name */
if ( (mmcnum = _ic35mmcpath( path, 1)) < 0 ) {
_mmcpatherror( mmcnum, path );
return ERR;
}
mmcput(path, NULL);
}
free(path);
}
rc = closedir( dirp );
if ( rval == OK ) rval = rc;
return rval; /* errcode of first failure or success OK */
}
static int
ic35mmcputtree( char * devname, char * ic35path)
{
int mmcnum;
int rval;
char * tmp;
/* check ic35path, check/set "MMCard" prefix and */
/* convert '/' to '\\', lowercase to uppercase */
tmp = strdup(ic35path);
mmcnum = _ic35mmcpath( tmp, 0 );
free(tmp);
if ( mmcnum < 0 ) {
_mmcpatherror( mmcnum, tmp );
return ERR;
}
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
if ( (rval = mmc_status( mmcnum )) == 0 ) {
message( "MMCard%d not present", mmcnum );
rval = ERR;
} else if (rval > 0)
rval = mmcputtree( ic35path );
mdisconnect();
return rval;
}
/* delete file on IC35 MMCard
* -------------------------
*/
static int
ic35mmcdel( char * devname, char * ic35path )
{
int mmcnum;
int rval;
/* check ic35path, check/set "MMCard" prefix and */
/* convert '/' to '\\', lowercase to uppercase */
if ( (mmcnum = _ic35mmcpath( ic35path, 0 )) < 0 ) {
_mmcpatherror( mmcnum, ic35path );
return ERR;
}
/* connect to IC35 in SyncStation via serial device */
if ( (rval = mconnect( devname, NULL )) != OK )
return rval;
/* get MMCard status (else delete MMCard file fails) */
if ( (rval = mmc_status( mmcnum )) > 0 ) {
message( "delete %s", ic35path );
rval = mmc_delfile( ic35path ); /* delete IC35 MMCard file */
} else if ( rval == 0 ) {
message( "MMCard%d not present", mmcnum );
rval = ERR;
}
/* disconnect from IC35 */
mdisconnect();
return rval;
}
/* -------------------- M A I N - program ----------------------------- */
static void
versinfo( void )
{
printf( "IC35manager for GNU/Linux %s (%s)\n", pkgvers, pkgdate );
printf( "%s\n", bldinfo );
printf(
"Copyright (C) 2001 Thomas Schulz\n"
"This is free software; see the GNU General Public Licence version 2 in\n"
"the file named COPYING for copying conditions. There is NO warranty.\n"
);
}
static void
usage( void )
{
static char * usetext[] = {
"usage: ic35mgr [option..] command [argument..]",
"commands and arguments are:",
" status [FILE] report IC35 status (and write to FILE)",
" backup FILE backup IC35 database to FILE",
" restore FILE restore IC35 database from FILE",
" mmcdir list contents of IC35 MMCard(s)",
" mmcdel IC35PATH delete MMCard file IC35PATH",
" mmcget IC35PATH [FILE] read FILE from IC35PATH on IC35 MMCard",
" mmcgettree [IC35PATH] read file tree starting at IC35PATH on IC35 MMCard",
" mmcput IC35PATH [FILE] write FILE to IC35PATH on IC35 MMCard",
" mmcputtree IC35PATH write file tree starting at IC35PATH to IC35 MMCard",
" IC35PATH e.g. MMCard1/ic35/app/reversi.app will be",
" converted to MMCard1\\IC35\\APP\\REVERSI.APP on IC35",
" filename FILE is taken from IC35PATH if absent",
"options in short and long form are:",
" -d DEV --device=DEV serial device with IC35 connected, default /dev/ic35",
" -b SIZE --blocksize=SIZE block size for mmcget / mmcput, default 5120 / 2048",
" -n NINC --nice=NINC lower process priority for restore,mmcput, default 2",
#ifndef NO_LOGSIM
" -l FILE --logfile=FILE log communications to FILE, default no logging",
" -s FILE --simfile=FILE simulate communication with IC35 using FILE",
" (create simulation FILE from logfile with 'ic35log')",
#endif
" -V --version show version information and exit",
" -h --help show this help and exit",
NULL
};
char ** lptr;
for ( lptr = usetext; *lptr != NULL; ++lptr )
printf( "%s\n", *lptr );
}
int
main( int argc, char *argv[] )
{
static struct option const long_opts[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "device", required_argument, NULL, 'd' },
{ "blocksize", required_argument, NULL, 'b' },
{ "nice", required_argument, NULL, 'n' },
#ifndef NO_LOGSIM
{ "logfile", required_argument, NULL, 'l' },
{ "simfile", required_argument, NULL, 's' },
#endif
{ NULL, 0, NULL, 0 }
};
char * devname = "/dev/ic35";
char * nicearg = "2";
char * command = NULL;
#ifndef NO_LOGSIM
char * logfname = NULL;
char * simfname = NULL;
#endif
int rval;
/*
* parse command line
*/
for ( ; ; ) {
switch ( getopt_long( argc, argv,
#ifndef NO_LOGSIM
"l:s:"
#endif
"d:b:hV", long_opts, NULL ) ) {
default: /* invalid option */
fprintf( stderr, "use 'ic35mgr --help' for more information\n" );
return 1;
case 'h': /* show Help and exit */
usage();
return 0;
case 'V': /* show Version and exit */
versinfo();
return 0;
case 'd': /* serial Device where IC35 */
devname = optarg;
continue;
case 'b': /* buffer size for mmcget,put */
blocksize = atoi( optarg );
continue;
case 'n': /* nice processs priority */
nicearg = optarg;
continue;
#ifndef NO_LOGSIM
case 'l': /* communication logfile */
logfname = optarg;
continue;
case 's': /* simulate: no communication */
simfname = optarg;
continue;
#endif /*NO_LOGSIM*/
case -1: /* end of options */
break;
}
break;
}
if ( argc < optind+1 ) {
fatal( "missing command\n"
"use 'ic35mgr --help' for more information" );
return 1;
}
if ( atoi( nicearg ) == 0 && !isdigit(*nicearg) ) {
fatal( "non-integer nice argument: %s", nicearg );
return 1;
}
com_waitnice( atoi( nicearg ) );
/*
* initial info to logfile: date,time, version, command line
* if 'logfname' is NULL or empty, nothing will be logged.
*/
LOG_INIT(( logfname, "ic35mgr", 0 ));
LOG_PROGINFO(( "ic35mgr", pkgvers, pkgdate, bldinfo ));
LOG_ARGSINFO(( argc, argv ));
/*
* setup simulated communication if requested
*/
COM_SIMINIT(( simfname ));
/*
* process command
*/
command = argv[optind]; /* note command */
argv += optind, argc -= optind; /* skip options */
rval = 1;
if ( strcmp( command, "status" ) == 0 ) {
if ( argc <= 2 )
rval = ic35mgrstat( devname, argc > 1 ? argv[1] /*???*/
: "/tmp/ic35.stat" );
else
error( "too many arguments" );
} else if ( strcmp( command, "backup" ) == 0 ) {
if ( argc == 2 )
rval = ic35backup( devname, argv[1] );
else
error( argc < 2 ? "missing backup file"
: "too many arguments" );
} else if ( strcmp( command, "restore" ) == 0 ) {
if ( argc == 2 )
rval = ic35restore( devname, argv[1] );
else
error( argc < 2 ? "missing restore file"
: "too many arguments" );
} else if ( strcmp( command, "mmcdir" ) == 0 ) {
if ( argc == 1 )
rval = ic35mmcdir( devname ) == OK ? 0 : 1;
else
error( "too many arguments" );
} else if ( strcmp( command, "mmcdel" ) == 0 ) {
if ( argc == 2 )
rval = ic35mmcdel( devname, argv[1] ) == OK ? 0 : 1;
else
error( argc < 2 ? "missing ic35path"
: "too many arguments" );
} else if ( strcmp( command, "mmcget" ) == 0 ) {
if ( argc == 2 || argc == 3 )
rval = ic35mmcget( devname, argv[1], argc == 3 ? argv[2] : NULL );
else
error( argc < 2 ? "missing ic35path"
: "too many arguments" );
} else if ( strcmp( command, "mmcgettree" ) == 0 ) {
if ( argc == 1 || argc == 2 )
rval = ic35mmcgettree( devname, argc == 2 ? argv[1] : NULL );
else
error( "too many arguments" );
} else if ( strcmp( command, "mmcput" ) == 0 ) {
if ( argc == 2 || argc == 3 )
rval = ic35mmcput( devname, argv[1], argc == 3 ? argv[2] : NULL );
else
error( argc < 2 ? "missing ic35path,file"
: "too many arguments" );
} else if ( strcmp( command, "mmcputtree" ) == 0 ) {
if ( argc == 2 )
rval = ic35mmcputtree( devname, argv[1]);
else
error( argc < 2 ? "missing ic35path,file"
: "too many arguments" );
} else {
error( "unsupported command: %s", command );
rval = 1;
}
if ( rval != OK )
rval = 1;
LOG_CLOSE(());
return rval;
}

980
src/ic35sync.c Normal file
View File

@ -0,0 +1,980 @@
/************************************************************************
* Copyright (C) 2000,2001 Thomas Schulz *
* */
static char rcsid[] =
"$Id: ic35sync.c,v 1.19 2001/03/02 02:10:42 tsch Rel $"; /*
* *
* IC35 synchronize PIM data *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
* conditional compile on NO_LOGSIM: if #defined, logging of the *
* IC35 communications as well as simulated communication are NOT *
* supported, default WITH logging and com-simulation support. *
* *
* for usage run ic35sync -h or see function usage() below. *
* *
************************************************************************/
#include <stdio.h> /* printf(), .. */
#include <string.h> /* strcmp(), .. */
#include <getopt.h> /* getopt(), optarg, .. */
#include <time.h> /* struct tm, time() .. */
#include "util.h" /* FALSE, .. */
#include "comio.h" /* com_siminit() */
#include "syntrans.h" /* IC35sync transactions */
#include "ic35frec.h" /* FILEADDR, .. */
#include "dataio.h" /* IC35sync import/export */
NOTUSED(rcsid)
extern char * pkgvers; /* these are all */
extern char * pkgdate; /* in versinfo.c, which is */
extern char * bldinfo; /* auto-generated by Makefile */
static const int fileids[4] = {
FILEADDR,
FILEMEMO,
FILESCHED,
FILETODO
};
/* report IC35 status
* ------------------
* show firmware version, sysinfo (date+time), total and modified
* number of records per IC35 file.
*/
static int
ic35status( char * devname, char * passwd )
{
int i, fileid;
int fd;
char * fname;
int nrec, nmod, nspc;
int rval;
char ic35dtime[16+1];
if ( (rval = connect( devname, passwd, ic35dtime )) != OK )
return rval;
for ( i = 0; i < sizeof(fileids)/sizeof(fileids[0]); ++i ) {
fileid = fileids[i];
rval = ERR;
if ( (fname = ic35fname( fileid )) == NULL ) {
error( "status failed: bad fileid %02X", fileid );
break;
}
LPRINTF(( L_INFO, "status fid=%02X \"%s\" ..", fileid, fname ));
if ( (fd = open_file( ic35fname( fileid ) )) >= 0 ) {
if ( (nrec = get_flen( fd )) >= 0 ) {
if ( (nmod = get_mod_flen( fd )) >= 0 ) {
if ( (nspc = 10 - strlen( fname )) < 0 ) nspc = 0;
message( "status \"%s\"%*s total %2d modified %2d records",
fname, nspc, "", nrec, nmod );
rval = OK;
} else
error( "status %s failed: get_mod_flen failed", fname );
} else
error( "status %s failed: get_flen failed", fname );
close_file( fd );
} else
error( "status %s failed: open_file failed", fname );
LPRINTF(( L_INFO, "status fid=%02X \"%s\" %s", fileid, fname,
rval == OK ? "OK" : "ERR" ));
if ( rval != OK )
break;
}
disconnect();
return rval;
}
/* run IC35 export session
* -----------------------
* read all IC35 records and export (i.e. add/update) to PIMfile:
* - set modified+created time in PIMrecord if added IC35 record
* - set modified time in PIMrecord if updated from IC35 record
* - do not change modified time in PIMrecord if same as IC35 record
* - set PIMrecord status to CLEAN if added/updated/same as IC35
* - set IC35 record-ID to added/updated PIMfile records
* changeflags of records in IC35 will not be reset,
* records in IC35 will not be modified/deleted, and
* sysinfo (date+time) will not be written to IC35.
* IC35 overrides PIMfile, PIMfile records not in IC35 remain untouched.
*/
static int
exportfile( int fileid )
{
char * fname;
int fd, nrec, irec;
IC35REC * rec;
int rval;
if ( (fname = ic35fname( fileid )) == NULL ) {
error( "export failed: bad fileid %02X", fileid );
return ERR;
}
LPRINTF(( L_INFO, "exportfile(fid=%02X) \"%s\" ..", fileid, fname ));
if ( (rec = new_ic35rec()) == NULL ) {
error( "export %s failed: no memory", fname );
return ERR;
}
if ( (fd = open_file( ic35fname( fileid ) )) < 0 ) {
error( "export %s failed: open_file failed", fname );
del_ic35rec( rec );
return ERR;
}
if ( (nrec = get_flen( fd )) < 0 ) {
error( "export %s failed: get_flen failed", fname );
close_file( fd );
del_ic35rec( rec );
return ERR;
}
message( "export \"%s\", %d records", fname, nrec );
rval = OK;
for ( irec = 0; irec < nrec; ++irec ) {
if ( read_frec( fd, irec, rec ) < 0 ) {
rval = ERR;
break;
}
pim_putic35rec( rec );
}
close_file( fd );
del_ic35rec( rec );
LPRINTF(( L_INFO, "exportfile(fid=%02X) \"%s\" %s",
fileid, fname, rval == OK ? "OK" : "ERR" ));
return rval;
}
static int
ic35export( char * devname, char * passwd )
{
int i, rval;
if ( (rval = connect( devname, passwd, NULL )) != 0 )
return rval;
for ( i = 0; i < sizeof(fileids)/sizeof(fileids[0]); ++i )
if ( (rval = exportfile( fileids[i] )) != OK )
break;
disconnect();
return rval;
}
/* maintain IC35 record table for import,sync
* ------------------------------------------
*/
enum ic35op { /* IC35 record operation */
IC35NOACT, /* 0 no action */
IC35DELETE, /* 1 delete record */
IC35WRITE, /* 2 write new record */
IC35UPDATE, /* 3 re-write existing record */
IC35COMMIT, /* 4 commit clears changeflag */
};
struct recop { /* IC35 record,op entry */
IC35REC * rec; /* ptr to IC35 record */
enum ic35op op; /* record operation to do */
void * pim; /* ptr to PIM record */
};
static struct recop * _ic35rectab;
static size_t _ic35rectablen;
#define ADD_CHUNKS 64
/* put IC35 record and action into table
* -------------------------------------
* if record already in table, just update action
* if free entry available, put record,action there
* if table full or not allocated yet, make it bigger
* in chunks of
*/
static void
_put_ic35recs( IC35REC * ic35rec, enum ic35op action, void * pimrec )
{
int i;
struct recop * ntab;
size_t nlen;
for ( i = 0; i < _ic35rectablen; ++i ) {
if ( _ic35rectab[i].rec == ic35rec ) {
_ic35rectab[i].op = action;
_ic35rectab[i].pim = pimrec;
return;
}
if ( _ic35rectab[i].rec == NULL )
break;
}
if ( i >= _ic35rectablen ) {
nlen = _ic35rectablen + ADD_CHUNKS;
if ( (ntab = realloc( _ic35rectab, nlen * sizeof(ntab[0]) )) == NULL )
return;
memset( ntab+_ic35rectablen, 0, ADD_CHUNKS * sizeof(ntab[0]) );
_ic35rectab = ntab;
_ic35rectablen = nlen;
}
_ic35rectab[i].rec = ic35rec;
_ic35rectab[i].op = action;
_ic35rectab[i].pim = pimrec;
}
/* get IC35 record and action from table
* -------------------------------------
* if non-zero 'recid' lookup IC35 record with that record-ID,
* otherwise just retrieve first non-NULL record in table.
* pass action associated with record to non-NULL 'paction'.
* the record will be removed from table !
*/
static IC35REC *
_get_ic35recs( ulong recid, enum ic35op * paction, void ** ppimrec )
{
int i;
IC35REC * rec;
for ( i = 0; i < _ic35rectablen; ++i ) {
if ( (rec = _ic35rectab[i].rec) == NULL )
continue;
if ( recid == 0 || ic35recid( rec ) == recid ) {
if ( paction ) *paction = _ic35rectab[i].op;
if ( ppimrec ) *ppimrec = _ic35rectab[i].pim;
_ic35rectab[i].op = IC35NOACT;
_ic35rectab[i].rec = NULL;
return rec;
}
}
return NULL;
}
/* delete IC35 record table
* ------------------------
* release all non-NULL records in table, then release table
* return number of records yet in table, used by "import" to
* detect records in IC35 but not in PIMfile.
*/
static int
_del_ic35recs( void )
{
int i;
int only_ic35;
for ( i = only_ic35 = 0; i < _ic35rectablen; ++i )
if ( _ic35rectab[i].rec != NULL ) {
++only_ic35; /* IC35 record not in PIMfile */
del_ic35rec( _ic35rectab[i].rec );
}
free( _ic35rectab );
_ic35rectab = NULL;
_ic35rectablen = 0;
return only_ic35; /* num.of records not in PIMfile */
}
/* run IC35 import session
* -----------------------
* read all records from IC35 and compare with PIMfile
* - update PIMrecord to IC35 if same record-ID on IC35
* - write PIMrecord to IC35 if record not on IC35
* and write back new IC35 record-ID to PIMrecord
* - reset IC35 record changeflag if same as PIMrecord
* - set PIMrecord status to CLEAN
* - owner address data must be written with update_frec() and recID 1
* otherwise on IC35 in category "Address", but not as owner data
* do not delete records neither in IC35 nor in PIMfile
* write sysinfo (date+time) if all IC35 records match PIMfile
* PIMfile overrides IC35, IC35 records not in PIMfile remain untouched,
* sysinfo (date+time) is not written if any IC35 record not in PIMfile.
*/
static int
importfile( int fileid, char * ic35dtime )
{
char * fname;
int fd, nrec, irec;
IC35REC * ic35rec;
void * pimrec;
ulong recid;
int n_write, n_update, n_commit;
int ic35_not_in_PIM;
enum ic35op action;
char * actext;
int rc, rval;
if ( (fname = ic35fname( fileid )) == NULL ) {
error( "import failed: bad fileid %02X", fileid );
return ERR;
}
LPRINTF(( L_INFO, "importfile(fid=%02X) \"%s\" ..", fileid, fname ));
if ( (fd = open_file( ic35fname( fileid ) )) < 0 ) {
error( "import %s failed: open_file failed", fname );
return ERR;
}
if ( (nrec = get_flen( fd )) < 0 ) {
error( "import %s failed: get_flen failed", fname );
close_file( fd );
return ERR;
}
/*
* read all IC35-records and note them
*/
message( "import \"%s\", read %d records", fname, nrec );
rval = OK;
for ( irec = 0; irec < nrec; ++irec ) {
if ( (ic35rec = new_ic35rec()) == NULL ) {
error( "import %s failed: no memory for ic35rec", fname );
rval = ERR;
break;
}
if ( read_frec( fd, irec, ic35rec ) < 0 ) {
rval = ERR;
break;
}
_put_ic35recs( ic35rec, IC35NOACT, NULL );
}
if ( rval != OK ) {
close_file( fd );
LPRINTF(( L_INFO, "importfile(fid=%02X) \"%s\" rval=ERR", fileid,fname ));
return rval;
}
/*
* compare all PIM-records with IC35-records, and do:
* - if PIM-record not in IC35, write it to IC35
* and write back record-ID from IC35 to PIM-record,
* - if different update IC35-record with PIM-record,
* - if same commit to IC35 if non-zero changeflag in IC35.
* mark all PIM-records CLEAN as they are now same as IC35.
* collect IC35 records with actions to do.
*/
n_write = n_update = n_commit = 0;
pim_rewind();
while ( (pimrec = pim_getrec( fileid )) != NULL ) {
if ( (recid = pim_recid( pimrec )) != 0 /* PIM record-ID on IC35 */
&& (ic35rec = _get_ic35recs( recid, NULL, NULL )) != NULL ) {
if ( pim_cmpic35rec( ic35rec, pimrec ) == 0 ) {
if ( ic35recchg( ic35rec ) == IC35_CLEAN ) {
del_ic35rec( ic35rec ); /* same as PIM, unchanged */
continue; /* no need for commit */
}
action = IC35COMMIT; /* same as PIM, commit it */
++n_commit;
} else {
action = IC35UPDATE; /* different, update rec */
++n_update;
}
} else { /* PIMrecord not on IC35 */
ic35rec = new_ic35rec();
if ( recid == FileRecId(FILEADDR,1) ) {
action = IC35UPDATE; /* must update owner-addr */
++n_update;
} else {
action = IC35WRITE; /* write new IC35 record */
++n_write;
}
}
pim_updic35rec( ic35rec, pimrec ); /* PIM update/new to IC35 */
_put_ic35recs( ic35rec, action, pimrec ); /* add action and PIMrec */
}
/*
* execute actions on IC35 records collected above.
* count records with no action, i.e. only existing
* on IC35, but not in PIMfile.
*/
message( "import \"%s\", write %d update %d commit %d records",
fname, n_write, n_update, n_commit );
ic35_not_in_PIM = 0;
while ( (ic35rec = _get_ic35recs( 0, &action, &pimrec )) != NULL ) {
rc = 0; actext = "";
switch ( action ) {
case IC35COMMIT:
actext = "commit";
rc = commit_frec( fd, ic35recid( ic35rec ) );
break;
case IC35UPDATE:
actext = "update";
rc = update_frec( fd, ic35rec );
break;
case IC35WRITE:
actext = "write";
rc = write_frec( fd, ic35rec );
break;
default:
++ic35_not_in_PIM;
continue;
}
if ( rc >= 0 ) { /* commit/update/write success */
if ( pimrec != NULL ) {
pim_set_recid( pimrec, ic35recid( ic35rec ) );
pim_set_recstat( pimrec, PIM_CLEAN );
}
} else { /* commit/update/write failed */
error( "import %s failed: %s_frec failed", fname, actext );
rval = ERR;
}
del_ic35rec( ic35rec );
}
_del_ic35recs();
if ( rval == OK )
rval = ic35_not_in_PIM; /* any IC35 records not in PIMfile */
close_file( fd );
LPRINTF(( L_INFO, "importfile(fid=%02X) \"%s\" rval=%d",
fileid, fname, rval ));
return rval;
}
static int
ic35import( char * devname, char * passwd )
{
int i, rc, rval;
bool ic35_same_as_PIM;
char ic35dtime[16+1];
if ( (rval = connect( devname, passwd, ic35dtime )) != 0 )
return rval;
set_oldic35dt( ic35dtime );
rval = OK;
ic35_same_as_PIM = TRUE;
for ( i = 0; i < sizeof(fileids)/sizeof(fileids[0]); ++i )
if ( (rc = importfile( fileids[i], ic35dtime )) != OK ) {
ic35_same_as_PIM = FALSE;
if ( rc < 0 ) {
rval = rc;
break;
}
}
if ( ic35_same_as_PIM ) {
get_newic35dt( ic35dtime );
WriteSysInfo( ic35dtime );
}
disconnect();
return rval;
}
/* run IC35 sync session
* ---------------------
* update PIMfile with IC35 changes (modify/delete) and vice versa
* - phase-0: initial export if PIMfile does not contains any records
* otherwise phase-3 below would delete all unmodified records on IC35,
* as they are regarded deleted from PIMfile.
* - phase-1a: update records modified/deleted on IC35 to PIMfile
* read all modified records from IC35, if unchanged in PIMfile:
* - delete from PIMfile if deleted on IC35,
* - update from IC35 to PIMfile if modified on IC35.
* note IC35-recID for commit (commit now would disturb read_mod_frec)
* conflict if record changed in IC35 AND also in PIMfile, resolve:
* - PIMfile overrides IC35: update from PIMrecord to IC35record
* will be done in next phase below (now would disturb read_mod_frec),
* - IC35 overrides PIMfile: update from IC35record to PIMrecord
* ??? ? add changed record on IC35/PIM to PIM/IC35 with conflict mark
* - phase-1b: commit handled IC35 changes to IC35
* commits noted above to avoid disturbing read_mod_frec, now do them.
* - phase-2: update records modified in PIMfile to IC35
* - if record exists on IC35, i.e. has record-ID,
* read record by ID from IC35, update with PIMrecord
* write record to IC35
* - if record is new in PIMfile (no record-ID)
* create IC35 record from PIMrecord, write to IC35
* and writeback new IC35 record-ID to PIMrecord
* - phase-3a: records deleted from PIMfile are detected by reading
* all records from IC35 and check if record in PIMfile
* ??? sanity check IC35 changeflags clean
* - PIMfile overrides IC35: note IC35-recID for delete
* (delete now would disturb read_frec)
* - IC35 overrides PIMfile: re-create PIMrecord from IC35 record
* - phase-3b: delete records on IC35
* deletes were noted above to avoid disturbing read_frec, now do them.
* now there should be no more pending changes neither in IC35 nor in PIM.
* write sysinfo (date+time) as now all IC35 records (shall) match PIMfile
*/
static int
syncfile( int fileid, char * ic35dtime )
{
char * fname;
bool initexp;
int fd, nrec, irec;
IC35REC * ic35rec;
void * pimrec;
ulong recid;
enum ic35op action;
int n_commit, n_delete;
int rc, rval;
if ( (fname = ic35fname( fileid )) == NULL ) {
error( "sync failed: bad fileid %02X", fileid );
return ERR;
}
/*
* phase-0: initial export if PIMfile does not contains any records
* otherwise phase-3 below would delete all unmodified records on IC35
*/
initexp = FALSE;
pim_rewind();
if ( pim_getrec( fileid ) == NULL ) {
message( "sync \"%s\", no PIM records: initial export", fname );
if ( (rval = exportfile( fileid )) != OK )
return rval;
initexp = TRUE;
}
LPRINTF(( L_INFO, "syncfile(fid=%02X) \"%s\" ..", fileid, fname ));
if ( (fd = open_file( ic35fname( fileid ) )) < 0 ) {
error( "sync %s failed: open_file failed", fname );
return ERR;
}
/*
* phase-1a: update records modified/deleted on IC35 to PIMfile
* read all modified records from IC35, if unchanged in PIMfile:
* - delete from PIMfile if deleted on IC35,
* - update from IC35 to PIMfile if modified on IC35.
* note IC35-recID for commit (commit now would disturb read_mod_frec)
* conflict if record changed in IC35 AND also in PIMfile, resolve:
* - PIMfile overrides IC35: update from PIMrecord to IC35record
* will be done in next phase below (now would disturb read_mod_frec),
* - IC35 overrides PIMfile: update from IC35record to PIMrecord
* ? add changed record on IC35/PIM to PIM/IC35 with conflict mark ???
*/
if ( (nrec = get_mod_flen( fd )) < 0 ) {
error( "sync %s failed: get_mod_flen failed", fname );
close_file( fd );
return ERR;
}
message( "sync \"%s\", read %d modified records%s",
fname, nrec, nrec > 0 ? ", update PIM" : "" );
n_commit = 0;
rval = OK;
for ( irec = 0; irec < nrec; ++irec ) {
if ( (ic35rec = new_ic35rec()) == NULL ) {
error( "sync %s failed: no memory", fname );
rval = ERR;
break;
}
if ( read_mod_frec( fd, ic35rec ) < 0 ) {
error( "sync %s failed: read_mod_frec failed", fname );
rval = ERR;
break;
}
if ( (pimrec = pim_getrec_byID( ic35recid( ic35rec ) )) == NULL
|| pim_recstat( pimrec ) == PIM_CLEAN ) {
switch ( ic35recchg( ic35rec ) ) {
case IC35_NEW:
case IC35_MOD:
pim_putic35rec( ic35rec );
break;
case IC35_DEL:
if ( pimrec )
pim_delrec( pimrec );
break;
}
_put_ic35recs( ic35rec, IC35COMMIT, NULL );
++n_commit;
} else {
; /*??? CONFLICT: changed on both sides */
}
}
/*
* phase-1b: commit handled IC35 changes to IC35
* commits noted above to avoid disturbing read_mod_frec, now do them.
*/
if ( rval == OK && n_commit > 0 ) {
message( "sync \"%s\", commit %d IC35 records", fname, n_commit );
while ( (ic35rec = _get_ic35recs( 0, &action, NULL )) != NULL ) {
if ( action == IC35COMMIT
&& commit_frec( fd, ic35recid( ic35rec ) ) < 0 ) {
error( "sync %s failed: commit_frec failed", fname );
rval = ERR;
break;
}
del_ic35rec( ic35rec );
}
}
_del_ic35recs();
if ( rval != OK ) {
close_file( fd );
LPRINTF(( L_INFO, "syncfile(fid=%02X) \"%s\" rval=ERR", fileid,fname ));
return rval;
}
/*
* if initial export was done, update from PIM to IC35 and
* check records removed from PIM and delete is not needed.
*/
if ( initexp ) {
close_file( fd );
LPRINTF(( L_INFO, "syncfile(fid=%02X) \"%s\" rval=OK", fileid, fname ));
return rval;
}
/*
* phase-2: update records modified in PIMfile to IC35
* - if record exists on IC35, i.e. has record-ID,
* read record by ID from IC35, update with PIMrecord
* write record to IC35
* - if record is new in PIMfile (no record-ID)
* create IC35 record from PIMrecord, write to IC35
* and writeback new IC35 record-ID to PIMrecord
*/
if ( (ic35rec = new_ic35rec()) == NULL ) {
close_file( fd );
error( "sync %s failed: no memory", fname );
return ERR;
}
message( "sync \"%s\", update IC35", fname );
pim_rewind();
while ( rval == OK && (pimrec = pim_getrec( fileid )) != NULL ) {
switch ( pim_recstat( pimrec ) ) {
case PIM_CLEAN:
continue;
case PIM_DEL:
if ( (recid = pim_recid( pimrec )) != 0 ) {
if ( delete_frec( fd, recid ) >= 0 ) {
pim_delrec( pimrec );
} else {
error( "sync %s failed: delete_frec failed", fname );
rval = ERR;
}
}
continue;
default:
error( "bad PIM record status: %d", pim_recstat( pimrec ) );
/* full through and handle as PIM_DIRTY */
case PIM_DIRTY:
if ( (recid = pim_recid( pimrec )) != 0 ) { /* PIMrec on IC35 */
if ( (rc = read_id_frec( fd, recid, ic35rec )) < 0 ) {
error( "sync %s failed: read_id_frec failed", fname );
rval = ERR;
break;
}
if ( rc > 0 ) { /* PIMrec found on IC35 */
pim_updic35rec( ic35rec, pimrec );
if ( update_frec( fd, ic35rec ) >= 0 ) {
pim_set_recstat( pimrec, PIM_CLEAN );
} else {
error( "sync %s failed: update_frec failed", fname );
rval = ERR;
}
}
break;
} /* PIMrecord not on IC35 */
set_ic35recdata( ic35rec, NULL, 0 );
pim_updic35rec( ic35rec, pimrec );
if ( write_frec( fd, ic35rec ) >= 0 ) {
pim_set_recid( pimrec, ic35recid( ic35rec ) );
pim_set_recstat( pimrec, PIM_CLEAN );
} else {
error( "sync %s failed: write_frec failed", fname );
rval = ERR;
}
break;
}
}
del_ic35rec( ic35rec ); ic35rec = NULL;
if ( rval != OK ) {
close_file( fd );
LPRINTF(( L_INFO, "syncfile(fid=%02X) \"%s\" rval=ERR", fileid,fname ));
return rval;
}
/*
* phase-3a: records deleted from PIMfile are detected by reading
* all records from IC35 and check if record in PIMfile
* ? sanity check IC35 changeflags clean ???
* - PIMfile overrides IC35: note IC35-recID for delete
* (delete now would disturb read_frec)
* - IC35 overrides PIMfile: re-create PIMrecord from IC35 record
*/
if ( (nrec = get_flen( fd )) < 0 ) {
error( "sync %s failed: get_flen failed", fname );
close_file( fd );
return ERR;
}
message( "sync \"%s\", read %d records, check PIM deleted", fname, nrec );
n_delete = 0;
for ( irec = 0; irec < nrec; ++irec ) {
if ( (ic35rec = new_ic35rec()) == NULL ) {
error( "sync %s failed: no memory", fname );
rval = ERR;
break;
}
if ( read_frec( fd, irec, ic35rec ) < 0 ) {
error( "sync %s failed: read_frec failed", fname );
rval = ERR;
break;
}
if ( pim_getrec_byID( ic35recid( ic35rec ) ) ) {
del_ic35rec( ic35rec );
continue;
}
/*??? sanity check ic35recchg() == 0 ? */
/*??? if PIM overrides IC35 */
_put_ic35recs( ic35rec, IC35DELETE, NULL );
++n_delete;
/*??? if IC35 overrides PIM */
/*??? pim_putic35rec( ic35rec ); */
}
/*
* phase-3b: delete records on IC35
* deletes were noted above to avoid disturbing read_frec, now do them.
*/
if ( rval == OK && n_delete ) {
message( "sync \"%s\", delete %d IC35 records", fname, n_delete );
while ( (ic35rec = _get_ic35recs( 0, &action, NULL )) != NULL ) {
if ( action == IC35DELETE
&& delete_frec( fd, ic35recid( ic35rec ) ) < 0 ) {
error( "sync %s failed: delete_frec failed", fname );
rval = ERR;
break;
}
del_ic35rec( ic35rec );
}
}
_del_ic35recs();
close_file( fd );
LPRINTF(( L_INFO, "syncfile(fid=%02X) \"%s\" rval=%d",
fileid, fname, rval ));
return rval;
}
static int
ic35sync( char * devname, char * passwd )
{
int i, rval;
char ic35dtime[16+1];
if ( (rval = connect( devname, passwd, ic35dtime )) != 0 )
return rval;
set_oldic35dt( ic35dtime );
for ( i = 0; i < sizeof(fileids)/sizeof(fileids[0]); ++i ) {
if ( (rval = syncfile( fileids[i], ic35dtime )) != OK )
break;
}
if ( rval == OK ) {
get_newic35dt( ic35dtime );
WriteSysInfo( ic35dtime );
}
disconnect();
return rval;
}
/* -------------------- M A I N - program ----------------------------- */
static void
versinfo( void )
{
printf( "IC35sync for GNU/Linux %s (%s)\n", pkgvers, pkgdate );
printf( "%s\n", bldinfo );
printf(
"Copyright (C) 2000,2001 Thomas Schulz\n"
"This is free software; see the GNU General Public Licence version 2 in\n"
"the file named COPYING for copying conditions. There is NO warranty.\n"
);
}
static void
usage( void )
{
static char * usetext[] = {
"usage: ic35sync [option..] command [pimfile..]",
"commands are:",
" sync synchronize IC35 with pimfile(s) data",
" export read all data from IC35 and write to pimfile(s)",
" import write to IC35 all data read from pimfile(s)",
" status report IC35 status (no pimfile access)",
"pimfile contains local Personal Information Management data,",
"e.g. in vCard/vCalendar format.",
"options in short and long form are:",
" -d DEV --device=DEV serial device with IC35 connected, default /dev/ic35",
" -p TEXT --password=TEXT password TEXT on IC35, default none",
" -f FORM --format=FORM format of pimfile(s), FORM and default pimfile(s):",
" vca (default) vCard,vCalendar,Memo, ic35.vcard ic35.vcal ic35.memo",
" txt (export only) plain text, ic35.txt",
" bin raw binary data, ic35.bin",
#ifndef NO_LOGSIM
" -l FILE --logfile=FILE log communications to FILE, default no logging",
" -s FILE --simfile=FILE simulate communication with IC35 using FILE",
" (create simulation FILE from logfile with 'ic35log')",
#endif
" -V --version show version information and exit",
" -h --help show this help and exit",
NULL
};
char ** lptr;
for ( lptr = usetext; *lptr != NULL; ++lptr )
printf( "%s\n", *lptr );
}
int
main( int argc, char *argv[] )
{
static struct option const long_opts[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "device", required_argument, NULL, 'd' },
{ "password", required_argument, NULL, 'p' },
{ "format", required_argument, NULL, 'f' },
#ifndef NO_LOGSIM
{ "logfile", required_argument, NULL, 'l' },
{ "simfile", required_argument, NULL, 's' },
#endif
{ NULL, 0, NULL, 0 }
};
char * passwd = "";
char * devname = "/dev/ic35";
char * pimfmtstr = "vca";
char * command = NULL;
char * pimaddrfname = NULL;
char * pimvcalfname = NULL;
char * pimmemofname = NULL;
#ifndef NO_LOGSIM
char * logfname = NULL;
char * simfname = NULL;
#endif
int rval;
/*
* parse command line
*/
for ( ; ; ) {
switch ( getopt_long( argc, argv,
#ifndef NO_LOGSIM
"l:s:"
#endif
"d:p:f:hV", long_opts, NULL ) ) {
default:
fprintf( stderr, "use 'ic35sync --help' for more information\n" );
return 1;
case 'h': /* show Help and exit */
usage();
return 0;
case 'V': /* show Version and exit */
versinfo();
return 0;
case 'd': /* serial Device where IC35 */
devname = optarg;
continue;
case 'p': /* password on IC35 */
passwd = optarg;
continue;
case 'f': /* format of PIMfile */
pimfmtstr = optarg;
continue;
#ifndef NO_LOGSIM
case 'l': /* communication logfile */
logfname = optarg;
continue;
case 's': /* simulate: no communication */
simfname = optarg;
continue;
#endif/*NO_LOGSIM*/
case -1: /* end of options */
break;
}
break;
}
if ( argc < optind+1 ) {
error( "missing command\n"
"use 'ic35sync --help' for more information" );
return 1;
}
command = argv[optind];
/*
* initial info to logfile: date,time, version, command line
* if 'logfname' is NULL or empty, nothing will be logged.
*/
LOG_INIT(( logfname, "ic35sync", 0 ));
LOG_PROGINFO(( "ic35sync", pkgvers, pkgdate, bldinfo ));
LOG_ARGSINFO(( argc, argv ));
/*
* setup simulated communication if requested
*/
COM_SIMINIT(( simfname ));
/*
* status command does not use pimfile(s)
*/
if ( strcmp( command, "status" ) == 0 ) {
rval = ic35status( devname, passwd ) == OK ? 0 : 1;
LOG_CLOSE(());
return rval;
}
/*
* defaults for filenames are:
* - no filename
* use defaults depending on format
* - text format ic35.txt
* - binary format ic35.bin
* - vCard,vCal format ic35.vcard, ic35.vcal, ic35.memo
* - 1 filename
* Addresses, Schedule,ToDo, Memo all in 1 file
* - 2 filenames
* Addresses to 1st file, Schedule,ToDo,Memo to 2nd file
* - 3 filenames
* Addresses to 1st file, Schedule,ToDo to 2nd, Memo to 3rd
*/
if ( set_pim_format( pimfmtstr ) != OK ) {
error( "unknown format: %s", pimfmtstr );
return 1;
}
argv += optind, argc -= optind; /* skip to non-option arguments */
switch ( argc ) {
default:
error( "max. 3 pimfiles supported, have %d", argc - 1 );
return 1;
case 4: /* 3 filenames */
pimmemofname = argv[3];
/* fall through */
case 3: /* 2 filenames */
pimvcalfname = argv[2];
/* fall through */
case 2: /* 1 filename */
pimaddrfname = argv[1];
break;
case 1: /* no filename */
switch ( pim_format() ) {
case PIM_TXT:
pimaddrfname = "ic35.txt";
break;
case PIM_BIN:
pimaddrfname = "ic35.bin";
break;
case PIM_VCA:
pimaddrfname = "ic35.vcard";
pimvcalfname = "ic35.vcal";
pimmemofname = "ic35.memo";
break;
}
break;
}
if ( pim_open( pimaddrfname, pimvcalfname, pimmemofname ) != OK ) {
error( "failed to open pimfile(s): %s %s %s\n",
pimaddrfname,
pimvcalfname ? pimvcalfname : "",
pimmemofname ? pimmemofname : "" );
return 1;
}
/*
* process command
*/
if ( strcmp( command, "export" ) == 0 ) {
rval = ic35export( devname, passwd ) == OK ? 0 : 1;
} else if ( strcmp( command, "import" ) == 0 ) {
rval = ic35import( devname, passwd ) == OK ? 0 : 1;
} else if ( strcmp( command, "sync" ) == 0 ) {
rval = ic35sync( devname, passwd ) == OK ? 0 : 1;
} else {
error( "unsupported command: %s", command );
rval = 1;
}
pim_close();
LOG_CLOSE(());
return rval;
}

951
src/mgrproto.c Normal file
View File

@ -0,0 +1,951 @@
/************************************************************************
* Copyright (C) 2001 Thomas Schulz *
* */
static char rcsid[] =
"$Id: mgrproto.c,v 1.17 2001/11/20 23:08:35 thosch Exp $"; /*
* *
* IC35 manager protocol *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
* IC35 manager protocol *
* Mcmdrsp send command-byte, get+check response-byte *
* Msendblk send datablock, test checksum, ack/retry *
* Mrecvblk receive datablock, test checksum, ack/retry *
* MMCard access protocol *
* MMCsend send MMCard command using Msendblk *
* MMCrecv receive MMCard response using Mrecvblk *
* MMCard commands *
* MMCgetstatus check if MMCard present / absent *
* MMCgetlabel get MMCard label *
* MMCdiropen open MMCard directory *
* MMCdirgetlen get number of entries in MMCard directory *
* MMCdirread read MMCard directory entry *
* MMCdirclose close MMCard directory *
* MMCfiledel delete MMCard file *
* MMCfileopen open MMCard file *
* MMCfilestat get MMCard file attributes *
* MMCfileread read block from MMCard file *
* MMCfilewrite write block to MMCard file *
* MMCfileclose close MMCard file *
* *
************************************************************************/
#include <stdlib.h> /* malloc(), .. */
#include <string.h> /* memcpy(), .. */
#include "util.h" /* ERR,OK, uchar, .. */
#include "comio.h" /* com_send(), .. */
#include "genproto.h" /* putxxx(),getxxx() .. */
#include "mgrproto.h"
NOTUSED(rcsid)
#define MAXRETRY 5 /* max.retries for manager protocol */
/* ==================================== */
/* IC35 manager protocol */
/* ==================================== */
/* send command-byte, get+check response-byte
* ------------------------------------------
*/
int
Mcmdrsp( uchar cmd, uchar rsp )
{
uchar rbyte;
int retry;
for ( retry = 0; retry < MAXRETRY; ++retry ) {
com_send( &cmd, sizeof(cmd) );
if ( com_recv( &rbyte, sizeof(rbyte) ) == sizeof(rbyte)
&& rbyte == rsp )
return OK;
}
return ERR;
}
/* local: send/receive block and ack or nak,retry
* ----------------------------------------------
* used by Msendblk(), Mrecvblk() for ack- or nak-handshake and retry,
* the trasnsmit function _sendblk(), _recvblk() is passed as function
* pointer 'pfxmit' and will set the appropriate timeout(s).
*/
static int
_xmitblk( uchar * data, size_t dlen, int pfxmit(uchar* data, size_t dlen) )
{
int old_tmo;
int retry;
int rval = ERR;
com_settimeout( old_tmo = com_settimeout( 0 ) );
for ( retry = 0; retry < MAXRETRY+1; ++retry ) {
rval = (*pfxmit)( data, dlen ); /* xmit data, recv csum */
if ( rval == dlen ) { /* datablock xmit OK */
if ( Mcmdrsp( MCMDposack, MRSPgotack ) != OK )
rval = ERR_acknak;
break;
} else if ( rval != ERR_recv /* bad checksum/length */
&& retry < MAXRETRY ) { /* and retries left */
if ( Mcmdrsp( MCMDnegack, MRSPgotack ) != OK ) {
rval = ERR_acknak;
break;
}
continue;
} else /* recv.err / timeout */
break; /* or out of retries */
}
com_settimeout( old_tmo );
return rval;
}
/* send block and ack/retry
* ------------------------
* send database block, receive checksum and test it, on success send
* acknowledge, receive ready response and return OK.
* on failure send nak and retry, after max.retries return ERR.
* -> (block of 'dlen' bytes)
* set timeout 10.0 sec
* <- cc_cc got them, checksum is cc_cc (arithmetic, LSB first)
* set timeout 3.0 sec
* -> 60 positive acknowledge
* <- A0 got ack
* on checksum mismatch send negative acknowledge:
* -> 62 negative acknowledge
* <- A0 got nak
* and restart send block.
* the long "(block of 'dlen' bytes)" must be sent with waiting!
*/
static int
_sendblk( uchar * data, size_t dlen )
{
uchar rcsum[2];
int lcsum;
ushort cksum;
int rval;
com_sendw( data, dlen ); /* -> data (with wait) */
com_settimeout( 10000 ); /* timeout 10.0 sec for chksum */
if ( (lcsum = com_recv( rcsum, sizeof(rcsum) )) /* <- checksum */
== sizeof(rcsum)
&& (cksum = chksum( data, dlen ))
== getword( rcsum ) ) {
rval = dlen;
} else {
if ( lcsum == sizeof(rcsum) ) { /* checksum mismatch */
LPRINTF(( L_NOISE, "_senddblk: chksum=%04X mismatch", cksum ));
rval = ERR_chksum;
} else /* recv.error / timeout */
rval = ERR_recv;
}
LPRINTF(( L_NOISE, "_sendblk(data,%d) = %d", dlen, rval ));
com_settimeout( 3000 ); /* timeout 3.0 sec ack/nak resp */
return rval;
}
int
Msendblk( uchar * data, size_t dlen )
{
return _xmitblk( data, dlen, _sendblk );
}
/* receive block and ack/retry
* ---------------------------
* receive data block, on success acknowledge and return OK.
* on failure send nak and retry, after max.retries return ERR.
* set timeout 2.0 sec
* <- (block of 'blen' bytes) cc_cc (arithmetic sum, LSB first)
* -> 60 positive acknowledge
* <- A0 got ack
* on mismatch of checksum or length, send negative acknowledge:
* -> 62 negative acknowledge
* <- A0 got nak
* and restart receive block.
*/
static int
_recvblk( uchar * buff, size_t blen )
{
uchar rcsum[2];
ushort cksum;
int lcsum;
int rval;
rcsum[0] = rcsum[1] = (uchar)0x00;
com_settimeout( 2000 ); /* timeout 2.0 sec for data,ack */
if ( (rval = com_recv( buff, blen )) >= 2 /* <- data */
&& (lcsum = com_recv( rcsum, sizeof(rcsum)) ) >= 0 ) { /* <- csum */
if ( lcsum == 1 ) {
rcsum[1] = buff[--rval]; /* take .. */
rcsum[0] = buff[--rval]; /* .. checksum bytes .. */
} else if ( lcsum == 0 ) {
rcsum[1] = rcsum[0]; /* .. from .. */
rcsum[0] = buff[--rval]; /* .. end of datablock */
}
if ( (cksum = chksum( buff, rval )) != getword( rcsum ) ) {
LPRINTF(( L_NOISE, "_recvblk: chksum=%04X mismatch", cksum ));
rval = ERR_chksum; /* checksum mismatch */
}
} else
rval = ERR_recv; /* too short for chksum */
LPRINTF(( L_NOISE, "_recvblk(buff,%d) = %d", blen, rval ));
return rval;
}
int
Mrecvblk( uchar * buff, size_t blen )
{
return _xmitblk( buff, blen, _recvblk );
}
/* ==================================== */
/* MMCard access protocol */
/* ==================================== */
/*
* protocol of MMCard operations
* MMCsend
* use timeout 0.5 sec
* -> 15 are you there ?
* <- 90 yes i am here !
* -> nn_nn expect nn_nn bytes from me
* <- E0 ok, send them
* sendretry:
* -> (block of nn_nn bytes)
* set timeout 10.0 sec
* <- cc_cc got them, checksum is cc_cc (arithmetic, LSB first)
* set timeout 3.0 sec
* -> 60 ack
* <- A0 got ack
* on checksum mismatch send negative acknowledge:
* -> 62 nak
* <- A0 got nak
* and restart at sendretry.
* the long "(block of nn_nn bytes)" must be sent with waiting!
* the blocklength nn_nn must be sent with wait before 1st byte!
* MMCrecv
* set timeout 5.0 sec
* <- nn_nn expect nn_nn bytes plus trailing checksum
* -> E0 ok, send them
* recvretry:
* <- (block of nn_nn bytes) cc_cc (arithmetic sum, LSB first)
* -> 60 ack
* <- A0 got ack
* on mismatch of checksum or length, send negative acknowledge:
* -> 62 nak
* <- A0 got nak
* and restart at recvretry.
*/
/* send MMCard command
* -------------------
*/
static int
MMCsend( uchar * sbuff, size_t slen )
{
uchar rchar;
uchar slbuff[2];
int rval;
if ( Mcmdrsp( MCMDmmcard, MRSPgotcmd ) == OK ) { /* -> 15 */
putword( slbuff, slen ); /* <- 90 */
com_sendw( slbuff, sizeof(slbuff) ); /* -> nn_nn (with wait) */
if ( com_recv( &rchar, 1 ) == 1 /* <- E0 */
&& rchar == MRSPgotlen ) {
rval = Msendblk( sbuff, slen ); /* send cmd, ack/retry */
if ( rval != slen ) /* Msendblk() bad length */
rval = ERR;
} else /* com_recv() MRSPgotlen failed */
rval = ERR;
} else /* Mcmdrsp() failed */
rval = ERR;
return rval;
}
/* receive MMCard response
* -----------------------
*/
static int
MMCrecv( uchar ** prbuff )
{
int old_tmo;
uchar rlbuff[2];
size_t rblen;
uchar rspgotlen = MRSPgotlen;
uchar * rbuff;
int rval;
old_tmo = com_settimeout( 5000 );
if ( (rval = com_recv( rlbuff, sizeof(rlbuff) )) == sizeof(rlbuff) ) {
rblen = getword( rlbuff ); /* <- nn nn */
if ( (rbuff = calloc( rblen, 1 )) != NULL ) {
com_send( &rspgotlen, 1 ); /* -> E0 */
rval = Mrecvblk( rbuff, rblen ); /* recv resp, ack/retry */
if ( rval == rblen ) {
*prbuff = rbuff; /* OK, buffer to caller */
} else {
free( rbuff ); /* Mrecvblk() bad length */
rval = ERR;
}
} else { /* calloc(rblen,1) failed */
LPRINTF(( L_ERROR, "MMCrecv: calloc(%d,1) failed", rblen ));
rval = ERR;
}
} else /* com_recv(rlbuff,) failed */
rval = ERR;
com_settimeout( old_tmo );
return rval;
}
/* ============================ */
/* MMCard commands */
/* ============================ */
/*
* MMCard command implementation
* the MMCard commands correspond to IC35 SDK API functions and are
* implemented as remote procedure calls: encode arguments to command
* PDU and send it to IC35, receive response PDU from IC35 and decode
* results from PDU.
* struct mcmdxxxx/mrspxxxx define the command/response PDU encoding.
* all MMCxxxx() functions work like:
* - _init*pdu() allocates the command PDU buffer and encodes the
* command code into it
* - encode MMCxxxx() function argument(s) into command PDU buffer
* (except fdstat argument)
* - _sendrecv() optionally encodes the MMCxxxx() fdstat argument
* into the command PDU for file/directory commands,
* sends the command PDU to IC35 with MMCsend() and releases it,
* receives the response PDU from IC35 with MMCrecv(),
* optionally decodes FILE_IDEN from response PDU back into the
* fdstat argument,
* and returns the status decoded from the response PDU.
* - decode MMCxxxx() result arguments
* - decode from the response PDU into MMCxxxx() result arguments,
* release response PDU buffer and return status from _sendrecv().
*/
/* MMCard command codes */ /* IC35 SDK API function: */
#define MMCMDgetstatus 0x20 /* 13.1 mInitialCard() */
#define MMCMDgetlabel 0x34 /* 13.4 mGetCardLabel() */
#define MMCMDdiropen 0x2A /* 13.14 mOpenDirectory() */
#define MMCMDdirgetlen 0x2B /* 13.15 mGetDirectorySubItemNum() */
#define MMCMDdirread 0x2C /* 13.16 mGetDirectorySubItem() */
#define MMCMDdirclose 0x2E /* 13.18 mCloseDirectory() */
#define MMCMDfileopen 0x22 /* 13.6 mOpenFile() */
#define MMCMDfilestat 0x26 /* 13.10 mGetFileInfo() */
#define MMCMDfilewrite 0x23 /* 13.8 mWriteToFile() */
#define MMCMDfileread 0x24 /* 13.9 mReadFromFile() */
#define MMCMDfileclose 0x27 /* 13.11 mCloseFile() */
#define MMCMDfiledel 0x28 /* 13.13 mDeleteFile() */
/* MMCard PDU definitions
* ----------------------
*/
/* getstatus, getlabel */
struct mcmdstatlbl { /* stat label */
char cmd[1]; /* 20 or 34 */
char mmcard[6]; /* "MMCard" */
char mmcnum[1]; /* "1" or "2" */
uchar zero[1]; /* 00 */
};
struct mrspstat {
uchar stat[2]; /* 01 00 or FF FF */
};
struct mrsplbl {
uchar stat[2]; /* 01 00 */
uchar zero[1]; /* 00 */
char label[8+1]; /* [MMClabel] 00 */
char reserved[11]; /* 20 20 00 00 00 00 00 00 00 00 48 */
};
/* diropen, fileopen */
struct mcmdfdopen { /* dopen fopen */
char cmd[1]; /* 2A or 22 */
uchar mode[2]; /* 01 00 */
uchar path[1]; /* [MMCardx\dir] 00 */
};
struct mrspfdopen {
uchar stat[2]; /* 01 00 */
uchar iden[FIDENSZ]; /* (27 bytes FILE_IDEN) */
};
/* dirglen, dirclose, filestat, fileclose */
struct mcmdfdstatcl { /* dglen dcls fstat fcls*/
char cmd[1]; /* 2B 2E 26 27 */
uchar iden[FIDENSZ]; /* (27 bytes FILE_IDEN) */
uchar zero[1]; /* 00 */
};
struct mrspdirglen {
uchar iden[FIDENSZ]; /* (27 bytes FILE_IDEN) */
uchar stat[2]; /* 01 00 */
uchar ndent[2]; /* nn_nn */
};
struct mrspfdclose {
uchar iden[FIDENSZ]; /* (27 bytes FILE_IDEN) */
};
/* dirread, fileread */
struct mcmdfdread { /* dread fread */
uchar cmd[1]; /* 2C or 24 */
uchar iden[FIDENSZ]; /* (27 bytes FILE_IDEN) */
union {
uchar index[2]; /* in_dx dir-index */
uchar blen[2]; /* nn_nn file-bufflen */
} u;
uchar zero[1]; /* 00 */
};
struct mrspfdstat {
uchar iden[FIDENSZ]; /* (27 bytes FILE_IDEN) */
uchar stat[2]; /* 01 00 */
FILE_INFO dirent; /* (24 bytes FILE_INFO) */
};
struct mrspfileread {
uchar iden[FIDENSZ]; /* (27 bytes FILE_IDEN) */
uchar stat[2]; /* 01 00 */
uchar rlen[2]; /* nn_nn */
uchar data[1]; /* filedata[nn_nn] */
};
/* filedel */
struct mcmdfiledel {
char cmd[1]; /* 28 */
uchar path[1]; /* [MMCardx\file] 00 */
};
/*resp mrspstat
*/
/* filewrite */
struct mcmdfilewrite {
uchar cmd[1]; /* 23 */
uchar iden[FIDENSZ]; /* (27 bytes FILE_IDEN) */
uchar wlen[2]; /* nn_nn */
uchar data[1]; /* filedata[nn_nn] 00 */
};
struct mrspfilewrite {
uchar iden[FIDENSZ]; /* (27 bytes FILE_IDEN) */
uchar stat[2]; /* 01 00 */
};
union mcmdpdu { /* MMCard command PDU */
uchar cmd;
struct mcmdstatlbl status;
struct mcmdstatlbl label;
struct mcmdfdopen diropen;
struct mcmdfdstatcl dirglen;
struct mcmdfdread dirread;
struct mcmdfdstatcl dirclose;
struct mcmdfiledel filedel;
struct mcmdfdopen fileopen;
struct mcmdfdstatcl filestat;
struct mcmdfdread fileread;
struct mcmdfilewrite filewrite;
struct mcmdfdstatcl fileclose;
uchar data[1];
};
union mrsppdu { /* MMCard response PDU */
uchar stat[2];
struct mrspstat status;
struct mrsplbl label;
struct mrspfdopen diropen;
struct mrspdirglen dirglen;
struct mrspfdstat dirread;
struct mrspfdclose dirclose;
struct mrspstat filedel;
struct mrspfdopen fileopen;
struct mrspfdstat filestat;
struct mrspfileread fileread;
struct mrspfilewrite filewrite;
struct mrspfdclose fileclose;
uchar data[1];
};
union mmcpdu { /* generic MMCard PDU */
union mcmdpdu cmd;
union mrsppdu rsp;
};
/* MMCard PDU table
* ----------------
*/
#define SPDULENOF(type) sizeof( struct type )
#define FIDENOFFS(type) offsetof( struct type, iden )
#define RSTATOFFS(type) offsetof( struct type, stat )
#define NOFFS 0xFFFF
struct mpdudesc { /* MMCard PDU description */
uchar cmd; /* command code */
size_t slen; /* fixed length of PDU */
size_t sidenoffs; /* offset FILE_IDEN in cmd PDU */
size_t rstatoffs; /* offset status in resp.PDU */
size_t ridenoffs; /* offset FILE_IDEN in rsp PDU */
};
struct mpdudesc mmcpdutab[] = {
{ MMCMDgetstatus, SPDULENOF(mcmdstatlbl), NOFFS,
RSTATOFFS(mrspstat), NOFFS, },
{ MMCMDgetlabel, SPDULENOF(mcmdstatlbl), NOFFS,
RSTATOFFS(mrsplbl), NOFFS, },
{ MMCMDdiropen, SPDULENOF(mcmdfdopen), NOFFS,
RSTATOFFS(mrspfdopen), FIDENOFFS(mrspfdopen) },
{ MMCMDdirgetlen, SPDULENOF(mcmdfdstatcl), FIDENOFFS(mcmdfdstatcl),
RSTATOFFS(mrspdirglen), FIDENOFFS(mrspdirglen) },
{ MMCMDdirread, SPDULENOF(mcmdfdread), FIDENOFFS(mcmdfdread),
RSTATOFFS(mrspfdstat), FIDENOFFS(mrspfdstat) },
{ MMCMDdirclose, SPDULENOF(mcmdfdstatcl), FIDENOFFS(mcmdfdstatcl),
NOFFS, FIDENOFFS(mrspfdclose) },
{ MMCMDfileopen, SPDULENOF(mcmdfdopen), NOFFS,
RSTATOFFS(mrspfdopen), FIDENOFFS(mrspfdopen) },
{ MMCMDfilestat, SPDULENOF(mcmdfdstatcl), FIDENOFFS(mcmdfdstatcl),
RSTATOFFS(mrspfdstat), FIDENOFFS(mrspfdstat) },
{ MMCMDfilewrite, SPDULENOF(mcmdfilewrite), FIDENOFFS(mcmdfilewrite),
RSTATOFFS(mrspfilewrite), FIDENOFFS(mrspfilewrite) },
{ MMCMDfileread, SPDULENOF(mcmdfdread), FIDENOFFS(mcmdfdread),
RSTATOFFS(mrspfileread), FIDENOFFS(mrspfileread) },
{ MMCMDfileclose, SPDULENOF(mcmdfdstatcl), FIDENOFFS(mcmdfdstatcl),
NOFFS, FIDENOFFS(mrspfdclose), },
{ MMCMDfiledel, SPDULENOF(mcmdfiledel), NOFFS,
RSTATOFFS(mrspstat), NOFFS },
{ 0, 0, 0,
0, 0 }
};
/* init MMCard command PDU
* -----------------------
* lookup MMCard PDU description by command code
* allocate MMCard PDU buffer plus optionally variable length
* setup MMCard command code and return allocated PDU length
*/
static int /* init variable length PDU */
_initvpdu( uchar cmd, size_t varlen, union mmcpdu ** ppdu )
{
struct mpdudesc * pmpdu;
union mmcpdu * spdu;
size_t pdulen;
for ( pmpdu = mmcpdutab; pmpdu->slen != 0; ++pmpdu )
if ( pmpdu->cmd == cmd ) {
pdulen = pmpdu->slen + varlen;
if ( ppdu == NULL /* allocate PDU buffer */
|| (spdu = calloc( 1, pdulen )) == NULL )
break;
spdu->cmd.cmd = cmd; /* MMCard command code */
*ppdu = spdu;
return pdulen; /* length of PDU buffer */
}
return 0;
}
static int /* init fixe length PDU */
_initfpdu( uchar cmd, union mmcpdu ** ppdu )
{
return _initvpdu( cmd, 0, ppdu );
}
/* send MMCard command PDU, receive response PDU
* ---------------------------------------------
* optionally encode FILE_IDEN into command PDU
* send command PDU and release it
* receive response PDU, MMCrecv() will allocate it
* optionally decode FILE_IDEN and status from response PDU
*/
static long
_sendrecv( union mmcpdu ** ppdu, size_t * ppdulen, uchar * fdstat )
{
struct mpdudesc * pmpdu;
int rval;
for ( pmpdu = mmcpdutab; pmpdu->cmd != (*ppdu)->cmd.cmd; ++pmpdu )
if ( pmpdu->slen == 0 )
return ERR; /* PDU description not in table */
if ( pmpdu->sidenoffs != NOFFS && fdstat ) /* encode FILE_IDEN */
putbtxt( (*ppdu)->cmd.data + pmpdu->sidenoffs, fdstat, FIDENSZ );
rval = MMCsend( (*ppdu)->cmd.data, *ppdulen ); /* send command PDU */
free( *ppdu ); *ppdu = NULL; *ppdulen = 0; /* and release it */
if ( rval < 0 ) /* ERR, send failed */
return rval;
if ( (rval = MMCrecv( (uchar**)ppdu )) < 0 ) /* recv response PDU */
return rval; /* ERR, recv failed */
*ppdulen = rval; /* recv'd PDU length */
if ( pmpdu->ridenoffs != NOFFS && fdstat ) /* decode FILE_IDEN */
getbtxt( (*ppdu)->rsp.data + pmpdu->ridenoffs, fdstat, FIDENSZ );
if ( pmpdu->rstatoffs != NOFFS ) /* return status .. */
return getword( (uchar*)*ppdu + pmpdu->rstatoffs );/* from resp PDU */
else
return 0x0000; /* or no status */
}
/* convert FILE_INFO
* -----------------
* converts integer fields from IC35's to host's byte order
*/
static void
_cvtfinfo( FILE_INFO * pdudirent, FILE_INFO * hostdirent )
{
if ( pdudirent == NULL || hostdirent == NULL )
return;
getbtxt( (uchar*)pdudirent, (uchar*)hostdirent, sizeof(*hostdirent) );
hostdirent->ModifyTime = getword( (uchar*)&pdudirent->ModifyTime);
hostdirent->ModifyDate = getword( (uchar*)&pdudirent->ModifyDate);
hostdirent->FileSize = getdword( (uchar*)&pdudirent->FileSize );
}
/* MMCard general commands */
/* ======================= */
/* get MMCard status
* -----------------
* IC35 SDK API 13.1 mInitialCard()
* command: 20 "MMCard" [mmc_num] 00
* response: 01 00 MMCard present
* FF FF MMCard not detected
*/
long
MMCgetstatus( int mmcnum )
{
union mmcpdu * pdu;
int pdulen;
long mstat;
if ( (pdulen = _initfpdu( MMCMDgetstatus, &pdu )) <= 0 )
return ERR;
puttext( pdu->cmd.status.mmcard, "MMCard" );
putbyte( pdu->cmd.status.mmcnum, (char)('0'+mmcnum) );
if ( (mstat = _sendrecv( &pdu, &pdulen, NULL )) < 0 )
return mstat;
free( pdu );
return mstat;
}
/* get MMCard label
* ----------------
* IC35 ADK API 13.4 mGetCardLabel()
* command: 34 "MMCard" [mmc_num] 00
* response: 01 00 00 label[8] 00 20 20 00 00 00 00 00 00 00 00 48
*/
long
MMCgetlabel( int mmcnum, char * plabel )
{
union mmcpdu * pdu;
int pdulen;
long mstat;
if ( (pdulen = _initfpdu( MMCMDgetlabel, &pdu )) <= 0 )
return ERR;
/* encode cmdargs */
puttext( pdu->cmd.status.mmcard, "MMCard" );
putbyte( pdu->cmd.status.mmcnum, (char)('0'+mmcnum) );
if ( (mstat = _sendrecv( &pdu, &pdulen, NULL )) < 0 )
return mstat;
/* decode rspargs */
gettext( pdu->rsp.label.label, plabel, strlen(pdu->rsp.label.label) );
free( pdu );
return mstat;
}
/* MMCard directory commands */
/* ========================= */
/* open MMC directory
* ------------------
* IC35 SDK API 13.14 mOpenDirectory()
* command: 2A 01 00 [MMCard1\path\to\dir] 00
* response: 01 00 fdiden[27]
*/
long
MMCdiropen( char * dirpath, uchar * fdstat )
{
union mmcpdu * pdu;
int pdulen;
long mstat;
if ( (pdulen = _initvpdu( MMCMDdiropen, strlen(dirpath), &pdu )) <= 0 )
return ERR;
/* encode cmdargs */
putword( pdu->cmd.diropen.mode, 0x0001 );
puttxt0( pdu->cmd.diropen.path, dirpath );
if ( (mstat = _sendrecv( &pdu, &pdulen, fdstat )) < 0 )
return mstat;
free( pdu );
return mstat;
}
long
MMCdircreate( char * dirpath, uchar * fdstat )
{
union mmcpdu * pdu;
int pdulen;
long mstat;
if ( (pdulen = _initvpdu( MMCMDdiropen, strlen(dirpath), &pdu )) <= 0 )
return ERR;
/* encode cmdargs */
putword( pdu->cmd.diropen.mode, 0x0000 );
puttxt0( pdu->cmd.diropen.path, dirpath );
if ( (mstat = _sendrecv( &pdu, &pdulen, fdstat )) < 0 )
return mstat;
free( pdu );
return mstat;
}
/* get num.of entries in MMCard directory
* --------------------------------------
* IC35 ADK API 13.15 mGetDirectorySubItemNum()
* command: 2B fdiden[27] 00
* response: fdiden[27] 01 00 nn_nn
*/
long
MMCdirgetlen( uchar * fdstat, ushort * pndent )
{
union mmcpdu * pdu;
int pdulen;
long mstat;
if ( (pdulen = _initfpdu( MMCMDdirgetlen, &pdu )) <= 0 )
return ERR;
if ( (mstat = _sendrecv( &pdu, &pdulen, fdstat )) < 0 )
return mstat;
/* decode rspargs */
*pndent = getword( pdu->rsp.dirglen.ndent );
free( pdu );
return mstat;
}
/* read MMC directory
* ------------------
* IC35 SDK API 13.16 mGetDirectorySubItem()
* command: 2C fdiden[27] in_dx 00
* response: fdiden[27] 01 00
* filename 00 ext 00 at ti_me_st_mp 00 00 fi_le_si_ze
*/
long
MMCdirread( uchar * fdstat, ushort index, FILE_INFO * pdirent )
{
union mmcpdu * pdu;
int pdulen;
long mstat;
if ( (pdulen = _initfpdu( MMCMDdirread, &pdu )) <= 0 )
return ERR;
/* encode cmdargs */
putword( pdu->cmd.dirread.u.index, index );
if ( (mstat = _sendrecv( &pdu, &pdulen, fdstat )) < 0 )
return mstat;
/* decode rspargs */
_cvtfinfo( &pdu->rsp.dirread.dirent, pdirent );
free( pdu );
return mstat;
}
/* close MMC directory
* -------------------
* IC35 SDK API 13.18 mCloseDirectory()
* command: 2E fdiden[27] 00
* response: fdiden[27]
*/
long
MMCdirclose( uchar * fdstat )
{
union mmcpdu * pdu;
int pdulen;
long mstat;
if ( (pdulen = _initfpdu( MMCMDdirclose, &pdu )) <= 0 )
return ERR;
if ( (mstat = _sendrecv( &pdu, &pdulen, fdstat )) < 0 )
return mstat;
free( pdu );
return mstat;
}
/* MMCard file commands */
/* ==================== */
/* delete MMC file
* ---------------
* IC35 SDK API 13.13 mDeleteFile()
* command: 28 [MMCard1\path\to\file] 00
* response: 01 00
*/
long
MMCfiledel( char * filepath )
{
union mmcpdu * pdu;
int pdulen;
long mstat;
if ( (pdulen = _initvpdu( MMCMDfiledel, strlen(filepath), &pdu )) <= 0 )
return ERR;
/* encode cmdargs */
puttxt0( pdu->cmd.filedel.path, filepath );
if ( (mstat = _sendrecv( &pdu, &pdulen, NULL )) < 0 )
return mstat;
free( pdu );
return mstat;
}
/* open MMC file
* -------------
* IC35 SDK API 13.6 mOpenFile()
* command: 22 01 00 [MMCard1\path\to\file] 00
* response: 01 00 fdiden[27]
*/
long
MMCfileopen( char * filepath, ushort mode, uchar * fdstat, ulong * psize )
{
union mmcpdu * pdu;
int pdulen;
long mstat;
if ( (pdulen = _initvpdu( MMCMDfileopen, strlen(filepath), &pdu )) <= 0 )
return ERR;
/* encode cmdargs */
putword( pdu->cmd.fileopen.mode, mode );
puttxt0( pdu->cmd.fileopen.path, filepath );
if ( (mstat = _sendrecv( &pdu, &pdulen, fdstat )) < 0 )
return mstat;
/* decode rspargs */
*psize = getdword( pdu->rsp.fileopen.iden+14 );
free( pdu );
return mstat;
}
/* get MMC file status
* -------------------
* IC35 SDK API 13.10 mGetFileInfo()
* command: 26 fdiden[27] 00
* response: fdiden[27] 01 00
* filename 00 ext 00 at ti_me_st_mp 00 00 fi_le_si_ze
*/
long
MMCfilestat( uchar * fdstat, FILE_INFO * pdirent )
{
union mmcpdu * pdu;
int pdulen;
long mstat;
if ( (pdulen = _initfpdu( MMCMDfilestat, &pdu )) <= 0 )
return ERR;
if ( (mstat = _sendrecv( &pdu, &pdulen, fdstat )) < 0 )
return mstat;
/* decode rspargs */
_cvtfinfo( &pdu->rsp.filestat.dirent, pdirent );
free( pdu );
return mstat;
}
/* read data from MMC file
* -----------------------
* IC35 SDK API 13.9 mReadFormFile()
* command: 24 fdiden[27] nn_nn 00
* response: fdiden[27] 01 00 rr_rr
* <rr_rr bytes filedata>
*/
long
MMCfileread( uchar * fdstat, uchar * buff, ushort blen, ushort * prlen )
{
union mmcpdu * pdu;
int pdulen;
long mstat;
size_t dlen;
if ( (pdulen = _initfpdu( MMCMDfileread, &pdu )) <= 0 )
return ERR;
/* encode cmdargs */
putword( pdu->cmd.fileread.u.blen, blen );
if ( (mstat = _sendrecv( &pdu, &pdulen, fdstat )) < 0 )
return mstat;
/* decode rspargs */
*prlen = getword( pdu->rsp.fileread.rlen );
dlen = pdulen - offsetof(struct mrspfileread, data);
getbtxt( pdu->rsp.fileread.data, buff, dlen );
if ( dlen != *prlen )
LPRINTF(( L_WARN, "MMCfileread: rlen=%u, dlen=%u", *prlen, dlen ));
free( pdu );
return mstat;
}
/* write data to MMC file
* ----------------------
* IC35 SDK API 13.8 mWriteToFile()
* command: 23 fdiden[27] ww_ww
* <ww_ww bytes filedata> 00
* response: fdiden[27] 01 00
*/
long
MMCfilewrite( uchar * fdstat, uchar * data, ushort dlen )
{
union mmcpdu * pdu;
int pdulen;
long mstat;
if ( (pdulen = _initvpdu( MMCMDfilewrite, dlen, &pdu )) <= 0 )
return ERR;
/* encode cmdargs */
putword( pdu->cmd.filewrite.wlen, dlen );
putbtxt( pdu->cmd.filewrite.data, data, dlen );
putbyte( pdu->cmd.filewrite.data+dlen, 0x00 );
if ( (mstat = _sendrecv( &pdu, &pdulen, fdstat )) < 0 )
return mstat;
free( pdu );
return mstat;
}
/* close MMC file
* --------------
* IC35 SDK API 13.11 mCloseFile()
* command: 27 fdiden[27] 00
* response: fdiden[27]
*/
long
MMCfileclose( uchar * fdstat )
{
union mmcpdu * pdu;
int pdulen;
long mstat;
if ( (pdulen = _initfpdu( MMCMDfileclose, &pdu )) <= 0 )
return ERR;
if ( (mstat = _sendrecv( &pdu, &pdulen, fdstat )) < 0 )
return mstat;
free( pdu );
return mstat;
}

95
src/mgrproto.h Normal file
View File

@ -0,0 +1,95 @@
/************************************************************************
* Copyright (C) 2001 Thomas Schulz *
* *
* $Id: mgrproto.h,v 1.8 2001/11/20 23:08:35 thosch Exp $ *
* *
* header for IC35 manager protocol *
* *
************************************************************************/
#ifndef _MGRPROTO_H
#define _MGRPROTO_H 1
#include "util.h" /* uchar */
/* manager command bytes */
#define MCMDdisconn (uchar)0x01 /* disconnect */
#define MCMDreset (uchar)0x09 /* reset communication */
#define MCMDident (uchar)0x10 /* identify: get "DCS_SDK" 00 */
#define MCMDbackup (uchar)0x13 /* backup database */
#define MCMDrestinit (uchar)0x14 /* restore database command-1 */
#define MCMDmmcard (uchar)0x15 /* start MMCard transaction */
#define MCMDinfo (uchar)0x18 /* get backup info "0128" */
#define MCMDinit (uchar)0x50 /* status command-2, no response*/
#define MCMDposack (uchar)0x60 /* positive acknowledge */
#define MCMDnegack (uchar)0x62 /* negative acknowledge */
#define MCMDrestdata (uchar)0x70 /* restore database command-2 */
#define MCMDstatus (uchar)0xFF /* get 16400 byte status block */
/* manager response bytes */
#define MRSPgotcmd (uchar)0x90 /* IC35 got command */
#define MRSPgotack (uchar)0xA0 /* IC35 got ack/nak */
#define MRSPrestdata (uchar)0xC0 /* restore database response-2 */
#define MRSPgotlen (uchar)0xE0 /* IC35/PC got length */
/* MMCard file attributes (from IC35 SDK Mmc.h) */
#define MMCattrReadOnly 0x01
#define MMCattrHidden 0x02
#define MMCattrSystemFile 0x04
#define MMCattrVolumeLabel 0x08
#define MMCattrDirectory 0x10
#define MMCattrArchive 0x20
/* MMCard file open modes (see IC35 SDK MMc.h) */
#define MMCopenexist 0x0001 /* open existing file for read,write */
#define MMCcreatrunc 0x0000 /* create new truncate existing file */
#pragma pack(1)
typedef struct _file_info { /* directory entry (see IC35 SDK Mmc.h) */
char FileName[8+1];
char ExtName[3+1];
uchar Attribute;
ushort ModifyTime;
ushort ModifyDate;
ushort Reserved;
ulong FileSize;
} FILE_INFO;
typedef struct _file_iden { /* file identifier (see IC35 SDK Mmc.h) */
ushort Sector;
ushort Cluster;
ushort SectorOffset;
ushort DirItemOffset;
ushort StartCluster;
ulong FilePointer;
ulong FileSize;
uchar CacheNo;
ushort CurCluster;
ushort CurClusterNo;
ushort CurSectorNo;
ushort Reserved;
} FILE_IDEN;
#pragma pack()
#define FIDENSZ sizeof(FILE_IDEN)
int Mcmdrsp( uchar cmd, uchar rsp ); /* send cmd, get+check rsp */
int Msendblk( uchar * data, size_t dlen ); /* send block, ack/retry */
int Mrecvblk( uchar * buff, size_t blen ); /* receive block, ack/retry */
long MMCgetstatus( int mmcnum );
long MMCgetlabel( int mmcnum, char * plabel );
long MMCdiropen( char * dirpath, uchar * fdstat );
long MMCdircreate( char * dirpath, uchar * fdstat );
long MMCdirgetlen( uchar * fdstat, ushort * pndent );
long MMCdirread( uchar * fdstat, ushort index, FILE_INFO * pdirent );
long MMCdirclose( uchar * fdstat );
long MMCfiledel( char * filepath );
long MMCfileopen( char * filepath, ushort mode, uchar * fdstat, ulong * psize );
long MMCfilestat( uchar * fdstat, FILE_INFO * pdirent );
long MMCfileread( uchar * fdstat, uchar * buff, ushort blen, ushort * prlen );
long MMCfilewrite( uchar * fdstat, uchar * data, ushort dlen );
long MMCfileclose( uchar * fdstat );
#endif /*_MGRPROTO_H*/

943
src/mgrtrans.c Normal file
View File

@ -0,0 +1,943 @@
/************************************************************************
* Copyright (C) 2001 Thomas Schulz *
* */
static char rcsid[] =
"$Id: mgrtrans.c,v 1.17 2001/11/20 23:08:35 thosch Exp $"; /*
* *
* IC35 manager transactions *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
*
* communication phases
* mconnect
* mdisconnect
* MMCard info
* mmc_status
* mmc_label
* MMCard directory ops
* mmc_opendir
* mmc_createdir
* mmc_readdir
* mmc_closedir
* mmctstampstr
* mmctstampunixtime
* MMCard file operations
* mmc_delfile
* mmc_openfile
* mmc_statfile
* mmc_readfile
* mmc_writefile
* mmc_closefile
* IC35 database backup,restore
* readdatabase
* writedatabase
* *
************************************************************************/
#include <stdio.h> /* fprintf(), .. */
#include <string.h> /* memcpy(), strlen() ..*/
#include <stdlib.h> /* malloc(), .. */
#include <unistd.h> /* usleep() */
#include <sys/types.h> /* size_t, .. */
#include <time.h> /* time_t, localtime()..*/
#include <errno.h>
#include "util.h" /* ERR,OK, uchar, .. */
#include "comio.h" /* com_init(), .. */
#include "genproto.h" /* welcome() */
#include "mgrproto.h" /* manager protocol */
#include "mgrtrans.h"
NOTUSED(rcsid);
/* ==================================== */
/* communication phases */
/* ==================================== */
/* welcome phase
* -------------
* opens comm.device and does welcome handshake
*/
static int
mgrwelcome( char * devname )
{
int rval;
LPRINTF(( L_INFO, "welcome(%s) ..", devname ));
if ( com_init( devname ) != OK ) {
error( "welcome failed: com_init(%s) failed", devname );
return ERR;
}
message( "welcome, start IC35 !" );
if ( (rval = welcome( 0x40 )) != OK ) {
error( "welcome %s", rval == ERR_intr ? "aborted"
: "failed: no response" );
return ERR;
}
message( "connected" );
LPRINTF(( L_INFO, "welcome(%s) OK", devname ));
return OK;
}
/* identify
* --------
* communication PC <-> IC35:
* reset-phase -> 09
* <- 90
* ident-phase -> 10
* <- 90 "DCS_SDK" 00
*/
static int
identify( char rtext[7+1] )
{
int rlen;
char rbuff[7+1]; /* for "DCS_SDK\x00" */
LPRINTF(( L_INFO, "identify .." ));
if ( Mcmdrsp( MCMDreset, MRSPgotcmd ) != OK ) {
error( "identify failed: reset-phase" );
return ERR;
}
if ( Mcmdrsp( MCMDident, MRSPgotcmd ) != OK
|| (rlen = com_recv( rbuff, sizeof(rbuff) )) <= 0 ) {
error( "identify failed: ident-phase" );
return ERR;
}
if ( rtext != NULL )
strncat( strcpy( rtext, "" ), rbuff, rlen );
LPRINTF(( L_INFO, "identify OK" ));
return OK;
}
/* init IC35, optionally get status data
* -------------------------------------
* communication PC <-> IC35:
* optional:
* -> FF
* <- [block of 16400 bytes]
* mandatory:
* -> 50
* <- 90 or timeout 0.1 sec
* IC35 may send response, but anyway needs time to get ready
*/
#define STATSIZE 16400
static int
status( char * fname )
{
uchar cmd;
char * rbuff;
int rlen = -1;
FILE * fp;
int old_tmo;
uchar rsp;
LPRINTF(( L_INFO, "status(%s) ..", fname ? fname : "NULL" ));
if ( fname && *fname ) {
if ( (rbuff = malloc( STATSIZE )) != NULL ) {
cmd = MCMDstatus;
com_send( &cmd, 1 );
if ( (rlen = com_recv( rbuff, STATSIZE )) < 0 ) {
error( "status failed: receive" );
free( rbuff );
return ERR;
}
if ( (fp = fopen( fname, "w")) != NULL ) {
fwrite( rbuff, 1, rlen, fp );
fclose( fp );
} else {
message( "cannot open statfile: %s", fname );
}
free( rbuff );
} else {
message( "cannot read statdata: no memory (%d)", STATSIZE );
}
}
cmd = MCMDinit;
com_send( &cmd, 1 ); /* -> 50 */
old_tmo = com_settimeout( 100 );
com_recv( &rsp, 1 ); /* <- 90 or wait 100 msec */
com_settimeout( old_tmo );
if ( rlen >= 0 ) /* received status block */
LPRINTF(( L_INFO, "status received %d bytes statdata", rlen ));
else
LPRINTF(( L_INFO, "status OK" ));
return OK;
}
/* open com-device and connect with IC35
* -------------------------------------
*/
int
mconnect( char * devname, char * statfname )
{
int rval;
char idtext[8];
LPRINTF(( L_INFO, "mconnect(%s,%s) ..",
devname, statfname ? statfname : "NULL" ));
if ( (rval = mgrwelcome( devname )) == OK
&& (rval = identify( idtext )) == OK ) {
message( "identity \"%s\"", idtext );
if ( statfname && *statfname )
message( "statdata %s", statfname );
rval = status( statfname );
}
if ( rval != OK )
mdisconnect();
LPRINTF(( L_INFO, "mconnect(%s,%s) %s",
devname, statfname ? statfname : "NULL",
rval == OK ? "OK" : "ERR" ));
return rval;
}
/* disconnect from IC35 and close com-device
* -----------------------------------------
* communication PC <-> IC35:
* -> 09
* timeout
* -> 09
* <- 90
* -> 01
* timeout
* -> 01
* <- 90
* until response '\x90' is received, send '\x09' or '\x01'
* respectively will be retried up to 5 times.
*/
int
mdisconnect( void )
{
uchar cmd, rsp;
int rval;
message( "disconnect" );
if ( (rval = Mcmdrsp( cmd = MCMDreset, rsp = MRSPgotcmd )) != OK
|| (rval = Mcmdrsp( cmd = MCMDdisconn, rsp = MRSPgotcmd )) != OK )
message( "disconnect sent '\\x%02X', failed receive '\\x%02X'",
cmd, rsp );
com_exit();
LPRINTF(( L_INFO, "disconnect done." ));
return rval;
}
/* ==================================== */
/* IC35 MMCard info */
/* ==================================== */
/* local: convert mstat to text
* ----------------------------
*/
static char *
_mstatxt( long mstat )
{
static char mstatxt[2+11+1]; /* "(-nnnnnnnnnn)"\0 */
if ( mstat >= 0 )
sprintf( mstatxt, "(%04hX)", (ushort)mstat );
else
sprintf( mstatxt, "(%ld)", mstat );
return mstatxt;
}
/* get MMCard status
* -----------------
* returns:
* 1 OK, MMCard found
* 0 OK, MMCard not detected
* -1 ERR, communication failed
*/
int
mmc_status( int mmcnum )
{
long mstat;
if ( mmcnum != 1 && mmcnum != 2 ) {
error( "mmc_status: bad MMCard number %d", mmcnum );
return ERR;
}
LPRINTF(( L_INFO, "mmc_status(%d) ..", mmcnum ));
if ( (mstat = MMCgetstatus( mmcnum )) < 0
|| !( mstat == 0xFFFF || mstat == 0x0001 ) ) {
error( "mmc_status failed %s", _mstatxt(mstat) );
return ERR;
}
LPRINTF(( L_INFO, "mmc_status(%d) = %04X", mmcnum, mstat ));
return mstat == 0xFFFF ? 0 : mstat;
}
/* get MMCard label
* ----------------
*/
int
mmc_label( int mmcnum, char label[11+1] )
{
long mstat;
if ( mmcnum != 1 && mmcnum != 2 ) {
error( "mmc_label: bad MMCard number %d", mmcnum );
return ERR;
}
LPRINTF(( L_INFO, "mmc_label(%d) ..", mmcnum ));
if ( (mstat = MMCgetlabel( mmcnum, label )) != 0x0001 ) {
error( "mmc_label failed %s", _mstatxt(mstat) );
return ERR;
}
LPRINTF(( L_INFO, "mmc_label(%d) = \"%s\"", mmcnum, label ));
return OK;
}
/* ==================================== */
/* IC35 MMCard directory ops */
/* ==================================== */
struct mmcdir { /* MMC directory descriptor */
uchar fdiden[FIDENSZ];/* MMC dir/file access ident */
MMCDIRENT dirent; /* decoded directory entry */
ushort ndirent; /* number of directory entries */
ushort dirindex; /* current directory index */
};
/* local: convert FILE_INFO to MMCDIRENT
* -------------------------------------
*/
static void
_mmc_finfo2dirent( FILE_INFO * finfo, MMCDIRENT * dirent )
{
if ( finfo == NULL || dirent == NULL )
return;
strncat( strcpy( dirent->name, "" ), finfo->FileName, 8 );
if ( strlen( finfo->ExtName ) != 0 ) {
strcat( dirent->name, "." );
strncat( dirent->name, finfo->ExtName, 3 );
}
dirent->attr = finfo->Attribute;
dirent->tstamp = finfo->ModifyDate << 16 | finfo->ModifyTime;
dirent->size = finfo->FileSize;
}
/* open MMC directory
* ------------------
*/
MMCDIR *
mmc_opendir( char * dirpath )
{
MMCDIR * dirp;
long mstat;
if ( (dirp = malloc( sizeof(*dirp) )) == NULL ) {
error( "mmc_opendir failed: no memory (%d)", sizeof(*dirp) );
return NULL;
}
LPRINTF(( L_INFO, "mmc_opendir(%s) ..", dirpath ));
if ( (mstat = MMCdiropen( dirpath, dirp->fdiden )) != 0x0001 ) {
error( "mmc_opendir(%s) diropen failed %s", dirpath, _mstatxt(mstat) );
return NULL;
}
if ( (mstat = MMCdirgetlen( dirp->fdiden, &dirp->ndirent )) != 0x0001 ) {
error( "mmc_opendir(%s) dirgetlen failed %s", dirpath,_mstatxt(mstat) );
return NULL;
}
dirp->dirindex = 0;
LPRINTF(( L_INFO, "mmc_opendir(%s) OK, ndirent=%d",
dirpath, dirp->ndirent ));
return dirp;
}
/* open MMC directory
* ------------------
*/
MMCDIR *
mmc_createdir( char * dirpath )
{
MMCDIR * dirp;
long mstat;
if ( (dirp = malloc( sizeof(*dirp) )) == NULL ) {
error( "mmc_createdir failed: no memory (%d)", sizeof(*dirp) );
return NULL;
}
LPRINTF(( L_INFO, "mmc_createdir(%s) ..", dirpath ));
if ( (mstat = MMCdircreate( dirpath, dirp->fdiden )) != 0x0001 ) {
error( "mmc_createdir(%s) dircreate failed %s", dirpath, _mstatxt(mstat) );
return NULL;
}
if ( (mstat = MMCdirgetlen( dirp->fdiden, &dirp->ndirent )) != 0x0001 ) {
error( "mmc_createdir(%s) dirgetlen failed %s", dirpath,_mstatxt(mstat) );
return NULL;
}
dirp->dirindex = 0;
LPRINTF(( L_INFO, "mmc_createdir(%s) OK, ndirent=%d",
dirpath, dirp->ndirent ));
return dirp;
}
/* read MMC directory
* ------------------
*/
MMCDIRENT *
mmc_readdir( MMCDIR * dirp )
{
long mstat;
FILE_INFO mmcdirent;
if ( dirp == NULL )
return NULL;
if ( dirp->dirindex >= dirp->ndirent ) {
LPRINTF(( L_INFO, "mmc_readdir: eodir (%d)", dirp->dirindex ));
return NULL;
}
++dirp->dirindex;
LPRINTF(( L_INFO, "mmc_readdir index=%d ..", dirp->dirindex ));
if ( (mstat = MMCdirread( dirp->fdiden, dirp->dirindex, &mmcdirent ))
!= 0x0001 ) {
error( "mmc_readdir failed %s", _mstatxt(mstat) );
return NULL;
}
_mmc_finfo2dirent( &mmcdirent, &dirp->dirent );
LPRINTF(( L_INFO, "mmc_readdir OK" ));
return &dirp->dirent;
}
/* close MMC directory
* -------------------
*/
int
mmc_closedir( MMCDIR * dirp )
{
if ( dirp == NULL )
return OK;
LPRINTF(( L_INFO, "mmc_closedir .." ));
if ( MMCdirclose( dirp->fdiden ) < 0 ) {
error( "mmc_closedir failed" );
return ERR;
}
free( dirp );
LPRINTF(( L_INFO, "mmc_closedir OK" ));
return OK;
}
/* convert MMC timestamp
* ---------------------
* the timestamp of MMCard dir/file is encoded like DOS:
* 3322222 2222 21111 11111 100000 00000 bit- ..
* 1098765 4321 09876 54321 098765 43210 .. number
* yyyyyyy mmmm ddddd hhhhh mmmmmm sssss bit fields
* the bit field meanings are:
* yyyyyyy years since 1980
* mmmm month 1..12
* ddddd day 1..31
* hhhhh hour 00..24
* mmmmmm minute 00..59
* sssss second/2 00..31
* mmctstampstr() returns:
* (char*) timestamp string: yyyy-mm-dd hh:mm:ss
* mmctstampunixtime() returns:
* (time_t) timestamp converted to Unix time
*/
static struct tm *
_mmctstamptm( ulong tstamp )
{
static struct tm mmctm;
mmctm.tm_year = ((tstamp & 0xFE000000) >> (4+5+5+6+5)) + 80;
mmctm.tm_mon = ((tstamp & 0x01E00000) >> ( 5+5+6+5)) - 1;
mmctm.tm_mday = (tstamp & 0x001F0000) >> ( 5+6+5);
mmctm.tm_hour = (tstamp & 0x0000F800) >> ( 6+5);
mmctm.tm_min = (tstamp & 0x000007E0) >> ( 5);
mmctm.tm_sec = (tstamp & 0x0000001F) * 2;
return &mmctm;
}
char *
mmctstampstr( ulong tstamp )
{
static char ymdhms[19+1];
struct tm * ptm;
ptm = _mmctstamptm( tstamp );
sprintf( ymdhms, "%04u-%02u-%02u %02u:%02u:%02u",
ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
ptm->tm_hour, ptm->tm_min, ptm->tm_sec );
return ymdhms;
}
time_t
mmctstampunixtime( ulong tstamp )
{
struct tm * ptm;
ptm = _mmctstamptm( tstamp );
ptm->tm_isdst = -1;
return mktime( ptm );
}
/* ==================================== */
/* IC35 MMCard file operations */
/* ==================================== */
struct mmcfile { /* MMC file descriptor */
uchar fdiden[FIDENSZ];/* MMC dir/file access ident */
MMCDIRENT filestat; /* decoded file status */
ulong size; /* file size */
ulong offset; /* current offset in file */
};
/* delete MMC file
* ---------------
*/
int
mmc_delfile( char * filepath )
{
long mstat;
LPRINTF(( L_INFO, "mmc_delfile(%s) ..", filepath ));
if ( (mstat = MMCfiledel( filepath )) != 0x0001 ) {
error( "mmc_delfile(%s) failed %s", filepath, _mstatxt(mstat) );
return ERR;
}
LPRINTF(( L_INFO, "mmc_delfile(%s) OK", filepath ));
return OK;
}
/* open MMC file
* -------------
*/
MMCFILE *
mmc_openfile( char * filepath, ushort mode )
{
MMCFILE * fp;
long mstat;
if ( (fp = malloc( sizeof(*fp) )) == NULL ) {
error( "mmc_openfile failed: no memory (%d)", sizeof(*fp) );
return NULL;
}
LPRINTF(( L_INFO, "mmc_openfile(%s) ..", filepath ));
if ( (mstat = MMCfileopen( filepath, mode, fp->fdiden, &fp->size ))
!= 0x0001 ) {
error( "mmc_openfile(%s) failed %s", filepath, _mstatxt(mstat) );
return NULL;
}
fp->offset = 0;
LPRINTF(( L_INFO, "mmc_openfile(%s) OK, size=%lu", filepath, fp->size ));
return fp;
}
/* get MMC file status
* -------------------
*/
MMCDIRENT *
mmc_statfile( MMCFILE * fp )
{
long mstat;
FILE_INFO mmcdirent;
if ( fp == NULL )
return NULL;
LPRINTF(( L_INFO, "mmc_statfile .." ));
if ( (mstat = MMCfilestat( fp->fdiden, &mmcdirent )) != 0x0001 ) {
error( "mmc_statfile failed %s", _mstatxt(mstat) );
return NULL;
}
_mmc_finfo2dirent( &mmcdirent, &fp->filestat );
LPRINTF(( L_INFO, "mmc_statfile OK" ));
return &fp->filestat;
}
/* read data from MMC file
* -----------------------
*/
int
mmc_readfile( MMCFILE * fp, uchar * buff, size_t blen )
{
long mstat;
ushort rlen;
if ( fp == NULL )
return ERR;
if ( fp->offset >= fp->size ) {
LPRINTF(( L_INFO, "mmc_readfile: eofile (%d)", fp->offset ));
return 0;
}
LPRINTF(( L_INFO, "mmc_readfile(buff,%d) ..", blen ));
if ( fp->offset + blen > fp->size )
blen = fp->size - fp->offset;
if ( (mstat = MMCfileread( fp->fdiden, buff, blen, &rlen )) != 0x0001 ) {
error( "mmc_readfile failed %s", _mstatxt(mstat) );
return ERR;
}
fp->offset += rlen;
LPRINTF(( L_INFO, "mmc_readfile(buff,%d) = %d", blen, rlen ));
return rlen;
}
/* write data to MMC file
* ----------------------
*/
int
mmc_writefile( MMCFILE * fp, uchar * data, size_t dlen )
{
long mstat;
if ( fp == NULL )
return ERR;
LPRINTF(( L_INFO, "mmc_writefile(data,%d) ..", dlen ));
if ( (mstat = MMCfilewrite( fp->fdiden, data, dlen )) != 0x0001 ) {
error( "mmc_writefile failed %s", _mstatxt(mstat) );
return ERR;
}
if ( fp->offset == fp->size )
fp->size += dlen;
fp->offset += dlen;
LPRINTF(( L_INFO, "mmc_writefile(data,%d) OK", dlen ));
return dlen;
}
/* close MMC file
* --------------
*/
int
mmc_closefile( MMCFILE * fp )
{
if ( fp == NULL )
return OK;
LPRINTF(( L_INFO, "mmc_closefile .." ));
if ( MMCfileclose( fp->fdiden ) < 0 ) {
error( "mmc_closefile failed" );
return ERR;
}
free( fp );
LPRINTF(( L_INFO, "mmc_closefile OK" ));
return OK;
}
/* ==================================== */
/* IC35 database backup,restore */
/* ==================================== */
#define HEADBLKSZ 136
#define DATABLKSZ 16384
#define INFOBLKSZ 4
#define NDATABLKS 26
#define NINFOBLKS 2
/* get database info
* -----------------
*/
static int
_getdbinfo( uchar * buff, size_t blen )
{
if ( Mcmdrsp( MCMDinfo, MRSPgotcmd ) != OK )
return ERR;
return com_recv( buff, blen );
}
/* textify protocol errorcode
* --------------------------
*/
static char *
_dbetext( int len )
{
static char etext[24+1];
switch ( len ) {
case ERR_recv:
return "recv.error/timeout";
case ERR_acknak:
return "ack/nak handshake failed";
case ERR_chksum:
return "checksum error";
default:
sprintf( etext, "%s (%d)", len < 0 ? "error" : "bad length", len );
return etext;
}
}
/* IC35 database backup to file
* ============================
* communication PC <-> IC35:
* backup command
* -> 13 command backup
* <- 90 response gotcmd
* on receive error / timeout retry sending command
* headblock
* <- [136-byte-block] cc_cc headblock
* -> 60 positive acknowledge
* <- A0 response gotack
* or on checksum mismatch:
* -> 62 negative acknowlegde
* <- A0 reponse gotnak
* and receive headblock again
* datablocks
* <- [16384-byte-block] cc_cc datablock
* -> 60 positive acknowledge
* <- A0 response gotack
* repeat receive for 26 datablocks of 16384 bytes. for each datablock
* do retry on checksum mismatch like above for headblock.
* database info
* -> 18 command getinfo
* <- 90 response gotcmd
* <- 30 31 32 38 infoblock-1
* -> 18 command getinfo
* <- 90 response gotcmd
* <- 30 31 32 38 infoblock-2
*/
/* read IC35 database to file
* --------------------------
*/
static int
_readdatabase( char * fname, FILE * fp, uchar * buff )
{
ulong frlen;
int rlen;
int i;
LPRINTF(( L_INFO, "readdatabase %s ..", fname ));
/* send backup command and wait for IC35 response */
if ( Mcmdrsp( MCMDbackup, MRSPgotcmd ) != OK ) {
error( "readdatabase backup command failed" );
return ERR;
}
/* receive head-,data-blocks from IC35 and write to file */
frlen = 0;
for ( i = 0; i <= NDATABLKS; ++i ) {
char btext[24+1];
size_t blen;
if ( i == 0 ) {
fprintf( stderr, "read database -> %s head ", fname );
strcpy( btext, "headblock" );
blen = HEADBLKSZ;
} else {
sprintf( btext, "datablock-%d", i );
blen = DATABLKSZ;
}
if ( (rlen = Mrecvblk( buff, blen )) != blen ) {
fprintf( stderr, "\n" );
error( "readdatabase %s %s", btext, _dbetext( rlen ) );
return ERR;
}
frlen += rlen;
fprintf( stderr, "\rread database -> %s %ldk ",
fname, (frlen+511)/1024 );
if ( fwrite( buff, sizeof(buff[0]), rlen, fp ) != rlen ) {
fprintf( stderr, "\n" );
error( "readdatabase %s %s: write error %s (%d)",
btext, fname, strerror(errno), errno );
return ERR;
}
}
/* receive database info from IC35 and write to file */
fprintf( stderr, "\nread database -> %s info ", fname );
for ( i = 1; i <= NINFOBLKS; ++i ) {
if ( (rlen = _getdbinfo( buff, INFOBLKSZ )) != INFOBLKSZ ) {
fprintf( stderr, "\n" );
error( "readdatabase info-%d recv.error/timeout", i );
return ERR;
}
if ( fwrite( buff, sizeof(buff[0]), rlen, fp ) != rlen ) {
fprintf( stderr, "\n" );
error( "readdatabase info-%d %s: write error %s (%d)",
i, fname, strerror(errno), errno );
return ERR;
}
}
fprintf( stderr, "\n" );
LPRINTF(( L_INFO, "readdatabase %s OK", fname ));
return OK;
}
/* read IC35 database: init,free resources
* ---------------------------------------
*/
int
readdatabase( char * fname )
{
uchar * buff;
FILE * fp;
int rval;
if ( (buff = malloc( DATABLKSZ )) != NULL ) {
if ( fname && *fname
&& (fp = fopen( fname, "w" )) != NULL ) {
rval = _readdatabase( fname, fp, buff );
fclose( fp );
} else {
error( "readdatabase cannot open %s", fname ? fname : "(NULL)" );
rval = ERR;
}
free( buff );
} else {
error( "readdatabase failed: no memory (%d)", DATABLKSZ );
rval = ERR;
}
return rval;
}
/* IC35 database restore from file
* ===============================
* communication PC <-> IC35:
* database info
* -> 18 command getinfo
* <- 90 response gotcmd
* <- 30 31 32 38 infoblock-1
* -> 18 command getinfo
* <- 90 response gotcmd
* <- 30 31 32 38 infoblock-2
* check both infoblocks matching with tail of database file,
* on mismatch abort and do not write database to IC35.
* restore commands
* -> 14 command restore-1
* <- 90 response gotcmd
* -> 70 command restore-2
* <- C0 response restore-2
* on receive error / timeout retry sending command-1/2.
* headblock
* -> [136-byte-block] headblock
* <- cc_cc response checksum
* -> 60 positive acknowledge
* <- A0 response gotack
* or on checksum mismatch:
* -> 62 negative acknowlegde
* <- A0 reponse gotnak
* and send headblock again.
* datablocks
* -> [16384-byte-block] datablock
* <- cc_cc response checksum
* -> 60 positive acknowledge
* <- A0 response gotack
* repeat send for 26 datablocks of 16384 bytes. for each datablock do
* retry on checksum mismatch like above for headblock.
* after all data is written to IC35, wait 3.25 sec to
* avoid failure in mdisconnect().
* warning: IC35 does NOT restore phonetype and date+time,
* they must be set manually after restore from file !
*/
/* write IC35 database from file
* -----------------------------
*/
static int
_writedatabase( char * fname, FILE * fp, uchar * buff )
{
ulong fwlen;
int wlen;
int i;
LPRINTF(( L_INFO, "writedatabase %s ..", fname ));
/* check info from IC35 matching info in database file */
fprintf( stderr, "write database <> %s info ", fname );
fseek( fp, -2*INFOBLKSZ, SEEK_END );
for ( i = 1; i <= NINFOBLKS; ++i ) {
uchar info[INFOBLKSZ];
if ( (wlen = _getdbinfo( buff, INFOBLKSZ )) != INFOBLKSZ ) {
fprintf( stderr, "\n" );
error( "writedatabase info-%d recv.error/timeout", i );
return ERR;
}
if ( fread( info, sizeof(info[0]), INFOBLKSZ, fp ) != INFOBLKSZ ) {
fprintf( stderr, "\n" );
error( "writedatabase info-%d %s: read error %s (%d)",
i, fname, strerror(errno), errno );
return ERR;
}
if ( memcmp( buff, info, INFOBLKSZ ) != 0 ) {
char * hextext;
int j;
fprintf( stderr, "\n" );
if ( (hextext = malloc( INFOBLKSZ*3 + 1 )) != NULL ) {
strcpy( hextext, "" );
for ( j = 0; j < INFOBLKSZ; ++j )
sprintf( hextext+strlen(hextext), "%02X ", buff[j] );
message( "%s IC35", hextext );
strcpy( hextext, "" );
for ( j = 0; j < INFOBLKSZ; ++j )
sprintf( hextext+strlen(hextext), "%02X ", info[j] );
message( "%s %s", hextext, fname );
free( hextext );
}
error( "writedatabase info-%d mismatch", i );
}
}
rewind( fp );
/* send restore commands and wait for IC35 responses */
fprintf( stderr, "\n" );
if ( Mcmdrsp( MCMDrestinit, MRSPgotcmd ) < 0
|| Mcmdrsp( MCMDrestdata, MRSPrestdata ) < 0 ) {
error( "writedatabase restore command failed" );
return ERR;
}
/* read headblock,datablocks from file and send to IC35 */
fwlen = 0;
for ( i = 0; i <= NDATABLKS; ++i ) {
char btext[24+1];
size_t blen;
if ( i == 0 ) {
fprintf( stderr, "write database <- %s head ", fname );
strcpy( btext, "headblock" );
blen = HEADBLKSZ;
} else {
sprintf( btext, "datablock-%d", i );
blen = DATABLKSZ;
}
if ( fread( buff, sizeof(buff[0]), blen, fp ) != blen ) {
fprintf( stderr, "\n" );
error( "writedatabase %s %s: read error %s (%d)",
btext, fname, strerror(errno), errno );
return ERR;
}
if ( (wlen = Msendblk( buff, blen )) != blen ) {
fprintf( stderr, "\n" );
error( "writedatabase %s %s", btext, _dbetext( wlen ) );
return ERR;
}
fwlen += wlen;
fprintf( stderr, "\rwrite database <- %s %ldk ",
fname, (fwlen+511)/1024 );
}
fprintf( stderr, "\n" );
usleep( 3250000 ); /* wait 3.25 sec for IC35 doing restore */
LPRINTF(( L_INFO, "writedatabase %s OK", fname ));
return OK;
}
/* write IC35 database: init,free resources
* ----------------------------------------
*/
int
writedatabase( char * fname )
{
uchar * buff;
FILE * fp;
int rval;
if ( (buff = malloc( DATABLKSZ )) != NULL ) {
if ( fname && *fname
&& (fp = fopen( fname, "r" )) != NULL ) {
rval = _writedatabase( fname, fp, buff );
fclose( fp );
} else {
error( "writedatabase cannot open %s", fname ? fname : "(NULL)" );
rval = ERR;
}
free( buff );
} else {
error( "writedatabase failed: no memory (%d)", DATABLKSZ );
rval = ERR;
}
return rval;
}

52
src/mgrtrans.h Normal file
View File

@ -0,0 +1,52 @@
/************************************************************************
* Copyright (C) 2001 Thomas Schulz *
* *
* $Id: mgrtrans.h,v 1.7 2001/11/20 23:08:35 thosch Exp $ *
* *
* header for IC35 manager transactions *
* *
************************************************************************/
#ifndef _MGRTRANS_H
#define _MGRTRANS_H 1
#include <time.h> /* time_t */
#include "util.h" /* uchar,ulong, .. */
#include "mgrproto.h" /* MMCattr*, open modes */
typedef struct mmcdir MMCDIR;
typedef struct mmcdirent { /* exported MMC directory entry */
char name[8+1+3+1]; /* filename.ext */
uchar attr; /* file attributes */
ulong tstamp; /* timestamp (DOS-format) */
ulong size; /* size in bytes */
} MMCDIRENT;
typedef struct mmcfile MMCFILE;
int mconnect( char * devname, char * statfname );
int mdisconnect( void );
int mmc_status( int mmcnum );
int mmc_label( int mmcnum, char label[11+1] );
MMCDIR * mmc_opendir( char * dirpath );
MMCDIR * mmc_createdir( char * dirpath );
MMCDIRENT * mmc_readdir( MMCDIR * dirp );
int mmc_closedir( MMCDIR * dirp );
char * mmctstampstr( ulong tstamp );
time_t mmctstampunixtime( ulong tstamp );
int mmc_delfile( char * filepath );
MMCFILE * mmc_openfile( char * filepath, ushort mode );
MMCDIRENT * mmc_statfile( MMCFILE * fp );
int mmc_readfile( MMCFILE * fp, uchar * buff, size_t blen );
int mmc_writefile( MMCFILE * fp, uchar * data, size_t dlen );
int mmc_closefile( MMCFILE * fp );
int readdatabase( char * fname );
int writedatabase( char * fname );
#endif /*_MGRTRANS_H*/

94
src/port.h Normal file
View File

@ -0,0 +1,94 @@
/***************************************************************************
(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
Business Machines Corporation and Siemens Rolm Communications Inc.
modified 2000 by Thomas Schulz:
$Id: port.h,v 1.3 2001/02/10 03:08:41 tsch Rel $
For purposes of this license notice, the term Licensors shall mean,
collectively, Apple Computer, Inc., AT&T Corp., International
Business Machines Corporation and Siemens Rolm Communications Inc.
The term Licensor shall mean any of the Licensors.
Subject to acceptance of the following conditions, permission is hereby
granted by Licensors without the need for written agreement and without
license or royalty fees, to use, copy, modify and distribute this
software for any purpose.
The above copyright notice and the following four paragraphs must be
reproduced in all copies of this software and any software including
this software.
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
MODIFICATIONS.
IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.
The software is provided with RESTRICTED RIGHTS. Use, duplication, or
disclosure by the government are subject to restrictions set forth in
DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
***************************************************************************/
#ifndef __PORT_H__
#define __PORT_H__ 1
#if defined(__CPLUSPLUS__) || defined(__cplusplus)
extern "C" {
#endif
/* some of these #defines are commented out because */
/* Visual C++ sets them on the compiler command line instead */
/* #define _DEBUG */
/* #define WIN32 */
/* #define WIN16 */
/* #define _WINDOWS */
/* #define __MWERKS__ */
/* #define INCLUDEMFC */
#define vCardClipboardFormat "+//ISBN 1-887687-00-9::versit::PDI//vCard"
#define vCalendarClipboardFormat "+//ISBN 1-887687-00-9::versit::PDI//vCalendar"
/* The above strings vCardClipboardFormat and vCalendarClipboardFormat
are globally unique IDs which can be used to generate clipboard format
ID's as per the requirements of a specific platform. For example, in
Windows they are used as the parameter in a call to RegisterClipboardFormat.
For example:
CLIPFORMAT foo = RegisterClipboardFormat(vCardClipboardFormat);
*/
#define vCardMimeType "text/x-vCard"
#define vCalendarMimeType "text/x-vCalendar"
#define DLLEXPORT(t) t
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#define stricmp strcasecmp
#ifdef __STRICT_ANSI__
#include "util.h" /* strcasecmp() */
#endif
#if defined(__CPLUSPLUS__) || defined(__cplusplus)
}
#endif
#endif /* __PORT_H__ */

649
src/synproto.c Normal file
View File

@ -0,0 +1,649 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* */
static char rcsid[] =
"$Id: synproto.c,v 1.11 2001/06/17 23:37:36 tsch Rel $"; /*
* *
* IC35 synchronize protocol *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
************************************************************************/
#include <stdio.h> /* sprintf(), .. */
#include <stdarg.h> /* va_start(), .. */
#include <string.h> /* memcpy(), strlen() ..*/
#include <time.h> /* struct tm, time(),.. */
#include <sys/types.h> /* size_t, .. */
#include "util.h" /* ERR,OK, uchar, .. */
#include "comio.h" /* com_send(), .. */
#include "genproto.h" /* putxxx(),getxxx() .. */
#include "synproto.h" /* Level-4 commands, .. */
NOTUSED(rcsid)
/* Level-1 PDU Ids */
#define L1INIT 0x01 /* initialize 01 03 00 */
#define L1DSEL 0x02 /* data select 02 ll ll <data> cc cc */
#define L1DREQ 0x04 /* data request 04 03 00 */
#define L1EXIT 0x05 /* exit 05 03 00 */
#define L1ACK0 0xF0 /* ack to initialize */
#define L1ACK1 0xF1 /* ack to datasel,exit */
#define L1DATA 0xF2 /* data response F2 ll ll <data> cc cc */
/* Level-2 PDU Ids */
#define L2INIT 0x80 /* cmd,rsp: identification */
#define L2EXIT 0x81 /* cmd: disconnect */
#define L2WMORE 0x02 /* cmd: write non-last of multiblk record */
#define L2WLAST 0x82 /* cmd: write last of multi-block record */
#define L2READ 0x83 /* cmd: read more of multi-block record */
#define L2RMORE 0x20 /* rsp: non-last data of multi-block record */
#define L2RLAST 0xA0 /* rsp: last data of multi-block record */
#define L2RCONT 0x90 /* rsp: write more of multi-block record */
/* Level-3 PDU Ids */
#define L3MORE 0x48 /* non-last of multi-block */
#define L3LAST 0x49 /* last of multi-block or single */
#define L3IDENT 0x4A /* identification */
/* Level-4 PDU definitions */
#define pdulenof(type,first,last) \
( offsetof(type,last) + sizeof(((type*)0)->last) \
- offsetof(type,first) )
struct hdr {
uchar id; /* id */
uchar len[2]; /* ll ll */
};
union recid {
uchar recid[4]; /* re_cd_id fi IC35 record-ID */
struct {
uchar rec[3]; /* re_cd_id record-id part */
uchar file[1]; /* fi file-id part */
} id;
};
struct cmdident {
struct hdr l1head; /* 02 ll ll */
struct hdr l2head; /* 80 ll ll */
uchar magic[4]; /* 10 00 64 00 */
struct hdr l3head; /* 4A ll ll */
char text[28]; /* "INVENTEC CORPORATION PRODUCT" */
};
#define LCMDident pdulenof(struct cmdident, magic, text)
struct rspident {
struct hdr l1head; /* F2 ll ll */
struct hdr l2head; /* A0 ll ll */
uchar magic[4]; /* 10 00 D0 07 */
struct hdr l3head; /* 4A ll ll */
char text[31]; /* "INVENTEC CORPORATION DCS15 1.28" */
};
struct cmdgetpower {
uchar cmd[2]; /* 03 01 */
char text[5]; /* "Power" */
uchar zero[3]; /* 00 00 00 */
};
#define LCMDgetpower pdulenof(struct cmdgetpower, cmd, zero)
struct rspgetpower {
uchar rsp[2]; /* 03 01 */
};
struct cmdpassword {
uchar cmd[2]; /* 03 00 */
char text[8]; /* [password] */
};
#define LCMDpassword pdulenof(struct cmdpassword, cmd, text)
struct rsppassword {
uchar rsp[2]; /* 01 01 */
};
struct cmdcategory {
uchar cmd[2]; /* 03 02 */
char name[8]; /* [category] */
};
#define LCMDcategory pdulenof(struct cmdcategory, cmd, name)
struct rspcategory {
uchar rsp[2]; /* 00 01 */
};
struct cmdgetdtime {
uchar cmd[2]; /* 02 00 */
uchar zero[1]; /* 00 */
};
#define LCMDgetdtime pdulenof(struct cmdgetdtime, cmd, zero)
struct rspgetdtime {
uchar mdyhms[14]; /* [mmddyyyyhhmmss] */
uchar zero[2]; /* 00 00 */
};
struct cmdsetdtime {
uchar cmd[2]; /* 02 01 */
uchar zero1[1]; /* 00 */
char mdyhms[14]; /* [mmddyyyyhhmmss] */
uchar zero2[2]; /* 00 00 */
};
#define LCMDsetdtime pdulenof(struct cmdsetdtime, cmd, zero2)
/* rspsetdtime is done only */
struct cmdfopen {
uchar cmd[2]; /* 00 02 */
uchar zero[7]; /* 00 00 00 00 00 00 00 */
uchar lf2[4]; /* length+2 (dword) */
uchar lf[1]; /* length of filename */
uchar fname[10+1]; /* [filename] 02 */
};
#define LCMDfopen (pdulenof(struct cmdfopen, cmd, lf) + 1) /* dynamic */
struct rspfopen {
uchar fd[2]; /* fd __ */
};
struct cmdfclose {
uchar cmd[2]; /* 00 03 */
uchar fd[2]; /* fd __ */
uchar zero[4]; /* 00 00 00 00 */
};
#define LCMDfclose pdulenof(struct cmdfclose, cmd, zero)
/* rspfclose is done only */
struct cmdfgetlen {
uchar cmd[2]; /* 01 03 (or 01 04) */
uchar fd[2]; /* fd __ */
uchar zero[4]; /* 00 00 00 00 */
};
#define LCMDfgetlen pdulenof(struct cmdfgetlen, cmd, zero)
struct rspfgetlen {
uchar n[2]; /* n_ __ */
};
struct cmdfgetrec {
uchar cmd[2]; /* 01 06 (or 01 07) */
uchar fd[2]; /* fd __ */
uchar index[2]; /* id x_ (not 01 07) */
uchar zero[2]; /* 00 00 00 00 */
};
#define LCMDfgetrec pdulenof(struct cmdfgetrec, cmd, zero)
struct cmdfgetirec {
uchar cmd[2]; /* 01 05 */
uchar fd[2]; /* fd __ */
union recid uid; /* re c- id fi IC35 record-ID */
};
#define LCMDfgetirec pdulenof(struct cmdfgetirec, cmd, uid)
struct rspfgetrec {
union recid uid; /* re c. id fi IC35 record-ID */
uchar fx[1]; /* fx change-flag on IC35 ? */
uchar data[1]; /* flens,fdata.. (variable len) */
};
struct cmdfputrec { /* putrec or updrec */
uchar cmd[2]; /* 01 08 01 09 */
uchar fd[2]; /* fd __ */
union recid uid; /* 00 00 00 00 or re c- id fi */
uchar magic[3]; /* m1 m2 m3 */
uchar zero2[2]; /* 00 00 */
uchar lr[4]; /* length of record (dword) */
uchar data[1]; /* flens,fdata.. (variable len) */
};
#define LCMDfputrec pdulenof(struct cmdfputrec, cmd, lr) /* dynamic */
struct rspfputrec {
union recid uid; /* re_cd_id fi IC35 record-ID */
};
struct cmdfclrchg { /* clrchg or delrec */
uchar cmd[2]; /* 01 08 01 02 */
uchar fd[2]; /* fd __ */
union recid uid; /* re c- id fi IC35 record-ID */
};
#define LCMDfclrchg pdulenof(struct cmdfclrchg, cmd, uid)
/* rspfclrchg is done only */
struct cmdpdu {
struct hdr l1head; /* 01,02,04,05 */
struct hdr l2head; /* 80,02,82,83,81 */
struct hdr l3head; /* 48,49 */
union {
uchar cmd[2];
struct cmdgetpower getpower;
struct cmdpassword password;
struct cmdcategory category;
struct cmdgetdtime getdtime;
struct cmdsetdtime setdtime;
struct cmdfopen fopen;
struct cmdfclose fclose;
struct cmdfgetlen fgetlen;
struct cmdfgetrec fgetrec;
struct cmdfgetirec fgetirec;
struct cmdfputrec fputrec;
struct cmdfclrchg fclrchg;
} u;
};
struct rsppdu {
struct hdr l1head; /* F0,F1,F2 */
struct hdr l2head; /* 20,A0,90 */
struct hdr l3head; /* 48,49 */
union {
uchar rsp[2];
struct rspgetpower getpower;
struct rsppassword password;
struct rspcategory category;
struct rspgetdtime getdtime;
/* rspsetdtime response done only */
struct rspfopen fopen;
/* rspfclose response done only */
struct rspfgetlen fgetlen;
struct rspfgetrec fgetrec;
struct rspfputrec fputrec;
/* rspfclrchg response done only */
} u;
};
/* ============================================ */
/* utilities for PDU encode/decode */
/* ============================================ */
/* encode data items to PDU
* ------------------------
* putbyte() etc. imported from genproto.c
*/
static int
puthdr( uchar * pduptr, uchar id, int len )
{
putbyte( pduptr+0, id );
putword( pduptr+1, (ushort)(len+3) );
return len+3;
}
static void
putcmd( uchar * pduptr, ushort cmd )
{
putbyte( pduptr+0, (cmd & 0xFF00) >> 8 ); /* MSB first .. */
putbyte( pduptr+1, cmd & 0x00FF ); /* LSB second (!) */
}
/* decode data items from PDU
* --------------------------
* getbyte() etc. imported from genproto.c
*/
static ushort
getrsp( uchar * pduptr )
{
return (getbyte( pduptr+0 ) << 8) | getbyte( pduptr+1 );
}
/* ==================================== */
/* Level-1 protocol */
/* ==================================== */
/*
* the Level-1 protocol transports a command to IC35 (->)
* and receives a response from IC35 (<-):
* L2sendcmd:
* use default timeout (0.5 sec)
* -> 01 03 00 init
* <- F0 ack0
* -> 02 ll ll <L2cmd> cc cc command to IC35
* set timeout 2.0 sec for ack1 response
* <- F1 ack1
* restore previous timeout (0.5 sec)
* L2recvrsp:
* -> 04 03 00 request response
* <- F2 ll ll <L2rsp> cc cc response from IC35
* -> 05 03 00 exit
* <- F1 ack1
* longer timeout 2.0 sec for ack1 response to command is needed
* e.g. for get_modflen. experiments showed ack1 response times
* of 0.7 .. 0.9 sec for ca. 860 address records.
*/
static uchar xbuff[4096]; /* PDU transmit buffer */
/* send Level-1 PDU
* ----------------
*/
static int
L1send( uchar id, uchar* pdu, size_t l2len )
{
size_t slen;
uchar * spdu;
uchar sbuff[3];
if ( pdu != NULL ) { /* long PDU with data and checksum */
slen = puthdr( spdu = pdu, id, l2len+2 );
putword( spdu+slen-2, chksum( spdu, slen-2 ) );
} else { /* short PDU without data,checksum */
slen = puthdr( spdu = sbuff, id, 0 );
}
return com_send( spdu, slen );
}
/* receive Level-1 PDU
* -------------------
* returns:
* <= 0 receive error: timeout, bad checksum of long PDU
* == 0 short PDU received, *p_id = PDU-Id
* > 0 long PDU received, *p_id = PDU-Id, *buff = PDU-data
*/
static int
L1recv( uchar* prid, uchar * pdu, size_t blen )
{
int rlen, pdulen;
if ( prid == NULL )
return ERR; /* semantic error */
*prid = '\0';
rlen = com_recv( prid, sizeof(*prid) );
if ( rlen < 1 )
return rlen; /* recv.ERR, timeout */
if ( *prid != L1DATA )
return OK; /* received ack0,ack1 */
if ( pdu == NULL ) {
/*??? flush receive data */
return ERR; /* semantic error */
}
pdu[0] = *prid;
rlen = com_recv( pdu+1, 2 );
if ( rlen < 2 )
return ERR; /* miss length field */
pdulen = getword( pdu+1 );
if ( pdulen <= 3 )
return ERR; /* too short data resp */
rlen = com_recv( pdu+3, min(pdulen,blen)-3 );
if ( rlen < pdulen - 3 )
return ERR; /* length mismatch */
if ( chksum( pdu, pdulen-2 ) != getword( pdu+pdulen-2 ) )
return ERR; /* checksum mismatch */
return pdulen - 3 - 2; /* length of L2data */
}
/* send command with Level-1 protocol
* ----------------------------------
*/
static int
L2sendcmd( uchar* pdu, size_t l2len )
{
uchar rid;
int old_tmo;
int rval;
rval = OK;
L1send( L1INIT, NULL, 0 ); /* -> 01 03 00 */
L1recv( &rid, NULL, 0 ); /* <- F0 */
if ( rid != L1ACK0 ) /* missing ack0 */
return ERR;
L1send( L1DSEL, pdu, l2len ); /* -> 02 ll ll <L2data> cc cc */
old_tmo = com_settimeout( 2000 ); /* timeout 2.0 sec for ack1resp */
L1recv( &rid, NULL, 0 ); /* <- F1 */
com_settimeout( old_tmo ); /* restore previous timeout */
if ( rid != L1ACK1 ) /* missing ack1 */
return ERR;
return rval;
}
/* receive response with Level-1 protocol
* --------------------------------------
*/
static int
L2recvrsp( uchar* rsp, size_t lrsp )
{
int rlen, rval;
uchar rid;
rval = ERR;
L1send( L1DREQ, NULL, 0 ); /* -> 04 03 00 */
rlen = L1recv( &rid, rsp, lrsp ); /* <- F2 ll ll <L2data> cc cc */
if ( rid == L1DATA )
rval = rlen; /* return length of L2data */
L1send( L1EXIT, NULL, 0 ); /* -> 05 03 00 */
L1recv( &rid, NULL, 0 ); /* <- F1 */
/*??? ignore if missing ack1 to exit */
return rval;
}
/* ==================================== */
/* Level-4 commands,responses */
/* ==================================== */
/* encode command and send it
* --------------------------
* depending on the command-id 'cmd' zero, one or more parameters
* are encoded.
*/
int
sendcmd( ushort cmd, ... )
{
va_list argp;
struct cmdpdu * pdu = (struct cmdpdu *)&xbuff[0];
size_t pdusize = sizeof(xbuff);
size_t pdulen;
uchar l2id, l3id;
memset( pdu, 0, pdusize );
putcmd( pdu->u.cmd, cmd );
va_start( argp, cmd );
switch ( cmd ) {
default:
return ERR; /* invalid 'cmd' */
case CMDident:
{ struct cmdident *idpdu = (struct cmdident *)pdu;
char * inventec = "INVENTEC CORPORATION PRODUCT";
putbtxt( idpdu->magic, "\x10\x00\x64\x00", sizeof(idpdu->magic) );
puttext( idpdu->text, inventec );
puthdr( (uchar*)&idpdu->l3head, L3IDENT, strlen(inventec) );
pdulen = LCMDident;
l2id = L2INIT; l3id = 0;
} break;
case CMDdisconn:
pdulen = 0;
l2id = L2EXIT; l3id = 0;
break;
case CMDgetpower:
puttext( pdu->u.getpower.text, "Power" );
pdulen = LCMDgetpower;
l2id = L2WLAST; l3id = L3LAST;
break;
case CMDpassword:
puttext( pdu->u.password.text, va_arg( argp, char* ) );
pdulen = LCMDpassword;
l2id = L2WLAST; l3id = L3LAST;
break;
case CMDcategory:
puttext( pdu->u.category.name, va_arg( argp, char* ) );
pdulen = LCMDcategory;
l2id = L2WLAST; l3id = L3LAST;
break;
case CMDgetdtime:
pdulen = LCMDgetdtime;
l2id = L2READ; l3id = L3LAST;
break;
case CMDsetdtime:
puttext( pdu->u.setdtime.mdyhms, va_arg( argp, char* ) );
pdulen = LCMDsetdtime;
l2id = L2WLAST; l3id = L3LAST;
break;
case CMDfopen:
{ char * strarg = va_arg( argp, char* );
putdword( pdu->u.fopen.lf2, (ulong)(strlen(strarg) + 2) );
putbyte( pdu->u.fopen.lf, (uchar)strlen(strarg) );
puttext( pdu->u.fopen.fname, strarg );
putbyte( pdu->u.fopen.fname+strlen(strarg), '\x02' );
pdulen = LCMDfopen + strlen(strarg);
l2id = L2WLAST; l3id = L3LAST;
} break;
case CMDfclose:
putword( pdu->u.fclose.fd, (ushort)va_arg( argp, int ) );
pdulen = LCMDfclose;
l2id = L2WLAST; l3id = L3LAST;
break;
case CMDfgetlen:
case CMDfgetmlen:
putword( pdu->u.fgetlen.fd, (ushort)va_arg( argp, int ) );
pdulen = LCMDfgetlen;
l2id = L2READ; l3id = L3LAST;
break;
case CMDfgetirec:
putword( pdu->u.fgetirec.fd, (ushort)va_arg( argp, int ) );
putdword( pdu->u.fgetirec.uid.recid, va_arg( argp, ulong ) );
pdulen = LCMDfgetirec;
l2id = L2READ; l3id = L3LAST;
break;
case CMDfgetrec:
putword( pdu->u.fgetrec.fd, (ushort)va_arg( argp, int ) );
putword( pdu->u.fgetrec.index, (ushort)va_arg( argp, int ) );
pdulen = LCMDfgetrec;
l2id = L2READ; l3id = L3LAST;
break;
case CMDfgetmrec:
putword( pdu->u.fgetrec.fd, (ushort)va_arg( argp, int ) );
pdulen = LCMDfgetrec;
l2id = L2READ; l3id = L3LAST;
break;
case CMDfgetmore:
pdulen = 0;
l2id = L2READ; l3id = 0;
break;
case CMDfputrec:
case CMDfupdrec:
{ bool last = va_arg( argp, bool );
uchar * bstrarg;
size_t bstrlen;
putword( pdu->u.fputrec.fd, (ushort)va_arg( argp, int ) );
putdword( pdu->u.fputrec.uid.recid, va_arg( argp, ulong ) );
putbtxt( pdu->u.fputrec.magic, va_arg( argp, uchar* ),
sizeof(pdu->u.fputrec.magic) );
putdword( pdu->u.fputrec.lr, va_arg( argp, size_t ) );
bstrarg = va_arg( argp, uchar* );
bstrlen = va_arg( argp, size_t );
putbtxt( pdu->u.fputrec.data, bstrarg, bstrlen );
pdulen = LCMDfputrec + bstrlen;
if ( ! last )
l2id = L2WMORE, l3id = L3MORE;
else
l2id = L2WLAST, l3id = L3LAST;
} break;
case CMDfputmore:
{ bool last = va_arg( argp, bool );
uchar * bstrarg = va_arg( argp, uchar* );
size_t bstrlen = va_arg( argp, size_t );
putbtxt( pdu->u.cmd, bstrarg, bstrlen );
pdulen = bstrlen;
if ( ! last )
l2id = L2WMORE, l3id = L3MORE;
else
l2id = L2WLAST, l3id = L3LAST;
} break;
case CMDfdelrec:
case CMDfclrchg:
putword( pdu->u.fclrchg.fd, (ushort)va_arg( argp, int ) );
putdword( pdu->u.fclrchg.uid.recid, va_arg( argp, ulong ) );
pdulen = LCMDfclrchg;
l2id = L2WLAST; l3id = L3LAST;
break;
}
va_end( argp );
if ( l3id )
pdulen = puthdr( (uchar*)&pdu->l3head, l3id, pdulen );
pdulen = puthdr( (uchar*)&pdu->l2head, l2id, pdulen );
return L2sendcmd( (uchar*)pdu, pdulen );
}
/* receive response and decode it
* ------------------------------
* ??? check received l2id,l3id match with cmd acc.to protocol
*/
int
recvrsp( ushort cmd, ... )
{
va_list argp;
uchar l2id, l3id;
ushort rsp;
int pdulen;
size_t pdusize = sizeof(xbuff);
struct rsppdu * pdu = (struct rsppdu *)&xbuff[0];
va_start( argp, cmd );
memset( pdu, 0, pdusize );
if ( (pdulen = L2recvrsp( (uchar*)pdu, pdusize )) < 0 )
return pdulen;
l2id = getbyte( (uchar*)&pdu->l2head );
l3id = 0x00;
if ( pdulen >= sizeof(pdu->l2head) ) {
pdulen -= sizeof(pdu->l2head);
l3id = getbyte( (uchar*)&pdu->l3head );
if ( pdulen >= sizeof(pdu->l3head) )
pdulen -= sizeof(pdu->l3head);
}
rsp = getrsp( pdu->u.rsp );
switch ( cmd ) {
default:
return ERR; /* invalid 'cmd' */
case CMDident:
{ struct rspident *idpdu = (struct rspident *)pdu;
char * ptext = va_arg( argp, char* );
size_t lptext = va_arg( argp, size_t );
pdulen -= sizeof(idpdu->magic);
gettext( idpdu->text, ptext, min(pdulen, lptext) );
} break;
case CMDdisconn:
break;
case CMDgetpower:
{ ushort * pstate = va_arg( argp, ushort* );
*pstate = rsp;
} break;
case CMDpassword:
{ ushort * pstate = va_arg( argp, ushort* );
*pstate = rsp;
} break;
case CMDgetdtime:
{ char * pdtime = va_arg( argp, char* );
size_t lpdtime = va_arg( argp, size_t );
gettext( pdu->u.getdtime.mdyhms, pdtime,
min(sizeof(pdu->u.getdtime.mdyhms), lpdtime) );
} break;
case CMDsetdtime:
break;
case CMDcategory:
{ ushort * pstate = va_arg( argp, ushort* );
*pstate = rsp;
} break;
case CMDfopen:
{ ushort * pfd = va_arg( argp, ushort* );
*pfd = getword( pdu->u.fopen.fd );
} break;
case CMDfclose:
break;
case CMDfgetlen:
case CMDfgetmlen:
{ ushort * pflen = va_arg( argp, ushort* );
*pflen = getword( pdu->u.fgetlen.n );
} break;
case CMDfgetrec:
{ bool * plast = va_arg( argp, bool* );
ulong * prid = va_arg( argp, ulong* );
uchar * pchg = va_arg( argp, uchar* );
uchar * buff = va_arg( argp, uchar* );
size_t blen = va_arg( argp, size_t );
*plast = (bool)( l2id == L2RLAST );
*prid = getdword( pdu->u.fgetrec.uid.recid );
*pchg = getbyte( pdu->u.fgetrec.fx );
memcpy( buff, pdu->u.fgetrec.data, min(blen,pdulen) );
pdulen -= offsetof(struct rspfgetrec, data); /* length of record data */
} break;
case CMDfgetmore:
{ bool * plast = va_arg( argp, bool* );
uchar * buff = va_arg( argp, uchar* );
size_t blen = va_arg( argp, size_t );
*plast = (bool)( l2id == L2RLAST );
memcpy( buff, pdu->u.rsp, min(blen,pdulen) );
} break;
case CMDfputrec:
if ( l2id == L2RLAST && l3id == L3LAST ) {
ulong * prid = va_arg( argp, ulong* );
*prid = getdword( pdu->u.fputrec.uid.recid );
}
break;
case CMDfdelrec:
case CMDfclrchg:
break;
}
return pdulen;
}

44
src/synproto.h Normal file
View File

@ -0,0 +1,44 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* *
* $Id: synproto.h,v 1.3 2000/12/03 07:50:44 tsch Rel $ *
* *
* header for IC35 synchronize protocol *
* *
************************************************************************/
#ifndef _SYNPROTO_H
#define _SYNPROTO_H 1
#include "util.h" /* ushort */
/* Level-4 commands,responses */
#define CMDident 0x1000
#define CMDpassword 0x0300
#define RSPpasswdOK 0x0101
#define CMDgetpower 0x0301
#define RSPpowerOK 0x0301
#define CMDcategory 0x0302
#define RSPcategOK 0x0001
#define CMDgetdtime 0x0200
#define CMDsetdtime 0x0201
#define CMDfopen 0x0002
#define CMDfclose 0x0003
#define CMDfdelrec 0x0102 /* delete record */
#define CMDfgetlen 0x0103 /* get total number of records */
#define CMDfgetmlen 0x0104 /* get number of modified records */
#define CMDfgetirec 0x0105 /* read record by recID */
#define CMDfgetrec 0x0106 /* read record by index */
#define CMDfgetmrec 0x0107 /* read next modified record */
#define CMDfgetmore 0x83
#define CMDfputrec 0x0108 /* write record, gets new recID */
#define CMDfupdrec 0x0109 /* update record, keeps recID */
#define CMDfputmore 0x90
#define CMDfclrchg 0x010A /* commit record */
#define CMDdisconn 0x81
int sendcmd( ushort cmd, ... ); /* encode command and send */
int recvrsp( ushort cmd, ... ); /* receive response and decode */
#endif /*_SYNPROTO_H*/

515
src/syntrans.c Normal file
View File

@ -0,0 +1,515 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* */
static char rcsid[] =
"$Id: syntrans.c,v 1.19 2001/03/02 02:09:59 tsch Rel $"; /*
* *
* IC35 synchronize transactions *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
************************************************************************/
#include <stdio.h> /* fprintf(), .. */
#include <string.h> /* memcpy(), strlen() ..*/
#include <stdlib.h> /* calloc(), .. */
#include <sys/types.h> /* size_t, .. */
#include "util.h" /* ERR,OK, uchar, .. */
#include "comio.h" /* com_init(), .. */
#include "genproto.h" /* welcome() */
#include "synproto.h" /* Level-4 commands, .. */
#include "syntrans.h"
#include "ic35frec.h" /* IC35REC, .. */
NOTUSED(rcsid);
/* ==================================== */
/* comunication phases */
/* ==================================== */
/* welcome phase
* -------------
* opens comm.device and does welcome handshake
*/
static int
synwelcome( char * devname )
{
int rval;
LPRINTF(( L_INFO, "welcome(%s) ..", devname ));
if ( com_init( devname ) != OK ) {
error( "welcome failed: com_init(%s) failed", devname );
return ERR;
}
message( "welcome, start IC35 !" );
if ( (rval = welcome( 0x41 )) != OK ) {
error( "welcome %s", rval == ERR_intr ? "aborted"
: "failed: no response" );
return ERR;
}
message( "connected" );
LPRINTF(( L_INFO, "welcome(%s) OK", devname ));
return OK;
}
/* identify
* --------
*/
static int
identify( char * rtext )
{
char idtext[39+1];
LPRINTF(( L_INFO, "identify .." ));
if ( sendcmd( CMDident ) < 0
|| recvrsp( CMDident, idtext, sizeof(idtext) ) < 0 ) {
error( "identify failed" );
return ERR;
}
if ( rtext != NULL )
strncat( strcpy( rtext, "" ), idtext, sizeof(idtext)-1 );
LPRINTF(( L_INFO, "identify OK" ));
return OK;
}
/* power
* -----
*/
static int
power( void )
{
ushort pstate = 0xFFFF;
LPRINTF(( L_INFO, "power .." ));
if ( sendcmd( CMDgetpower ) < 0
|| recvrsp( CMDgetpower, &pstate ) < 0
|| pstate != RSPpowerOK ) {
error( "power failed (%04X)", pstate );
return ERR;
}
LPRINTF(( L_INFO, "power OK (%04X)", pstate ));
return OK;
}
/* authenticate
* ------------
*/
static int
authenticate( char * passwd )
{
ushort pstate = 0xFFFF;
LPRINTF(( L_INFO, "password .." ));
if ( sendcmd( CMDpassword, passwd ) < 0
|| recvrsp( CMDpassword, &pstate ) < 0
|| pstate != RSPpasswdOK ) {
error( "password failed (%04X)", pstate );
return ERR;
}
LPRINTF(( L_INFO, "password OK (%04X)", pstate ));
return OK;
}
/* read/write IC35 reference info
* ------------------------------
* reference info can be an arbitrary string of up to 16 chars.
* IC35sync/Windows uses mmddyyyyhhmmss to retrieve date+time of
* last sync from IC35 or store it into IC35.
*/
int
ReadSysInfo( char * infobuff )
{
char rinfo[16+1];
LPRINTF(( L_INFO, "ReadSysInfo .." ));
if ( sendcmd( CMDgetdtime ) < 0
|| recvrsp( CMDgetdtime, rinfo, sizeof(rinfo) ) < 0 ) {
error( "ReadSysInfo failed" );
return ERR;
}
if ( infobuff != NULL )
strncat( strcpy( infobuff, "" ), rinfo, sizeof(rinfo)-1 );
LPRINTF(( L_INFO, "ReadSysInfo OK (%s)", rinfo ));
return OK;
}
int
WriteSysInfo( char * infodata )
{
LPRINTF(( L_INFO, "WriteSysInfo %s ..", infodata ));
if ( sendcmd( CMDsetdtime, infodata ) < 0
|| recvrsp( CMDsetdtime ) < 0 ) {
error( "WriteSysInfo \"%s\" failed", infodata );
return ERR;
}
message( "set sysinfo \"%s\"", infodata );
LPRINTF(( L_INFO, "WriteSysInfo OK" ));
return OK;
}
/* category
* --------
* ??? semantics not clear
*/
int
category( char * name )
{
ushort state = 0xFFFF;
LPRINTF(( L_INFO, "category(%s) ..", name ));
if ( sendcmd( CMDcategory, name ) < 0
|| recvrsp( CMDcategory, &state ) < 0 ) {
error( "category(%s) failed (%04hX)", name, state );
return ERR;
}
LPRINTF(( L_INFO, "category(%s) OK (%04hX)", name, state ));
return OK;
}
/* open com-device and connect with IC35
* -------------------------------------
*/
int
connect( char * devname, char * passwd, char * rdtime )
{
int rval;
char idtext[64];
if ( (rval = synwelcome( devname )) == OK
&& (rval = identify( idtext )) == OK
&& (rval = power()) == OK
&& (rval = authenticate( passwd )) == OK
&& (rval = ReadSysInfo( rdtime )) == OK )
if ( rdtime != NULL )
message( "version \"%s\" sysinfo \"%s\"", idtext, rdtime );
else
message( "version \"%s\"", idtext );
else
disconnect();
return rval;
}
/* disconnect from IC35 and close com-device
* -----------------------------------------
*/
int
disconnect( void )
{
message( "disconnect" );
sendcmd( CMDdisconn );
recvrsp( CMDdisconn );
com_exit();
LPRINTF(( L_INFO, "disconnect done." ));
return OK;
}
/* ==================================== */
/* access file on IC35 */
/* ==================================== */
/* open file
* ---------
*/
int
open_file( char * fname )
{
ushort fd;
LPRINTF(( L_INFO, "open_file(%s) ..", fname ));
if ( sendcmd( CMDfopen, fname ) < 0
|| recvrsp( CMDfopen, &fd ) < 0 ) {
error( "openfile(%s) failed", fname );
return ERR;
}
LPRINTF(( L_INFO, "open_file(%s) fd=%04hX", fname, fd ));
return fd;
}
/* get filelength
* --------------
*/
/* get total number of records */
int
get_flen( int fd )
{
ushort flen;
LPRINTF(( L_INFO, "get_flen(fd=%04hX) ..", fd ));
if ( sendcmd( CMDfgetlen, fd ) < 0
|| recvrsp( CMDfgetlen, &flen ) < 0 ) {
error( "get_flen(fd=%04X) failed", fd );
return ERR;
}
LPRINTF(( L_INFO, "get_flen(fd=%04X) %hd records", fd, flen ));
return flen;
}
/* get number of modified records */
int
get_mod_flen( int fd )
{
ushort flen;
LPRINTF(( L_INFO, "get_mod_flen(fd=%04X) ..", fd ));
if ( sendcmd( CMDfgetmlen, fd ) < 0
|| recvrsp( CMDfgetmlen, &flen ) < 0 ) {
error( "get_mod_flen(fd=%04X) failed", fd );
return ERR;
}
LPRINTF(( L_INFO, "get_mod_flen(fd=%04X) %hd records", fd, flen ));
return flen;
}
/* read file record
* ----------------
* there are 3 methods to read records from IC35 file:
* - read_frec read record by index
* - read_mod_frec read next modified record
* - read_id_frec read record by record-ID
* return:
* -1 ERR, communication error
* 0 uncommitted deleted record (read_mod_frec)
* or record does not exist (read_id_frec)
* >0 OK, length of record data
*/
static int
_read_frec( IC35REC * rec )
{
ulong rid; /* record-id on IC35 */
uchar chg; /* change-flag on IC35 */
bool last; /* last of multi-block */
uchar * buff;
size_t blen;
uchar *rptr, *rend;
int rlen;
if ( (buff = calloc( blen = MAXRLEN, sizeof(*buff) )) == NULL ) {
error( "_read_frec() failed: no memory for buffer (%d)", blen );
return -1;
}
rend = (rptr = buff) + blen;
for ( ; ; ) {
if ( rptr == buff )
rlen = recvrsp( CMDfgetrec, &last, &rid, &chg, rptr, rend - rptr );
else
rlen = recvrsp( CMDfgetmore, &last, rptr, rend - rptr );
if ( rlen < 0 ) {
free( buff );
error( "_read_frec() failed: recvrsp(%s)",
rptr == buff ? "getrec" : "getmore" );
return ERR;
}
rptr += rptr + rlen <= rend ? rlen : 0;
if ( last )
break;
sendcmd( CMDfgetmore );
}
rlen = rptr - buff;
set_ic35recid( rec, rid );
set_ic35recchg( rec, chg );
set_ic35recdata( rec, buff, rlen );
free( buff );
return rlen;
}
/* read file record by record-ID */
int
read_id_frec( int fd, ulong rid, IC35REC * rec )
{
int rlen;
LPRINTF(( L_INFO, "read_id_frec(fd=%04X,rid=%08lX) ..", fd, rid ));
if ( sendcmd( CMDfgetirec, fd, rid ) < 0 ) {
error( "read_id_frec(fd=%04X,rid=%08lX) failed: sendcmd", fd, rid );
return ERR;
}
if ( (rlen = _read_frec( rec )) < 0 ) {
error( "read_id_frec(fd=%04X,rid=%08lX) failed: recvrsp", fd, rid );
return ERR;
}
if ( ic35recid( rec ) != rid ) {
LPRINTF(( L_INFO, "read_id_frec(fd=%04X,rid=%08lX) non-exist", fd, rid ));
return 0;
}
LPRINTF(( L_INFO, "read_id_frec(fd=%04X,rid=%08lX) len=%d", fd, rid, rlen ));
return rlen;
}
/* read file record by index */
int
read_frec( int fd, int idx, IC35REC * rec )
{
int rlen;
LPRINTF(( L_INFO, "read_frec(fd=%04X,i=%04X) ..", fd, idx ));
if ( sendcmd( CMDfgetrec, fd, idx ) < 0 ) {
error( "read_frec(fd=%04X,i=%04X) failed: sendcmd", fd, idx );
return ERR;
}
if ( (rlen = _read_frec( rec )) < 0 ) {
error( "read_frec(fd=%04X,i=%04X) failed: recvrsp", fd, idx );
return ERR;
}
LPRINTF(( L_INFO, "read_frec(fd=%04X,i=%04X) len=%d", fd, idx, rlen ));
return rlen;
}
/* read next modified file record */
int
read_mod_frec( int fd, IC35REC * rec )
{
int rlen;
LPRINTF(( L_INFO, "read_mod_frec(fd=%04X) ..", fd ));
if ( sendcmd( CMDfgetmrec, fd ) < 0 ) {
error( "read_mod_frec(fd=%04X) failed: sendcmd", fd );
return ERR;
}
if ( (rlen = _read_frec( rec )) < 0 ) {
error( "read_mod_frec(fd=%04X) failed: recvrsp", fd );
return ERR;
}
LPRINTF(( L_INFO, "read_mod_frec(fd=%04X) len=%d", fd, rlen ));
return rlen;
}
/* write/update file record
* ------------------------
* write_frec() writes new record, which gets new record-ID,
* update_frec() writes new data into an existing record and
* keeps same record-ID.
* ??? the meaning of magic is unclear, perceived were:
* IC35file bytes
* Addresses 51 00 00
* Memo 58 48 99
* 60 16 99
* Schedule 10 00 00
* ToDoList 10 00 00
*/
#define DOwrite TRUE
#define DOupdate FALSE
static int
_write_frec( bool do_write, int fd, IC35REC * rec )
{
uchar * data;
size_t dlen;
uchar * wptr;
size_t wlen;
uchar * magic;
bool last;
int rval;
ulong orecid, recid;
orecid = ic35recid( rec );
get_ic35recdata( rec, &data, &dlen );
switch ( FileId( orecid ) ) {
case FILEADDR: magic = "\x51\x00\x00"; break;
case FILEMEMO: magic = "\x60\x16\x99"; break;
case FILETODO:
case FILESCHED: magic = "\x10\x00\x00"; break;
default: magic = "\x00\x00\x00"; break;
}
wptr = data;
do {
wlen = data+dlen - wptr;
if ( wlen > 80 ) wlen = 80;
last = (bool)( wptr+wlen >= data+dlen );
if ( wptr == data )
if ( do_write )
rval = sendcmd( CMDfputrec, last, fd, 0L, magic, dlen,
wptr, wlen );
else /* update */
rval = sendcmd( CMDfupdrec, last, fd, orecid, magic, dlen,
wptr, wlen );
else
rval = sendcmd( CMDfputmore, last, wptr, wlen );
if ( rval < 0 )
return -1;
if ( recvrsp( CMDfputrec, &recid ) < 0 )
return -2;
wptr += wlen;
} while ( wptr < data+dlen );
set_ic35recid( rec, recid );
return 0;
}
/* write record, gets new record-ID */
int
write_frec( int fd, IC35REC * rec )
{
int rval;
LPRINTF(( L_INFO, "write_frec(fd=%04X) ..", fd ));
if ( (rval = _write_frec( DOwrite, fd, rec )) < 0 ) {
error( "write_frec(fd=%04X) failed: %s",
fd, rval == -1 ? "sendcmd" : "recvrsp" );
return ERR;
}
LPRINTF(( L_INFO, "write_frec(fd=%04X) rid=%08lX", fd, ic35recid( rec ) ));
return OK;
}
/* write record update, keeps record-ID */
int
update_frec( int fd, IC35REC * rec )
{
int rval;
ulong orecid;
orecid = ic35recid( rec );
LPRINTF(( L_INFO, "update_frec(fd=%04X,orid=%08lX) ..", fd, orecid ));
if ( (rval = _write_frec( DOupdate, fd, rec )) < 0 ) {
error( "update_frec(fd=%04X,orid=%08lX) failed: %s",
fd, orecid, rval == -1 ? "sendcmd" : "recvrsp" );
return ERR;
}
LPRINTF(( L_INFO, "update_frec(fd=%04X,orid=%08lX) nrid=%08lX",
fd, orecid, ic35recid( rec ) ));
return OK;
}
/* delete file record
* ------------------
*/
int
delete_frec( int fd, ulong recid )
{
LPRINTF(( L_INFO, "delete_frec(fd=%04X,rid=%08lX) ..", fd, recid ));
if ( sendcmd( CMDfdelrec, fd, recid ) < 0
|| recvrsp( CMDfdelrec ) < 0 ) {
error( "delete_frec(fd=%04X,rid=%08X) failed", fd, recid );
return ERR;
}
LPRINTF(( L_INFO, "delete_frec(fd=%04X,rid=%08lX) OK", fd, recid ));
return OK;
}
/* commit file record, i.e. reset change flag
* ------------------------------------------
*/
int
commit_frec( int fd, ulong recid )
{
LPRINTF(( L_INFO, "commit_frec(fd=%04X,rid=%08lX) ..", fd, recid ));
if ( sendcmd( CMDfclrchg, fd, recid ) < 0
|| recvrsp( CMDfclrchg ) < 0 ) {
error( "commit_frec(fd=%04hX,rid=%08X) failed", fd, recid );
return ERR;
}
LPRINTF(( L_INFO, "commit_frec(fd=%04hX,rid=%08lX) OK", fd, recid ));
return OK;
}
/* close file
* ----------
*/
int
close_file( int fd )
{
LPRINTF(( L_INFO, "close_file(fd=%04X) ..", fd ));
if ( sendcmd( CMDfclose, fd ) < 0
|| recvrsp( CMDfclose ) < 0 ) {
error( "close_file(fd=%04X) failed", fd );
return ERR;
}
LPRINTF(( L_INFO, "close_file(fd=%04X) OK", fd ));
return OK;
}

37
src/syntrans.h Normal file
View File

@ -0,0 +1,37 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* *
* $Id: syntrans.h,v 1.10 2000/12/21 11:05:52 tsch Rel $ *
* *
* header for IC35 synchronize transactions *
* *
************************************************************************/
#ifndef _SYNTRANS_H
#define _SYNTRANS_H 1
#include <sys/types.h> /* size_t */
#include "util.h" /* uchar, .. */
#include "ic35frec.h" /* IC35REC */
int connect( char * devname, char * passwd, char * rdtime );
int disconnect( void );
int ReadSysInfo( char * infobuff );
int WriteSysInfo( char * infodata );
int category( char * name );
int open_file( char * fname );
int get_flen( int fd );
int get_mod_flen( int fd );
int read_id_frec( int fd, ulong rid, IC35REC * rec );
int read_frec( int fd, int idx, IC35REC * rec );
int read_mod_frec( int fd, IC35REC * rec );
int write_frec( int fd, IC35REC * rec );
int update_frec( int fd, IC35REC * rec );
int delete_frec( int fd, ulong recid );
int commit_frec( int fd, ulong recid );
int close_file( int fd );
#endif /*_SYNTRANS_H*/

298
src/util.c Normal file
View File

@ -0,0 +1,298 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* */
static char rcsid[] =
"$Id: util.c,v 1.9 2001/06/11 09:14:59 tsch Rel $"; /*
* *
* IC35 utilities: logging, errors, messages *
* *
*************************************************************************
* *
* conditional compile on NO_LOGSIM: if #defined, logging of the *
* IC35 communications is NOT supported, default WITH logging. *
* conditional compile on __STRICT_ANSI__: if #defined, substitute *
* functions, which are not available with the ANSI C standard. *
* (compilation with 'gcc -ansi ..' does #define __STRICT_ANSI__) *
* *
* logging #ifndef NO_LOGSIM *
* log_init initialize logfile, logtag and loglevel *
* log_close close logfile *
* lprintf printf to logfile *
* ldump dump data to logfile *
* log_proginfo log program name, version and build info *
* log_argsinfo log command line of program invocation *
* (error-)messages *
* vlmessage local: vprintf message *
* message output and log L_MESG message *
* error output and log L_ERROR message *
* fatal output,log L_FATAL message and abort program *
* _not_impl report unimplemented feature *
* substitute functions #ifdef __STRICT_ANSI__ *
* strncasecmp *
* strcasecmp *
* strdup *
* *
************************************************************************/
#include <stdio.h> /* fprintf(), .. */
#include <stdarg.h> /* va_start(), .. */
#include <stdlib.h> /* malloc(), free(), .. */
#include <string.h> /* strcpy(), .. */
#include <sys/types.h> /* size_t, .. */
#include <sys/time.h> /* gettimeofday(), .. */
#include <time.h> /* struct tm, time() .. */
#include "util.h"
NOTUSED(rcsid)
/* logging
* -------
* format of log entries:
* hh:mm:ss.mmmm tag level message
* hh:mm:ss.mmmm tag level addr hex... char...
*/
#ifndef NO_LOGSIM
static char * logfname = NULL;
static FILE * logfp = NULL;
static char * logtag = "";
static int loglevel = L_DEBUG;
static int
_log_init( char * l_fname, char * l_tag, int level )
{
if ( l_fname && *l_fname ) {
logfp = fopen( logfname = l_fname, "w" );
if ( logfp == NULL )
return ERR;
}
if ( l_tag && *l_tag )
logtag = l_tag;
if ( level )
loglevel = level;
return OK;
}
void
log_init( char * l_fname, char * l_tag, int level )
{
if ( _log_init( l_fname, l_tag, level ) != OK )
fatal( "cannot open logfile: %s", l_fname );
}
void
log_close( void )
{
if ( logfp ) {
fclose( logfp );
logfp = NULL;
}
}
static char *
ltstamp( void )
{
static char timestamp[16];
struct timeval tv;
struct tm * ptm;
gettimeofday( &tv, NULL );
ptm = localtime( (time_t*)&tv.tv_sec );
sprintf( timestamp, "%02d:%02d:%02d.%04d",
ptm->tm_hour, ptm->tm_min, ptm->tm_sec,
(int)(tv.tv_usec/100) );
return timestamp;
}
static void
vltprintf( int level, char * tstamp, const char * format, va_list argp )
{
if ( logfp == NULL || level > loglevel )
return;
fprintf( logfp, "%s %s %d ", tstamp, logtag, level );
vfprintf( logfp, format, argp );
fprintf( logfp, "\n" );
}
static void
vlprintf( int level, const char * format, va_list argp )
{
vltprintf( level, ltstamp(), format, argp );
}
void
lprintf( int level, const char * format, ... )
{
va_list argp;
va_start( argp, format );
vlprintf( level, format, argp );
va_end( argp );
}
static void
ltprintf( int level, char * tstamp, const char * format, ... )
{
va_list argp;
va_start( argp, format );
vltprintf( level, tstamp, format, argp );
va_end( argp );
}
void
ldump( int level, void * data, size_t dlen, const char * format, ... )
{
va_list argp;
char * tstamp;
int i;
uchar *dptr, *dend;
char *hdptr, hdump[5+3*16+1];
char *cdptr, cdump[16+1];
tstamp = ltstamp();
va_start( argp, format );
vltprintf( level, tstamp, format, argp );
va_end( argp );
dend = (dptr = (uchar*)data) + dlen;
while ( dptr < dend ) {
hdptr = hdump;
cdptr = memset( cdump, 0, sizeof(cdump) );
sprintf( hdptr, "%04lX:", dptr - (uchar*)data ); hdptr += 5;
for ( i = 0; i < 16 && dptr < dend; ++i, ++dptr ) {
sprintf( hdptr, " %02X", *dptr ); hdptr += 3;
*cdptr++ = ' ' < *dptr && *dptr <= '~' ? *dptr : '.';
}
ltprintf( level, tstamp, " %-53s %s", hdump, cdump );
}
}
/* log program info
* ----------------
* current date and time, as log has only hh:mm:ss.mmmm stamps
* program name, version and release date
* build date+time, user, host
*/
void
log_proginfo( char * name, char * version, char * date, char * bldinfo )
{
time_t tnow;
struct tm * ptm;
char dtime[24+1]; /* yyyy-mm-dd hh:mm:ss zzzz */
tnow = time( NULL );
ptm = localtime( &tnow );
strftime( dtime, sizeof(dtime), "%Y-%m-%d %T %Z", ptm );
lprintf( L_MESG, "%s", dtime );
lprintf( L_MESG, "%s %s (%s)", name, version, date );
lprintf( L_MESG, "%s", bldinfo );
}
/* log command line
* ----------------
*/
void
log_argsinfo( int argc, char ** argv )
{
int i, len;
char * cmdline;
for ( i = len = 0; i < argc; ++i )
len += strlen( argv[i] ) + 1;
if ( (cmdline = malloc( len )) != NULL ) {
strcpy( cmdline, argv[0] );
for ( i = 1; i < argc; ++i )
strcat( strcat( cmdline, " " ), argv[i] );
lprintf( L_MESG, "cmd: %s", cmdline );
free( cmdline );
}
}
#endif /*NO_LOGSIM*/
/* output (error-)message
* ----------------------
*/
static void
vlmessage( int level, const char * format, va_list argp )
{
vfprintf( stderr, format, argp );
fprintf( stderr, "\n" );
#ifndef NO_LOGSIM
vlprintf( level, format, argp );
#endif
}
void
message( const char * format, ... )
{
va_list argp;
va_start( argp, format );
vlmessage( L_MESG, format, argp );
va_end( argp );
}
void
error( const char * format, ... )
{
va_list argp;
va_start( argp, format );
vlmessage( L_ERROR, format, argp );
va_end( argp );
}
void
fatal( const char * format, ... )
{
va_list argp;
va_start( argp, format );
vlmessage( L_FATAL, format, argp );
va_end( argp );
exit( 1 );
}
/* report unimplemented feature
* ----------------------------
*/
int
_not_impl( char * feature )
{
error( "%s NOT IMPLEMENTED", feature );
return ERR;
}
/* substitute functions
* --------------------
* the functions below are unavailable on compilation with "-ansi",
* which #defines __STRICT_ANSI__
*/
#ifdef __STRICT_ANSI__
#include <ctype.h> /* toupper() */
int
strncasecmp( const char * s1, const char * s2, size_t n )
{
int cmp;
for ( ; n; ++s1, ++s2, --n ) {
cmp = toupper(*s1) - toupper(*s2);
if ( cmp != 0 )
return cmp;
if ( !( *s1 && *s2 ) )
break;
}
return 0;
}
int
strcasecmp( const char * s1, const char * s2 )
{
size_t n;
if ( (n = strlen(s1)) < strlen(s2) )
n = strlen(s2);
return strncasecmp( s1, s2, n );
}
char *
strdup( const char * s )
{
char * nstr;
if ( (nstr = malloc( strlen(s) + 1 )) != NULL )
strcpy( nstr, s );
return nstr;
}
#endif /*__STRICT_ANSI__*/

96
src/util.h Normal file
View File

@ -0,0 +1,96 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* *
* $Id: util.h,v 1.9 2001/03/02 02:08:32 tsch Rel $ *
* *
* header for IC35 utilities *
* *
************************************************************************/
#ifndef _UTIL_H
#define _UTIL_H 1
#include <sys/types.h> /* size_t */
#ifdef HAVE_CONFIG_H
#include <config.h> /* NO_LOGSIM */
#endif
#define NOTUSED(x) static void _nu_ ## x( void ) \
{ (void)( _nu_ ## x + 0 ); (void)( x + 0 ); }
#define UNUSED(x) (void)( x + 0 ) /* LINT: unused function arg */
#if !defined(OK) || !defined(ERR)
# define OK 0
# define ERR -1
#endif
#if !defined(TRUE) || !defined(FALSE)
# define TRUE 1
# define FALSE 0
#endif
#define bool int
#define uchar unsigned char
#define ushort unsigned short
#define uint unsigned int
#define ulong unsigned long
#if !defined(min) || !defined(max)
# define min(a,b) ( (a) < (b) ? (a) : (b) )
# define max(a,b) ( (a) < (b) ? (b) : (a) )
#endif
#ifndef offsetof
# define offsetof(type,fld) (size_t)&( ((type*)0)->fld )
#endif
#ifndef alenof
# define alenof(array) ( sizeof(array) / sizeof(array[0]) )
#endif
/* log levels */
#define L_FATAL 0 /* program will end, SYSLOG LOG_ALERT */
#define L_ERROR 1 /* action should be taken, SYSLOG LOG_ERR */
#define L_AUDIT 2 /* serious info, SYSLOG LOG_NOTICE */
#define L_WARN 3 /* something goes wrong ? */
#define L_MESG 4 /* info - level 1 */
#define L_INFO 5 /* info - level 2 */
#define L_NOISE 6 /* info - level 3 */
#define L_DEBUG 7 /* debugging, very noisy */
#ifdef NO_LOGSIM /* log and com-simulation disabled */
#define LOG_INIT(args)
#define LOG_CLOSE(args)
#define LPRINTF(args)
#define LDUMP(args)
#define LOG_PROGINFO(args)
#define LOG_ARGSINFO(args)
#else /*!NO_LOGSIM*/ /* log and com-simulation enabled */
#define LOG_INIT(args) log_init args
#define LOG_CLOSE(args) log_close args
#define LPRINTF(args) lprintf args
#define LDUMP(args) ldump args
#define LOG_PROGINFO(args) log_proginfo args
#define LOG_ARGSINFO(args) log_argsinfo args
#endif /*NO_LOGSIM*/
void log_init( char * l_fname, char * l_tag, int level );
void log_close( void );
void lprintf( int level, const char * format, ... );
void ldump( int level, void * data, size_t dlen, const char * format, ... );
void log_proginfo( char * name, char * version, char * date, char * bldinfo );
void log_argsinfo( int argc, char ** argv );
void message( const char * format, ... );
void error( const char * format, ... );
void fatal( const char * format, ... );
int _not_impl( char * feature );
#ifdef __STRICT_ANSI__
int strcasecmp( const char * s1, const char * s2 );
int strncasecmp( const char * s1, const char * s2, size_t n );
char * strdup( const char * s );
#endif /*__STRICT_ANSI__*/
#endif /*_UTIL_H*/

722
src/vcaconv.c Normal file
View File

@ -0,0 +1,722 @@
/************************************************************************
* Copyright (C) 2000,2001 Thomas Schulz *
* */
static char rcsid[] =
"$Id: vcaconv.c,v 1.17 2001/02/17 20:56:49 tsch Rel $"; /*
* *
* vCard,vCalendar conversion *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
* for usage run vcaconv -h or see function usage() below. *
* *
************************************************************************/
#include <stdio.h> /* printf(), .. */
#include <string.h> /* strcasecmp(), .. */
#include <getopt.h> /* getopt(), optarg, .. */
#include <ctype.h> /* isdigit() */
#include <time.h> /* struct tm, time() .. */
#include "vcc.h" /* VObject, .. */
#include "syntrans.h" /* FILEADDR, .. */
#include "dataio.h" /* ic35addr_to_vcard()..*/
#include "vcutil.h" /* vca_type(), .. */
#include "util.h" /* uchar, .. */
NOTUSED(rcsid)
extern char * pkgvers; /* these are all */
extern char * pkgdate; /* in versinfo.c, which is */
extern char * bldinfo; /* auto-generated by Makefile */
/* get VObject's string value (dupStr()'d)
* --------------------------
*/
static char *
dupStrValue( VObject * vobj, const char * id )
{
char * strval;
if ( (strval = dupStringValue( vobj, id )) == NULL )
strval = dupStr( "", 0 );
return strval;
}
/* ==================================================== */
/* parse VObject list from vCard/vCal file */
/* ==================================================== */
/* parse error handler
* -------------------
*/
static bool _vca_error;
static char * _vca_fname;
static void
_vca_errmsg( char * msg ) /* mimeErrorHandler for Parse_MIME_FromFile() */
{
error( "vcafile \"%s\": %s", _vca_fname, msg );
_vca_error = TRUE;
}
/* parse vCard,vCal file
* ---------------------
*/
static VObject *
vca_parse( char * fname )
{
FILE * infp;
VObject * vlist;
if ( fname && *fname && strcmp( fname, "-" ) != 0 ) {
if ( (infp = fopen( fname, "r" )) == NULL ) {
error( "cannot open vcafile: %s", fname );
return NULL;
}
} else {
fname = "(stdin)";
infp = stdin;
}
registerMimeErrorHandler( _vca_errmsg );
_vca_error = FALSE;
_vca_fname = fname;
vlist = Parse_MIME_FromFile( infp );
if ( _vca_error ) {
cleanVObjects( vlist );
vlist = NULL;
}
if ( infp != stdin )
fclose( infp );
return vlist;
}
/* ==================================== */
/* sort list of VObjects */
/* ==================================== */
/* compare property of VObjects
* ----------------------------
*/
static int
_compare_vprop( const char * id, VObject * vobj1, VObject * vobj2 )
{
int cmp;
if ( !( id && *id )
|| (vobj1 == NULL && vobj2 == NULL) )
return 0;
if ( vobj1 == NULL )
return -1;
if ( vobj2 == NULL )
return +1;
if ( strcasecmp( id, VCNameProp ) == 0 ) {
VObject * vprop1 = isAPropertyOf( vobj1, id );
VObject * vprop2 = isAPropertyOf( vobj2, id );
if ( (cmp = _compare_vprop( VCFamilyNameProp, vprop1, vprop2 )) != 0 )
return cmp;
else
return _compare_vprop( VCGivenNameProp, vprop1, vprop2 );
}
if ( strcasecmp( id, XPilotIdProp ) == 0 ) {
ulong val1 = LongValue( vobj1, id );
ulong val2 = LongValue( vobj2, id );
if ( val1 < val2 )
return -1;
if ( val1 > val2 )
return +1;
return 0;
}
if ( strcasecmp( id, VCLastModifiedProp ) == 0
|| strcasecmp( id, VCLastRevisedProp ) == 0
|| strcasecmp( id, VCDTstartProp ) == 0
|| strcasecmp( id, VCDTendProp ) == 0 ) {
time_t time1 = isodtime_to_unixtime( vobj1, id );
time_t time2 = isodtime_to_unixtime( vobj2, id );
if ( time1 < time2 )
return -1;
if ( time1 > time2 )
return +1;
return 0;
}
{
char * str1 = dupStrValue( vobj1, id );
char * str2 = dupStrValue( vobj2, id );
cmp = strcmp( str1, str2 );
deleteStr( str1 );
deleteStr( str2 );
return cmp;
}
}
/* compare VObjects for sorting
* ----------------------------
*/
static int
_compare_vobj( const void * pvobj1, const void * pvobj2 )
{
VObject * vobj1 = *(VObject**)pvobj1;
VObject * vobj2 = *(VObject**)pvobj2;
int type1 = vca_type( vobj1 );
int type2 = vca_type( vobj2 );
int cmp;
if ( type1 < type2 )
return -1;
else if ( type1 > type2 )
return +1;
switch ( type1 ) {
case VCARD: /* addr: Name, REV, */
if ( (cmp = _compare_vprop( VCNameProp, vobj1, vobj2 )) != 0 )
return cmp;
if ( (cmp = _compare_vprop( VCLastRevisedProp, vobj1, vobj2 )) != 0 )
return cmp;
break;
case VMEMO: /* memo: subject, */
if ( (cmp = _compare_vprop( VCSummaryProp, vobj1, vobj2 )) != 0 )
return cmp;
if ( (cmp = _compare_vprop( VCLastModifiedProp, vobj1, vobj2 )) != 0 )
return cmp;
break;
case VEVENT: /* vcal.sched: DTSTART, subject, rev, */
if ( (cmp = _compare_vprop( VCDTstartProp, vobj1, vobj2 )) != 0 )
return cmp;
if ( (cmp = _compare_vprop( VCSummaryProp, vobj1, vobj2 )) != 0 )
return cmp;
if ( (cmp = _compare_vprop( VCLastModifiedProp, vobj1, vobj2 )) != 0 )
return cmp;
break;
case VTODO: /* vcal.todo: DTSTART, subject, rev, */
if ( (cmp = _compare_vprop( VCDueProp, vobj1, vobj2 )) != 0 )
return cmp;
if ( (cmp = _compare_vprop( VCSummaryProp, vobj1, vobj2 )) != 0 )
return cmp;
if ( (cmp = _compare_vprop( VCLastModifiedProp, vobj1, vobj2 )) != 0 )
return cmp;
break;
case VCAL: /* multiple vCAL ? VERSION, PRODID */
if ( (cmp = _compare_vprop( VCVersionProp, vobj1, vobj2 )) != 0 )
return cmp;
return _compare_vprop( VCProdIdProp, vobj1, vobj2 );
}
/* same with above compares: X-PILOTID, UID */
if ( (cmp = _compare_vprop( XPilotIdProp, vobj1, vobj2 )) != 0 )
return cmp;
return _compare_vprop( VCUniqueStringProp, vobj1, vobj2 );
}
/* sort VObject's property list
* ----------------------------
*/
struct propseq {
int seq;
char * id;
};
static struct propseq _propseq[] = {
{ -6, VCNameProp },
{ -5, VCDTstartProp },
{ -4, VCDTendProp },
{ -3, VCDueProp },
{ -2, VCSummaryProp },
{ -1, VCDescriptionProp },
{ +1, VCCategoriesProp },
{ +2, VCDCreatedProp },
{ +3, VCLastModifiedProp },
{ +4, VCLastRevisedProp },
{ +5, VCUniqueStringProp },
{ +6, XPilotIdProp },
{ +7, XPilotStatusProp },
{ 0, NULL }
};
static int
_propid_seq( const char * id )
{
struct propseq * pseq;
for ( pseq = _propseq; pseq->id; ++pseq )
if ( strcasecmp( id, pseq->id ) == 0 )
return pseq->seq;
return 0;
}
static int /* compare properties for sorting */
_compare_props( const void * pvprop1, const void * pvprop2 )
{
VObject * vprop1 = *(VObject**)pvprop1;
VObject * vprop2 = *(VObject**)pvprop2;
const char *id1, *id2;
int seq1, seq2;
char *str1, *str2;
int cmp;
seq1 = _propid_seq( id1 = vObjectName( vprop1 ) );
seq2 = _propid_seq( id2 = vObjectName( vprop2 ) );
if ( seq1 < seq2 )
return -1;
if ( seq1 > seq2 )
return +1;
if ( (cmp = strcasecmp( id1, id2 )) == 0 ) {
cmp = strcmp( str1 = dupStrValue( vprop1, NULL ),
str2 = dupStrValue( vprop2, NULL ) );
deleteStr( str1 );
deleteStr( str2 );
}
return cmp;
}
static void /* sort VObject's property list */
vobjsort( VObject * vobj )
{
size_t n, i;
VObjectIterator iter;
VObject ** vproptab;
VObject * vprop;
n = 0; /* count number of properties, alloc table */
initPropIterator( &iter, vobj );
while ( moreIteration( &iter ) ) {
(void)nextVObject( &iter );
++n;
}
vproptab = malloc ( n * sizeof(vproptab[0]) );
if ( vproptab == NULL )
return;
/* build table of property ptrs and sort */
i = 0;
initPropIterator( &iter, vobj );
while ( i < n && moreIteration( &iter ) )
vproptab[i++] = nextVObject( &iter );
qsort( vproptab, n, sizeof(vproptab[0]), _compare_props );
/* rebuild property list in sorted sequ */
for ( i = 0; i < n; ++i )
if ( (vprop = delProp( vobj, vproptab[i] )) != NULL )
addVObjectProp( vobj, vprop );
free( vproptab );
}
/* sort VObject list
* -----------------
*/
static int
vca_sort( VObject ** vlist )
{
size_t n, i;
VObject * vcal;
VObject ** vobjtab;
VObject * vobj;
VObjectIterator iter;
/* count number of VObjects, alloc table */
n = 0; vcal = NULL;
for ( vobj = *vlist; vobj !=NULL; vobj = nextVObjectInList( vobj ) ) {
++n;
if ( vca_type( vobj ) == VCAL ) {
if ( vcal == NULL )
vcal = vobj;
initPropIterator( &iter, vobj );
while ( moreIteration( &iter ) ) {
(void)nextVObject( &iter );
++n;
}
}
}
vobjtab = malloc ( n * sizeof(vobjtab[0]) );
if ( vobjtab == NULL )
return ERR;
/* build table of VObject ptrs and sort */
i = 0;
for ( vobj = *vlist; vobj !=NULL; vobj = nextVObjectInList( vobj ) ) {
vobjtab[i++] = vobj;
if ( vca_type( vobj ) == VCAL ) {
initPropIterator( &iter, vobj );
while ( moreIteration( &iter ) )
vobjtab[i++] = nextVObject( &iter );
}
}
qsort( vobjtab, n, sizeof(vobjtab[0]), _compare_vobj );
/* rebuild VObject list in sorted sequ */
for ( i = 0; i < n; ++i ) {
vobj = vobjtab[i];
switch ( vca_type( vobj ) ) {
case VCARD:
case VMEMO:
vobjsort( vobj ); /* sort VObject's property list */
/* fall thru */
case VCAL:
vobj = delList( vlist, vobj );
if ( vobj != NULL )
addList( vlist, vobj );
break;
case VEVENT:
case VTODO:
if ( vcal == NULL )
break;
vobjsort( vobj ); /* sort VObject's property list */
vobj = delProp( vcal, vobj );
if ( vobj != NULL )
addVObjectProp( vcal, vobj );
break;
}
}
free( vobjtab );
return OK;
}
/* ==================================== */
/* create telbook for handy */
/* ==================================== */
static bool
hasCategory( VObject * vobj, char * wanted )
{
char * categories;
char * category;
if ( !( vobj && wanted && *wanted ) )
return FALSE;
categories = dupStrValue( vobj, VCCategoriesProp );
for ( category = strtok( categories, ";" );
category; category = strtok( NULL, ";" ) )
if ( strcasecmp( category, wanted ) == 0 )
break;
deleteStr( categories );
return (bool)( category != NULL );
}
static char *
NameValue( VObject * vobj, const char * type )
{
VObject * vprop;
char * namestr;
if ( !( vobj && type && *type )
|| (vprop = isAPropertyOf( vobj, VCNameProp )) == NULL )
return NULL;
if ( (namestr = dupStrValue( vprop, type )) && *namestr )
return namestr;
deleteStr( namestr );
if ( (namestr = dupStrValue( vprop, VCFamilyNameProp )) && *namestr )
return namestr;
deleteStr( namestr );
return dupStrValue( vprop, VCGivenNameProp );
}
static char *
TelnoValue( VObject * vobj, const char * type )
{
VObjectIterator iter, teliter;
VObject * vprop;
VObject * teltype;
VObject * telpref;
VObject * teldflt;
char * telstr, *src, *dst;
if ( !( vobj && type && *type ) )
return NULL;
teltype = telpref = teldflt = NULL;
initPropIterator( &iter, vobj );
while ( moreIteration( &iter ) ) {
vprop = nextVObject( &iter );
if ( strcmp( vObjectName( vprop ), VCTelephoneProp ) != 0 )
continue;
if ( teltype == NULL
&& isAPropertyOf( vprop, type ) )
teltype = vprop;
if ( telpref == NULL
&& isAPropertyOf( vprop, VCPreferredProp ) )
telpref = vprop;
initPropIterator( &teliter, vprop );
if ( teldflt == NULL
&& ! moreIteration( &teliter ) )
teldflt = vprop;
}
telstr = dupStrValue( teltype ? teltype :
( telpref ? telpref : teldflt ), NULL );
if ( (dst = src = telstr) && *telstr ) {
do {
if ( (src == telstr && *src == '+') /* international +49 */
|| isdigit( *src ) ) /* skip separators, because */
*dst++ = *src; /* handy does not like them */
} while ( *src++ );
}
return telstr;
}
/*
* special categories for handy telbook:
* S35SIM pre-installed entries from S35i
* HANDY created for import into handy
* special conversions
* - vCards for handy have only VCNameProp.VCFamilyNameProp and
* VCTelephoneProp with VCCellularProp attribute
* for category "Business" and other derive from VCFamilyNameProp
* for category "Personal" derive from VCGivenNameProp
* - for multiple telnos make multiple vCards with append to name:
* Business: append none, "-priv", "-mobil" for WORK, HOME, CELL
* Personal: append "-Buero", none, "-mobil" for WORK, HOME, CELL
* - for category "Personal" make "VIP" entries by appending "!"
*/
static VObject *
new_handycard( char * name, char * suffix, char * telno )
{
VObject * vcard;
char namebuff[18+1];
time_t tnow;
struct tm * ptm;
char isodtime[24];
if ( !(name && *name)
|| !(telno && *telno)
|| (vcard = newVObject( VCCardProp )) == NULL )
return NULL;
strncat( strcpy( namebuff, "" ), name, sizeof(namebuff)-1 );
if ( suffix && *suffix ) {
namebuff[ sizeof(namebuff)-1 - 4 ] = '\0';
strncat( namebuff, suffix, sizeof(namebuff)-1 - strlen(namebuff) );
}
addPropValue( vcard, VCFullNameProp, namebuff );
addPropValue( addProp( vcard, VCNameProp ), VCFamilyNameProp, namebuff );
addProp( addPropValue( vcard, VCTelephoneProp, telno ), VCCellularProp );
addPropValue( vcard, VCCategoriesProp, "HANDY" );
tnow = time( NULL );
ptm = localtime( &tnow );
strftime( isodtime, sizeof(isodtime), "%Y-%m-%dT%H:%M:%S", ptm );
addPropValue( vcard, VCLastRevisedProp, isodtime );
return vcard;
}
static int
vcard_to_handy( VObject ** vlist )
{
VObject * vobj;
VObject * vcard;
VObject * vdel;
VObject * handylist;
VObject * vnext;
char * name, *tel1, *tel2;
vdel = handylist = NULL;
for ( vobj = *vlist; vobj !=NULL; vobj = nextVObjectInList( vobj ) ) {
if ( vca_type( vobj ) != VCARD )
continue;
if ( hasCategory( vobj, "HANDY" ) ) {
if ( vdel )
cleanVObject( vdel );
vdel = delList( vlist, vobj );
continue;
}
if ( hasCategory( vobj, "NOTHANDY" ) )
continue;
if ( hasCategory( vobj, "S35SIM" ) ) {
name = NameValue( vobj, VCGivenNameProp );
if ( (tel1 = TelnoValue( vobj, VCCellularProp )) && *tel1
&& (vcard = new_handycard( name, NULL, tel1 )) != NULL )
addList( &handylist, vcard );
deleteStr( tel1 );
deleteStr( name );
} else if ( hasCategory( vobj, "Personal" ) ) {
name = NameValue( vobj, VCGivenNameProp );
if ( (tel1 = TelnoValue( vobj, VCHomeProp )) && *tel1
&& (vcard = new_handycard( name, "!", tel1 )) != NULL )
addList( &handylist, vcard );
if ( (tel2 = TelnoValue( vobj, VCWorkProp )) && *tel2
&& strcmp( tel1, tel2 ) != 0
&& (vcard = new_handycard( name, "-Büro!", tel2 )) != NULL )
addList( &handylist, vcard );
deleteStr( tel2 );
if ( (tel2 = TelnoValue( vobj, VCCellularProp )) && *tel2
&& strcmp( tel1, tel2 ) != 0
&& (vcard = new_handycard( name, "-mobil!", tel2 )) != NULL )
addList( &handylist, vcard );
deleteStr( tel2 );
deleteStr( tel1 );
deleteStr( name );
} else { /* Business etc. */
name = NameValue( vobj, VCFamilyNameProp );
if ( (tel1 = TelnoValue( vobj, VCWorkProp )) && *tel1
&& (vcard = new_handycard( name, NULL, tel1 )) != NULL )
addList( &handylist, vcard );
if ( (tel2 = TelnoValue( vobj, VCHomeProp )) && *tel2
&& strcmp( tel1, tel2 ) != 0
&& (vcard = new_handycard( name, "-priv", tel2 )) != NULL )
addList( &handylist, vcard );
deleteStr( tel2 );
if ( (tel2 = TelnoValue( vobj, VCCellularProp )) && *tel2
&& strcmp( tel1, tel2 ) != 0
&& (vcard = new_handycard( name, "-mobil", tel2 )) != NULL )
addList( &handylist, vcard );
deleteStr( tel2 );
deleteStr( tel1 );
deleteStr( name );
}
}
if ( vdel )
cleanVObject( vdel );
vobj = handylist;
while ( vobj ) {
vnext = nextVObjectInList( vobj );
addList( vlist, vobj );
vobj = vnext;
}
return OK;
}
/* -------------------- M A I N - program ----------------------------- */
static void
versinfo( void )
{
printf( "vCard/vCalendar converter %s (%s)\n", pkgvers, pkgdate );
printf( "%s\n", bldinfo );
printf(
"Copyright (C) 2000,2001 Thomas Schulz\n"
"This is free software; see the GNU General Public Licence version 2 in\n"
"the file named COPYING for copying conditions. There is NO warranty.\n"
);
}
static void
usage( void )
{
static char * usetext[] = {
"usage:",
" vcaconv bin2vca binfile vcafile",
" convert IC35 binary data to vCard,vCalendar format",
" vcaconv bin2txt binfile txtfile",
" convert IC35 binary data to plain text format",
" vcaconv vca2bin vcafile binfile",
" convert vCard,vCalendar file to IC35 binary data",
" vcaconv prvca vcafile",
" pretty print vCard/vCalendar format 'vcafile'",
" vcaconv sortvca vcafile",
" sort vCard,vCalendar file to standard output",
" vcaconv imphandy vcafile",
" create vCards in HANDY category for upload to mobile phone",
" if inputfile or outputfile is absent or -, standard input",
" or standard output will be used",
"options:",
" -V --version show version information and exit",
" -h --help show this help and exit",
NULL
};
char ** lptr;
for ( lptr = usetext; *lptr != NULL; ++lptr )
printf( "%s\n", *lptr );
}
int
main( int argc, char *argv[] )
{
static struct option const long_opts[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
};
for ( ; ; ) {
switch ( getopt_long( argc, argv, "hV", long_opts, NULL ) ) {
default: /* invalid option */
fprintf( stderr, "use 'vcaconv --help' for more information\n" );
return 1;
case 'h': /* show Help and exit */
usage();
return 0;
case 'V': /* show Version and exit */
versinfo();
return 0;
case -1: /* end of options */
break;
}
break;
}
if ( argc < 2 ) {
error( "missing conversion\n"
"use 'vcaconv --help' for more information" );
return 1;
}
if ( ( strcmp( argv[1], "bin2vca" ) == 0
|| strcmp( argv[1], "bin2txt" ) == 0
|| strcmp( argv[1], "vca2bin" ) == 0 )
&& 2 <= argc && argc <= 4 ) {
void * rec;
argv[1][3] = '\0'; /* split input,output format */
if ( pim_openinp( argv[1]+0, argc >= 3 ? argv[2] : "-" ) != OK ) {
error( "bad input format/file: %s %s\n", argv[1]+0, argv[2] );
return 1;
}
if ( pim_openout( argv[1]+4, argc >= 4 ? argv[3] : "-" ) != OK ) {
error( "bad output format/file: %s %s\n", argv[1]+4, argv[3] );
return 1;
}
while ( (rec = pim_getrec( FILE_ANY )) != NULL )
pim_putrec( rec );
pim_close();
} else if ( strcmp( argv[1], "prvca" ) == 0
&& 2 <= argc && argc <= 3 ) {
VObject * vlist;
VObject * vdel;
if ( (vlist = vca_parse( argc >= 3 ? argv[2] : "-" )) == NULL )
return 1;
while ( vlist ) {
printVObject( stdout, vlist );
vlist = nextVObjectInList( vdel = vlist );
cleanVObject( vdel );
}
} else if ( strcmp( argv[1], "sortvca" ) == 0
&& 2 <= argc && argc <= 3 ) {
VObject * vlist;
VObject * vdel;
if ( (vlist = vca_parse( argc >= 3 ? argv[2] : "-" )) == NULL )
return 1;
vca_sort( &vlist );
while ( vlist ) {
writeVObject( stdout, vlist );
vlist = nextVObjectInList( vdel = vlist );
cleanVObject( vdel );
}
} else if ( strcmp( argv[1], "imphandy" ) == 0
&& 2 <= argc && argc <= 3 ) {
VObject * vlist;
VObject * vdel;
if ( (vlist = vca_parse( argc >= 3 ? argv[2] : "-" )) == NULL )
return 1;
vcard_to_handy( &vlist );
while ( vlist ) {
writeVObject( stdout, vlist );
vlist = nextVObjectInList( vdel = vlist );
cleanVObject( vdel );
}
} else {
error( "unknown conversion: %s\n"
"use 'vcaconv --help' for more information", argv[1] );
return 1;
}
return 0;
}

2710
src/vcc.c Normal file

File diff suppressed because it is too large Load Diff

83
src/vcc.h Normal file
View File

@ -0,0 +1,83 @@
/***************************************************************************
(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
Business Machines Corporation and Siemens Rolm Communications Inc.
modified 2000 by Thomas Schulz:
$Id: vcc.h,v 1.2 2000/11/19 18:14:45 tsch Rel $
For purposes of this license notice, the term Licensors shall mean,
collectively, Apple Computer, Inc., AT&T Corp., International
Business Machines Corporation and Siemens Rolm Communications Inc.
The term Licensor shall mean any of the Licensors.
Subject to acceptance of the following conditions, permission is hereby
granted by Licensors without the need for written agreement and without
license or royalty fees, to use, copy, modify and distribute this
software for any purpose.
The above copyright notice and the following four paragraphs must be
reproduced in all copies of this software and any software including
this software.
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
MODIFICATIONS.
IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.
The software is provided with RESTRICTED RIGHTS. Use, duplication, or
disclosure by the government are subject to restrictions set forth in
DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
***************************************************************************/
#ifndef __VCC_H__
#define __VCC_H__ 1
#include "vobject.h"
#if defined(__CPLUSPLUS__) || defined(__cplusplus)
extern "C" {
#endif
typedef void (*MimeErrorHandler)(char *);
extern DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler);
extern DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len);
extern DLLEXPORT(VObject*) Parse_MIME_FromFileName(char* fname);
/* NOTE regarding Parse_MIME_FromFile
The function above, Parse_MIME_FromFile, comes in two flavors,
neither of which is exported from the DLL. Each version takes
a CFile or FILE* as a parameter, neither of which can be
passed across a DLL interface (at least that is my experience).
If you are linking this code into your build directly then
you may find them a more convenient API that the other flavors
that take a file name. If you use them with the DLL LIB you
will get a link error.
*/
#if INCLUDEMFC
extern VObject* Parse_MIME_FromFile(CFile *file);
#else
extern VObject* Parse_MIME_FromFile(FILE *file);
#endif
#if defined(__CPLUSPLUS__) || defined(__cplusplus)
}
#endif
#endif /* __VCC_H__ */

1249
src/vcc.y Normal file

File diff suppressed because it is too large Load Diff

762
src/vcutil.c Normal file
View File

@ -0,0 +1,762 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* */
static char rcsid[] =
"$Id: vcutil.c,v 1.44 2000/12/28 02:26:31 tsch Rel $"; /*
* *
* IC35 synchronize data import/export: vCard,vCalendar utilities *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
* vca_type determine vCard,vCal record type *
* dupSubst substitute in string, dupStr()'d result *
* dupSubstNL translate NL to CRLF, dupStr()'d result *
* dupSubstCRLF translate CRLF to NL, dupStr()'d result *
* utilities for IC35 to/from vCard,vCal *
* clr_vobjdirty clear vCard,vCal record modified status
* SetModtimeIfdirty modified date+time to vCard,vCal record
* _ChangeString set property string, note if changed
* SetProp
* SetString
* StringValue
* SetLong set property long integer value
* LongValue
* _NoteId NOTE/DESCRIPTION for vCard/vCal
* _NotePropsLen
* SetNotes
* NotesValue
* SetNoteProp
* NotePropValue
* _is_stdCategory standard categories Personal,Business..
* SetCategory
* CategoryValue
* SetTel set telephone HOME/WORK/CELL/FAX
* SetEmail set Email1,Email2
* utilities for date+time conversion *
* isodtstr_to_unixtime
* isodtstr_to_ymd_or_today
* isodtime_to_unixtime
* isodtime_to_ymd
* isodtime_to_ymd_or_today
* isodtime_to_hms_or_now
* *
************************************************************************/
#include <stdio.h> /* sprintf(), .. */
#include <stdlib.h> /* atol() */
#include <string.h> /* strcpy(), .. */
#include <ctype.h> /* isprint(), .. */
#include <sys/types.h> /* size_t, .. */
#include <time.h> /* struct tm, time() .. */
#include "util.h" /* bool */
#include "dataio.h" /* newic35dt() */
#include "vcc.h" /* VObject, .. */
#include "vcutil.h"
NOTUSED(rcsid);
/* map vCard,vCal record name to numeric type
* ------------------------------------------
*/
int
vca_type( VObject * vobj )
{
const char * name;
if ( vobj == NULL )
return 0;
name = vObjectName( vobj );
if ( strcasecmp( name, VCCardProp ) == 0 ) return VCARD;
if ( strcasecmp( name, VCMemoProp ) == 0 ) return VMEMO;
if ( strcasecmp( name, VCCalProp ) == 0 ) return VCAL;
if ( strcasecmp( name, VCEventProp ) == 0 ) return VEVENT;
if ( strcasecmp( name, VCTodoProp ) == 0 ) return VTODO;
return 0;
}
/* string substitutions
* --------------------
*/
/* substitutes 'new' for sub-string 'old' in 'str' */
char * /* and returns dupStr()'sd resulting string */
dupSubst( char * str, char * old, char * new )
{ /* substitutes 'new' for sub-string 'old' in 'str' */
char *match, *nstr;
char *pdst, *psrc;
if ( str == NULL )
return NULL; /* marginal .. */
if ( ! (old && *old && new ) /* .. parameters */
|| (match = strstr( str, old )) == NULL ) /* or no match */
return dupStr( str, 0 );
nstr = dupStr( "", strlen(str) + strlen(new) - strlen(old) );
pdst = nstr; psrc = str;
while ( *psrc )
if ( psrc == match ) {
strcpy( pdst, new );
psrc += strlen( old );
pdst += strlen( new );
} else
*pdst++ = *psrc++;
return nstr;
}
char * /* substitute vCard,vCal NewLine with IC35 CRLF */
dupSubstNL( char * src )
{
char *psrc, *dst, *pdst;
size_t len;
len = strlen( src );
for ( psrc = src; *psrc; ++psrc )
if ( *psrc == '\n' )
++len;
pdst = dst = dupStr( "", len );
psrc = src, pdst = dst;
while ( *psrc ) {
if ( *psrc == '\n'
&& !( psrc > src && *(psrc-1) == '\r' ) )
*pdst++ = '\r';
*pdst++ = *psrc++;
}
*pdst = '\0';
return dst;
}
char * /* substitute IC35 CRLF with vCard,vCal NewLine */
dupSubstCRLF( char * src )
{
char *dst, *pdst;
dst = pdst = dupStr( src, 0 );
while ( *src )
if ( (*pdst = *src++) != '\r' && *src != '\n' )
++pdst;
*pdst = '\0';
return dst;
}
/* ============================================ */
/* utilities for IC35 to/from vCard,vCal */
/* ============================================ */
static bool _vobj_dirty; /* VObject changed in ic35xxx_to_vyyy() */
static char ic35fld[511+1]; /* field buffer used by SetXxx() */
/* clear vCard,vCal modified status
* --------------------------------
*/
void
clr_vobjdirty( void )
{
_vobj_dirty = FALSE;
}
/* revised date+time for vCard,vCal records
* ----------------------------------------
*/
static char *
_iso_ic35dt( const char * format )
{
time_t ic35dt;
struct tm * ptm;
static char isodtime[24];
ic35dt = newic35dt();
ptm = localtime( &ic35dt );
strftime( isodtime, sizeof(isodtime), format, ptm );
return isodtime;
}
void
SetModtimeIfdirty( VObject * vobj )
{
if ( ! _vobj_dirty )
return;
switch ( vca_type( vobj ) ) {
case VCARD: /* yyyy-mm-ddThh:mm:ss for VCARRD */
SetString( vobj, VCLastRevisedProp, _iso_ic35dt("%Y-%m-%dT%H:%M:%S") );
break;
case VEVENT:
case VTODO: /* also create-time for VEVENT,VTODO */
if ( ! isAPropertyOf( vobj, VCDCreatedProp ) )
SetString( vobj, VCDCreatedProp, _iso_ic35dt("%Y%m%dT%H%M%S") );
/* fall through */
case VMEMO: /* yyyymmddThhmmss for VEVENT,VTODO,memo */
SetString( vobj, VCLastModifiedProp, _iso_ic35dt("%Y%m%dT%H%M%S") );
break;
}
}
/* set,get property string value
* -----------------------------
* handle VObject value types StringZ, UStringZ, Integer, Long
* determine need for QUOTED-PRINTABLE and CHARSET
* note if property / string changed in _vobj_dirty
*/
static void /* set property string, check and note if changed */
_ChangeString( VObject * vobj, char * str )
{
const char * oldstr;
switch ( vObjectValueType( vobj ) ) {
case VCVT_STRINGZ:
oldstr = dupStr( vObjectStringZValue( vobj ), 0 );
break;
case VCVT_USTRINGZ:
oldstr = fakeCString( vObjectUStringZValue( vobj ) );
break;
default:
oldstr = NULL;
}
if ( oldstr == NULL || strcmp( oldstr, str ) != 0 ) {
_vobj_dirty = TRUE;
setVObjectStringZValue( vobj, str );
}
deleteStr( oldstr );
}
VObject * /* add property if not yet there */
SetProp( VObject * vobj, const char * id )
{
VObject * vprop;
if ( (vprop = isAPropertyOf( vobj, id )) )
return vprop;
_vobj_dirty = TRUE;
return addProp( vobj, id );
}
void /* delete property */
DelProp( VObject * vobj, const char * id )
{
VObject * vprop;
if ( vobj && id && *id
&& (vprop = isAPropertyOf( vobj, id )) ) {
vprop = delProp( vobj, vprop );
cleanVObject( vprop );
_vobj_dirty = TRUE;
}
}
VObject * /* set string, check if need QUOTED-PRINTABLE or CHARSET */
SetString( VObject * vobj, const char * id, char * str )
{
VObject * vprop;
char * pstr;
bool prop_charset;
bool prop_quoted;
VObject * vpropchars;
if ( !( vobj && id && *id ) )
return NULL;
if ( !( str && *str ) ) {
DelProp( vobj, id );
return NULL;
}
if ( (vprop = isAPropertyOf( vobj, id )) == NULL )
vprop = addProp( vobj, id );
prop_quoted = prop_charset = FALSE;
for ( pstr = str; *pstr; ++pstr ) {
if ( *pstr & 0x80 )
prop_charset = TRUE;
if ( ! isprint( *pstr ) )
prop_quoted = TRUE;
}
if ( prop_quoted || prop_charset ) {
/*
* single-field property like VCARD:FN needs charset,quoted property
* attached to the property 'vprop'
* multi-field sub-property like VCARD:ADR:VCCityProp needs charset
* prop attached to the toplevel property 'vobj'
* multi-field property must not use QUOTED-PRINTABLE due to problem
* with vcc.y parser. fixing the parser would not help, because other
* programs using the vCard,vCal output do not have the fixed parser.
*/
switch ( vca_type( vobj ) ) {
case VCARD:
case VMEMO:
case VEVENT:
case VTODO:
vpropchars = vprop; /* single-field property */
break;
default:
vpropchars = vobj; /* multi-field sub-property */
}
if ( prop_quoted /* QUOTED-PRINTABLE must not */
&& vpropchars != vobj ) /* be used with multi-field */
SetProp( vpropchars, VCQuotedPrintableProp );
if ( prop_charset )
SetString( vpropchars, VCCharacterSetProp, "ISO-8859-1" );
}
_ChangeString( vprop, str );
return vprop;
}
char * /* dupStr()'d property's string value or NULL */
dupStringValue( VObject * vobj, const char * id )
{
VObject * vprop;
char vtext[1+10+1];
if ( vobj == NULL )
return NULL;
if ( id && *id ) {
if ( (vprop = isAPropertyOf( vobj, id )) == NULL )
return NULL;
} else
vprop = vobj;
switch ( vObjectValueType( vprop ) ) {
case VCVT_STRINGZ:
return dupStr( vObjectStringZValue( vprop ), 0 );
case VCVT_USTRINGZ:
return fakeCString( vObjectUStringZValue( vprop ) );
case VCVT_UINT:
sprintf( vtext, "%+010d", vObjectIntegerValue( vprop ) );
return dupStr( vtext, 0 );
case VCVT_ULONG:
sprintf( vtext, "%+010ld", vObjectLongValue( vprop ) );
return dupStr( vtext, 0 );
default:
return NULL;
}
}
char * /* property's string value or "" */
StringValue( VObject * vobj, const char * id )
{
char * strval;
if ( (strval = dupStringValue( vobj, id )) == NULL )
return "";
strncat( strcpy( ic35fld, "" ), strval, sizeof(ic35fld)-1 );
deleteStr( strval );
return ic35fld;
}
/* set,get property long integer value
* -----------------------------------
*/
void
SetLong( VObject * vobj, const char * id, long value )
{
VObject * vprop;
if ( (vprop = isAPropertyOf( vobj, id )) == NULL )
vprop = addProp( vobj, id );
setVObjectLongValue( vprop, value );
}
long /* property's long value or -1 if unknown */
LongValue( VObject * vobj, const char * id )
{
VObject * vprop;
char * strval;
long value;
if ( !( vobj && id && *id )
|| (vprop = isAPropertyOf( vobj, id )) == NULL )
return -1;
switch ( vObjectValueType( vprop ) ) {
case VCVT_STRINGZ:
return atol( vObjectStringZValue( vprop ) );
case VCVT_USTRINGZ:
strval = fakeCString( vObjectUStringZValue( vprop ) );
value = atol( strval );
deleteStr( strval );
return value;
case VCVT_UINT:
return vObjectIntegerValue( vprop );
case VCVT_ULONG:
return vObjectLongValue( vprop );
}
return -1;
}
/* set,get VObject NOTE/DESCRIPTION
* --------------------------------
* some properties are not supported by e.g. korganizer, gnomecal,
* as workaround they are kept is marked lines in NOTE/DESCRIPTION.
*/
static const char *
_NoteId( VObject * vobj )
{
switch( vca_type( vobj ) ) {
case VCARD:
case VMEMO: return VCNoteProp;
case VEVENT:
case VTODO: return VCDescriptionProp;
}
return NULL;
}
static size_t
_NotePropsLen( char * str, int vtype )
{
static struct {
int type;
const char * id;
} proptab[] = {
{ VCARD, DEF1PROP },
{ VCARD, DEF2PROP },
{ VTODO, VCDTstartProp },
{ VTODO, VCDueProp },
{ VTODO, VCCategoriesProp },
{ 0, NULL }
},
*ptab;
char * pline;
size_t lid;
for ( pline = str; pline; pline = strchr( pline, '\n' ) ) {
if ( *pline == '\n' )
++pline;
for ( ptab = proptab; ptab->id != NULL; ++ptab )
if ( ptab->type == vtype ) {
lid = strlen( ptab->id );
if ( strncmp( pline, ptab->id, lid ) == 0
&& *(pline+lid) == ':' )
break;
}
if ( ptab->id == NULL )
break;
}
return pline ? pline - str : 0;
}
void
SetNotes( VObject * vobj, char * value )
{
/* preserve property values stored in NOTE,DESCRIPTION */
/* translate CRLF to NL to avoid confusing korganizer */
char * onote;
char * nnote;
size_t lprops;
const char *id;
if ( (id = _NoteId( vobj )) == NULL )
return;
value = dupSubstCRLF( value ? value : "" );
if ( (onote = StringValue( vobj, id )) != NULL && *onote ) {
lprops = _NotePropsLen( onote, vca_type( vobj ) );
nnote = dupStr( "", lprops + strlen(value) );
strcat( strncat( strcpy( nnote, "" ), onote, lprops ), value );
deleteStr( value );
} else {
nnote = value;
}
SetString( vobj, id, nnote );
deleteStr( nnote );
}
char *
NotesValue( VObject * vobj )
{
/* skip property values stored in NOTE,DESCRIPTION */
/* translate NL to CRLF to avoid confusing IC35 */
char * note;
size_t lprops;
if ( (note = StringValue( vobj, _NoteId( vobj ) )) == NULL
|| strlen( note ) == 0 )
return "";
lprops = _NotePropsLen( note, vca_type( vobj ) );
note = dupSubstNL( note+lprops );
strcat( strcpy( ic35fld, "" ), note );
deleteStr( note );
return ic35fld;
}
void
SetNoteProp( VObject * vobj, const char * id, char * value )
{
/* replace or prepend property value in NOTE/DESCRIPTION */
/* as marked line "<id>:<value>\n" */
char *onote, *oprop, *oldstr;
char *nnote, *nprop;
const char *noteid;
if ( !((noteid = _NoteId( vobj )) && id && *id ) )
return;
onote = dupSubstNL( StringValue( vobj, noteid ) );
if ( value && *value ) {
nprop = dupStr( "", strlen(id)+1+strlen(value)+2 );
sprintf( nprop, "%s:%s\r\n", id, value );
} else
nprop = dupStr( "", 0 );
if ( (oldstr = NotePropValue( vobj, id )) != NULL && *oldstr ) {
oprop = dupStr( "", strlen(id)+1+strlen(oldstr)+2 );
sprintf( oprop, "%s:%s\r\n", id, oldstr );
nnote = dupSubst( onote, oprop, nprop );
deleteStr( oprop );
} else {
nnote = dupStr( "", strlen(nprop)+strlen(onote) );
strcat( strcpy( nnote, nprop ), onote );
}
deleteStr( onote );
deleteStr( nprop );
nnote = dupSubstCRLF( oldstr = nnote ); deleteStr( oldstr );
SetString( vobj, noteid, nnote );
deleteStr( nnote );
}
char *
NotePropValue( VObject * vobj, const char * id )
{
/* retrieve property value stored in NOTE/DESCRIPTION */
/* from marked line "<id>:<value>\n" */
char * note;
char * linetag;
char * pprop;
char * ptr;
if ( (note = StringValue( vobj, _NoteId( vobj ) )) == NULL
|| strlen( note ) == 0 ) {
return "";
}
sprintf( ptr = dupStr( "", strlen(note)+1 ), "\n%s", note );
note = dupSubstNL( ptr );
deleteStr( ptr );
sprintf( linetag = dupStr( "", strlen(id)+3 ), "\r\n%s:", id );
if ( (pprop = strstr( note, linetag )) != NULL ) {
pprop += strlen( linetag );
if ( (ptr = strstr( pprop, "\r\n" )) != NULL )
*ptr = '\0';
strncat( strcpy( ic35fld, "" ), pprop, sizeof(ic35fld) );
}
deleteStr( linetag );
deleteStr( note );
return pprop ? ic35fld : "";
}
/* categories
* ----------
*/
static char *
_is_stdCategory( char * category )
{
char * Address = "Address";
char * Business = "Business";
char * Personal = "Personal";
char * Unfiled = "Unfiled";
if ( strcasecmp( category, Address ) == 0 )
return Address;
else if ( strcasecmp( category, Business ) == 0 )
return Business;
else if ( strcasecmp( category, Personal ) == 0 )
return Personal;
else if ( strcasecmp( category, Unfiled ) == 0 )
return Unfiled;
return NULL;
}
VObject *
SetCategory( VObject * vobj, char * newcategory )
{
char * categories;
char * oldcategories;
char * category;
VObject * vprop;
if ( (oldcategories = StringValue( vobj, VCCategoriesProp )) == NULL
|| strlen( oldcategories ) == 0 /* no categories or */
|| strchr( oldcategories, ';' ) == NULL ) /* single category */
return SetString( vobj, VCCategoriesProp, newcategory );
categories = dupStr( oldcategories, strlen( oldcategories )
+ 1 + strlen( newcategory ) );
for ( category = strtok( categories, ";" );
category != NULL; category = strtok( NULL, ";" ) ) {
if ( strcmp( category, newcategory ) == 0 )
return isAPropertyOf( vobj, VCCategoriesProp );
if ( _is_stdCategory( category ) )
break;
}
if ( category != NULL ) { /* replace standard category */
category = dupStr( category, 0 );
deleteStr( categories );
categories = dupSubst( oldcategories, category, newcategory );
deleteStr( category );
} else /* else prepend new category */
sprintf( categories, "%s;%s", newcategory, oldcategories );
vprop = SetString( vobj, VCCategoriesProp, categories );
deleteStr( categories );
return vprop;
}
char * /* single, first standard or "Unfiled" */
CategoryValue( VObject * vobj )
{
char * Unfiled = "Unfiled";
char * categories;
char * category;
char * firstcategory;
char * firststdcategory;
if ( (categories = StringValue( vobj, VCCategoriesProp )) == NULL
|| strlen( categories ) == 0 )
return Unfiled;
firstcategory = firststdcategory = NULL;
for ( category = strtok( categories, ";" );
category; category = strtok( NULL, ";" ) ) {
if ( firstcategory == NULL )
firstcategory = dupStr( category, 0 );
if ( firststdcategory == NULL )
firststdcategory = _is_stdCategory( category );
}
if ( (category = firststdcategory) == NULL ) {
if ( firstcategory )
category = strncat( strcpy( ic35fld, "" ),
firstcategory, sizeof(ic35fld)-1 );
else
category = Unfiled;
}
deleteStr( firstcategory );
return category;
}
/* telephone numbers
* -----------------
*/
VObject *
SetTel( VObject * vobj, const char * type, char * str )
{
VObject * vprop;
VObjectIterator iter;
initPropIterator( &iter, vobj );
while ( moreIteration( &iter ) ) {
vprop = nextVObject( &iter );
if ( strcmp( vObjectName( vprop ), VCTelephoneProp ) == 0
&& isAPropertyOf( vprop, type ) ) {
if ( str && *str ) {
_ChangeString( vprop, str );
return vprop;
} else {
cleanVObject( delProp( vobj, vprop ) );
_vobj_dirty = TRUE;
return NULL;
}
}
}
if ( !( str && *str ) )
return NULL;
_vobj_dirty = TRUE;
vprop = addPropValue( vobj, VCTelephoneProp, str );
addProp( vprop, type );
return vprop;
}
/* email addresses
* ---------------
*/
VObject *
SetEmail( VObject * vobj, int num, char * str )
{
VObject * vprop;
VObjectIterator iter;
int index;
index = 0;
initPropIterator( &iter, vobj );
while ( moreIteration( &iter ) ) {
vprop = nextVObject( &iter );
if ( strcmp( vObjectName( vprop ), VCEmailAddressProp ) == 0
&& ++index == num ) {
if ( str && *str ) {
_ChangeString( vprop, str );
return vprop;
} else {
cleanVObject( delProp( vobj, vprop ) );
_vobj_dirty = TRUE;
return NULL;
}
}
}
if ( !( str && *str ) )
return NULL;
_vobj_dirty = TRUE;
vprop = addPropValue( vobj, VCEmailAddressProp, str );
addProp( vprop, VCInternetProp );
return vprop;
}
/* ============================================ */
/* ISO date+time conversions */
/* ============================================ */
static time_t /* convert ISO date+time to Unix-time */
isodtstr_to_unixtime( char * dtstr )
{
char * format;
struct tm dtm;
time_t dtime;
if ( !( dtstr && *dtstr ) )
return -1;
if ( strspn( dtstr, "0123456789" ) == 8 )
format = "%4d" "%2d" "%2d%*[^0-9]%2d" "%2d" "%2d";
else
format = "%4d%*[^0-9]%2d%*[^0-9]%2d%*[^0-9]%2d%*[^0-9]%2d%*[^0-9]%2d";
dtime = time( NULL );
memcpy( &dtm, localtime( &dtime ), sizeof(dtm) ); /* default: today,now */
sscanf( dtstr, format, &dtm.tm_year, &dtm.tm_mon, &dtm.tm_mday,
&dtm.tm_hour, &dtm.tm_min, &dtm.tm_sec );
dtm.tm_year -= 1900;
dtm.tm_mon -= 1;
dtm.tm_isdst = -1;
dtime = mktime( &dtm );
/*??? ymdhms_from_isodtime() does not respect timezone/Zulu in isodtime ???*/
return dtime;
}
char *
isodtstr_to_ymd_or_today( char * dtstr )
{
static char ymd[8+1];
time_t utsec;
if ( (utsec = isodtstr_to_unixtime( dtstr )) == -1 )
utsec = time( NULL );
strftime( ymd, sizeof(ymd), "%Y%m%d", localtime( &utsec ) );
return ymd;
}
time_t /* convert ISO date+time to Unix-time */
isodtime_to_unixtime( VObject * vobj, const char * id )
{
VObject * vprop;
char * dtstr;
time_t dtime;
if ( (vprop = isAPropertyOf( vobj, id )) == NULL )
return -1;
dtstr = fakeCString( vObjectUStringZValue( vprop ) );
dtime = isodtstr_to_unixtime( dtstr );
deleteStr( dtstr );
return dtime;
}
char *
isodtime_to_ymd( VObject * vobj, const char * id )
{
static char ymd[8+1];
time_t utsec;
if ( (utsec = isodtime_to_unixtime( vobj, id )) == -1 )
return "";
strftime( ymd, sizeof(ymd), "%Y%m%d", localtime( &utsec ) );
return ymd;
}
char *
isodtime_to_ymd_or_today( VObject * vobj, const char * id )
{
static char ymd[8+1];
time_t utsec;
if ( (utsec = isodtime_to_unixtime( vobj, id )) == -1 )
utsec = time( NULL );
strftime( ymd, sizeof(ymd), "%Y%m%d", localtime( &utsec ) );
return ymd;
}
char *
isodtime_to_hms_or_now( VObject * vobj, const char * id )
{
static char hms[6+1];
time_t utsec;
if ( (utsec = isodtime_to_unixtime( vobj, id )) == -1 )
utsec = time( NULL );
strftime( hms, sizeof(hms), "%H%M%S", localtime( &utsec ) );
return hms;
}

61
src/vcutil.h Normal file
View File

@ -0,0 +1,61 @@
/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* *
* $Id: vcutil.h,v 1.44 2000/12/27 22:26:52 tsch Rel $ *
* *
* header for IC35 data import/export: vCard,vCalendar utilities *
* *
************************************************************************/
#ifndef _VCUTIL_H
#define _VCUTIL_H 1
#include "vcc.h" /* VObject, .. */
/* vCard,vCal record types */
#define VCARD 1
#define VMEMO 2
#define VCAL 3
#define VEVENT 4
#define VTODO 5
/* markers for (def.) in IC35 address */
#define DEF1PROP "(def1)"
#define DEF2PROP "(def2)"
int vca_type( VObject * vobj );
char * dupSubst( char * str, char * old, char * new );
char * dupSubstNL( char * src );
char * dupSubstCRLF( char * src );
void clr_vobjdirty( void );
void SetModtimeIfdirty( VObject * vobj );
VObject * SetProp( VObject * vobj, const char * id );
void DelProp( VObject * vobj, const char * id );
VObject * SetString( VObject * vobj, const char * id, char * str );
char * dupStringValue( VObject * vobj, const char * id );
char * StringValue( VObject * vobj, const char * id );
void SetLong( VObject * vobj, const char * id, long value );
long LongValue( VObject * vobj, const char * id );
void SetNotes( VObject * vobj, char * value );
void SetNoteProp( VObject * vobj, const char * id, char * value );
char * NotesValue( VObject * vobj );
char * NotePropValue( VObject * vobj, const char * id );
VObject * SetCategory( VObject * vobj, char * newcategory );
char * CategoryValue( VObject * vobj );
VObject * SetTel( VObject * vobj, const char * type, char * str );
VObject * SetEmail( VObject * vobj, int num, char * str );
char * isodtstr_to_ymd_or_today( char * dtstr );
time_t isodtime_to_unixtime( VObject * vobj, const char * id );
char * isodtime_to_ymd( VObject * vobj, const char * id );
char * isodtime_to_ymd_or_today( VObject * vobj, const char * id );
char * isodtime_to_hms_or_now( VObject * vobj, const char * id );
#endif /*_VCUTIL_H*/

1511
src/vobject.c Normal file

File diff suppressed because it is too large Load Diff

380
src/vobject.h Normal file
View File

@ -0,0 +1,380 @@
/***************************************************************************
(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
Business Machines Corporation and Siemens Rolm Communications Inc.
modified 2000 by Thomas Schulz:
$Id: vobject.h,v 1.6 2000/12/21 23:01:45 tsch Rel $
For purposes of this license notice, the term Licensors shall mean,
collectively, Apple Computer, Inc., AT&T Corp., International
Business Machines Corporation and Siemens Rolm Communications Inc.
The term Licensor shall mean any of the Licensors.
Subject to acceptance of the following conditions, permission is hereby
granted by Licensors without the need for written agreement and without
license or royalty fees, to use, copy, modify and distribute this
software for any purpose.
The above copyright notice and the following four paragraphs must be
reproduced in all copies of this software and any software including
this software.
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
MODIFICATIONS.
IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.
The software is provided with RESTRICTED RIGHTS. Use, duplication, or
disclosure by the government are subject to restrictions set forth in
DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
***************************************************************************/
/*
The vCard/vCalendar C interface is implemented in the set
of files as follows:
vcc.y, yacc source, and vcc.c, the yacc output you will use
implements the core parser
vobject.c implements an API that insulates the caller from
the parser and changes in the vCard/vCalendar BNF
port.h defines compilation environment dependent stuff
vcc.h and vobject.h are header files for their .c counterparts
vcaltmp.h and vcaltmp.c implement vCalendar "macro" functions
which you may find useful.
test.c is a standalone test driver that exercises some of
the features of the APIs provided. Invoke test.exe on a
VCARD/VCALENDAR input text file and you will see the pretty
print output of the internal representation (this pretty print
output should give you a good idea of how the internal
representation looks like -- there is one such output in the
following too). Also, a file with the .out suffix is generated
to show that the internal representation can be written back
in the original text format.
For more information on this API see the readme.txt file
which accompanied this distribution.
Also visit:
http://www.versit.com
http://www.ralden.com
*/
#ifndef __VOBJECT_H__
#define __VOBJECT_H__ 1
#include "port.h"
#include <stdlib.h>
#include <stdio.h>
#if defined(__CPLUSPLUS__) || defined(__cplusplus)
extern "C" {
#endif
#define VC7bitProp "7BIT"
#define VC8bitProp "8BIT"
#define VCAAlarmProp "AALARM"
#define VCAdditionalNamesProp "ADDN"
#define VCAdrProp "ADR"
#define VCAgentProp "AGENT"
#define VCAIFFProp "AIFF"
#define VCAOLProp "AOL"
#define VCAppleLinkProp "APPLELINK"
#define VCAttachProp "ATTACH"
#define VCAttendeeProp "ATTENDEE"
#define VCATTMailProp "ATTMAIL"
#define VCAudioContentProp "AUDIOCONTENT"
#define VCAVIProp "AVI"
#define VCBase64Prop "BASE64"
#define VCBBSProp "BBS"
#define VCBirthDateProp "BDAY"
#define VCBMPProp "BMP"
#define VCBodyProp "BODY"
#define VCBusinessRoleProp "ROLE"
#define VCCalProp "VCALENDAR"
#define VCCaptionProp "CAP"
#define VCCardProp "VCARD"
#define VCCarProp "CAR"
#define VCCategoriesProp "CATEGORIES"
#define VCCellularProp "CELL"
#define VCCGMProp "CGM"
#define VCCharSetProp "CS"
#define VCCIDProp "CID"
#define VCCISProp "CIS"
#define VCCityProp "L"
#define VCClassProp "CLASS"
#define VCCommentProp "NOTE"
#define VCCompletedProp "COMPLETED"
#define VCContentIDProp "CONTENT-ID"
#define VCCountryNameProp "C"
#define VCDAlarmProp "DALARM"
#define VCDataSizeProp "DATASIZE"
#define VCDayLightProp "DAYLIGHT"
#define VCDCreatedProp "DCREATED"
#define VCDeliveryLabelProp "LABEL"
#define VCDescriptionProp "DESCRIPTION"
#define VCDIBProp "DIB"
#define VCDisplayStringProp "DISPLAYSTRING"
#define VCDomesticProp "DOM"
#define VCDTendProp "DTEND"
#define VCDTstartProp "DTSTART"
#define VCDueProp "DUE"
#define VCEmailAddressProp "EMAIL"
#define VCEncodingProp "ENCODING"
#define VCEndProp "END"
#define VCEventProp "VEVENT"
#define VCEWorldProp "EWORLD"
#define VCExNumProp "EXNUM"
#define VCExpDateProp "EXDATE"
#define VCExpectProp "EXPECT"
#define VCExtAddressProp "EXT ADD"
#define VCFamilyNameProp "F"
#define VCFaxProp "FAX"
#define VCFullNameProp "FN"
#define VCGeoProp "GEO"
#define VCGeoLocationProp "GEO"
#define VCGIFProp "GIF"
#define VCGivenNameProp "G"
#define VCGroupingProp "Grouping"
#define VCHomeProp "HOME"
#define VCIBMMailProp "IBMMail"
#define VCInlineProp "INLINE"
#define VCInternationalProp "INTL"
#define VCInternetProp "INTERNET"
#define VCISDNProp "ISDN"
#define VCJPEGProp "JPEG"
#define VCLanguageProp "LANG"
#define VCLastModifiedProp "LAST-MODIFIED"
#define VCLastRevisedProp "REV"
#define VCLocationProp "LOCATION"
#define VCLogoProp "LOGO"
#define VCMailerProp "MAILER"
#define VCMAlarmProp "MALARM"
#define VCMCIMailProp "MCIMAIL"
#define VCMessageProp "MSG"
#define VCMETProp "MET"
#define VCModemProp "MODEM"
#define VCMPEG2Prop "MPEG2"
#define VCMPEGProp "MPEG"
#define VCMSNProp "MSN"
#define VCNamePrefixesProp "NPRE"
#define VCNameProp "N"
#define VCNameSuffixesProp "NSUF"
#define VCNoteProp "NOTE"
#define VCOrgNameProp "ORGNAME"
#define VCOrgProp "ORG"
#define VCOrgUnit2Prop "OUN2"
#define VCOrgUnit3Prop "OUN3"
#define VCOrgUnit4Prop "OUN4"
#define VCOrgUnitProp "OUN"
#define VCPagerProp "PAGER"
#define VCPAlarmProp "PALARM"
#define VCParcelProp "PARCEL"
#define VCPartProp "PART"
#define VCPCMProp "PCM"
#define VCPDFProp "PDF"
#define VCPGPProp "PGP"
#define VCPhotoProp "PHOTO"
#define VCPICTProp "PICT"
#define VCPMBProp "PMB"
#define VCPostalBoxProp "BOX"
#define VCPostalCodeProp "PC"
#define VCPostalProp "POSTAL"
#define VCPowerShareProp "POWERSHARE"
#define VCPreferredProp "PREF"
#define VCPriorityProp "PRIORITY"
#define VCProcedureNameProp "PROCEDURENAME"
#define VCProdIdProp "PRODID"
#define VCProdigyProp "PRODIGY"
#define VCPronunciationProp "SOUND"
#define VCPSProp "PS"
#define VCPublicKeyProp "KEY"
#define VCQPProp "QP"
#define VCQuickTimeProp "QTIME"
#define VCQuotedPrintableProp "QUOTED-PRINTABLE"
#define VCRDateProp "RDATE"
#define VCRegionProp "R"
#define VCRelatedToProp "RELATED-TO"
#define VCRepeatCountProp "REPEATCOUNT"
#define VCResourcesProp "RESOURCES"
#define VCRNumProp "RNUM"
#define VCRoleProp "ROLE"
#define VCRRuleProp "RRULE"
#define VCRSVPProp "RSVP"
#define VCRunTimeProp "RUNTIME"
#define VCSequenceProp "SEQUENCE"
#define VCSnoozeTimeProp "SNOOZETIME"
#define VCStartProp "START"
#define VCStatusProp "STATUS"
#define VCStreetAddressProp "STREET"
#define VCSubTypeProp "SUBTYPE"
#define VCSummaryProp "SUMMARY"
#define VCTelephoneProp "TEL"
#define VCTIFFProp "TIFF"
#define VCTimeZoneProp "TZ"
#define VCTitleProp "TITLE"
#define VCTLXProp "TLX"
#define VCTodoProp "VTODO"
#define VCTranspProp "TRANSP"
#define VCUniqueStringProp "UID"
#define VCURLProp "URL"
#define VCURLValueProp "URLVAL"
#define VCValueProp "VALUE"
#define VCVersionProp "VERSION"
#define VCVideoProp "VIDEO"
#define VCVoiceProp "VOICE"
#define VCWAVEProp "WAVE"
#define VCWMFProp "WMF"
#define VCWorkProp "WORK"
#define VCX400Prop "X400"
#define VCX509Prop "X509"
#define VCXRuleProp "XRULE"
/* missing, although described in "vCard v2.1" vcard-21.ps */
#define VCCharacterSetProp "CHARSET"
/* Extensions */
#define XPilotIdProp "X-PILOTID"
#define XPilotStatusProp "X-PILOTSTAT"
/* non-standard for Memo/Note */
#define VCMemoProp "VMEMO"
typedef struct VObject VObject;
typedef struct VObjectIterator {
VObject* start;
VObject* next;
} VObjectIterator;
extern DLLEXPORT(VObject*) newVObject(const char *id);
extern DLLEXPORT(void) deleteVObject(VObject *p);
extern DLLEXPORT(char*) dupStr(const char *s, unsigned int size);
extern DLLEXPORT(void) deleteStr(const char *p);
extern DLLEXPORT(void) unUseStr(const char *s);
extern DLLEXPORT(void) setVObjectName(VObject *o, const char* id);
extern DLLEXPORT(void) setVObjectStringZValue(VObject *o, const char *s);
extern DLLEXPORT(void) setVObjectStringZValue_(VObject *o, const char *s);
extern DLLEXPORT(void) setVObjectUStringZValue(VObject *o, const wchar_t *s);
extern DLLEXPORT(void) setVObjectUStringZValue_(VObject *o, const wchar_t *s);
extern DLLEXPORT(void) setVObjectIntegerValue(VObject *o, unsigned int i);
extern DLLEXPORT(void) setVObjectLongValue(VObject *o, unsigned long l);
extern DLLEXPORT(void) setVObjectAnyValue(VObject *o, void *t);
extern DLLEXPORT(VObject*) setValueWithSize(VObject *prop, void *val, unsigned int size);
extern DLLEXPORT(VObject*) setValueWithSize_(VObject *prop, void *val, unsigned int size);
extern DLLEXPORT(const char*) vObjectName(VObject *o);
extern DLLEXPORT(const char*) vObjectStringZValue(VObject *o);
extern DLLEXPORT(const wchar_t*) vObjectUStringZValue(VObject *o);
extern DLLEXPORT(unsigned int) vObjectIntegerValue(VObject *o);
extern DLLEXPORT(unsigned long) vObjectLongValue(VObject *o);
extern DLLEXPORT(void*) vObjectAnyValue(VObject *o);
extern DLLEXPORT(VObject*) vObjectVObjectValue(VObject *o);
extern DLLEXPORT(void) setVObjectVObjectValue(VObject *o, VObject *p);
extern DLLEXPORT(VObject*) addVObjectProp(VObject *o, VObject *p);
extern DLLEXPORT(VObject*) addProp(VObject *o, const char *id);
extern DLLEXPORT(VObject*) addProp_(VObject *o, const char *id);
extern DLLEXPORT(VObject*) addPropValue(VObject *o, const char *p, const char *v);
extern DLLEXPORT(VObject*) addPropSizedValue_(VObject *o, const char *p, const char *v, unsigned int size);
extern DLLEXPORT(VObject*) addPropSizedValue(VObject *o, const char *p, const char *v, unsigned int size);
extern DLLEXPORT(VObject*) addGroup(VObject *o, const char *g);
extern DLLEXPORT(void) addList(VObject **o, VObject *p);
extern DLLEXPORT(VObject*) isAPropertyOf(VObject *o, const char *id);
extern DLLEXPORT(VObject*) nextVObjectInList(VObject *o);
extern DLLEXPORT(void) initPropIterator(VObjectIterator *i, VObject *o);
extern DLLEXPORT(int) moreIteration(VObjectIterator *i);
extern DLLEXPORT(VObject*) nextVObject(VObjectIterator *i);
extern DLLEXPORT(char*) writeMemVObject(char *s, int *len, VObject *o);
extern DLLEXPORT(char*) writeMemVObjects(char *s, int *len, VObject *list);
extern DLLEXPORT(const char*) lookupStr(const char *s);
extern DLLEXPORT(void) cleanStrTbl(void);
extern DLLEXPORT(void) cleanVObject(VObject *o);
extern DLLEXPORT(void) cleanVObjects(VObject *list);
extern DLLEXPORT(VObject*) delList( VObject ** list, VObject * vobj );
extern DLLEXPORT(VObject*) delProp( VObject * vobj, VObject * prop );
extern DLLEXPORT(const char*) lookupProp(const char* str);
extern DLLEXPORT(const char*) lookupProp_(const char* str);
extern DLLEXPORT(wchar_t*) fakeUnicode(const char *ps, int *bytes);
extern DLLEXPORT(int) uStrLen(const wchar_t *u);
extern DLLEXPORT(char*) fakeCString(const wchar_t *u);
extern DLLEXPORT(void) printVObjectToFile(char *fname,VObject *o);
extern DLLEXPORT(void) printVObjectsToFile(char *fname,VObject *list);
extern DLLEXPORT(void) writeVObjectToFile(char *fname, VObject *o);
extern DLLEXPORT(void) writeVObjectsToFile(char *fname, VObject *list);
extern DLLEXPORT(void) setCRLFmode( int mode );
extern DLLEXPORT(int) CRLFmode( void );
extern DLLEXPORT(int) vObjectValueType(VObject *o);
/* return type of vObjectValueType: */
#define VCVT_NOVALUE 0
/* if the VObject has no value associated with it. */
#define VCVT_STRINGZ 1
/* if the VObject has value set by setVObjectStringZValue. */
#define VCVT_USTRINGZ 2
/* if the VObject has value set by setVObjectUStringZValue. */
#define VCVT_UINT 3
/* if the VObject has value set by setVObjectIntegerValue. */
#define VCVT_ULONG 4
/* if the VObject has value set by setVObjectLongValue. */
#define VCVT_RAW 5
/* if the VObject has value set by setVObjectAnyValue. */
#define VCVT_VOBJECT 6
/* if the VObject has value set by setVObjectVObjectValue. */
extern const char** fieldedProp;
/* NOTE regarding printVObject and writeVObject
The functions below are not exported from the DLL because they
take a FILE* as a parameter, which cannot be passed across a DLL
interface (at least that is my experience). Instead you can use
their companion functions which take file names or pointers
to memory. However, if you are linking this code into
your build directly then you may find them a more convenient API
and you can go ahead and use them. If you try to use them with
the DLL LIB you will get a link error.
*/
extern void printVObject(FILE *fp,VObject *o);
extern void writeVObject(FILE *fp, VObject *o);
#if defined(__CPLUSPLUS__) || defined(__cplusplus)
}
#endif
#endif /* __VOBJECT_H__ */

1
stamp-h1 Normal file
View File

@ -0,0 +1 @@
timestamp for config.h

247
ylwrap Executable file
View File

@ -0,0 +1,247 @@
#! /bin/sh
# ylwrap - wrapper for lex/yacc invocations.
scriptversion=2018-03-07.03; # UTC
# Copyright (C) 1996-2020 Free Software Foundation, Inc.
#
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be 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, see <https://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
get_dirname ()
{
case $1 in
*/*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';;
# Otherwise, we want the empty string (not ".").
esac
}
# guard FILE
# ----------
# The CPP macro used to guard inclusion of FILE.
guard ()
{
printf '%s\n' "$1" \
| sed \
-e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \
-e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g' \
-e 's/__*/_/g'
}
# quote_for_sed [STRING]
# ----------------------
# Return STRING (or stdin) quoted to be used as a sed pattern.
quote_for_sed ()
{
case $# in
0) cat;;
1) printf '%s\n' "$1";;
esac \
| sed -e 's|[][\\.*]|\\&|g'
}
case "$1" in
'')
echo "$0: No files given. Try '$0 --help' for more information." 1>&2
exit 1
;;
--basedir)
basedir=$2
shift 2
;;
-h|--h*)
cat <<\EOF
Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
Wrapper for lex/yacc invocations, renaming files as desired.
INPUT is the input file
OUTPUT is one file PROG generates
DESIRED is the file we actually want instead of OUTPUT
PROGRAM is program to run
ARGS are passed to PROG
Any number of OUTPUT,DESIRED pairs may be used.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v|--v*)
echo "ylwrap $scriptversion"
exit $?
;;
esac
# The input.
input=$1
shift
# We'll later need for a correct munging of "#line" directives.
input_sub_rx=`get_dirname "$input" | quote_for_sed`
case $input in
[\\/]* | ?:[\\/]*)
# Absolute path; do nothing.
;;
*)
# Relative path. Make it absolute.
input=`pwd`/$input
;;
esac
input_rx=`get_dirname "$input" | quote_for_sed`
# Since DOS filename conventions don't allow two dots,
# the DOS version of Bison writes out y_tab.c instead of y.tab.c
# and y_tab.h instead of y.tab.h. Test to see if this is the case.
y_tab_nodot=false
if test -f y_tab.c || test -f y_tab.h; then
y_tab_nodot=true
fi
# The parser itself, the first file, is the destination of the .y.c
# rule in the Makefile.
parser=$1
# A sed program to s/FROM/TO/g for all the FROM/TO so that, for
# instance, we rename #include "y.tab.h" into #include "parse.h"
# during the conversion from y.tab.c to parse.c.
sed_fix_filenames=
# Also rename header guards, as Bison 2.7 for instance uses its header
# guard in its implementation file.
sed_fix_header_guards=
while test $# -ne 0; do
if test x"$1" = x"--"; then
shift
break
fi
from=$1
# Handle y_tab.c and y_tab.h output by DOS
if $y_tab_nodot; then
case $from in
"y.tab.c") from=y_tab.c;;
"y.tab.h") from=y_tab.h;;
esac
fi
shift
to=$1
shift
sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;"
sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;"
done
# The program to run.
prog=$1
shift
# Make any relative path in $prog absolute.
case $prog in
[\\/]* | ?:[\\/]*) ;;
*[\\/]*) prog=`pwd`/$prog ;;
esac
dirname=ylwrap$$
do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
mkdir $dirname || exit 1
cd $dirname
case $# in
0) "$prog" "$input" ;;
*) "$prog" "$@" "$input" ;;
esac
ret=$?
if test $ret -eq 0; then
for from in *
do
to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"`
if test -f "$from"; then
# If $2 is an absolute path name, then just use that,
# otherwise prepend '../'.
case $to in
[\\/]* | ?:[\\/]*) target=$to;;
*) target=../$to;;
esac
# Do not overwrite unchanged header files to avoid useless
# recompilations. Always update the parser itself: it is the
# destination of the .y.c rule in the Makefile. Divert the
# output of all other files to a temporary file so we can
# compare them to existing versions.
if test $from != $parser; then
realtarget=$target
target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'`
fi
# Munge "#line" or "#" directives. Don't let the resulting
# debug information point at an absolute srcdir. Use the real
# output file name, not yy.lex.c for instance. Adjust the
# include guards too.
sed -e "/^#/!b" \
-e "s|$input_rx|$input_sub_rx|" \
-e "$sed_fix_filenames" \
-e "$sed_fix_header_guards" \
"$from" >"$target" || ret=$?
# Check whether files must be updated.
if test "$from" != "$parser"; then
if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
echo "$to is unchanged"
rm -f "$target"
else
echo "updating $to"
mv -f "$target" "$realtarget"
fi
fi
else
# A missing file is only an error for the parser. This is a
# blatant hack to let us support using "yacc -d". If -d is not
# specified, don't fail when the header file is "missing".
if test "$from" = "$parser"; then
ret=1
fi
fi
done
fi
# Remove the directory.
cd ..
rm -rf $dirname
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End: