Import nweadmin 0.1b from upstream zip
This commit is contained in:
339
COPYING
Normal file
339
COPYING
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, 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) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
BIN
NWADMIN.EXE
Normal file
BIN
NWADMIN.EXE
Normal file
Binary file not shown.
339
NWTP/COPYING
Normal file
339
NWTP/COPYING
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, 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) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
9
NWTP/FILE_ID.DIZ
Normal file
9
NWTP/FILE_ID.DIZ
Normal file
@@ -0,0 +1,9 @@
|
||||
Netware Interface Units for Pascal.
|
||||
(Novell Netware 3.x and TP/BP 6.x/7.x)
|
||||
Freeware. Full sources, over 300 kb. of
|
||||
documentation and lots of examples. The
|
||||
most complete API available for PASCAL.
|
||||
KEYWORDS: LAN, Network, Novell, API,
|
||||
Library, Bindery, IPX, SPX, Queue,
|
||||
Tool, Reference, Workstation, Client,
|
||||
Real Mode, Protected Mode, Windows.
|
||||
561
NWTP/NWACCT.PAS
Normal file
561
NWTP/NWACCT.PAS
Normal file
@@ -0,0 +1,561 @@
|
||||
{$X+,B-,V-,S-} {essential compiler directives}
|
||||
|
||||
Unit nwAcct;
|
||||
|
||||
{ nwAcct unit as of 950301 / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
INTERFACE
|
||||
|
||||
Uses nwIntr,nwMisc,nwBindry,nwConn;
|
||||
|
||||
{ Primary functions: Interrupt: Comments:
|
||||
|
||||
* GetAccountStatus (F217/96) (1)
|
||||
* SubmitAccountCharge (F217/97) (2)(3)
|
||||
* SubmitAccountHold (F217/98) (2)
|
||||
* SubmitAccountNote (F217/99) (2)
|
||||
|
||||
Secondary functions:
|
||||
|
||||
* AccountingInstalled (4)
|
||||
* SetAccountStatus (5)
|
||||
* AddAccountingServer (5)
|
||||
* DeleteAccountingServer (5)
|
||||
* DeleteAccountHolds (2)
|
||||
|
||||
Notes: (1) To be called by:
|
||||
-accounting servers;
|
||||
-supervisor equivalent users;
|
||||
-objects querying their own account status.
|
||||
(2) To be called by accounting servers only.
|
||||
(3) Can be imitated by supervisor-equivalent users by
|
||||
calling GetAccountStatus and SetAccountStatus. Atomicity
|
||||
of such a bindery transaction can not be guaranteed.
|
||||
(4) Can be called by all logged on users.
|
||||
(5) Supervisor equivalent users only.
|
||||
|
||||
}
|
||||
|
||||
Var result:word;
|
||||
|
||||
{ Type definitions based on NET$ACCT.FMT by Wolfgang Schreiber }
|
||||
{ See Acct.pas in the XACCT archive for an example of their use. }
|
||||
|
||||
CONST { Accounting file record types }
|
||||
RT_SUBMIT_CHARGE=1;
|
||||
RT_ACCOUNT_NOTE =2;
|
||||
|
||||
{ comment types within accounting file }
|
||||
|
||||
CT_CONN_CHARGE = 1;
|
||||
CT_STORAGE_CHARGE = 2;
|
||||
CT_LOGIN_NOTE = 3;
|
||||
CT_LOGOUT_NOTE = 4;
|
||||
CT_INTRUDER_NOTE = 5;
|
||||
CT_TIMEMOD_NOTE = 6;
|
||||
CT_BOOT_NOTE = 8;
|
||||
CT_DOWN_NOTE = 9;
|
||||
CT_COMMENT = 99;
|
||||
|
||||
Type TAccDateTime6 = Array [1..6] of Byte; { date and time stamp of entry YMDHMS}
|
||||
|
||||
Type TComment = RECORD { interprete comments according to CmtType }
|
||||
CASE Integer of
|
||||
CT_CONN_CHARGE : (ConnectTime : LongInt;
|
||||
RequestCount : LongInt;
|
||||
BytesRead : Array[1..6] of BYTE; {hi-lo}
|
||||
BytesWritten : Array[1..6] of BYTE); {hi-lo}
|
||||
CT_STORAGE_CHARGE : (BlocksOwned : LongInt;
|
||||
HalfHours : LongInt);
|
||||
CT_LOGIN_NOTE,
|
||||
CT_LOGOUT_NOTE,
|
||||
CT_INTRUDER_NOTE : (Net :TnetworkAddress;
|
||||
Node:TnodeAddress);
|
||||
CT_TIMEMOD_NOTE : (ServerTime : TAccDateTime6);
|
||||
CT_BOOT_NOTE,
|
||||
CT_DOWN_NOTE : ();{ NO comment fields }
|
||||
CT_COMMENT : (Comment : String)
|
||||
END;
|
||||
|
||||
{ Use either the Type SubmitCharge or SubmitNote to interprete
|
||||
an entry - decide on typecasting with the aid of the RecType field. }
|
||||
|
||||
Type TChargeRecord = RECORD
|
||||
Length : Word;
|
||||
ServerObjId : LongInt; {hi-lo}
|
||||
TimeStamp : TAccDateTime6;
|
||||
RecType : BYTE; {Record type Note/Charge}
|
||||
ccode : BYTE; {completion code}
|
||||
ServiceType : WORD; {hi-lo}
|
||||
ClientObjID : LongInt; {hi-lo}
|
||||
Charge : LongInt; {hi-lo}
|
||||
CommentType : WORD; {hi-lo}
|
||||
Comment : Tcomment; {Variable length field}
|
||||
END;
|
||||
|
||||
Type TNoteRecord = RECORD
|
||||
Length : Word;
|
||||
ServerObjId : LongInt; {hi-lo}
|
||||
TimeStamp : TAccDateTime6;
|
||||
RecType : BYTE;
|
||||
ccode : BYTE;
|
||||
ServiceType : WORD; {hi-lo}
|
||||
ClientObjID : LongInt; {hi-lo}
|
||||
CommentType : WORD; {hi-lo}
|
||||
Comment : TComment;
|
||||
END;
|
||||
|
||||
|
||||
{F217/96 [2.15c+]}
|
||||
Function GetAccountStatus(objName:string; objType:word;
|
||||
Var balance,limit,holds:LongInt):boolean;
|
||||
|
||||
{F217/97 [2.15c+]}
|
||||
Function SubmitAccountCharge(objName:string; objType:word;
|
||||
charge,cancelHoldAmount:Longint;
|
||||
serviceType, commentType:word; comment:string):boolean;
|
||||
|
||||
{F217/98 [2.15c+]}
|
||||
Function SubmitAccountHold(objName:string; objType:word;
|
||||
reserveAmount:Longint ):boolean;
|
||||
|
||||
{F217/99 [2.15c+]}
|
||||
Function SubmitAccountNote(objName:string; objType:word;
|
||||
serviceType,commentType:word; comment:string):boolean;
|
||||
|
||||
{--------Secondary Functions-----------------------------------------------}
|
||||
|
||||
Function AccountingInstalled:boolean;
|
||||
|
||||
Function SetAccountStatus(objName:string; objType:word; balance,limit:LongInt):boolean;
|
||||
{ need to be supervisor equivalent to use this call }
|
||||
|
||||
Function AddAccountingServer(objName:string;objType:word):boolean;
|
||||
{ need to be supervisor equivalent to use this call }
|
||||
|
||||
Function DeleteAccountingServer(objName:string;objType:word):boolean;
|
||||
{ need to be supervisor equivalent to use this call }
|
||||
|
||||
Function DeleteAccountHolds(objName:string; objType:word):boolean;
|
||||
{ delete all holds the caller (an accounting server) has on the
|
||||
object with name objName of type objType. }
|
||||
|
||||
Type Tcharge=record
|
||||
DaysOfCharge:Byte; { bit 0=sunday,.. bit 6=saturday }
|
||||
TimeOfCharge:Byte; { 0:00=0 ..23:30 =47, half-hour
|
||||
during which the specified 'new' rate takes effect. }
|
||||
ChargeRateMultiplier,
|
||||
ChargeRateDivisor:Word;
|
||||
end;
|
||||
TchargeRec=record
|
||||
NextChargeTime:Longint; { minutes since 1-1-1985 }
|
||||
charges:array[1..20] of Tcharge;
|
||||
end;
|
||||
|
||||
|
||||
Type TchargeTableEntry=array[0..47] of Real;
|
||||
Var ChargeTable:Array [0..6] of TchargeTableEntry;
|
||||
|
||||
IMPLEMENTATION {===========================================================}
|
||||
|
||||
Procedure GetBindryAccountStatus(objName:string; objType:word;
|
||||
Var balance,limit,holds:LongInt);
|
||||
{ called by GetAccountStatus when the calling object isn't an
|
||||
accounting server. The F217/96 fails, but a bindery read will
|
||||
work for supervisor-equivalent users. }
|
||||
Var accPropVal:Tproperty;
|
||||
accVal: record
|
||||
_balance:LongInt; {hi-lo}
|
||||
_limit:LongInt; {hi-lo}
|
||||
_Reserved:array[1..120] of byte; { NW internal info }
|
||||
end ABSOLUTE accPropVal;
|
||||
holdPropVal:Tproperty;
|
||||
holdVal: array[1..16]
|
||||
of record
|
||||
AccountServerID:Longint; {hi-lo}
|
||||
HoldAmount :LongInt; {hi-lo}
|
||||
end ABSOLUTE holdPropVal;
|
||||
moreSegments:boolean;
|
||||
t,propFlags:byte;
|
||||
begin
|
||||
IF ReadPropertyValue(objName,objType,'ACCOUNT_BALANCE',1,
|
||||
accPropVal,moreSegments,propFlags)
|
||||
then begin
|
||||
balance:=Lswap(accVal._balance);
|
||||
limit:=Lswap(accVal._limit);
|
||||
IF ReadPropertyValue(objName,objType,'ACCOUNT_HOLDS',1,
|
||||
holdPropVal,moreSegments,propFlags)
|
||||
then begin { holds exist. }
|
||||
holds:=0;
|
||||
for t:=1 to 16
|
||||
do if holdVal[t].AccountServerID<>0
|
||||
then holds:=holds+Lswap(holdVal[t].HoldAmount);
|
||||
end;
|
||||
if nwBindry.result=$FB
|
||||
then begin
|
||||
result:=0;
|
||||
holds:=0;
|
||||
end
|
||||
else result:=nwBindry.result;
|
||||
end
|
||||
else if nwBindry.result=$FB { no such property }
|
||||
then result:=$C1
|
||||
else if nwBindry.result=$F1 { invalid bindery security }
|
||||
then result:=$C0
|
||||
else result:=nwBindry.result;
|
||||
{ resultcodes: 00 success; C0 No Account Privileges; C1 No Account Balance;
|
||||
96 Server Out Of memory; FC No Such Object; FE Server Bindery Locked;
|
||||
FF Bindery Failure}
|
||||
end;
|
||||
|
||||
|
||||
{F217/96 [2.15c+]}
|
||||
Function GetAccountStatus(objName:string; objType:word;
|
||||
Var balance,limit,holds:LongInt):boolean;
|
||||
{ equivalent to reading the ACCOUNT_BALANCE and ACCOUNT_HOLDS properties
|
||||
of the object. The properties may not exist. }
|
||||
{ This function will be successful if:
|
||||
a) the caller is an accounting server on the current fileserver
|
||||
OR b) the caller is supervisor-equivalent
|
||||
OR c) the caller is querying his own account status }
|
||||
Type Treq=record
|
||||
len:word;
|
||||
subF:byte;
|
||||
_objType:word; {hi-lo}
|
||||
_objName:string[48];
|
||||
end;
|
||||
Trep=record
|
||||
_balance: LongInt; {hi-lo}
|
||||
_limit : Longint; {hi-lo}
|
||||
reserved: array [1..120] of byte;
|
||||
_holds : array [1..16]
|
||||
of record
|
||||
serverObjId:LongInt; {hi-lo}
|
||||
HoldAmount :LongInt {hi-lo}
|
||||
end;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
Var t:byte;
|
||||
begin
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
len:=sizeOf(Treq)-2;
|
||||
subf:=$96;
|
||||
_objType:=swap(objType); { force hi-lo}
|
||||
PstrCopy(_objName,objName,48); UpString(_objName);
|
||||
end;
|
||||
F2SystemCall($17,sizeOf(Treq),sizeOf(Trep),result);
|
||||
With TPrep(GlobalReplyBuf)^
|
||||
do begin
|
||||
balance:=Lswap(_balance); { force lo-hi again }
|
||||
limit:=Lswap(_limit); { force lo-hi again }
|
||||
holds:=0;
|
||||
for t:=1 to 16
|
||||
do if _holds[t].serverObjId<>0
|
||||
then holds:=holds+Lswap(_holds[t].holdAmount); { force lo-hi again }
|
||||
end;
|
||||
IF result=$C0 { no account privileges }
|
||||
then GetBindryAccountStatus(objName,objType,balance,limit,holds);
|
||||
{ try to read status not as an accounting server, but as a supervisor }
|
||||
GetAccountStatus:=(result=0);
|
||||
{ resultcodes: 00 success; C0 No Account Privileges; C1 No Account Balance }
|
||||
end;
|
||||
|
||||
|
||||
{F217/97 [2.15c+]}
|
||||
Function SubmitAccountCharge(objName:string; objType:word;
|
||||
charge,cancelHoldAmount:Longint;
|
||||
serviceType, commentType:word; comment:string):boolean;
|
||||
{ -The cancelHold amount should be exactly the same as the amount that
|
||||
was put on huld with the SubmitAccountHold call. If no
|
||||
SubmitAccountHold call was made, the cancelHoldAmount should be set to zero.
|
||||
-'negative charges' are allowed. They will increase the balance of
|
||||
the object objName of objType.
|
||||
-Use the objectType of caller for the serviceType parameter.
|
||||
(audit log purposes)
|
||||
-Set commentType to 0 and comment to '' if you aren't interested in the
|
||||
audit log.
|
||||
-To be called by accounting servers only.
|
||||
-Can be imitated by supervisor-equivalent users by
|
||||
calling GetAccountStatus and SetAccountStatus. Atomicity
|
||||
of such a bindery transcation can not be guaranteed.
|
||||
|
||||
}
|
||||
Type Treq=record
|
||||
len :word;
|
||||
subf:byte;
|
||||
_serviceType:word; {hi-lo}
|
||||
_charge :Longint; {hi-lo}
|
||||
_cancelHold :Longint; {hi-lo}
|
||||
_objType :word; {hi-lo}
|
||||
_commentType:word; {hi-lo}
|
||||
_objNameAndComment:Array[1..305] of char;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
Var p:byte;
|
||||
begin
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
subf:=$97;
|
||||
_serviceType:= swap(serviceType); {force hi-lo}
|
||||
_charge :=Lswap(charge); {force hi-lo}
|
||||
_cancelHold :=Lswap(cancelHoldAmount); {force hi-lo}
|
||||
_objType := swap(objType); {force hi-lo}
|
||||
_commentType:= swap(commentType); {force hi-lo}
|
||||
p:=ord(objName[0]);if p>48 then p:=48;
|
||||
UpString(objName);
|
||||
Move(objname[0],_objNameandComment[1],p+1);
|
||||
Move(comment[0],_objNameandComment[p+2],ord(comment[0])+1);
|
||||
len:=15+p+1+ord(comment[0])+1;
|
||||
F2SystemCall($17,len+2,0,result);
|
||||
end;
|
||||
SubmitAccountCharge:=(result=$00);
|
||||
{ resultcodes: 00 successful; C0 No Account Privileges;
|
||||
C1 No Account Balance; C2 Credit Limit Exceeded. }
|
||||
end;
|
||||
|
||||
|
||||
{F217/98 [2.15c+]}
|
||||
Function SubmitAccountHold(objName:string; objType:word;
|
||||
reserveAmount:Longint ):boolean;
|
||||
{ To be called by accounting servers only. }
|
||||
Type Treq=record
|
||||
len :word;
|
||||
subf:byte;
|
||||
_reserveAmount:Longint; {hi-lo}
|
||||
_objType:word; {hi-lo}
|
||||
_objName:string[48];
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
Var p:byte;
|
||||
begin
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
subf:=$98;
|
||||
_reserveAmount:=Lswap(ReserveAmount); { force hi-lo}
|
||||
_objType:=swap(objType); { force hi-lo }
|
||||
p:=ord(objName[0]); if p>48 then p:=48;
|
||||
_objName:=objname;UpString(_objName);_objName[0]:=chr(p);
|
||||
len:=7+p+1;
|
||||
F2SystemCall($17,len+2,0,result);
|
||||
end;
|
||||
SubmitAccountHold:=(result=$00);
|
||||
{ resultcodes: 00 successful; C0 No Account Privileges;
|
||||
C1 No Account Balance; C2 Credit Limit Exceeded.
|
||||
C3 Account Too Many Holds }
|
||||
end;
|
||||
|
||||
{F217/99 [2.15c+]}
|
||||
Function SubmitAccountNote(objName:string; objType:word;
|
||||
serviceType,commentType:word; comment:string):boolean;
|
||||
{ To be called by accounting servers only.}
|
||||
Type Treq=record
|
||||
len:word;
|
||||
subf:byte;
|
||||
_serviceType:word; {hi-lo}
|
||||
_objType:word; {hi-lo}
|
||||
_commentType:word; {hi-lo}
|
||||
_objNameAndComment:array[1..305] of char;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
Var p:byte;
|
||||
begin
|
||||
with TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
subf:=$99;
|
||||
_serviceType:= swap(serviceType); {force hi-lo}
|
||||
_objType := swap(objType); {force hi-lo}
|
||||
_commentType:= swap(commentType); {force hi-lo}
|
||||
p:=ord(objName[0]);if p>48 then p:=48;
|
||||
UpString(objName);
|
||||
Move(objname[0],_objNameandComment[1],p+1);
|
||||
Move(comment[0],_objNameandComment[p+2],ord(comment[0])+1);
|
||||
len:=7+p+1+ord(comment[0])+1;
|
||||
F2SystemCall($17,len+2,0,result);
|
||||
end;
|
||||
SubmitAccountNote:=(result=0);
|
||||
{resultcodes: 00 Successful; C0 No Account Privileges }
|
||||
end;
|
||||
|
||||
{---------------- Secondary Functions--------------------------------------}
|
||||
|
||||
|
||||
Function AccountingInstalled:boolean;
|
||||
Var propVal:Tproperty;
|
||||
connId:byte;
|
||||
moreSegments:boolean;
|
||||
propFlags:byte;
|
||||
currServerName:string;
|
||||
begin
|
||||
IF NOT GetEffectiveConnectionID(ConnId)
|
||||
then result:=nwConn.result
|
||||
else if NOT GetFileServerName(ConnId,currServerName)
|
||||
then result:=nwConn.result
|
||||
else begin
|
||||
ReadPropertyValue(currServerName,OT_FILE_SERVER,'ACCOUNT_SERVERS',1,
|
||||
propVal,moreSegments,propFlags);
|
||||
result:=nwBindry.result;
|
||||
end;
|
||||
AccountingInstalled:=(result=0);
|
||||
end;
|
||||
|
||||
|
||||
Function SetAccountStatus(objName:string; objType:word; balance,limit:LongInt):boolean;
|
||||
{ will change the account status to reflect the given parameters.
|
||||
any holds will not be changed.
|
||||
You need to be supervisor-eq. to do this...}
|
||||
Var accPropVal:Tproperty;
|
||||
accVal: record
|
||||
_balance:LongInt; {hi-lo}
|
||||
_limit:LongInt; {hi-lo}
|
||||
_Reserved:array[1..120] of byte; { NW internal info }
|
||||
end ABSOLUTE accPropVal;
|
||||
OldBalance,OldLimit,OldHolds:LongInt;
|
||||
moreSegments:boolean;
|
||||
propFlags:byte;
|
||||
begin
|
||||
IF ReadPropertyValue(objName,objType,'ACCOUNT_BALANCE',1,
|
||||
accPropVal,moreSegments,propFlags)
|
||||
then begin
|
||||
accVal._balance:=Lswap(balance); { force hi-lo}
|
||||
accVal._limit:=Lswap(limit); { force hi-lo}
|
||||
WritePropertyValue(objName,objType,'ACCOUNT_BALANCE',
|
||||
1,accPropVal,FALSE);
|
||||
if (nwBindry.result=$F1) or (nwBindry.result=$F8)
|
||||
then result:=$C0
|
||||
else result:=nwBindry.result;
|
||||
end
|
||||
else if nwBindry.result=$FB { no such property }
|
||||
then result:=$C1
|
||||
else if nwBindry.result=$F1 { invalid bindery security }
|
||||
then result:=$C0
|
||||
else result:=nwBindry.result;
|
||||
SetAccountStatus:=(result=$00);
|
||||
{ resultcodes: 00 success; C0 No Account Privileges; C1 No Account Balance;
|
||||
96 Server Out Of memory; FC No Such Object; FE Server Bindery Locked;
|
||||
FF Bindery Failure}
|
||||
end;
|
||||
|
||||
|
||||
Function AddAccountingServer(objName:string;objType:word):boolean;
|
||||
Var ConnId:byte;
|
||||
currServerName:string;
|
||||
begin
|
||||
IF NOT GetEffectiveConnectionID(ConnId)
|
||||
then result:=nwConn.result
|
||||
else if NOT GetFileServerName(ConnId,currServerName)
|
||||
then result:=nwConn.result
|
||||
else begin
|
||||
AddBinderyObjectToSet(currServerName,OT_FILE_SERVER,'ACCOUNT_SERVERS',
|
||||
objName,objType);
|
||||
result:=nwBindry.result;
|
||||
end;
|
||||
AddAccountingServer:=(result=0);
|
||||
end;
|
||||
|
||||
Function DeleteAccountingServer(objName:string;objType:word):boolean;
|
||||
Var ConnId:byte;
|
||||
currServerName:string;
|
||||
begin
|
||||
IF NOT GetEffectiveConnectionID(ConnId)
|
||||
then result:=nwConn.result
|
||||
else if NOT GetFileServerName(ConnId,currServerName)
|
||||
then result:=nwConn.result
|
||||
else begin
|
||||
DeleteBinderyObjectFromSet(currServerName,OT_FILE_SERVER,'ACCOUNT_SERVERS',
|
||||
objName,objType);
|
||||
result:=nwBindry.result;
|
||||
end;
|
||||
DeleteAccountingServer:=(result=0);
|
||||
end;
|
||||
|
||||
{F217/96 }
|
||||
Function DeleteAccountHolds(objName:string; objType:word):boolean;
|
||||
{ delete all holds the caller (an accounting server) has on the
|
||||
object with name objName of type objType. }
|
||||
Type Treq=record
|
||||
len:word;
|
||||
subF:byte;
|
||||
_objType:word; {hi-lo}
|
||||
_objName:string[48];
|
||||
end;
|
||||
Trep=record
|
||||
_balance: LongInt; {hi-lo}
|
||||
_limit : Longint; {hi-lo}
|
||||
reserved: array [1..120] of byte;
|
||||
_holds : array [1..16]
|
||||
of record
|
||||
serverObjId:LongInt; {hi-lo}
|
||||
HoldAmount :LongInt {hi-lo}
|
||||
end;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
Var t:byte;
|
||||
holds:LongInt;
|
||||
level:byte;
|
||||
accServerId:LongInt;
|
||||
accServerType:word;
|
||||
accServerName:string;
|
||||
begin
|
||||
GetBinderyAccessLevel(Level,accServerID);
|
||||
GetBinderyObjectName(accServerID,accServerName,accServerType);
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
len:=sizeOf(Treq)-2;
|
||||
subf:=$96;
|
||||
_objType:=swap(objType); { force hi-lo}
|
||||
PstrCopy(_objName,objName,48); UpString(_objName);
|
||||
end;
|
||||
F2SystemCall($17,sizeOf(Treq),sizeOf(Trep),result);
|
||||
if result=0
|
||||
then With TPrep(GlobalReplyBuf)^
|
||||
do begin
|
||||
holds:=0;
|
||||
for t:=1 to 16
|
||||
do if accServerID=Lswap(_holds[t].serverObjId)
|
||||
then holds:=holds+Lswap(_holds[t].holdAmount); { force lo-hi again }
|
||||
if holds<>0
|
||||
then SubmitAccountCharge(objName,objType,0,holds,
|
||||
accServerType,0,'clearing holds');
|
||||
end;
|
||||
DeleteAccountHolds:=(result=0);
|
||||
{ resultcodes: 00 success; C0 No Account Privileges; C1 No Account Balance }
|
||||
end;
|
||||
|
||||
|
||||
Function GetConnectTimeCharge(Var currentCharge:Real;Var chargeRec:TchargeRec):boolean;
|
||||
Var propVal:Tproperty;
|
||||
_chargeRec:TchargeRec ABSOLUTE propVal;
|
||||
_currcharge:record
|
||||
fill:LongInt;
|
||||
currMult,currDiv:word; {hi-lo}
|
||||
end ABSOLUTE propVal;
|
||||
connId:byte;
|
||||
moreSegments:boolean;
|
||||
propFlags:byte;
|
||||
currServerName:string;
|
||||
begin
|
||||
IF NOT GetEffectiveConnectionID(ConnId)
|
||||
then result:=nwConn.result
|
||||
else if NOT GetFileServerName(ConnId,currServerName)
|
||||
then result:=nwConn.result
|
||||
else if ReadPropertyValue(currServerName,OT_FILE_SERVER,
|
||||
'CONNECT_TIME',1,
|
||||
propVal,moreSegments,propFlags)
|
||||
then begin
|
||||
IF _currCharge.currDiv=0
|
||||
then currentCharge:=0
|
||||
else currentCharge:=Swap(_currCharge.currMult)/Swap(_currCharge.currDiv);
|
||||
move(propVal[9],propVal[5],124);
|
||||
chargeRec:=_chargeRec;
|
||||
result:=0;
|
||||
end
|
||||
else result:=nwBindry.result;
|
||||
GetConnectTimeCharge:=(result=0);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
end.
|
||||
1442
NWTP/NWBINDRY.PAS
Normal file
1442
NWTP/NWBINDRY.PAS
Normal file
File diff suppressed because it is too large
Load Diff
1455
NWTP/NWCONN.PAS
Normal file
1455
NWTP/NWCONN.PAS
Normal file
File diff suppressed because it is too large
Load Diff
2999
NWTP/NWFILE.PAS
Normal file
2999
NWTP/NWFILE.PAS
Normal file
File diff suppressed because it is too large
Load Diff
761
NWTP/NWINTR.PAS
Normal file
761
NWTP/NWINTR.PAS
Normal file
@@ -0,0 +1,761 @@
|
||||
UNIT NWintr;
|
||||
|
||||
{ DPMI Protected mode calls: Hubert Plattfaut of 2:2447/203.4
|
||||
Windows Protected Mode calls:
|
||||
-Based on EZDPMI by Julian M. Bucknall [1993: 100116.1572@Compuserve.Com]
|
||||
-Based on the NetCalls and WinDPMI units by Siebrand Dijkstra [1995: 2:512/250.595]
|
||||
-Corrections by Berend de Boer [1995: berend@beard.nest.nl or 2:281/527.23]
|
||||
|
||||
NwTP Version 0.6, 950301, Copyright 1993,1995 R. Spronk
|
||||
}
|
||||
|
||||
INTERFACE
|
||||
|
||||
{$B-,F+,O-,R-,S-,X+}
|
||||
|
||||
{$DEFINE ProtMode}
|
||||
{$IFDEF MSDOS}
|
||||
{$DEFINE RealMode}
|
||||
{$UNDEF ProtMode}
|
||||
{$ENDIF}
|
||||
|
||||
uses
|
||||
{$IFDEF RealMode} Dos
|
||||
{$ENDIF}
|
||||
{$IFDEF DPMI} Dos,WinApi { we need the GlobalDosAlloc-Function}
|
||||
{$ENDIF}
|
||||
{$IFDEF WINDOWS} WinTypes,WinDOS,WinProcs
|
||||
{$ENDIF};
|
||||
|
||||
CONST VLM_ID_UNKNOWN = $0000; { non-VLM application }
|
||||
VLM_ID_VLM = $0001;
|
||||
VLM_ID_CONN = $0010;
|
||||
VLM_ID_TRAN = $0020;
|
||||
VLM_ID_IPX = $0021;
|
||||
VLM_ID_TCP = $0022;
|
||||
VLM_ID_NWP = $0030;
|
||||
VLM_ID_BIND = $0031;
|
||||
VLM_ID_NDS = $0032;
|
||||
VLM_ID_PNW = $0033;
|
||||
VLM_ID_RSA = $0034;
|
||||
VLM_ID_REDIR = $0040;
|
||||
VLM_ID_FIO = $0041;
|
||||
VLM_ID_PRINT = $0042;
|
||||
VLM_ID_GENR = $0043;
|
||||
VLM_ID_NETX = $0050;
|
||||
VLM_ID_AUTO = $0060;
|
||||
VLM_ID_SECURITY = $0061;
|
||||
VLM_ID_NMR = $0100;
|
||||
VLM_ID_DRVPRN = $09F2;
|
||||
VLM_ID_SAA = $09F5; { SAA Client API for NetWare }
|
||||
VLM_ID_IPXMIB = $09F6;
|
||||
VLM_ID_PNWMIB = $09F7;
|
||||
VLM_ID_PNTRAP = $09F8;
|
||||
VLM_ID_MIB2PROT = $09F9;
|
||||
VLM_ID_MIB2IF = $09FA;
|
||||
VLM_ID_NVT = $09FB;
|
||||
VLM_ID_TRAP = $09FC;
|
||||
VLM_ID_REG = $09FD;
|
||||
VLM_ID_ASN1 = $09FE;
|
||||
VLM_ID_SNMP = $09FF;
|
||||
|
||||
Type
|
||||
{$ifdef ProtMode}
|
||||
|
||||
TTregisters= Record {This is the data-structure for the}
|
||||
Case Byte Of {real-mode-interrupts in DPMI-mode}
|
||||
0: {32 bit registers}
|
||||
(EDI,ESI,EBP,Reserved,EBX,EDX,
|
||||
ECX,EAX:LongInt);
|
||||
1: {16 bit registers}
|
||||
(DI,DIHigh,SI,SIHigh,
|
||||
BP,BPHigh,ReservedLow,ReservedHigh,
|
||||
BX,BXHigh,DX,DXHigh,
|
||||
CX,CXHigh,AX,AXHigh,
|
||||
Flags,ES,DS,FS,GS,IP,
|
||||
CS,SP,SS:Word);
|
||||
2: {8 bit registers}
|
||||
(DILowLow,DILowHigh,DIHighLow,DIHighHigh,
|
||||
SILowLow,SILowHigh,SIHighLow,SIHighHigh,
|
||||
BPLowLow,BPLowHigh,BPHighLow,BPHighHigh,
|
||||
ReservedLowLow,ReservedLowHigh,ReservedHighLow,ReservedHighHigh,
|
||||
BL,BH,BXHighLow,BXHighHigh,
|
||||
DL,DH,DXHighLow,DXHighHigh,
|
||||
CL,CH,CXHighLow,CXHighHigh,
|
||||
AL,AH,AXHighLow,AXHighHigh:Byte)
|
||||
End;
|
||||
|
||||
{$else} {RealMode}
|
||||
|
||||
TTregisters= Record
|
||||
case Integer of
|
||||
0: (AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags: Word);
|
||||
1: (AL, AH, BL, BH, CL, CH, DL, DH: Byte);
|
||||
end;
|
||||
{$endif}
|
||||
|
||||
TPtrRec=record Ofs,Seg:word end;
|
||||
|
||||
TintrBuffer=array[1..576] of byte;
|
||||
TPintrBuffer=^TintrBuffer;
|
||||
|
||||
TVLMheader=record
|
||||
unknown1 :array[1..4] of byte;
|
||||
ptr1ofs,ptr1seg, { pointers to 'procedures' }
|
||||
ptr2ofs,ptr2seg,
|
||||
ptr3ofs,ptr3seg,
|
||||
ptr4ofs,ptr4seg :word;
|
||||
unknown2 :array[1..4] of byte; { 00 00 00 00 }
|
||||
HeaderLen :byte; { 1.11-> 4E; 1.20-> 4E}
|
||||
MultiplexIDstring :array[1..3] of char; { 56 4C 4D 'VLM' }
|
||||
unknown3 :array[1..4] of byte; { 01 00 80 00 }
|
||||
|
||||
TransientSwitchCount :word;
|
||||
CallCount :word;
|
||||
ControlBlockOfs :word; { in same segment as this header }
|
||||
CurrentVLMID :word;
|
||||
MemoryType :byte; { 04 = XMS }
|
||||
ModulesLoaded :byte;
|
||||
BlockId :word;
|
||||
TransientBlock :word;
|
||||
GlobalSegment :word;
|
||||
AsyncQueue :array[1..3] of record { head, tail, s }
|
||||
pqofs,pqseg:word;
|
||||
end;
|
||||
BusyQueue :array[1..3] of record { head, tail, s }
|
||||
pqofs,pqseg:word;
|
||||
end;
|
||||
ReEntranceLevel :word;
|
||||
FullMapCount :word;
|
||||
unknown5 :word; { 00 00 }
|
||||
end;
|
||||
|
||||
TVLMcontrolBlockEntry=record
|
||||
Flag :word;
|
||||
ID :word;
|
||||
Func :word;
|
||||
Maps :word;
|
||||
TimesCalled :word;
|
||||
unknown1 :word; { SSeg ? }
|
||||
TransientSeg,GlobalSeg :word;
|
||||
AddressLow,AddressHi :word;
|
||||
TsegSize,GSegSize,SSegSize:word; { in 16 byte paragraphs }
|
||||
VLMname :array[1..9] of char;
|
||||
{ null terminated string }
|
||||
end;
|
||||
|
||||
Var GlobalReqBuf,GlobalReplyBuf:TPintrBuffer;
|
||||
|
||||
{ real-mode only, DPMI: all flags are set to false }
|
||||
VLM_EXE_loaded :Boolean;
|
||||
NETX_VLM_loaded:Boolean; { if true, then VLM_EXE_loaded must also be true. }
|
||||
NETX_EXE_loaded:Boolean;
|
||||
|
||||
Function RealModeIntr(intNo:byte;Var regs:TTregisters):boolean;
|
||||
Procedure F2SystemCall(subf:byte;req_size,rep_size:word;Var result:word);
|
||||
Procedure nwMsDos(VAR R:ttregisters);
|
||||
Function InRealMode:Boolean;
|
||||
|
||||
Function MapRealmodeSegment(RSeg:Word):Word;
|
||||
Function nwPtr(s,o:word):Pointer;
|
||||
Procedure GetGlobalBufferAddress(VAR Sreq,Oreq,Srep,Orep:Word);
|
||||
|
||||
{$IFDEF RealMode}
|
||||
Function GetVLMheader(Var VLMheader:TVLMheader):Boolean;
|
||||
Function GetVLMControlBlock(Entry:Byte;
|
||||
Var ControlBlock:TVLMControlBlockEntry):Boolean;
|
||||
{ entry: 0 .. VLMheader.ModulesLoaded }
|
||||
{$ENDIF}
|
||||
|
||||
IMPLEMENTATION {===========================================================}
|
||||
|
||||
Var GlobalRegisters:TTregisters; { all Modes ! }
|
||||
|
||||
VLMCall:Procedure;
|
||||
|
||||
{$IFDEF RealMode}
|
||||
|
||||
Var VLMtransientSeg:word;
|
||||
|
||||
{ ---------- Real mode procedures ------------------------------------}
|
||||
|
||||
{$F+}
|
||||
|
||||
Var RequesterProc:Procedure(Var regs:Registers);
|
||||
{ VLMCall:Procedure; }
|
||||
|
||||
Procedure VlmSystemCall(Var regs:registers); assembler;
|
||||
asm
|
||||
push ds
|
||||
|
||||
{ check if VLMCall known. If not, return error $FF in fake AL }
|
||||
xor ah,ah
|
||||
mov al,$FF
|
||||
les di,VLMCall
|
||||
mov bx,es
|
||||
cmp bx,$0000
|
||||
je @1
|
||||
{ move fake regs registers to 'real' registers }
|
||||
{ AX, CX, DX, DS, SI, DI, ES only. }
|
||||
les di,regs
|
||||
mov ax,es:[di+16]
|
||||
push ax { push new es }
|
||||
mov ax,es:[di+12]
|
||||
push ax { push new di }
|
||||
mov ds,es:[di+14]
|
||||
mov ax,es:[di]
|
||||
mov cx,es:[di+4]
|
||||
mov dx,es:[di+6]
|
||||
mov si,es:[di+10]
|
||||
pop di
|
||||
pop es
|
||||
{ farr call to VLM handler }
|
||||
push bp
|
||||
CALL VLMCall
|
||||
pop bp
|
||||
@1: { move 'real' registers to fake regs registers }
|
||||
|
||||
{push es
|
||||
push di}
|
||||
les di,regs
|
||||
mov es:[di],ax
|
||||
{mov es:[di+4],cx
|
||||
mov es:[di+6],dx
|
||||
mov es:[di+10],si
|
||||
pop ax ax:= 'di'
|
||||
mov es:[di+12],ax
|
||||
pop ax ax:= 'es'
|
||||
mov es:[di+16],ax }
|
||||
|
||||
pop ds
|
||||
end;
|
||||
|
||||
Procedure VLMcheck;
|
||||
CONST DOS_MULTIPLEX =$2F;
|
||||
Var regs:registers;
|
||||
ccode:byte;
|
||||
Function getBinderyAccessLevel:boolean; { to be replaced by a non-bindery call }
|
||||
Type Treq=record
|
||||
len :word;
|
||||
subF :byte;
|
||||
end;
|
||||
Trep=record
|
||||
accLeveL:byte;
|
||||
_objId:longInt;
|
||||
fill:array[1..20] of byte;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
Var result:word;
|
||||
BEGIN
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
subF:=$46;
|
||||
len:=sizeOf(Treq)-2;
|
||||
end;
|
||||
F2SystemCall($17,sizeOf(Treq),sizeOf(Trep),result);
|
||||
GetBinderyAccessLevel:=(result=0);
|
||||
end;
|
||||
|
||||
Var phdr:^TVLMHeader;
|
||||
pVLMcbl:^TVLMcontrolBlockEntry;
|
||||
t:word;
|
||||
|
||||
begin
|
||||
VLM_EXE_Loaded:=false;
|
||||
Regs.AX:=$7A20;
|
||||
Regs.BX:=$0000;
|
||||
Regs.CX:=$0000;
|
||||
Intr($2F,Regs);
|
||||
if regs.AX=$0000
|
||||
then begin
|
||||
{ OK. AX=0000. All seems well. But is it really the 2F VLM handler? }
|
||||
phdr:=ptr(regs.es,$0000);
|
||||
VLM_EXE_Loaded:=(phdr^.MultiplexIdString[1]='V')
|
||||
and (phdr^.MultiplexIdString[2]='L')
|
||||
and (phdr^.MultiplexIdString[3]='M');
|
||||
|
||||
IF VLM_EXE_Loaded
|
||||
then begin
|
||||
NETX_EXE_loaded:=False;
|
||||
|
||||
{ Determine whether netx.vlm is loaded }
|
||||
NETX_VLM_Loaded:=False;
|
||||
t:=0;
|
||||
While t<phdr^.ModulesLoaded
|
||||
do begin
|
||||
pVLMcbl:=ptr(regs.es,phdr^.ControlBlockOfs+(t*SizeOf(TVLMControlBlockEntry)));
|
||||
IF pVLMcbl^.ID=VLM_ID_NETX
|
||||
then begin
|
||||
t:=$0100; { end of iteration }
|
||||
NETX_VLM_Loaded:=True;
|
||||
end;
|
||||
inc(t);
|
||||
end;
|
||||
|
||||
{ Set requester proc to VLM entry point }
|
||||
@VLMcall:=Ptr(Regs.es,Regs.bx);
|
||||
VLMtransientSeg:=regs.es;
|
||||
|
||||
{ @requesterProc:=@VLMsystemCall; ---------- ERR ------}
|
||||
@RequesterProc:=@dos.msdos;
|
||||
|
||||
end
|
||||
end;
|
||||
if NOT VLM_EXE_Loaded
|
||||
then begin
|
||||
NETX_VLM_loaded:=false;
|
||||
@RequesterProc:=@dos.msdos;
|
||||
NETX_EXE_loaded:=GetBinderyAccessLevel;
|
||||
end;
|
||||
end;
|
||||
|
||||
Function RealModeIntr(intNo:byte;Var regs:TTregisters):boolean;
|
||||
begin
|
||||
Intr(intNo,registers(regs));
|
||||
RealModeIntr:=true;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
Procedure nwMsDos(VAR R:ttregisters);
|
||||
begin
|
||||
msDos(registers(R));
|
||||
end;
|
||||
|
||||
|
||||
Procedure F2SystemCall(subf:byte;req_size,rep_size:word;Var result:word);
|
||||
begin
|
||||
With GlobalRegisters
|
||||
do begin
|
||||
CX := Req_size;
|
||||
DX := rep_size;
|
||||
AH := $f2;
|
||||
AL := subf;
|
||||
DS := Seg(GlobalReqBuf^); SI := Ofs(GlobalReqBuf^);
|
||||
ES := Seg(GlobalReplyBuf^);DI := Ofs(GlobalReplyBuf^);
|
||||
MSDOS(registers(GlobalRegisters));
|
||||
Result:=al;
|
||||
end;
|
||||
end;
|
||||
|
||||
Procedure GetGlobalBufferAddress(VAR Sreq,Oreq,Srep,Orep:Word);
|
||||
begin
|
||||
Sreq := Seg(GlobalReqBuf^);
|
||||
Oreq := Ofs(GlobalReqBuf^);
|
||||
Srep := Seg(GlobalReplyBuf^);
|
||||
Orep := Ofs(GlobalReplyBuf^);
|
||||
end;
|
||||
|
||||
|
||||
Function GetVLMheader(Var VLMheader:TVLMheader):Boolean;
|
||||
Var p:^TVLMHeader;
|
||||
begin
|
||||
if VLMtransientSeg<>$0000
|
||||
then begin
|
||||
p:=ptr(VLMtransientSeg,$0000);
|
||||
move(p^,VLMheader,SizeOf(TVLMHeader));
|
||||
end;
|
||||
GetVLMHeader:=(VLMtransientSeg<>$0000);
|
||||
end;
|
||||
|
||||
Function GetVLMControlBlock(Entry:Byte;
|
||||
Var ControlBlock:TVLMControlBlockEntry):Boolean;
|
||||
{ entry: 0 .. VLMheader.ModulesLoaded }
|
||||
Var ph:^TVLMHeader;
|
||||
pcb:^TVLMControlBlockEntry;
|
||||
begin
|
||||
if VLMtransientSeg<>$0000
|
||||
then begin
|
||||
ph:=ptr(VLMtransientSeg,$0000);
|
||||
pcb:=ptr(VLMtransientSeg,ph^.ControlBlockOfs+entry*SizeOf(TVLMControlBlockEntry));
|
||||
move(pcb^,ControlBlock,SizeOf(TVLMControlBlockEntry));
|
||||
end;
|
||||
GetVLMControlBlock:=(VLMtransientSeg<>$0000);
|
||||
end;
|
||||
|
||||
Function nwPtr(s,o:word):Pointer;
|
||||
begin
|
||||
nwPtr:=Ptr(s,o);
|
||||
end;
|
||||
|
||||
Function MapRealmodeSegment(RSeg:Word):Word;
|
||||
begin
|
||||
MapRealmodeSegment:=RSeg;
|
||||
end;
|
||||
|
||||
{$ENDIF} {------------- end of real-mode procedures -------------------}
|
||||
|
||||
{$IFDEF ProtMode}
|
||||
|
||||
Type pRealSegItem=^tRealSegItem;
|
||||
tRealSegItem=record {structure to store information}
|
||||
Seg:word; {about allocated selectors}
|
||||
Sel:Word;
|
||||
prev,next:pRealSegItem;
|
||||
end;
|
||||
{we need to allocate selectors which map real-mode segments.}
|
||||
{all these selectors are stored in an dynamic list}
|
||||
{and are cleand up them at then end of the program}
|
||||
|
||||
Var GlobalRealReqSeg,
|
||||
GlobalRealReplySeg:Word;
|
||||
SelectorList:pRealSegItem;
|
||||
|
||||
Function RealModeIntr (IntNo:Byte;VAR Regs:ttregisters):Boolean;Assembler;
|
||||
{Simulate a call to the spectified real mode interrupt. The registers passed
|
||||
to the real mode code are held in RealModeRegisters. This structure contains
|
||||
the register content upon termination of the real mode ISR.
|
||||
Returns False if there was an error.}
|
||||
|
||||
ASM
|
||||
push di
|
||||
push es
|
||||
|
||||
mov bh,00 {For DOSX to reset the int controller and A20 line. Windows ingores it.}
|
||||
mov bl,IntNo {Tell DPMI which interrupt to simulate}
|
||||
xor cx,cx {0 bytes to copy to real mode stack}
|
||||
les di,Regs {Get the real mode structure}
|
||||
mov word ptr es:[di+$c],0 {reserved to 0}
|
||||
mov word ptr es:[di+$c+2],0
|
||||
mov word ptr es:[di+$26],0 {fs to 0}
|
||||
mov word ptr es:[di+$28],0 {gs to 0}
|
||||
mov word ptr es:[di+$2e],0 {sp to 0}
|
||||
mov word ptr es:[di+$30],0 {ss to 0}
|
||||
|
||||
mov ax,$0300 {Function 0300h is simulate real mode interrupt}
|
||||
int 31h
|
||||
|
||||
jc @Error {The carry flag was set, so there was an error}
|
||||
mov ax,True {Return no error}
|
||||
jmp @AllDone
|
||||
|
||||
@Error:
|
||||
mov ax,False {Return false indicating an error}
|
||||
|
||||
@AllDone:
|
||||
pop es
|
||||
pop di
|
||||
End;
|
||||
|
||||
Procedure F2SystemCall(subf:byte;req_size,rep_size:word;Var result:word);
|
||||
begin
|
||||
With GlobalRegisters
|
||||
do begin
|
||||
CX := Req_size;
|
||||
DX := rep_size;
|
||||
AH := $f2;
|
||||
AL := subf;
|
||||
DS := GlobalRealReqSeg; {Use then REAL-MODE segments}
|
||||
ES := GlobalRealReplySeg; {of the global buffers}
|
||||
DI := 0; {OFFSET always 0 for}
|
||||
SI := 0; {'GlobalDosAlloc'ated memory}
|
||||
if not RealModeIntr($21,GlobalRegisters)
|
||||
then RUNERROR(217);
|
||||
{DPMI-ERRORS, maybe we should stop the system with the new Errorcode 217}
|
||||
Result:=al;
|
||||
end;
|
||||
end;
|
||||
|
||||
Procedure nwMsDos(VAR R:ttregisters);
|
||||
begin
|
||||
if not RealModeIntr($21,R)
|
||||
then RUNERROR(217);
|
||||
{DPMI-ERRORS, maybe we should stop then system with the new Errorcode 217}
|
||||
end;
|
||||
|
||||
Procedure GetGlobalBufferAddress(VAR Sreq,Oreq,Srep,Orep:Word);
|
||||
begin
|
||||
Sreq := GlobalRealReqSeg; {Use the REAL-MODE segments}
|
||||
Srep := GlobalRealReplySeg; {of the global buffers}
|
||||
Oreq := 0; {OFFSET always 0 for}
|
||||
Orep := 0; {'GlobalDosAlloc'ated memory}
|
||||
end;
|
||||
|
||||
{----- Some low-level functions for DPMI -----------}
|
||||
TYPE os = record
|
||||
o, s : Word;
|
||||
end; {for typecasts}
|
||||
LDTStr = record {Structure of LDT-Elements}
|
||||
limit : Word;
|
||||
base : Word;
|
||||
data : Array[0..1] of Word;
|
||||
end;
|
||||
|
||||
Procedure Halt218; {runError 218: low-level DPMI-Errors}
|
||||
begin
|
||||
RunError(218);
|
||||
end;
|
||||
|
||||
{DMPI-Function 0: Allocate LDT Descriptor}
|
||||
function AllocLDTD(var NEWD : Word) : Word; Assembler;
|
||||
asm
|
||||
xor ax,ax
|
||||
mov cx,1 {only 1 descriptor needed}
|
||||
int 31h {Call DPMI}
|
||||
jnc @@ok
|
||||
Call Halt218 {Error on carry}
|
||||
@@ok:
|
||||
les di,NEWD {save descriptor to VAR NEWD}
|
||||
mov es:[di],ax
|
||||
xor ax,ax
|
||||
end;
|
||||
|
||||
{DMPI-Function 1: Free LDT Descriptor}
|
||||
function FreeLDTD(D : Word) : Word; Assembler;
|
||||
asm
|
||||
mov ax,0001h
|
||||
mov bx,D
|
||||
int 31h
|
||||
jc @@Ex {carry: return Error in ax}
|
||||
xor ax,ax
|
||||
@@Ex:
|
||||
end;
|
||||
|
||||
{DMPI-Function 7: Set Segment Base Address}
|
||||
function SetSBA(S: Word; BA: LongInt) : Word; Assembler;
|
||||
asm
|
||||
mov ax,0007h
|
||||
mov bx,S
|
||||
mov cx,word ptr BA+2
|
||||
mov dx,word ptr BA
|
||||
int 31h
|
||||
jc @@Ex {carry: return Error in ax}
|
||||
xor ax,ax
|
||||
@@Ex:
|
||||
end;
|
||||
|
||||
{DMPI-Function 8: Set Segment Limit}
|
||||
function SetSL(S: Word; L: LongInt) : Word; Assembler;
|
||||
asm
|
||||
mov ax,0008h
|
||||
mov bx,S
|
||||
mov dx,word ptr L
|
||||
mov cx,word ptr L+2
|
||||
int 31h
|
||||
jc @@Ex {carry: return Error in ax}
|
||||
xor ax,ax
|
||||
@@Ex:
|
||||
end;
|
||||
|
||||
{DMPI-Function 9: Set Descriptor Access Rights}
|
||||
function SetDAS(S: Word; R: Word) : Word; Assembler;
|
||||
asm
|
||||
mov ax,0009h
|
||||
mov bx,S
|
||||
mov cx,R
|
||||
int 31h
|
||||
jc @@Ex {carry: return Error in ax}
|
||||
xor ax,ax
|
||||
@@Ex:
|
||||
end;
|
||||
|
||||
{DMPI-Function 11: Get Descriptor}
|
||||
function GetD(S: Word; var D : LDTStr) : Word; Assembler;
|
||||
asm
|
||||
mov ax,000Bh
|
||||
mov bx,S
|
||||
les di,D
|
||||
int 31h
|
||||
jc @@Ex {carry: return Error in ax}
|
||||
xor ax,ax
|
||||
@@Ex:
|
||||
end;
|
||||
|
||||
|
||||
{Set then Length of the Descriptor-Segment}
|
||||
function SetLimit(Sele: Word; L: LongInt) : Word;
|
||||
var St,R: Word;
|
||||
Des : LDTStr;
|
||||
begin
|
||||
St:= GetD(Sele, Des); {get the Descriptor-Entry from LDT}
|
||||
if St <> 0
|
||||
then begin
|
||||
SetLimit:= St; {not in LDT, return Error}
|
||||
Exit;
|
||||
end;
|
||||
with Des
|
||||
do R := (Data[0] shr 8) or ((Data[1] and $00F0) shl 8);
|
||||
{form then rights for the DPMI-9-Call, register cl}
|
||||
if L > $FFFFF
|
||||
then begin {> 1MB: Page aligned}
|
||||
if L and $FFF <> $FFF
|
||||
then begin {Limit=Length-1!}
|
||||
SetLimit := $8021; {return Error: not page aligned}
|
||||
Exit;
|
||||
end;
|
||||
R:= R or $8000; {set Page granularity}
|
||||
end
|
||||
else R:= R and $7FFF; {set Byte granularity}
|
||||
St := SetSL(Sele, 0); {fist set limit to 0}
|
||||
if St = 0 then St := SetDAS(Sele, R); {ok, set the new rights}
|
||||
if St = 0 then St:= SetSL(Sele, L); {ok, set then limit}
|
||||
SetLimit := St; {return errorcode}
|
||||
end;
|
||||
|
||||
|
||||
{get a Selector for a part of then real-mode memory}
|
||||
function RealMemSel(RealP : Pointer; Limit : LongInt; var Sele : Word) : Word;
|
||||
function NP(P : Pointer) : LongInt;
|
||||
VAR TC:OS absolute P;
|
||||
begin
|
||||
NP := (LongInt(TC.S) shl 4)+LongInt(TC.O);
|
||||
end;
|
||||
var St : Word;
|
||||
begin
|
||||
St := AllocLDTD(Sele); {get a new Selector}
|
||||
if St = 0
|
||||
then begin
|
||||
St := SetSBA(Sele, NP(RealP)); {set base addresse to the linear}
|
||||
if St = 0
|
||||
then begin {address of the Real-Segment}
|
||||
St := SetLimit(Sele, Limit); {set the selector-limit}
|
||||
if St <> 0
|
||||
then if FreeLDTD(Sele)<>0 then; {on error: free selector}
|
||||
end
|
||||
else if FreeLDTD(Sele)<>0 then; {on error: free selector}
|
||||
end;
|
||||
RealMemSel := St; {return errorcode}
|
||||
end;
|
||||
|
||||
{check if the required selector is already allocated}
|
||||
Function InSelectorList(S:Word):pRealSegItem;
|
||||
VAR li:pRealSegItem;
|
||||
begin
|
||||
li:=SelectorList;
|
||||
while li<>NIL
|
||||
do begin
|
||||
if li^.Seg=S
|
||||
then begin
|
||||
InSelectorList:=Li;
|
||||
exit;
|
||||
end;
|
||||
li:=li^.Next;
|
||||
end;
|
||||
InSelectorList:=NIL;
|
||||
end;
|
||||
|
||||
{insert a new SelectorItem at start of the list}
|
||||
Procedure AddToSelectorlist(Segment,Selector:Word);
|
||||
VAR li:pRealSegItem;
|
||||
begin
|
||||
new(li);
|
||||
with li^
|
||||
do begin
|
||||
Seg:=segment;
|
||||
Sel:=Selector;
|
||||
next:=Selectorlist;
|
||||
prev:=NIL;
|
||||
end;
|
||||
Selectorlist^.prev:=li;
|
||||
Selectorlist:=li;
|
||||
end;
|
||||
|
||||
{clean up}
|
||||
Procedure FreeSelectorList;
|
||||
VAR li:pRealSegItem;
|
||||
begin
|
||||
while Selectorlist<>NIL
|
||||
do begin
|
||||
li:=selectorlist;
|
||||
selectorlist:=li^.next;
|
||||
if li^.sel<>0
|
||||
then FreeLDTD(li^.Sel);
|
||||
dispose(li);
|
||||
end;
|
||||
end;
|
||||
|
||||
Function MapRealmodeSegment(RSeg:Word):Word;
|
||||
VAR sel:Word;
|
||||
li:pRealSegItem;
|
||||
begin
|
||||
li:=InSelectorList(RSeg);
|
||||
if li=NIL
|
||||
then begin
|
||||
if RealMemSel(Ptr(RSeg,0),$ffff,Sel)<>0
|
||||
then RUNERROR(217); {something's wrong: Errorcode 217}
|
||||
MapRealModeSegment:=Sel;
|
||||
AddToSelectorList(Rseg,Sel);
|
||||
end
|
||||
else MapRealModeSegment:=li^.Sel;
|
||||
end;
|
||||
|
||||
|
||||
Function nwPtr(s,o:word):Pointer;
|
||||
begin
|
||||
nwPtr:=Ptr(MapRealModeSegment(s),o);
|
||||
end;
|
||||
|
||||
|
||||
{$ENDIF} {----------------- end of protected mode procedures -------------}
|
||||
|
||||
Var OldExitProc:pointer;
|
||||
|
||||
Function InRealMode:Boolean;
|
||||
begin
|
||||
{$IFDEF Windows}
|
||||
InRealMode:=(GetWinFlags and wf_PMode)=0;
|
||||
{$ELSE}
|
||||
{$IFDEF ProtMode}
|
||||
InRealMode:=False;
|
||||
{$ELSE}
|
||||
InRealMode:=True;
|
||||
{$ENDIF}
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
|
||||
{$F+}
|
||||
Procedure IntrExit;
|
||||
begin
|
||||
ExitProc:=OldExitProc;
|
||||
{$IFDEF ProtMode}
|
||||
if GlobalDosFree(Seg(GlobalReqBuf^))<>0 then; {ignore Errors}
|
||||
if GlobalDosFree(Seg(GlobalReplyBuf^))<>0 then;
|
||||
FreeSelectorList;
|
||||
{$ELSE} {RealMode}
|
||||
FreeMem(GlobalReqBuf,SizeOf(TintrBuffer));
|
||||
Freemem(GlobalReplyBuf,Sizeof(TintrBuffer));
|
||||
{$ENDIF}
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
|
||||
{$IFDEF ProtMode}
|
||||
VAR w1:Longint absolute GlobalRegisters;
|
||||
{ we only need w1 during the initialisation, so we use the static
|
||||
var GlobalRegisters to save 4 bytes of memory :-) }
|
||||
{$ENDIF}
|
||||
|
||||
begin
|
||||
VLM_EXE_Loaded:=false;
|
||||
NETX_EXE_loaded:=false;
|
||||
NETX_VLM_loaded:=false;
|
||||
{$IFDEF ProtMode}
|
||||
new(SelectorList);
|
||||
fillchar(Selectorlist^,Sizeof(Selectorlist^),0);
|
||||
w1:=GlobalDosAlloc(Sizeof(tIntrBuffer)); {alloc REQ-Buffer}
|
||||
if w1=0
|
||||
then runerror(217); {DPMI-ERROR, no free Memory}
|
||||
GlobalReqBuf:=Ptr(loWord(w1),0); {buffer-address for protected Mode}
|
||||
GlobalRealReqSeg:=hiWord(w1); {REAL-Mode-Segment of the buffer-address}
|
||||
w1:=GlobalDosAlloc(Sizeof(tIntrBuffer)); {alloc REPLY-Buffer}
|
||||
if w1=0
|
||||
then runerror(217);
|
||||
GlobalReplyBuf:=Ptr(loWord(w1),0);
|
||||
GlobalRealReplySeg:=hiWord(w1);
|
||||
{$else} {RealMode}
|
||||
new(GlobalReqBuf);
|
||||
if GlobalReqBuf=NIL
|
||||
then RunError(203); {where has all the memory gone?? /Heap-Overflow}
|
||||
new(GlobalReplyBuf);
|
||||
if GlobalReplyBuf=NIL
|
||||
then RunError(203);
|
||||
VLMtransientSeg:=$0000;
|
||||
VLMcheck;
|
||||
{$endif}
|
||||
OldExitProc:=ExitProc;
|
||||
ExitProc:=@IntrExit;
|
||||
end.
|
||||
|
||||
|
||||
606
NWTP/NWIPX.PAS
Normal file
606
NWTP/NWIPX.PAS
Normal file
@@ -0,0 +1,606 @@
|
||||
{$B-,V-,X+}
|
||||
UNIT nwIPX;
|
||||
|
||||
{$DEFINE ProtMode}
|
||||
{$IFDEF MSDOS} {$UNDEF ProtMode} {$DEFINE RealMode} {$ENDIF}
|
||||
{$IFDEF ProtMode} sorry, protected mode not supported (yet) {$ENDIF}
|
||||
|
||||
{ nwIPX unit as of 950301 / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
INTERFACE
|
||||
|
||||
Uses Dos,nwMisc;
|
||||
|
||||
{ Primary IPX calls: Subf: Comments:
|
||||
|
||||
IPXCancelEvent 6 AES
|
||||
* IPXCloseSocket 1 (1)
|
||||
IPXDisconnectFromTarget B (1)
|
||||
* IPXGetInterNetworkaddress 9
|
||||
* IPXGetIntervalMarker 8
|
||||
* IPXGetLocalTarget 2
|
||||
- IPXGetPacketSize D (IPX internal use only)
|
||||
* IPXInitialize INT 2F
|
||||
- IPXInitializeNetworkAddress C (IPX internal use only)
|
||||
* IPXListenForPacket 4
|
||||
* IPXOpenSocket 0
|
||||
* IPXRelinquishControl A
|
||||
* IPXScheduleIPXEvent 5 AES
|
||||
IPXScheduleSpecialEvent 7
|
||||
* IPXSendPacket 3
|
||||
- IPXTerminateSockets E (IPX internal use only)
|
||||
|
||||
Secondary calls:
|
||||
|
||||
* IPXpresent
|
||||
* IPXsetupSendECB
|
||||
* IPXsetupListenECB
|
||||
|
||||
Notes: (1) These functions use INT 21 and are not to be called from
|
||||
within an ESR.
|
||||
}
|
||||
|
||||
CONST
|
||||
LONG_LIVED_SOCKET = TRUE; { IPXopenSocket }
|
||||
SHORT_LIVED_SOCKET = FALSE;
|
||||
|
||||
{*** PACKET TYPES ***}
|
||||
|
||||
UNKNOWN_PACKET_TYPE =0; { (basic) Unknown IPX packet }
|
||||
IPX_PACKET_TYPE =0;
|
||||
RIP_PACKET_TYPE =1; { Routing Information Packet }
|
||||
ECHO_PACKET_TYPE =2;
|
||||
ERROR_PACKET_TYPE =3;
|
||||
PEP_PACKET_TYPE =4; { Packet Exchange Protocol }
|
||||
SPX_PACKET_TYPE =5; { Sequenced Packet Protocol Packet }
|
||||
PUP_PACKET_TYPE =12;
|
||||
DOD_IP_PACKET_TYPE =13; { Internet Protocol packet Type }
|
||||
NCP_PACKET_TYPE =17; { NetWare Core Protocol }
|
||||
{ Experimental packet types: 20 - 37 }
|
||||
|
||||
{*** SOCKET NUMBERS ***}
|
||||
|
||||
{0001-0BB8 Registered with Xerox }
|
||||
SKT_XEROX_ROUTING_INFORMATION= $0001;
|
||||
SKT_ECHO_PROTOCOL = $0002;
|
||||
SKT_ERROR_HANDLER = $0003;
|
||||
|
||||
{0020-003F Xerox : Experimental }
|
||||
SKT_NW4_TIME_SYNC_SERVER = $0040; { used by OT_NW4_TIME_SYNC_SERVER }
|
||||
SKT_FILE_SERVICE = $0451; { see also $8140, used by OT_RSPCX_SERVER }
|
||||
SKT_SERVICE_ADVERTISING = $0452; { SAP }
|
||||
SKT_ROUTING_INFORMATION = $0453; { Novell's RIP Socket }
|
||||
SKT_NETBIOS = $0455;
|
||||
SKT_DIAGNOSTIC = $0456;
|
||||
{ 0457h ??? (appears to be related to server serial numbers) }
|
||||
|
||||
{0BB9-FFFF Xerox : Dynamically assignable Sockets }
|
||||
{0BB9-3FFF Novell: }
|
||||
SKT_NMA_AGENT =$2F90; { used by OT_NMA_AGENT (NMS) }
|
||||
|
||||
{4000-7FFF Novell: Dynamically assignable Sockets }
|
||||
{ Use a socket in this range for your own applications. }
|
||||
{ To avoid conflicts with other programs, you are advised NOT }
|
||||
{ to use sockets numbers where the hi-byte equals the low-byte, }
|
||||
{ C programmers mostly use those to avoid byte-order swapping. }
|
||||
|
||||
{ ! See the SKT_XXX file in the XIPX archive for the latest info
|
||||
on socket numbers... }
|
||||
|
||||
{8000-FFFF Novell: Well known sockets, registered with Novell. }
|
||||
SKT_EMAIL_CHAT =$8055; { Niche Corp. }
|
||||
SKT_EMAIL_CHAT_2 =$8056; { Niche Corp. }
|
||||
SKT_BTRIEVE =$8058;
|
||||
SKT_BTRIEVE_2 =$8059;
|
||||
SKT_NW_SQL =$805A;
|
||||
SKT_NW_SQL_2 =$805B;
|
||||
SKT_GAMESERVER =$805C;
|
||||
SKT_GAMESERVER_2 =$805D;
|
||||
SKT_PRINT_SERVER =$8060;
|
||||
SKT_DIGITAL_CHAT =$806C; { Digital Inc. }
|
||||
SKT_NW_ACCESS_SERVER =$806F;
|
||||
SKT_OXXI_EMAIL_CHAT =$80C3; { Oxxi Inc. }
|
||||
SKT_PRINT_SERVER_2 =$811E;
|
||||
SKT_INTEL_EMAIL_CHAT =$845F; { Intel Corp. }
|
||||
SKT_WINDOWS_EMAIL_CHAT =$9017;
|
||||
SKT_JOB_SERVER =$9022;
|
||||
|
||||
Var Result:word; { unit errorcode variable }
|
||||
|
||||
Type TipxHeader=Record
|
||||
checksum :word; { not used, set to $FFFF }
|
||||
length :word; { total number of bytes }
|
||||
TransportControl :byte; { used by bridges: low 4 bits= hop count }
|
||||
packetType :byte; { ignored by IPX, used by higher level
|
||||
protocols only. $00=unknown packet type}
|
||||
destination,
|
||||
source :TinternetWorkAddress;
|
||||
{ if dest.network equals 0; dest
|
||||
assumed on same network as sender }
|
||||
{ if dest.node =$FFFFFFFFFFFF, packet
|
||||
will be sent to all nodes. }
|
||||
end;
|
||||
{ Fields within IPX and SPX are high-low. Byte swapping will be done
|
||||
by the IPX functions, except network and node addresses. }
|
||||
|
||||
Tfragment=record { address and size of buffer fragment. }
|
||||
Address:Pointer;
|
||||
Size:word;
|
||||
end;
|
||||
|
||||
Tecb=record
|
||||
Linkaddress :Pointer; { used by IPX itself }
|
||||
ESRaddress :Pointer;
|
||||
InUseFlag :Byte; { reset to $00 when request completed }
|
||||
CompletionCode :Byte; { valid after InUseFlag becomes $00;
|
||||
completionCode=$00: packet sent/received. }
|
||||
SocketNumber :word;
|
||||
IPXworkspace :array[1..4] of byte;
|
||||
DriverWorkspace :array[1..12] of byte;
|
||||
Immediateaddress:Tnodeaddress; { 6 bytes }
|
||||
FragmentCount :word; { must be >0 }
|
||||
Fragment :array[1..2] of Tfragment; { [1..FragmentCount] }
|
||||
{ The number of fragments is unlimited.
|
||||
However, most applications use 1 or 2. }
|
||||
end;
|
||||
Tpecb=^Tecb;
|
||||
|
||||
{ TAESecb=:
|
||||
Offset Size Description
|
||||
00h DWORD Link
|
||||
04h DWORD ESR address
|
||||
08h BYTE in use flag (see below)
|
||||
09h 5 BYTEs AES workspace }
|
||||
|
||||
Function IpxPresent:boolean;
|
||||
{ Determines if an IPX driver is loaded. Calls IPXInitialize. }
|
||||
|
||||
Function IPXinitialize:Boolean;
|
||||
{ Determines if an IPX driver is loaded. }
|
||||
|
||||
{IPX/SPX: 09h}
|
||||
Function IPXGetInternetworkAddress(Var Address:TinterNetworkAddress):boolean;
|
||||
{ This call returns the network and node address of the requesting workstation. }
|
||||
{ The two byte socketnumber must be appended to the end to form a full }
|
||||
{ 12-Byte network address. The socketnumber will be set to 0000, indicating
|
||||
that it has to be filled later with a meaningfule number. }
|
||||
|
||||
{IPX/SPX: 00h}
|
||||
Function IPXOpenSocket(Var socket:word; PermanentSocket:boolean):boolean;
|
||||
{ When an application wants to send or receive packets on a socket,
|
||||
it should first open the socket. PermanentSocket should be set to TRUE
|
||||
if the socket is used by a TSR. This way, the socket will only be
|
||||
closed when the IPXcloseSocket function is called. Otherwise, set to FALSE. }
|
||||
|
||||
{IPX/SPX: 01h}
|
||||
Function IPXCloseSocket(socket:word):boolean;
|
||||
{ Closes the socket. TSRs should close permanent sockets before terminating. }
|
||||
|
||||
{IPX/SPX: 02h}
|
||||
Function IPXGetLocalTarget(Address:TinternetworkAddress;
|
||||
Var ImmAddr:TnodeAddress;
|
||||
Var Ticks:word ):boolean;
|
||||
{ Returns the nodeaddress (Immediate address) of a bridge/router that
|
||||
connects the senders' network with the target-network. If the target
|
||||
lies within the same network as the sender, the returned node address
|
||||
is the same as the target node-address. }
|
||||
|
||||
{IPX/SPX: 03h}
|
||||
Function IPXSendPacket(Var Ecb:Tecb):boolean;
|
||||
{ After calling this function, control is immediately turned back to the
|
||||
calling process, whilst in the background the IPX driver is trying to
|
||||
send the packet. To check if the message has been sent, check the
|
||||
ECB.InUseFlag or use a SendESR.
|
||||
The ecb must be filled with appropriate values before calling this function,
|
||||
the socket to send on must be open. }
|
||||
|
||||
{IPX/SPX: 0Fh}
|
||||
Function IPXInternalSendPacket(Var Ecb:Tecb):boolean;
|
||||
|
||||
{IPX/SPX: 04h}
|
||||
Function IPXListenForPacket(Var Ecb:Tecb):Boolean;
|
||||
{ After calling this function, control is immediately turned back to the
|
||||
calling process. The IPX driver will wait in the background for a packet
|
||||
to be received. To check if a message has been received, check the
|
||||
ECB.InUseFlag or use a ListenESR.
|
||||
The ecb must be filled with appropriate values before calling this function,
|
||||
the socket to receive on must be open. }
|
||||
|
||||
{IPX/SPX: 0Ah}
|
||||
Function IPXrelinquishControl:boolean;
|
||||
{ Temporarily gives away CPU time to bakcground processes. This call
|
||||
improves efficeincy by informing the IPX driver that the CPU is
|
||||
available. }
|
||||
|
||||
{IPX/SPX: 08h}
|
||||
Function IPXgetIntervalMarker(Var ticks:word):boolean;
|
||||
{ Gets a time marker from IPX. The difference between two known
|
||||
time-markers can be used to determine if a timeout has occurred.
|
||||
1 Tick = 1/18.2 second. }
|
||||
|
||||
{IPX/SPX: 06h}
|
||||
Function IPXcancelEvent(ECB:Tecb):boolean;
|
||||
{ AES call: Cancel an event.
|
||||
When the event is canceled, the ECB.InUseFlag will be set to $00 and the
|
||||
ECB.CompletionCode to $FC: Event Canceled. }
|
||||
|
||||
{IPX/SPX: 0Bh}
|
||||
Function IPXdisconnectFromTarget(Address:TinternetworkAddress):boolean;
|
||||
{ Informs the listening socket at the specified adress that no more
|
||||
packets will be sent to the listening socket.
|
||||
This function is not required in your application, it is merely used
|
||||
to inform some drivers that the connection (if any) has ended. }
|
||||
|
||||
{IPX/SPX: 05h}
|
||||
Function IPXscheduleIPXevent(ticks:word;Var ECB:Tecb):boolean;
|
||||
{ AES call: schedule an event.
|
||||
After calling this function, control is immediately turned back to the
|
||||
calling process. After waiting the number of ticks specified
|
||||
(1 tick= 1/18.2 sec.), the IPX driver activates the ECB.
|
||||
This function should never be called with an ECB that is still in use
|
||||
by the IPXdriver (i.e. ECB.InUseFlag should be 0 before calling)
|
||||
}
|
||||
|
||||
{UPX: 0007}
|
||||
Function IPXscheduleSpecialEvent(ticks:word;Var ECB:Tecb):boolean;
|
||||
|
||||
Procedure IpxSpxSystemCall(Var regs:registers);
|
||||
{ Provides an entry into the INT A7 interrupt handler;
|
||||
Valid only if IPXinitialize or IPXinstalled were called previously. }
|
||||
|
||||
{************** Secondary Procedures ***************************************}
|
||||
|
||||
Procedure IPXSetupListenECB(ESRptr:Pointer; ReceiveSocket:word;
|
||||
BufPtr:Pointer; BufSize:word;
|
||||
{out:} Var IpxHdr:TipxHeader; Var ecb:Tecb);
|
||||
{ Clears IPXheader and ECB, sets values of the required fields within
|
||||
the ecb and IPX header. }
|
||||
|
||||
Procedure IPXsetupSendECB(ESRptr:pointer; SourceSocket:Word;
|
||||
DestAddr:TinterNetworkAddress;
|
||||
BufPtr:pointer; BufSize:word;
|
||||
{out:} Var IpxHdr:TipxHeader; Var ecb:Tecb);
|
||||
{ Clears IPXheader and ECB, sets values of the required fields within
|
||||
the ecb and IPX header. }
|
||||
|
||||
IMPLEMENTATION {==============================================================}
|
||||
|
||||
CONST
|
||||
IPX_MAX_DATA_LENGTH =546;
|
||||
|
||||
Var IpxSpxCall:Procedure;
|
||||
|
||||
Procedure IpxSpxSystemCall(Var regs:registers); assembler;
|
||||
{ This method of calling IPX/SPX is preferred by Novell. }
|
||||
{ For what its' worth: this call is 48 bytes longer than the other one.. }
|
||||
asm
|
||||
{ check if IpxSpxCall known. If not, return error $FF in fake AL }
|
||||
xor ah,ah
|
||||
mov al,$FF
|
||||
les di,IpxSpxCall
|
||||
mov bx,es
|
||||
cmp bx,$0000
|
||||
je @1
|
||||
{ move fake regs registers to 'real' registers }
|
||||
{ AX, BX, CX, DX, SI, DI, ES only. }
|
||||
les di,regs
|
||||
mov ax,es:[di+16]
|
||||
push ax { push new es }
|
||||
mov ax,es:[di+12]
|
||||
push ax { push new di }
|
||||
mov ax,es:[di]
|
||||
mov bx,es:[di+2]
|
||||
mov cx,es:[di+4]
|
||||
mov dx,es:[di+6]
|
||||
mov si,es:[di+10]
|
||||
pop di
|
||||
pop es
|
||||
{ farr call to A7 interrup handler }
|
||||
push bp
|
||||
CALL IpxSpxCall
|
||||
pop bp
|
||||
@1: { move 'real' registers to fake regs registers }
|
||||
push es
|
||||
push di
|
||||
les di,regs
|
||||
mov es:[di],ax
|
||||
mov es:[di+2],bx
|
||||
mov es:[di+4],cx
|
||||
mov es:[di+6],dx
|
||||
mov es:[di+10],si
|
||||
pop ax { ax:= 'di' }
|
||||
mov es:[di+12],ax
|
||||
pop ax { ax:= 'es' }
|
||||
mov es:[di+16],ax
|
||||
end;
|
||||
|
||||
Function IPXinitialize:Boolean;
|
||||
CONST DOS_MULTIPLEX =$2F;
|
||||
Var regs:registers;
|
||||
begin
|
||||
Regs.AX:=$7A00;
|
||||
INTR(DOS_MULTIPLEX,Regs);
|
||||
if regs.AL<>$FF
|
||||
then begin
|
||||
Result:=IPX_NOT_INSTALLED;
|
||||
IpxInitialize:=false
|
||||
end
|
||||
else begin
|
||||
@IpxSpxCall:=Ptr(Regs.es,Regs.di);
|
||||
Result:=0;
|
||||
IpxInitialize:=true;
|
||||
end;
|
||||
end;
|
||||
|
||||
Function IpxPresent:boolean;
|
||||
begin
|
||||
IpxPresent:=IpxInitialize
|
||||
end;
|
||||
|
||||
{IPX: 09h}
|
||||
Function IPXGetInternetworkAddress(Var Address:TinterNetworkAddress):boolean;
|
||||
{ This call returns the network and node address of the requesting workstation. }
|
||||
{ The two byte socketnumber must be appended to the end to form a full }
|
||||
{ 12-Byte network address. }
|
||||
Var regs:registers;
|
||||
begin
|
||||
regs.bx:=$0009;
|
||||
regs.es:=seg(Address);
|
||||
regs.si:=ofs(Address);
|
||||
IpxSpxSystemCall(Regs);
|
||||
result:=regs.al;
|
||||
address.socket:=$0000; { unknown, to be set later. }
|
||||
if result<>$FF
|
||||
then result:=$00;
|
||||
IPXGetInternetworkAddress:=(result=$00);
|
||||
{ possible resultcodes: $00 Successful; $FF IPX not initialized }
|
||||
end;
|
||||
|
||||
{IPX: 00}
|
||||
Function IPXOpenSocket(Var socket:word; permanentSocket:boolean):boolean;
|
||||
Var regs:registers;
|
||||
reqForSocket:boolean;
|
||||
begin
|
||||
regs.bx:=$0000;
|
||||
if permanentSocket
|
||||
then regs.al:=$FF
|
||||
else regs.al:=$00;
|
||||
regs.dx:=swap(socket); {hi-lo}
|
||||
reqForSocket:=(socket=$0000);
|
||||
|
||||
IpxSpxSystemCall(Regs);
|
||||
|
||||
result:=regs.al;
|
||||
if reqForSocket
|
||||
then socket:=swap(regs.dx); {force lo-hi}
|
||||
IPXopenSocket:=(result=0);
|
||||
{ resultcodes: $00 successful; $FE Socket Table Is Full;
|
||||
$FF socket already open OR IPX not initilazed. }
|
||||
end;
|
||||
|
||||
{IPX: 01}
|
||||
Function IPXCloseSocket(socket:word):boolean;
|
||||
Var regs:registers;
|
||||
begin
|
||||
regs.bx:=$01;
|
||||
regs.dx:=swap(socket);
|
||||
IpxSpxSystemCall(regs);
|
||||
result:=regs.al;
|
||||
if result<>$FF then result:=$00;
|
||||
IPXCloseSocket:=(result=$00);
|
||||
{ possible resultcodes: $00 Successful; $FF IPX not initialized }
|
||||
end;
|
||||
|
||||
|
||||
{IPX: 02}
|
||||
Function IPXGetLocalTarget(Address:TinternetworkAddress;
|
||||
Var ImmAddr:TnodeAddress;
|
||||
VAR ticks:Word ):boolean;
|
||||
{ Ticks = estimated transmission time, in number of ticks (1/18 sec) }
|
||||
Var reqAddr:TinternetworkAddress;
|
||||
repNode:TnodeAddress;
|
||||
Regs :registers;
|
||||
begin
|
||||
move(Address,reqAddr,10);
|
||||
reqAddr.socket:=swap(Address.socket); {hi-lo}
|
||||
With regs
|
||||
do begin
|
||||
bx:=$0002;
|
||||
es:=seg(reqAddr); si:=ofs(reqAddr); di:=ofs(repNode);
|
||||
IpxSpxSystemCall(regs);
|
||||
ticks:=regs.cx;
|
||||
result:=regs.al;
|
||||
if result=0
|
||||
then move(repNode,ImmAddr,6);
|
||||
end;
|
||||
IPXGetLocalTarget:=(result=$00);
|
||||
{ resultcodes: $00 Successful; $FA No path to destination node found;
|
||||
$FF IPX not initialized. }
|
||||
end;
|
||||
|
||||
Function IPXSendPacket(Var Ecb:Tecb):boolean;
|
||||
{ the ecb must be filled, before calling this function }
|
||||
{ Right after this call, IPXrelinquishControl should be called Iteratively,
|
||||
this allows the sending of the IPX packet. }
|
||||
Var regs:Registers;
|
||||
begin
|
||||
regs.bx:=$0003;
|
||||
regs.es:=seg(ecb);
|
||||
regs.si:=ofs(ecb);
|
||||
IpxSpxSystemCall(Regs);
|
||||
result:=regs.al;
|
||||
if result<>$FF then result:=$00;
|
||||
IpxSendPacket:=(result=$00);
|
||||
{ possible resultcodes: $00 Successful; $FF IPX not initialized }
|
||||
end;
|
||||
|
||||
|
||||
Function IPXInternalSendPacket(Var Ecb:Tecb):boolean;
|
||||
Var regs:Registers;
|
||||
begin
|
||||
regs.bx:=$000F;
|
||||
regs.es:=seg(ecb);
|
||||
regs.si:=ofs(ecb);
|
||||
IpxSpxSystemCall(Regs);
|
||||
result:=regs.al;
|
||||
if result<>$FF then result:=$00;
|
||||
IpxInternalSendPacket:=(result=$00);
|
||||
{ possible resultcodes: $00 Successful; $FF IPX not initialized }
|
||||
end;
|
||||
|
||||
|
||||
Function IPXListenForPacket(Var Ecb:Tecb):Boolean;
|
||||
{ socket must be opened, ECB (partly) filled. }
|
||||
Var regs:Registers;
|
||||
begin
|
||||
regs.bx:=$0004;
|
||||
regs.es:=seg(ecb);
|
||||
regs.si:=ofs(ecb);
|
||||
IpxSpxSystemCall(Regs);
|
||||
result:=regs.al;
|
||||
if result<>$FF
|
||||
then result:=$00;
|
||||
IpxListenForPacket:=(result=$00);
|
||||
{resultcodes: $00 Successful;
|
||||
$FF Listening Socket doesn't exist OR IPX not initialized }
|
||||
end;
|
||||
|
||||
Function IPXrelinquishControl:boolean;
|
||||
Var regs:Registers;
|
||||
begin
|
||||
regs.bx:=$000A;
|
||||
IpxSpxSystemCall(Regs);
|
||||
result:=regs.al;
|
||||
if result<>$FF then result:=$00;
|
||||
IpxrelinquishControl:=(result=$00);
|
||||
{resultcodes: $00 Successful; $FF IPX not initialized }
|
||||
end;
|
||||
|
||||
Function IPXgetIntervalMarker(Var ticks:word):boolean;
|
||||
Var regs:Registers;
|
||||
begin
|
||||
regs.bx:=$0008;
|
||||
IpxSpxSystemCall(Regs);
|
||||
ticks:=regs.ax;
|
||||
result:=$00;
|
||||
IPXgetIntervalMarker:=True;
|
||||
end;
|
||||
|
||||
Function IPXcancelEvent(ECB:Tecb):boolean;
|
||||
Var regs:registers;
|
||||
begin
|
||||
regs.bx:=$0006;
|
||||
regs.es:=seg(ecb);
|
||||
regs.si:=ofs(ecb);
|
||||
IpxSpxSystemCall(Regs);
|
||||
result:=regs.al;
|
||||
IPXcancelEvent:=(result=0);
|
||||
{ resultcodes: 00 Successful; F9 ECB cannot be canceled;
|
||||
FF ECB not in use OR IPX not initialized. }
|
||||
end;
|
||||
|
||||
Function IPXdisconnectFromTarget(Address:TinternetworkAddress):boolean;
|
||||
VAR regs:registers;
|
||||
LocAddr:TinternetworkAddress;
|
||||
begin
|
||||
move(Address,LocAddr,10);
|
||||
LocAddr.socket:=swap(Address.socket);
|
||||
regs.bx:=$000B;
|
||||
regs.es:=seg(LocAddr);
|
||||
regs.si:=ofs(LocAddr);
|
||||
IpxSpxSystemCall(Regs);
|
||||
result:=regs.al;
|
||||
if result<>$FF
|
||||
then result:=$00;
|
||||
IPXdisconnectFromTarget:=(result=0);
|
||||
{resultcodes: $00 Successful; $FF IPX not initialized }
|
||||
end;
|
||||
|
||||
Function IPXscheduleIPXevent(ticks:word;Var ECB:Tecb):boolean;
|
||||
Var regs:registers;
|
||||
begin
|
||||
regs.bx:=$0005;
|
||||
regs.ax:=ticks;
|
||||
regs.es:=seg(ECB);
|
||||
regs.si:=ofs(ECB);
|
||||
IpxSpxSystemCall(Regs);
|
||||
if result<>$FF
|
||||
then result:=$00;
|
||||
IPXscheduleIPXevent:=(result=0);
|
||||
{resulcodes: 00 successful; FF IPX not initialized }
|
||||
end;
|
||||
|
||||
Function IPXscheduleSpecialEvent(ticks:word;Var ECB:Tecb):boolean;
|
||||
Var regs:registers;
|
||||
begin
|
||||
regs.bx:=$0007;
|
||||
regs.ax:=ticks;
|
||||
regs.es:=seg(ECB);
|
||||
regs.si:=ofs(ECB);
|
||||
IpxSpxSystemCall(Regs);
|
||||
if result<>$FF
|
||||
then result:=$00;
|
||||
IPXscheduleSpecialEvent:=(result=0);
|
||||
{resulcodes: 00 successful; FF IPX not initialized }
|
||||
end;
|
||||
|
||||
{************** Secondary Procedures ***************************************}
|
||||
|
||||
Procedure IPXSetupListenECB(ESRptr:Pointer;ReceiveSocket:word;
|
||||
BufPtr:Pointer;BufSize:word;
|
||||
{out:} Var IpxHdr:TipxHeader; Var ecb:Tecb);
|
||||
{ Clears IPXheader and ECB, sets values of the required fields within
|
||||
the ecb and IPX header. }
|
||||
{ ECB: ESR adress field, socket number, fragment count, frag.descriptor fields }
|
||||
begin
|
||||
FillChar(ecb,SizeOf(Tecb),#0);
|
||||
FillChar(ipxHdr,SizeOF(TipxHeader),#0);
|
||||
WITH ECB
|
||||
do begin
|
||||
if ESRptr<>NIL
|
||||
then ESRaddress:=ESRptr;
|
||||
Fragmentcount:=2;
|
||||
socketNumber:=swap(ReceiveSocket); {hi-lo}
|
||||
|
||||
Fragment[1].Address:=@ipxHdr;
|
||||
Fragment[2].Address:=BufPtr;
|
||||
Fragment[1].size:=SizeOf(Tipxheader);
|
||||
Fragment[2].size:=BufSize;
|
||||
end;
|
||||
end;
|
||||
|
||||
Procedure IPXsetupSendECB(ESRptr:pointer; SourceSocket:word;
|
||||
DestAddr:TinterNetworkAddress;
|
||||
BufPtr:pointer; BufSize:word;
|
||||
{out:} Var IpxHdr:TipxHeader; Var ecb:Tecb);
|
||||
{ Clears IPXheader and ECB, sets values of the required fields within
|
||||
the ecb and IPX header. }
|
||||
Var ImmAddr:TnodeAddress;
|
||||
Ticks:word;
|
||||
begin
|
||||
fillchar(ipxHdr,SizeOf(TipxHeader),#0);
|
||||
with ipxhdr
|
||||
do begin
|
||||
PacketType:=IPX_PACKET_TYPE;
|
||||
Move(DestAddr,Destination,10);
|
||||
destination.socket:=swap(DestAddr.socket); {hi-lo}
|
||||
end;
|
||||
IPXGetLocalTarget(DestAddr,ImmAddr,Ticks);
|
||||
fillchar(ecb,sizeOf(ecb),#0);
|
||||
With ecb
|
||||
do begin
|
||||
if ESRptr<>NIL
|
||||
then ESRaddress:=ESRptr;
|
||||
socketNumber:=swap(SourceSocket); {hi-lo}
|
||||
Move(ImmAddr,ImmediateAddress,6);
|
||||
FragmentCount:=2;
|
||||
fragment[1].Address:=@ipxhdr;
|
||||
fragment[1].size:=SizeOf(TipxHeader);
|
||||
fragment[2].Address:=BufPtr;
|
||||
fragment[2].size:=BufSize;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
end.
|
||||
663
NWTP/NWLOCK.PAS
Normal file
663
NWTP/NWLOCK.PAS
Normal file
@@ -0,0 +1,663 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
UNIT nwLock;
|
||||
|
||||
{ nwLock unit as of 950301 / NwTP 0.6 API. (c) 1993,1995, R. Spronk
|
||||
|
||||
This unit was based on units by
|
||||
|
||||
a. Scott A. Lewis, 36 Maythorpe Drive, Windsor, CT 06095, U.S.A.
|
||||
Note: (1987) 76515,135@Compuserve.Com
|
||||
|
||||
b. Erik van Heyningen, Hague Consulting Group,
|
||||
The Hague, the Netherlands.
|
||||
Note: (1994) hcg@hacktick.nl }
|
||||
|
||||
{ Function: Interrupt: Notes:
|
||||
|
||||
Physical File locking/unlocking
|
||||
-------------------------------
|
||||
|
||||
* LogPhysicalFile EB (6) -> F203
|
||||
* LockPhysicalFileSet F204
|
||||
* ReleasePhysicalFile EC -> F205
|
||||
* ReleasePhysicalFileSet CD -> F206
|
||||
* ClearPhysicalFile ED (6) -> F207
|
||||
* ClearPhysicalFileSet CF -> F208
|
||||
|
||||
Logical File Locking
|
||||
--------------------
|
||||
|
||||
+ LogLogicalFile (5)
|
||||
+ LogLogicalFileSet (5)
|
||||
+ ReleaseLogicalFile (5)
|
||||
+ ReleaseLogicalFileSet (5)
|
||||
+ ClearLogicalFile (5)
|
||||
+ ClearLogicalFileSet (5)
|
||||
|
||||
Logical record locking/unlocking
|
||||
--------------------------------
|
||||
|
||||
* LogLogicalRecord D0 -> F209
|
||||
* LockLogicalRecordSet D1 -> F20A
|
||||
* ReleaseLogicalRecord D2 -> F20C
|
||||
* ReleaseLogicalRecordSet D3 -> F20D
|
||||
* ClearLogicalRecord D4 -> F20B
|
||||
* ClearLogicalRecordSet D5 -> F20E
|
||||
|
||||
GetLogicalRecordInformation F217/F0 (3)
|
||||
GetLogicalRecordsByConnection F217/EF (3)
|
||||
|
||||
Physical record locking/unlocking
|
||||
---------------------------------
|
||||
|
||||
. LogPhysicalRecord BC -> F21A
|
||||
. LockPhysicalRecordSet C2 -> F21B
|
||||
. ReleasePhysicalRecord BD -> F21C
|
||||
. ReleasePhysicalRecordSet C3 -> F21D
|
||||
. ClearPhysicalRecord BE -> F21E
|
||||
. ClearPhysicalRecordSet C4 -> F21F
|
||||
|
||||
GetPhysRecLocksByConnectionAndFile F217/ED (3)
|
||||
GetPhysRecLocksByFile F217/EE (3)
|
||||
|
||||
- ControlRecordAccess 5C (DOS) (4)
|
||||
|
||||
|
||||
Not Implemented
|
||||
---------------
|
||||
|
||||
- GetLockMode C600 (1)
|
||||
- SetLockMode C601 (1)
|
||||
- BeginLogicalFileLocking C8 / F201 (2)
|
||||
- EndLogicalFileLocking C9 / F202 (2)
|
||||
|
||||
Notes: -Semaphores can be found in the nwSema Unit
|
||||
(1) Obsolete
|
||||
(2) Not supported by (all) 3.x versions
|
||||
(3) Supported by NW 3.x and upwards
|
||||
(4) Generic physical record locking call, DOS 3.1+
|
||||
Equivalent to:
|
||||
I . LockPhysicalRecord (without logging)
|
||||
II. ReleasePhysicalrecord
|
||||
(5) Use the equivalent LogicalRecordLocking calls
|
||||
to emulate LogicalFileLocking. NOTE: remember
|
||||
that there's only ONE Log.
|
||||
(6) Includes VLM fix for filenames (GetTrueEntryName
|
||||
in the nwFile unit is called)
|
||||
-> F2xx To be rewritten to the F2 interface.
|
||||
}
|
||||
|
||||
INTERFACE
|
||||
|
||||
Uses nwIntr,nwMisc;
|
||||
|
||||
CONST { Log Resource }
|
||||
LD_LOG = 0;
|
||||
LD_LOG_LOCK = 1; { Deny all access to file/record }
|
||||
LD_LOG_LOCK_RO = 3; { Allow read / deny write (record locking only)}
|
||||
{ Lock Resource }
|
||||
LD_lOCK = 0; { Deny all access to file/record }
|
||||
LD_LOCK_RO = 1; { Allow read / deny write (record locking only)}
|
||||
|
||||
Var Result:word;
|
||||
|
||||
{------------------- PHYSICAL FILE LOCKING OPERATIONS -----------------------}
|
||||
|
||||
{F204 [2.15c+]}
|
||||
FUNCTION LockPhysicalFileSet(TimeoutLimit : Word) : Boolean;
|
||||
{Lock a set of files that were logged by the LogFile function }
|
||||
|
||||
{CD.. [1.0+]}
|
||||
FUNCTION ReleasePhysicalFileSet:boolean;
|
||||
{ Release lock on set of files in logged table, files remain logged }
|
||||
|
||||
{CF [1.0+]}
|
||||
FUNCTION ClearPhysicalFileSet : Boolean;
|
||||
{ Unlock and UnLog the entire logged file set }
|
||||
|
||||
{EB.. [1.0+]}
|
||||
FUNCTION LogPhysicalFile(FileName : String; LockDirective : Byte; TimeoutLimit : Word) : Boolean;
|
||||
{Log files for later use }
|
||||
|
||||
{EC.. [1.0+]}
|
||||
FUNCTION ReleasePhysicalFile(FileName : String) : boolean;
|
||||
{Release file lock, but keep logged in the table }
|
||||
|
||||
{ED.. [1.0+]}
|
||||
FUNCTION ClearPhysicalFile(FileName : String) : boolean;
|
||||
{Release a file from the file log table, unlock the file if it is locked }
|
||||
|
||||
{ ------------------- LOGICAL RECORD LOCKING OPERATIONS --------------------}
|
||||
|
||||
{D0 [1.0+]}
|
||||
FUNCTION LogLogicalRecord(Name:string; LockDirective:Byte; Timeout: Word) : Boolean;
|
||||
{Add a record to the lockable logical record table }
|
||||
|
||||
{D1.. [1.0+]}
|
||||
FUNCTION LockLogicalRecordSet(LockDirective:Byte; TimeoutLimit : Word) : Boolean;
|
||||
{Lock all logged records }
|
||||
|
||||
{D2.. [1.0+]}
|
||||
FUNCTION ReleaseLogicalRecord(Name : String) : Boolean;
|
||||
{Unlock a record, keep record in logtable }
|
||||
|
||||
{D3.. [1.0+]}
|
||||
FUNCTION ReleaseLogicalRecordSet : Boolean;
|
||||
{Unlock all locked records, keep records logged }
|
||||
|
||||
{D4.. [1.0+]}
|
||||
FUNCTION ClearLogicalRecord(Name : String) : Boolean;
|
||||
{Unlock and UnLog a record }
|
||||
|
||||
{D5.. [1.0+]}
|
||||
FUNCTION ClearLogicalRecordSet : Boolean;
|
||||
{Unlocks and UnLogs all logged records }
|
||||
|
||||
{F217/EF [2.1x+]}
|
||||
Function GetLogicalRecordLocksByConnection(ConnNbr:word;
|
||||
{i/o} Var NextRecNbr:word;
|
||||
Var TaskNbr:word;
|
||||
Var LockStatus:Byte;
|
||||
Var LockName:String):Boolean;
|
||||
{ You need console operator rights to use this function }
|
||||
|
||||
|
||||
{----------------------- PHYSICAL RECORD LOCKING OPERATION -----------------}
|
||||
|
||||
{BC.. [1.0+]}
|
||||
function LogPhysicalRecord(Handle:Word;
|
||||
LockDirective:Byte;
|
||||
RecordOffset,RecordLength:Longint;
|
||||
TimeOutLimit:Word): boolean;
|
||||
{Add a record to the lockable physical record logtable }
|
||||
|
||||
{BD.. [1.0+]}
|
||||
function ReleasePhysicalRecord( Handle:Word; RecordOffset,RecordLength:Longint) : boolean;
|
||||
{Unlock record, keep record logged }
|
||||
|
||||
{BE.. [1.0+]}
|
||||
function ClearPhysicalRecord(Handle:Word; RecordOffset,RecordLength:Longint): boolean;
|
||||
{Unlock and Unlog a record }
|
||||
|
||||
{C2.. [1.0+]}
|
||||
function LockPhysicalRecordSet(LockDirective: byte; TimeoutLimit : Word): boolean;
|
||||
{Lock all logged records }
|
||||
|
||||
{C3.. [1.0+]}
|
||||
function ReleasePhysicalRecordSet : boolean;
|
||||
{Unlock all logged records, keep records logged }
|
||||
|
||||
{C4.. [1.0+]}
|
||||
function ClearPhysicalRecordSet : boolean;
|
||||
{Unlocks and unLogs all logged records }
|
||||
|
||||
|
||||
IMPLEMENTATION{==============================================================}
|
||||
|
||||
uses nwFile;
|
||||
|
||||
Var regs:TTRegisters;
|
||||
|
||||
|
||||
Procedure SetLockMode(mode:Byte);
|
||||
begin
|
||||
regs.AH:=$c6;
|
||||
regs.al:=mode; { 0 or 1 }
|
||||
RealModeIntr($21,regs);
|
||||
end;
|
||||
|
||||
(* THE FOLLOWING PROCEDURES ARE FOR LOGGING AND LOCKING/RELEASING FILE SETS *)
|
||||
(* File locking by set can be very effective in avoiding deadly embrace *)
|
||||
|
||||
{F204 [3.x+]}
|
||||
FUNCTION LockPhysicalFileSet(TimeoutLimit : Word) : Boolean;
|
||||
Type Treq=record
|
||||
_TimeOutLimit:Word;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
BEGIN
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
_TimeoutLimit:=swap(TimeoutLimit);
|
||||
end;
|
||||
F2SystemCall($04,SizeOf(Treq),0,result);
|
||||
LockPhysicalFileSet:=(result=0);
|
||||
{ 00 Successful FF Fail FE Timeout }
|
||||
END;
|
||||
|
||||
|
||||
{CD.. [1.0+]}
|
||||
FUNCTION ReleasePhysicalFileSet:boolean;
|
||||
{ Release lock on set of files in logged table, files remain logged }
|
||||
{ These files remain open but cannot be accessed without an error }
|
||||
{ To reuse them, send another lock file set }
|
||||
Type Treq=record
|
||||
end;
|
||||
BEGIN
|
||||
WITH Regs
|
||||
DO BEGIN
|
||||
AH := $CD;
|
||||
RealModeIntr($21,Regs);
|
||||
result:=0;
|
||||
END;
|
||||
ReleasePhysicalFileSet:=true;
|
||||
END;
|
||||
|
||||
{CF [2.0+]}
|
||||
FUNCTION ClearPhysicalFileSet : Boolean;
|
||||
{ Unlock and UnLog the entire personal file set (all files are closed) }
|
||||
BEGIN
|
||||
WITH Regs
|
||||
DO BEGIN
|
||||
AH := $CF;
|
||||
RealModeIntr($21,Regs);
|
||||
result:=0;
|
||||
END;
|
||||
ClearPhysicalFileSet:=true;
|
||||
END;
|
||||
|
||||
|
||||
{EB.. [2.0+] }
|
||||
FUNCTION LogPhysicalFile(FileName : String; LockDirective : Byte; TimeoutLimit : Word) : Boolean;
|
||||
{ This function allows a station to log files for later personal use }
|
||||
{ After the desired files are logged, function CBh can be used to lock }
|
||||
{ the entire set of files }
|
||||
{ !! There is a known problem with lock directive 3 (log and lock shareable)
|
||||
use 1 instead. }
|
||||
Type Treq=record
|
||||
LockDirective:Byte;
|
||||
TimeOutLimit:Word;
|
||||
FileName:string[255]; { or Asciiz ? }
|
||||
end;
|
||||
Var temp1,temp2:word;
|
||||
TEname:string;
|
||||
BEGIN
|
||||
GetTrueEntryName(FileName,TEname); { also UpCases string }
|
||||
{ IF this function isn't included and VLMs are used, this call will
|
||||
*appear* to be successful. No error code is returned, the call is
|
||||
however unsuccessful. }
|
||||
WITH Regs
|
||||
DO BEGIN
|
||||
AH := $EB;
|
||||
AL := LockDirective; { 0 = Log Only, 1 Log and Lock }
|
||||
BP := TimeoutLimit; { in 1/18 seconds, 0 = No wait }
|
||||
TEname := TEName+#0; { Terminate with a nul for asciiz }
|
||||
Move(TEname[1],GlobalReqBuf^,ord(TEname[0]));
|
||||
GetGlobalBufferAddress(DS,DX,temp1,temp2);
|
||||
{ DS:DX real mode pointer to buffer in realmode-range holding Filename }
|
||||
RealModeIntr($21,Regs);
|
||||
Result:=AL;
|
||||
LogPhysicalFile := (Result = 0);
|
||||
END;
|
||||
{ FE Timeout FF hardware error }
|
||||
END;
|
||||
|
||||
|
||||
{EC.. [1.0+]}
|
||||
FUNCTION ReleasePhysicalFile(FileName : String) : boolean;
|
||||
{ Release file lock, but keep logged in the table }
|
||||
Var temp1,temp2:word;
|
||||
TEname:string;
|
||||
BEGIN
|
||||
GetTrueEntryName(FileName,TEname); { also UpCases string }
|
||||
{ IF this function isn't included and VLMs are used, this call will
|
||||
*appear* to be successful. No error code is returned, the call is
|
||||
however unsuccessful. }
|
||||
WITH Regs
|
||||
DO BEGIN
|
||||
AH := $EC;
|
||||
UpString(FileName);
|
||||
TEName := TEName+#0; { null terminate }
|
||||
Move(TEname[1],GlobalReqBuf^,ord(TEname[0]));
|
||||
GetGlobalBufferAddress(DS,DX,temp1,temp2);
|
||||
{ DS:DX real mode pointer to buffer in realmode-range holding Filename }
|
||||
RealModeIntr($21,Regs);
|
||||
result:=AL;
|
||||
ReleasePhysicalFile:=(result=0);
|
||||
END;
|
||||
{FF File not found }
|
||||
END;
|
||||
|
||||
{ED.. [1.0+]}
|
||||
FUNCTION ClearPhysicalFile(FileName : String) : boolean;
|
||||
{ Release a file from the file log table, unlock the file if it is locked }
|
||||
Var temp1,temp2:word;
|
||||
BEGIN
|
||||
WITH Regs
|
||||
DO BEGIN
|
||||
AH := $ED;
|
||||
UpString(FileName);
|
||||
FileName := FileName+#0; { null terminate }
|
||||
Move(Filename[1],GlobalReqBuf^,ord(Filename[0]));
|
||||
GetGlobalBufferAddress(DS,DX,temp1,temp2);
|
||||
{ DS:DX real mode pointer to buffer in realmode-range holding Filename }
|
||||
RealModeIntr($21,Regs);
|
||||
Result:=AL;
|
||||
ClearPhysicalFile := (Result = 0);
|
||||
{ 0 means OK FF File not found}
|
||||
END;
|
||||
END;
|
||||
|
||||
|
||||
(* THE FOLLOWING FUNCTIONS ARE FOR LOGICAL LOCKING OPERATIONS *)
|
||||
(* Logical locks work only if all software accessing the files use the *)
|
||||
(* same logical synchronization scheme. Logical locks are much easier *)
|
||||
(* and faster to implement than physical locks. *)
|
||||
|
||||
|
||||
{D0 [1.0+]}
|
||||
FUNCTION LogLogicalRecord(Name:String; LockDirective:Byte; Timeout: Word) : Boolean;
|
||||
{ This function will log the specified record string in the record log table }
|
||||
{ of the requesting station. }
|
||||
{ Max length of name: 99 chars }
|
||||
{ LockDirective LD_LOG = 0;
|
||||
LD_LOG_LOCK = 1; Deny all access to file/record
|
||||
LD_LOG_LOCK_RO = 3; Allow read / deny write }
|
||||
{ TimeOut=0 means NoWait }
|
||||
Var temp1,temp2:word;
|
||||
BEGIN
|
||||
WITH Regs
|
||||
DO BEGIN
|
||||
AH := $D0;
|
||||
AL := LockDirective;
|
||||
UpString(Name);
|
||||
Move(Name,GlobalReqBuf^,ord(Name[0])+1);
|
||||
GetGlobalBufferAddress(DS,DX,temp1,temp2);
|
||||
{ DS:DX real mode pointer to buffer in realmode-range holding Filename }
|
||||
BP := Timeout; { In 1/18th seconds (use only with lock bit set }
|
||||
RealModeIntr($21,Regs);
|
||||
Result:=AL;
|
||||
LogLogicalRecord := (Result=0);
|
||||
{ FFh fail }
|
||||
{ FEh timeout }
|
||||
{ 96h No dynamic memory for file }
|
||||
END;
|
||||
END;
|
||||
|
||||
|
||||
{D1 [1.0+]}
|
||||
FUNCTION LockLogicalRecordSet(LockDirective:Byte; TimeoutLimit : Word) : Boolean;
|
||||
{ Call this to lock all records logged with Log_Logical_Record }
|
||||
{ LockDirective LD_LOCK = 0; Deny all access to file/record
|
||||
LD_LOCK_RO = 1; Allow read / deny write }
|
||||
BEGIN
|
||||
WITH Regs
|
||||
DO BEGIN
|
||||
AH := $D1;
|
||||
AL := LockDirective;
|
||||
BP := TimeoutLimit; { In 1/18th seconds, 0 = No wait }
|
||||
RealModeIntr($21,Regs);
|
||||
Result:=AL;
|
||||
LockLogicalRecordSet := (Result=0);
|
||||
{00 - Success
|
||||
FF - fail,
|
||||
FE - timeout }
|
||||
END;
|
||||
END;
|
||||
|
||||
{D2.. [1.0+]}
|
||||
FUNCTION ReleaseLogicalRecord(Name : String) : Boolean;
|
||||
{ Call this to release a logical record lock without removing the rec }
|
||||
{ from the table }
|
||||
Var temp1,temp2:word;
|
||||
BEGIN
|
||||
WITH Regs
|
||||
DO BEGIN
|
||||
AH := $D2;
|
||||
UpString(Name);
|
||||
Move(Name,GlobalReqBuf^,ord(Name[0])+1);
|
||||
GetGlobalBufferAddress(DS,DX,temp1,temp2);
|
||||
{ DS:DX real mode pointer to buffer in realmode-range holding Filename }
|
||||
RealModeIntr($21,Regs);
|
||||
Result:=AL;
|
||||
ReleaseLogicalRecord := (Result=0);
|
||||
{ FF No record found }
|
||||
END;
|
||||
END;
|
||||
|
||||
{D3.. [1.0+]}
|
||||
FUNCTION ReleaseLogicalRecordSet : Boolean;
|
||||
{ release all locked logical records, doesn't remove them from the table }
|
||||
BEGIN
|
||||
WITH Regs
|
||||
DO BEGIN
|
||||
AH := $D3;
|
||||
RealModeIntr($21,Regs);
|
||||
Result:=0;
|
||||
ReleaseLogicalRecordSet := True;
|
||||
END;
|
||||
END;
|
||||
|
||||
{D4.. [1.0+]}
|
||||
FUNCTION ClearLogicalRecord(Name : String) : Boolean;
|
||||
{ This call unlocks and removes the Logical Record lock from the table }
|
||||
Var temp1,temp2:word;
|
||||
BEGIN
|
||||
WITH Regs
|
||||
DO BEGIN
|
||||
AH := $D4;
|
||||
UpString(Name);
|
||||
Move(Name,GlobalReqBuf^,ord(Name[0])+1);
|
||||
GetGlobalBufferAddress(DS,DX,temp1,temp2);
|
||||
{ DS:DX real mode pointer to buffer in realmode-range holding Filename }
|
||||
RealModeIntr($21,Regs);
|
||||
Result:=AL;
|
||||
ClearLogicalRecord := (Result=0);
|
||||
{ FF No record Found }
|
||||
END;
|
||||
END;
|
||||
|
||||
{D5.. [1.0+]}
|
||||
FUNCTION ClearLogicalRecordSet : Boolean;
|
||||
{ Unlocks and removes from the table all of the stations logical record locks }
|
||||
BEGIN
|
||||
WITH Regs
|
||||
DO BEGIN
|
||||
AH := $D5;
|
||||
RealModeIntr($21,Regs);
|
||||
Result:=0;
|
||||
ClearLogicalRecordSet := True;
|
||||
END;
|
||||
END;
|
||||
|
||||
|
||||
(************* THE FOLLOWING ARE PHYSICAL RECORD LOCK CALLS ****************)
|
||||
|
||||
{F:BC..:Lock (& Log) records in a file}
|
||||
function LogPhysicalRecord(Handle:Word;
|
||||
LockDirective:Byte;
|
||||
RecordOffset,RecordLength:Longint;
|
||||
TimeOutLimit:Word): boolean;
|
||||
{ Max length of name: 99 chars }
|
||||
{ LockDirective LD_LOG = 0;
|
||||
LD_LOG_LOCK = 1; Deny all access to file/record
|
||||
LD_LOG_LOCK_RO = 3; Allow read / deny write }
|
||||
{ TimeOut=0 means NoWait; TimeOut not valid if logging only }
|
||||
{ Handle is the file handle }
|
||||
begin
|
||||
with regs
|
||||
do begin
|
||||
AH := $BC;
|
||||
AL := LockDirective;
|
||||
BX := Handle;
|
||||
CX := HiLong(RecordOffset);
|
||||
DX := LowLong(RecordOffset);
|
||||
BP := TimeOutLimit;
|
||||
SI := HiLong(RecordLength);
|
||||
DI := LowLong(RecordLength);
|
||||
RealModeIntr($21,Regs);
|
||||
Result:=AL;
|
||||
LogPhysicalRecord := (Result=0);
|
||||
{ $FF = fail, $FE Timeout, $96 = No dynamic memory }
|
||||
end;
|
||||
end;
|
||||
|
||||
{BD.. [1.0+]}
|
||||
function ReleasePhysicalRecord( Handle:Word; RecordOffset,RecordLength:Longint) : boolean;
|
||||
{ When a record is released, it is unlocked for use by someone else, but }
|
||||
{ it remains in the log table }
|
||||
{ Handle is the file handle, Start_Hi and Start_Lo are the boundaries of }
|
||||
{ the locked region to be released }
|
||||
begin
|
||||
with regs
|
||||
do begin
|
||||
AH := $BD;
|
||||
BX := Handle;
|
||||
CX := HiLong(RecordOffset);
|
||||
DX := LowLong(RecordOffset);
|
||||
SI := HiLong(RecordLength);
|
||||
DI := LowLong(RecordLength);
|
||||
RealModeIntr($21,Regs);
|
||||
Result:=AL;
|
||||
ReleasePhysicalRecord := (Result=0);
|
||||
{ $FF = No locked record found}
|
||||
end;
|
||||
end;
|
||||
|
||||
{BE.. [1.0+]}
|
||||
function ClearPhysicalRecord(Handle: Word;
|
||||
RecordOffset,RecordLength:Longint): boolean;
|
||||
{ Handle is the file handle, Start_Hi and Start_Lo are the boundaries }
|
||||
{ of the file region to be locked. Clearing a record will unlock it }
|
||||
{ and remove it from the log table. }
|
||||
begin
|
||||
with regs
|
||||
do begin
|
||||
AH := $BE;
|
||||
BX := Handle;
|
||||
CX := HiLong(RecordOffset);
|
||||
DX := LowLong(RecordOffset);
|
||||
SI := HiLong(RecordLength);
|
||||
DI := LowLong(RecordLength);
|
||||
RealModeIntr($21,Regs);
|
||||
Result:=AL;
|
||||
ClearPhysicalRecord := (Result=0);
|
||||
{ $FF No locked record found }
|
||||
end;
|
||||
end;
|
||||
|
||||
{C2.. [1.0+]}
|
||||
function LockPhysicalRecordSet(LockDirective: byte; TimeoutLimit: Word): boolean;
|
||||
{ flgs are the lock flags: bit 1 set means shared (non-exclusive) lock }
|
||||
{ Timeout is in 1/18 seconds, 0 = no wait, -1 means indefinite wait }
|
||||
{ This function attempts to lock all of the records logged in the station's }
|
||||
{ log table. }
|
||||
{ LockDirective LD_LOCK = 0; Deny all access to file/record
|
||||
LD_LOCK_RO = 1; Allow read / deny write }
|
||||
{ !! There is known problem when the locking directive equals 1. }
|
||||
begin
|
||||
with regs
|
||||
do begin
|
||||
AH := $C2;
|
||||
AL := LockDirective;
|
||||
BP := TimeOutLimit;
|
||||
RealModeIntr($21,Regs);
|
||||
Result:=AL;
|
||||
LockPhysicalRecordSet := (Result=0);
|
||||
{ $FF = fail, $FE = timeout fail }
|
||||
end;
|
||||
end;
|
||||
|
||||
{C3.. [1.0+]}
|
||||
function ReleasePhysicalRecordSet : boolean;
|
||||
{ unlocks the entire record log table of the station. records remain in }
|
||||
{ the log table. }
|
||||
begin
|
||||
regs.AH := $C3;
|
||||
RealModeIntr($21,Regs);
|
||||
Result:=0;
|
||||
ReleasePhysicalRecordSet := True;
|
||||
end;
|
||||
|
||||
{C4.. [1.0+]}
|
||||
function ClearPhysicalRecordSet : boolean;
|
||||
{ unlocks and removes from the log table any records logged and locked }
|
||||
begin
|
||||
regs.AH := $C4;
|
||||
RealModeIntr($21,Regs);
|
||||
Result:=0;
|
||||
ClearPhysicalRecordSet := True;
|
||||
end;
|
||||
|
||||
|
||||
{F217/EF [2.1x+]}
|
||||
Function GetLogicalRecordLocksByConnection(ConnNbr:word;
|
||||
{i/o} Var NextRecNbr:word;
|
||||
Var TaskNbr:word;
|
||||
Var LockStatus:Byte;
|
||||
Var LockName:String):Boolean;
|
||||
{ You need console operator rights to use this function }
|
||||
Type Treq=record
|
||||
len :Word;
|
||||
subFunc :Byte;
|
||||
_ConnNbr :word; {lo-hi} { !! Invalid numbers may cause an abend }
|
||||
_LastRecSeen:word; {lo-hi}
|
||||
end;
|
||||
Trep=record
|
||||
_LastRecSeen :word; {lo-hi}
|
||||
_NbrOfRecords:word; {lo-hi}
|
||||
_LockInfo :array[1..508] of byte;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
Begin
|
||||
WITH TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
subFunc:=$EF;
|
||||
_ConnNbr:=ConnNbr;
|
||||
_LastRecSeen:=NextRecNbr;
|
||||
len:=SizeOf(Treq)-2;
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result);
|
||||
With TPrep(GlobalReplyBuf)^
|
||||
do begin
|
||||
Move(_LastRecSeen,NextRecNbr,2);
|
||||
|
||||
|
||||
end;
|
||||
GetLogicalRecordLocksByConnection:=(result=0)
|
||||
{ Valid completion codes:
|
||||
$00 Success
|
||||
$FF Failure
|
||||
}
|
||||
end;
|
||||
|
||||
{$IFDEF xxxx}
|
||||
|
||||
{F217/ [2.1x+]}
|
||||
Function ( ):Boolean;
|
||||
Type Treq=record
|
||||
len:Word;
|
||||
subFunc:Byte;
|
||||
|
||||
end;
|
||||
Trep=record
|
||||
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
Begin
|
||||
WITH TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
subFunc:=$
|
||||
|
||||
len:=SizeOf(Treq)-2;
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result);
|
||||
With TPrep(GlobalReplyBuf)^
|
||||
do begin
|
||||
|
||||
end;
|
||||
:=(result=0)
|
||||
{ Valid completion codes:
|
||||
$00 Success
|
||||
$FF Failure.
|
||||
}
|
||||
end;
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
Begin
|
||||
SetLockMode(1);
|
||||
END.
|
||||
308
NWTP/NWMESS.PAS
Normal file
308
NWTP/NWMESS.PAS
Normal file
@@ -0,0 +1,308 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
UNIT nwMess;
|
||||
|
||||
{ nwMess unit as of 950301 / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
INTERFACE
|
||||
|
||||
Uses nwIntr,nwMisc;
|
||||
|
||||
{ Primary functions: Interrupt: comments:
|
||||
|
||||
* BroadcastToConsole (F215/09)
|
||||
* GetBroadcastMessage (F215/01)
|
||||
* GetBroadcastMode (DE..(..04))
|
||||
* SendBroadcastMessage (F215/00)
|
||||
* SendConsoleBroadcast (F217/D1)
|
||||
* SetBroadcastMode (DE..(..0x)), x= 0,1,2,3
|
||||
|
||||
Secondary Functions:
|
||||
|
||||
* SendMessageToUser
|
||||
|
||||
Not implemented:
|
||||
|
||||
- CheckPipeStatus (F215/08) (1)
|
||||
- CloseMessagePipe (F215/07) (1)
|
||||
- DisableStationBroadcast (F215/02) (3)
|
||||
- EnableStationBroadcast (F215/03) (3)
|
||||
- GetPersonalMessage (F215/05) (1)
|
||||
- LogNetworkMessage (F215/0D) (2)
|
||||
- OpenMessagePipe (F215/06) (1)
|
||||
- SendPersonalMessage (F215/04) (1)
|
||||
|
||||
Notes:
|
||||
(1) These calls are NOT supported by Netware 386 versions shipped after
|
||||
December 1990, because they use pipe mechanisms, which cause a
|
||||
considerable deal of server overhead.
|
||||
These functions are not implemented in this unit.
|
||||
Use IPX/SPX peer-to-peer communication instead (nwIPX,nwSPX,nwPEP).
|
||||
(2) Network msg file no longer supported by 3.x
|
||||
(3) Not supported by Netware 3.x. Use SetBroadcastMode instead.
|
||||
}
|
||||
|
||||
Var result:word;
|
||||
|
||||
{F215/09 [2.15c+]}
|
||||
Function BroadcastToConsole(message:string):boolean;
|
||||
{ broadcast a message to the file server console. }
|
||||
|
||||
{F215/01 [2.15c+]}
|
||||
Function GetBroadcastMessage(var bmessage: string):boolean;
|
||||
{ Reads a broadcast message strored at server }
|
||||
|
||||
{DE..(..04) [1.x/2.x/ 3.x]}
|
||||
Function GetBroadcastMode(var bmode:byte):boolean;
|
||||
{ Returns the message mode. }
|
||||
|
||||
{F215/00 [2.15c+]}
|
||||
Function SendBroadcastMessage( message:string;
|
||||
connCount:byte;
|
||||
connList:TconnectionList;
|
||||
VAR resultlist:TconnectionList ):boolean;
|
||||
{ Sends a broadcast message to a number of logical connections. }
|
||||
|
||||
{DE..(..0n) n=0,1,2,3 [1.x/2.x/3.x]}
|
||||
Function SetBroadcastMode(bmode:byte):boolean;
|
||||
|
||||
{F217/D1 [2.15c+]}
|
||||
Function SendConsoleBroadcast(message:string; connCount:byte;
|
||||
connList:TconnectionList ):boolean;
|
||||
{ Sends a message to a number of connections, as if the message was send
|
||||
by a console broadcast command. Console oprator privileges required. }
|
||||
|
||||
{--------------------Secondary Functions-------------------------------}
|
||||
|
||||
Procedure SendMessageToUser(UserName,Message:String);
|
||||
{ sends a message to a (group of) users.
|
||||
The username may contain wildcards (* and ?).
|
||||
The message will not be received by stations whose status is CASTOFF.}
|
||||
|
||||
|
||||
IMPLEMENTATION {============================================================}
|
||||
|
||||
USES nwConn;
|
||||
|
||||
{DE..(..04) [1.x/2.x/ 3.x]}
|
||||
Function GetBroadcastMode(var bmode:byte):boolean;
|
||||
{ Returns the message mode.
|
||||
|
||||
00 Server Stores : Netware Messages and User Messages,
|
||||
Shell automaticly displays messages.
|
||||
01 Server Stores : Server Messages. (User messages discarded)
|
||||
Shell automaticly displays messages.
|
||||
02 Server stores : Server messages only.
|
||||
Applications have to use GetBroadCastMessage to see if there is a message.
|
||||
03 Server stores : Server messages and User messages.
|
||||
Applications have to use GetBroadCastMessage to see if there is a message. }
|
||||
var regs : TTregisters;
|
||||
begin
|
||||
regs.ah := $de;
|
||||
regs.dl := $04;
|
||||
RealModeIntr($21,regs);
|
||||
bmode := regs.al;
|
||||
result:=$00; { the call has no return codes }
|
||||
GetBroadCastMode:=True;
|
||||
end;
|
||||
|
||||
|
||||
{DE..(..0n) n=0,1,2,3 [1.x/2.x/3.x]}
|
||||
Function SetBroadcastMode(bmode:byte):boolean;
|
||||
{ Sets the new message mode.
|
||||
|
||||
possible resultcode: $FF ( illegal broadcastmode supplied or
|
||||
the broadcastmode after the call is not equal
|
||||
to the intended broadcast mode )
|
||||
|
||||
00 Server Stores : Netware Messages and User Messages,
|
||||
Shell automaticly displays messages.
|
||||
01 Server Stores : Server Messages. (User messages discarded)
|
||||
Shell automaticly displays messages.
|
||||
02 Server stores : Server messages only.
|
||||
Applications have to use GetBroadCastMessage to see if there is a message.
|
||||
03 Server stores : Server messages and User messages.
|
||||
Applications have to use GetBroadCastMessage to see if there is a message. }
|
||||
var regs : TTregisters;
|
||||
begin
|
||||
if (bmode <4)
|
||||
then begin
|
||||
regs.ah := $de;
|
||||
regs.dl := bmode;
|
||||
RealModeIntr($21,regs);
|
||||
if regs.al<>bmode { if confirmation of new mode unequal desired mode }
|
||||
then result:=$FF
|
||||
else result:=$00;
|
||||
end
|
||||
else result:=$FF;
|
||||
SetBroadcastMode:=(result=0);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{F215/01 [2.15c+]}
|
||||
Function GetBroadcastMessage(var bmessage: string):boolean;
|
||||
{ An application should poll this to see if there is a broadcastmessage
|
||||
stored (for this workstation) at the default server.
|
||||
The message mode must be 2 or 3. (No Notification by Shell)
|
||||
If no message was stored at the server, or the message was empty,
|
||||
this function will return FALSE and an errorcode of $103. }
|
||||
Type Treq=record
|
||||
len :word;
|
||||
subF :byte;
|
||||
end;
|
||||
Trep=record
|
||||
_message:string[55];
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
BEGIN
|
||||
With TPreq(GlobalreqBuf)^
|
||||
do begin
|
||||
subF:=$01;
|
||||
len:=1;
|
||||
end;
|
||||
F2SystemCall($15,sizeOf(Treq),sizeOf(Trep),result);
|
||||
If result=0
|
||||
then bmessage:=TPrep(GlobalReplyBuf)^._message;
|
||||
|
||||
if bmessage[0]=#0 then result:=$103; { whups! empty message }
|
||||
|
||||
GetBroadCastMessage:=(result=0);
|
||||
{ returncodes:
|
||||
00 Successful; FC Message Queue Full;
|
||||
FE I/O failure: Lack of dynamic workspace.
|
||||
103 No msgs stored at server. }
|
||||
end;
|
||||
|
||||
|
||||
{F215/00 [2.15c+]}
|
||||
Function SendBroadcastMessage( message:string;
|
||||
connCount:byte;
|
||||
connList:TconnectionList;
|
||||
VAR resultlist:TconnectionList ):boolean;
|
||||
{ Sends a broadcast message to a number of logical connections.
|
||||
The connectionlist is an array[1..connCount] of logical connection numbers,
|
||||
the result of the broadcast can be found in the resultList parameter.
|
||||
example:
|
||||
connCount=5
|
||||
connList= [ 4,9,1,5,2 ]
|
||||
|
||||
resultList= [$00, $00, $FC, $FD, $FF]
|
||||
|
||||
possible codes in resultList:
|
||||
$00: broadcast to this logical connnection was successful.
|
||||
$FC: message rejected, buffer for this station already contains a message,
|
||||
$FD: invalid connection number
|
||||
$FF: The target connection has blocked incoming messages,
|
||||
or the target connection is not in use. }
|
||||
Type Treq=record
|
||||
len :word;
|
||||
subF :byte;
|
||||
_connCount :byte;
|
||||
connLandMessage:array[1..306] of byte; { 250 conn, 56 msg }
|
||||
end;
|
||||
Trep=record
|
||||
connCount:byte;
|
||||
_ResultList:TconnectionList;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
Var t:byte;
|
||||
BEGIN
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
subF:=$00;
|
||||
_connCount:=connCount;
|
||||
move(connList[1],connLandMessage[1],connCount);
|
||||
t:=ord(message[0]); if t>55 then t:=55;
|
||||
move(message[0],connLandMessage[connCount+1],t+1);
|
||||
len:=3+connCount+t; { 2 bytes + [connList] + len(str) + str[0] }
|
||||
end;
|
||||
F2SystemCall($15,sizeOf(Treq),sizeOf(Trep),result);
|
||||
If result=0
|
||||
then with TPrep(GlobalReplyBuf)^
|
||||
do resultList:=_resultlist;
|
||||
SendBroadcastMessage:=(result=0);
|
||||
end;
|
||||
|
||||
|
||||
{F215/09 [2.15c+]}
|
||||
Function BroadcastToConsole(message:string):boolean;
|
||||
{ broadcast a message to the file server console.
|
||||
The message (max 60 chars, in ascii range [$20..$7E]) will be displayed
|
||||
at the bottom of the console screen.
|
||||
This function truncates the messagelength to 60 and repaces illegal
|
||||
characters with a . }
|
||||
Type Treq=record
|
||||
len :word;
|
||||
subF :byte;
|
||||
_message :string;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
Var t:byte;
|
||||
BEGIN
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
subF:=$09;
|
||||
PstrCopy(_message,message,60);
|
||||
for t:=1 to 60
|
||||
do if (_message[t]<>#$0) and
|
||||
((_message[t]<#$20) or (_message[t]>#$7E))
|
||||
then _message[t]:='.';
|
||||
len:=62;
|
||||
end;
|
||||
F2SystemCall($15,sizeOf(Treq),0,result);
|
||||
BroadcastToConsole:=(result=0);
|
||||
{ resultcodes: 00 success ; $FC message queue full ;
|
||||
$FE I/O failure: lack of dynamic workspace }
|
||||
end;
|
||||
|
||||
|
||||
{F217/D1 [2.15c+]}
|
||||
Function SendConsoleBroadcast(message:string; connCount:byte;
|
||||
connList:TconnectionList ):boolean;
|
||||
{Sends a message to a number of connections, as if the message was send
|
||||
by a console oprator. Console operator privileges required.
|
||||
If connCount equals 0, then the message is send to all connections. }
|
||||
Type Treq=record
|
||||
len :word;
|
||||
subF :byte;
|
||||
_ConnCount:byte;
|
||||
_connAndMess:array[1..306] of byte;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
Var t:byte;
|
||||
BEGIN
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
subF:=$D1;
|
||||
_connCount:=connCount;
|
||||
Move(connList[1],_connAndMess[1],connCount);
|
||||
t:=ord(message[0]); if t>55 then t:=55;
|
||||
{!! to do: strip hi-bit of message.. }
|
||||
Move(message[0],_connAndMess[connCount+1],t+1);
|
||||
len:=t+connCount+3;
|
||||
end;
|
||||
F2SystemCall($17,sizeOf(Treq),0,result);
|
||||
SendConsoleBroadcast:=(result=0);
|
||||
{Resultcodes: $00 success; $C6 No Console Rights}
|
||||
end;
|
||||
|
||||
{=================== Secondary Functions ===================================}
|
||||
|
||||
Procedure SendMessageToUser(UserName,Message:String);
|
||||
{ sends a message to a (group of) users.
|
||||
The username may contain wildcards (* and ?).
|
||||
The message will not be received by stations whose status is CASTOFF.}
|
||||
{ calls nwConn.getObjectConnectionNumber and nwMess.SendBroadcastMessage }
|
||||
Var NbrOfConn:byte;
|
||||
connList,ResultList:TconnectionList;
|
||||
begin
|
||||
IF NwConn.GetObjectConnectionNumbers(UserName,1 {OT_USER},NbrOfConn,connList)
|
||||
AND (NbrOfConn>0)
|
||||
then SendBroadcastMessage(Message,NbrOfConn,connList,ResultList);
|
||||
end;
|
||||
|
||||
|
||||
end. {unit nwMess}
|
||||
961
NWTP/NWMISC.PAS
Normal file
961
NWTP/NWMISC.PAS
Normal file
@@ -0,0 +1,961 @@
|
||||
{$X+,B-,V-,R-,S-} { essential compiler directives }
|
||||
|
||||
UNIT NWMISC;
|
||||
|
||||
{ nwMisc unit as of 950301 / NwTP 0.6 API. (c) 1993,1995 R.Spronk }
|
||||
{ Includes a bugfix of the EncryptPassword function by Horst Jelonneck }
|
||||
|
||||
INTERFACE
|
||||
|
||||
uses nwIntr;
|
||||
|
||||
{ Miscellaneous Functions: Comments:
|
||||
|
||||
Diagnostic Functions:
|
||||
|
||||
* IsV3Supported
|
||||
* GetNWversion
|
||||
|
||||
Novell types comparison functions:
|
||||
|
||||
* IsLowerNetworkAddress
|
||||
* IsEqualNetworkAddress
|
||||
* IsLaterNovTime
|
||||
* IsEqualNovTime
|
||||
|
||||
Password Encryption Functions:
|
||||
|
||||
* EncryptPassword (1)
|
||||
* EncryptPasswordDifference (1)
|
||||
|
||||
Conversion Functions:
|
||||
|
||||
* UpString (2)
|
||||
* HexStr
|
||||
* HexDumpStr
|
||||
* PStrCopy
|
||||
* ZStrCopy
|
||||
* LoNibble
|
||||
* HiNibble
|
||||
* Lswap
|
||||
* HiLong
|
||||
* LowLong
|
||||
* MakeLong
|
||||
* NovTime2String
|
||||
* DosTime2NovTime
|
||||
* NovTime2DosTime
|
||||
* NovPath2DosPath
|
||||
DosPath2NovPath
|
||||
. MapV2RightsToV3
|
||||
. MapV3RightsToV2
|
||||
|
||||
Notes: (1)-Encrypt3 and associated tables adapted from a c source
|
||||
(NVPW.C) by Willem Jan Hengeveld, A.K.A. Itsme@Hacktic.nl
|
||||
-Source of the encryption routine: LOGON.PAS by Barry Nance,
|
||||
[1:141/209] BYTE March'93
|
||||
(2) Fast upcasestring by Bob Swart.
|
||||
}
|
||||
|
||||
|
||||
Type TnovTime=record
|
||||
year,month,day,hour,min,sec,DayOfWeek:byte; { 0=sunday }
|
||||
end;
|
||||
TconnectionList=array[1..250] of byte;
|
||||
|
||||
TencryptionKey=array[0..7] of byte;
|
||||
TencrPWdifference=array[0..15] of byte;
|
||||
|
||||
|
||||
TnetworkAddress=array[1..4] of byte; { hi-endian }
|
||||
TnodeAddress =array[1..6] of byte; { Hi-endian }
|
||||
TinterNetworkAddress=record
|
||||
net :TnetworkAddress; {hi-lo}
|
||||
node :Tnodeaddress; {hi-lo}
|
||||
socket:word; {lo-hi}
|
||||
end;
|
||||
|
||||
Function IsV3Supported:Boolean;
|
||||
|
||||
Procedure NovTime2String(tim:TnovTime;Var DateStr:string);
|
||||
{ Puts the time/date information of a NovTime into a string.
|
||||
output format: 'DOW, dd mmm yyyy hh:mm:ss' DOW= day of the week. }
|
||||
|
||||
Procedure DosTime2NovTime(dt:Longint;Var nt:TnovTime);
|
||||
{ Converts a compact DOS time record (4 bytes) into a Tnovtime record }
|
||||
|
||||
Procedure NovTime2DosTime(nt:TnovTime;Var dt:Longint);
|
||||
|
||||
Procedure NovPath2DosPath(np:String;Var dp:string);
|
||||
{ Converts Novell type path into a DOS path of type
|
||||
Subdir1\Subdir2\.. \subDirN }
|
||||
|
||||
{============================level 0 support functions=======================}
|
||||
|
||||
Procedure UpString(s:string);
|
||||
{ Converts s to upperstring. Assembler, so it's realy a Var parameter. }
|
||||
|
||||
Function HexStr(dw:LongInt;len:byte):string;
|
||||
{ Converts dw into a hex-string of length len. }
|
||||
|
||||
Function HexDumpStr(Var dumpVar;len:Byte):String;
|
||||
{ Converts dumpVar into a hex-string of length len.
|
||||
Basically the same as HexStr, but accepts variables only.
|
||||
(Mostly used to dump an array of byte) }
|
||||
|
||||
procedure PStrCopy(Var dest:String;source:String;len:byte);
|
||||
{ if length(source)>len
|
||||
then Copy len bytes from source to dest.
|
||||
else Copy source to dest and fill out with NULLs.
|
||||
Length(Dest) will allways be set to len. }
|
||||
|
||||
procedure ZStrCopy(dest:String;VAR source;len:byte);
|
||||
{ 1. Copies len bytes form an array to a pascal type string. }
|
||||
{ 2. Trailing NULLs are removed from the string. }
|
||||
{ consequently, the length of dest (dest[0]) will allways be <= len. }
|
||||
{ -SOURCE is an array of byte: array[ ] of byte; }
|
||||
|
||||
Function IsLowerNetworkAddress(Var a, b): Boolean;
|
||||
{ Compare two net&node addresses.
|
||||
a and b should be of type TinternetworkAddress }
|
||||
|
||||
Function IsEqualNetworkAddress(Var a, b): Boolean;
|
||||
{ Compare two net&node addresses.
|
||||
a and b should be of type TinternetworkAddress }
|
||||
|
||||
Function IsLaterNovTime(time1,time2:TnovTime):boolean;
|
||||
|
||||
Function IsEqualNovTime(time1,time2:TnovTime):boolean;
|
||||
|
||||
Function MapV2RightsToV3(V2Rights:byte):word;
|
||||
|
||||
Function MapV3RightsToV2(V3Rights:Word):Byte;
|
||||
|
||||
Procedure GetNWversion(Var version:word);
|
||||
{ determine the version of software installed on the current file server. }
|
||||
{ see GetFileServerInformation F217/11 for more information }
|
||||
{ Version: MajorVersion * 100 + MinorVersion; e.g. 311 for 3.11 }
|
||||
|
||||
Procedure EncryptPassword(objId:longint;password:string;
|
||||
{i/o} Var Ekey:TencryptionKey);
|
||||
{ called by LoginToFileServer (unit nwConn),
|
||||
and by VerifyBinderyObjectPassword, ChangeBinderyObjectPassword (nwBindry) }
|
||||
{ Source of the encryption routine: LOGON.PAS by Barry Nance, [1:141/209]
|
||||
BYTE March'93 }
|
||||
|
||||
|
||||
Procedure EncryptPasswordDifference(objId:Longint;
|
||||
OldPassword,NewPassword:string;
|
||||
Var key:TencryptionKey;
|
||||
Var PWdif:TencrPWdifference;
|
||||
Var PWdifChecksum:byte
|
||||
);
|
||||
|
||||
|
||||
Function LoNibble(b:Byte):Byte;
|
||||
{ Returns the low nibble of the argument (in low nibble position),
|
||||
with high nibble set to 0000 }
|
||||
Function HiNibble(b:Byte):Byte;
|
||||
{ Returns the high nibble of the argument (in low nibble position),
|
||||
with high nibble set to 0000 }
|
||||
|
||||
|
||||
Function Lswap(l:Longint):Longint;
|
||||
{ swaps bytes in a longInt; ( reverse byte order ) }
|
||||
Inline(
|
||||
$5A/ {pop DX ; low word of long }
|
||||
$58/ {pop AX ; hi word of long }
|
||||
|
||||
$86/$F2/ {xchg dl,dh ; swap bytes }
|
||||
$86/$E0); {xchg al,ah ; swap bytes }
|
||||
|
||||
function HiLong(Long : LongInt) : Word;
|
||||
{ This inline directive is similar to Turbo's Hi() function, except }
|
||||
{ it returns the high word of a LongInt }
|
||||
Inline(
|
||||
$5A/ {pop dx ; low word of long }
|
||||
$58); {pop ax ; hi word of long }
|
||||
|
||||
function LowLong(Long : LongInt) : Word;
|
||||
{ This inline directive is similar to Turbo's Lo() function, except }
|
||||
{ it returns the Low word of a LongInt }
|
||||
Inline(
|
||||
$5A/ {pop dx ; low word of long }
|
||||
$58/ {pop ax ; hi word of long }
|
||||
$89/$D0); {mov ax,dx ; return lo word as func. result in Ax }
|
||||
|
||||
function MakeLong(HiWord,LoWord : Word) : LongInt;
|
||||
{ Takes hi and lo words and makes a longint }
|
||||
Inline(
|
||||
$58/ { pop ax ; pop low word into AX }
|
||||
$5A); { pop dx ; pop high word into DX }
|
||||
|
||||
|
||||
CONST
|
||||
{** ERRORS DEFINED BY NWxxx UNITS *******}
|
||||
|
||||
{** STANDARD ERRORS AS USED BY NETWARE **}
|
||||
HARDWARE_FAILURE = 255;
|
||||
INVALID_INITIAL_SEMAPHORE_VALUE = 255; {nwSema}
|
||||
INVALID_SEMAPHORE_HANDLE = 255; {nwSema}
|
||||
BAD_PRINTER_ERROR = 255;
|
||||
QUEUE_FULL_ERROR = 255;
|
||||
NO_FILES_FOUND_ERROR = 255;
|
||||
BAD_RECORD_OFFSET = 255;
|
||||
PATH_NOT_LOCATABLE = 255;
|
||||
SOCKET_ALREADY_OPEN = 255;
|
||||
INVALID_DRIVE_NUMBER = 255; {nwDir}
|
||||
NO_RECORD_FOUND = 255;
|
||||
NO_RESPONSE_FROM_SERVER = 255;
|
||||
REQUEST_NOT_OUTSTANDING = 255;
|
||||
NO_SUCH_OBJECT_OR_BAD_PASSWORD = 255;
|
||||
CLOSE_FCB_ERROR = 255;
|
||||
FILE_EXTENSION_ERROR = 255;
|
||||
FILE_NAME_ERROR = 255;
|
||||
IO_BOUND_ERROR = 255;
|
||||
SPX_IS_INSTALLED = 255; {nwIpx}
|
||||
SPX_SOCKET_NOT_OPENED = 255; {nwIpx}
|
||||
EXPLICIT_TRANSACTION_ACTIVE = 255; {nwTTS}
|
||||
NO_EXPLICIT_TRANSACTION_ACTIVE = 255; {nwTTS}
|
||||
TRANSACTION_NOT_YET_WRITTEN = 255; {nwTTS}
|
||||
NO_MORE_MATCHING_FILES = 255; {nwTTS}
|
||||
BINDERY_FAILURE = 255;
|
||||
OPEN_FILES = 255; {3.x}
|
||||
PRINT_JOB_ALREADY_QUEUED = 255; {3.x}
|
||||
PRINT_JOB_ALREADY_SET = 255; {3.x}
|
||||
SUPERVISOR_HAS_DISABLED_LOGIN = 254; {nwConn}
|
||||
TIMEOUT_FAILURE = 254;
|
||||
BINDERY_LOCKED = 254; {nwBindry}
|
||||
SERVER_BINDERY_LOCKED = 254;
|
||||
INVALID_SEMAPHORE_NAME_LENGTH = 254; {nwSema}
|
||||
PACKET_NOT_DELIVERABLE = 254;
|
||||
SOCKET_TABLE_FULL = 254;
|
||||
DIRECTORY_LOCKED = 254;
|
||||
SPOOL_DIRECTORY_ERROR = 254;
|
||||
IMPLICIT_TRANSACTION_ACTIVE = 254; {nwTTS}
|
||||
TRANSACTION_ENDS_RECORD_LOCK = 254; {nwTTS}
|
||||
IO_FAILURE = 254; {3.x}
|
||||
UNKNOWN_REQUEST = 253;
|
||||
INVALID_PACKET_LENGTH = 253;
|
||||
FIELD_ALREADY_LOCKED = 253;
|
||||
BAD_STATION_NUMBER = 253;
|
||||
SPX_MALFORMED_PACKET = 253;
|
||||
SPX_PACKET_OVERFLOW = 253;
|
||||
TTS_DISABLED = 253;
|
||||
NO_SUCH_OBJECT = 252;
|
||||
UNKNOWN_FILE_SERVER = 252;
|
||||
INTERNET_PACKET_REQT_CANCELED = 252;
|
||||
MESSAGE_QUEUE_FULL = 252; {nwMess}
|
||||
SPX_LISTEN_CANCELED = 252;
|
||||
NO_SUCH_PROPERTY = 251;
|
||||
INVALID_PARAMETERS = 251;
|
||||
{UNKNOWN_REQUEST = 251; ?double see 253}
|
||||
NO_MORE_SERVER_SLOTS = 250;
|
||||
TEMP_REMAP_ERROR = 250;
|
||||
NO_PROPERTY_READ_PRIVILEGE = 249;
|
||||
NO_FREE_CONNECTION_SLOTS = 249;
|
||||
NO_PROPERTY_WRITE_PRIVILEGE = 248;
|
||||
ALREADY_ATTACHED_TO_SERVER = 248;
|
||||
NOT_ATTACHED_TO_SERVER = 248;
|
||||
NO_PROPERTY_CREATE_PRIVILEGE = 247;
|
||||
TARGET_DRIVE_NOT_LOCAL = 247;
|
||||
NO_PROPERTY_DELETE_PRIVILEGE = 246;
|
||||
NOT_SAME_LOCAL_DRIVE = 246;
|
||||
NO_OBJECT_CREATE_PRIVILEGE = 245;
|
||||
NO_OBJECT_DELETE_PRIVILEGE = 244;
|
||||
NO_OBJECT_RENAME_PRIVILEGE = 243;
|
||||
NO_OBJECT_READ_PRIVILEGE = 242;
|
||||
INVALID_BINDERY_SECURITY = 241;
|
||||
WILD_CARD_NOT_ALLOWED = 240;
|
||||
IPX_NOT_INSTALLED = 240; {nwIpx}
|
||||
INVALID_NAME = 239;
|
||||
SPX_CONNECTION_TABLE_FULL = 239;
|
||||
OBJECT_ALREADY_EXISTS = 238;
|
||||
SPX_INVALID_CONNECTION = 238;
|
||||
PROPERTY_ALREADY_EXISTS = 237;
|
||||
SPX_NO_ANSWER_FROM_TARGET = 237;
|
||||
SPX_CONNECTION_FAILED = 237;
|
||||
SPX_CONNECTION_TERMINATED = 237;
|
||||
NO_SUCH_SEGMENT = 236;
|
||||
SPX_TERMINATED_POORLY = 236;
|
||||
NOT_GROUP_PROPERTY = 235;
|
||||
NO_SUCH_MEMBER = 234;
|
||||
MEMBER_ALREADY_EXISTS = 233;
|
||||
NOT_ITEM_PROPERTY = 232;
|
||||
WRITE_PROPERTY_TO_GROUP = 232;
|
||||
PASSWORD_HAS_EXPIRED = 223;
|
||||
PASSWORD_HAS_EXPIRED_NO_GRACE = 222;
|
||||
ACCOUNT_DISABLED = 220;
|
||||
UNAUTHORIZED_LOGIN_STATION = 219;
|
||||
MAX_Q_SERVERS = 219;
|
||||
UNAUTHORIZED_LOGIN_TIME = 218;
|
||||
Q_HALTED = 218;
|
||||
LOGIN_DENIED_NO_CONNECTION = 217;
|
||||
STN_NOT_SERVER = 217;
|
||||
PASSWORD_TOO_SHORT = 216;
|
||||
Q_NOT_ACTIVE = 216;
|
||||
PASSWORD_NOT_UNIQUE = 215;
|
||||
Q_SERVICING = 215;
|
||||
NO_JOB_RIGHTS = 214;
|
||||
NO_Q_JOB = 213;
|
||||
Q_FULL = 212;
|
||||
NO_Q_RIGHTS = 211;
|
||||
NO_Q_SERVER = 210;
|
||||
NO_QUEUE = 209;
|
||||
Q_ERROR = 208;
|
||||
NOT_CONSOLE_OPERATOR = 198;
|
||||
INTRUDER_DETECTION_LOCK = 197;
|
||||
ACCOUNT_TOO_MANY_HOLDS = 195;
|
||||
CREDIT_LIMIT_EXCEEDED = 194;
|
||||
NO_ACCOUNT_BALANCE = 193;
|
||||
NO_ACCOUNT_PRIVILEGES = 192;
|
||||
READ_FILE_WITH_RECORD_LOCKED = 162;
|
||||
DIRECTORY_IO_ERROR = 161;
|
||||
DIRECTORY_NOT_EMPTY = 160;
|
||||
DIRECTORY_ACTIVE = 159;
|
||||
INVALID_FILENAME = 158;
|
||||
NO_MORE_DIRECTORY_HANDLES = 157;
|
||||
NO_MORE_TRUSTEES = 156;
|
||||
INVALID_PATH = 156;
|
||||
BAD_DIRECTORY_HANDLE = 155;
|
||||
RENAMING_ACROSS_VOLUMES = 154;
|
||||
DIRECTORY_FULL = 153;
|
||||
VOLUME_DOES_NOT_EXIST = 152;
|
||||
NO_DISK_SPACE_FOR_SPOOL_FILE = 151;
|
||||
SERVER_OUT_OF_MEMORY = 150;
|
||||
OUT_OF_DYNAMIC_WORKSPACE = 150;
|
||||
FILE_DETACHED = 149;
|
||||
NO_WRITE_PRIVILEGES = 148;
|
||||
READ_ONLY = 148;
|
||||
NO_READ_PRIVILEGES = 147;
|
||||
NO_FILES_RENAMED_NAME_EXISTS = 146;
|
||||
SOME_FILES_RENAMED_NAME_EXISTS = 145;
|
||||
NO_FILES_AFFECTED_READ_ONLY = 144;
|
||||
SOME_FILES_AFFECTED_READ_ONLY = 143;
|
||||
NO_FILES_AFFECTED_IN_USE = 142;
|
||||
SOME_FILES_AFFECTED_IN_USE = 141;
|
||||
NO_MODIFY_PRIVILEGES = 140;
|
||||
NO_RENAME_PRIVILEGES = 139;
|
||||
NO_DELETE_PRIVILEGES = 138;
|
||||
NO_SEARCH_PRIVILEGES = 137;
|
||||
INVALID_FILE_HANDLE = 136;
|
||||
WILD_CARDS_IN_CREATE_FILENAME = 135;
|
||||
CREATE_FILE_EXISTS_READ_ONLY = 134;
|
||||
NO_CREATE_DELETE_PRIVILEGES = 133;
|
||||
NO_CREATE_PRIVILEGES = 132;
|
||||
IO_ERROR_NETWORK_DISK = 131;
|
||||
NO_OPEN_PRIVILEGES = 130;
|
||||
NO_MORE_FILE_HANDLES = 129;
|
||||
FILE_IN_USE_ERROR = 128;
|
||||
DOS_LOCK_VIOLATION = 33;
|
||||
DOS_SHARING_VIOLATION = 32;
|
||||
DOS_NO_MORE_FILES = 31;
|
||||
DOS_NOT_SAME_DEVICE = 30;
|
||||
DOS_ATTEMPT_TO_DEL_CURRENT_DIR = 16;
|
||||
DOS_INVALID_DRIVE = 15;
|
||||
DOS_INVALID_DATA = 13;
|
||||
DOS_INVALID_ACCESS_CODE = 12;
|
||||
DOS_INVALID_FORMAT = 11;
|
||||
DOS_INVALID_ENVIRONMENT = 10;
|
||||
DOS_INVALID_MEMORY_BLOCK_ADDR = 9;
|
||||
DOS_INSUFFICIENT_MEMORY = 8;
|
||||
DOS_MEMORY_BLOCKS_DESTROYED = 7;
|
||||
DOS_INVALID_FILE_HANDLE = 6;
|
||||
DOS_ACCESS_DENIED = 5;
|
||||
DOS_TOO_MANY_OPEN_FILES = 4;
|
||||
DOS_PATH_NOT_FOUND = 3;
|
||||
DOS_FILE_NOT_FOUND = 2;
|
||||
TTS_AVAILABLE = 1;
|
||||
SERVER_IN_USE = 1;
|
||||
SEMAPHORE_OVERFLOW = 1;
|
||||
DOS_INVALID_FUNCTION_NUMBER = 1;
|
||||
TTS_NOT_AVAILABLE = 1;
|
||||
SERVER_NOT_IN_USE = 1;
|
||||
|
||||
IMPLEMENTATION{=============================================================}
|
||||
|
||||
|
||||
|
||||
{----------------------- Encryption tables and procedures --------------}
|
||||
|
||||
TYPE
|
||||
Buf32 = ARRAY [0..31] OF Byte;
|
||||
Buf16 = ARRAY [0..15] OF Byte;
|
||||
Buf8 = ARRAY [0..7] OF Byte;
|
||||
Buf4 = ARRAY [0..3] OF Byte;
|
||||
|
||||
|
||||
CONST
|
||||
EncryptTable : ARRAY [0..255] OF Byte =
|
||||
($7,$8,$0,$8,$6,$4,$E,$4,$5,$C,$1,$7,$B,$F,$A,$8,
|
||||
$F,$8,$C,$C,$9,$4,$1,$E,$4,$6,$2,$4,$0,$A,$B,$9,
|
||||
$2,$F,$B,$1,$D,$2,$1,$9,$5,$E,$7,$0,$0,$2,$6,$6,
|
||||
$0,$7,$3,$8,$2,$9,$3,$F,$7,$F,$C,$F,$6,$4,$A,$0,
|
||||
$2,$3,$A,$B,$D,$8,$3,$A,$1,$7,$C,$F,$1,$8,$9,$D,
|
||||
$9,$1,$9,$4,$E,$4,$C,$5,$5,$C,$8,$B,$2,$3,$9,$E,
|
||||
$7,$7,$6,$9,$E,$F,$C,$8,$D,$1,$A,$6,$E,$D,$0,$7,
|
||||
$7,$A,$0,$1,$F,$5,$4,$B,$7,$B,$E,$C,$9,$5,$D,$1,
|
||||
$B,$D,$1,$3,$5,$D,$E,$6,$3,$0,$B,$B,$F,$3,$6,$4,
|
||||
$9,$D,$A,$3,$1,$4,$9,$4,$8,$3,$B,$E,$5,$0,$5,$2,
|
||||
$C,$B,$D,$5,$D,$5,$D,$2,$D,$9,$A,$C,$A,$0,$B,$3,
|
||||
$5,$3,$6,$9,$5,$1,$E,$E,$0,$E,$8,$2,$D,$2,$2,$0,
|
||||
$4,$F,$8,$5,$9,$6,$8,$6,$B,$A,$B,$F,$0,$7,$2,$8,
|
||||
$C,$7,$3,$A,$1,$4,$2,$5,$F,$7,$A,$C,$E,$5,$9,$3,
|
||||
$E,$7,$1,$2,$E,$1,$F,$4,$A,$6,$C,$6,$F,$4,$3,$0,
|
||||
$C,$0,$3,$6,$F,$8,$7,$B,$2,$D,$C,$6,$A,$A,$8,$D);
|
||||
|
||||
EncryptKeys : Array[0..31] of byte =
|
||||
($48,$93,$46,$67,$98,$3D,$E6,$8D,$B7,$10,$7A,$26,$5A,$B9,$B1,$35,
|
||||
$6B,$0F,$D5,$70,$AE,$FB,$AD,$11,$F4,$47,$DC,$A7,$EC,$CF,$50,$C0);
|
||||
|
||||
EncryptTable1:array [0..7,0..1,0..15] OF byte= { used by encrypt3 }
|
||||
{ 0 1 2 3 4 5 6 7 8 9 a b c d e f }
|
||||
((( $F,$8,$5,$7,$C,$2,$E,$9,$0,$1,$6,$D,$3,$4,$B,$A),
|
||||
( $2,$C,$E,$6,$F,$0,$1,$8,$D,$3,$A,$4,$9,$B,$5,$7)),
|
||||
(( $5,$2,$9,$F,$C,$4,$D,$0,$E,$A,$6,$8,$B,$1,$3,$7),
|
||||
( $F,$D,$2,$6,$7,$8,$5,$9,$0,$4,$C,$3,$1,$A,$B,$E)),
|
||||
(( $5,$E,$2,$B,$D,$A,$7,$0,$8,$6,$4,$1,$F,$C,$3,$9),
|
||||
( $8,$2,$F,$A,$5,$9,$6,$C,$0,$B,$1,$D,$7,$3,$4,$E)),
|
||||
(( $E,$8,$0,$9,$4,$B,$2,$7,$C,$3,$A,$5,$D,$1,$6,$F),
|
||||
( $1,$4,$8,$A,$D,$B,$7,$E,$5,$F,$3,$9,$0,$2,$6,$C)),
|
||||
(( $5,$3,$C,$8,$B,$2,$E,$A,$4,$1,$D,$0,$6,$7,$F,$9),
|
||||
( $6,$0,$B,$E,$D,$4,$C,$F,$7,$2,$8,$A,$1,$5,$3,$9)),
|
||||
(( $B,$5,$A,$E,$F,$1,$C,$0,$6,$4,$2,$9,$3,$D,$7,$8),
|
||||
( $7,$2,$A,$0,$E,$8,$F,$4,$C,$B,$9,$1,$5,$D,$3,$6)),
|
||||
(( $7,$4,$F,$9,$5,$1,$C,$B,$0,$3,$8,$E,$2,$A,$6,$D),
|
||||
( $9,$4,$8,$0,$A,$3,$1,$C,$5,$F,$7,$2,$B,$E,$6,$D)),
|
||||
(( $9,$5,$4,$7,$E,$8,$3,$1,$D,$B,$C,$2,$0,$F,$6,$A),
|
||||
( $9,$A,$B,$D,$5,$3,$F,$0,$1,$C,$8,$7,$6,$4,$E,$2))
|
||||
);
|
||||
|
||||
EncryptTable3:array[0..15] of byte= { used by encrypt3 }
|
||||
( $3,$E,$F,$2,$D,$C,$4,$5,$9,$6,$0,$1,$B,$7,$A,$8 );
|
||||
|
||||
|
||||
PROCEDURE Shuffle(VAR ShuffleKey, buf; buflen : Word; VAR target);
|
||||
{ UNIT INTERNAL PROCEDURE }
|
||||
{ id, password[1.. ],length(passw), OUT: buf }
|
||||
|
||||
PROCEDURE Shuffle1(VAR temp : Buf32; VAR target);
|
||||
VAR _target : Buf16 ABSOLUTE target;
|
||||
b4 : Word;
|
||||
b3 : Byte;
|
||||
d, k, i : Word;
|
||||
Begin
|
||||
|
||||
{** Step 4: .. }
|
||||
b4 := 0;
|
||||
FOR k := 0 TO 1
|
||||
DO Begin
|
||||
FOR i := 0 TO 31
|
||||
DO Begin
|
||||
b3 := Lo( Lo(temp[i] + b4) XOR
|
||||
Lo(temp[(i + b4) AND 31] - EncryptKeys[i]));
|
||||
b4 := b4 + b3;
|
||||
temp[i] := b3;
|
||||
End;
|
||||
End;
|
||||
|
||||
{*** Step 5:... }
|
||||
|
||||
FOR i := 0 TO 15
|
||||
DO _Target[i] := EncryptTable[temp[i Shl 1]] OR
|
||||
(EncryptTable[temp[i Shl 1 +1]] Shl 4);
|
||||
End;
|
||||
|
||||
VAR locShuffleKey : Buf4 ABSOLUTE ShuffleKey;
|
||||
localBuf : ARRAY [0..127] OF Byte ABSOLUTE buf;
|
||||
BufBytesUsed : Word;
|
||||
temp : Buf32;
|
||||
t, IndexOfBufBytes : Word;
|
||||
Begin
|
||||
{ strip trailing NULLs of the to-be-encoded buf,
|
||||
last element of buf must be a NULL ? }
|
||||
While (buflen > 0) AND (localBuf[buflen-1] = 0)
|
||||
DO buflen := buflen - 1;
|
||||
{ clear output of 1st shuffle }
|
||||
FillChar(temp, SizeOf(temp), #0);
|
||||
|
||||
{*** 1ST Step: XOR folding of first (32*(buflen DIV 32)) bytes. }
|
||||
|
||||
{ temp= buf[0..31] XOR buf[32..63] XOR buf[64..95] XOR etc.. }
|
||||
|
||||
{ IndexOfBufBytes is a multiple of 32, length password= IndexOfBufBytes + buflen }
|
||||
{ Temp varuable filled with XOR folding of the first IndexOfBufBytes bytes of the PW. }
|
||||
IndexOfBufBytes := 0;
|
||||
WHILE buflen >= 32
|
||||
DO Begin
|
||||
FOR t := 0 TO 31
|
||||
DO Begin
|
||||
temp[t] := temp[t] XOR localBuf[IndexOfBufBytes];
|
||||
IndexOfBufBytes := IndexOfBufBytes + 1;
|
||||
End;
|
||||
buflen := buflen - 32;
|
||||
End;
|
||||
|
||||
{*** 2ND step: repetitive XOR folding with (remainder of) password
|
||||
|
||||
password='hello', (BufBytesUsed=0)
|
||||
or password='12345678901234567890123456789012hello' (BufBytesUsed=32)
|
||||
of which the first 32 bytes were used in the 1st encryption step.
|
||||
|
||||
temp=temp XOR [hellohellohellohellohellohellohe];
|
||||
}
|
||||
BufBytesUsed:=IndexOfBufBytes;
|
||||
IF buflen > 0
|
||||
Then Begin
|
||||
FOR t := 0 TO 31
|
||||
DO Begin
|
||||
IF IndexOfBufBytes + buflen = BufBytesUsed
|
||||
Then Begin
|
||||
BufBytesUsed := IndexOfBufBytes;
|
||||
temp[t] := temp[t] XOR EncryptKeys[t];
|
||||
End
|
||||
Else Begin
|
||||
temp[t] := temp[t] XOR localBuf[BufBytesUsed];
|
||||
BufBytesUsed := BufBytesUsed + 1;
|
||||
End;
|
||||
End;
|
||||
End;
|
||||
{*** 3RD step: XOR-ing with shuffleKey (bytes of a longint)}
|
||||
|
||||
FOR t := 0 TO 31 DO temp[t] := temp[t] XOR locShuffleKey[t AND 3];
|
||||
|
||||
{*** 4&5 TH Step: see Shuffle1 }
|
||||
|
||||
Shuffle1(temp, target);
|
||||
End;
|
||||
|
||||
PROCEDURE Encrypt(VAR key, buf, EncrPassword);
|
||||
{ The encryptionKey 'key' is encrypted with the aid of
|
||||
the shuffled login name/id within 'buf'.
|
||||
Result: the encrypted Password (of type TencryptionKey). }
|
||||
VAR _Key : TencryptionKey ABSOLUTE Key;
|
||||
_EncrKey : TencryptionKey ABSOLUTE EncrPassword;
|
||||
_LocalBuf : Buf32;
|
||||
i: Byte;
|
||||
Begin
|
||||
Shuffle(_Key[0], buf, 16, _LocalBuf[0]);
|
||||
Shuffle(_Key[4], buf, 16, _LocalBuf[16]);
|
||||
FOR i := 0 TO 15 DO _LocalBuf[i] := _LocalBuf[i] XOR _LocalBuf[31-i];
|
||||
FOR i := 0 TO 7 DO _EncrKey[i] := _LocalBuf[i] XOR _LocalBuf[15-i];
|
||||
End;
|
||||
|
||||
Procedure EncryptPassword(objId:longint;password:string;Var Ekey:TencryptionKey);
|
||||
{ Source of the encryption routine: LOGON.PAS by Barry Nance, [1:141/209] BYTE March'93 }
|
||||
{ Two bugs fixed by Horst Jelonneck (930323) }
|
||||
Var buf:buf32;
|
||||
TobjId:Longint;
|
||||
Tpassword:string;
|
||||
|
||||
begin
|
||||
TobjId:=Lswap(objId);
|
||||
Tpassword:=password+#0;
|
||||
Shuffle(TObjId,Tpassword[1],length(password),buf);
|
||||
Encrypt(Ekey,buf,Ekey);
|
||||
end;
|
||||
|
||||
Procedure EncryptPasswordDifference(objId:Longint;
|
||||
OldPassword,NewPassword:string;
|
||||
Var key:TencryptionKey;
|
||||
Var PWdif:TencrPWdifference;
|
||||
Var PWdifChecksum:byte
|
||||
);
|
||||
{ Used by nwBindry.ChangeEncrBinderyObjectPassword.
|
||||
|
||||
Encrypt3 and associated tables adapted from a c source (NVPW.C)
|
||||
by Willem Jan Hengeveld, A.K.A. Itsme@Hacktic.nl }
|
||||
Procedure Encrypt3(Var buf1,buf2,buf3);
|
||||
{ buf1: (part of) encrypted oldPW
|
||||
buf2: (part of) encrypted newPW
|
||||
buf3: 'change pw' data (result) }
|
||||
Var p1:buf8 absolute buf1;
|
||||
p2:buf8 absolute buf2;
|
||||
p3:buf8 absolute buf3;
|
||||
j,c,i:byte;
|
||||
buf:buf8;
|
||||
begin
|
||||
buf:=p2;
|
||||
for i:=0 to 15
|
||||
do begin
|
||||
|
||||
for j:=0 to 7
|
||||
do begin
|
||||
c:=buf[j] XOR p1[j];
|
||||
buf[j]:=EncryptTable1[j][0][c AND $0F]
|
||||
OR (EncryptTable1[j][1][c SHR 4] SHL 4);
|
||||
end;
|
||||
|
||||
c:=p1[7];
|
||||
for j:=7 downto 1
|
||||
do p1[j]:=(p1[j] SHL 4) OR (p1[j-1] SHR 4);
|
||||
p1[0]:=(c SHR 4) OR (p1[0] SHL 4);
|
||||
|
||||
FillChar(p3,8,#$0);
|
||||
for j:=0 to 15
|
||||
do begin
|
||||
c:=EncryptTable3[j];
|
||||
If odd(EncryptTable3[j])
|
||||
then c:=buf[c DIV 2] SHR 4
|
||||
else c:=buf[c DIV 2] AND $0F;
|
||||
if Odd(j)
|
||||
then p3[j DIV 2]:=p3[j DIV 2] XOR (c SHL 4)
|
||||
else p3[j DIV 2]:=p3[j DIV 2] XOR c;
|
||||
end;
|
||||
|
||||
buf:=p3;
|
||||
end;
|
||||
end;
|
||||
Var l:byte;
|
||||
OldShuffledPW,NewShuffledPW:array[0..15] of byte;
|
||||
begin
|
||||
objId:=Lswap(objId);
|
||||
Shuffle(objId,OldPassword[1],Length(OldPassword),OldShuffledPW);
|
||||
Shuffle(objId,NewPassword[1],Length(NewPassword),NewShuffledPW);
|
||||
Encrypt(key,OldShuffledPW,key);
|
||||
|
||||
Encrypt3(OldShuffledPW,NewShuffledPW,PWdif);
|
||||
Encrypt3(OldShuffledPW[8],NewShuffledPW[8],PWdif[8]);
|
||||
if Length(NewPassword)<63
|
||||
then l:=length(NewPassword)
|
||||
else l:=63;
|
||||
PWdifChecksum:=(((l XOR OldShuffledPW[1] XOR OldShuffledPW[2]) AND $7F) OR $40);
|
||||
end;
|
||||
|
||||
|
||||
{-------------- End of encryption procedures ----------------------------}
|
||||
|
||||
Procedure UpString(s : String); Assembler;
|
||||
{ fast upcasestring by Bob Swart }
|
||||
ASM
|
||||
PUSH DS
|
||||
LDS SI, s
|
||||
LES DI, s
|
||||
CLD
|
||||
XOR AH, AH
|
||||
LODSB
|
||||
STOSB
|
||||
XCHG AX, CX { empty string? }
|
||||
JCXZ @2
|
||||
@1: LODSB
|
||||
SUB AL, 'a'
|
||||
CMP AL, 'z'-'a'+1
|
||||
SBB AH, AH
|
||||
AND AH, 'a'-'A'
|
||||
SUB AL, AH
|
||||
ADD AL, 'a'
|
||||
STOSB
|
||||
LOOP @1
|
||||
@2: POP DS
|
||||
end;
|
||||
|
||||
|
||||
procedure ZStrCopy(dest:String;Var source;len:byte); assembler;
|
||||
{ 1. Copies len bytes from an array to a pascal type string. }
|
||||
{ 2. Trailing NULLs are removed from the string. }
|
||||
{ consequently, the length of det (dest[0]) will allways be <= len. }
|
||||
asm
|
||||
mov dx,ds
|
||||
|
||||
les di,dest
|
||||
xor ch,ch
|
||||
mov [es:di],ch { dest[0]:=#0 }
|
||||
mov cl,len
|
||||
jcxz @4 { if len=0 then goto @4 }
|
||||
lds si,source
|
||||
@3: lodsb
|
||||
or al,al
|
||||
jz @2 { determine non-0 length of source }
|
||||
dec cx
|
||||
jnz @3
|
||||
@2: xor ax,ax
|
||||
mov al,len
|
||||
sub ax,cx { ax:= bytes to copy }
|
||||
|
||||
les di,dest
|
||||
lds si,source
|
||||
mov es:[di],al { dest[0]:=actual non-0 len }
|
||||
inc di { es:di => dest[1] ; ds:si => source[0] }
|
||||
|
||||
mov cx,ax
|
||||
cld
|
||||
rep movsb { copy cx bytes from ds:si to es:di }
|
||||
|
||||
@4: mov ds,dx
|
||||
end;
|
||||
|
||||
procedure PStrCopy(Var dest:String;source:String;len:byte);
|
||||
Var w:byte;
|
||||
begin
|
||||
w:=1;
|
||||
dest[0]:=chr(len);
|
||||
While w<=ord(source[0])
|
||||
do begin
|
||||
dest[w]:=source[w];
|
||||
inc(w)
|
||||
end;
|
||||
While w<=len
|
||||
do begin
|
||||
dest[w]:=#0;
|
||||
inc(w)
|
||||
end;
|
||||
end;
|
||||
|
||||
Procedure NovTime2String(tim:TnovTime;Var DateStr:string);
|
||||
CONST day:array[0..6] of string[3]
|
||||
=('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
|
||||
Month:array[1..12] of string[3]
|
||||
=('Jan','Feb','Mar','Apr','May','Jun',
|
||||
'Jul','Aug','Sep','Oct','Nov','Dec');
|
||||
Type string4=string[4];
|
||||
Var sday,syear,shour,smin,ssec:string4;
|
||||
Procedure zstr(n:byte;Var s:string4);
|
||||
begin
|
||||
str(n,s);
|
||||
if s[0]=#1 then s:='0'+s;
|
||||
end;
|
||||
begin
|
||||
if (tim.month>12) or (tim.month<1)
|
||||
or (tim.day<1) or (tim.day>31)
|
||||
or (tim.hour>23) or (tim.min>59) or (tim.sec>59)
|
||||
then DateStr:='<invalid date & time> '
|
||||
else begin
|
||||
zstr(tim.day,sday);
|
||||
if sday[1]='0' then sday[1]:=' ';
|
||||
if tim.year<80 then str(tim.year+2000,syear)
|
||||
else str(tim.year+1900,syear);
|
||||
zstr(tim.hour,shour);
|
||||
zstr(tim.min,smin);
|
||||
zstr(tim.sec,ssec);
|
||||
DateStr:=day[tim.DayOfWeek]+', '+
|
||||
sday+' '+Month[tim.month]+' '+syear+' '+
|
||||
shour+':'+smin+':'+ssec;
|
||||
end;
|
||||
end;
|
||||
|
||||
Procedure DosTime2NovTime(dt:Longint;Var nt:TnovTime);
|
||||
Var k:array[1..2] of word absolute dt;
|
||||
begin
|
||||
with nt
|
||||
do begin
|
||||
year:=(80+byte(k[2] SHR 9)) MOD 100;
|
||||
month:=(byte(k[2] SHR 5) AND 15);
|
||||
day:=byte(k[2] AND 31);
|
||||
|
||||
hour:=byte (k[1] SHR 11);
|
||||
min:=(byte(k[1] SHR 5) AND 63);
|
||||
sec:=2*byte(k[1] AND 31);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
Procedure NovTime2DosTime(nt:TnovTime;Var dt:Longint);
|
||||
Var k:array[1..2] of word absolute dt;
|
||||
begin
|
||||
with nt
|
||||
do begin
|
||||
k[2]:=(((100+year-80) mod 100) SHL 9)+(month SHL 5)+day;
|
||||
k[1]:=(hour SHL 11)+(min SHL 5)+(sec DIV 2);
|
||||
end;
|
||||
end;
|
||||
|
||||
Procedure NovPath2DosPath(np:String;Var dp:string);
|
||||
{ np is a pascal type string with the folowing format:
|
||||
|
||||
chr(length(subdir1)),subdir1,
|
||||
...
|
||||
chr(length(subdirN)),subDirN.
|
||||
|
||||
It will be transformed to a DOS path of type Subdir1\Subdir2\.. \subDirN }
|
||||
Var t:Byte;
|
||||
begin
|
||||
dp:=np;
|
||||
delete(dp,1,1);
|
||||
for t:=1 to ord(dp[1])
|
||||
do if dp[t]<=#20 then dp[t]:='\';
|
||||
end;
|
||||
|
||||
|
||||
Function LoNibble(b:Byte):Byte; assembler;
|
||||
asm
|
||||
mov al,b
|
||||
and al,$0F
|
||||
end;
|
||||
|
||||
Function HiNibble(b:Byte):Byte; assembler;
|
||||
asm
|
||||
mov ah,$00
|
||||
mov al,b
|
||||
shr ax,1
|
||||
shr ax,1
|
||||
shr ax,1
|
||||
shr ax,1
|
||||
end;
|
||||
|
||||
Function HexStr(dw:LongInt;len:byte):string;
|
||||
CONST n:array[0..15] of char
|
||||
=('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
|
||||
Var t:integer;
|
||||
ldw:LongInt;
|
||||
res:string;
|
||||
begin
|
||||
res:='';
|
||||
for t:=1 to len
|
||||
do begin
|
||||
ldw:=dw AND $0000000F;
|
||||
res:=n[ldw]+res;
|
||||
dw:=dw SHR 4;
|
||||
end;
|
||||
HexStr:=res;
|
||||
end;
|
||||
|
||||
Function HexDumpStr(Var dumpVar;len:Byte):String;
|
||||
Var arr:Array[1..256] of Byte ABSOLUTE dumpVar;
|
||||
t:Byte;
|
||||
res:String;
|
||||
begin
|
||||
res:='';
|
||||
for t:=1 to (1+(len DIV 2))
|
||||
do res:=res+HexStr(arr[t],2);
|
||||
res[0]:=chr(len);
|
||||
HexDumpStr:=res;
|
||||
end;
|
||||
|
||||
Function IsLowerNetworkAddress(Var a, b): Boolean;
|
||||
Type TCharNetAddress = Array [1..10] of Char;
|
||||
Var Aaddr : TCharNetAddress ABSOLUTE a;
|
||||
Baddr : TCharNetAddress ABSOLUTE b;
|
||||
Begin
|
||||
IsLowerNetworkAddress := Aaddr < Baddr;
|
||||
End;
|
||||
|
||||
Function IsEqualNetworkAddress(Var a, b): Boolean;
|
||||
Type TCharNetAddress = Array [1..10] of Char;
|
||||
Var Aaddr : TCharNetAddress ABSOLUTE a;
|
||||
Baddr : TCharNetAddress ABSOLUTE b;
|
||||
Begin
|
||||
IsEqualNetworkAddress := (Aaddr = Baddr);
|
||||
End;
|
||||
|
||||
Function IsLaterNovTime(time1,time2:TnovTime):boolean;
|
||||
Var bAft:boolean;
|
||||
y1,y2:word;
|
||||
begin
|
||||
if time1.year>=80
|
||||
then y1:=1900+time1.year
|
||||
else y1:=2000+time1.year;
|
||||
if time2.year>=80
|
||||
then y2:=1900+time2.year
|
||||
else y2:=2000+time2.year;
|
||||
bAft:=(y1>y2);
|
||||
if y1=y2
|
||||
then begin
|
||||
bAft:=(time1.month>time2.month);
|
||||
if time1.month=time2.month
|
||||
then begin
|
||||
bAft:=(time1.day>time2.day);
|
||||
if time1.day=time2.day
|
||||
then begin
|
||||
bAft:=(time1.hour>time2.hour);
|
||||
if time1.hour=time2.hour
|
||||
then begin
|
||||
bAft:=(time1.min>time2.min);
|
||||
if time1.min=time2.min
|
||||
then bAft:=(time1.sec>time2.sec);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
IsLaterNovTime:=bAft
|
||||
end;
|
||||
|
||||
|
||||
Function IsEqualNovTime(time1,time2:TnovTime):boolean;
|
||||
Var t1:array[1..Sizeof(TnovTime)-1] of char absolute time1;
|
||||
t2:array[1..SizeOf(TnovTime)-1] of char absolute time2;
|
||||
begin
|
||||
IsEqualNovTime:=(t1=t2);
|
||||
end;
|
||||
|
||||
|
||||
Function MapV2RightsToV3(V2Rights:byte):word;
|
||||
CONST RightsNotChanged:byte=$08+$10+$40+$80;
|
||||
Var result:Word;
|
||||
begin
|
||||
if (V2Rights and $FF)>0
|
||||
then result:=$1FF
|
||||
else begin
|
||||
result:=(V2Rights and RightsNotChanged);
|
||||
if (V2Rights and ($01+$04))>0
|
||||
then result:=result or $01;
|
||||
if (V2Rights and ($02+$04))>0
|
||||
then result:=result or $02;
|
||||
if (V2Rights and $04)>0
|
||||
then result:=result or $01;
|
||||
if (V2Rights and $20)>0
|
||||
then result:=result or $28;
|
||||
end;
|
||||
MapV2RightsToV3:=result;
|
||||
end;
|
||||
|
||||
Function MapV3RightsToV2(V3Rights:Word):Byte;
|
||||
CONST RightsNotChanged:word=$10+$20+$40+$80;
|
||||
Var result:Byte;
|
||||
begin
|
||||
If (V3Rights and $0100)>0
|
||||
then result:=$FF
|
||||
else begin
|
||||
result:=(lo(V3Rights) and RightsNotChanged);
|
||||
If (V3Rights and $01)>0
|
||||
then result:=result or $05;
|
||||
If (V3Rights and $02)>0
|
||||
then result:=result or $06;
|
||||
{If (V3Rights and $04)>0
|
||||
then result:=result or $00;}
|
||||
If (V3Rights and $08)>0
|
||||
then result:=result or $28;
|
||||
end;
|
||||
MapV3RightsToV2:=result;
|
||||
end;
|
||||
|
||||
Procedure GetNWversion(Var version:word);
|
||||
{ determine the version of the software installed on the current file server. }
|
||||
{ see GetFileServerInformation F217/11 in the nwServ unit for more information }
|
||||
|
||||
{ version : word; contains the versionnumber of the fileserver we're
|
||||
currently connected to. Used by primary functions to
|
||||
determine what type of calls to use to perform a certain function.
|
||||
|
||||
format: (majorVersion*100)+minorVersion
|
||||
e.g. 311 for 3.11
|
||||
Range: 215 (advanced netware 2.15) and upwards }
|
||||
{ If the version is lower than 2.15, 2.15 is returned. }
|
||||
{ note: you don't have to be logged in to call this function. }
|
||||
Type TReq= Record
|
||||
PacketLength : Word;
|
||||
FunctionVal : Byte;
|
||||
End;
|
||||
TRep=array[1..$80] of byte;
|
||||
Tpreq=^Treq;
|
||||
Tprep=^Trep;
|
||||
Var Result:word;
|
||||
Begin
|
||||
With TPreq(GlobalReqBuf)^
|
||||
Do Begin
|
||||
PacketLength := 1; FunctionVal := $11;
|
||||
End;
|
||||
F2SystemCall($17,sizeof(Treq),Sizeof(Trep),result);
|
||||
If result=0
|
||||
then version:=(TPrep(GlobalReplyBuf)^[49]*100)+TPrep(GlobalReplyBuf)^[50]
|
||||
else version:=215;
|
||||
End;
|
||||
|
||||
|
||||
Function IsV3Supported:boolean;
|
||||
Var version:word;
|
||||
begin
|
||||
GetNWversion(version);
|
||||
IsV3Supported:=(version>=300);
|
||||
end;
|
||||
|
||||
|
||||
END.
|
||||
1149
NWTP/NWQMS.PAS
Normal file
1149
NWTP/NWQMS.PAS
Normal file
File diff suppressed because it is too large
Load Diff
330
NWTP/NWSEMA.PAS
Normal file
330
NWTP/NWSEMA.PAS
Normal file
@@ -0,0 +1,330 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
Unit nwSema;
|
||||
|
||||
{ nwSema unit as of 950301 / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
INTERFACE
|
||||
|
||||
{ Primary functions: Interrupt: comments:
|
||||
|
||||
* CloseSemaphore (F220/04)
|
||||
* ExamineSemaphore (F220/01)
|
||||
* GetConnectionsSemaphores (F217/F1)
|
||||
* GetSemaphoreInformation (F217/F2)
|
||||
* OpenSemaphore (F220/00)
|
||||
* SignalSemaphore (F220/03)
|
||||
* WaitOnSemaphore (F220/02)
|
||||
|
||||
Notes: Functions marked with a '*' have been tested and found correct.
|
||||
}
|
||||
|
||||
Uses nwIntr,nwMisc;
|
||||
|
||||
Type TsemaInfo=record
|
||||
ConnNbr:word;
|
||||
TaskNbr:word;
|
||||
end;
|
||||
TsemaInfoList=array[1..100] of TsemaInfo;
|
||||
{ used by GetSemaphoreInformation }
|
||||
|
||||
TconnSema=record
|
||||
OpenCount: Byte;
|
||||
Value : Integer;
|
||||
TaskNbr : Word;
|
||||
unknown : byte; { always 00 ?! }
|
||||
Name : string[127];
|
||||
end;
|
||||
{ used by GetConnectionsSemaphores }
|
||||
|
||||
Var Result:word;
|
||||
|
||||
{F220/00 [2.15? 3.x]}
|
||||
Function OpenSemaphore(SemName : String; InitVal : Integer;
|
||||
VAR SemHandle : LongInt;
|
||||
VAR OpenCount : Word ):Boolean;
|
||||
|
||||
{F220/01 [2.15? 3.x]}
|
||||
FUNCTION ExamineSemaphore( SemHandle :LongInt;
|
||||
VAR Value :Integer;
|
||||
VAR OpenCount :Word ) :Boolean;
|
||||
{ This functions returns the current value and open count of a semaphore.}
|
||||
|
||||
{F220/02 [3.x]}
|
||||
FUNCTION WaitOnSemaphore( SemHandle :LongInt;
|
||||
Wait_Time :Word ) :Boolean;
|
||||
{ Decrement the semaphore value and, if it is negative, }
|
||||
{ wait until it becomes non-negative or until a timeout occurs. }
|
||||
|
||||
{F220/03 [3.x]}
|
||||
FUNCTION SignalSemaphore(SemHandle:LongInt) : Boolean;
|
||||
{ Increment the semaphore value and release if waiting. }
|
||||
|
||||
{F220/04 [3.x]}
|
||||
FUNCTION CloseSemaphore(SemHandle:LongInt) : Boolean;
|
||||
{ Decrement the open count of a semaphore.}
|
||||
{ When the open count goes to zero, the semaphore is destroyed. }
|
||||
|
||||
|
||||
{F217/F1 [2.15+? 3.x+]}
|
||||
Function GetConnectionsSemaphores(ConnNbr:Word;
|
||||
{i/o} Var seqNbr:Word;
|
||||
{out} Var NbrOfSemaLeft:Byte;
|
||||
{out} Var SemaInfo:TconnSema):Boolean;
|
||||
{Caller needs console privileges }
|
||||
|
||||
{F217/F2 [2.15? 3.x+]}
|
||||
Function GetSemaphoreInformation(SemaName:String;
|
||||
{i/o} Var seqNbr:word;
|
||||
{out} Var OpenCount:word;
|
||||
Var SemValue:Integer;
|
||||
Var NbrOfSemaLeft:byte;
|
||||
Var info:TsemaInfoList):Boolean;
|
||||
{ Caller needs console privileges }
|
||||
|
||||
|
||||
IMPLEMENTATION {=============================================================}
|
||||
|
||||
|
||||
{F220/00 [3.x]}
|
||||
Function OpenSemaphore(SemName : String; InitVal : Integer;
|
||||
VAR SemHandle : LongInt;
|
||||
VAR OpenCount : Word ):Boolean;
|
||||
Type Treq=Record
|
||||
subf:byte;
|
||||
_InitVal:byte;
|
||||
_SemNameLen:byte;
|
||||
_SemName:array[0..127] of byte;
|
||||
end;
|
||||
Trep=record
|
||||
_SemHandle:LongInt;
|
||||
_OpenCount:Byte;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
begin
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
subf:=$00;
|
||||
If InitVal<0
|
||||
then _InitVal:=Lo(256+Initval)
|
||||
else _InitVal:=Lo(InitVal);
|
||||
UpString(SemName);SemName:=SemName+#0;
|
||||
move(semName[1],_SemName[0],ord(SemName[0]));
|
||||
_SemNameLen:=ord(semName[0])-1;
|
||||
end;
|
||||
F2SystemCall($20,SizeOf(treq),SizeOf(trep),result);
|
||||
With TPrep(GlobalReplyBuf)^
|
||||
do begin
|
||||
SemHandle:=Lswap(_SemHandle);
|
||||
OpenCount:=_OPenCount;
|
||||
end;
|
||||
OpenSemaphore:=(result=0);
|
||||
end;
|
||||
|
||||
|
||||
{F220/02 [3.x]}
|
||||
Function WaitOnSemaphore( SemHandle : LongInt;
|
||||
Wait_Time : Word ) : Boolean;
|
||||
{ Decrement the semaphore value and wait if it is negative. If negative,}
|
||||
{ the workstation will wait until it becomes non-negative or until a }
|
||||
{ timeout occurs. }
|
||||
Type Treq=Record
|
||||
subf:byte;
|
||||
_SemHandle:Longint;
|
||||
_wait :word; { hi-lo }
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
begin
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
subf:=$02;
|
||||
_semHandle:=Lswap(SemHandle);
|
||||
_wait:=swap(wait_Time);
|
||||
end;
|
||||
F2SystemCall($20,SizeOf(treq),0,result);
|
||||
WaitOnSemaphore:=(result=0);
|
||||
end;
|
||||
|
||||
|
||||
{F220/03 [3.x+]}
|
||||
Function SignalSemaphore(SemHandle:LongInt) : Boolean;
|
||||
{ Increment the semaphore value and release if waiting. If any stations}
|
||||
{ are waiting, the station that has been waiting the longest will be }
|
||||
{ signalled to proceed }
|
||||
Type Treq=Record
|
||||
subf:byte;
|
||||
_semhandle:Longint;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
begin
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
subf:=$03;
|
||||
_semHandle:=Lswap(SemHandle);
|
||||
end;
|
||||
F2SystemCall($20,SizeOf(treq),0,result);
|
||||
SignalSemaphore:=(result=0);
|
||||
end;
|
||||
|
||||
|
||||
{F220/04 [3.x+]}
|
||||
Function CloseSemaphore(SemHandle:LongInt) : Boolean;
|
||||
{ Decrement the open count of a semaphore. When the open count goes }
|
||||
{ to zero, the semaphore is destroyed. }
|
||||
Type Treq=Record
|
||||
subf:byte;
|
||||
_semhandle:Longint;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
begin
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
subf:=$04;
|
||||
_semHandle:=Lswap(SemHandle);
|
||||
end;
|
||||
F2SystemCall($20,SizeOf(treq),0,result);
|
||||
CloseSemaphore:=(result=0);
|
||||
end;
|
||||
|
||||
|
||||
{F220/01 [2.x/3.x]}
|
||||
FUNCTION ExamineSemaphore(SemHandle:LongInt;
|
||||
VAR Value : Integer;
|
||||
VAR OpenCount : Word ) : Boolean;
|
||||
{ The semaphore value that comes back is the count from the open call }
|
||||
{ - the open count is incremented }
|
||||
{ anytime a station opens the semaphore this can be used for controlling }
|
||||
{ the number of users using your software }
|
||||
Type Treq=record
|
||||
subf:byte;
|
||||
_semHandle:Longint;
|
||||
end;
|
||||
Trep=record
|
||||
_Value:Byte;
|
||||
_OpenCount:Byte;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
BEGIN
|
||||
With TPreq(GlobalReqBuf)^
|
||||
DO begin
|
||||
subf:=$01;
|
||||
_semHandle:=Lswap(SemHandle);
|
||||
end;
|
||||
F2SystemCall($20,SizeOf(Treq),SizeOf(Trep),result);
|
||||
With TPrep(GlobalReplyBuf)^
|
||||
do begin
|
||||
if (_Value and $80)>0
|
||||
then Value:=254-_Value
|
||||
else Value:=_Value;
|
||||
OpenCount:=_OpenCount;
|
||||
end;
|
||||
ExamineSemaphore := (result = 0);
|
||||
END;
|
||||
|
||||
{F217/F1 [2.15+? 3.x+]}
|
||||
Function GetConnectionsSemaphores(ConnNbr:Word;
|
||||
{i/o} Var seqNbr:Word;
|
||||
{out} Var NbrOfSemaLeft:Byte;
|
||||
{out} Var SemaInfo:TconnSema):Boolean;
|
||||
{ To be called iteratively. Inital seqNbr=1. Iterate until seqNbr
|
||||
becomes 0 (or until NbrOfSemaLeft becomes 0).
|
||||
|
||||
This function can return information about several semaphores at the
|
||||
same time. However, the size of the reply buffer is limited, causing
|
||||
several as of now unsolvable problems. For now this function will
|
||||
return information on a per semaphore basis. }
|
||||
Type Treq=Record
|
||||
len:word;
|
||||
subf:byte;
|
||||
_ConnNbr:word; {lo-hi}
|
||||
_SeqNbr:word; {lo-hi}
|
||||
end;
|
||||
Trep=record
|
||||
_NextSeqNbr:word;
|
||||
_nbrOfSema:byte; { word (lo-hi) ? }
|
||||
_unknown:byte; { -^ }
|
||||
_SemaInfoBuf:array[1..508] of byte;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
Var i,t:Byte;
|
||||
begin
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
len:=SizeOf(Treq)-2;
|
||||
subf:=$F1;
|
||||
_ConnNbr:=ConnNbr;
|
||||
_SeqNbr:=SeqNbr;
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(treq),SizeOf(trep),result);
|
||||
if result=0
|
||||
then With TPrep(GlobalReplyBuf)^
|
||||
do begin
|
||||
NbrOfSemaLeft:=(_NbrOfSema-1);
|
||||
if NbrOfSemaLeft=0
|
||||
then seqNbr:=0
|
||||
else seqNbr:=seqNbr+1; { unfortunately, _NextSeqNbr returns no valid info. }
|
||||
|
||||
Move(_SemaInfoBuf[1],SemaInfo,7+_SemaInfoBuf[7]);
|
||||
With SemaInfo
|
||||
do begin
|
||||
Value:=swap(Value);
|
||||
TaskNbr:=swap(TaskNbr);
|
||||
end;
|
||||
end;
|
||||
GetConnectionsSemaphores:=(result=0);
|
||||
{ 00 Successful C6 No console rights FD Bad connection number }
|
||||
end;
|
||||
|
||||
{F217/F2 [2.15? 3.x+]}
|
||||
Function GetSemaphoreInformation(SemaName:String;
|
||||
{i/o} Var seqNbr:word;
|
||||
{out} Var OpenCount:word;
|
||||
Var SemValue:Integer;
|
||||
Var NbrOfSemaLeft:byte;
|
||||
Var info:TsemaInfoList):Boolean;
|
||||
Type Treq=Record
|
||||
len:word;
|
||||
subf:byte;
|
||||
_seqNbr: word;
|
||||
_semaName:string[127];
|
||||
end;
|
||||
Trep=record
|
||||
_NextSeqNbr:Word;
|
||||
_OpenCount:word;
|
||||
_SemValue:word;
|
||||
_NbrOfRecords:word;
|
||||
_SemaInfoBuf:array[1..514] of byte;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
begin
|
||||
UpString(SemaName);
|
||||
if SemaName[0]>#127
|
||||
then SemaName[0]:=#127;
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
subf:=$F2;
|
||||
_seqNbr:=seqNbr;
|
||||
_SemaName:=SemaName;
|
||||
len:=4+ord(_SemaName[0]);
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(treq),SizeOf(trep),result);
|
||||
With TPrep(GlobalReplyBuf)^
|
||||
do begin
|
||||
OpenCount:=_OpenCount;
|
||||
SemValue:=Integer(_SemValue);
|
||||
NbrOfSemaLeft:=_NbrOfRecords;
|
||||
move(_SemaInfoBuf,Info,SizeOf(TsemaInfoList));
|
||||
if NbrOfSemaLeft>100
|
||||
then seqNbr:=seqNbr+100
|
||||
else seqNbr:=0;
|
||||
end;
|
||||
GetSemaphoreInformation:=(result=0);
|
||||
{ 00 Successful C6 No console rights }
|
||||
end;
|
||||
|
||||
|
||||
END.
|
||||
748
NWTP/NWSERV.PAS
Normal file
748
NWTP/NWSERV.PAS
Normal file
@@ -0,0 +1,748 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
UNIT nwServ;
|
||||
|
||||
{ nwServ unit as of 950301 / NwTP 0.6 API. (c) 1993,1995, R. Spronk }
|
||||
|
||||
INTERFACE
|
||||
|
||||
uses nwIntr,NwMisc,nwConn;
|
||||
|
||||
Var result:word;
|
||||
|
||||
{ Primary Functions: Interrupt: Comments:
|
||||
|
||||
* CheckConsolePrivileges (F217/C8)
|
||||
* ClearConnectionNumber (F217/D2)
|
||||
* DisableFileServerLogin (F217/CB)
|
||||
. DisableTransactionTracking (F217/CF)
|
||||
* DownFileServer (F217/D3)
|
||||
* EnableFileServerLogin (F217/CC)
|
||||
. EnableTransactionTracking (F217/D0)
|
||||
* GetConnectionsOpenFiles (F217/EB)
|
||||
GetConnectionsUsingAFile (F217/EC)
|
||||
* GetDiskUtilization (F217/0E)
|
||||
* GetFileServerDateAndTime (F214)
|
||||
* GetFileServerDescriptionStrings (F217/C9)
|
||||
* GetFileServerLoginStatus (F217/CD)
|
||||
* GetNetworkSerialNumber (F217/12)
|
||||
* GetFileServerInformation (F217/11)
|
||||
* SetFileServerDateAndTime (F217/CA)
|
||||
* VerifyNetworkSerialNumber (F217/0C)
|
||||
|
||||
Secondary functions:
|
||||
|
||||
* CheckNetwareVersion
|
||||
|
||||
Not supported by netware 3.x: (2.x only)
|
||||
|
||||
- GetBinderyObjectDiskSpaceLeft (F217/E6) (failed during testing)
|
||||
- GetConnectionsTaskInformation (E3../DA)
|
||||
- GetConnectionsUsageStats (E3../E5)
|
||||
- GetConnectionsUsingAFile (E3../DC)
|
||||
- GetDiskCacheStats (E3../D6)
|
||||
- GetDiskChannelStats (E3../D9)
|
||||
- GetDriveMappingTable (E3../D7)
|
||||
- GetFileServerLANIOStats (E3../E7)
|
||||
- GetFileServerMiscInformation (E3../E8)
|
||||
- GetFileSystemStats (E3../D4)
|
||||
- GetLANDriverConfigInfo (E3../E3)
|
||||
- GetLogicalRecordInformation (E3../E0)
|
||||
- GetLogicalRecordsByConnection (E3../DF)
|
||||
- GetPhysicalDiskStats (E3../D8)
|
||||
- GetPhysicalRecordLocksByFile (E3../DE)
|
||||
- GetPhysRecLocksByConnectAndFile (E3../DD)
|
||||
}
|
||||
|
||||
|
||||
Type TFileServerInformation
|
||||
=Record
|
||||
ServerName : string[48];
|
||||
NetwareVersion : Byte;
|
||||
NetwareSubVersion : Byte; { 0..99 }
|
||||
ConnectionsMax : word;
|
||||
ConnectionsInUse : word;
|
||||
MaxConnVol : word; { max connected volumes }
|
||||
{---Advanced Netware 2.1x/3.x------------}
|
||||
OS_revision : byte;
|
||||
SFT_level : byte;
|
||||
TTS_level : byte;
|
||||
peak_conn_used : word; { max simult.used connections}
|
||||
accounting_version : byte;
|
||||
vap_version : byte;
|
||||
queuing_version : byte;
|
||||
print_server_version : byte;
|
||||
virtual_console_version : byte;
|
||||
security_restrictions_level : byte;
|
||||
Internetwork_bridge_version : byte;
|
||||
Undefined : Array [1..60] of Byte;
|
||||
End;
|
||||
|
||||
Type TfileInfoRecord=record
|
||||
TaskNbr :Word;
|
||||
LockType :Byte; { 00 no lock; FE file lock; FF locked by Begin Share File Set }
|
||||
AccessFlag :Byte;
|
||||
LockFlag :Byte;
|
||||
VolNbr :Byte; { 0..31 }
|
||||
ParentEntryId:Longint;
|
||||
DirEntryId :Longint;
|
||||
ForkCount :Byte;
|
||||
NStype :Byte;
|
||||
FileName :String;
|
||||
end;
|
||||
TfileInfoRecList=array[1..28] of TfileInfoRecord;
|
||||
|
||||
Type TfileUsageList=record
|
||||
UseCount :word;
|
||||
OpenCount :word;
|
||||
OpenForReadCount :word;
|
||||
OpenForWriteCount:word;
|
||||
DenyReadCount :word;
|
||||
DenyWriteCount :word;
|
||||
LockFlag :Byte; { boolean }
|
||||
NStype :Byte; { Fork Count = File siz? of NStype? }
|
||||
NbrOfRec :word; { max 70 }
|
||||
FileUsage:array[1..70] of record
|
||||
ConnNbr :word;
|
||||
TaskNbr :word;
|
||||
LockType :byte;
|
||||
AccessFlag:Byte;
|
||||
LockFlag :Byte;
|
||||
end;
|
||||
end;
|
||||
|
||||
{F217/C8 [2.15c+]}
|
||||
FUNCTION CheckConsolePrivileges : Boolean;
|
||||
|
||||
{F217/D2 [2.15c+]}
|
||||
Function ClearConnectionNumber(connectionNbr:byte):boolean;
|
||||
{ Console Rights needed;
|
||||
-Terminates a connection. }
|
||||
|
||||
{F217/CB [2.15c+]}
|
||||
FUNCTION DisableFileServerLogin : Boolean;
|
||||
|
||||
{F217/CF [2.15c+]}
|
||||
FUNCTION DisableTransactionTracking : Boolean;
|
||||
|
||||
{F217/D3 [2.15c+]}
|
||||
FUNCTION DownFileServer (ForceFlag : Boolean) : Boolean;
|
||||
|
||||
{F217/CC [2.15c+]}
|
||||
FUNCTION EnableFileServerLogin : Boolean;
|
||||
|
||||
{F217/D0 [2.15c+]}
|
||||
FUNCTION EnableTransactionTracking : Boolean;
|
||||
|
||||
|
||||
{F217/EB [3.0+]}
|
||||
FUNCTION GetConnectionsOpenFiles
|
||||
( ConnNumber : Byte;
|
||||
{i/o:} var LastRecordSeen : word;
|
||||
{out:} var NbrOfRecords : word;
|
||||
var FileInfo : TfileInfoRecList ) : Boolean;
|
||||
|
||||
{F217/0E [2.15c+]}
|
||||
FUNCTION GetDiskUtilization(volNbr:byte; objID:Longint;
|
||||
Var usedDirs,usedFiles,usedBlocks:Word ):Boolean;
|
||||
|
||||
{F214 [2.15c+]}
|
||||
FUNCTION GetFileServerDateAndTime ( Var time:TnovTime): Boolean;
|
||||
|
||||
{F217/C9 [2.15c+]}
|
||||
FUNCTION GetFileServerDescriptionStrings(Var companyName,
|
||||
VersionAndRevision,revisionDate,
|
||||
copyrightNotice:String
|
||||
):Boolean;
|
||||
|
||||
{F217/CD [2.15c+]}
|
||||
FUNCTION GetFileServerLoginStatus (Var LoginEnabled:Boolean): Boolean;
|
||||
{ if Login is enabled then returns TRUE in LoginEnabled }
|
||||
|
||||
{F217/12 [2.15c+]}
|
||||
Function GetNetworkSerialNumber(Var serialNbr:LongInt; Var ApplicNbr:Word ):Boolean;
|
||||
{return the serial number and application number for the software
|
||||
installed on the file server}
|
||||
|
||||
{F217/11 [2.15c+]}
|
||||
Function GetFileServerInformation (Var serverInfo:TFileServerInformation):boolean;
|
||||
{determine the version of software installed on the file server and how it is configured}
|
||||
|
||||
{F217/CA [2.15c+]}
|
||||
FUNCTION SetFileServerDateAndTime(time:TnovTime):Boolean;
|
||||
{need console operator privileges to do this}
|
||||
|
||||
{F217/OC [2.15c+]}
|
||||
Function VerifyNetworkSerialNumber(serialNbr: LongInt ;
|
||||
Var ApplicNbr: Word ):Boolean;
|
||||
{if the network serial number to be verified is correct, the reply
|
||||
buffer will contain the corresponding application number }
|
||||
|
||||
{*********************** Secondary Functions ******************************}
|
||||
|
||||
{ [1.x/2.x/3.x] }
|
||||
FUNCTION CheckNetwareVersion(MinimumVersion,MinimumSubVersion,
|
||||
MinimumRevision,MinimumSFT,MinimumTTS:word):Boolean;
|
||||
|
||||
IMPLEMENTATION{=============================================================}
|
||||
|
||||
|
||||
{F217/D2 [2.15c+]}
|
||||
Function ClearConnectionNumber(connectionNbr:byte):boolean;
|
||||
{ Console Rights needed;
|
||||
-Terminates a connection. }
|
||||
Type Treq=record
|
||||
len : word;
|
||||
subf: byte;
|
||||
_connNbr:byte;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
begin
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
len:=2;
|
||||
subf:=$D2;
|
||||
_connNbr:=connectionNbr
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),0,result);
|
||||
ClearConnectionNumber:=(result=0);
|
||||
{result codes: 00 successful; C6 No Console Rights}
|
||||
end;
|
||||
|
||||
{F214 [2.15c+]}
|
||||
FUNCTION GetFileServerDateAndTime ( Var time:TnovTime): Boolean;
|
||||
Type Trep=TnovTime;
|
||||
TPrep=^Trep;
|
||||
BEGIN
|
||||
F2SystemCall($14,0,SizeOf(Trep),result);
|
||||
Time:=TPrep(GlobalreplyBuf)^;
|
||||
if time.year>100
|
||||
then time.year:=time.year-100;
|
||||
{ year<80 : 21st century }
|
||||
result:=0;
|
||||
getFileServerDateAndTime:=TRUE;
|
||||
end;
|
||||
|
||||
|
||||
{F217/CA [2.15c+]}
|
||||
FUNCTION SetFileServerDateAndTime (time:TnovTime): Boolean;
|
||||
Type Treq=record
|
||||
Len:word;
|
||||
subF:byte;
|
||||
_time:TnovTime
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
BEGIN
|
||||
{ year<80 : 21st century }
|
||||
WITH TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
Len:=SizeOf(Treq)-3; { dow is not a parameter }
|
||||
subF:=$CA;
|
||||
_time:=time;
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),0,result);
|
||||
SetFileServerDateAndTime:=(Result=$00);
|
||||
{ Resulcodes: $00 Success; $C6 No Console Operator Rights }
|
||||
end;
|
||||
|
||||
|
||||
{F217/11 [2.15c+]}
|
||||
Function GetFileServerInformation (Var serverInfo:TFileServerInformation):boolean;
|
||||
{determine the version of software installed on the file server and how it is configured}
|
||||
|
||||
{SeeAlso: GetDiskUtilization, GetNetworkSerialNumber, GetFileServerLoginStatus,
|
||||
GetFileServerDateAndTime}
|
||||
|
||||
Type TReq=Record
|
||||
Len : word;
|
||||
SubF : Byte;
|
||||
End;
|
||||
TRep=TFileServerInformation;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
|
||||
Var t:word;
|
||||
Begin
|
||||
With TPreq(GlobalReqBuf)^
|
||||
Do Begin
|
||||
Len := 1;
|
||||
SubF:= $11;
|
||||
End;
|
||||
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep)-1,result);
|
||||
Move(GlobalReplyBuf^[1],GlobalReplyBuf^[2],SizeOf(Trep)-1);
|
||||
serverInfo:=TPrep(GlobalReplyBuf)^;
|
||||
With serverinfo
|
||||
do begin
|
||||
connectionsMax :=Swap(connectionsMax); { force lo-hi again }
|
||||
ConnectionsInUse:=Swap(connectionsInUse);
|
||||
MaxConnVol :=Swap(maxConnVol);
|
||||
peak_conn_used :=Swap(peak_conn_used);
|
||||
for t:=48 downto 1
|
||||
do if serverInfo.serverName[t]=#0
|
||||
then serverInfo.serverName[0]:=chr(t-1);
|
||||
end;
|
||||
GetFileServerInformation:=(result=0);
|
||||
End;
|
||||
|
||||
|
||||
|
||||
{F217/C9 [2.15c+]}
|
||||
FUNCTION GetFileServerDescriptionStrings(Var companyName,
|
||||
VersionAndRevision,revisionDate,
|
||||
copyrightNotice:String
|
||||
):Boolean;
|
||||
{SeeAlso: GetFileServerLoginStatus, GetFileServerInformation. }
|
||||
Type Treq=record
|
||||
len : word;
|
||||
subf: byte;
|
||||
end;
|
||||
Trep=record
|
||||
stuff : array [1..512] of byte;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
Var x,xofs:word;
|
||||
begin
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
len := 1;
|
||||
subf := $c9;
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result);
|
||||
companyName:=''; VersionAndRevision:='';
|
||||
revisionDate:=''; copyrightNotice:='';
|
||||
if result=$00
|
||||
then with TPrep(GlobalReplyBuf)^
|
||||
do begin
|
||||
x:=1;xofs:=x;
|
||||
while (stuff[x]<>$00) and (x<512) do inc(x);
|
||||
ZStrCopy(companyName,stuff[xofs],x-xofs);
|
||||
|
||||
inc(x);xofs:=x; { skip 1 zero. ? skip more zero's? }
|
||||
While (stuff[x]<>$00) and (x<512) do inc(x);
|
||||
ZStrCopy(VersionAndRevision,stuff[xofs],x-xofs);
|
||||
|
||||
inc(x);xofs:=x;
|
||||
While (stuff[x]<>$00) and (x<512) do inc(x);
|
||||
ZStrCopy(revisionDate,stuff[xofs],x-xofs); { mm/dd/yy }
|
||||
|
||||
inc(x);xofs:=x;
|
||||
While (stuff[x]<>$00) and (x<512) do inc(x);
|
||||
ZStrCopy(copyrightNotice,stuff[xofs],x-xofs);
|
||||
end;
|
||||
GetFileServerDescriptionStrings:=(Result=$00);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{F217/D3 [2.15c+]}
|
||||
FUNCTION DownFileServer (ForceFlag : Boolean) : Boolean;
|
||||
Type Treq=record
|
||||
len : word;
|
||||
subf : byte;
|
||||
flag : byte;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
BEGIN
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
len := 2;
|
||||
subf := $D3;
|
||||
if ForceFlag then flag := $FF { non-zero }
|
||||
else flag := $00;
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),0,result);
|
||||
DownFileServer:=(result=0);
|
||||
{ resultcodes: 00=successful; C6 No Console Rights ; FF Open Files}
|
||||
end;
|
||||
|
||||
|
||||
{F217/CF [3.x]}
|
||||
FUNCTION DisableTransactionTracking : Boolean;
|
||||
{ Caller must have console-operator rights. }
|
||||
Type Treq=record
|
||||
len : word;
|
||||
subf: byte
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
BEGIN
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
len := 1;
|
||||
subf:= $CF;
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),0,result);
|
||||
DisableTransactionTracking:=(result=0);
|
||||
{ resultcodes: 00=successful; C6 No Console Rights }
|
||||
end;
|
||||
|
||||
|
||||
{F217/D0 [3.x]}
|
||||
FUNCTION EnableTransactionTracking : Boolean;
|
||||
{ Caller must have console-operator rights. }
|
||||
Type Treq=record
|
||||
len : word;
|
||||
subf: byte
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
BEGIN
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
len := 1;
|
||||
subf:= $D0;
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),0,result);
|
||||
EnableTransactionTracking:=(result=0);
|
||||
{ resultcodes: 00=successful; C6 No Console Rights }
|
||||
end;
|
||||
|
||||
|
||||
{F217/CB [2.15c+]}
|
||||
FUNCTION DisableFileServerLogin : Boolean;
|
||||
{ Caller must have console-operator rights. }
|
||||
Type Treq=record
|
||||
len : word;
|
||||
subf: byte
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
BEGIN
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
len := 1;
|
||||
subf:= $CB;
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),0,result);
|
||||
DisableFileServerLogin:=(result=0);
|
||||
{ resultcodes: 00=successful; C6 No Console Rights }
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{F217/CC [2.15c+]}
|
||||
FUNCTION EnableFileServerLogin : Boolean;
|
||||
{ Caller needs console-operator rights. }
|
||||
Type Treq=record
|
||||
len : word;
|
||||
subf: byte
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
BEGIN
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
len := 1;
|
||||
subf:= $CC;
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),0,result);
|
||||
EnableFileServerLogin:=(result=0);
|
||||
{ resultcodes: 00=successful; C6 No Console Rights }
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{F217/CD [2.15c+]}
|
||||
FUNCTION GetFileServerLoginStatus( Var LoginEnabled:Boolean ): Boolean;
|
||||
{ if Login is enabled then returns TRUE in LoginEnabled }
|
||||
{ result byte: 00h - Success, C6h No Console Rights }
|
||||
{ Caller must have operator status.}
|
||||
Type TReq=record
|
||||
Len : Word;
|
||||
SubF : Byte;
|
||||
end;
|
||||
TRep=record
|
||||
Flag : Byte;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
begin
|
||||
with TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
Len := 1;
|
||||
SubF := $CD;
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result);
|
||||
LoginEnabled:=Boolean(TPrep(GlobalReplyBuf)^.Flag);
|
||||
GetFileServerLoginStatus := (result=0);
|
||||
end;
|
||||
|
||||
|
||||
{F217/C8 [2.15c+]}
|
||||
FUNCTION CheckConsolePrivileges : Boolean;
|
||||
Type TReq=record
|
||||
Len : Word;
|
||||
SubF : Byte;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
begin
|
||||
with TPReq(GlobalReqBuf)^
|
||||
do begin
|
||||
Len := 1;
|
||||
SubF := $C8;
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),0,result);
|
||||
CheckConsolePrivileges := (Result=$00);
|
||||
{ result byte: 00h - Success, C6h No Console Rights }
|
||||
end;
|
||||
|
||||
|
||||
{F217/EB [3.0+]}
|
||||
FUNCTION GetConnectionsOpenFiles
|
||||
( ConnNumber : Byte;
|
||||
{i/o:} var LastRecordSeen : word;
|
||||
{out:} var NbrOfRecords : word;
|
||||
var FileInfo : TfileInfoRecList ) : Boolean;
|
||||
|
||||
{ the calling workstation must have console operator privileges }
|
||||
{ LastRecordSeen is an i/o parameter;
|
||||
-An initial value of 0 has to be supplied;
|
||||
-The function can be called until LastRecordSeen becomes 0,
|
||||
indicating the end of the FIR-list.
|
||||
|
||||
to be called iteratively. }
|
||||
|
||||
Type TReq=record
|
||||
len :word;
|
||||
subf :byte;
|
||||
logicalConnNbr:word;
|
||||
lastRecSeen :word; {lo-hi, $0000 on first call }
|
||||
end;
|
||||
TRep=record
|
||||
nextReqRec : word; { lo-hi, use as lastRecSeen in next iterative call }
|
||||
{ $0000 if no more records }
|
||||
RecCount : word;
|
||||
FIRbuf:array[1..508] of byte;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
Var t,Foff:Word;
|
||||
begin
|
||||
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
len:=sizeof(Treq)-2;
|
||||
subf:=$EB;
|
||||
logicalConnNbr:=connNumber;
|
||||
lastRecSeen:=LastRecordSeen; { force hi-lo }
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result);
|
||||
if result=$00
|
||||
then with TPrep(GlobalReplyBuf)^
|
||||
do begin
|
||||
{ Copy recCount FIRs from FIRbuf to the FileInfo[] array }
|
||||
LastRecordSeen:=NextReqRec;
|
||||
NbrOfrecords:=RecCount;
|
||||
Foff:=0;
|
||||
For t:=1 to RecCount
|
||||
do begin
|
||||
Move(FIRbuf[1+Foff],FileInfo[t],17+FIRbuf[Foff+17]);
|
||||
inc(Foff,17+FIRbuf[Foff+17]);
|
||||
{ Direntry and ParentEntry may have to be swapped lo-hi }
|
||||
end;
|
||||
end
|
||||
else begin
|
||||
NbrOfRecords:=0;
|
||||
LastRecordSeen:=0;
|
||||
end;
|
||||
GetConnectionsOpenFiles:=(result=$00);
|
||||
{ errorcodes: $00 Success; $C6 no console privileges }
|
||||
end;
|
||||
|
||||
|
||||
{F217/EC }
|
||||
Function GetConnectionsUsingAFile(VolNbr:Byte; EntryId:Longint; NStype:byte;
|
||||
{i/o} Var LastRecordSeen:word;
|
||||
Var NbrOfRecords:Word;
|
||||
Var FileInfo:TfileUsageList):boolean;
|
||||
{ This call returns all connection numbers using the file specified
|
||||
by the Volume Number and Directory Entry Id. }
|
||||
|
||||
{ !! UNDER CONSTRUCTION !! }
|
||||
|
||||
Type TReq=record
|
||||
len :word;
|
||||
subf :byte;
|
||||
NStype :Byte; {= data stream type / Fork type }
|
||||
VolNbr :Byte;
|
||||
DirEntryId :Longint;
|
||||
LastRecSeen:Word; {initially set to 0}
|
||||
end;
|
||||
|
||||
TRep=record
|
||||
NextRec :word; { iteration }
|
||||
|
||||
UseCount :word;
|
||||
OpenCount :word;
|
||||
OpenForReadCount :word;
|
||||
OpenForWriteCount:word;
|
||||
DenyReadCount :word;
|
||||
DenyWriteCount :word;
|
||||
LockFlag :Byte; { boolean }
|
||||
NStype :Byte; { Fork Count -> ?? NStype }
|
||||
NbrOfRec :word; { max 70 }
|
||||
FileUsage:array[1..70] of record
|
||||
ConnNbr :word;
|
||||
TaskNbr :word;
|
||||
LockType :byte;
|
||||
AccessFlag:Byte;
|
||||
LockFlag :Byte;
|
||||
end;
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
begin
|
||||
With TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
len:=sizeof(Treq)-2;
|
||||
subf:=$EC;
|
||||
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result);
|
||||
if result=$00
|
||||
then with TPrep(GlobalReplyBuf)^
|
||||
do begin
|
||||
|
||||
end
|
||||
else begin
|
||||
NbrOfRecords:=0;
|
||||
LastRecordSeen:=0;
|
||||
end;
|
||||
GetConnectionsUsingAFile:=(result=$00);
|
||||
{ errorcodes: $00 Success; $C6 no console privileges }
|
||||
end;
|
||||
|
||||
|
||||
{F217/0E [2.15c+]}
|
||||
FUNCTION GetDiskUtilization(volNbr:byte; objID:Longint;
|
||||
Var usedDirs,usedFiles,usedBlocks:Word ):Boolean;
|
||||
{ SeeAlso: GetFileServerInformation,getBinderyObjectDiskSpaceLeft }
|
||||
Type TReq=record
|
||||
Len : Word;
|
||||
SubF : Byte;
|
||||
_volNbr:Byte;
|
||||
_objID:longInt; { hi-lo }
|
||||
end;
|
||||
TRep=record
|
||||
_volNbr:Byte;
|
||||
_objID:Longint; {hi-lo}
|
||||
_usedDirs,
|
||||
_usedFiles,
|
||||
_usedBlocks:Word; { all hi-lo }
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
begin
|
||||
with TPReq(GlobalReqBuf)^
|
||||
do begin
|
||||
Len := SizeOf(TReq)-2;
|
||||
SubF := $0E;
|
||||
_volNbr:=volNbr;
|
||||
_objID:=Lswap(objID);
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result);
|
||||
if result=$00
|
||||
then begin
|
||||
with TPrep(GlobalReplyBuf)^
|
||||
do begin
|
||||
usedDirs:=swap(_usedDirs); { force lo-hi }
|
||||
usedFiles:=swap(_usedFiles); { force lo-hi }
|
||||
usedBlocks:=swap(_usedBlocks);{ force lo-hi }
|
||||
end;
|
||||
end;
|
||||
GetDiskUtilization:=(result=$00);
|
||||
{Resultcodes: 00h successful; 98h volume doesn't exist
|
||||
89h No Search Privileges
|
||||
F2h no Object read privileges }
|
||||
end;
|
||||
|
||||
|
||||
{F217/12 [2.15c+]}
|
||||
Function GetNetworkSerialNumber(Var serialNbr:LongInt; Var ApplicNbr:Word ):Boolean;
|
||||
{return the serial number and application number for the software
|
||||
installed on the file server}
|
||||
{SeeAlso: VerifyNetworkSerialNumber,GetFileServerInformation}
|
||||
Type TReq=record
|
||||
Len : Word;
|
||||
SubF : Byte;
|
||||
end;
|
||||
TRep=record
|
||||
_serNbr : LongInt; {hi-lo}
|
||||
_applicNbr: Word; {hi-lo}
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
begin
|
||||
with TPreq(GlobalReqBuf)^
|
||||
do begin
|
||||
Len := 1;
|
||||
SubF := $12;
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result);
|
||||
with TPrep(GlobalReplyBuf)^
|
||||
do begin
|
||||
ApplicNbr:=swap(_applicNbr); { force lo-hi }
|
||||
serialNbr:=Lswap(_serNbr); { force lo-hi }
|
||||
end;
|
||||
GetNetworkSerialNumber := (result=0);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{F217/OC [2.15c+]}
|
||||
Function VerifyNetworkSerialNumber(serialNbr: LongInt ;
|
||||
Var ApplicNbr: Word ):Boolean;
|
||||
{if the network serial number to be verified is correct, the reply
|
||||
buffer will contain the corresponding application number }
|
||||
{SeeAlso: GetNetworkSerialNumber}
|
||||
Type Treq=record
|
||||
Len : Word;
|
||||
SubF : Byte;
|
||||
_netwSerNbr: LongInt; {hi-lo}
|
||||
end;
|
||||
TRep=record
|
||||
_applicNbr: word; {hi-lo}
|
||||
end;
|
||||
TPreq=^Treq;
|
||||
TPrep=^Trep;
|
||||
begin
|
||||
with TPReq(GlobalReqBuf)^
|
||||
do begin
|
||||
Len := 1;
|
||||
SubF := $0C;
|
||||
_netwSerNbr:=Lswap(serialNbr);
|
||||
end;
|
||||
F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result);
|
||||
with TPrep(GlobalReplyBuf)^
|
||||
do begin
|
||||
ApplicNbr:=swap(_applicNbr); { force lo-hi }
|
||||
end;
|
||||
VerifyNetworkSerialNumber := (result=0);
|
||||
end;
|
||||
|
||||
{****************** secondary functions ************************************}
|
||||
|
||||
|
||||
FUNCTION CheckNetwareVersion(MinimumVersion,MinimumSubVersion,
|
||||
MinimumRevision,MinimumSFT,MinimumTTS:word):Boolean;
|
||||
{ checks if the current OS/TTS/SFT version is greater or equal to the minimal version }
|
||||
Var info:TFileServerInformation;
|
||||
res:boolean;
|
||||
begin
|
||||
IF GetFileServerInformation(info)
|
||||
then begin
|
||||
IF (info.NetwareVersion>MinimumVersion)
|
||||
then res:=true
|
||||
else if (info.NetwareVersion=MinimumVersion)
|
||||
AND (info.NetwareSubVersion>MinimumSubVersion)
|
||||
then res:=true
|
||||
else if (info.NetwareVersion=MinimumVersion)
|
||||
AND (info.NetwareSubVersion=MinimumSubVersion)
|
||||
AND (info.OS_Revision>=MinimumRevision)
|
||||
then res:=true
|
||||
else res:=false
|
||||
end
|
||||
else res:=false;
|
||||
|
||||
CheckNetwareVersion:=res AND (info.SFT_Level>=MinimumSFT)
|
||||
AND (info.TTS_Level>=MinimumTTS)
|
||||
end;
|
||||
|
||||
end. {unit nwServ}
|
||||
315
NWTP/NWSPX.PAS
Normal file
315
NWTP/NWSPX.PAS
Normal file
@@ -0,0 +1,315 @@
|
||||
{$B-,V-,X+}
|
||||
|
||||
UNIT nwSPX;
|
||||
|
||||
{ nwSPX unit as of 950301 / NwTP 0.6 API. (c) 1993,1995, R. Spronk }
|
||||
{ NOTE: These SPX calls are not documented in this version }
|
||||
|
||||
INTERFACE
|
||||
|
||||
Uses Dos,nwMisc,nwIPX;
|
||||
|
||||
{ Primary SPX calls: Subf: Comments:
|
||||
|
||||
SPXabortConnection 14
|
||||
SPXGetConnectionStatus 15
|
||||
SPXestablishConnection 11
|
||||
* SPXinitialize 10
|
||||
SPXlistenForConnection 12
|
||||
SPXlistenForSequencedPacket 17
|
||||
SPXsendSequencedPacket 16
|
||||
SPXTerminateConnection 13
|
||||
|
||||
Secondary calls:
|
||||
|
||||
* SPXpresent
|
||||
|
||||
Notes: (1) These functions use INT 21 and are not to be called from
|
||||
within an ESR.
|
||||
}
|
||||
|
||||
Var Result:word; { unit errorcode variable }
|
||||
|
||||
Type TspxHeader=Record
|
||||
IPXhdr :TipxHeader; { SPX will set packetType to 5 }
|
||||
connControl :byte; { rarely used, set to $00 }
|
||||
{ ignored by SPX, but passed on to receiver:
|
||||
$10 End of message; $20 Attention packet }
|
||||
dataStreamType:Byte; { to be used by higher level protocols.
|
||||
nust be < $FE, passed on to receiver }
|
||||
sourceConnId,
|
||||
destConnId :Word;
|
||||
sequenceNbr,
|
||||
acknowledgeNbr,
|
||||
allocationNbr :Word;
|
||||
end;
|
||||
{ Fields within IPX and SPX are high-low. Byte swapping will be done
|
||||
by the IPX functions, except network and node addresses. }
|
||||
|
||||
Type TSPXconnectionInformation
|
||||
=record
|
||||
ConnectionState :Byte; { all fields are returned hi-lo }
|
||||
WatchDogState :Byte;
|
||||
LocalSPXConnectionId :Word;
|
||||
RemoteSPXConnectionId :Word;
|
||||
SequenceNumber :Word;
|
||||
LocalAcknowledgeNumber :Word;
|
||||
LocalAllocationNumber :Word;
|
||||
RemoteAcknowledgeNumber:Word;
|
||||
RemoteAllocationNumber :Word;
|
||||
LocalSocket :Word;
|
||||
ImmediateAddress :TnodeAddress;
|
||||
RemoteAddress :TinterNetworkAddress;
|
||||
RetransmissionCount :Word;
|
||||
EstimatedRoundTripDelay:Word;
|
||||
RetransmittedPackets :Word;
|
||||
SuppressedPackets :Word;
|
||||
end;
|
||||
|
||||
Function SPXpresent:boolean;
|
||||
{ Determines if SPX is installed. Calls SPXInitialize. }
|
||||
|
||||
{IPX/SPX: 10h}
|
||||
Function SpxInitialize(Var SPXhiVer,SPXloVer:Byte;
|
||||
Var MaxConn,AvailConn:word):boolean;
|
||||
{ Determines if SPX is loaded. (this function also tests the presence of IPX, }
|
||||
{ as IPX is required for running SPX. Remember: Netware 2.2 allows IPX and SPX }
|
||||
{ to be loaded seperately, so only IPX may be present. }
|
||||
|
||||
{IPX/SPX: 11h}
|
||||
Function SPXestablishConnection(retryCount:byte; WatchdogFlag:Byte;
|
||||
{i/o} Var ECB:Tecb;
|
||||
{out} Var SPXconnectionID:Word):boolean;
|
||||
|
||||
{IPX/SPX: 12h}
|
||||
Function SPXlistenForConnection(retryCount:Byte; WatchdogFlag: Byte;
|
||||
Var ECB:Tecb ):boolean;
|
||||
|
||||
{IPX/SPX: 15h}
|
||||
Function SPXGetConnectionStatus(SPXconnectionID:word;
|
||||
Var connInfo:TSPXconnectionInformation):boolean;
|
||||
|
||||
{IPX/SPX: 13h}
|
||||
Function SPXTerminateConnection(SPXconnectionID:Word; ECB:Tecb):boolean;
|
||||
|
||||
{IPX/SPX: 14h}
|
||||
Function SPXabortConnection(SPXconnectionID:Word):boolean;
|
||||
|
||||
{IPX/SPX: 16h}
|
||||
Function SPXsendSequencedPacket(SPXconnectionID:Word; Var ECB:Tecb):boolean;
|
||||
|
||||
{IPX/SPX: 17h}
|
||||
Function SPXlistenForSequencedPacket(Var ECB:Tecb):boolean;
|
||||
|
||||
{************** Secondary Procedures ***************************************}
|
||||
|
||||
IMPLEMENTATION {==============================================================}
|
||||
|
||||
CONST
|
||||
SPX_WATCHDOG_ENABLED =1;
|
||||
SPX_WATCHDOG_DISABLED =0;
|
||||
SPX_DEFAULT_RETRY_COUNT =0;
|
||||
|
||||
SPX_POOL_SIZE =10;
|
||||
|
||||
SPX_MAX_DATA_LENGTH =534;
|
||||
|
||||
{IPX/SPX: 10 }
|
||||
Function SpxInitialize(Var SPXhiVer,SPXloVer:Byte;
|
||||
Var MaxConn,AvailConn:word):boolean;
|
||||
Var Regs:registers;
|
||||
begin
|
||||
With regs
|
||||
do begin
|
||||
al:=$00;
|
||||
bx:=$0010;
|
||||
IpxSpxSystemCall(Regs);
|
||||
result:=regs.al;
|
||||
|
||||
if AL<>$FF
|
||||
then begin
|
||||
result:=$FF;
|
||||
SpxInitialize:=false
|
||||
end
|
||||
else begin
|
||||
SPXhiVer:=BH;
|
||||
SPXloVer:=BL;
|
||||
MaxConn:=CX;
|
||||
AvailConn:=DX;
|
||||
result:=$00;
|
||||
SpxInitialize:=true;
|
||||
end;
|
||||
end; {with}
|
||||
{ resultcodes: $00 successfull (SPX installed); $FF SPX not installed }
|
||||
end;
|
||||
|
||||
Function SpxPresent:boolean;
|
||||
Var SpxHi,SpxLo:Byte;
|
||||
MaxConn,AvConn:word;
|
||||
begin
|
||||
SpxPresent:=( IpxPresent and SpxInitialize(SpxHi,SpxLo,MaxConn,AvConn) );
|
||||
end;
|
||||
|
||||
{IPX/SPX: 11h}
|
||||
Function SPXestablishConnection(retryCount:byte; WatchdogFlag:Byte;
|
||||
{i/o} Var ECB:Tecb;
|
||||
{out} Var SPXconnectionID:Word):boolean;
|
||||
Var regs:registers;
|
||||
begin
|
||||
With regs
|
||||
do begin
|
||||
BX:=$0011;
|
||||
AL:=retryCount;
|
||||
AH:=WatchDogFlag;
|
||||
ES:=Seg(ECB);
|
||||
SI:=ofs(ECB);
|
||||
end;
|
||||
IpxSpxSystemCall(Regs);
|
||||
result:=regs.AL;
|
||||
SPXconnectionID:=regs.DX;
|
||||
SPXestablishConnection:=(result=$00);
|
||||
{ resultcodes: $00 SPX Attempting to contact destination socket;
|
||||
$EF Local connection table full;
|
||||
$FD Fragment count not 1 AND/OR Buffer size not 42;
|
||||
$FF Send Socket not open OR IPX/SPX not initialized. }
|
||||
end;
|
||||
|
||||
|
||||
{IPX/SPX: 12h}
|
||||
Function SPXlistenForConnection(retryCount:Byte; WatchdogFlag: Byte;
|
||||
Var ECB:Tecb ):boolean;
|
||||
Var regs:Registers;
|
||||
begin
|
||||
With regs
|
||||
do begin
|
||||
BX:=$0012;
|
||||
AL:=retryCount;
|
||||
AH:=WatchdogFlag;
|
||||
ES:=Seg(ECB);
|
||||
SI:=Ofs(ECB);
|
||||
IpxSpxSystemCall(Regs);
|
||||
result:=AL;
|
||||
if result<>$FF
|
||||
then result:=$00;
|
||||
end;
|
||||
SPXlistenForConnection:=(result=$00);
|
||||
end;
|
||||
|
||||
{IPX/SPX: 15h}
|
||||
Function SPXGetConnectionStatus(SPXconnectionID:word;
|
||||
Var connInfo:TSPXconnectionInformation):boolean;
|
||||
Var regs:Registers;
|
||||
begin
|
||||
With regs
|
||||
do begin
|
||||
BX:=$0015;
|
||||
DX:=SPXconnectionID;
|
||||
ES:=Seg(connInfo);
|
||||
SI:=Ofs(connInfo);
|
||||
IpxSpxSystemCall(Regs);
|
||||
Result:=AL;
|
||||
end;
|
||||
if result=0
|
||||
then begin
|
||||
With ConnInfo
|
||||
do begin { force all returned words lo-hi }
|
||||
LocalSPXConnectionId :=Swap(LocalSPXconnectionID);
|
||||
RemoteSPXConnectionId :=Swap(RemoteSPXconnectionID);
|
||||
SequenceNumber :=swap(SequenceNumber);
|
||||
LocalAcknowledgeNumber :=swap(LocalAcknowledgeNumber);
|
||||
LocalAllocationNumber :=swap(LocalAllocationNumber);
|
||||
RemoteAcknowledgeNumber:=swap(RemoteAcknowledgeNumber);
|
||||
RemoteAllocationNumber :=swap(RemoteAllocationNumber);
|
||||
LocalSocket :=swap(LocalSocket);
|
||||
RemoteAddress.socket :=swap(remoteAddress.socket);
|
||||
RetransmissionCount :=swap(RetransmissionCount);
|
||||
EstimatedRoundTripDelay:=swap(EstimatedRoundTripDelay);
|
||||
RetransmittedPackets :=swap(RetransmittedPackets);
|
||||
SuppressedPackets :=swap(SuppressedPackets);
|
||||
end;
|
||||
end;
|
||||
SPXGetConnectionStatus:=(result=0);
|
||||
{ Resulcodes: $00 Connection is active; $EE No such connection }
|
||||
end;
|
||||
|
||||
|
||||
{IPX/SPX: 13h}
|
||||
Function SPXTerminateConnection(SPXconnectionID:Word; ECB:Tecb):boolean;
|
||||
Var regs:Registers;
|
||||
begin
|
||||
with regs
|
||||
do begin
|
||||
BX:=$0013;
|
||||
DX:=SPXconnectionID;
|
||||
ES:=seg(ECB);
|
||||
SI:=Ofs(ECB);
|
||||
end;
|
||||
IpxSpxSystemCall(Regs);
|
||||
result:=regs.al;
|
||||
if result<>$FF
|
||||
then result:=$00;
|
||||
SPXterminateConnection:=(result=0);
|
||||
{resultcodes: $00 SPX attempting to break connection;
|
||||
$FF IPX/SPX not loaded. }
|
||||
end;
|
||||
|
||||
{IPX/SPX: 14h}
|
||||
Function SPXabortConnection(SPXconnectionID:Word):boolean;
|
||||
Var regs:Registers;
|
||||
begin
|
||||
with regs
|
||||
do begin
|
||||
BX:=$0014;
|
||||
DX:=SPXconnectionID;
|
||||
end;
|
||||
IpxSpxSystemCall(Regs);
|
||||
result:=regs.al;
|
||||
if result<>$FF
|
||||
then result:=$00;
|
||||
SPXabortConnection:=(result=0);
|
||||
{resultcodes: $00 SPX trying to unilateral break the connection;
|
||||
$FF IPX/SPX not loaded. }
|
||||
end;
|
||||
|
||||
{IPX/SPX: 16h}
|
||||
Function SPXsendSequencedPacket(SPXconnectionID:Word; Var ECB:Tecb):boolean;
|
||||
Var regs:Registers;
|
||||
begin
|
||||
with regs
|
||||
do begin
|
||||
BX:=$0016;
|
||||
DX:=SPXconnectionID;
|
||||
ES:=Seg(ECB);
|
||||
SI:=Ofs(ECB);
|
||||
end;
|
||||
IpxSpxSystemCall(Regs);
|
||||
result:=regs.al;
|
||||
if result<>$FF
|
||||
then result:=$00;
|
||||
SPXsendSequencedPacket:=(result=0);
|
||||
{resultcodes: $00 SPX will attempt to send packet;
|
||||
$FF IPX/SPX not loaded. }
|
||||
end;
|
||||
|
||||
{IPX/SPX: 17h}
|
||||
Function SPXlistenForSequencedPacket(Var ECB:Tecb):boolean;
|
||||
Var regs:Registers;
|
||||
begin
|
||||
with regs
|
||||
do begin
|
||||
BX:=$0017;
|
||||
ES:=Seg(ECB);
|
||||
SI:=Ofs(ECB);
|
||||
end;
|
||||
IpxSpxSystemCall(Regs);
|
||||
result:=regs.al;
|
||||
if result<>$FF
|
||||
then result:=$00;
|
||||
SPXlistenForSequencedPacket:=(result=0);
|
||||
{resultcodes: $00 SPX waits for incoming packets;
|
||||
$FF IPX/SPX not loaded. }
|
||||
end;
|
||||
|
||||
{************** Secondary Procedures ***************************************}
|
||||
|
||||
end.
|
||||
198
NWTP/NWTP.FAQ
Normal file
198
NWTP/NWTP.FAQ
Normal file
@@ -0,0 +1,198 @@
|
||||
FAQ for the NWTP API
|
||||
====================
|
||||
|
||||
B01. How am I knwon at the server ?
|
||||
B02. How do I give someone Console Operator rights ?
|
||||
|
||||
C01. How can I reset the servertime ?
|
||||
C02. How can I synchronize the workstation's time to that of the server ?
|
||||
|
||||
L01. How can I place a limit on the number of concurrent users of my
|
||||
program ? (licensing)
|
||||
|
||||
M01. How can I send a message to another user ?
|
||||
|
||||
S01. How do I determine whether or not I'm logged into a server ?
|
||||
S02. Is the shell installed ?
|
||||
S03. What is the name of the server I'm logged into ?
|
||||
|
||||
******************************** Answers ********************************
|
||||
|
||||
B01. What name do I have ?
|
||||
--------------------------
|
||||
A: You are known at the server by two names: a short (object) name
|
||||
(i.e. the name you use to login) and a full name stored in the
|
||||
bindery.
|
||||
|
||||
Var SecurityLevel:Byte;
|
||||
ObjectID:Longint;
|
||||
ObjectType:Word;
|
||||
ObjectName,LongName:String;
|
||||
begin
|
||||
GetBinderyAccessLevel(SecurityLevel,ObjectID);
|
||||
GetBinderyObjectname(ObjectID,ObjectName,ObjectType);
|
||||
writeln('You''re known to the server as:',ObjectName);
|
||||
GetRealUserName(ObjectName,LongName);
|
||||
writeln('And to the supervisor as:',LongName);
|
||||
if LongName=''
|
||||
then writeln('<Your full name wasn''t set by the Supervisor>');
|
||||
end.
|
||||
|
||||
B02. How do I give someone Console Operator rights?
|
||||
---------------------------------------------------
|
||||
A: You'll have to add the ObjectID of the target user to the OPERATORS
|
||||
property of the supervisor object in the bindery. Note that having
|
||||
console operator rights differs significantly from being supervisor
|
||||
equivalent. Console operator rights allow the user to perform actions
|
||||
from a workstation that could also be done on the server console.
|
||||
|
||||
Var UserName:string;
|
||||
begin
|
||||
UserName='Goofy';
|
||||
IF NOT CreateProperty('SUPERVISOR',OT_USER,'OPERATORS',
|
||||
BF_SET or BF_STAT_OBJ,
|
||||
BS_LOGGED_READ or BS_SUPER_WRITE)
|
||||
then if nwBindry.result<>$ED { property already exists }
|
||||
then begin
|
||||
writeln('Error creating operators property.');
|
||||
Halt(1);
|
||||
end;
|
||||
|
||||
IF AddBinderyObjectToSet('SUPERVISOR',OT_USER,'OPERATORS',
|
||||
UserName,OT_USER)
|
||||
then writeln('User ',UserName,' is now a console operator.');
|
||||
end.
|
||||
|
||||
|
||||
C01. How can I reset the servertime ?
|
||||
-------------------------------------
|
||||
A: Use the SetFileServerDateAndTime function in the nwServ unit. In order
|
||||
for this call to be successful, you have to either be the supervisor
|
||||
or have console operator privileges.
|
||||
|
||||
Var newTime:TnovTime;
|
||||
begin
|
||||
WITH newTime
|
||||
do begin
|
||||
year:=94; month:=6; day:=1;
|
||||
hour:=5; min:=0; sec:=0;
|
||||
end;
|
||||
IF NOT SetFileServerDateAndTime(newTime)
|
||||
then writeln('You need to have console operator rights.');
|
||||
end.
|
||||
|
||||
C02. How can I synchronize the workstation's time to that of the server ?
|
||||
-------------------------------------------------------------------------
|
||||
A: Use Pascal's SetTime and SetDate functions in combination with the
|
||||
GetFileServerDateAndTime function.
|
||||
|
||||
Var time:TnovTime;
|
||||
year:word;
|
||||
begin
|
||||
GetFileServerDateAndTime(time);
|
||||
if time.year<80
|
||||
then year:=2000+time.year
|
||||
else year:=1900+time.year;
|
||||
setdate(year,time.month,time.day);
|
||||
settime(time.hour,time.minute,time.second,0);
|
||||
end.
|
||||
|
||||
L01. How can I place a limit on the number of concurrent users of my program ?
|
||||
------------------------------------------------------------------------------
|
||||
A: Use the semaphore functions in the nwSema unit. Note that these enable
|
||||
you to limit the number of concurrent users on a server basis. When a
|
||||
user is refused access because the limit for his current fileserver is
|
||||
exceeded, he can simply login to another fileserver (if available) and
|
||||
try to use the program there. Limiting the number of concurrent users
|
||||
on multiple servers in an internetwork is quite a problem: Novell doesn't
|
||||
provide a method to synchronize semaphore values between servers.
|
||||
|
||||
|
||||
CONST
|
||||
INITIAL_SEMAPHORE_VALUE=10;
|
||||
{ suppose a licence for 10 concurrent users }
|
||||
SEMAPHORE_NAME='YourProgramName';
|
||||
{ anything goes, as long as it's unique. Max. 128 characters.}
|
||||
|
||||
VAR openCount :Word;
|
||||
semValue :Integer;
|
||||
semHandle :LongInt;
|
||||
|
||||
BEGIN {main}
|
||||
|
||||
{ Open Semaphore }
|
||||
semValue := INITIAL_SEMAPHORE_VALUE;
|
||||
{ Need in case we're creating the semaphore }
|
||||
IF NOT OpenSemaphore( SEMAPHORE_NAME, semValue, semHandle, openCount )
|
||||
then begin
|
||||
writeln('Error opening semaphore. error #',nwSema.Result);
|
||||
Halt(1);
|
||||
end;
|
||||
{ Wait on the Semaphore (get permission to use the program) }
|
||||
IF NOT WaitOnSemaphore( semHandle, 0 )
|
||||
then begin
|
||||
if ( nwSema.Result = $FE )
|
||||
then begin
|
||||
writeln( 'Sorry, license exceeded. Please try again later.' );
|
||||
halt(1);
|
||||
end
|
||||
else begin
|
||||
writeln('WaitOnSemaphore returned eror# ',nwSema.result);
|
||||
halt(1);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ <===== INSERT YOUR to be licensed PROGRAM HERE =====> }
|
||||
|
||||
{ Signal Semaphore (that we're through with the program) }
|
||||
SignalSemaphore( semHandle );
|
||||
{ Close Semaphore }
|
||||
CloseSemaphore( semHandle );
|
||||
end.
|
||||
|
||||
|
||||
|
||||
M01. How can I send a message to another user ?
|
||||
-----------------------------------------------
|
||||
A: Use the SendMessageToUser function in the nwMess unit. This
|
||||
function allows you to send a message to a user or to the members
|
||||
of a group. If there are more than 64 members in the group, only the
|
||||
first 64 members of the group will receive the message due to the way
|
||||
this function is implemented on the server.
|
||||
|
||||
var name : string;
|
||||
message : string;
|
||||
begin
|
||||
name := 'MBRAMWEL';
|
||||
message := 'Hi Mark, how is it going?';
|
||||
SendMessageToUser(name,message);
|
||||
SendMessageToUser('FINANCE_DEPT','Hand over the money..');
|
||||
SendMessageToUser('*','Goodmorning');
|
||||
end.
|
||||
|
||||
Note that unlike the messages broadcasted by the SEND utility, the
|
||||
source of the message is not automatically put in the message itself.
|
||||
|
||||
S01. How do I determine whether or not I'm logged into a server ?
|
||||
-----------------------------------------------------------------
|
||||
A: Use the nwBindr IsUserLoggedOn function.
|
||||
|
||||
|
||||
S02. Is the shell installed ?
|
||||
----------------------------------------------
|
||||
A: Use the nwBindy IsShellLoaded function or query the variables
|
||||
NETX_EXE_Loaded or VLM_EXE_Loaded. (see nwIntr)
|
||||
|
||||
|
||||
S03. What is the name of the server I'm logged into ?
|
||||
-----------------------------------------------------
|
||||
A: If you already know that you're logged in:
|
||||
|
||||
Var ConnId:Byte;
|
||||
ServerName:string;
|
||||
begin
|
||||
GetEffectiveConnectionID(ConnId);
|
||||
IF GetFileserverName(connId,ServerName)
|
||||
then Writeln('You''re logged into server :',ServerName);
|
||||
end.
|
||||
|
||||
BIN
NWTP/NWTP.TPH
Normal file
BIN
NWTP/NWTP.TPH
Normal file
Binary file not shown.
9
NWTP/NWTP06.TXT
Normal file
9
NWTP/NWTP06.TXT
Normal file
@@ -0,0 +1,9 @@
|
||||
Netware Interface Units for Pascal.
|
||||
(Novell Netware 3.x and TP/BP 6.x/7.x)
|
||||
Freeware. Full sources, over 300 kb. of
|
||||
documentation and lots of examples. The
|
||||
most complete API available for PASCAL.
|
||||
KEYWORDS: LAN, Network, Novell, API,
|
||||
Library, Bindery, IPX, SPX, Queue,
|
||||
Tool, Reference, Workstation, Client,
|
||||
Real Mode, Protected Mode, Windows.
|
||||
22
NWTP/README.1ST
Normal file
22
NWTP/README.1ST
Normal file
@@ -0,0 +1,22 @@
|
||||
Netware Interface Libraries for Borland/Turbo Pascal (NwTP) version 0.6
|
||||
=======================================================================
|
||||
|
||||
A set of libraries (units) that allow Pascal programmers to write
|
||||
Netware-aware programs. Includes functionalty ranging from reading
|
||||
the bindery to multi-threaded peer tot peer communication. Supports
|
||||
Real, DPMI, and Windows protected mode. Full sources included. Fully
|
||||
documented. Ample examples.
|
||||
|
||||
Required: -Knowledge of Pascal;
|
||||
-BP/TP 6.x/7.x
|
||||
-Netware 2.15c/2.2/3.x
|
||||
|
||||
A few notes on some files:
|
||||
|
||||
README.EXE Full documentation
|
||||
NWTP .TPH Turbo Pascal helpfile, use within the 7.x IDE or with THELP.
|
||||
See Readme.EXE for help on how to install.
|
||||
|
||||
NW____.PAS Source code of the units
|
||||
X_____.ZIP Source code of examples
|
||||
REL .TXT Release note
|
||||
BIN
NWTP/README.EXE
Normal file
BIN
NWTP/README.EXE
Normal file
Binary file not shown.
96
NWTP/REL.TXT
Normal file
96
NWTP/REL.TXT
Normal file
@@ -0,0 +1,96 @@
|
||||
Netware Interface Libraries for Borland/Turbo Pascal (NwTP)
|
||||
===========================================================
|
||||
|
||||
> Release note for NwTP Version 0.6
|
||||
|
||||
NwTP is a set of libraries (units) that allow Pascal
|
||||
programmers to write Netware-aware programs. Included
|
||||
functionalty ranges from reading the bindery to multi-
|
||||
threaded IPX peer tot peer communication.
|
||||
|
||||
> Some characteristics:
|
||||
|
||||
-Over 250 interface functions / Full sources included
|
||||
-Bindery, Connection, Workstation, Server, Message,
|
||||
Semaphore, Locking, Accounting and Communication services
|
||||
-More than 500 Kb of documentation (English)
|
||||
-Turbo Pascal Helpfile (use within the IDE or with THELP)
|
||||
-Real mode, DPMI and Windows protected mode supported
|
||||
-Numerous examples & testprograms (over 200 kb.)
|
||||
-Free software (GNU)
|
||||
|
||||
If I may be so bold as to quote some users:
|
||||
|
||||
> .... die Unit-Sammlung NwTP, da ist alles dabei,
|
||||
> was ein Novell-Herz h”her schlagen l„sst :-))
|
||||
---------
|
||||
Wenn es NWTP nicht kostenlos geben wuerde, ich muessste es
|
||||
glatt kaufen, vor allendingen, weil [der Author sich] die
|
||||
Arbeit gemacht hat, Hilfs Files fuer Pascal dazu zu schreiben.
|
||||
Ich muss sagen ich finde das Paket in seiner jetzigen
|
||||
Ausbaustufe fuer mich (und bestimmt auch fuer andere) voll
|
||||
gut. Es beinhaltet alles was ich fuers taegliche Novell
|
||||
Client Leben brauche.
|
||||
|
||||
> Een een echt goede gedocumenteerde unit voor Netware !
|
||||
> Ik heb er al naar gekeken en denk dat ik toch wel aardig
|
||||
> wat aardigheidjes voor ons netwerk [..] kan maken :))
|
||||
-------
|
||||
Een heel interessante verzameling van routines die ik prima
|
||||
kan gebruiken bij het schrijven van NetWare-aware programma's.
|
||||
|
||||
> ..when NWTP wouldn't be free, I'd have to buy it, especially
|
||||
> since help files are included.
|
||||
--------
|
||||
.. the Unit collection NWTP, which has everything to make a Novell
|
||||
minded heart beat somewhat faster ;-))
|
||||
|
||||
(Woops.. back to Earth again: )
|
||||
|
||||
>*** A few Notes:
|
||||
|
||||
-NwTP V0.6, Netware API for TP.
|
||||
Copyright (C) 1993,1995 by R.Spronk
|
||||
NwTP is free software; The terms of the GNU General Public
|
||||
License as published by the Free Software Foundation apply.
|
||||
|
||||
-Minimum Development Environment
|
||||
- NetWare 2.15c+ / 3.x
|
||||
- Turbo/Borland Pascal Compiler (6.x/7.x)
|
||||
|
||||
>*** Availability
|
||||
|
||||
Anonymous FTP:
|
||||
|
||||
novftp.rc.rug.nl:/proglibs/NWTP06.ZIP
|
||||
|
||||
Filerequest/Downloads:
|
||||
|
||||
Germany 04:30-02:30 CET [UTC+1]
|
||||
Heinz Veenker NWTP (Magic Filename)
|
||||
Smalltown BBS 2:2426/4030 V.FC/V.32B +49-5935-1224
|
||||
2:2426/4031 ZyX+/V.32B +49-5935-1225
|
||||
2:2426/4032 V.34/V.FC +49-5935-1226
|
||||
2:2426/4033 ISDN X.75/V.110 +49-5935-925254
|
||||
Downloading of NWTP at first logon is supported.
|
||||
|
||||
Germany 00:00-24:00
|
||||
Stefan Braunstein NWTP (Magic Filename)
|
||||
Pandora BBS 2:2476/709, Zyxel E+ +49-781-65066
|
||||
2:2476/719, Creatix 1400 (mail only system)
|
||||
Downloading of NWTP at first logon is supported.
|
||||
|
||||
The Netherlands 08:30-02:00 CET [UTC+1]
|
||||
Rolf Mulder NWTP (Magic Filename)
|
||||
Fawlty Towers 2:282/601 Tron 28k8 +31-50-717051
|
||||
|
||||
Osterreich 00:00-24:00
|
||||
Josef Braun NWTP (Magic filename)
|
||||
Joe's BBS Corner 2:313/2 28k8 +43-2758-3357
|
||||
2:313/22 19k2 +43-2758-3233
|
||||
No downloading at first logon. Use guest account.
|
||||
|
||||
United Kingdom 03:30-02:30 GMT [UTC]
|
||||
Michael Turner NWTP (Magic Filename)
|
||||
Wizard's Haunt 2:254/80 +44-181-491-0795
|
||||
Downloading of NWTP at first logon is supported.
|
||||
3
NWTP/THELP.CFG
Normal file
3
NWTP/THELP.CFG
Normal file
@@ -0,0 +1,3 @@
|
||||
/fC:\BP\BIN\TURBO.TPH
|
||||
/fC:\BP\BIN\TVISION.TPH
|
||||
/fC:\BP\BIN\NWTP.TPH
|
||||
BIN
NWTP/THELP.COM
Normal file
BIN
NWTP/THELP.COM
Normal file
Binary file not shown.
63
NWTP/XACCT/ACCT.PAS
Normal file
63
NWTP/XACCT/ACCT.PAS
Normal file
@@ -0,0 +1,63 @@
|
||||
Program ACCT;
|
||||
|
||||
{ Example for the NwAcct unit / NWTP 0.6, (c) 1995, R. Spronk }
|
||||
{ Displays all login/logout account notes in the HET$ACCT.DAT file. }
|
||||
|
||||
uses nwMisc,nwAcct;
|
||||
|
||||
LABEL q;
|
||||
|
||||
{$I-}
|
||||
Var f:File of byte;
|
||||
|
||||
b,b2 :Byte;
|
||||
t,w :word;
|
||||
s :string;
|
||||
nTime:TnovTime;
|
||||
|
||||
buf :Array[1..4096] of byte;
|
||||
NoteAKA :TNoteRecord ABSOLUTE buf;
|
||||
ChargeAKA:TChargeRecord ABSOLUTE buf;
|
||||
|
||||
Begin
|
||||
FileMode:=0; {open file read-only }
|
||||
assign(f,'F:\system\net$acct.dat');
|
||||
reset(f);
|
||||
IF Ioresult<>0
|
||||
then begin
|
||||
writeln('Accounting file couldn''t be found..');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
REPEAT
|
||||
read(f,b); {length of record}
|
||||
read(f,b2);
|
||||
If IOresult<>0 then goto q;
|
||||
buf[1]:=b2;
|
||||
buf[2]:=b;
|
||||
for t:=1 to NoteAKA.Length
|
||||
do begin
|
||||
read(f,buf[t+2]);
|
||||
if IOresult>0 then goto q;
|
||||
end;
|
||||
IF (NoteAKA.RecType=RT_ACCOUNT_NOTE) and (swap(NoteAKA.CommentType) IN [3,4])
|
||||
then with NoteAKA
|
||||
do begin
|
||||
If swap(CommentType)=3
|
||||
then write('Logon of ')
|
||||
else write('Logoff of ');
|
||||
write(HexStr(Lswap(ClientObjId),8));
|
||||
write(' from address ',HexDumpStr(Comment.Net,8),':',
|
||||
HexDumpStr(Comment.Node,12));
|
||||
Move(TimeStamp,ntime.year,6);
|
||||
ntime.dayOfWeek:=0;
|
||||
NovTime2String(ntime,s);delete(s,1,4);
|
||||
write(' at: ',s);
|
||||
|
||||
writeln;
|
||||
end;
|
||||
UNTIL eof(f);
|
||||
|
||||
q: ;
|
||||
close(f);
|
||||
end.
|
||||
171
NWTP/XACCT/TSTACCT.PAS
Normal file
171
NWTP/XACCT/TSTACCT.PAS
Normal file
@@ -0,0 +1,171 @@
|
||||
{$X+,V-,B-}
|
||||
Program tstacct; {as of 940601}
|
||||
|
||||
{ Testprogram for the nwAcct unit / NwTP 0.5 API. (c) 1993,1994, R.Spronk }
|
||||
|
||||
{ Tests the following nwAcct functions:
|
||||
|
||||
AccountingInstalled
|
||||
AddAccountingServer
|
||||
DeleteAccountHolds
|
||||
DeleteAccountingServer
|
||||
GetAccountStatus
|
||||
SetAccountStatus
|
||||
SubmitAccountCharge
|
||||
SubmitAccountHold
|
||||
SubmitAccountNote
|
||||
}
|
||||
|
||||
uses nwBindry,nwConn,nwAcct;
|
||||
|
||||
CONST testObjName='TEST';
|
||||
|
||||
Var connId :byte;
|
||||
currServer:string;
|
||||
balance,limit,holds :Longint;
|
||||
newBalance,newLimit :LongInt;
|
||||
nCharge,nCancelHoldAmount:Longint;
|
||||
oldBalance,Oldholds :LongInt;
|
||||
|
||||
begin
|
||||
writeln('Test of the accounting functions.');
|
||||
writeln;
|
||||
writeln('You have to be logged in as SUPERVISOR');
|
||||
writeln('User ',testObjName,' has to exists. (hardcoded in source, change if needed).');
|
||||
writeln;
|
||||
If NOT AccountingInstalled
|
||||
then begin
|
||||
writeln('error#:',nwAcct.result);
|
||||
write('Err:Accounting isn''t installed on the current effective server:');
|
||||
GetEffectiveConnectionID(ConnID);
|
||||
GetFileServerName(connId,currServer);
|
||||
writeln(currServer);
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
AddAccountingServer('SUPERVISOR',OT_USER);
|
||||
|
||||
|
||||
IF GetAccountStatus(testObjName,OT_USER,balance,limit,holds)
|
||||
then begin
|
||||
writeln('Current account status for user ',testObjName,' :');
|
||||
writeln('Balance :',balance);
|
||||
writeln('Credit Limit:',limit);
|
||||
writeln('Holds :',holds);
|
||||
end
|
||||
else writeln('Err: GetAccountStatus failed. error #',nwAcct.result);
|
||||
|
||||
writeln('Setting new account values..');
|
||||
newBalance:=1020304;
|
||||
newLimit:=123456;
|
||||
IF NOT SetAccountStatus(testObjName,OT_USER,newBalance,newLimit)
|
||||
then writeln('Err: SetAccountStatus failed. error #',nwAcct.result);
|
||||
|
||||
IF GetAccountStatus(testObjName,OT_USER,balance,limit,holds)
|
||||
then begin
|
||||
writeln('Current account status for user ',testObjName,' :');
|
||||
writeln('Balance :',balance);
|
||||
writeln('Credit Limit:',limit);
|
||||
writeln('Holds :',holds);
|
||||
if (balance<>newBalance) or (newLimit<>Limit)
|
||||
then writeln('Err: the new account values where not set!');
|
||||
end
|
||||
else writeln('Err: GetAccountStatus failed. error #',nwAcct.result);
|
||||
|
||||
OldBalance:=balance;
|
||||
nCharge:=100;
|
||||
nCancelHoldAmount:=0;
|
||||
Writeln('Submitting an account charge. charge=',ncharge,',CancelHold=',ncancelholdamount);
|
||||
IF NOT SubmitAccountCharge(testObjName,OT_USER,nCharge,nCancelHoldAmount,
|
||||
OT_USER,0,'no note')
|
||||
then writeln('Err: SubmitAccountCharge failed. error #',nwAcct.result);
|
||||
|
||||
IF GetAccountStatus(testObjName,OT_USER,balance,limit,holds)
|
||||
then begin
|
||||
writeln('Current account status for user ',testObjName,' :');
|
||||
writeln('Balance :',balance);
|
||||
writeln('Credit Limit:',limit);
|
||||
writeln('Holds :',holds);
|
||||
if (balance<>(oldBalance-nCharge))
|
||||
then writeln('Err: the account charge was not carried out !');
|
||||
end
|
||||
else writeln('Err: GetAccountStatus failed. error #',nwAcct.result);
|
||||
|
||||
|
||||
OldBalance:=balance;
|
||||
nCharge:=-200;
|
||||
nCancelHoldAmount:=0;
|
||||
Writeln('Submitting a NEGATIVE account charge. charge=',ncharge,',CancelHold=',ncancelholdamount);
|
||||
Writeln(' (in fact increasing the balance of the ',testObjName,' object.');
|
||||
IF NOT SubmitAccountCharge(testObjName,OT_USER,nCharge,nCancelHoldAmount,
|
||||
OT_USER,99,'charge! charge!')
|
||||
then writeln('Err: SubmitAccountCharge failed. error #',nwAcct.result);
|
||||
|
||||
IF GetAccountStatus(testObjName,OT_USER,balance,limit,holds)
|
||||
then begin
|
||||
writeln('Current account status for user ',testObjName,' :');
|
||||
writeln('Balance :',balance);
|
||||
writeln('Credit Limit:',limit);
|
||||
writeln('Holds :',holds);
|
||||
if (balance<>(oldBalance-nCharge))
|
||||
then writeln('Err: the account charge was not carried out !');
|
||||
end
|
||||
else writeln('Err: GetAccountStatus failed. error #',nwAcct.result);
|
||||
|
||||
OldHolds:=holds;
|
||||
writeln('Submit an hold in the amount of 1234');
|
||||
IF SubmitAccountHold(testObjName,OT_USER,1234)
|
||||
then begin
|
||||
GetAccountStatus(testObjName,OT_USER,balance,limit,holds);
|
||||
writeln('Current account status for user ',testObjName,' :');
|
||||
writeln('Balance :',balance);
|
||||
writeln('Credit Limit:',limit);
|
||||
writeln('Holds :',holds);
|
||||
|
||||
if (holds<>(OldHolds+1234))
|
||||
then writeln('Err: the account hold was not carried out !');
|
||||
end
|
||||
else writeln('Err: SubmitAccountHold failed. error #',nwAcct.result);
|
||||
|
||||
Writeln('Submit a charge of 1000, unhold 1234');
|
||||
OldHolds:=holds;
|
||||
nCharge:=1000;
|
||||
nCancelHoldAmount:=1234;
|
||||
IF SubmitAccountCharge(testObjName,OT_USER,nCharge,nCancelHoldAmount,
|
||||
OT_USER,99,'let''s charge a few bucks :-)')
|
||||
then begin
|
||||
GetAccountStatus(testObjName,OT_USER,balance,limit,holds);
|
||||
writeln('Current account status for user ',testObjName,' :');
|
||||
writeln('Balance :',balance);
|
||||
writeln('Credit Limit:',limit);
|
||||
writeln('Holds :',holds);
|
||||
|
||||
if (holds<>(OldHolds-1234))
|
||||
then writeln('Err: the account hold was not carried out !');
|
||||
end
|
||||
else writeln('Err: SubmitAccountHold failed. error #',nwAcct.result);
|
||||
|
||||
IF DeleteAccountHolds(testObjName,OT_USER)
|
||||
then begin
|
||||
writeln('All further holds bythis accounting server were released.');
|
||||
GetAccountStatus(testObjName,OT_USER,balance,limit,holds);
|
||||
writeln('Current account status for user ',testObjName,' :');
|
||||
writeln('Balance :',balance);
|
||||
writeln('Credit Limit:',limit);
|
||||
writeln('Holds :',holds);
|
||||
end
|
||||
else writeln('Err: DeleteAccountHolds failed. error #',nwAcct.result);
|
||||
|
||||
IF SubmitAccountNote(testObjName,OT_USER,
|
||||
OT_USER,99,'<<TEST OF ACCOUNTNOTE>>')
|
||||
then begin
|
||||
writeln('Accountnote was submitted correctly.');
|
||||
writeln('Please use a hexeditor and have look at \system\net$acct.dat');
|
||||
writeln('to check if the accountnote was added to the file.');
|
||||
end
|
||||
else writeln('Err: SubmitAccountNote failed. error #',nwAcct.result);
|
||||
|
||||
IF NOT DeleteAccountingServer('SUPERVISOR',1)
|
||||
then writeln('Err: DeleteAccountServer failed. error #',nwacct.result);
|
||||
|
||||
end.
|
||||
143
NWTP/XBINDRY/BACKBIN.PAS
Normal file
143
NWTP/XBINDRY/BACKBIN.PAS
Normal file
@@ -0,0 +1,143 @@
|
||||
{$X+,B-,V-,S-,I-} {essential compiler directives}
|
||||
|
||||
Program Backbin; { as of 950301}
|
||||
|
||||
{ Example for the nwBindry unit / NwTP 0.6 API. (c) 1994,1995 R.Spronk }
|
||||
|
||||
{ Purpose: Backs up the bindery files to the a: drive. }
|
||||
{ You need to be supervisor-equivalent to run this. }
|
||||
|
||||
{ Tests the following nwBindry calls:
|
||||
|
||||
OpenBindery
|
||||
CloseBindery
|
||||
}
|
||||
|
||||
Uses DOS,nwMisc,nwBindry;
|
||||
|
||||
Var BindSeq:byte;
|
||||
myObjID:LongInt;
|
||||
Version:word;
|
||||
s :string;
|
||||
|
||||
LABEL enable;
|
||||
|
||||
Procedure FileCopy(fn1,fn2:string);
|
||||
LABEL 1;
|
||||
Var f1,f2 :file;
|
||||
buffer :array[1..4096] of byte;
|
||||
BytesRead:word;
|
||||
begin
|
||||
assign(f1,fn1);
|
||||
reset(f1,1);
|
||||
if ioresult<>0
|
||||
then begin
|
||||
writeln('Error opening input file:',fn1);
|
||||
writeln('>> File wasn''t copied.');
|
||||
goto 1;
|
||||
end;
|
||||
assign(f2,fn2);
|
||||
rewrite(f2,1);
|
||||
if ioresult<>0
|
||||
then begin
|
||||
writeln('Error opening output file :',fn2);
|
||||
writeln('>> File wasn''t copied.');
|
||||
goto 1;
|
||||
end;
|
||||
REPEAT
|
||||
BlockRead(f1,buffer[1],4096,BytesRead);
|
||||
BlockWrite(f2,buffer[1],BytesRead);
|
||||
UNTIL (BytesRead<4096);
|
||||
1: ;
|
||||
close(f1);
|
||||
close(f2);
|
||||
{$I+}
|
||||
end;
|
||||
|
||||
|
||||
begin
|
||||
writeln('BACKBIN Test program for the nwBindry unit of the NwTP package.');
|
||||
writeln('-Backs up the bindery files to drive A');
|
||||
writeln;
|
||||
|
||||
IF NOT IsShellLoaded
|
||||
then begin
|
||||
writeln('Load network shell before executing this program.');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
{ need supervisor privileges to run this test }
|
||||
GetBinderyAccessLevel(BindSeq,myObjId);
|
||||
if bindSeq<>(BS_SUPER_WRITE OR BS_SUPER_READ) { $33}
|
||||
then begin
|
||||
writeln('You need to be supervisor equivalent to run this program.');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
writeln;
|
||||
writeln('WARNING:');
|
||||
writeln('Continue this program ONLY WHEN:');
|
||||
writeln('-You are the only user logged in.');
|
||||
writeln('-No other users will login in next few minutes.');
|
||||
writeln('-You are running Netware 2.15c, 2.2 or 3.x');
|
||||
writeln('-A diskette with sufficient space is in the A drive.');
|
||||
writeln;
|
||||
writeln('-If you have doubts about any of the above points: PLEASE ABORT NOW');
|
||||
writeln('-This program was made for test purposes only.');
|
||||
writeln;
|
||||
write('Type Y <return> to continue, <return> to abort.');
|
||||
readln(s);
|
||||
if NOT ( s[1] IN ['y','Y'])
|
||||
then begin
|
||||
writeln('Program aborted..');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
{determine Advanced Netware version. }
|
||||
nwMisc.GetNWVersion(version);
|
||||
|
||||
if (Version<215) or (version>399)
|
||||
then begin
|
||||
writeln('This util only works with NW 2.15+ or 3.x');
|
||||
writeln('The bindery files were NOT backed up.');
|
||||
halt(1);
|
||||
end;
|
||||
version:=(version DIV 100);
|
||||
|
||||
{Note for final version: make sure no users are logged in. (NwConn functions)}
|
||||
{Note for final version: disable user login (see nwServ) }
|
||||
|
||||
{close the bindery to backup the files..}
|
||||
IF NOT CloseBindery
|
||||
then begin
|
||||
writeln('Couldn''t close the bindery.');
|
||||
writeln('The bindery files were NOT backed up');
|
||||
writeln('Error : $',HexStr(NwBindry.Result,2));
|
||||
goto enable;
|
||||
end;
|
||||
|
||||
{back up the bindery files}
|
||||
if version=2
|
||||
then begin
|
||||
FileCopy('SYS:\SYSTEM\NET$BIND.SYS','A:\NET$BIND.OLD');
|
||||
FileCopy('SYS:\SYSTEM\NET$BVAL.SYS','A:\NET$BVAL.OLD');
|
||||
end
|
||||
else begin {3.x}
|
||||
FileCopy('SYS:\SYSTEM\NET$OBJ.SYS' ,'A:\NET$OBJ.OLD');
|
||||
FileCopy('SYS:\SYSTEM\NET$PROP.SYS','A:\NET$PROP.OLD');
|
||||
FileCopy('SYS:\SYSTEM\NET$VAL.SYS' ,'A:\NET$VAL.OLD');
|
||||
end;
|
||||
|
||||
{open the bindery again}
|
||||
IF NOT OpenBindery
|
||||
then begin
|
||||
writeln('Couldn''t open the bindery after copying the bindery files.');
|
||||
writeln('Error : $',HexStr(NwBindry.Result,2),' (',NwBindry.result,')');
|
||||
end
|
||||
else writeln('The bindery files were successfully backed up.');
|
||||
|
||||
{Note for final version: enable users to login (see nwServ) }
|
||||
|
||||
enable: ;
|
||||
|
||||
end.
|
||||
69
NWTP/XBINDRY/NEW.TXT
Normal file
69
NWTP/XBINDRY/NEW.TXT
Normal file
@@ -0,0 +1,69 @@
|
||||
ScanBind V1.2
|
||||
Provides information about all accessible bindery objects.
|
||||
All objects with a read security level <= Sup (3) will be shown.
|
||||
|
||||
01000001 EVERYONE
|
||||
The object type is :User group
|
||||
The object is a static object.
|
||||
Security: Read: Log (1) / Write: Sup (3)
|
||||
The object has the following properties:
|
||||
GROUP_MEMBERS (Static Set-Property)
|
||||
Security: Read: Log (1) /Write: Sup (3)
|
||||
*SUPERVISOR (User)(00000001)
|
||||
*DALEK (User)(00010002)
|
||||
*TARDIS (User)(00010003)
|
||||
|
||||
00010002 DALEK
|
||||
The object type is :User
|
||||
The object is a static object.
|
||||
Security: Read: Log (1) / Write: Sup (3)
|
||||
The object has the following properties:
|
||||
UNIX_USER (Static Item-Property)
|
||||
Security: Read: Any (0) /Write: Sup (3)
|
||||
*64 61 6C 65 6B 00 00 00 00 00 00 00 00 00 00 00 dalek
|
||||
SECURITY_EQUALS (Static Set-Property)
|
||||
Security: Read: Obj (2) /Write: Sup (3)
|
||||
*EVERYONE (Group)(01000001)
|
||||
GROUPS_I'M_IN (Static Set-Property)
|
||||
Security: Read: Log (1) /Write: Sup (3)
|
||||
*EVERYONE (Group)(01000001)
|
||||
|
||||
03000001 DOCTORWHO
|
||||
The object type is :Fileserver
|
||||
The object is a dynamic object.
|
||||
Security: Read: Any (0) / Write: Netw(4)
|
||||
The object has the following properties:
|
||||
NET_ADDRESS (Static property), Property type= 1 (Unknown, not Item or Set)
|
||||
Security: Read: Any (0) /Write: Netw(4)
|
||||
*C0 A8 01 02 00 00 00 00 00 01 04 51 00 00 00 00 <20><> Q
|
||||
|
||||
00000001 SUPERVISOR
|
||||
The object type is :User
|
||||
The object is a static object.
|
||||
Security: Read: Log (1) / Write: Sup (3)
|
||||
The object has the following properties:
|
||||
GROUPS_I'M_IN (Static Set-Property)
|
||||
Security: Read: Log (1) /Write: Sup (3)
|
||||
*EVERYONE (Group)(01000001)
|
||||
UNIX_USER (Static Item-Property)
|
||||
Security: Read: Any (0) /Write: Sup (3)
|
||||
*72 6F 6F 74 00 00 00 00 00 00 00 00 00 00 00 00 root
|
||||
SECURITY_EQUALS (Static Set-Property)
|
||||
Security: Read: Obj (2) /Write: Sup (3)
|
||||
*EVERYONE (Group)(01000001)
|
||||
|
||||
00010003 TARDIS
|
||||
The object type is :User
|
||||
The object is a static object.
|
||||
Security: Read: Log (1) / Write: Sup (3)
|
||||
The object has the following properties:
|
||||
GROUPS_I'M_IN (Static Set-Property)
|
||||
Security: Read: Log (1) /Write: Sup (3)
|
||||
*EVERYONE (Group)(01000001)
|
||||
UNIX_USER (Static Item-Property)
|
||||
Security: Read: Any (0) /Write: Sup (3)
|
||||
*74 61 72 64 69 73 00 00 00 00 00 00 00 00 00 00 tardis
|
||||
SECURITY_EQUALS (Static Set-Property)
|
||||
Security: Read: Obj (2) /Write: Sup (3)
|
||||
*EVERYONE (Group)(01000001)
|
||||
|
||||
53
NWTP/XBINDRY/NEW2.TXT
Normal file
53
NWTP/XBINDRY/NEW2.TXT
Normal file
@@ -0,0 +1,53 @@
|
||||
ScanBind V1.2
|
||||
Provides information about all accessible bindery objects.
|
||||
All objects with a read security level <= Sup (3) will be shown.
|
||||
|
||||
01000001 EVERYONE
|
||||
The object type is :User group
|
||||
The object is a static object.
|
||||
Security: Read: Log (1) / Write: Sup (3)
|
||||
The object has the following properties:
|
||||
GROUP_MEMBERS (Static Set-Property)
|
||||
Security: Read: Log (1) /Write: Sup (3)
|
||||
*SUPERVISOR (User)(00000001)
|
||||
*DALEK (User)(00010002)
|
||||
|
||||
00010002 DALEK
|
||||
The object type is :User
|
||||
The object is a static object.
|
||||
Security: Read: Log (1) / Write: Sup (3)
|
||||
The object has the following properties:
|
||||
UNIX_USER (Static Item-Property)
|
||||
Security: Read: Any (0) /Write: Sup (3)
|
||||
*64 61 6C 65 6B 00 00 00 00 00 00 00 00 00 00 00 dalek
|
||||
SECURITY_EQUALS (Static Set-Property)
|
||||
Security: Read: Obj (2) /Write: Sup (3)
|
||||
*EVERYONE (Group)(01000001)
|
||||
GROUPS_I'M_IN (Static Set-Property)
|
||||
Security: Read: Log (1) /Write: Sup (3)
|
||||
*EVERYONE (Group)(01000001)
|
||||
|
||||
03000001 DOCTORWHO
|
||||
The object type is :Fileserver
|
||||
The object is a dynamic object.
|
||||
Security: Read: Any (0) / Write: Netw(4)
|
||||
The object has the following properties:
|
||||
NET_ADDRESS (Static property), Property type= 1 (Unknown, not Item or Set)
|
||||
Security: Read: Any (0) /Write: Netw(4)
|
||||
*C0 A8 01 02 00 00 00 00 00 01 04 51 00 00 00 00 <20><> Q
|
||||
|
||||
00000001 SUPERVISOR
|
||||
The object type is :User
|
||||
The object is a static object.
|
||||
Security: Read: Log (1) / Write: Sup (3)
|
||||
The object has the following properties:
|
||||
GROUPS_I'M_IN (Static Set-Property)
|
||||
Security: Read: Log (1) /Write: Sup (3)
|
||||
*EVERYONE (Group)(01000001)
|
||||
UNIX_USER (Static Item-Property)
|
||||
Security: Read: Any (0) /Write: Sup (3)
|
||||
*72 6F 6F 74 00 00 00 00 00 00 00 00 00 00 00 00 root
|
||||
SECURITY_EQUALS (Static Set-Property)
|
||||
Security: Read: Obj (2) /Write: Sup (3)
|
||||
*EVERYONE (Group)(01000001)
|
||||
|
||||
BIN
NWTP/XBINDRY/NONAME00.EXE
Normal file
BIN
NWTP/XBINDRY/NONAME00.EXE
Normal file
Binary file not shown.
199
NWTP/XBINDRY/NWPN9401.TXT
Normal file
199
NWTP/XBINDRY/NWPN9401.TXT
Normal file
@@ -0,0 +1,199 @@
|
||||
NWTP Note 0501 "About the encryption mechanism"
|
||||
|
||||
This note discribes the password encryption mechanisms as used by Novell
|
||||
Netware 3.x/4.x. Passwords are encrypted by workstations
|
||||
and servers. The password verification process is also based on encryption.
|
||||
|
||||
This note describes the entire process of password verification and
|
||||
password change. It has 3 appendices:
|
||||
1. A description of the ASM calls involved with encrypted passwords;
|
||||
2. Sourcecode of the encryption routines and tables in Turbo Pascal;
|
||||
3. Sourcecode of the encryption routines and tables in C.
|
||||
|
||||
Initial state
|
||||
=============
|
||||
|
||||
Our transaction model starts with a description of the initial state
|
||||
of the server.
|
||||
|
||||
The following tables are stored at the server:
|
||||
|
||||
-The EncryptionKeyTable, containing an 8 byte EncryptionKey for
|
||||
every workstation connection. This table can be queried by
|
||||
workstations using the GetEncryptionKey (INT 21h, AX=F217h, subf. 17h).
|
||||
Table entry [c] is renewed whenever connection c used a call using
|
||||
encrypted passwords.
|
||||
|
||||
-The PasswordTable containing an 16 Byte encrypted password
|
||||
(socalled "Shuffled" Password) for every connection.
|
||||
|
||||
A short description of the various encryption mechanisms involved:
|
||||
|
||||
-Shuffling. ('S' for short)
|
||||
The encryption of the password (string of char) into 16 bytes (the
|
||||
shuffled password), using a number of static tables and the objectID
|
||||
of the object the password is associated with.
|
||||
|
||||
In Mathematical terms:
|
||||
ShuffledPassWord=S(PasswordString) or Spw=S(pw)
|
||||
|
||||
-Encryption ('E' for short)
|
||||
The main encryption process, encrypting the shuffled password (S(pw)
|
||||
for short) into 8 bytes, using the same static tables as the Shuffling
|
||||
functions and a dynamic encryption key requested from the server.
|
||||
|
||||
In mathematical terms:
|
||||
EncryptedPassWord=E(EncryptionKey,ShuffledPassword) or Epw=E(Ekey,Spw)
|
||||
|
||||
-EncryptDifference ('D' for short)
|
||||
Encrypts the 'difference' between the Shuffled old password and the
|
||||
Shuffled new password, using a static table. The encrypted difference
|
||||
is passed to the server. The computed 'difference' consist of
|
||||
16 bytes of data and 1 checksum byte.
|
||||
|
||||
In mathematical terms:
|
||||
PasswordDiff=D(ShuffledOldPW,ShuffledNewPW) or pwDiff=D(SOpw,SNpw)
|
||||
|
||||
-DecryptDifference ('Dinv' for short)
|
||||
Server decryption process. Decrypts a 'password-difference'
|
||||
encrypted block as suplied by a workstation to a shuffled version
|
||||
of the new password. The shuffled old password, as stored in the
|
||||
servers' EncryptionKeyTable is used in the decryption process.
|
||||
|
||||
In mathematical terms:
|
||||
ShuffledNewPW=Dinv(ShuffledOldPW,PasswordDiff) or SNpw=Dinv(SOpw,pwDiff)
|
||||
Notes:-ShuffledOldPassword is taken by the server from its'
|
||||
EncryptionKeyTable, i.e. ShuffledOldPassword=EncryptionKeyTable[c]
|
||||
where c is the connection number of the object the password
|
||||
is associated with.
|
||||
-SNpw=Dinv(SOpw,D(SNpw,Opw)), hence the name "D inverse".
|
||||
|
||||
-GenerateNewKey ('GNK' for short)
|
||||
The server process creating a new encryption key for a certain
|
||||
connection after the previous one has been used by that connection.
|
||||
|
||||
In mathematical terms:
|
||||
EncryptionKeyTable[c]:=GenerateNewKey(EncryptionTable[c])
|
||||
|
||||
|
||||
Password Verification
|
||||
=====================
|
||||
|
||||
Password verification procedure when the encrypted password calls
|
||||
(VerifyEncrBinderyObjectPassword and LoginEncrToFileServer)
|
||||
are used:
|
||||
|
||||
Workstation Server
|
||||
=========== ======
|
||||
|
||||
GetEncryptionKey ----------------> Return EncryptionKeyTable[c]
|
||||
|
||||
EncrKey <---------------------
|
||||
|
||||
Epw:=E(EncrKey,S(pw))
|
||||
|
||||
Verify/Login(Epw) ---------------> Epw'=E(EncryptionKeyTable[c],
|
||||
PasswordTable[c])
|
||||
|
||||
Epw'=Epw ?
|
||||
completion code <--------------------
|
||||
|
||||
EncryptionKeyTable[c]=
|
||||
GNK(EncryptionKeyTable[c])
|
||||
|
||||
Note: c = Workstation connection number
|
||||
pw = Password (string, max. 128 characters)
|
||||
Epw= Encrypted Password (8 bytes)
|
||||
|
||||
|
||||
Password verification procedure when the calls using unencrypted
|
||||
passwords (VerifyBinderyObjectPassword and LoginToFileserver)
|
||||
are used in combination with a 3.x server:
|
||||
|
||||
Workstation Server
|
||||
=========== ======
|
||||
|
||||
|
||||
Verify/Login(pw) ---------------->
|
||||
|
||||
S(pw)=PasswordTable[c] ?
|
||||
completion code <--------------------
|
||||
|
||||
EncryptionKeyTable[c]=
|
||||
GNK(EncryptionKeyTable[c])
|
||||
|
||||
Note: c = Workstation connection number
|
||||
pw = Password (string, max. 128 characters)
|
||||
|
||||
|
||||
|
||||
Changing Passwords
|
||||
==================
|
||||
|
||||
The process of changeing a password using encrypted passwords:
|
||||
|
||||
Workstation Server
|
||||
=========== ======
|
||||
|
||||
GetEncryptionKey ----------------> Return EncryptionKeyTable[c]
|
||||
|
||||
EncrKey <---------------------
|
||||
|
||||
SOpw=S(oldPW)
|
||||
SNpw=S(newPW)
|
||||
|
||||
EOpw=E(encrKey,SOpw)
|
||||
|
||||
PWdif=D(SNpw,SOpw)
|
||||
|
||||
ChangeEncrBinderyObjPW
|
||||
(EOpw,PWdiff)
|
||||
--------------> Epw'=E(EncryptionKeyTable[c],
|
||||
PasswordTable[c])
|
||||
|
||||
Epw'=Epw ?
|
||||
completion code <--------------------
|
||||
|
||||
SNpw'=Dinv(PasswordTable[c],
|
||||
PWdiff)
|
||||
PasswordTable[c]=SNpw'
|
||||
|
||||
EncryptionKeyTable[c]=
|
||||
GNK(EncryptionKeyTable[c])
|
||||
|
||||
|
||||
Note: c = Workstation connection number
|
||||
OldPW = Old password (string, max. 128 characters)
|
||||
NewPW = New password (string, max. 128 characters)
|
||||
SNpw = Shuffled new password (12 bytes)
|
||||
SOpw = Shuffled old password (12 bytes)
|
||||
EOpw = Encrypted old Password (8 bytes)
|
||||
|
||||
|
||||
THe process of chageing a password when using unencrypted passwords:
|
||||
|
||||
Workstation Server
|
||||
=========== ======
|
||||
|
||||
|
||||
ChangeBinderyObjPW
|
||||
(OldPW,NewPW)
|
||||
-------------->
|
||||
S(OldPW)=PasswordTable[c] ?
|
||||
completion code <--------------------
|
||||
|
||||
PasswordTable[c]=S(NewPW)
|
||||
|
||||
EncryptionKeyTable[c]=
|
||||
GNK(EncryptionKeyTable[c])
|
||||
|
||||
|
||||
Note: c = Workstation connection number
|
||||
OldPW = Old password (string, max. 128 characters)
|
||||
NewPW = New password (string, max. 128 characters)
|
||||
|
||||
|
||||
Sources: NVPW.C by Itsme [Itsme@Hacktic.nl]
|
||||
LOGON.PAS by Barry Nance/Terje Mathesen, Byte, March 1993.
|
||||
|
||||
|
||||
1212
NWTP/XBINDRY/OT_XXX
Normal file
1212
NWTP/XBINDRY/OT_XXX
Normal file
File diff suppressed because it is too large
Load Diff
381
NWTP/XBINDRY/SCANBIND.BAK
Normal file
381
NWTP/XBINDRY/SCANBIND.BAK
Normal file
@@ -0,0 +1,381 @@
|
||||
{$X+,B-,V-,S-,I-} {essential compiler directives}
|
||||
|
||||
Program ScanBind;
|
||||
|
||||
{ Example for the nwBindry unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Purpose: Dumps the entire contents of the bindery. }
|
||||
|
||||
{ Tests the following nwBindry calls:
|
||||
|
||||
IsShellLoaded
|
||||
GetBinderyAccessLevel
|
||||
ScanBinderyObject
|
||||
ScanProperty
|
||||
ReadPropertyValue
|
||||
GetRealUserName
|
||||
}
|
||||
|
||||
Uses nwMisc,nwBindry;
|
||||
|
||||
Type string30=string[30];
|
||||
PobjRec =^objRec;
|
||||
objRec =Record
|
||||
objId:LongInt;
|
||||
name:string30;
|
||||
next:PobjRec;
|
||||
end;
|
||||
|
||||
Var PstartObj:Pobjrec;
|
||||
GlobalPath:string;
|
||||
f:text;
|
||||
|
||||
procedure WriteReadSecurity(sec:Byte);
|
||||
begin
|
||||
Case LoNibble(Sec) of
|
||||
BS_ANY_READ :write('Any (0)');
|
||||
BS_LOGGED_READ :write('Log (1)');
|
||||
BS_OBJECT_READ :write('Obj (2)');
|
||||
BS_SUPER_READ :write('Sup (3)');
|
||||
BS_BINDERY_READ :write('Netw(4)');
|
||||
else writeln('Unknown. (Read Rights Flag=$',HexStr(LoNibble(Sec),2),')');
|
||||
end;{case}
|
||||
end;
|
||||
|
||||
Procedure WriteWriteSecurity(Sec:Byte);
|
||||
begin
|
||||
Case (HiNibble(Sec) SHL 4) of
|
||||
BS_ANY_WRITE :write('Any (0)');
|
||||
BS_LOGGED_WRITE :write('Log (1)');
|
||||
BS_OBJECT_WRITE :write('Obj (2)');
|
||||
BS_SUPER_WRITE :write('Sup (3)');
|
||||
BS_BINDERY_WRITE :write('Netw(4)');
|
||||
else writeln('Unknown. (Write Rights Flag=$',HexStr(HiNibble(Sec) SHL 4,2),')');
|
||||
end; {case}
|
||||
end;
|
||||
|
||||
Procedure PutInLinkedList(objId:LongInt;objName:String;objType:Word);
|
||||
Var rp,np,lp:PobjRec;
|
||||
lName :string;
|
||||
begin
|
||||
lName:=objname;
|
||||
if lName[0]>#20
|
||||
then lName[0]:=#20; { shorten object name; }
|
||||
New(np);
|
||||
if objType=OT_USER
|
||||
then lname:=lname+' (User)'
|
||||
else if objType=OT_USER_GROUP
|
||||
then lname:=lname+' (Group)';
|
||||
np^.name:=lname;
|
||||
np^.objId:=objId;
|
||||
np^.next:=NIL;
|
||||
If PstartObj=NIL
|
||||
then PstartObj:=np
|
||||
else begin
|
||||
lp:=PstartObj;
|
||||
while (lp^.next<>NIL) do lp:=lp^.next;
|
||||
lp^.next:=np;
|
||||
end;
|
||||
end;
|
||||
|
||||
Function getNameFromLL(id:Longint):String;
|
||||
Var rp:PobjRec;
|
||||
begin
|
||||
rp:=PstartObj;
|
||||
While ((rp<>NIL) and (rp^.objId<>id)) do rp:=rp^.next;
|
||||
if rp=NIL then getNameFromLL:='!error: ID not found in stored ID List.'
|
||||
else getNameFromLL:=rp^.name;
|
||||
end;
|
||||
|
||||
Procedure ShowSet(pset:Tproperty);
|
||||
Var i :Byte;
|
||||
objId:LongInt;
|
||||
begin
|
||||
{ A segment of a set-property consists of a list of object IDs,
|
||||
each ID 4 bytes long, stored hi-lo.
|
||||
The end of the list (within THIS segment) is marked by an ID of 00000000. }
|
||||
i:=1;
|
||||
Repeat
|
||||
objId:=MakeLong((pset[i] *256 +pset[i+1]), ( pset[i+2] *256 + pset[i+3] ) );
|
||||
if objId<>0
|
||||
then writeln(' *',GetNameFromLL(objId),'(',HexStr(objId,8),')');
|
||||
inc(i,4);
|
||||
Until (i>128) or (objId=0);
|
||||
end;
|
||||
|
||||
Procedure DumpPropVal(DontSkipZeros:boolean;pv:Tproperty);
|
||||
Var t,g,skip:Byte;
|
||||
c :char;
|
||||
s :string;
|
||||
begin
|
||||
if DontSkipZeros
|
||||
then skip:=7
|
||||
else begin
|
||||
skip:=128;
|
||||
while (pv[skip]=$00) and (skip>1) do dec(skip);
|
||||
skip:=(skip-1) DIV 16;
|
||||
end;
|
||||
t:=0;
|
||||
While t<=skip
|
||||
do begin
|
||||
s:='';
|
||||
write(' *');
|
||||
for g:=1 to 16
|
||||
do begin
|
||||
write(HexStr(pv[t*16+g],2),' ');
|
||||
c:=chr(pv[t*16+g]);
|
||||
if c>=' ' then s:=s+c else s:=s+' ';
|
||||
end;
|
||||
writeln(s);
|
||||
inc(t);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
Var lastObjSeen:LongInt;
|
||||
objName :String;
|
||||
objType :Word;
|
||||
objId :LongInt;
|
||||
objFlag :Byte;
|
||||
objSec :Byte;
|
||||
objHasProp :Boolean;
|
||||
|
||||
SecAccessLevel:Byte;
|
||||
MyObjId :LongInt;
|
||||
|
||||
SeqNumber :LongInt;
|
||||
propName :String;
|
||||
propFlags,
|
||||
propSecurity :Byte;
|
||||
propHasValue,
|
||||
moreProperties:Boolean;
|
||||
|
||||
SegNbr :Byte;
|
||||
propValue:Tproperty; { array[1..128] of byte }
|
||||
accVal: record
|
||||
balance :LongInt; {hi-lo}
|
||||
limit :LongInt; {hi-lo}
|
||||
Reserved:array[1..120] of byte; { NW internal info }
|
||||
end ABSOLUTE PropValue;
|
||||
holdVal: array[1..16]
|
||||
of record
|
||||
AccountServerID:Longint; {hi-lo}
|
||||
HoldAmount :LongInt; {hi-lo}
|
||||
end ABSOLUTE PropValue;
|
||||
holds :Longint;
|
||||
moreSeg:boolean;
|
||||
|
||||
t :word;
|
||||
tempString:String;
|
||||
|
||||
OTfileFound:Boolean;
|
||||
ObjTypeStr,s:string;
|
||||
|
||||
begin
|
||||
Writeln('ScanBind V1.2');
|
||||
Writeln('Provides information about all accessible bindery objects.');
|
||||
|
||||
GlobalPath:=ParamStr(0);
|
||||
while NOT (GlobalPath[ord(GlobalPath[0])] IN [':','\','/'])
|
||||
do dec(GlobalPath[0]);
|
||||
|
||||
assign(f,GlobalPath+'OT_XXX.');
|
||||
reset(f);
|
||||
OTfileFound:=(IOresult=0);
|
||||
IF NOT OTfileFound
|
||||
then begin
|
||||
writeln('WARNING: OT_XXX. file with object types not found.');
|
||||
writeln(' A limited number of object type descriptions will be shown.');
|
||||
writeln;
|
||||
end;
|
||||
|
||||
If NOT ({IpxInitialize and} IsShellLoaded)
|
||||
then begin
|
||||
writeln('Error: Scanbind requires:');
|
||||
writeln(' -IPX to be loaded;');
|
||||
writeln(' -The Netware Shell to be loaded.');
|
||||
halt(1);
|
||||
end;
|
||||
GetBinderyAccessLevel(SecAccessLevel,MyObjId);
|
||||
write('All objects with a read security level <= ');
|
||||
WriteReadSecurity(SecAccessLevel); writeln(' will be shown.');
|
||||
writeln;
|
||||
|
||||
{ put all objects in a table}
|
||||
lastObjSeen:=-1;
|
||||
PstartObj:=NIL;
|
||||
|
||||
While ScanBinderyObject('*',OT_WILD,lastObjSeen,
|
||||
objName,objType,objID,objFlag,objSec,objHasProp)
|
||||
do PutInLinkedList(objId,objName,objType);
|
||||
|
||||
if nwBindry.Result<>$FC { no such object }
|
||||
then writeln('Error Scanning Objects: $',HexStr(nwBindry.Result,2));
|
||||
|
||||
|
||||
{ show all objects and asociated properties/values:}
|
||||
lastObjSeen:=-1;
|
||||
|
||||
While ScanBinderyObject('*',OT_WILD,lastObjSeen,
|
||||
objName,objType,objID,objFlag,objSec,objHasProp)
|
||||
do begin
|
||||
writeln(HexStr(objId,8),' ',objName);
|
||||
|
||||
write('The object type is :');
|
||||
Case objType of
|
||||
OT_UNKNOWN :writeln('Unknown Object Type ');
|
||||
OT_USER :writeln('User ');
|
||||
OT_USER_GROUP :writeln('User group ');
|
||||
OT_PRINT_QUEUE :writeln('Print Queue ');
|
||||
OT_FILE_SERVER :writeln('Fileserver ');
|
||||
OT_JOB_SERVER :writeln('Jobserver ');
|
||||
OT_GATEWAY :writeln('Gateway ');
|
||||
OT_PRINT_SERVER :writeln('Printserver ');
|
||||
OT_ARCHIVE_QUEUE :writeln('Archive Queue ');
|
||||
OT_ARCHIVE_SERVER :writeln('Archive Server ');
|
||||
OT_JOB_QUEUE :writeln('Job Queue ');
|
||||
OT_ADMINISTRATION :writeln('Administration Object');
|
||||
OT_RSPCX_SERVER :writeln('RSPCX Server (Rconsole) ');
|
||||
else begin
|
||||
if OTfileFound
|
||||
then begin
|
||||
reset(f);
|
||||
ObjTypeStr:=HexStr(objType,4);
|
||||
REPEAT
|
||||
readln(f,s);
|
||||
UNTIL eof(f) or (pos(ObjTypeStr,s)=1);
|
||||
if pos(ObjTypeStr,s)=1
|
||||
then begin
|
||||
delete(s,1,5);
|
||||
writeln(s);
|
||||
end;
|
||||
end
|
||||
else writeln('objType= 0x',HexStr(objType,4),' (unknown)');
|
||||
end;
|
||||
end; {case}
|
||||
|
||||
Case objFlag of
|
||||
0:writeln('The object is a static object.');
|
||||
1:writeln('The object is a dynamic object.');
|
||||
else writeln('Unknown objectFlag:',objFlag);
|
||||
end; {case}
|
||||
|
||||
write('Security: Read: ');WriteReadSecurity(objSec);
|
||||
write(' / Write: ');WriteWriteSecurity(objSec); writeln;
|
||||
|
||||
if objHasProp
|
||||
then begin
|
||||
SeqNumber:=-1;
|
||||
writeln('The object has the following properties:');
|
||||
|
||||
While ScanProperty({in} objName,objType,'*',
|
||||
{i/o} SeqNumber,
|
||||
{out} propName,propFlags,propSecurity,
|
||||
propHasValue,moreProperties)
|
||||
do begin
|
||||
write(' ',propName);
|
||||
|
||||
if HiNibble(propFlags)=0
|
||||
then write (' (Static') { 0 }
|
||||
else write (' (Dynamic'); { 1 }
|
||||
|
||||
Case LoNibble(propFlags) of
|
||||
BF_ITEM:writeln(' Item-Property)');
|
||||
BF_SET :writeln(' Set-Property)');
|
||||
else writeln(' property), Property type= ',LoNibble(propFlags),' (Unknown, not Item or Set)');
|
||||
end; {case}
|
||||
|
||||
write(' Security: Read: ');WriteReadSecurity(propSecurity);
|
||||
write(' /Write: ');WriteWriteSecurity(propSecurity); writeln;
|
||||
|
||||
{ show value of properties: }
|
||||
if propHasValue
|
||||
then begin
|
||||
if LoNibble(propFlags)=BF_SET
|
||||
then begin
|
||||
SegNbr:=1;
|
||||
|
||||
While ReadPropertyValue(objName,objType,propName,SegNbr,
|
||||
propValue,moreSeg,propFlags)
|
||||
do begin
|
||||
ShowSet(propValue);
|
||||
inc(SegNbr);
|
||||
end;
|
||||
If nwBindry.Result<>$EC { no such segment }
|
||||
then writeln('Error Reading Property Values: $',
|
||||
HexStr(nwBindry.Result,2));
|
||||
end
|
||||
else begin { item property }
|
||||
if propName='IDENTIFICATION'
|
||||
then begin
|
||||
getRealUserName(objName,tempString);
|
||||
writeln(' *',tempString)
|
||||
end
|
||||
else if propname='Q_DIRECTORY'
|
||||
then begin
|
||||
{ asciiz string in 1st seg }
|
||||
SegNbr:=1;
|
||||
IF ReadPropertyValue(objName,objType,propName,SegNbr,
|
||||
propValue,moreSeg,propFlags)
|
||||
then begin
|
||||
ZStrCopy(tempString,propValue,127);
|
||||
writeln(' *',tempString);
|
||||
end
|
||||
end
|
||||
else if propname='ACCOUNT_BALANCE'
|
||||
then begin
|
||||
{ conversion of 1st 4 bytes to longint }
|
||||
SegNbr:=1;
|
||||
IF ReadPropertyValue(objName,objType,propName,SegNbr,
|
||||
propValue,moreSeg,propFlags)
|
||||
then writeln(' * Balance:',Lswap(accVal.balance),' Limit: ',Lswap(accVal.Limit));
|
||||
end
|
||||
else if propname='ACCOUNT_HOLDS'
|
||||
then begin
|
||||
SegNbr:=1;
|
||||
IF ReadPropertyValue(objName,objType,propName,SegNbr,
|
||||
propValue,moreSeg,propFlags)
|
||||
then begin
|
||||
holds:=0;
|
||||
for t:=1 to 16
|
||||
do if holdVal[t].AccountServerID<>0
|
||||
then holds:=holds+Lswap(holdVal[t].HoldAmount);
|
||||
writeln(' * Total holds:',holds)
|
||||
end;
|
||||
end
|
||||
else begin { structure not known, dump it }
|
||||
SegNbr:=1;
|
||||
While ReadPropertyValue(objName,objType,propName,SegNbr,
|
||||
propValue,moreSeg,propFlags)
|
||||
do begin
|
||||
inc(segNbr);
|
||||
DumpPropVal(moreSeg,propValue);
|
||||
end;
|
||||
|
||||
If nwBindry.Result<>$EC { no such segment }
|
||||
then writeln('Error Reading Property Values: $',
|
||||
HexStr(nwBindry.Result,2));
|
||||
end
|
||||
|
||||
end;
|
||||
end {if propHasValue then }
|
||||
else begin { prop has NO value }
|
||||
writeln(' *<property has no value>');
|
||||
end;
|
||||
end; { While scanProperty do }
|
||||
|
||||
If nwBindry.Result<>$FB { no such property }
|
||||
then writeln('Error Scanning Properties: $',HexStr(nwBindry.Result,2));
|
||||
end { if objHasProp then }
|
||||
else begin { object has NO properties }
|
||||
writeln(' <object has no properties>');
|
||||
end;
|
||||
|
||||
writeln;
|
||||
end; { While scanObject }
|
||||
if nwBindry.Result<>$FC { no such object }
|
||||
then writeln('Error Scanning Objects: $',HexStr(nwBindry.Result,2));
|
||||
|
||||
IF OTfileFound
|
||||
then close(f);
|
||||
end.
|
||||
BIN
NWTP/XBINDRY/SCANBIND.EXE
Normal file
BIN
NWTP/XBINDRY/SCANBIND.EXE
Normal file
Binary file not shown.
376
NWTP/XBINDRY/SCANBIND.PAS
Normal file
376
NWTP/XBINDRY/SCANBIND.PAS
Normal file
@@ -0,0 +1,376 @@
|
||||
{$X+,B-,V-,S-,I-} {essential compiler directives}
|
||||
|
||||
Program ScanBind;
|
||||
|
||||
{ Example for the nwBindry unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Purpose: Dumps the entire contents of the bindery. }
|
||||
|
||||
{ Tests the following nwBindry calls:
|
||||
|
||||
IsShellLoaded
|
||||
GetBinderyAccessLevel
|
||||
ScanBinderyObject
|
||||
ScanProperty
|
||||
ReadPropertyValue
|
||||
GetRealUserName
|
||||
}
|
||||
|
||||
Uses nwMisc,nwBindry;
|
||||
|
||||
Type string30=string[30];
|
||||
PobjRec =^objRec;
|
||||
objRec =Record
|
||||
objId:LongInt;
|
||||
name:string30;
|
||||
next:PobjRec;
|
||||
end;
|
||||
|
||||
Var PstartObj:Pobjrec;
|
||||
GlobalPath:string;
|
||||
f:text;
|
||||
|
||||
procedure WriteReadSecurity(sec:Byte);
|
||||
begin
|
||||
Case LoNibble(Sec) of
|
||||
BS_ANY_READ :write('Any (0)');
|
||||
BS_LOGGED_READ :write('Log (1)');
|
||||
BS_OBJECT_READ :write('Obj (2)');
|
||||
BS_SUPER_READ :write('Sup (3)');
|
||||
BS_BINDERY_READ :write('Netw(4)');
|
||||
else writeln('Unknown. (Read Rights Flag=$',HexStr(LoNibble(Sec),2),')');
|
||||
end;{case}
|
||||
end;
|
||||
|
||||
Procedure WriteWriteSecurity(Sec:Byte);
|
||||
begin
|
||||
Case (HiNibble(Sec) SHL 4) of
|
||||
BS_ANY_WRITE :write('Any (0)');
|
||||
BS_LOGGED_WRITE :write('Log (1)');
|
||||
BS_OBJECT_WRITE :write('Obj (2)');
|
||||
BS_SUPER_WRITE :write('Sup (3)');
|
||||
BS_BINDERY_WRITE :write('Netw(4)');
|
||||
else writeln('Unknown. (Write Rights Flag=$',HexStr(HiNibble(Sec) SHL 4,2),')');
|
||||
end; {case}
|
||||
end;
|
||||
|
||||
Procedure PutInLinkedList(objId:LongInt;objName:String;objType:Word);
|
||||
Var rp,np,lp:PobjRec;
|
||||
lName :string;
|
||||
begin
|
||||
lName:=objname;
|
||||
if lName[0]>#20
|
||||
then lName[0]:=#20; { shorten object name; }
|
||||
New(np);
|
||||
if objType=OT_USER
|
||||
then lname:=lname+' (User)'
|
||||
else if objType=OT_USER_GROUP
|
||||
then lname:=lname+' (Group)';
|
||||
np^.name:=lname;
|
||||
np^.objId:=objId;
|
||||
np^.next:=NIL;
|
||||
If PstartObj=NIL
|
||||
then PstartObj:=np
|
||||
else begin
|
||||
lp:=PstartObj;
|
||||
while (lp^.next<>NIL) do lp:=lp^.next;
|
||||
lp^.next:=np;
|
||||
end;
|
||||
end;
|
||||
|
||||
Function getNameFromLL(id:Longint):String;
|
||||
Var rp:PobjRec;
|
||||
begin
|
||||
rp:=PstartObj;
|
||||
While ((rp<>NIL) and (rp^.objId<>id)) do rp:=rp^.next;
|
||||
if rp=NIL then getNameFromLL:='!error: ID not found in stored ID List.'
|
||||
else getNameFromLL:=rp^.name;
|
||||
end;
|
||||
|
||||
Procedure ShowSet(pset:Tproperty);
|
||||
Var i :Byte;
|
||||
objId:LongInt;
|
||||
begin
|
||||
{ A segment of a set-property consists of a list of object IDs,
|
||||
each ID 4 bytes long, stored hi-lo.
|
||||
The end of the list (within THIS segment) is marked by an ID of 00000000. }
|
||||
i:=1;
|
||||
Repeat
|
||||
objId:=MakeLong((pset[i] *256 +pset[i+1]), ( pset[i+2] *256 + pset[i+3] ) );
|
||||
if objId<>0
|
||||
then writeln(' *',GetNameFromLL(objId),'(',HexStr(objId,8),')');
|
||||
inc(i,4);
|
||||
Until (i>128) or (objId=0);
|
||||
end;
|
||||
|
||||
Procedure DumpPropVal(DontSkipZeros:boolean;pv:Tproperty);
|
||||
Var t,g,skip:Byte;
|
||||
c :char;
|
||||
s :string;
|
||||
begin
|
||||
if DontSkipZeros
|
||||
then skip:=7
|
||||
else begin
|
||||
skip:=128;
|
||||
while (pv[skip]=$00) and (skip>1) do dec(skip);
|
||||
skip:=(skip-1) DIV 16;
|
||||
end;
|
||||
t:=0;
|
||||
While t<=skip
|
||||
do begin
|
||||
s:='';
|
||||
write(' *');
|
||||
for g:=1 to 16
|
||||
do begin
|
||||
write(HexStr(pv[t*16+g],2),' ');
|
||||
c:=chr(pv[t*16+g]);
|
||||
if c>=' ' then s:=s+c else s:=s+' ';
|
||||
end;
|
||||
writeln(s);
|
||||
inc(t);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
Var lastObjSeen:LongInt;
|
||||
objName :String;
|
||||
objType :Word;
|
||||
objId :LongInt;
|
||||
objFlag :Byte;
|
||||
objSec :Byte;
|
||||
objHasProp :Boolean;
|
||||
|
||||
SecAccessLevel:Byte;
|
||||
MyObjId :LongInt;
|
||||
|
||||
SeqNumber :LongInt;
|
||||
propName :String;
|
||||
propFlags,
|
||||
propSecurity :Byte;
|
||||
propHasValue,
|
||||
moreProperties:Boolean;
|
||||
|
||||
SegNbr :Byte;
|
||||
propValue:Tproperty; { array[1..128] of byte }
|
||||
accVal: record
|
||||
balance :LongInt; {hi-lo}
|
||||
limit :LongInt; {hi-lo}
|
||||
Reserved:array[1..120] of byte; { NW internal info }
|
||||
end ABSOLUTE PropValue;
|
||||
holdVal: array[1..16]
|
||||
of record
|
||||
AccountServerID:Longint; {hi-lo}
|
||||
HoldAmount :LongInt; {hi-lo}
|
||||
end ABSOLUTE PropValue;
|
||||
holds :Longint;
|
||||
moreSeg:boolean;
|
||||
|
||||
t :word;
|
||||
tempString:String;
|
||||
|
||||
OTfileFound:Boolean;
|
||||
ObjTypeStr,s:string;
|
||||
|
||||
begin
|
||||
Writeln('ScanBind V1.2');
|
||||
Writeln('Provides information about all accessible bindery objects.');
|
||||
assign(f,'OT_XXX.');
|
||||
reset(f);
|
||||
OTfileFound:=(IOresult=0);
|
||||
IF NOT OTfileFound
|
||||
then begin
|
||||
writeln('WARNING: OT_XXX. file with object types not found.');
|
||||
writeln(' A limited number of object type descriptions will be shown.');
|
||||
writeln;
|
||||
end;
|
||||
|
||||
If NOT ({IpxInitialize and} IsShellLoaded)
|
||||
then begin
|
||||
writeln('Error: Scanbind requires:');
|
||||
writeln(' -IPX to be loaded;');
|
||||
writeln(' -The Netware Shell to be loaded.');
|
||||
halt(1);
|
||||
end;
|
||||
GetBinderyAccessLevel(SecAccessLevel,MyObjId);
|
||||
write('All objects with a read security level <= ');
|
||||
WriteReadSecurity(SecAccessLevel); writeln(' will be shown.');
|
||||
writeln;
|
||||
|
||||
{ put all objects in a table}
|
||||
lastObjSeen:=-1;
|
||||
PstartObj:=NIL;
|
||||
|
||||
While ScanBinderyObject('*',OT_WILD,lastObjSeen,
|
||||
objName,objType,objID,objFlag,objSec,objHasProp)
|
||||
do PutInLinkedList(objId,objName,objType);
|
||||
|
||||
if nwBindry.Result<>$FC { no such object }
|
||||
then writeln('Error Scanning Objects: $',HexStr(nwBindry.Result,2));
|
||||
|
||||
|
||||
{ show all objects and asociated properties/values:}
|
||||
lastObjSeen:=-1;
|
||||
|
||||
While ScanBinderyObject('*',OT_WILD,lastObjSeen,
|
||||
objName,objType,objID,objFlag,objSec,objHasProp)
|
||||
do begin
|
||||
writeln(HexStr(objId,8),' ',objName);
|
||||
|
||||
write('The object type is :');
|
||||
Case objType of
|
||||
OT_UNKNOWN :writeln('Unknown Object Type ');
|
||||
OT_USER :writeln('User ');
|
||||
OT_USER_GROUP :writeln('User group ');
|
||||
OT_PRINT_QUEUE :writeln('Print Queue ');
|
||||
OT_FILE_SERVER :writeln('Fileserver ');
|
||||
OT_JOB_SERVER :writeln('Jobserver ');
|
||||
OT_GATEWAY :writeln('Gateway ');
|
||||
OT_PRINT_SERVER :writeln('Printserver ');
|
||||
OT_ARCHIVE_QUEUE :writeln('Archive Queue ');
|
||||
OT_ARCHIVE_SERVER :writeln('Archive Server ');
|
||||
OT_JOB_QUEUE :writeln('Job Queue ');
|
||||
OT_ADMINISTRATION :writeln('Administration Object');
|
||||
OT_RSPCX_SERVER :writeln('RSPCX Server (Rconsole) ');
|
||||
else begin
|
||||
if OTfileFound
|
||||
then begin
|
||||
reset(f);
|
||||
ObjTypeStr:=HexStr(objType,4);
|
||||
REPEAT
|
||||
readln(f,s);
|
||||
UNTIL eof(f) or (pos(ObjTypeStr,s)=1);
|
||||
if pos(ObjTypeStr,s)=1
|
||||
then begin
|
||||
delete(s,1,5);
|
||||
writeln(s);
|
||||
end;
|
||||
end
|
||||
else writeln('objType= 0x',HexStr(objType,4),' (unknown)');
|
||||
end;
|
||||
end; {case}
|
||||
|
||||
Case objFlag of
|
||||
0:writeln('The object is a static object.');
|
||||
1:writeln('The object is a dynamic object.');
|
||||
else writeln('Unknown objectFlag:',objFlag);
|
||||
end; {case}
|
||||
|
||||
write('Security: Read: ');WriteReadSecurity(objSec);
|
||||
write(' / Write: ');WriteWriteSecurity(objSec); writeln;
|
||||
|
||||
if objHasProp
|
||||
then begin
|
||||
SeqNumber:=-1;
|
||||
writeln('The object has the following properties:');
|
||||
|
||||
While ScanProperty({in} objName,objType,'*',
|
||||
{i/o} SeqNumber,
|
||||
{out} propName,propFlags,propSecurity,
|
||||
propHasValue,moreProperties)
|
||||
do begin
|
||||
write(' ',propName);
|
||||
|
||||
if HiNibble(propFlags)=0
|
||||
then write (' (Static') { 0 }
|
||||
else write (' (Dynamic'); { 1 }
|
||||
|
||||
Case LoNibble(propFlags) of
|
||||
BF_ITEM:writeln(' Item-Property)');
|
||||
BF_SET :writeln(' Set-Property)');
|
||||
else writeln(' property), Property type= ',LoNibble(propFlags),' (Unknown, not Item or Set)');
|
||||
end; {case}
|
||||
|
||||
write(' Security: Read: ');WriteReadSecurity(propSecurity);
|
||||
write(' /Write: ');WriteWriteSecurity(propSecurity); writeln;
|
||||
|
||||
{ show value of properties: }
|
||||
if propHasValue
|
||||
then begin
|
||||
if LoNibble(propFlags)=BF_SET
|
||||
then begin
|
||||
SegNbr:=1;
|
||||
|
||||
While ReadPropertyValue(objName,objType,propName,SegNbr,
|
||||
propValue,moreSeg,propFlags)
|
||||
do begin
|
||||
ShowSet(propValue);
|
||||
inc(SegNbr);
|
||||
end;
|
||||
If nwBindry.Result<>$EC { no such segment }
|
||||
then writeln('Error Reading Property Values: $',
|
||||
HexStr(nwBindry.Result,2));
|
||||
end
|
||||
else begin { item property }
|
||||
if propName='IDENTIFICATION'
|
||||
then begin
|
||||
getRealUserName(objName,tempString);
|
||||
writeln(' *',tempString)
|
||||
end
|
||||
else if propname='Q_DIRECTORY'
|
||||
then begin
|
||||
{ asciiz string in 1st seg }
|
||||
SegNbr:=1;
|
||||
IF ReadPropertyValue(objName,objType,propName,SegNbr,
|
||||
propValue,moreSeg,propFlags)
|
||||
then begin
|
||||
ZStrCopy(tempString,propValue,127);
|
||||
writeln(' *',tempString);
|
||||
end
|
||||
end
|
||||
else if propname='ACCOUNT_BALANCE'
|
||||
then begin
|
||||
{ conversion of 1st 4 bytes to longint }
|
||||
SegNbr:=1;
|
||||
IF ReadPropertyValue(objName,objType,propName,SegNbr,
|
||||
propValue,moreSeg,propFlags)
|
||||
then writeln(' * Balance:',Lswap(accVal.balance),' Limit: ',Lswap(accVal.Limit));
|
||||
end
|
||||
else if propname='ACCOUNT_HOLDS'
|
||||
then begin
|
||||
SegNbr:=1;
|
||||
IF ReadPropertyValue(objName,objType,propName,SegNbr,
|
||||
propValue,moreSeg,propFlags)
|
||||
then begin
|
||||
holds:=0;
|
||||
for t:=1 to 16
|
||||
do if holdVal[t].AccountServerID<>0
|
||||
then holds:=holds+Lswap(holdVal[t].HoldAmount);
|
||||
writeln(' * Total holds:',holds)
|
||||
end;
|
||||
end
|
||||
else begin { structure not known, dump it }
|
||||
SegNbr:=1;
|
||||
While ReadPropertyValue(objName,objType,propName,SegNbr,
|
||||
propValue,moreSeg,propFlags)
|
||||
do begin
|
||||
inc(segNbr);
|
||||
DumpPropVal(moreSeg,propValue);
|
||||
end;
|
||||
|
||||
If nwBindry.Result<>$EC { no such segment }
|
||||
then writeln('Error Reading Property Values: $',
|
||||
HexStr(nwBindry.Result,2));
|
||||
end
|
||||
|
||||
end;
|
||||
end {if propHasValue then }
|
||||
else begin { prop has NO value }
|
||||
writeln(' *<property has no value>');
|
||||
end;
|
||||
end; { While scanProperty do }
|
||||
|
||||
If nwBindry.Result<>$FB { no such property }
|
||||
then writeln('Error Scanning Properties: $',HexStr(nwBindry.Result,2));
|
||||
end { if objHasProp then }
|
||||
else begin { object has NO properties }
|
||||
writeln(' <object has no properties>');
|
||||
end;
|
||||
|
||||
writeln;
|
||||
end; { While scanObject }
|
||||
if nwBindry.Result<>$FC { no such object }
|
||||
then writeln('Error Scanning Objects: $',HexStr(nwBindry.Result,2));
|
||||
|
||||
IF OTfileFound
|
||||
then close(f);
|
||||
end.
|
||||
38
NWTP/XBINDRY/SUPEQ.PAS
Normal file
38
NWTP/XBINDRY/SUPEQ.PAS
Normal file
@@ -0,0 +1,38 @@
|
||||
{$X+,B-,V-,S-} {essential compiler directives}
|
||||
|
||||
Program SupEq; {as of 950301}
|
||||
|
||||
{ Example for the nwBindry unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Purpose: Shows all supervisor equivalent users. }
|
||||
|
||||
uses nwMisc,nwBindry;
|
||||
|
||||
Var Info :TobjIdArray;
|
||||
SeqNbr :Longint;
|
||||
NbrOfObj:word;
|
||||
ObjName :string;
|
||||
ObjType :word;
|
||||
NbrOfEqUsers:word;
|
||||
t :word;
|
||||
begin
|
||||
writeln('Objects that are supervisor equivalent:');
|
||||
writeln;
|
||||
NbrOfEqUsers:=0;
|
||||
SeqNbr:=-1;
|
||||
REPEAT
|
||||
if GetRelationOfBinderyObject('SUPERVISOR',1,'SECURITY_EQUALS',
|
||||
SeqNbr,NbrOfObj,Info)
|
||||
then for t:=1 to NbrOfObj
|
||||
do begin
|
||||
inc(NbrOfEqUsers);
|
||||
write(HexStr(Info[t],8));
|
||||
GetBinderyObjectName(Info[t],ObjName,ObjType);
|
||||
writeln(' ',ObjName);
|
||||
end;
|
||||
UNTIL SeqNbr=-1;
|
||||
if nwBindry.result<>0
|
||||
then writeln('Search for security equivalent users aborted due to an error.');
|
||||
if NbrOfEqUsers=0
|
||||
then writeln('No supervisor equivalent users found');
|
||||
end.
|
||||
96
NWTP/XBINDRY/SWAPNAME.PAS
Normal file
96
NWTP/XBINDRY/SWAPNAME.PAS
Normal file
@@ -0,0 +1,96 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
program swapnames; { as of 950301 }
|
||||
|
||||
{ Example for the nwBindry unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ AREA:NOVELL
|
||||
(1394) Thu 30 Sep 93 16:07
|
||||
By: JAMES SIMONSON
|
||||
To: All
|
||||
Re: Novell 3.11/4.01 bindery access
|
||||
------------------------------------------------------------
|
||||
|
||||
Is there a way to access the full name information inthe bindery files?
|
||||
Here's the scoop:
|
||||
|
||||
We've got "firstname mi lastname" in the FULLNAME space in the user record.
|
||||
We need to convert that to "lastname, firstname mi" & place that
|
||||
information BACK into the FULLNAME field. Is there any relatively fast way
|
||||
to do this conversion?
|
||||
|
||||
--- SLMAIL v3.0 (#0623)
|
||||
* Origin: WorkStations Unlimited / 312-404-2824 (1:115/404) }
|
||||
|
||||
{ This program will reverse all first & last names in the bindery.
|
||||
Lastname is defined as being everything after the last space in the full name.
|
||||
This may not be true for all names.
|
||||
If there is no space in the full name, nothing changes. }
|
||||
|
||||
uses nwBindry;
|
||||
|
||||
Var lastObjSeen:LongInt;
|
||||
objName :string;
|
||||
objType :word;
|
||||
objId :LongInt;
|
||||
objFlag,objSec:Byte;
|
||||
hasProp :boolean;
|
||||
|
||||
propVal :Tproperty;
|
||||
moreseg :boolean;
|
||||
propFlags:Byte;
|
||||
|
||||
NewName,FullName:string;
|
||||
t:byte;
|
||||
s:string;
|
||||
begin
|
||||
IF NOT IsShellLoaded
|
||||
then begin
|
||||
writeln('Load network shell before executing this testprogram.');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
writeln('SWAPNAME: Will swap the first and last names of the IDENTIFICATION');
|
||||
writeln(' property in the bindery. (Full Name of an object)');
|
||||
writeln;
|
||||
writeln('--WARNING: Changes the property values irrevokably ! --');
|
||||
writeln;
|
||||
writeln('Type ''y'' and <Return> to continue.. (all else will abort)');
|
||||
readln(s);
|
||||
if (s[0]=#0) or ((s[1]<>'y') and (s[1]<>'Y'))
|
||||
then halt(1);
|
||||
|
||||
LastObjSeen:=-1;
|
||||
WHILE ScanBinderyObject('*',1,LastObjSeen,
|
||||
objName,objType,objId,objFlag,objSec,hasProp)
|
||||
do begin
|
||||
IF ReadPropertyValue(objName,objType,'IDENTIFICATION',1,
|
||||
propVal,moreSeg,propFlags)
|
||||
then begin
|
||||
t:=1;
|
||||
while (propVal[t]<>0)
|
||||
do begin FullName[t]:=chr(propVal[t]);inc(t) end;
|
||||
FullName[0]:=chr(t-1);
|
||||
IF pos(',',FullName)=0
|
||||
then begin
|
||||
writeln(FullName);
|
||||
while fullName[ord(fullName[0])]=' '
|
||||
do dec(FullName[0]);
|
||||
t:=ord(FullName[0]);
|
||||
while (t>0) and (FullName[t]<>' ') do dec(t);
|
||||
if t>0
|
||||
then begin
|
||||
NewName:=copy(FullName,t+1,255)+', '
|
||||
+copy(FullName,1,t-1);
|
||||
writeln(newname);
|
||||
fillChar(propVal,SizeOf(propVal),#0);
|
||||
for t:=1 to ord(newName[0])
|
||||
do propVal[t]:=ord(newName[t]);
|
||||
WritePropertyValue(objName,objType,
|
||||
'IDENTIFICATION',1,propVal,FALSE);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
if nwBindry.result<>$FC then writeln('error scanning bindery');
|
||||
end.
|
||||
249
NWTP/XBINDRY/TSTBIND.PAS
Normal file
249
NWTP/XBINDRY/TSTBIND.PAS
Normal file
@@ -0,0 +1,249 @@
|
||||
{$X+,B-,V-,S-} {essential compiler directives}
|
||||
|
||||
Program TSTBin; { as of 950301 }
|
||||
|
||||
{ Testprogram for the nwBindry unit / NwTP 0.6 API. (c) 1994,1995 R.Spronk }
|
||||
|
||||
{ Purpose: Testing only. }
|
||||
|
||||
{ Tests the following nwBindry calls:
|
||||
|
||||
AddBinderyObjectToSet
|
||||
ChangeBinderyObjectSecurity
|
||||
ChangeBinderyObjectPassword
|
||||
ChangeEncrBinderyObjectPassword
|
||||
ChangePropertySecurity
|
||||
CreateBinderyObject
|
||||
CreateProperty
|
||||
DeleteBinderyObject
|
||||
DeleteBinderyObjectFromSet
|
||||
DeleteProperty
|
||||
GetBinderyAccessLevel
|
||||
GetBinderyObjectID
|
||||
GetBinderyObjectName
|
||||
IsBinderyObjectInSet
|
||||
RenameBinderyObject
|
||||
VerifyBinderyObjectPassword
|
||||
VerifyEncrBinderyObjectPassword
|
||||
WritePropertyValue
|
||||
}
|
||||
|
||||
Uses nwMisc,nwBindry;
|
||||
|
||||
Procedure Warning(mess:string);
|
||||
begin
|
||||
writeln(' ERROR:',mess);
|
||||
writeln(' ERROR#: $',hexstr(result,2),' (',result,')');
|
||||
end;
|
||||
|
||||
|
||||
Function ExistsProperty(objName:string;objType:word;propertyName:String):boolean;
|
||||
|
||||
Var propName:string;
|
||||
pf,ps :byte;
|
||||
phv,mp :boolean;
|
||||
seqNbr :LongInt;
|
||||
begin
|
||||
seqNbr:=-1;
|
||||
ExistsProperty:=ScanProperty(objName,objType,propertyname,
|
||||
seqNbr,propName,pf,ps,phv,mp);
|
||||
end;
|
||||
|
||||
|
||||
Var myObjId:longInt;
|
||||
BindSeq:Byte;
|
||||
|
||||
ObjId :longint;
|
||||
usrName,TrueName:string;
|
||||
pTrueName:Tproperty;
|
||||
|
||||
replyUsrName:string;
|
||||
replyObjType:word;
|
||||
|
||||
t:byte;
|
||||
s:string;
|
||||
|
||||
begin
|
||||
writeln('BINTEST Test program for the nwBindry unit of the NwTP package.');
|
||||
|
||||
IF not IsShellLoaded
|
||||
then begin
|
||||
writeln('Please load shell before running.');
|
||||
halt(1);
|
||||
end;
|
||||
{ need supervisor privileges to run this test }
|
||||
GetBinderyAccessLevel(BindSeq,myObjId);
|
||||
if bindSeq<>(BS_SUPER_WRITE OR BS_SUPER_READ) { $33}
|
||||
then begin
|
||||
writeln('you need to be supervisor equivalent to run this test program.');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
writeln('-Assumes there is a group ''EVERYONE''');
|
||||
writeln('-Non destructive to the bindery. ');
|
||||
writeln(' (unless you already have a user named ''USR_OINK'' or ''THE_DIVA'')');
|
||||
writeln;
|
||||
writeln('For testing of the unencrypted calls, you must have');
|
||||
writeln(' SET ALLOW UNENCRYPTED PASSWORDS=ON on the server--');
|
||||
writeln(' Otherwise these calls will fail and trigger the servers'' intruder detection.');
|
||||
writeln;
|
||||
writeln('<ENTER> To Continue..');
|
||||
readln;
|
||||
|
||||
{ you are reminded that the bindery functions turn all object names, property
|
||||
names and passwords to upcase. Returned strings are also upcase. }
|
||||
|
||||
usrName:='UsR_OiNk';
|
||||
TrueName:='Miss Piggy';
|
||||
|
||||
writeln('Creating Bindery object :',usrName);
|
||||
IF NOT CreateBinderyObject(usrName,OT_USER,
|
||||
BF_ITEM,BS_ANY_READ OR BS_ANY_WRITE)
|
||||
then Warning('couldn''t create a bindery object.');
|
||||
|
||||
IF NOT GetBinderyObjectID(usrName,OT_USER,objID)
|
||||
then Warning('couldn''t find the created user object');
|
||||
|
||||
writeln('Changing object security.');
|
||||
IF NOT ChangeBinderyObjectSecurity(usrName,OT_USER,BS_LOGGED_READ OR BS_SUPER_WRITE)
|
||||
then warning('Couldn''t change object security.');
|
||||
|
||||
{ this program assumes there is a group called everyone. }
|
||||
writeln('Making ',usrName,' a member of the group EVERYONE.');
|
||||
IF IsBinderyObjectInSet(usrName,OT_USER,
|
||||
'GROUP_MEMBERS','EVERYONE',OT_USER_GROUP)
|
||||
then writeln('??: object already is a member of everyone (group)');
|
||||
|
||||
IF NOT AddBinderyObjectToSet('EVERYONE',OT_USER_GROUP,'GROUP_MEMBERS',
|
||||
usrName,OT_USER)
|
||||
then Warning('couldn''t make user a member of everyone');
|
||||
|
||||
IF NOT IsBinderyObjectInSet('EVERYONE',OT_USER_GROUP,'GROUP_MEMBERS',
|
||||
usrName,OT_USER)
|
||||
then writeln('??: user is NOT a member of everyone.');
|
||||
|
||||
|
||||
{ ------------AND NOW: the property test.
|
||||
create a static property with default security... }
|
||||
writeln;
|
||||
writeln('Creating a property IDENTIFICATION associated withe the ',usrName,' object.');
|
||||
IF NOT CreateProperty(usrName,OT_USER,
|
||||
'IDENTIFICATION',BF_ITEM,BS_ANY_WRITE OR BS_ANY_READ)
|
||||
then writeln('Couldn''t create property.');
|
||||
|
||||
IF NOT ChangePropertySecurity(usrName,OT_USER,'IDENTIFICATION',
|
||||
BS_LOGGED_READ or BS_SUPER_WRITE)
|
||||
then writeln('Couldn''t change property security.');
|
||||
|
||||
writeln('Writing the property value: ',trueName);
|
||||
FillChar(pTrueName[1],SizeOf(pTrueName),#0);
|
||||
for t:=1 to ord(truename[0]) do pTrueName[t]:=ord(TrueName[t]);
|
||||
|
||||
IF NOT WritePropertyValue(usrName,OT_USER,'IDENTIFICATION',1,pTrueName,FALSE)
|
||||
then Warning('Couldn''t write the property value.');
|
||||
|
||||
{ The next calls were tested before, so they are not tested again.
|
||||
They create the minimal properties needed to login as the new object. }
|
||||
|
||||
CreateProperty(usrName,OT_USER,'GROUPS_I''M_IN',
|
||||
BF_SET,BS_SUPER_WRITE OR BS_LOGGED_READ);
|
||||
|
||||
AddBinderyObjectToSet(usrName,OT_USER,'GROUPS_I''M_IN',
|
||||
'EVERYONE',OT_USER_GROUP);
|
||||
|
||||
CreateProperty(usrName,OT_USER,'SECURITY_EQUALS',
|
||||
BF_SET,BS_SUPER_WRITE OR BS_LOGGED_READ);
|
||||
|
||||
AddBinderyObjectToSet(usrName,OT_USER,'SECURITY_EQUALS',
|
||||
'EVERYONE',OT_USER_GROUP);
|
||||
|
||||
{------------- Renaming the object. }
|
||||
writeln;
|
||||
writeln('Renaming the object.');
|
||||
UpString(usrName); { make usrName upstring for comparison with found name.}
|
||||
|
||||
GetBinderyObjectName(objId,replyUsrName,replyObjType);
|
||||
IF (nwBindry.result>0) or (replyUsrName<>usrName) or (replyObjType<>OT_USER)
|
||||
then Warning('Something very wrong here.');
|
||||
writeln(' Object name was :',replyUsrName);
|
||||
|
||||
IF NOT RenameBinderyObject(usrName,'THE_DIVA',OT_USER)
|
||||
then Warning('Couldn''t rename the object.');
|
||||
|
||||
usrName:='THE_DIVA'; {that's what it should be now}
|
||||
|
||||
GetBinderyObjectName(objId,replyUsrName,replyObjType);
|
||||
IF (nwBindry.result<>0) or (replyUsrName<>usrName) or (replyObjType<>OT_USER)
|
||||
then Warning('Object was NOT renamed.');
|
||||
writeln(' Object name now is:',replyUsrName);
|
||||
|
||||
{------------ Change and verify bindery object password. }
|
||||
|
||||
writeln;
|
||||
writeln('Changing Object Password. (encrypted)');
|
||||
IF ChangeEncrBinderyObjectPassword(usrName,OT_USER,'','KERMIT')
|
||||
then writeln('Password successfully changed. (encrypted)')
|
||||
else Warning('Couldn''t change password. (encrypted)');
|
||||
|
||||
writeln('Verifying new password. (encrypted)');
|
||||
IF VerifyEncrBinderyObjectPassword(usrName,OT_USER,'wrong password')
|
||||
then Warning('A wrong (encrypted) password was verified as being OK.');
|
||||
|
||||
IF NOT VerifyEncrBinderyObjectPassword(usrName,OT_USER,'KERMIT')
|
||||
then Warning('The correct (encrypted) Password was NOT verified.');
|
||||
|
||||
{ If you stop execution of this program AT THIS POINT, you will
|
||||
have added a user THE_DIVA with password KERMIT, member of the
|
||||
group EVERYONE to your bindery. }
|
||||
|
||||
{ halt(0); }
|
||||
|
||||
writeln;
|
||||
writeln('WARNING: If you didn''t SET ALLOW UNENCRYPTED PASSWORDS=ON,');
|
||||
writeln(' -The server will beep;');
|
||||
writeln(' -Supervisor(s) will receive a 1 line message.');
|
||||
writeln(' (unless CASTOFF ALL was used);');
|
||||
writeln(' -The next(unencrypted) calls will fail.');
|
||||
writeln(' (All the above is essentially harmless)');
|
||||
writeln;
|
||||
writeln(' <ENTER> to continue...');
|
||||
readln;
|
||||
|
||||
writeln;
|
||||
writeln('Changing Object Password. (unencrypted)');
|
||||
IF ChangeBinderyObjectPassword(usrName,OT_USER,'KERMIT','SECRET')
|
||||
then writeln('Password successfully changed. (unencrypted)')
|
||||
else Warning('Couldn''t change password. (unencrypted)');
|
||||
|
||||
writeln('Verifying new password. (unencrypted)');
|
||||
IF VerifyBinderyObjectPassword(usrName,OT_USER,'wrong password')
|
||||
then Warning('A wrong (unencrypted) password was verified as being OK.');
|
||||
|
||||
IF NOT VerifyBinderyObjectPassword(usrName,OT_USER,'SECRET')
|
||||
then Warning('The correct (unencrypted) Password was NOT verified.');
|
||||
|
||||
{------------ Deleting properties and objects }
|
||||
writeln;
|
||||
writeln('Deleting a property.');
|
||||
IF NOT DeleteProperty(usrName,OT_USER,'IDENTIFICATION')
|
||||
then writeln('Couldn''t delete property.');
|
||||
|
||||
IF ExistsProperty(usrName,OT_USER,'IDENTIFICATION')
|
||||
then writeln('??:Property wasn''t deleted.');
|
||||
|
||||
writeln('Removing the user object from the group EVERYONE.');
|
||||
DeleteBinderyObjectFromSet(usrName,OT_USER,
|
||||
'GROUP_MEMBERS','EVERYONE',OT_USER_GROUP);
|
||||
|
||||
IF IsBinderyObjectInSet(usrName,OT_USER,
|
||||
'GROUP_MEMBERS','EVERYONE',OT_USER_GROUP)
|
||||
then writeln('Couldn''t throw '+usrName+' out of everyone (group)');
|
||||
|
||||
writeln('Deleting the ',usrName,' object and all related properties.');
|
||||
IF NOT DeleteBinderyObject(usrName,OT_USER)
|
||||
then writeln('Couldn''t delete object.');
|
||||
|
||||
IF GetBinderyObjectID(usrName,OT_USER,objID)
|
||||
then writeln('??: deleted object still exists.');
|
||||
|
||||
end.
|
||||
66
NWTP/XCONN/CEXPPW.PAS
Normal file
66
NWTP/XCONN/CEXPPW.PAS
Normal file
@@ -0,0 +1,66 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
Program CexpPw;
|
||||
|
||||
{ Example for the nwConn unit / NwTP 0.6 API. (c) 1993,1995, R. Spronk }
|
||||
|
||||
{ Andre Middendorp [2:512/220] wrote on Sun 3 Jul 94
|
||||
|
||||
Q: Ik ben op zoek naar een tooltje waarmee ik op een NW 3.1x server
|
||||
een file aan kan maken met daarin alle gebruikers waarvan het
|
||||
wachtwoord is vervallen. Wie weet iets....?
|
||||
|
||||
A: Here's a short program that will check whether or not the password
|
||||
has expired of any user object. It will present you with a list of
|
||||
all accounts that are expired.}
|
||||
|
||||
Uses nwMisc,nwBindry,nwConn,nwServ;
|
||||
{ nwServ used for GetFileServerDateAndTime only }
|
||||
|
||||
{ Demonstates the GetObjectLoginControl function.
|
||||
see also the information provided with the ObjectCanLoginAt call }
|
||||
|
||||
Var TimeNow :TnovTime;
|
||||
lastObjSeen :Longint;
|
||||
RepName :String;
|
||||
RepType :Word;
|
||||
RepId :LongInt;
|
||||
RepFlag :Byte;
|
||||
RepSecurity :Byte;
|
||||
RepHasProperties:Boolean;
|
||||
LogControlInfo :TloginControl;
|
||||
NbrOfExp :word;
|
||||
Begin
|
||||
Writeln('CEXPPW: Check Expired Passwords.');
|
||||
IF NOT (IsShellLoaded and IsUserLoggedOn)
|
||||
then begin
|
||||
writeln('Load network shell and logon before running this program');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
GetFileServerDateAndTime(TimeNow);
|
||||
|
||||
NbrOfExp:=0;
|
||||
lastObjSeen:=-1;
|
||||
WHILE
|
||||
ScanBinderyObject('*',OT_USER,lastObjSeen,
|
||||
RepName, RepType, RepId,
|
||||
RepFlag, RepSecurity, RepHasProperties)
|
||||
do begin
|
||||
IF GetObjectLoginControl(RepName,RepType,LogControlInfo)
|
||||
then with LogControlInfo.AccountExpirationDate
|
||||
do if (year>0) { year=0: no expiration date was set }
|
||||
and (TimeNow.year>=year)
|
||||
and (TimeNow.month>=month)
|
||||
and (TimeNow.day>=day)
|
||||
then begin
|
||||
writeln('Account of ',Repname,' expired on: ',day,'/',month,'/',year);
|
||||
inc(NbrOfExp);
|
||||
end;
|
||||
end;
|
||||
if nwBindry.Result<>$FC { NO_SUCH_OBJECT, indicates end of search }
|
||||
then writeln('Error scanning bindery : $',HexStr( nwBindry.Result,2));
|
||||
if NbrOfExp=0
|
||||
then writeln(#10#13,'No expired passwords found.')
|
||||
else writeln('(dates expressed in dd/mm/yy format.');
|
||||
end.
|
||||
44
NWTP/XCONN/CHKATT.PAS
Normal file
44
NWTP/XCONN/CHKATT.PAS
Normal file
@@ -0,0 +1,44 @@
|
||||
{X+,V-,B-}
|
||||
|
||||
program ChkAtt;
|
||||
|
||||
{ Example for the nwConn unit/ NwTP 0.6 API. (c) 1993,1995, R. Spronk }
|
||||
|
||||
uses nwMisc,nwBindry,nwConn;
|
||||
|
||||
Var srvr,usr:string;
|
||||
connId,PrConnId:Byte;
|
||||
MyObjName:string;
|
||||
MyObjType:word;
|
||||
MyObjId:Longint;
|
||||
accLev:byte;
|
||||
|
||||
begin
|
||||
if ParamCount<>2
|
||||
then begin
|
||||
writeln('CHKATT - Batch file utility to check for an attachment.');
|
||||
writeln;
|
||||
writeln('Supply 2 parameters : CHKATT <servername> <username>');
|
||||
writeln('If attached/logged on : ChkAtt returns errorlevel 0');
|
||||
writeln('in *all* other circumstances, errorlevel 1 will be returned.');
|
||||
halt(1);
|
||||
end;
|
||||
srvr:=ParamStr(1);UpString(srvr);
|
||||
Usr:=paramStr(2);UpString(usr);
|
||||
IF NOT GetConnectionId(srvr,connId)
|
||||
then halt(1);
|
||||
{ ok.. attachment to <servername> exists... am I logged in as <username> ? }
|
||||
GetPreferredConnectionId(prConnId);
|
||||
SetPreferredConnectionId(connId);
|
||||
IF GetBinderyAccessLevel(accLev,MyObjId)
|
||||
and GetBinderyObjectName(MyObjId,MyObjName,MyObjType)
|
||||
and (MyObjName=usr)
|
||||
then begin
|
||||
SetPreferredConnectionId(PrConnId);
|
||||
halt(0);
|
||||
end
|
||||
else begin
|
||||
SetPreferredConnectionId(PrConnId);
|
||||
halt(1);
|
||||
end
|
||||
end.
|
||||
31
NWTP/XCONN/DETACH.PAS
Normal file
31
NWTP/XCONN/DETACH.PAS
Normal file
@@ -0,0 +1,31 @@
|
||||
Program Detach;
|
||||
|
||||
{ Example for the NwConn unit / NwTP 0.6, (c) 1993,1995 R.Spronk }
|
||||
|
||||
{ Detach from the fileserver whose name is in parameter #1,
|
||||
delete all drivemappings to directories of target server's volumes }
|
||||
|
||||
Uses nwMisc,nwConn,nwFile;
|
||||
|
||||
Var ConnId:Byte;
|
||||
Srvr:String;
|
||||
begin
|
||||
If paramCount<>1
|
||||
then begin
|
||||
writeln('ERR: Supply name of server to detach from as a parameter.');
|
||||
writeln;
|
||||
writeln('Detaches from server/ removes all drive mappings to server.');
|
||||
writeln('Returns errorlevel 1 when detaching was successful. 0 otherwise.');
|
||||
halt(0);
|
||||
end;
|
||||
Srvr:=ParamStr(1);UpString(Srvr);
|
||||
IF NOT GetConnectionId(Srvr,connId)
|
||||
then begin
|
||||
writeln('ERR: Not attached to server ',Srvr);
|
||||
halt(0);
|
||||
end;
|
||||
DeleteConnectionsDriveMappings(connId);
|
||||
IF DetachFromFileServer(connId)
|
||||
then halt(1)
|
||||
else halt(0);
|
||||
end.
|
||||
81
NWTP/XCONN/LOGCON.PAS
Normal file
81
NWTP/XCONN/LOGCON.PAS
Normal file
@@ -0,0 +1,81 @@
|
||||
{$X+,V-,B-}
|
||||
program LogCon;
|
||||
|
||||
{ Example program for the nwConn unit/ NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Shows the use of the GetObjectLoginControl Function. }
|
||||
|
||||
uses nwMisc,nwConn;
|
||||
|
||||
CONST TestObjName='TEST';
|
||||
{ name of the object whose LOGIN_CONTROL property is read. }
|
||||
{ must be of objecttype 'ot_user' }
|
||||
|
||||
Var li:TloginControl;
|
||||
s :string;
|
||||
|
||||
{
|
||||
BadLoginCount :byte;
|
||||
AccountResetTime :TnovTime; dmy, hms valid only
|
||||
LastIntruderAdress :TinterNetworkAdress;
|
||||
|
||||
MaxConcurrentConnections :byte;
|
||||
LoginTimes :array[1..42] of byte;
|
||||
|
||||
unknown1 :byte;
|
||||
unknown2 :array[1..6] of byte;
|
||||
}
|
||||
|
||||
begin
|
||||
IF NOT GetObjectLoginControl('TEST',1,li)
|
||||
then begin
|
||||
writeln('GetObjectLoginControl Failed. error#',nwConn.result);
|
||||
writeln;
|
||||
writeln('(Hint: change the hardcoded username in the source to a username that exists.)');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
writeln('Logincontrol Information:');
|
||||
writeln;
|
||||
if li.AccountDisabled then writeln('The account is DISABLED.');
|
||||
|
||||
NovTime2String(li.AccountExpirationDate,s);delete(s,1,5);
|
||||
if pos('lid date &',s)>0 then s:='No expiration date set.';
|
||||
writeln('Account Expires: ',s);
|
||||
|
||||
writeln;
|
||||
writeln('Minimum Password length =',li.MinimumPasswordLength);
|
||||
writeln('Days between password changes =',li.DaysBetweenPasswordChanges);
|
||||
|
||||
NovTime2String(li.PasswordExpirationDate,s);delete(s,1,5);
|
||||
if pos('lid date &',s)>0 then s:='No Expiration date set.';
|
||||
writeln('Password Expiration date: ',s);
|
||||
|
||||
write('Password control flag: ');
|
||||
CASE li.PasswordControlFlag of
|
||||
0:writeln('User is allowed to change password.');
|
||||
1:writeln('Supervisor must change password.');
|
||||
2:writeln('User is allowed to change password. Passwords must be unique.');
|
||||
3:writeln('Supervisor must change passwords. Passwords must be unique.');
|
||||
else writeln('Unknown Password control Flag:',li.PasswordControlFlag);
|
||||
end; {case}
|
||||
|
||||
writeln;
|
||||
IF li.MaxGraceLoginsAllowed=0
|
||||
then writeln('Grace logins are unlimited.')
|
||||
else begin
|
||||
writeln('Max. Grace Logins: ',li.MaxGraceLoginsAllowed);
|
||||
writeln('Remaining Grace Logins: ',li.GraceLoginsRemaining);
|
||||
end;
|
||||
writeln;
|
||||
|
||||
NovTime2String(li.LastLoginTime,s);delete(s,1,5);
|
||||
if pos('lid date &',s)>0 then s:='Object has never logged in.';
|
||||
writeln('Last login time: ',s);
|
||||
|
||||
writeln;
|
||||
NovTime2String(li.AccountResetTime,s);delete(s,1,5);
|
||||
if pos('lid date &',s)>0 then s:='?? time not set.';
|
||||
writeln('Date of last Account reset: ',s);
|
||||
|
||||
end.
|
||||
214
NWTP/XCONN/LOGOUT.PAS
Normal file
214
NWTP/XCONN/LOGOUT.PAS
Normal file
@@ -0,0 +1,214 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
Program Logout;
|
||||
|
||||
{ Fixed by RPL }
|
||||
|
||||
uses crt,dos,graph,nwConn;
|
||||
{ demo of a program that logs out the user, and fills the screen with
|
||||
a worm, functionally equal to the worm of the netware console monitor. }
|
||||
|
||||
const
|
||||
MaxTailLen = 30;
|
||||
MaxDeviations = 15;
|
||||
MaxSymbols = 5;
|
||||
TailSegments : array[1..MaxSymbols] of byte
|
||||
= (32,176,177,178,219);
|
||||
|
||||
type
|
||||
BorderColl = (left,right,upside,downside);
|
||||
|
||||
var
|
||||
gd,gm : integer;
|
||||
|
||||
color : boolean;
|
||||
wormrecord : record
|
||||
x_head,y_head : integer;
|
||||
ChosenDir : integer;
|
||||
PreferredDir : integer;
|
||||
LengthFactor : integer;
|
||||
TailLen : integer;
|
||||
x,y : array[1..MaxTailLen] of integer;
|
||||
end;
|
||||
|
||||
|
||||
procedure Initialization;
|
||||
var CurrSegment : integer;
|
||||
begin
|
||||
randomize;
|
||||
|
||||
with wormrecord
|
||||
do begin
|
||||
LengthFactor:=random(5)+3;
|
||||
TailLen:=MaxSymbols*LengthFactor;
|
||||
if TailLen>MaxTailLen then TailLen:=MaxTailLen;
|
||||
x_head:=40;
|
||||
y_head:=12;
|
||||
PreferredDir:=random(8);
|
||||
for CurrSegment:=1 to MaxTailLen
|
||||
do begin
|
||||
x[CurrSegment]:=0;
|
||||
y[CurrSegment]:=0;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure ChooseDir;
|
||||
{ This procedure determines the future direction of the worm. }
|
||||
VAR NbrOfDev : integer;
|
||||
begin
|
||||
NbrOfDev:=0;
|
||||
with wormrecord
|
||||
do begin
|
||||
repeat
|
||||
repeat
|
||||
inc (NbrOfDev);
|
||||
ChosenDir:=random(8);
|
||||
until (NbrOfDev>=MaxDeviations)
|
||||
or (ChosenDir=PreferredDir);
|
||||
until abs(PreferredDir-ChosenDir)<>4;
|
||||
PreferredDir:=ChosenDir;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure DrawWorm;
|
||||
var CurrSegment : integer;
|
||||
SegmentSym : integer;
|
||||
begin
|
||||
with wormrecord
|
||||
do begin
|
||||
if color then textcolor (7);
|
||||
for CurrSegment:=1 to TailLen
|
||||
do begin
|
||||
SegmentSym:=(CurrSegment-1) div LengthFactor+1;
|
||||
if (x[CurrSegment]<>0)
|
||||
then begin
|
||||
gotoxy (x[CurrSegment],y[CurrSegment]);
|
||||
write (chr(TailSegments[SegmentSym]),
|
||||
chr(TailSegments[SegmentSym]));
|
||||
end;
|
||||
if (CurrSegment<TailLen)
|
||||
then begin
|
||||
x[CurrSegment]:=x[CurrSegment+1];
|
||||
y[CurrSegment]:=y[CurrSegment+1];
|
||||
end;
|
||||
end;
|
||||
gotoxy (x[TailLen],y[TailLen]);
|
||||
x[TailLen]:=x_head;
|
||||
y[TailLen]:=y_head;
|
||||
end;
|
||||
if color then textcolor (7);
|
||||
end;
|
||||
|
||||
procedure ReverseDir (ScreenBorder:BorderColl);
|
||||
{ Bounce directions on screenborders }
|
||||
begin
|
||||
with wormrecord
|
||||
do case ScreenBorder of
|
||||
left : case PreferredDir of
|
||||
3 : PreferredDir:=1;
|
||||
4 : PreferredDir:=0;
|
||||
5 : PreferredDir:=7;
|
||||
end;
|
||||
right : case PreferredDir of
|
||||
1 : PreferredDir:=3;
|
||||
0 : PreferredDir:=4;
|
||||
7 : PreferredDir:=5;
|
||||
end;
|
||||
upside : case PreferredDir of
|
||||
1 : PreferredDir:=7;
|
||||
2 : PreferredDir:=6;
|
||||
3 : PreferredDir:=5;
|
||||
end;
|
||||
downside : case PreferredDir of
|
||||
5 : PreferredDir:=3;
|
||||
6 : PreferredDir:=2;
|
||||
7 : PreferredDir:=1;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure DeterminePos;
|
||||
begin
|
||||
with wormrecord
|
||||
do begin
|
||||
if (ChosenDir in [1..3])
|
||||
then dec (y_head);
|
||||
if (ChosenDir in [5..7])
|
||||
then inc (y_head);
|
||||
if (ChosenDir in [3..5])
|
||||
then dec (x_head);
|
||||
if (ChosenDir<2) or (ChosenDir=7)
|
||||
then inc (x_head);
|
||||
if (ChosenDir=0)
|
||||
then inc (x_head);
|
||||
if (ChosenDir=4)
|
||||
then dec (x_head);
|
||||
|
||||
if (x_head<1)
|
||||
then begin
|
||||
x_head:=2-x_head;
|
||||
ReverseDir (left);
|
||||
end;
|
||||
if (x_head>77)
|
||||
then begin
|
||||
x_head:=77-(x_head-77);
|
||||
ReverseDir (right);
|
||||
end;
|
||||
if (y_head<1)
|
||||
then begin
|
||||
y_head:=2-y_head;
|
||||
ReverseDir (upside);
|
||||
end;
|
||||
if (y_head>24)
|
||||
then begin
|
||||
y_head:=24-(y_head-24);
|
||||
ReverseDir (downside);
|
||||
end;
|
||||
end; {with}
|
||||
end;
|
||||
|
||||
|
||||
procedure logoutservers;
|
||||
{ Logs you out form all servers by logging out and detaching on
|
||||
a server by server basis. You are not detached from your primary server. }
|
||||
Var connId:byte;
|
||||
servName:string;
|
||||
primserv:byte;
|
||||
begin
|
||||
GetPrimaryConnectionId(primServ);
|
||||
for connId:=1 to 8
|
||||
do begin
|
||||
IF GetFileServerName(ConnId,servName)
|
||||
then begin
|
||||
IF LogoutFromFileServer(ConnId)
|
||||
then begin
|
||||
if (connId<>PrimServ)
|
||||
then begin
|
||||
DetachFromFileServer(connId);
|
||||
writeln('You are now detached from fileserver ',servName);
|
||||
end
|
||||
else writeln('You are now logged out from fileserver ',servName);
|
||||
end;
|
||||
end
|
||||
end;
|
||||
delay(2500);
|
||||
end;
|
||||
|
||||
|
||||
begin
|
||||
color:=false;
|
||||
detectgraph (gd,gm);
|
||||
color:=(gd<>7);
|
||||
logoutservers;
|
||||
clrscr;
|
||||
Initialization;
|
||||
repeat
|
||||
ChooseDir ;
|
||||
DeterminePos;
|
||||
DrawWorm ;
|
||||
delay (150);
|
||||
until keypressed;
|
||||
clrscr;
|
||||
end.
|
||||
63
NWTP/XCONN/PWEXP.PAS
Normal file
63
NWTP/XCONN/PWEXP.PAS
Normal file
@@ -0,0 +1,63 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
program pwexp;
|
||||
|
||||
{ Example for the nwConn unit / NwTP 0.6 API. (c) 1993,1995, R. Spronk }
|
||||
|
||||
|
||||
{ Q: We're forcing our users to change their passwords every 40 days.
|
||||
After the password expiration date, they have 3 grace logins, one
|
||||
of which they should use to change their password. To force them
|
||||
to change their passwords whenever they login after the expiration
|
||||
date, we need an utility that returns a distinctive Errorlevel
|
||||
whenever the password has expired.
|
||||
|
||||
The following program will return an errorlevel 0 whenever the calling
|
||||
station's password has expired (current date later than expiration
|
||||
date). In all other cases (i.e. an expiration date wasn't set, 1 will
|
||||
be returned.
|
||||
}
|
||||
|
||||
Uses nwMisc,NwBindry,nwConn,nwServ;
|
||||
|
||||
Function LaterDate(Var t1,t2):Boolean;
|
||||
Type Tascii3=array[1..3] of char;
|
||||
Var ta:Tascii3 ABSOLUTE t1;
|
||||
tb:Tascii3 ABSOLUTE t2;
|
||||
begin
|
||||
if ta[1]<#80 then inc(ta[1],100);
|
||||
if tb[1]<#80 then inc(tb[1],100);
|
||||
LaterDate:=(ta>tb);
|
||||
end;
|
||||
|
||||
Var AccLev:Byte;
|
||||
MyObjId:Longint;
|
||||
MyObjName:string;
|
||||
MyObjType:word;
|
||||
Info:TloginControl;
|
||||
Now:TnovTime;
|
||||
|
||||
begin
|
||||
IF GetBinderyAccessLevel(AccLev,MyObjId)
|
||||
and GetBinderyObjectname(MyObjId,MyObjName,MyObjType)
|
||||
then begin
|
||||
IF GetObjectLoginControl(MyObjName,MyObjType,info)
|
||||
then with Info.PasswordExpirationDate
|
||||
do begin
|
||||
if (year=0) and (month=0) and (day=0)
|
||||
then begin
|
||||
writeln('PWEXP: Expiration date not set.');
|
||||
halt(1); { exp. date not set }
|
||||
end;
|
||||
GetFileServerDateAndTime(now);
|
||||
IF LaterDate(now,info.PasswordExpirationDate)
|
||||
then begin
|
||||
writeln('PWEXP: Password expired !');
|
||||
halt(0) { PW expired }
|
||||
end
|
||||
else halt(1);
|
||||
end;
|
||||
end;
|
||||
writeln('PWEXP: Bindery read error. Shell wel geladen ? Ingelogd ?');
|
||||
halt(1);
|
||||
end.
|
||||
188
NWTP/XCONN/TRCOPY.PAS
Normal file
188
NWTP/XCONN/TRCOPY.PAS
Normal file
@@ -0,0 +1,188 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
Program TrCopy;
|
||||
|
||||
{ Example for the nwConn unit/ NwTP 0.6 API. (c) 1993,1995, R. Spronk }
|
||||
|
||||
{ Copies the time restrictions of a supplied user to amother user,
|
||||
or another user group. The destination may conatain wildcards. }
|
||||
|
||||
{ Note that it is possible to change the time restrictions of a number of
|
||||
users by tagging them with F5 (in SYSCON) and then changing the time
|
||||
restrictions. }
|
||||
|
||||
{(4395) Tue 8 Feb 94 8:43
|
||||
By: Jos Cobbenhagen
|
||||
To: Allen
|
||||
Re: MUTATIE TIME-RESTR.
|
||||
St:
|
||||
------------------------------------------------------------
|
||||
Aan :Allen Van :Jos Cobbenhagen Betreft :Mutaties Time-restrictions
|
||||
|
||||
Ik moet incidenteel voor een aantal wisselende afdelingen/gebruikers de
|
||||
time-restrictions aanpassen. Dit komt voor bij crises en apparte gebeurtenissen
|
||||
waarbij users ijdelijk 's avonds en in weekenden moeten werken. Enige
|
||||
mogelijkheid die ik hiervoor ken is voor de betreffende users appart deze
|
||||
restricties aanpassen, en voor 50+ gebruikers is dat vrij omslachtig. Vraag is
|
||||
of er een bindery utility is die dit in een keer voor een bepaalde groep
|
||||
gebruikers kan regelen?
|
||||
}
|
||||
|
||||
uses nwMisc,nwBindry;
|
||||
|
||||
Var source :string;
|
||||
TimeRestr:array[1..42] of byte;
|
||||
|
||||
Function ChangeTRforUser(dest:string):boolean;
|
||||
Var res:boolean;
|
||||
|
||||
ObjName :string;
|
||||
ObjType :word;
|
||||
ObjId :LongInt;
|
||||
Iter :LongInt;
|
||||
Flag,Sec :byte;
|
||||
HasProperties:boolean;
|
||||
|
||||
propValue:Tproperty;
|
||||
moreSegs :boolean;
|
||||
propFlags:byte;
|
||||
begin
|
||||
res :=false;
|
||||
iter:=-1;
|
||||
WHILE ScanBinderyObject(dest,OT_USER,iter,
|
||||
ObjName,ObjType,ObjId, Flag,Sec,HasProperties)
|
||||
do begin
|
||||
res:=true;
|
||||
IF (source<>ObjName)
|
||||
and ReadPropertyValue(ObjName,OT_USER,'LOGIN_CONTROL',1,
|
||||
propValue,moreSegs,propFlags)
|
||||
then begin
|
||||
Move(TimeRestr[1],propValue[15],42);
|
||||
IF WritePropertyvalue(ObjName,ObjType,'LOGIN_CONTROL',1,
|
||||
propValue,FALSE)
|
||||
then writeln('Time restrictions of user ',ObjName,' changed.');
|
||||
end;
|
||||
end;
|
||||
ChangeTRForUser:=res;
|
||||
end;
|
||||
|
||||
|
||||
Function ChangeTRforGroup(GroupDest:string):boolean;
|
||||
Var res:boolean;
|
||||
|
||||
ObjName :string;
|
||||
ObjType :word;
|
||||
ObjId :LongInt;
|
||||
Iter :LongInt;
|
||||
Flag,Sec :byte;
|
||||
HasProperties:boolean;
|
||||
|
||||
propValue:Tproperty;
|
||||
moreSegs :boolean;
|
||||
propFlags:byte;
|
||||
seg,i :byte;
|
||||
|
||||
UserObjId :LongInt;
|
||||
UserObjName:string;
|
||||
begin
|
||||
res :=false;
|
||||
iter:=-1;
|
||||
WHILE ScanBinderyObject(GroupDest,OT_USER_GROUP,iter,
|
||||
ObjName,ObjType,ObjId, Flag,Sec,HasProperties)
|
||||
do begin
|
||||
res:=true;
|
||||
seg:=1;
|
||||
|
||||
WHILE ReadPropertyValue(ObjName,OT_USER_GROUP,'GROUP_MEMBERS',seg,
|
||||
propValue,moreSegs,propFlags)
|
||||
do begin
|
||||
i:=1;
|
||||
Repeat
|
||||
UserObjId:=MakeLong((propValue[i] *256 + PropValue[i+1] ),
|
||||
(propValue[i+2] *256 + PropValue[i+3] ) );
|
||||
if UserObjId<>0
|
||||
then begin
|
||||
IF GetBinderyObjectName(UserObjId,UserObjName,ObjType)
|
||||
and (UserObjName<>Source)
|
||||
then ChangeTRForUser(UserObjName);
|
||||
end;
|
||||
inc(i,4);
|
||||
Until (i>128) or (objId=0);
|
||||
|
||||
inc(seg);
|
||||
end;
|
||||
end;
|
||||
ChangeTRForGroup:=res;
|
||||
end;
|
||||
|
||||
Procedure GetSourceTR(source:string);
|
||||
Var propValue:Tproperty;
|
||||
MoreSegs :boolean;
|
||||
PropFlags:byte;
|
||||
begin
|
||||
IF NOT ReadPropertyValue(source,OT_USER,'LOGIN_CONTROL',1,
|
||||
propValue,moreSegs,propFlags)
|
||||
then begin
|
||||
writeln;
|
||||
Case nwBindry.result OF
|
||||
$F0 :writeln('Wildcards in source not allowed.');
|
||||
$FC,$FB:writeln('No such userobject');
|
||||
$F9,$F1:writeln('Not enough privileges..');
|
||||
else writeln('General error reading the bindery.');
|
||||
end;{case}
|
||||
Halt(1);
|
||||
end;
|
||||
Move(propValue[15],TimeRestr[1],42);
|
||||
end;
|
||||
|
||||
|
||||
{--------------------------------- main -------------------------------------}
|
||||
Var dest :string;
|
||||
MyObjId :Longint;
|
||||
secLevel:byte;
|
||||
version :word;
|
||||
|
||||
begin
|
||||
If ParamCount<>2
|
||||
then begin
|
||||
writeln('----- TRCOPY: Copy Login Time Restrictions from one user to another. -----');
|
||||
writeln;
|
||||
writeln('Usage: TRCOPY <source> <dest>');
|
||||
writeln;
|
||||
writeln('Where <source> is the name of a USER,');
|
||||
writeln('and <dest> the name of a user or group the time restrictions');
|
||||
writeln('are to be copied to. <dest> may contain wildcards.');
|
||||
writeln;
|
||||
writeln('----- Use with NetWare 3.x only ---------- Written with the NwTP API -----');
|
||||
halt(0);
|
||||
end;
|
||||
writeln('TRCOPY: Copy Time Restrictions.');
|
||||
source:=ParamStr(1);
|
||||
dest :=ParamStr(2);
|
||||
UpString(Source);
|
||||
UpString(dest);
|
||||
|
||||
IF (NOT GetBinderyAccessLevel(secLevel,MyObjId))
|
||||
or (secLevel<>$33)
|
||||
then begin
|
||||
writeln;
|
||||
writeln('You need to be logged in as a Supervisor equivalent user');
|
||||
writeln('to use this utility.');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
GetNWversion(version);
|
||||
if (version DIV 100)<>3
|
||||
then begin
|
||||
writeln;
|
||||
writeln('TRCOPY runs with NetWare 3.X only.');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
GetSourceTR(source);
|
||||
|
||||
IF NOT ChangeTRforUser(dest)
|
||||
then IF NOT ChangeTRforGroup(dest)
|
||||
then writeln('Error: destination user or group doesn''t exist.');
|
||||
|
||||
end.
|
||||
172
NWTP/XCONN/TSTCONN.PAS
Normal file
172
NWTP/XCONN/TSTCONN.PAS
Normal file
@@ -0,0 +1,172 @@
|
||||
{$X+,V-,B-}
|
||||
Program testconn;
|
||||
|
||||
{ Testprogram for the nwConn unit / NwTP 0.6 API. (c) 1993, 1995, R.Spronk }
|
||||
|
||||
{ Purpose: testing of nwConn calls }
|
||||
|
||||
{ Tests the following nwConn functions:
|
||||
|
||||
GetConnectionId
|
||||
GetConnectionInformation
|
||||
GetConnectionNumber
|
||||
GetDefaultConnectionId
|
||||
GetFileserverName
|
||||
GetInternetAddress
|
||||
GetObjectConnectionNumbers
|
||||
GetPreferredConnectionId
|
||||
GetPrimaryConnectionId
|
||||
GetWorkstationNodeAddress
|
||||
GetUserAtConnection
|
||||
}
|
||||
|
||||
Uses nwMisc,nwConn;
|
||||
|
||||
Procedure Warning(s:string);
|
||||
begin
|
||||
writeln(s);
|
||||
writeln(' ERROR #: $',HexStr(nwConn.Result,2),' (',nwConn.result,')');
|
||||
writeln;
|
||||
writeln('...Press <Enter> to Continue..');
|
||||
readln;
|
||||
end;
|
||||
|
||||
Var myConnNumber:byte;
|
||||
myConnId :byte; { connID of server I'm attached to }
|
||||
myPhysNode2:TnodeAddress;
|
||||
myObjName :string;
|
||||
myObjType :word;
|
||||
myObjId :longInt;
|
||||
myLoginTime :TnovTime;
|
||||
|
||||
myAddress:TinternetworkAddress;
|
||||
|
||||
nbrOfConn:byte;
|
||||
connList :TconnectionList;
|
||||
|
||||
objName :string;
|
||||
objType :word;
|
||||
objId :LongInt;
|
||||
LoginTime:TnovTime;
|
||||
|
||||
connId :byte;
|
||||
serverName:string;
|
||||
routeInfo :string;
|
||||
|
||||
t :byte;
|
||||
tempStr:string;
|
||||
|
||||
begin
|
||||
|
||||
IF GetConnectionNumber(myConnNumber)
|
||||
then writeln('Your connection number is:',myConnNumber)
|
||||
else warning('!!! The GetConnectionNumber call failed');
|
||||
|
||||
IF GetInterNetAddress(myConnNumber,myAddress)
|
||||
then begin
|
||||
write('Your Netw.:Node:Socket Nbr is: [$');
|
||||
for t:=1 to 4 do write(hexStr(myAddress.Net[t],2));
|
||||
write(':');
|
||||
for t:=1 to 6 do write(HexStr(myAddress.Node[t],2));
|
||||
writeln(':',hexstr(myAddress.socket,4),']');
|
||||
end
|
||||
else warning('!!! GetInterNetAdress failed.');
|
||||
|
||||
|
||||
IF GetWorkstationNodeAddress(myPhysNode2)
|
||||
and (myAddress.Node[6]=myPhysNode2[6])
|
||||
and (myAddress.Node[5]=myPhysNode2[5])
|
||||
and (myAddress.Node[4]=myPhysNode2[4])
|
||||
then { ok }
|
||||
else begin
|
||||
warning('!!! GetStationadress failed');
|
||||
write('returned: $');
|
||||
for t:=1 to 6 do write(HexStr(myPhysNode2[t],2));
|
||||
end;
|
||||
|
||||
IF GetConnectionInformation(myConnNumber,
|
||||
myObjName,myObjType,myObjId,myLoginTime)
|
||||
then begin
|
||||
writeln('You are :',myObjName);
|
||||
if myObjType=$1 { OT_USER}
|
||||
then writeln(' of object type : USER')
|
||||
else writeln(' of object type : $',HexStr(myObjType,4));
|
||||
writeln(' with object ID: $',HexStr(myObjId,8));
|
||||
NovTime2String(myLoginTime,tempStr);
|
||||
writeln(' logged in at ',tempStr);
|
||||
end
|
||||
else warning('!!! GetConnectionInformation failed.');
|
||||
|
||||
if NOT (GetUserAtConnection(myConnNumber,tempStr) and (tempStr=myObjName))
|
||||
then warning('!!! GetUserAtConnection (2) failed.');
|
||||
|
||||
IF GetObjectConnectionNumbers(myObjName,1 {OT_USER},
|
||||
nbrOfConn,connList)
|
||||
then begin
|
||||
writeln('User ',myObjName,' has ',nbrOfConn,' active connection(s).');
|
||||
t:=nbrOfConn;
|
||||
if t>0
|
||||
then begin
|
||||
t:=1;
|
||||
while t<=nbrOfConn
|
||||
do begin
|
||||
writeln(' at connectionNumber:',connList[t]);
|
||||
inc(t);
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else warning('!!! GetObjectConnectionNumbers failed.');
|
||||
|
||||
|
||||
writeln;
|
||||
t:=1;
|
||||
writeln('ConnNbr Name LoginTime');
|
||||
WHILE t<250 { nw 3.x / 2.x 100 }
|
||||
do begin
|
||||
IF GetConnectionInformation(t, objName,objType,objId,LoginTime)
|
||||
then begin
|
||||
PstrCopy(TempStr,objName,15);
|
||||
objName:=TempStr;
|
||||
NovTime2String(LoginTime,TempStr);
|
||||
writeln(t:4,' ',objName,' ',TempStr);
|
||||
end
|
||||
else if nwConn.result<>$FD { bad_station_number / nbr not in use }
|
||||
then warning('!!! GetConnectionInformation failed.');
|
||||
inc(t);
|
||||
end;
|
||||
|
||||
{*********** connection ID's ( server numbers in server table )************ }
|
||||
|
||||
{ to which server have we been sending all the above requests? }
|
||||
|
||||
routeInfo:='preferred';
|
||||
GetPreferredConnectionID(ConnId);
|
||||
{ if set previously, this server has the highest priority. }
|
||||
|
||||
if connId=0 { preferred server was not set }
|
||||
then begin
|
||||
RouteInfo:='default';
|
||||
GetDefaultConnectionID(ConnId);
|
||||
end;
|
||||
{ your current default drive is attached to this server }
|
||||
|
||||
if connId=0
|
||||
then begin
|
||||
RouteInfo:='primary';
|
||||
GetPrimaryConnectionID(ConnId);
|
||||
end;
|
||||
{ the server your shell initially attached to, used if the default drive
|
||||
is a local drive. Lowest priority. }
|
||||
|
||||
{ These three calls are also incorporated in the secondary function:
|
||||
GetEffectiveConnectionID. }
|
||||
writeln;
|
||||
writeln('All requests are routed to the ',RouteInfo,'-server with conn.ID=',connId);
|
||||
|
||||
GetFileServerName(connId,{out:} serverName);
|
||||
GetConnectionID(serverName,{out} t);
|
||||
if t<>connId
|
||||
then warning('!!! GetFileServerName and GetConnectionId report different values.')
|
||||
else writeln('Name of the server: ',serverName);
|
||||
|
||||
end.
|
||||
127
NWTP/XCONN/TSTCONN2.PAS
Normal file
127
NWTP/XCONN/TSTCONN2.PAS
Normal file
@@ -0,0 +1,127 @@
|
||||
{$X+,V-,B-}
|
||||
program tstconn2;
|
||||
|
||||
{ Testprogram for the nwConn unit / NwTP 0.6 API. (c) 1993, 1995, R.Spronk }
|
||||
|
||||
{ Purpose: testing of nwConn calls }
|
||||
|
||||
{ Tests the following nwConn functions:
|
||||
|
||||
GetConnectionIdTable
|
||||
GetEndOfJobStatus
|
||||
GetPrimaryConnectionId
|
||||
GetNetwareErrorMode
|
||||
GetNetwareShellVersion
|
||||
GetWorkstationEnvironment
|
||||
SetEndOfJobStatus
|
||||
SetNetwareErrorMode
|
||||
SetPrimaryConnectionId
|
||||
|
||||
}
|
||||
|
||||
uses nwMisc,nwConn;
|
||||
|
||||
Var MajorVersion,MinorVersion,RevisionLevel:byte;
|
||||
OStype,OSversion,HardwareType,ShortHWType :string;
|
||||
|
||||
primConnId,TestConnId:byte;
|
||||
|
||||
c:byte;
|
||||
ConnInfo:TconnectionIDtableEntry;
|
||||
|
||||
status,status1:boolean;
|
||||
|
||||
mode,mode1:byte;
|
||||
|
||||
begin
|
||||
Writeln('Testing GetNWshellVersion.');
|
||||
IF GetNetwareShellVersion(MajorVersion,MinorVersion,RevisionLevel)
|
||||
then begin
|
||||
write(' Shell version: ',MajorVersion,'.',Minorversion);
|
||||
if RevisionLevel>0
|
||||
then writeln(' Rev.',chr(ord('A')+RevisionLevel-1))
|
||||
else writeln;
|
||||
if MajorVersion>=3
|
||||
then begin
|
||||
writeln;
|
||||
Writeln('Testing GetWSEnvironment.');
|
||||
IF GetWorkstationEnvironment(OStype,OSversion,
|
||||
HardwareType,ShortHWType)
|
||||
then begin
|
||||
writeln(' OStype :',OStype);
|
||||
writeln(' OSversion :',OSversion);
|
||||
writeln(' HardwareType:',HardwareType);
|
||||
writeln(' ShortHWtype :',ShortHWtype);
|
||||
end
|
||||
else writeln('GetWSenvironment returned error#:',HexStr(nwConn.result,2));
|
||||
|
||||
|
||||
|
||||
end;
|
||||
end
|
||||
else writeln('GetNWshellversion returned error#:',HexStr(nwConn.result,2));
|
||||
|
||||
writeln;
|
||||
writeln('Tesing SetPrimaryConnectionId.');
|
||||
GetPrimaryConnectionId(primConnId);
|
||||
writeln(' Primary connId=',primConnId);
|
||||
IF SetPrimaryConnectionId(0)
|
||||
then begin
|
||||
writeln(' OK. prim.connid set to 0');
|
||||
GetPrimaryConnectionId(testConnId);
|
||||
if testConnId<>0
|
||||
then writeln('ERR. primary connection wasn''t changed.');
|
||||
end;
|
||||
SetPrimaryConnectionId(primConnId);
|
||||
GetPrimaryConnectionId(testConnId);
|
||||
If testConnId=primConnId
|
||||
then writeln(' Primary connId reset to ',testConnId)
|
||||
else writeln('Error setting primary connectionId');
|
||||
|
||||
writeln;
|
||||
writeln('Testing GetConnectionIDtable.');
|
||||
for c:=1 to 8
|
||||
do begin
|
||||
GetConnectionIdTable(c,ConnInfo);
|
||||
if ConnInfo.SlotInuse>0
|
||||
then with ConnInfo
|
||||
do begin
|
||||
writeln(' Data for server with connId=',c);
|
||||
Writeln(' Adress of server :$',HexDumpstr(ServerAddress,24),' (net,node HI-LO, socket LO-HI)');
|
||||
Writeln(' Router address :$',HexDumpStr(RouterAddress,12));
|
||||
writeln(' My connection Nbr:',ConnectionNumber);
|
||||
writeln(' Connection Status:$',hexStr(connectionStatus,2));
|
||||
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
writeln;
|
||||
writeln('Testing Set/Get endOfJobStatus');
|
||||
GetEndOfJobStatus(status);
|
||||
SetEndOfJobStatus(NOT status);
|
||||
GetEndOfJobStatus(status1);
|
||||
if status1=NOT status
|
||||
then writeln(' Tested OK.')
|
||||
else writeln(' Error: test failed.');
|
||||
SetEndOfJobStatus(status);
|
||||
GetEndOfJobStatus(status1);
|
||||
if status1=status
|
||||
then writeln(' EOJ status reset to original mode.')
|
||||
else writeln('Err: status not reset to original mode.');
|
||||
|
||||
writeln;
|
||||
writeln('Testing Set/Get netwareErrorMode.');
|
||||
GetNetwareErrorMode(mode);
|
||||
SetNetwareErrorMode(2);
|
||||
GetNetwareErrorMode(mode1);
|
||||
if mode1=2
|
||||
then writeln(' Tested OK.')
|
||||
else writeln(' Error: test failed.');
|
||||
SetNetwareErrorMode(mode);
|
||||
GetNetwareErrorMode(mode1);
|
||||
if mode1=mode
|
||||
then writeln(' Error Mode reset to original mode.')
|
||||
else writeln('Err: error mode not reset to original mode.');
|
||||
|
||||
end.
|
||||
53
NWTP/XCONN/TSTCONN3.PAS
Normal file
53
NWTP/XCONN/TSTCONN3.PAS
Normal file
@@ -0,0 +1,53 @@
|
||||
{$X+,V-,B-}
|
||||
program tstconn3;
|
||||
|
||||
{ Testprogram for the nwConn unit / NwTP 0.6 API. (c) 1993, 1995, R.Spronk }
|
||||
|
||||
{ Purpose: testing of nwConn calls }
|
||||
|
||||
{ Tests the following nwConn functions:
|
||||
|
||||
AttachToFileServer
|
||||
AttachToFileServerWithAddress (called by AttachToFileServer)
|
||||
|
||||
}
|
||||
|
||||
uses nwMisc,nwConn;
|
||||
|
||||
Var connId,PrimConnId,t:byte;
|
||||
serverName:string;
|
||||
|
||||
begin
|
||||
writeln('This program tests the AttachToFileServer call.');
|
||||
writeln('Can be tested in a multi-server network only.');
|
||||
getPrimaryConnectionId(PrimConnId);
|
||||
GetFileServerName(PrimConnId,serverName);
|
||||
writeln;
|
||||
writeln('Your primary server is ',serverName,' with connectionId ',PrimConnId);
|
||||
|
||||
writeln;
|
||||
writeln('ConnectionIDtable:');
|
||||
for t:=1 to 8
|
||||
do If GetFileServerName(t,servername)
|
||||
and (serverName<>'')
|
||||
then writeln('ConnId: ',t:2,' Servername: ',serverName);
|
||||
|
||||
writeln;
|
||||
write('Enter name of new server (not in above list) to attach to:');
|
||||
readln(servername);
|
||||
IF NOT AttachToFileServer(serverName,connId)
|
||||
then begin
|
||||
writeln('AttachtoFileserver returned error: $',HexStr(nwConn.result,2));
|
||||
if nwconn.result=$7D
|
||||
then writeln(' (wrong servername or server unknown)');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
writeln;
|
||||
writeln('ConnectionIDtable:');
|
||||
for t:=1 to 8
|
||||
do If GetFileServerName(t,servername)
|
||||
and (serverName<>'')
|
||||
then writeln('ConnId: ',t:2,' Servername: ',serverName);
|
||||
|
||||
end.
|
||||
307
NWTP/XCONN/WHO.PAS
Normal file
307
NWTP/XCONN/WHO.PAS
Normal file
@@ -0,0 +1,307 @@
|
||||
{$X+,V-,B-}
|
||||
program who;
|
||||
|
||||
{ Adaption of a similar program privided with one of the other public
|
||||
domain TP API's.
|
||||
|
||||
Example program for the nwConn unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
uses nwMisc,nwBindry,nwConn,nwServ;
|
||||
{nwServ used for GetFileServerDateAndTime only}
|
||||
|
||||
Type String25=string[25];
|
||||
PTuserInfo=^TuserInfo;
|
||||
TuserInfo=record
|
||||
objName :string25;
|
||||
objId :LongInt;
|
||||
TrueName :string25;
|
||||
LoginTime:TnovTime; { time of last logon }
|
||||
ConnNbr :byte; { 0= not logged on}
|
||||
next :PTuserInfo;
|
||||
end;
|
||||
|
||||
var Param : string;
|
||||
DispAll,DispHelp : boolean;
|
||||
MyConnNbr : byte;
|
||||
MyServer : string;
|
||||
ConnInUse,UsersConnected,ConnNotLogIn:byte;
|
||||
startPtr : PTuserInfo;
|
||||
|
||||
Procedure ScanBinderyUsers;
|
||||
Var lastObjSeen:LongInt;
|
||||
UserName :string;
|
||||
UserType :word;
|
||||
UserId :LongInt;
|
||||
Flag,Security:Byte;
|
||||
hp :boolean;
|
||||
nUser,lUser,wUser:PTuserInfo;
|
||||
tempStr :string;
|
||||
LogInfo :TloginControl;
|
||||
|
||||
begin
|
||||
LastObjSeen:=-1;
|
||||
WHILE ScanBinderyObject('*',1 {OT_USER},LastObjSeen,
|
||||
UserName,UserType,UserId,Flag,Security,hp)
|
||||
do begin
|
||||
New(nUser);
|
||||
PstrCopy(nUser^.objName,UserName,25);
|
||||
nUser^.objId:=UserId;
|
||||
nUser^.ConnNbr:=0;
|
||||
nUser^.next:=NIL;
|
||||
|
||||
GetObjectLoginControl(UserName,1 {ot_user},LogInfo);
|
||||
nUser^.LoginTime:=LogInfo.LastLoginTime;
|
||||
|
||||
IF nwBindry.GetRealUserName(UserName,tempstr)
|
||||
then if (tempStr='')
|
||||
then tempStr:='_';
|
||||
PstrCopy(nUser^.TrueName,tempStr,25);
|
||||
|
||||
wUser:=startPtr;
|
||||
While (wUser<>NIL) and (wUser^.objName<nUser^.objName)
|
||||
do begin lUser:=wUser;wUser:=wUser^.next; end;
|
||||
nUser^.next:=wUser;
|
||||
lUser^.next:=nUser;
|
||||
|
||||
end;
|
||||
if nwBindry.Result<>$FC { no such object}
|
||||
then writeln('Error scanning Bindery.');
|
||||
|
||||
end;
|
||||
|
||||
Procedure DumpLoginTime(connNbr:byte;objName:string;objId:LongInt;time:TnovTime);
|
||||
Var nUser,lUser:PTuserInfo;
|
||||
begin
|
||||
lUser:=startPtr^.next;
|
||||
while (lUser<>NIL) and (luser^.objId<>objId)
|
||||
do lUser:=lUser^.next;
|
||||
if lUser<>NIL
|
||||
then begin
|
||||
if lUser^.ConnNbr=0 { first time the user is found at some connection }
|
||||
then begin
|
||||
lUser^.LoginTime:=time;
|
||||
lUser^.ConnNbr:=ConnNbr;
|
||||
end
|
||||
else begin { user logged in at multiple connections }
|
||||
new(nUser);
|
||||
nUser^:=lUser^;
|
||||
{nUser^.next:=lUser^.next}
|
||||
nUser^.LoginTime:=time;
|
||||
nUser^.ConnNbr:=ConnNbr;
|
||||
lUser^.next:=nUser;
|
||||
end;
|
||||
end
|
||||
else begin
|
||||
writeln('SECURITY WARNING: USER ''',objName,''' @ connection:',connNbr);
|
||||
writeln(' IS LOGGED IN W/O CORRESPONDING BINDERY OBJECT.');
|
||||
end
|
||||
end;
|
||||
|
||||
procedure DisplayHeader;
|
||||
Var connId :byte;
|
||||
username:string;
|
||||
objType :word;
|
||||
objID :LongInt;
|
||||
dateTime:TnovTime;
|
||||
begin
|
||||
UpString(Param);
|
||||
If NOT (GetPreferredConnectionID(connId) and (connId<>0))
|
||||
then if NOT (GetDefaultConnectionID(connId) and (connId<>0))
|
||||
then GetPrimaryConnectionId(connId);
|
||||
GetFileServerName(connId,MyServer);
|
||||
GetConnectionNumber(MyConnNbr);
|
||||
GetConnectionInformation(MyconnNbr,username,objType,objID,datetime);
|
||||
if Param='' then writeln('List of currently logged on users for server ',MyServer)
|
||||
else writeln('List for user ',Param,' on ',MyServer,'.');
|
||||
writeln;
|
||||
writeln('Con: Name: Login/off Time:');
|
||||
writeln('--- -------------------- -------------------------');
|
||||
end;
|
||||
|
||||
|
||||
procedure GetConnectedUsers;
|
||||
Var connNbr:byte;
|
||||
objName:string;
|
||||
objType:word;
|
||||
objId :LongInt;
|
||||
LogTime:TnovTime;
|
||||
{serverInfo:TFileServerInformation;}
|
||||
begin
|
||||
ConnInUse:=0;
|
||||
UsersConnected:=0;
|
||||
ConnNotLogIn:=0;
|
||||
{ To determine the maximum number of connections allowed by the
|
||||
license, you would normally use the
|
||||
nwServ.GetFileServerInformation(servername,serverInfo)
|
||||
call. For now, we'll suppose there are max. 250 connectios allowed. }
|
||||
|
||||
for connNbr := 1 to 250 {serverinfo.ConnectionsMax}
|
||||
do begin
|
||||
IF GetConnectionInformation(connNbr,objName,objType,objId,LogTime)
|
||||
then begin
|
||||
if objName='NOT-LOGGED-IN'
|
||||
then begin
|
||||
inc(ConnNotLogIn);
|
||||
inc(connInUse);
|
||||
DumpLoginTime(connNbr,objName,objId,LogTime);{ logOUT time }
|
||||
end
|
||||
else if objType=1 {OT_USER}
|
||||
then begin
|
||||
inc(ConnInUse);
|
||||
inc(UsersConnected);
|
||||
DumpLoginTime(connNbr,objName,objId,LogTime);{ logIN }
|
||||
end
|
||||
else inc(connInUse);
|
||||
end
|
||||
end; {do}
|
||||
end;
|
||||
|
||||
|
||||
procedure DisplayAllUsers;
|
||||
Var lUser :PTuserInfo;
|
||||
time,tempStr:string;
|
||||
Begin
|
||||
lUser:=startPtr^.next;
|
||||
while lUser<>NIL
|
||||
do begin
|
||||
if (param='') or (pos(param,lUser^.objName)>0)
|
||||
then begin
|
||||
if lUser^.ConnNbr=0
|
||||
then begin
|
||||
if DispAll and (lUser^.objName<>'NOT-LOGGED-IN')
|
||||
then begin
|
||||
PstrCopy(tempStr,lUser^.objName,20);
|
||||
write('N/A ',tempStr);
|
||||
if lUser^.LoginTime.day<>0
|
||||
then begin
|
||||
NovTime2String(lUser^.LoginTime,time);
|
||||
time[1]:='?';time[2]:='?';time[3]:='?';
|
||||
writeln(' ',time);
|
||||
end
|
||||
else writeln(' ------not available------');
|
||||
writeln('':5,lUser^.TrueName);
|
||||
end
|
||||
end
|
||||
else begin
|
||||
|
||||
NovTime2String(lUser^.LoginTime,time);
|
||||
PstrCopy(tempStr,lUser^.objName,20);
|
||||
|
||||
write(lUser^.connNbr:3);
|
||||
if Luser^.ConnNbr=MyConnNbr
|
||||
then write(' *')
|
||||
else write(' ');
|
||||
|
||||
writeln(tempstr,' ',time);
|
||||
writeln('':5,lUser^.TrueName);
|
||||
end;
|
||||
end;
|
||||
lUser:=lUser^.next
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure DisplayFooter;
|
||||
Var now:TnovTime;
|
||||
nowStr:string;
|
||||
remainder:byte;
|
||||
begin
|
||||
getFileServerDateAndTime(now);
|
||||
NovTime2String(now,nowStr);
|
||||
If UsersConnected=1 then write('1 user is');
|
||||
if UsersConnected>1 then write(UsersConnected,' users are');
|
||||
if UsersConnected>0 then writeln(' logged into ',MyServer,' as of ',nowStr);
|
||||
IF ConnNotLogIn=1 then write('1 connection is');
|
||||
IF ConnNotLogIn>1 then write(ConnNotLogIn,' connections are');
|
||||
IF ConnNotLogIn>0 then writeln(' in use, but the workstation has logged out.');
|
||||
remainder:=ConnInUse-UsersConnected-ConnNotLogIn;
|
||||
IF remainder>0 then writeln(remainder,' connection(s) used by non-user objects.');
|
||||
end;
|
||||
|
||||
procedure credits;
|
||||
begin
|
||||
writeln;
|
||||
writeln('WHO: Displays a list of currently logged in users.');
|
||||
writeln;
|
||||
writeln('SYNTAX: WHO [servername/][username] [/A]');
|
||||
writeln;
|
||||
writeln('Servername has to match an existing server.');
|
||||
writeln('All users with ''username'' contained in them wil be displayed.');
|
||||
writeln;
|
||||
writeln('Example: WHO Display everyone');
|
||||
writeln(' WHO username Display a particular user.');
|
||||
writeln(' WHO server/ Display a different server.');
|
||||
writeln;
|
||||
halt(0);
|
||||
end;
|
||||
|
||||
|
||||
procedure ChangeServer; { change default server to something else }
|
||||
var ServerChanged:Boolean;
|
||||
p,connId:byte;
|
||||
NewServer : string;
|
||||
servername : string;
|
||||
begin
|
||||
ServerChanged:=False;
|
||||
p := pos('/',Param);
|
||||
NewServer := copy(Param,1,p-1);
|
||||
UpString(NewServer);
|
||||
Param := copy(Param,p+1,255);
|
||||
for connId := 1 to 8
|
||||
do begin
|
||||
GetFileServerName(connId,servername);
|
||||
if servername=NewServer
|
||||
then begin
|
||||
serverChanged:=True;
|
||||
SetPreferredConnectionId(connId);
|
||||
end;
|
||||
end;
|
||||
if NOT ServerChanged
|
||||
then begin
|
||||
writeln('Server ',NewServer,' not found.');
|
||||
halt(1);
|
||||
end;
|
||||
end;
|
||||
|
||||
Var OldConnId:Byte;
|
||||
nliConn:PTuserInfo;
|
||||
|
||||
begin {---------main-----------------------------------------------------}
|
||||
New(startPtr);
|
||||
New(nliConn);
|
||||
nliConn^.objName:='NOT-LOGGED-IN';
|
||||
nliConn^.objId:=0;
|
||||
nliConn^.TrueName:='';
|
||||
nliConn^.next:=NIL;
|
||||
nliConn^.connNbr:=0;
|
||||
startPtr^.next:=nliConn;
|
||||
startPtr^.objName:=#0;
|
||||
|
||||
if paramcount > 0
|
||||
then Param := paramstr(1)
|
||||
else Param := '';
|
||||
DispAll:=(paramCount > 0)
|
||||
and ( (pos('/A',paramstr(1))=1)
|
||||
or (pos('/a',paramStr(1))=1)
|
||||
);
|
||||
If dispall then param:='';
|
||||
DispAll:=DispAll or ( (paramCount > 1)
|
||||
and ( (pos('/A',paramstr(2))=1)
|
||||
or (pos('/a',paramStr(2))=1)
|
||||
)
|
||||
);
|
||||
UpString(Param);
|
||||
DispHelp:=(Param = '?') or (Pos('/H',Param)=1);
|
||||
|
||||
|
||||
GetPreferredConnectionId(OldConnId);
|
||||
if DispHelp then credits;
|
||||
if pos('/',Param) > 1 then ChangeServer;
|
||||
ScanBinderyUsers;
|
||||
GetConnectedUsers;
|
||||
DisplayHeader;
|
||||
DisplayAllUsers;
|
||||
DisplayFooter;
|
||||
SetPreferredConnectionId(OldConnId);
|
||||
end.
|
||||
|
||||
87
NWTP/XFILE/GETOFIL.PAS
Normal file
87
NWTP/XFILE/GETOFIL.PAS
Normal file
@@ -0,0 +1,87 @@
|
||||
program GetOFil;
|
||||
|
||||
{ Testprogram for the nwFile unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Uses the following calls:
|
||||
|
||||
GetConnectionsOpenFiles (nwServ)
|
||||
MapDirEntryIdToPath (nwFile)
|
||||
|
||||
}
|
||||
|
||||
uses nwMisc,nwConn,nwFile,nwServ;
|
||||
|
||||
|
||||
Var ConnNumber : Byte;
|
||||
LastRecordSeen : word;
|
||||
NbrOfRecords : word;
|
||||
FileInfo : TfileInfoRecList;
|
||||
t : Byte;
|
||||
ExtPath,DosPath: string;
|
||||
VolName : string;
|
||||
|
||||
errCode:Integer;
|
||||
dHelp:byte;
|
||||
INaddress:TinternetworkAddress;
|
||||
|
||||
begin
|
||||
dHelp:=0;
|
||||
|
||||
If (NOT CheckConsolePrivileges)
|
||||
then dHelp:=4;
|
||||
|
||||
IF (ParamCount<>1)
|
||||
then dHelp:=1;
|
||||
|
||||
if dHelp=0
|
||||
then begin
|
||||
Val(ParamStr(1),ConnNumber,errCode);
|
||||
if (errCode<>0) then dHelp:=2;
|
||||
end;
|
||||
|
||||
{ determine whether connectionnumber is valid.
|
||||
Remember: using invalid connectionnumbers in combination with the
|
||||
GetConnection'sOpenFiles function may result in an Abend.. }
|
||||
if (dHelp=0) and (NOT GetInterNetAddress(connNumber,INaddress))
|
||||
then dHelp:=3;
|
||||
|
||||
if dHelp>0
|
||||
then begin
|
||||
if (dHelp=2) or (dHelp=3)
|
||||
then writeln('Error: invalid connection number specified.');
|
||||
if dHelp=4
|
||||
then writeln('!! You need console operator privileges to use this utility.');
|
||||
writeln;
|
||||
writeln('GETOFIL - Get connection''s open files.');
|
||||
writeln;
|
||||
writeln('Usage: GETOFIL <connection number>');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
LastRecordSeen:=0;
|
||||
|
||||
Writeln('Files currently held open by connection ',ConnNumber);
|
||||
REPEAT { iterate / "only" 28 files (max.) returned per call }
|
||||
IF GetConnectionsOpenFiles (ConnNumber, LastRecordSeen,
|
||||
NbrOfRecords ,FileInfo)
|
||||
then begin
|
||||
for t:=1 to NbrOfRecords
|
||||
do with FileInfo[t]
|
||||
do begin
|
||||
IF MapDirEntryIdToPath(VolNbr,ParentEntryID,NStype,
|
||||
FileName)
|
||||
then begin
|
||||
NovPath2DosPath(ExtPath,DosPath);
|
||||
GetVolumeName(VolNbr,VolName);
|
||||
writeln(VolName,':',DosPath,'\',FileName)
|
||||
end
|
||||
else writeln('Error calling MapDirEntryIdToPath, err#',nwFile.result);
|
||||
end;
|
||||
end
|
||||
else begin
|
||||
writeln('err: ',nwServ.result);
|
||||
halt(1);
|
||||
end;
|
||||
UNTIL LastRecordSeen=0;
|
||||
|
||||
end.
|
||||
243
NWTP/XFILE/LDIR.PAS
Normal file
243
NWTP/XFILE/LDIR.PAS
Normal file
@@ -0,0 +1,243 @@
|
||||
program ldir;
|
||||
|
||||
{ Testprogram for the nwFile unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ LDIR is an alternative for NDIR, showing the use of the
|
||||
ScanDirectoryEntry function. }
|
||||
|
||||
uses nwMisc,nwBindry,nwFile;
|
||||
|
||||
Function GetEntryAttributeString(Attr:Longint):string;
|
||||
Var res:string;
|
||||
begin
|
||||
if (Attr and A_DIRECTORY)=0
|
||||
then res:=' RwSAXHSyTPCDR '
|
||||
else res:=' -----HSy-P-DR ';
|
||||
if (Attr and A_HIDDEN)=0 then res[7]:='-';
|
||||
if (Attr and A_SYSTEM)=0 then begin res[8]:='-';res[9]:='-'; end;
|
||||
if (Attr and A_RENAME_INHIBIT)=0 then res[14]:='-';
|
||||
if (Attr and A_DELETE_INHIBIT)=0 then res[13]:='-';
|
||||
if (Attr and A_PURGE)=0 then res[11]:='-';
|
||||
if (Attr and A_DIRECTORY)=0
|
||||
then begin
|
||||
if ((Attr and A_READ_ONLY)>0) then res[3]:='o';
|
||||
if (Attr and A_EXECUTE_ONLY)=0 then res[6]:='-';
|
||||
if (Attr and A_NEEDS_ARCHIVED)=0 then res[5]:='-';
|
||||
if (Attr and A_SHAREABLE)=0 then res[4]:='-';
|
||||
if (Attr and A_TRANSACTIONAL)=0 then res[10]:='-';
|
||||
if (Attr and A_COPY_INHIBIT)=0 then res[12]:='-';
|
||||
end;
|
||||
GetEntryAttributeString:=res;
|
||||
end;
|
||||
|
||||
Var DirHandle:Byte;
|
||||
DirPath:String;
|
||||
SequenceNumber:Byte;
|
||||
TrusteeInfo: TtrusteeInformation;
|
||||
|
||||
t:Byte;
|
||||
ObjName:string;
|
||||
ObjType:word;
|
||||
ObjId:Longint;
|
||||
DH,EffRights:byte;
|
||||
|
||||
EntryName:string;
|
||||
SearchFlags:Longint;
|
||||
EntryId:Longint;
|
||||
Entry:Tentry;
|
||||
s,s1:string;
|
||||
|
||||
p:byte;
|
||||
OwnerName:string;
|
||||
OwnerType:word;
|
||||
|
||||
entry2:Tentry;
|
||||
begin
|
||||
|
||||
DirHandle:=0;
|
||||
|
||||
if ParamCount>0
|
||||
then s:=paramStr(1)
|
||||
else s:='.';
|
||||
|
||||
IF NOT GetTrueEntryName(s,DirPath)
|
||||
then begin
|
||||
writeln('Error resolving given filename (err: 0-',nwfile.result,')');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
if pos(':',DirPath)=2
|
||||
then begin
|
||||
writeln('You cannot use this program on a local drive.');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
{ ok. Try to separate EntryName from path }
|
||||
|
||||
p:=ord(DirPath[0]);
|
||||
while (p>0) and (DirPath[p]<>'\') do dec(p);
|
||||
|
||||
s:=copy(DirPath,p+1,255);
|
||||
if (pos('.',s)>0) or (pos('*',s)>0) or (pos('?',s)>0)
|
||||
then begin { last part is definately a filename }
|
||||
EntryName:=s;
|
||||
DirPath[0]:=chr(p-1);
|
||||
IF NOT AllocTemporaryDirHandle(31,0,DirPath,DH,EffRights)
|
||||
then begin
|
||||
writeln('Could not locate directory (err: 1-',nwfile.result,')');
|
||||
halt(1);
|
||||
end;
|
||||
end
|
||||
else begin
|
||||
IF AllocTemporaryDirHandle(31,0,DirPath,DH,EffRights) { assume it's a path}
|
||||
then begin
|
||||
{ whole thing appears to be a path.. }
|
||||
EntryName:='*';
|
||||
end
|
||||
else begin
|
||||
{ whoops.. not a path, but a filename without an extension }
|
||||
EntryName:=s;
|
||||
DirPath[0]:=chr(p-1);
|
||||
IF NOT AllocTemporaryDirHandle(31,0,DirPath,DH,EffRights)
|
||||
then begin
|
||||
writeln('Could not locate directory (err: 2-',nwfile.result,')');
|
||||
halt(1);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
writeln('EntryName Size Flags EntryID Creation Owner');
|
||||
writeln('------------+---------+---------------+--------+---------------+----------');
|
||||
|
||||
SearchFlags:=$ef; { all NON directories, i.e. all files }
|
||||
EntryId:=-1;
|
||||
|
||||
While ScanDirectoryEntry(DH,EntryName,SearchFlags,EntryID,Entry)
|
||||
do begin
|
||||
s:=entry.EntryName;
|
||||
p:=pos('.',s);
|
||||
if p=0
|
||||
then begin
|
||||
s:=s+' ';
|
||||
s[0]:=#12;
|
||||
end
|
||||
else begin
|
||||
s1:=copy(s,1,p-1)+' ';
|
||||
s1[0]:=#8;
|
||||
s:=s1+copy(s,p,255)+' ';
|
||||
s[0]:=#12;
|
||||
end;
|
||||
write(s);
|
||||
write(entry.FileSize:10);
|
||||
s:=GetEntryAttributeString(entry.Attributes);
|
||||
write(' F',s);
|
||||
write(HexStr(entryId,8));
|
||||
|
||||
NovTime2String(entry.CreationTime,s);
|
||||
delete(s,1,5);dec(s[0],3);
|
||||
delete(s,8,2);
|
||||
s[3]:='-';s[7]:='-';
|
||||
write(' ',s);
|
||||
|
||||
GetBinderyObjectName(entry.OwnerId,OwnerName,OwnerType);
|
||||
s:=ownerName+' ';
|
||||
s[0]:=#10; write(' ',s);
|
||||
writeln;
|
||||
|
||||
end;
|
||||
|
||||
if nwFile.result<>$FF { no more matching entries }
|
||||
then writeln('Error scanning directory information (err : 3-',nwfile.result,')');
|
||||
|
||||
|
||||
{-- As an extra gimmick: if you DEFINE ShowScan, salvagable files will
|
||||
also be shown.. }
|
||||
|
||||
{$IFDEF ShowScan}
|
||||
|
||||
{ Scan salvagable files.. }
|
||||
EntryId:=-1;
|
||||
|
||||
WHILE ScanSalvagableFiles(DH,EntryId,Entry)
|
||||
do begin
|
||||
s:=entry.EntryName;
|
||||
p:=pos('.',s);
|
||||
if p=0
|
||||
then begin
|
||||
s:=s+' ';
|
||||
s[0]:=#12;
|
||||
end
|
||||
else begin
|
||||
s1:=copy(s,1,p-1)+' ';
|
||||
s1[0]:=#8;
|
||||
s:=s1+copy(s,p,255)+' ';
|
||||
s[0]:=#12;
|
||||
end;
|
||||
write(s);
|
||||
write(entry.FileSize:10);
|
||||
s:=GetEntryAttributeString(entry.Attributes);
|
||||
write(' S',s);
|
||||
write(HexStr(entryId,8));
|
||||
|
||||
NovTime2String(entry.CreationTime,s);
|
||||
delete(s,1,5);dec(s[0],3);
|
||||
delete(s,8,2);
|
||||
s[3]:='-';s[7]:='-';
|
||||
write(' ',s);
|
||||
|
||||
GetBinderyObjectName(entry.OwnerId,OwnerName,OwnerType);
|
||||
s:=ownerName+' ';
|
||||
s[0]:=#10; write(' ',s);
|
||||
|
||||
writeln;
|
||||
|
||||
end;
|
||||
If nwFile.result<>$FF { normal iteration end }
|
||||
then writeln('Error using ScanSalvagableFiles.');
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
{------------------ show subdir info }
|
||||
|
||||
SearchFlags:=$3f;
|
||||
EntryId:=-1;
|
||||
|
||||
While ScanDirectoryEntry(DH,EntryName,SearchFlags,EntryID,Entry)
|
||||
do begin
|
||||
s:=entry.EntryName;
|
||||
p:=pos('.',s);
|
||||
if p=0
|
||||
then begin
|
||||
s:=s+' ';
|
||||
s[0]:=#11;
|
||||
end
|
||||
else begin
|
||||
delete(s,p,1);
|
||||
s:=s+' ';
|
||||
s[0]:=#11;
|
||||
end;
|
||||
write('\',s);
|
||||
|
||||
write(0:10); { filesize }
|
||||
|
||||
s:=GetEntryAttributeString(entry.Attributes);
|
||||
write(' D',s);
|
||||
write(HexStr(entryId,8));
|
||||
|
||||
NovTime2String(entry.CreationTime,s);
|
||||
delete(s,1,5);dec(s[0],3);
|
||||
delete(s,8,2);
|
||||
s[3]:='-';s[7]:='-';
|
||||
write(' ',s);
|
||||
|
||||
GetBinderyObjectName(entry.OwnerId,OwnerName,OwnerType);
|
||||
s:=ownerName+' ';
|
||||
s[0]:=#12; write(' ',s);
|
||||
writeln;
|
||||
end;
|
||||
if nwFile.result<>$FF { no more matching entries }
|
||||
then writeln('Error scanning directory information (err : 4-',nwfile.result,')');
|
||||
|
||||
DeallocateDirHandle(DH);
|
||||
end.
|
||||
211
NWTP/XFILE/TSTDH.PAS
Normal file
211
NWTP/XFILE/TSTDH.PAS
Normal file
@@ -0,0 +1,211 @@
|
||||
program tstdh;
|
||||
|
||||
{ Testprogram for the nwFile unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
uses nwMisc,nwConn,nwFile;
|
||||
|
||||
{ Test the following drive(handle) related calls:
|
||||
|
||||
GetDirectoryHandle
|
||||
GetDirectoryPath
|
||||
GetDriveConnectionId
|
||||
GetDriveHandle
|
||||
GetDriveFlag
|
||||
GetNumberOfLocalDrives (nwConn)
|
||||
GetVolumeNameWithHandle
|
||||
IsNetworkDrive
|
||||
|
||||
GetEnvPath
|
||||
GetSearchDriveVector
|
||||
IsSearchDrive
|
||||
SetEnvPath
|
||||
SetSearchDriveVector
|
||||
|
||||
}
|
||||
|
||||
Var t,dirhandle,status:byte;
|
||||
status2,dirHandle2:byte;
|
||||
volname:string;
|
||||
connId:byte;
|
||||
locDrives:byte;
|
||||
dirPath:string;
|
||||
serverName:string;
|
||||
|
||||
NewDirHandle, EffectiveRights:byte;
|
||||
connId2,Dflag:byte;
|
||||
|
||||
vector,vector2:TsearchDriveVector;
|
||||
pth,pth2:string;
|
||||
|
||||
begin
|
||||
{-- drivenumbers, dirhandles --}
|
||||
|
||||
nwconn.GetNumberofLocalDrives(locDrives);
|
||||
writeln('Local Drives:',locDrives); { Drivenumbers 0..locDrives-1 taken by local drives }
|
||||
writeln;
|
||||
|
||||
for t:=0 to locDrives-1
|
||||
do If IsNetworkDrive(t)
|
||||
then writeln('Error?: IsNetworkDrive failed for drive ',chr(ord('A')+t));
|
||||
|
||||
for t:=locDrives to 31
|
||||
do begin
|
||||
IF GetDirectoryHandle(t,dirHandle,status)
|
||||
then begin
|
||||
writeln(chr(t+ord('A')),' handle=',dirHandle,' status=',status);
|
||||
GetDriveHandle(t,dirHandle2);
|
||||
GetDriveFlag(t,status2);
|
||||
if (status<>status2) or (dirHandle<>dirHandle2)
|
||||
then writeln('Error: GetDirectoryHandle data differs from GetDriveHandle/Flag data.');
|
||||
|
||||
if IsNetworkDrive(t) XOR ((status AND $80)=0)
|
||||
then writeln('Error: IsNetworkDrive failed.');
|
||||
|
||||
GetDirectoryPath(dirHandle,dirpath);
|
||||
write('=> ',dirpath);
|
||||
|
||||
if GetDriveConnectionId(t,connId)
|
||||
then begin
|
||||
write(' connId=',connId);
|
||||
nwConn.GetFileServerName(connId,serverName);
|
||||
write(' volume=\\',servername,'\');
|
||||
end;
|
||||
|
||||
IF (status<3) {temporary or permanent mapping}
|
||||
and GetVolumeNameWithHandle(dirHandle,volName)
|
||||
then write(volName);
|
||||
|
||||
writeln;
|
||||
end
|
||||
end;
|
||||
|
||||
|
||||
{-- seachdrives, searchdrive vector-- }
|
||||
writeln;
|
||||
writeln('<RETURN> to continue..');
|
||||
writeln;
|
||||
readln;
|
||||
|
||||
GetSearchDriveVector(vector);
|
||||
write('Searchdrivevector: ');
|
||||
for t:=1 to 17
|
||||
do if vector[t]<255
|
||||
then write(chr(byte(vector[t]+ord('A'))),' ')
|
||||
else write('$FF ');
|
||||
writeln;
|
||||
|
||||
FillChar(vector2,Sizeof(TsearchDriveVector),#$FF);
|
||||
SetSearchDriveVector(vector2);
|
||||
FillChar(vector2,Sizeof(TsearchDriveVector),#$00);
|
||||
GetSearchDriveVector(vector2);
|
||||
if (vector2[1]<>$FF)
|
||||
then writeln('Error: SetSearchdriveVector Failed.');
|
||||
SetSearchDriveVector(vector); { restore old vector }
|
||||
|
||||
GetEnvPath(pth);
|
||||
writeln('PATH setting in the master environment=',pth);
|
||||
SetEnvPath('this_is_a_bogus_path;');
|
||||
GetEnvPath(pth2);
|
||||
writeln('Path is temporarily set to: ',pth2);
|
||||
SetEnvPath(pth);
|
||||
writeln('Path reset to original value.');
|
||||
|
||||
Write('Searchdrives (using IsSearchDrive):');
|
||||
for t:=locDrives to 31
|
||||
do If IsSearchDrive(t)
|
||||
then write(chr(t+ord('A')),' ');
|
||||
writeln;
|
||||
|
||||
{----------------- directory handles ---------------------}
|
||||
writeln('<RETURN> to continue..');
|
||||
writeln;
|
||||
|
||||
t:=locDrives;
|
||||
While (t<26) and GetDirectoryHandle(t,dirHandle,status)
|
||||
do inc(t);
|
||||
Writeln('First free drive: ',chr(t+ord('A')));
|
||||
|
||||
IF NOT AllocPermanentDirHandle(t,0,'SYS:LOGIN',NewDirHandle, EffectiveRights)
|
||||
then writeln('Error calling AllocPermanentDirHandle: ',nwFile.result);
|
||||
|
||||
GetDirectoryPath(NewDirHandle,pth);
|
||||
IF SetDriveHandle(t,NewDirHandle)
|
||||
then writeln('SetDriveHandle: drive ',chr(t+ord('A')),' asociated with dirHandle to path ',pth)
|
||||
else writeln('Error using SetDriveHandle: ',nwFile.result);
|
||||
|
||||
GetDriveHandle(t,dirHandle);
|
||||
if dirHandle<>NewDirHandle
|
||||
then writeln('Error in SetDriveHandle.');
|
||||
|
||||
GetEffectiveConnectionId(connId);
|
||||
{ all requests have been sent to the effective server up to now, so
|
||||
that's the server the drive is connected to }
|
||||
SetDriveConnectionId(t,connId);
|
||||
GetDriveConnectionId(t,connId2);
|
||||
If ConnId2<>ConnId
|
||||
then writeln('Error in Set/GetDriveConnectionId');
|
||||
GetDriveFlag(t,Dflag);
|
||||
SetDriveFlag(t,(Dflag and $80) or 1);
|
||||
|
||||
writeln('(non-root) Mapping completed.');
|
||||
{ see the MAPDRIVE function in nwFile;
|
||||
it creates (temporary) mappings in much the same way as above }
|
||||
|
||||
|
||||
{map a temporary drive}
|
||||
IF MapDrive(31,'SYS:MAIL',{root drive:} false, {permanent mapping:} false {true})
|
||||
then begin
|
||||
GetDriveHandle(31,dirHandle);
|
||||
GetDirectoryPath(dirHAndle,pth);
|
||||
Writeln('Temporary! drive ',chr(31+ord('A')),' mapped to ',pth);
|
||||
{ If mapdrive works, so must
|
||||
|
||||
DeleteFakeRootDirectory
|
||||
GetTrueEntryName
|
||||
MapFakeRootDirectory
|
||||
|
||||
}
|
||||
end
|
||||
else writeln('Error using MapDrive: ',nwFile.result);
|
||||
|
||||
|
||||
writeln;
|
||||
t:=locDrives;
|
||||
While (t<26) and GetDirectoryHandle(t,dirHandle,status)
|
||||
do inc(t);
|
||||
Writeln('Another free drive: ',chr(t+ord('A')));
|
||||
|
||||
IF MapSearchDrive(t,'SYS:PUBLIC',16,{insert:}false,
|
||||
{root:}false,{permanent:}true)
|
||||
then begin
|
||||
GetDriveHandle(t,dirHandle);
|
||||
GetDirectoryPATh(dirHAndle,pth);
|
||||
Writeln('drive ',chr(t+ord('A')),' mapped (as a searchdrive) to ',pth);
|
||||
end
|
||||
else writeln('Error using MapSearchDrive: ',nwFile.result);
|
||||
|
||||
|
||||
writeln;
|
||||
t:=locDrives;
|
||||
While (t<26) and GetDirectoryHandle(t,dirHandle,status)
|
||||
do inc(t);
|
||||
Writeln('Another free drive: ',chr(t+ord('A')));
|
||||
|
||||
IF MapPermanentDrive(t,'SYS:PUBLIC',{root:}true)
|
||||
then begin
|
||||
GetDriveHandle(t,dirHandle);
|
||||
GetDirectoryPATh(dirHAndle,pth);
|
||||
Writeln('drive ',chr(t+ord('A')),' mapped (permanently) to ',pth);
|
||||
|
||||
IF NOT SetDirectoryHandle(0,'SYS:MAIL',dirHandle)
|
||||
then writeln('Error using SetDirectoryHandle: ',nwFile.result)
|
||||
else begin
|
||||
GetDirectoryPATh(dirHAndle,pth);
|
||||
Writeln('drive ',chr(t+ord('A')),' => handle changed to ',pth);
|
||||
end;
|
||||
|
||||
end
|
||||
else writeln('Error using MapPermanentDrive: ',nwFile.result);
|
||||
|
||||
|
||||
end.
|
||||
138
NWTP/XFILE/TSTENT2.PAS
Normal file
138
NWTP/XFILE/TSTENT2.PAS
Normal file
@@ -0,0 +1,138 @@
|
||||
Program tstent2;
|
||||
|
||||
{ Testprogram for the nwFile unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Tests the following nwFile calls:
|
||||
|
||||
GetDirectoryEntry
|
||||
ScanDirectoryInformation
|
||||
ScanFileInformation
|
||||
ScanSalvagableFiles
|
||||
}
|
||||
|
||||
uses nwMisc,nwBindry,nwFile;
|
||||
|
||||
|
||||
Procedure PrintEntry(e:Tentry);
|
||||
VAr s,ObjName:String;
|
||||
ObjType:Word;
|
||||
begin
|
||||
with e
|
||||
do begin
|
||||
writeln('----------------------------------');
|
||||
writeln('Name:',EntryName);
|
||||
writeln('FileSize :',FileSize);
|
||||
writeln('Name space :',NStype);
|
||||
writeln('Data fork size :',DataForkSize);
|
||||
writeln;
|
||||
writeln('Attributes:',HexStr(Attributes,8));
|
||||
writeln('RightsMask:',HexStr(RightsMask,4));
|
||||
writeln;
|
||||
|
||||
objName:='';
|
||||
NovTime2String(CreationTime,s);
|
||||
GetBinderyObjectName(OwnerId,ObjName,ObjType);
|
||||
writeln('Created at :',s,' by ',ObjName,' (',HexStr(OwnerId,8),')');
|
||||
|
||||
objName:='';
|
||||
NovTime2String(ArchiveTime,s);
|
||||
GetBinderyObjectName(ArchiverId,ObjName,ObjType);
|
||||
writeln('Last archived at :',s,' by ',ObjName,' (',HexStr(ArchiverId,8),')');
|
||||
|
||||
objName:='';
|
||||
NovTime2String(ModifyTime,s);
|
||||
GetBinderyObjectName(ModifierId,ObjName,ObjType);
|
||||
writeln('Last modified at :',s,' by ',ObjName,' (',HexStr(ModifierId,8),')');
|
||||
|
||||
NovTime2String(LastAccessTime,s);
|
||||
writeln('Last accessed at :',s);
|
||||
|
||||
objName:='';
|
||||
NovTime2String(DeleteTime,s);
|
||||
GetBinderyObjectName(DeletorId,ObjName,ObjType);
|
||||
writeln('Deleted at :',s,' by ',ObjName,' (',HexStr(DeletorId,8),')');
|
||||
writeln;
|
||||
end;
|
||||
end;
|
||||
|
||||
Var DirHandle,EffRights:Byte;
|
||||
DirEntry:Tentry;
|
||||
SearchFlags,EntryId:Longint;
|
||||
PathNAme:STring;
|
||||
SeqNbr:Integer;
|
||||
WseqNbr:word;
|
||||
|
||||
begin
|
||||
|
||||
AllocPermanentDirHandle(7,0,'SYS:PUBLIC',DirHandle,EffRights);
|
||||
|
||||
writeln;
|
||||
writeln('Test of GetDirectoryEntry (get entry SYS:\PUBLIC');
|
||||
write('<RETURN> to contimue...');
|
||||
readln;
|
||||
|
||||
IF GetDirectoryEntry(dirHandle,dirEntry)
|
||||
then PrintEntry(dirEntry)
|
||||
else writeln('Error using GetDirectoryEntry, err#',nwFile.result);
|
||||
|
||||
SetDirectoryHandle(0,'SYS:',DirHandle);
|
||||
|
||||
GetDirectoryPAth(DirHandle,PathNAme);
|
||||
writeln('handle ass. with:',PathName);
|
||||
|
||||
writeln;
|
||||
writeln('Test of ScanDirectoryInformation (scan subdirs of SYS:\PUBLIC');
|
||||
write('<RETURN> to contimue...');
|
||||
readln;
|
||||
|
||||
WseqNbr:=0;
|
||||
while ScanDirectoryInformation(dirHandle,'PUBLIC\*',WseqNbr,dirEntry)
|
||||
do begin
|
||||
writeln('SeqNbr now is: ',WseqNbr);
|
||||
PrintEntry(DirEntry);
|
||||
end;
|
||||
if nwFile.result<>$9C
|
||||
then writeln('error using ScanDirInfo :',nwFile.result);
|
||||
|
||||
|
||||
writeln;
|
||||
writeln('Test of ScanFileInformation (scan *.EXE files in SYS:\PUBLIC');
|
||||
write('<RETURN> to contimue...');
|
||||
readln;
|
||||
|
||||
seqNbr:=-1;
|
||||
while ScanFileInformation(DirHandle,'PUBLIC\*.EXE',
|
||||
$FF,
|
||||
SeqNbr,
|
||||
dirEntry)
|
||||
do begin
|
||||
PrintEntry(DirEntry);
|
||||
end;
|
||||
if nwFile.result<>$FF
|
||||
then writeln('error using ScanFileInfo :',nwFile.result);
|
||||
|
||||
|
||||
writeln;
|
||||
writeln('Test of ScanSalvagableFiles (erased files in SYS:\PUBLIC');
|
||||
write('<RETURN> to contimue...');
|
||||
readln;
|
||||
|
||||
SetDirectoryHandle(0,'SYS:\PUBLIC',DirHandle);
|
||||
|
||||
|
||||
EntryId:=-1;
|
||||
WHILE ScanSalvagableFiles(DirHandle,
|
||||
EntryId,
|
||||
dirEntry)
|
||||
do begin
|
||||
PrintEntry(dirEntry);
|
||||
writeln('NextEntryId:',hexStr(entryId,8));
|
||||
end;
|
||||
if nwFile.result<>$FF
|
||||
then writeln('error using ScanSalvagable files :',nwFile.result);
|
||||
|
||||
|
||||
DeallocateDirHandle(DirHandle);
|
||||
|
||||
|
||||
end.
|
||||
91
NWTP/XFILE/TSTENTRY.PAS
Normal file
91
NWTP/XFILE/TSTENTRY.PAS
Normal file
@@ -0,0 +1,91 @@
|
||||
Program tstentry;
|
||||
|
||||
{ Example for the nwFile unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Tests the following nwFile calls:
|
||||
|
||||
AllocPermanentDirHandle
|
||||
CreateDirectory
|
||||
DeallocateDirHandle
|
||||
RenameDirectory
|
||||
ScanDirRestrictions
|
||||
SetDirectoryHandle
|
||||
SetDirRestriction
|
||||
|
||||
}
|
||||
uses nwMisc,nwFile;
|
||||
|
||||
Var DirHandle:Byte;
|
||||
NumberOfEntries:Byte;
|
||||
RestrInfo:TdirRestrList;
|
||||
t,EffRights:Byte;
|
||||
|
||||
begin
|
||||
|
||||
|
||||
AllocPermanentDirHandle(7,0,'SYS:',DirHandle,EffRights);
|
||||
|
||||
IF NOT CreateDirectory(DirHandle,'NWTP',$FF)
|
||||
then writeln('Error using CreateDirectory, err# ',nwFile.result);
|
||||
|
||||
SetDirectoryHandle(DirHandle,'NWTP',DirHandle);
|
||||
|
||||
IF NOT SetDirRestriction(DirHandle,4096) { 4096 blocks = 16 Mb }
|
||||
then writeln('Error using SetDirRestriction, err# ',nwFile.result);
|
||||
|
||||
IF NOT ScanDirRestrictions(DirHandle,NumberOfEntries,RestrInfo)
|
||||
then writeln('Error calling ScanDirRestrictions:',nwFile.result);
|
||||
writeln(NumberOfEntries);
|
||||
For t:=1 to NumberOfEntries
|
||||
do begin
|
||||
writeln;
|
||||
writeln('Level :',RestrInfo[t].level);
|
||||
writeln('MaxBlocks :',HexStr(RestrInfo[t].MaxBlocks,8));
|
||||
writeln('AvailBlocks:',HexStr(RestrInfo[t].AvailableBlocks,8));
|
||||
end;
|
||||
writeln('------');
|
||||
|
||||
IF NOT CreateDirectory(DirHandle,'TEST',$FF)
|
||||
then writeln('Error using CreateDirectory, err# ',nwFile.result);
|
||||
|
||||
IF NOT RenameDirectory(DirHandle,'TEST','TESTDIR')
|
||||
then writeln('Error using RenameDirectory, err# ',nwFile.result);
|
||||
|
||||
|
||||
IF NOT SetDirectoryHandle(DirHandle,'TESTDIR',DirHandle)
|
||||
then writeln('Error using SetDirectoryHandle, err# ',nwFile.result)
|
||||
else writeln('SetDirHandle: ok');
|
||||
|
||||
IF NOT SetDirRestriction(DirHandle,8192)
|
||||
then writeln('Error using SetDirRestriction, err# ',nwFile.result);
|
||||
|
||||
IF NOT ScanDirRestrictions(DirHandle,NumberOfEntries,RestrInfo)
|
||||
then writeln('Error calling ScanDirRestrictions:',nwFile.result);
|
||||
writeln(NumberOfEntries);
|
||||
For t:=1 to NumberOfEntries
|
||||
do begin
|
||||
writeln;
|
||||
writeln('Level :',RestrInfo[t].level);
|
||||
writeln('MaxBlocks :',HexStr(RestrInfo[t].MaxBlocks,8));
|
||||
writeln('AvailBlocks:',HexStr(RestrInfo[t].AvailableBlocks,8));
|
||||
end;
|
||||
|
||||
writeln('<Return> to continue...........');
|
||||
readln;
|
||||
|
||||
SetDirRestriction(DirHandle,0);
|
||||
|
||||
SetDirectoryHandle(0,'SYS:NWTP',DirHandle);
|
||||
IF Not DeleteDirectory(DirHandle,'TESTDIR')
|
||||
then writeln('Error using DeleteDirectory, err#', nwFile.result);
|
||||
|
||||
{SetDirRestriction(DirHandle,0);}
|
||||
|
||||
SetDirectoryHandle(0,'SYS:',DirHandle);
|
||||
IF Not DeleteDirectory(DirHandle,'NWTP')
|
||||
then writeln('Error using DeleteDirectory, err#', nwFile.result);
|
||||
|
||||
|
||||
DeallocateDirHandle(DirHandle);
|
||||
|
||||
end.
|
||||
58
NWTP/XFILE/TSTTRUST.PAS
Normal file
58
NWTP/XFILE/TSTTRUST.PAS
Normal file
@@ -0,0 +1,58 @@
|
||||
program tsttrust;
|
||||
|
||||
{ Testprogram for the NwFile unit / NwTP 0.6, (c) 1993,1995 R.Spronk }
|
||||
|
||||
uses nwMisc,nwBindry,nwFile;
|
||||
|
||||
Var DirHandle:Byte;
|
||||
DirPath:String;
|
||||
SequenceNumber:Byte;
|
||||
TrusteeInfo: TtrusteeInformation;
|
||||
|
||||
t:Byte;
|
||||
ObjName:string;
|
||||
ObjType:word;
|
||||
ObjId:Longint;
|
||||
DH,EffRights:byte;
|
||||
begin
|
||||
|
||||
DirHandle:=0;
|
||||
DirPath:='SYS:SYSTEM';
|
||||
|
||||
IF NOT AllocTemporaryDirHandle(31,0,DirPath,DH,EffRights)
|
||||
then writeln('allocTempDH returned err: ',nwfile.result);
|
||||
|
||||
{ Before scanning the trustees, you might add or delete a
|
||||
trustee for testing purposes.
|
||||
|
||||
ObjId:=$06000006;
|
||||
IF NOT DeleteTrustee(0,DirPath,ObjId)
|
||||
then writeln('DeleteTrustee returned error: ',nwFile.result);
|
||||
|
||||
ObjId:=$06000006;
|
||||
IF NOT SetTrustee(0,DirPath,ObjId,TA_READ or TA_SEARCH)
|
||||
then writeln('SetTrustee returned error: ',nwFile.result); }
|
||||
|
||||
SequenceNumber:=0;
|
||||
While ScanEntryForTrustees(DirHandle,DirPath,
|
||||
SequenceNumber,TrusteeInfo)
|
||||
do begin
|
||||
with TrusteeInfo
|
||||
do begin
|
||||
for t:=1 to TrusteeInfo.NumberOfTrustees
|
||||
do begin
|
||||
write(HexStr(TrusteeID[t],8));
|
||||
GetBinderyObjectName(TrusteeId[t],ObjName,oBjType);
|
||||
writeln(' ',HexStr(TrusteeRights[t],4),' ',ObjName);
|
||||
end;
|
||||
|
||||
end;
|
||||
end;
|
||||
|
||||
if nwFile.result<>$9C { no more trustees }
|
||||
then writeln('ScanEntryForTrustees returned error :',nwfile.result);
|
||||
|
||||
DeallocateDirHandle(DH);
|
||||
|
||||
readln;
|
||||
end.
|
||||
170
NWTP/XFILE/TSTVOL.PAS
Normal file
170
NWTP/XFILE/TSTVOL.PAS
Normal file
@@ -0,0 +1,170 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
program tstvol;
|
||||
|
||||
{ Example for the nwFile unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Tests the following volume related functions in nwFile and nwServ:
|
||||
|
||||
ClearObjectVolRestriction
|
||||
GetDiskUtilization (nwServ)
|
||||
GetObjectVolRestriction
|
||||
GetVolumeName
|
||||
GetVolumeNumber
|
||||
GetVolumeUsage
|
||||
IsVolumeRemovable
|
||||
SetObjectVolRestriction
|
||||
|
||||
}
|
||||
|
||||
uses nwMisc,nwServ,nwFile;
|
||||
|
||||
|
||||
Var volNbr :byte;
|
||||
volName:string;
|
||||
|
||||
volUsage :TvolUsage;
|
||||
isremovable:boolean;
|
||||
|
||||
MaxAllowedBlocks,
|
||||
BlocksInUse:Longint;
|
||||
|
||||
VolumeNbr :byte;
|
||||
sequenceNbr :LongInt;
|
||||
NbrOfObjects:byte;
|
||||
ResultBuffer:TobjVolRestr;
|
||||
|
||||
usedDirs,usedFiles,usedBlocks:word;
|
||||
|
||||
t:byte;
|
||||
begin
|
||||
writeln('Testing GetVolumeNumber');
|
||||
IF GetVolumeNumber('XXXX',volNbr)
|
||||
then writeln('--Err. GetVolumeNuber returned a volumenumber when it should have failed.');
|
||||
IF GetVolumeNumber('VOL',volNbr)
|
||||
then writeln(' VolNbr of ''VOL:'' equals ',volNbr)
|
||||
else writeln(' Volume VOL appears not to exist.');
|
||||
IF GetVolumeNumber('SYS',volNbr)
|
||||
then writeln(' VolNbr of SYS: equals ',volNbr)
|
||||
else begin
|
||||
writeln('Error Using GetVolumeNumber, err#',nwFile.result);
|
||||
writeln('Critical error. Test aborted.');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
writeln;
|
||||
writeln('Testing GetVolumeName');
|
||||
for volNbr:=0 to 31
|
||||
do begin
|
||||
IF GetVolumeName(volNbr,volName)
|
||||
then writeln(' VolNbr ',volNbr,' is ''',volName,'''')
|
||||
else if result<>$98 { no such volume }
|
||||
then writeln('--Error testing GetVolumeName, err#',result);
|
||||
end;
|
||||
|
||||
writeln;
|
||||
writeln('Testing GetVolumeUsage.');
|
||||
IF GetVolumeNumber('SYS:',volNbr) and GetVolumeUsage(volNbr,VolUsage)
|
||||
then with VolUsage
|
||||
do begin
|
||||
writeln(' Volume Usage Information:');
|
||||
writeln(' Total Blocks: ',totalBlocks,' Free: ',freeBlocks);
|
||||
writeln(' Total Dir entries: ',totalDirEntries,' Free: ',availDirEntries);
|
||||
writeln(' Volumename: ''',volumename,'''');
|
||||
writeln(' Blocksize: ',SectorsPerBlock*512,' bytes.');
|
||||
end;
|
||||
|
||||
|
||||
writeln;
|
||||
writeln('Testing IsVolumeRemovable');
|
||||
IF IsVolumeRemovable(0,isremovable)
|
||||
then writeln(' Removable: ',isremovable)
|
||||
else writeln('--IsVolumeRemovable failed.');
|
||||
|
||||
|
||||
{==================Testing the volume restriction calls====================}
|
||||
|
||||
GetVolumeNumber('SYS',volNbr);
|
||||
|
||||
writeln('Getting the volume restrictions for user supervisor on SYS volume..');
|
||||
IF GetObjectVolRestriction(volNbr,1 {objectId of Supervisor},
|
||||
MaxAllowedBlocks,BlocksInUse)
|
||||
then begin
|
||||
writeln(' GetObjectVolRestriction:');
|
||||
writeln(' Supervisor on volume SYS');
|
||||
write(' Restricted to:');
|
||||
if MaxAllowedBlocks=$40000000
|
||||
then write('(unlimited)')
|
||||
else write(MaxAllowedBlocks);
|
||||
writeln(' Blocks ,BlocksInUse: ',BlocksInUse);
|
||||
end
|
||||
else writeln('--Error returned by GetObjectVolRestriction, err#',nwFile.result);
|
||||
|
||||
writeln;
|
||||
writeln('Testing GetDiskUtilization (nwServ) for user supervisor');
|
||||
IF NOT nwServ.GetDiskUtilization(volNbr,1 {supervisor ObjId},usedDirs,usedFiles,usedBlocks)
|
||||
then begin
|
||||
writeln('--Error returned by nwServ.GetDiskUtilization, err#',nwServ.result);
|
||||
if nwServ.result>=$89
|
||||
then writeln('--( Object Search/Read rights are necessary.)');
|
||||
end
|
||||
else begin
|
||||
writeln(' dirs in use :',usedDirs);
|
||||
writeln(' files in use :',usedFiles);
|
||||
writeln(' blocks in use:',usedBlocks);
|
||||
{ note that blocksinuse is a word (Max ownership= 262 Mb.)
|
||||
GetObjectVolRestriction returns the BlocksInUse value as a LongInt }
|
||||
writeln(' (created/owned dirs/files/blocks)');
|
||||
end;
|
||||
|
||||
writeln('Test of SetObjectVolRestriction:');
|
||||
IF NOT SetObjectVolRestriction(volNbr,$1,BlocksInUse+100)
|
||||
then begin
|
||||
writeln('--Error returned by setObjectVolRestriction, err#',nwFile.result);
|
||||
if nwFile.result=140
|
||||
then writeln('--( Supervisor equivalent rights are necessary.)');
|
||||
end
|
||||
else writeln('--OK, volume restriction set.');
|
||||
|
||||
IF GetObjectVolRestriction(volNbr,$1 {objectId of Supervisor},
|
||||
MaxAllowedBlocks,BlocksInUse)
|
||||
then begin
|
||||
if MaxAllowedBlocks=$40000000 { no restriction }
|
||||
then writeln('--SetObjectVolRestriction failed.');
|
||||
end;
|
||||
|
||||
writeln;
|
||||
writeln('Testing ScanVolForRestrictions:');
|
||||
sequenceNbr:=0;
|
||||
While ScanVolForRestrictions(volNbr,sequenceNbr,NbrOfObjects,ResultBuffer)
|
||||
do begin
|
||||
for t:=1 to NbrOfObjects
|
||||
do begin
|
||||
write(' ObjectId:',HexStr(resultbuffer[t].objId,8));
|
||||
writeln(' /Restriction: ',resultBuffer[t].MaxallowedBlocks,' Blocks');
|
||||
end;
|
||||
end;
|
||||
IF nwFile.result=$FF { NO MORE DATA, normal iteration end }
|
||||
then writeln('--No (more) volume restrictions.')
|
||||
else writeln('--Error returned by ScanVolForRestrictions, err#',nwFile.result);
|
||||
|
||||
|
||||
writeln;
|
||||
writeln('Clearing SUPERVISOR restrictions using ClearObjectVolRestriction.');
|
||||
IF NOT ClearObjectVolRestriction(VolNbr,$1)
|
||||
then begin
|
||||
writeln('--Error calling ClearObjectVolRestriction, err#',nwFile.result);
|
||||
if nwFile.result=140
|
||||
then writeln('--( Supervisor equivalent rights are necessary.)');
|
||||
end;
|
||||
|
||||
|
||||
IF GetObjectVolRestriction(volNbr,1 {objectId of Supervisor},
|
||||
MaxAllowedBlocks,BlocksInUse)
|
||||
then begin
|
||||
if MaxAllowedBlocks=$40000000
|
||||
then writeln('--OK, user now has no restriction.')
|
||||
else writeln('--Error: ClearObjectVolRestriction Failed.');
|
||||
end;
|
||||
|
||||
end.
|
||||
100
NWTP/XFILE/USPACE.PAS
Normal file
100
NWTP/XFILE/USPACE.PAS
Normal file
@@ -0,0 +1,100 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
program uspace;
|
||||
|
||||
{ Example for the nwFile unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Purpose: A quick way of telling how much space each of your users is
|
||||
taking up. For Novell 3.x networks.
|
||||
|
||||
|
||||
(3867) Tue 29 Mar 94 19:01
|
||||
By: Richard Jary
|
||||
To: All
|
||||
Re: Disk Space by Login Name
|
||||
St:
|
||||
------------------------------------------------------------
|
||||
After a quick way of telling how much space each of our users is
|
||||
taking up. Novell 3.11 system, same info as you get by SYSCON ->
|
||||
UserInfo -> Volume/Disk Restrictions. But preferably for all
|
||||
users in a text file format, rather than one by one.
|
||||
|
||||
Reason - we have a shared area with many directories. All with
|
||||
fun names like CAMBODIA, where any one of 10 people could be
|
||||
saving stuff. I'd like to go the the (l)users and say "OI! -
|
||||
You've got 40MB of stuff on this server - Clean It Up!" sort
|
||||
of thing. Either more or less polite depending on the user
|
||||
involved!
|
||||
|
||||
Richard
|
||||
Internet: rjary@nibueng.ccdn.otc.com.au
|
||||
|
||||
--- msgedsq 2.1a
|
||||
* Origin: Networking from Narara. (3:711/445) }
|
||||
|
||||
|
||||
Uses nwMisc,nwBindry,nwFile;
|
||||
|
||||
Var lastObjSeen : Longint;
|
||||
RepName : String;
|
||||
RepType : Word;
|
||||
RepId : LongInt;
|
||||
RepFlag : Byte;
|
||||
RepSecurity : Byte;
|
||||
RepHasProperties: Boolean;
|
||||
FullUserName : string;
|
||||
MaxAllowedBlocks,BlocksInUse:Longint;
|
||||
VolumeNbr : Byte;
|
||||
VolUsageInfo : TvolUsage;
|
||||
Version : Word;
|
||||
|
||||
VolInfo:array[0..31] of record
|
||||
Name :string;
|
||||
SectorsPerBlock:Byte;
|
||||
end;
|
||||
|
||||
begin
|
||||
If NOT IsShellLoaded
|
||||
then begin
|
||||
writeln('USPACE requires:');
|
||||
writeln(' -The shell to be loaded;');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
GetNWversion(version);
|
||||
if version<300
|
||||
then begin
|
||||
writeln('Netware 3.x only.');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
for VolumeNbr:=0 to 31
|
||||
do begin
|
||||
IF GetVolumeName(VolumeNbr,VolInfo[VolumeNbr].name)
|
||||
and GetVolumeUsage(VolumeNbr,VolUsageInfo)
|
||||
then VolInfo[VolumeNbr].SectorsPerBlock:=VolUsageInfo.SectorsPerBlock;
|
||||
end;
|
||||
|
||||
lastObjSeen:=-1;
|
||||
While ScanBinderyObject('*',OT_USER,
|
||||
lastObjSeen,
|
||||
RepName,RepType,RepId,RepFlag,RepSecurity,RepHasProperties)
|
||||
do begin
|
||||
GetRealUserName(RepName,FullUserName);
|
||||
writeln(Repname+' ('+FullUserName+')');
|
||||
|
||||
For VolumeNbr:=0 to 31
|
||||
do if GetObjectVolRestriction(VolumeNbr,RepId,MaxAllowedBlocks,BlocksInUse)
|
||||
then begin
|
||||
write(' ',volInfo[VolumeNbr].Name,' :',
|
||||
BlocksInUse*(VolInfo[VolumeNbr].SectorsPerBlock DIV 2),' Kb.');
|
||||
if MaxAllowedBlocks=$40000000
|
||||
then writeln
|
||||
else writeln(' Restriction: ',MaxAllowedBlocks*4,' Kb.');
|
||||
end;
|
||||
end;
|
||||
if nwBindry.Result=$FC { NO_SUCH_OBJECT, indicates end of search }
|
||||
then writeln('')
|
||||
else writeln('error scanning bindery:',HexStr( nwBindry.Result,2));
|
||||
|
||||
end.
|
||||
111
NWTP/XFILE/VOLSTAT.PAS
Normal file
111
NWTP/XFILE/VOLSTAT.PAS
Normal file
@@ -0,0 +1,111 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
program volstat;
|
||||
|
||||
{ Example for the nwFile unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Purpose: Lists all volume information for each volume on all
|
||||
servers logged in to. If used with the parameter 'c',
|
||||
the volume information will be displayed in a condensed
|
||||
form and will be updated every 5 seconds.
|
||||
|
||||
Tests the following functions in the nwDir Unit:
|
||||
|
||||
GetVolumeUsage
|
||||
GetVolumeName
|
||||
GetVolumeNumber
|
||||
|
||||
|
||||
(3410) Thu 10 Feb 94 11:24
|
||||
By: Frank Van.Wensveen
|
||||
To: All
|
||||
Re: MULTISERVER VOLINFO
|
||||
St:
|
||||
------------------------------------------------------------
|
||||
Ik zoek z.s.m. een utility waarmee ik de volspace van meerdere
|
||||
servers tegelijk in de gaten kan houden. Een soort multi-server
|
||||
VolInfo dus. Er zijn pakketten om dat heel mooi te doen (ik heb
|
||||
er zelfs een ter evaluatie liggen momenteel) maar ik zoek nu
|
||||
even snel (want de nood is hoog) iets eenvoudigs.
|
||||
|
||||
FVW
|
||||
|
||||
---
|
||||
* Origin: * NGN Point-Service -31-4752-6190 * (2:512/250) }
|
||||
|
||||
Uses Crt,nwMisc,nwBindry,nwConn,nwFile;
|
||||
|
||||
CONST testing=TRUE;
|
||||
|
||||
Var volNbr:Byte;
|
||||
volumeName:String;
|
||||
volInfo:TvolUsage;
|
||||
cont:Boolean;
|
||||
ConnId,OldConnId:Byte;
|
||||
ServerName:string;
|
||||
version:word;
|
||||
|
||||
Begin
|
||||
If NOT (IsShellLoaded and IsUserLoggedOn)
|
||||
then begin
|
||||
writeln('VolStat requires:');
|
||||
writeln(' -The shell to be loaded;');
|
||||
writeln(' -You to be logged in.');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
GetNWversion(version);
|
||||
if version<300
|
||||
then begin
|
||||
writeln('Netware 3.x only.');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
cont:=(ParamCount>0) and ((pos('c',paramstr(1))>0) or (pos('C',paramStr(1))>0));
|
||||
|
||||
GetPreferredConnectionId(OldConnId);
|
||||
REPEAT
|
||||
clrscr;
|
||||
For ConnId:=1 to MaxServers
|
||||
do begin
|
||||
IF GetFileServerName(connId,ServerName)
|
||||
then begin
|
||||
SetPreferredConnectionId(connId);
|
||||
volNbr:=0;
|
||||
While volNbr<32
|
||||
do begin
|
||||
|
||||
If GetVolumeUsage(volNbr,volInfo)
|
||||
then with volInfo
|
||||
do begin
|
||||
if cont { condensed output }
|
||||
then begin
|
||||
writeln('\\'+Servername+'\'+VolumeName);
|
||||
writeln(' VS: ',totalblocks*(sectorsPerBlock div 2),' ',freeblocks*(sectorsperBlock div 2),' '+
|
||||
'DE: ',totalDirentries,' ',AvailDirEntries);
|
||||
end
|
||||
else begin { normal output }
|
||||
writeln;
|
||||
writeln('Servername : ',ServerName);
|
||||
writeln('Volumenumber: ',volNbr);
|
||||
writeln('Volume name : ',volumeName);
|
||||
writeln('Blocksize : ',SectorsPerBlock * 512,' bytes.');
|
||||
writeln('Total blocks: ',totalblocks,' (=',(totalblocks * (sectorsPerBlock div 2)),' Kb.)');
|
||||
writeln('Free blocks : ',freeblocks,' (=',(freeblocks * (sectorsPerBlock div 2)),' Kb.)');
|
||||
writeln('Purgable blocks : ',purgableblocks,' (=',
|
||||
purgableblocks * (sectorsPerBlock div 2),' Kb.)');
|
||||
writeln('TotalDirEntries : ',totalDirEntries);
|
||||
writeln('Available DE : ',availDirEntries);
|
||||
end;
|
||||
end;
|
||||
|
||||
inc(volNbr);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
if cont
|
||||
then delay(5000); { 5 second interval }
|
||||
UNTIL KeyPressed or (not cont);
|
||||
|
||||
SetPreferredConnectionId(OldConnId);
|
||||
end.
|
||||
1644
NWTP/XIPX/APPN9001.TXT
Normal file
1644
NWTP/XIPX/APPN9001.TXT
Normal file
File diff suppressed because it is too large
Load Diff
288
NWTP/XIPX/APPN9008.TXT
Normal file
288
NWTP/XIPX/APPN9008.TXT
Normal file
@@ -0,0 +1,288 @@
|
||||
(Note: AppNote August 1990)
|
||||
|
||||
A Comparison of NetWare IPX, SPX and NetBIOS
|
||||
|
||||
Bill Bodine
|
||||
Consultant
|
||||
Systems Engineering Division
|
||||
|
||||
Abstract:
|
||||
|
||||
One of the first questions always asked during comparisons of NetWare
|
||||
IPX, SPX and NetBIOS is which of these protocols will transfer data
|
||||
the fastest, and how much slower the others are. This AppNote details
|
||||
the results of four benchmarks written to illustrate the relative
|
||||
speed of each of these communication interfaces. Performance, maximum
|
||||
packet length, naming capabilities and memory usage are each singled
|
||||
out as additional factors in the decision to implement systems using
|
||||
these protocols. Clarification and explanation of SHELL.CFG parameters
|
||||
are also included.
|
||||
|
||||
Novell, Inc. makes no representations or warranties with respect to
|
||||
the contents or use of these Application Notes, or any of the third-party
|
||||
products discussed in the AppNotes. Novell reserves the right to revise
|
||||
these Application Notes and to make changes in their contents at any
|
||||
time, without obligation to notify any person or entity of such revisions
|
||||
or changes. These AppNotes do not constitute an endorsement of the
|
||||
third-party product or products that were tested. The configuration
|
||||
or configurations tested or described may or may not be the only available
|
||||
solution. Any test is not a determination of product quality or
|
||||
correctness, nor does it ensure compliance with any federal, state or local
|
||||
requirements. Novell does not warranty products except as stated in
|
||||
applicable Novell product warranties or license agreements.
|
||||
|
||||
Copyright { 1990 by Novell, Inc., Provo, Utah. All rights reserved.
|
||||
|
||||
As a means of promoting NetWare Application Notes, Novell grants you
|
||||
without charge the right to reproduce, distribute and use copies of
|
||||
the AppNotes provided you do not receive any payment, commercial benefit
|
||||
or other consideration for the reproduction or distribution, or change
|
||||
any copyright notices appearing on or in the document.
|
||||
|
||||
Introduction
|
||||
|
||||
When Novell began operations in 1982, several proprietary protocols
|
||||
for transferring data between workstations were used. As time went
|
||||
on, the decision was made to base Novell's network communications
|
||||
on a fast and efficient networking standard. Xerox's XNS protocol
|
||||
was determined to be one of the best available at the time so Novell's
|
||||
Internetwork Packet Exchange (IPX) protocol was developed to conform
|
||||
to the XNS standard. NetWare IPX is functionally equivalent to Xerox's
|
||||
Internet Datagram Protocol (IDP).
|
||||
|
||||
This AppNote discusses the three primary peer-to-peer protocols
|
||||
that are supported in the NetWare LAN environment-NetWare IPX, SPX
|
||||
and NetBIOS. Additional protocols supported include the Transport
|
||||
Layer Interface (TLI), Named Pipes, LU6.2 and others, but are not
|
||||
covered in this AppNote.
|
||||
|
||||
NetWare IPX
|
||||
|
||||
NetWare IPX is a true datagram protocol. It makes a best-effort
|
||||
attempt to send packets by using a 12-byte addressing scheme.
|
||||
The 12-byte address is split into three addresses: the network
|
||||
address, which is used to address individual workgroups; the node
|
||||
address, which addresses network nodes within the workgroups; and
|
||||
the socket address, which can be used to multiplex between functions
|
||||
within a network node. When sending an NetWare IPX packet from one
|
||||
node to another, the sending node must know the receiving node's 12-byte
|
||||
address.
|
||||
|
||||
SPX
|
||||
|
||||
The Sequenced Packet Exchange protocol (SPX) is a connection-oriented
|
||||
communications protocol that is built upon NetWare IPX. When a call
|
||||
is made to SPX to send a packet by an application program, SPX will
|
||||
do some housekeeping-type work on the packet, but will call NetWare
|
||||
IPX to actually send the packet. SPX guarantees packet delivery, whereas
|
||||
NetWare IPX only gives a best effort to deliver packets. This added
|
||||
feature of SPX has obvious advantages, but as we shall see later in
|
||||
the paper, it also adds overhead to the data transfer cycle and is
|
||||
slower.
|
||||
|
||||
NetBIOS
|
||||
|
||||
The Network Basic Input/Output System (NetBIOS) functions in either
|
||||
a connectionless mode or a connection-oriented mode. An application
|
||||
written to the NetBIOS interface can be designed to use either of
|
||||
these modes. For instance, if an application functions in a request/reply
|
||||
mode with a transfer size of only one packet, then the connectionless
|
||||
mode should be used to take advantage of connectionless response times.
|
||||
On the other hand, if most of the transfers are one-sided or consist
|
||||
of large numbers of packets, the transfers should use the connection-
|
||||
oriented mode in order to ensure packet delivery and integrity of data.
|
||||
Novell's NetBIOS emulator is built upon NetWare IPX in the same way
|
||||
that SPX is.
|
||||
|
||||
The NetBIOS emulator is called an emulator because it is implemented
|
||||
entirely in software, whereas the original NetBIOS introduced by IBM
|
||||
and Sytek was located in firmware.
|
||||
|
||||
Because NetBIOS was introduced by IBM, it was almost instantly accepted
|
||||
as an industry standard. Most networking vendors have implemented
|
||||
the specification given by IBM that allows almost any application
|
||||
written to the NetBIOS interface to operate in any environment.
|
||||
|
||||
A common problem with the NetBIOS specification, however, is that
|
||||
it only deals with the upper layer functions of the interface. It
|
||||
does not specify what communications protocol should be used underneath
|
||||
it. As a result, almost every networking vendor has written NetBIOS
|
||||
on top of their own proprietary communications protocol, which cannot
|
||||
communicate with other vendors' protocols.
|
||||
|
||||
A nice feature that NetBIOS has to offer the networking industry is
|
||||
its allowance of easy address resolution among locally-connected
|
||||
workstations. All nodes on a network that use NetBIOS register a unique
|
||||
name. When a node desires to communicate with another node, all it
|
||||
needs to know is the node's unique NetBIOS name and NetBIOS will ensure
|
||||
that the packet arrives at the proper location.
|
||||
|
||||
Performance Results
|
||||
|
||||
One of the first questions regarding the comparison of NetWare IPX,
|
||||
SPX and NetBIOS is which of these protocols will transfer data the
|
||||
fastest, and how much slower the others are. As part of this AppNote,
|
||||
four benchmarks have been written to illustrate the relative speed
|
||||
of each of these communications interfaces. The scope of the benchmark
|
||||
is relatively simple-to send 2,000 255-byte packets and to record
|
||||
the time that it takes for the transfer to complete. All the programs
|
||||
were written by the same person and were intentionally kept as simple
|
||||
as possible to make each benchmark represent the speed of the interface
|
||||
and not efficiencies or lack thereof in the benchmark tests.
|
||||
|
||||
Each of the benchmarks encompassed two programs. One program
|
||||
was used to send packets and the other was used to receive. The sending
|
||||
side sent a packet and then incremented a counter. Before the packet
|
||||
was sent, a call was made by the sender to the system clock. Once
|
||||
the 2,000th packet had been sent successfully, another call was made
|
||||
to the system clock. The first value was subtracted from the second
|
||||
and the result represented the time in clock ticks that it took to
|
||||
send 2,000 packets on the given communication interface. The receiving
|
||||
side did nothing but receive packets and count the number that arrived.
|
||||
No other processing took place within the code.
|
||||
|
||||
The following results were achieved on standard 8MHz 80286-based
|
||||
machines on a 4MB Token-Ring network. While the test does not
|
||||
represent any real-world scenario, it does indicate the relative
|
||||
speed of each interface tested.
|
||||
|
||||
NetWare IPX 366.0 packets per second
|
||||
|
||||
SPX 140.3 packets per second
|
||||
|
||||
Novell NetBIOS datagram 224.8 packets per second
|
||||
|
||||
Novell NetBIOS session 135.9 packets per second
|
||||
|
||||
NetWare IPX is the fastest protocol available from Novell. This is
|
||||
expected since all others are written in terms of NetWare IPX. SPX
|
||||
and NetBIOS are slower than NetWare IPX due to the extra overhead
|
||||
they introduce into the communications process. SPX and the NetBIOS
|
||||
session level interface run at virtually the same speed. They both
|
||||
have to maintain the same level of connection overhead for the
|
||||
guaranteeing of packets and are both written in terms of another
|
||||
interface.
|
||||
|
||||
Other Decision Criteria
|
||||
|
||||
There are a few primary differences between writing an application
|
||||
to NetWare IPX or SPX and writing an application to NetBIOS. Two of
|
||||
these differences deal with the maximum length of packets that can
|
||||
be sent and the address resolution.
|
||||
|
||||
Maximum Packet Length
|
||||
|
||||
With NetWare IPX and SPX the maximum packet size that can be sent
|
||||
by an application depends on either of two things. If the packet to
|
||||
be sent must cross a NetWare bridge, the maximum packet size possible
|
||||
is 576 bytes. The bridge will drop any packets that exceed this size.
|
||||
|
||||
On the other hand, if the packet will not be crossing any bridges,
|
||||
the network interface card (NIC) drivers limit the size. While most
|
||||
drivers allow packets of 1,024 bytes or larger to be transferred,
|
||||
NetWare documentation recommends that the maximum size transferred
|
||||
be 576 bytes. This is in case the packet crosses a bridge or the driver
|
||||
cannot handle larger packets.
|
||||
|
||||
NetBIOS allows an application to send packets up to 64KB in size.
|
||||
This is possible because the NetBIOS emulator breaks the packet into
|
||||
smaller packets for the application and sends them out in sizes that
|
||||
can be handled by NetWare IPX and the NIC drivers. While this feature
|
||||
is useful, some developers choose to split packets up themselves in
|
||||
order to optimize the NetWare IPX bandwidth for their application.
|
||||
This may or may not be a factor in different situations.
|
||||
|
||||
Naming Capabilities
|
||||
|
||||
The second primary difference is the naming capability supplied with
|
||||
NetBIOS. NetBIOS makes it convenient for an application to determine
|
||||
the addresses of other nodes on the network. Each workstation identifies
|
||||
itself with a particular name. Once any other workstation on the LAN
|
||||
knows that name, data can be sent between the two workstations.
|
||||
|
||||
Novell recognized the need for this easy address resolution when it
|
||||
developed NetWare IPX, so the Service Advertising Protocol (SAP) was
|
||||
developed. With SAP, a node advertises, or broadcasts to the entire
|
||||
network its name and address. This name and address are stored internally
|
||||
on all NetWare network file servers. When any other node wants to
|
||||
find an address, it queries a NetWare file server and the necessary
|
||||
information is returned. There are also other ways of finding an address
|
||||
without accessing the NetWare file server, but they are not as common.
|
||||
|
||||
Both of these methods have advantages and disadvantages. While it
|
||||
is probably easier for an application with the naming capability of
|
||||
NetBIOS to be developed, using the SAP provided by NetWare does not
|
||||
require much more work. The advantage gained by using the SAP is that
|
||||
once the address is resolved, the underlying protocol is very fast.
|
||||
The SAP is designed for a client-server environment, which means
|
||||
that a client always initiates a dialogue with the server. The client
|
||||
can always find the server's address through the SAP. Since all packets
|
||||
on the network contain the 12-byte address of the node they were
|
||||
sent from, the server will know which address to send responses to.
|
||||
|
||||
Memory Usage
|
||||
|
||||
When an application runs on a network workstation, particularly in
|
||||
the DOS environment, the amount of memory that is free for the application
|
||||
to use is often a primary concern. In NetWare the first software to
|
||||
load on the network is a terminate-and-stay-resident (TSR)
|
||||
program called IPX.COM. This program contains all the interfaces needed
|
||||
to run NetWare IPX programs and SPX, and uses about 14KB of workstation
|
||||
memory. This is the only piece of NetWare software that needs to be
|
||||
run in the workstation if no communications are needed with any file
|
||||
servers. If a file server is needed, the TSR NET3.COM is loaded after
|
||||
IPX.COM. This program contains all the functions needed by the workstation
|
||||
to communicate with any NetWare file server on the LAN. It uses about
|
||||
38KB of workstation memory. NetBIOS is an optional TSR like NET3.
|
||||
IPX.COM must be loaded first. When NetBIOS is loaded it takes up about
|
||||
30KB of workstation memory. Just as NET3 is only used when communications
|
||||
are sent to a NetWare file server, NetBIOS is only run if an application
|
||||
needs to use the NetBIOS services. Native NetWare does not use NetBIOS
|
||||
for any of its communications services.
|
||||
|
||||
Appendix A lists parameters that have been modified in the recent
|
||||
versions of NetBIOS. Because of the differences among versions, they
|
||||
will be discussed as they relate to the specific versions.
|
||||
|
||||
The values listed in Appendix A are approximates. It is not possible
|
||||
to state exactly how much memory any of the three protocols will use
|
||||
up because they all contain custom parameters that change their sizes
|
||||
and configurations. The parameters that alter these configurations
|
||||
are located in a file named SHELL.CFG. As IPX.COM or NetBIOS.EXE is
|
||||
loaded, it looks for this file in the local directory or a search
|
||||
directory. Once it locates SHELL.CFG it searches within the file to
|
||||
determine if any of its default parameters have been altered. These
|
||||
parameters can be configured from within the SHELL.CFG file. Appendix
|
||||
B of the NetWare Supervisor Reference manual also explains
|
||||
the parameters.
|
||||
|
||||
Conclusion
|
||||
|
||||
While the primary advantage of writing to NetWare IPX is speed, the
|
||||
main advantage of writing to NetBIOS is that the application will
|
||||
work on other environments in addition to NetWare. This should obviously
|
||||
be considered for applications that are marketed on a variety of platforms.
|
||||
|
||||
Even though different vendors' NetBIOSs can rarely communicate with
|
||||
each other, most applications do port well over these vendors'
|
||||
implementations.
|
||||
|
||||
There are a variety of reasons applications are developed to
|
||||
one protocol or another. One reason a protocol is chosen is because
|
||||
it is perceived as the defacto standard. For many developers, NetBIOS
|
||||
is seen as a standard. Applications are developed to that platform
|
||||
for reasons of portability to a variety of environments. On the other
|
||||
hand, many developers are developing to NetWare IPX because they recognize
|
||||
NetWare's large market share and want to reach the greatest market
|
||||
possible with the most efficient protocol available.
|
||||
|
||||
Sometimes, one protocol may be perceived as easier to develop to than
|
||||
another. Of course whether one is actually easier than another depends
|
||||
entirely on the resources that are available, such as the Novell C
|
||||
Interface libraries for NetWare IPX and SPX, the experience of the
|
||||
development team or even available documentation and training.
|
||||
|
||||
Appendix A: SHELL.CFG Parameters
|
||||
|
||||
******* Note: The appendix (mostly outdated info) has been removed ********
|
||||
|
||||
758
NWTP/XIPX/BLTS9401.TXT
Normal file
758
NWTP/XIPX/BLTS9401.TXT
Normal file
@@ -0,0 +1,758 @@
|
||||
ARTICLES: IPX/SPX for NetBIOS Developers
|
||||
|
||||
Original article: (c) Copyright Novell, 1994
|
||||
Novell Professional Developer BULLETS
|
||||
January 1994 (Volume 6, Number 1)
|
||||
NwTP additions : (between angular brackets/ minus signs [- ... -])
|
||||
|
||||
NetBIOS is a popular peer-to-peer communication method that it is
|
||||
supported under NetWare through a NetBIOS emulator. However, even though
|
||||
NetBIOS is supported, there are definite advantages to using Novell's
|
||||
"native tongue" protocols, IPX (Internet Packet eXchange) and SPX
|
||||
(Sequenced Packet eXchange), when doing peer-to-peer communication.
|
||||
|
||||
This article discusses the advantages of using IPX/SPX and provides an
|
||||
introduction to Novell's IPX and SPX protocols for developers who have a
|
||||
working familiarity with NetBIOS.
|
||||
|
||||
Why Use IPX/SPX?
|
||||
|
||||
The most obvious reason to use IPX and SPX is to improve performance;
|
||||
since NetWare emulates NetBIOS, processing NetBIOS commands involves more
|
||||
overhead than processing IPX/SPX commands. NetWare encapsulates emulated
|
||||
NetBIOS packets within IPX packets before they go out on the wire, so
|
||||
moving to IPX/SPX allows you to "cut out the middleman."
|
||||
|
||||
You lose no connectivity by switching protocols either, since the
|
||||
emulated NetBIOS layer cannot communicate with hardware NetBIOS systems.
|
||||
In fact, moving to IPX/SPX gives you a net gain in connectivity; NetWare
|
||||
has a 70% share of the network operating system market.
|
||||
|
||||
Also, since the NetBIOS emulator adds an additional layer of complexity
|
||||
to packets being sent out, it is more difficult to troubleshoot problems.
|
||||
Emulating NetBIOS involves an extra driver and an extra set of potential
|
||||
incompatibilities. Generally speaking, since IPX and SPX are not
|
||||
dramatically different from NetBIOS, it makes your job easier to work
|
||||
with the protocols that NetWare is designed to support.
|
||||
|
||||
Datagram Services
|
||||
|
||||
Novell's IPX protocol provides almost the same functionality as NetBIOS
|
||||
datagrams. Both specifications deliver packets on a best-effort basis,
|
||||
but with no guarantee of delivery or sequencing. Both IPX and NetBIOS
|
||||
also provide the capability to send packets either to a single node or to
|
||||
multiple nodes. NetBIOS supports the multicast, or the sending of a
|
||||
datagram to a selected group of nodes with the same group name. Since IPX
|
||||
is address-based instead of name-based, this capability is not directly
|
||||
supported; instead IPX must send an individual packet to each node.
|
||||
|
||||
NetBIOS also supports the broadcast datagram, a datagram that is
|
||||
broadcast to the entire internetwork. IPX supports broadcasts, but only
|
||||
to one subnet at a time. Usually, this restriction poses no problem,
|
||||
since mechanisms such as the NetWare Service Advertising Protocol (SAP)
|
||||
overcome this limitation.
|
||||
|
||||
The data portion of a NetBIOS datagram is limited in length to 512 bytes,
|
||||
whereas IPX packets allow 546 bytes of data on all networks and can
|
||||
sometimes be substantially larger than that depending on the maximum
|
||||
packet size supported by network routers. Some networks can handle packet
|
||||
sizes of 4096 bytes or more.
|
||||
|
||||
Session Services
|
||||
|
||||
As in the relationship between IPX and NetBIOS datagrams, Novell's SPX
|
||||
protocol serves much the same function as the NetBIOS session. Both SPX
|
||||
and NetBIOS sessions provide guaranteed delivery and sequencing of
|
||||
packets, but at the cost of increased overhead.
|
||||
|
||||
The primary difference between the two is the supported packet size.
|
||||
NetBIOS sessions support 64K packet sizes (128K with Chain Sends). SPX
|
||||
has the same 546-byte packet size limitation as IPX and, in fact, SPX
|
||||
allows slightly less data in a packet than IPX, since the SPX header
|
||||
requires an additional 12 bytes. SPX therefore supports 534 bytes of data
|
||||
on all networks with the potential for much larger packets if supported
|
||||
by the routers, although attaining a 64K packet size is unlikely.
|
||||
|
||||
Probably the most noticeable difference between IPX/SPX and NetBIOS is
|
||||
how each addresses packets. IPX/SPX addresses packets using network,
|
||||
node, and socket numbers. NetBIOS uses unique names to address packets.
|
||||
Each workstation can be uniquely addressed using the network and node
|
||||
numbers.
|
||||
|
||||
A workstation can then have as many open sockets as desired for receiving
|
||||
peer-to-peer data packets. Many methods exist for determining a
|
||||
workstation's network, node, and destination socket number, but for
|
||||
simplicity the example code in this article uses SAP to obtain this
|
||||
information.
|
||||
|
||||
The Waiting Game
|
||||
|
||||
With NetBIOS, you can choose to allow most NetBIOS commands to complete
|
||||
before returning control to the application, but most IPX/SPX commands
|
||||
return control immediately. In other words, most IPX/SPX commands are
|
||||
"no-wait" commands; there is no IPX/SPX "wait" counterpart.
|
||||
|
||||
Since most NetBIOS developers use the "no-wait" variants, this difference
|
||||
should not pose a problem, but if you need to use a "wait," you can code
|
||||
it very simply by issuing the command and then looping on the in use
|
||||
field.
|
||||
|
||||
Asynchronous Events
|
||||
|
||||
IPX/SPX also has a feature that is not used with NetBIOS: the
|
||||
asynchronous event. An asynchronous event can be initiated at any time
|
||||
and, as the name implies, can be set to occur independent of an
|
||||
application's execution path. An event could be set up, for example, to
|
||||
automatically broadcast an IPX packet every 45 seconds. The application
|
||||
initiating this event could then continue processing and leave the timing
|
||||
and broadcasting of packets to the IPX event handler.
|
||||
|
||||
The Network Control Block & the Event Control Block
|
||||
|
||||
From a developer's perspective, the "core" of NetBIOS is the Network
|
||||
Control Block (NCB). IPX and SPX are based on an Event Control Block
|
||||
(ECB) and an IPX/SPX header. Figure 1 describes the fields in the ECB.
|
||||
|
||||
*********************************************************
|
||||
Figure 1: The IPX/SPX Event Control Block [- C structure -]
|
||||
|
||||
void far *linkAddress Set by IPX
|
||||
void (far *ESRAddress)() Equivalent to NetBIOS POST routine
|
||||
BYTE inUseFlag Set when the ECB is in use, zero
|
||||
when it is available
|
||||
BYTE completionCode Equivalent to NetBIOS Command
|
||||
Completion
|
||||
WORD socketNumber Socket number associated with ECB
|
||||
BYTE IPXWorkspace[4] Set by IPX
|
||||
BYTE driverWorkspace[12] Set by IPX
|
||||
BYTE immediateAddress[6] Node address of next "hop"
|
||||
WORD fragmentCount Number of buffer fragments in packet
|
||||
ECBFragment fragmentDescriptor[2] Address and size of fragment(s)
|
||||
|
||||
END of FIGURE 1
|
||||
*********************************************************
|
||||
|
||||
[- *********************************************************
|
||||
Figure 1a: The IPX/SPX Event Control Block (Pascal syntax)
|
||||
|
||||
linkAddress :Pointer Set by IPX
|
||||
ESRAddress :Pointer Equivalent to NetBIOS
|
||||
POST routine
|
||||
InUseFlag :Byte; Set when the ECB is in use,
|
||||
zero when it is available
|
||||
CompletionCode :Byte; Equivalent to NetBIOS Command
|
||||
Completion
|
||||
SocketNumber :Word; Socket number associated
|
||||
with ECB
|
||||
IPXWorkspace :array[1..4] of byte; Set by IPX
|
||||
DriverWorkspace :array[1..12] of byte; Set by IPX
|
||||
ImmediateAddress:array[1..6] of byte; (Tnodeaddress)
|
||||
Node address of next "hop"
|
||||
FragmentCount :word; Number of buffer fragments
|
||||
in packet
|
||||
Fragment :array[1.. ] of Tfragment Address and size of
|
||||
fragment(s)
|
||||
|
||||
(Note: this structure is declared as the Tecb type in the nwIPX unit)
|
||||
|
||||
END of FIGURE 1a
|
||||
********************************************************* -]
|
||||
|
||||
Note that the ECB contains a field that has no equivalent in the NCB
|
||||
called the immediate address field. This field should be populated with
|
||||
the node address of the first "hop" on the way to the packet's ultimate
|
||||
destination. Novell provides an API call to populate this field, the
|
||||
IPXGetLocalTarget() API available in the NetWare Client SDK.
|
||||
|
||||
IPX Send Example
|
||||
|
||||
The sample code in this article includes simple examples written under
|
||||
DOS with the NetWare Client SDK. Figure 2 shows a routine sending an IPX
|
||||
packet.
|
||||
|
||||
*********************************************************
|
||||
Figure 2: IPX Send [- C example -]
|
||||
|
||||
/* Send "Hello!" to the station at network 0x11111111, node
|
||||
0x222222222222, socket 0x3333 using IPX */
|
||||
|
||||
void IPXSayHello()
|
||||
{
|
||||
char buffer[] = "Hello!";
|
||||
ECB ecb;
|
||||
IPXHeader header;
|
||||
int transTime;
|
||||
header.packetType = 4;
|
||||
memset(header.destination.network, 0x11, 4);
|
||||
memset(header.destination.node, 0x22, 6);
|
||||
memset(header.destination.socket, 0x33, 2);
|
||||
|
||||
ecb.ESRAddress = NULL;
|
||||
ecb.socketNumber = 0x4444;
|
||||
IPXGetLocalTarget(header.destination,
|
||||
ecb.immediateAddress, &transTime);
|
||||
ecb.fragmentCount = 2;
|
||||
ecb.fragmentDescriptor[0].address = &header;
|
||||
ecb.fragmentDescriptor[0].size = sizeof(IPXHeader);
|
||||
ecb.fragmentDescriptor[1].address = buffer;
|
||||
ecb.fragmentDescriptor[1].size = strlen(buffer) + 1;
|
||||
IPXSendPacket(&ecb);
|
||||
}
|
||||
|
||||
END of FIGURE 2
|
||||
*********************************************************
|
||||
|
||||
[- *********************************************************
|
||||
Figure 2a: IPX Send (Pascal example)
|
||||
|
||||
{ Send "Hello!" to the station at network $11111111, node
|
||||
$222222222222, socket $3333 using IPX }
|
||||
|
||||
Procedure IPXSayHello;
|
||||
Var buffer:string;
|
||||
ecb:Tecb;
|
||||
header:TipxHeader;
|
||||
transTime:Word;
|
||||
begin
|
||||
Buffer:="Hello!";
|
||||
header.packetType := 4;
|
||||
FillChar(header.destination.network,4,$11);
|
||||
FillChar(header.destination.node, 6,$22);
|
||||
FillChar(header.destination.socket, 2,$33);
|
||||
|
||||
ecb.ESRAddress:=NIL;
|
||||
ecb.socketNumber:=$4444;
|
||||
IPXGetLocalTarget(header.destination,
|
||||
ecb.immediateAddress, transTime);
|
||||
ecb.fragmentCount:=2;
|
||||
ecb.fragment[1].address:= @header;
|
||||
ecb.fragment[1].size := SizeOf(TIPXHeader);
|
||||
ecb.fragment[2].address:= @buffer[1];
|
||||
ecb.fragment[2].size:= ord(buffer[0]);
|
||||
IPXSendPacket(ecb);
|
||||
end;
|
||||
|
||||
END of FIGURE 2a
|
||||
********************************************************* -]
|
||||
|
||||
|
||||
The first apparent difference between IPX and NetBIOS is that IPX uses
|
||||
two buffers where NetBIOS would use one. The first buffer is the IPX
|
||||
Header containing the source and destination addresses, the packet type,
|
||||
and several "housekeeping" fields. Refer to Figure 3 for a description of
|
||||
the IPX header.
|
||||
|
||||
*********************************************************
|
||||
Figure 3: IPX Header
|
||||
|
||||
WORD checkSum Included to conform to Xerox IDP standard
|
||||
Set to FFFF by IPX
|
||||
WORD length Length of entire IPX packet including
|
||||
header
|
||||
Set by IPX
|
||||
BYTE transportControl Hop count - Set to zero by IPX
|
||||
BYTE packetType IPX packet type is 4
|
||||
IPXAddress destination Address the packet is sent to
|
||||
[- Pascal: of type TInternetworkAddress -]
|
||||
IPXAddress source Address of node sending packet set by IPX
|
||||
[- Pascal: of type TinternetworkAddress -]
|
||||
|
||||
END of FIGURE 3
|
||||
*********************************************************
|
||||
|
||||
The second buffer is the data to be sent. Two fields in the IPX header
|
||||
must be set for an IPX send: the packet type and the destination address.
|
||||
IPX packets are type 4, SPX packets are type 5. [- Note that according
|
||||
to the original xerox definitions this statement is not correct. Type 4
|
||||
packets are reserved for the PEP protocol. Use type 0 (undefined) when
|
||||
transmitting standard IPX packets-] The destination address consists
|
||||
of a four-byte network number, a six-byte node number, and a two-byte
|
||||
socket number.
|
||||
|
||||
If these examples used an Event Service Routine (ESR), the ESR address
|
||||
would be filled with the address of a procedure to be run when the send
|
||||
completes, but since NULL is specified, this routine will not be run. The
|
||||
ESR is equivalent to the NetBIOS POST routine. When the IPX send
|
||||
executes, the rest of the fields in the IPX header are filled in
|
||||
automatically, including the source address. You must specify the socket
|
||||
number to be included in the source address, but the socket need not be
|
||||
open to send a packet. For this example, socket number 0x4444 was
|
||||
arbitrarily chosen.
|
||||
|
||||
The immediate address field described above must be filled in as well,
|
||||
and the IPXGetLocalTarget() API call fills in this field with the
|
||||
appropriate value. It is passed the final destination of the packet and
|
||||
it calculates the address of the "first hop" on the way to the final
|
||||
destination. Note that if the target workstation is on the same subnet as
|
||||
the sending workstation the immediate address will be the same as the
|
||||
final destination. Otherwise, it will be a bridge or router on the
|
||||
subnet.
|
||||
|
||||
Each of the buffers sent in the IPX packet is considered to be a
|
||||
fragment. Since there are two buffers (the IPX header and the data), the
|
||||
fragment count is equal to two. The address and size of the fragments are
|
||||
then entered, starting with the IPX header. As soon as all of the
|
||||
relevant fields are filled, the example calls IPXSendPacket() and passes
|
||||
it the address of the ECB.
|
||||
|
||||
Receiving an IPX packet is much like sending one from a programming
|
||||
standpoint, except that you do not need to set the IPX header fields. In
|
||||
the ECB, you should set the ESR address, socket number, immediate
|
||||
address, and fragment descriptors.
|
||||
|
||||
Note about socket numbers: the socket number specified for an IPX send
|
||||
does not need to be open, but for an IPX receive the socket must be open.
|
||||
The API call to receive an IPX packet is IPXListenForPacket().
|
||||
|
||||
SPX Connection Example
|
||||
|
||||
Figure 4 contains a code sample that establishes an SPX connection.
|
||||
Before the request for an SPX connection is submitted, several ECBs are
|
||||
already listening for data (this is important). SPX temporarily "steals"
|
||||
two ECBs from the available and waiting ones for connection maintenance,
|
||||
and then it puts the stolen ECBs back in the pool when finished. If there
|
||||
are no pending ECBs for SPX to use, it cannot send an acknowledgement to
|
||||
the remote site and the connection will stall and time out.
|
||||
|
||||
*********************************************************
|
||||
Figure 4: Establishing an SPX Connection [- C code example -]
|
||||
|
||||
/* Start an SPX connection with the station at network
|
||||
0x11111111, node 0x222222222222, socket 0x3333, use
|
||||
local socket 0x4444 */
|
||||
|
||||
#define NUM_BUFFS 5
|
||||
|
||||
void call()
|
||||
{
|
||||
ECB send, receive[NUM_BUFFS], connect, term;
|
||||
SPXHeader sendHdr, rcvHdr[NUM_BUFFS], connHdr;
|
||||
char buffer[NUM_BUFFS][80], sendbuf[] = "Hello!";
|
||||
int i, ccode, packetsReceived;
|
||||
WORD spxConnectionID;
|
||||
|
||||
for (i = 0; i < NUM_BUFFS; i++) {
|
||||
receive[i].ESRAddress = NULL;
|
||||
receive[i].socketNumber = 0x4444;
|
||||
receive[i].fragmentCount = 2;
|
||||
receive[i].fragmentDescriptor[0].address
|
||||
= &(rcvHdr[i]);
|
||||
receive[i].fragmentDescriptor[0].size
|
||||
= sizeof(SPXHeader);
|
||||
receive[i].fragmentDescriptor[1].address
|
||||
= &(buffer[i]);
|
||||
receive[i].fragmentDescriptor[1].size = 80;
|
||||
SPXListenForSequencedPacket(receive[i]);
|
||||
}
|
||||
|
||||
connect.ESRAddress = NULL;
|
||||
connect.socketNumber = 0x4444;
|
||||
connect.fragmentCount = 1;
|
||||
connect.fragmentDescriptor[0].address = &connHdr;
|
||||
connect.fragmentDescriptor[0].size
|
||||
= sizeof(SPXHeader);
|
||||
|
||||
memset(connHdr.destination.network, 0x11, 4);
|
||||
memset(connHdr.destination.node, 0x22, 6);
|
||||
memset(connHdr.destination.socket, 0x33, 2);
|
||||
|
||||
ccode = SPXEstablishConnection(0, 0,
|
||||
&spxConnectionID,
|
||||
&connect);
|
||||
printf("SPXEstablishConnection return code
|
||||
= 0x%x\n", ccode);
|
||||
if (ccode != 0)
|
||||
return;
|
||||
while (connect.inUseFlag != 0)
|
||||
IPXRelinquishControl();
|
||||
if (connect.completionCode != 0)
|
||||
return;
|
||||
send.ESRAddress = NULL;
|
||||
send.fragmentCount = 2;
|
||||
send.fragmentDescriptor[0].address = &sendHdr;
|
||||
send.fragmentDescriptor[0].size = sizeof(SPXHeader);
|
||||
send.fragmentDescriptor[1].address = sendbuf;
|
||||
send.fragmentDescriptor[1].size = 7;
|
||||
SPXSendSequencedPacket(spxConnectionID, &send);
|
||||
|
||||
packetsReceived = 0;
|
||||
while (packetsReceived < 10) {
|
||||
for (i = 0; i < NUM_BUFFS; i++) {
|
||||
if (receive[i].inUseFlag != 0) {
|
||||
if (receive[i].completionCode != 0) {
|
||||
packetsReceived = 10;
|
||||
/* If we get an error, terminate */
|
||||
break;
|
||||
}
|
||||
printf("Received: %s\n", buffer[i]);
|
||||
packetsReceived++;
|
||||
}
|
||||
SPXListenForSequencedPacket(receive[i]);
|
||||
}
|
||||
IPXRelinquishControl();
|
||||
}
|
||||
|
||||
term.ESRAddress = NULL;
|
||||
term.fragmentCount = 1;
|
||||
term.fragmentDescriptor[0].address = &connHdr;
|
||||
term.fragmentDescriptor[0].size = sizeof(SPXHeader);
|
||||
SPXTerminateConnection(spxConnectionID, &term);
|
||||
while (term.inUseFlag != 0)
|
||||
IPXRelinquishControl();
|
||||
for (i = 0; i < NUM_BUFFS; i++)
|
||||
IPXCancelEvent(receive[i]);
|
||||
}
|
||||
END of FIGURE 4
|
||||
*********************************************************
|
||||
|
||||
[- *********************************************************
|
||||
Figure 4a: Establishing an SPX Connection (Pascal example)
|
||||
|
||||
{ Start an SPX connection with the station at network
|
||||
$11111111, node $222222222222, socket $3333, use
|
||||
local socket $4444 }
|
||||
|
||||
CONST NUM_BUFFS=5;
|
||||
|
||||
Procedure call;
|
||||
Var send,connect,term:Tecb;
|
||||
receive :array[1..NUM_BUFFS] of Tecb;
|
||||
sendHdr, connHdr : TspxHeader;
|
||||
rcvHdr :array[1..NUM_BUFFS] of TspxHeader;
|
||||
buffer :array[1..NUM_BUFFS] of string[80];
|
||||
sendBuf :string;
|
||||
i,packetsReceived:Integer;
|
||||
spxConnectionId :word;
|
||||
begin;
|
||||
sendbuf:="Hello!";
|
||||
|
||||
for i:= 1 to NUM_BUFFS
|
||||
do begin
|
||||
receive[i].ESRAddress := NIL;
|
||||
receive[i].socketNumber := $4444;
|
||||
receive[i].fragmentCount = 2;
|
||||
receive[i].fragment[1].address := @rcvHdr[i];
|
||||
receive[i].fragment[1].size := sizeof(TSPXHeader);
|
||||
receive[i].fragment[2].address := @buffer[i];
|
||||
receive[i].fragment[2].size := 80;
|
||||
SPXListenForSequencedPacket(receive[i]);
|
||||
end;
|
||||
|
||||
connect.ESRAddress := NIL;
|
||||
connect.socketNumber := $4444;
|
||||
connect.fragmentCount := 1;
|
||||
connect.fragment[1].address := @connHdr;
|
||||
connect.fragment[1].size := sizeof(TSPXHeader);
|
||||
|
||||
FillChar(connHdr.destination.network, 4, $11);
|
||||
FillChar(connHdr.destination.node, 6, $22);
|
||||
FillChar(connHdr.destination.socket, 2, $33);
|
||||
|
||||
IF NOT SPXEstablishConnection(0, 0,
|
||||
spxConnectionID,
|
||||
connect)
|
||||
then begin
|
||||
writeln('SPXEstablishConnection return code',
|
||||
HexStr(nwSpx.result,2));
|
||||
exit;
|
||||
end;
|
||||
|
||||
while (connect.inUseFlag <> 0)
|
||||
do IPXRelinquishControl();
|
||||
if (connect.completionCode <> 0)
|
||||
then exit;
|
||||
|
||||
send.ESRAddress := NIL;
|
||||
send.fragmentCount := 2;
|
||||
send.fragment[1].address = @sendHdr;
|
||||
send.fragment[1].size := sizeof(TSPXHeader);
|
||||
send.fragment[2].address := @sendbuf[0];
|
||||
send.fragment[2].size := ord(sendBuf[0])+1;
|
||||
SPXSendSequencedPacket(spxConnectionID, send);
|
||||
|
||||
packetsReceived := 0;
|
||||
while (packetsReceived < 10)
|
||||
do begin
|
||||
for i :=1 to NUM_BUFFS
|
||||
do begin
|
||||
if (receive[i].inUseFlag <> 0)
|
||||
and (receive[i].completionCode <> 0)
|
||||
then begin
|
||||
packetsReceived := 10;
|
||||
exit;
|
||||
{ If we get an error, terminate }
|
||||
end;
|
||||
writeln('Received: ", buffer[i]);
|
||||
inc(packetsReceived);
|
||||
SPXListenForSequencedPacket(receive[i]);
|
||||
end;
|
||||
IPXRelinquishControl;
|
||||
end;
|
||||
|
||||
term.ESRAddress := NIL;
|
||||
term.fragmentCount := 1;
|
||||
term.fragment[1].address := @connHdr;
|
||||
term.fragment[1].size := sizeof(TSPXHeader);
|
||||
SPXTerminateConnection(spxConnectionID, term);
|
||||
while (term.inUseFlag <> 0)
|
||||
do IPXRelinquishControl;
|
||||
for i:=1 to NUM_BUFFS
|
||||
do IPXCancelEvent(receive[i]);
|
||||
end;
|
||||
|
||||
END of FIGURE 4a
|
||||
********************************************************* -]
|
||||
|
||||
This process may sound complicated, but everything happens transparently.
|
||||
As long as there are extra ECBs available, the application never knows
|
||||
they have been borrowed, since SPX puts them back in the exact same state
|
||||
they were in when they were pressed into service.
|
||||
|
||||
If the connection is established with the SPX watchdog enabled, the
|
||||
watchdog monitors the connection and notifies the application if the
|
||||
connection fails, even if the application is not currently sending data
|
||||
over the connection. This feature is useful for applications that start
|
||||
SPX connections, but use them infrequently. For simplicity, however, the
|
||||
example does not use the SPX watchdog.
|
||||
|
||||
After the listen ECBs have been posted, the connection ECB is then set up
|
||||
in much the same way the IPX send ECB was, except that this ECB has only
|
||||
one fragment: the SPX header. The destination network, node, and socket
|
||||
also are set the same way they were in the previous example.
|
||||
|
||||
SPXEstablishConnection() is passed a retry count of zero, indicating that
|
||||
you should use the default value for number of retries. This value is set
|
||||
in the workstation's NET.CFG file using the IPX RETRY COUNT parameter,
|
||||
which defaults to 20. The last zero passed in SPXEstablishConnection()
|
||||
indicates not to use the SPX watchdog. The SPX connection ID is returned
|
||||
as the third parameter. The SPX connection ID can be considered
|
||||
equivalent to the NetBIOS local session number.
|
||||
|
||||
Next, the sample code attempts to establish a connection. It polls the
|
||||
ECB's in use flag waiting for the event to complete. The
|
||||
IPXRelinquishControl() call is very important at this stage. If the code
|
||||
did nothing but sit in a tight loop, IPX and SPX would never get the
|
||||
chance to do any processing. IPXRelinquishControl() allows the IPX/SPX
|
||||
layer to get some work done.
|
||||
|
||||
Once the in use flag is set to zero, the example checks the return code
|
||||
to see if the attempt to establish a connection was successful. The code
|
||||
does not illustrate how to handle the various failure cases, but the most
|
||||
likely cause of a failure would be that the other side is not yet
|
||||
listening for a connection, just like in NetBIOS. After establishing the
|
||||
connection, packets can be sent to the remote station.
|
||||
|
||||
The SPXSendSequencedPacket() call requires much less information than its
|
||||
IPX counterpart. Since the connection is already established, all
|
||||
SPXSendSequencedPacket() needs is the SPX connection ID, an ESR address,
|
||||
and the fragment information.
|
||||
|
||||
After sending a packet, the example program waits for ten packets to
|
||||
arrive. When an ECB comes back, the example displays the data and then
|
||||
re-submits the ECB so that it can be used to receive a packet again.
|
||||
After receiving ten packets, it issues an SPXTerminateConnection() call
|
||||
to notify the other side that it is done.
|
||||
|
||||
The call to terminate the connection takes almost the same parameters
|
||||
that the establish connection call does, except that there is no need to
|
||||
fill out any information in the SPX header. Once the connection has been
|
||||
terminated, the pending listen ECBs must be cancelled. To do so, the
|
||||
example calls IPXCancelEvent(). Unlike most other ECB-related calls,
|
||||
IPXCancelEvent() does not return until the ECB has been cancelled so
|
||||
there is no need to poll the in use flag.
|
||||
|
||||
Event Service Routines
|
||||
|
||||
Event Service Routines (ESRs) serve the same purpose as the NetBIOS POST
|
||||
routines, but require a little more setup than the standard POST routine.
|
||||
Most ESRs are written in Assembly, although some call C functions.
|
||||
|
||||
Figure 5 shows a generic ESR that calls a C function after allocating its
|
||||
own stack. This is very important since the amount of free stack space
|
||||
(if any) at interrupt time is unknown, and any attempt by a C function to
|
||||
use the stack could result in memory corruption if the stack is
|
||||
overflowed. The only way to guarantee that this will not occur is to
|
||||
allocate sufficient stack space in the ESR.
|
||||
|
||||
*********************************************************
|
||||
Figure 5: Example Event Service Routine (ESR) [- C/ASM code -]
|
||||
|
||||
.MODEL LARGE
|
||||
|
||||
public _ReceiveESRHandler
|
||||
extrn _ProcessReceiveData:PROC
|
||||
|
||||
.DATA
|
||||
|
||||
; The stack segment and pointer must be saved so that you can set up
|
||||
; your own stack.
|
||||
|
||||
stk_seg dw 0 ; variable to store old stack segment
|
||||
stk_ptr dw 0 ; variable to store old stack pointer
|
||||
stk_stk dw 512 dup (0) ; new stack of 1024 bytes in length
|
||||
stk_end dw 0 ; the end of the stack
|
||||
|
||||
.CODE
|
||||
|
||||
; @datasize is TRUE if the model is MEDIUM or LARGE and FALSE if the
|
||||
; model is SMALL or COMPACT. Just modify the .MODEL ???? above for the
|
||||
; model you want. ES/SI holds the seg/offset of the currently used ECB
|
||||
; that ProcessReceivedData needs to process.
|
||||
|
||||
_ReceiveESRHandler PROC far
|
||||
mov ax,DGroup
|
||||
mov ds,ax
|
||||
mov stk_seg,ss ; Save the stack segment
|
||||
mov stk_ptr,sp ; Save the stack pointer
|
||||
mov ss,ax ; move the segment of new_stk into ss
|
||||
mov sp,offset stk_end ; move offset of new_stk to sp
|
||||
IF @datasize
|
||||
push es ; push es if mem. model medium/large
|
||||
ENDIF
|
||||
push si
|
||||
call _ProcessReceivedData
|
||||
mov ss,stk_seg ; Restore old stack segment
|
||||
mov sp,stk_ptr ; Restore old stack pointer
|
||||
retf
|
||||
_ReceiveESRHandler ENDP
|
||||
|
||||
END END of FIGURE 5
|
||||
*********************************************************
|
||||
|
||||
|
||||
[- *********************************************************
|
||||
Figure 5a: Example Event Service Routine (ESR) (BASM/Pascal)
|
||||
|
||||
{ The stack segment and pointer must be saved so that you can set up
|
||||
your own stack. }
|
||||
|
||||
Var stk_stk:array[1..512] of word; { new stack of 1024 bytes in length }
|
||||
stk_end:word; { the end of the stack }
|
||||
|
||||
{$F+}
|
||||
Procedure ESRhandler(Var p:Tpecb); { * Type TPecb=^Tecb }
|
||||
begin
|
||||
.
|
||||
.
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
{$F+}
|
||||
Procedure ListenESR; assembler;
|
||||
asm { ES:SI are the only valid registers when entering this procedure ! }
|
||||
mov dx, seg stk_stk { = seg @DATA }
|
||||
mov ds, dx
|
||||
|
||||
mov dx,ss { setup of a new local stack }
|
||||
mov bx,sp { ss:sp copied to dx:bx}
|
||||
mov ax,ds
|
||||
mov ss,ax
|
||||
mov sp,offset stk_end
|
||||
push dx { push old ss:sp on new stack }
|
||||
push bx
|
||||
push es { * push es:si on stack as local vars }
|
||||
push si { * }
|
||||
mov di,sp { * }
|
||||
push ss { * push address of local ptr on stack }
|
||||
push di { * }
|
||||
|
||||
CALL EsrHandler
|
||||
|
||||
add sp,4 { skip stack ptr-copy }
|
||||
pop bx { restore ss:sp from new stack }
|
||||
pop dx
|
||||
mov sp,bx
|
||||
mov ss,dx
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
Note that a local stack of 1024 bytes (512 words) may not be large
|
||||
enough for some applications calling other functions within the
|
||||
ESRhandler. Increase the stacksize by 1024 bytes at a time to
|
||||
determine the stack requirement.
|
||||
|
||||
|
||||
END END of FIGURE 5a
|
||||
********************************************************* -]
|
||||
|
||||
Figure 6 contains a code fragment demonstrating the use of an ESR. It
|
||||
receives ten SPX packets just like the example in Figure 3 does, but it
|
||||
uses an ESR instead of polling the in use flag. The assembly language
|
||||
routine from Figure 4 is declared as the ESR, and it in turn calls the
|
||||
C [-/Pascal-] function ProcessReceivedData().
|
||||
|
||||
*********************************************************
|
||||
Figure 6: Using an Event Service Routine (ESR) [- C Code -]
|
||||
|
||||
int packetCount = 0;
|
||||
|
||||
void ProcessReceivedData(ECB *ecb)
|
||||
{
|
||||
packetCount++;
|
||||
printf("%s\n", ecb->fragmentDescriptor[1].address);
|
||||
SPXListenForSequencedPacket(ecb); /* Re-issue the listen */
|
||||
}
|
||||
|
||||
main()
|
||||
{
|
||||
.
|
||||
. /* This code is identical to SPX setup code in Fig. 4, except */
|
||||
. /* for receive[i].ESRAddress line, which will be as follows: */
|
||||
|
||||
receive[i].ESRAddress = (void (far *) () ) ReceiveESRHandler;
|
||||
|
||||
.
|
||||
. /* The send ECB does not normally use an ESR. */
|
||||
.
|
||||
|
||||
while (packetCount < 10)
|
||||
IPXRelinquishControl();
|
||||
.
|
||||
. /* Shut down connection, cancel ECBs */
|
||||
.
|
||||
}
|
||||
|
||||
END of FIGURE 6
|
||||
*********************************************************
|
||||
|
||||
[- *********************************************************
|
||||
Figure 6a: Using an Event Service Routine (ESR) (Pascal)
|
||||
|
||||
Var PacketCount;
|
||||
|
||||
Procedure ProcessReceivedData(Var ECB:Tecb)
|
||||
begin
|
||||
inc(packetCount);
|
||||
writeln(string(ecb^.fragment[2].address^));
|
||||
SPXListenForSequencedPacket(ecb); { Re-issue the listen }
|
||||
end;
|
||||
|
||||
begin { main body }
|
||||
PacketCount:=0;
|
||||
|
||||
.
|
||||
. { This code is identical to SPX setup code in Fig. 4a, except }
|
||||
. { for receive[i].ESRAddress line, which will be as follows: }
|
||||
|
||||
receive[i].ESRAddress := @ReceiveESRHandler;
|
||||
.
|
||||
. { The send ECB does not normally use an ESR. }
|
||||
.
|
||||
|
||||
while (packetCount < 10)
|
||||
do IPXRelinquishControl;
|
||||
.
|
||||
. { Shut down connection, cancel ECBs }
|
||||
.
|
||||
end;
|
||||
|
||||
END of FIGURE 6a
|
||||
********************************************************* -]
|
||||
|
||||
IPX and SPX may look a little more complicated than NetBIOS at first, but
|
||||
as soon as you begin using these protocols, you see how similar they
|
||||
really are. Using IPX/SPX requires slightly more effort, but the
|
||||
performance and compatibility gains when running under NetWare more than
|
||||
compensate. If you are thinking about becoming more familiar with IPX and
|
||||
SPX development, feel free to contact Novell's Developer Support group at
|
||||
1-800-NETWARE (1-800-638-9273) or 1-801-429-5588.
|
||||
105
NWTP/XIPX/CHKVEND.PAS
Normal file
105
NWTP/XIPX/CHKVEND.PAS
Normal file
@@ -0,0 +1,105 @@
|
||||
program chkvend;
|
||||
{$I-}
|
||||
|
||||
{ Testprogram checking all nodes on all attached servers and
|
||||
showing the manifacturers of the corresponding ethernet cards. }
|
||||
|
||||
uses nwMisc,nwConn,nwServ;
|
||||
|
||||
var PleaseMail:Boolean;
|
||||
Path :string;
|
||||
|
||||
StationNbr : byte;
|
||||
StationAddress: TinternetworkAddress;
|
||||
Sinfo : TFileServerInformation;
|
||||
t,conn : byte;
|
||||
|
||||
ObjName :string;
|
||||
objType :word;
|
||||
ObjId :Longint;
|
||||
LoginTime:TnovTime;
|
||||
|
||||
s,ts,subs:string;
|
||||
f :text;
|
||||
fnd :boolean;
|
||||
p :byte;
|
||||
begin
|
||||
PleaseMail:=False;
|
||||
|
||||
Path:=ParamStr(0);
|
||||
while NOT (path[ord(path[0])] IN [':','\','/']) do dec(Path[0]);
|
||||
{Path now holds the name of the path where the chkvend.exe file is located }
|
||||
|
||||
assign(f,Path+'VEND_XXX.');
|
||||
reset(f);
|
||||
IF IOresult<>0
|
||||
then begin
|
||||
writeln('Couldn''t open VEND_XXX');
|
||||
writeln('<CHKVEND expects the file to in the same directory as the executable>');
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
{ Check all 8 possible server attchments }
|
||||
For conn:=1 to 8
|
||||
do begin
|
||||
SetPreferredConnectionId(conn);
|
||||
If IsConnectionIdInUse(conn)
|
||||
then begin
|
||||
GetFileServerInformation(Sinfo); { Get maximum number of conections }
|
||||
for t:=1 to Sinfo.ConnectionsMax
|
||||
do begin
|
||||
{ check all connections }
|
||||
IF GetInternetAddress(t,StationAddress)
|
||||
then begin
|
||||
GetConnectionInformation(t,objName,objType,ObjId,LoginTime);
|
||||
objname:=objName+' ';
|
||||
objName[0]:=#16;
|
||||
ts:=HexDumpStr(StationAddress.node,12);
|
||||
{ check file if vendor's code known }
|
||||
fnd:=False;
|
||||
reset(f);
|
||||
REPEAT
|
||||
readln(f,s);
|
||||
p:=pos('#',s);
|
||||
if p>0 then s[0]:=chr(p-1);
|
||||
p:=pos(' ',s);
|
||||
if p=0
|
||||
then suBs:=''
|
||||
else begin
|
||||
subS:=copy(s,1,p-1);
|
||||
if pos(subs,ts)=1
|
||||
then begin
|
||||
fnd:=true;
|
||||
writeln(ts,' ',objName,' -',s);
|
||||
end;
|
||||
end;
|
||||
|
||||
UNTIL eof(f) or fnd;
|
||||
|
||||
if (NOT fnd)
|
||||
then begin
|
||||
PleaseMail:=true;
|
||||
writeln(ts,' ',objname,' -????');
|
||||
end;
|
||||
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
IF PleaseMail
|
||||
then begin
|
||||
writeln;
|
||||
writeln('A number of unknown Vendor codes have been found.');
|
||||
writeln('If you know the vendor(s) of the Ethernet cards in question,');
|
||||
writeln('you can update the VEND_XXX. file with a text editor.');
|
||||
writeln;
|
||||
writeln('You are also kindly requested to mail the information to us.');
|
||||
writeln('Fido : 2:512/250.4064 or 2:2426/4030.13');
|
||||
writeln('InterNet: Rene.Spronk@p4064.f250.n512.z2.fidonet.org');
|
||||
writeln;
|
||||
end;
|
||||
|
||||
SetPreferredConnectionId(0);
|
||||
close(f);
|
||||
end.
|
||||
201
NWTP/XIPX/FGET.PAS
Normal file
201
NWTP/XIPX/FGET.PAS
Normal file
@@ -0,0 +1,201 @@
|
||||
{$X+,V-,B-,I-}
|
||||
program Fget; { Listening Process / receiver / Slave }
|
||||
|
||||
{ Testprogram for the nwPEP unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{$DEFINE noTRACE}
|
||||
|
||||
uses crt,nwMisc,nwIPX,nwPEP;
|
||||
|
||||
Var ListenECB :Tecb; { used to listen for packets }
|
||||
ListenPepHdr :TpepHeader;
|
||||
|
||||
SendECB :Tecb; { used to send acknowledgements }
|
||||
SendPepHdr :TpepHeader;
|
||||
|
||||
IOsocket :word;
|
||||
DataBuffer :array[1..546] of byte;
|
||||
SendDataBuffer:byte;
|
||||
|
||||
PacketReceived :Boolean;
|
||||
LastTransactionID:LongInt;
|
||||
|
||||
NewStack:array[1..8192] of word; { !! used by ESR }
|
||||
StackBottom:word; { !! used by ESR }
|
||||
|
||||
Procedure CheckError(err:boolean; errNbr:word);
|
||||
begin
|
||||
if err
|
||||
then begin
|
||||
CASE errNbr of
|
||||
$0100:writeln('IPX needs to be installed.');
|
||||
$0101:writeln('ERROR: Connection not established. A Timeout occured');
|
||||
$0102:writeln('ERROR: The transfer is aborted; A timeout occured.');
|
||||
$0108:writeln('Transfer aborted.');
|
||||
$0300:writeln('The supplied path doesn'' exist / no write rights in directory.');
|
||||
$0301:writeln('Error writing to file / no write rights in directory.');
|
||||
$10FE:writeln('Error opening socket: Socket Table Is Full.');
|
||||
$10FF:writeln('Error opening socket: Socket is already open.');
|
||||
else writeln('Unspecified error.');
|
||||
end; {case}
|
||||
IPXcloseSocket(IOsocket);
|
||||
halt(1);
|
||||
end;
|
||||
end;
|
||||
|
||||
Function TimeOut(t1,t2:word;n:byte):boolean;
|
||||
{ ticks t2 - ticks t1 > n seconds ? }
|
||||
Var lt1,lt2:LongInt;
|
||||
begin
|
||||
lt2:=t2;
|
||||
if t1>t2 then lt2:=lt2+$FFFF;
|
||||
TimeOut:=(lt2-t1)>(n*18);
|
||||
end;
|
||||
|
||||
{$F+}
|
||||
Procedure ListenAndAckHandler;
|
||||
begin
|
||||
If (ListenECB.CompletionCode<>0)
|
||||
or (ListenPepHdr.IPXhdr.packetType<>PEP_PACKET_TYPE)
|
||||
or (ListenPepHdr.clienttype<>$EA)
|
||||
or (ListenPepHdr.TransactionID<LastTransactionID) { discard dupe old packet }
|
||||
then IPXlistenForPacket(ListenECB)
|
||||
else begin
|
||||
PacketReceived:=(ListenPepHdr.transactionID>LastTransactionID); { new packet received }
|
||||
|
||||
{ Acknowledge new packets and duplicates of the latest packet, }
|
||||
{ as the original acknowledgement may have been lost. }
|
||||
LastTransactionID:=ListenPepHdr.TransactionID;
|
||||
|
||||
{ Setup acknowledgement ECB and PEPheader, and send it. }
|
||||
if SendECB.InUseFlag=0
|
||||
then begin
|
||||
ListenPepHdr.IPXhdr.source.socket:=swap(ListenPepHdr.IPXhdr.source.socket);
|
||||
{ socket is hi-lo in IPX/PEPHeaders. SetupSendECB expects lo-hi }
|
||||
PEPsetupSendECB(NIL,IOsocket,ListenPepHdr.IPXhdr.source,
|
||||
@SendDataBuffer,0,
|
||||
SendPepHdr,SendECB);
|
||||
SendPepHdr.TransactionId:=LastTransactionID;
|
||||
SendPepHdr.ClientType:=$EA;
|
||||
IPXsendPacket(SendECB);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
{$F+}
|
||||
Procedure ListenAndAckESR; assembler;
|
||||
asm
|
||||
mov dx, seg stackbottom
|
||||
mov ds, dx
|
||||
|
||||
mov dx,ss { setup of a new local stack }
|
||||
mov bx,sp { ss:sp copied to dx:bx}
|
||||
mov ax,ds
|
||||
mov ss,ax
|
||||
mov sp,offset stackbottom
|
||||
push dx { push old ss:sp on new stack }
|
||||
push bx
|
||||
CALL ListenAndAckHandler
|
||||
pop bx { restore ss:sp from new stack }
|
||||
pop dx
|
||||
mov sp,bx
|
||||
mov ss,dx
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
Var ticks,ticks2 :word;
|
||||
FileName:string;
|
||||
FileSize:LongInt;
|
||||
DirName:string;
|
||||
f:file;
|
||||
BytesToWrite,BytesWritten:word;
|
||||
|
||||
begin
|
||||
IpxInitialize;
|
||||
CheckError(nwIPX.result>0,$100);
|
||||
|
||||
If (pos('?',ParamStr(1))>0) or (paramcount>1)
|
||||
then begin
|
||||
writeln('Usage: FGET <directory>');
|
||||
writeln('-The File sent by FSEND on another workstation');
|
||||
writeln('will be copied to the supplied directory.');
|
||||
halt(1);
|
||||
end;
|
||||
If paramcount=1
|
||||
then DirName:=ParamStr(1)
|
||||
else DirName:='.';
|
||||
|
||||
IF NOT (DirName[ord(dirName[0])] IN [':','\'])
|
||||
then DirName:=DirName+'\';
|
||||
assign(f,DirName+'temp.$$$');
|
||||
rewrite(f,1);
|
||||
CheckError(IOresult<>0,$0300);
|
||||
close(f);
|
||||
|
||||
IOSocket:=$5678;
|
||||
IPXopenSocket(IOsocket,SHORT_LIVED_SOCKET);
|
||||
CheckError(nwIPX.result>0,$1000+nwIPX.result);
|
||||
|
||||
{ Setup of ECB and PepHeader, start listening for incoming packets. }
|
||||
LastTransactionID:=0;
|
||||
PacketReceived:=False;
|
||||
PEPSetupListenECB(Addr(ListenAndAckESR),IOsocket,@DataBuffer,546,
|
||||
ListenPepHdr,ListenECB);
|
||||
IPXListenForPacket(ListenECB);
|
||||
writeln('Waiting for FSEND to start sending.. (any key to abort)');
|
||||
|
||||
IPXGetIntervalMarker(ticks);
|
||||
REPEAT
|
||||
IPXrelinquishControl;
|
||||
IPXGetIntervalMarker(ticks2);
|
||||
CheckError(TimeOut(ticks,ticks2,130),$101);{ error if a timeout occurred }
|
||||
CheckError(Keypressed,$108);
|
||||
UNTIL PacketReceived;
|
||||
|
||||
writeln('Handshaking.. Initiating transfer process.');
|
||||
{$IFDEF TRACE}
|
||||
writeln('Received PacketID:',LastTransactionID);
|
||||
{$ENDIF}
|
||||
|
||||
{ do something with DataBuffer: the data that was just received. }
|
||||
{ the first packet contains the filename and filesize }
|
||||
Move(DataBuffer[1],FileName[0],15);
|
||||
Move(DataBuffer[16],FileSize,4);
|
||||
writeln('Receiving file ',FileName,', size: ',FileSize);
|
||||
|
||||
assign(f,DirName+filename);
|
||||
rewrite(f,1);
|
||||
BytesToWrite:=512;
|
||||
|
||||
REPEAT { Listen for remaining packets }
|
||||
Packetreceived:=false;
|
||||
|
||||
While SendECB.InuseFlag<>0
|
||||
do IPXrelinquishControl;
|
||||
|
||||
IPXListenForPacket(ListenECB);
|
||||
IPXGetIntervalMarker(ticks);
|
||||
Repeat
|
||||
IPXrelinquishControl;
|
||||
IPXGetIntervalMarker(ticks2);
|
||||
CheckError(TimeOut(ticks,ticks2,10),$102); { error if Timeout occurred }
|
||||
CheckError(Keypressed,$108);
|
||||
until PacketReceived;
|
||||
{$IFDEF TRACE}
|
||||
writeln('Received packet#:',LastTransactionID);
|
||||
{$ENDIF}
|
||||
|
||||
{ Write DataBuffer to disk. }
|
||||
IF FileSize<512
|
||||
then BytesToWrite:=FileSize;
|
||||
BlockWrite(f,DataBuffer,BytesToWrite,BytesWritten);
|
||||
CheckError(BytesToWrite<>BytesWritten,$0301);
|
||||
|
||||
FileSize:=FileSize-512;
|
||||
UNTIL (FileSize<=0); { entire file received }
|
||||
|
||||
writeln('Transfer complete.');
|
||||
IPXcloseSocket(IOsocket);
|
||||
close(f);
|
||||
end.
|
||||
255
NWTP/XIPX/FSEND.PAS
Normal file
255
NWTP/XIPX/FSEND.PAS
Normal file
@@ -0,0 +1,255 @@
|
||||
{$X+,V-,B-,I-}
|
||||
program Fsend; { Master / Sender }
|
||||
|
||||
{ Testprogram for the nwPEP unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{$DEFINE noTRACE}
|
||||
|
||||
uses dos,crt,nwMisc,nwBindry,nwConn,nwIPX,nwPEP;
|
||||
|
||||
CONST IOSocket=$5678; { socket to transmit/receive on }
|
||||
|
||||
Var ListenECB :Tecb; { ECB and header, to listen for acknowledgement }
|
||||
ListenPepHdr :TpepHeader;
|
||||
|
||||
SendECB :Tecb; { ECB and header, used to send the data }
|
||||
SendPepHdr :TpepHeader;
|
||||
|
||||
socket :word;
|
||||
|
||||
SendDataBuffer :array[1..546] of byte; { SendDataBufferfer for data to be sent }
|
||||
|
||||
ListenDataBuffer:array[1..8] of byte;
|
||||
|
||||
AckReceived :boolean; { set to true within the ListenForAckESR }
|
||||
|
||||
SendTransId :LongInt; { transactionID. This uniquely identifies
|
||||
the packet. The slave/receiver has to
|
||||
reply with the same transactionID in the
|
||||
header of the acknowledgement. Only if
|
||||
this number is the same as the transactioID
|
||||
of the sent packet, the pavket is considered
|
||||
successfully delivered. }
|
||||
|
||||
NewStack:array[1..1024] of word; { !! used by ESR }
|
||||
StackBottom:word; { !! used by ESR }
|
||||
|
||||
f:file;
|
||||
|
||||
|
||||
Procedure CheckError(err:boolean; errNbr:word);
|
||||
begin
|
||||
if err
|
||||
then begin
|
||||
writeln;
|
||||
CASE errNbr of
|
||||
$0100:writeln('IPX needs to be installed.');
|
||||
$0200:writeln('Error: can''t locate the spcified username.');
|
||||
$0201:begin
|
||||
writeln('The specified user has multiple connections.');
|
||||
writeln('This demonstation program doesn''t support multiple connections.');
|
||||
end;
|
||||
$0202:writeln('Error: can''t find the address of the supplied username.');
|
||||
$0204:writeln('Transfer aborted after 50 retries.');
|
||||
$0205:writeln('Key pressed: Transfer aborted.');
|
||||
$0206:writeln('The supplied file couldn''t be found. Please supply full path.');
|
||||
$0300:writeln('Error reading file.');
|
||||
$10FE:writeln('Error opening socket: Socket Table Is Full.');
|
||||
$10FF:writeln('Error opening socket: Socket is already open.');
|
||||
end; {case}
|
||||
IPXcloseSocket(IOsocket);
|
||||
close(f);
|
||||
halt(1);
|
||||
end;
|
||||
end;
|
||||
|
||||
Function TimeOut(t1,t2:word;n:byte):boolean;
|
||||
{ ticks t2 - ticks t1 > n seconds ? }
|
||||
Var lt1,lt2:LongInt;
|
||||
begin
|
||||
lt2:=t2;
|
||||
if t1>t2 then lt2:=lt2+$FFFF;
|
||||
TimeOut:=(lt2-t1)>(n*18);
|
||||
end;
|
||||
|
||||
|
||||
{$F+}
|
||||
Procedure ListenForAckHandler(Var p:TPecb);
|
||||
{ Interrupts are turned off -and should remain turned off- }
|
||||
begin
|
||||
IF (ListenECB.CompletionCode<>0) { packet must be suucessfully received.. }
|
||||
or (ListenPepHdr.IPXhdr.packetType<>PEP_PACKET_TYPE) { of type PEP.. }
|
||||
or (ListenPepHdr.ClientType<>$EA) { of client type $EA }
|
||||
or (ListenPepHdr.TransactionID<>SendTransId) { with a correct clientID (of the packet the master sent) }
|
||||
then IPXListenForPacket(ListenECB) { Invalid packet => listen again }
|
||||
else AckReceived:=true; { valid packet => ACK received ! }
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
{$F+}
|
||||
Procedure ListenForAckESR; assembler;
|
||||
asm { ES:SI are the only valid registers when entering this procedure ! }
|
||||
{ interrupts are turned off -and should remain turned off- }
|
||||
mov dx, seg stackbottom
|
||||
mov ds, dx
|
||||
|
||||
mov dx,ss { setup of a new local stack }
|
||||
mov bx,sp { ss:sp copied to dx:bx}
|
||||
mov ax,ds
|
||||
mov ss,ax
|
||||
mov sp,offset stackbottom
|
||||
push dx { push old ss:sp on new stack }
|
||||
push bx
|
||||
|
||||
push es { push es:si on stack as local vars }
|
||||
push si
|
||||
mov di,sp
|
||||
|
||||
push ss { push address of local ptr on stack }
|
||||
push di
|
||||
CALL ListenForAckHandler
|
||||
|
||||
add sp,4 { skip stack ptr-copy }
|
||||
pop bx { restore ss:sp from new stack }
|
||||
pop dx
|
||||
mov sp,bx
|
||||
mov ss,dx
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
|
||||
Var dest:TinternetworkAddress;
|
||||
ticks,ticks2:word;
|
||||
retries :word;
|
||||
|
||||
Uname,Fname:string;
|
||||
NbrOfConn:byte;
|
||||
connList:TconnectionList;
|
||||
|
||||
p:byte;
|
||||
FileInfo:searchrec;
|
||||
FileSize:LongInt;
|
||||
BytesRead:word;
|
||||
|
||||
TransferStartTicks,TransferEndTicks:word;
|
||||
OriginalFileSize:LongInt;
|
||||
|
||||
begin
|
||||
If paramcount<>2
|
||||
then begin
|
||||
writeln('Usage: FSEND <username> <filename>');
|
||||
writeln('-The file will be sent to the workstation of the supplied username.');
|
||||
writeln('-Run FGET on that workstation to receive the file.');
|
||||
halt(1);
|
||||
end;
|
||||
Uname:=ParamStr(1);
|
||||
UpString(Uname);
|
||||
NbrOfConn:=0;
|
||||
GetObjectConnectionNumbers(Uname,OT_USER,NbrOfConn,connList);
|
||||
CheckError((nwConn.result>0) or (NbrOfConn=0),$200);
|
||||
CheckError(NbrOfConn>1,$0201);
|
||||
|
||||
GetInternetAddress(connList[1],dest);
|
||||
CheckError(nwconn.result>0,$0202);
|
||||
dest.socket:=IOsocket;
|
||||
|
||||
Fname:=ParamStr(2);
|
||||
Assign(f,Fname);
|
||||
Reset(f,1);
|
||||
CheckError(IOresult<>0,$0206);
|
||||
|
||||
|
||||
IpxInitialize;
|
||||
CheckError(nwIPX.result>0,$0100);
|
||||
|
||||
socket:=IOSocket;
|
||||
IPXopenSocket(Socket,SHORT_LIVED_SOCKET);
|
||||
CheckError(nwIPX.result>0,$1000+nwIPX.result);
|
||||
|
||||
{ setup listening for ack }
|
||||
AckReceived:=False;
|
||||
|
||||
PEPsetupListenECB(Addr(ListenForAckESR),IOsocket,@ListenDataBuffer,8,
|
||||
ListenPepHdr,ListenECB);
|
||||
IPXListenForPacket(ListenECB);
|
||||
|
||||
{ send initial packet with the name and size of the file to be sent. }
|
||||
findfirst(Fname,$FF,FileInfo);
|
||||
Move(FileInfo.size,SendDataBuffer[16],4);
|
||||
FileSize:=Fileinfo.size;
|
||||
p:=length(Fname);
|
||||
while (p>0) and (Fname[p]<>':') and (Fname[p]<>'\')
|
||||
do dec(p);
|
||||
If p>0
|
||||
then delete (Fname,1,p);
|
||||
Move(Fname[0],SendDataBuffer[1],15);
|
||||
|
||||
PEPsetupSendECB(NIL,IOsocket,dest,@SendDataBuffer[1],512,
|
||||
SendPepHdr,SendECB);
|
||||
SendTransID:=1;
|
||||
SendPepHdr.ClientType:=$EA;
|
||||
|
||||
OriginalFileSize:=FileSize;
|
||||
FileSize:=FileSize+512; { compensate length for information header }
|
||||
|
||||
writeln('FSEND waiting for remote handshake. (any key to abort)');
|
||||
|
||||
While Filesize>0
|
||||
do begin
|
||||
ackreceived:=false;
|
||||
SendPepHdr.TransactionId:=SendTransId;
|
||||
IPXsendPacket(SendECB);
|
||||
{$IFDEF TRACE}
|
||||
write('Packet#',SendTransID,' sent.');
|
||||
{$ENDIF}
|
||||
while sendECB.InuseFlag<>0
|
||||
do IPXrelinquishControl;
|
||||
|
||||
IPXGetIntervalMarker(ticks);
|
||||
retries:=0;
|
||||
REPEAT
|
||||
IPXrelinquishcontrol;
|
||||
IPXGetIntervalMarker(ticks2);
|
||||
if (ticks2-ticks)>2
|
||||
then begin
|
||||
inc(retries);
|
||||
{$IFDEF TRACE}
|
||||
writeln;
|
||||
write('Timeout: resending packet#',SendTransID);
|
||||
{$ENDIF}
|
||||
IPXsendPacket(SendECB);
|
||||
while sendECB.InuseFlag<>0
|
||||
do IPXrelinquishControl;
|
||||
IPXGetIntervalMarker(ticks);
|
||||
end;
|
||||
CheckError(retries>50,$0204);
|
||||
CheckError(Keypressed,$0205);
|
||||
UNTIL AckReceived;
|
||||
if SendTransID=1
|
||||
then begin
|
||||
writeln('Handshake received. Starting file transfer.');
|
||||
IPXGetIntervalMarker(TransferStartTicks);
|
||||
end;
|
||||
{$IFDEF TRACE}
|
||||
writeln(' Ackn.#',ListenPepHdr.TransactionID,' received.');
|
||||
{$ENDIF}
|
||||
FileSize:=FileSize-512;
|
||||
|
||||
{ fill buffer with next block of data }
|
||||
IF FileSize>0
|
||||
then begin
|
||||
BlockRead(f,SendDataBuffer,512,bytesread);
|
||||
CheckError((bytesread<512) and (filesize<>bytesread),$0300);
|
||||
end;
|
||||
|
||||
inc(SendTransID);
|
||||
IPXListenForPacket(ListenECB); { start listening for acks again }
|
||||
end;
|
||||
IPXGetIntervalMarker(TransferEndTicks);
|
||||
IPXcancelEvent(ListenECB);
|
||||
Writeln('Transfer completed.');
|
||||
writeln('Throughput: ', 18*OriginalFileSize/(TransferEndTicks-TransferStartTicks):4:2,' bps');
|
||||
IPXcloseSocket(IOsocket);
|
||||
close(f);
|
||||
|
||||
end.
|
||||
230
NWTP/XIPX/M1_PEP.PAS
Normal file
230
NWTP/XIPX/M1_PEP.PAS
Normal file
@@ -0,0 +1,230 @@
|
||||
{$X+,V-,B-,I-}
|
||||
program M1_PEP; { Master / Sender }
|
||||
|
||||
{ Testprogram for the nwPEP unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
uses dos,crt,nwMisc,nwBindry,nwConn,nwIPX,nwPEP;
|
||||
|
||||
CONST IOSocket=$5678; { socket to transmit/receive on }
|
||||
|
||||
Var ListenECB :Tecb; { ECB and header, to listen for acknowledgement }
|
||||
ListenPepHdr :TpepHeader;
|
||||
|
||||
SendECB :Tecb; { ECB and header, used to send the data }
|
||||
SendPepHdr :TpepHeader;
|
||||
|
||||
socket :word;
|
||||
|
||||
SendDataBuffer :array[1..546] of byte; { SendDataBufferfer for data to be sent }
|
||||
|
||||
ListenDataBuffer:array[1..8] of byte;
|
||||
|
||||
AckReceived :boolean; { set to true within the ListenForAckESR }
|
||||
|
||||
SendTransId :LongInt; { transactionID. This uniquely identifies
|
||||
the packet. The slave/receiver has to
|
||||
reply with the same transactionID in the
|
||||
header of the acknowledgement. Only if
|
||||
this number is the same as the transactioID
|
||||
of the sent packet, the pavket is considered
|
||||
successfully delivered. }
|
||||
|
||||
NewStack:array[1..1024] of word; { !! used by ESR }
|
||||
StackBottom:word; { !! used by ESR }
|
||||
|
||||
f:file;
|
||||
|
||||
|
||||
Procedure CheckError(err:boolean; errNbr:word);
|
||||
begin
|
||||
if err
|
||||
then begin
|
||||
CASE errNbr of
|
||||
$0100:writeln('IPX needs to be installed.');
|
||||
$0200:writeln('Error: can''t locate the spcified username.');
|
||||
$0201:begin
|
||||
writeln('The specified user has multiple connections.');
|
||||
writeln('This demonstation program doesn''t support multiple connections.');
|
||||
end;
|
||||
$0202:writeln('Error: can''t find the address of the supplied username.');
|
||||
$0204:writeln('Transfer aborted after 50 retries.');
|
||||
$0205:writeln('Key pressed: Transfer aborted.');
|
||||
$0206:writeln('The supplied file couldn''t be found. Please supply full path.');
|
||||
$10FE:writeln('Error opening socket: Socket Table Is Full.');
|
||||
$10FF:writeln('Error opening socket: Socket is already open.');
|
||||
end; {case}
|
||||
IPXcloseSocket(IOsocket);
|
||||
close(f);
|
||||
halt(1);
|
||||
end;
|
||||
end;
|
||||
|
||||
Function TimeOut(t1,t2:word;n:byte):boolean;
|
||||
{ ticks t2 - ticks t1 > n seconds ? }
|
||||
Var lt1,lt2:LongInt;
|
||||
begin
|
||||
lt2:=t2;
|
||||
if t1>t2 then lt2:=lt2+$FFFF;
|
||||
TimeOut:=(lt2-t1)>(n*18);
|
||||
end;
|
||||
|
||||
|
||||
{$F+}
|
||||
Procedure ListenForAckHandler(Var p:TPecb);
|
||||
{ Interrupts are turned off -and should remain turned off- }
|
||||
begin
|
||||
IF (ListenECB.CompletionCode<>0) { packet must be suucessfully received.. }
|
||||
or (ListenPepHdr.IPXhdr.packetType<>PEP_PACKET_TYPE) { of type PEP.. }
|
||||
or (ListenPepHdr.ClientType<>$EA) { of client type $EA }
|
||||
or (ListenPepHdr.TransactionID<>SendTransId) { with a correct clientID (of the packet the master sent) }
|
||||
then IPXListenForPacket(ListenECB) { Invalid packet => listen again }
|
||||
else AckReceived:=true; { valid packet => ACK received ! }
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
{$F+}
|
||||
Procedure ListenForAckESR; assembler;
|
||||
asm { ES:SI are the only valid registers when entering this procedure ! }
|
||||
{ interrupts are turned off -and should remain turned off- }
|
||||
mov dx, seg stackbottom
|
||||
mov ds, dx
|
||||
|
||||
mov dx,ss { setup of a new local stack }
|
||||
mov bx,sp { ss:sp copied to dx:bx}
|
||||
mov ax,ds
|
||||
mov ss,ax
|
||||
mov sp,offset stackbottom
|
||||
push dx { push old ss:sp on new stack }
|
||||
push bx
|
||||
|
||||
push es { push es:si on stack as local vars }
|
||||
push si
|
||||
mov di,sp
|
||||
|
||||
push ss { push address of local ptr on stack }
|
||||
push di
|
||||
CALL ListenForAckHandler
|
||||
|
||||
add sp,4 { skip stack ptr-copy }
|
||||
pop bx { restore ss:sp from new stack }
|
||||
pop dx
|
||||
mov sp,bx
|
||||
mov ss,dx
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
|
||||
Var dest:TinternetworkAddress;
|
||||
ticks,ticks2:word;
|
||||
retries :word;
|
||||
|
||||
Uname,Fname:string;
|
||||
NbrOfConn:byte;
|
||||
connList:TconnectionList;
|
||||
|
||||
p:byte;
|
||||
FileInfo:searchrec;
|
||||
FileSize:LongInt;
|
||||
|
||||
begin
|
||||
If paramcount<>2
|
||||
then begin
|
||||
writeln('Usage: M1_PEP <username> <filename>');
|
||||
writeln('-The file will be sent to the workstation of the supplied username.');
|
||||
writeln('-Run S1_PEP on that workstation to receive the file.');
|
||||
halt(1);
|
||||
end;
|
||||
Uname:=ParamStr(1);
|
||||
UpString(Uname);
|
||||
NbrOfConn:=0;
|
||||
GetObjectConnectionNumbers(Uname,OT_USER,NbrOfConn,connList);
|
||||
CheckError((nwConn.result>0) or (NbrOfConn=0),$200);
|
||||
CheckError(NbrOfConn>1,$0201);
|
||||
|
||||
GetInternetAddress(connList[1],dest);
|
||||
CheckError(nwconn.result>0,$0202);
|
||||
dest.socket:=IOsocket;
|
||||
|
||||
Fname:=ParamStr(2);
|
||||
Assign(f,Fname);
|
||||
Reset(f);
|
||||
CheckError(IOresult<>0,$0206);
|
||||
|
||||
|
||||
IpxInitialize;
|
||||
CheckError(nwIPX.result>0,$0100);
|
||||
|
||||
socket:=IOSocket;
|
||||
IPXopenSocket(Socket,SHORT_LIVED_SOCKET);
|
||||
CheckError(nwIPX.result>0,$1000+nwIPX.result);
|
||||
|
||||
{ setup listening for ack }
|
||||
AckReceived:=False;
|
||||
|
||||
PEPsetupListenECB(Addr(ListenForAckESR),IOsocket,@ListenDataBuffer,8,
|
||||
ListenPepHdr,ListenECB);
|
||||
IPXListenForPacket(ListenECB);
|
||||
|
||||
{ send initial packet with the name and size of the file to be sent. }
|
||||
findfirst(Fname,$FF,FileInfo);
|
||||
Move(FileInfo.size,SendDataBuffer[16],4);
|
||||
FileSize:=Fileinfo.size;
|
||||
p:=length(Fname);
|
||||
while (p>0) and (Fname[p]<>':') and (Fname[p]<>'\')
|
||||
do dec(p);
|
||||
If p>0
|
||||
then delete (Fname,1,p);
|
||||
Move(Fname[0],SendDataBuffer[1],15);
|
||||
|
||||
PEPsetupSendECB(NIL,IOsocket,dest,@SendDataBuffer[1],512,
|
||||
SendPepHdr,SendECB);
|
||||
SendTransID:=1;
|
||||
SendPepHdr.ClientType:=$EA;
|
||||
|
||||
FileSize:=FileSize+512; { compensate length for information header }
|
||||
|
||||
While Filesize>0
|
||||
do begin
|
||||
ackreceived:=false;
|
||||
SendPepHdr.TransactionId:=SendTransId;
|
||||
IPXsendPacket(SendECB);
|
||||
writeln('Packet#',SendTransID,' was sent.');
|
||||
while sendECB.InuseFlag<>0
|
||||
do IPXrelinquishControl;
|
||||
|
||||
|
||||
IPXGetIntervalMarker(ticks);
|
||||
retries:=0;
|
||||
REPEAT
|
||||
IPXrelinquishcontrol;
|
||||
IPXGetIntervalMarker(ticks2);
|
||||
if (ticks2-ticks)>2
|
||||
then begin
|
||||
inc(retries);
|
||||
writeln('Timeout: resending pkt#',SendTransID);
|
||||
PEPsetupSendECB(NIL,IOsocket,dest,@SendDataBuffer[1],512,
|
||||
SendPepHdr,SendECB);
|
||||
SendPepHdr.ClientType:=$EA;
|
||||
SendPepHdr.TransactionId:=SendTransId;
|
||||
IPXsendPacket(SendECB);
|
||||
while sendECB.InuseFlag<>0
|
||||
do IPXrelinquishControl;
|
||||
IPXGetIntervalMarker(ticks);
|
||||
end;
|
||||
CheckError(retries>50,$0204);
|
||||
CheckError(Keypressed,$0205);
|
||||
UNTIL AckReceived;
|
||||
writeln('Ack ',ListenPepHdr.TransactionID,' was received.');
|
||||
|
||||
FileSize:=FileSize-512;
|
||||
inc(SendTransID);
|
||||
{XXX fill buffer met volgende fileblock }
|
||||
|
||||
|
||||
IPXListenForPacket(ListenECB); { start listening for acks again }
|
||||
end;
|
||||
|
||||
IPXcloseSocket(IOsocket);
|
||||
close(f);
|
||||
|
||||
end.
|
||||
176
NWTP/XIPX/M_PEP.PAS
Normal file
176
NWTP/XIPX/M_PEP.PAS
Normal file
@@ -0,0 +1,176 @@
|
||||
{$X+,V-,B-}
|
||||
program M_PEP; { Master / Sender }
|
||||
|
||||
{ Testprogram for the nwPEP unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Sents a single packet, waits for acknowledgement }
|
||||
|
||||
uses crt,nwMisc,nwBindry,nwConn,nwIPX,nwPEP;
|
||||
|
||||
CONST IOSocket=$5678; { socket to transmit/receive on }
|
||||
|
||||
Var ListenECB :Tecb; { ECB and header, to listen for acknowledgement }
|
||||
ListenPepHdr :TpepHeader;
|
||||
|
||||
SendECB :Tecb; { ECB and header, used to send the data }
|
||||
SendPepHdr :TpepHeader;
|
||||
|
||||
socket :word;
|
||||
|
||||
buf :array[1..546] of byte; { buffer for data to be sent }
|
||||
|
||||
AckReceived :boolean; { set to true within the ListenForAckESR }
|
||||
|
||||
SendTransId :LongInt; { transactionID. This uniquely identifies
|
||||
the packet. The slave/receiver has to
|
||||
reply with the same transactionID in the
|
||||
header of the acknowledgement. Only if
|
||||
this number is the same as the transactioID
|
||||
of the sent packet, the pavket is considered
|
||||
successfully delivered. }
|
||||
|
||||
NewStack:array[1..1024] of word; { !! used by ESR }
|
||||
StackBottom:word; { !! used by ESR }
|
||||
|
||||
|
||||
{$F+}
|
||||
Procedure ListenForAckHandler(Var p:TPecb);
|
||||
{ Interrupts are turned off -and should remain turned off- }
|
||||
begin
|
||||
IF (ListenECB.CompletionCode<>0) { packet must be suucessfully received.. }
|
||||
or (ListenPepHdr.IPXhdr.packetType<>PEP_PACKET_TYPE) { of type PEP.. }
|
||||
or (ListenPepHdr.ClientType<>$EA) { of client type $EA }
|
||||
or (ListenPepHdr.TransactionID<>SendTransId) { with a correct clientID (of the packet the master sent) }
|
||||
then IPXListenForPacket(ListenECB) { Invalid packet => listen again }
|
||||
else AckReceived:=true; { valid packet => ACK received ! }
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
{$F+}
|
||||
Procedure ListenForAckESR; assembler;
|
||||
asm { ES:SI are the only valid registers when entering this procedure ! }
|
||||
{ interrupts are turned off -and should remain turned off- }
|
||||
mov dx, seg stackbottom
|
||||
mov ds, dx
|
||||
|
||||
mov dx,ss { setup of a new local stack }
|
||||
mov bx,sp { ss:sp copied to dx:bx}
|
||||
mov ax,ds
|
||||
mov ss,ax
|
||||
mov sp,offset stackbottom
|
||||
push dx { push old ss:sp on new stack }
|
||||
push bx
|
||||
|
||||
push es { push es:si on stack as local vars }
|
||||
push si
|
||||
mov di,sp
|
||||
|
||||
push ss { push address of local ptr on stack }
|
||||
push di
|
||||
CALL ListenForAckHandler
|
||||
|
||||
add sp,4 { skip stack ptr-copy }
|
||||
pop bx { restore ss:sp from new stack }
|
||||
pop dx
|
||||
mov sp,bx
|
||||
mov ss,dx
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
|
||||
Var dest:TinternetworkAddress;
|
||||
ticks,ticks2:word;
|
||||
retries :word;
|
||||
|
||||
Uname:string;
|
||||
NbrOfConn:byte;
|
||||
connList:TconnectionList;
|
||||
|
||||
begin
|
||||
If paramcount<>1
|
||||
then begin
|
||||
writeln('Usage: M_PEP <username>');
|
||||
writeln('-a test pep packet will be sent to the workstation of this user.');
|
||||
writeln('-run S_PEP on that workstation to receive the packet.');
|
||||
halt(1);
|
||||
end;
|
||||
Uname:=ParamStr(1);
|
||||
UpString(Uname);
|
||||
NbrOfConn:=0;
|
||||
IF (NOT GetObjectConnectionNumbers(Uname,OT_USER,NbrOfConn,connList))
|
||||
or (NbrOfConn=0)
|
||||
then begin
|
||||
writeln('Error: can''t locate user ',Uname);
|
||||
halt(1);
|
||||
end;
|
||||
IF NbrOfConn>1
|
||||
then begin
|
||||
writeln('The specified user has multiple connections.');
|
||||
writeln('This demonstation program doesn''t support multiple connections.');
|
||||
halt(1);
|
||||
end;
|
||||
IF NOT GetInternetAddress(connList[1],dest)
|
||||
then begin
|
||||
writeln('Error: can''t find the address of user ',Uname);
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
|
||||
IF NOT IpxInitialize
|
||||
then begin
|
||||
writeln('Ipx needs to be installed.');
|
||||
halt(1);
|
||||
end;
|
||||
socket:=IOSocket;
|
||||
IF NOT IPXopenSocket(Socket,SHORT_LIVED_SOCKET)
|
||||
then begin
|
||||
writeln('IPXopenSocket returned error# ',nwIPX.result);
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
|
||||
{ setup listening for ack }
|
||||
AckReceived:=False;
|
||||
FillChar(buf,546,#0);
|
||||
{ Setup ECB and IPX header }
|
||||
PEPsetupListenECB(Addr(ListenForAckESR),IOsocket,@buf,546,
|
||||
ListenPepHdr,ListenECB);
|
||||
IPXListenForPacket(ListenECB);
|
||||
|
||||
{ send packet }
|
||||
|
||||
dest.socket:=IOsocket;
|
||||
buf[1]:=ord('s');buf[2]:=ord('m');
|
||||
PEPsetupSendECB(NIL,IOsocket,dest,@buf[1],2,
|
||||
SendPepHdr,SendECB);
|
||||
SendTransID:=1;
|
||||
SendPepHdr.TransactionId:=SendTransId;
|
||||
SendPepHdr.ClientType:=$EA;
|
||||
IPXsendPacket(SendECB);
|
||||
writeln('Packet was sent.');
|
||||
while sendECB.InuseFlag<>0 do IPXrelinquishControl;
|
||||
IPXGetIntervalMarker(ticks);
|
||||
|
||||
{ wait for acknowledgement or timeout }
|
||||
retries:=0;
|
||||
|
||||
REPEAT
|
||||
IPXrelinquishcontrol;
|
||||
IPXGetIntervalMarker(ticks2);
|
||||
if (ticks2-ticks)>4
|
||||
then begin
|
||||
inc(retries);
|
||||
writeln('Timeout: resending');
|
||||
IPXsendPacket(SendECB);
|
||||
while sendECB.InuseFlag<>0 do IPXrelinquishControl;
|
||||
IPXGetIntervalMarker(ticks);
|
||||
end;
|
||||
UNTIL AckReceived or Keypressed or (retries>50);
|
||||
|
||||
if AckReceived
|
||||
then writeln('Ack was received.');
|
||||
|
||||
IF NOT IPXcloseSocket(IOsocket)
|
||||
then writeln('IPXcloseSocket returned error# ',nwIPX.result);
|
||||
|
||||
end.
|
||||
97
NWTP/XIPX/NWPEP.PAS
Normal file
97
NWTP/XIPX/NWPEP.PAS
Normal file
@@ -0,0 +1,97 @@
|
||||
{$B-,V-,X+}
|
||||
UNIT nwPEP;
|
||||
|
||||
{ nwPEP unit as of 950301 / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
INTERFACE
|
||||
|
||||
Uses Dos,nwIPX,nwMisc;
|
||||
|
||||
{ Primary IPX calls: Subf: Comments:
|
||||
|
||||
Secondary calls:
|
||||
|
||||
PEPsetupSendECB
|
||||
PEPsetupListenECB
|
||||
|
||||
}
|
||||
|
||||
Var Result:word; { unit errorcode variable }
|
||||
|
||||
Type TpepHeader=Record
|
||||
IPXhdr :TipxHeader; { set packettype to $04 }
|
||||
TransactionID:Longint;
|
||||
clientType :word;
|
||||
end;
|
||||
|
||||
Procedure PEPSetupListenECB(ESRptr:Pointer; ReceiveSocket:word;
|
||||
BufPtr:Pointer; BufSize:word;
|
||||
{out:} Var PepHdr:TpepHeader; Var ecb:Tecb);
|
||||
{ Clears IPXheader and ECB, sets values of the required fields within
|
||||
the ecb and IPX header. }
|
||||
|
||||
Procedure PEPSetupSendECB(ESRptr:pointer; SourceSocket:word;
|
||||
DestAddr:TinterNetworkAddress;
|
||||
BufPtr:pointer; BufSize:word;
|
||||
{out:} Var PepHdr:TpepHeader; Var ecb:Tecb);
|
||||
{ Clears IPXheader and ECB, sets values of the required fields within
|
||||
the ecb and IPX header. }
|
||||
|
||||
IMPLEMENTATION {==============================================================}
|
||||
|
||||
Procedure PEPSetupListenECB(ESRptr:Pointer;ReceiveSocket:word;
|
||||
BufPtr:Pointer;BufSize:word;
|
||||
{out:} Var PepHdr:TpepHeader; Var ecb:Tecb);
|
||||
{ Clears IPXheader and ECB, sets values of the required fields within
|
||||
the ecb and IPX header. }
|
||||
{ ECB: ESR adress field, socket number, fragment count, frag.descriptor fields }
|
||||
begin
|
||||
FillChar(ecb,SizeOf(Tecb),#0);
|
||||
FillChar(pepHdr,SizeOF(TpepHeader),#0);
|
||||
WITH ECB
|
||||
do begin
|
||||
if ESRptr<>NIL
|
||||
then ESRaddress:=ESRptr;
|
||||
Fragmentcount:=2;
|
||||
socketNumber:=swap(ReceiveSocket); {hi-lo}
|
||||
|
||||
Fragment[1].Address:=@pepHdr;
|
||||
Fragment[2].Address:=BufPtr;
|
||||
Fragment[1].size:=SizeOf(Tpepheader);
|
||||
Fragment[2].size:=BufSize;
|
||||
end;
|
||||
end;
|
||||
|
||||
Procedure PEPsetupSendECB(ESRptr:pointer; SourceSocket:word;
|
||||
DestAddr:TinterNetworkAddress;
|
||||
BufPtr:pointer; BufSize:word;
|
||||
{out:} Var PepHdr:TpepHeader; Var ecb:Tecb);
|
||||
{ Clears IPXheader and ECB, sets values of the required fields within
|
||||
the ecb and IPX header. }
|
||||
Var ImmAddr:TnodeAddress;
|
||||
Ticks:word;
|
||||
begin
|
||||
fillchar(pepHdr,SizeOf(TpepHeader),#0);
|
||||
with pepHdr.IPXhdr
|
||||
do begin
|
||||
PacketType:=PEP_PACKET_TYPE;
|
||||
Move(DestAddr,Destination,10);
|
||||
destination.socket:=swap(DestAddr.socket); {hi-lo}
|
||||
end;
|
||||
IPXGetLocalTarget(DestAddr,ImmAddr,Ticks);
|
||||
fillchar(ecb,sizeOf(ecb),#0);
|
||||
With ecb
|
||||
do begin
|
||||
if ESRptr<>NIL
|
||||
then ESRaddress:=ESRptr;
|
||||
socketNumber:=swap(SourceSocket); {hi-lo}
|
||||
Move(ImmAddr,ImmediateAddress,6);
|
||||
FragmentCount:=2;
|
||||
fragment[1].Address:=@pephdr;
|
||||
fragment[1].size:=SizeOf(TpepHeader);
|
||||
fragment[2].Address:=BufPtr;
|
||||
fragment[2].size:=BufSize;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
152
NWTP/XIPX/NWRIP.PAS
Normal file
152
NWTP/XIPX/NWRIP.PAS
Normal file
@@ -0,0 +1,152 @@
|
||||
Unit NwRIP;
|
||||
|
||||
{ NwTP Version 0.6, Copyright 1993,1994 R. Spronk
|
||||
|
||||
WARNING: Test your program thoroughly if you're using nwRip functions.
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Using the RIP functionality the wrong way may very well result in
|
||||
aborting servers ! (no kidding.)
|
||||
|
||||
As far as I know the diagnostic RIP function(s) included in this unit
|
||||
are perfectly safe to use.
|
||||
|
||||
Based on:
|
||||
|
||||
-GETALL, written in C by Barry Lagerweij of 2:2802/110.2
|
||||
posted in the Fido NOVELL area on Tue 7 Sep 93 0:36.
|
||||
-GETRIP, written in C by Koos van den Hout of 2:500/101.11012
|
||||
last updated 8 Feb 93 }
|
||||
|
||||
INTERFACE
|
||||
|
||||
Uses nwMisc,nwIPX;
|
||||
|
||||
CONST ECB_COUNT=10;
|
||||
{ assumption : 10 receiveECBs are used, which means a max of 500 networks }
|
||||
|
||||
{ Type definitions for RIP request/response structures}
|
||||
type TRIPentry=record
|
||||
network:TnetworkAddress;
|
||||
hops :word;
|
||||
ticks :word;
|
||||
end;
|
||||
|
||||
TRIPanswerPacket=record
|
||||
operation:word;
|
||||
entry :array[1..50] of TRIPEntry;
|
||||
end;
|
||||
|
||||
TRIPinfo=array[1..50*ECB_COUNT] of record
|
||||
address:TnetworkAddress;
|
||||
hops :byte;
|
||||
Ticks :word;
|
||||
end;
|
||||
|
||||
Function GetAllNetworks(SegmentNetworkAddress:TnetworkAddress;
|
||||
Var NetInfo:TRIPinfo):word;
|
||||
{SegmentNetworkAddress: The target network whose routers
|
||||
will be queried. Set to all zeroes (00 00 00 00)
|
||||
if querying your own segment.
|
||||
NetInfo : the buffer where the network-info is stored.
|
||||
Returns : the number of known networks.
|
||||
|
||||
Assumed is that IPXInitialize is already called. }
|
||||
|
||||
IMPLEMENTATION {===========================================================}
|
||||
|
||||
Function GetAllNetworks(SegmentNetworkAddress:TnetworkAddress;
|
||||
Var NetInfo:TRIPinfo):word;
|
||||
Var
|
||||
RIPrequest :TRIPanswerPacket;
|
||||
RIPanswer :array[1..ECB_COUNT] of TRIPanswerPacket;
|
||||
RequestEcb :Tecb;
|
||||
RequestIPXheader:TipxHeader;
|
||||
ReplyECB :array[1..ECB_COUNT] of Tecb;
|
||||
ReplyIPX :array[1..ECB_COUNT] of TipxHeader;
|
||||
Target :TinternetworkAddress;
|
||||
Sourcesocket :word;
|
||||
RIPsocket :word;
|
||||
|
||||
NumberOfNets :word;
|
||||
cnt :word;
|
||||
n :word;
|
||||
RoutableNetworks:word;
|
||||
timer1,timer2:word;
|
||||
|
||||
Begin
|
||||
RIPsocket:=$0453;
|
||||
|
||||
SourceSocket:=0;
|
||||
{ open socket for receiving the RIP packets }
|
||||
IF NOT IPXopenSocket(SourceSocket,SHORT_LIVED_SOCKET)
|
||||
then begin
|
||||
result:=nwIPX.result;
|
||||
GetAllnetworks:=0;
|
||||
exit;
|
||||
end;
|
||||
|
||||
{set-up sendpacket }
|
||||
target.net:=SegMentNetworkAddress;
|
||||
fillchar(target.node,6,#$FF); { all nodes i.e. all routers }
|
||||
target.socket:=RIPsocket;
|
||||
IPXsetUpSendECB(NIL,SourceSocket,target,@RIPrequest,SizeOf(RIPrequest),
|
||||
RequestIPXheader, RequestECB);
|
||||
RequestIPXheader.packetType := 1;
|
||||
{ 1=RIP / Any value will work/ type seems to be ignored by Routers
|
||||
as long as socket is OK. }
|
||||
|
||||
{ set-up the RIP request }
|
||||
FillChar(RIPrequest,SizeOf(RIPrequest),#$FF);
|
||||
RIPrequest.operation := $0100; { hi-lo, RIP request }
|
||||
FillChar(RIPanswer,SizeOf(RIPanswer),#$00);
|
||||
|
||||
|
||||
{ set-up the receive ECBs }
|
||||
for n:=1 to ECB_COUNT
|
||||
do begin
|
||||
IPXsetupListenECB(NIL,SourceSocket,
|
||||
@RIPanswer[n],SizeOf(TRIPanswerPacket),
|
||||
ReplyIpx[n],ReplyECB[n]);
|
||||
IPXListenForPacket(ReplyECB[n]);
|
||||
end;
|
||||
|
||||
{ send the RIP request }
|
||||
IPXSendPacket(RequestECB);
|
||||
|
||||
{ wait a while for answers }
|
||||
IPXgetIntervalMarker(timer1);
|
||||
REPEAT
|
||||
IPXrelinquishcontrol;
|
||||
IPXGetIntervalMarker(timer2);
|
||||
UNTIL abs(timer2-timer1)>20;
|
||||
|
||||
NumberOfNets := 0;
|
||||
|
||||
{ check all possible RIP responses, and fill the tables }
|
||||
for n:=1 to ECB_COUNT
|
||||
do if (ReplyECB[n].INuseFlag=0) and (RIPanswer[n].operation=$0200)
|
||||
then begin
|
||||
RoutableNetworks:=(swap(ReplyIPX[n].Length)-32) DIV SizeOf(TRIPentry);
|
||||
for cnt:=1 to RoutableNetworks
|
||||
do begin
|
||||
inc(NumberOfNets);
|
||||
With NetInfo[NumberOfNets]
|
||||
do begin
|
||||
Address:=RIPanswer[n].entry[cnt].network;
|
||||
hops:=swap(RIPanswer[n].entry[cnt].hops);
|
||||
ticks:=swap(RIPanswer[n].Entry[cnt].ticks);
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else IPXcancelEvent(ReplyECB[n]);
|
||||
|
||||
{ our socket is no longer needed }
|
||||
IPXCloseSocket(SourceSocket);
|
||||
|
||||
{ return the number of networks we found }
|
||||
GetAllNetworks:=NumberOfNets;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
50
NWTP/XIPX/NWSAP.PAS
Normal file
50
NWTP/XIPX/NWSAP.PAS
Normal file
@@ -0,0 +1,50 @@
|
||||
Unit NwSAP;
|
||||
|
||||
{ NwTP Version 0.6, Copyright 1993,1995 R. Spronk
|
||||
|
||||
WARNING: Test your program thoroughly if you're using nwSAP functions.
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Using the SAP functionality the wrong way may very well result in
|
||||
aborting servers ! (no kidding.)
|
||||
|
||||
NOTE: Type Declarations only. See SHWSAPS.PAS for an example }
|
||||
|
||||
|
||||
INTERFACE
|
||||
|
||||
Uses nwMisc,nwIPX;
|
||||
|
||||
CONST { server SAP priodic broadcast type }
|
||||
PERIODIC_ID_PACKET = $0002;
|
||||
{ server SAP (reply) packet types }
|
||||
GENERAL_SERVICE_RESPONSE=$0002;
|
||||
NEAREST_SERVICE_RESPONSE=$0004;
|
||||
{ client SAP (request) packet types }
|
||||
GENERAL_SERVICE_QUERY =$0001;
|
||||
NEAREST_SERVICE_QUERY =$0003;
|
||||
|
||||
{ Type definitions for SAP request/response structures}
|
||||
Type TSAPserver=record
|
||||
ObjType:word;
|
||||
Name :array[1..48] of byte; { asciiz }
|
||||
Address:TinternetworkAddress;
|
||||
Hops :word;
|
||||
end;
|
||||
|
||||
TSAPresponse=record
|
||||
ResponseType:word; { 0002 General server; 0004 nearest server }
|
||||
ServerEntry:array[1..7] of TSAPserver;
|
||||
end;
|
||||
|
||||
TSAPrequest=record
|
||||
RequestType:word; {hi-lo}
|
||||
ServerType :word; {hi-lo}
|
||||
end;
|
||||
|
||||
IMPLEMENTATION {===========================================================}
|
||||
|
||||
|
||||
|
||||
|
||||
end.
|
||||
136
NWTP/XIPX/R1_HELLO.PAS
Normal file
136
NWTP/XIPX/R1_HELLO.PAS
Normal file
@@ -0,0 +1,136 @@
|
||||
{$X+,V-,B-}
|
||||
program RecHello1;
|
||||
|
||||
{ Simple IPX demonstration program, that uses one receive ESR.
|
||||
|
||||
Run this program on 1 workstation, run S_HELLO or S1_HELLO on another.
|
||||
S_HELLO will send "hello world" messages,
|
||||
this workstation will receive them. }
|
||||
|
||||
uses crt,nwMisc,nwIPX;
|
||||
|
||||
CONST IOSocket=$5678;
|
||||
|
||||
Var ReceiveEcb :Tecb;
|
||||
IpxHdr :TipxHeader;
|
||||
socket :word;
|
||||
buf :array[1..546] of byte;
|
||||
t :byte;
|
||||
ReceivedBufLen:word;
|
||||
PacketReceived:boolean;
|
||||
|
||||
NewStack:array[1..1024] of word; { !! used by ESR }
|
||||
StackBottom:word; { !! used by ESR }
|
||||
|
||||
|
||||
{$F+}
|
||||
Procedure ListenESRhandler;
|
||||
begin
|
||||
PacketReceived:=true;
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
{$F+}
|
||||
Procedure ListenESR; assembler;
|
||||
asm { ES:SI are the only valid registers when entering this procedure ! }
|
||||
mov dx, seg stackbottom
|
||||
mov ds, dx
|
||||
|
||||
mov dx,ss { setup of a new local stack }
|
||||
mov bx,sp { ss:sp copied to dx:bx}
|
||||
mov ax,ds
|
||||
mov ss,ax
|
||||
mov sp,offset stackbottom
|
||||
push dx
|
||||
push bx
|
||||
|
||||
CALL ListenEsrHandler
|
||||
|
||||
pop bx
|
||||
pop dx
|
||||
mov sp,bx { restore stack }
|
||||
mov ss,dx
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
|
||||
begin
|
||||
IF NOT IpxInitialize
|
||||
then begin
|
||||
writeln('Ipx needs to be installed.');
|
||||
halt(1);
|
||||
end;
|
||||
socket:=IOSocket;
|
||||
IF NOT IPXopenSocket(Socket,SHORT_LIVED_SOCKET)
|
||||
then begin
|
||||
writeln('IPXopenSocket returned error# ',nwIPX.result);
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
Repeat
|
||||
PacketReceived:=False;
|
||||
{ Empty receive buffer (ReceiveEcb.fragment[2].address^) }
|
||||
FillChar(buf,546,#0);
|
||||
|
||||
{ Setup ECB and IPX header }
|
||||
IPXsetupListenECB(Addr(ListenESR),IOsocket,@buf,546,
|
||||
IpxHdr,ReceiveEcb);
|
||||
|
||||
IPXListenForPacket(ReceiveECB);
|
||||
|
||||
REPEAT
|
||||
|
||||
delay(1000);
|
||||
Writeln('Packet received: ',PacketReceived);
|
||||
|
||||
IF PacketReceived { ESR has signalled that a packet has been received }
|
||||
then begin
|
||||
Case ReceiveECB.CompletionCode OF
|
||||
$00:begin { Dump received bytes.. }
|
||||
Write('Data received : ');
|
||||
ReceivedBufLen:=swap(IpxHdr.length)-SizeOf(TipxHeader);
|
||||
for t:=1 to ReceivedBufLen
|
||||
do write(chr(buf[t]));
|
||||
writeln;
|
||||
end;
|
||||
$FC:Writeln('The listen request has been canceled.');
|
||||
{ impossible, as the cancelation has to be done by this program, and it doesn't }
|
||||
$FD:Writeln('Packet overflow error.');
|
||||
{ 0 fragments, or receiving buffer too small. }
|
||||
$FF:Writeln('The socket is closed.');
|
||||
{ Impossible. The socket is definitely open. See above. }
|
||||
end;
|
||||
|
||||
{ Now we're going to squeeze all information out of the IpxHdr }
|
||||
writeln('*IPX header info*');
|
||||
writeln('-total length : ',swap(IpxHdr.length):0);
|
||||
writeln('-data length : ',swap(IpxHdr.Length)-SizeOf(TipxHeader));
|
||||
writeln('-number of hops: ',(IpxHdr.TransportControl AND $0F):0);
|
||||
write('-sending adress: [');
|
||||
for t:=1 to 4
|
||||
do write(HexStr(IpxHdr.source.net[t],2));
|
||||
write('|');
|
||||
for t:=1 to 6
|
||||
do write(HexStr(IpxHdr.source.node[t],2));
|
||||
write('|');
|
||||
writeln(HexStr(swap(IpxHdr.source.socket),4),']');
|
||||
write('-destined for : [');
|
||||
for t:=1 to 4
|
||||
do write(HexStr(IpxHdr.destination.net[t],2));
|
||||
write('|');
|
||||
for t:=1 to 6
|
||||
do write(HexStr(IpxHdr.destination.node[t],2));
|
||||
write('|');
|
||||
writeln(HexStr(swap(IpxHdr.destination.socket),4),']');
|
||||
|
||||
writeln;
|
||||
end;
|
||||
|
||||
UNTIL (KeyPressed or PacketReceived);
|
||||
|
||||
UNTIL keypressed;
|
||||
|
||||
IF NOT IPXcloseSocket(IOsocket)
|
||||
then writeln('IPXcloseSocket returned error# ',nwIPX.result);
|
||||
|
||||
end.
|
||||
107
NWTP/XIPX/R2_HELLO.PAS
Normal file
107
NWTP/XIPX/R2_HELLO.PAS
Normal file
@@ -0,0 +1,107 @@
|
||||
{$X+,V-,B-}
|
||||
program RecHello2;
|
||||
|
||||
{ Simple IPX demonstration program, that uses one receive ESR.
|
||||
|
||||
Run this program on 1 workstation, run S_HELLO or S1_HELLO on another.
|
||||
S_HELLO will send "hello world" messages,
|
||||
this workstation will receive them. }
|
||||
|
||||
uses crt,nwMisc,nwIPX;
|
||||
|
||||
CONST IOSocket=$5678;
|
||||
|
||||
Var ReceiveEcb :Tecb;
|
||||
IpxHdr :TipxHeader;
|
||||
socket :word;
|
||||
buf :array[1..546] of byte;
|
||||
t :byte;
|
||||
ReceivedBufLen:word;
|
||||
PacketReceived:boolean;
|
||||
|
||||
RecString :string;
|
||||
|
||||
NewStack:array[1..1024] of word; { !! used by ESR }
|
||||
StackBottom:word; { !! used by ESR }
|
||||
|
||||
|
||||
{$F+}
|
||||
Procedure ListenESRhandler(Var p:Tpecb);
|
||||
begin
|
||||
RecString[0]:=chr(p^.fragment[2].size);
|
||||
move(p^.fragment[2].address^,RecString[1],byte(RecString[0]));
|
||||
PacketReceived:=true;
|
||||
IPXListenForPacket(ReceiveECB);
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
{$F+}
|
||||
Procedure ListenESR; assembler;
|
||||
asm { ES:SI are the only valid registers when entering this procedure ! }
|
||||
mov dx, seg stackbottom
|
||||
mov ds, dx
|
||||
|
||||
mov dx,ss { setup of a new local stack }
|
||||
mov bx,sp { ss:sp copied to dx:bx}
|
||||
mov ax,ds
|
||||
mov ss,ax
|
||||
mov sp,offset stackbottom
|
||||
push dx { push old ss:sp on new stack }
|
||||
push bx
|
||||
|
||||
push es { push es:si on stack as local vars }
|
||||
push si
|
||||
mov di,sp
|
||||
|
||||
push ss { push address of local ptr on stack }
|
||||
push di
|
||||
CALL ListenEsrHandler
|
||||
|
||||
add sp,4 { skip stack ptr-copy }
|
||||
pop bx { restore ss:sp from new stack }
|
||||
pop dx
|
||||
mov sp,bx
|
||||
mov ss,dx
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
|
||||
begin
|
||||
IF NOT IpxInitialize
|
||||
then begin
|
||||
writeln('Ipx needs to be installed.');
|
||||
halt(1);
|
||||
end;
|
||||
socket:=IOSocket;
|
||||
IF NOT IPXopenSocket(Socket,SHORT_LIVED_SOCKET)
|
||||
then begin
|
||||
writeln('IPXopenSocket returned error# ',nwIPX.result);
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
PacketReceived:=False;
|
||||
{ Empty receive buffer (ReceiveEcb.fragment[2].address^) }
|
||||
FillChar(buf,546,#0);
|
||||
|
||||
{ Setup ECB and IPX header }
|
||||
IPXsetupListenECB(Addr(ListenESR),IOsocket,@buf,546,
|
||||
IpxHdr,ReceiveEcb);
|
||||
|
||||
IPXListenForPacket(ReceiveECB);
|
||||
|
||||
REPEAT
|
||||
|
||||
IPXrelinquishControl;
|
||||
|
||||
IF PacketReceived { ESR has signalled that a packet has been received }
|
||||
then begin
|
||||
writeln(RecString);
|
||||
PacketReceived:=false;
|
||||
end;
|
||||
|
||||
UNTIL KeyPressed;
|
||||
|
||||
IF NOT IPXcloseSocket(IOsocket)
|
||||
then writeln('IPXcloseSocket returned error# ',nwIPX.result);
|
||||
|
||||
end.
|
||||
146
NWTP/XIPX/R3_HELLO.PAS
Normal file
146
NWTP/XIPX/R3_HELLO.PAS
Normal file
@@ -0,0 +1,146 @@
|
||||
{$X+,V-,B-}
|
||||
program RecHello3;
|
||||
|
||||
{ Simple IPX demonstration program, that uses one receive ESR.
|
||||
|
||||
Run this program on 1 workstation, run S_HELLO or S1_HELLO on another.
|
||||
S_HELLO will send "hello world" messages,
|
||||
this workstation will receive them. }
|
||||
|
||||
{ This program consists of two concurrent processes:
|
||||
|
||||
1. (background) An ESR that fills a global receive buffer with
|
||||
incoming packets. Only when the buffer is full
|
||||
will packets be discarded.
|
||||
|
||||
2. (foreground) A process that performs its regular task. Whenever
|
||||
there is time, the process will process the
|
||||
received packets. }
|
||||
|
||||
uses crt,nwMisc,nwIPX;
|
||||
|
||||
CONST IOSocket=$5678;
|
||||
|
||||
Var ReceiveEcb :Tecb;
|
||||
IpxHdr :TipxHeader;
|
||||
socket :word;
|
||||
buf :array[1..546] of byte;
|
||||
t :byte;
|
||||
ReceivedBufLen:word;
|
||||
|
||||
ReceivedMsg:array[1..100] of record
|
||||
InUse:Boolean;
|
||||
Message:string[25];
|
||||
end;
|
||||
|
||||
EsrBufInd :Byte; { used by ESR }
|
||||
|
||||
NewStack:array[1..1024] of word; { !! used by ESR }
|
||||
StackBottom:word; { !! used by ESR }
|
||||
|
||||
|
||||
{$F+}
|
||||
Procedure ListenESRhandler(Var p:Tpecb);
|
||||
begin
|
||||
{ look for an empty spot in the global buffer }
|
||||
EsrBufInd:=1;
|
||||
while (EsrBufInd<=100) and ReceivedMsg[EsrBufInd].Inuse
|
||||
do inc(EsrBufInd);
|
||||
IF EsrBufInd<=100
|
||||
then begin
|
||||
{ empty place found. Insert msg }
|
||||
with ReceivedMsg[EsrBufInd]
|
||||
do begin
|
||||
Message[0]:=chr(p^.fragment[2].size);
|
||||
if Message[0]>#25 then Message[0]:=#25;
|
||||
move(p^.fragment[2].address^,Message[1],ord(Message[0]));
|
||||
InUse:=True;
|
||||
end;
|
||||
end
|
||||
else ; { entire buffer is filled => discard packet }
|
||||
{ Setup to listen for next incoming packet }
|
||||
IPXListenForPacket(ReceiveECB);
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
{$F+}
|
||||
Procedure ListenESR; assembler;
|
||||
asm { ES:SI are the only valid registers when entering this procedure ! }
|
||||
mov dx, seg stackbottom
|
||||
mov ds, dx
|
||||
|
||||
mov dx,ss { setup of a new local stack }
|
||||
mov bx,sp { ss:sp copied to dx:bx}
|
||||
mov ax,ds
|
||||
mov ss,ax
|
||||
mov sp,offset stackbottom
|
||||
push dx { push old ss:sp on new stack }
|
||||
push bx
|
||||
|
||||
push es { push es:si on stack as local vars }
|
||||
push si
|
||||
mov di,sp
|
||||
|
||||
push ss { push address of local ptr on stack }
|
||||
push di
|
||||
CALL ListenEsrHandler
|
||||
|
||||
add sp,4 { skip stack ptr-copy }
|
||||
pop bx { restore ss:sp from new stack }
|
||||
pop dx
|
||||
mov sp,bx
|
||||
mov ss,dx
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
|
||||
begin
|
||||
IF NOT IpxInitialize
|
||||
then begin
|
||||
writeln('Ipx needs to be installed.');
|
||||
halt(1);
|
||||
end;
|
||||
socket:=IOSocket;
|
||||
IF NOT IPXopenSocket(Socket,SHORT_LIVED_SOCKET)
|
||||
then begin
|
||||
writeln('IPXopenSocket returned error# ',nwIPX.result);
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
FillChar(buf,546,#0);
|
||||
|
||||
{ Setup ECB and IPX header }
|
||||
IPXsetupListenECB(Addr(ListenESR),IOsocket,@buf,546,
|
||||
IpxHdr,ReceiveEcb);
|
||||
|
||||
IPXListenForPacket(ReceiveECB);
|
||||
|
||||
writeln('ESR will start filling a global buffer with packets received.');
|
||||
writeln('Starting foreground process...');
|
||||
writeln;
|
||||
writeln('Foreground process just writes a ''dot'' to the screen every second.');
|
||||
writeln('When a key is pressed, this process is terminated and the received');
|
||||
writeln('packets are shown.');
|
||||
|
||||
REPEAT
|
||||
IPXrelinquishControl;
|
||||
delay(1000);
|
||||
write('.');
|
||||
UNTIL KeyPressed;
|
||||
|
||||
writeln;
|
||||
writeln('Dumping global receive buffer -- filled by background process.');
|
||||
|
||||
for t:=1 to 100
|
||||
do if ReceivedMsg[t].Inuse
|
||||
then begin
|
||||
writeln(ReceivedMsg[t].Message);
|
||||
ReceivedMsg[t].Inuse:=False; { give entry in buffer free }
|
||||
end;
|
||||
{ You may also choose to process just 1 entry in the received buffer.
|
||||
Set Inuse to False after processing, so the ESR can fill it again }
|
||||
|
||||
IF NOT IPXcloseSocket(IOsocket)
|
||||
then writeln('IPXcloseSocket returned error# ',nwIPX.result);
|
||||
|
||||
end.
|
||||
92
NWTP/XIPX/R_HELLO.PAS
Normal file
92
NWTP/XIPX/R_HELLO.PAS
Normal file
@@ -0,0 +1,92 @@
|
||||
{$X+,V-,B-}
|
||||
program RecHello;
|
||||
|
||||
{ Simple IPX demonstration program. Run this program on 1 workstation,
|
||||
run S_HELLO on another. S_HELLO will send "hello world" messages,
|
||||
this workstation will receive them.
|
||||
|
||||
Polls the ECB until a packet is received. No ESR used. }
|
||||
|
||||
uses crt,nwMisc,nwIPX;
|
||||
|
||||
CONST IOSocket=$5678;
|
||||
|
||||
Var ReceiveEcb:Tecb;
|
||||
IpxHdr:TipxHeader;
|
||||
socket:word;
|
||||
buf:array[1..546] of byte;
|
||||
t:byte;
|
||||
w:word;
|
||||
s:string;
|
||||
ReceivedBufLen:word;
|
||||
begin
|
||||
IF NOT IpxInitialize
|
||||
then begin
|
||||
writeln('Ipx needs to be installed.');
|
||||
halt(1);
|
||||
end;
|
||||
socket:=IOSocket;
|
||||
IF NOT IPXopenSocket(Socket,SHORT_LIVED_SOCKET)
|
||||
then begin
|
||||
writeln('IPXopenSocket returned error# ',nwIPX.result);
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
Repeat
|
||||
{ Empty receive buffer (ReceiveEcb.fragment[2].address^) }
|
||||
FillChar(buf,546,#0);
|
||||
|
||||
{ Setup ECB and IPX header }
|
||||
IPXsetupListenECB(NIL,IOsocket,@buf,546,
|
||||
IpxHdr,ReceiveEcb);
|
||||
IPXListenForPacket(ReceiveECB);
|
||||
|
||||
{ Poll InUse flag until a packet was received }
|
||||
while ReceiveECB.InUseFlag<>0
|
||||
do IPXrelinquishControl;
|
||||
|
||||
Case ReceiveECB.CompletionCode OF
|
||||
$00:begin { Dump received bytes.. }
|
||||
Write('Data received : ');
|
||||
ReceivedBufLen:=swap(IpxHdr.length)-SizeOf(TipxHeader);
|
||||
for t:=1 to ReceivedBufLen
|
||||
do write(chr(buf[t]));
|
||||
writeln;
|
||||
end;
|
||||
$FC:Writeln('The listen request has been canceled.');
|
||||
{ impossible, as the cancelation has to be done by this program, and it doesn't }
|
||||
$FD:Writeln('Packet overflow error.');
|
||||
{ 0 fragments, or receiving buffer too small. }
|
||||
$FF:Writeln('The socket is closed.');
|
||||
{ Impossible. The socket is definitely open. See above. }
|
||||
end;
|
||||
|
||||
{ Now we're going to squeeze all information out of the IpxHdr }
|
||||
writeln('*IPX header info*');
|
||||
writeln('-total length : ',swap(IpxHdr.length):0);
|
||||
writeln('-data length : ',swap(IpxHdr.Length)-SizeOf(TipxHeader));
|
||||
writeln('-number of hops: ',(IpxHdr.TransportControl AND $0F):0);
|
||||
write('-sending adress: [');
|
||||
for t:=1 to 4
|
||||
do write(HexStr(IpxHdr.source.net[t],2));
|
||||
write('|');
|
||||
for t:=1 to 6
|
||||
do write(HexStr(IpxHdr.source.node[t],2));
|
||||
write('|');
|
||||
writeln(HexStr(swap(IpxHdr.source.socket),4),']');
|
||||
write('-destined for : [');
|
||||
for t:=1 to 4
|
||||
do write(HexStr(IpxHdr.destination.net[t],2));
|
||||
write('|');
|
||||
for t:=1 to 6
|
||||
do write(HexStr(IpxHdr.destination.node[t],2));
|
||||
write('|');
|
||||
writeln(HexStr(swap(IpxHdr.destination.socket),4),']');
|
||||
|
||||
writeln;
|
||||
UNTIL keypressed;
|
||||
|
||||
IF NOT IPXcloseSocket(IOsocket)
|
||||
then writeln('IPXcloseSocket returned error# ',nwIPX.result);
|
||||
|
||||
end.
|
||||
114
NWTP/XIPX/S1_HELLO.PAS
Normal file
114
NWTP/XIPX/S1_HELLO.PAS
Normal file
@@ -0,0 +1,114 @@
|
||||
{$X+,B-,V-}
|
||||
program SendHello;
|
||||
|
||||
{ Simple IPX demonstration program with 1 ESR.}
|
||||
|
||||
uses crt,nwMisc,nwIPX;
|
||||
|
||||
CONST IOSocket=$5678;
|
||||
|
||||
Var NewStack :array[1..512] of word; { !! used by ESR }
|
||||
StackBottom:word; { !! used by ESR }
|
||||
|
||||
SendEcb :Tecb;
|
||||
IpxHdr :TipxHeader;
|
||||
socket :word;
|
||||
dest :TinternetworkAddress;
|
||||
buf :array[1..546] of byte;
|
||||
t :byte;
|
||||
w :word;
|
||||
s :string;
|
||||
PacketSent :boolean;
|
||||
|
||||
{$F+}
|
||||
Procedure SendESRhandler;
|
||||
begin
|
||||
PacketSent:=true;
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
{$F+}
|
||||
Procedure SendESR; assembler;
|
||||
asm { ES:SI are the only valid registers when entering this procedure ! }
|
||||
mov dx, seg stackbottom
|
||||
mov ds, dx
|
||||
|
||||
mov dx,ss { setup of a new local stack }
|
||||
mov bx,sp { ss:sp copied to dx:bx}
|
||||
mov ax,ds
|
||||
mov ss,ax
|
||||
mov sp,offset stackbottom
|
||||
push bx
|
||||
push dx
|
||||
|
||||
CALL SendEsrHandler
|
||||
|
||||
pop dx
|
||||
pop bx
|
||||
mov sp,bx { restore stack }
|
||||
mov ss,dx
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
begin
|
||||
IF NOT IpxInitialize
|
||||
then begin
|
||||
writeln('Ipx needs to be installed.');
|
||||
halt(1);
|
||||
end;
|
||||
socket:=IOSocket;
|
||||
IF NOT IPXopenSocket(Socket,SHORT_LIVED_SOCKET)
|
||||
then begin
|
||||
writeln('IPXopenSocket returned error# ',nwIPX.result);
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
for t:=1 to 4 do dest.net[t]:=$00; { this net / segment }
|
||||
for t:=1 to 6 do dest.node[t]:=$FF; { all nodes }
|
||||
dest.socket:=IOsocket;
|
||||
w:=0;
|
||||
|
||||
Repeat
|
||||
inc (w);
|
||||
|
||||
{ Fill buffer (ECB.fragment[2]^) }
|
||||
str(w:4,s);
|
||||
s:=s+' IPX: Hello World';
|
||||
FillChar(buf,546,#0);
|
||||
move(s[1],buf,ord(s[0]));
|
||||
|
||||
{ setup ECB and IPX header }
|
||||
PacketSent:=False;
|
||||
IPXsetupSendECB(Addr(SendESR),IOsocket,dest,@buf,ord(s[0]),
|
||||
IpxHdr,SendEcb);
|
||||
IPXsendPacket(SendEcb);
|
||||
|
||||
REPEAT
|
||||
|
||||
IpxRelinquishControl;
|
||||
delay(100);
|
||||
|
||||
IF PacketSent
|
||||
then begin
|
||||
{ ECB.InUseFlag was lowered, now determine if packet was sent: }
|
||||
CASE SendEcb.CompletionCode OF
|
||||
$00:writeln('IPX packet #',w:0,' was sent.');
|
||||
$FC:writeln('The send of packet #',w:0,' was canceled.');
|
||||
{ impossible, as this cancelation to be done by THIS program, and it doesn't }
|
||||
$FD:writeln('Packet# ',w:0,' is malformed and was not sent.');
|
||||
{ illegal param: packet length, number of fragments, fragment size. }
|
||||
$FE:writeln('Packet# ',w:0,' was undelivered. No stations listening.');
|
||||
$FF:writeln('Packet# ',w:0,' not sent due to a hardware error.');
|
||||
end;
|
||||
end;
|
||||
|
||||
UNTIL PacketSent or Keypressed;
|
||||
|
||||
delay(750); { delay 0.75 sec before sending another packet }
|
||||
|
||||
UNTIL keypressed;
|
||||
|
||||
IF NOT IPXcloseSocket(IOsocket)
|
||||
then writeln('IPXcloseSocket returned error# ',nwIPX.result);
|
||||
|
||||
end.
|
||||
170
NWTP/XIPX/S1_PEP.PAS
Normal file
170
NWTP/XIPX/S1_PEP.PAS
Normal file
@@ -0,0 +1,170 @@
|
||||
{$X+,V-,B-}
|
||||
program S1_PEP; { Listening Process / receiver / Slave }
|
||||
|
||||
{ Testprogram for the nwPEP unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
uses crt,nwMisc,nwIPX,nwPEP;
|
||||
|
||||
Var ListenECB :Tecb; { used to listen for packets }
|
||||
ListenPepHdr :TpepHeader;
|
||||
|
||||
SendECB :Tecb; { used to send acknowledgements }
|
||||
SendPepHdr :TpepHeader;
|
||||
|
||||
IOsocket :word;
|
||||
DataBuffer :array[1..546] of byte;
|
||||
SendDataBuffer:byte;
|
||||
|
||||
PacketReceived :Boolean;
|
||||
LastTransactionID:LongInt;
|
||||
BytesReceived :Word;
|
||||
|
||||
NewStack:array[1..8192] of word; { !! used by ESR }
|
||||
StackBottom:word; { !! used by ESR }
|
||||
|
||||
lnr:word;
|
||||
|
||||
Procedure CheckError(err:boolean; errNbr:word);
|
||||
begin
|
||||
if err
|
||||
then begin
|
||||
CASE errNbr of
|
||||
$0100:writeln('IPX needs to be installed.');
|
||||
$0101:writeln('ERROR: Connection not established. A Timeout occured');
|
||||
$0102:writeln('ERROR: The transfer is aborted; A timeout occured.');
|
||||
$10FE:writeln('Error opening socket: Socket Table Is Full.');
|
||||
$10FF:writeln('Error opening socket: Socket is already open.');
|
||||
else writeln('Unspecified error.');
|
||||
end; {case}
|
||||
IPXcloseSocket(IOsocket);
|
||||
halt(1);
|
||||
end;
|
||||
end;
|
||||
|
||||
Function TimeOut(t1,t2:word;n:byte):boolean;
|
||||
{ ticks t2 - ticks t1 > n seconds ? }
|
||||
Var lt1,lt2:LongInt;
|
||||
begin
|
||||
lt2:=t2;
|
||||
if t1>t2 then lt2:=lt2+$FFFF;
|
||||
TimeOut:=(lt2-t1)>(n*18);
|
||||
end;
|
||||
|
||||
{$F+}
|
||||
Procedure ListenAndAckHandler;
|
||||
begin
|
||||
lnr:=ListenPepHdr.TransactionID;
|
||||
|
||||
If (ListenECB.CompletionCode<>0)
|
||||
or (ListenPepHdr.IPXhdr.packetType<>PEP_PACKET_TYPE)
|
||||
or (ListenPepHdr.clienttype<>$EA)
|
||||
or (ListenPepHdr.TransactionID<LastTransactionID) { discard dupe old packet }
|
||||
then IPXlistenForPacket(ListenECB)
|
||||
else begin
|
||||
PacketReceived:=(ListenPepHdr.transactionID>LastTransactionID); { new packet received }
|
||||
|
||||
{ Acknowledge new packets and duplicates of the latest packet, }
|
||||
{ as the original acknowledgement may have been lost. }
|
||||
BytesReceived:=swap(ListenPepHdr.IPXhdr.length)-SizeOf(TpepHeader);
|
||||
LastTransactionID:=ListenPepHdr.TransactionID;
|
||||
|
||||
{ Setup acknowledgement ECB and PEPheader, and send it. }
|
||||
if 1=1 {SendECB.InUseFlag=0}
|
||||
then begin
|
||||
ListenPepHdr.IPXhdr.source.socket:=swap(ListenPepHdr.IPXhdr.source.socket);
|
||||
{ socket is hi-lo in IPX/PEPHeaders. SetupSendECB expects lo-hi }
|
||||
PEPsetupSendECB(NIL,IOsocket,ListenPepHdr.IPXhdr.source,@SendDataBuffer,0,
|
||||
SendPepHdr,SendECB);
|
||||
SendPepHdr.TransactionId:=LastTransactionID;
|
||||
SendPepHdr.ClientType:=$EA;
|
||||
IPXsendPacket(SendECB);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
{$F+}
|
||||
Procedure ListenAndAckESR; assembler;
|
||||
asm
|
||||
mov dx, seg stackbottom
|
||||
mov ds, dx
|
||||
|
||||
mov dx,ss { setup of a new local stack }
|
||||
mov bx,sp { ss:sp copied to dx:bx}
|
||||
mov ax,ds
|
||||
mov ss,ax
|
||||
mov sp,offset stackbottom
|
||||
push dx { push old ss:sp on new stack }
|
||||
push bx
|
||||
CALL ListenAndAckHandler
|
||||
pop bx { restore ss:sp from new stack }
|
||||
pop dx
|
||||
mov sp,bx
|
||||
mov ss,dx
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
Var ticks,ticks2 :word;
|
||||
FileName:string;
|
||||
FileSize:LongInt;
|
||||
|
||||
begin
|
||||
lnr:=0;
|
||||
|
||||
IpxInitialize;
|
||||
CheckError(nwIPX.result>0,$100);
|
||||
|
||||
IOSocket:=$5678;
|
||||
IPXopenSocket(IOsocket,SHORT_LIVED_SOCKET);
|
||||
CheckError(nwIPX.result>0,$1000+nwIPX.result);
|
||||
|
||||
{ Setup of ECB and PepHeader, start listening for incoming packets. }
|
||||
LastTransactionID:=0;
|
||||
PacketReceived:=False;
|
||||
PEPSetupListenECB(Addr(ListenAndAckESR),IOsocket,@DataBuffer,546,
|
||||
ListenPepHdr,ListenECB);
|
||||
IPXListenForPacket(ListenECB);
|
||||
writeln('Listening for incoming packet.');
|
||||
|
||||
IPXGetIntervalMarker(ticks);
|
||||
REPEAT
|
||||
IPXrelinquishControl;
|
||||
IPXGetIntervalMarker(ticks2);
|
||||
CheckError(TimeOut(ticks,ticks2,130),$101);{ error if a timeout occurred }
|
||||
UNTIL PacketReceived;
|
||||
|
||||
writeln('Packet received.. initiating transfer process.');
|
||||
writeln('Received PacketID:',LastTransactionID);
|
||||
writeln('len of data:',BytesReceived);
|
||||
|
||||
{ do something with DataBuffer: the data that was just received. }
|
||||
{ the first packet contains the filename and filesize }
|
||||
Move(DataBuffer[1],FileName[0],15);
|
||||
Move(DataBuffer[16],FileSize,4);
|
||||
writeln('Receiving file ',FileName,', size: ',FileSize);
|
||||
|
||||
REPEAT { Listen for remaining packets }
|
||||
Packetreceived:=false;
|
||||
|
||||
While SendECB.InuseFlag<>0
|
||||
do IPXrelinquishControl;
|
||||
|
||||
IPXListenForPacket(ListenECB);
|
||||
IPXGetIntervalMarker(ticks);
|
||||
writeln(FileSize);
|
||||
Repeat
|
||||
{write(lnr);}
|
||||
IPXrelinquishControl;
|
||||
IPXGetIntervalMarker(ticks2);
|
||||
CheckError(TimeOut(ticks,ticks2,10),$102); { error if Timeout occurred }
|
||||
until PacketReceived;
|
||||
writeln('Packet#:',LastTransactionID);
|
||||
writeln('len of data:',BytesReceived);
|
||||
FileSize:=FileSize-BytesReceived;
|
||||
{ do something with DataBuffer: the data that was just received. }
|
||||
|
||||
UNTIL (FileSize<=0); { entire file received }
|
||||
|
||||
writeln('Transfer complete.');
|
||||
IPXcloseSocket(IOsocket);
|
||||
end.
|
||||
189
NWTP/XIPX/SHWSAPS.PAS
Normal file
189
NWTP/XIPX/SHWSAPS.PAS
Normal file
@@ -0,0 +1,189 @@
|
||||
{$X+,V-,B-}
|
||||
program ShSAPs;
|
||||
|
||||
{ Testprogram for the nwSAP unit / NwTP 0.6 (c) 1993,1995 R.Spronk }
|
||||
|
||||
{ Dump all incoming SAP broadcasts on screen;
|
||||
Sends -no- packets; receiving packets only }
|
||||
|
||||
{ Demonstrates
|
||||
-The use of the Service Advertizing Protocol;
|
||||
-Asynchronous handling of receiving and processing
|
||||
(using 1 receive ESR and intermediate buffers }
|
||||
|
||||
uses crt,nwMisc,nwIPX,nwSAP;
|
||||
|
||||
CONST SAPsocket=$0452;
|
||||
BUFSIZ=511;
|
||||
{ May 'hang' your WS if more than 70 SAP broadcast were received
|
||||
in a short interval (a few ticks). Increase the BUFSIZ value. }
|
||||
|
||||
Type TSAPserver=record
|
||||
ObjType:word;
|
||||
Name :array[1..48] of byte; { asciiz }
|
||||
Address:TinternetworkAddress;
|
||||
Hops :word;
|
||||
end;
|
||||
|
||||
TSAPresponse=record
|
||||
ResponseType:word; { 0002 General server; 0004 nearest server }
|
||||
ServerEntry:array[1..7] of TSAPserver;
|
||||
end;
|
||||
|
||||
Type String48=string[48];
|
||||
Tservices=record
|
||||
InUseFlag :Byte; { 0: not being accessed by other threads }
|
||||
TimeStamp :Word; { Ticks / max 60. minutes }
|
||||
ObjType:word;
|
||||
Name :array[1..48] of byte; { asciiz }
|
||||
Address:TinternetworkAddress;
|
||||
Hops :word;
|
||||
end;
|
||||
|
||||
Var ServBuf:array[0..BUFSIZ] of TServices;
|
||||
ECBServBufInd:word; { 0..BUFSIZ }
|
||||
ServBufInd :word; { 0..BUFSIZ }
|
||||
|
||||
StartTicks:Longint;
|
||||
|
||||
PktCount:word;
|
||||
|
||||
Var ReceiveEcb :Tecb;
|
||||
IpxHdr :TipxHeader;
|
||||
socket :word;
|
||||
IPXreceiveBuffer: array[1..546] of byte;
|
||||
SAPreceiveBuffer: TSAPresponse absolute IPXreceiveBuffer;
|
||||
|
||||
ReceivedBufLen:word;
|
||||
PacketReceived:boolean;
|
||||
|
||||
RecString :string;
|
||||
|
||||
NewStack:array[1..1024] of word; { !! used by ESR }
|
||||
StackBottom:word; { !! used by ESR }
|
||||
ESRctr:byte; { !! used by SAP ESR }
|
||||
|
||||
|
||||
{$F+}
|
||||
Procedure SAPListenESRhandler(Var p:Tpecb);
|
||||
begin
|
||||
if SAPreceiveBuffer.Responsetype=$0200 { 0002 hi-lo: general server SAP reply }
|
||||
then begin
|
||||
ESRctr:=1;
|
||||
while (ESRctr<=7) and (SAPreceiveBuffer.ServerEntry[ESRctr].ObjType>$0000)
|
||||
do begin
|
||||
while ServBuf[ECBservBufInd].inUseFlag>0
|
||||
do begin
|
||||
inc(ECBServBufInd);
|
||||
ECBservBufInd:=ECBservBufInd and BUFSIZ;
|
||||
end;
|
||||
with SAPreceiveBuffer.ServerEntry[ESRctr]
|
||||
do begin
|
||||
Move(ObjType,ServBuf[ECBServBufInd].ObjType,SizeOf(TSAPserver));
|
||||
ObjType:=$0000; { To mark that the entry has been dealt with;
|
||||
to 'clear' receive buffer }
|
||||
end;
|
||||
with ServBuf[ECBServBufInd]
|
||||
do begin
|
||||
IPXgetIntervalMarker(TimeStamp);
|
||||
InUseFlag:=$FF;
|
||||
end;
|
||||
inc(ESRctr);
|
||||
end;
|
||||
PacketReceived:=true;
|
||||
inc(PktCount);
|
||||
end;
|
||||
IPXListenForPacket(ReceiveECB);
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
{$F+}
|
||||
Procedure SAPListenESR; assembler;
|
||||
asm { ES:SI are the only valid registers when entering this procedure ! }
|
||||
mov dx, seg stackbottom
|
||||
mov ds, dx
|
||||
|
||||
mov dx,ss { setup of a new local stack }
|
||||
mov bx,sp { ss:sp copied to dx:bx}
|
||||
mov ax,ds
|
||||
mov ss,ax
|
||||
mov sp,offset stackbottom
|
||||
push dx { push old ss:sp on new stack }
|
||||
push bx
|
||||
|
||||
push es { push es:si on stack as local vars }
|
||||
push si
|
||||
mov di,sp
|
||||
|
||||
push ss { push address of local ptr on stack }
|
||||
push di
|
||||
CALL SAPListenEsrHandler
|
||||
|
||||
add sp,4 { skip stack ptr-copy }
|
||||
pop bx { restore ss:sp from new stack }
|
||||
pop dx
|
||||
mov sp,bx
|
||||
mov ss,dx
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
|
||||
Var ServerName:string;
|
||||
|
||||
begin
|
||||
IF NOT IpxInitialize
|
||||
then begin
|
||||
writeln('Ipx needs to be installed.');
|
||||
halt(1);
|
||||
end;
|
||||
socket:=SAPSocket;
|
||||
IF NOT IPXopenSocket(Socket,SHORT_LIVED_SOCKET)
|
||||
then begin
|
||||
writeln('IPXopenSocket returned error# ',nwIPX.result);
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
PktCount:=0;
|
||||
ECBservBufInd:=0;
|
||||
PacketReceived:=False;
|
||||
{ Empty receive buffer (ReceiveEcb.fragment[2].address^) }
|
||||
FillChar(IPXreceiveBuffer,546,#0);
|
||||
|
||||
{ Setup ECB and IPX header }
|
||||
IPXsetupListenECB(Addr(SAPListenESR),SAPsocket,@IPXreceiveBuffer,546,
|
||||
IpxHdr,ReceiveEcb);
|
||||
|
||||
IPXListenForPacket(ReceiveECB);
|
||||
|
||||
ServBufInd:=0;
|
||||
REPEAT
|
||||
|
||||
WHILE (ServBufInd<512) and (NOT keypressed)
|
||||
do begin
|
||||
IPXrelinquishControl;
|
||||
|
||||
IF ServBuf[ServBufInd].InUseFlag>0
|
||||
then begin
|
||||
with ServBuf[ServBufInd]
|
||||
do begin
|
||||
writeln('---------');
|
||||
writeln('BufIndex:',ServBufInd);
|
||||
writeln('Timestamp: ',HexStr(TimeStamp,4));
|
||||
writeln('ObjType : ',HexStr(swap(ObjType),4));
|
||||
ZStrCopy(ServerName,name[1],48);
|
||||
writeln('ServerNm : ',ServerName);
|
||||
writeln('Address : ',HexDumpStr(Address,24));
|
||||
writeln('Hops : ',HexStr(swap(Hops),4));
|
||||
end;
|
||||
ServBuf[ServBufInd].InUseFlag:=0;
|
||||
end;
|
||||
|
||||
inc(ServBufInd);ServBufInd:=ServBufInd and BUFSIZ;
|
||||
end;
|
||||
|
||||
UNTIL KeyPressed;
|
||||
|
||||
IF NOT IPXcloseSocket(SAPsocket)
|
||||
then writeln('IPXcloseSocket returned error# ',nwIPX.result);
|
||||
|
||||
end.
|
||||
1881
NWTP/XIPX/SKT_XXX
Normal file
1881
NWTP/XIPX/SKT_XXX
Normal file
File diff suppressed because it is too large
Load Diff
76
NWTP/XIPX/S_HELLO.PAS
Normal file
76
NWTP/XIPX/S_HELLO.PAS
Normal file
@@ -0,0 +1,76 @@
|
||||
{$X+,B-,V-}
|
||||
program SendHello;
|
||||
|
||||
{ Simple IPX demonstration program. Run this program on 1 workstation,
|
||||
run R_HELLO on another. R_HELLO will receive the "hello world" messages
|
||||
that this program sends.
|
||||
|
||||
Polls the ECB until a packet is sent. No ESR used. }
|
||||
|
||||
uses crt,nwMisc,nwIPX;
|
||||
|
||||
CONST IOSocket=$5678;
|
||||
|
||||
Var SendEcb:Tecb;
|
||||
IpxHdr:TipxHeader;
|
||||
socket:word;
|
||||
dest:TinternetworkAddress;
|
||||
buf:array[1..546] of byte;
|
||||
t:byte;
|
||||
w:word;
|
||||
s:string;
|
||||
begin
|
||||
IF NOT IpxInitialize
|
||||
then begin
|
||||
writeln('Ipx needs to be installed.');
|
||||
halt(1);
|
||||
end;
|
||||
socket:=IOSocket;
|
||||
IF NOT IPXopenSocket(Socket,SHORT_LIVED_SOCKET)
|
||||
then begin
|
||||
writeln('IPXopenSocket returned error# ',nwIPX.result);
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
for t:=1 to 4 do dest.net[t]:=$00; { this net / segment }
|
||||
for t:=1 to 6 do dest.node[t]:=$FF; { all nodes }
|
||||
dest.socket:=IOsocket;
|
||||
w:=0;
|
||||
|
||||
Repeat
|
||||
inc (w);
|
||||
|
||||
{ Fill buffer (ECB.fragment[2]^) }
|
||||
str(w:4,s);
|
||||
s:=s+' IPX: Hello World';
|
||||
FillChar(buf,546,#0);
|
||||
move(s[1],buf,ord(s[0]));
|
||||
|
||||
{ setup ECB and IPX header }
|
||||
IPXsetupSendECB(NIL,IOsocket,dest,@buf,ord(s[0]),
|
||||
IpxHdr,SendEcb);
|
||||
IPXsendPacket(SendEcb);
|
||||
|
||||
{ Poll the Inuse Flag until the packet is sent. }
|
||||
While SendEcb.InUseFlag<>0
|
||||
do IPXrelinquishControl;
|
||||
|
||||
{ ECB.InUseFlag was lowered, now determine if packet was sent: }
|
||||
CASE SendEcb.CompletionCode OF
|
||||
$00:writeln('IPX packet #',w:0,' was sent.');
|
||||
$FC:writeln('The send of packet #',w:0,' was canceled.');
|
||||
{ impossible, as this cancelation to be done by THIS program, and it doesn't }
|
||||
$FD:writeln('Packet# ',w:0,' is malformed and was not sent.');
|
||||
{ illegal param: packet length, number of fragments, fragment size. }
|
||||
$FE:writeln('Packet# ',w:0,' was undelivered. No stations listening.');
|
||||
$FF:writeln('Packet# ',w:0,' not sent due to a hardware error.');
|
||||
end;
|
||||
|
||||
{ Wait 5 seconds between sending packets }
|
||||
delay(5000);
|
||||
UNTIL keypressed;
|
||||
|
||||
IF NOT IPXcloseSocket(IOsocket)
|
||||
then writeln('IPXcloseSocket returned error# ',nwIPX.result);
|
||||
|
||||
end.
|
||||
125
NWTP/XIPX/S_PEP.PAS
Normal file
125
NWTP/XIPX/S_PEP.PAS
Normal file
@@ -0,0 +1,125 @@
|
||||
{$X+,V-,B-}
|
||||
program S_PEP;
|
||||
|
||||
{ Testprogram for the nwPEP unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
uses crt,nwMisc,nwIPX,nwPEP; { Listener/ Slave }
|
||||
|
||||
{ Listen for incoming packet.. sent acknowledgement of receipt }
|
||||
|
||||
{ Note that the acknowledgement is done automatically by the receiving ESR }
|
||||
|
||||
CONST IOSocket=$5678;
|
||||
|
||||
Var ListenECB :Tecb;
|
||||
ListenPepHdr :TpepHeader;
|
||||
|
||||
SendECB :Tecb;
|
||||
SendPepHdr :TpepHeader;
|
||||
|
||||
socket :word;
|
||||
buf :array[1..546] of byte;
|
||||
t :byte;
|
||||
ReceivedBufLen:word;
|
||||
PacketReceived:boolean;
|
||||
|
||||
NewStack:array[1..1024] of word; { !! used by ESR }
|
||||
StackBottom:word; { !! used by ESR }
|
||||
|
||||
|
||||
|
||||
{$F+}
|
||||
Procedure ListenAndAckHandler(Var p:TPecb);
|
||||
begin
|
||||
If (ListenECB.CompletionCode<>0)
|
||||
or (ListenPepHdr.IPXhdr.packetType<>PEP_PACKET_TYPE)
|
||||
or (ListenPepHdr.clienttype<>$EA)
|
||||
then IPXlistenForPacket(ListenECB)
|
||||
else begin
|
||||
PacketReceived:=true;
|
||||
ListenPepHdr.IPXhdr.source.socket:=swap(ListenPepHdr.IPXhdr.source.socket);
|
||||
{ socket is hi-lo in IPX/PEPHeaders. SetupSendECB expects lo-hi }
|
||||
PEPsetupSendECB(NIL,IOsocket,ListenPepHdr.IPXhdr.source,@buf,0,
|
||||
SendPepHdr,SendECB);
|
||||
SendPepHdr.TransactionId:=ListenPepHdr.TransactionId;
|
||||
SendPepHdr.clientType:=$EA;
|
||||
IPXsendPacket(SendECB);
|
||||
end;
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
{$F+}
|
||||
Procedure ListenAndAckESR; assembler;
|
||||
asm { ES:SI are the only valid registers when entering this procedure ! }
|
||||
mov dx, seg stackbottom
|
||||
mov ds, dx
|
||||
|
||||
mov dx,ss { setup of a new local stack }
|
||||
mov bx,sp { ss:sp copied to dx:bx}
|
||||
mov ax,ds
|
||||
mov ss,ax
|
||||
mov sp,offset stackbottom
|
||||
push dx { push old ss:sp on new stack }
|
||||
push bx
|
||||
|
||||
push es { push es:si on stack as local vars }
|
||||
push si
|
||||
mov di,sp
|
||||
|
||||
push ss { push address of local ptr on stack }
|
||||
push di
|
||||
CALL ListenAndAckHandler
|
||||
|
||||
add sp,4 { skip stack ptr-copy }
|
||||
pop bx { restore ss:sp from new stack }
|
||||
pop dx
|
||||
mov sp,bx
|
||||
mov ss,dx
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
|
||||
Var dest:TinternetworkAddress;
|
||||
ticks,ticks2:word;
|
||||
|
||||
begin
|
||||
IF NOT IpxInitialize
|
||||
then begin
|
||||
writeln('Ipx needs to be installed.');
|
||||
halt(1);
|
||||
end;
|
||||
socket:=IOSocket;
|
||||
IF NOT IPXopenSocket(Socket,SHORT_LIVED_SOCKET)
|
||||
then begin
|
||||
writeln('IPXopenSocket returned error# ',nwIPX.result);
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
{ listen for incoming pep-packet }
|
||||
|
||||
PacketReceived:=False;
|
||||
{ Empty receive buffer (ListenECB.fragment[2].address^) }
|
||||
FillChar(buf,546,#0);
|
||||
|
||||
{ Setup ECB and IPX header }
|
||||
PEPSetupListenECB(Addr(ListenAndAckESR),IOsocket,@buf,546,
|
||||
ListenPepHdr,ListenECB);
|
||||
|
||||
IPXListenForPacket(ListenECB);
|
||||
writeln('Listening for incoming packet.');
|
||||
|
||||
IPXGetIntervalMarker(ticks);
|
||||
REPEAT
|
||||
IPXrelinquishControl;
|
||||
IPXGetIntervalMarker(ticks2)
|
||||
UNTIL PacketReceived or ((ticks2-ticks)>(30*18));
|
||||
|
||||
{ do something with received buffer }
|
||||
IF PacketReceived
|
||||
then writeln('Packet received and acknowledged.')
|
||||
else writeln('Timeout: no packet received in 30 seconds.');
|
||||
|
||||
IF NOT IPXcloseSocket(IOsocket)
|
||||
then writeln('IPXcloseSocket returned error# ',nwIPX.result);
|
||||
|
||||
end.
|
||||
30
NWTP/XIPX/TSTRIP.PAS
Normal file
30
NWTP/XIPX/TSTRIP.PAS
Normal file
@@ -0,0 +1,30 @@
|
||||
Program tstRIP;
|
||||
|
||||
USES NwMisc,NwIPX,NwRIP;
|
||||
|
||||
Var ripInfo:TRIPinfo;
|
||||
k,n :word;
|
||||
NetAddr:TnetworkAddress;
|
||||
begin
|
||||
IF NOT IPXinitialize
|
||||
then begin
|
||||
writeln('IPX must be loaded before this program can be ran.');
|
||||
halt(1);
|
||||
end;
|
||||
FillChar(NetAddr,4,#$0); { own segment }
|
||||
n:=GetAllNetworks(NetAddr,ripInfo);
|
||||
|
||||
writeln;
|
||||
writeln('MAIN: ',n,' network segment(s) found.');
|
||||
writeln('Dumping the RIP tables of all found segments...');
|
||||
writeln;
|
||||
|
||||
writeln('NetAddr Tcks Hops');
|
||||
for k:=1 to n
|
||||
do begin
|
||||
write(HexDumpStr(ripinfo[k].address,8));
|
||||
write(' ',ripinfo[k].ticks:4);
|
||||
writeln(' ',ripinfo[k].hops:4);
|
||||
end;
|
||||
writeln('End of RIP table dump.');
|
||||
end.
|
||||
246
NWTP/XIPX/VEND_XXX
Normal file
246
NWTP/XIPX/VEND_XXX
Normal file
@@ -0,0 +1,246 @@
|
||||
# -----------------------------------------------------------------------
|
||||
# VEND_XXX Ethernet Vendor Address Components
|
||||
# Ethernet Multicast Addresses
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
# This list is in 'First Fit' format, i.e. the first entry that matches
|
||||
# the ethernet address contains the 'most fitting' description.
|
||||
|
||||
# Example: cardno = 00001B40EF45. First Fit => 00001B4 'NE 2000'
|
||||
# cardno = 00001B267EA7. First Fit => 00001B 'Novell Eagle'
|
||||
|
||||
000000000001 Netware Server (dynamically assigned address)
|
||||
000002 BBN
|
||||
00000C Cisco
|
||||
00000E Fujitsu
|
||||
00000F NeXT
|
||||
000010 Sytek/Hughes LAN systems
|
||||
000011 Tektronics
|
||||
000015 Datapoint
|
||||
000018 Webster
|
||||
00001A AMD ?
|
||||
00001B4 Novell Eagle NE2000 (v1.12?)
|
||||
00001B3 Novell Eagle NE2000
|
||||
00001B2 Novell Eagle NE2000
|
||||
00001B1 Novell Eagle NE2000
|
||||
00001B Novell Eagle
|
||||
00001D Cabletron
|
||||
000020 DIAB (Data Intdustrier AB)
|
||||
000021 SC&C
|
||||
000022 Visual Technology (Vistec)
|
||||
000023 ABB
|
||||
000029 IMC
|
||||
00002A TRW
|
||||
00003C Auspex
|
||||
00003D ATT
|
||||
000044 Castelle
|
||||
000046 Bunker Ramo
|
||||
000049 Apricot
|
||||
00004B APT
|
||||
00004F Logicraft
|
||||
000051 Hob Electronic
|
||||
000052 ODS
|
||||
000055 AT & T
|
||||
00005A S & Koch/ ?Xerox
|
||||
00005D RCE
|
||||
00005E IANA
|
||||
000061 Gateway
|
||||
000062 Honeywell
|
||||
000065 Network General
|
||||
000069 Silicon Graphics
|
||||
00006B MIPS
|
||||
00006E Artisoft
|
||||
000077 MIPS
|
||||
000078 Labtam
|
||||
00007A Ardent
|
||||
00007B Research Machines
|
||||
00007D Cray Research/ ? Harris
|
||||
00007F Linotronic
|
||||
000080 Dowty Network Systems / ? Harris
|
||||
000081 SynOptics
|
||||
000084 ? Aquila
|
||||
000086 Gateway
|
||||
000089 Cayman Systems (Gatorbox)
|
||||
00008A Datahouse Information Systems
|
||||
00008E Jupiter ? Solbourne ?
|
||||
000093 Proteon
|
||||
000094 Asante
|
||||
000095 Sony/Tektronics
|
||||
000097 Epoch
|
||||
000098 CrossCom
|
||||
00009F Ameristar Technology
|
||||
0000A0 Sanyo Electronics
|
||||
0000A2 Wellfleet Communications
|
||||
0000A3 Network Application Technology (NAT)
|
||||
0000A6 Network General (internal assignment, not for products)
|
||||
0000A7 NCD (X-terminals)
|
||||
0000A8 Stratus
|
||||
0000A9 Network Systems
|
||||
0000AA Xerox
|
||||
0000B3 CIMLinc
|
||||
0000B7 Dove (Fastnet)
|
||||
0000BC Allen-Bradley
|
||||
0000C0 Western Digital (WD/SMC)
|
||||
0000C6 HP Intelligent Networks Operation (formerly Eon Systems)
|
||||
0000C8 Altos
|
||||
0000C9 Emulex (Terminal Servers)
|
||||
0000D7 Dartmouth College (NED Router)
|
||||
0000D8 3Com? Novell? PS/2
|
||||
0000DD Gould
|
||||
0000DE Unigraph
|
||||
0000E2 Acer (Counterpoint)
|
||||
0000EF Alantec
|
||||
0000FD High Level Hardware (Orion, UK)
|
||||
000102 BBN (internal usage - not registered)
|
||||
00082D Siemens Nixdorf: TACLAN ?
|
||||
001700 Kabel
|
||||
0020AF 3Com Etherlink III
|
||||
0040F62 Novell Eagle NE2000 (v1.05EC?)
|
||||
0040F6 Novell Eagle
|
||||
00608CF 3Com
|
||||
00608CB 3Com Etherlink III
|
||||
00608C5 3Com
|
||||
00608C 3Com
|
||||
008029 Novell Eagle ? / NE2000 compat. ?
|
||||
00802D Xylogics, Inc. Annex terminal servers
|
||||
00805A0 Tulip NCC16
|
||||
00805A1 AMD PCNTNW Ethernet
|
||||
00805A Tulip
|
||||
00805C Agilis ?
|
||||
00808C Frontier Software Development
|
||||
0080C2 IEEE (802.1 Committee)
|
||||
0080D3 Shiva
|
||||
00AA00 Intel (NetPort printserver)
|
||||
00C002 Trust (printserver)
|
||||
00DD00 Ungermann-Bass
|
||||
00DD01 Ungermann-Bass
|
||||
01005E1 IANA Internet Multicast (RFC-1112)
|
||||
01005E2 IANA Internet Multicast (RFC-1112)
|
||||
01005E3 IANA Internet Multicast (RFC-1112)
|
||||
01005E4 IANA Internet Multicast (RFC-1112)
|
||||
01005E5 IANA Internet Multicast (RFC-1112)
|
||||
01005E6 IANA Internet Multicast (RFC-1112)
|
||||
01005E6 IANA Internet Multicast (RFC-1112)
|
||||
01005E7 IANA Internet Multicast (RFC-1112)
|
||||
01005E8 IANA Internet reserved (Multicast)
|
||||
01005E9 IANA Internet reserved (Multicast)
|
||||
01005EA IANA Internet reserved (Multicast)
|
||||
01005EB IANA Internet reserved (Multicast)
|
||||
01005EC IANA Internet reserved (Multicast)
|
||||
01005ED IANA Internet reserved (Multicast)
|
||||
01005EE IANA Internet reserved (Multicast)
|
||||
01005EF IANA Internet reserved (Multicast)
|
||||
0180C2000000 Spanning tree (for bridges) (Multicast)
|
||||
020701 Racal/Micom InterLan
|
||||
020406 BBN (internal usage - not registered)
|
||||
026086 Satelcom MegaPac (UK)
|
||||
02608C 3Com (IBM PC; Imagen; Valid; Cisco)
|
||||
02CF1F CMC (Masscomp; Silicon Graphics; Prime EXL)
|
||||
080001 CmpVsn ?
|
||||
080002 3Com (Formerly Bridge)
|
||||
080003 ACC (Advanced Computer Communications)
|
||||
080005 Symbolics (LISP machines)
|
||||
080006 Siemens-Nixdorf
|
||||
080007 Apple
|
||||
080008 BBN
|
||||
080009 Hewlett-Packard
|
||||
08000A Nestar Systems
|
||||
08000B Unisys
|
||||
080010 AT & T
|
||||
080011 Tektronix, Inc.
|
||||
080014 Excelan (BBN Butterfly, Masscomp, Silicon Graphics)
|
||||
080017 NSC
|
||||
08001A Data General
|
||||
08001B Data General
|
||||
08001E Apollo
|
||||
080020 Sun (Sun microsystems)
|
||||
080022 NBI
|
||||
080025 CDC
|
||||
080026 Norsk Data (Nord)
|
||||
080027 PCS Computer Systems GmbH
|
||||
080028 Texas Instruments (Explorer)
|
||||
08002B DEC
|
||||
08002E Metaphor
|
||||
08002F Prime Computer (Prime 50-Series LHC300)
|
||||
080036 Intergraph (CAE stations)
|
||||
080037 Fujitsu-Xerox
|
||||
080038 Bull
|
||||
080039 Spider Systems
|
||||
080041 DCA Digital Comm. Assoc.
|
||||
080045 Xylogic !? (they claim not to know this number)
|
||||
080046 Sony
|
||||
080047 Sequent
|
||||
080049 Univation
|
||||
08004C Encore
|
||||
08004E BICC
|
||||
080056 Stanford University
|
||||
080058 DECsystem-20
|
||||
08005A IBM
|
||||
08005C Agilis ??
|
||||
080067 Comdesign
|
||||
080068 Ridge
|
||||
080069 Silicon Graphics
|
||||
08006A AT & T
|
||||
08006E Excelan
|
||||
080075 DDE (Danish Data Elektronik A/S)
|
||||
08007C Vitalink (TransLAN III)
|
||||
080080 XIOS
|
||||
080086 Imagen/QMS
|
||||
080087 Xyplex (terminal servers)
|
||||
080089 Kinetics (AppleTalk-Ethernet interface)
|
||||
08008B Pyramid
|
||||
08008D XyVision (XyVision machines)
|
||||
080090 Retix Inc. (Bridges)
|
||||
090002040001 ? Vitalink printer (Multicast)
|
||||
090002040002 ? Vitalink management (Multicast)
|
||||
090009000001 HP Probe (Multicast)
|
||||
090009000001 HP Probe (Multicast)
|
||||
090009000004 HP DTC (Multicast)
|
||||
09001E000000 Apollo DOMAIN (Multicast)
|
||||
09002B000000 DEC MUMPS? (Multicast)
|
||||
09002B000001 DEC DSM/DTP? (Multicast)
|
||||
09002B000002 DEC VAXELN? (Multicast)
|
||||
09002B000003 DEC Lanbridge Traffic Monitor (LTM) (Multicast)
|
||||
09002B000004 DEC MAP End System Hello (Multicast)
|
||||
09002B000005 DEC MAP Intermediate System Hello (Multicast)
|
||||
09002B000006 DEC CSMA/CD Encryption? (Multicast)
|
||||
09002B000007 DEC NetBios Emulator? (Multicast)
|
||||
09002B00000F DEC Local Area Transport (LAT) (Multicast)
|
||||
09002B00001 DEC Experimental (Multicast)
|
||||
09002B010000 DEC LanBridge Copy packets (All bridges) (Multicast)
|
||||
09002B010001 DEC LanBridge Hello packets (All local bridges) (Multicast)
|
||||
09002B020000 DEC DNA Lev.2 Routing Layer routers? (Multicast)
|
||||
09002B020100 DEC DNA Naming Service Advertisement? (Multicast)
|
||||
09002B020101 DEC DNA Naming Service Solicitation? (Multicast)
|
||||
09002B020102 DEC DNA Time Service? (Multicast)
|
||||
09002B03 DEC default filtering by bridges? (Multicast)
|
||||
09002B040000 DEC Local Area Sys. Transport (LAST)? (Multicast)
|
||||
09002B230000 DEC Argonaut Console? (Multicast)
|
||||
09004E000002 ? Novell IPX (Multicast)
|
||||
090056FF Stanford V Kernel, version 6.0 (Multicast)
|
||||
090056 ? Stanford reserved (Multicast)
|
||||
090077000001 Retix spanning tree bridges (Multicast)
|
||||
09007C020005 Vitalink diagnostics (Multicast)
|
||||
09007C050001 Vitalink gateway? (Multicast)
|
||||
0D1E15BADD06 HP (Multicast)
|
||||
484453 HDS ???
|
||||
800010 AT&T
|
||||
AA0000 DEC - multicast (obsolete)
|
||||
AA0001 DEC - multicast (obsolete)
|
||||
AA0002 DEC - multicast (obsolete)
|
||||
AA0003 DEC - multicast (Global physical address for some DEC machines)
|
||||
AA0004 DEC - multicast (Local logical address for systems running DECNET)
|
||||
AA002C Intel ?? (Multicast)
|
||||
AB0000010000 DEC Maintenance Operation Protocol (MOP) Dump/Load Assistance (Multicast)
|
||||
AB0000020000 DEC MOP (System ID packets) DEC LanBridge/DEUNA/DELUA/DEQNA) (Multicast)
|
||||
AB0000030000 DECNET Phase IV (end node Hello packets) DECNET host (Multicast)
|
||||
AB0000040000 DECNET Phase IV (Router Hello packets) DECNET router (Multicast)
|
||||
AB00000 Reserved by DEC (Multicast)
|
||||
AB0001 Reserved by DEC (Multicast)
|
||||
AB0002 Reserved by DEC (Multicast)
|
||||
AB0003000000 DEC Local Area Transport (LAT) -old (Multicast)
|
||||
AB0003 Reserved by DEC (Multicast)
|
||||
AB000400 Reserved DEC customer private use (Multicast)
|
||||
AB000401 DEC Local Area VAX Cluster groups Sys. Communication Architecture (SCA) (Multicast)
|
||||
CF0000000000 Ethernet Configuration Test protocol (Loopback) (Multicast)
|
||||
FFFFFFFFFFFF (Multicast address - Used by numerous systems - see RFC 1340)
|
||||
74
NWTP/XLOCK/TSTLRL.PAS
Normal file
74
NWTP/XLOCK/TSTLRL.PAS
Normal file
@@ -0,0 +1,74 @@
|
||||
Program TstLRL;
|
||||
|
||||
{ Example for the nwLock unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Tests the following nwLock calls: (Logical Record Locking)
|
||||
|
||||
LogLocalRecord
|
||||
LockLogicalrecordSet
|
||||
ReleaseLogicalRecord
|
||||
ClearLogicalRecordSet
|
||||
|
||||
}
|
||||
|
||||
Uses nwLock; { using this unit will automatically set the locmode to 1 }
|
||||
|
||||
Var RecordName:string;
|
||||
TimeOutTicks:word;
|
||||
|
||||
begin
|
||||
TimeOutTicks:=360; {wait 20 seconds before locking process times out}
|
||||
|
||||
writeln('TSTLRL: Test of logical record locking.');
|
||||
writeln(' -Start the exe on 2 or more workstations & enjoy the effect.');
|
||||
writeln;
|
||||
writeln('Suppose we want to perform a transaction on a file, where:');
|
||||
writeln('-we want to update (read&write) Records # 123, 678 and 056.');
|
||||
writeln;
|
||||
writeln('To do this, this program uses logical record locking in the following manner:');
|
||||
writeln('-It locks records #123,678 and 056 in Exclusive mode.');
|
||||
writeln(' (denying all attempts at locking by other stations.');
|
||||
|
||||
{ Put the names of records-to-be-EXCLUSIVELY-locked in the 'logged record set' }
|
||||
RecordName:='#123';
|
||||
IF NOT LogLogicalRecord(RecordName,LD_LOG,0)
|
||||
then writeln('LogRecord failed. Error# ',nwLock.result);
|
||||
{ Note: The recordnames used have no linkage whatsover with physical
|
||||
records. They form a logical representation of a physical record.
|
||||
All processes involved in locking processes on the same data must
|
||||
use the same naming convention }
|
||||
RecordName:='#678';
|
||||
IF NOT LogLogicalRecord(RecordName,LD_LOG,0)
|
||||
then writeln('LogRecord failed. Error# ',nwLock.result);
|
||||
RecordName:='#056';
|
||||
IF NOT LogLogicalRecord(RecordName,LD_LOG,0)
|
||||
then writeln('LogRecord failed. Error# ',nwLock.result);
|
||||
|
||||
{ Lock all records that are currently stored in the 'logged record set' }
|
||||
writeln('Attempting to place locks on records.. ');
|
||||
|
||||
|
||||
IF NOT LockLogicalRecordSet(LD_LOCK,TimeoutTicks)
|
||||
then writeln('LockLogicalRecordSet (after TimeOut=20 sec) failed. Error# ',nwLock.result);
|
||||
|
||||
if nwlock.result=0 { locking of records was successful }
|
||||
then begin
|
||||
{ ---Update records, change records, etc.--- }
|
||||
|
||||
{ Readln to simulate update }
|
||||
writeln('Now ''processing'' locked records. Press RETURN to release locks.');
|
||||
readln;
|
||||
|
||||
{ Suppose we're done with record #123, but still need the other record
|
||||
-unlock 1 record; keep record in log }
|
||||
IF NOT ReleaseLogicalRecord('#123')
|
||||
then writeln('ReleaseLogicalRecord Failed. Error# ',nwLock.result);
|
||||
|
||||
writeln('Now ''processing'' still locked records');
|
||||
end;
|
||||
|
||||
{ unlock all records; clear 'logged record set' }
|
||||
IF NOT ClearLogicalRecordSet
|
||||
then writeln('ClearLogicalRecordSet Failed. Error# ',nwLock.result);
|
||||
|
||||
end.
|
||||
65
NWTP/XLOCK/TSTPFL.PAS
Normal file
65
NWTP/XLOCK/TSTPFL.PAS
Normal file
@@ -0,0 +1,65 @@
|
||||
Program TstPFL;
|
||||
|
||||
{ Example for the nwLock unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Tests the following nwLock calls: (Physical File Locking)
|
||||
|
||||
ClearPhysicalFileSet
|
||||
LogPhysicalFile
|
||||
LockPhysicalFileSet
|
||||
ReleasePhysicalFile
|
||||
}
|
||||
|
||||
Uses nwFile,nwLock; { using this unit will automatically set the locmode to 1 }
|
||||
|
||||
Var FileName:string;
|
||||
TimeOutTicks:word;
|
||||
|
||||
begin
|
||||
TimeOutTicks:=360; {wait 20 seconds before locking process times out}
|
||||
|
||||
writeln('TSTLF: Test of logical file locking.');
|
||||
writeln(' -Make sure the files referenced to in this example exist.');
|
||||
writeln(' -Start the exe on 2 or more workstations & enjoy the effect.');
|
||||
writeln;
|
||||
|
||||
{ Put the names of files-to-be-locked in the 'logged file set' }
|
||||
FileName:='SYS:PUBLIC/SYSCON.EXE';
|
||||
IF NOT LogPhysicalFile(FileName,LD_LOG,0)
|
||||
then writeln('Logfile failed. Error# ',nwLock.result);
|
||||
{ Note: The files specified have to exist, or an error 156 is
|
||||
returned. Using EXE files instead of data files can be
|
||||
a bit confusing in this example, but at least those
|
||||
files are very likely to be there. }
|
||||
FileName:='SYS:\PUBLIC\PCONSOLE.EXE';
|
||||
IF NOT LogPhysicalFile(FileName,LD_LOG,0)
|
||||
then writeln('Logfile failed. Error# ',nwLock.result);
|
||||
{ Repeat logging process for other (if needed) }
|
||||
|
||||
|
||||
{ Lock all files that are currently stored in the 'logged file set' }
|
||||
writeln('Attempting to Lock files.. ');
|
||||
IF NOT LockPhysicalFileSet(TimeOutTicks)
|
||||
then writeln('LockFileSet (after TimeOut=20 sec) failed. Error# ',nwLock.result);
|
||||
|
||||
if nwlock.result=0 { locking of files was successful }
|
||||
then begin
|
||||
{ ---Update file, change file, etc.--- }
|
||||
|
||||
{ Readln to simulate update }
|
||||
writeln('Now ''processing'' files. Press RETURN to release locks.');
|
||||
readln;
|
||||
|
||||
{ Suppose we're done with the 1st datafile, but still need file #2:
|
||||
-unlock 1 single file; keep in log }
|
||||
IF NOT ReleasePhysicalFile('SYS:\PUBLIC\SYSCON.EXE')
|
||||
then writeln('ReleaseFile Failed. Error# ',nwLock.result);
|
||||
|
||||
writeln('Now ''processing'' still locked file');
|
||||
end;
|
||||
|
||||
{ unlock all files; clear 'logged file set' }
|
||||
IF NOT ClearPhysicalFileSet
|
||||
then writeln('ClearFileSet Failed. Error# ',nwLock.result);
|
||||
|
||||
end.
|
||||
409
NWTP/XMESS/PMAIL.PAS
Normal file
409
NWTP/XMESS/PMAIL.PAS
Normal file
@@ -0,0 +1,409 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
Unit pmail;
|
||||
|
||||
{Example unit for the nwMess unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
INTERFACE
|
||||
|
||||
uses nwMisc,nwBindry,nwMess,nwServ;
|
||||
{nwserv used for GetFileServerDateAndTime only. }
|
||||
|
||||
CONST {Mail Options}
|
||||
PM_NO_NOTIFY =$02;
|
||||
PM_DELIVER_IF_AF=$10;
|
||||
PM_NO_CONF_REQ =$08;
|
||||
PM_NO_MAIL =$04;
|
||||
|
||||
Var result:word;
|
||||
|
||||
Function PMailInstalled:boolean;
|
||||
{ Checks if an object PEGASUS_MAIL of type OT_PEGASUS_MAIL exists
|
||||
in the bindery. If the object exists, pmail is installed.}
|
||||
|
||||
Function SendMailFile(DestObjectName:string;objType:word;
|
||||
subject,fileName:string):boolean;
|
||||
{ PEGASUS MAIL V3.0 Compatible:
|
||||
|
||||
Sends a messagebody textfile (ASCII) to the mail directory of the
|
||||
destination object. The object can either be a user or a group object.
|
||||
Wildcards are allowed.
|
||||
|
||||
The destination object will see the calling object as the message
|
||||
originating object.
|
||||
|
||||
Notes:
|
||||
-Autoforwarding will be ignored.
|
||||
-This is a single server function.
|
||||
-Possible resultcodes:
|
||||
$0 Success;
|
||||
|
||||
$100 * The given file could not be found. Supply full path and filename.
|
||||
$101 * User and Group objects only;
|
||||
$102 ? Error scanning bindery, see Nwbindry.Result for netware error # ;
|
||||
$110 ? Group has no members / error reading members of a group.
|
||||
$111 * Group or user object doesn't exist
|
||||
|
||||
$200 * Insufficient privilege to use the mail system.
|
||||
$201 * You are not allowed to send to groups.
|
||||
$202 * The supplied receiver user object has no access to mail /
|
||||
has halted all incoming mail OR
|
||||
the receiving object equals the sending object.
|
||||
|
||||
-All msgs were sent when the resultcode is $00;
|
||||
-No msgs are send. (resultcodes marked with *)
|
||||
-Some or no msgs may have been sent before this error occured.(marked ?)
|
||||
}
|
||||
|
||||
IMPLEMENTATION{=============================================================}
|
||||
|
||||
Function PMailInstalled:boolean;
|
||||
Var lastObj :LongInt;
|
||||
foundObjName:string;
|
||||
rt :word;
|
||||
rid :LongInt;
|
||||
rf,rs :byte;
|
||||
rhp :Boolean;
|
||||
begin
|
||||
{ Checks if an object PEGASUS_MAIL of type OT_PEGASUS_MAIL exists
|
||||
in the bindery. If the object exists, pmail is installed.}
|
||||
lastObj:=-1;
|
||||
PmailInstalled:=ScanBinderyObject('PEGASUS_MAIL',OT_PEGASUS_MAIL,lastObj,
|
||||
foundObjName,rt,rid,rf,rs,rhp);
|
||||
end;
|
||||
|
||||
{------------------Send file as message--------------------------------------}
|
||||
|
||||
Type TPmailHdr=record
|
||||
from,too,date,subject,xmailer:string;
|
||||
end;
|
||||
|
||||
var senderObjId:LongInt;
|
||||
warning :byte;
|
||||
time :TnovTime;
|
||||
|
||||
|
||||
Procedure getRandomFileName(Var filename:string);
|
||||
{ construct a semi-random filename out of the current date & time }
|
||||
Var tim:TnovTime;
|
||||
t :byte;
|
||||
begin
|
||||
nwServ.GetFileServerDateAndTime(tim);
|
||||
fileName[0]:=#8;
|
||||
filename[1]:=chr(tim.month);
|
||||
filename[2]:=chr(tim.day);
|
||||
filename[3]:=chr(tim.hour);
|
||||
filename[4]:=chr(tim.min DIV 2);
|
||||
filename[5]:=chr(tim.sec DIV 2);
|
||||
filename[6]:=chr(random(36));
|
||||
filename[7]:=chr(random(36));
|
||||
filename[8]:=chr(random(36));
|
||||
for t:=1 to 8
|
||||
do if filename[t]<=#9 then inc(filename[t],ord('0'))
|
||||
else inc(filename[t],ord('A')-10);
|
||||
end;
|
||||
|
||||
Function IsObjGroupMember(objId:longInt;GroupName:string):boolean;
|
||||
Var objName:string;
|
||||
objType:word;
|
||||
begin
|
||||
IsObjGroupMember:=GetBinderyObjectName(objId,objName,objType)
|
||||
and IsBinderyObjectInSet(GroupName,OT_USER_GROUP,'GROUP_MEMBERS',
|
||||
objName,OT_USER);
|
||||
end;
|
||||
|
||||
Function PmailNotifyUser(objName:string):boolean;
|
||||
{ Read the MAIL_OPTIONS property (created by Pmail) of the destination object.
|
||||
Structure of the property:
|
||||
|
||||
01 len Pmail_forwarding_adress_(asciiz) [OPTIONAL]
|
||||
02 len Internet_forwarding_adress_(asciiz) [OPTIONAL]
|
||||
03 04 extended_features_byte ???_byte [NOT optional]
|
||||
04 len Charon 3.5+ sender synonym. [OPTIONAL]
|
||||
|
||||
Notes: -len= 3+length of the next asciiz string (excluding trailing 0)
|
||||
-the above fields appear within the property in random order.
|
||||
|
||||
If the PM_NO_NOTIFY or the PM_NO_MAIL flag within the extended features
|
||||
byte is set, then the destination object won't be notified. }
|
||||
Var segNbr :word;
|
||||
propValue:Tproperty;
|
||||
moreSeg :boolean;
|
||||
propFlags:Byte;
|
||||
t :word;
|
||||
fieldFlag:byte;
|
||||
Notify :boolean;
|
||||
begin
|
||||
SegNbr:=1;
|
||||
warning:=$00;
|
||||
IF ReadPropertyValue(objName,OT_USER,'MAIL_OPTIONS',SegNbr,
|
||||
propValue,moreSeg,propFlags)
|
||||
then begin
|
||||
t:=1;
|
||||
|
||||
REPEAT
|
||||
fieldFlag:=propValue[t];
|
||||
if fieldFlag<>3 then t:=t+propValue[t+1];
|
||||
UNTIL (t>127) or (fieldFlag=3);
|
||||
|
||||
if fieldFlag=3
|
||||
then begin
|
||||
Notify:=((propValue[t+2] and PM_NO_NOTIFY)=0)
|
||||
and ((propValue[t+2] and PM_NO_MAIL)=0);
|
||||
if (propValue[t+2] and PM_NO_MAIL)>0
|
||||
then warning:=$02;
|
||||
end;
|
||||
end
|
||||
else if nwBindry.result=$EC { empty property, default: notify. }
|
||||
then Notify:=true
|
||||
else Notify:=false; { when in doubt, don't notify }
|
||||
PmailNotifyUser:=Notify;
|
||||
end;
|
||||
|
||||
|
||||
Procedure SendMsgToUser(UserObjID:LongInt;VAR Hdr:TPmailHdr;fileName:string);
|
||||
{copy file as a msg to the users' mail directory.}
|
||||
Var userObjName:string;
|
||||
objType :word;
|
||||
buffer :array[1..4096] of byte;
|
||||
bytesRead,bufOffs:word;
|
||||
MsgFilePath,MailDir,MailFile:string;
|
||||
Fin,Fout :file;
|
||||
sendIt,NotifyReceiver:boolean;
|
||||
MsgFrom :string;
|
||||
begin
|
||||
SendIt:=NOT(UserObjId=SenderObjId); { don't mail yourself }
|
||||
|
||||
{ checking Pmail settings.. }
|
||||
IF IsObjGroupMember(UserObjId,'NOMAILBOX')
|
||||
then SendIt:=false;
|
||||
|
||||
IsObjGroupMember(UserObjId,'MAILUSERS');
|
||||
if (nwBindry.result=$EA) { no such member }
|
||||
OR IsObjGroupMember(UserObjId,'NOMAIL')
|
||||
then sendit:=false;
|
||||
|
||||
GetBinderyObjectName(UserObjID,UserObjName,objType);
|
||||
NotifyReceiver:=PmailNotifyUser(UserObjName);
|
||||
if warning=$02 { receiving user has PM_NO_MAIL flag raised }
|
||||
then sendit:=false;
|
||||
|
||||
if sendit
|
||||
then begin
|
||||
warning:=$00;
|
||||
if pos('From',hdr.from)=0
|
||||
then Hdr.from:= 'From: '+Hdr.from;
|
||||
MsgFrom:=Hdr.From; delete(MsgFrom,1,16);
|
||||
Hdr.too := 'To: '+UserObjName;
|
||||
if pos('Date',Hdr.date)=0
|
||||
then Hdr.date:= 'Date: '+Hdr.date;
|
||||
if pos('Subj',Hdr.subject)=0
|
||||
then Hdr.subject:='Subject: '+hdr.subject;
|
||||
Hdr.xmailer:='X-mailer: NwTP gateway to Pmail.';
|
||||
|
||||
bufOffs:=1;
|
||||
move(hdr.from[1],buffer[bufOffs],ord(hdr.from[0]));
|
||||
inc(bufOffs,2+ord(hdr.from[0]));
|
||||
buffer[bufOffs-2]:=13;buffer[bufOffs-1]:=10; { ret/ lf }
|
||||
move(hdr.too[1],buffer[bufOffs],ord(hdr.too[0]));
|
||||
inc(bufOffs,2+ord(hdr.too[0]));
|
||||
buffer[bufOffs-2]:=13;buffer[bufOffs-1]:=10; { ret/ lf }
|
||||
move(hdr.date[1],buffer[bufOffs],ord(hdr.date[0]));
|
||||
inc(bufOffs,2+ord(hdr.date[0]));
|
||||
buffer[bufOffs-2]:=13;buffer[bufOffs-1]:=10; { ret/ lf }
|
||||
move(hdr.subject[1],buffer[bufOffs],ord(hdr.subject[0]));
|
||||
inc(bufOffs,2+ord(hdr.subject[0]));
|
||||
buffer[bufOffs-2]:=13;buffer[bufOffs-1]:=10; { ret/ lf }
|
||||
move(hdr.xmailer[1],buffer[bufOffs],ord(hdr.xmailer[0]));
|
||||
inc(bufOffs,2+ord(hdr.xmailer[0]));
|
||||
buffer[bufOffs-2]:=13;buffer[bufOffs-1]:=10; { ret/ lf }
|
||||
buffer[bufOffs]:=13;buffer[bufOffs+1]:=10; { empty line }
|
||||
inc(bufOffs,2);
|
||||
|
||||
MailDir:=HexStr(UserObjId,8);
|
||||
while maildir[1]='0' do delete(Maildir,1,1);
|
||||
GetRandomFileName(MailFile);
|
||||
|
||||
{$I-}
|
||||
MsgFilePath:='SYS:MAIL\'+MailDir+'\'+MailFile+'.CNM';
|
||||
assign(Fin,fileName);
|
||||
reset(Fin,1);
|
||||
assign(Fout,MsgFilePath);
|
||||
rewrite(Fout,1);
|
||||
{ buffOfs-1 = number of bytes in buffer already filled }
|
||||
BlockRead(Fin,buffer[bufOffs],4096-(bufOffs-1),bytesRead);
|
||||
BlockWrite(Fout,buffer[1],bytesRead+(bufOffs-1));
|
||||
REPEAT
|
||||
BlockRead(Fin,buffer[1],4096,bytesRead);
|
||||
BlockWrite(Fout,buffer[1],bytesRead);
|
||||
UNTIL bytesRead<4096;
|
||||
close(Fin);
|
||||
close(Fout);
|
||||
{$I+}
|
||||
|
||||
IF NotifyReceiver
|
||||
then nwMess.SendmessageToUser(UserObjName,
|
||||
'(NwTP/Pmail:) You have mail. (From:'+MsgFrom+')')
|
||||
end
|
||||
else warning:=$01;
|
||||
end;
|
||||
|
||||
Procedure SendMsgToGroup(GroupObjName:string;Hdr:TPmailHdr;fileName:string);
|
||||
Label abrt;
|
||||
Var NbrOfWrites:word;
|
||||
i :byte;
|
||||
|
||||
lastObj :LongInt;
|
||||
foundGroupName:string;
|
||||
rt :word;
|
||||
rid :LongInt;
|
||||
rf,rs :byte;
|
||||
rhp :boolean;
|
||||
|
||||
SegNbr :byte;
|
||||
propValue:Tproperty;
|
||||
moreSeg :boolean;
|
||||
propFlags:byte;
|
||||
|
||||
objId : LongInt;
|
||||
begin
|
||||
NbrOfWrites:=0;
|
||||
lastObj:=-1;
|
||||
WHILE ScanBinderyObject(GroupObjName,OT_USER_GROUP,lastObj,
|
||||
foundGroupName,rt,rid,rf,rs,rhp)
|
||||
do begin {1}
|
||||
if (GroupObjName<>'NOMAIL') and (GroupObjName<>'NOMAILBOX')
|
||||
then begin {3}
|
||||
SegNbr:=1;
|
||||
While ReadPropertyValue(foundGroupName,OT_USER_GROUP,'GROUP_MEMBERS',
|
||||
SegNbr,propValue,moreSeg,propFlags)
|
||||
do begin {5}
|
||||
i:=1;
|
||||
Repeat
|
||||
objId:=MakeLong((PropValue[i] *256 +PropValue[i+1]),
|
||||
(PropValue[i+2] *256 + PropValue[i+3] ) );
|
||||
if objId<>0
|
||||
then begin
|
||||
SendMsgToUser(objId,Hdr,fileName);
|
||||
inc(NbrOfWrites);
|
||||
end;
|
||||
inc(i,4);
|
||||
Until (i>128) or (objId=0);
|
||||
inc(SegNbr);
|
||||
end; {5}
|
||||
If nwBindry.Result<>$EC {no such segment}
|
||||
then begin
|
||||
Result:=$110;
|
||||
goto abrt;
|
||||
end;
|
||||
end; {3}
|
||||
end; {1}
|
||||
if nwBindry.Result<>$FC {no such object}
|
||||
then begin
|
||||
result:=$111;
|
||||
goto abrt;
|
||||
end;
|
||||
if NbrOfWrites=0 {no users found}
|
||||
then result:=$110;
|
||||
|
||||
abrt: ;
|
||||
end;
|
||||
|
||||
|
||||
Function SendMailFile(DestObjectName:string;objType:word;
|
||||
subject,fileName:string):boolean;
|
||||
Var secLevel :byte;
|
||||
senderName:string;
|
||||
SenderObjType:word;
|
||||
Hdr :TPmailHdr;
|
||||
lastObj :longInt;
|
||||
foundUserName:string;
|
||||
rt :word;
|
||||
rf,rs :byte;
|
||||
rhp :boolean;
|
||||
DestObjId :longint;
|
||||
testFile :file;
|
||||
begin
|
||||
Warning:=$00;
|
||||
|
||||
{ check: does filename exist? if not, stop right away. error $100 }
|
||||
{$I-}
|
||||
assign(testFile,filename);
|
||||
reset(testFile);
|
||||
if IOresult<>0
|
||||
then begin
|
||||
result:=$100;
|
||||
SendmailFile:=False;
|
||||
exit;
|
||||
end
|
||||
else close(testFile);
|
||||
{$I+}
|
||||
|
||||
GetBinderyAccessLevel(secLevel,senderObjId);
|
||||
GetBinderyObjectName(senderObjId,senderName,SenderObjType);
|
||||
|
||||
{checking pmail config. groups... }
|
||||
IsObjGroupMember(senderObjId,'MAILUSERS');
|
||||
if (nwBindry.result=$EA) { mailusers group exists, sender not a member }
|
||||
OR IsObjGroupMember(senderObjId,'NOMAIL')
|
||||
then begin
|
||||
result:=$200; { Insufficient privilege to use the mail system. }
|
||||
SendMailFile:=false;
|
||||
exit;
|
||||
end;
|
||||
|
||||
Hdr.from:=senderName;
|
||||
Hdr.subject:=subject;
|
||||
GetFileServerDateAndTime(time);
|
||||
NovTime2String(time,Hdr.date);
|
||||
|
||||
Result:=0;
|
||||
if objType=OT_USER
|
||||
then begin
|
||||
lastObj:=-1;
|
||||
WHILE ScanBinderyObject(DestObjectName,OT_USER,lastObj,
|
||||
foundUserName,rt,DestObjID,rf,rs,rhp)
|
||||
do begin
|
||||
SendMsgToUser(DestObjId,Hdr,fileName);
|
||||
end;
|
||||
IF nwBindry.result<>$FC { no such object } then result:=$102;
|
||||
end
|
||||
else if objType=OT_USER_GROUP
|
||||
then begin
|
||||
IsObjGroupMember(senderObjId,'GROUPMAIL');
|
||||
if (nwBindry.result=$EA) { group groupmail exists, sender not a member }
|
||||
OR IsObjGroupMember(senderObjId,'NOGROUPMAIL')
|
||||
then result:=$201 { don't send }
|
||||
else SendMsgToGroup(DestObjectName,Hdr,fileName)
|
||||
end
|
||||
else result:=$101;
|
||||
|
||||
if (warning=$01) and (objType=OT_USER) and (result=$00)
|
||||
and (pos('*',DestObjectName)=0) and (pos('?',DestObjectName)=0)
|
||||
then result:=$202;
|
||||
|
||||
SendMailFile:=(result=0);
|
||||
{ possible resultcodes:
|
||||
$0 Success;
|
||||
|
||||
$100 * The given file could not be found. Supply full path and filename.
|
||||
$101 * User and Group objects only;
|
||||
$102 ? Error scanning bindery, see Nwbindry.Result for netware error # ;
|
||||
$110 ? Group has no members / error reading members of a group.
|
||||
$111 * Group or user object doesn't exist
|
||||
|
||||
$200 * Insufficient privilege to use the mail system.
|
||||
$201 * You are not allowed to send to groups.
|
||||
$202 * The supplied receiver user object has no access to mail /
|
||||
has halted all incoming mail OR
|
||||
the receiving object equals the sending object.
|
||||
|
||||
Note: -All msgs were send when the resultcode is $00;
|
||||
-No msgs are send. (resultcodes marked with *)
|
||||
-Some or no msgs may have been send before this error occured.(marked ?)
|
||||
}
|
||||
end;
|
||||
|
||||
begin
|
||||
Randomize;
|
||||
end.
|
||||
118
NWTP/XMESS/TSTMESS.PAS
Normal file
118
NWTP/XMESS/TSTMESS.PAS
Normal file
@@ -0,0 +1,118 @@
|
||||
{$X+,B-,V-}
|
||||
program test;
|
||||
|
||||
{ Test program for the nwMess unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Test the following nwMess functions:
|
||||
|
||||
BroadcastToConsole
|
||||
GetBroadcastMessage
|
||||
GetBroadCastMode
|
||||
SetBroadcastMode
|
||||
SendBroadcastMessage
|
||||
SendConsoleBroadcast
|
||||
|
||||
}
|
||||
|
||||
uses nwmisc,nwMess;
|
||||
|
||||
Var t,tbm,bm:byte;
|
||||
connL,connResultL:TconnectionList;
|
||||
mess :string;
|
||||
|
||||
Procedure DisplayBrMode(bm:byte);
|
||||
begin
|
||||
Case bm of
|
||||
00: begin writeln('Server Stores : Netware Messages and User Messages,');
|
||||
writeln('Shell automaticly displays messages.')
|
||||
end;
|
||||
01: begin writeln('Server Stores : Server Messages. (User messages discarded)');
|
||||
writeln('Shell automaticly displays messages.')
|
||||
end;
|
||||
02: begin writeln('Server stores : Server messages only.');
|
||||
writeln('Applications have to use GetBroadCastMessage to see if there is a message.')
|
||||
end;
|
||||
03: begin writeln('Server stores : Server messages and User messages.');
|
||||
writeln('Applications have to use GetBroadCastMessage to see if there is a message.')
|
||||
end;
|
||||
else writeln('Unknown broadcastMode')
|
||||
end; {case}
|
||||
end;
|
||||
|
||||
begin
|
||||
writeln;
|
||||
writeln('Testing BroadcastToConsole..');
|
||||
writeln('This will make the server beep ! (NOT an error this time)');
|
||||
writeln;
|
||||
writeln('<Return> to continue..');
|
||||
readln(mess);
|
||||
|
||||
if BroadcastToConsole('Hello, Console Operator!')
|
||||
then writeln('BroadcastToConsole: Msg was broadcasted..')
|
||||
else writeln('Broadcast To Console error:'+hexstr(nwMess.result,2));
|
||||
|
||||
writeln;
|
||||
if GetBroadcastMode(bm)
|
||||
then begin
|
||||
writeln('GetBroadcastMode: $',HexStr(bm,2));
|
||||
DisplayBrMode(bm);
|
||||
|
||||
t:=3;
|
||||
while (t>=0) and (t<=3)
|
||||
do if SetBroadcastMode(t) and GetBroadcastMode(tbm) and (tbm=t)
|
||||
then dec(t) { ok, try next mode, alowed modes: 0,1,2,3 }
|
||||
else begin
|
||||
writeln('SetBroadcastMode/GetBroadcastMode test failed.');
|
||||
t:=$80;
|
||||
end;
|
||||
|
||||
if t=byte(-1)
|
||||
then begin
|
||||
SetBroadCastMode(bm); { restore old broadcastmode.. }
|
||||
if nwmess.result=$00
|
||||
then begin
|
||||
writeln;
|
||||
writeln('SetBroadcastMode tested OK..');
|
||||
end
|
||||
else writeln('SetBroadcastMode error: Old mode couldn''t be restored..');
|
||||
end;
|
||||
end
|
||||
else writeln('GetBroadcastMode error:'+hexstr(nwMess.result,2));
|
||||
|
||||
writeln;
|
||||
for t:=1 to 20 do connL[t]:=t;
|
||||
IF sendBroadcastMessage('Hello u there!',20,connL,connResultL)
|
||||
then begin
|
||||
writeln('SendBroadcastMessage: Msg was broadcasted..');
|
||||
writeln('--and displayed at the folowing connections:');
|
||||
for t:=1 to 20 do if connResultL[t]=$00 then write(t,' ');
|
||||
writeln;
|
||||
end
|
||||
else writeln('SendBroadcastMessage error:'+hexstr(nwMess.result,2));
|
||||
|
||||
writeln;
|
||||
IF SendConsoleBroadcast('Testmessage from Console-operator..',0,connL)
|
||||
then writeln('SendConsoleBroadcast: console message sent.')
|
||||
else begin
|
||||
write('SendConsoleBroadCast: Error ');
|
||||
if nwMess.result=$C6
|
||||
then writeln('! You need to have console privileges..')
|
||||
else writeln(HexStr(nwMess.result,2));
|
||||
end;
|
||||
|
||||
GetBroadCastMode(bm);
|
||||
|
||||
writeln;
|
||||
if SetBroadCastMode(3) { store all messages at the server, no notification.. }
|
||||
then begin
|
||||
writeln('Test of getBroadCastMessage..');
|
||||
writeln('--use SEND on another workstation and send a message to this station.');
|
||||
writeln;
|
||||
writeln('Polling for a message.....');
|
||||
REPEAT {} UNTIL GetBroadCastMessage(mess);
|
||||
writeln('Message: ',mess);
|
||||
end;
|
||||
|
||||
SetBroadCastMode(bm); { restore broadcastmode }
|
||||
|
||||
end.
|
||||
21
NWTP/XMESS/XPMAIL.PAS
Normal file
21
NWTP/XMESS/XPMAIL.PAS
Normal file
@@ -0,0 +1,21 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
Program xpmail;
|
||||
|
||||
{ Example program for the pmail unit / NwTP 0.6 API. (c) 1993,1994, R.Spronk }
|
||||
|
||||
uses nwMisc,nwBindry,pmail;
|
||||
|
||||
CONST MsgBodyTXTfile='a:testmsg.txt';
|
||||
|
||||
{ Simple program illustrating the use of the SendMailFile call. }
|
||||
begin
|
||||
IF NOT PmailInstalled
|
||||
then begin
|
||||
writeln('PMail not installed on the current server.');
|
||||
halt(1);
|
||||
end;
|
||||
IF NOT SendMailFile('SUPERVISOR',OT_USER,
|
||||
'testmessage',MsgBodyTXTfile)
|
||||
then writeln('Error sending file as mail. err# :',HexStr(pmail.result,4));
|
||||
end.
|
||||
819
NWTP/XOTHER/PHONE.PAS
Normal file
819
NWTP/XOTHER/PHONE.PAS
Normal file
@@ -0,0 +1,819 @@
|
||||
Program Phone;
|
||||
{$IFDEF VER70}
|
||||
{$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,P+,Q-,R-,S-,T-,V-,X+}
|
||||
{$ELSE}
|
||||
{$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,R-,S-,V-,X+}
|
||||
{$ENDIF}
|
||||
|
||||
{ Source code for Borland/Turbo Pascal 6/7.
|
||||
To be compiled with NwTP version 0.6 or higher.
|
||||
NwTP is a FreeWare Netware Interface for Pascal.
|
||||
}
|
||||
|
||||
{ Based on the phone.pas program by Eduardo M. Serrat,
|
||||
as published in Dr.Dobbs #207, November 1993.
|
||||
|
||||
The NwTP units and this adaption of his program are
|
||||
(c) 1993,1995 by Rene Spronk ,Groningen, the Netherlands. }
|
||||
|
||||
uses dos,crt,nwMisc,nwBindry,nwConn,nwMess,nwServ,nwIPX;
|
||||
|
||||
const Socket = $80C3;
|
||||
{ This socket was assigned by Novell to an IPX Chatprogram by OXXI }
|
||||
{ Don't use this program in conjunction with theirs.. }
|
||||
Var
|
||||
SendECB,
|
||||
ListenECB :TEcb; { Definition of ECBs }
|
||||
SendIpxHeader,
|
||||
ListenIPXheader:TIpxHeader; { Definition of IPX Headers }
|
||||
SendData,
|
||||
ReadData :Array [1..100] of Byte; { Data area of packets }
|
||||
readflg :Boolean; { Flag to signal received packets }
|
||||
|
||||
MyConnNbr :Byte;
|
||||
MyAddress :TinternetworkAddress;
|
||||
MyName :String;
|
||||
MyServerId :Byte;
|
||||
MyServerName :String;
|
||||
myx,myy :Byte; { my viewport cursor position }
|
||||
|
||||
RconnNbr :Byte;
|
||||
Raddress :TinterNetworkAddress;
|
||||
Rname :String;
|
||||
RfullName :String;
|
||||
RserverID :Byte;
|
||||
RserverName :String;
|
||||
LocalTarget :TnodeAddress; { Node Address of bridge to remote address }
|
||||
|
||||
NewStack :Array[1..256] of Word; { !! used by ESR }
|
||||
StackBottom :Word; { !! used by ESR }
|
||||
HeapCheckPtr :pointer; { Pointer that holds heapPointers }
|
||||
|
||||
{---------------------------------------------------------------------------}
|
||||
|
||||
Procedure CheckError(b:Boolean;errCode:Word; mess:String);
|
||||
begin
|
||||
IF b
|
||||
then begin
|
||||
writeln;
|
||||
CASE errCode of
|
||||
{ main body: 0000-000F }
|
||||
$0001:writeln('IPX not installed.');
|
||||
$0002:writeln('Error opening socket.');
|
||||
{ Procedure whoami }
|
||||
$0010:writeln('Error whilst determining connectionnumber.');
|
||||
$0011:writeln('Error determining internet address.');
|
||||
$0012:writeln('Error retreiving connection information.');
|
||||
{ Procedure process input command }
|
||||
$0022:writeln('Servername ',mess,' is invalid.');
|
||||
$0023:writeln('Error interpreting connection number parameter :',mess);
|
||||
$0025:begin
|
||||
writeln('The supplied username is not unique,');
|
||||
writeln('or the target user isn''t logged in.');
|
||||
end;
|
||||
$0026:writeln('Please select a target user from the above list.');
|
||||
$0027:writeln('Phone cancelled.');
|
||||
{ handshake with sender }
|
||||
$0032:writeln('Packet received from a user claiming to be ConnectionNumber $',mess);
|
||||
{ Sendbroadcast message in Procedure HandshakeWithreceiver }
|
||||
$1000: writeln('Error: Broadcasting a message to the target user failed.');
|
||||
$10FC: begin
|
||||
Writeln('The target user is logged in, but appears not to be at his/her workstation:');
|
||||
writeln('The (last) message was rejected, message buffer for the target station is full.');
|
||||
end;
|
||||
$10FD: begin
|
||||
Writeln('The connection number of the target user has become invalid,');
|
||||
Writeln('Most likely because the user has logged out.');
|
||||
end;
|
||||
$10FF: begin
|
||||
Writeln('The target user is logged in, but has blocked incoming messages.');
|
||||
end;
|
||||
else writeln('An unspecified error occurred.');
|
||||
end; {case }
|
||||
if errCode>$000F then IPXcloseSocket(socket);
|
||||
if errCode>$001F
|
||||
then begin
|
||||
SetPreferredConnectionId(MyServerId);
|
||||
release(HeapCheckPtr);
|
||||
end;
|
||||
if ((errCode=$0026) or (errCode=$0027))
|
||||
then halt(0)
|
||||
else halt(1);
|
||||
end;
|
||||
end;
|
||||
|
||||
{-----------------------------------------------------------------------------}
|
||||
|
||||
Function Confirm:Boolean;
|
||||
Var ch:char;
|
||||
begin
|
||||
repeat
|
||||
repeat {} until keypressed;
|
||||
ch:=readkey;
|
||||
if ch=#0 then ch:=readkey;
|
||||
until ch IN ['y','Y','n','N'];
|
||||
Confirm:=((ch='Y') or (ch='y'))
|
||||
end;
|
||||
|
||||
{-----------------------------------------------------------------------------}
|
||||
|
||||
{$F+}
|
||||
Procedure ESRproc;
|
||||
begin
|
||||
ReadFlg:=true;
|
||||
end;
|
||||
|
||||
Procedure ESRHandler; assembler;
|
||||
asm { ES:SI are the only valid registers when entering this Procedure ! }
|
||||
mov dx, seg stackbottom
|
||||
mov ds, dx
|
||||
|
||||
mov dx,ss { setup of a new local stack }
|
||||
mov bx,sp { ss:sp copied to dx:bx}
|
||||
mov ax,ds
|
||||
mov ss,ax
|
||||
mov sp,offset stackbottom
|
||||
push dx
|
||||
push bx
|
||||
|
||||
CALL EsrProc
|
||||
|
||||
pop bx
|
||||
pop dx
|
||||
mov sp,bx
|
||||
mov ss,dx
|
||||
end;
|
||||
{$F-}
|
||||
|
||||
{-----------------------------------------------------------------------------}
|
||||
|
||||
Function SameAddress(Var a,b):Boolean;
|
||||
{ check if networkaddress a and b have the same net and node address }
|
||||
Type Taddress=Array[1..10] of char;
|
||||
Var addrA:Taddress ABSOLUTE a;
|
||||
addrB:Taddress ABSOLUTE b;
|
||||
begin
|
||||
SameAddress:=(addrA=addrB);
|
||||
end;
|
||||
|
||||
{----------------------------------------------------------------------------}
|
||||
|
||||
Function Time:String;
|
||||
Function LeadingZero(w:Word):String;
|
||||
Var s : String;
|
||||
begin
|
||||
Str(w:0,s);
|
||||
if Length(s) = 1
|
||||
then s := '0' + s;
|
||||
LeadingZero := s;
|
||||
end;
|
||||
Var h, m, s, hund : Word;
|
||||
begin
|
||||
GetTime(h,m,s,hund);
|
||||
Time:=LeadingZero(h)+':'+LeadingZero(m)+':'+LeadingZero(s);
|
||||
end;
|
||||
|
||||
{-----------------------------------------------------------------------------}
|
||||
Procedure HandshakeWithReceiver;
|
||||
const Progress : Array [1..4] of char = ('/','Ä','\','|');
|
||||
Var
|
||||
SecondInd :Word;
|
||||
ProgressInd :Byte;
|
||||
x,y :Byte;
|
||||
KeyNbr :Byte;
|
||||
ConnUp :Boolean;
|
||||
|
||||
ObjName :String;
|
||||
ObjType :Word;
|
||||
ObjId :LongInt;
|
||||
LogonTime :TnovTime;
|
||||
|
||||
Message :String;
|
||||
ConnList,
|
||||
ResultList :TconnectionList;
|
||||
begin
|
||||
Writeln('Calling User ',Rname);
|
||||
Write('Press <ESC> to cancel [ ]');
|
||||
x:=wherex-2; y:=wherey;
|
||||
Message:='User '+MyName+' is phoning you........... ['+Time+']';
|
||||
SecondInd:=0; ProgressInd:=1;
|
||||
|
||||
SetPreferredConnectionId(RserverId);
|
||||
ConnList[1]:=RconnNbr;
|
||||
SendBroadcastMessage(message,1,ConnList,ResultList);
|
||||
Checkerror(nwMess.result>0,$1000,'');
|
||||
CheckError(ResultList[1]>0,$1000+ResultList[1],'');
|
||||
|
||||
IPXListenForPacket(ListenECB);
|
||||
|
||||
KeyNbr:=$ff;
|
||||
ConnUp:=False;
|
||||
FillChar(SendData,SizeOf(SendData),#0);
|
||||
SendData[1]:=Hi(MyConnNbr);
|
||||
SendData[2]:=Lo(MyConnNbr);
|
||||
Move(MyServerName[1],SendData[3],ord(MyserverName[0]));
|
||||
Move(MyName[1],SendData[50],ord(Myname[0]));
|
||||
|
||||
repeat { send a packet every 4 seconds and a broadcast message every 30 seconds }
|
||||
gotoxy(x,y);
|
||||
write(Progress[ProgressInd]);
|
||||
inc(ProgressInd);
|
||||
if ProgressInd > 4
|
||||
then begin
|
||||
ProgressInd:=1;
|
||||
IPXSendPacket(SendECB);
|
||||
end;
|
||||
inc(SecondInd);
|
||||
if SecondInd = 30
|
||||
then begin
|
||||
SendBroadcastMessage(message,1,ConnList,ResultList);
|
||||
Checkerror(nwMess.result>0,$1000,'');
|
||||
CheckError(ResultList[1]>0,$1000+ResultList[1],'');
|
||||
SecondInd:=0;
|
||||
end;
|
||||
delay(1000);
|
||||
if readflg
|
||||
then begin
|
||||
writeln('recieved a packet..');
|
||||
if not SameAddress(ListenIPXheader.source,Raddress)
|
||||
then begin
|
||||
readflg:=false;
|
||||
IPXListenForPacket(ListenECB);
|
||||
end
|
||||
else ConnUp:=TRUE;
|
||||
end;
|
||||
if keypressed
|
||||
then KeyNbr:=ord(readkey);
|
||||
|
||||
until (KeyNbr = $1b) or ConnUp;
|
||||
|
||||
if KeyNbr = $1b
|
||||
then begin
|
||||
Writeln;
|
||||
Write('Wait...');
|
||||
Delay(5000);
|
||||
SendData[1]:=$1b;
|
||||
IPXSendPacket(SendECB);
|
||||
message:='The user phoning you canceled the call... ['+Time+']';
|
||||
SendBroadcastMessage(message,1,ConnList,ResultList);
|
||||
IpxCloseSocket(Socket);
|
||||
SetPreferredConnectionID(MyServerId);
|
||||
halt(1);
|
||||
end;
|
||||
Writeln;
|
||||
Write('User ',Rname,' answered your call......!');
|
||||
delay(1200);
|
||||
ReadFlg:=false;
|
||||
end;
|
||||
|
||||
{--------------------------------------------------------------------------}
|
||||
|
||||
Procedure HandshakeWithSender;
|
||||
const Progress:Array [1..4] of char = ('/','Ä','\','|');
|
||||
Var p :Byte;
|
||||
ObjType :Word;
|
||||
ObjId :LongInt;
|
||||
LoginTime:TnovTime;
|
||||
ticks :Word;
|
||||
x,y :Word;
|
||||
begin
|
||||
Writeln('Listening for calls..');
|
||||
Write('Press <ESC> to cancel [ ]');
|
||||
x:=wherex-2; y:=wherey;
|
||||
IPXListenForPacket(ListenECB);
|
||||
p:=1;
|
||||
while(p<=4) and (not ReadFlg)
|
||||
do begin
|
||||
gotoxy(x,y);
|
||||
write(Progress[p]);
|
||||
delay(1200);
|
||||
inc(p);
|
||||
end;
|
||||
If not readflg
|
||||
then begin
|
||||
Writeln;
|
||||
Writeln('Nobody is Calling you..........');
|
||||
writeln;
|
||||
writeln('( PHONE ? for help )');
|
||||
IpxCloseSocket(Socket);
|
||||
SetPreferredConnectionId(MyServerId);
|
||||
halt(1);
|
||||
end
|
||||
else begin
|
||||
readflg:=false;
|
||||
Raddress:=ListenIPXheader.source;
|
||||
Raddress.socket:=Socket;
|
||||
RconnNbr:=(ReadData[1]*256)+ReadData[2];
|
||||
ZstrCopy(RserverName,ReadData[3],47);
|
||||
ZstrCopy(Rname,ReadData[50],47);
|
||||
IPXGetLocalTarget(Raddress,LocalTarget,ticks);
|
||||
IPXSetupSendECB(NIL, Socket, Raddress,
|
||||
Addr(SendData), SizeOf(SendData),
|
||||
SendIPXheader,SendECB);
|
||||
IPXSendPacket(SendECB); { acknowledge by sending a packet. Packet contents unimportant. }
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{-----------------------------------------------------------------------------}
|
||||
|
||||
Procedure InitWindows;
|
||||
Var i: Byte;
|
||||
begin
|
||||
ClrScr;
|
||||
myx:=1; myy:=1;
|
||||
gotoxy(1,1);
|
||||
write('É'); for i:=2 to 79 do write('Í'); write('»');
|
||||
write('º'); for i:=2 to 79 do write(' '); write('º');
|
||||
|
||||
gotoxy(3,2);
|
||||
Write('User: '+MyName+' ° Server: '+MyServerName);
|
||||
write(' ° Connection: '); write(MyConnNbr);
|
||||
gotoxy(1,3);
|
||||
write('È'); for i:=2 to 79 do write('Í'); write('¼');
|
||||
|
||||
gotoxy(1,13);
|
||||
write('É'); for i:=2 to 79 do write('Í'); write('»');
|
||||
write('º'); for i:=2 to 79 do write(' '); write('º');
|
||||
|
||||
gotoxy(3,14);
|
||||
Write('User: '+Rname+' ° Server: '+RserverName);
|
||||
Write(' ° Connection: '); write(RconnNbr);
|
||||
Gotoxy(1,15);
|
||||
write('È'); for i:=2 to 79 do write('Í'); write('¼');
|
||||
|
||||
gotoxy(26,25);
|
||||
Write('±±±²²² Phone Utility ²²²±±±');
|
||||
gotoxy(1,1);
|
||||
HighVideo;
|
||||
end;
|
||||
|
||||
{-----------------------------------------------------------------------------}
|
||||
|
||||
Procedure Talk;
|
||||
|
||||
Function Timeout(w1,w2:Word;sec:Byte):Boolean;
|
||||
Var lw2:Longint;
|
||||
begin
|
||||
if w2<w1
|
||||
then lw2:=$10000+w2
|
||||
else lw2:=w2;
|
||||
Timeout:=((lw2-w1) DIV 18)>sec;
|
||||
end;
|
||||
|
||||
Procedure MyWindow;
|
||||
begin
|
||||
Window(1,5,80,12);
|
||||
gotoxy(myx,myy);
|
||||
end;
|
||||
|
||||
Procedure RemoteWindow;
|
||||
begin
|
||||
Window(1,17,80,24);
|
||||
end;
|
||||
|
||||
|
||||
Var currMarker,
|
||||
SendMarker,
|
||||
ListenMarker:Word;
|
||||
ch :Char;
|
||||
RlastChar,
|
||||
RlastX,
|
||||
RlastY :byte;
|
||||
begin
|
||||
MyWindow;
|
||||
IPXListenForPacket(ListenECB);
|
||||
IPXSetupSendECB(NIL, Socket, Raddress, Addr(SendData), 7,
|
||||
SendIPXheader,SendECB); { make size of sendBuffer smaller }
|
||||
IPXgetIntervalMarker(SendMarker);
|
||||
ListenMarker:=SendMarker;
|
||||
SendData[1]:=$FF;
|
||||
RlastChar:=$FF;
|
||||
|
||||
REPEAT
|
||||
if keypressed
|
||||
then begin
|
||||
MyWindow;
|
||||
SendData[4]:=SendData[1]; { append last typed char to packet. }
|
||||
SendData[5]:=SendData[2]; { original packet may have been lost }
|
||||
SendData[6]:=SendData[3]; { Remember: IPX is unreliable ! }
|
||||
ch:=readkey;
|
||||
if ch=#0
|
||||
then begin
|
||||
ch:=readkey;
|
||||
CASE ord(ch) of
|
||||
75:begin { <- 'cursor left' }
|
||||
SendData[2]:=myx-1;
|
||||
if (myx=1) then SendData[2]:=1;
|
||||
gotoxy(SendData[2],myy);
|
||||
SendData[3]:=myy;
|
||||
SendData[1]:=$00;
|
||||
end;
|
||||
77:begin { -> 'cursor right' }
|
||||
SendData[2]:=myx+1;
|
||||
if (myx=80) then SendData[2]:=80;
|
||||
gotoxy(SendData[2],myy);
|
||||
SendData[3]:=myy;
|
||||
SendData[1]:=$00;
|
||||
end;
|
||||
else SendData[1]:=$FF;
|
||||
end; {case}
|
||||
|
||||
end
|
||||
else begin
|
||||
SendData[1]:=ord(ch);
|
||||
SendData[2]:=myx;
|
||||
SendData[3]:=myy;
|
||||
Case ord(SendData[1]) of
|
||||
8 :write(#8+#$20+#8); { backspace }
|
||||
13:writeln; { return }
|
||||
else write(chr(SendData[1]));
|
||||
end; {case}
|
||||
end;
|
||||
myx:=wherex;
|
||||
myy:=wherey;
|
||||
IPXSendPacket(SendECB); { send current and previous char }
|
||||
IPXGetIntervalMarker(SendMarker);
|
||||
end;
|
||||
|
||||
if readflg
|
||||
then begin
|
||||
If SameAddress(ListenIPXheader.source,Raddress)
|
||||
then begin
|
||||
if (readData[4]<>$FF)
|
||||
and ( (readData[4]<>RlastChar)
|
||||
or (readData[5]<>Rlastx)
|
||||
or (readData[6]<>Rlasty)
|
||||
)
|
||||
then begin { if we missed a packet, display char now }
|
||||
RemoteWindow;
|
||||
Gotoxy(ReadData[5],ReadData[6]);
|
||||
CASE ReadData[4] of
|
||||
0:begin { don't print, cursor movement only }
|
||||
end;
|
||||
8:write(#8+#$20+#8); { backspace }
|
||||
13:writeln; { return }
|
||||
else write(chr(ReadData[1]));
|
||||
end;{case}
|
||||
end;
|
||||
|
||||
if ReadData[1]<>$FF
|
||||
then begin
|
||||
RemoteWindow;
|
||||
Gotoxy(ReadData[2],ReadData[3]);
|
||||
CASE ReadData[1] of
|
||||
0:begin { don't print, cursor movement only }
|
||||
end;
|
||||
8:write(#8+#$20+#8);
|
||||
13:writeln;
|
||||
else write(chr(ReadData[1]));
|
||||
end;{case}
|
||||
end;
|
||||
RlastChar:=ReadData[1];
|
||||
RlastX :=ReadData[2];
|
||||
RlastY :=ReadData[3];
|
||||
IPXGetIntervalMarker(ListenMarker);
|
||||
end;
|
||||
readflg:=false;
|
||||
IPXListenForPacket(ListenECB);
|
||||
end;
|
||||
|
||||
IPXRelinquishControl;
|
||||
IPXGetIntervalMarker(currMarker);
|
||||
IF Timeout(SendMarker,currMarker,5) { send an "I'm alive" msg after 5 idle secs }
|
||||
then begin
|
||||
SendData[4]:=SendData[1]; { redundant info: append last char to packet. }
|
||||
SendData[5]:=SendData[2];
|
||||
SendData[6]:=SendData[3];
|
||||
SendData[1]:=$FF;
|
||||
IPXSendPacket(SendECB);
|
||||
IPXGetIntervalMarker(SendMarker);
|
||||
end;
|
||||
IF Timeout(ListenMarker,currMarker,17) { fake an "hang-up" if no msgs received during 17 secs }
|
||||
then begin
|
||||
ReadData[1]:=$1B;
|
||||
RemoteWindow;
|
||||
end;
|
||||
UNTIL (ReadData[1]=$1b) or (SendData[1]=$1b); { .. until either party has hung up }
|
||||
|
||||
SendData[1]:=$1b;
|
||||
IPXSendPacket(SendECB);
|
||||
IpxCloseSocket(Socket);
|
||||
Writeln;
|
||||
Writeln;
|
||||
writeln('<Hanging Up...........>');
|
||||
Delay(2000);
|
||||
Window(1,1,80,25);
|
||||
LowVideo;
|
||||
gotoxy(80,25);
|
||||
end;
|
||||
|
||||
{--------------- ProcessInputCommand----------------------------------------}
|
||||
|
||||
Type PusrInfo=^TusrInfo;
|
||||
TusrInfo=record
|
||||
ObjName :String[47];
|
||||
FullName:String[40];
|
||||
ConnId,
|
||||
ConnNbr :Byte;
|
||||
Address :TinterNetworkAddress; { socket field not used }
|
||||
next :PusrInfo;
|
||||
end;
|
||||
|
||||
Var startInfo:PusrInfo;
|
||||
|
||||
Procedure PushInLL(_objName,_objFullName:String;
|
||||
_connId,_connNbr:Byte;
|
||||
_address:TinternetworkAddress);
|
||||
Var p,m,l:PusrInfo;
|
||||
begin
|
||||
p:=startInfo;
|
||||
new(l);
|
||||
With l^
|
||||
do begin
|
||||
if _objFullName[0]>#40
|
||||
then _objFullName[0]:=#40;
|
||||
objName:=_objName;
|
||||
fullName:=_objFullName;
|
||||
connId:=_connId;
|
||||
connNbr:=_connNbr;
|
||||
address:=_address;
|
||||
next:=NIL;
|
||||
end;
|
||||
if p=NIL
|
||||
then startInfo:=l
|
||||
else begin
|
||||
m:=p;
|
||||
While (p<>NIL) and (p^.objName<=_obJname)
|
||||
do begin m:=p;p:=p^.next; end;
|
||||
if p=startInfo
|
||||
then begin { insert before first LL entry }
|
||||
l^.next:=startInfo;
|
||||
startInfo:=l;
|
||||
end
|
||||
else begin { insert in LL or append to end }
|
||||
l^.next:=m^.next;
|
||||
m^.next:=l;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
Function GetTargetUser:PusrInfo;
|
||||
{ returns NIL if a target user was not uniquely identified by the user }
|
||||
Var l :PusrInfo;
|
||||
serverName :String;
|
||||
SelectedUsers:Word;
|
||||
t :Word;
|
||||
s :String;
|
||||
ch :char;
|
||||
Laddr :TinternetworkAddress;
|
||||
AddrSame :boolean;
|
||||
begin
|
||||
{ are all objNames the same?
|
||||
Yes => multple logins (connNbr must have been supplied)
|
||||
or login on multiple servers (serverName must h.b. supplied)
|
||||
No => the supplied userName is not unique. }
|
||||
l:=startInfo;
|
||||
SelectedUsers:=0;
|
||||
IF l<>NIL
|
||||
then Laddr:=l^.address;
|
||||
AddrSame:=true;
|
||||
While (l<>NIL)
|
||||
do begin
|
||||
inc(SelectedUsers);
|
||||
AddrSame:=AddrSame and SameAddress(Laddr,l^.address);
|
||||
l:=l^.next;
|
||||
end;
|
||||
If AddrSame { are all the users essentially the same ? }
|
||||
then SelectedUsers:=1;
|
||||
|
||||
CASE SelectedUsers of
|
||||
0:begin
|
||||
GetTargetUser:=NIL;
|
||||
end;
|
||||
1:begin { OK! unique users identified }
|
||||
GetTargetUser:=StartInfo;
|
||||
end;
|
||||
else begin
|
||||
writeln('The target user has multiple connections.');
|
||||
writeln('Please give connection number and/or server name of the intended user.');
|
||||
writeln;
|
||||
writeln('Username | Server | Con | Full Name');
|
||||
writeln('---------------------+-----------------+-----+----------------------');
|
||||
|
||||
t:=3;
|
||||
l:=startInfo;
|
||||
while l<>NIL
|
||||
do begin
|
||||
GetFileServerName(l^.connId,servername);
|
||||
PstrCopy(s,l^.objName,20);
|
||||
write(s,' | ');
|
||||
PstrCopy(s,serverName,15);
|
||||
write(s,' | ',l^.connNbr:3,' | ');
|
||||
PstrCopy(s,l^.fullname,30);
|
||||
writeln(s);
|
||||
l:=l^.next;
|
||||
inc(t);
|
||||
if t=20
|
||||
then begin
|
||||
writeln('--- more (any key)---');
|
||||
repeat {} until keypressed;
|
||||
ch:=readkey;
|
||||
if ch=#0 then ch:=readkey;
|
||||
t:=0;
|
||||
end;
|
||||
end;
|
||||
GetTargetUser:=NIL;
|
||||
end;
|
||||
end; {case}
|
||||
end;
|
||||
|
||||
Procedure ProcessInputCommand;
|
||||
Var SearchStartServer,
|
||||
SearchEndServer :Byte;
|
||||
ConnIdCtr,
|
||||
ConnNbrCtr :Byte;
|
||||
|
||||
LuserName,
|
||||
LserverName :String;
|
||||
LconnId :Byte;
|
||||
LfullName :String;
|
||||
LconnNbr :Byte;
|
||||
|
||||
ServerInfo :TFileServerInformation;
|
||||
objName :String;
|
||||
objType :Word;
|
||||
objId :Longint;
|
||||
ticks :Word;
|
||||
LoginTime :TnovTime;
|
||||
IntNWaddress :TinternetworkAddress;
|
||||
|
||||
TargetUserPtr :PusrInfo;
|
||||
|
||||
p :Byte;
|
||||
errcode :Integer;
|
||||
begin
|
||||
StartInfo:=NIL;
|
||||
If (ParamCount>0)
|
||||
and ( (pos('?',paramstr(1))>0)
|
||||
or (pos('help',paramstr(1))>0)
|
||||
or (pos('HELP',paramstr(1))>0)
|
||||
)
|
||||
then begin
|
||||
writeln;
|
||||
writeln('** Phone V 1.3., By E.M. Serrat and R. Spronk');
|
||||
writeln;
|
||||
writeln('** Usage: PHONE');
|
||||
writeln;
|
||||
writeln('Listen for others calling you.');
|
||||
writeln;
|
||||
writeln;
|
||||
writeln('** Usage: PHONE [servername/]UserName [connection]');
|
||||
writeln;
|
||||
writeln('Call someone.');
|
||||
writeln('-Username may be a ''*'' wildcard.');
|
||||
writeln(' All logged in users on all attached servers will be shown.');
|
||||
writeln('-Sender and receiver must be attached to a common server in the internetwork.');
|
||||
writeln('-The supplied username is compared with the first characters of');
|
||||
writeln(' the login name and with the full user name, as set by SYSCON.');
|
||||
writeln('-Servername must be supplied if the target user has connections');
|
||||
writeln(' with more than one server.');
|
||||
writeln('-ConnectionNumber must be supplied if the target user is logged in');
|
||||
writeln(' at multiple workstations attached to the same server.');
|
||||
writeln;
|
||||
writeln('The program will timeout if the program on the other end of the link');
|
||||
writeln('is terminated abnormally.');
|
||||
halt(1);
|
||||
end;
|
||||
if paramcount=0 { ---- Listen if anyone is calling us ----- }
|
||||
then begin
|
||||
HandshakeWithSender;
|
||||
InitWindows;
|
||||
Talk;
|
||||
IpxCloseSocket(Socket);
|
||||
SetPreferredConnectionId(MyServerId);
|
||||
halt(0);
|
||||
end;
|
||||
{ ** Paramcount>0, We're calling someone ** }
|
||||
LconnNbr:=0;
|
||||
SearchStartServer:=1;
|
||||
SearchEndServer:=8;
|
||||
LuserName:=ParamStr(1);
|
||||
UpString(LuserName);
|
||||
p:=pos('/',LuserName);
|
||||
checkError((p=1) and (LuserName[0]=#1),$0020,'');
|
||||
if p>0
|
||||
then begin
|
||||
LserverName:=copy(LuserName,1,p-1);
|
||||
delete(LuserName,1,p);
|
||||
if LuserName=''
|
||||
then LuserName:='*';
|
||||
if pos('*',LserverName)=0
|
||||
then begin
|
||||
GetConnectionId(LserverName,LconnId);
|
||||
checkError(nwConn.result>0,$0022,LserverName);
|
||||
SearchStartServer:=LconnId;
|
||||
SearchEndServer:=LconnId;
|
||||
end;
|
||||
end;
|
||||
if paramcount>1
|
||||
then begin
|
||||
Val(ParamStr(2),LconnNbr,errcode);
|
||||
checkError(errcode<>0,$0023,Paramstr(2));
|
||||
end;
|
||||
|
||||
writeln('Scanning logged in users..');
|
||||
ConnIdCtr:=SearchStartServer;
|
||||
While ConnIdCtr<=SearchEndServer
|
||||
do begin
|
||||
If IsConnectionIdInUse(ConnIdCtr)
|
||||
then begin
|
||||
SetPreferredConnectionId(ConnIdCtr);
|
||||
IF NOT GetFileServerInformation(ServerInfo)
|
||||
then ServerInfo.connectionsMax:=250; { patch value if call failed }
|
||||
for ConnNbrCtr:=1 to ServerInfo.ConnectionsMax
|
||||
do begin
|
||||
IF GetConnectionInformation(ConnNbrCtr,ObjName,objType,objId,LoginTime)
|
||||
and (objType=OT_USER)
|
||||
then begin
|
||||
GetInterNetAddress(ConnNbrCtr,IntNWaddress);
|
||||
GetRealUserName(ObjName,LfullName);
|
||||
UpString(LfullName);
|
||||
IF (pos('NOT-LOGGED-',objName)=0) { skip not logged in connections }
|
||||
and ((LconnNbr=0) or (LconnNbr=ConnNbrCtr)) { if user supplied connNbr, check it }
|
||||
and (NOT SameAddress(MyAddress,IntNWAddress)) { no mail to yourself }
|
||||
and ( (LuserName[1]='*') { wildcard overrules nameselection }
|
||||
or (pos(LuserName,ObjName)=1) { username matched with firts few characters in objName? }
|
||||
or (pos(LuserName,LfullName)>0) { usermane matches part of objects' Full_Name ? }
|
||||
)
|
||||
then PushInLL(objName,LfullName,ConnIdCtr,ConnNbrCtr,
|
||||
IntNWaddress);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
inc(ConnIdCtr);
|
||||
end;
|
||||
TargetUserPtr:=GetTargetUser;
|
||||
checkError((LuserName[1]<>'*') and (TargetUserPtr=NIL),$0025,''); { No user selected }
|
||||
checkError(TargetUserPtr=NIL,$0026,'');
|
||||
RconnNbr:=TargetUserPtr^.connNbr;
|
||||
Raddress:=TargetUserPtr^.address;
|
||||
Raddress.Socket:=Socket;
|
||||
Rname:=TargetUserPtr^.objName;
|
||||
RserverId:=TargetUserPtr^.connId;
|
||||
GetFileServerName(RserverId,RserverName);
|
||||
release(HeapCheckPtr);
|
||||
|
||||
SetPreferredConnectionId(RserverId);
|
||||
GetRealUserName(Rname,RfullName);
|
||||
writeln;
|
||||
writeln(RserverName,'/',Rname,' Connection_Number= ',RconnNbr);
|
||||
writeln('(Full name =',RfullName,')');
|
||||
writeln;
|
||||
write('Is the above user the intended chat partner ? (Y/N)');
|
||||
checkError(NOT Confirm,$0027,''); { user abort }
|
||||
writeln;
|
||||
|
||||
IPXGetLocalTarget(Raddress,LocalTarget,ticks);
|
||||
IPXSetupSendECB(NIL, Socket, Raddress, Addr(SendData), SizeOf(SendData),
|
||||
SendIPXheader,SendECB);
|
||||
HandShakeWithReceiver;
|
||||
InitWindows;
|
||||
Talk;
|
||||
IpxCloseSocket(Socket);
|
||||
SetPreferredConnectionId(MyServerId);
|
||||
halt(0);
|
||||
end;
|
||||
|
||||
Procedure WhoAmI; {---------------------------------------------------------}
|
||||
Var ObjType :Word;
|
||||
ObjId :LongInt;
|
||||
LogonTime:TnovTime;
|
||||
begin
|
||||
GetConnectionNumber(MyConnNbr);
|
||||
checkError(nwConn.result>0,$0010,'');
|
||||
GetInternetAddress(MyConnNbr,MyAddress);
|
||||
checkError(nwConn.result>0,$0011,'');
|
||||
MyAddress.Socket:=Socket;
|
||||
GetConnectionInformation(MyConnNbr,MyName,ObjType,ObjId,LogonTime);
|
||||
checkError(nwConn.result>0,$0012,'');
|
||||
GetEffectiveConnectionID(MyServerId);
|
||||
GetFileServerName(MyServerId,MyServerName);
|
||||
end;
|
||||
|
||||
{-----------------------------------------------------------------------------}
|
||||
Var LocSocket:Word;
|
||||
|
||||
begin
|
||||
Writeln('*** PHONE V1.3 ***');
|
||||
Mark(HeapCheckPtr);
|
||||
LocSocket:=Socket;
|
||||
readflg:=false;
|
||||
Checkerror(NOT IpxPresent,$0001,'');
|
||||
IpxOpenSocket(LocSocket,FALSE);
|
||||
Checkerror(nwIPX.result>0,$0002,'');
|
||||
WhoAmI;
|
||||
IPXSetupListenECB(Addr(EsrHandler),socket,Addr(ReadData),SizeOf(ReadData),
|
||||
ListenIPXheader,ListenECB);
|
||||
ProcessInputCommand; {doesn't return}
|
||||
end.
|
||||
83
NWTP/XOTHER/TVLM.PAS
Normal file
83
NWTP/XOTHER/TVLM.PAS
Normal file
@@ -0,0 +1,83 @@
|
||||
program tvlm;
|
||||
{$F+}
|
||||
|
||||
{ Example for the nwIntr unit / NwTP 0.6 (c) 1995, R.Spronk
|
||||
|
||||
Shows the same information as the VLM /X command.
|
||||
|
||||
Example for the use of the GetVLMHeader and GetVLMControlBlock
|
||||
functions in the unit nwIntr }
|
||||
|
||||
uses dos,nwintr,nwmisc;
|
||||
|
||||
Var t:byte;
|
||||
HDR:TVLMHeader;
|
||||
CBL:TVLMcontrolBlockEntry;
|
||||
s:string;
|
||||
GlobSize,TransSize:longint;
|
||||
regs:registers;
|
||||
w:word;
|
||||
|
||||
begin
|
||||
IF NOT VLM_EXE_Loaded
|
||||
then begin
|
||||
writeln('VLM.EXE not loaded.');
|
||||
halt(0);
|
||||
end;
|
||||
GetVLMHeader(HDR);
|
||||
|
||||
regs.ax:=$7a20;
|
||||
regs.bx:=$0000;
|
||||
regs.cx:=$0000;
|
||||
intr($2f,regs);
|
||||
|
||||
writeln('Handler entry point : ',HexStr(regs.es,4),':',HexStr(regs.bx,4));
|
||||
writeln('Headerlength (or id?): ',HexStr(HDR.headerlen,2),'h');
|
||||
writeln('IDstring : ',hdr.multiplexIdString[1],
|
||||
hdr.multiplexIdString[2],
|
||||
hdr.multiplexIdString[3]);
|
||||
|
||||
writeln('TransientSwitchCount : ',hdr.TransientSwitchCount);
|
||||
writeln('CallCount : ',hdr.CallCount);
|
||||
writeln('CurrentVLMid : ',HexStr(hdr.CurrentVLMID,4),'h');
|
||||
writeln('MemoryType : ',HexStr(hdr.MemoryType,2),'h [04 = XMS]');
|
||||
writeln('ModulesLoaded : ',hdr.ModulesLoaded);
|
||||
writeln('BlockID : ',HexStr(hdr.BlockId,4),'h');
|
||||
writeln('TransientBlock : ',HexStr(hdr.TransientBlock,4),'h');
|
||||
writeln('GlobalSegment : ',HexStr(hdr.GlobalSegment,4),'h');
|
||||
writeln('FullMapCount : ',hdr.FullMapCount);
|
||||
|
||||
GlobSize:=0;TransSize:=0;
|
||||
writeln;
|
||||
writeln('VLM control block information Address Memory size (bytes) ');
|
||||
writeln('Name ID Flag Func Maps Call TSeg Gseg Low Hi TSize Gsize SSize ');
|
||||
writeln('-------- ---- ---- ---- ---- ---- ---- ---- ---- ---- ------ ------ ------');
|
||||
for t:=0 to hdr.modulesLoaded
|
||||
do begin
|
||||
GetVLMcontrolBlock(t,CBL);
|
||||
|
||||
With CBL
|
||||
do begin
|
||||
s[0]:=#8;
|
||||
move(cbl.VLMname,s[1],8);
|
||||
write(s,' ');
|
||||
|
||||
write(HexStr(id,4),' ');
|
||||
write(HexStr(Flag,4),' ');
|
||||
write(HexStr(Func,4),' ');
|
||||
write(HexStr(Maps,4),' ');
|
||||
write(HexStr(TimesCalled,4),' ');
|
||||
write(HexStr(TransientSeg,4),' ');
|
||||
write(HexStr(GlobalSeg,4),' ');
|
||||
write(HexStr(AddressLow,4),' ');
|
||||
write(HexStr(AddressHi,4),' ');
|
||||
writeln(16*TsegSize:6,' ',16*GSegSize:6,' ',16*SSegSize:6);
|
||||
if TsegSize>TransSize
|
||||
then TransSize:=TsegSize;
|
||||
GlobSize:=GlobSize+GSegSize;
|
||||
end;
|
||||
end;
|
||||
writeln('Transient block size: ',TransSize*16);
|
||||
writeln('Global segment size : ',GlobSize*16);
|
||||
|
||||
end.
|
||||
95
NWTP/XQMS/QAVAIL.PAS
Normal file
95
NWTP/XQMS/QAVAIL.PAS
Normal file
@@ -0,0 +1,95 @@
|
||||
program QAvailable;
|
||||
|
||||
{ QMS related utility / NwTP 0.5 API. (c) 1993,1994, R.Spronk }
|
||||
|
||||
uses nwMisc,nwBindry,nwQMS;
|
||||
|
||||
Var Qname :string;
|
||||
QobjId:Longint;
|
||||
Qtype :word;
|
||||
|
||||
BinAccLev:Byte;
|
||||
MyObjId :Longint;
|
||||
MyObjName:string;
|
||||
MyObjType:word;
|
||||
|
||||
SegNbr :Byte;
|
||||
propName :string;
|
||||
propValue:Tproperty;
|
||||
moreSeg :boolean;
|
||||
propFlags:byte;
|
||||
i :Byte;
|
||||
|
||||
GrpObjId :Longint;
|
||||
GrpObjName:string;
|
||||
GrpObjType:word;
|
||||
|
||||
begin
|
||||
{--- Parameter section }
|
||||
|
||||
if paramCount<>1
|
||||
then begin
|
||||
writeln('QAVAIL usage: QAVAIL <queue name>');
|
||||
writeln('Batch file utility to check for the availability of queues.');
|
||||
writeln;
|
||||
writeln('Errorlevel 0 : Queue exists, calling user is allowed to use Queue');
|
||||
writeln(' 1 : Queue doesn''t exist on default fileserver.');
|
||||
writeln(' 2 : Queue exists but calling user has no Queue rights.');
|
||||
halt(1); { No queue available }
|
||||
end;
|
||||
Qname:=ParamStr(1);
|
||||
|
||||
{--- Startup checks }
|
||||
|
||||
IF Not (IsShellLoaded and IsUserLoggedOn)
|
||||
then halt(1); { Queue not available }
|
||||
|
||||
{--- Queue name in bindery of effective server ? }
|
||||
|
||||
UpString(Qname);
|
||||
IF not GetBinderyObjectId(Qname,3 {ot_print_queue},QobjId)
|
||||
then halt(1);
|
||||
|
||||
{--- Queue exists. Does the caller have rights to use the queue ? }
|
||||
|
||||
IF NOT (GetBinderyAccessLevel(BinAccLev,MyObjId) and
|
||||
GetBinderyObjectName(MyObjId,MyObjName,MyObjType))
|
||||
then halt(1); { Oops.. some kind of bindery error }
|
||||
|
||||
IF IsBinderyObjectInSet(Qname,3 {OT_PRINT_QUEUE},'Q_USERS',MyObjName, MyObjType)
|
||||
then halt(0); { OK. Caller has rights }
|
||||
|
||||
if nwbindry.result=$FB { According to QMS definitions, when the property }
|
||||
then halt(0); { Q_USERS doesn't exist, all users have queue rights. }
|
||||
|
||||
{--- Is one of the groups I'm a member of a queue user ? }
|
||||
|
||||
SegNbr:=1;
|
||||
propName:='GROUPS_I''M_IN';
|
||||
|
||||
While ReadPropertyValue(MyObjName,MyObjType,propName,SegNbr,
|
||||
propValue,moreSeg,propFlags)
|
||||
do begin
|
||||
{ A segment of a set-property consists of a list of object IDs,
|
||||
each ID 4 bytes long, stored hi-lo.
|
||||
The end of the list (within THIS segment) is marked by an ID of 00000000. }
|
||||
i:=1;
|
||||
Repeat
|
||||
GrpObjId:=MakeLong((propValue[i] *256 +propValue[i+1]), ( propValue[i+2] *256 + propValue[i+3] ) );
|
||||
if GrpObjId<>0
|
||||
then begin
|
||||
IF GetBinderyObjectName(GrpObjId,GrpObjName,GrpObjType)
|
||||
and IsBinderyObjectInSet(Qname,3 {OT_PRINT_QUEUE},
|
||||
'Q_USERS',GrpObjName, GrpObjType)
|
||||
then halt(0); { OK. Caller's group has queue rights }
|
||||
end;
|
||||
inc(i,4);
|
||||
Until (i>128) or (GrpObjId=0);
|
||||
inc(SegNbr);
|
||||
end;
|
||||
|
||||
{--- Still no rights found.. }
|
||||
halt(2);
|
||||
|
||||
end.
|
||||
|
||||
91
NWTP/XSEMA/SEMATEST.PAS
Normal file
91
NWTP/XSEMA/SEMATEST.PAS
Normal file
@@ -0,0 +1,91 @@
|
||||
{$X+,V-,B-}
|
||||
Program SemaTest;
|
||||
|
||||
{ */
|
||||
/* SemaTest - Tests semaphores by showing application metering example */
|
||||
/* */
|
||||
/* by Charles Rose */
|
||||
/* */}
|
||||
|
||||
{ Testprogram for the nwSema unit, this version (c) 1994,1995 R.Spronk }
|
||||
|
||||
USES Crt,nwMisc,nwSema;
|
||||
|
||||
CONST
|
||||
INITIAL_SEMAPHORE_VALUE=2;
|
||||
WAIT_SECONDS=2;
|
||||
|
||||
{ Global data }
|
||||
VAR openCount :Word;
|
||||
semValue :Integer;
|
||||
semHandle :LongInt;
|
||||
done :boolean;
|
||||
t :Byte;
|
||||
|
||||
BEGIN {main}
|
||||
|
||||
done := False;
|
||||
|
||||
{ Open Semaphore }
|
||||
semValue := INITIAL_SEMAPHORE_VALUE; { Need in case we're creating the semaphore }
|
||||
IF NOT OpenSemaphore( 'TestSemaphore', semValue, semHandle, openCount )
|
||||
then begin
|
||||
writeln('Error opening semaphore. error #',nwSema.Result);
|
||||
Halt(1);
|
||||
end;
|
||||
|
||||
{ Wait on the Semaphore (get permission to use the resource) }
|
||||
IF NOT WaitOnSemaphore( semHandle, 3*18 ) { 0 = Don't wait }
|
||||
then begin
|
||||
if ( nwSema.Result = $FE )
|
||||
then begin
|
||||
writeln( 'Sorry, all of the slots for this resource are currently in use' );
|
||||
halt(1);
|
||||
end
|
||||
else begin
|
||||
writeln('WaitOnSemaphore returned eror# ',nwSema.result);
|
||||
halt(1);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
clrscr;
|
||||
gotoxy(1,4);
|
||||
Writeln('Testing semaphore functions.');
|
||||
writeln('Workstation ',INITIAL_SEMAPHORE_VALUE+1,' that starts this testprogram');
|
||||
writeln('(concurrently) will be refused access to the (imaginary) resource.');
|
||||
gotoxy( 24,24 );
|
||||
write( 'Press any key to exit' );
|
||||
|
||||
IF NOT ExamineSemaphore( semHandle, semValue, openCount )
|
||||
then begin
|
||||
writeln('Error while examining semaphore value. Error #',nwSema.Result);
|
||||
Halt(1);
|
||||
end;
|
||||
|
||||
{ Wait loop }
|
||||
while ( NOT done )
|
||||
do begin
|
||||
gotoxy( 1,23 );
|
||||
write( 'Semaphore Test --> Open at [',openCount,
|
||||
'] stations *** Value is [',semValue,'] ');
|
||||
t:=0;
|
||||
While (t<100) and (not done)
|
||||
do begin
|
||||
delay(WAIT_SECONDS*10); { wait a while };
|
||||
done:=KeyPressed;
|
||||
inc(t);
|
||||
end;
|
||||
|
||||
gotoxy( 60,23 );
|
||||
write( 'Checking...' ); Delay(500); { wait half a sec }
|
||||
|
||||
IF NOT ExamineSemaphore( semHandle, semValue, openCount )
|
||||
then writeln('ExamnineSemaphore2 error#',nwsema.result);
|
||||
end;
|
||||
|
||||
{ Signal Semaphore (that we're through with the resource) }
|
||||
SignalSemaphore( semHandle );
|
||||
{ Close Semaphore }
|
||||
CloseSemaphore( semHandle );
|
||||
end.
|
||||
86
NWTP/XSEMA/TSTSEMA2.PAS
Normal file
86
NWTP/XSEMA/TSTSEMA2.PAS
Normal file
@@ -0,0 +1,86 @@
|
||||
{$X+,B-,V-}
|
||||
Program tstsema2;
|
||||
|
||||
{ Example for the nwSema unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
uses nwMisc,nwConn,nwSema;
|
||||
|
||||
|
||||
Var ConnNbr:Byte;
|
||||
seqNbr:Word;
|
||||
NbrOfSema:Byte;
|
||||
SemaInfo:TconnSema;
|
||||
|
||||
SemValue:Integer;
|
||||
info:TsemaInfoList;
|
||||
|
||||
t:byte;
|
||||
s:string;
|
||||
|
||||
handle4,handle5,
|
||||
handle6,handle7:LongInt;
|
||||
openCount:word;
|
||||
begin
|
||||
|
||||
connNbr:=2;seqNbr:=0;
|
||||
|
||||
OpenSemapHore('SEMA4',4,handle4,openCount);
|
||||
OpenSemaphore('SEMAPHORE5',5,handle5,OpenCount);
|
||||
OpenSemapHore('SEM6',6,handle6,OpenCount);
|
||||
OpenSemapHore('SEMAP7',7,handle7,OpenCount);
|
||||
|
||||
writeln('Semaphores have been opened..');
|
||||
writeln;
|
||||
writeln('<RETURN> to continue..');
|
||||
readln(s);
|
||||
|
||||
GetConnectionNumber(connNbr); { my connection number }
|
||||
|
||||
seqNbr:=1;
|
||||
REPEAT
|
||||
IF NOT GetConnectionsSemaphores(ConnNbr,seqNbr,NbrOfSema,SemaInfo)
|
||||
then begin
|
||||
writeln('GetConnectionsSemaphores returned error #', nwSema.result);
|
||||
seqNbr:=0;
|
||||
end
|
||||
else begin
|
||||
writeln;
|
||||
writeln('NbrOfSema Left to Scan: ',NbrOfSema);
|
||||
writeln('Next seq Nbr : ',seqNbr);
|
||||
|
||||
with SemaInfo
|
||||
do begin
|
||||
writeln('Sema Name:',Name);
|
||||
writeln('Opencount:',OpenCount);
|
||||
writeln('Value :',Value);
|
||||
writeln('TaskNbr :',taskNbr);
|
||||
end;
|
||||
end;
|
||||
|
||||
UNTIL seqNbr=0;
|
||||
|
||||
|
||||
seqNbr:=1;
|
||||
REPEAT
|
||||
IF GetSemaphoreInformation('SEMA4',seqNbr,
|
||||
OpenCount,SemValue,NbrOfSema,info)
|
||||
then begin
|
||||
writeln;
|
||||
writeln('Test of GetSemaphoreInformation...');
|
||||
writeln('Connections using semaphore:',Opencount);
|
||||
writeln('Semaphore value:',semvalue);
|
||||
|
||||
If NbrOfSema>100
|
||||
then NbrOfSema:=100;
|
||||
for t:=1 to NbrOfSema
|
||||
do writeln('Record #:',t,' Connection: ',info[t].ConnNbr,' Task: ',info[t].taskNbr);
|
||||
end
|
||||
else writeln('GetSemaphoreInformation returned error #', nwSema.result);
|
||||
UNTIL seqNbr=0;
|
||||
|
||||
CloseSemaphore(handle4);
|
||||
CloseSemaphore(handle5);
|
||||
CloseSemaPhore(handle6);
|
||||
CloseSemaphore(handle7);
|
||||
end.
|
||||
|
||||
59
NWTP/XSERV/CLRCONN.PAS
Normal file
59
NWTP/XSERV/CLRCONN.PAS
Normal file
@@ -0,0 +1,59 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
Program ClrConn;
|
||||
|
||||
{ Example for the nwServ unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Purpose: Utility for users with console privileges:
|
||||
Terminate a connection on the current server. }
|
||||
|
||||
{ Tests the following nwServ functions:
|
||||
|
||||
CheckConsolePrivileges
|
||||
ClearConnectionNumber
|
||||
}
|
||||
|
||||
Uses nwMisc,nwServ;
|
||||
|
||||
Var errCode:Integer;
|
||||
connNbr:byte;
|
||||
connStr:String;
|
||||
showHelp:boolean;
|
||||
|
||||
begin
|
||||
|
||||
IF NOT CheckConsolePrivileges
|
||||
then begin
|
||||
IF nwServ.result=$C6
|
||||
then writeln('You need console privileges to run this util.')
|
||||
else writeln('Error checking console privileges, err#',nwServ.result);
|
||||
halt(1);
|
||||
end;
|
||||
|
||||
IF ParamCount=1
|
||||
then begin
|
||||
connStr:=ParamStr(1);
|
||||
Val(connStr,connNbr,errCode);
|
||||
showhelp:=(errCode<>0);
|
||||
end
|
||||
else showHelp:=true;
|
||||
|
||||
IF showHelp
|
||||
then begin
|
||||
writeln('CLRCONN-- usage:');
|
||||
writeln;
|
||||
writeln('CLRCONN connection_number');
|
||||
writeln;
|
||||
writeln('the connection_number must be supplied.');
|
||||
writeln('it should contain numbers only (range 1..255)');
|
||||
halt(1);
|
||||
end;
|
||||
IF ClearConnectionNumber(connNbr)
|
||||
then writeln('Connection ',connNbr,' was terminated.')
|
||||
else if nwServ.result=253
|
||||
then writeln('Connection NOT cleared. The supplied ConnectionNumber was too high.')
|
||||
else if nwServ.result=162
|
||||
then writeln('You cleared your own connection!')
|
||||
else writeln('Connection NOT cleared. Error# ',nwServ.result);
|
||||
|
||||
end.
|
||||
39
NWTP/XSERV/LOGLOCK.PAS
Normal file
39
NWTP/XSERV/LOGLOCK.PAS
Normal file
@@ -0,0 +1,39 @@
|
||||
{$X+,B-,V-} {essential compiler directives}
|
||||
|
||||
program loglock;
|
||||
|
||||
{ Example for the nwServ unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Purpose: This program toggles the login status..
|
||||
If User Login was enabled, it will be diabled and v.v. }
|
||||
|
||||
{ Tests the following nwServ functions:
|
||||
|
||||
DisableFileServerLogin
|
||||
EnableFileServerLogin
|
||||
GetFileServerLoginStatus
|
||||
}
|
||||
|
||||
uses nwMisc,nwServ;
|
||||
|
||||
Var allowed:boolean;
|
||||
|
||||
begin
|
||||
IF GetFileServerLoginStatus(allowed)
|
||||
then begin
|
||||
if allowed
|
||||
then begin
|
||||
DisableFileServerLogin;
|
||||
writeln('Login Disabled.')
|
||||
end
|
||||
else begin
|
||||
EnableFileserverLogin;
|
||||
writeln('Login Enabled.')
|
||||
end
|
||||
end
|
||||
else begin
|
||||
if nwServ.result=$C6
|
||||
then writeln('You need console operator rights to run this utility.')
|
||||
else writeln('GetFileserverLoginStatus Error : $',HexStr(nwServ.result,2));
|
||||
end;
|
||||
end.
|
||||
122
NWTP/XSERV/TSTSERV.PAS
Normal file
122
NWTP/XSERV/TSTSERV.PAS
Normal file
@@ -0,0 +1,122 @@
|
||||
{$X+,V-,B-}
|
||||
program tstServ;
|
||||
|
||||
{ Testprogram for the nwServ unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
||||
|
||||
{ Tests the following nwServ functions:
|
||||
|
||||
GetFileServerDateAndTime
|
||||
GetFileServerDescriptionStrings
|
||||
GetNetworkSerialNumber
|
||||
GetFileServerInformation
|
||||
SetFileServerDateAndTime
|
||||
VerifyNetworkSerialNumber
|
||||
}
|
||||
|
||||
uses nwMisc,nwServ;
|
||||
|
||||
Var t1,t2,t3:TnovTime;
|
||||
s1,s3:string;
|
||||
|
||||
serialNbr:Longint;
|
||||
appNbr,appNbr2:word;
|
||||
|
||||
Sinfo:TFileServerInformation;
|
||||
|
||||
companyName,VersionAndRevision,
|
||||
revisionDate,copyrightNotice:String;
|
||||
|
||||
begin
|
||||
writeln('TSTSERV: Test of some server function calls.');
|
||||
writeln;
|
||||
writeln('This program will change (and reset) the server time & date.');
|
||||
writeln('--This will cause the server to beep (twice)--');
|
||||
writeln;
|
||||
writeln('Continue ? (Y/N) + <RETURN>');
|
||||
readln(s1);
|
||||
if (pos('y',s1)=0) and (pos('Y',s1)=0)
|
||||
then halt(1);
|
||||
|
||||
writeln('Testing the Get/Set ServerTime Calls. (temporarily setting the year to 2020)');
|
||||
IF GetFileServerDateAndTime(t1)
|
||||
then begin
|
||||
nwMisc.NovTime2String(t1,s1);
|
||||
writeln('Original server time:',s1);
|
||||
t2:=t1;
|
||||
t2.year:=20; { set year to 2020 }
|
||||
t2.day:=1;
|
||||
t2.month:=4;
|
||||
IF SetFileServerDateAndTime(t2)
|
||||
then begin
|
||||
GetFileServerDateAndTime(t3);
|
||||
nwMisc.NovTime2String(t3,s3);
|
||||
if t3.year<>t2.year
|
||||
then writeln('Error: FileServerDateAndTime NOT changed..');
|
||||
writeln('New server time:',s3);
|
||||
SetFileServerDateAndTime(t1) {restore old date & time }
|
||||
end
|
||||
else begin
|
||||
if nwServ.result=$C6
|
||||
then writeln('Error: You need console privileges in order to change the server time.')
|
||||
else writeln('SetFileServerDateAndTime Error: $',HexStr(nwServ.result,2));
|
||||
end
|
||||
end
|
||||
else writeln('GetFileServerDateAndTime Error: $',HexStr(nwServ.result,2));
|
||||
|
||||
writeln;
|
||||
IF GetFileServerInformation(Sinfo)
|
||||
then begin
|
||||
writeln('Testing GetServerInformation..');
|
||||
writeln('Servername:',Sinfo.serverName);
|
||||
writeln('NW version:',Sinfo.NetwareVersion,'.',Sinfo.NetwareSubVersion);
|
||||
writeln('Conn Max,Current:',Sinfo.ConnectionsMax,',',Sinfo.ConnectionsInUse);
|
||||
writeln('Peak Conn Used :',Sinfo.Peak_Conn_Used);
|
||||
end
|
||||
else writeln('GetFileServerDateAndTime Error: $',HexStr(nwServ.result,2));
|
||||
|
||||
writeln;
|
||||
IF GetFileServerDescriptionStrings(companyName,VersionAndRevision,
|
||||
revisionDate,copyrightNotice)
|
||||
then begin
|
||||
writeln('Testing GetFileServerDescriptionStrings');
|
||||
writeln('Company :',companyName);
|
||||
writeln('Version/Rev:',VersionAndRevision);
|
||||
writeln('Rev.Date :',revisionDate);
|
||||
writeln('Copyright :',copyRightNotice);
|
||||
end
|
||||
else writeln('GetFileServerDescriptionStrings Error: $',HexStr(nwServ.result,2));
|
||||
|
||||
|
||||
writeln;
|
||||
IF GetNetworkSerialNumber(serialNbr,appNbr)
|
||||
then begin
|
||||
writeln('Testing GetNetworkSerialNumber');
|
||||
writeln('SerialNbr=',HexStr(serialNbr,8));
|
||||
writeln('AppNbr =',HexStr(appNbr,4));
|
||||
end
|
||||
else writeln('GetNetworkServerSerialNumber Error: $',HexStr(nwServ.result,2));
|
||||
|
||||
{ The last test is commented out. It works, but it is a bit irritating to
|
||||
be disconnected every time I'm testing a call.. }
|
||||
|
||||
|
||||
writeln('Testing VerifyNetworkSerialNumber (will abort workstations'' connection)');
|
||||
writeln('Continue ? (Y/N) + <RETURN>');
|
||||
readln(s1);
|
||||
if (pos('y',s1)=0) and (pos('Y',s1)=0)
|
||||
then halt(1);
|
||||
|
||||
{
|
||||
IF VerifyNetworkSerialNumber(serialNbr,appNbr2)
|
||||
then begin
|
||||
if appNbr2=appNbr then writeln('Serial Number Verified.');
|
||||
writeln;
|
||||
writeln('Verifying a wrong network serialnumber..');
|
||||
writeln('**** THIS WILL TERMINATE THE CONNECTION **** (if the calls works..)');
|
||||
If VerifyNetworkSerialNumber($12345678,appNbr2)
|
||||
then writeln('false serialnumber verified as being OK');
|
||||
end
|
||||
else writeln('VerifyNetworkSerialNumber Error: $',HexStr(nwServ.result,2));
|
||||
}
|
||||
|
||||
end.
|
||||
92
README
Normal file
92
README
Normal file
@@ -0,0 +1,92 @@
|
||||
James@linux-box.demon.co.uk
|
||||
|
||||
README FOR NWE Admin 0.1
|
||||
========================
|
||||
|
||||
Please read COPYING for licence and other important information.
|
||||
This software is released unde the GNU General Public Licence.
|
||||
|
||||
The latest version of this software can be found
|
||||
at http://www.linux-box.demon.co.uk.
|
||||
|
||||
Hi Folks! I'm James Jeffrey Thanks for trying my software and I hope
|
||||
you like it.
|
||||
|
||||
!This software is in a very early state, the interface is fairly self!
|
||||
!explanatory (I HOPE ;-) ) So I will let you work it out! !
|
||||
VERY VERY VERY BUGGY BE VERY VERY VERY CAREFULL! BACK STUFF UP!
|
||||
YOU COULD SCREW UP YOUR SERVER!
|
||||
|
||||
|============================================================|
|
||||
|If you use this software, I ask you to mail me and tell me, |
|
||||
|use James@linux-box.demon.co.uk. |
|
||||
|============================================================|
|
||||
|
||||
If you hate this software tell me why, mabye I can fix it.
|
||||
If you find a bug, have a suggetsion or a code fix, mail me it,
|
||||
your name will be mentioned in the next release!
|
||||
|
||||
I am sorry, the source is next to unreadable, I will clear this
|
||||
up for 0.2 if enough interest is shown.
|
||||
|
||||
If you wish to make a small donation to this hard-up student then
|
||||
please feel free, I need UK currency if possible. Donations VERY
|
||||
gratefully accepted.
|
||||
|
||||
James Jeffrey
|
||||
41 West Park Avenue
|
||||
Roundhay
|
||||
Leeds
|
||||
LS8 2EB
|
||||
United Kingdom
|
||||
|
||||
|
||||
PLEASE NOTE
|
||||
===========
|
||||
|
||||
This program works with Mars_NWE, it runs under Windows 3+ and may
|
||||
require some DLL's I have not shipped (If it needs them mail me
|
||||
but they should be easily available.), it requires a running netware
|
||||
client.
|
||||
|
||||
|
||||
INSTRUCTIONS
|
||||
============
|
||||
|
||||
Remove the supervisor password form nwserv.conf, also remove all user
|
||||
entries in nwserv.conf.
|
||||
|
||||
Run NWADMIN.EXE on your windows machine when attached to the mars server.
|
||||
|
||||
Good Luck.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
PLANS FOR 0.2 or 0.3 or 0.4 etc..
|
||||
==================================
|
||||
|
||||
Write a TCP/IP demon to run under INETD on the unix system
|
||||
to allow for automatic creation and deletion of unix users
|
||||
and setting of quitas on ext2 file systems under linux, as
|
||||
well as managing volumes.
|
||||
|
||||
German Language Version (I don't speak German...)
|
||||
|
||||
Any help welcome.
|
||||
|
||||
|
||||
|
||||
See Ya All
|
||||
|
||||
|
||||
P.S. My congratulations to MArtin Stover and Team for a fantastic
|
||||
piece of software - Mars NWE!
|
||||
|
||||
P.P.S.
|
||||
|
||||
This program was written in delphi using a GPL'd netware library
|
||||
which I have slightly modified for Delphi. This library was mainly
|
||||
written by R.Spronk. I have included both original and modified
|
||||
versions.
|
||||
339
SRC/COPYING
Normal file
339
SRC/COPYING
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, 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) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
BIN
SRC/DELUSER.DCU
Normal file
BIN
SRC/DELUSER.DCU
Normal file
Binary file not shown.
BIN
SRC/DELUSER.DFM
Normal file
BIN
SRC/DELUSER.DFM
Normal file
Binary file not shown.
29
SRC/DELUSER.PAS
Normal file
29
SRC/DELUSER.PAS
Normal file
@@ -0,0 +1,29 @@
|
||||
unit Deluser;
|
||||
|
||||
interface
|
||||
|
||||
uses WinTypes, WinProcs, Classes, Graphics, Forms, Controls, Buttons,
|
||||
StdCtrls, ExtCtrls;
|
||||
|
||||
type
|
||||
TBtnRightDlg = class(TForm)
|
||||
OKBtn: TBitBtn;
|
||||
CancelBtn: TBitBtn;
|
||||
HelpBtn: TBitBtn;
|
||||
Bevel1: TBevel;
|
||||
ListBox1: TListBox;
|
||||
Label1: TLabel;
|
||||
private
|
||||
{ Private declarations }
|
||||
public
|
||||
{ Public declarations }
|
||||
end;
|
||||
|
||||
var
|
||||
BtnRightDlg: TBtnRightDlg;
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.DFM}
|
||||
|
||||
end.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user